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