xref: /trunk/main/sc/source/core/data/drwlayer.cxx (revision 4d7c9de0)
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_sc.hxx"
26 #include <com/sun/star/uno/Reference.hxx>
27 #include <com/sun/star/chart/XChartDocument.hpp>
28 #include <com/sun/star/embed/XEmbeddedObject.hpp>
29 #include <com/sun/star/embed/XVisualObject.hpp>
30 #include <com/sun/star/embed/XClassifiedObject.hpp>
31 #include <com/sun/star/embed/XComponentSupplier.hpp>
32 #include <com/sun/star/embed/EmbedStates.hpp>
33 #include <com/sun/star/embed/ElementModes.hpp>
34 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
35 #include <com/sun/star/datatransfer/XTransferable.hpp>
36 
37 // INCLUDE ---------------------------------------------------------------
38 
39 #include "scitems.hxx"
40 #include <editeng/eeitem.hxx>
41 #include <editeng/frmdiritem.hxx>
42 #include <sot/exchange.hxx>
43 #include <svx/objfac3d.hxx>
44 #include <svx/xtable.hxx>
45 #include <svx/svdoutl.hxx>
46 #include <svx/svditer.hxx>
47 #include <svx/svdocapt.hxx>
48 #include <svx/svdocirc.hxx>
49 #include <svx/svdoedge.hxx>
50 #include <svx/svdograf.hxx>
51 #include <svx/svdoole2.hxx>
52 #include <svx/svdundo.hxx>
53 #include <editeng/unolingu.hxx>
54 #include <svx/drawitem.hxx>
55 #include <editeng/fhgtitem.hxx>
56 #include <editeng/scriptspaceitem.hxx>
57 #include <svx/shapepropertynotifier.hxx>
58 #include <sfx2/viewsh.hxx>
59 #include <sfx2/docfile.hxx>
60 #include <sot/storage.hxx>
61 #include <unotools/pathoptions.hxx>
62 #include <svl/itempool.hxx>
63 #include <vcl/virdev.hxx>
64 #include <vcl/svapp.hxx>
65 #include <unotools/ucbstreamhelper.hxx>
66 
67 #include "drwlayer.hxx"
68 #include "drawpage.hxx"
69 #include "global.hxx"
70 #include "document.hxx"
71 #include "rechead.hxx"
72 #include "userdat.hxx"
73 #include "markdata.hxx"
74 #include "globstr.hrc"
75 #include "scmod.hxx"
76 #include "chartarr.hxx"
77 #include "postit.hxx"
78 #include "attrib.hxx"
79 #include "charthelper.hxx"
80 
81 #define DET_ARROW_OFFSET	1000
82 
83 //	Abstand zur naechsten Zelle beim Loeschen (bShrink), damit der Anker
84 //	immer an der richtigen Zelle angezeigt wird
85 //#define SHRINK_DIST		3
86 //	und noch etwas mehr, damit das Objekt auch sichtbar in der Zelle liegt
87 #define SHRINK_DIST		25
88 
89 #define SHRINK_DIST_TWIPS	15
90 
91 using namespace ::com::sun::star;
92 
93 // STATIC DATA -----------------------------------------------------------
94 
95 TYPEINIT1(ScTabDeletedHint, SfxHint);
96 TYPEINIT1(ScTabSizeChangedHint, SfxHint);
97 
98 static ScDrawObjFactory* pFac = NULL;
99 static E3dObjFactory* pF3d = NULL;
100 static sal_uInt16 nInst = 0;
101 
102 SfxObjectShell* ScDrawLayer::pGlobalDrawPersist = NULL;
103 //REMOVE	SvPersist* ScDrawLayer::pGlobalDrawPersist = NULL;
104 
105 sal_Bool bDrawIsInUndo = sal_False;			//! Member
106 
107 // -----------------------------------------------------------------------
108 
109 ScUndoObjData::ScUndoObjData( SdrObject* pObjP, const ScAddress& rOS, const ScAddress& rOE,
110 											   const ScAddress& rNS, const ScAddress& rNE ) :
111     SdrUndoObj( *pObjP ),
112 	aOldStt( rOS ),
113 	aOldEnd( rOE ),
114 	aNewStt( rNS ),
115 	aNewEnd( rNE )
116 {
117 }
118 
119 __EXPORT ScUndoObjData::~ScUndoObjData()
120 {
121 }
122 
123 void ScUndoObjData::Undo()
124 {
125 	ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
126 	DBG_ASSERT(pData,"ScUndoObjData: Daten nicht da");
127 	if (pData)
128 	{
129 		pData->maStart = aOldStt;
130 		pData->maEnd = aOldEnd;
131 	}
132 }
133 
134 void __EXPORT ScUndoObjData::Redo()
135 {
136 	ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
137 	DBG_ASSERT(pData,"ScUndoObjData: Daten nicht da");
138 	if (pData)
139 	{
140 		pData->maStart = aNewStt;
141 		pData->maEnd = aNewEnd;
142 	}
143 }
144 
145 // -----------------------------------------------------------------------
146 
147 ScTabDeletedHint::ScTabDeletedHint( SCTAB nTabNo ) :
148 	nTab( nTabNo )
149 {
150 }
151 
152 __EXPORT ScTabDeletedHint::~ScTabDeletedHint()
153 {
154 }
155 
156 ScTabSizeChangedHint::ScTabSizeChangedHint( SCTAB nTabNo ) :
157 	nTab( nTabNo )
158 {
159 }
160 
161 __EXPORT ScTabSizeChangedHint::~ScTabSizeChangedHint()
162 {
163 }
164 
165 // -----------------------------------------------------------------------
166 
167 #define MAXMM	10000000
168 
169 inline void TwipsToMM( long& nVal )
170 {
171 	nVal = (long) ( nVal * HMM_PER_TWIPS );
172 }
173 
174 inline void ReverseTwipsToMM( long& nVal )
175 {
176 	//	reverse the effect of TwipsToMM - round up here (add 1)
177 
178 	nVal = ((long) ( nVal / HMM_PER_TWIPS )) + 1;
179 }
180 
181 void lcl_TwipsToMM( Point& rPoint )
182 {
183 	TwipsToMM( rPoint.X() );
184 	TwipsToMM( rPoint.Y() );
185 }
186 
187 void lcl_ReverseTwipsToMM( Point& rPoint )
188 {
189 	ReverseTwipsToMM( rPoint.X() );
190 	ReverseTwipsToMM( rPoint.Y() );
191 }
192 
193 void lcl_ReverseTwipsToMM( Rectangle& rRect )
194 {
195 	ReverseTwipsToMM( rRect.Left() );
196 	ReverseTwipsToMM( rRect.Right() );
197 	ReverseTwipsToMM( rRect.Top() );
198 	ReverseTwipsToMM( rRect.Bottom() );
199 }
200 
201 // -----------------------------------------------------------------------
202 
203 
204 ScDrawLayer::ScDrawLayer( ScDocument* pDocument, const String& rName ) :
205 	FmFormModel( SvtPathOptions().GetPalettePath(),
206 				 NULL, 							// SfxItemPool* Pool
207 				 pGlobalDrawPersist ?
208 				 	pGlobalDrawPersist :
209 				 	( pDocument ? pDocument->GetDocumentShell() : NULL )),
210 	aName( rName ),
211 	pDoc( pDocument ),
212 	pUndoGroup( NULL ),
213 	bRecording( sal_False ),
214 	bAdjustEnabled( sal_True ),
215 	bHyphenatorSet( sal_False ),
216         mbUndoAllowed( sal_True )
217 {
218 	pGlobalDrawPersist = NULL;			// nur einmal benutzen
219 
220 	SfxObjectShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : NULL;
221 	if ( pObjSh )
222 	{
223 		SetObjectShell( pObjSh );
224 
225 		// set color table
226         const SvxColorTableItem* pColItem = static_cast< const SvxColorTableItem* >(pObjSh->GetItem( SID_COLOR_TABLE ));
227 		XColorListSharedPtr aXCol = pColItem ? pColItem->GetColorTable() : XColorList::GetStdColorList();
228 		SetColorTableAtSdrModel( aXCol );
229 	}
230 	else
231 		SetColorTableAtSdrModel( XColorList::GetStdColorList() );
232 
233 	SetSwapGraphics(sal_True);
234 //	SetSwapAsynchron(sal_True);		// an der View
235 
236 	SetScaleUnit(MAP_100TH_MM);
237 	SfxItemPool& rPool = GetItemPool();
238 	rPool.SetDefaultMetric(SFX_MAPUNIT_100TH_MM);
239 	SvxFrameDirectionItem aModeItem( FRMDIR_ENVIRONMENT, EE_PARA_WRITINGDIR );
240 	rPool.SetPoolDefaultItem( aModeItem );
241 
242 	// #i33700#
243 	// Set shadow distance defaults as PoolDefaultItems. Details see bug.
244 	rPool.SetPoolDefaultItem(SdrShadowXDistItem(300));
245 	rPool.SetPoolDefaultItem(SdrShadowYDistItem(300));
246 
247 	// #111216# default for script spacing depends on locale, see SdDrawDocument ctor in sd
248 	LanguageType eOfficeLanguage = Application::GetSettings().GetLanguage();
249 	if ( eOfficeLanguage == LANGUAGE_KOREAN || eOfficeLanguage == LANGUAGE_KOREAN_JOHAB ||
250 		 eOfficeLanguage == LANGUAGE_JAPANESE )
251 	{
252 		// secondary is edit engine pool
253 		rPool.GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( sal_False, EE_PARA_ASIANCJKSPACING ) );
254 	}
255 
256 	rPool.FreezeIdRanges();							// the pool is also used directly
257 
258 	SdrLayerAdmin& rAdmin = GetLayerAdmin();
259 	rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("vorne")),    SC_LAYER_FRONT);
260 	rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("hinten")),   SC_LAYER_BACK);
261 	rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("intern")),   SC_LAYER_INTERN);
262 	rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Controls")), SC_LAYER_CONTROLS);
263     rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("hidden")),   SC_LAYER_HIDDEN);
264 	// "Controls" is new - must also be created when loading
265 
266 	//	Link fuer URL-Fields setzen
267 	ScModule* pScMod = SC_MOD();
268 	Outliner& rOutliner = GetDrawOutliner();
269 	rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
270 
271 	Outliner& rHitOutliner = GetHitTestOutliner();
272 	rHitOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
273 
274     // #95129# SJ: set FontHeight pool defaults without changing static SdrEngineDefaults
275     SfxItemPool* pOutlinerPool = rOutliner.GetEditTextObjectPool();
276     if ( pOutlinerPool )
277  	    pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT ));           // 12Pt
278     SfxItemPool* pHitOutlinerPool = rHitOutliner.GetEditTextObjectPool();
279     if ( pHitOutlinerPool )
280  	    pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT ));    // 12Pt
281 
282     // initial undo mode as in Calc document
283     if( pDoc )
284         EnableUndo( pDoc->IsUndoEnabled() );
285 
286 	//	URL-Buttons haben keinen Handler mehr, machen alles selber
287 
288 	if( !nInst++ )
289 	{
290 		pFac = new ScDrawObjFactory;
291 		pF3d = new E3dObjFactory;
292 	}
293 }
294 
295 __EXPORT ScDrawLayer::~ScDrawLayer()
296 {
297 	Broadcast(SdrHint(HINT_MODELCLEARED));
298 
299 	// #116168#
300 	//Clear();
301 	ClearModel(sal_True);
302 
303 	delete pUndoGroup;
304 	if( !--nInst )
305 	{
306 		delete pFac, pFac = NULL;
307 		delete pF3d, pF3d = NULL;
308 	}
309 }
310 
311 void ScDrawLayer::UseHyphenator()
312 {
313 	if (!bHyphenatorSet)
314 	{
315 		com::sun::star::uno::Reference< com::sun::star::linguistic2::XHyphenator >
316 									xHyphenator = LinguMgr::GetHyphenator();
317 
318 		GetDrawOutliner().SetHyphenator( xHyphenator );
319 		GetHitTestOutliner().SetHyphenator( xHyphenator );
320 
321 		bHyphenatorSet = sal_True;
322 	}
323 }
324 
325 SdrPage* __EXPORT ScDrawLayer::AllocPage(FASTBOOL bMasterPage)
326 {
327 	//	don't create basic until it is needed
328 	StarBASIC* pBasic = NULL;
329     ScDrawPage* pPage = new ScDrawPage( *this, pBasic, sal::static_int_cast<sal_Bool>(bMasterPage) );
330 	return pPage;
331 }
332 
333 sal_Bool ScDrawLayer::HasObjects() const
334 {
335 	sal_Bool bFound = sal_False;
336 
337 	sal_uInt16 nCount = GetPageCount();
338 	for (sal_uInt16 i=0; i<nCount && !bFound; i++)
339 		if (GetPage(i)->GetObjCount())
340 			bFound = sal_True;
341 
342 	return bFound;
343 }
344 
345 void ScDrawLayer::UpdateBasic()
346 {
347 	//	don't create basic until it is needed
348 	//!	remove this method?
349 }
350 
351 SdrModel* __EXPORT ScDrawLayer::AllocModel() const
352 {
353 	//	#103849# Allocated model (for clipboard etc) must not have a pointer
354 	//	to the original model's document, pass NULL as document:
355 
356 	return new ScDrawLayer( NULL, aName );
357 }
358 
359 Window* __EXPORT ScDrawLayer::GetCurDocViewWin()
360 {
361 	DBG_ASSERT( pDoc, "ScDrawLayer::GetCurDocViewWin without document" );
362 	if ( !pDoc )
363 		return NULL;
364 
365 	SfxViewShell* pViewSh = SfxViewShell::Current();
366 	SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
367 
368 	if (pViewSh && pViewSh->GetObjectShell() == pObjSh)
369 		return pViewSh->GetWindow();
370 
371 	return NULL;
372 }
373 
374 sal_Bool ScDrawLayer::ScAddPage( SCTAB nTab )
375 {
376 	if (bDrawIsInUndo)
377         return sal_False;   // not inserted
378 
379 	ScDrawPage* pPage = (ScDrawPage*)AllocPage( sal_False );
380 	InsertPage(pPage, static_cast<sal_uInt16>(nTab));
381 	if (bRecording)
382 	        AddCalcUndo< SdrUndoNewPage >(*pPage);
383 
384     return sal_True;        // inserted
385 }
386 
387 void ScDrawLayer::ScRemovePage( SCTAB nTab )
388 {
389 	if (bDrawIsInUndo)
390 		return;
391 
392 	Broadcast( ScTabDeletedHint( nTab ) );
393 	if (bRecording)
394 	{
395 		SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
396         AddCalcUndo< SdrUndoDelPage >(*pPage);		// Undo-Action wird Owner der Page
397 		RemovePage( static_cast<sal_uInt16>(nTab) );							// nur austragen, nicht loeschen
398 	}
399 	else
400 		DeletePage( static_cast<sal_uInt16>(nTab) );							// einfach weg damit
401 }
402 
403 void ScDrawLayer::ScRenamePage( SCTAB nTab, const String& rNewName )
404 {
405 	ScDrawPage* pPage = (ScDrawPage*) GetPage(static_cast<sal_uInt16>(nTab));
406 	if (pPage)
407 		pPage->SetName(rNewName);
408 }
409 
410 void ScDrawLayer::ScMovePage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
411 {
412 	MovePage( nOldPos, nNewPos );
413 }
414 
415 void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos, sal_Bool bAlloc )
416 {
417 	//!	remove argument bAlloc (always sal_False)
418 
419 	if (bDrawIsInUndo)
420 		return;
421 
422 	SdrPage* pOldPage = GetPage(nOldPos);
423 	SdrPage* pNewPage = bAlloc ? AllocPage(sal_False) : GetPage(nNewPos);
424 
425 	// kopieren
426 
427 	if (pOldPage && pNewPage)
428 	{
429 		SdrObjListIter aIter( *pOldPage, IM_FLAT );
430 		SdrObject* pOldObject = aIter.Next();
431 		while (pOldObject)
432 		{
433             // #i112034# do not copy internal objects (detective) and note captions
434             if ( pOldObject->GetLayer() != SC_LAYER_INTERN && !IsNoteCaption( pOldObject ) )
435             {
436                 // #116235#
437                 SdrObject* pNewObject = pOldObject->Clone();
438                 //SdrObject* pNewObject = pOldObject->Clone( pNewPage, this );
439                 pNewObject->SetModel(this);
440                 pNewObject->SetPage(pNewPage);
441 
442                 pNewObject->NbcMove(Size(0,0));
443                 pNewPage->InsertObject( pNewObject );
444                 if (bRecording)
445 	                AddCalcUndo< SdrUndoInsertObj >( *pNewObject );
446             }
447 
448 			pOldObject = aIter.Next();
449 		}
450 	}
451 
452 	if (bAlloc)
453 		InsertPage(pNewPage, nNewPos);
454 }
455 
456 inline sal_Bool IsInBlock( const ScAddress& rPos, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2 )
457 {
458 	return rPos.Col() >= nCol1 && rPos.Col() <= nCol2 &&
459 		   rPos.Row() >= nRow1 && rPos.Row() <= nRow2;
460 }
461 
462 void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
463 								SCsCOL nDx,SCsROW nDy, bool bUpdateNoteCaptionPos )
464 {
465 	SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
466 	DBG_ASSERT(pPage,"Page nicht gefunden");
467 	if (!pPage)
468 		return;
469 
470 	sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
471 
472 	sal_uLong nCount = pPage->GetObjCount();
473 	for ( sal_uLong i = 0; i < nCount; i++ )
474 	{
475 		SdrObject* pObj = pPage->GetObj( i );
476 		ScDrawObjData* pData = GetObjDataTab( pObj, nTab );
477 		if( pData )
478 		{
479 			const ScAddress aOldStt = pData->maStart;
480 			const ScAddress aOldEnd = pData->maEnd;
481 			sal_Bool bChange = sal_False;
482 			if ( aOldStt.IsValid() && IsInBlock( aOldStt, nCol1,nRow1, nCol2,nRow2 ) )
483 			{
484                 pData->maStart.IncCol( nDx );
485 				pData->maStart.IncRow( nDy );
486 				bChange = sal_True;
487 			}
488 			if ( aOldEnd.IsValid() && IsInBlock( aOldEnd, nCol1,nRow1, nCol2,nRow2 ) )
489 			{
490 				pData->maEnd.IncCol( nDx );
491 				pData->maEnd.IncRow( nDy );
492 				bChange = sal_True;
493 			}
494 			if (bChange)
495 			{
496 				if ( pObj->ISA( SdrRectObj ) && pData->maStart.IsValid() && pData->maEnd.IsValid() )
497                     pData->maStart.PutInOrder( pData->maEnd );
498                 AddCalcUndo< ScUndoObjData >( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd );
499                 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
500 			}
501 		}
502 	}
503 }
504 
505 void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos )
506 {
507 	SdrPage* pPage = GetPage(nPageNo);
508 	if (pPage)
509 	{
510 		if ( rSize != pPage->GetSize() )
511 		{
512 			pPage->SetSize( rSize );
513 			Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) );	// SetWorkArea() an den Views
514 		}
515 
516 		// Detektivlinien umsetzen (an neue Hoehen/Breiten anpassen)
517 		//	auch wenn Groesse gleich geblieben ist
518 		//	(einzelne Zeilen/Spalten koennen geaendert sein)
519 
520 		sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
521 
522 		sal_uLong nCount = pPage->GetObjCount();
523 		for ( sal_uLong i = 0; i < nCount; i++ )
524 		{
525 			SdrObject* pObj = pPage->GetObj( i );
526 			ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
527 			if( pData )
528                 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
529 		}
530 	}
531 }
532 
533 void ScDrawLayer::RecalcPos( SdrObject* pObj, const ScDrawObjData& rData, bool bNegativePage, bool bUpdateNoteCaptionPos )
534 {
535 	DBG_ASSERT( pDoc, "ScDrawLayer::RecalcPos - missing document" );
536 	if( !pDoc )
537 		return;
538 
539 	if( rData.mbNote )
540 	{
541         DBG_ASSERT( rData.maStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
542         /*  #i109372# On insert/remove rows/columns/cells: Updating the caption
543             position must not be done, if the cell containing the note has not
544             been moved yet in the document. The calling code now passes an
545             additional boolean stating if the cells are already moved. */
546         if( bUpdateNoteCaptionPos )
547             /*  When inside an undo action, there may be pending note captions
548                 where cell note is already deleted (thus document cannot find
549                 the note object anymore). The caption will be deleted later
550                 with drawing undo. */
551             if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
552                 pNote->UpdateCaptionPos( rData.maStart );
553         return;
554 	}
555 
556     bool bValid1 = rData.maStart.IsValid();
557     SCCOL nCol1 = rData.maStart.Col();
558 	SCROW nRow1 = rData.maStart.Row();
559 	SCTAB nTab1 = rData.maStart.Tab();
560     bool bValid2 = rData.maEnd.IsValid();
561     SCCOL nCol2 = rData.maEnd.Col();
562 	SCROW nRow2 = rData.maEnd.Row();
563 	SCTAB nTab2 = rData.maEnd.Tab();
564 
565     // validation circle
566 	bool bCircle = pObj->ISA( SdrCircObj );
567     // detective arrow
568 	bool bArrow = pObj->IsPolyObj() && (pObj->GetPointCount() == 2);
569 
570 	if( bCircle )
571 	{
572 		Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
573 		TwipsToMM( aPos.X() );
574 		TwipsToMM( aPos.Y() );
575 
576 		//	Berechnung und Werte wie in detfunc.cxx
577 
578 		Size aSize( (long)(pDoc->GetColWidth( nCol1, nTab1 ) * HMM_PER_TWIPS),
579 					(long)(pDoc->GetRowHeight( nRow1, nTab1 ) * HMM_PER_TWIPS) );
580 		Rectangle aRect( aPos, aSize );
581 		aRect.Left()	-= 250;
582 		aRect.Right()	+= 250;
583 		aRect.Top()		-= 70;
584 		aRect.Bottom()	+= 70;
585 		if ( bNegativePage )
586 			MirrorRectRTL( aRect );
587 
588 		if ( pObj->GetLogicRect() != aRect )
589 		{
590 			if (bRecording)
591 		                AddCalcUndo<SdrUndoGeoObj>( *pObj );
592 			pObj->SetLogicRect(aRect);
593 		}
594 	}
595 	else if( bArrow )
596 	{
597 		//!	nicht mehrere Undos fuer ein Objekt erzeugen (hinteres kann dann weggelassen werden)
598 
599         SCCOL nLastCol;
600         SCROW nLastRow;
601 		if( bValid1 )
602 		{
603 			Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
604             if (!pDoc->ColHidden(nCol1, nTab1, nLastCol))
605 				aPos.X() += pDoc->GetColWidth( nCol1, nTab1 ) / 4;
606             if (!pDoc->RowHidden(nRow1, nTab1, nLastRow))
607 				aPos.Y() += pDoc->GetRowHeight( nRow1, nTab1 ) / 2;
608 			TwipsToMM( aPos.X() );
609 			TwipsToMM( aPos.Y() );
610 			Point aStartPos = aPos;
611 			if ( bNegativePage )
612 				aStartPos.X() = -aStartPos.X();		// don't modify aPos - used below
613 			if ( pObj->GetPoint( 0 ) != aStartPos )
614 			{
615 				if (bRecording)
616 		                    AddCalcUndo< SdrUndoGeoObj> ( *pObj );
617 				pObj->SetPoint( aStartPos, 0 );
618 			}
619 
620 			if( !bValid2 )
621 			{
622 				Point aEndPos( aPos.X() + DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
623 				if (aEndPos.Y() < 0)
624 					aEndPos.Y() += (2 * DET_ARROW_OFFSET);
625 				if ( bNegativePage )
626 					aEndPos.X() = -aEndPos.X();
627 				if ( pObj->GetPoint( 1 ) != aEndPos )
628 				{
629 					if (bRecording)
630 		                        AddCalcUndo< SdrUndoGeoObj >( *pObj );
631 					pObj->SetPoint( aEndPos, 1 );
632 				}
633 			}
634 		}
635 		if( bValid2 )
636 		{
637 			Point aPos( pDoc->GetColOffset( nCol2, nTab2 ), pDoc->GetRowOffset( nRow2, nTab2 ) );
638             if (!pDoc->ColHidden(nCol2, nTab2, nLastCol))
639 				aPos.X() += pDoc->GetColWidth( nCol2, nTab2 ) / 4;
640             if (!pDoc->RowHidden(nRow2, nTab2, nLastRow))
641 				aPos.Y() += pDoc->GetRowHeight( nRow2, nTab2 ) / 2;
642 			TwipsToMM( aPos.X() );
643 			TwipsToMM( aPos.Y() );
644 			Point aEndPos = aPos;
645 			if ( bNegativePage )
646 				aEndPos.X() = -aEndPos.X();			// don't modify aPos - used below
647 			if ( pObj->GetPoint( 1 ) != aEndPos )
648 			{
649 				if (bRecording)
650 		                    AddCalcUndo< SdrUndoGeoObj> ( *pObj  );
651 				pObj->SetPoint( aEndPos, 1 );
652 			}
653 
654 			if( !bValid1 )
655 			{
656 				Point aStartPos( aPos.X() - DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
657 				if (aStartPos.X() < 0)
658 					aStartPos.X() += (2 * DET_ARROW_OFFSET);
659 				if (aStartPos.Y() < 0)
660 					aStartPos.Y() += (2 * DET_ARROW_OFFSET);
661 				if ( bNegativePage )
662 					aStartPos.X() = -aStartPos.X();
663 				if ( pObj->GetPoint( 0 ) != aStartPos )
664 				{
665 					if (bRecording)
666 			                        AddCalcUndo< SdrUndoGeoObj >( *pObj );
667 					pObj->SetPoint( aStartPos, 0 );
668 				}
669 			}
670 		}
671 	}
672 	else								// Referenz-Rahmen
673 	{
674 		DBG_ASSERT( bValid1, "ScDrawLayer::RecalcPos - invalid start position" );
675 		Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
676 		TwipsToMM( aPos.X() );
677 		TwipsToMM( aPos.Y() );
678 
679 		if( bValid2 )
680 		{
681 			Point aEnd( pDoc->GetColOffset( nCol2 + 1, nTab2 ), pDoc->GetRowOffset( nRow2 + 1, nTab2 ) );
682 			TwipsToMM( aEnd.X() );
683 			TwipsToMM( aEnd.Y() );
684 
685 			Rectangle aNew( aPos, aEnd );
686 			if ( bNegativePage )
687 				MirrorRectRTL( aNew );
688 			if ( pObj->GetLogicRect() != aNew )
689 			{
690 				if (bRecording)
691 		                    AddCalcUndo< SdrUndoGeoObj >( *pObj );
692 				pObj->SetLogicRect(aNew);
693 			}
694 		}
695 		else
696 		{
697 			if ( bNegativePage )
698 				aPos.X() = -aPos.X();
699 			if ( pObj->GetRelativePos() != aPos )
700 			{
701 				if (bRecording)
702 		                    AddCalcUndo< SdrUndoGeoObj >( *pObj );
703 				pObj->SetRelativePos( aPos );
704 			}
705 		}
706 	}
707 }
708 
709 sal_Bool ScDrawLayer::GetPrintArea( ScRange& rRange, sal_Bool bSetHor, sal_Bool bSetVer ) const
710 {
711 	DBG_ASSERT( pDoc, "ScDrawLayer::GetPrintArea without document" );
712 	if ( !pDoc )
713 		return sal_False;
714 
715 	SCTAB nTab = rRange.aStart.Tab();
716 	DBG_ASSERT( rRange.aEnd.Tab() == nTab, "GetPrintArea: Tab unterschiedlich" );
717 
718 	sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
719 
720 	sal_Bool bAny = sal_False;
721 	long nEndX = 0;
722 	long nEndY = 0;
723 	long nStartX = LONG_MAX;
724 	long nStartY = LONG_MAX;
725 
726 	// Grenzen ausrechnen
727 
728 	if (!bSetHor)
729 	{
730 		nStartX = 0;
731 		SCCOL nStartCol = rRange.aStart.Col();
732 	        SCCOL i;
733 		for (i=0; i<nStartCol; i++)
734 			nStartX +=pDoc->GetColWidth(i,nTab);
735 		nEndX = nStartX;
736 		SCCOL nEndCol = rRange.aEnd.Col();
737 		for (i=nStartCol; i<=nEndCol; i++)
738 			nEndX += pDoc->GetColWidth(i,nTab);
739 		nStartX = (long)(nStartX * HMM_PER_TWIPS);
740 		nEndX   = (long)(nEndX   * HMM_PER_TWIPS);
741 	}
742 	if (!bSetVer)
743 	{
744 		nStartY = pDoc->GetRowHeight( 0, rRange.aStart.Row()-1, nTab);
745         nEndY = nStartY + pDoc->GetRowHeight( rRange.aStart.Row(),
746                 rRange.aEnd.Row(), nTab);
747 		nStartY = (long)(nStartY * HMM_PER_TWIPS);
748 		nEndY   = (long)(nEndY   * HMM_PER_TWIPS);
749 	}
750 
751 	if ( bNegativePage )
752 	{
753 		nStartX = -nStartX;		// positions are negative, swap start/end so the same comparisons work
754 		nEndX   = -nEndX;
755 		::std::swap( nStartX, nEndX );
756 	}
757 
758 	const SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
759 	DBG_ASSERT(pPage,"Page nicht gefunden");
760 	if (pPage)
761 	{
762 		SdrObjListIter aIter( *pPage, IM_FLAT );
763 		SdrObject* pObject = aIter.Next();
764 		while (pObject)
765 		{
766 							//! Flags (ausgeblendet?) testen
767 
768 			Rectangle aObjRect = pObject->GetCurrentBoundRect();
769 			sal_Bool bFit = sal_True;
770 			if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
771 				bFit = sal_False;
772 			if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
773 				bFit = sal_False;
774             // #i104716# don't include hidden note objects
775             if ( bFit && pObject->GetLayer() != SC_LAYER_HIDDEN )
776 			{
777 				if (bSetHor)
778 				{
779 					if (aObjRect.Left() < nStartX) nStartX = aObjRect.Left();
780 					if (aObjRect.Right()  > nEndX) nEndX = aObjRect.Right();
781 				}
782 				if (bSetVer)
783 				{
784 					if (aObjRect.Top()  < nStartY) nStartY = aObjRect.Top();
785 					if (aObjRect.Bottom() > nEndY) nEndY = aObjRect.Bottom();
786 				}
787 				bAny = sal_True;
788 			}
789 
790 			pObject = aIter.Next();
791 		}
792 	}
793 
794 	if ( bNegativePage )
795 	{
796 		nStartX = -nStartX;		// reverse transformation, so the same cell address calculation works
797 		nEndX   = -nEndX;
798 		::std::swap( nStartX, nEndX );
799 	}
800 
801 	if (bAny)
802 	{
803 		DBG_ASSERT( nStartX<=nEndX && nStartY<=nEndY, "Start/End falsch in ScDrawLayer::GetPrintArea" );
804 
805 		if (bSetHor)
806 		{
807 			nStartX = (long) (nStartX / HMM_PER_TWIPS);
808 			nEndX = (long) (nEndX / HMM_PER_TWIPS);
809 			long nWidth;
810 	        SCCOL i;
811 
812 			nWidth = 0;
813 			for (i=0; i<=MAXCOL && nWidth<=nStartX; i++)
814 				nWidth += pDoc->GetColWidth(i,nTab);
815 			rRange.aStart.SetCol( i>0 ? (i-1) : 0 );
816 
817 			nWidth = 0;
818 			for (i=0; i<=MAXCOL && nWidth<=nEndX; i++)			//! bei Start anfangen
819 				nWidth += pDoc->GetColWidth(i,nTab);
820 			rRange.aEnd.SetCol( i>0 ? (i-1) : 0 );
821 		}
822 
823 		if (bSetVer)
824 		{
825 			nStartY = (long) (nStartY / HMM_PER_TWIPS);
826 			nEndY = (long) (nEndY / HMM_PER_TWIPS);
827             SCROW nRow = pDoc->GetRowForHeight( nTab, nStartY);
828 			rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
829             nRow = pDoc->GetRowForHeight( nTab, nEndY);
830 			rRange.aEnd.SetRow( nRow == MAXROW ? MAXROW :
831                     (nRow>0 ? (nRow-1) : 0));
832 		}
833 	}
834 	else
835 	{
836 		if (bSetHor)
837 		{
838 			rRange.aStart.SetCol(0);
839 			rRange.aEnd.SetCol(0);
840 		}
841 		if (bSetVer)
842 		{
843 			rRange.aStart.SetRow(0);
844 			rRange.aEnd.SetRow(0);
845 		}
846 	}
847 	return bAny;
848 }
849 
850 void ScDrawLayer::AddCalcUndo( SdrUndoAction* pUndo )
851 {
852 	if (bRecording)
853 	{
854 		if (!pUndoGroup)
855 			pUndoGroup = new SdrUndoGroup(*this);
856 
857 		pUndoGroup->AddAction( pUndo );
858 	}
859 	else
860 		delete pUndo;
861 }
862 
863 void ScDrawLayer::BeginCalcUndo(bool bDisableTextEditUsesCommonUndoManager)
864 {
865 //! DBG_ASSERT( !bRecording, "BeginCalcUndo ohne GetCalcUndo" );
866     SetDisableTextEditUsesCommonUndoManager(bDisableTextEditUsesCommonUndoManager);
867 	DELETEZ(pUndoGroup);
868 	bRecording = sal_True;
869 }
870 
871 SdrUndoGroup* ScDrawLayer::GetCalcUndo()
872 {
873 //! DBG_ASSERT( bRecording, "GetCalcUndo ohne BeginCalcUndo" );
874 
875 	SdrUndoGroup* pRet = pUndoGroup;
876 	pUndoGroup = NULL;
877 	bRecording = sal_False;
878     SetDisableTextEditUsesCommonUndoManager(false);
879 	return pRet;
880 }
881 
882 //	MoveAreaTwips: all measures are kept in twips
883 void ScDrawLayer::MoveAreaTwips( SCTAB nTab, const Rectangle& rArea,
884 		const Point& rMove, const Point& rTopLeft )
885 {
886 	if (!rMove.X() && !rMove.Y())
887 		return; 									// nix
888 
889 	SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
890 	DBG_ASSERT(pPage,"Page nicht gefunden");
891 	if (!pPage)
892 		return;
893 
894 	sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
895 
896 	// fuer Shrinking!
897 	Rectangle aNew( rArea );
898 	sal_Bool bShrink = sal_False;
899 	if ( rMove.X() < 0 || rMove.Y() < 0 )		// verkleinern
900 	{
901 		if ( rTopLeft != rArea.TopLeft() )		// sind gleich beim Verschieben von Zellen
902 		{
903 			bShrink = sal_True;
904 			aNew.Left() = rTopLeft.X();
905 			aNew.Top() = rTopLeft.Y();
906 		}
907 	}
908 	SdrObjListIter aIter( *pPage, IM_FLAT );
909 	SdrObject* pObject = aIter.Next();
910 	while (pObject)
911 	{
912 		if( GetAnchor( pObject ) == SCA_CELL )
913 		{
914 			if ( GetObjData( pObject ) )					// Detektiv-Pfeil ?
915 			{
916 				// hier nichts
917 			}
918 			else if ( pObject->ISA( SdrEdgeObj ) )			// Verbinder?
919 			{
920 				//	hier auch nichts
921 				//!	nicht verbundene Enden wie bei Linien (s.u.) behandeln?
922 			}
923 			else if ( pObject->IsPolyObj() && pObject->GetPointCount()==2 )
924 			{
925 				for (sal_uInt16 i=0; i<2; i++)
926 				{
927 					sal_Bool bMoved = sal_False;
928 					Point aPoint = pObject->GetPoint(i);
929 					lcl_ReverseTwipsToMM( aPoint );
930 					if (rArea.IsInside(aPoint))
931 					{
932 						aPoint += rMove; bMoved = sal_True;
933 					}
934 					else if (bShrink && aNew.IsInside(aPoint))
935 					{
936 						//	Punkt ist in betroffener Zelle - Test auf geloeschten Bereich
937 						if ( rMove.X() && aPoint.X() >= rArea.Left() + rMove.X() )
938 						{
939 							aPoint.X() = rArea.Left() + rMove.X() - SHRINK_DIST_TWIPS;
940 							if ( aPoint.X() < 0 ) aPoint.X() = 0;
941 							bMoved = sal_True;
942 						}
943 						if ( rMove.Y() && aPoint.Y() >= rArea.Top() + rMove.Y() )
944 						{
945 							aPoint.Y() = rArea.Top() + rMove.Y() - SHRINK_DIST_TWIPS;
946 							if ( aPoint.Y() < 0 ) aPoint.Y() = 0;
947 							bMoved = sal_True;
948 						}
949 					}
950 					if( bMoved )
951 					{
952 			                        AddCalcUndo< SdrUndoGeoObj >( *pObject );
953 						lcl_TwipsToMM( aPoint );
954 						pObject->SetPoint( aPoint, i );
955 					}
956 				}
957 			}
958 			else
959 			{
960 				Rectangle aObjRect = pObject->GetLogicRect();
961 				// aOldMMPos: not converted, millimeters
962 				Point aOldMMPos = bNegativePage ? aObjRect.TopRight() : aObjRect.TopLeft();
963 				lcl_ReverseTwipsToMM( aObjRect );
964 				Point aTopLeft = bNegativePage ? aObjRect.TopRight() : aObjRect.TopLeft();	// logical left
965 				Size aMoveSize;
966 				sal_Bool bDoMove = sal_False;
967 				if (rArea.IsInside(aTopLeft))
968 				{
969 					aMoveSize = Size(rMove.X(),rMove.Y());
970 					bDoMove = sal_True;
971 				}
972 				else if (bShrink && aNew.IsInside(aTopLeft))
973 				{
974 					//	Position ist in betroffener Zelle - Test auf geloeschten Bereich
975 					if ( rMove.X() && aTopLeft.X() >= rArea.Left() + rMove.X() )
976 					{
977 						aMoveSize.Width() = rArea.Left() + rMove.X() - SHRINK_DIST - aTopLeft.X();
978 						bDoMove = sal_True;
979 					}
980 					if ( rMove.Y() && aTopLeft.Y() >= rArea.Top() + rMove.Y() )
981 					{
982 						aMoveSize.Height() = rArea.Top() + rMove.Y() - SHRINK_DIST - aTopLeft.Y();
983 						bDoMove = sal_True;
984 					}
985 				}
986 				if ( bDoMove )
987 				{
988 					if ( bNegativePage )
989 					{
990 						if ( aTopLeft.X() + aMoveSize.Width() > 0 )
991 							aMoveSize.Width() = -aTopLeft.X();
992 					}
993 					else
994 					{
995 						if ( aTopLeft.X() + aMoveSize.Width() < 0 )
996 							aMoveSize.Width() = -aTopLeft.X();
997 					}
998 					if ( aTopLeft.Y() + aMoveSize.Height() < 0 )
999 						aMoveSize.Height() = -aTopLeft.Y();
1000 
1001 					//	get corresponding move size in millimeters:
1002 					Point aNewPos( aTopLeft.X() + aMoveSize.Width(), aTopLeft.Y() + aMoveSize.Height() );
1003 					lcl_TwipsToMM( aNewPos );
1004 					aMoveSize = Size( aNewPos.X() - aOldMMPos.X(), aNewPos.Y() - aOldMMPos.Y() );	// millimeters
1005 
1006 			                    AddCalcUndo< SdrUndoMoveObj >( *pObject, aMoveSize );
1007 					pObject->Move( aMoveSize );
1008 				}
1009 				else if ( rArea.IsInside( bNegativePage ? aObjRect.BottomLeft() : aObjRect.BottomRight() ) &&
1010 							!pObject->IsResizeProtect() )
1011 				{
1012 					//	geschuetzte Groessen werden nicht veraendert
1013 					//	(Positionen schon, weil sie ja an der Zelle "verankert" sind)
1014 		                    AddCalcUndo< SdrUndoGeoObj >( *pObject );
1015 					long nOldSizeX = aObjRect.Right() - aObjRect.Left() + 1;
1016 					long nOldSizeY = aObjRect.Bottom() - aObjRect.Top() + 1;
1017 					long nLogMoveX = rMove.X() * ( bNegativePage ? -1 : 1 );	// logical direction
1018 					pObject->Resize( aOldMMPos, Fraction( nOldSizeX+nLogMoveX, nOldSizeX ),
1019 												Fraction( nOldSizeY+rMove.Y(), nOldSizeY ) );
1020 				}
1021 			}
1022 		}
1023 		pObject = aIter.Next();
1024 	}
1025 }
1026 
1027 void ScDrawLayer::MoveArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
1028 							SCsCOL nDx,SCsROW nDy, sal_Bool bInsDel, bool bUpdateNoteCaptionPos )
1029 {
1030 	DBG_ASSERT( pDoc, "ScDrawLayer::MoveArea without document" );
1031 	if ( !pDoc )
1032 		return;
1033 
1034 	if (!bAdjustEnabled)
1035 		return;
1036 
1037 	sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1038 
1039 	Rectangle aRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1040 	lcl_ReverseTwipsToMM( aRect );
1041 	//!	use twips directly?
1042 
1043 	Point aMove;
1044 
1045 	if (nDx > 0)
1046 		for (SCsCOL s=0; s<nDx; s++)
1047 			aMove.X() += pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
1048 	else
1049 		for (SCsCOL s=-1; s>=nDx; s--)
1050 			aMove.X() -= pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
1051 	if (nDy > 0)
1052         aMove.Y() += pDoc->GetRowHeight( nRow1, nRow1+nDy-1, nTab);
1053 	else
1054         aMove.Y() -= pDoc->GetRowHeight( nRow1+nDy, nRow1-1, nTab);
1055 
1056 	if ( bNegativePage )
1057 		aMove.X() = -aMove.X();
1058 
1059 	Point aTopLeft = aRect.TopLeft();		// Anfang beim Verkleinern
1060 	if (bInsDel)
1061 	{
1062 		if ( aMove.X() != 0 && nDx < 0 )	// nDx counts cells, sign is independent of RTL
1063 			aTopLeft.X() += aMove.X();
1064 		if ( aMove.Y() < 0 )
1065 			aTopLeft.Y() += aMove.Y();
1066 	}
1067 
1068 	//	drawing objects are now directly included in cut&paste
1069 	//	-> only update references when inserting/deleting (or changing widths or heights)
1070 	if ( bInsDel )
1071 		MoveAreaTwips( nTab, aRect, aMove, aTopLeft );
1072 
1073 		//
1074 		//		Detektiv-Pfeile: Zellpositionen anpassen
1075 		//
1076 
1077 	MoveCells( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy, bUpdateNoteCaptionPos );
1078 }
1079 
1080 void ScDrawLayer::WidthChanged( SCTAB nTab, SCCOL nCol, long nDifTwips )
1081 {
1082 	DBG_ASSERT( pDoc, "ScDrawLayer::WidthChanged without document" );
1083 	if ( !pDoc )
1084 		return;
1085 
1086 	if (!bAdjustEnabled)
1087 		return;
1088 
1089 	Rectangle aRect;
1090 	Point aTopLeft;
1091 
1092 	for (SCCOL i=0; i<nCol; i++)
1093 		aRect.Left() += pDoc->GetColWidth(i,nTab);
1094 	aTopLeft.X() = aRect.Left();
1095 	aRect.Left() += pDoc->GetColWidth(nCol,nTab);
1096 
1097 	aRect.Right() = MAXMM;
1098 	aRect.Top() = 0;
1099 	aRect.Bottom() = MAXMM;
1100 
1101 	//!	aTopLeft ist falsch, wenn mehrere Spalten auf einmal ausgeblendet werden
1102 
1103 	sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1104 	if ( bNegativePage )
1105 	{
1106 		MirrorRectRTL( aRect );
1107 		aTopLeft.X() = -aTopLeft.X();
1108 		nDifTwips = -nDifTwips;
1109 	}
1110 
1111 	MoveAreaTwips( nTab, aRect, Point( nDifTwips,0 ), aTopLeft );
1112 }
1113 
1114 void ScDrawLayer::HeightChanged( SCTAB nTab, SCROW nRow, long nDifTwips )
1115 {
1116 	DBG_ASSERT( pDoc, "ScDrawLayer::HeightChanged without document" );
1117 	if ( !pDoc )
1118 		return;
1119 
1120 	if (!bAdjustEnabled)
1121 		return;
1122 
1123     SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1124     DBG_ASSERT(pPage,"Page not found");
1125     if (!pPage)
1126         return;
1127 
1128     // for an empty page, there's no need to calculate the row heights
1129     if (!pPage->GetObjCount())
1130         return;
1131 
1132 	Rectangle aRect;
1133 	Point aTopLeft;
1134 
1135     aRect.Top() += pDoc->GetRowHeight( 0, nRow-1, nTab);
1136 	aTopLeft.Y() = aRect.Top();
1137 	aRect.Top() += pDoc->GetRowHeight(nRow, nTab);
1138 
1139 	aRect.Bottom() = MAXMM;
1140 	aRect.Left() = 0;
1141 	aRect.Right() = MAXMM;
1142 
1143 	//!	aTopLeft ist falsch, wenn mehrere Zeilen auf einmal ausgeblendet werden
1144 
1145 	sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1146 	if ( bNegativePage )
1147 	{
1148 		MirrorRectRTL( aRect );
1149 		aTopLeft.X() = -aTopLeft.X();
1150 	}
1151 
1152 	MoveAreaTwips( nTab, aRect, Point( 0,nDifTwips ), aTopLeft );
1153 }
1154 
1155 sal_Bool ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow, bool bIncludeNotes )
1156 {
1157 	DBG_ASSERT( pDoc, "ScDrawLayer::HasObjectsInRows without document" );
1158 	if ( !pDoc )
1159 		return sal_False;
1160 
1161     SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1162     DBG_ASSERT(pPage,"Page not found");
1163     if (!pPage)
1164         return sal_False;
1165 
1166     // for an empty page, there's no need to calculate the row heights
1167     if (!pPage->GetObjCount())
1168         return sal_False;
1169 
1170 	Rectangle aTestRect;
1171 
1172     aTestRect.Top() += pDoc->GetRowHeight( 0, nStartRow-1, nTab);
1173 
1174 	if (nEndRow==MAXROW)
1175 		aTestRect.Bottom() = MAXMM;
1176 	else
1177 	{
1178 		aTestRect.Bottom() = aTestRect.Top();
1179         aTestRect.Bottom() += pDoc->GetRowHeight( nStartRow, nEndRow, nTab);
1180 		TwipsToMM( aTestRect.Bottom() );
1181 	}
1182 
1183 	TwipsToMM( aTestRect.Top() );
1184 
1185 	aTestRect.Left()  = 0;
1186 	aTestRect.Right() = MAXMM;
1187 
1188 	sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1189 	if ( bNegativePage )
1190 		MirrorRectRTL( aTestRect );
1191 
1192 	sal_Bool bFound = sal_False;
1193 
1194 	Rectangle aObjRect;
1195 	SdrObjListIter aIter( *pPage );
1196 	SdrObject* pObject = aIter.Next();
1197 	while ( pObject && !bFound )
1198 	{
1199 		aObjRect = pObject->GetSnapRect();	//! GetLogicRect ?
1200         // #i116164# note captions are handled separately, don't have to be included for each single row height change
1201         if ( (aTestRect.IsInside(aObjRect.TopLeft()) || aTestRect.IsInside(aObjRect.BottomLeft())) &&
1202              (bIncludeNotes || !IsNoteCaption(pObject)) )
1203 			bFound = sal_True;
1204 
1205 		pObject = aIter.Next();
1206 	}
1207 
1208 	return bFound;
1209 }
1210 
1211 #if 0
1212 void ScDrawLayer::DeleteObjects( SCTAB nTab )
1213 {
1214 	SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1215 	DBG_ASSERT(pPage,"Page ?");
1216 	if (!pPage)
1217 		return;
1218 
1219 	pPage->RecalcObjOrdNums();
1220 
1221 	long	nDelCount = 0;
1222 	sal_uLong	nObjCount = pPage->GetObjCount();
1223 	if (nObjCount)
1224 	{
1225 		SdrObject** ppObj = new SdrObject*[nObjCount];
1226 
1227 		SdrObjListIter aIter( *pPage, IM_FLAT );
1228 		SdrObject* pObject = aIter.Next();
1229 		while (pObject)
1230 		{
1231 			//	alle loeschen
1232 			ppObj[nDelCount++] = pObject;
1233 			pObject = aIter.Next();
1234 		}
1235 
1236 		long i;
1237 		if (bRecording)
1238 			for (i=1; i<=nDelCount; i++)
1239 		                AddCalcUndo< SdrUndoRemoveObj >( *ppObj[nDelCount-i] );
1240 
1241 		for (i=1; i<=nDelCount; i++)
1242 			pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1243 
1244 		delete[] ppObj;
1245 	}
1246 }
1247 #endif
1248 
1249 void ScDrawLayer::DeleteObjectsInArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1,
1250 											SCCOL nCol2,SCROW nRow2 )
1251 {
1252 	DBG_ASSERT( pDoc, "ScDrawLayer::DeleteObjectsInArea without document" );
1253 	if ( !pDoc )
1254 		return;
1255 
1256 	SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1257 	DBG_ASSERT(pPage,"Page ?");
1258 	if (!pPage)
1259 		return;
1260 
1261 	pPage->RecalcObjOrdNums();
1262 
1263 	long	nDelCount = 0;
1264 	sal_uLong	nObjCount = pPage->GetObjCount();
1265 	if (nObjCount)
1266 	{
1267 		Rectangle aDelRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1268 
1269 		SdrObject** ppObj = new SdrObject*[nObjCount];
1270 
1271 		SdrObjListIter aIter( *pPage, IM_FLAT );
1272 		SdrObject* pObject = aIter.Next();
1273 		while (pObject)
1274 		{
1275             // do not delete note caption, they are always handled by the cell note
1276             // TODO: detective objects are still deleted, is this desired?
1277             if (!IsNoteCaption( pObject ))
1278             {
1279                 Rectangle aObjRect = pObject->GetCurrentBoundRect();
1280                 if ( aDelRect.IsInside( aObjRect ) )
1281                     ppObj[nDelCount++] = pObject;
1282             }
1283 
1284 			pObject = aIter.Next();
1285 		}
1286 
1287 		long i;
1288 		if (bRecording)
1289 			for (i=1; i<=nDelCount; i++)
1290 		                AddCalcUndo< SdrUndoRemoveObj >( *ppObj[nDelCount-i] );
1291 
1292 		for (i=1; i<=nDelCount; i++)
1293 			pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1294 
1295 		delete[] ppObj;
1296 	}
1297 }
1298 
1299 void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
1300 {
1301 	DBG_ASSERT( pDoc, "ScDrawLayer::DeleteObjectsInSelection without document" );
1302 	if ( !pDoc )
1303 		return;
1304 
1305 	if ( !rMark.IsMultiMarked() )
1306 		return;
1307 
1308 	ScRange aMarkRange;
1309 	rMark.GetMultiMarkArea( aMarkRange );
1310 
1311 	SCTAB nTabCount = pDoc->GetTableCount();
1312 	for (SCTAB nTab=0; nTab<=nTabCount; nTab++)
1313 		if ( rMark.GetTableSelect( nTab ) )
1314 		{
1315 			SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1316 			if (pPage)
1317 			{
1318 				pPage->RecalcObjOrdNums();
1319 				long	nDelCount = 0;
1320 				sal_uLong	nObjCount = pPage->GetObjCount();
1321 				if (nObjCount)
1322 				{
1323 					//	Rechteck um die ganze Selektion
1324 					Rectangle aMarkBound = pDoc->GetMMRect(
1325 								aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
1326 								aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab );
1327 
1328 					SdrObject** ppObj = new SdrObject*[nObjCount];
1329 
1330 					SdrObjListIter aIter( *pPage, IM_FLAT );
1331 					SdrObject* pObject = aIter.Next();
1332 					while (pObject)
1333 					{
1334                         // do not delete note caption, they are always handled by the cell note
1335                         // TODO: detective objects are still deleted, is this desired?
1336                         if (!IsNoteCaption( pObject ))
1337                         {
1338                             Rectangle aObjRect = pObject->GetCurrentBoundRect();
1339                             if ( aMarkBound.IsInside( aObjRect ) )
1340                             {
1341                                 ScRange aRange = pDoc->GetRange( nTab, aObjRect );
1342                                 if (rMark.IsAllMarked(aRange))
1343                                     ppObj[nDelCount++] = pObject;
1344                             }
1345                         }
1346 
1347 						pObject = aIter.Next();
1348 					}
1349 
1350 					//	Objekte loeschen (rueckwaerts)
1351 
1352 					long i;
1353 					if (bRecording)
1354 						for (i=1; i<=nDelCount; i++)
1355 			                            AddCalcUndo< SdrUndoRemoveObj >( *ppObj[nDelCount-i] );
1356 
1357 					for (i=1; i<=nDelCount; i++)
1358 						pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1359 
1360 					delete[] ppObj;
1361 				}
1362 			}
1363 			else
1364 			{
1365 				DBG_ERROR("pPage?");
1366 			}
1367 		}
1368 }
1369 
1370 void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const Rectangle& rRange )
1371 {
1372 	//	copy everything in the specified range into the same page (sheet) in the clipboard doc
1373 
1374 	SdrPage* pSrcPage = GetPage(static_cast<sal_uInt16>(nTab));
1375 	if (pSrcPage)
1376 	{
1377 		ScDrawLayer* pDestModel = NULL;
1378 		SdrPage* pDestPage = NULL;
1379 
1380 		SdrObjListIter aIter( *pSrcPage, IM_FLAT );
1381 		SdrObject* pOldObject = aIter.Next();
1382 		while (pOldObject)
1383 		{
1384 			Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1385             // do not copy internal objects (detective) and note captions
1386             if ( rRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
1387 			{
1388 				if ( !pDestModel )
1389 				{
1390 					pDestModel = pClipDoc->GetDrawLayer();		// does the document already have a drawing layer?
1391 					if ( !pDestModel )
1392 					{
1393 						//	allocate drawing layer in clipboard document only if there are objects to copy
1394 
1395 						pClipDoc->InitDrawLayer();					//!	create contiguous pages
1396 						pDestModel = pClipDoc->GetDrawLayer();
1397 					}
1398 					if (pDestModel)
1399 						pDestPage = pDestModel->GetPage( static_cast<sal_uInt16>(nTab) );
1400 				}
1401 
1402 				DBG_ASSERT( pDestPage, "no page" );
1403 				if (pDestPage)
1404 				{
1405 					// #116235#
1406 					SdrObject* pNewObject = pOldObject->Clone();
1407 					//SdrObject* pNewObject = pOldObject->Clone( pDestPage, pDestModel );
1408 					pNewObject->SetModel(pDestModel);
1409 					pNewObject->SetPage(pDestPage);
1410 
1411                     uno::Reference< chart2::XChartDocument > xOldChart( ScChartHelper::GetChartFromSdrObject( pOldObject ) );
1412                     if(!xOldChart.is())//#i110034# do not move charts as they loose all their data references otherwise
1413                         pNewObject->NbcMove(Size(0,0));
1414 					pDestPage->InsertObject( pNewObject );
1415 
1416 					//	no undo needed in clipboard document
1417 					//	charts are not updated
1418 				}
1419 			}
1420 
1421 			pOldObject = aIter.Next();
1422 		}
1423 	}
1424 }
1425 
1426 sal_Bool lcl_IsAllInRange( const ::std::vector< ScRangeList >& rRangesVector, const ScRange& rClipRange )
1427 {
1428 	//	check if every range of rRangesVector is completely in rClipRange
1429 
1430     ::std::vector< ScRangeList >::const_iterator aIt = rRangesVector.begin();
1431     for( ;aIt!=rRangesVector.end(); ++aIt )
1432     {
1433         const ScRangeList& rRanges = *aIt;
1434 	    sal_uLong nCount = rRanges.Count();
1435 	    for (sal_uLong i=0; i<nCount; i++)
1436 	    {
1437 		    ScRange aRange = *rRanges.GetObject(i);
1438 		    if ( !rClipRange.In( aRange ) )
1439 		    {
1440 			    return sal_False;	// at least one range is not valid
1441 		    }
1442 	    }
1443     }
1444 
1445 	return sal_True;			// everything is fine
1446 }
1447 
1448 sal_Bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const ScRange& rSourceRange, const ScAddress& rDestPos )
1449 {
1450 	sal_Bool bChanged = sal_False;
1451 
1452     ::std::vector< ScRangeList >::iterator aIt = rRangesVector.begin();
1453     for( ;aIt!=rRangesVector.end(); ++aIt )
1454     {
1455         ScRangeList& rRanges = *aIt;
1456         sal_uLong nCount = rRanges.Count();
1457 	    for (sal_uLong i=0; i<nCount; i++)
1458 	    {
1459 		    ScRange* pRange = rRanges.GetObject(i);
1460 		    if ( rSourceRange.In( *pRange ) )
1461 		    {
1462 			    SCsCOL nDiffX = rDestPos.Col() - (SCsCOL)rSourceRange.aStart.Col();
1463 			    SCsROW nDiffY = rDestPos.Row() - (SCsROW)rSourceRange.aStart.Row();
1464 			    SCsTAB nDiffZ = rDestPos.Tab() - (SCsTAB)rSourceRange.aStart.Tab();
1465 			    pRange->Move( nDiffX, nDiffY, nDiffZ );
1466 			    bChanged = sal_True;
1467 		    }
1468 	    }
1469     }
1470 
1471 	return bChanged;
1472 }
1473 
1474 void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const Rectangle& rSourceRange,
1475 									const ScAddress& rDestPos, const Rectangle& rDestRange )
1476 {
1477 	DBG_ASSERT( pDoc, "ScDrawLayer::CopyFromClip without document" );
1478 	if ( !pDoc )
1479 		return;
1480 
1481 	if (!pClipModel)
1482 		return;
1483 
1484 	if (bDrawIsInUndo)		//! can this happen?
1485 	{
1486 		DBG_ERROR("CopyFromClip, bDrawIsInUndo");
1487 		return;
1488 	}
1489 
1490 	sal_Bool bMirrorObj = ( rSourceRange.Left() < 0 && rSourceRange.Right() < 0 &&
1491 						rDestRange.Left()   > 0 && rDestRange.Right()   > 0 ) ||
1492 					  ( rSourceRange.Left() > 0 && rSourceRange.Right() > 0 &&
1493 						rDestRange.Left()   < 0 && rDestRange.Right()   < 0 );
1494 	Rectangle aMirroredSource = rSourceRange;
1495 	if ( bMirrorObj )
1496 		MirrorRectRTL( aMirroredSource );
1497 
1498 	SCTAB nDestTab = rDestPos.Tab();
1499 
1500     SdrPage* pSrcPage = pClipModel->GetPage(static_cast<sal_uInt16>(nSourceTab));
1501     SdrPage* pDestPage = GetPage(static_cast<sal_uInt16>(nDestTab));
1502     DBG_ASSERT( pSrcPage && pDestPage, "draw page missing" );
1503     if ( !pSrcPage || !pDestPage )
1504         return;
1505 
1506     SdrObjListIter aIter( *pSrcPage, IM_FLAT );
1507     SdrObject* pOldObject = aIter.Next();
1508 
1509     ScDocument* pClipDoc = pClipModel->GetDocument();
1510     //  a clipboard document and its source share the same document item pool,
1511     //  so the pointers can be compared to see if this is copy&paste within
1512     //  the same document
1513     sal_Bool bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
1514     sal_Bool bDestClip = pDoc && pDoc->IsClipboard();
1515 
1516     //#i110034# charts need correct sheet names for xml range conversion during load
1517     //so the target sheet name is temporarily renamed (if we have any SdrObjects)
1518     String aDestTabName;
1519     sal_Bool bRestoreDestTabName = sal_False;
1520     if( pOldObject && !bSameDoc && !bDestClip )
1521     {
1522         if( pDoc && pClipDoc )
1523         {
1524             String aSourceTabName;
1525             if( pClipDoc->GetName( nSourceTab, aSourceTabName )
1526                 && pDoc->GetName( nDestTab, aDestTabName ) )
1527             {
1528                 if( !(aSourceTabName==aDestTabName) &&
1529                     pDoc->ValidNewTabName(aSourceTabName) )
1530                 {
1531                     bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName ); //sal_Bool bUpdateRef = sal_True, sal_Bool bExternalDocument = sal_False
1532                 }
1533             }
1534         }
1535     }
1536 
1537 	// first mirror, then move
1538 	Size aMove( rDestRange.Left() - aMirroredSource.Left(), rDestRange.Top() - aMirroredSource.Top() );
1539 
1540 	long nDestWidth = rDestRange.GetWidth();
1541 	long nDestHeight = rDestRange.GetHeight();
1542 	long nSourceWidth = rSourceRange.GetWidth();
1543 	long nSourceHeight = rSourceRange.GetHeight();
1544 
1545 	long nWidthDiff = nDestWidth - nSourceWidth;
1546 	long nHeightDiff = nDestHeight - nSourceHeight;
1547 
1548 	Fraction aHorFract(1,1);
1549 	Fraction aVerFract(1,1);
1550 	sal_Bool bResize = sal_False;
1551 	// sizes can differ by 1 from twips->1/100mm conversion for equal cell sizes,
1552 	// don't resize to empty size when pasting into hidden columns or rows
1553 	if ( Abs(nWidthDiff) > 1 && nDestWidth > 1 && nSourceWidth > 1 )
1554 	{
1555 		aHorFract = Fraction( nDestWidth, nSourceWidth );
1556 		bResize = sal_True;
1557 	}
1558 	if ( Abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
1559 	{
1560 		aVerFract = Fraction( nDestHeight, nSourceHeight );
1561 		bResize = sal_True;
1562 	}
1563 	Point aRefPos = rDestRange.TopLeft();		// for resizing (after moving)
1564 
1565 	while (pOldObject)
1566 	{
1567 		Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1568         // do not copy internal objects (detective) and note captions
1569         if ( rSourceRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
1570 		{
1571 			// #116235#
1572 			SdrObject* pNewObject = pOldObject->Clone();
1573 			//SdrObject* pNewObject = pOldObject->Clone( pDestPage, this );
1574 			pNewObject->SetModel(this);
1575 			pNewObject->SetPage(pDestPage);
1576 
1577 			if ( bMirrorObj )
1578 				MirrorRTL( pNewObject );		// first mirror, then move
1579 
1580 			pNewObject->NbcMove( aMove );
1581 			if ( bResize )
1582 				pNewObject->NbcResize( aRefPos, aHorFract, aVerFract );
1583 
1584 			pDestPage->InsertObject( pNewObject );
1585 			if (bRecording)
1586 		                AddCalcUndo< SdrUndoInsertObj >( *pNewObject );
1587 
1588 			//#i110034#	handle chart data references (after InsertObject)
1589 
1590 			if ( pNewObject->GetObjIdentifier() == OBJ_OLE2 )
1591 			{
1592 				uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pNewObject)->GetObjRef();
1593 				uno::Reference< embed::XClassifiedObject > xClassified( xIPObj, uno::UNO_QUERY );
1594 				SvGlobalName aObjectClassName;
1595 				if ( xClassified.is() )
1596 			    {
1597 					try {
1598 						aObjectClassName = SvGlobalName( xClassified->getClassID() );
1599 					} catch( uno::Exception& )
1600 					{
1601 						// TODO: handle error?
1602 					}
1603 				}
1604 
1605 				if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
1606 				{
1607                     uno::Reference< chart2::XChartDocument > xNewChart( ScChartHelper::GetChartFromSdrObject( pNewObject ) );
1608                     if( xNewChart.is() && !xNewChart->hasInternalDataProvider() )
1609                     {
1610                         String aChartName = ((SdrOle2Obj*)pNewObject)->GetPersistName();
1611                         ::std::vector< ScRangeList > aRangesVector;
1612                         pDoc->GetChartRanges( aChartName, aRangesVector, pDoc );
1613                         if( !aRangesVector.empty() )
1614                         {
1615                             sal_Bool bInSourceRange = sal_False;
1616                             ScRange aClipRange;
1617                             if ( pClipDoc )
1618                             {
1619                                 SCCOL nClipStartX;
1620                                 SCROW nClipStartY;
1621                                 SCCOL nClipEndX;
1622                                 SCROW nClipEndY;
1623                                 pClipDoc->GetClipStart( nClipStartX, nClipStartY );
1624                                 pClipDoc->GetClipArea( nClipEndX, nClipEndY, sal_True );
1625                                 nClipEndX = nClipEndX + nClipStartX;
1626                                 nClipEndY += nClipStartY;   // GetClipArea returns the difference
1627 
1628                                 SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
1629                                 aClipRange = ScRange( nClipStartX, nClipStartY, nClipTab,
1630                                                         nClipEndX, nClipEndY, nClipTab );
1631 
1632                                 bInSourceRange = lcl_IsAllInRange( aRangesVector, aClipRange );
1633                             }
1634 
1635                             // always lose references when pasting into a clipboard document (transpose)
1636                             if ( ( bInSourceRange || bSameDoc ) && !bDestClip )
1637                             {
1638                                 if ( bInSourceRange )
1639                                 {
1640                                     if ( rDestPos != aClipRange.aStart )
1641                                     {
1642                                         //  update the data ranges to the new (copied) position
1643                                         if ( lcl_MoveRanges( aRangesVector, aClipRange, rDestPos ) )
1644                                             pDoc->SetChartRanges( aChartName, aRangesVector );
1645                                     }
1646                                 }
1647                                 else
1648                                 {
1649                                     //  leave the ranges unchanged
1650                                 }
1651                             }
1652                             else
1653                             {
1654                                 //  pasting into a new document without the complete source data
1655                                 //  -> break connection to source data and switch to own data
1656 
1657                                 uno::Reference< chart::XChartDocument > xOldChartDoc( ScChartHelper::GetChartFromSdrObject( pOldObject ), uno::UNO_QUERY );
1658                                 uno::Reference< chart::XChartDocument > xNewChartDoc( xNewChart, uno::UNO_QUERY );
1659                                 if( xOldChartDoc.is() && xNewChartDoc.is() )
1660                                     xNewChartDoc->attachData( xOldChartDoc->getData() );
1661 
1662                                 //  (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
1663                             }
1664 					    }
1665                     }
1666 				}
1667 			}
1668 		}
1669 
1670 		pOldObject = aIter.Next();
1671 	}
1672 
1673     if( bRestoreDestTabName )
1674         pDoc->RenameTab( nDestTab, aDestTabName );
1675 }
1676 
1677 void ScDrawLayer::MirrorRTL( SdrObject* pObj )
1678 {
1679 	sal_uInt16 nIdent = pObj->GetObjIdentifier();
1680 
1681 	//	don't mirror OLE or graphics, otherwise ask the object
1682 	//	if it can be mirrored
1683 	sal_Bool bCanMirror = ( nIdent != OBJ_GRAF && nIdent != OBJ_OLE2 );
1684 	if (bCanMirror)
1685 	{
1686 		SdrObjTransformInfoRec aInfo;
1687 		pObj->TakeObjInfo( aInfo );
1688 		bCanMirror = aInfo.bMirror90Allowed;
1689 	}
1690 
1691 	if (bCanMirror)
1692 	{
1693 		Point aRef1( 0, 0 );
1694 		Point aRef2( 0, 1 );
1695 		if (bRecording)
1696 		            AddCalcUndo< SdrUndoGeoObj >( *pObj );
1697 		pObj->Mirror( aRef1, aRef2 );
1698 	}
1699 	else
1700 	{
1701 		//	Move instead of mirroring:
1702 		//	New start position is negative of old end position
1703 		//	-> move by sum of start and end position
1704 		Rectangle aObjRect = pObj->GetLogicRect();
1705 		Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
1706 		if (bRecording)
1707 		            AddCalcUndo< SdrUndoMoveObj >( *pObj, aMoveSize );
1708 		pObj->Move( aMoveSize );
1709 	}
1710 }
1711 
1712 // static
1713 void ScDrawLayer::MirrorRectRTL( Rectangle& rRect )
1714 {
1715 	//	mirror and swap left/right
1716 	long nTemp = rRect.Left();
1717 	rRect.Left() = -rRect.Right();
1718 	rRect.Right() = -nTemp;
1719 }
1720 
1721 Rectangle ScDrawLayer::GetCellRect( ScDocument& rDoc, const ScAddress& rPos, bool bMergedCell )
1722 {
1723     Rectangle aCellRect;
1724     DBG_ASSERT( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ), "ScDrawLayer::GetCellRect - invalid cell address" );
1725     if( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ) )
1726     {
1727         // find top left position of passed cell address
1728         Point aTopLeft;
1729         for( SCCOL nCol = 0; nCol < rPos.Col(); ++nCol )
1730             aTopLeft.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
1731         if( rPos.Row() > 0 )
1732             aTopLeft.Y() += rDoc.GetRowHeight( 0, rPos.Row() - 1, rPos.Tab() );
1733 
1734         // find bottom-right position of passed cell address
1735         ScAddress aEndPos = rPos;
1736         if( bMergedCell )
1737         {
1738             const ScMergeAttr* pMerge = static_cast< const ScMergeAttr* >( rDoc.GetAttr( rPos.Col(), rPos.Row(), rPos.Tab(), ATTR_MERGE ) );
1739             if( pMerge->GetColMerge() > 1 )
1740                 aEndPos.IncCol( pMerge->GetColMerge() - 1 );
1741             if( pMerge->GetRowMerge() > 1 )
1742                 aEndPos.IncRow( pMerge->GetRowMerge() - 1 );
1743         }
1744         Point aBotRight = aTopLeft;
1745         for( SCCOL nCol = rPos.Col(); nCol <= aEndPos.Col(); ++nCol )
1746             aBotRight.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
1747         aBotRight.Y() += rDoc.GetRowHeight( rPos.Row(), aEndPos.Row(), rPos.Tab() );
1748 
1749         // twips -> 1/100 mm
1750         aTopLeft.X() = static_cast< long >( aTopLeft.X() * HMM_PER_TWIPS );
1751         aTopLeft.Y() = static_cast< long >( aTopLeft.Y() * HMM_PER_TWIPS );
1752         aBotRight.X() = static_cast< long >( aBotRight.X() * HMM_PER_TWIPS );
1753         aBotRight.Y() = static_cast< long >( aBotRight.Y() * HMM_PER_TWIPS );
1754 
1755         aCellRect = Rectangle( aTopLeft, aBotRight );
1756         if( rDoc.IsNegativePage( rPos.Tab() ) )
1757             MirrorRectRTL( aCellRect );
1758     }
1759     return aCellRect;
1760 }
1761 
1762 // static
1763 String ScDrawLayer::GetVisibleName( SdrObject* pObj )
1764 {
1765 	String aName = pObj->GetName();
1766 	if ( pObj->GetObjIdentifier() == OBJ_OLE2 )
1767 	{
1768 		//	#95575# For OLE, the user defined name (GetName) is used
1769 		//	if it's not empty (accepting possibly duplicate names),
1770 		//	otherwise the persist name is used so every object appears
1771 		//	in the Navigator at all.
1772 
1773 		if ( !aName.Len() )
1774 			aName = static_cast<SdrOle2Obj*>(pObj)->GetPersistName();
1775 	}
1776 	return aName;
1777 }
1778 
1779 inline sal_Bool IsNamedObject( SdrObject* pObj, const String& rName )
1780 {
1781 	//	sal_True if rName is the object's Name or PersistName
1782 	//	(used to find a named object)
1783 
1784 	return ( pObj->GetName() == rName ||
1785 			( pObj->GetObjIdentifier() == OBJ_OLE2 &&
1786 			  static_cast<SdrOle2Obj*>(pObj)->GetPersistName() == rName ) );
1787 }
1788 
1789 SdrObject* ScDrawLayer::GetNamedObject( const String& rName, sal_uInt16 nId, SCTAB& rFoundTab ) const
1790 {
1791 	sal_uInt16 nTabCount = GetPageCount();
1792 	for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
1793 	{
1794 		const SdrPage* pPage = GetPage(nTab);
1795 		DBG_ASSERT(pPage,"Page ?");
1796 		if (pPage)
1797 		{
1798 			SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
1799 			SdrObject* pObject = aIter.Next();
1800 			while (pObject)
1801 			{
1802 				if ( nId == 0 || pObject->GetObjIdentifier() == nId )
1803 					if ( IsNamedObject( pObject, rName ) )
1804 					{
1805 						rFoundTab = static_cast<SCTAB>(nTab);
1806 						return pObject;
1807 					}
1808 
1809 				pObject = aIter.Next();
1810 			}
1811 		}
1812 	}
1813 
1814 	return NULL;
1815 }
1816 
1817 String ScDrawLayer::GetNewGraphicName( long* pnCounter ) const
1818 {
1819 	String aBase = ScGlobal::GetRscString(STR_GRAPHICNAME);
1820 	aBase += ' ';
1821 
1822 	sal_Bool bThere = sal_True;
1823     String aGraphicName;
1824 	SCTAB nDummy;
1825     long nId = pnCounter ? *pnCounter : 0;
1826 	while (bThere)
1827 	{
1828 		++nId;
1829         aGraphicName = aBase;
1830         aGraphicName += String::CreateFromInt32( nId );
1831         bThere = ( GetNamedObject( aGraphicName, 0, nDummy ) != NULL );
1832 	}
1833 
1834     if ( pnCounter )
1835         *pnCounter = nId;
1836 
1837     return aGraphicName;
1838 }
1839 
1840 void ScDrawLayer::EnsureGraphicNames()
1841 {
1842 	//	make sure all graphic objects have names (after Excel import etc.)
1843 
1844 	sal_uInt16 nTabCount = GetPageCount();
1845 	for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
1846 	{
1847 		SdrPage* pPage = GetPage(nTab);
1848 		DBG_ASSERT(pPage,"Page ?");
1849 		if (pPage)
1850 		{
1851 			SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
1852 			SdrObject* pObject = aIter.Next();
1853 
1854             /* #101799# The index passed to GetNewGraphicName() will be set to
1855                 the used index in each call. This prevents the repeated search
1856                 for all names from 1 to current index. */
1857             long nCounter = 0;
1858 
1859 			while (pObject)
1860 			{
1861 				if ( pObject->GetObjIdentifier() == OBJ_GRAF && pObject->GetName().Len() == 0 )
1862                     pObject->SetName( GetNewGraphicName( &nCounter ) );
1863 
1864 				pObject = aIter.Next();
1865 			}
1866 		}
1867 	}
1868 }
1869 
1870 void ScDrawLayer::SetAnchor( SdrObject* pObj, ScAnchorType eType )
1871 {
1872     ScAnchorType eOldAnchorType = GetAnchor( pObj );
1873 
1874     // Ein an der Seite verankertes Objekt zeichnet sich durch eine Anker-Pos
1875 	// von (0,1) aus. Das ist ein shabby Trick, der aber funktioniert!
1876 	Point aAnchor( 0, eType == SCA_PAGE ? 1 : 0 );
1877 	pObj->SetAnchorPos( aAnchor );
1878 
1879     if ( eOldAnchorType != eType )
1880         pObj->notifyShapePropertyChange( ::svx::eSpreadsheetAnchor );
1881 }
1882 
1883 ScAnchorType ScDrawLayer::GetAnchor( const SdrObject* pObj )
1884 {
1885 	Point aAnchor( pObj->GetAnchorPos() );
1886 	return ( aAnchor.Y() != 0 ) ? SCA_PAGE : SCA_CELL;
1887 }
1888 
1889 ScDrawObjData* ScDrawLayer::GetObjData( SdrObject* pObj, sal_Bool bCreate )		// static
1890 {
1891 	sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
1892 	for( sal_uInt16 i = 0; i < nCount; i++ )
1893 	{
1894 		SdrObjUserData* pData = pObj->GetUserData( i );
1895 		if( pData && pData->GetInventor() == SC_DRAWLAYER
1896 					&& pData->GetId() == SC_UD_OBJDATA )
1897 			return (ScDrawObjData*) pData;
1898 	}
1899 	if( pObj && bCreate )
1900 	{
1901 		ScDrawObjData* pData = new ScDrawObjData;
1902 		pObj->InsertUserData( pData, 0 );
1903 		return pData;
1904 	}
1905 	return 0;
1906 }
1907 
1908 ScDrawObjData* ScDrawLayer::GetObjDataTab( SdrObject* pObj, SCTAB nTab )    // static
1909 {
1910     ScDrawObjData* pData = GetObjData( pObj );
1911     if ( pData )
1912     {
1913         if ( pData->maStart.IsValid() )
1914             pData->maStart.SetTab( nTab );
1915         if ( pData->maEnd.IsValid() )
1916             pData->maEnd.SetTab( nTab );
1917     }
1918     return pData;
1919 }
1920 
1921 bool ScDrawLayer::IsNoteCaption( SdrObject* pObj )
1922 {
1923     ScDrawObjData* pData = pObj ? GetObjData( pObj ) : 0;
1924     return pData && pData->mbNote;
1925 }
1926 
1927 ScDrawObjData* ScDrawLayer::GetNoteCaptionData( SdrObject* pObj, SCTAB nTab )
1928 {
1929     ScDrawObjData* pData = pObj ? GetObjDataTab( pObj, nTab ) : 0;
1930     return (pData && pData->mbNote) ? pData : 0;
1931 }
1932 
1933 ScIMapInfo* ScDrawLayer::GetIMapInfo( SdrObject* pObj )				// static
1934 {
1935 	sal_uInt16 nCount = pObj->GetUserDataCount();
1936 	for( sal_uInt16 i = 0; i < nCount; i++ )
1937 	{
1938 		SdrObjUserData* pData = pObj->GetUserData( i );
1939 		if( pData && pData->GetInventor() == SC_DRAWLAYER
1940 					&& pData->GetId() == SC_UD_IMAPDATA )
1941 			return (ScIMapInfo*) pData;
1942 	}
1943 	return NULL;
1944 }
1945 
1946 // static:
1947 IMapObject*	ScDrawLayer::GetHitIMapObject( SdrObject* pObj,
1948 										  const Point& rWinPoint, const Window& rCmpWnd )
1949 {
1950 	const MapMode		aMap100( MAP_100TH_MM );
1951 	MapMode				aWndMode = rCmpWnd.GetMapMode();
1952 	Point				aRelPoint( rCmpWnd.LogicToLogic( rWinPoint, &aWndMode, &aMap100 ) );
1953 	Rectangle			aLogRect = rCmpWnd.LogicToLogic( pObj->GetLogicRect(), &aWndMode, &aMap100 );
1954 	ScIMapInfo*			pIMapInfo = GetIMapInfo( pObj );
1955 	IMapObject*			pIMapObj = NULL;
1956 
1957 	if ( pIMapInfo )
1958 	{
1959 		Size		aGraphSize;
1960 		ImageMap&	rImageMap = (ImageMap&) pIMapInfo->GetImageMap();
1961 		Graphic		aGraphic;
1962 		sal_Bool		bObjSupported = sal_False;
1963 
1964 		if ( pObj->ISA( SdrGrafObj )  ) // einfaches Grafik-Objekt
1965 		{
1966 			const SdrGrafObj*	pGrafObj = (const SdrGrafObj*) pObj;
1967 			const GeoStat&		rGeo = pGrafObj->GetGeoStat();
1968 			const Graphic&		rGraphic = pGrafObj->GetGraphic();
1969 
1970 			// Drehung rueckgaengig
1971 			if ( rGeo.nDrehWink )
1972 				RotatePoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nSin, rGeo.nCos );
1973 
1974 			// Spiegelung rueckgaengig
1975 			if ( ( (const SdrGrafObjGeoData*) pGrafObj->GetGeoData() )->bMirrored )
1976 				aRelPoint.X() = aLogRect.Right() + aLogRect.Left() - aRelPoint.X();
1977 
1978 			// ggf. Unshear:
1979 			if ( rGeo.nShearWink )
1980 				ShearPoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nTan );
1981 
1982 
1983 			if ( rGraphic.GetPrefMapMode().GetMapUnit() == MAP_PIXEL )
1984 				aGraphSize = rCmpWnd.PixelToLogic( rGraphic.GetPrefSize(),
1985 														 aMap100 );
1986 			else
1987 				aGraphSize = OutputDevice::LogicToLogic( rGraphic.GetPrefSize(),
1988 														 rGraphic.GetPrefMapMode(),
1989 														 aMap100 );
1990 
1991 			bObjSupported = sal_True;
1992 		}
1993 		else if ( pObj->ISA( SdrOle2Obj ) ) // OLE-Objekt
1994 		{
1995             // TODO/LEAN: working with visual area needs running state
1996 			aGraphSize = ((SdrOle2Obj*)pObj)->GetOrigObjSize();
1997 			bObjSupported = sal_True;
1998 		}
1999 
2000 		// hat alles geklappt, dann HitTest ausfuehren
2001 		if ( bObjSupported )
2002 		{
2003 			// relativen Mauspunkt berechnen
2004 			aRelPoint -= aLogRect.TopLeft();
2005 			pIMapObj = rImageMap.GetHitIMapObject( aGraphSize, aLogRect.GetSize(), aRelPoint );
2006 		}
2007 	}
2008 
2009 	return pIMapObj;
2010 }
2011 
2012 ScMacroInfo* ScDrawLayer::GetMacroInfo( SdrObject* pObj, sal_Bool bCreate )             // static
2013 {
2014     sal_uInt16 nCount = pObj->GetUserDataCount();
2015     for( sal_uInt16 i = 0; i < nCount; i++ )
2016     {
2017         SdrObjUserData* pData = pObj->GetUserData( i );
2018         if( pData && pData->GetInventor() == SC_DRAWLAYER
2019                     && pData->GetId() == SC_UD_MACRODATA )
2020             return (ScMacroInfo*) pData;
2021     }
2022     if ( bCreate )
2023     {
2024         ScMacroInfo* pData = new ScMacroInfo;
2025         pObj->InsertUserData( pData, 0 );
2026         return pData;
2027     }
2028     return 0;
2029 }
2030 ImageMap* ScDrawLayer::GetImageMapForObject(SdrObject* pObj)
2031 {
2032 	ScIMapInfo* pIMapInfo = const_cast<ScIMapInfo*>( GetIMapInfo( pObj ) );
2033 	if ( pIMapInfo )
2034 	{
2035 		return const_cast<ImageMap*>( &(pIMapInfo->GetImageMap()) );
2036 	}
2037 	return NULL;
2038 }
2039 
2040 sal_Int32 ScDrawLayer::GetHyperlinkCount(SdrObject* pObj)
2041 {
2042 	sal_Int32 nHLCount = 0;
2043 	ScMacroInfo* pMacroInfo = GetMacroInfo(pObj, sal_False);
2044 	if (pMacroInfo)
2045 		// MT IA2: GetHlink*( doesn|t exist in DEV300 anymore...
2046 		nHLCount = 0; // pMacroInfo->GetHlink().getLength() > 0 ? 1 : 0;
2047 	return nHLCount;
2048 }
2049 void ScDrawLayer::SetGlobalDrawPersist(SfxObjectShell* pPersist)			// static
2050 {
2051 	DBG_ASSERT(!pGlobalDrawPersist,"SetGlobalDrawPersist mehrfach");
2052 	pGlobalDrawPersist = pPersist;
2053 }
2054 
2055 void __EXPORT ScDrawLayer::SetChanged( sal_Bool bFlg /* = sal_True */ )
2056 {
2057 	if ( bFlg && pDoc )
2058 		pDoc->SetChartListenerCollectionNeedsUpdate( sal_True );
2059 	FmFormModel::SetChanged( bFlg );
2060 }
2061 
2062 SvStream* __EXPORT ScDrawLayer::GetDocumentStream(SdrDocumentStreamInfo& rStreamInfo) const
2063 {
2064 	DBG_ASSERT( pDoc, "ScDrawLayer::GetDocumentStream without document" );
2065 	if ( !pDoc )
2066 		return NULL;
2067 
2068 	uno::Reference< embed::XStorage > xStorage = pDoc->GetDocumentShell() ?
2069 														pDoc->GetDocumentShell()->GetStorage() :
2070 														NULL;
2071 	SvStream*	pRet = NULL;
2072 
2073 	if( xStorage.is() )
2074 	{
2075 		if( rStreamInfo.maUserData.Len() &&
2076 			( rStreamInfo.maUserData.GetToken( 0, ':' ) ==
2077 			  String( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.Package" ) ) ) )
2078 		{
2079 			const String aPicturePath( rStreamInfo.maUserData.GetToken( 1, ':' ) );
2080 
2081 			// graphic from picture stream in picture storage in XML package
2082 			if( aPicturePath.GetTokenCount( '/' ) == 2 )
2083 			{
2084 				const String aPictureStreamName( aPicturePath.GetToken( 1, '/' ) );
2085 				const String aPictureStorageName( aPicturePath.GetToken( 0, '/' ) );
2086 
2087 				try {
2088 					if ( xStorage->isStorageElement( aPictureStorageName ) )
2089 					{
2090 						uno::Reference< embed::XStorage > xPictureStorage =
2091                                     xStorage->openStorageElement( aPictureStorageName, embed::ElementModes::READ );
2092 
2093 						if( xPictureStorage.is() &&
2094 							xPictureStorage->isStreamElement( aPictureStreamName ) )
2095 						{
2096 							uno::Reference< io::XStream > xStream =
2097                                 xPictureStorage->openStreamElement( aPictureStreamName, embed::ElementModes::READ );
2098 							if ( xStream.is() )
2099 								pRet = ::utl::UcbStreamHelper::CreateStream( xStream );
2100 						}
2101 					}
2102 				}
2103 				catch( uno::Exception& )
2104 				{
2105 					// TODO: error handling
2106 				}
2107 			}
2108 		}
2109 		// the following code seems to be related to binary format
2110 //REMOVE			else
2111 //REMOVE			{
2112 //REMOVE				pRet = pStor->OpenStream( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(STRING_SCSTREAM)),
2113 //REMOVE										  STREAM_READ | STREAM_WRITE | STREAM_TRUNC );
2114 //REMOVE
2115 //REMOVE				if( pRet )
2116 //REMOVE				{
2117 //REMOVE					pRet->SetVersion( pStor->GetVersion() );
2118 //REMOVE					pRet->SetKey( pStor->GetKey() );
2119 //REMOVE				}
2120 //REMOVE			}
2121 
2122 		rStreamInfo.mbDeleteAfterUse = ( pRet != NULL );
2123 	}
2124 
2125 	return pRet;
2126 }
2127 
2128 //REMOVE	void ScDrawLayer::ReleasePictureStorage()
2129 //REMOVE	{
2130 //REMOVE		xPictureStorage.Clear();
2131 //REMOVE	}
2132 
2133 SdrLayerID __EXPORT ScDrawLayer::GetControlExportLayerId( const SdrObject & ) const
2134 {
2135 	//	Layer fuer Export von Form-Controls in Versionen vor 5.0 - immer SC_LAYER_FRONT
2136 	return SC_LAYER_FRONT;
2137 }
2138 
2139 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > ScDrawLayer::createUnoModel()
2140 {
2141 	::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet;
2142 	if( pDoc && pDoc->GetDocumentShell() )
2143 		xRet = pDoc->GetDocumentShell()->GetModel();
2144 
2145 	return xRet;
2146 }
2147