summaryrefslogtreecommitdiff
path: root/editeng/source/editeng/editdoc2.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'editeng/source/editeng/editdoc2.cxx')
-rw-r--r--editeng/source/editeng/editdoc2.cxx544
1 files changed, 544 insertions, 0 deletions
diff --git a/editeng/source/editeng/editdoc2.cxx b/editeng/source/editeng/editdoc2.cxx
new file mode 100644
index 000000000000..b2a83ffd6274
--- /dev/null
+++ b/editeng/source/editeng/editdoc2.cxx
@@ -0,0 +1,544 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_editeng.hxx"
+
+#include <vcl/wrkwin.hxx>
+#include <vcl/dialog.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/smplhint.hxx>
+
+#include <tools/rtti.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/adjitem.hxx>
+#include <editeng/tstpitem.hxx>
+
+#include <editdoc.hxx>
+#include <impedit.hxx>
+#include <editdbg.hxx>
+
+#include <editeng/numitem.hxx>
+
+#include <editeng/akrnitem.hxx>
+#include <editeng/cntritem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/charscaleitem.hxx>
+
+#include <vcl/svapp.hxx> // Fuer AppWindow...
+
+DBG_NAME( EE_ParaPortion )
+
+SV_IMPL_VARARR( CharPosArray, sal_Int32 );
+
+/*
+
+BOOL EditStyleSheet::HasStyleAsAnyParent( SfxStyleSheet& rStyle )
+{
+ if ( GetParent() == rStyle.GetName() )
+ return TRUE;
+
+ if ( GetParent().Len() && ( GetParent() != GetName() ) )
+ {
+ EditStyleSheet* pS = (EditStyleSheet*)GetPool().Find( GetParent(), rStyle.GetFamily() );
+ if ( pS )
+ return pS->HasStyleAsAnyParent( rStyle );
+ }
+ return FALSE;
+}
+
+*/
+
+// -------------------------------------------------------------------------
+// class TextPortionList
+// -------------------------------------------------------------------------
+TextPortionList::TextPortionList()
+{
+}
+
+TextPortionList::~TextPortionList()
+{
+ Reset();
+}
+
+void TextPortionList::Reset()
+{
+ for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ )
+ delete GetObject( nPortion );
+ Remove( 0, Count() );
+}
+
+void TextPortionList::DeleteFromPortion( USHORT nDelFrom )
+{
+ DBG_ASSERT( ( nDelFrom < Count() ) || ( (nDelFrom == 0) && (Count() == 0) ), "DeleteFromPortion: Out of range" );
+ for ( USHORT nP = nDelFrom; nP < Count(); nP++ )
+ delete GetObject( nP );
+ Remove( nDelFrom, Count()-nDelFrom );
+}
+
+USHORT TextPortionList::FindPortion( USHORT nCharPos, USHORT& nPortionStart, BOOL bPreferStartingPortion )
+{
+ // Bei nCharPos an Portion-Grenze wird die linke Portion gefunden
+ USHORT nTmpPos = 0;
+ for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ )
+ {
+ TextPortion* pPortion = GetObject( nPortion );
+ nTmpPos = nTmpPos + pPortion->GetLen();
+ if ( nTmpPos >= nCharPos )
+ {
+ // take this one if we don't prefer the starting portion, or if it's the last one
+ if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == Count() - 1 ) )
+ {
+ nPortionStart = nTmpPos - pPortion->GetLen();
+ return nPortion;
+ }
+ }
+ }
+ DBG_ERROR( "FindPortion: Nicht gefunden!" );
+ return ( Count() - 1 );
+}
+
+USHORT TextPortionList::GetStartPos( USHORT nPortion )
+{
+ USHORT nPos = 0;
+ for ( USHORT n = 0; n < nPortion; n++ )
+ {
+ TextPortion* pPortion = GetObject( n );
+ nPos = nPos + pPortion->GetLen();
+ }
+ return nPos;
+}
+
+
+// -------------------------------------------------------------------------
+// class ExtraPortionInfo
+// -------------------------------------------------------------------------
+
+ExtraPortionInfo::ExtraPortionInfo()
+{
+ nOrgWidth = 0;
+ nWidthFullCompression = 0;
+ nMaxCompression100thPercent = 0;
+ nAsianCompressionTypes = 0;
+ nPortionOffsetX = 0;
+ bFirstCharIsRightPunktuation = FALSE;
+ bCompressed = FALSE;
+ pOrgDXArray = NULL;
+}
+
+ExtraPortionInfo::~ExtraPortionInfo()
+{
+ delete[] pOrgDXArray;
+}
+
+void ExtraPortionInfo::SaveOrgDXArray( const sal_Int32* pDXArray, USHORT nLen )
+{
+ delete[] pOrgDXArray;
+ pOrgDXArray = new sal_Int32[nLen];
+ memcpy( pOrgDXArray, pDXArray, nLen*sizeof(sal_Int32) );
+}
+
+void ExtraPortionInfo::DestroyOrgDXArray()
+{
+ delete[] pOrgDXArray;
+ pOrgDXArray = NULL;
+}
+
+
+// -------------------------------------------------------------------------
+// class ParaPortion
+// -------------------------------------------------------------------------
+ParaPortion::ParaPortion( ContentNode* pN )
+{
+ DBG_CTOR( EE_ParaPortion, 0 );
+
+ pNode = pN;
+ bInvalid = TRUE;
+ bVisible = TRUE;
+ bSimple = FALSE;
+ bForceRepaint = FALSE;
+ nInvalidPosStart = 0;
+ nInvalidDiff = 0;
+ nHeight = 0;
+ nFirstLineOffset = 0;
+ nBulletX = 0;
+}
+
+ParaPortion::~ParaPortion()
+{
+ DBG_DTOR( EE_ParaPortion, 0 );
+}
+
+void ParaPortion::MarkInvalid( USHORT nStart, short nDiff )
+{
+ if ( bInvalid == FALSE )
+ {
+// nInvalidPosEnd = nStart; // ??? => CreateLines
+ nInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff );
+ nInvalidDiff = nDiff;
+ }
+ else
+ {
+ // Einfaches hintereinander tippen
+ if ( ( nDiff > 0 ) && ( nInvalidDiff > 0 ) &&
+ ( ( nInvalidPosStart+nInvalidDiff ) == nStart ) )
+ {
+ nInvalidDiff = nInvalidDiff + nDiff;
+ }
+ // Einfaches hintereinander loeschen
+ else if ( ( nDiff < 0 ) && ( nInvalidDiff < 0 ) && ( nInvalidPosStart == nStart ) )
+ {
+ nInvalidPosStart = nInvalidPosStart + nDiff;
+ nInvalidDiff = nInvalidDiff + nDiff;
+ }
+ else
+ {
+// nInvalidPosEnd = pNode->Len();
+ DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" );
+ nInvalidPosStart = Min( nInvalidPosStart, (USHORT) ( nDiff < 0 ? nStart+nDiff : nDiff ) );
+ nInvalidDiff = 0;
+ bSimple = FALSE;
+ }
+ }
+ bInvalid = TRUE;
+ aScriptInfos.Remove( 0, aScriptInfos.Count() );
+ aWritingDirectionInfos.Remove( 0, aWritingDirectionInfos.Count() );
+// aExtraCharInfos.Remove( 0, aExtraCharInfos.Count() );
+}
+
+void ParaPortion::MarkSelectionInvalid( USHORT nStart, USHORT /* nEnd */ )
+{
+ if ( bInvalid == FALSE )
+ {
+ nInvalidPosStart = nStart;
+// nInvalidPosEnd = nEnd;
+ }
+ else
+ {
+ nInvalidPosStart = Min( nInvalidPosStart, nStart );
+// nInvalidPosEnd = pNode->Len();
+ }
+ nInvalidDiff = 0;
+ bInvalid = TRUE;
+ bSimple = FALSE;
+ aScriptInfos.Remove( 0, aScriptInfos.Count() );
+ aWritingDirectionInfos.Remove( 0, aWritingDirectionInfos.Count() );
+// aExtraCharInfos.Remove( 0, aExtraCharInfos.Count() );
+}
+
+USHORT ParaPortion::GetLineNumber( USHORT nIndex )
+{
+ DBG_ASSERTWARNING( aLineList.Count(), "Leere ParaPortion in GetLine!" );
+ DBG_ASSERT( bVisible, "Wozu GetLine() bei einem unsichtbaren Absatz?" );
+
+ for ( USHORT nLine = 0; nLine < aLineList.Count(); nLine++ )
+ {
+ if ( aLineList[nLine]->IsIn( nIndex ) )
+ return nLine;
+ }
+
+ // Dann sollte es am Ende der letzten Zeile sein!
+ DBG_ASSERT( nIndex == aLineList[ aLineList.Count() - 1 ]->GetEnd(), "Index voll daneben!" );
+ return (aLineList.Count()-1);
+}
+
+void ParaPortion::SetVisible( BOOL bMakeVisible )
+{
+ bVisible = bMakeVisible;
+}
+
+void ParaPortion::CorrectValuesBehindLastFormattedLine( USHORT nLastFormattedLine )
+{
+ USHORT nLines = aLineList.Count();
+ DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Leere Portion?" );
+ if ( nLastFormattedLine < ( nLines - 1 ) )
+ {
+ const EditLine* pLastFormatted = aLineList[ nLastFormattedLine ];
+ const EditLine* pUnformatted = aLineList[ nLastFormattedLine+1 ];
+ short nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion();
+ short nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd();
+ nTextDiff++; // LastFormatted->GetEnd() war incl. => 1 zuviel abgezogen!
+
+ // Die erste unformatierte muss genau eine Portion hinter der letzten der
+ // formatierten beginnen:
+ // Wenn in der geaenderten Zeile eine Portion gesplittet wurde,
+ // kann nLastEnd > nNextStart sein!
+ int nPDiff = -( nPortionDiff-1 );
+ int nTDiff = -( nTextDiff-1 );
+ if ( nPDiff || nTDiff )
+ {
+ for ( USHORT nL = nLastFormattedLine+1; nL < nLines; nL++ )
+ {
+ EditLine* pLine = aLineList[ nL ];
+
+ pLine->GetStartPortion() = sal::static_int_cast< USHORT >(
+ pLine->GetStartPortion() + nPDiff);
+ pLine->GetEndPortion() = sal::static_int_cast< USHORT >(
+ pLine->GetEndPortion() + nPDiff);
+
+ pLine->GetStart() = sal::static_int_cast< USHORT >(
+ pLine->GetStart() + nTDiff);
+ pLine->GetEnd() = sal::static_int_cast< USHORT >(
+ pLine->GetEnd() + nTDiff);
+
+ pLine->SetValid();
+ }
+ }
+ }
+ DBG_ASSERT( aLineList[ aLineList.Count()-1 ]->GetEnd() == pNode->Len(), "CorrectLines: Ende stimmt nicht!" );
+}
+
+// Shared reverse lookup acceleration pieces ...
+
+static USHORT FastGetPos( const VoidPtr *pPtrArray, USHORT nPtrArrayLen,
+ VoidPtr pPtr, USHORT &rLastPos )
+{
+ // Through certain filter code-paths we do a lot of appends, which in
+ // turn call GetPos - creating some N^2 nightmares. If we have a
+ // non-trivially large list, do a few checks from the end first.
+ if( rLastPos > 16 )
+ {
+ USHORT nEnd;
+ if (rLastPos > nPtrArrayLen - 2)
+ nEnd = nPtrArrayLen;
+ else
+ nEnd = rLastPos + 2;
+
+ for( USHORT nIdx = rLastPos - 2; nIdx < nEnd; nIdx++ )
+ {
+ if( pPtrArray[ nIdx ] == pPtr )
+ {
+ rLastPos = nIdx;
+ return nIdx;
+ }
+ }
+ }
+ // The world's lamest linear search from svarray ...
+ for( USHORT nIdx = 0; nIdx < nPtrArrayLen; nIdx++ )
+ if (pPtrArray[ nIdx ] == pPtr )
+ return rLastPos = nIdx;
+ return USHRT_MAX;
+}
+
+// -------------------------------------------------------------------------
+// class ParaPortionList
+// -------------------------------------------------------------------------
+ParaPortionList::ParaPortionList() : nLastCache( 0 )
+{
+}
+
+ParaPortionList::~ParaPortionList()
+{
+ Reset();
+}
+
+USHORT ParaPortionList::GetPos( const ParaPortionPtr &rPtr ) const
+{
+ return FastGetPos( reinterpret_cast<const VoidPtr *>( GetData() ),
+ Count(), static_cast<VoidPtr>( rPtr ),
+ ((ParaPortionList *)this)->nLastCache );
+}
+
+USHORT ContentList::GetPos( const ContentNodePtr &rPtr ) const
+{
+ return FastGetPos( reinterpret_cast<const VoidPtr *>( GetData() ),
+ Count(), static_cast<VoidPtr>( rPtr ),
+ ((ContentList *)this)->nLastCache );
+}
+
+void ParaPortionList::Reset()
+{
+ for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ )
+ delete GetObject( nPortion );
+ Remove( 0, Count() );
+}
+
+long ParaPortionList::GetYOffset( ParaPortion* pPPortion )
+{
+ long nHeight = 0;
+ for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ )
+ {
+ ParaPortion* pTmpPortion = GetObject(nPortion);
+ if ( pTmpPortion == pPPortion )
+ return nHeight;
+ nHeight += pTmpPortion->GetHeight();
+ }
+ DBG_ERROR( "GetYOffset: Portion nicht gefunden" );
+ return nHeight;
+}
+
+USHORT ParaPortionList::FindParagraph( long nYOffset )
+{
+ long nY = 0;
+ for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ )
+ {
+ nY += GetObject(nPortion)->GetHeight(); // sollte auch bei !bVisible richtig sein!
+ if ( nY > nYOffset )
+ return nPortion;
+ }
+ return 0xFFFF; // solte mal ueber EE_PARA_NOT_FOUND erreicht werden!
+}
+
+void ParaPortionList::DbgCheck( EditDoc&
+#ifdef DBG_UTIL
+ rDoc
+#endif
+ )
+{
+#ifdef DBG_UTIL
+ DBG_ASSERT( Count() == rDoc.Count(), "ParaPortionList::DbgCheck() - Count() ungleich!" );
+ for ( USHORT i = 0; i < Count(); i++ )
+ {
+ DBG_ASSERT( SaveGetObject(i), "ParaPortionList::DbgCheck() - Null-Pointer in Liste!" );
+ DBG_ASSERT( GetObject(i)->GetNode(), "ParaPortionList::DbgCheck() - Null-Pointer in Liste(2)!" );
+ DBG_ASSERT( GetObject(i)->GetNode() == rDoc.GetObject(i), "ParaPortionList::DbgCheck() - Eintraege kreuzen sich!" );
+ }
+#endif
+}
+
+
+ContentAttribsInfo::ContentAttribsInfo( const SfxItemSet& rParaAttribs ) :
+ aPrevParaAttribs( rParaAttribs)
+{
+}
+
+
+void ConvertItem( SfxPoolItem& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit )
+{
+ DBG_ASSERT( eSourceUnit != eDestUnit, "ConvertItem - Why?!" );
+
+ switch ( rPoolItem.Which() )
+ {
+ case EE_PARA_LRSPACE:
+ {
+ DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLRSpaceItem ) ), "ConvertItem: Ungueltiges Item!" );
+ SvxLRSpaceItem& rItem = (SvxLRSpaceItem&)rPoolItem;
+ rItem.SetTxtFirstLineOfst( sal::static_int_cast< short >( OutputDevice::LogicToLogic( rItem.GetTxtFirstLineOfst(), eSourceUnit, eDestUnit ) ) );
+ rItem.SetTxtLeft( OutputDevice::LogicToLogic( rItem.GetTxtLeft(), eSourceUnit, eDestUnit ) );
+// rItem.SetLeft( OutputDevice::LogicToLogic( rItem.GetLeft(), eSourceUnit, eDestUnit ) ); // #96298# SetLeft manipulates nTxtLeft!
+ rItem.SetRight( OutputDevice::LogicToLogic( rItem.GetRight(), eSourceUnit, eDestUnit ) );
+ }
+ break;
+ case EE_PARA_ULSPACE:
+ {
+ DBG_ASSERT( rPoolItem.IsA( TYPE( SvxULSpaceItem ) ), "ConvertItem: Ungueltiges Item!" );
+ SvxULSpaceItem& rItem = (SvxULSpaceItem&)rPoolItem;
+ rItem.SetUpper( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetUpper(), eSourceUnit, eDestUnit ) ) );
+ rItem.SetLower( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetLower(), eSourceUnit, eDestUnit ) ) );
+ }
+ break;
+ case EE_PARA_SBL:
+ {
+ DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLineSpacingItem ) ), "ConvertItem: Ungueltiges Item!" );
+ SvxLineSpacingItem& rItem = (SvxLineSpacingItem&)rPoolItem;
+ // #96298# SetLineHeight changes also eLineSpace!
+ if ( rItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN )
+ rItem.SetLineHeight( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetLineHeight(), eSourceUnit, eDestUnit ) ) );
+ }
+ break;
+ case EE_PARA_TABS:
+ {
+ DBG_ASSERT( rPoolItem.IsA( TYPE( SvxTabStopItem ) ), "ConvertItem: Ungueltiges Item!" );
+ SvxTabStopItem& rItem = (SvxTabStopItem&)rPoolItem;
+ SvxTabStopItem aNewItem( EE_PARA_TABS );
+ for ( USHORT i = 0; i < rItem.Count(); i++ )
+ {
+ const SvxTabStop& rTab = rItem[i];
+ SvxTabStop aNewStop( OutputDevice::LogicToLogic( rTab.GetTabPos(), eSourceUnit, eDestUnit ), rTab.GetAdjustment(), rTab.GetDecimal(), rTab.GetFill() );
+ aNewItem.Insert( aNewStop );
+ }
+ rItem = aNewItem;
+ }
+ break;
+ case EE_CHAR_FONTHEIGHT:
+ case EE_CHAR_FONTHEIGHT_CJK:
+ case EE_CHAR_FONTHEIGHT_CTL:
+ {
+ DBG_ASSERT( rPoolItem.IsA( TYPE( SvxFontHeightItem ) ), "ConvertItem: Ungueltiges Item!" );
+ SvxFontHeightItem& rItem = (SvxFontHeightItem&)rPoolItem;
+ rItem.SetHeight( OutputDevice::LogicToLogic( rItem.GetHeight(), eSourceUnit, eDestUnit ) );
+ }
+ break;
+ }
+}
+
+void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit, const MapUnit* pDestUnit )
+{
+ const SfxItemPool* pSourcePool = rSource.GetPool();
+ const SfxItemPool* pDestPool = rDest.GetPool();
+
+ for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
+ {
+ // Wenn moeglich ueber SlotID gehen...
+
+ USHORT nSourceWhich = nWhich;
+ USHORT nSlot = pDestPool->GetTrueSlotId( nWhich );
+ if ( nSlot )
+ {
+ USHORT nW = pSourcePool->GetTrueWhich( nSlot );
+ if ( nW )
+ nSourceWhich = nW;
+ }
+
+ if ( rSource.GetItemState( nSourceWhich, FALSE ) == SFX_ITEM_ON )
+ {
+ MapUnit eSourceUnit = pSourceUnit ? *pSourceUnit : (MapUnit)pSourcePool->GetMetric( nSourceWhich );
+ MapUnit eDestUnit = pDestUnit ? *pDestUnit : (MapUnit)pDestPool->GetMetric( nWhich );
+ if ( eSourceUnit != eDestUnit )
+ {
+ SfxPoolItem* pItem = rSource.Get( nSourceWhich ).Clone();
+// pItem->SetWhich( nWhich );
+ ConvertItem( *pItem, eSourceUnit, eDestUnit );
+ rDest.Put( *pItem, nWhich );
+ delete pItem;
+ }
+ else
+ {
+ rDest.Put( rSource.Get( nSourceWhich ), nWhich );
+ }
+ }
+ else
+ {
+ // MT 3.3.99: Waere so eigentlich richtig, aber schon seit Jahren nicht so...
+// rDest.ClearItem( nWhich );
+ }
+ }
+}
+