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