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