1*190118d0SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*190118d0SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*190118d0SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*190118d0SAndrew Rist  * distributed with this work for additional information
6*190118d0SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*190118d0SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*190118d0SAndrew Rist  * "License"); you may not use this file except in compliance
9*190118d0SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*190118d0SAndrew Rist  *
11*190118d0SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*190118d0SAndrew Rist  *
13*190118d0SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*190118d0SAndrew Rist  * software distributed under the License is distributed on an
15*190118d0SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*190118d0SAndrew Rist  * KIND, either express or implied.  See the License for the
17*190118d0SAndrew Rist  * specific language governing permissions and limitations
18*190118d0SAndrew Rist  * under the License.
19*190118d0SAndrew Rist  *
20*190118d0SAndrew Rist  *************************************************************/
21*190118d0SAndrew Rist 
22*190118d0SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_editeng.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <vcl/wrkwin.hxx>
28cdf0e10cSrcweir #include <vcl/dialog.hxx>
29cdf0e10cSrcweir #include <vcl/msgbox.hxx>
30cdf0e10cSrcweir #include <vcl/svapp.hxx>
31cdf0e10cSrcweir #include <svl/smplhint.hxx>
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include <tools/rtti.hxx>
34cdf0e10cSrcweir #include <editeng/lspcitem.hxx>
35cdf0e10cSrcweir #include <editeng/adjitem.hxx>
36cdf0e10cSrcweir #include <editeng/tstpitem.hxx>
37cdf0e10cSrcweir 
38cdf0e10cSrcweir #include <editdoc.hxx>
39cdf0e10cSrcweir #include <impedit.hxx>
40cdf0e10cSrcweir #include <editdbg.hxx>
41cdf0e10cSrcweir 
42cdf0e10cSrcweir #include <editeng/numitem.hxx>
43cdf0e10cSrcweir 
44cdf0e10cSrcweir #include <editeng/akrnitem.hxx>
45cdf0e10cSrcweir #include <editeng/cntritem.hxx>
46cdf0e10cSrcweir #include <editeng/colritem.hxx>
47cdf0e10cSrcweir #include <editeng/crsditem.hxx>
48cdf0e10cSrcweir #include <editeng/escpitem.hxx>
49cdf0e10cSrcweir #include <editeng/fhgtitem.hxx>
50cdf0e10cSrcweir #include <editeng/fontitem.hxx>
51cdf0e10cSrcweir #include <editeng/kernitem.hxx>
52cdf0e10cSrcweir #include <editeng/lrspitem.hxx>
53cdf0e10cSrcweir #include <editeng/postitem.hxx>
54cdf0e10cSrcweir #include <editeng/shdditem.hxx>
55cdf0e10cSrcweir #include <editeng/udlnitem.hxx>
56cdf0e10cSrcweir #include <editeng/ulspitem.hxx>
57cdf0e10cSrcweir #include <editeng/wghtitem.hxx>
58cdf0e10cSrcweir #include <editeng/wrlmitem.hxx>
59cdf0e10cSrcweir #include <editeng/charscaleitem.hxx>
60cdf0e10cSrcweir 
61cdf0e10cSrcweir #include <vcl/svapp.hxx>	// Fuer AppWindow...
62cdf0e10cSrcweir 
63cdf0e10cSrcweir DBG_NAME( EE_ParaPortion )
64cdf0e10cSrcweir 
65cdf0e10cSrcweir SV_IMPL_VARARR( CharPosArray, sal_Int32 );
66cdf0e10cSrcweir 
67cdf0e10cSrcweir /*
68cdf0e10cSrcweir 
69cdf0e10cSrcweir sal_Bool EditStyleSheet::HasStyleAsAnyParent( SfxStyleSheet& rStyle )
70cdf0e10cSrcweir {
71cdf0e10cSrcweir 	if ( GetParent() == rStyle.GetName() )
72cdf0e10cSrcweir 		return sal_True;
73cdf0e10cSrcweir 
74cdf0e10cSrcweir 	if ( GetParent().Len() && ( GetParent() != GetName() ) )
75cdf0e10cSrcweir 	{
76cdf0e10cSrcweir 		EditStyleSheet* pS = (EditStyleSheet*)GetPool().Find( GetParent(), rStyle.GetFamily() );
77cdf0e10cSrcweir 		if ( pS )
78cdf0e10cSrcweir 			return pS->HasStyleAsAnyParent( rStyle );
79cdf0e10cSrcweir 	}
80cdf0e10cSrcweir 	return sal_False;
81cdf0e10cSrcweir }
82cdf0e10cSrcweir 
83cdf0e10cSrcweir */
84cdf0e10cSrcweir 
85cdf0e10cSrcweir // -------------------------------------------------------------------------
86cdf0e10cSrcweir // class TextPortionList
87cdf0e10cSrcweir // -------------------------------------------------------------------------
TextPortionList()88cdf0e10cSrcweir TextPortionList::TextPortionList()
89cdf0e10cSrcweir {
90cdf0e10cSrcweir }
91cdf0e10cSrcweir 
~TextPortionList()92cdf0e10cSrcweir TextPortionList::~TextPortionList()
93cdf0e10cSrcweir {
94cdf0e10cSrcweir 	Reset();
95cdf0e10cSrcweir }
96cdf0e10cSrcweir 
Reset()97cdf0e10cSrcweir void TextPortionList::Reset()
98cdf0e10cSrcweir {
99cdf0e10cSrcweir 	for ( sal_uInt16 nPortion = 0; nPortion < Count(); nPortion++ )
100cdf0e10cSrcweir 		delete GetObject( nPortion );
101cdf0e10cSrcweir 	Remove( 0, Count() );
102cdf0e10cSrcweir }
103cdf0e10cSrcweir 
DeleteFromPortion(sal_uInt16 nDelFrom)104cdf0e10cSrcweir void TextPortionList::DeleteFromPortion( sal_uInt16 nDelFrom )
105cdf0e10cSrcweir {
106cdf0e10cSrcweir 	DBG_ASSERT( ( nDelFrom < Count() ) || ( (nDelFrom == 0) && (Count() == 0) ), "DeleteFromPortion: Out of range" );
107cdf0e10cSrcweir 	for ( sal_uInt16 nP = nDelFrom; nP < Count(); nP++ )
108cdf0e10cSrcweir 		delete GetObject( nP );
109cdf0e10cSrcweir 	Remove( nDelFrom, Count()-nDelFrom );
110cdf0e10cSrcweir }
111cdf0e10cSrcweir 
FindPortion(sal_uInt16 nCharPos,sal_uInt16 & nPortionStart,sal_Bool bPreferStartingPortion)112cdf0e10cSrcweir sal_uInt16 TextPortionList::FindPortion( sal_uInt16 nCharPos, sal_uInt16& nPortionStart, sal_Bool bPreferStartingPortion )
113cdf0e10cSrcweir {
114cdf0e10cSrcweir 	// Bei nCharPos an Portion-Grenze wird die linke Portion gefunden
115cdf0e10cSrcweir 	sal_uInt16 nTmpPos = 0;
116cdf0e10cSrcweir 	for ( sal_uInt16 nPortion = 0; nPortion < Count(); nPortion++ )
117cdf0e10cSrcweir 	{
118cdf0e10cSrcweir 		TextPortion* pPortion = GetObject( nPortion );
119cdf0e10cSrcweir 		nTmpPos = nTmpPos + pPortion->GetLen();
120cdf0e10cSrcweir 		if ( nTmpPos >= nCharPos )
121cdf0e10cSrcweir 		{
122cdf0e10cSrcweir             // take this one if we don't prefer the starting portion, or if it's the last one
123cdf0e10cSrcweir             if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == Count() - 1 ) )
124cdf0e10cSrcweir             {
125cdf0e10cSrcweir 			    nPortionStart = nTmpPos - pPortion->GetLen();
126cdf0e10cSrcweir 			    return nPortion;
127cdf0e10cSrcweir             }
128cdf0e10cSrcweir 		}
129cdf0e10cSrcweir 	}
130cdf0e10cSrcweir 	DBG_ERROR( "FindPortion: Nicht gefunden!" );
131cdf0e10cSrcweir 	return ( Count() - 1 );
132cdf0e10cSrcweir }
133cdf0e10cSrcweir 
GetStartPos(sal_uInt16 nPortion)134cdf0e10cSrcweir sal_uInt16 TextPortionList::GetStartPos( sal_uInt16 nPortion )
135cdf0e10cSrcweir {
136cdf0e10cSrcweir     sal_uInt16 nPos = 0;
137cdf0e10cSrcweir 	for ( sal_uInt16 n = 0; n < nPortion; n++ )
138cdf0e10cSrcweir 	{
139cdf0e10cSrcweir 		TextPortion* pPortion = GetObject( n );
140cdf0e10cSrcweir 		nPos = nPos + pPortion->GetLen();
141cdf0e10cSrcweir 	}
142cdf0e10cSrcweir     return nPos;
143cdf0e10cSrcweir }
144cdf0e10cSrcweir 
145cdf0e10cSrcweir 
146cdf0e10cSrcweir // -------------------------------------------------------------------------
147cdf0e10cSrcweir // class ExtraPortionInfo
148cdf0e10cSrcweir // -------------------------------------------------------------------------
149cdf0e10cSrcweir 
ExtraPortionInfo()150cdf0e10cSrcweir ExtraPortionInfo::ExtraPortionInfo()
151cdf0e10cSrcweir {
152cdf0e10cSrcweir     nOrgWidth = 0;
153cdf0e10cSrcweir     nWidthFullCompression = 0;
154cdf0e10cSrcweir     nMaxCompression100thPercent = 0;
155cdf0e10cSrcweir     nAsianCompressionTypes = 0;
156cdf0e10cSrcweir     nPortionOffsetX = 0;
157cdf0e10cSrcweir     bFirstCharIsRightPunktuation = sal_False;
158cdf0e10cSrcweir     bCompressed = sal_False;
159cdf0e10cSrcweir     pOrgDXArray = NULL;
160cdf0e10cSrcweir }
161cdf0e10cSrcweir 
~ExtraPortionInfo()162cdf0e10cSrcweir ExtraPortionInfo::~ExtraPortionInfo()
163cdf0e10cSrcweir {
164cdf0e10cSrcweir     delete[] pOrgDXArray;
165cdf0e10cSrcweir }
166cdf0e10cSrcweir 
SaveOrgDXArray(const sal_Int32 * pDXArray,sal_uInt16 nLen)167cdf0e10cSrcweir void ExtraPortionInfo::SaveOrgDXArray( const sal_Int32* pDXArray, sal_uInt16 nLen )
168cdf0e10cSrcweir {
169cdf0e10cSrcweir     delete[] pOrgDXArray;
170cdf0e10cSrcweir     pOrgDXArray = new sal_Int32[nLen];
171cdf0e10cSrcweir     memcpy( pOrgDXArray, pDXArray, nLen*sizeof(sal_Int32) );
172cdf0e10cSrcweir }
173cdf0e10cSrcweir 
DestroyOrgDXArray()174cdf0e10cSrcweir void ExtraPortionInfo::DestroyOrgDXArray()
175cdf0e10cSrcweir {
176cdf0e10cSrcweir     delete[] pOrgDXArray;
177cdf0e10cSrcweir     pOrgDXArray = NULL;
178cdf0e10cSrcweir }
179cdf0e10cSrcweir 
180cdf0e10cSrcweir 
181cdf0e10cSrcweir // -------------------------------------------------------------------------
182cdf0e10cSrcweir // class ParaPortion
183cdf0e10cSrcweir // -------------------------------------------------------------------------
ParaPortion(ContentNode * pN)184cdf0e10cSrcweir ParaPortion::ParaPortion( ContentNode* pN )
185cdf0e10cSrcweir {
186cdf0e10cSrcweir 	DBG_CTOR( EE_ParaPortion, 0 );
187cdf0e10cSrcweir 
188cdf0e10cSrcweir 	pNode 				= pN;
189cdf0e10cSrcweir 	bInvalid 			= sal_True;
190cdf0e10cSrcweir 	bVisible 			= sal_True;
191cdf0e10cSrcweir 	bSimple 			= sal_False;
192cdf0e10cSrcweir 	bForceRepaint 		= sal_False;
193cdf0e10cSrcweir 	nInvalidPosStart	= 0;
194cdf0e10cSrcweir 	nInvalidDiff 		= 0;
195cdf0e10cSrcweir 	nHeight 			= 0;
196cdf0e10cSrcweir 	nFirstLineOffset 	= 0;
197cdf0e10cSrcweir 	nBulletX			= 0;
198cdf0e10cSrcweir }
199cdf0e10cSrcweir 
~ParaPortion()200cdf0e10cSrcweir ParaPortion::~ParaPortion()
201cdf0e10cSrcweir {
202cdf0e10cSrcweir 	DBG_DTOR( EE_ParaPortion, 0 );
203cdf0e10cSrcweir }
204cdf0e10cSrcweir 
MarkInvalid(sal_uInt16 nStart,short nDiff)205cdf0e10cSrcweir void ParaPortion::MarkInvalid( sal_uInt16 nStart, short nDiff )
206cdf0e10cSrcweir {
207cdf0e10cSrcweir 	if ( bInvalid == sal_False )
208cdf0e10cSrcweir 	{
209cdf0e10cSrcweir //		nInvalidPosEnd = nStart;	// ??? => CreateLines
210cdf0e10cSrcweir 		nInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff );
211cdf0e10cSrcweir 		nInvalidDiff = nDiff;
212cdf0e10cSrcweir 	}
213cdf0e10cSrcweir 	else
214cdf0e10cSrcweir 	{
215cdf0e10cSrcweir 		// Einfaches hintereinander tippen
216cdf0e10cSrcweir 		if ( ( nDiff > 0 ) && ( nInvalidDiff > 0 ) &&
217cdf0e10cSrcweir 			 ( ( nInvalidPosStart+nInvalidDiff ) == nStart ) )
218cdf0e10cSrcweir 		{
219cdf0e10cSrcweir 			nInvalidDiff = nInvalidDiff + nDiff;
220cdf0e10cSrcweir 		}
221cdf0e10cSrcweir 		// Einfaches hintereinander loeschen
222cdf0e10cSrcweir 		else if ( ( nDiff < 0 ) && ( nInvalidDiff < 0 ) && ( nInvalidPosStart == nStart ) )
223cdf0e10cSrcweir 		{
224cdf0e10cSrcweir 			nInvalidPosStart = nInvalidPosStart + nDiff;
225cdf0e10cSrcweir 			nInvalidDiff = nInvalidDiff + nDiff;
226cdf0e10cSrcweir 		}
227cdf0e10cSrcweir 		else
228cdf0e10cSrcweir 		{
229cdf0e10cSrcweir //			nInvalidPosEnd = pNode->Len();
230cdf0e10cSrcweir 			DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" );
231cdf0e10cSrcweir 			nInvalidPosStart = Min( nInvalidPosStart, (sal_uInt16) ( nDiff < 0 ? nStart+nDiff : nDiff ) );
232cdf0e10cSrcweir 			nInvalidDiff = 0;
233cdf0e10cSrcweir 			bSimple = sal_False;
234cdf0e10cSrcweir 		}
235cdf0e10cSrcweir 	}
236cdf0e10cSrcweir 	bInvalid = sal_True;
237cdf0e10cSrcweir 	aScriptInfos.clear();
238cdf0e10cSrcweir 	aWritingDirectionInfos.clear();
239cdf0e10cSrcweir }
240cdf0e10cSrcweir 
MarkSelectionInvalid(sal_uInt16 nStart,sal_uInt16)241cdf0e10cSrcweir void ParaPortion::MarkSelectionInvalid( sal_uInt16 nStart, sal_uInt16 /* nEnd */ )
242cdf0e10cSrcweir {
243cdf0e10cSrcweir 	if ( bInvalid == sal_False )
244cdf0e10cSrcweir 	{
245cdf0e10cSrcweir 		nInvalidPosStart = nStart;
246cdf0e10cSrcweir //		nInvalidPosEnd = nEnd;
247cdf0e10cSrcweir 	}
248cdf0e10cSrcweir 	else
249cdf0e10cSrcweir 	{
250cdf0e10cSrcweir 		nInvalidPosStart = Min( nInvalidPosStart, nStart );
251cdf0e10cSrcweir //		nInvalidPosEnd = pNode->Len();
252cdf0e10cSrcweir 	}
253cdf0e10cSrcweir 	nInvalidDiff = 0;
254cdf0e10cSrcweir 	bInvalid = sal_True;
255cdf0e10cSrcweir 	bSimple = sal_False;
256cdf0e10cSrcweir 	aScriptInfos.clear();
257cdf0e10cSrcweir 	aWritingDirectionInfos.clear();
258cdf0e10cSrcweir }
259cdf0e10cSrcweir 
GetLineNumber(sal_uInt16 nIndex)260cdf0e10cSrcweir sal_uInt16 ParaPortion::GetLineNumber( sal_uInt16 nIndex )
261cdf0e10cSrcweir {
262cdf0e10cSrcweir 	DBG_ASSERTWARNING( aLineList.Count(), "Leere ParaPortion in GetLine!" );
263cdf0e10cSrcweir 	DBG_ASSERT( bVisible, "Wozu GetLine() bei einem unsichtbaren Absatz?" );
264cdf0e10cSrcweir 
265cdf0e10cSrcweir 	for ( sal_uInt16 nLine = 0; nLine < aLineList.Count(); nLine++ )
266cdf0e10cSrcweir 	{
267cdf0e10cSrcweir 		if ( aLineList[nLine]->IsIn( nIndex ) )
268cdf0e10cSrcweir 			return nLine;
269cdf0e10cSrcweir 	}
270cdf0e10cSrcweir 
271cdf0e10cSrcweir 	// Dann sollte es am Ende der letzten Zeile sein!
272cdf0e10cSrcweir 	DBG_ASSERT( nIndex == aLineList[ aLineList.Count() - 1 ]->GetEnd(), "Index voll daneben!" );
273cdf0e10cSrcweir 	return (aLineList.Count()-1);
274cdf0e10cSrcweir }
275cdf0e10cSrcweir 
SetVisible(sal_Bool bMakeVisible)276cdf0e10cSrcweir void ParaPortion::SetVisible( sal_Bool bMakeVisible )
277cdf0e10cSrcweir {
278cdf0e10cSrcweir 	bVisible = bMakeVisible;
279cdf0e10cSrcweir }
280cdf0e10cSrcweir 
CorrectValuesBehindLastFormattedLine(sal_uInt16 nLastFormattedLine)281cdf0e10cSrcweir void ParaPortion::CorrectValuesBehindLastFormattedLine( sal_uInt16 nLastFormattedLine )
282cdf0e10cSrcweir {
283cdf0e10cSrcweir 	sal_uInt16 nLines = aLineList.Count();
284cdf0e10cSrcweir 	DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Leere Portion?" );
285cdf0e10cSrcweir 	if ( nLastFormattedLine < ( nLines - 1 ) )
286cdf0e10cSrcweir 	{
287cdf0e10cSrcweir 		const EditLine* pLastFormatted = aLineList[ nLastFormattedLine ];
288cdf0e10cSrcweir 		const EditLine* pUnformatted = aLineList[ nLastFormattedLine+1 ];
289cdf0e10cSrcweir 		short nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion();
290cdf0e10cSrcweir 		short nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd();
291cdf0e10cSrcweir 		nTextDiff++;	// LastFormatted->GetEnd() war incl. => 1 zuviel abgezogen!
292cdf0e10cSrcweir 
293cdf0e10cSrcweir 		// Die erste unformatierte muss genau eine Portion hinter der letzten der
294cdf0e10cSrcweir 		// formatierten beginnen:
295cdf0e10cSrcweir 		// Wenn in der geaenderten Zeile eine Portion gesplittet wurde,
296cdf0e10cSrcweir 		// kann nLastEnd > nNextStart sein!
297cdf0e10cSrcweir 		int nPDiff = -( nPortionDiff-1 );
298cdf0e10cSrcweir 		int nTDiff = -( nTextDiff-1 );
299cdf0e10cSrcweir 		if ( nPDiff || nTDiff )
300cdf0e10cSrcweir 		{
301cdf0e10cSrcweir 			for ( sal_uInt16 nL = nLastFormattedLine+1; nL < nLines; nL++ )
302cdf0e10cSrcweir 			{
303cdf0e10cSrcweir 				EditLine* pLine = aLineList[ nL ];
304cdf0e10cSrcweir 
305cdf0e10cSrcweir 				pLine->GetStartPortion() = sal::static_int_cast< sal_uInt16 >(
306cdf0e10cSrcweir                     pLine->GetStartPortion() + nPDiff);
307cdf0e10cSrcweir 				pLine->GetEndPortion() = sal::static_int_cast< sal_uInt16 >(
308cdf0e10cSrcweir                     pLine->GetEndPortion() + nPDiff);
309cdf0e10cSrcweir 
310cdf0e10cSrcweir 				pLine->GetStart() = sal::static_int_cast< sal_uInt16 >(
311cdf0e10cSrcweir                     pLine->GetStart() + nTDiff);
312cdf0e10cSrcweir 				pLine->GetEnd() = sal::static_int_cast< sal_uInt16 >(
313cdf0e10cSrcweir                     pLine->GetEnd() + nTDiff);
314cdf0e10cSrcweir 
315cdf0e10cSrcweir 				pLine->SetValid();
316cdf0e10cSrcweir 			}
317cdf0e10cSrcweir 		}
318cdf0e10cSrcweir 	}
319cdf0e10cSrcweir 	DBG_ASSERT( aLineList[ aLineList.Count()-1 ]->GetEnd() == pNode->Len(), "CorrectLines: Ende stimmt nicht!" );
320cdf0e10cSrcweir }
321cdf0e10cSrcweir 
322cdf0e10cSrcweir // Shared reverse lookup acceleration pieces ...
323cdf0e10cSrcweir 
FastGetPos(const VoidPtr * pPtrArray,sal_uInt16 nPtrArrayLen,VoidPtr pPtr,sal_uInt16 & rLastPos)324cdf0e10cSrcweir static sal_uInt16 FastGetPos( const VoidPtr *pPtrArray, sal_uInt16 nPtrArrayLen,
325cdf0e10cSrcweir 						  VoidPtr pPtr, sal_uInt16 &rLastPos )
326cdf0e10cSrcweir {
327cdf0e10cSrcweir   // Through certain filter code-paths we do a lot of appends, which in
328cdf0e10cSrcweir   // turn call GetPos - creating some N^2 nightmares. If we have a
329cdf0e10cSrcweir   // non-trivially large list, do a few checks from the end first.
330cdf0e10cSrcweir   if( rLastPos > 16 )
331cdf0e10cSrcweir     {
332cdf0e10cSrcweir       sal_uInt16 nEnd;
333cdf0e10cSrcweir       if (rLastPos > nPtrArrayLen - 2)
334cdf0e10cSrcweir 		nEnd = nPtrArrayLen;
335cdf0e10cSrcweir       else
336cdf0e10cSrcweir 		nEnd = rLastPos + 2;
337cdf0e10cSrcweir 
338cdf0e10cSrcweir       for( sal_uInt16 nIdx = rLastPos - 2; nIdx < nEnd; nIdx++ )
339cdf0e10cSrcweir 		{
340cdf0e10cSrcweir 		  if( pPtrArray[ nIdx ] == pPtr )
341cdf0e10cSrcweir 			{
342cdf0e10cSrcweir 			  rLastPos = nIdx;
343cdf0e10cSrcweir 			  return nIdx;
344cdf0e10cSrcweir 			}
345cdf0e10cSrcweir 		}
346cdf0e10cSrcweir     }
347cdf0e10cSrcweir   // The world's lamest linear search from svarray ...
348cdf0e10cSrcweir   for( sal_uInt16 nIdx = 0; nIdx < nPtrArrayLen; nIdx++ )
349cdf0e10cSrcweir 	if (pPtrArray[ nIdx ] == pPtr )
350cdf0e10cSrcweir 	  return rLastPos = nIdx;
351cdf0e10cSrcweir   return USHRT_MAX;
352cdf0e10cSrcweir }
353cdf0e10cSrcweir 
354cdf0e10cSrcweir // -------------------------------------------------------------------------
355cdf0e10cSrcweir // class ParaPortionList
356cdf0e10cSrcweir // -------------------------------------------------------------------------
ParaPortionList()357cdf0e10cSrcweir ParaPortionList::ParaPortionList() : nLastCache( 0 )
358cdf0e10cSrcweir {
359cdf0e10cSrcweir }
360cdf0e10cSrcweir 
~ParaPortionList()361cdf0e10cSrcweir ParaPortionList::~ParaPortionList()
362cdf0e10cSrcweir {
363cdf0e10cSrcweir 	Reset();
364cdf0e10cSrcweir }
365cdf0e10cSrcweir 
GetPos(const ParaPortionPtr & rPtr) const366cdf0e10cSrcweir sal_uInt16 ParaPortionList::GetPos( const ParaPortionPtr &rPtr ) const
367cdf0e10cSrcweir {
368cdf0e10cSrcweir 	return FastGetPos( reinterpret_cast<const VoidPtr *>( GetData() ),
369cdf0e10cSrcweir 					   Count(), static_cast<VoidPtr>( rPtr ),
370cdf0e10cSrcweir 					   ((ParaPortionList *)this)->nLastCache );
371cdf0e10cSrcweir }
372cdf0e10cSrcweir 
GetPos(const ContentNodePtr & rPtr) const373cdf0e10cSrcweir sal_uInt16 ContentList::GetPos( const ContentNodePtr &rPtr ) const
374cdf0e10cSrcweir {
375cdf0e10cSrcweir     return FastGetPos( reinterpret_cast<const VoidPtr *>( GetData() ),
376cdf0e10cSrcweir 					   Count(), static_cast<VoidPtr>( rPtr ),
377cdf0e10cSrcweir 					   ((ContentList *)this)->nLastCache );
378cdf0e10cSrcweir }
379cdf0e10cSrcweir 
Reset()380cdf0e10cSrcweir void ParaPortionList::Reset()
381cdf0e10cSrcweir {
382cdf0e10cSrcweir 	for ( sal_uInt16 nPortion = 0; nPortion < Count(); nPortion++ )
383cdf0e10cSrcweir 		delete GetObject( nPortion );
384cdf0e10cSrcweir 	Remove( 0, Count() );
385cdf0e10cSrcweir }
386cdf0e10cSrcweir 
GetYOffset(ParaPortion * pPPortion)387cdf0e10cSrcweir long ParaPortionList::GetYOffset( ParaPortion* pPPortion )
388cdf0e10cSrcweir {
389cdf0e10cSrcweir 	long nHeight = 0;
390cdf0e10cSrcweir 	for ( sal_uInt16 nPortion = 0; nPortion < Count(); nPortion++ )
391cdf0e10cSrcweir 	{
392cdf0e10cSrcweir 		ParaPortion* pTmpPortion = GetObject(nPortion);
393cdf0e10cSrcweir 		if ( pTmpPortion == pPPortion )
394cdf0e10cSrcweir 			return nHeight;
395cdf0e10cSrcweir 		nHeight += pTmpPortion->GetHeight();
396cdf0e10cSrcweir 	}
397cdf0e10cSrcweir 	DBG_ERROR( "GetYOffset: Portion nicht gefunden" );
398cdf0e10cSrcweir 	return nHeight;
399cdf0e10cSrcweir }
400cdf0e10cSrcweir 
FindParagraph(long nYOffset)401cdf0e10cSrcweir sal_uInt16 ParaPortionList::FindParagraph( long nYOffset )
402cdf0e10cSrcweir {
403cdf0e10cSrcweir 	long nY = 0;
404cdf0e10cSrcweir 	for ( sal_uInt16 nPortion = 0; nPortion < Count(); nPortion++ )
405cdf0e10cSrcweir 	{
406cdf0e10cSrcweir 		nY += GetObject(nPortion)->GetHeight(); // sollte auch bei !bVisible richtig sein!
407cdf0e10cSrcweir 		if ( nY > nYOffset )
408cdf0e10cSrcweir 			return nPortion;
409cdf0e10cSrcweir 	}
410cdf0e10cSrcweir 	return 0xFFFF;	// solte mal ueber EE_PARA_NOT_FOUND erreicht werden!
411cdf0e10cSrcweir }
412cdf0e10cSrcweir 
DbgCheck(EditDoc & rDoc)413cdf0e10cSrcweir void ParaPortionList::DbgCheck( EditDoc&
414cdf0e10cSrcweir #ifdef DBG_UTIL
415cdf0e10cSrcweir 							   rDoc
416cdf0e10cSrcweir #endif
417cdf0e10cSrcweir 								)
418cdf0e10cSrcweir {
419cdf0e10cSrcweir #ifdef DBG_UTIL
420cdf0e10cSrcweir 	DBG_ASSERT( Count() == rDoc.Count(), "ParaPortionList::DbgCheck() - Count() ungleich!" );
421cdf0e10cSrcweir 	for ( sal_uInt16 i = 0; i < Count(); i++ )
422cdf0e10cSrcweir 	{
423cdf0e10cSrcweir 		DBG_ASSERT( SaveGetObject(i), "ParaPortionList::DbgCheck() - Null-Pointer in Liste!" );
424cdf0e10cSrcweir 		DBG_ASSERT( GetObject(i)->GetNode(), "ParaPortionList::DbgCheck() - Null-Pointer in Liste(2)!" );
425cdf0e10cSrcweir 		DBG_ASSERT( GetObject(i)->GetNode() == rDoc.GetObject(i), "ParaPortionList::DbgCheck() - Eintraege kreuzen sich!" );
426cdf0e10cSrcweir 	}
427cdf0e10cSrcweir #endif
428cdf0e10cSrcweir }
429cdf0e10cSrcweir 
430cdf0e10cSrcweir 
ContentAttribsInfo(const SfxItemSet & rParaAttribs)431cdf0e10cSrcweir ContentAttribsInfo::ContentAttribsInfo( const SfxItemSet& rParaAttribs ) :
432cdf0e10cSrcweir 		aPrevParaAttribs( rParaAttribs)
433cdf0e10cSrcweir {
434cdf0e10cSrcweir }
435cdf0e10cSrcweir 
436cdf0e10cSrcweir 
ConvertItem(SfxPoolItem & rPoolItem,MapUnit eSourceUnit,MapUnit eDestUnit)437cdf0e10cSrcweir void ConvertItem( SfxPoolItem& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit )
438cdf0e10cSrcweir {
439cdf0e10cSrcweir 	DBG_ASSERT( eSourceUnit != eDestUnit, "ConvertItem - Why?!" );
440cdf0e10cSrcweir 
441cdf0e10cSrcweir 	switch ( rPoolItem.Which() )
442cdf0e10cSrcweir 	{
443cdf0e10cSrcweir 		case EE_PARA_LRSPACE:
444cdf0e10cSrcweir 		{
445cdf0e10cSrcweir 			DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLRSpaceItem ) ), "ConvertItem: Ungueltiges Item!" );
446cdf0e10cSrcweir 			SvxLRSpaceItem& rItem = (SvxLRSpaceItem&)rPoolItem;
447cdf0e10cSrcweir 			rItem.SetTxtFirstLineOfst( sal::static_int_cast< short >( OutputDevice::LogicToLogic( rItem.GetTxtFirstLineOfst(), eSourceUnit, eDestUnit ) ) );
448cdf0e10cSrcweir 			rItem.SetTxtLeft( OutputDevice::LogicToLogic( rItem.GetTxtLeft(), eSourceUnit, eDestUnit ) );
449cdf0e10cSrcweir //			rItem.SetLeft( OutputDevice::LogicToLogic( rItem.GetLeft(), eSourceUnit, eDestUnit ) ); // #96298# SetLeft manipulates nTxtLeft!
450cdf0e10cSrcweir 			rItem.SetRight( OutputDevice::LogicToLogic( rItem.GetRight(), eSourceUnit, eDestUnit ) );
451cdf0e10cSrcweir 		}
452cdf0e10cSrcweir 		break;
453cdf0e10cSrcweir 		case EE_PARA_ULSPACE:
454cdf0e10cSrcweir 		{
455cdf0e10cSrcweir 			DBG_ASSERT( rPoolItem.IsA( TYPE( SvxULSpaceItem ) ), "ConvertItem: Ungueltiges Item!" );
456cdf0e10cSrcweir 			SvxULSpaceItem& rItem = (SvxULSpaceItem&)rPoolItem;
457cdf0e10cSrcweir 			rItem.SetUpper( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetUpper(), eSourceUnit, eDestUnit ) ) );
458cdf0e10cSrcweir 			rItem.SetLower( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetLower(), eSourceUnit, eDestUnit ) ) );
459cdf0e10cSrcweir 		}
460cdf0e10cSrcweir 		break;
461cdf0e10cSrcweir 		case EE_PARA_SBL:
462cdf0e10cSrcweir 		{
463cdf0e10cSrcweir 			DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLineSpacingItem ) ), "ConvertItem: Ungueltiges Item!" );
464cdf0e10cSrcweir 			SvxLineSpacingItem& rItem = (SvxLineSpacingItem&)rPoolItem;
465cdf0e10cSrcweir             // #96298# SetLineHeight changes also eLineSpace!
466cdf0e10cSrcweir 		    if ( rItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN )
467cdf0e10cSrcweir 			    rItem.SetLineHeight( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetLineHeight(), eSourceUnit, eDestUnit ) ) );
468cdf0e10cSrcweir 		}
469cdf0e10cSrcweir 		break;
470cdf0e10cSrcweir 		case EE_PARA_TABS:
471cdf0e10cSrcweir 		{
472cdf0e10cSrcweir 			DBG_ASSERT( rPoolItem.IsA( TYPE( SvxTabStopItem ) ), "ConvertItem: Ungueltiges Item!" );
473cdf0e10cSrcweir 			SvxTabStopItem& rItem = (SvxTabStopItem&)rPoolItem;
474cdf0e10cSrcweir 			SvxTabStopItem aNewItem( EE_PARA_TABS );
475cdf0e10cSrcweir 			for ( sal_uInt16 i = 0; i < rItem.Count(); i++ )
476cdf0e10cSrcweir 			{
477cdf0e10cSrcweir 				const SvxTabStop& rTab = rItem[i];
478cdf0e10cSrcweir 				SvxTabStop aNewStop( OutputDevice::LogicToLogic( rTab.GetTabPos(), eSourceUnit, eDestUnit ), rTab.GetAdjustment(), rTab.GetDecimal(), rTab.GetFill() );
479cdf0e10cSrcweir 				aNewItem.Insert( aNewStop );
480cdf0e10cSrcweir 			}
481cdf0e10cSrcweir 			rItem = aNewItem;
482cdf0e10cSrcweir 		}
483cdf0e10cSrcweir 		break;
484cdf0e10cSrcweir 		case EE_CHAR_FONTHEIGHT:
485cdf0e10cSrcweir 		case EE_CHAR_FONTHEIGHT_CJK:
486cdf0e10cSrcweir 		case EE_CHAR_FONTHEIGHT_CTL:
487cdf0e10cSrcweir 		{
488cdf0e10cSrcweir 			DBG_ASSERT( rPoolItem.IsA( TYPE( SvxFontHeightItem ) ), "ConvertItem: Ungueltiges Item!" );
489cdf0e10cSrcweir 			SvxFontHeightItem& rItem = (SvxFontHeightItem&)rPoolItem;
490cdf0e10cSrcweir 			rItem.SetHeight( OutputDevice::LogicToLogic( rItem.GetHeight(), eSourceUnit, eDestUnit ) );
491cdf0e10cSrcweir 		}
492cdf0e10cSrcweir 		break;
493cdf0e10cSrcweir 	}
494cdf0e10cSrcweir }
495cdf0e10cSrcweir 
ConvertAndPutItems(SfxItemSet & rDest,const SfxItemSet & rSource,const MapUnit * pSourceUnit,const MapUnit * pDestUnit)496cdf0e10cSrcweir void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit, const MapUnit* pDestUnit )
497cdf0e10cSrcweir {
498cdf0e10cSrcweir 	const SfxItemPool* pSourcePool = rSource.GetPool();
499cdf0e10cSrcweir 	const SfxItemPool* pDestPool = rDest.GetPool();
500cdf0e10cSrcweir 
501cdf0e10cSrcweir 	for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
502cdf0e10cSrcweir 	{
503cdf0e10cSrcweir 		// Wenn moeglich ueber SlotID gehen...
504cdf0e10cSrcweir 
505cdf0e10cSrcweir 		sal_uInt16 nSourceWhich = nWhich;
506cdf0e10cSrcweir 		sal_uInt16 nSlot = pDestPool->GetTrueSlotId( nWhich );
507cdf0e10cSrcweir 		if ( nSlot )
508cdf0e10cSrcweir 		{
509cdf0e10cSrcweir 			sal_uInt16 nW = pSourcePool->GetTrueWhich( nSlot );
510cdf0e10cSrcweir 			if ( nW )
511cdf0e10cSrcweir 				nSourceWhich = nW;
512cdf0e10cSrcweir 		}
513cdf0e10cSrcweir 
514cdf0e10cSrcweir 		if ( rSource.GetItemState( nSourceWhich, sal_False ) == SFX_ITEM_ON )
515cdf0e10cSrcweir 		{
516cdf0e10cSrcweir 			MapUnit eSourceUnit = pSourceUnit ? *pSourceUnit : (MapUnit)pSourcePool->GetMetric( nSourceWhich );
517cdf0e10cSrcweir 			MapUnit eDestUnit = pDestUnit ? *pDestUnit : (MapUnit)pDestPool->GetMetric( nWhich );
518cdf0e10cSrcweir 			if ( eSourceUnit != eDestUnit )
519cdf0e10cSrcweir 			{
520cdf0e10cSrcweir 				SfxPoolItem* pItem = rSource.Get( nSourceWhich ).Clone();
521cdf0e10cSrcweir //				pItem->SetWhich( nWhich );
522cdf0e10cSrcweir 				ConvertItem( *pItem, eSourceUnit, eDestUnit );
523cdf0e10cSrcweir 				rDest.Put( *pItem, nWhich );
524cdf0e10cSrcweir 				delete pItem;
525cdf0e10cSrcweir 			}
526cdf0e10cSrcweir 			else
527cdf0e10cSrcweir 			{
528cdf0e10cSrcweir 				rDest.Put( rSource.Get( nSourceWhich ), nWhich );
529cdf0e10cSrcweir 			}
530cdf0e10cSrcweir 		}
531cdf0e10cSrcweir 		else
532cdf0e10cSrcweir 		{
533cdf0e10cSrcweir 			// MT 3.3.99: Waere so eigentlich richtig, aber schon seit Jahren nicht so...
534cdf0e10cSrcweir //			rDest.ClearItem( nWhich );
535cdf0e10cSrcweir 		}
536cdf0e10cSrcweir 	}
537cdf0e10cSrcweir }
538cdf0e10cSrcweir 
539