xref: /AOO41X/main/sc/source/core/data/drwlayer.cxx (revision 5443dcac4da55ae8863c5c80e8907938642a7f1b)
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()
864 {
865 //! DBG_ASSERT( !bRecording, "BeginCalcUndo ohne GetCalcUndo" );
866 
867     DELETEZ(pUndoGroup);
868     bRecording = sal_True;
869 }
870 
871 SdrUndoGroup* ScDrawLayer::GetCalcUndo()
872 {
873 //! DBG_ASSERT( bRecording, "GetCalcUndo ohne BeginCalcUndo" );
874 
875     SdrUndoGroup* pRet = pUndoGroup;
876     pUndoGroup = NULL;
877     bRecording = sal_False;
878     return pRet;
879 }
880 
881 //  MoveAreaTwips: all measures are kept in twips
882 void ScDrawLayer::MoveAreaTwips( SCTAB nTab, const Rectangle& rArea,
883         const Point& rMove, const Point& rTopLeft )
884 {
885     if (!rMove.X() && !rMove.Y())
886         return;                                     // nix
887 
888     SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
889     DBG_ASSERT(pPage,"Page nicht gefunden");
890     if (!pPage)
891         return;
892 
893     sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
894 
895     // fuer Shrinking!
896     Rectangle aNew( rArea );
897     sal_Bool bShrink = sal_False;
898     if ( rMove.X() < 0 || rMove.Y() < 0 )       // verkleinern
899     {
900         if ( rTopLeft != rArea.TopLeft() )      // sind gleich beim Verschieben von Zellen
901         {
902             bShrink = sal_True;
903             aNew.Left() = rTopLeft.X();
904             aNew.Top() = rTopLeft.Y();
905         }
906     }
907     SdrObjListIter aIter( *pPage, IM_FLAT );
908     SdrObject* pObject = aIter.Next();
909     while (pObject)
910     {
911         if( GetAnchor( pObject ) == SCA_CELL )
912         {
913             if ( GetObjData( pObject ) )                    // Detektiv-Pfeil ?
914             {
915                 // hier nichts
916             }
917             else if ( pObject->ISA( SdrEdgeObj ) )          // Verbinder?
918             {
919                 //  hier auch nichts
920                 //! nicht verbundene Enden wie bei Linien (s.u.) behandeln?
921             }
922             else if ( pObject->IsPolyObj() && pObject->GetPointCount()==2 )
923             {
924                 for (sal_uInt16 i=0; i<2; i++)
925                 {
926                     sal_Bool bMoved = sal_False;
927                     Point aPoint = pObject->GetPoint(i);
928                     lcl_ReverseTwipsToMM( aPoint );
929                     if (rArea.IsInside(aPoint))
930                     {
931                         aPoint += rMove; bMoved = sal_True;
932                     }
933                     else if (bShrink && aNew.IsInside(aPoint))
934                     {
935                         //  Punkt ist in betroffener Zelle - Test auf geloeschten Bereich
936                         if ( rMove.X() && aPoint.X() >= rArea.Left() + rMove.X() )
937                         {
938                             aPoint.X() = rArea.Left() + rMove.X() - SHRINK_DIST_TWIPS;
939                             if ( aPoint.X() < 0 ) aPoint.X() = 0;
940                             bMoved = sal_True;
941                         }
942                         if ( rMove.Y() && aPoint.Y() >= rArea.Top() + rMove.Y() )
943                         {
944                             aPoint.Y() = rArea.Top() + rMove.Y() - SHRINK_DIST_TWIPS;
945                             if ( aPoint.Y() < 0 ) aPoint.Y() = 0;
946                             bMoved = sal_True;
947                         }
948                     }
949                     if( bMoved )
950                     {
951                                     AddCalcUndo< SdrUndoGeoObj >( *pObject );
952                         lcl_TwipsToMM( aPoint );
953                         pObject->SetPoint( aPoint, i );
954                     }
955                 }
956             }
957             else
958             {
959                 Rectangle aObjRect = pObject->GetLogicRect();
960                 // aOldMMPos: not converted, millimeters
961                 Point aOldMMPos = bNegativePage ? aObjRect.TopRight() : aObjRect.TopLeft();
962                 lcl_ReverseTwipsToMM( aObjRect );
963                 Point aTopLeft = bNegativePage ? aObjRect.TopRight() : aObjRect.TopLeft();  // logical left
964                 Size aMoveSize;
965                 sal_Bool bDoMove = sal_False;
966                 if (rArea.IsInside(aTopLeft))
967                 {
968                     aMoveSize = Size(rMove.X(),rMove.Y());
969                     bDoMove = sal_True;
970                 }
971                 else if (bShrink && aNew.IsInside(aTopLeft))
972                 {
973                     //  Position ist in betroffener Zelle - Test auf geloeschten Bereich
974                     if ( rMove.X() && aTopLeft.X() >= rArea.Left() + rMove.X() )
975                     {
976                         aMoveSize.Width() = rArea.Left() + rMove.X() - SHRINK_DIST - aTopLeft.X();
977                         bDoMove = sal_True;
978                     }
979                     if ( rMove.Y() && aTopLeft.Y() >= rArea.Top() + rMove.Y() )
980                     {
981                         aMoveSize.Height() = rArea.Top() + rMove.Y() - SHRINK_DIST - aTopLeft.Y();
982                         bDoMove = sal_True;
983                     }
984                 }
985                 if ( bDoMove )
986                 {
987                     if ( bNegativePage )
988                     {
989                         if ( aTopLeft.X() + aMoveSize.Width() > 0 )
990                             aMoveSize.Width() = -aTopLeft.X();
991                     }
992                     else
993                     {
994                         if ( aTopLeft.X() + aMoveSize.Width() < 0 )
995                             aMoveSize.Width() = -aTopLeft.X();
996                     }
997                     if ( aTopLeft.Y() + aMoveSize.Height() < 0 )
998                         aMoveSize.Height() = -aTopLeft.Y();
999 
1000                     //  get corresponding move size in millimeters:
1001                     Point aNewPos( aTopLeft.X() + aMoveSize.Width(), aTopLeft.Y() + aMoveSize.Height() );
1002                     lcl_TwipsToMM( aNewPos );
1003                     aMoveSize = Size( aNewPos.X() - aOldMMPos.X(), aNewPos.Y() - aOldMMPos.Y() );   // millimeters
1004 
1005                                 AddCalcUndo< SdrUndoMoveObj >( *pObject, aMoveSize );
1006                     pObject->Move( aMoveSize );
1007                 }
1008                 else if ( rArea.IsInside( bNegativePage ? aObjRect.BottomLeft() : aObjRect.BottomRight() ) &&
1009                             !pObject->IsResizeProtect() )
1010                 {
1011                     //  geschuetzte Groessen werden nicht veraendert
1012                     //  (Positionen schon, weil sie ja an der Zelle "verankert" sind)
1013                             AddCalcUndo< SdrUndoGeoObj >( *pObject );
1014                     long nOldSizeX = aObjRect.Right() - aObjRect.Left() + 1;
1015                     long nOldSizeY = aObjRect.Bottom() - aObjRect.Top() + 1;
1016                     long nLogMoveX = rMove.X() * ( bNegativePage ? -1 : 1 );    // logical direction
1017                     pObject->Resize( aOldMMPos, Fraction( nOldSizeX+nLogMoveX, nOldSizeX ),
1018                                                 Fraction( nOldSizeY+rMove.Y(), nOldSizeY ) );
1019                 }
1020             }
1021         }
1022         pObject = aIter.Next();
1023     }
1024 }
1025 
1026 void ScDrawLayer::MoveArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
1027                             SCsCOL nDx,SCsROW nDy, sal_Bool bInsDel, bool bUpdateNoteCaptionPos )
1028 {
1029     DBG_ASSERT( pDoc, "ScDrawLayer::MoveArea without document" );
1030     if ( !pDoc )
1031         return;
1032 
1033     if (!bAdjustEnabled)
1034         return;
1035 
1036     sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1037 
1038     Rectangle aRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1039     lcl_ReverseTwipsToMM( aRect );
1040     //! use twips directly?
1041 
1042     Point aMove;
1043 
1044     if (nDx > 0)
1045         for (SCsCOL s=0; s<nDx; s++)
1046             aMove.X() += pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
1047     else
1048         for (SCsCOL s=-1; s>=nDx; s--)
1049             aMove.X() -= pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
1050     if (nDy > 0)
1051         aMove.Y() += pDoc->GetRowHeight( nRow1, nRow1+nDy-1, nTab);
1052     else
1053         aMove.Y() -= pDoc->GetRowHeight( nRow1+nDy, nRow1-1, nTab);
1054 
1055     if ( bNegativePage )
1056         aMove.X() = -aMove.X();
1057 
1058     Point aTopLeft = aRect.TopLeft();       // Anfang beim Verkleinern
1059     if (bInsDel)
1060     {
1061         if ( aMove.X() != 0 && nDx < 0 )    // nDx counts cells, sign is independent of RTL
1062             aTopLeft.X() += aMove.X();
1063         if ( aMove.Y() < 0 )
1064             aTopLeft.Y() += aMove.Y();
1065     }
1066 
1067     //  drawing objects are now directly included in cut&paste
1068     //  -> only update references when inserting/deleting (or changing widths or heights)
1069     if ( bInsDel )
1070         MoveAreaTwips( nTab, aRect, aMove, aTopLeft );
1071 
1072         //
1073         //      Detektiv-Pfeile: Zellpositionen anpassen
1074         //
1075 
1076     MoveCells( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy, bUpdateNoteCaptionPos );
1077 }
1078 
1079 void ScDrawLayer::WidthChanged( SCTAB nTab, SCCOL nCol, long nDifTwips )
1080 {
1081     DBG_ASSERT( pDoc, "ScDrawLayer::WidthChanged without document" );
1082     if ( !pDoc )
1083         return;
1084 
1085     if (!bAdjustEnabled)
1086         return;
1087 
1088     Rectangle aRect;
1089     Point aTopLeft;
1090 
1091     for (SCCOL i=0; i<nCol; i++)
1092         aRect.Left() += pDoc->GetColWidth(i,nTab);
1093     aTopLeft.X() = aRect.Left();
1094     aRect.Left() += pDoc->GetColWidth(nCol,nTab);
1095 
1096     aRect.Right() = MAXMM;
1097     aRect.Top() = 0;
1098     aRect.Bottom() = MAXMM;
1099 
1100     //! aTopLeft ist falsch, wenn mehrere Spalten auf einmal ausgeblendet werden
1101 
1102     sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1103     if ( bNegativePage )
1104     {
1105         MirrorRectRTL( aRect );
1106         aTopLeft.X() = -aTopLeft.X();
1107         nDifTwips = -nDifTwips;
1108     }
1109 
1110     MoveAreaTwips( nTab, aRect, Point( nDifTwips,0 ), aTopLeft );
1111 }
1112 
1113 void ScDrawLayer::HeightChanged( SCTAB nTab, SCROW nRow, long nDifTwips )
1114 {
1115     DBG_ASSERT( pDoc, "ScDrawLayer::HeightChanged without document" );
1116     if ( !pDoc )
1117         return;
1118 
1119     if (!bAdjustEnabled)
1120         return;
1121 
1122     SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1123     DBG_ASSERT(pPage,"Page not found");
1124     if (!pPage)
1125         return;
1126 
1127     // for an empty page, there's no need to calculate the row heights
1128     if (!pPage->GetObjCount())
1129         return;
1130 
1131     Rectangle aRect;
1132     Point aTopLeft;
1133 
1134     aRect.Top() += pDoc->GetRowHeight( 0, nRow-1, nTab);
1135     aTopLeft.Y() = aRect.Top();
1136     aRect.Top() += pDoc->GetRowHeight(nRow, nTab);
1137 
1138     aRect.Bottom() = MAXMM;
1139     aRect.Left() = 0;
1140     aRect.Right() = MAXMM;
1141 
1142     //! aTopLeft ist falsch, wenn mehrere Zeilen auf einmal ausgeblendet werden
1143 
1144     sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1145     if ( bNegativePage )
1146     {
1147         MirrorRectRTL( aRect );
1148         aTopLeft.X() = -aTopLeft.X();
1149     }
1150 
1151     MoveAreaTwips( nTab, aRect, Point( 0,nDifTwips ), aTopLeft );
1152 }
1153 
1154 sal_Bool ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow, bool bIncludeNotes )
1155 {
1156     DBG_ASSERT( pDoc, "ScDrawLayer::HasObjectsInRows without document" );
1157     if ( !pDoc )
1158         return sal_False;
1159 
1160     SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1161     DBG_ASSERT(pPage,"Page not found");
1162     if (!pPage)
1163         return sal_False;
1164 
1165     // for an empty page, there's no need to calculate the row heights
1166     if (!pPage->GetObjCount())
1167         return sal_False;
1168 
1169     Rectangle aTestRect;
1170 
1171     aTestRect.Top() += pDoc->GetRowHeight( 0, nStartRow-1, nTab);
1172 
1173     if (nEndRow==MAXROW)
1174         aTestRect.Bottom() = MAXMM;
1175     else
1176     {
1177         aTestRect.Bottom() = aTestRect.Top();
1178         aTestRect.Bottom() += pDoc->GetRowHeight( nStartRow, nEndRow, nTab);
1179         TwipsToMM( aTestRect.Bottom() );
1180     }
1181 
1182     TwipsToMM( aTestRect.Top() );
1183 
1184     aTestRect.Left()  = 0;
1185     aTestRect.Right() = MAXMM;
1186 
1187     sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1188     if ( bNegativePage )
1189         MirrorRectRTL( aTestRect );
1190 
1191     sal_Bool bFound = sal_False;
1192 
1193     Rectangle aObjRect;
1194     SdrObjListIter aIter( *pPage );
1195     SdrObject* pObject = aIter.Next();
1196     while ( pObject && !bFound )
1197     {
1198         aObjRect = pObject->GetSnapRect();  //! GetLogicRect ?
1199         // #i116164# note captions are handled separately, don't have to be included for each single row height change
1200         if ( (aTestRect.IsInside(aObjRect.TopLeft()) || aTestRect.IsInside(aObjRect.BottomLeft())) &&
1201              (bIncludeNotes || !IsNoteCaption(pObject)) )
1202             bFound = sal_True;
1203 
1204         pObject = aIter.Next();
1205     }
1206 
1207     return bFound;
1208 }
1209 
1210 #if 0
1211 void ScDrawLayer::DeleteObjects( SCTAB nTab )
1212 {
1213     SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1214     DBG_ASSERT(pPage,"Page ?");
1215     if (!pPage)
1216         return;
1217 
1218     pPage->RecalcObjOrdNums();
1219 
1220     long    nDelCount = 0;
1221     sal_uLong   nObjCount = pPage->GetObjCount();
1222     if (nObjCount)
1223     {
1224         SdrObject** ppObj = new SdrObject*[nObjCount];
1225 
1226         SdrObjListIter aIter( *pPage, IM_FLAT );
1227         SdrObject* pObject = aIter.Next();
1228         while (pObject)
1229         {
1230             //  alle loeschen
1231             ppObj[nDelCount++] = pObject;
1232             pObject = aIter.Next();
1233         }
1234 
1235         long i;
1236         if (bRecording)
1237             for (i=1; i<=nDelCount; i++)
1238                         AddCalcUndo< SdrUndoRemoveObj >( *ppObj[nDelCount-i] );
1239 
1240         for (i=1; i<=nDelCount; i++)
1241             pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1242 
1243         delete[] ppObj;
1244     }
1245 }
1246 #endif
1247 
1248 void ScDrawLayer::DeleteObjectsInArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1,
1249                                             SCCOL nCol2,SCROW nRow2 )
1250 {
1251     DBG_ASSERT( pDoc, "ScDrawLayer::DeleteObjectsInArea without document" );
1252     if ( !pDoc )
1253         return;
1254 
1255     SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1256     DBG_ASSERT(pPage,"Page ?");
1257     if (!pPage)
1258         return;
1259 
1260     pPage->RecalcObjOrdNums();
1261 
1262     long    nDelCount = 0;
1263     sal_uLong   nObjCount = pPage->GetObjCount();
1264     if (nObjCount)
1265     {
1266         Rectangle aDelRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1267 
1268         SdrObject** ppObj = new SdrObject*[nObjCount];
1269 
1270         SdrObjListIter aIter( *pPage, IM_FLAT );
1271         SdrObject* pObject = aIter.Next();
1272         while (pObject)
1273         {
1274             // do not delete note caption, they are always handled by the cell note
1275             // TODO: detective objects are still deleted, is this desired?
1276             if (!IsNoteCaption( pObject ))
1277             {
1278                 Rectangle aObjRect = pObject->GetCurrentBoundRect();
1279                 if ( aDelRect.IsInside( aObjRect ) )
1280                     ppObj[nDelCount++] = pObject;
1281             }
1282 
1283             pObject = aIter.Next();
1284         }
1285 
1286         long i;
1287         if (bRecording)
1288             for (i=1; i<=nDelCount; i++)
1289                         AddCalcUndo< SdrUndoRemoveObj >( *ppObj[nDelCount-i] );
1290 
1291         for (i=1; i<=nDelCount; i++)
1292             pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1293 
1294         delete[] ppObj;
1295     }
1296 }
1297 
1298 void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
1299 {
1300     DBG_ASSERT( pDoc, "ScDrawLayer::DeleteObjectsInSelection without document" );
1301     if ( !pDoc )
1302         return;
1303 
1304     if ( !rMark.IsMultiMarked() )
1305         return;
1306 
1307     ScRange aMarkRange;
1308     rMark.GetMultiMarkArea( aMarkRange );
1309 
1310     SCTAB nTabCount = pDoc->GetTableCount();
1311     for (SCTAB nTab=0; nTab<=nTabCount; nTab++)
1312         if ( rMark.GetTableSelect( nTab ) )
1313         {
1314             SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1315             if (pPage)
1316             {
1317                 pPage->RecalcObjOrdNums();
1318                 long    nDelCount = 0;
1319                 sal_uLong   nObjCount = pPage->GetObjCount();
1320                 if (nObjCount)
1321                 {
1322                     //  Rechteck um die ganze Selektion
1323                     Rectangle aMarkBound = pDoc->GetMMRect(
1324                                 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
1325                                 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab );
1326 
1327                     SdrObject** ppObj = new SdrObject*[nObjCount];
1328 
1329                     SdrObjListIter aIter( *pPage, IM_FLAT );
1330                     SdrObject* pObject = aIter.Next();
1331                     while (pObject)
1332                     {
1333                         // do not delete note caption, they are always handled by the cell note
1334                         // TODO: detective objects are still deleted, is this desired?
1335                         if (!IsNoteCaption( pObject ))
1336                         {
1337                             Rectangle aObjRect = pObject->GetCurrentBoundRect();
1338                             if ( aMarkBound.IsInside( aObjRect ) )
1339                             {
1340                                 ScRange aRange = pDoc->GetRange( nTab, aObjRect );
1341                                 if (rMark.IsAllMarked(aRange))
1342                                     ppObj[nDelCount++] = pObject;
1343                             }
1344                         }
1345 
1346                         pObject = aIter.Next();
1347                     }
1348 
1349                     //  Objekte loeschen (rueckwaerts)
1350 
1351                     long i;
1352                     if (bRecording)
1353                         for (i=1; i<=nDelCount; i++)
1354                                         AddCalcUndo< SdrUndoRemoveObj >( *ppObj[nDelCount-i] );
1355 
1356                     for (i=1; i<=nDelCount; i++)
1357                         pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1358 
1359                     delete[] ppObj;
1360                 }
1361             }
1362             else
1363             {
1364                 DBG_ERROR("pPage?");
1365             }
1366         }
1367 }
1368 
1369 void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const Rectangle& rRange )
1370 {
1371     //  copy everything in the specified range into the same page (sheet) in the clipboard doc
1372 
1373     SdrPage* pSrcPage = GetPage(static_cast<sal_uInt16>(nTab));
1374     if (pSrcPage)
1375     {
1376         ScDrawLayer* pDestModel = NULL;
1377         SdrPage* pDestPage = NULL;
1378 
1379         SdrObjListIter aIter( *pSrcPage, IM_FLAT );
1380         SdrObject* pOldObject = aIter.Next();
1381         while (pOldObject)
1382         {
1383             Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1384             // do not copy internal objects (detective) and note captions
1385             if ( rRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
1386             {
1387                 if ( !pDestModel )
1388                 {
1389                     pDestModel = pClipDoc->GetDrawLayer();      // does the document already have a drawing layer?
1390                     if ( !pDestModel )
1391                     {
1392                         //  allocate drawing layer in clipboard document only if there are objects to copy
1393 
1394                         pClipDoc->InitDrawLayer();                  //! create contiguous pages
1395                         pDestModel = pClipDoc->GetDrawLayer();
1396                     }
1397                     if (pDestModel)
1398                         pDestPage = pDestModel->GetPage( static_cast<sal_uInt16>(nTab) );
1399                 }
1400 
1401                 DBG_ASSERT( pDestPage, "no page" );
1402                 if (pDestPage)
1403                 {
1404                     // #116235#
1405                     SdrObject* pNewObject = pOldObject->Clone();
1406                     //SdrObject* pNewObject = pOldObject->Clone( pDestPage, pDestModel );
1407                     pNewObject->SetModel(pDestModel);
1408                     pNewObject->SetPage(pDestPage);
1409 
1410                     uno::Reference< chart2::XChartDocument > xOldChart( ScChartHelper::GetChartFromSdrObject( pOldObject ) );
1411                     if(!xOldChart.is())//#i110034# do not move charts as they loose all their data references otherwise
1412                         pNewObject->NbcMove(Size(0,0));
1413                     pDestPage->InsertObject( pNewObject );
1414 
1415                     //  no undo needed in clipboard document
1416                     //  charts are not updated
1417                 }
1418             }
1419 
1420             pOldObject = aIter.Next();
1421         }
1422     }
1423 }
1424 
1425 sal_Bool lcl_IsAllInRange( const ::std::vector< ScRangeList >& rRangesVector, const ScRange& rClipRange )
1426 {
1427     //  check if every range of rRangesVector is completely in rClipRange
1428 
1429     ::std::vector< ScRangeList >::const_iterator aIt = rRangesVector.begin();
1430     for( ;aIt!=rRangesVector.end(); ++aIt )
1431     {
1432         const ScRangeList& rRanges = *aIt;
1433         sal_uLong nCount = rRanges.Count();
1434         for (sal_uLong i=0; i<nCount; i++)
1435         {
1436             ScRange aRange = *rRanges.GetObject(i);
1437             if ( !rClipRange.In( aRange ) )
1438             {
1439                 return sal_False;   // at least one range is not valid
1440             }
1441         }
1442     }
1443 
1444     return sal_True;            // everything is fine
1445 }
1446 
1447 sal_Bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const ScRange& rSourceRange, const ScAddress& rDestPos )
1448 {
1449     sal_Bool bChanged = sal_False;
1450 
1451     ::std::vector< ScRangeList >::iterator aIt = rRangesVector.begin();
1452     for( ;aIt!=rRangesVector.end(); ++aIt )
1453     {
1454         ScRangeList& rRanges = *aIt;
1455         sal_uLong nCount = rRanges.Count();
1456         for (sal_uLong i=0; i<nCount; i++)
1457         {
1458             ScRange* pRange = rRanges.GetObject(i);
1459             if ( rSourceRange.In( *pRange ) )
1460             {
1461                 SCsCOL nDiffX = rDestPos.Col() - (SCsCOL)rSourceRange.aStart.Col();
1462                 SCsROW nDiffY = rDestPos.Row() - (SCsROW)rSourceRange.aStart.Row();
1463                 SCsTAB nDiffZ = rDestPos.Tab() - (SCsTAB)rSourceRange.aStart.Tab();
1464                 pRange->Move( nDiffX, nDiffY, nDiffZ );
1465                 bChanged = sal_True;
1466             }
1467         }
1468     }
1469 
1470     return bChanged;
1471 }
1472 
1473 void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const Rectangle& rSourceRange,
1474                                     const ScAddress& rDestPos, const Rectangle& rDestRange )
1475 {
1476     DBG_ASSERT( pDoc, "ScDrawLayer::CopyFromClip without document" );
1477     if ( !pDoc )
1478         return;
1479 
1480     if (!pClipModel)
1481         return;
1482 
1483     if (bDrawIsInUndo)      //! can this happen?
1484     {
1485         DBG_ERROR("CopyFromClip, bDrawIsInUndo");
1486         return;
1487     }
1488 
1489     sal_Bool bMirrorObj = ( rSourceRange.Left() < 0 && rSourceRange.Right() < 0 &&
1490                         rDestRange.Left()   > 0 && rDestRange.Right()   > 0 ) ||
1491                       ( rSourceRange.Left() > 0 && rSourceRange.Right() > 0 &&
1492                         rDestRange.Left()   < 0 && rDestRange.Right()   < 0 );
1493     Rectangle aMirroredSource = rSourceRange;
1494     if ( bMirrorObj )
1495         MirrorRectRTL( aMirroredSource );
1496 
1497     SCTAB nDestTab = rDestPos.Tab();
1498 
1499     SdrPage* pSrcPage = pClipModel->GetPage(static_cast<sal_uInt16>(nSourceTab));
1500     SdrPage* pDestPage = GetPage(static_cast<sal_uInt16>(nDestTab));
1501     DBG_ASSERT( pSrcPage && pDestPage, "draw page missing" );
1502     if ( !pSrcPage || !pDestPage )
1503         return;
1504 
1505     SdrObjListIter aIter( *pSrcPage, IM_FLAT );
1506     SdrObject* pOldObject = aIter.Next();
1507 
1508     ScDocument* pClipDoc = pClipModel->GetDocument();
1509     //  a clipboard document and its source share the same document item pool,
1510     //  so the pointers can be compared to see if this is copy&paste within
1511     //  the same document
1512     sal_Bool bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
1513     sal_Bool bDestClip = pDoc && pDoc->IsClipboard();
1514 
1515     //#i110034# charts need correct sheet names for xml range conversion during load
1516     //so the target sheet name is temporarily renamed (if we have any SdrObjects)
1517     String aDestTabName;
1518     sal_Bool bRestoreDestTabName = sal_False;
1519     if( pOldObject && !bSameDoc && !bDestClip )
1520     {
1521         if( pDoc && pClipDoc )
1522         {
1523             String aSourceTabName;
1524             if( pClipDoc->GetName( nSourceTab, aSourceTabName )
1525                 && pDoc->GetName( nDestTab, aDestTabName ) )
1526             {
1527                 if( !(aSourceTabName==aDestTabName) &&
1528                     pDoc->ValidNewTabName(aSourceTabName) )
1529                 {
1530                     bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName ); //sal_Bool bUpdateRef = sal_True, sal_Bool bExternalDocument = sal_False
1531                 }
1532             }
1533         }
1534     }
1535 
1536     // first mirror, then move
1537     Size aMove( rDestRange.Left() - aMirroredSource.Left(), rDestRange.Top() - aMirroredSource.Top() );
1538 
1539     long nDestWidth = rDestRange.GetWidth();
1540     long nDestHeight = rDestRange.GetHeight();
1541     long nSourceWidth = rSourceRange.GetWidth();
1542     long nSourceHeight = rSourceRange.GetHeight();
1543 
1544     long nWidthDiff = nDestWidth - nSourceWidth;
1545     long nHeightDiff = nDestHeight - nSourceHeight;
1546 
1547     Fraction aHorFract(1,1);
1548     Fraction aVerFract(1,1);
1549     sal_Bool bResize = sal_False;
1550     // sizes can differ by 1 from twips->1/100mm conversion for equal cell sizes,
1551     // don't resize to empty size when pasting into hidden columns or rows
1552     if ( Abs(nWidthDiff) > 1 && nDestWidth > 1 && nSourceWidth > 1 )
1553     {
1554         aHorFract = Fraction( nDestWidth, nSourceWidth );
1555         bResize = sal_True;
1556     }
1557     if ( Abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
1558     {
1559         aVerFract = Fraction( nDestHeight, nSourceHeight );
1560         bResize = sal_True;
1561     }
1562     Point aRefPos = rDestRange.TopLeft();       // for resizing (after moving)
1563 
1564     while (pOldObject)
1565     {
1566         Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1567         // do not copy internal objects (detective) and note captions
1568         if ( rSourceRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
1569         {
1570             // #116235#
1571             SdrObject* pNewObject = pOldObject->Clone();
1572             //SdrObject* pNewObject = pOldObject->Clone( pDestPage, this );
1573             pNewObject->SetModel(this);
1574             pNewObject->SetPage(pDestPage);
1575 
1576             if ( bMirrorObj )
1577                 MirrorRTL( pNewObject );        // first mirror, then move
1578 
1579             pNewObject->NbcMove( aMove );
1580             if ( bResize )
1581                 pNewObject->NbcResize( aRefPos, aHorFract, aVerFract );
1582 
1583             pDestPage->InsertObject( pNewObject );
1584             if (bRecording)
1585                         AddCalcUndo< SdrUndoInsertObj >( *pNewObject );
1586 
1587             //#i110034# handle chart data references (after InsertObject)
1588 
1589             if ( pNewObject->GetObjIdentifier() == OBJ_OLE2 )
1590             {
1591                 uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pNewObject)->GetObjRef();
1592                 uno::Reference< embed::XClassifiedObject > xClassified( xIPObj, uno::UNO_QUERY );
1593                 SvGlobalName aObjectClassName;
1594                 if ( xClassified.is() )
1595                 {
1596                     try {
1597                         aObjectClassName = SvGlobalName( xClassified->getClassID() );
1598                     } catch( uno::Exception& )
1599                     {
1600                         // TODO: handle error?
1601                     }
1602                 }
1603 
1604                 if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
1605                 {
1606                     uno::Reference< chart2::XChartDocument > xNewChart( ScChartHelper::GetChartFromSdrObject( pNewObject ) );
1607                     if( xNewChart.is() && !xNewChart->hasInternalDataProvider() )
1608                     {
1609                         String aChartName = ((SdrOle2Obj*)pNewObject)->GetPersistName();
1610                         ::std::vector< ScRangeList > aRangesVector;
1611                         pDoc->GetChartRanges( aChartName, aRangesVector, pDoc );
1612                         if( !aRangesVector.empty() )
1613                         {
1614                             sal_Bool bInSourceRange = sal_False;
1615                             ScRange aClipRange;
1616                             if ( pClipDoc )
1617                             {
1618                                 SCCOL nClipStartX;
1619                                 SCROW nClipStartY;
1620                                 SCCOL nClipEndX;
1621                                 SCROW nClipEndY;
1622                                 pClipDoc->GetClipStart( nClipStartX, nClipStartY );
1623                                 pClipDoc->GetClipArea( nClipEndX, nClipEndY, sal_True );
1624                                 nClipEndX = nClipEndX + nClipStartX;
1625                                 nClipEndY += nClipStartY;   // GetClipArea returns the difference
1626 
1627                                 SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
1628                                 aClipRange = ScRange( nClipStartX, nClipStartY, nClipTab,
1629                                                         nClipEndX, nClipEndY, nClipTab );
1630 
1631                                 bInSourceRange = lcl_IsAllInRange( aRangesVector, aClipRange );
1632                             }
1633 
1634                             // always lose references when pasting into a clipboard document (transpose)
1635                             if ( ( bInSourceRange || bSameDoc ) && !bDestClip )
1636                             {
1637                                 if ( bInSourceRange )
1638                                 {
1639                                     if ( rDestPos != aClipRange.aStart )
1640                                     {
1641                                         //  update the data ranges to the new (copied) position
1642                                         if ( lcl_MoveRanges( aRangesVector, aClipRange, rDestPos ) )
1643                                             pDoc->SetChartRanges( aChartName, aRangesVector );
1644                                     }
1645                                 }
1646                                 else
1647                                 {
1648                                     //  leave the ranges unchanged
1649                                 }
1650                             }
1651                             else
1652                             {
1653                                 //  pasting into a new document without the complete source data
1654                                 //  -> break connection to source data and switch to own data
1655 
1656                                 uno::Reference< chart::XChartDocument > xOldChartDoc( ScChartHelper::GetChartFromSdrObject( pOldObject ), uno::UNO_QUERY );
1657                                 uno::Reference< chart::XChartDocument > xNewChartDoc( xNewChart, uno::UNO_QUERY );
1658                                 if( xOldChartDoc.is() && xNewChartDoc.is() )
1659                                     xNewChartDoc->attachData( xOldChartDoc->getData() );
1660 
1661                                 //  (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
1662                             }
1663                         }
1664                     }
1665                 }
1666             }
1667         }
1668 
1669         pOldObject = aIter.Next();
1670     }
1671 
1672     if( bRestoreDestTabName )
1673         pDoc->RenameTab( nDestTab, aDestTabName );
1674 }
1675 
1676 void ScDrawLayer::MirrorRTL( SdrObject* pObj )
1677 {
1678     sal_uInt16 nIdent = pObj->GetObjIdentifier();
1679 
1680     //  don't mirror OLE or graphics, otherwise ask the object
1681     //  if it can be mirrored
1682     sal_Bool bCanMirror = ( nIdent != OBJ_GRAF && nIdent != OBJ_OLE2 );
1683     if (bCanMirror)
1684     {
1685         SdrObjTransformInfoRec aInfo;
1686         pObj->TakeObjInfo( aInfo );
1687         bCanMirror = aInfo.bMirror90Allowed;
1688     }
1689 
1690     if (bCanMirror)
1691     {
1692         Point aRef1( 0, 0 );
1693         Point aRef2( 0, 1 );
1694         if (bRecording)
1695                     AddCalcUndo< SdrUndoGeoObj >( *pObj );
1696         pObj->Mirror( aRef1, aRef2 );
1697     }
1698     else
1699     {
1700         //  Move instead of mirroring:
1701         //  New start position is negative of old end position
1702         //  -> move by sum of start and end position
1703         Rectangle aObjRect = pObj->GetLogicRect();
1704         Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
1705         if (bRecording)
1706                     AddCalcUndo< SdrUndoMoveObj >( *pObj, aMoveSize );
1707         pObj->Move( aMoveSize );
1708     }
1709 }
1710 
1711 // static
1712 void ScDrawLayer::MirrorRectRTL( Rectangle& rRect )
1713 {
1714     //  mirror and swap left/right
1715     long nTemp = rRect.Left();
1716     rRect.Left() = -rRect.Right();
1717     rRect.Right() = -nTemp;
1718 }
1719 
1720 Rectangle ScDrawLayer::GetCellRect( ScDocument& rDoc, const ScAddress& rPos, bool bMergedCell )
1721 {
1722     Rectangle aCellRect;
1723     DBG_ASSERT( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ), "ScDrawLayer::GetCellRect - invalid cell address" );
1724     if( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ) )
1725     {
1726         // find top left position of passed cell address
1727         Point aTopLeft;
1728         for( SCCOL nCol = 0; nCol < rPos.Col(); ++nCol )
1729             aTopLeft.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
1730         if( rPos.Row() > 0 )
1731             aTopLeft.Y() += rDoc.GetRowHeight( 0, rPos.Row() - 1, rPos.Tab() );
1732 
1733         // find bottom-right position of passed cell address
1734         ScAddress aEndPos = rPos;
1735         if( bMergedCell )
1736         {
1737             const ScMergeAttr* pMerge = static_cast< const ScMergeAttr* >( rDoc.GetAttr( rPos.Col(), rPos.Row(), rPos.Tab(), ATTR_MERGE ) );
1738             if( pMerge->GetColMerge() > 1 )
1739                 aEndPos.IncCol( pMerge->GetColMerge() - 1 );
1740             if( pMerge->GetRowMerge() > 1 )
1741                 aEndPos.IncRow( pMerge->GetRowMerge() - 1 );
1742         }
1743         Point aBotRight = aTopLeft;
1744         for( SCCOL nCol = rPos.Col(); nCol <= aEndPos.Col(); ++nCol )
1745             aBotRight.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
1746         aBotRight.Y() += rDoc.GetRowHeight( rPos.Row(), aEndPos.Row(), rPos.Tab() );
1747 
1748         // twips -> 1/100 mm
1749         aTopLeft.X() = static_cast< long >( aTopLeft.X() * HMM_PER_TWIPS );
1750         aTopLeft.Y() = static_cast< long >( aTopLeft.Y() * HMM_PER_TWIPS );
1751         aBotRight.X() = static_cast< long >( aBotRight.X() * HMM_PER_TWIPS );
1752         aBotRight.Y() = static_cast< long >( aBotRight.Y() * HMM_PER_TWIPS );
1753 
1754         aCellRect = Rectangle( aTopLeft, aBotRight );
1755         if( rDoc.IsNegativePage( rPos.Tab() ) )
1756             MirrorRectRTL( aCellRect );
1757     }
1758     return aCellRect;
1759 }
1760 
1761 // static
1762 String ScDrawLayer::GetVisibleName( SdrObject* pObj )
1763 {
1764     String aName = pObj->GetName();
1765     if ( pObj->GetObjIdentifier() == OBJ_OLE2 )
1766     {
1767         //  #95575# For OLE, the user defined name (GetName) is used
1768         //  if it's not empty (accepting possibly duplicate names),
1769         //  otherwise the persist name is used so every object appears
1770         //  in the Navigator at all.
1771 
1772         if ( !aName.Len() )
1773             aName = static_cast<SdrOle2Obj*>(pObj)->GetPersistName();
1774     }
1775     return aName;
1776 }
1777 
1778 inline sal_Bool IsNamedObject( SdrObject* pObj, const String& rName )
1779 {
1780     //  sal_True if rName is the object's Name or PersistName
1781     //  (used to find a named object)
1782 
1783     return ( pObj->GetName() == rName ||
1784             ( pObj->GetObjIdentifier() == OBJ_OLE2 &&
1785               static_cast<SdrOle2Obj*>(pObj)->GetPersistName() == rName ) );
1786 }
1787 
1788 SdrObject* ScDrawLayer::GetNamedObject( const String& rName, sal_uInt16 nId, SCTAB& rFoundTab ) const
1789 {
1790     sal_uInt16 nTabCount = GetPageCount();
1791     for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
1792     {
1793         const SdrPage* pPage = GetPage(nTab);
1794         DBG_ASSERT(pPage,"Page ?");
1795         if (pPage)
1796         {
1797             SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
1798             SdrObject* pObject = aIter.Next();
1799             while (pObject)
1800             {
1801                 if ( nId == 0 || pObject->GetObjIdentifier() == nId )
1802                     if ( IsNamedObject( pObject, rName ) )
1803                     {
1804                         rFoundTab = static_cast<SCTAB>(nTab);
1805                         return pObject;
1806                     }
1807 
1808                 pObject = aIter.Next();
1809             }
1810         }
1811     }
1812 
1813     return NULL;
1814 }
1815 
1816 String ScDrawLayer::GetNewGraphicName( long* pnCounter ) const
1817 {
1818     String aBase = ScGlobal::GetRscString(STR_GRAPHICNAME);
1819     aBase += ' ';
1820 
1821     sal_Bool bThere = sal_True;
1822     String aGraphicName;
1823     SCTAB nDummy;
1824     long nId = pnCounter ? *pnCounter : 0;
1825     while (bThere)
1826     {
1827         ++nId;
1828         aGraphicName = aBase;
1829         aGraphicName += String::CreateFromInt32( nId );
1830         bThere = ( GetNamedObject( aGraphicName, 0, nDummy ) != NULL );
1831     }
1832 
1833     if ( pnCounter )
1834         *pnCounter = nId;
1835 
1836     return aGraphicName;
1837 }
1838 
1839 void ScDrawLayer::EnsureGraphicNames()
1840 {
1841     //  make sure all graphic objects have names (after Excel import etc.)
1842 
1843     sal_uInt16 nTabCount = GetPageCount();
1844     for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
1845     {
1846         SdrPage* pPage = GetPage(nTab);
1847         DBG_ASSERT(pPage,"Page ?");
1848         if (pPage)
1849         {
1850             SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
1851             SdrObject* pObject = aIter.Next();
1852 
1853             /* #101799# The index passed to GetNewGraphicName() will be set to
1854                 the used index in each call. This prevents the repeated search
1855                 for all names from 1 to current index. */
1856             long nCounter = 0;
1857 
1858             while (pObject)
1859             {
1860                 if ( pObject->GetObjIdentifier() == OBJ_GRAF && pObject->GetName().Len() == 0 )
1861                     pObject->SetName( GetNewGraphicName( &nCounter ) );
1862 
1863                 pObject = aIter.Next();
1864             }
1865         }
1866     }
1867 }
1868 
1869 void ScDrawLayer::SetAnchor( SdrObject* pObj, ScAnchorType eType )
1870 {
1871     ScAnchorType eOldAnchorType = GetAnchor( pObj );
1872 
1873     // Ein an der Seite verankertes Objekt zeichnet sich durch eine Anker-Pos
1874     // von (0,1) aus. Das ist ein shabby Trick, der aber funktioniert!
1875     Point aAnchor( 0, eType == SCA_PAGE ? 1 : 0 );
1876     pObj->SetAnchorPos( aAnchor );
1877 
1878     if ( eOldAnchorType != eType )
1879         pObj->notifyShapePropertyChange( ::svx::eSpreadsheetAnchor );
1880 }
1881 
1882 ScAnchorType ScDrawLayer::GetAnchor( const SdrObject* pObj )
1883 {
1884     Point aAnchor( pObj->GetAnchorPos() );
1885     return ( aAnchor.Y() != 0 ) ? SCA_PAGE : SCA_CELL;
1886 }
1887 
1888 ScDrawObjData* ScDrawLayer::GetObjData( SdrObject* pObj, sal_Bool bCreate )     // static
1889 {
1890     sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
1891     for( sal_uInt16 i = 0; i < nCount; i++ )
1892     {
1893         SdrObjUserData* pData = pObj->GetUserData( i );
1894         if( pData && pData->GetInventor() == SC_DRAWLAYER
1895                     && pData->GetId() == SC_UD_OBJDATA )
1896             return (ScDrawObjData*) pData;
1897     }
1898     if( pObj && bCreate )
1899     {
1900         ScDrawObjData* pData = new ScDrawObjData;
1901         pObj->InsertUserData( pData, 0 );
1902         return pData;
1903     }
1904     return 0;
1905 }
1906 
1907 ScDrawObjData* ScDrawLayer::GetObjDataTab( SdrObject* pObj, SCTAB nTab )    // static
1908 {
1909     ScDrawObjData* pData = GetObjData( pObj );
1910     if ( pData )
1911     {
1912         if ( pData->maStart.IsValid() )
1913             pData->maStart.SetTab( nTab );
1914         if ( pData->maEnd.IsValid() )
1915             pData->maEnd.SetTab( nTab );
1916     }
1917     return pData;
1918 }
1919 
1920 bool ScDrawLayer::IsNoteCaption( SdrObject* pObj )
1921 {
1922     ScDrawObjData* pData = pObj ? GetObjData( pObj ) : 0;
1923     return pData && pData->mbNote;
1924 }
1925 
1926 ScDrawObjData* ScDrawLayer::GetNoteCaptionData( SdrObject* pObj, SCTAB nTab )
1927 {
1928     ScDrawObjData* pData = pObj ? GetObjDataTab( pObj, nTab ) : 0;
1929     return (pData && pData->mbNote) ? pData : 0;
1930 }
1931 
1932 ScIMapInfo* ScDrawLayer::GetIMapInfo( SdrObject* pObj )             // static
1933 {
1934     sal_uInt16 nCount = pObj->GetUserDataCount();
1935     for( sal_uInt16 i = 0; i < nCount; i++ )
1936     {
1937         SdrObjUserData* pData = pObj->GetUserData( i );
1938         if( pData && pData->GetInventor() == SC_DRAWLAYER
1939                     && pData->GetId() == SC_UD_IMAPDATA )
1940             return (ScIMapInfo*) pData;
1941     }
1942     return NULL;
1943 }
1944 
1945 // static:
1946 IMapObject* ScDrawLayer::GetHitIMapObject( SdrObject* pObj,
1947                                           const Point& rWinPoint, const Window& rCmpWnd )
1948 {
1949     const MapMode       aMap100( MAP_100TH_MM );
1950     MapMode             aWndMode = rCmpWnd.GetMapMode();
1951     Point               aRelPoint( rCmpWnd.LogicToLogic( rWinPoint, &aWndMode, &aMap100 ) );
1952     Rectangle           aLogRect = rCmpWnd.LogicToLogic( pObj->GetLogicRect(), &aWndMode, &aMap100 );
1953     ScIMapInfo*         pIMapInfo = GetIMapInfo( pObj );
1954     IMapObject*         pIMapObj = NULL;
1955 
1956     if ( pIMapInfo )
1957     {
1958         Size        aGraphSize;
1959         ImageMap&   rImageMap = (ImageMap&) pIMapInfo->GetImageMap();
1960         Graphic     aGraphic;
1961         sal_Bool        bObjSupported = sal_False;
1962 
1963         if ( pObj->ISA( SdrGrafObj )  ) // einfaches Grafik-Objekt
1964         {
1965             const SdrGrafObj*   pGrafObj = (const SdrGrafObj*) pObj;
1966             const GeoStat&      rGeo = pGrafObj->GetGeoStat();
1967             const Graphic&      rGraphic = pGrafObj->GetGraphic();
1968 
1969             // Drehung rueckgaengig
1970             if ( rGeo.nDrehWink )
1971                 RotatePoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nSin, rGeo.nCos );
1972 
1973             // Spiegelung rueckgaengig
1974             if ( ( (const SdrGrafObjGeoData*) pGrafObj->GetGeoData() )->bMirrored )
1975                 aRelPoint.X() = aLogRect.Right() + aLogRect.Left() - aRelPoint.X();
1976 
1977             // ggf. Unshear:
1978             if ( rGeo.nShearWink )
1979                 ShearPoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nTan );
1980 
1981 
1982             if ( rGraphic.GetPrefMapMode().GetMapUnit() == MAP_PIXEL )
1983                 aGraphSize = rCmpWnd.PixelToLogic( rGraphic.GetPrefSize(),
1984                                                          aMap100 );
1985             else
1986                 aGraphSize = OutputDevice::LogicToLogic( rGraphic.GetPrefSize(),
1987                                                          rGraphic.GetPrefMapMode(),
1988                                                          aMap100 );
1989 
1990             bObjSupported = sal_True;
1991         }
1992         else if ( pObj->ISA( SdrOle2Obj ) ) // OLE-Objekt
1993         {
1994             // TODO/LEAN: working with visual area needs running state
1995             aGraphSize = ((SdrOle2Obj*)pObj)->GetOrigObjSize();
1996             bObjSupported = sal_True;
1997         }
1998 
1999         // hat alles geklappt, dann HitTest ausfuehren
2000         if ( bObjSupported )
2001         {
2002             // relativen Mauspunkt berechnen
2003             aRelPoint -= aLogRect.TopLeft();
2004             pIMapObj = rImageMap.GetHitIMapObject( aGraphSize, aLogRect.GetSize(), aRelPoint );
2005         }
2006     }
2007 
2008     return pIMapObj;
2009 }
2010 
2011 ScMacroInfo* ScDrawLayer::GetMacroInfo( SdrObject* pObj, sal_Bool bCreate )             // static
2012 {
2013     sal_uInt16 nCount = pObj->GetUserDataCount();
2014     for( sal_uInt16 i = 0; i < nCount; i++ )
2015     {
2016         SdrObjUserData* pData = pObj->GetUserData( i );
2017         if( pData && pData->GetInventor() == SC_DRAWLAYER
2018                     && pData->GetId() == SC_UD_MACRODATA )
2019             return (ScMacroInfo*) pData;
2020     }
2021     if ( bCreate )
2022     {
2023         ScMacroInfo* pData = new ScMacroInfo;
2024         pObj->InsertUserData( pData, 0 );
2025         return pData;
2026     }
2027     return 0;
2028 }
2029 
2030 void ScDrawLayer::SetGlobalDrawPersist(SfxObjectShell* pPersist)            // static
2031 {
2032     DBG_ASSERT(!pGlobalDrawPersist,"SetGlobalDrawPersist mehrfach");
2033     pGlobalDrawPersist = pPersist;
2034 }
2035 
2036 void __EXPORT ScDrawLayer::SetChanged( sal_Bool bFlg /* = sal_True */ )
2037 {
2038     if ( bFlg && pDoc )
2039         pDoc->SetChartListenerCollectionNeedsUpdate( sal_True );
2040     FmFormModel::SetChanged( bFlg );
2041 }
2042 
2043 SvStream* __EXPORT ScDrawLayer::GetDocumentStream(SdrDocumentStreamInfo& rStreamInfo) const
2044 {
2045     DBG_ASSERT( pDoc, "ScDrawLayer::GetDocumentStream without document" );
2046     if ( !pDoc )
2047         return NULL;
2048 
2049     uno::Reference< embed::XStorage > xStorage = pDoc->GetDocumentShell() ?
2050                                                         pDoc->GetDocumentShell()->GetStorage() :
2051                                                         NULL;
2052     SvStream*   pRet = NULL;
2053 
2054     if( xStorage.is() )
2055     {
2056         if( rStreamInfo.maUserData.Len() &&
2057             ( rStreamInfo.maUserData.GetToken( 0, ':' ) ==
2058               String( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.Package" ) ) ) )
2059         {
2060             const String aPicturePath( rStreamInfo.maUserData.GetToken( 1, ':' ) );
2061 
2062             // graphic from picture stream in picture storage in XML package
2063             if( aPicturePath.GetTokenCount( '/' ) == 2 )
2064             {
2065                 const String aPictureStreamName( aPicturePath.GetToken( 1, '/' ) );
2066                 const String aPictureStorageName( aPicturePath.GetToken( 0, '/' ) );
2067 
2068                 try {
2069                     if ( xStorage->isStorageElement( aPictureStorageName ) )
2070                     {
2071                         uno::Reference< embed::XStorage > xPictureStorage =
2072                                     xStorage->openStorageElement( aPictureStorageName, embed::ElementModes::READ );
2073 
2074                         if( xPictureStorage.is() &&
2075                             xPictureStorage->isStreamElement( aPictureStreamName ) )
2076                         {
2077                             uno::Reference< io::XStream > xStream =
2078                                 xPictureStorage->openStreamElement( aPictureStreamName, embed::ElementModes::READ );
2079                             if ( xStream.is() )
2080                                 pRet = ::utl::UcbStreamHelper::CreateStream( xStream );
2081                         }
2082                     }
2083                 }
2084                 catch( uno::Exception& )
2085                 {
2086                     // TODO: error handling
2087                 }
2088             }
2089         }
2090         // the following code seems to be related to binary format
2091 //REMOVE            else
2092 //REMOVE            {
2093 //REMOVE                pRet = pStor->OpenStream( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(STRING_SCSTREAM)),
2094 //REMOVE                                          STREAM_READ | STREAM_WRITE | STREAM_TRUNC );
2095 //REMOVE
2096 //REMOVE                if( pRet )
2097 //REMOVE                {
2098 //REMOVE                    pRet->SetVersion( pStor->GetVersion() );
2099 //REMOVE                    pRet->SetKey( pStor->GetKey() );
2100 //REMOVE                }
2101 //REMOVE            }
2102 
2103         rStreamInfo.mbDeleteAfterUse = ( pRet != NULL );
2104     }
2105 
2106     return pRet;
2107 }
2108 
2109 //REMOVE    void ScDrawLayer::ReleasePictureStorage()
2110 //REMOVE    {
2111 //REMOVE        xPictureStorage.Clear();
2112 //REMOVE    }
2113 
2114 SdrLayerID __EXPORT ScDrawLayer::GetControlExportLayerId( const SdrObject & ) const
2115 {
2116     //  Layer fuer Export von Form-Controls in Versionen vor 5.0 - immer SC_LAYER_FRONT
2117     return SC_LAYER_FRONT;
2118 }
2119 
2120 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > ScDrawLayer::createUnoModel()
2121 {
2122     ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet;
2123     if( pDoc && pDoc->GetDocumentShell() )
2124         xRet = pDoc->GetDocumentShell()->GetModel();
2125 
2126     return xRet;
2127 }
2128