Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / drwlayer.cxx
blob5d52b0c1c9c7ff3a2a37517c96a8a1300bc086f2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/uno/Reference.hxx>
21 #include <com/sun/star/chart/XChartDocument.hpp>
22 #include <com/sun/star/embed/XEmbeddedObject.hpp>
23 #include <com/sun/star/embed/XVisualObject.hpp>
24 #include <com/sun/star/embed/XClassifiedObject.hpp>
25 #include <com/sun/star/embed/XComponentSupplier.hpp>
26 #include <com/sun/star/embed/EmbedStates.hpp>
27 #include <com/sun/star/embed/ElementModes.hpp>
28 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
29 #include <com/sun/star/datatransfer/XTransferable.hpp>
31 #include "scitems.hxx"
32 #include <editeng/eeitem.hxx>
33 #include <editeng/frmdiritem.hxx>
34 #include <sot/exchange.hxx>
35 #include <svx/objfac3d.hxx>
36 #include <svx/xtable.hxx>
37 #include <svx/svdoutl.hxx>
38 #include <svx/svditer.hxx>
39 #include <svx/svdocapt.hxx>
40 #include <svx/svdocirc.hxx>
41 #include <svx/svdoedge.hxx>
42 #include <svx/svdograf.hxx>
43 #include <svx/svdoole2.hxx>
44 #include <svx/svdundo.hxx>
45 #include <i18nlangtag/mslangid.hxx>
46 #include <editeng/unolingu.hxx>
47 #include <svx/drawitem.hxx>
48 #include <editeng/fhgtitem.hxx>
49 #include <editeng/scriptspaceitem.hxx>
50 #include <svx/shapepropertynotifier.hxx>
51 #include <sfx2/viewsh.hxx>
52 #include <sfx2/docfile.hxx>
53 #include <sot/storage.hxx>
54 #include <unotools/pathoptions.hxx>
55 #include <svl/itempool.hxx>
56 #include <vcl/virdev.hxx>
57 #include <vcl/svapp.hxx>
58 #include <unotools/ucbstreamhelper.hxx>
60 #include <basegfx/polygon/b2dpolygon.hxx>
61 #include <basegfx/polygon/b2dpolygontools.hxx>
63 #include "drwlayer.hxx"
64 #include "drawpage.hxx"
65 #include "global.hxx"
66 #include "document.hxx"
67 #include "rechead.hxx"
68 #include "userdat.hxx"
69 #include "markdata.hxx"
70 #include "globstr.hrc"
71 #include "scmod.hxx"
72 #include "chartarr.hxx"
73 #include "postit.hxx"
74 #include "attrib.hxx"
75 #include "charthelper.hxx"
76 #include "basegfx/matrix/b2dhommatrix.hxx"
78 #include <vcl/field.hxx>
80 #define DET_ARROW_OFFSET 1000
82 using namespace ::com::sun::star;
84 // STATIC DATA -----------------------------------------------------------
86 TYPEINIT1(ScTabDeletedHint, SfxHint);
87 TYPEINIT1(ScTabSizeChangedHint, SfxHint);
89 static ScDrawObjFactory* pFac = NULL;
90 static E3dObjFactory* pF3d = NULL;
91 static sal_uInt16 nInst = 0;
93 SfxObjectShell* ScDrawLayer::pGlobalDrawPersist = NULL;
95 sal_Bool bDrawIsInUndo = false; //! Member
97 // -----------------------------------------------------------------------
99 ScUndoObjData::ScUndoObjData( SdrObject* pObjP, const ScAddress& rOS, const ScAddress& rOE,
100 const ScAddress& rNS, const ScAddress& rNE ) :
101 SdrUndoObj( *pObjP ),
102 aOldStt( rOS ),
103 aOldEnd( rOE ),
104 aNewStt( rNS ),
105 aNewEnd( rNE )
109 ScUndoObjData::~ScUndoObjData()
113 void ScUndoObjData::Undo()
115 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
116 OSL_ENSURE(pData,"ScUndoObjData: Data missing");
117 if (pData)
119 pData->maStart = aOldStt;
120 pData->maEnd = aOldEnd;
124 void ScUndoObjData::Redo()
126 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
127 OSL_ENSURE(pData,"ScUndoObjData: Data missing");
128 if (pData)
130 pData->maStart = aNewStt;
131 pData->maEnd = aNewEnd;
135 // -----------------------------------------------------------------------
137 ScTabDeletedHint::ScTabDeletedHint( SCTAB nTabNo ) :
138 nTab( nTabNo )
142 ScTabDeletedHint::~ScTabDeletedHint()
146 ScTabSizeChangedHint::ScTabSizeChangedHint( SCTAB nTabNo ) :
147 nTab( nTabNo )
151 ScTabSizeChangedHint::~ScTabSizeChangedHint()
155 // -----------------------------------------------------------------------
157 #define MAXMM 10000000
159 inline long TwipsToHmm (long nVal)
161 return static_cast< long >( MetricField::ConvertDoubleValue (static_cast<sal_Int64>(nVal), 0, 0,
162 FUNIT_TWIP, FUNIT_100TH_MM) );
165 inline long HmmToTwips (long nVal)
167 return static_cast< long > ( MetricField::ConvertDoubleValue (static_cast<sal_Int64>(nVal), 0, 0,
168 FUNIT_100TH_MM, FUNIT_TWIP) );
171 inline void TwipsToMM( long& nVal )
173 nVal = TwipsToHmm (nVal);
176 inline void ReverseTwipsToMM( long& nVal )
178 nVal = HmmToTwips (nVal);
181 static void lcl_ReverseTwipsToMM( Rectangle& rRect )
183 ReverseTwipsToMM( rRect.Left() );
184 ReverseTwipsToMM( rRect.Right() );
185 ReverseTwipsToMM( rRect.Top() );
186 ReverseTwipsToMM( rRect.Bottom() );
189 // -----------------------------------------------------------------------
192 ScDrawLayer::ScDrawLayer( ScDocument* pDocument, const OUString& rName ) :
193 FmFormModel( SvtPathOptions().GetPalettePath(),
194 NULL, // SfxItemPool* Pool
195 pGlobalDrawPersist ?
196 pGlobalDrawPersist :
197 ( pDocument ? pDocument->GetDocumentShell() : NULL ),
198 sal_True ), // bUseExtColorTable (is set below)
199 aName( rName ),
200 pDoc( pDocument ),
201 pUndoGroup( NULL ),
202 bRecording( false ),
203 bAdjustEnabled( sal_True ),
204 bHyphenatorSet( false )
206 pGlobalDrawPersist = NULL; // nur einmal benutzen
208 SfxObjectShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : NULL;
209 XColorListRef pXCol = XColorList::GetStdColorList();
210 if ( pObjSh )
212 SetObjectShell( pObjSh );
214 // set color table
215 SvxColorListItem* pColItem = (SvxColorListItem*) pObjSh->GetItem( SID_COLOR_TABLE );
216 if ( pColItem )
217 pXCol = pColItem->GetColorList();
219 SetPropertyList( static_cast<XPropertyList *> (pXCol.get()) );
221 SetSwapGraphics(sal_True);
223 SetScaleUnit(MAP_100TH_MM);
224 SfxItemPool& rPool = GetItemPool();
225 rPool.SetDefaultMetric(SFX_MAPUNIT_100TH_MM);
226 SvxFrameDirectionItem aModeItem( FRMDIR_ENVIRONMENT, EE_PARA_WRITINGDIR );
227 rPool.SetPoolDefaultItem( aModeItem );
229 // #i33700#
230 // Set shadow distance defaults as PoolDefaultItems. Details see bug.
231 rPool.SetPoolDefaultItem(SdrShadowXDistItem(300));
232 rPool.SetPoolDefaultItem(SdrShadowYDistItem(300));
234 // default for script spacing depends on locale, see SdDrawDocument ctor in sd
235 LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
236 if (MsLangId::isKorean(eOfficeLanguage) || eOfficeLanguage == LANGUAGE_JAPANESE)
238 // secondary is edit engine pool
239 rPool.GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
242 rPool.FreezeIdRanges(); // the pool is also used directly
244 SdrLayerAdmin& rAdmin = GetLayerAdmin();
245 rAdmin.NewLayer(OUString("vorne"), SC_LAYER_FRONT);
246 rAdmin.NewLayer(OUString("hinten"), SC_LAYER_BACK);
247 rAdmin.NewLayer(OUString("intern"), SC_LAYER_INTERN);
248 rAdmin.NewLayer(OUString("Controls"), SC_LAYER_CONTROLS);
249 rAdmin.NewLayer(OUString("hidden"), SC_LAYER_HIDDEN);
250 // "Controls" is new - must also be created when loading
252 // Link fuer URL-Fields setzen
253 ScModule* pScMod = SC_MOD();
254 Outliner& rOutliner = GetDrawOutliner();
255 rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
257 Outliner& rHitOutliner = GetHitTestOutliner();
258 rHitOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
260 // set FontHeight pool defaults without changing static SdrEngineDefaults
261 SfxItemPool* pOutlinerPool = rOutliner.GetEditTextObjectPool();
262 if ( pOutlinerPool )
263 pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
264 SfxItemPool* pHitOutlinerPool = rHitOutliner.GetEditTextObjectPool();
265 if ( pHitOutlinerPool )
266 pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
268 // initial undo mode as in Calc document
269 if( pDoc )
270 EnableUndo( pDoc->IsUndoEnabled() );
272 // URL-Buttons haben keinen Handler mehr, machen alles selber
274 if( !nInst++ )
276 pFac = new ScDrawObjFactory;
277 pF3d = new E3dObjFactory;
281 ScDrawLayer::~ScDrawLayer()
283 Broadcast(SdrHint(HINT_MODELCLEARED));
285 ClearModel(sal_True);
287 delete pUndoGroup;
288 if( !--nInst )
290 delete pFac, pFac = NULL;
291 delete pF3d, pF3d = NULL;
295 void ScDrawLayer::UseHyphenator()
297 if (!bHyphenatorSet)
299 com::sun::star::uno::Reference< com::sun::star::linguistic2::XHyphenator >
300 xHyphenator = LinguMgr::GetHyphenator();
302 GetDrawOutliner().SetHyphenator( xHyphenator );
303 GetHitTestOutliner().SetHyphenator( xHyphenator );
305 bHyphenatorSet = sal_True;
309 SdrPage* ScDrawLayer::AllocPage(bool bMasterPage)
311 // don't create basic until it is needed
312 StarBASIC* pBasic = NULL;
313 ScDrawPage* pPage = new ScDrawPage( *this, pBasic, bMasterPage);
314 return pPage;
317 sal_Bool ScDrawLayer::HasObjects() const
319 sal_Bool bFound = false;
321 sal_uInt16 nCount = GetPageCount();
322 for (sal_uInt16 i=0; i<nCount && !bFound; i++)
323 if (GetPage(i)->GetObjCount())
324 bFound = sal_True;
326 return bFound;
329 SdrModel* ScDrawLayer::AllocModel() const
331 // Allocated model (for clipboard etc) must not have a pointer
332 // to the original model's document, pass NULL as document:
334 return new ScDrawLayer( NULL, aName );
337 sal_Bool ScDrawLayer::ScAddPage( SCTAB nTab )
339 if (bDrawIsInUndo)
340 return false; // not inserted
342 ScDrawPage* pPage = (ScDrawPage*)AllocPage( false );
343 InsertPage(pPage, static_cast<sal_uInt16>(nTab));
344 if (bRecording)
345 AddCalcUndo(new SdrUndoNewPage(*pPage));
347 ResetTab(nTab, pDoc->GetTableCount()-1);
348 return true; // inserted
351 void ScDrawLayer::ScRemovePage( SCTAB nTab )
353 if (bDrawIsInUndo)
354 return;
356 Broadcast( ScTabDeletedHint( nTab ) );
357 if (bRecording)
359 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
360 AddCalcUndo(new SdrUndoDelPage(*pPage)); // Undo-Action wird Owner der Page
361 RemovePage( static_cast<sal_uInt16>(nTab) ); // nur austragen, nicht loeschen
363 else
364 DeletePage( static_cast<sal_uInt16>(nTab) ); // einfach weg damit
366 ResetTab(nTab, pDoc->GetTableCount()-1);
369 void ScDrawLayer::ScRenamePage( SCTAB nTab, const OUString& rNewName )
371 ScDrawPage* pPage = (ScDrawPage*) GetPage(static_cast<sal_uInt16>(nTab));
372 if (pPage)
373 pPage->SetName(rNewName);
376 void ScDrawLayer::ScMovePage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
378 MovePage( nOldPos, nNewPos );
379 sal_uInt16 nMinPos = std::min(nOldPos, nNewPos);
380 ResetTab(nMinPos, pDoc->GetTableCount()-1);
383 void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos, sal_Bool bAlloc )
385 //! remove argument bAlloc (always sal_False)
387 if (bDrawIsInUndo)
388 return;
390 SdrPage* pOldPage = GetPage(nOldPos);
391 SdrPage* pNewPage = bAlloc ? AllocPage(false) : GetPage(nNewPos);
393 // kopieren
395 if (pOldPage && pNewPage)
397 SCTAB nOldTab = static_cast<SCTAB>(nOldPos);
398 SCTAB nNewTab = static_cast<SCTAB>(nNewPos);
400 SdrObjListIter aIter( *pOldPage, IM_FLAT );
401 SdrObject* pOldObject = aIter.Next();
402 while (pOldObject)
404 ScDrawObjData* pOldData = GetObjData(pOldObject);
405 if (pOldData)
407 pOldData->maStart.SetTab(nOldTab);
408 pOldData->maEnd.SetTab(nOldTab);
410 SdrObject* pNewObject = pOldObject->Clone();
411 pNewObject->SetModel(this);
412 pNewObject->SetPage(pNewPage);
414 pNewObject->NbcMove(Size(0,0));
415 pNewPage->InsertObject( pNewObject );
416 ScDrawObjData* pNewData = GetObjData(pNewObject);
417 if (pNewData)
419 pNewData->maStart.SetTab(nNewTab);
420 pNewData->maEnd.SetTab(nNewTab);
423 if (bRecording)
424 AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) );
426 pOldObject = aIter.Next();
430 if (bAlloc)
431 InsertPage(pNewPage, nNewPos);
433 ResetTab(static_cast<SCTAB>(nNewPos), pDoc->GetTableCount()-1);
436 void ScDrawLayer::ResetTab( SCTAB nStart, SCTAB nEnd )
438 SCTAB nPageSize = static_cast<SCTAB>(GetPageCount());
439 if (nPageSize < 0)
440 // No drawing pages exist.
441 return;
443 if (nEnd >= nPageSize)
444 // Avoid iterating beyond the last existing page.
445 nEnd = nPageSize - 1;
447 for (SCTAB i = nStart; i <= nEnd; ++i)
449 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(i));
450 if (!pPage)
451 continue;
453 SdrObjListIter aIter(*pPage, IM_FLAT);
454 for (SdrObject* pObj = aIter.Next(); pObj; pObj = aIter.Next())
456 ScDrawObjData* pData = GetObjData(pObj);
457 if (!pData)
458 continue;
460 pData->maStart.SetTab(i);
461 pData->maEnd.SetTab(i);
466 inline sal_Bool IsInBlock( const ScAddress& rPos, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2 )
468 return rPos.Col() >= nCol1 && rPos.Col() <= nCol2 &&
469 rPos.Row() >= nRow1 && rPos.Row() <= nRow2;
472 void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
473 SCsCOL nDx,SCsROW nDy, bool bUpdateNoteCaptionPos )
475 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
476 OSL_ENSURE(pPage,"Page not found");
477 if (!pPage)
478 return;
480 sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
482 sal_uLong nCount = pPage->GetObjCount();
483 for ( sal_uLong i = 0; i < nCount; i++ )
485 SdrObject* pObj = pPage->GetObj( i );
486 ScDrawObjData* pData = GetObjDataTab( pObj, nTab );
487 if( pData )
489 const ScAddress aOldStt = pData->maStart;
490 const ScAddress aOldEnd = pData->maEnd;
491 sal_Bool bChange = false;
492 if ( aOldStt.IsValid() && IsInBlock( aOldStt, nCol1,nRow1, nCol2,nRow2 ) )
494 pData->maStart.IncCol( nDx );
495 pData->maStart.IncRow( nDy );
496 bChange = sal_True;
498 if ( aOldEnd.IsValid() && IsInBlock( aOldEnd, nCol1,nRow1, nCol2,nRow2 ) )
500 pData->maEnd.IncCol( nDx );
501 pData->maEnd.IncRow( nDy );
502 bChange = sal_True;
504 if (bChange)
506 if ( pObj->ISA( SdrRectObj ) && pData->maStart.IsValid() && pData->maEnd.IsValid() )
507 pData->maStart.PutInOrder( pData->maEnd );
508 AddCalcUndo( new ScUndoObjData( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd ) );
509 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
515 void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos )
517 SdrPage* pPage = GetPage(nPageNo);
518 if (pPage)
520 if ( rSize != pPage->GetSize() )
522 pPage->SetSize( rSize );
523 Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) ); // SetWorkArea() an den Views
526 // Detektivlinien umsetzen (an neue Hoehen/Breiten anpassen)
527 // auch wenn Groesse gleich geblieben ist
528 // (einzelne Zeilen/Spalten koennen geaendert sein)
530 sal_Bool bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
532 sal_uLong nCount = pPage->GetObjCount();
533 for ( sal_uLong i = 0; i < nCount; i++ )
535 SdrObject* pObj = pPage->GetObj( i );
536 ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
537 if( pData )
538 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
543 namespace
545 //Can't have a zero width dimension
546 Rectangle lcl_makeSafeRectangle(const Rectangle &rNew)
548 Rectangle aRect = rNew;
549 if (aRect.Bottom() == aRect.Top())
550 aRect.Bottom() = aRect.Top()+1;
551 if (aRect.Right() == aRect.Left())
552 aRect.Right() = aRect.Left()+1;
553 return aRect;
556 Point lcl_calcAvailableDiff(ScDocument &rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const Point &aWantedDiff)
558 Point aAvailableDiff(aWantedDiff);
559 long nHeight = static_cast<long>(rDoc.GetRowHeight( nRow, nTab ) * HMM_PER_TWIPS);
560 long nWidth = static_cast<long>(rDoc.GetColWidth( nCol, nTab ) * HMM_PER_TWIPS);
561 if (aAvailableDiff.Y() > nHeight)
562 aAvailableDiff.Y() = nHeight;
563 if (aAvailableDiff.X() > nWidth)
564 aAvailableDiff.X() = nWidth;
565 return aAvailableDiff;
568 Rectangle lcl_UpdateCalcPoly(basegfx::B2DPolygon &rCalcPoly, int nWhichPoint, const Point &rPos)
570 rCalcPoly.setB2DPoint(nWhichPoint, basegfx::B2DPoint(rPos.X(), rPos.Y()));
571 basegfx::B2DRange aRange(basegfx::tools::getRange(rCalcPoly));
572 return Rectangle(static_cast<long>(aRange.getMinX()), static_cast<long>(aRange.getMinY()),
573 static_cast<long>(aRange.getMaxX()), static_cast<long>(aRange.getMaxY()));
576 void ScDrawLayer::ResizeLastRectFromAnchor( SdrObject* pObj, ScDrawObjData& rData, bool bUseLogicRect, bool bNegativePage, bool bCanResize, bool bHiddenAsZero )
578 rData.maLastRect = ( bUseLogicRect ? pObj->GetLogicRect() : pObj->GetSnapRect() );
579 SCCOL nCol1 = rData.maStart.Col();
580 SCROW nRow1 = rData.maStart.Row();
581 SCTAB nTab1 = rData.maStart.Tab();
582 SCCOL nCol2 = rData.maEnd.Col();
583 SCROW nRow2 = rData.maEnd.Row();
584 SCTAB nTab2 = rData.maEnd.Tab();
585 Point aPos( pDoc->GetColOffset( nCol1, nTab1, bHiddenAsZero ), pDoc->GetRowOffset( nRow1, nTab1, bHiddenAsZero ) );
586 TwipsToMM( aPos.X() );
587 TwipsToMM( aPos.Y() );
588 aPos += lcl_calcAvailableDiff(*pDoc, nCol1, nRow1, nTab1, rData.maStartOffset);
590 if( bCanResize )
592 Point aEnd( pDoc->GetColOffset( nCol2, nTab2, bHiddenAsZero ), pDoc->GetRowOffset( nRow2, nTab2, bHiddenAsZero ) );
593 TwipsToMM( aEnd.X() );
594 TwipsToMM( aEnd.Y() );
595 aEnd += lcl_calcAvailableDiff(*pDoc, nCol2, nRow2, nTab2, rData.maEndOffset);
597 Rectangle aNew = Rectangle( aPos, aEnd );
598 if ( bNegativePage )
599 MirrorRectRTL( aNew );
601 rData.maLastRect = lcl_makeSafeRectangle(aNew);
603 else
605 if ( bNegativePage )
606 aPos.X() = -aPos.X() - rData.maLastRect.GetWidth();
607 // shouldn't we initialise maLastRect with the object rectangle ?
608 rData.maLastRect.SetPos( aPos );
612 void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegativePage, bool bUpdateNoteCaptionPos )
614 OSL_ENSURE( pDoc, "ScDrawLayer::RecalcPos - missing document" );
615 if( !pDoc )
616 return;
618 if (rData.meType == ScDrawObjData::CellNote)
620 OSL_ENSURE( rData.maStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
621 /* #i109372# On insert/remove rows/columns/cells: Updating the caption
622 position must not be done, if the cell containing the note has not
623 been moved yet in the document. The calling code now passes an
624 additional boolean stating if the cells are already moved. */
625 if( bUpdateNoteCaptionPos )
626 /* When inside an undo action, there may be pending note captions
627 where cell note is already deleted (thus document cannot find
628 the note object anymore). The caption will be deleted later
629 with drawing undo. */
630 if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
631 pNote->UpdateCaptionPos( rData.maStart );
632 return;
635 bool bValid1 = rData.maStart.IsValid();
636 SCCOL nCol1 = rData.maStart.Col();
637 SCROW nRow1 = rData.maStart.Row();
638 SCTAB nTab1 = rData.maStart.Tab();
639 bool bValid2 = rData.maEnd.IsValid();
640 SCCOL nCol2 = rData.maEnd.Col();
641 SCROW nRow2 = rData.maEnd.Row();
642 SCTAB nTab2 = rData.maEnd.Tab();
644 if (rData.meType == ScDrawObjData::ValidationCircle)
646 // Validation circle for detective.
647 rData.maLastRect = pObj->GetLogicRect();
649 Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
650 TwipsToMM( aPos.X() );
651 TwipsToMM( aPos.Y() );
653 // Berechnung und Werte wie in detfunc.cxx
655 Size aSize( (long)( TwipsToHmm( pDoc->GetColWidth( nCol1, nTab1) ) ),
656 (long)( TwipsToHmm( pDoc->GetRowHeight( nRow1, nTab1) ) ) );
657 Rectangle aRect( aPos, aSize );
658 aRect.Left() -= 250;
659 aRect.Right() += 250;
660 aRect.Top() -= 70;
661 aRect.Bottom() += 70;
662 if ( bNegativePage )
663 MirrorRectRTL( aRect );
665 if ( pObj->GetLogicRect() != aRect )
667 if (bRecording)
668 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
669 rData.maLastRect = lcl_makeSafeRectangle(aRect);
670 pObj->SetLogicRect(rData.maLastRect);
673 else if (rData.meType == ScDrawObjData::DetectiveArrow)
675 rData.maLastRect = pObj->GetLogicRect();
676 basegfx::B2DPolygon aCalcPoly;
677 Point aOrigStartPos(pObj->GetPoint(0));
678 Point aOrigEndPos(pObj->GetPoint(1));
679 aCalcPoly.append(basegfx::B2DPoint(aOrigStartPos.X(), aOrigStartPos.Y()));
680 aCalcPoly.append(basegfx::B2DPoint(aOrigEndPos.X(), aOrigEndPos.Y()));
681 //! nicht mehrere Undos fuer ein Objekt erzeugen (hinteres kann dann weggelassen werden)
683 SCCOL nLastCol;
684 SCROW nLastRow;
685 if( bValid1 )
687 Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
688 if (!pDoc->ColHidden(nCol1, nTab1, NULL, &nLastCol))
689 aPos.X() += pDoc->GetColWidth( nCol1, nTab1 ) / 4;
690 if (!pDoc->RowHidden(nRow1, nTab1, NULL, &nLastRow))
691 aPos.Y() += pDoc->GetRowHeight( nRow1, nTab1 ) / 2;
692 TwipsToMM( aPos.X() );
693 TwipsToMM( aPos.Y() );
694 Point aStartPos = aPos;
695 if ( bNegativePage )
696 aStartPos.X() = -aStartPos.X(); // don't modify aPos - used below
697 if ( pObj->GetPoint( 0 ) != aStartPos )
699 if (bRecording)
700 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
702 rData.maLastRect = lcl_UpdateCalcPoly(aCalcPoly, 0, aStartPos);
703 pObj->SetPoint( aStartPos, 0 );
706 if( !bValid2 )
708 Point aEndPos( aPos.X() + DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
709 if (aEndPos.Y() < 0)
710 aEndPos.Y() += (2 * DET_ARROW_OFFSET);
711 if ( bNegativePage )
712 aEndPos.X() = -aEndPos.X();
713 if ( pObj->GetPoint( 1 ) != aEndPos )
715 if (bRecording)
716 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
718 rData.maLastRect = lcl_UpdateCalcPoly(aCalcPoly, 1, aEndPos);
719 pObj->SetPoint( aEndPos, 1 );
723 if( bValid2 )
725 Point aPos( pDoc->GetColOffset( nCol2, nTab2 ), pDoc->GetRowOffset( nRow2, nTab2 ) );
726 if (!pDoc->ColHidden(nCol2, nTab2, NULL, &nLastCol))
727 aPos.X() += pDoc->GetColWidth( nCol2, nTab2 ) / 4;
728 if (!pDoc->RowHidden(nRow2, nTab2, NULL, &nLastRow))
729 aPos.Y() += pDoc->GetRowHeight( nRow2, nTab2 ) / 2;
730 TwipsToMM( aPos.X() );
731 TwipsToMM( aPos.Y() );
732 Point aEndPos = aPos;
733 if ( bNegativePage )
734 aEndPos.X() = -aEndPos.X(); // don't modify aPos - used below
735 if ( pObj->GetPoint( 1 ) != aEndPos )
737 if (bRecording)
738 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
740 rData.maLastRect = lcl_UpdateCalcPoly(aCalcPoly, 1, aEndPos);
741 pObj->SetPoint( aEndPos, 1 );
744 if( !bValid1 )
746 Point aStartPos( aPos.X() - DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
747 if (aStartPos.X() < 0)
748 aStartPos.X() += (2 * DET_ARROW_OFFSET);
749 if (aStartPos.Y() < 0)
750 aStartPos.Y() += (2 * DET_ARROW_OFFSET);
751 if ( bNegativePage )
752 aStartPos.X() = -aStartPos.X();
753 if ( pObj->GetPoint( 0 ) != aStartPos )
755 if (bRecording)
756 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
758 rData.maLastRect = lcl_UpdateCalcPoly(aCalcPoly, 0, aStartPos);
759 pObj->SetPoint( aStartPos, 0 );
764 else
766 bool bCanResize = bValid2 && !pObj->IsResizeProtect();
768 //First time positioning, must be able to at least move it
769 ScDrawObjData& rNoRotatedAnchor = *GetNonRotatedObjData( pObj, true );
770 if (rData.maLastRect.IsEmpty())
772 // It's confusing ( but blame that we persist the anchor in terms of unrotated shape )
773 // that the initial anchor we get here is in terms of an unrotated shape ( if the shape is rotated )
774 // we need to save the old anchor ( for persisting ) and also track any resize or repositions that happen.
776 // This is an evil hack, having a anchor that is one minute in terms of untransformed object and then later
777 // in terms of the transformed object is not ideal, similary having 2 anchors per object is wasteful, can't
778 // see another way out of this at the moment though.
779 rNoRotatedAnchor.maStart = rData.maStart;
780 rNoRotatedAnchor.maEnd = rData.maEnd;
781 rNoRotatedAnchor.maStartOffset = rData.maStartOffset;
782 rNoRotatedAnchor.maEndOffset = rData.maEndOffset;
784 Rectangle aRect = pObj->GetLogicRect();
786 // get bounding rectangle of shape ( include any hidden row/columns ), <sigh> we need to do this
787 // because if the shape is rotated the anchor from xml is in terms of the unrotated shape, if
788 // the shape is hidden ( by the rows that contain the shape being hidden ) then our hack of
789 // trying to infer the 'real' e.g. rotated anchor from the SnapRect will fail ( because the LogicRect will
790 // not have the correct position or size ) The only way we can possible do this is to first get the
791 // 'unrotated' shape dimensions from the persisted Anchor (from xml) and then 'create' an Anchor from the
792 // associated rotated shape ( note: we do this by actually setting the LogicRect for the shape temporarily to the
793 // *full* size then grabbing the SnapRect ( which gives the transformed rotated dimensions ), it would be
794 // wonderful if we could do this mathematically without having to temporarily tweak the object... othoh this way
795 // is gauranteed to get consistent results )
796 ResizeLastRectFromAnchor( pObj, rData, true, bNegativePage, bCanResize, false );
797 // aFullRect contains the unrotated size and position of the shape ( regardless of any hidden row/columns )
798 Rectangle aFullRect = rData.maLastRect;
800 // get current size and position from the anchor for use later
801 ResizeLastRectFromAnchor( pObj, rNoRotatedAnchor, true, bNegativePage, bCanResize );
803 // resize/position the shape to *full* size e.g. how it would be ( if no hidden rows/cols affected things )
804 pObj->SetLogicRect(aFullRect);
805 // capture rotated shape ( if relevant )
806 aRect = pObj->GetSnapRect();
808 // Ok, here is more nastyness, from xml the Anchor is in terms of the LogicRect which is the
809 // untransformed unrotated shape, here we swap out that initial anchor and from now on use
810 // an Anchor based on the SnapRect ( which is what you see on the screen )
811 ScDrawLayer::GetCellAnchorFromPosition( *pObj, rData, *pDoc, nTab1, false, false );
812 // reset shape to true 'maybe affected by hidden rows/cols' size calculated previously
813 pObj->SetLogicRect(rNoRotatedAnchor.maLastRect);
816 // update anchor with snap rect
817 ResizeLastRectFromAnchor( pObj, rData, false, bNegativePage, bCanResize );
819 if( bCanResize )
821 Rectangle aNew = rData.maLastRect;
823 if ( pObj->GetSnapRect() != aNew )
825 Rectangle aOld(pObj->GetSnapRect());
827 if (bRecording)
828 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
829 if (pObj->IsPolyObj())
831 // Polyline objects need special treatment.
832 Size aSizeMove(aNew.Left()-aOld.Left(), aNew.Top()-aOld.Top());
833 pObj->NbcMove(aSizeMove);
835 double fXFrac = static_cast<double>(aNew.GetWidth()) / static_cast<double>(aOld.GetWidth());
836 double fYFrac = static_cast<double>(aNew.GetHeight()) / static_cast<double>(aOld.GetHeight());
837 pObj->NbcResize(aNew.TopLeft(), Fraction(fXFrac), Fraction(fYFrac));
839 // order of these lines is important, modify rData.maLastRect carefully it is used as both
840 // a value and a flag for initialisation
841 rData.maLastRect = lcl_makeSafeRectangle(rData.maLastRect);
842 pObj->SetSnapRect(rData.maLastRect);
843 // update 'unrotated anchor' it's the anchor we persist, it must be kept in sync
844 // with the normal Anchor
845 ResizeLastRectFromAnchor( pObj, rNoRotatedAnchor, true, bNegativePage, bCanResize );
848 else
850 Point aPos( rData.maLastRect.getX(), rData.maLastRect.getY() );
851 if ( pObj->GetRelativePos() != aPos )
853 if (bRecording)
854 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
855 pObj->SetRelativePos( aPos );
859 * If we were not allowed resize the object, then the end cell anchor
860 * is possibly incorrect now, and if the object has no end-cell (e.g.
861 * missing in original .xml) we are also forced to generate one
863 bool bEndAnchorIsBad = !bValid2 || pObj->IsResizeProtect();
864 if (bEndAnchorIsBad)
866 // update 'rotated' anchor
867 ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, rData, *pDoc, nTab1, false);
868 // update 'unrotated' anchor
869 ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1 );
874 sal_Bool ScDrawLayer::GetPrintArea( ScRange& rRange, sal_Bool bSetHor, sal_Bool bSetVer ) const
876 OSL_ENSURE( pDoc, "ScDrawLayer::GetPrintArea without document" );
877 if ( !pDoc )
878 return false;
880 SCTAB nTab = rRange.aStart.Tab();
881 OSL_ENSURE( rRange.aEnd.Tab() == nTab, "GetPrintArea: Tab differ" );
883 sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
885 sal_Bool bAny = false;
886 long nEndX = 0;
887 long nEndY = 0;
888 long nStartX = LONG_MAX;
889 long nStartY = LONG_MAX;
891 // Grenzen ausrechnen
893 if (!bSetHor)
895 nStartX = 0;
896 SCCOL nStartCol = rRange.aStart.Col();
897 SCCOL i;
898 for (i=0; i<nStartCol; i++)
899 nStartX +=pDoc->GetColWidth(i,nTab);
900 nEndX = nStartX;
901 SCCOL nEndCol = rRange.aEnd.Col();
902 for (i=nStartCol; i<=nEndCol; i++)
903 nEndX += pDoc->GetColWidth(i,nTab);
904 nStartX = TwipsToHmm( nStartX );
905 nEndX = TwipsToHmm( nEndX );
907 if (!bSetVer)
909 nStartY = pDoc->GetRowHeight( 0, rRange.aStart.Row()-1, nTab);
910 nEndY = nStartY + pDoc->GetRowHeight( rRange.aStart.Row(),
911 rRange.aEnd.Row(), nTab);
912 nStartY = TwipsToHmm( nStartY );
913 nEndY = TwipsToHmm( nEndY );
916 if ( bNegativePage )
918 nStartX = -nStartX; // positions are negative, swap start/end so the same comparisons work
919 nEndX = -nEndX;
920 ::std::swap( nStartX, nEndX );
923 const SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
924 OSL_ENSURE(pPage,"Page not found");
925 if (pPage)
927 SdrObjListIter aIter( *pPage, IM_FLAT );
928 SdrObject* pObject = aIter.Next();
929 while (pObject)
931 //! Flags (ausgeblendet?) testen
933 Rectangle aObjRect = pObject->GetCurrentBoundRect();
934 sal_Bool bFit = sal_True;
935 if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
936 bFit = false;
937 if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
938 bFit = false;
939 // #i104716# don't include hidden note objects
940 if ( bFit && pObject->GetLayer() != SC_LAYER_HIDDEN )
942 if (bSetHor)
944 if (aObjRect.Left() < nStartX) nStartX = aObjRect.Left();
945 if (aObjRect.Right() > nEndX) nEndX = aObjRect.Right();
947 if (bSetVer)
949 if (aObjRect.Top() < nStartY) nStartY = aObjRect.Top();
950 if (aObjRect.Bottom() > nEndY) nEndY = aObjRect.Bottom();
952 bAny = sal_True;
955 pObject = aIter.Next();
959 if ( bNegativePage )
961 nStartX = -nStartX; // reverse transformation, so the same cell address calculation works
962 nEndX = -nEndX;
963 ::std::swap( nStartX, nEndX );
966 if (bAny)
968 OSL_ENSURE( nStartX<=nEndX && nStartY<=nEndY, "Start/End falsch in ScDrawLayer::GetPrintArea" );
970 if (bSetHor)
972 nStartX = HmmToTwips( nStartX );
973 nEndX = HmmToTwips( nEndX );
974 long nWidth;
975 SCCOL i;
977 nWidth = 0;
978 for (i=0; i<=MAXCOL && nWidth<=nStartX; i++)
979 nWidth += pDoc->GetColWidth(i,nTab);
980 rRange.aStart.SetCol( i>0 ? (i-1) : 0 );
982 nWidth = 0;
983 for (i=0; i<=MAXCOL && nWidth<=nEndX; i++) //! bei Start anfangen
984 nWidth += pDoc->GetColWidth(i,nTab);
985 rRange.aEnd.SetCol( i>0 ? (i-1) : 0 );
988 if (bSetVer)
990 nStartY = HmmToTwips( nStartY );
991 nEndY = HmmToTwips( nEndY );
992 SCROW nRow = pDoc->GetRowForHeight( nTab, nStartY);
993 rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
994 nRow = pDoc->GetRowForHeight( nTab, nEndY);
995 rRange.aEnd.SetRow( nRow == MAXROW ? MAXROW :
996 (nRow>0 ? (nRow-1) : 0));
999 else
1001 if (bSetHor)
1003 rRange.aStart.SetCol(0);
1004 rRange.aEnd.SetCol(0);
1006 if (bSetVer)
1008 rRange.aStart.SetRow(0);
1009 rRange.aEnd.SetRow(0);
1012 return bAny;
1015 void ScDrawLayer::AddCalcUndo( SdrUndoAction* pUndo )
1017 if (bRecording)
1019 if (!pUndoGroup)
1020 pUndoGroup = new SdrUndoGroup(*this);
1022 pUndoGroup->AddAction( pUndo );
1024 else
1025 delete pUndo;
1028 void ScDrawLayer::BeginCalcUndo(bool bDisableTextEditUsesCommonUndoManager)
1030 SetDisableTextEditUsesCommonUndoManager(bDisableTextEditUsesCommonUndoManager);
1031 DELETEZ(pUndoGroup);
1032 bRecording = sal_True;
1035 SdrUndoGroup* ScDrawLayer::GetCalcUndo()
1037 SdrUndoGroup* pRet = pUndoGroup;
1038 pUndoGroup = NULL;
1039 bRecording = false;
1040 SetDisableTextEditUsesCommonUndoManager(false);
1041 return pRet;
1044 void ScDrawLayer::MoveArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
1045 SCsCOL nDx,SCsROW nDy, sal_Bool bInsDel, bool bUpdateNoteCaptionPos )
1047 OSL_ENSURE( pDoc, "ScDrawLayer::MoveArea without document" );
1048 if ( !pDoc )
1049 return;
1051 if (!bAdjustEnabled)
1052 return;
1054 sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1056 Rectangle aRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1057 lcl_ReverseTwipsToMM( aRect );
1058 //! use twips directly?
1060 Point aMove;
1062 if (nDx > 0)
1063 for (SCsCOL s=0; s<nDx; s++)
1064 aMove.X() += pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
1065 else
1066 for (SCsCOL s=-1; s>=nDx; s--)
1067 aMove.X() -= pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
1068 if (nDy > 0)
1069 aMove.Y() += pDoc->GetRowHeight( nRow1, nRow1+nDy-1, nTab);
1070 else
1071 aMove.Y() -= pDoc->GetRowHeight( nRow1+nDy, nRow1-1, nTab);
1073 if ( bNegativePage )
1074 aMove.X() = -aMove.X();
1076 Point aTopLeft = aRect.TopLeft(); // Anfang beim Verkleinern
1077 if (bInsDel)
1079 if ( aMove.X() != 0 && nDx < 0 ) // nDx counts cells, sign is independent of RTL
1080 aTopLeft.X() += aMove.X();
1081 if ( aMove.Y() < 0 )
1082 aTopLeft.Y() += aMove.Y();
1086 // Detektiv-Pfeile: Zellpositionen anpassen
1089 MoveCells( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy, bUpdateNoteCaptionPos );
1092 sal_Bool ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow )
1094 OSL_ENSURE( pDoc, "ScDrawLayer::HasObjectsInRows without document" );
1095 if ( !pDoc )
1096 return false;
1098 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1099 OSL_ENSURE(pPage,"Page not found");
1100 if (!pPage)
1101 return sal_False;
1103 // for an empty page, there's no need to calculate the row heights
1104 if (!pPage->GetObjCount())
1105 return sal_False;
1107 Rectangle aTestRect;
1109 aTestRect.Top() += pDoc->GetRowHeight( 0, nStartRow-1, nTab);
1111 if (nEndRow==MAXROW)
1112 aTestRect.Bottom() = MAXMM;
1113 else
1115 aTestRect.Bottom() = aTestRect.Top();
1116 aTestRect.Bottom() += pDoc->GetRowHeight( nStartRow, nEndRow, nTab);
1117 TwipsToMM( aTestRect.Bottom() );
1120 TwipsToMM( aTestRect.Top() );
1122 aTestRect.Left() = 0;
1123 aTestRect.Right() = MAXMM;
1125 sal_Bool bNegativePage = pDoc->IsNegativePage( nTab );
1126 if ( bNegativePage )
1127 MirrorRectRTL( aTestRect );
1129 sal_Bool bFound = false;
1131 Rectangle aObjRect;
1132 SdrObjListIter aIter( *pPage );
1133 SdrObject* pObject = aIter.Next();
1134 while ( pObject && !bFound )
1136 aObjRect = pObject->GetSnapRect(); //! GetLogicRect ?
1137 if (aTestRect.IsInside(aObjRect.TopLeft()) || aTestRect.IsInside(aObjRect.BottomLeft()))
1138 bFound = true;
1140 pObject = aIter.Next();
1143 return bFound;
1146 void ScDrawLayer::DeleteObjectsInArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1,
1147 SCCOL nCol2,SCROW nRow2 )
1149 OSL_ENSURE( pDoc, "ScDrawLayer::DeleteObjectsInArea without document" );
1150 if ( !pDoc )
1151 return;
1153 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1154 OSL_ENSURE(pPage,"Page ?");
1155 if (!pPage)
1156 return;
1158 pPage->RecalcObjOrdNums();
1160 sal_uLong nObjCount = pPage->GetObjCount();
1161 if (nObjCount)
1163 long nDelCount = 0;
1164 Rectangle aDelRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1166 SdrObject** ppObj = new SdrObject*[nObjCount];
1168 SdrObjListIter aIter( *pPage, IM_FLAT );
1169 SdrObject* pObject = aIter.Next();
1170 while (pObject)
1172 // do not delete note caption, they are always handled by the cell note
1173 // TODO: detective objects are still deleted, is this desired?
1174 if (!IsNoteCaption( pObject ))
1176 Rectangle aObjRect = pObject->GetCurrentBoundRect();
1177 if ( aDelRect.IsInside( aObjRect ) )
1178 ppObj[nDelCount++] = pObject;
1181 pObject = aIter.Next();
1184 long i;
1185 if (bRecording)
1186 for (i=1; i<=nDelCount; i++)
1187 AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
1189 for (i=1; i<=nDelCount; i++)
1190 pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1192 delete[] ppObj;
1196 void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
1198 OSL_ENSURE( pDoc, "ScDrawLayer::DeleteObjectsInSelection without document" );
1199 if ( !pDoc )
1200 return;
1202 if ( !rMark.IsMultiMarked() )
1203 return;
1205 ScRange aMarkRange;
1206 rMark.GetMultiMarkArea( aMarkRange );
1208 SCTAB nTabCount = pDoc->GetTableCount();
1209 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
1210 for (; itr != itrEnd && *itr < nTabCount; ++itr)
1212 SCTAB nTab = *itr;
1213 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1214 if (pPage)
1216 pPage->RecalcObjOrdNums();
1217 sal_uLong nObjCount = pPage->GetObjCount();
1218 if (nObjCount)
1220 long nDelCount = 0;
1221 // Rechteck um die ganze Selektion
1222 Rectangle aMarkBound = pDoc->GetMMRect(
1223 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
1224 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab );
1226 SdrObject** ppObj = new SdrObject*[nObjCount];
1228 SdrObjListIter aIter( *pPage, IM_FLAT );
1229 SdrObject* pObject = aIter.Next();
1230 while (pObject)
1232 // do not delete note caption, they are always handled by the cell note
1233 // TODO: detective objects are still deleted, is this desired?
1234 if (!IsNoteCaption( pObject ))
1236 Rectangle aObjRect = pObject->GetCurrentBoundRect();
1237 if ( aMarkBound.IsInside( aObjRect ) )
1239 ScRange aRange = pDoc->GetRange( nTab, aObjRect );
1240 if (rMark.IsAllMarked(aRange))
1241 ppObj[nDelCount++] = pObject;
1245 pObject = aIter.Next();
1248 // Objekte loeschen (rueckwaerts)
1250 long i;
1251 if (bRecording)
1252 for (i=1; i<=nDelCount; i++)
1253 AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
1255 for (i=1; i<=nDelCount; i++)
1256 pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1258 delete[] ppObj;
1261 else
1263 OSL_FAIL("pPage?");
1268 void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const Rectangle& rRange )
1270 // copy everything in the specified range into the same page (sheet) in the clipboard doc
1272 SdrPage* pSrcPage = GetPage(static_cast<sal_uInt16>(nTab));
1273 if (pSrcPage)
1275 ScDrawLayer* pDestModel = NULL;
1276 SdrPage* pDestPage = NULL;
1278 SdrObjListIter aIter( *pSrcPage, IM_FLAT );
1279 SdrObject* pOldObject = aIter.Next();
1280 while (pOldObject)
1282 Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1283 // do not copy internal objects (detective) and note captions
1284 if ( rRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
1286 if ( !pDestModel )
1288 pDestModel = pClipDoc->GetDrawLayer(); // does the document already have a drawing layer?
1289 if ( !pDestModel )
1291 // allocate drawing layer in clipboard document only if there are objects to copy
1293 pClipDoc->InitDrawLayer(); //! create contiguous pages
1294 pDestModel = pClipDoc->GetDrawLayer();
1296 if (pDestModel)
1297 pDestPage = pDestModel->GetPage( static_cast<sal_uInt16>(nTab) );
1300 OSL_ENSURE( pDestPage, "no page" );
1301 if (pDestPage)
1303 SdrObject* pNewObject = pOldObject->Clone();
1304 pNewObject->SetModel(pDestModel);
1305 pNewObject->SetPage(pDestPage);
1307 uno::Reference< chart2::XChartDocument > xOldChart( ScChartHelper::GetChartFromSdrObject( pOldObject ) );
1308 if(!xOldChart.is())//#i110034# do not move charts as they loose all their data references otherwise
1309 pNewObject->NbcMove(Size(0,0));
1310 pDestPage->InsertObject( pNewObject );
1312 // no undo needed in clipboard document
1313 // charts are not updated
1317 pOldObject = aIter.Next();
1322 static sal_Bool lcl_IsAllInRange( const ::std::vector< ScRangeList >& rRangesVector, const ScRange& rClipRange )
1324 // check if every range of rRangesVector is completely in rClipRange
1326 ::std::vector< ScRangeList >::const_iterator aIt = rRangesVector.begin();
1327 for( ;aIt!=rRangesVector.end(); ++aIt )
1329 const ScRangeList& rRanges = *aIt;
1330 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
1332 ScRange aRange = *rRanges[ i ];
1333 if ( !rClipRange.In( aRange ) )
1335 return false; // at least one range is not valid
1340 return sal_True; // everything is fine
1343 static sal_Bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const ScRange& rSourceRange, const ScAddress& rDestPos )
1345 sal_Bool bChanged = false;
1347 ::std::vector< ScRangeList >::iterator aIt = rRangesVector.begin();
1348 for( ;aIt!=rRangesVector.end(); ++aIt )
1350 ScRangeList& rRanges = *aIt;
1351 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
1353 ScRange* pRange = rRanges[ i ];
1354 if ( rSourceRange.In( *pRange ) )
1356 SCsCOL nDiffX = rDestPos.Col() - (SCsCOL)rSourceRange.aStart.Col();
1357 SCsROW nDiffY = rDestPos.Row() - (SCsROW)rSourceRange.aStart.Row();
1358 SCsTAB nDiffZ = rDestPos.Tab() - (SCsTAB)rSourceRange.aStart.Tab();
1359 pRange->Move( nDiffX, nDiffY, nDiffZ );
1360 bChanged = sal_True;
1365 return bChanged;
1368 void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const Rectangle& rSourceRange,
1369 const ScAddress& rDestPos, const Rectangle& rDestRange )
1371 OSL_ENSURE( pDoc, "ScDrawLayer::CopyFromClip without document" );
1372 if ( !pDoc )
1373 return;
1375 if (!pClipModel)
1376 return;
1378 if (bDrawIsInUndo) //! can this happen?
1380 OSL_FAIL("CopyFromClip, bDrawIsInUndo");
1381 return;
1384 sal_Bool bMirrorObj = ( rSourceRange.Left() < 0 && rSourceRange.Right() < 0 &&
1385 rDestRange.Left() > 0 && rDestRange.Right() > 0 ) ||
1386 ( rSourceRange.Left() > 0 && rSourceRange.Right() > 0 &&
1387 rDestRange.Left() < 0 && rDestRange.Right() < 0 );
1388 Rectangle aMirroredSource = rSourceRange;
1389 if ( bMirrorObj )
1390 MirrorRectRTL( aMirroredSource );
1392 SCTAB nDestTab = rDestPos.Tab();
1394 SdrPage* pSrcPage = pClipModel->GetPage(static_cast<sal_uInt16>(nSourceTab));
1395 SdrPage* pDestPage = GetPage(static_cast<sal_uInt16>(nDestTab));
1396 OSL_ENSURE( pSrcPage && pDestPage, "draw page missing" );
1397 if ( !pSrcPage || !pDestPage )
1398 return;
1400 SdrObjListIter aIter( *pSrcPage, IM_FLAT );
1401 SdrObject* pOldObject = aIter.Next();
1403 ScDocument* pClipDoc = pClipModel->GetDocument();
1404 // a clipboard document and its source share the same document item pool,
1405 // so the pointers can be compared to see if this is copy&paste within
1406 // the same document
1407 sal_Bool bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
1408 sal_Bool bDestClip = pDoc && pDoc->IsClipboard();
1410 //#i110034# charts need correct sheet names for xml range conversion during load
1411 //so the target sheet name is temporarily renamed (if we have any SdrObjects)
1412 OUString aDestTabName;
1413 sal_Bool bRestoreDestTabName = false;
1414 if( pOldObject && !bSameDoc && !bDestClip )
1416 if( pDoc && pClipDoc )
1418 OUString aSourceTabName;
1419 if( pClipDoc->GetName( nSourceTab, aSourceTabName )
1420 && pDoc->GetName( nDestTab, aDestTabName ) )
1422 if( !aSourceTabName.equals(aDestTabName) &&
1423 pDoc->ValidNewTabName(aSourceTabName) )
1425 bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName ); //sal_Bool bUpdateRef = sal_True, sal_Bool bExternalDocument = sal_False
1431 // first mirror, then move
1432 Size aMove( rDestRange.Left() - aMirroredSource.Left(), rDestRange.Top() - aMirroredSource.Top() );
1434 long nDestWidth = rDestRange.GetWidth();
1435 long nDestHeight = rDestRange.GetHeight();
1436 long nSourceWidth = rSourceRange.GetWidth();
1437 long nSourceHeight = rSourceRange.GetHeight();
1439 long nWidthDiff = nDestWidth - nSourceWidth;
1440 long nHeightDiff = nDestHeight - nSourceHeight;
1442 Fraction aHorFract(1,1);
1443 Fraction aVerFract(1,1);
1444 sal_Bool bResize = false;
1445 // sizes can differ by 1 from twips->1/100mm conversion for equal cell sizes,
1446 // don't resize to empty size when pasting into hidden columns or rows
1447 if ( std::abs(nWidthDiff) > 1 && nDestWidth > 1 && nSourceWidth > 1 )
1449 aHorFract = Fraction( nDestWidth, nSourceWidth );
1450 bResize = sal_True;
1452 if ( std::abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
1454 aVerFract = Fraction( nDestHeight, nSourceHeight );
1455 bResize = sal_True;
1457 Point aRefPos = rDestRange.TopLeft(); // for resizing (after moving)
1459 while (pOldObject)
1461 Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1462 // do not copy internal objects (detective) and note captions
1463 if ( rSourceRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
1465 SdrObject* pNewObject = pOldObject->Clone();
1466 pNewObject->SetModel(this);
1467 pNewObject->SetPage(pDestPage);
1469 if ( bMirrorObj )
1470 MirrorRTL( pNewObject ); // first mirror, then move
1472 pNewObject->NbcMove( aMove );
1473 if ( bResize )
1474 pNewObject->NbcResize( aRefPos, aHorFract, aVerFract );
1476 pDestPage->InsertObject( pNewObject );
1477 if (bRecording)
1478 AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) );
1480 //#i110034# handle chart data references (after InsertObject)
1482 if ( pNewObject->GetObjIdentifier() == OBJ_OLE2 )
1484 uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pNewObject)->GetObjRef();
1485 uno::Reference< embed::XClassifiedObject > xClassified( xIPObj, uno::UNO_QUERY );
1486 SvGlobalName aObjectClassName;
1487 if ( xClassified.is() )
1489 try {
1490 aObjectClassName = SvGlobalName( xClassified->getClassID() );
1491 } catch( uno::Exception& )
1493 // TODO: handle error?
1497 if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
1499 uno::Reference< chart2::XChartDocument > xNewChart( ScChartHelper::GetChartFromSdrObject( pNewObject ) );
1500 if( xNewChart.is() && !xNewChart->hasInternalDataProvider() )
1502 OUString aChartName = ((SdrOle2Obj*)pNewObject)->GetPersistName();
1503 ::std::vector< ScRangeList > aRangesVector;
1504 pDoc->GetChartRanges( aChartName, aRangesVector, pDoc );
1505 if( !aRangesVector.empty() )
1507 sal_Bool bInSourceRange = false;
1508 ScRange aClipRange;
1509 if ( pClipDoc )
1511 SCCOL nClipStartX;
1512 SCROW nClipStartY;
1513 SCCOL nClipEndX;
1514 SCROW nClipEndY;
1515 pClipDoc->GetClipStart( nClipStartX, nClipStartY );
1516 pClipDoc->GetClipArea( nClipEndX, nClipEndY, sal_True );
1517 nClipEndX = nClipEndX + nClipStartX;
1518 nClipEndY += nClipStartY; // GetClipArea returns the difference
1520 SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
1521 aClipRange = ScRange( nClipStartX, nClipStartY, nClipTab,
1522 nClipEndX, nClipEndY, nClipTab );
1524 bInSourceRange = lcl_IsAllInRange( aRangesVector, aClipRange );
1527 // always lose references when pasting into a clipboard document (transpose)
1528 if ( ( bInSourceRange || bSameDoc ) && !bDestClip )
1530 if ( bInSourceRange )
1532 if ( rDestPos != aClipRange.aStart )
1534 // update the data ranges to the new (copied) position
1535 if ( lcl_MoveRanges( aRangesVector, aClipRange, rDestPos ) )
1536 pDoc->SetChartRanges( aChartName, aRangesVector );
1539 else
1541 // leave the ranges unchanged
1544 else
1546 // pasting into a new document without the complete source data
1547 // -> break connection to source data and switch to own data
1549 uno::Reference< chart::XChartDocument > xOldChartDoc( ScChartHelper::GetChartFromSdrObject( pOldObject ), uno::UNO_QUERY );
1550 uno::Reference< chart::XChartDocument > xNewChartDoc( xNewChart, uno::UNO_QUERY );
1551 if( xOldChartDoc.is() && xNewChartDoc.is() )
1552 xNewChartDoc->attachData( xOldChartDoc->getData() );
1554 // (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
1562 pOldObject = aIter.Next();
1565 if( bRestoreDestTabName )
1566 pDoc->RenameTab( nDestTab, aDestTabName );
1569 void ScDrawLayer::MirrorRTL( SdrObject* pObj )
1571 sal_uInt16 nIdent = pObj->GetObjIdentifier();
1573 // don't mirror OLE or graphics, otherwise ask the object
1574 // if it can be mirrored
1575 sal_Bool bCanMirror = ( nIdent != OBJ_GRAF && nIdent != OBJ_OLE2 );
1576 if (bCanMirror)
1578 SdrObjTransformInfoRec aInfo;
1579 pObj->TakeObjInfo( aInfo );
1580 bCanMirror = aInfo.bMirror90Allowed;
1583 if (bCanMirror)
1585 Point aRef1( 0, 0 );
1586 Point aRef2( 0, 1 );
1587 if (bRecording)
1588 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
1589 pObj->Mirror( aRef1, aRef2 );
1591 else
1593 // Move instead of mirroring:
1594 // New start position is negative of old end position
1595 // -> move by sum of start and end position
1596 Rectangle aObjRect = pObj->GetLogicRect();
1597 Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
1598 if (bRecording)
1599 AddCalcUndo( new SdrUndoMoveObj( *pObj, aMoveSize ) );
1600 pObj->Move( aMoveSize );
1604 void ScDrawLayer::MirrorRectRTL( Rectangle& rRect )
1606 // mirror and swap left/right
1607 long nTemp = rRect.Left();
1608 rRect.Left() = -rRect.Right();
1609 rRect.Right() = -nTemp;
1612 Rectangle ScDrawLayer::GetCellRect( ScDocument& rDoc, const ScAddress& rPos, bool bMergedCell )
1614 Rectangle aCellRect;
1615 OSL_ENSURE( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ), "ScDrawLayer::GetCellRect - invalid cell address" );
1616 if( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ) )
1618 // find top left position of passed cell address
1619 Point aTopLeft;
1620 for( SCCOL nCol = 0; nCol < rPos.Col(); ++nCol )
1621 aTopLeft.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
1622 if( rPos.Row() > 0 )
1623 aTopLeft.Y() += rDoc.GetRowHeight( 0, rPos.Row() - 1, rPos.Tab() );
1625 // find bottom-right position of passed cell address
1626 ScAddress aEndPos = rPos;
1627 if( bMergedCell )
1629 const ScMergeAttr* pMerge = static_cast< const ScMergeAttr* >( rDoc.GetAttr( rPos.Col(), rPos.Row(), rPos.Tab(), ATTR_MERGE ) );
1630 if( pMerge->GetColMerge() > 1 )
1631 aEndPos.IncCol( pMerge->GetColMerge() - 1 );
1632 if( pMerge->GetRowMerge() > 1 )
1633 aEndPos.IncRow( pMerge->GetRowMerge() - 1 );
1635 Point aBotRight = aTopLeft;
1636 for( SCCOL nCol = rPos.Col(); nCol <= aEndPos.Col(); ++nCol )
1637 aBotRight.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
1638 aBotRight.Y() += rDoc.GetRowHeight( rPos.Row(), aEndPos.Row(), rPos.Tab() );
1640 // twips -> 1/100 mm
1641 aTopLeft.X() = static_cast< long >( aTopLeft.X() * HMM_PER_TWIPS );
1642 aTopLeft.Y() = static_cast< long >( aTopLeft.Y() * HMM_PER_TWIPS );
1643 aBotRight.X() = static_cast< long >( aBotRight.X() * HMM_PER_TWIPS );
1644 aBotRight.Y() = static_cast< long >( aBotRight.Y() * HMM_PER_TWIPS );
1646 aCellRect = Rectangle( aTopLeft, aBotRight );
1647 if( rDoc.IsNegativePage( rPos.Tab() ) )
1648 MirrorRectRTL( aCellRect );
1650 return aCellRect;
1653 OUString ScDrawLayer::GetVisibleName( SdrObject* pObj )
1655 OUString aName = pObj->GetName();
1656 if ( pObj->GetObjIdentifier() == OBJ_OLE2 )
1658 // For OLE, the user defined name (GetName) is used
1659 // if it's not empty (accepting possibly duplicate names),
1660 // otherwise the persist name is used so every object appears
1661 // in the Navigator at all.
1663 if ( aName.isEmpty() )
1664 aName = static_cast<SdrOle2Obj*>(pObj)->GetPersistName();
1666 return aName;
1669 inline sal_Bool IsNamedObject( SdrObject* pObj, const OUString& rName )
1671 // sal_True if rName is the object's Name or PersistName
1672 // (used to find a named object)
1674 return ( pObj->GetName().equals(rName) ||
1675 ( pObj->GetObjIdentifier() == OBJ_OLE2 &&
1676 static_cast<SdrOle2Obj*>(pObj)->GetPersistName() == rName ) );
1679 SdrObject* ScDrawLayer::GetNamedObject( const OUString& rName, sal_uInt16 nId, SCTAB& rFoundTab ) const
1681 sal_uInt16 nTabCount = GetPageCount();
1682 for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
1684 const SdrPage* pPage = GetPage(nTab);
1685 OSL_ENSURE(pPage,"Page ?");
1686 if (pPage)
1688 SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
1689 SdrObject* pObject = aIter.Next();
1690 while (pObject)
1692 if ( nId == 0 || pObject->GetObjIdentifier() == nId )
1693 if ( IsNamedObject( pObject, rName ) )
1695 rFoundTab = static_cast<SCTAB>(nTab);
1696 return pObject;
1699 pObject = aIter.Next();
1704 return NULL;
1707 OUString ScDrawLayer::GetNewGraphicName( long* pnCounter ) const
1709 OUString aBase = ScGlobal::GetRscString(STR_GRAPHICNAME);
1710 aBase += " ";
1712 bool bThere = true;
1713 OUString aGraphicName;
1714 SCTAB nDummy;
1715 long nId = pnCounter ? *pnCounter : 0;
1716 while (bThere)
1718 ++nId;
1719 aGraphicName = aBase;
1720 aGraphicName += OUString::number( nId );
1721 bThere = ( GetNamedObject( aGraphicName, 0, nDummy ) != NULL );
1724 if ( pnCounter )
1725 *pnCounter = nId;
1727 return aGraphicName;
1730 void ScDrawLayer::EnsureGraphicNames()
1732 // make sure all graphic objects have names (after Excel import etc.)
1734 sal_uInt16 nTabCount = GetPageCount();
1735 for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
1737 SdrPage* pPage = GetPage(nTab);
1738 OSL_ENSURE(pPage,"Page ?");
1739 if (pPage)
1741 SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
1742 SdrObject* pObject = aIter.Next();
1744 /* The index passed to GetNewGraphicName() will be set to
1745 the used index in each call. This prevents the repeated search
1746 for all names from 1 to current index. */
1747 long nCounter = 0;
1749 while (pObject)
1751 if ( pObject->GetObjIdentifier() == OBJ_GRAF && pObject->GetName().isEmpty())
1752 pObject->SetName( GetNewGraphicName( &nCounter ) );
1754 pObject = aIter.Next();
1760 namespace
1762 SdrObjUserData* GetFirstUserDataOfType(const SdrObject *pObj, sal_uInt16 nId)
1764 sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
1765 for( sal_uInt16 i = 0; i < nCount; i++ )
1767 SdrObjUserData* pData = pObj->GetUserData( i );
1768 if( pData && pData->GetInventor() == SC_DRAWLAYER && pData->GetId() == nId )
1769 return pData;
1771 return NULL;
1774 void DeleteFirstUserDataOfType(SdrObject *pObj, sal_uInt16 nId)
1776 sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
1777 for( sal_uInt16 i = nCount; i > 0; i-- )
1779 SdrObjUserData* pData = pObj->GetUserData( i-1 );
1780 if( pData && pData->GetInventor() == SC_DRAWLAYER && pData->GetId() == nId )
1781 pObj->DeleteUserData(i-1);
1786 void ScDrawLayer::SetVisualCellAnchored( SdrObject &rObj, const ScDrawObjData &rAnchor )
1788 ScDrawObjData* pAnchor = GetNonRotatedObjData( &rObj, true );
1789 pAnchor->maStart = rAnchor.maStart;
1790 pAnchor->maEnd = rAnchor.maEnd;
1791 pAnchor->maStartOffset = rAnchor.maStartOffset;
1792 pAnchor->maEndOffset = rAnchor.maEndOffset;
1795 void ScDrawLayer::SetCellAnchored( SdrObject &rObj, const ScDrawObjData &rAnchor )
1797 ScDrawObjData* pAnchor = GetObjData( &rObj, true );
1798 pAnchor->maStart = rAnchor.maStart;
1799 pAnchor->maEnd = rAnchor.maEnd;
1800 pAnchor->maStartOffset = rAnchor.maStartOffset;
1801 pAnchor->maEndOffset = rAnchor.maEndOffset;
1805 void ScDrawLayer::SetCellAnchoredFromPosition( SdrObject &rObj, const ScDocument &rDoc, SCTAB nTab )
1807 ScDrawObjData aAnchor;
1808 // set anchor in terms of the visual ( SnapRect )
1809 // object ( e.g. for when object is rotated )
1810 GetCellAnchorFromPosition( rObj, aAnchor, rDoc, nTab, false );
1811 SetCellAnchored( rObj, aAnchor );
1812 // - keep also an anchor in terms of the Logic ( untransformed ) object
1813 // because thats what we stored ( and still do ) to xml
1814 ScDrawObjData aVisAnchor;
1815 GetCellAnchorFromPosition( rObj, aVisAnchor, rDoc, nTab );
1816 SetVisualCellAnchored( rObj, aVisAnchor );
1817 // absolutely necessary to set flag that in order to preven ScDrawLayer::RecalcPos
1818 // doing an initialisation hack
1819 if ( ScDrawObjData* pAnchor = GetObjData( &rObj ) )
1821 pAnchor->maLastRect = rObj.GetSnapRect();
1825 void ScDrawLayer::GetCellAnchorFromPosition( SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect, bool bHiddenAsZero )
1827 Rectangle aObjRect( bUseLogicRect ? rObj.GetLogicRect() : rObj.GetSnapRect() );
1828 ScRange aRange = rDoc.GetRange( nTab, aObjRect, bHiddenAsZero );
1830 Rectangle aCellRect;
1832 rAnchor.maStart = aRange.aStart;
1833 aCellRect = rDoc.GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(),
1834 aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), bHiddenAsZero );
1835 rAnchor.maStartOffset.Y() = aObjRect.Top()-aCellRect.Top();
1836 if (!rDoc.IsNegativePage(nTab))
1837 rAnchor.maStartOffset.X() = aObjRect.Left()-aCellRect.Left();
1838 else
1839 rAnchor.maStartOffset.X() = aCellRect.Right()-aObjRect.Right();
1841 rAnchor.maEnd = aRange.aEnd;
1842 aCellRect = rDoc.GetMMRect( aRange.aEnd.Col(), aRange.aEnd.Row(),
1843 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), bHiddenAsZero );
1844 rAnchor.maEndOffset.Y() = aObjRect.Bottom()-aCellRect.Top();
1845 if (!rDoc.IsNegativePage(nTab))
1846 rAnchor.maEndOffset.X() = aObjRect.Right()-aCellRect.Left();
1847 else
1848 rAnchor.maEndOffset.X() = aCellRect.Right()-aObjRect.Left();
1853 void ScDrawLayer::UpdateCellAnchorFromPositionEnd( SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect )
1855 Rectangle aObjRect(bUseLogicRect ? rObj.GetLogicRect() : rObj.GetSnapRect());
1856 ScRange aRange = rDoc.GetRange( nTab, aObjRect );
1858 ScDrawObjData* pAnchor = &rAnchor;
1859 pAnchor->maEnd = aRange.aEnd;
1861 Rectangle aCellRect;
1862 aCellRect = rDoc.GetMMRect( aRange.aEnd.Col(), aRange.aEnd.Row(),
1863 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab() );
1864 pAnchor->maEndOffset.Y() = aObjRect.Bottom()-aCellRect.Top();
1865 if (!rDoc.IsNegativePage(nTab))
1866 pAnchor->maEndOffset.X() = aObjRect.Right()-aCellRect.Left();
1867 else
1868 pAnchor->maEndOffset.X() = aCellRect.Right()-aObjRect.Left();
1871 bool ScDrawLayer::IsCellAnchored( const SdrObject& rObj )
1873 // Cell anchored object always has a user data, to store the anchor cell
1874 // info. If it doesn't then it's page-anchored.
1875 return GetFirstUserDataOfType(&rObj, SC_UD_OBJDATA) != NULL;
1878 void ScDrawLayer::SetPageAnchored( SdrObject &rObj )
1880 DeleteFirstUserDataOfType(&rObj, SC_UD_OBJDATA);
1881 DeleteFirstUserDataOfType(&rObj, SC_UD_OBJDATA);
1884 ScAnchorType ScDrawLayer::GetAnchorType( const SdrObject &rObj )
1886 //If this object has a cell anchor associated with it
1887 //then its cell-anchored, otherwise its page-anchored
1888 return ScDrawLayer::GetObjData(const_cast<SdrObject*>(&rObj)) ? SCA_CELL : SCA_PAGE;
1891 ScDrawObjData* ScDrawLayer::GetNonRotatedObjData( SdrObject* pObj, sal_Bool bCreate )
1893 sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
1894 sal_uInt16 nFound = 0;
1895 for( sal_uInt16 i = 0; i < nCount; i++ )
1897 SdrObjUserData* pData = pObj->GetUserData( i );
1898 if( pData && pData->GetInventor() == SC_DRAWLAYER && pData->GetId() == SC_UD_OBJDATA && ++nFound == 2 )
1899 return (ScDrawObjData*)pData;
1901 if( pObj && bCreate )
1903 ScDrawObjData* pData = new ScDrawObjData;
1904 pObj->AppendUserData(pData);
1905 return pData;
1907 return 0;
1910 ScDrawObjData* ScDrawLayer::GetObjData( SdrObject* pObj, sal_Bool bCreate )
1912 if (SdrObjUserData *pData = GetFirstUserDataOfType(pObj, SC_UD_OBJDATA))
1913 return (ScDrawObjData*) pData;
1915 if( pObj && bCreate )
1917 ScDrawObjData* pData = new ScDrawObjData;
1918 pObj->AppendUserData(pData);
1919 return pData;
1921 return 0;
1924 ScDrawObjData* ScDrawLayer::GetObjDataTab( SdrObject* pObj, SCTAB nTab )
1926 ScDrawObjData* pData = GetObjData( pObj );
1927 if ( pData )
1929 if ( pData->maStart.IsValid() )
1930 pData->maStart.SetTab( nTab );
1931 if ( pData->maEnd.IsValid() )
1932 pData->maEnd.SetTab( nTab );
1934 return pData;
1937 bool ScDrawLayer::IsNoteCaption( SdrObject* pObj )
1939 ScDrawObjData* pData = pObj ? GetObjData( pObj ) : 0;
1940 return pData && pData->meType == ScDrawObjData::CellNote;
1943 ScDrawObjData* ScDrawLayer::GetNoteCaptionData( SdrObject* pObj, SCTAB nTab )
1945 ScDrawObjData* pData = pObj ? GetObjDataTab( pObj, nTab ) : 0;
1946 return (pData && pData->meType == ScDrawObjData::CellNote) ? pData : 0;
1949 ScIMapInfo* ScDrawLayer::GetIMapInfo( SdrObject* pObj )
1951 return (ScIMapInfo*)GetFirstUserDataOfType(pObj, SC_UD_IMAPDATA);
1954 IMapObject* ScDrawLayer::GetHitIMapObject( SdrObject* pObj,
1955 const Point& rWinPoint, const Window& rCmpWnd )
1957 const MapMode aMap100( MAP_100TH_MM );
1958 MapMode aWndMode = rCmpWnd.GetMapMode();
1959 Point aRelPoint( rCmpWnd.LogicToLogic( rWinPoint, &aWndMode, &aMap100 ) );
1960 Rectangle aLogRect = rCmpWnd.LogicToLogic( pObj->GetLogicRect(), &aWndMode, &aMap100 );
1961 ScIMapInfo* pIMapInfo = GetIMapInfo( pObj );
1962 IMapObject* pIMapObj = NULL;
1964 if ( pIMapInfo )
1966 Size aGraphSize;
1967 ImageMap& rImageMap = (ImageMap&) pIMapInfo->GetImageMap();
1968 Graphic aGraphic;
1969 sal_Bool bObjSupported = false;
1971 if ( pObj->ISA( SdrGrafObj ) ) // einfaches Grafik-Objekt
1973 const SdrGrafObj* pGrafObj = (const SdrGrafObj*) pObj;
1974 const GeoStat& rGeo = pGrafObj->GetGeoStat();
1975 const Graphic& rGraphic = pGrafObj->GetGraphic();
1977 // Drehung rueckgaengig
1978 if ( rGeo.nDrehWink )
1979 RotatePoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nSin, rGeo.nCos );
1981 // Spiegelung rueckgaengig
1982 if ( ( (const SdrGrafObjGeoData*) pGrafObj->GetGeoData() )->bMirrored )
1983 aRelPoint.X() = aLogRect.Right() + aLogRect.Left() - aRelPoint.X();
1985 // ggf. Unshear:
1986 if ( rGeo.nShearWink )
1987 ShearPoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nTan );
1990 if ( rGraphic.GetPrefMapMode().GetMapUnit() == MAP_PIXEL )
1991 aGraphSize = rCmpWnd.PixelToLogic( rGraphic.GetPrefSize(),
1992 aMap100 );
1993 else
1994 aGraphSize = OutputDevice::LogicToLogic( rGraphic.GetPrefSize(),
1995 rGraphic.GetPrefMapMode(),
1996 aMap100 );
1998 bObjSupported = sal_True;
2000 else if ( pObj->ISA( SdrOle2Obj ) ) // OLE-Objekt
2002 // TODO/LEAN: working with visual area needs running state
2003 aGraphSize = ((const SdrOle2Obj*)pObj)->GetOrigObjSize();
2004 bObjSupported = true;
2007 // hat alles geklappt, dann HitTest ausfuehren
2008 if ( bObjSupported )
2010 // relativen Mauspunkt berechnen
2011 aRelPoint -= aLogRect.TopLeft();
2012 pIMapObj = rImageMap.GetHitIMapObject( aGraphSize, aLogRect.GetSize(), aRelPoint );
2016 return pIMapObj;
2019 ScMacroInfo* ScDrawLayer::GetMacroInfo( SdrObject* pObj, sal_Bool bCreate )
2021 if (SdrObjUserData *pData = GetFirstUserDataOfType(pObj, SC_UD_MACRODATA))
2022 return (ScMacroInfo*) pData;
2024 if ( bCreate )
2026 ScMacroInfo* pData = new ScMacroInfo;
2027 pObj->AppendUserData(pData);
2028 return pData;
2030 return 0;
2033 void ScDrawLayer::SetGlobalDrawPersist(SfxObjectShell* pPersist)
2035 OSL_ENSURE(!pGlobalDrawPersist,"Multiple SetGlobalDrawPersist");
2036 pGlobalDrawPersist = pPersist;
2039 void ScDrawLayer::SetChanged( sal_Bool bFlg /* = sal_True */ )
2041 if ( bFlg && pDoc )
2042 pDoc->SetChartListenerCollectionNeedsUpdate( sal_True );
2043 FmFormModel::SetChanged( bFlg );
2046 SdrLayerID ScDrawLayer::GetControlExportLayerId( const SdrObject & ) const
2048 // Layer fuer Export von Form-Controls in Versionen vor 5.0 - immer SC_LAYER_FRONT
2049 return SC_LAYER_FRONT;
2052 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > ScDrawLayer::createUnoModel()
2054 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet;
2055 if( pDoc && pDoc->GetDocumentShell() )
2056 xRet = pDoc->GetDocumentShell()->GetModel();
2058 return xRet;
2061 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */