xref: /trunk/main/sc/source/core/data/drwlayer.cxx (revision 577c0052)
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 				 sal_True ),		// bUseExtColorTable (is set below)
211 	aName( rName ),
212 	pDoc( pDocument ),
213 	pUndoGroup( NULL ),
214 	bRecording( sal_False ),
215 	bAdjustEnabled( sal_True ),
216 	bHyphenatorSet( sal_False ),
217         mbUndoAllowed( sal_True )
218 {
219 	pGlobalDrawPersist = NULL;			// nur einmal benutzen
220 
221 	SfxObjectShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : NULL;
222 	if ( pObjSh )
223 	{
224 		SetObjectShell( pObjSh );
225 
226 		// set color table
227         SvxColorTableItem* pColItem = (SvxColorTableItem*) pObjSh->GetItem( SID_COLOR_TABLE );
228 		XColorTable* pXCol = pColItem ? pColItem->GetColorTable() : XColorTable::GetStdColorTable();
229 		SetColorTable( pXCol );
230 	}
231 	else
232 		SetColorTable( XColorTable::GetStdColorTable() );
233 
234 	SetSwapGraphics(sal_True);
235 //	SetSwapAsynchron(sal_True);		// an der View
236 
237 	SetScaleUnit(MAP_100TH_MM);
238 	SfxItemPool& rPool = GetItemPool();
239 	rPool.SetDefaultMetric(SFX_MAPUNIT_100TH_MM);
240 	SvxFrameDirectionItem aModeItem( FRMDIR_ENVIRONMENT, EE_PARA_WRITINGDIR );
241 	rPool.SetPoolDefaultItem( aModeItem );
242 
243 	// #i33700#
244 	// Set shadow distance defaults as PoolDefaultItems. Details see bug.
245 	rPool.SetPoolDefaultItem(SdrShadowXDistItem(300));
246 	rPool.SetPoolDefaultItem(SdrShadowYDistItem(300));
247 
248 	// #111216# default for script spacing depends on locale, see SdDrawDocument ctor in sd
249 	LanguageType eOfficeLanguage = Application::GetSettings().GetLanguage();
250 	if ( eOfficeLanguage == LANGUAGE_KOREAN || eOfficeLanguage == LANGUAGE_KOREAN_JOHAB ||
251 		 eOfficeLanguage == LANGUAGE_JAPANESE )
252 	{
253 		// secondary is edit engine pool
254 		rPool.GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( sal_False, EE_PARA_ASIANCJKSPACING ) );
255 	}
256 
257 	rPool.FreezeIdRanges();							// the pool is also used directly
258 
259 	SdrLayerAdmin& rAdmin = GetLayerAdmin();
260 	rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("vorne")),    SC_LAYER_FRONT);
261 	rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("hinten")),   SC_LAYER_BACK);
262 	rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("intern")),   SC_LAYER_INTERN);
263 	rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Controls")), SC_LAYER_CONTROLS);
264     rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("hidden")),   SC_LAYER_HIDDEN);
265 	// "Controls" is new - must also be created when loading
266 
267 	//	Link fuer URL-Fields setzen
268 	ScModule* pScMod = SC_MOD();
269 	Outliner& rOutliner = GetDrawOutliner();
270 	rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
271 
272 	Outliner& rHitOutliner = GetHitTestOutliner();
273 	rHitOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
274 
275     // #95129# SJ: set FontHeight pool defaults without changing static SdrEngineDefaults
276     SfxItemPool* pOutlinerPool = rOutliner.GetEditTextObjectPool();
277     if ( pOutlinerPool )
278  	    pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT ));           // 12Pt
279     SfxItemPool* pHitOutlinerPool = rHitOutliner.GetEditTextObjectPool();
280     if ( pHitOutlinerPool )
281  	    pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT ));    // 12Pt
282 
283     // initial undo mode as in Calc document
284     if( pDoc )
285         EnableUndo( pDoc->IsUndoEnabled() );
286 
287 	//	URL-Buttons haben keinen Handler mehr, machen alles selber
288 
289 	if( !nInst++ )
290 	{
291 		pFac = new ScDrawObjFactory;
292 		pF3d = new E3dObjFactory;
293 	}
294 }
295 
296 __EXPORT ScDrawLayer::~ScDrawLayer()
297 {
298 	Broadcast(SdrHint(HINT_MODELCLEARED));
299 
300 	// #116168#
301 	//Clear();
302 	ClearModel(sal_True);
303 
304 	delete pUndoGroup;
305 	if( !--nInst )
306 	{
307 		delete pFac, pFac = NULL;
308 		delete pF3d, pF3d = NULL;
309 	}
310 }
311 
312 void ScDrawLayer::UseHyphenator()
313 {
314 	if (!bHyphenatorSet)
315 	{
316 		com::sun::star::uno::Reference< com::sun::star::linguistic2::XHyphenator >
317 									xHyphenator = LinguMgr::GetHyphenator();
318 
319 		GetDrawOutliner().SetHyphenator( xHyphenator );
320 		GetHitTestOutliner().SetHyphenator( xHyphenator );
321 
322 		bHyphenatorSet = sal_True;
323 	}
324 }
325 
326 SdrPage* __EXPORT ScDrawLayer::AllocPage(FASTBOOL bMasterPage)
327 {
328 	//	don't create basic until it is needed
329 	StarBASIC* pBasic = NULL;
330     ScDrawPage* pPage = new ScDrawPage( *this, pBasic, sal::static_int_cast<sal_Bool>(bMasterPage) );
331 	return pPage;
332 }
333 
334 sal_Bool ScDrawLayer::HasObjects() const
335 {
336 	sal_Bool bFound = sal_False;
337 
338 	sal_uInt16 nCount = GetPageCount();
339 	for (sal_uInt16 i=0; i<nCount && !bFound; i++)
340 		if (GetPage(i)->GetObjCount())
341 			bFound = sal_True;
342 
343 	return bFound;
344 }
345 
346 void ScDrawLayer::UpdateBasic()
347 {
348 	//	don't create basic until it is needed
349 	//!	remove this method?
350 }
351 
352 SdrModel* __EXPORT ScDrawLayer::AllocModel() const
353 {
354 	//	#103849# Allocated model (for clipboard etc) must not have a pointer
355 	//	to the original model's document, pass NULL as document:
356 
357 	return new ScDrawLayer( NULL, aName );
358 }
359 
360 Window* __EXPORT ScDrawLayer::GetCurDocViewWin()
361 {
362 	DBG_ASSERT( pDoc, "ScDrawLayer::GetCurDocViewWin without document" );
363 	if ( !pDoc )
364 		return NULL;
365 
366 	SfxViewShell* pViewSh = SfxViewShell::Current();
367 	SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
368 
369 	if (pViewSh && pViewSh->GetObjectShell() == pObjSh)
370 		return pViewSh->GetWindow();
371 
372 	return NULL;
373 }
374 
375 sal_Bool ScDrawLayer::ScAddPage( SCTAB nTab )
376 {
377 	if (bDrawIsInUndo)
378         return sal_False;   // not inserted
379 
380 	ScDrawPage* pPage = (ScDrawPage*)AllocPage( sal_False );
381 	InsertPage(pPage, static_cast<sal_uInt16>(nTab));
382 	if (bRecording)
383 	        AddCalcUndo< SdrUndoNewPage >(*pPage);
384 
385     return sal_True;        // inserted
386 }
387 
388 void ScDrawLayer::ScRemovePage( SCTAB nTab )
389 {
390 	if (bDrawIsInUndo)
391 		return;
392 
393 	Broadcast( ScTabDeletedHint( nTab ) );
394 	if (bRecording)
395 	{
396 		SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
397         AddCalcUndo< SdrUndoDelPage >(*pPage);		// Undo-Action wird Owner der Page
398 		RemovePage( static_cast<sal_uInt16>(nTab) );							// nur austragen, nicht loeschen
399 	}
400 	else
401 		DeletePage( static_cast<sal_uInt16>(nTab) );							// einfach weg damit
402 }
403 
404 void ScDrawLayer::ScRenamePage( SCTAB nTab, const String& rNewName )
405 {
406 	ScDrawPage* pPage = (ScDrawPage*) GetPage(static_cast<sal_uInt16>(nTab));
407 	if (pPage)
408 		pPage->SetName(rNewName);
409 }
410 
411 void ScDrawLayer::ScMovePage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
412 {
413 	MovePage( nOldPos, nNewPos );
414 }
415 
416 void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos, sal_Bool bAlloc )
417 {
418 	//!	remove argument bAlloc (always sal_False)
419 
420 	if (bDrawIsInUndo)
421 		return;
422 
423 	SdrPage* pOldPage = GetPage(nOldPos);
424 	SdrPage* pNewPage = bAlloc ? AllocPage(sal_False) : GetPage(nNewPos);
425 
426 	// kopieren
427 
428 	if (pOldPage && pNewPage)
429 	{
430 		SdrObjListIter aIter( *pOldPage, IM_FLAT );
431 		SdrObject* pOldObject = aIter.Next();
432 		while (pOldObject)
433 		{
434             // #i112034# do not copy internal objects (detective) and note captions
435             if ( pOldObject->GetLayer() != SC_LAYER_INTERN && !IsNoteCaption( pOldObject ) )
436             {
437                 // #116235#
438                 SdrObject* pNewObject = pOldObject->Clone();
439                 //SdrObject* pNewObject = pOldObject->Clone( pNewPage, this );
440                 pNewObject->SetModel(this);
441                 pNewObject->SetPage(pNewPage);
442 
443                 pNewObject->NbcMove(Size(0,0));
444                 pNewPage->InsertObject( pNewObject );
445                 if (bRecording)
446 	                AddCalcUndo< SdrUndoInsertObj >( *pNewObject );
447             }
448 
449 			pOldObject = aIter.Next();
450 		}
451 	}
452 
453 	if (bAlloc)
454 		InsertPage(pNewPage, nNewPos);
455 }
456 
457 inline sal_Bool IsInBlock( const ScAddress& rPos, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2 )
458 {
459 	return rPos.Col() >= nCol1 && rPos.Col() <= nCol2 &&
460 		   rPos.Row() >= nRow1 && rPos.Row() <= nRow2;
461 }
462 
463 void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
464 								SCsCOL nDx,SCsROW nDy, bool bUpdateNoteCaptionPos )
465 {
466 	SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
467 	DBG_ASSERT(pPage,"Page nicht gefunden");
468 	if (!pPage)
469 		return;
470 
471 	sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
472 
473 	sal_uLong nCount = pPage->GetObjCount();
474 	for ( sal_uLong i = 0; i < nCount; i++ )
475 	{
476 		SdrObject* pObj = pPage->GetObj( i );
477 		ScDrawObjData* pData = GetObjDataTab( pObj, nTab );
478 		if( pData )
479 		{
480 			const ScAddress aOldStt = pData->maStart;
481 			const ScAddress aOldEnd = pData->maEnd;
482 			sal_Bool bChange = sal_False;
483 			if ( aOldStt.IsValid() && IsInBlock( aOldStt, nCol1,nRow1, nCol2,nRow2 ) )
484 			{
485                 pData->maStart.IncCol( nDx );
486 				pData->maStart.IncRow( nDy );
487 				bChange = sal_True;
488 			}
489 			if ( aOldEnd.IsValid() && IsInBlock( aOldEnd, nCol1,nRow1, nCol2,nRow2 ) )
490 			{
491 				pData->maEnd.IncCol( nDx );
492 				pData->maEnd.IncRow( nDy );
493 				bChange = sal_True;
494 			}
495 			if (bChange)
496 			{
497 				if ( pObj->ISA( SdrRectObj ) && pData->maStart.IsValid() && pData->maEnd.IsValid() )
498                     pData->maStart.PutInOrder( pData->maEnd );
499                 AddCalcUndo< ScUndoObjData >( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd );
500                 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
501 			}
502 		}
503 	}
504 }
505 
506 void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos )
507 {
508 	SdrPage* pPage = GetPage(nPageNo);
509 	if (pPage)
510 	{
511 		if ( rSize != pPage->GetSize() )
512 		{
513 			pPage->SetSize( rSize );
514 			Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) );	// SetWorkArea() an den Views
515 		}
516 
517 		// Detektivlinien umsetzen (an neue Hoehen/Breiten anpassen)
518 		//	auch wenn Groesse gleich geblieben ist
519 		//	(einzelne Zeilen/Spalten koennen geaendert sein)
520 
521 		sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
522 
523 		sal_uLong nCount = pPage->GetObjCount();
524 		for ( sal_uLong i = 0; i < nCount; i++ )
525 		{
526 			SdrObject* pObj = pPage->GetObj( i );
527 			ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
528 			if( pData )
529                 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
530 		}
531 	}
532 }
533 
534 void ScDrawLayer::RecalcPos( SdrObject* pObj, const ScDrawObjData& rData, bool bNegativePage, bool bUpdateNoteCaptionPos )
535 {
536 	DBG_ASSERT( pDoc, "ScDrawLayer::RecalcPos - missing document" );
537 	if( !pDoc )
538 		return;
539 
540 	if( rData.mbNote )
541 	{
542         DBG_ASSERT( rData.maStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
543         /*  #i109372# On insert/remove rows/columns/cells: Updating the caption
544             position must not be done, if the cell containing the note has not
545             been moved yet in the document. The calling code now passes an
546             additional boolean stating if the cells are already moved. */
547         if( bUpdateNoteCaptionPos )
548             /*  When inside an undo action, there may be pending note captions
549                 where cell note is already deleted (thus document cannot find
550                 the note object anymore). The caption will be deleted later
551                 with drawing undo. */
552             if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
553                 pNote->UpdateCaptionPos( rData.maStart );
554         return;
555 	}
556 
557     bool bValid1 = rData.maStart.IsValid();
558     SCCOL nCol1 = rData.maStart.Col();
559 	SCROW nRow1 = rData.maStart.Row();
560 	SCTAB nTab1 = rData.maStart.Tab();
561     bool bValid2 = rData.maEnd.IsValid();
562     SCCOL nCol2 = rData.maEnd.Col();
563 	SCROW nRow2 = rData.maEnd.Row();
564 	SCTAB nTab2 = rData.maEnd.Tab();
565 
566     // validation circle
567 	bool bCircle = pObj->ISA( SdrCircObj );
568     // detective arrow
569 	bool bArrow = pObj->IsPolyObj() && (pObj->GetPointCount() == 2);
570 
571 	if( bCircle )
572 	{
573 		Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
574 		TwipsToMM( aPos.X() );
575 		TwipsToMM( aPos.Y() );
576 
577 		//	Berechnung und Werte wie in detfunc.cxx
578 
579 		Size aSize( (long)(pDoc->GetColWidth( nCol1, nTab1 ) * HMM_PER_TWIPS),
580 					(long)(pDoc->GetRowHeight( nRow1, nTab1 ) * HMM_PER_TWIPS) );
581 		Rectangle aRect( aPos, aSize );
582 		aRect.Left()	-= 250;
583 		aRect.Right()	+= 250;
584 		aRect.Top()		-= 70;
585 		aRect.Bottom()	+= 70;
586 		if ( bNegativePage )
587 			MirrorRectRTL( aRect );
588 
589 		if ( pObj->GetLogicRect() != aRect )
590 		{
591 			if (bRecording)
592 		                AddCalcUndo<SdrUndoGeoObj>( *pObj );
593 			pObj->SetLogicRect(aRect);
594 		}
595 	}
596 	else if( bArrow )
597 	{
598 		//!	nicht mehrere Undos fuer ein Objekt erzeugen (hinteres kann dann weggelassen werden)
599 
600         SCCOL nLastCol;
601         SCROW nLastRow;
602 		if( bValid1 )
603 		{
604 			Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
605             if (!pDoc->ColHidden(nCol1, nTab1, nLastCol))
606 				aPos.X() += pDoc->GetColWidth( nCol1, nTab1 ) / 4;
607             if (!pDoc->RowHidden(nRow1, nTab1, nLastRow))
608 				aPos.Y() += pDoc->GetRowHeight( nRow1, nTab1 ) / 2;
609 			TwipsToMM( aPos.X() );
610 			TwipsToMM( aPos.Y() );
611 			Point aStartPos = aPos;
612 			if ( bNegativePage )
613 				aStartPos.X() = -aStartPos.X();		// don't modify aPos - used below
614 			if ( pObj->GetPoint( 0 ) != aStartPos )
615 			{
616 				if (bRecording)
617 		                    AddCalcUndo< SdrUndoGeoObj> ( *pObj );
618 				pObj->SetPoint( aStartPos, 0 );
619 			}
620 
621 			if( !bValid2 )
622 			{
623 				Point aEndPos( aPos.X() + DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
624 				if (aEndPos.Y() < 0)
625 					aEndPos.Y() += (2 * DET_ARROW_OFFSET);
626 				if ( bNegativePage )
627 					aEndPos.X() = -aEndPos.X();
628 				if ( pObj->GetPoint( 1 ) != aEndPos )
629 				{
630 					if (bRecording)
631 		                        AddCalcUndo< SdrUndoGeoObj >( *pObj );
632 					pObj->SetPoint( aEndPos, 1 );
633 				}
634 			}
635 		}
636 		if( bValid2 )
637 		{
638 			Point aPos( pDoc->GetColOffset( nCol2, nTab2 ), pDoc->GetRowOffset( nRow2, nTab2 ) );
639             if (!pDoc->ColHidden(nCol2, nTab2, nLastCol))
640 				aPos.X() += pDoc->GetColWidth( nCol2, nTab2 ) / 4;
641             if (!pDoc->RowHidden(nRow2, nTab2, nLastRow))
642 				aPos.Y() += pDoc->GetRowHeight( nRow2, nTab2 ) / 2;
643 			TwipsToMM( aPos.X() );
644 			TwipsToMM( aPos.Y() );
645 			Point aEndPos = aPos;
646 			if ( bNegativePage )
647 				aEndPos.X() = -aEndPos.X();			// don't modify aPos - used below
648 			if ( pObj->GetPoint( 1 ) != aEndPos )
649 			{
650 				if (bRecording)
651 		                    AddCalcUndo< SdrUndoGeoObj> ( *pObj  );
652 				pObj->SetPoint( aEndPos, 1 );
653 			}
654 
655 			if( !bValid1 )
656 			{
657 				Point aStartPos( aPos.X() - DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
658 				if (aStartPos.X() < 0)
659 					aStartPos.X() += (2 * DET_ARROW_OFFSET);
660 				if (aStartPos.Y() < 0)
661 					aStartPos.Y() += (2 * DET_ARROW_OFFSET);
662 				if ( bNegativePage )
663 					aStartPos.X() = -aStartPos.X();
664 				if ( pObj->GetPoint( 0 ) != aStartPos )
665 				{
666 					if (bRecording)
667 			                        AddCalcUndo< SdrUndoGeoObj >( *pObj );
668 					pObj->SetPoint( aStartPos, 0 );
669 				}
670 			}
671 		}
672 	}
673 	else								// Referenz-Rahmen
674 	{
675 		DBG_ASSERT( bValid1, "ScDrawLayer::RecalcPos - invalid start position" );
676 		Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
677 		TwipsToMM( aPos.X() );
678 		TwipsToMM( aPos.Y() );
679 
680 		if( bValid2 )
681 		{
682 			Point aEnd( pDoc->GetColOffset( nCol2 + 1, nTab2 ), pDoc->GetRowOffset( nRow2 + 1, nTab2 ) );
683 			TwipsToMM( aEnd.X() );
684 			TwipsToMM( aEnd.Y() );
685 
686 			Rectangle aNew( aPos, aEnd );
687 			if ( bNegativePage )
688 				MirrorRectRTL( aNew );
689 			if ( pObj->GetLogicRect() != aNew )
690 			{
691 				if (bRecording)
692 		                    AddCalcUndo< SdrUndoGeoObj >( *pObj );
693 				pObj->SetLogicRect(aNew);
694 			}
695 		}
696 		else
697 		{
698 			if ( bNegativePage )
699 				aPos.X() = -aPos.X();
700 			if ( pObj->GetRelativePos() != aPos )
701 			{
702 				if (bRecording)
703 		                    AddCalcUndo< SdrUndoGeoObj >( *pObj );
704 				pObj->SetRelativePos( aPos );
705 			}
706 		}
707 	}
708 }
709 
710 sal_Bool ScDrawLayer::GetPrintArea( ScRange& rRange, sal_Bool bSetHor, sal_Bool bSetVer ) const
711 {
712 	DBG_ASSERT( pDoc, "ScDrawLayer::GetPrintArea without document" );
713 	if ( !pDoc )
714 		return sal_False;
715 
716 	SCTAB nTab = rRange.aStart.Tab();
717 	DBG_ASSERT( rRange.aEnd.Tab() == nTab, "GetPrintArea: Tab unterschiedlich" );
718 
719 	sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
720 
721 	sal_Bool bAny = sal_False;
722 	long nEndX = 0;
723 	long nEndY = 0;
724 	long nStartX = LONG_MAX;
725 	long nStartY = LONG_MAX;
726 
727 	// Grenzen ausrechnen
728 
729 	if (!bSetHor)
730 	{
731 		nStartX = 0;
732 		SCCOL nStartCol = rRange.aStart.Col();
733 	        SCCOL i;
734 		for (i=0; i<nStartCol; i++)
735 			nStartX +=pDoc->GetColWidth(i,nTab);
736 		nEndX = nStartX;
737 		SCCOL nEndCol = rRange.aEnd.Col();
738 		for (i=nStartCol; i<=nEndCol; i++)
739 			nEndX += pDoc->GetColWidth(i,nTab);
740 		nStartX = (long)(nStartX * HMM_PER_TWIPS);
741 		nEndX   = (long)(nEndX   * HMM_PER_TWIPS);
742 	}
743 	if (!bSetVer)
744 	{
745 		nStartY = pDoc->GetRowHeight( 0, rRange.aStart.Row()-1, nTab);
746         nEndY = nStartY + pDoc->GetRowHeight( rRange.aStart.Row(),
747                 rRange.aEnd.Row(), nTab);
748 		nStartY = (long)(nStartY * HMM_PER_TWIPS);
749 		nEndY   = (long)(nEndY   * HMM_PER_TWIPS);
750 	}
751 
752 	if ( bNegativePage )
753 	{
754 		nStartX = -nStartX;		// positions are negative, swap start/end so the same comparisons work
755 		nEndX   = -nEndX;
756 		::std::swap( nStartX, nEndX );
757 	}
758 
759 	const SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
760 	DBG_ASSERT(pPage,"Page nicht gefunden");
761 	if (pPage)
762 	{
763 		SdrObjListIter aIter( *pPage, IM_FLAT );
764 		SdrObject* pObject = aIter.Next();
765 		while (pObject)
766 		{
767 							//! Flags (ausgeblendet?) testen
768 
769 			Rectangle aObjRect = pObject->GetCurrentBoundRect();
770 			sal_Bool bFit = sal_True;
771 			if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
772 				bFit = sal_False;
773 			if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
774 				bFit = sal_False;
775             // #i104716# don't include hidden note objects
776             if ( bFit && pObject->GetLayer() != SC_LAYER_HIDDEN )
777 			{
778 				if (bSetHor)
779 				{
780 					if (aObjRect.Left() < nStartX) nStartX = aObjRect.Left();
781 					if (aObjRect.Right()  > nEndX) nEndX = aObjRect.Right();
782 				}
783 				if (bSetVer)
784 				{
785 					if (aObjRect.Top()  < nStartY) nStartY = aObjRect.Top();
786 					if (aObjRect.Bottom() > nEndY) nEndY = aObjRect.Bottom();
787 				}
788 				bAny = sal_True;
789 			}
790 
791 			pObject = aIter.Next();
792 		}
793 	}
794 
795 	if ( bNegativePage )
796 	{
797 		nStartX = -nStartX;		// reverse transformation, so the same cell address calculation works
798 		nEndX   = -nEndX;
799 		::std::swap( nStartX, nEndX );
800 	}
801 
802 	if (bAny)
803 	{
804 		DBG_ASSERT( nStartX<=nEndX && nStartY<=nEndY, "Start/End falsch in ScDrawLayer::GetPrintArea" );
805 
806 		if (bSetHor)
807 		{
808 			nStartX = (long) (nStartX / HMM_PER_TWIPS);
809 			nEndX = (long) (nEndX / HMM_PER_TWIPS);
810 			long nWidth;
811 	        SCCOL i;
812 
813 			nWidth = 0;
814 			for (i=0; i<=MAXCOL && nWidth<=nStartX; i++)
815 				nWidth += pDoc->GetColWidth(i,nTab);
816 			rRange.aStart.SetCol( i>0 ? (i-1) : 0 );
817 
818 			nWidth = 0;
819 			for (i=0; i<=MAXCOL && nWidth<=nEndX; i++)			//! bei Start anfangen
820 				nWidth += pDoc->GetColWidth(i,nTab);
821 			rRange.aEnd.SetCol( i>0 ? (i-1) : 0 );
822 		}
823 
824 		if (bSetVer)
825 		{
826 			nStartY = (long) (nStartY / HMM_PER_TWIPS);
827 			nEndY = (long) (nEndY / HMM_PER_TWIPS);
828             SCROW nRow = pDoc->GetRowForHeight( nTab, nStartY);
829 			rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
830             nRow = pDoc->GetRowForHeight( nTab, nEndY);
831 			rRange.aEnd.SetRow( nRow == MAXROW ? MAXROW :
832                     (nRow>0 ? (nRow-1) : 0));
833 		}
834 	}
835 	else
836 	{
837 		if (bSetHor)
838 		{
839 			rRange.aStart.SetCol(0);
840 			rRange.aEnd.SetCol(0);
841 		}
842 		if (bSetVer)
843 		{
844 			rRange.aStart.SetRow(0);
845 			rRange.aEnd.SetRow(0);
846 		}
847 	}
848 	return bAny;
849 }
850 
851 void ScDrawLayer::AddCalcUndo( SdrUndoAction* pUndo )
852 {
853 	if (bRecording)
854 	{
855 		if (!pUndoGroup)
856 			pUndoGroup = new SdrUndoGroup(*this);
857 
858 		pUndoGroup->AddAction( pUndo );
859 	}
860 	else
861 		delete pUndo;
862 }
863 
864 void ScDrawLayer::BeginCalcUndo()
865 {
866 //! DBG_ASSERT( !bRecording, "BeginCalcUndo ohne GetCalcUndo" );
867 
868 	DELETEZ(pUndoGroup);
869 	bRecording = sal_True;
870 }
871 
872 SdrUndoGroup* ScDrawLayer::GetCalcUndo()
873 {
874 //! DBG_ASSERT( bRecording, "GetCalcUndo ohne BeginCalcUndo" );
875 
876 	SdrUndoGroup* pRet = pUndoGroup;
877 	pUndoGroup = NULL;
878 	bRecording = sal_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 
2031 void ScDrawLayer::SetGlobalDrawPersist(SfxObjectShell* pPersist)			// static
2032 {
2033 	DBG_ASSERT(!pGlobalDrawPersist,"SetGlobalDrawPersist mehrfach");
2034 	pGlobalDrawPersist = pPersist;
2035 }
2036 
2037 void __EXPORT ScDrawLayer::SetChanged( sal_Bool bFlg /* = sal_True */ )
2038 {
2039 	if ( bFlg && pDoc )
2040 		pDoc->SetChartListenerCollectionNeedsUpdate( sal_True );
2041 	FmFormModel::SetChanged( bFlg );
2042 }
2043 
2044 SvStream* __EXPORT ScDrawLayer::GetDocumentStream(SdrDocumentStreamInfo& rStreamInfo) const
2045 {
2046 	DBG_ASSERT( pDoc, "ScDrawLayer::GetDocumentStream without document" );
2047 	if ( !pDoc )
2048 		return NULL;
2049 
2050 	uno::Reference< embed::XStorage > xStorage = pDoc->GetDocumentShell() ?
2051 														pDoc->GetDocumentShell()->GetStorage() :
2052 														NULL;
2053 	SvStream*	pRet = NULL;
2054 
2055 	if( xStorage.is() )
2056 	{
2057 		if( rStreamInfo.maUserData.Len() &&
2058 			( rStreamInfo.maUserData.GetToken( 0, ':' ) ==
2059 			  String( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.Package" ) ) ) )
2060 		{
2061 			const String aPicturePath( rStreamInfo.maUserData.GetToken( 1, ':' ) );
2062 
2063 			// graphic from picture stream in picture storage in XML package
2064 			if( aPicturePath.GetTokenCount( '/' ) == 2 )
2065 			{
2066 				const String aPictureStreamName( aPicturePath.GetToken( 1, '/' ) );
2067 				const String aPictureStorageName( aPicturePath.GetToken( 0, '/' ) );
2068 
2069 				try {
2070 					if ( xStorage->isStorageElement( aPictureStorageName ) )
2071 					{
2072 						uno::Reference< embed::XStorage > xPictureStorage =
2073                                     xStorage->openStorageElement( aPictureStorageName, embed::ElementModes::READ );
2074 
2075 						if( xPictureStorage.is() &&
2076 							xPictureStorage->isStreamElement( aPictureStreamName ) )
2077 						{
2078 							uno::Reference< io::XStream > xStream =
2079                                 xPictureStorage->openStreamElement( aPictureStreamName, embed::ElementModes::READ );
2080 							if ( xStream.is() )
2081 								pRet = ::utl::UcbStreamHelper::CreateStream( xStream );
2082 						}
2083 					}
2084 				}
2085 				catch( uno::Exception& )
2086 				{
2087 					// TODO: error handling
2088 				}
2089 			}
2090 		}
2091 		// the following code seems to be related to binary format
2092 //REMOVE			else
2093 //REMOVE			{
2094 //REMOVE				pRet = pStor->OpenStream( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(STRING_SCSTREAM)),
2095 //REMOVE										  STREAM_READ | STREAM_WRITE | STREAM_TRUNC );
2096 //REMOVE
2097 //REMOVE				if( pRet )
2098 //REMOVE				{
2099 //REMOVE					pRet->SetVersion( pStor->GetVersion() );
2100 //REMOVE					pRet->SetKey( pStor->GetKey() );
2101 //REMOVE				}
2102 //REMOVE			}
2103 
2104 		rStreamInfo.mbDeleteAfterUse = ( pRet != NULL );
2105 	}
2106 
2107 	return pRet;
2108 }
2109 
2110 //REMOVE	void ScDrawLayer::ReleasePictureStorage()
2111 //REMOVE	{
2112 //REMOVE		xPictureStorage.Clear();
2113 //REMOVE	}
2114 
2115 SdrLayerID __EXPORT ScDrawLayer::GetControlExportLayerId( const SdrObject & ) const
2116 {
2117 	//	Layer fuer Export von Form-Controls in Versionen vor 5.0 - immer SC_LAYER_FRONT
2118 	return SC_LAYER_FRONT;
2119 }
2120 
2121 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > ScDrawLayer::createUnoModel()
2122 {
2123 	::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet;
2124 	if( pDoc && pDoc->GetDocumentShell() )
2125 		xRet = pDoc->GetDocumentShell()->GetModel();
2126 
2127 	return xRet;
2128 }
2129