xref: /trunk/main/sc/source/core/data/drwlayer.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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