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