xref: /AOO41X/main/sc/source/core/data/drwlayer.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 #include <com/sun/star/uno/Reference.hxx>
27 #include <com/sun/star/chart/XChartDocument.hpp>
28 #include <com/sun/star/embed/XEmbeddedObject.hpp>
29 #include <com/sun/star/embed/XVisualObject.hpp>
30 #include <com/sun/star/embed/XClassifiedObject.hpp>
31 #include <com/sun/star/embed/XComponentSupplier.hpp>
32 #include <com/sun/star/embed/EmbedStates.hpp>
33 #include <com/sun/star/embed/ElementModes.hpp>
34 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
35 #include <com/sun/star/datatransfer/XTransferable.hpp>
36 
37 // INCLUDE ---------------------------------------------------------------
38 
39 #include "scitems.hxx"
40 #include <editeng/eeitem.hxx>
41 #include <editeng/frmdiritem.hxx>
42 #include <sot/exchange.hxx>
43 #include <svx/objfac3d.hxx>
44 #include <svx/xtable.hxx>
45 #include <svx/svdoutl.hxx>
46 #include <svx/svditer.hxx>
47 #include <svx/svdocapt.hxx>
48 #include <svx/svdocirc.hxx>
49 #include <svx/svdoedge.hxx>
50 #include <svx/svdograf.hxx>
51 #include <svx/svdoole2.hxx>
52 #include <svx/svdundo.hxx>
53 #include <editeng/unolingu.hxx>
54 #include <svx/drawitem.hxx>
55 #include <editeng/fhgtitem.hxx>
56 #include <editeng/scriptspaceitem.hxx>
57 #include <svx/shapepropertynotifier.hxx>
58 #include <sfx2/viewsh.hxx>
59 #include <sfx2/docfile.hxx>
60 #include <sot/storage.hxx>
61 #include <unotools/pathoptions.hxx>
62 #include <svl/itempool.hxx>
63 #include <vcl/virdev.hxx>
64 #include <vcl/svapp.hxx>
65 #include <unotools/ucbstreamhelper.hxx>
66 
67 #include "drwlayer.hxx"
68 #include "drawpage.hxx"
69 #include "global.hxx"
70 #include "document.hxx"
71 #include "rechead.hxx"
72 #include "userdat.hxx"
73 #include "markdata.hxx"
74 #include "globstr.hrc"
75 #include "scmod.hxx"
76 #include "chartarr.hxx"
77 #include "postit.hxx"
78 #include "attrib.hxx"
79 #include "charthelper.hxx"
80 
81 #define DET_ARROW_OFFSET    1000
82 
83 //  Abstand zur naechsten Zelle beim Loeschen (bShrink), damit der Anker
84 //  immer an der richtigen Zelle angezeigt wird
85 //#define SHRINK_DIST       3
86 //  und noch etwas mehr, damit das Objekt auch sichtbar in der Zelle liegt
87 #define SHRINK_DIST     25
88 
89 #define SHRINK_DIST_TWIPS   15
90 
91 using namespace ::com::sun::star;
92 
93 // STATIC DATA -----------------------------------------------------------
94 
95 TYPEINIT1(ScTabDeletedHint, SfxHint);
96 TYPEINIT1(ScTabSizeChangedHint, SfxHint);
97 
98 static ScDrawObjFactory* pFac = NULL;
99 static E3dObjFactory* pF3d = NULL;
100 static sal_uInt16 nInst = 0;
101 
102 SfxObjectShell* ScDrawLayer::pGlobalDrawPersist = NULL;
103 //REMOVE    SvPersist* ScDrawLayer::pGlobalDrawPersist = NULL;
104 
105 sal_Bool bDrawIsInUndo = sal_False;         //! Member
106 
107 // -----------------------------------------------------------------------
108 
109 ScUndoObjData::ScUndoObjData( SdrObject* pObjP, const ScAddress& rOS, const ScAddress& rOE,
110                                                const ScAddress& rNS, const ScAddress& rNE ) :
111     SdrUndoObj( *pObjP ),
112     aOldStt( rOS ),
113     aOldEnd( rOE ),
114     aNewStt( rNS ),
115     aNewEnd( rNE )
116 {
117 }
118 
119 __EXPORT ScUndoObjData::~ScUndoObjData()
120 {
121 }
122 
123 void ScUndoObjData::Undo()
124 {
125     ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
126     DBG_ASSERT(pData,"ScUndoObjData: Daten nicht da");
127     if (pData)
128     {
129         pData->maStart = aOldStt;
130         pData->maEnd = aOldEnd;
131     }
132 }
133 
134 void __EXPORT ScUndoObjData::Redo()
135 {
136     ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
137     DBG_ASSERT(pData,"ScUndoObjData: Daten nicht da");
138     if (pData)
139     {
140         pData->maStart = aNewStt;
141         pData->maEnd = aNewEnd;
142     }
143 }
144 
145 // -----------------------------------------------------------------------
146 
147 ScTabDeletedHint::ScTabDeletedHint( SCTAB nTabNo ) :
148     nTab( nTabNo )
149 {
150 }
151 
152 __EXPORT ScTabDeletedHint::~ScTabDeletedHint()
153 {
154 }
155 
156 ScTabSizeChangedHint::ScTabSizeChangedHint( SCTAB nTabNo ) :
157     nTab( nTabNo )
158 {
159 }
160 
161 __EXPORT ScTabSizeChangedHint::~ScTabSizeChangedHint()
162 {
163 }
164 
165 // -----------------------------------------------------------------------
166 
167 #define MAXMM   10000000
168 
169 inline void TwipsToMM( long& nVal )
170 {
171     nVal = (long) ( nVal * HMM_PER_TWIPS );
172 }
173 
174 inline void ReverseTwipsToMM( long& nVal )
175 {
176     //  reverse the effect of TwipsToMM - round up here (add 1)
177 
178     nVal = ((long) ( nVal / HMM_PER_TWIPS )) + 1;
179 }
180 
181 void lcl_TwipsToMM( Point& rPoint )
182 {
183     TwipsToMM( rPoint.X() );
184     TwipsToMM( rPoint.Y() );
185 }
186 
187 void lcl_ReverseTwipsToMM( Point& rPoint )
188 {
189     ReverseTwipsToMM( rPoint.X() );
190     ReverseTwipsToMM( rPoint.Y() );
191 }
192 
193 void lcl_ReverseTwipsToMM( Rectangle& rRect )
194 {
195     ReverseTwipsToMM( rRect.Left() );
196     ReverseTwipsToMM( rRect.Right() );
197     ReverseTwipsToMM( rRect.Top() );
198     ReverseTwipsToMM( rRect.Bottom() );
199 }
200 
201 // -----------------------------------------------------------------------
202 
203 
204 ScDrawLayer::ScDrawLayer( ScDocument* pDocument, const String& rName ) :
205     FmFormModel( SvtPathOptions().GetPalettePath(),
206                  NULL,                          // SfxItemPool* Pool
207                  pGlobalDrawPersist ?
208                     pGlobalDrawPersist :
209                     ( pDocument ? pDocument->GetDocumentShell() : NULL ),
210                  sal_True ),        // bUseExtColorTable (is set below)
211     aName( rName ),
212     pDoc( pDocument ),
213     pUndoGroup( NULL ),
214     bRecording( sal_False ),
215     bAdjustEnabled( sal_True ),
216     bHyphenatorSet( sal_False ),
217         mbUndoAllowed( sal_True )
218 {
219     pGlobalDrawPersist = NULL;          // nur einmal benutzen
220 
221     SfxObjectShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : NULL;
222     if ( pObjSh )
223     {
224         SetObjectShell( pObjSh );
225 
226         // set color table
227         SvxColorTableItem* pColItem = (SvxColorTableItem*) pObjSh->GetItem( SID_COLOR_TABLE );
228         XColorTable* pXCol = pColItem ? pColItem->GetColorTable() : XColorTable::GetStdColorTable();
229         SetColorTable( pXCol );
230     }
231     else
232         SetColorTable( XColorTable::GetStdColorTable() );
233 
234     SetSwapGraphics(sal_True);
235 //  SetSwapAsynchron(sal_True);     // an der View
236 
237     SetScaleUnit(MAP_100TH_MM);
238     SfxItemPool& rPool = GetItemPool();
239     rPool.SetDefaultMetric(SFX_MAPUNIT_100TH_MM);
240     SvxFrameDirectionItem aModeItem( FRMDIR_ENVIRONMENT, EE_PARA_WRITINGDIR );
241     rPool.SetPoolDefaultItem( aModeItem );
242 
243     // #i33700#
244     // Set shadow distance defaults as PoolDefaultItems. Details see bug.
245     rPool.SetPoolDefaultItem(SdrShadowXDistItem(300));
246     rPool.SetPoolDefaultItem(SdrShadowYDistItem(300));
247 
248     // #111216# default for script spacing depends on locale, see SdDrawDocument ctor in sd
249     LanguageType eOfficeLanguage = Application::GetSettings().GetLanguage();
250     if ( eOfficeLanguage == LANGUAGE_KOREAN || eOfficeLanguage == LANGUAGE_KOREAN_JOHAB ||
251          eOfficeLanguage == LANGUAGE_JAPANESE )
252     {
253         // secondary is edit engine pool
254         rPool.GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( sal_False, EE_PARA_ASIANCJKSPACING ) );
255     }
256 
257     rPool.FreezeIdRanges();                         // the pool is also used directly
258 
259     SdrLayerAdmin& rAdmin = GetLayerAdmin();
260     rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("vorne")),    SC_LAYER_FRONT);
261     rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("hinten")),   SC_LAYER_BACK);
262     rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("intern")),   SC_LAYER_INTERN);
263     rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Controls")), SC_LAYER_CONTROLS);
264     rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("hidden")),   SC_LAYER_HIDDEN);
265     // "Controls" is new - must also be created when loading
266 
267     //  Link fuer URL-Fields setzen
268     ScModule* pScMod = SC_MOD();
269     Outliner& rOutliner = GetDrawOutliner();
270     rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
271 
272     Outliner& rHitOutliner = GetHitTestOutliner();
273     rHitOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
274 
275     // #95129# SJ: set FontHeight pool defaults without changing static SdrEngineDefaults
276     SfxItemPool* pOutlinerPool = rOutliner.GetEditTextObjectPool();
277     if ( pOutlinerPool )
278         pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT ));           // 12Pt
279     SfxItemPool* pHitOutlinerPool = rHitOutliner.GetEditTextObjectPool();
280     if ( pHitOutlinerPool )
281         pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT ));    // 12Pt
282 
283     // initial undo mode as in Calc document
284     if( pDoc )
285         EnableUndo( pDoc->IsUndoEnabled() );
286 
287     //  URL-Buttons haben keinen Handler mehr, machen alles selber
288 
289     if( !nInst++ )
290     {
291         pFac = new ScDrawObjFactory;
292         pF3d = new E3dObjFactory;
293     }
294 }
295 
296 __EXPORT ScDrawLayer::~ScDrawLayer()
297 {
298     Broadcast(SdrHint(HINT_MODELCLEARED));
299 
300     // #116168#
301     //Clear();
302     ClearModel(sal_True);
303 
304     delete pUndoGroup;
305     if( !--nInst )
306     {
307         delete pFac, pFac = NULL;
308         delete pF3d, pF3d = NULL;
309     }
310 }
311 
312 void ScDrawLayer::UseHyphenator()
313 {
314     if (!bHyphenatorSet)
315     {
316         com::sun::star::uno::Reference< com::sun::star::linguistic2::XHyphenator >
317                                     xHyphenator = LinguMgr::GetHyphenator();
318 
319         GetDrawOutliner().SetHyphenator( xHyphenator );
320         GetHitTestOutliner().SetHyphenator( xHyphenator );
321 
322         bHyphenatorSet = sal_True;
323     }
324 }
325 
326 SdrPage* __EXPORT ScDrawLayer::AllocPage(FASTBOOL bMasterPage)
327 {
328     //  don't create basic until it is needed
329     StarBASIC* pBasic = NULL;
330     ScDrawPage* pPage = new ScDrawPage( *this, pBasic, sal::static_int_cast<sal_Bool>(bMasterPage) );
331     return pPage;
332 }
333 
334 sal_Bool ScDrawLayer::HasObjects() const
335 {
336     sal_Bool bFound = sal_False;
337 
338     sal_uInt16 nCount = GetPageCount();
339     for (sal_uInt16 i=0; i<nCount && !bFound; i++)
340         if (GetPage(i)->GetObjCount())
341             bFound = sal_True;
342 
343     return bFound;
344 }
345 
346 void ScDrawLayer::UpdateBasic()
347 {
348     //  don't create basic until it is needed
349     //! remove this method?
350 }
351 
352 SdrModel* __EXPORT ScDrawLayer::AllocModel() const
353 {
354     //  #103849# Allocated model (for clipboard etc) must not have a pointer
355     //  to the original model's document, pass NULL as document:
356 
357     return new ScDrawLayer( NULL, aName );
358 }
359 
360 Window* __EXPORT ScDrawLayer::GetCurDocViewWin()
361 {
362     DBG_ASSERT( pDoc, "ScDrawLayer::GetCurDocViewWin without document" );
363     if ( !pDoc )
364         return NULL;
365 
366     SfxViewShell* pViewSh = SfxViewShell::Current();
367     SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
368 
369     if (pViewSh && pViewSh->GetObjectShell() == pObjSh)
370         return pViewSh->GetWindow();
371 
372     return NULL;
373 }
374 
375 sal_Bool ScDrawLayer::ScAddPage( SCTAB nTab )
376 {
377     if (bDrawIsInUndo)
378         return sal_False;   // not inserted
379 
380     ScDrawPage* pPage = (ScDrawPage*)AllocPage( sal_False );
381     InsertPage(pPage, static_cast<sal_uInt16>(nTab));
382     if (bRecording)
383             AddCalcUndo< SdrUndoNewPage >(*pPage);
384 
385     return sal_True;        // inserted
386 }
387 
388 void ScDrawLayer::ScRemovePage( SCTAB nTab )
389 {
390     if (bDrawIsInUndo)
391         return;
392 
393     Broadcast( ScTabDeletedHint( nTab ) );
394     if (bRecording)
395     {
396         SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
397         AddCalcUndo< SdrUndoDelPage >(*pPage);      // Undo-Action wird Owner der Page
398         RemovePage( static_cast<sal_uInt16>(nTab) );                            // nur austragen, nicht loeschen
399     }
400     else
401         DeletePage( static_cast<sal_uInt16>(nTab) );                            // einfach weg damit
402 }
403 
404 void ScDrawLayer::ScRenamePage( SCTAB nTab, const String& rNewName )
405 {
406     ScDrawPage* pPage = (ScDrawPage*) GetPage(static_cast<sal_uInt16>(nTab));
407     if (pPage)
408         pPage->SetName(rNewName);
409 }
410 
411 void ScDrawLayer::ScMovePage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
412 {
413     MovePage( nOldPos, nNewPos );
414 }
415 
416 void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos, sal_Bool bAlloc )
417 {
418     //! remove argument bAlloc (always sal_False)
419 
420     if (bDrawIsInUndo)
421         return;
422 
423     SdrPage* pOldPage = GetPage(nOldPos);
424     SdrPage* pNewPage = bAlloc ? AllocPage(sal_False) : GetPage(nNewPos);
425 
426     // kopieren
427 
428     if (pOldPage && pNewPage)
429     {
430         SdrObjListIter aIter( *pOldPage, IM_FLAT );
431         SdrObject* pOldObject = aIter.Next();
432         while (pOldObject)
433         {
434             // #i112034# do not copy internal objects (detective) and note captions
435             if ( pOldObject->GetLayer() != SC_LAYER_INTERN && !IsNoteCaption( pOldObject ) )
436             {
437                 // #116235#
438                 SdrObject* pNewObject = pOldObject->Clone();
439                 //SdrObject* pNewObject = pOldObject->Clone( pNewPage, this );
440                 pNewObject->SetModel(this);
441                 pNewObject->SetPage(pNewPage);
442 
443                 pNewObject->NbcMove(Size(0,0));
444                 pNewPage->InsertObject( pNewObject );
445                 if (bRecording)
446                     AddCalcUndo< SdrUndoInsertObj >( *pNewObject );
447             }
448 
449             pOldObject = aIter.Next();
450         }
451     }
452 
453     if (bAlloc)
454         InsertPage(pNewPage, nNewPos);
455 }
456 
457 inline sal_Bool IsInBlock( const ScAddress& rPos, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2 )
458 {
459     return rPos.Col() >= nCol1 && rPos.Col() <= nCol2 &&
460            rPos.Row() >= nRow1 && rPos.Row() <= nRow2;
461 }
462 
463 void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
464                                 SCsCOL nDx,SCsROW nDy, bool bUpdateNoteCaptionPos )
465 {
466     SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
467     DBG_ASSERT(pPage,"Page nicht gefunden");
468     if (!pPage)
469         return;
470 
471     sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
472 
473     sal_uLong nCount = pPage->GetObjCount();
474     for ( sal_uLong i = 0; i < nCount; i++ )
475     {
476         SdrObject* pObj = pPage->GetObj( i );
477         ScDrawObjData* pData = GetObjDataTab( pObj, nTab );
478         if( pData )
479         {
480             const ScAddress aOldStt = pData->maStart;
481             const ScAddress aOldEnd = pData->maEnd;
482             sal_Bool bChange = sal_False;
483             if ( aOldStt.IsValid() && IsInBlock( aOldStt, nCol1,nRow1, nCol2,nRow2 ) )
484             {
485                 pData->maStart.IncCol( nDx );
486                 pData->maStart.IncRow( nDy );
487                 bChange = sal_True;
488             }
489             if ( aOldEnd.IsValid() && IsInBlock( aOldEnd, nCol1,nRow1, nCol2,nRow2 ) )
490             {
491                 pData->maEnd.IncCol( nDx );
492                 pData->maEnd.IncRow( nDy );
493                 bChange = sal_True;
494             }
495             if (bChange)
496             {
497                 if ( pObj->ISA( SdrRectObj ) && pData->maStart.IsValid() && pData->maEnd.IsValid() )
498                     pData->maStart.PutInOrder( pData->maEnd );
499                 AddCalcUndo< ScUndoObjData >( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd );
500                 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
501             }
502         }
503     }
504 }
505 
506 void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos )
507 {
508     SdrPage* pPage = GetPage(nPageNo);
509     if (pPage)
510     {
511         if ( rSize != pPage->GetSize() )
512         {
513             pPage->SetSize( rSize );
514             Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) );   // SetWorkArea() an den Views
515         }
516 
517         // Detektivlinien umsetzen (an neue Hoehen/Breiten anpassen)
518         //  auch wenn Groesse gleich geblieben ist
519         //  (einzelne Zeilen/Spalten koennen geaendert sein)
520 
521         sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
522 
523         sal_uLong nCount = pPage->GetObjCount();
524         for ( sal_uLong i = 0; i < nCount; i++ )
525         {
526             SdrObject* pObj = pPage->GetObj( i );
527             ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
528             if( pData )
529                 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
530         }
531     }
532 }
533 
534 void ScDrawLayer::RecalcPos( SdrObject* pObj, const ScDrawObjData& rData, bool bNegativePage, bool bUpdateNoteCaptionPos )
535 {
536     DBG_ASSERT( pDoc, "ScDrawLayer::RecalcPos - missing document" );
537     if( !pDoc )
538         return;
539 
540     if( rData.mbNote )
541     {
542         DBG_ASSERT( rData.maStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
543         /*  #i109372# On insert/remove rows/columns/cells: Updating the caption
544             position must not be done, if the cell containing the note has not
545             been moved yet in the document. The calling code now passes an
546             additional boolean stating if the cells are already moved. */
547         if( bUpdateNoteCaptionPos )
548             /*  When inside an undo action, there may be pending note captions
549                 where cell note is already deleted (thus document cannot find
550                 the note object anymore). The caption will be deleted later
551                 with drawing undo. */
552             if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
553                 pNote->UpdateCaptionPos( rData.maStart );
554         return;
555     }
556 
557     bool bValid1 = rData.maStart.IsValid();
558     SCCOL nCol1 = rData.maStart.Col();
559     SCROW nRow1 = rData.maStart.Row();
560     SCTAB nTab1 = rData.maStart.Tab();
561     bool bValid2 = rData.maEnd.IsValid();
562     SCCOL nCol2 = rData.maEnd.Col();
563     SCROW nRow2 = rData.maEnd.Row();
564     SCTAB nTab2 = rData.maEnd.Tab();
565 
566     // validation circle
567     bool bCircle = pObj->ISA( SdrCircObj );
568     // detective arrow
569     bool bArrow = pObj->IsPolyObj() && (pObj->GetPointCount() == 2);
570 
571     if( bCircle )
572     {
573         Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
574         TwipsToMM( aPos.X() );
575         TwipsToMM( aPos.Y() );
576 
577         //  Berechnung und Werte wie in detfunc.cxx
578 
579         Size aSize( (long)(pDoc->GetColWidth( nCol1, nTab1 ) * HMM_PER_TWIPS),
580                     (long)(pDoc->GetRowHeight( nRow1, nTab1 ) * HMM_PER_TWIPS) );
581         Rectangle aRect( aPos, aSize );
582         aRect.Left()    -= 250;
583         aRect.Right()   += 250;
584         aRect.Top()     -= 70;
585         aRect.Bottom()  += 70;
586         if ( bNegativePage )
587             MirrorRectRTL( aRect );
588 
589         if ( pObj->GetLogicRect() != aRect )
590         {
591             if (bRecording)
592                         AddCalcUndo<SdrUndoGeoObj>( *pObj );
593             pObj->SetLogicRect(aRect);
594         }
595     }
596     else if( bArrow )
597     {
598         //! nicht mehrere Undos fuer ein Objekt erzeugen (hinteres kann dann weggelassen werden)
599 
600         SCCOL nLastCol;
601         SCROW nLastRow;
602         if( bValid1 )
603         {
604             Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
605             if (!pDoc->ColHidden(nCol1, nTab1, nLastCol))
606                 aPos.X() += pDoc->GetColWidth( nCol1, nTab1 ) / 4;
607             if (!pDoc->RowHidden(nRow1, nTab1, nLastRow))
608                 aPos.Y() += pDoc->GetRowHeight( nRow1, nTab1 ) / 2;
609             TwipsToMM( aPos.X() );
610             TwipsToMM( aPos.Y() );
611             Point aStartPos = aPos;
612             if ( bNegativePage )
613                 aStartPos.X() = -aStartPos.X();     // don't modify aPos - used below
614             if ( pObj->GetPoint( 0 ) != aStartPos )
615             {
616                 if (bRecording)
617                             AddCalcUndo< SdrUndoGeoObj> ( *pObj );
618                 pObj->SetPoint( aStartPos, 0 );
619             }
620 
621             if( !bValid2 )
622             {
623                 Point aEndPos( aPos.X() + DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
624                 if (aEndPos.Y() < 0)
625                     aEndPos.Y() += (2 * DET_ARROW_OFFSET);
626                 if ( bNegativePage )
627                     aEndPos.X() = -aEndPos.X();
628                 if ( pObj->GetPoint( 1 ) != aEndPos )
629                 {
630                     if (bRecording)
631                                 AddCalcUndo< SdrUndoGeoObj >( *pObj );
632                     pObj->SetPoint( aEndPos, 1 );
633                 }
634             }
635         }
636         if( bValid2 )
637         {
638             Point aPos( pDoc->GetColOffset( nCol2, nTab2 ), pDoc->GetRowOffset( nRow2, nTab2 ) );
639             if (!pDoc->ColHidden(nCol2, nTab2, nLastCol))
640                 aPos.X() += pDoc->GetColWidth( nCol2, nTab2 ) / 4;
641             if (!pDoc->RowHidden(nRow2, nTab2, nLastRow))
642                 aPos.Y() += pDoc->GetRowHeight( nRow2, nTab2 ) / 2;
643             TwipsToMM( aPos.X() );
644             TwipsToMM( aPos.Y() );
645             Point aEndPos = aPos;
646             if ( bNegativePage )
647                 aEndPos.X() = -aEndPos.X();         // don't modify aPos - used below
648             if ( pObj->GetPoint( 1 ) != aEndPos )
649             {
650                 if (bRecording)
651                             AddCalcUndo< SdrUndoGeoObj> ( *pObj  );
652                 pObj->SetPoint( aEndPos, 1 );
653             }
654 
655             if( !bValid1 )
656             {
657                 Point aStartPos( aPos.X() - DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
658                 if (aStartPos.X() < 0)
659                     aStartPos.X() += (2 * DET_ARROW_OFFSET);
660                 if (aStartPos.Y() < 0)
661                     aStartPos.Y() += (2 * DET_ARROW_OFFSET);
662                 if ( bNegativePage )
663                     aStartPos.X() = -aStartPos.X();
664                 if ( pObj->GetPoint( 0 ) != aStartPos )
665                 {
666                     if (bRecording)
667                                     AddCalcUndo< SdrUndoGeoObj >( *pObj );
668                     pObj->SetPoint( aStartPos, 0 );
669                 }
670             }
671         }
672     }
673     else                                // Referenz-Rahmen
674     {
675         DBG_ASSERT( bValid1, "ScDrawLayer::RecalcPos - invalid start position" );
676         Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
677         TwipsToMM( aPos.X() );
678         TwipsToMM( aPos.Y() );
679 
680         if( bValid2 )
681         {
682             Point aEnd( pDoc->GetColOffset( nCol2 + 1, nTab2 ), pDoc->GetRowOffset( nRow2 + 1, nTab2 ) );
683             TwipsToMM( aEnd.X() );
684             TwipsToMM( aEnd.Y() );
685 
686             Rectangle aNew( aPos, aEnd );
687             if ( bNegativePage )
688                 MirrorRectRTL( aNew );
689             if ( pObj->GetLogicRect() != aNew )
690             {
691                 if (bRecording)
692                             AddCalcUndo< SdrUndoGeoObj >( *pObj );
693                 pObj->SetLogicRect(aNew);
694             }
695         }
696         else
697         {
698             if ( bNegativePage )
699                 aPos.X() = -aPos.X();
700             if ( pObj->GetRelativePos() != aPos )
701             {
702                 if (bRecording)
703                             AddCalcUndo< SdrUndoGeoObj >( *pObj );
704                 pObj->SetRelativePos( aPos );
705             }
706         }
707     }
708 }
709 
710 sal_Bool ScDrawLayer::GetPrintArea( ScRange& rRange, sal_Bool bSetHor, sal_Bool bSetVer ) const
711 {
712     DBG_ASSERT( pDoc, "ScDrawLayer::GetPrintArea without document" );
713     if ( !pDoc )
714         return sal_False;
715 
716     SCTAB nTab = rRange.aStart.Tab();
717     DBG_ASSERT( rRange.aEnd.Tab() == nTab, "GetPrintArea: Tab unterschiedlich" );
718 
719     sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
720 
721     sal_Bool bAny = sal_False;
722     long nEndX = 0;
723     long nEndY = 0;
724     long nStartX = LONG_MAX;
725     long nStartY = LONG_MAX;
726 
727     // Grenzen ausrechnen
728 
729     if (!bSetHor)
730     {
731         nStartX = 0;
732         SCCOL nStartCol = rRange.aStart.Col();
733             SCCOL i;
734         for (i=0; i<nStartCol; i++)
735             nStartX +=pDoc->GetColWidth(i,nTab);
736         nEndX = nStartX;
737         SCCOL nEndCol = rRange.aEnd.Col();
738         for (i=nStartCol; i<=nEndCol; i++)
739             nEndX += pDoc->GetColWidth(i,nTab);
740         nStartX = (long)(nStartX * HMM_PER_TWIPS);
741         nEndX   = (long)(nEndX   * HMM_PER_TWIPS);
742     }
743     if (!bSetVer)
744     {
745         nStartY = pDoc->GetRowHeight( 0, rRange.aStart.Row()-1, nTab);
746         nEndY = nStartY + pDoc->GetRowHeight( rRange.aStart.Row(),
747                 rRange.aEnd.Row(), nTab);
748         nStartY = (long)(nStartY * HMM_PER_TWIPS);
749         nEndY   = (long)(nEndY   * HMM_PER_TWIPS);
750     }
751 
752     if ( bNegativePage )
753     {
754         nStartX = -nStartX;     // positions are negative, swap start/end so the same comparisons work
755         nEndX   = -nEndX;
756         ::std::swap( nStartX, nEndX );
757     }
758 
759     const SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
760     DBG_ASSERT(pPage,"Page nicht gefunden");
761     if (pPage)
762     {
763         SdrObjListIter aIter( *pPage, IM_FLAT );
764         SdrObject* pObject = aIter.Next();
765         while (pObject)
766         {
767                             //! Flags (ausgeblendet?) testen
768 
769             Rectangle aObjRect = pObject->GetCurrentBoundRect();
770             sal_Bool bFit = sal_True;
771             if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
772                 bFit = sal_False;
773             if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
774                 bFit = sal_False;
775             // #i104716# don't include hidden note objects
776             if ( bFit && pObject->GetLayer() != SC_LAYER_HIDDEN )
777             {
778                 if (bSetHor)
779                 {
780                     if (aObjRect.Left() < nStartX) nStartX = aObjRect.Left();
781                     if (aObjRect.Right()  > nEndX) nEndX = aObjRect.Right();
782                 }
783                 if (bSetVer)
784                 {
785                     if (aObjRect.Top()  < nStartY) nStartY = aObjRect.Top();
786                     if (aObjRect.Bottom() > nEndY) nEndY = aObjRect.Bottom();
787                 }
788                 bAny = sal_True;
789             }
790 
791             pObject = aIter.Next();
792         }
793     }
794 
795     if ( bNegativePage )
796     {
797         nStartX = -nStartX;     // reverse transformation, so the same cell address calculation works
798         nEndX   = -nEndX;
799         ::std::swap( nStartX, nEndX );
800     }
801 
802     if (bAny)
803     {
804         DBG_ASSERT( nStartX<=nEndX && nStartY<=nEndY, "Start/End falsch in ScDrawLayer::GetPrintArea" );
805 
806         if (bSetHor)
807         {
808             nStartX = (long) (nStartX / HMM_PER_TWIPS);
809             nEndX = (long) (nEndX / HMM_PER_TWIPS);
810             long nWidth;
811             SCCOL i;
812 
813             nWidth = 0;
814             for (i=0; i<=MAXCOL && nWidth<=nStartX; i++)
815                 nWidth += pDoc->GetColWidth(i,nTab);
816             rRange.aStart.SetCol( i>0 ? (i-1) : 0 );
817 
818             nWidth = 0;
819             for (i=0; i<=MAXCOL && nWidth<=nEndX; i++)          //! bei Start anfangen
820                 nWidth += pDoc->GetColWidth(i,nTab);
821             rRange.aEnd.SetCol( i>0 ? (i-1) : 0 );
822         }
823 
824         if (bSetVer)
825         {
826             nStartY = (long) (nStartY / HMM_PER_TWIPS);
827             nEndY = (long) (nEndY / HMM_PER_TWIPS);
828             SCROW nRow = pDoc->GetRowForHeight( nTab, nStartY);
829             rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
830             nRow = pDoc->GetRowForHeight( nTab, nEndY);
831             rRange.aEnd.SetRow( nRow == MAXROW ? MAXROW :
832                     (nRow>0 ? (nRow-1) : 0));
833         }
834     }
835     else
836     {
837         if (bSetHor)
838         {
839             rRange.aStart.SetCol(0);
840             rRange.aEnd.SetCol(0);
841         }
842         if (bSetVer)
843         {
844             rRange.aStart.SetRow(0);
845             rRange.aEnd.SetRow(0);
846         }
847     }
848     return bAny;
849 }
850 
851 void ScDrawLayer::AddCalcUndo( SdrUndoAction* pUndo )
852 {
853     if (bRecording)
854     {
855         if (!pUndoGroup)
856             pUndoGroup = new SdrUndoGroup(*this);
857 
858         pUndoGroup->AddAction( pUndo );
859     }
860     else
861         delete pUndo;
862 }
863 
864 void ScDrawLayer::BeginCalcUndo()
865 {
866 //! DBG_ASSERT( !bRecording, "BeginCalcUndo ohne GetCalcUndo" );
867 
868     DELETEZ(pUndoGroup);
869     bRecording = sal_True;
870 }
871 
872 SdrUndoGroup* ScDrawLayer::GetCalcUndo()
873 {
874 //! DBG_ASSERT( bRecording, "GetCalcUndo ohne BeginCalcUndo" );
875 
876     SdrUndoGroup* pRet = pUndoGroup;
877     pUndoGroup = NULL;
878     bRecording = sal_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