fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / drwlayer.cxx
blob27e47c81719dbbf11ac0505166a24500986d7da3
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>
30 #include <basegfx/matrix/b2dhommatrixtools.hxx>
32 #include "scitems.hxx"
33 #include <editeng/eeitem.hxx>
34 #include <editeng/frmdiritem.hxx>
35 #include <sot/exchange.hxx>
36 #include <svx/objfac3d.hxx>
37 #include <svx/xtable.hxx>
38 #include <svx/svdoutl.hxx>
39 #include <svx/svditer.hxx>
40 #include <svx/svdocapt.hxx>
41 #include <svx/svdocirc.hxx>
42 #include <svx/svdoedge.hxx>
43 #include <svx/svdograf.hxx>
44 #include <svx/svdoole2.hxx>
45 #include <svx/svdundo.hxx>
46 #include <i18nlangtag/mslangid.hxx>
47 #include <editeng/unolingu.hxx>
48 #include <svx/drawitem.hxx>
49 #include <editeng/fhgtitem.hxx>
50 #include <editeng/scriptspaceitem.hxx>
51 #include <svx/shapepropertynotifier.hxx>
52 #include <sfx2/viewsh.hxx>
53 #include <sfx2/docfile.hxx>
54 #include <sot/storage.hxx>
55 #include <unotools/pathoptions.hxx>
56 #include <svl/itempool.hxx>
57 #include <vcl/virdev.hxx>
58 #include <vcl/svapp.hxx>
59 #include <vcl/settings.hxx>
60 #include <unotools/ucbstreamhelper.hxx>
62 #include <basegfx/polygon/b2dpolygon.hxx>
63 #include <basegfx/polygon/b2dpolygontools.hxx>
65 #include "drwlayer.hxx"
66 #include "drawpage.hxx"
67 #include "global.hxx"
68 #include "document.hxx"
69 #include "rechead.hxx"
70 #include "userdat.hxx"
71 #include "markdata.hxx"
72 #include "globstr.hrc"
73 #include "scmod.hxx"
74 #include "chartarr.hxx"
75 #include "postit.hxx"
76 #include "attrib.hxx"
77 #include "charthelper.hxx"
78 #include <basegfx/matrix/b2dhommatrix.hxx>
80 #include <vcl/field.hxx>
81 #include <boost/scoped_array.hpp>
83 #define DET_ARROW_OFFSET 1000
85 using namespace ::com::sun::star;
87 // STATIC DATA -----------------------------------------------------------
89 static ScDrawObjFactory* pFac = NULL;
90 static E3dObjFactory* pF3d = NULL;
91 static sal_uInt16 nInst = 0;
93 SfxObjectShell* ScDrawLayer::pGlobalDrawPersist = NULL;
95 bool bDrawIsInUndo = false; //TODO: Member
97 ScUndoObjData::ScUndoObjData( SdrObject* pObjP, const ScAddress& rOS, const ScAddress& rOE,
98 const ScAddress& rNS, const ScAddress& rNE ) :
99 SdrUndoObj( *pObjP ),
100 aOldStt( rOS ),
101 aOldEnd( rOE ),
102 aNewStt( rNS ),
103 aNewEnd( rNE )
107 ScUndoObjData::~ScUndoObjData()
111 void ScUndoObjData::Undo()
113 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
114 OSL_ENSURE(pData,"ScUndoObjData: Data missing");
115 if (pData)
117 pData->maStart = aOldStt;
118 pData->maEnd = aOldEnd;
121 // Undo also an untransformed anchor
122 pData = ScDrawLayer::GetNonRotatedObjData( pObj );
123 if (pData)
125 pData->maStart = aOldStt;
126 pData->maEnd = aOldEnd;
130 void ScUndoObjData::Redo()
132 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
133 OSL_ENSURE(pData,"ScUndoObjData: Data missing");
134 if (pData)
136 pData->maStart = aNewStt;
137 pData->maEnd = aNewEnd;
140 // Redo also an untransformed anchor
141 pData = ScDrawLayer::GetNonRotatedObjData( pObj );
142 if (pData)
144 pData->maStart = aNewStt;
145 pData->maEnd = aNewEnd;
149 ScUndoAnchorData::ScUndoAnchorData( SdrObject* pObjP, ScDocument* pDoc, SCTAB nTab ) :
150 SdrUndoObj( *pObjP ),
151 mpDoc( pDoc ),
152 mnTab( nTab )
154 mbWasCellAnchored = ScDrawLayer::IsCellAnchored( *pObjP );
157 ScUndoAnchorData::~ScUndoAnchorData()
161 void ScUndoAnchorData::Undo()
163 // Trigger Object Change
164 if (pObj->IsInserted() && pObj->GetPage() && pObj->GetModel())
166 SdrHint aHint(*pObj);
167 pObj->GetModel()->Broadcast(aHint);
170 if (mbWasCellAnchored)
171 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *mpDoc, mnTab);
172 else
173 ScDrawLayer::SetPageAnchored( *pObj );
176 void ScUndoAnchorData::Redo()
178 if (mbWasCellAnchored)
179 ScDrawLayer::SetPageAnchored( *pObj );
180 else
181 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *mpDoc, mnTab);
183 // Trigger Object Change
184 if (pObj->IsInserted() && pObj->GetPage() && pObj->GetModel())
186 SdrHint aHint(*pObj);
187 pObj->GetModel()->Broadcast(aHint);
191 ScTabDeletedHint::ScTabDeletedHint( SCTAB nTabNo ) :
192 nTab( nTabNo )
196 ScTabDeletedHint::~ScTabDeletedHint()
200 ScTabSizeChangedHint::ScTabSizeChangedHint( SCTAB nTabNo ) :
201 nTab( nTabNo )
205 ScTabSizeChangedHint::~ScTabSizeChangedHint()
209 #define MAXMM 10000000
211 inline long TwipsToHmm (long nVal)
213 return static_cast< long >( MetricField::ConvertDoubleValue (static_cast<sal_Int64>(nVal), 0, 0,
214 FUNIT_TWIP, FUNIT_100TH_MM) );
217 inline long HmmToTwips (long nVal)
219 return static_cast< long > ( MetricField::ConvertDoubleValue (static_cast<sal_Int64>(nVal), 0, 0,
220 FUNIT_100TH_MM, FUNIT_TWIP) );
223 inline void TwipsToMM( long& nVal )
225 nVal = TwipsToHmm (nVal);
228 inline void ReverseTwipsToMM( long& nVal )
230 nVal = HmmToTwips (nVal);
233 static void lcl_ReverseTwipsToMM( Rectangle& rRect )
235 ReverseTwipsToMM( rRect.Left() );
236 ReverseTwipsToMM( rRect.Right() );
237 ReverseTwipsToMM( rRect.Top() );
238 ReverseTwipsToMM( rRect.Bottom() );
241 ScDrawLayer::ScDrawLayer( ScDocument* pDocument, const OUString& rName ) :
242 FmFormModel( SvtPathOptions().GetPalettePath(),
243 NULL, // SfxItemPool* Pool
244 pGlobalDrawPersist ?
245 pGlobalDrawPersist :
246 ( pDocument ? pDocument->GetDocumentShell() : NULL ),
247 true ), // bUseExtColorTable (is set below)
248 aName( rName ),
249 pDoc( pDocument ),
250 pUndoGroup( NULL ),
251 bRecording( false ),
252 bAdjustEnabled( true ),
253 bHyphenatorSet( false )
255 pGlobalDrawPersist = NULL; // Only use once
257 SfxObjectShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : NULL;
258 XColorListRef pXCol = XColorList::GetStdColorList();
259 if ( pObjSh )
261 SetObjectShell( pObjSh );
263 // set color table
264 const SvxColorListItem* pColItem = static_cast<const SvxColorListItem*>( pObjSh->GetItem( SID_COLOR_TABLE ) );
265 if ( pColItem )
266 pXCol = pColItem->GetColorList();
268 SetPropertyList( static_cast<XPropertyList *> (pXCol.get()) );
270 SetSwapGraphics(true);
272 SetScaleUnit(MAP_100TH_MM);
273 SfxItemPool& rPool = GetItemPool();
274 rPool.SetDefaultMetric(SFX_MAPUNIT_100TH_MM);
275 SvxFrameDirectionItem aModeItem( FRMDIR_ENVIRONMENT, EE_PARA_WRITINGDIR );
276 rPool.SetPoolDefaultItem( aModeItem );
278 // #i33700#
279 // Set shadow distance defaults as PoolDefaultItems. Details see bug.
280 rPool.SetPoolDefaultItem(makeSdrShadowXDistItem(300));
281 rPool.SetPoolDefaultItem(makeSdrShadowYDistItem(300));
283 // default for script spacing depends on locale, see SdDrawDocument ctor in sd
284 LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
285 if (MsLangId::isKorean(eOfficeLanguage) || eOfficeLanguage == LANGUAGE_JAPANESE)
287 // secondary is edit engine pool
288 rPool.GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
291 rPool.FreezeIdRanges(); // the pool is also used directly
293 SdrLayerAdmin& rAdmin = GetLayerAdmin();
294 rAdmin.NewLayer(OUString("vorne"), SC_LAYER_FRONT);
295 rAdmin.NewLayer(OUString("hinten"), SC_LAYER_BACK);
296 rAdmin.NewLayer(OUString("intern"), SC_LAYER_INTERN);
297 rAdmin.NewLayer(OUString("Controls"), SC_LAYER_CONTROLS);
298 rAdmin.NewLayer(OUString("hidden"), SC_LAYER_HIDDEN);
299 // "Controls" is new - must also be created when loading
301 // Set link for URL-Fields
302 ScModule* pScMod = SC_MOD();
303 Outliner& rOutliner = GetDrawOutliner();
304 rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
306 Outliner& rHitOutliner = GetHitTestOutliner();
307 rHitOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
309 // set FontHeight pool defaults without changing static SdrEngineDefaults
310 SfxItemPool* pOutlinerPool = rOutliner.GetEditTextObjectPool();
311 if ( pOutlinerPool )
313 pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
314 pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CJK )); // 12Pt
315 pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CTL )); // 12Pt
317 SfxItemPool* pHitOutlinerPool = rHitOutliner.GetEditTextObjectPool();
318 if ( pHitOutlinerPool )
320 pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
321 pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CJK )); // 12Pt
322 pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT_CTL )); // 12Pt
325 // initial undo mode as in Calc document
326 if( pDoc )
327 EnableUndo( pDoc->IsUndoEnabled() );
329 // URL-Buttons have no handler anymore, all is done by themselves
331 if( !nInst++ )
333 pFac = new ScDrawObjFactory;
334 pF3d = new E3dObjFactory;
338 ScDrawLayer::~ScDrawLayer()
340 Broadcast(SdrHint(HINT_MODELCLEARED));
342 ClearModel(true);
344 delete pUndoGroup;
345 if( !--nInst )
347 delete pFac, pFac = NULL;
348 delete pF3d, pF3d = NULL;
352 void ScDrawLayer::UseHyphenator()
354 if (!bHyphenatorSet)
356 com::sun::star::uno::Reference< com::sun::star::linguistic2::XHyphenator >
357 xHyphenator = LinguMgr::GetHyphenator();
359 GetDrawOutliner().SetHyphenator( xHyphenator );
360 GetHitTestOutliner().SetHyphenator( xHyphenator );
362 bHyphenatorSet = true;
366 SdrPage* ScDrawLayer::AllocPage(bool bMasterPage)
368 return new ScDrawPage(*this, bMasterPage);
371 bool ScDrawLayer::HasObjects() const
373 bool bFound = false;
375 sal_uInt16 nCount = GetPageCount();
376 for (sal_uInt16 i=0; i<nCount && !bFound; i++)
377 if (GetPage(i)->GetObjCount())
378 bFound = true;
380 return bFound;
383 SdrModel* ScDrawLayer::AllocModel() const
385 // Allocated model (for clipboard etc) must not have a pointer
386 // to the original model's document, pass NULL as document:
388 return new ScDrawLayer( NULL, aName );
391 bool ScDrawLayer::ScAddPage( SCTAB nTab )
393 if (bDrawIsInUndo)
394 return false; // not inserted
396 ScDrawPage* pPage = static_cast<ScDrawPage*>(AllocPage( false ));
397 InsertPage(pPage, static_cast<sal_uInt16>(nTab));
398 if (bRecording)
399 AddCalcUndo(new SdrUndoNewPage(*pPage));
401 ResetTab(nTab, pDoc->GetTableCount()-1);
402 return true; // inserted
405 void ScDrawLayer::ScRemovePage( SCTAB nTab )
407 if (bDrawIsInUndo)
408 return;
410 Broadcast( ScTabDeletedHint( nTab ) );
411 if (bRecording)
413 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
414 AddCalcUndo(new SdrUndoDelPage(*pPage)); // Undo-Action becomes the page owner
415 RemovePage( static_cast<sal_uInt16>(nTab) ); // just deliver, not deleting
417 else
418 DeletePage( static_cast<sal_uInt16>(nTab) ); // just get rid of it
420 ResetTab(nTab, pDoc->GetTableCount()-1);
423 void ScDrawLayer::ScRenamePage( SCTAB nTab, const OUString& rNewName )
425 ScDrawPage* pPage = static_cast<ScDrawPage*>( GetPage(static_cast<sal_uInt16>(nTab)) );
426 if (pPage)
427 pPage->SetName(rNewName);
430 void ScDrawLayer::ScMovePage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
432 MovePage( nOldPos, nNewPos );
433 sal_uInt16 nMinPos = std::min(nOldPos, nNewPos);
434 ResetTab(nMinPos, pDoc->GetTableCount()-1);
437 void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos)
439 if (bDrawIsInUndo)
440 return;
442 SdrPage* pOldPage = GetPage(nOldPos);
443 SdrPage* pNewPage = GetPage(nNewPos);
445 // Copying
447 if (pOldPage && pNewPage)
449 SCTAB nOldTab = static_cast<SCTAB>(nOldPos);
450 SCTAB nNewTab = static_cast<SCTAB>(nNewPos);
452 SdrObjListIter aIter( *pOldPage, IM_FLAT );
453 SdrObject* pOldObject = aIter.Next();
454 while (pOldObject)
456 ScDrawObjData* pOldData = GetObjData(pOldObject);
457 if (pOldData)
459 pOldData->maStart.SetTab(nOldTab);
460 pOldData->maEnd.SetTab(nOldTab);
462 SdrObject* pNewObject = pOldObject->Clone();
463 pNewObject->SetModel(this);
464 pNewObject->SetPage(pNewPage);
466 pNewObject->NbcMove(Size(0,0));
467 pNewPage->InsertObject( pNewObject );
468 ScDrawObjData* pNewData = GetObjData(pNewObject);
469 if (pNewData)
471 pNewData->maStart.SetTab(nNewTab);
472 pNewData->maEnd.SetTab(nNewTab);
475 if (bRecording)
476 AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) );
478 pOldObject = aIter.Next();
482 ResetTab(static_cast<SCTAB>(nNewPos), pDoc->GetTableCount()-1);
485 void ScDrawLayer::ResetTab( SCTAB nStart, SCTAB nEnd )
487 SCTAB nPageSize = static_cast<SCTAB>(GetPageCount());
488 if (nPageSize < 0)
489 // No drawing pages exist.
490 return;
492 if (nEnd >= nPageSize)
493 // Avoid iterating beyond the last existing page.
494 nEnd = nPageSize - 1;
496 for (SCTAB i = nStart; i <= nEnd; ++i)
498 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(i));
499 if (!pPage)
500 continue;
502 SdrObjListIter aIter(*pPage, IM_FLAT);
503 for (SdrObject* pObj = aIter.Next(); pObj; pObj = aIter.Next())
505 ScDrawObjData* pData = GetObjData(pObj);
506 if (!pData)
507 continue;
509 pData->maStart.SetTab(i);
510 pData->maEnd.SetTab(i);
515 inline bool IsInBlock( const ScAddress& rPos, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2 )
517 return rPos.Col() >= nCol1 && rPos.Col() <= nCol2 &&
518 rPos.Row() >= nRow1 && rPos.Row() <= nRow2;
521 void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
522 SCsCOL nDx,SCsROW nDy, bool bUpdateNoteCaptionPos )
524 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
525 OSL_ENSURE(pPage,"Page not found");
526 if (!pPage)
527 return;
529 bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
531 const size_t nCount = pPage->GetObjCount();
532 for ( size_t i = 0; i < nCount; ++i )
534 SdrObject* pObj = pPage->GetObj( i );
535 ScDrawObjData* pData = GetObjDataTab( pObj, nTab );
536 if( pData )
538 const ScAddress aOldStt = pData->maStart;
539 const ScAddress aOldEnd = pData->maEnd;
540 bool bChange = false;
541 if ( aOldStt.IsValid() && IsInBlock( aOldStt, nCol1,nRow1, nCol2,nRow2 ) )
543 pData->maStart.IncCol( nDx );
544 pData->maStart.IncRow( nDy );
545 bChange = true;
547 if ( aOldEnd.IsValid() && IsInBlock( aOldEnd, nCol1,nRow1, nCol2,nRow2 ) )
549 pData->maEnd.IncCol( nDx );
550 pData->maEnd.IncRow( nDy );
551 bChange = true;
553 if (bChange)
555 if ( pObj->ISA( SdrRectObj ) && pData->maStart.IsValid() && pData->maEnd.IsValid() )
556 pData->maStart.PutInOrder( pData->maEnd );
558 // Update also an untransformed anchor thats what we stored ( and still do ) to xml
559 ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData( pObj, false );
560 if ( pNoRotatedAnchor )
562 pNoRotatedAnchor->maStart = pData->maStart;
563 pNoRotatedAnchor->maEnd = pData->maEnd;
566 AddCalcUndo( new ScUndoObjData( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd ) );
567 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
573 void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos )
575 SdrPage* pPage = GetPage(nPageNo);
576 if (pPage)
578 if ( rSize != pPage->GetSize() )
580 pPage->SetSize( rSize );
581 Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) ); // SetWorkArea() an den Views
584 // Implement Detective lines (adjust to new heights / widths)
585 // even if size is still the same
586 // (individual rows/columns can have been changed))
588 bool bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
590 const size_t nCount = pPage->GetObjCount();
591 for ( size_t i = 0; i < nCount; ++i )
593 SdrObject* pObj = pPage->GetObj( i );
594 ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
595 if( pData )
596 RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
601 namespace
603 //Can't have a zero width dimension
604 Rectangle lcl_makeSafeRectangle(const Rectangle &rNew)
606 Rectangle aRect = rNew;
607 if (aRect.Bottom() == aRect.Top())
608 aRect.Bottom() = aRect.Top()+1;
609 if (aRect.Right() == aRect.Left())
610 aRect.Right() = aRect.Left()+1;
611 return aRect;
614 Point lcl_calcAvailableDiff(ScDocument &rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const Point &aWantedDiff)
616 Point aAvailableDiff(aWantedDiff);
617 long nHeight = static_cast<long>(rDoc.GetRowHeight( nRow, nTab ) * HMM_PER_TWIPS);
618 long nWidth = static_cast<long>(rDoc.GetColWidth( nCol, nTab ) * HMM_PER_TWIPS);
619 if (aAvailableDiff.Y() > nHeight)
620 aAvailableDiff.Y() = nHeight;
621 if (aAvailableDiff.X() > nWidth)
622 aAvailableDiff.X() = nWidth;
623 return aAvailableDiff;
626 Rectangle lcl_UpdateCalcPoly(basegfx::B2DPolygon &rCalcPoly, int nWhichPoint, const Point &rPos)
628 rCalcPoly.setB2DPoint(nWhichPoint, basegfx::B2DPoint(rPos.X(), rPos.Y()));
629 basegfx::B2DRange aRange(basegfx::tools::getRange(rCalcPoly));
630 return Rectangle(static_cast<long>(aRange.getMinX()), static_cast<long>(aRange.getMinY()),
631 static_cast<long>(aRange.getMaxX()), static_cast<long>(aRange.getMaxY()));
634 void ScDrawLayer::ResizeLastRectFromAnchor( SdrObject* pObj, ScDrawObjData& rData, bool bUseLogicRect, bool bNegativePage, bool bCanResize, bool bHiddenAsZero )
636 rData.maLastRect = ( bUseLogicRect ? pObj->GetLogicRect() : pObj->GetSnapRect() );
637 SCCOL nCol1 = rData.maStart.Col();
638 SCROW nRow1 = rData.maStart.Row();
639 SCTAB nTab1 = rData.maStart.Tab();
640 SCCOL nCol2 = rData.maEnd.Col();
641 SCROW nRow2 = rData.maEnd.Row();
642 SCTAB nTab2 = rData.maEnd.Tab();
643 Point aPos( pDoc->GetColOffset( nCol1, nTab1, bHiddenAsZero ), pDoc->GetRowOffset( nRow1, nTab1, bHiddenAsZero ) );
644 TwipsToMM( aPos.X() );
645 TwipsToMM( aPos.Y() );
646 aPos += lcl_calcAvailableDiff(*pDoc, nCol1, nRow1, nTab1, rData.maStartOffset);
648 if( bCanResize )
650 Point aEnd( pDoc->GetColOffset( nCol2, nTab2, bHiddenAsZero ), pDoc->GetRowOffset( nRow2, nTab2, bHiddenAsZero ) );
651 TwipsToMM( aEnd.X() );
652 TwipsToMM( aEnd.Y() );
653 aEnd += lcl_calcAvailableDiff(*pDoc, nCol2, nRow2, nTab2, rData.maEndOffset);
655 Rectangle aNew = Rectangle( aPos, aEnd );
656 if ( bNegativePage )
657 MirrorRectRTL( aNew );
659 rData.maLastRect = lcl_makeSafeRectangle(aNew);
661 else
663 if ( bNegativePage )
664 aPos.X() = -aPos.X() - rData.maLastRect.GetWidth();
665 // shouldn't we initialise maLastRect with the object rectangle ?
666 rData.maLastRect.SetPos( aPos );
670 void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegativePage, bool bUpdateNoteCaptionPos )
672 OSL_ENSURE( pDoc, "ScDrawLayer::RecalcPos - missing document" );
673 if( !pDoc )
674 return;
676 if (rData.meType == ScDrawObjData::CellNote)
678 OSL_ENSURE( rData.maStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
679 /* #i109372# On insert/remove rows/columns/cells: Updating the caption
680 position must not be done, if the cell containing the note has not
681 been moved yet in the document. The calling code now passes an
682 additional boolean stating if the cells are already moved. */
683 if( bUpdateNoteCaptionPos )
684 /* When inside an undo action, there may be pending note captions
685 where cell note is already deleted (thus document cannot find
686 the note object anymore). The caption will be deleted later
687 with drawing undo. */
688 if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
689 pNote->UpdateCaptionPos( rData.maStart );
690 return;
693 bool bValid1 = rData.maStart.IsValid();
694 SCCOL nCol1 = rData.maStart.Col();
695 SCROW nRow1 = rData.maStart.Row();
696 SCTAB nTab1 = rData.maStart.Tab();
697 bool bValid2 = rData.maEnd.IsValid();
698 SCCOL nCol2 = rData.maEnd.Col();
699 SCROW nRow2 = rData.maEnd.Row();
700 SCTAB nTab2 = rData.maEnd.Tab();
702 if (rData.meType == ScDrawObjData::ValidationCircle)
704 // Validation circle for detective.
705 rData.maLastRect = pObj->GetLogicRect();
707 Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
708 TwipsToMM( aPos.X() );
709 TwipsToMM( aPos.Y() );
711 // Calculations and values as in detfunc.cxx
713 Size aSize( (long)( TwipsToHmm( pDoc->GetColWidth( nCol1, nTab1) ) ),
714 (long)( TwipsToHmm( pDoc->GetRowHeight( nRow1, nTab1) ) ) );
715 Rectangle aRect( aPos, aSize );
716 aRect.Left() -= 250;
717 aRect.Right() += 250;
718 aRect.Top() -= 70;
719 aRect.Bottom() += 70;
720 if ( bNegativePage )
721 MirrorRectRTL( aRect );
723 if ( pObj->GetLogicRect() != aRect )
725 if (bRecording)
726 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
727 rData.maLastRect = lcl_makeSafeRectangle(aRect);
728 pObj->SetLogicRect(rData.maLastRect);
731 else if (rData.meType == ScDrawObjData::DetectiveArrow)
733 rData.maLastRect = pObj->GetLogicRect();
734 basegfx::B2DPolygon aCalcPoly;
735 Point aOrigStartPos(pObj->GetPoint(0));
736 Point aOrigEndPos(pObj->GetPoint(1));
737 aCalcPoly.append(basegfx::B2DPoint(aOrigStartPos.X(), aOrigStartPos.Y()));
738 aCalcPoly.append(basegfx::B2DPoint(aOrigEndPos.X(), aOrigEndPos.Y()));
739 //TODO: do not create multiple Undos for one object (last one can be omitted then)
741 SCCOL nLastCol;
742 SCROW nLastRow;
743 if( bValid1 )
745 Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
746 if (!pDoc->ColHidden(nCol1, nTab1, NULL, &nLastCol))
747 aPos.X() += pDoc->GetColWidth( nCol1, nTab1 ) / 4;
748 if (!pDoc->RowHidden(nRow1, nTab1, NULL, &nLastRow))
749 aPos.Y() += pDoc->GetRowHeight( nRow1, nTab1 ) / 2;
750 TwipsToMM( aPos.X() );
751 TwipsToMM( aPos.Y() );
752 Point aStartPos = aPos;
753 if ( bNegativePage )
754 aStartPos.X() = -aStartPos.X(); // don't modify aPos - used below
755 if ( pObj->GetPoint( 0 ) != aStartPos )
757 if (bRecording)
758 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
760 rData.maLastRect = lcl_UpdateCalcPoly(aCalcPoly, 0, aStartPos);
761 pObj->SetPoint( aStartPos, 0 );
764 if( !bValid2 )
766 Point aEndPos( aPos.X() + DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
767 if (aEndPos.Y() < 0)
768 aEndPos.Y() += (2 * DET_ARROW_OFFSET);
769 if ( bNegativePage )
770 aEndPos.X() = -aEndPos.X();
771 if ( pObj->GetPoint( 1 ) != aEndPos )
773 if (bRecording)
774 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
776 rData.maLastRect = lcl_UpdateCalcPoly(aCalcPoly, 1, aEndPos);
777 pObj->SetPoint( aEndPos, 1 );
781 if( bValid2 )
783 Point aPos( pDoc->GetColOffset( nCol2, nTab2 ), pDoc->GetRowOffset( nRow2, nTab2 ) );
784 if (!pDoc->ColHidden(nCol2, nTab2, NULL, &nLastCol))
785 aPos.X() += pDoc->GetColWidth( nCol2, nTab2 ) / 4;
786 if (!pDoc->RowHidden(nRow2, nTab2, NULL, &nLastRow))
787 aPos.Y() += pDoc->GetRowHeight( nRow2, nTab2 ) / 2;
788 TwipsToMM( aPos.X() );
789 TwipsToMM( aPos.Y() );
790 Point aEndPos = aPos;
791 if ( bNegativePage )
792 aEndPos.X() = -aEndPos.X(); // don't modify aPos - used below
793 if ( pObj->GetPoint( 1 ) != aEndPos )
795 if (bRecording)
796 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
798 rData.maLastRect = lcl_UpdateCalcPoly(aCalcPoly, 1, aEndPos);
799 pObj->SetPoint( aEndPos, 1 );
802 if( !bValid1 )
804 Point aStartPos( aPos.X() - DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
805 if (aStartPos.X() < 0)
806 aStartPos.X() += (2 * DET_ARROW_OFFSET);
807 if (aStartPos.Y() < 0)
808 aStartPos.Y() += (2 * DET_ARROW_OFFSET);
809 if ( bNegativePage )
810 aStartPos.X() = -aStartPos.X();
811 if ( pObj->GetPoint( 0 ) != aStartPos )
813 if (bRecording)
814 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
816 rData.maLastRect = lcl_UpdateCalcPoly(aCalcPoly, 0, aStartPos);
817 pObj->SetPoint( aStartPos, 0 );
822 else
824 bool bCanResize = bValid2 && !pObj->IsResizeProtect();
826 //First time positioning, must be able to at least move it
827 ScDrawObjData& rNoRotatedAnchor = *GetNonRotatedObjData( pObj, true );
828 if (rData.maLastRect.IsEmpty())
830 // Every shape it is saved with an negative offset relative to cell
831 if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL)
833 double fRotate(0.0);
834 double fShearX(0.0);
836 Point aPoint;
837 Rectangle aRect;
839 basegfx::B2DTuple aScale;
840 basegfx::B2DTuple aTranslate;
841 basegfx::B2DPolyPolygon aPolyPolygon;
842 basegfx::B2DHomMatrix aOriginalMatrix;
844 aRect = pDoc->GetMMRect(nCol1, nRow1, nCol1 , nRow1, nTab1);
846 if (bNegativePage)
847 aPoint.X() = aRect.Right();
848 else
849 aPoint.X() = aRect.Left();
850 aPoint.Y() = aRect.Top();
852 pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon);
853 aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
854 aTranslate += ::basegfx::B2DTuple(aPoint.X(), aPoint.Y());
855 aOriginalMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
856 aScale,
857 fShearX,
858 fRotate,
859 aTranslate);
860 pObj->TRSetBaseGeometry(aOriginalMatrix, aPolyPolygon);
863 // It's confusing ( but blame that we persist the anchor in terms of unrotated shape )
864 // that the initial anchor we get here is in terms of an unrotated shape ( if the shape is rotated )
865 // we need to save the old anchor ( for persisting ) and also track any resize or repositions that happen.
867 // This is an evil hack, having a anchor that is one minute in terms of untransformed object and then later
868 // in terms of the transformed object is not ideal, similary having 2 anchors per object is wasteful, can't
869 // see another way out of this at the moment though.
870 rNoRotatedAnchor.maStart = rData.maStart;
871 rNoRotatedAnchor.maEnd = rData.maEnd;
872 rNoRotatedAnchor.maStartOffset = rData.maStartOffset;
873 rNoRotatedAnchor.maEndOffset = rData.maEndOffset;
875 Rectangle aRect = pObj->GetLogicRect();
877 // get bounding rectangle of shape ( include any hidden row/columns ), <sigh> we need to do this
878 // because if the shape is rotated the anchor from xml is in terms of the unrotated shape, if
879 // the shape is hidden ( by the rows that contain the shape being hidden ) then our hack of
880 // trying to infer the 'real' e.g. rotated anchor from the SnapRect will fail ( because the LogicRect will
881 // not have the correct position or size ) The only way we can possible do this is to first get the
882 // 'unrotated' shape dimensions from the persisted Anchor (from xml) and then 'create' an Anchor from the
883 // associated rotated shape ( note: we do this by actually setting the LogicRect for the shape temporarily to the
884 // *full* size then grabbing the SnapRect ( which gives the transformed rotated dimensions ), it would be
885 // wonderful if we could do this mathematically without having to temporarily tweak the object... othoh this way
886 // is guaranteed to get consistent results )
887 ResizeLastRectFromAnchor( pObj, rData, true, bNegativePage, bCanResize, false );
888 // aFullRect contains the unrotated size and position of the shape ( regardless of any hidden row/columns )
889 Rectangle aFullRect = rData.maLastRect;
891 // get current size and position from the anchor for use later
892 ResizeLastRectFromAnchor( pObj, rNoRotatedAnchor, true, bNegativePage, bCanResize );
894 // resize/position the shape to *full* size e.g. how it would be ( if no hidden rows/cols affected things )
895 pObj->SetLogicRect(aFullRect);
896 // capture rotated shape ( if relevant )
897 aRect = pObj->GetSnapRect();
899 // Ok, here is more nastyness, from xml the Anchor is in terms of the LogicRect which is the
900 // untransformed unrotated shape, here we swap out that initial anchor and from now on use
901 // an Anchor based on the SnapRect ( which is what you see on the screen )
902 ScDrawLayer::GetCellAnchorFromPosition( *pObj, rData, *pDoc, nTab1, false, false );
903 // reset shape to true 'maybe affected by hidden rows/cols' size calculated previously
904 pObj->SetLogicRect(rNoRotatedAnchor.maLastRect);
907 // update anchor with snap rect
908 ResizeLastRectFromAnchor( pObj, rData, false, bNegativePage, bCanResize );
910 if( bCanResize )
912 Rectangle aNew = rData.maLastRect;
914 if ( pObj->GetSnapRect() != aNew )
916 Rectangle aOld(pObj->GetSnapRect());
918 if (bRecording)
919 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
920 long nOldWidth = aOld.GetWidth();
921 long nOldHeight = aOld.GetHeight();
922 if (pObj->IsPolyObj() && nOldWidth && nOldHeight)
924 // Polyline objects need special treatment.
925 Size aSizeMove(aNew.Left()-aOld.Left(), aNew.Top()-aOld.Top());
926 pObj->NbcMove(aSizeMove);
928 double fXFrac = static_cast<double>(aNew.GetWidth()) / static_cast<double>(nOldWidth);
929 double fYFrac = static_cast<double>(aNew.GetHeight()) / static_cast<double>(nOldHeight);
930 pObj->NbcResize(aNew.TopLeft(), Fraction(fXFrac), Fraction(fYFrac));
932 // order of these lines is important, modify rData.maLastRect carefully it is used as both
933 // a value and a flag for initialisation
934 rData.maLastRect = lcl_makeSafeRectangle(rData.maLastRect);
935 pObj->SetSnapRect(rData.maLastRect);
936 // update 'unrotated anchor' it's the anchor we persist, it must be kept in sync
937 // with the normal Anchor
938 ResizeLastRectFromAnchor( pObj, rNoRotatedAnchor, true, bNegativePage, bCanResize );
941 else
943 Point aPos( rData.maLastRect.getX(), rData.maLastRect.getY() );
944 if ( pObj->GetRelativePos() != aPos )
946 if (bRecording)
947 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
948 pObj->SetRelativePos( aPos );
952 * If we were not allowed resize the object, then the end cell anchor
953 * is possibly incorrect now, and if the object has no end-cell (e.g.
954 * missing in original .xml) we are also forced to generate one
956 bool bEndAnchorIsBad = !bValid2 || pObj->IsResizeProtect();
957 if (bEndAnchorIsBad)
959 // update 'rotated' anchor
960 ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, rData, *pDoc, nTab1, false);
961 // update 'unrotated' anchor
962 ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1 );
967 bool ScDrawLayer::GetPrintArea( ScRange& rRange, bool bSetHor, bool bSetVer ) const
969 OSL_ENSURE( pDoc, "ScDrawLayer::GetPrintArea without document" );
970 if ( !pDoc )
971 return false;
973 SCTAB nTab = rRange.aStart.Tab();
974 OSL_ENSURE( rRange.aEnd.Tab() == nTab, "GetPrintArea: Tab differ" );
976 bool bNegativePage = pDoc->IsNegativePage( nTab );
978 bool bAny = false;
979 long nEndX = 0;
980 long nEndY = 0;
981 long nStartX = LONG_MAX;
982 long nStartY = LONG_MAX;
984 // Calculate borders
986 if (!bSetHor)
988 nStartX = 0;
989 SCCOL nStartCol = rRange.aStart.Col();
990 SCCOL i;
991 for (i=0; i<nStartCol; i++)
992 nStartX +=pDoc->GetColWidth(i,nTab);
993 nEndX = nStartX;
994 SCCOL nEndCol = rRange.aEnd.Col();
995 for (i=nStartCol; i<=nEndCol; i++)
996 nEndX += pDoc->GetColWidth(i,nTab);
997 nStartX = TwipsToHmm( nStartX );
998 nEndX = TwipsToHmm( nEndX );
1000 if (!bSetVer)
1002 nStartY = pDoc->GetRowHeight( 0, rRange.aStart.Row()-1, nTab);
1003 nEndY = nStartY + pDoc->GetRowHeight( rRange.aStart.Row(),
1004 rRange.aEnd.Row(), nTab);
1005 nStartY = TwipsToHmm( nStartY );
1006 nEndY = TwipsToHmm( nEndY );
1009 if ( bNegativePage )
1011 nStartX = -nStartX; // positions are negative, swap start/end so the same comparisons work
1012 nEndX = -nEndX;
1013 ::std::swap( nStartX, nEndX );
1016 const SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1017 OSL_ENSURE(pPage,"Page not found");
1018 if (pPage)
1020 SdrObjListIter aIter( *pPage, IM_FLAT );
1021 SdrObject* pObject = aIter.Next();
1022 while (pObject)
1024 //TODO: test Flags (hidden?)
1026 Rectangle aObjRect = pObject->GetCurrentBoundRect();
1027 bool bFit = true;
1028 if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
1029 bFit = false;
1030 if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
1031 bFit = false;
1032 // #i104716# don't include hidden note objects
1033 if ( bFit && pObject->GetLayer() != SC_LAYER_HIDDEN )
1035 if (bSetHor)
1037 if (aObjRect.Left() < nStartX) nStartX = aObjRect.Left();
1038 if (aObjRect.Right() > nEndX) nEndX = aObjRect.Right();
1040 if (bSetVer)
1042 if (aObjRect.Top() < nStartY) nStartY = aObjRect.Top();
1043 if (aObjRect.Bottom() > nEndY) nEndY = aObjRect.Bottom();
1045 bAny = true;
1048 pObject = aIter.Next();
1052 if ( bNegativePage )
1054 nStartX = -nStartX; // reverse transformation, so the same cell address calculation works
1055 nEndX = -nEndX;
1056 ::std::swap( nStartX, nEndX );
1059 if (bAny)
1061 OSL_ENSURE( nStartX<=nEndX && nStartY<=nEndY, "Start/End wrong in ScDrawLayer::GetPrintArea" );
1063 if (bSetHor)
1065 nStartX = HmmToTwips( nStartX );
1066 nEndX = HmmToTwips( nEndX );
1067 long nWidth;
1068 SCCOL i;
1070 nWidth = 0;
1071 for (i=0; i<=MAXCOL && nWidth<=nStartX; i++)
1072 nWidth += pDoc->GetColWidth(i,nTab);
1073 rRange.aStart.SetCol( i>0 ? (i-1) : 0 );
1075 nWidth = 0;
1076 for (i=0; i<=MAXCOL && nWidth<=nEndX; i++) //TODO: start at Start
1077 nWidth += pDoc->GetColWidth(i,nTab);
1078 rRange.aEnd.SetCol( i>0 ? (i-1) : 0 );
1081 if (bSetVer)
1083 nStartY = HmmToTwips( nStartY );
1084 nEndY = HmmToTwips( nEndY );
1085 SCROW nRow = pDoc->GetRowForHeight( nTab, nStartY);
1086 rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
1087 nRow = pDoc->GetRowForHeight( nTab, nEndY);
1088 rRange.aEnd.SetRow( nRow == MAXROW ? MAXROW :
1089 (nRow>0 ? (nRow-1) : 0));
1092 else
1094 if (bSetHor)
1096 rRange.aStart.SetCol(0);
1097 rRange.aEnd.SetCol(0);
1099 if (bSetVer)
1101 rRange.aStart.SetRow(0);
1102 rRange.aEnd.SetRow(0);
1105 return bAny;
1108 void ScDrawLayer::AddCalcUndo( SdrUndoAction* pUndo )
1110 if (bRecording)
1112 if (!pUndoGroup)
1113 pUndoGroup = new SdrUndoGroup(*this);
1115 pUndoGroup->AddAction( pUndo );
1117 else
1118 delete pUndo;
1121 void ScDrawLayer::BeginCalcUndo(bool bDisableTextEditUsesCommonUndoManager)
1123 SetDisableTextEditUsesCommonUndoManager(bDisableTextEditUsesCommonUndoManager);
1124 DELETEZ(pUndoGroup);
1125 bRecording = true;
1128 SdrUndoGroup* ScDrawLayer::GetCalcUndo()
1130 SdrUndoGroup* pRet = pUndoGroup;
1131 pUndoGroup = NULL;
1132 bRecording = false;
1133 SetDisableTextEditUsesCommonUndoManager(false);
1134 return pRet;
1137 void ScDrawLayer::MoveArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
1138 SCsCOL nDx,SCsROW nDy, bool bInsDel, bool bUpdateNoteCaptionPos )
1140 OSL_ENSURE( pDoc, "ScDrawLayer::MoveArea without document" );
1141 if ( !pDoc )
1142 return;
1144 if (!bAdjustEnabled)
1145 return;
1147 bool bNegativePage = pDoc->IsNegativePage( nTab );
1149 Rectangle aRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1150 lcl_ReverseTwipsToMM( aRect );
1151 //TODO: use twips directly?
1153 Point aMove;
1155 if (nDx > 0)
1156 for (SCsCOL s=0; s<nDx; s++)
1157 aMove.X() += pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
1158 else
1159 for (SCsCOL s=-1; s>=nDx; s--)
1160 aMove.X() -= pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
1161 if (nDy > 0)
1162 aMove.Y() += pDoc->GetRowHeight( nRow1, nRow1+nDy-1, nTab);
1163 else
1164 aMove.Y() -= pDoc->GetRowHeight( nRow1+nDy, nRow1-1, nTab);
1166 if ( bNegativePage )
1167 aMove.X() = -aMove.X();
1169 Point aTopLeft = aRect.TopLeft(); // Beginning when zoomed out
1170 if (bInsDel)
1172 if ( aMove.X() != 0 && nDx < 0 ) // nDx counts cells, sign is independent of RTL
1173 aTopLeft.X() += aMove.X();
1174 if ( aMove.Y() < 0 )
1175 aTopLeft.Y() += aMove.Y();
1178 // Detectiv arrows: Adjust cell position
1180 MoveCells( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy, bUpdateNoteCaptionPos );
1183 bool ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow )
1185 OSL_ENSURE( pDoc, "ScDrawLayer::HasObjectsInRows without document" );
1186 if ( !pDoc )
1187 return false;
1189 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1190 OSL_ENSURE(pPage,"Page not found");
1191 if (!pPage)
1192 return false;
1194 // for an empty page, there's no need to calculate the row heights
1195 if (!pPage->GetObjCount())
1196 return false;
1198 Rectangle aTestRect;
1200 aTestRect.Top() += pDoc->GetRowHeight( 0, nStartRow-1, nTab);
1202 if (nEndRow==MAXROW)
1203 aTestRect.Bottom() = MAXMM;
1204 else
1206 aTestRect.Bottom() = aTestRect.Top();
1207 aTestRect.Bottom() += pDoc->GetRowHeight( nStartRow, nEndRow, nTab);
1208 TwipsToMM( aTestRect.Bottom() );
1211 TwipsToMM( aTestRect.Top() );
1213 aTestRect.Left() = 0;
1214 aTestRect.Right() = MAXMM;
1216 bool bNegativePage = pDoc->IsNegativePage( nTab );
1217 if ( bNegativePage )
1218 MirrorRectRTL( aTestRect );
1220 bool bFound = false;
1222 Rectangle aObjRect;
1223 SdrObjListIter aIter( *pPage );
1224 SdrObject* pObject = aIter.Next();
1225 while ( pObject && !bFound )
1227 aObjRect = pObject->GetSnapRect(); //TODO: GetLogicRect ?
1228 if (aTestRect.IsInside(aObjRect.TopLeft()) || aTestRect.IsInside(aObjRect.BottomLeft()))
1229 bFound = true;
1231 pObject = aIter.Next();
1234 return bFound;
1237 void ScDrawLayer::DeleteObjectsInArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1,
1238 SCCOL nCol2,SCROW nRow2 )
1240 OSL_ENSURE( pDoc, "ScDrawLayer::DeleteObjectsInArea without document" );
1241 if ( !pDoc )
1242 return;
1244 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1245 OSL_ENSURE(pPage,"Page ?");
1246 if (!pPage)
1247 return;
1249 pPage->RecalcObjOrdNums();
1251 const size_t nObjCount = pPage->GetObjCount();
1252 if (nObjCount)
1254 size_t nDelCount = 0;
1255 Rectangle aDelRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1257 boost::scoped_array<SdrObject*> ppObj(new SdrObject*[nObjCount]);
1259 SdrObjListIter aIter( *pPage, IM_FLAT );
1260 SdrObject* pObject = aIter.Next();
1261 while (pObject)
1263 // do not delete note caption, they are always handled by the cell note
1264 // TODO: detective objects are still deleted, is this desired?
1265 if (!IsNoteCaption( pObject ))
1267 Rectangle aObjRect = pObject->GetCurrentBoundRect();
1268 if ( aDelRect.IsInside( aObjRect ) )
1269 ppObj[nDelCount++] = pObject;
1272 pObject = aIter.Next();
1275 if (bRecording)
1276 for (size_t i=1; i<=nDelCount; ++i)
1277 AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
1279 for (size_t i=1; i<=nDelCount; ++i)
1280 pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1284 void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
1286 OSL_ENSURE( pDoc, "ScDrawLayer::DeleteObjectsInSelection without document" );
1287 if ( !pDoc )
1288 return;
1290 if ( !rMark.IsMultiMarked() )
1291 return;
1293 ScRange aMarkRange;
1294 rMark.GetMultiMarkArea( aMarkRange );
1296 SCTAB nTabCount = pDoc->GetTableCount();
1297 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
1298 for (; itr != itrEnd && *itr < nTabCount; ++itr)
1300 SCTAB nTab = *itr;
1301 SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1302 if (pPage)
1304 pPage->RecalcObjOrdNums();
1305 const size_t nObjCount = pPage->GetObjCount();
1306 if (nObjCount)
1308 size_t nDelCount = 0;
1309 // Rectangle around the whole selection
1310 Rectangle aMarkBound = pDoc->GetMMRect(
1311 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
1312 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab );
1314 boost::scoped_array<SdrObject*> ppObj(new SdrObject*[nObjCount]);
1316 SdrObjListIter aIter( *pPage, IM_FLAT );
1317 SdrObject* pObject = aIter.Next();
1318 while (pObject)
1320 // do not delete note caption, they are always handled by the cell note
1321 // TODO: detective objects are still deleted, is this desired?
1322 if (!IsNoteCaption( pObject ))
1324 Rectangle aObjRect = pObject->GetCurrentBoundRect();
1325 if ( aMarkBound.IsInside( aObjRect ) )
1327 ScRange aRange = pDoc->GetRange( nTab, aObjRect );
1328 if (rMark.IsAllMarked(aRange))
1329 ppObj[nDelCount++] = pObject;
1333 pObject = aIter.Next();
1336 // Delete objects (backwards)
1338 if (bRecording)
1339 for (size_t i=1; i<=nDelCount; ++i)
1340 AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
1342 for (size_t i=1; i<=nDelCount; ++i)
1343 pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1346 else
1348 OSL_FAIL("pPage?");
1353 void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const Rectangle& rRange )
1355 // copy everything in the specified range into the same page (sheet) in the clipboard doc
1357 SdrPage* pSrcPage = GetPage(static_cast<sal_uInt16>(nTab));
1358 if (pSrcPage)
1360 ScDrawLayer* pDestModel = NULL;
1361 SdrPage* pDestPage = NULL;
1363 SdrObjListIter aIter( *pSrcPage, IM_FLAT );
1364 SdrObject* pOldObject = aIter.Next();
1365 while (pOldObject)
1367 Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1368 // do not copy internal objects (detective) and note captions
1369 if ( rRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
1371 if ( !pDestModel )
1373 pDestModel = pClipDoc->GetDrawLayer(); // does the document already have a drawing layer?
1374 if ( !pDestModel )
1376 // allocate drawing layer in clipboard document only if there are objects to copy
1378 pClipDoc->InitDrawLayer(); //TODO: create contiguous pages
1379 pDestModel = pClipDoc->GetDrawLayer();
1381 if (pDestModel)
1382 pDestPage = pDestModel->GetPage( static_cast<sal_uInt16>(nTab) );
1385 OSL_ENSURE( pDestPage, "no page" );
1386 if (pDestPage)
1388 SdrObject* pNewObject = pOldObject->Clone();
1389 pNewObject->SetModel(pDestModel);
1390 pNewObject->SetPage(pDestPage);
1392 uno::Reference< chart2::XChartDocument > xOldChart( ScChartHelper::GetChartFromSdrObject( pOldObject ) );
1393 if(!xOldChart.is())//#i110034# do not move charts as they lose all their data references otherwise
1394 pNewObject->NbcMove(Size(0,0));
1395 pDestPage->InsertObject( pNewObject );
1397 // no undo needed in clipboard document
1398 // charts are not updated
1402 pOldObject = aIter.Next();
1407 static bool lcl_IsAllInRange( const ::std::vector< ScRangeList >& rRangesVector, const ScRange& rClipRange )
1409 // check if every range of rRangesVector is completely in rClipRange
1411 ::std::vector< ScRangeList >::const_iterator aIt = rRangesVector.begin();
1412 for( ;aIt!=rRangesVector.end(); ++aIt )
1414 const ScRangeList& rRanges = *aIt;
1415 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
1417 ScRange aRange = *rRanges[ i ];
1418 if ( !rClipRange.In( aRange ) )
1420 return false; // at least one range is not valid
1425 return true; // everything is fine
1428 static bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const ScRange& rSourceRange, const ScAddress& rDestPos )
1430 bool bChanged = false;
1432 ::std::vector< ScRangeList >::iterator aIt = rRangesVector.begin();
1433 for( ;aIt!=rRangesVector.end(); ++aIt )
1435 ScRangeList& rRanges = *aIt;
1436 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
1438 ScRange* pRange = rRanges[ i ];
1439 if ( rSourceRange.In( *pRange ) )
1441 SCsCOL nDiffX = rDestPos.Col() - (SCsCOL)rSourceRange.aStart.Col();
1442 SCsROW nDiffY = rDestPos.Row() - (SCsROW)rSourceRange.aStart.Row();
1443 SCsTAB nDiffZ = rDestPos.Tab() - (SCsTAB)rSourceRange.aStart.Tab();
1444 pRange->Move( nDiffX, nDiffY, nDiffZ );
1445 bChanged = true;
1450 return bChanged;
1453 void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const Rectangle& rSourceRange,
1454 const ScAddress& rDestPos, const Rectangle& rDestRange )
1456 OSL_ENSURE( pDoc, "ScDrawLayer::CopyFromClip without document" );
1457 if ( !pDoc )
1458 return;
1460 if (!pClipModel)
1461 return;
1463 if (bDrawIsInUndo) //TODO: can this happen?
1465 OSL_FAIL("CopyFromClip, bDrawIsInUndo");
1466 return;
1469 bool bMirrorObj = ( rSourceRange.Left() < 0 && rSourceRange.Right() < 0 &&
1470 rDestRange.Left() > 0 && rDestRange.Right() > 0 ) ||
1471 ( rSourceRange.Left() > 0 && rSourceRange.Right() > 0 &&
1472 rDestRange.Left() < 0 && rDestRange.Right() < 0 );
1473 Rectangle aMirroredSource = rSourceRange;
1474 if ( bMirrorObj )
1475 MirrorRectRTL( aMirroredSource );
1477 SCTAB nDestTab = rDestPos.Tab();
1479 SdrPage* pSrcPage = pClipModel->GetPage(static_cast<sal_uInt16>(nSourceTab));
1480 SdrPage* pDestPage = GetPage(static_cast<sal_uInt16>(nDestTab));
1481 OSL_ENSURE( pSrcPage && pDestPage, "draw page missing" );
1482 if ( !pSrcPage || !pDestPage )
1483 return;
1485 SdrObjListIter aIter( *pSrcPage, IM_FLAT );
1486 SdrObject* pOldObject = aIter.Next();
1488 ScDocument* pClipDoc = pClipModel->GetDocument();
1489 // a clipboard document and its source share the same document item pool,
1490 // so the pointers can be compared to see if this is copy&paste within
1491 // the same document
1492 bool bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
1493 bool bDestClip = pDoc && pDoc->IsClipboard();
1495 //#i110034# charts need correct sheet names for xml range conversion during load
1496 //so the target sheet name is temporarily renamed (if we have any SdrObjects)
1497 OUString aDestTabName;
1498 bool bRestoreDestTabName = false;
1499 if( pOldObject && !bSameDoc && !bDestClip )
1501 if( pDoc && pClipDoc )
1503 OUString aSourceTabName;
1504 if( pClipDoc->GetName( nSourceTab, aSourceTabName )
1505 && pDoc->GetName( nDestTab, aDestTabName ) )
1507 if( !aSourceTabName.equals(aDestTabName) &&
1508 pDoc->ValidNewTabName(aSourceTabName) )
1510 bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName ); //sal_Bool bUpdateRef = sal_True, sal_Bool bExternalDocument = sal_False
1516 // first mirror, then move
1517 Size aMove( rDestRange.Left() - aMirroredSource.Left(), rDestRange.Top() - aMirroredSource.Top() );
1519 long nDestWidth = rDestRange.GetWidth();
1520 long nDestHeight = rDestRange.GetHeight();
1521 long nSourceWidth = rSourceRange.GetWidth();
1522 long nSourceHeight = rSourceRange.GetHeight();
1524 long nWidthDiff = nDestWidth - nSourceWidth;
1525 long nHeightDiff = nDestHeight - nSourceHeight;
1527 Fraction aHorFract(1,1);
1528 Fraction aVerFract(1,1);
1529 bool bResize = false;
1530 // sizes can differ by 1 from twips->1/100mm conversion for equal cell sizes,
1531 // don't resize to empty size when pasting into hidden columns or rows
1532 if ( std::abs(nWidthDiff) > 1 && nDestWidth > 1 && nSourceWidth > 1 )
1534 aHorFract = Fraction( nDestWidth, nSourceWidth );
1535 bResize = true;
1537 if ( std::abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
1539 aVerFract = Fraction( nDestHeight, nSourceHeight );
1540 bResize = true;
1542 Point aRefPos = rDestRange.TopLeft(); // for resizing (after moving)
1544 while (pOldObject)
1546 Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1547 // do not copy internal objects (detective) and note captions
1548 if ( rSourceRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
1550 SdrObject* pNewObject = pOldObject->Clone();
1551 pNewObject->SetModel(this);
1552 pNewObject->SetPage(pDestPage);
1554 if ( bMirrorObj )
1555 MirrorRTL( pNewObject ); // first mirror, then move
1557 pNewObject->NbcMove( aMove );
1558 if ( bResize )
1559 pNewObject->NbcResize( aRefPos, aHorFract, aVerFract );
1561 pDestPage->InsertObject( pNewObject );
1562 if (bRecording)
1563 AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) );
1565 //#i110034# handle chart data references (after InsertObject)
1567 if ( pNewObject->GetObjIdentifier() == OBJ_OLE2 )
1569 uno::Reference< embed::XEmbeddedObject > xIPObj = static_cast<SdrOle2Obj*>(pNewObject)->GetObjRef();
1570 uno::Reference< embed::XClassifiedObject > xClassified( xIPObj, uno::UNO_QUERY );
1571 SvGlobalName aObjectClassName;
1572 if ( xClassified.is() )
1574 try {
1575 aObjectClassName = SvGlobalName( xClassified->getClassID() );
1576 } catch( uno::Exception& )
1578 // TODO: handle error?
1582 if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
1584 uno::Reference< chart2::XChartDocument > xNewChart( ScChartHelper::GetChartFromSdrObject( pNewObject ) );
1585 if( xNewChart.is() && !xNewChart->hasInternalDataProvider() )
1587 OUString aChartName = static_cast<SdrOle2Obj*>(pNewObject)->GetPersistName();
1588 ::std::vector< ScRangeList > aRangesVector;
1589 pDoc->GetChartRanges( aChartName, aRangesVector, pDoc );
1590 if( !aRangesVector.empty() )
1592 bool bInSourceRange = false;
1593 ScRange aClipRange;
1594 if ( pClipDoc )
1596 SCCOL nClipStartX;
1597 SCROW nClipStartY;
1598 SCCOL nClipEndX;
1599 SCROW nClipEndY;
1600 pClipDoc->GetClipStart( nClipStartX, nClipStartY );
1601 pClipDoc->GetClipArea( nClipEndX, nClipEndY, true );
1602 nClipEndX = nClipEndX + nClipStartX;
1603 nClipEndY += nClipStartY; // GetClipArea returns the difference
1605 SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
1606 aClipRange = ScRange( nClipStartX, nClipStartY, nClipTab,
1607 nClipEndX, nClipEndY, nClipTab );
1609 bInSourceRange = lcl_IsAllInRange( aRangesVector, aClipRange );
1612 // always lose references when pasting into a clipboard document (transpose)
1613 if ( ( bInSourceRange || bSameDoc ) && !bDestClip )
1615 if ( bInSourceRange )
1617 if ( rDestPos != aClipRange.aStart )
1619 // update the data ranges to the new (copied) position
1620 if ( lcl_MoveRanges( aRangesVector, aClipRange, rDestPos ) )
1621 pDoc->SetChartRanges( aChartName, aRangesVector );
1624 else
1626 // leave the ranges unchanged
1629 else
1631 // pasting into a new document without the complete source data
1632 // -> break connection to source data and switch to own data
1634 uno::Reference< chart::XChartDocument > xOldChartDoc( ScChartHelper::GetChartFromSdrObject( pOldObject ), uno::UNO_QUERY );
1635 uno::Reference< chart::XChartDocument > xNewChartDoc( xNewChart, uno::UNO_QUERY );
1636 if( xOldChartDoc.is() && xNewChartDoc.is() )
1637 xNewChartDoc->attachData( xOldChartDoc->getData() );
1639 // (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
1647 pOldObject = aIter.Next();
1650 if( bRestoreDestTabName )
1651 pDoc->RenameTab( nDestTab, aDestTabName );
1654 void ScDrawLayer::MirrorRTL( SdrObject* pObj )
1656 sal_uInt16 nIdent = pObj->GetObjIdentifier();
1658 // don't mirror OLE or graphics, otherwise ask the object
1659 // if it can be mirrored
1660 bool bCanMirror = ( nIdent != OBJ_GRAF && nIdent != OBJ_OLE2 );
1661 if (bCanMirror)
1663 SdrObjTransformInfoRec aInfo;
1664 pObj->TakeObjInfo( aInfo );
1665 bCanMirror = aInfo.bMirror90Allowed;
1668 if (bCanMirror)
1670 Point aRef1( 0, 0 );
1671 Point aRef2( 0, 1 );
1672 if (bRecording)
1673 AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
1674 pObj->Mirror( aRef1, aRef2 );
1676 else
1678 // Move instead of mirroring:
1679 // New start position is negative of old end position
1680 // -> move by sum of start and end position
1681 Rectangle aObjRect = pObj->GetLogicRect();
1682 Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
1683 if (bRecording)
1684 AddCalcUndo( new SdrUndoMoveObj( *pObj, aMoveSize ) );
1685 pObj->Move( aMoveSize );
1689 void ScDrawLayer::MirrorRectRTL( Rectangle& rRect )
1691 // mirror and swap left/right
1692 long nTemp = rRect.Left();
1693 rRect.Left() = -rRect.Right();
1694 rRect.Right() = -nTemp;
1697 Rectangle ScDrawLayer::GetCellRect( ScDocument& rDoc, const ScAddress& rPos, bool bMergedCell )
1699 Rectangle aCellRect;
1700 OSL_ENSURE( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ), "ScDrawLayer::GetCellRect - invalid cell address" );
1701 if( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ) )
1703 // find top left position of passed cell address
1704 Point aTopLeft;
1705 for( SCCOL nCol = 0; nCol < rPos.Col(); ++nCol )
1706 aTopLeft.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
1707 if( rPos.Row() > 0 )
1708 aTopLeft.Y() += rDoc.GetRowHeight( 0, rPos.Row() - 1, rPos.Tab() );
1710 // find bottom-right position of passed cell address
1711 ScAddress aEndPos = rPos;
1712 if( bMergedCell )
1714 const ScMergeAttr* pMerge = static_cast< const ScMergeAttr* >( rDoc.GetAttr( rPos.Col(), rPos.Row(), rPos.Tab(), ATTR_MERGE ) );
1715 if( pMerge->GetColMerge() > 1 )
1716 aEndPos.IncCol( pMerge->GetColMerge() - 1 );
1717 if( pMerge->GetRowMerge() > 1 )
1718 aEndPos.IncRow( pMerge->GetRowMerge() - 1 );
1720 Point aBotRight = aTopLeft;
1721 for( SCCOL nCol = rPos.Col(); nCol <= aEndPos.Col(); ++nCol )
1722 aBotRight.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
1723 aBotRight.Y() += rDoc.GetRowHeight( rPos.Row(), aEndPos.Row(), rPos.Tab() );
1725 // twips -> 1/100 mm
1726 aTopLeft.X() = static_cast< long >( aTopLeft.X() * HMM_PER_TWIPS );
1727 aTopLeft.Y() = static_cast< long >( aTopLeft.Y() * HMM_PER_TWIPS );
1728 aBotRight.X() = static_cast< long >( aBotRight.X() * HMM_PER_TWIPS );
1729 aBotRight.Y() = static_cast< long >( aBotRight.Y() * HMM_PER_TWIPS );
1731 aCellRect = Rectangle( aTopLeft, aBotRight );
1732 if( rDoc.IsNegativePage( rPos.Tab() ) )
1733 MirrorRectRTL( aCellRect );
1735 return aCellRect;
1738 OUString ScDrawLayer::GetVisibleName( SdrObject* pObj )
1740 OUString aName = pObj->GetName();
1741 if ( pObj->GetObjIdentifier() == OBJ_OLE2 )
1743 // For OLE, the user defined name (GetName) is used
1744 // if it's not empty (accepting possibly duplicate names),
1745 // otherwise the persist name is used so every object appears
1746 // in the Navigator at all.
1748 if ( aName.isEmpty() )
1749 aName = static_cast<SdrOle2Obj*>(pObj)->GetPersistName();
1751 return aName;
1754 inline bool IsNamedObject( SdrObject* pObj, const OUString& rName )
1756 // sal_True if rName is the object's Name or PersistName
1757 // (used to find a named object)
1759 return ( pObj->GetName().equals(rName) ||
1760 ( pObj->GetObjIdentifier() == OBJ_OLE2 &&
1761 static_cast<SdrOle2Obj*>(pObj)->GetPersistName() == rName ) );
1764 SdrObject* ScDrawLayer::GetNamedObject( const OUString& rName, sal_uInt16 nId, SCTAB& rFoundTab ) const
1766 sal_uInt16 nTabCount = GetPageCount();
1767 for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
1769 const SdrPage* pPage = GetPage(nTab);
1770 OSL_ENSURE(pPage,"Page ?");
1771 if (pPage)
1773 SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
1774 SdrObject* pObject = aIter.Next();
1775 while (pObject)
1777 if ( nId == 0 || pObject->GetObjIdentifier() == nId )
1778 if ( IsNamedObject( pObject, rName ) )
1780 rFoundTab = static_cast<SCTAB>(nTab);
1781 return pObject;
1784 pObject = aIter.Next();
1789 return NULL;
1792 OUString ScDrawLayer::GetNewGraphicName( long* pnCounter ) const
1794 OUString aBase = ScGlobal::GetRscString(STR_GRAPHICNAME);
1795 aBase += " ";
1797 bool bThere = true;
1798 OUString aGraphicName;
1799 SCTAB nDummy;
1800 long nId = pnCounter ? *pnCounter : 0;
1801 while (bThere)
1803 ++nId;
1804 aGraphicName = aBase;
1805 aGraphicName += OUString::number( nId );
1806 bThere = ( GetNamedObject( aGraphicName, 0, nDummy ) != NULL );
1809 if ( pnCounter )
1810 *pnCounter = nId;
1812 return aGraphicName;
1815 void ScDrawLayer::EnsureGraphicNames()
1817 // make sure all graphic objects have names (after Excel import etc.)
1819 sal_uInt16 nTabCount = GetPageCount();
1820 for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
1822 SdrPage* pPage = GetPage(nTab);
1823 OSL_ENSURE(pPage,"Page ?");
1824 if (pPage)
1826 SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
1827 SdrObject* pObject = aIter.Next();
1829 /* The index passed to GetNewGraphicName() will be set to
1830 the used index in each call. This prevents the repeated search
1831 for all names from 1 to current index. */
1832 long nCounter = 0;
1834 while (pObject)
1836 if ( pObject->GetObjIdentifier() == OBJ_GRAF && pObject->GetName().isEmpty())
1837 pObject->SetName( GetNewGraphicName( &nCounter ) );
1839 pObject = aIter.Next();
1845 namespace
1847 SdrObjUserData* GetFirstUserDataOfType(const SdrObject *pObj, sal_uInt16 nId)
1849 sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
1850 for( sal_uInt16 i = 0; i < nCount; i++ )
1852 SdrObjUserData* pData = pObj->GetUserData( i );
1853 if( pData && pData->GetInventor() == SC_DRAWLAYER && pData->GetId() == nId )
1854 return pData;
1856 return NULL;
1859 void DeleteFirstUserDataOfType(SdrObject *pObj, sal_uInt16 nId)
1861 sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
1862 for( sal_uInt16 i = nCount; i > 0; i-- )
1864 SdrObjUserData* pData = pObj->GetUserData( i-1 );
1865 if( pData && pData->GetInventor() == SC_DRAWLAYER && pData->GetId() == nId )
1866 pObj->DeleteUserData(i-1);
1871 void ScDrawLayer::SetVisualCellAnchored( SdrObject &rObj, const ScDrawObjData &rAnchor )
1873 ScDrawObjData* pAnchor = GetNonRotatedObjData( &rObj, true );
1874 pAnchor->maStart = rAnchor.maStart;
1875 pAnchor->maEnd = rAnchor.maEnd;
1876 pAnchor->maStartOffset = rAnchor.maStartOffset;
1877 pAnchor->maEndOffset = rAnchor.maEndOffset;
1880 void ScDrawLayer::SetCellAnchored( SdrObject &rObj, const ScDrawObjData &rAnchor )
1882 ScDrawObjData* pAnchor = GetObjData( &rObj, true );
1883 pAnchor->maStart = rAnchor.maStart;
1884 pAnchor->maEnd = rAnchor.maEnd;
1885 pAnchor->maStartOffset = rAnchor.maStartOffset;
1886 pAnchor->maEndOffset = rAnchor.maEndOffset;
1889 void ScDrawLayer::SetCellAnchoredFromPosition( SdrObject &rObj, const ScDocument &rDoc, SCTAB nTab )
1891 ScDrawObjData aAnchor;
1892 // set anchor in terms of the visual ( SnapRect )
1893 // object ( e.g. for when object is rotated )
1894 GetCellAnchorFromPosition( rObj, aAnchor, rDoc, nTab, false );
1895 SetCellAnchored( rObj, aAnchor );
1896 // - keep also an anchor in terms of the Logic ( untransformed ) object
1897 // because thats what we stored ( and still do ) to xml
1898 ScDrawObjData aVisAnchor;
1899 GetCellAnchorFromPosition( rObj, aVisAnchor, rDoc, nTab );
1900 SetVisualCellAnchored( rObj, aVisAnchor );
1901 // absolutely necessary to set flag that in order to preven ScDrawLayer::RecalcPos
1902 // doing an initialisation hack
1903 if ( ScDrawObjData* pAnchor = GetObjData( &rObj ) )
1905 pAnchor->maLastRect = rObj.GetSnapRect();
1909 void ScDrawLayer::GetCellAnchorFromPosition( SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect, bool bHiddenAsZero )
1911 Rectangle aObjRect( bUseLogicRect ? rObj.GetLogicRect() : rObj.GetSnapRect() );
1912 ScRange aRange = rDoc.GetRange( nTab, aObjRect, bHiddenAsZero );
1914 Rectangle aCellRect;
1916 rAnchor.maStart = aRange.aStart;
1917 aCellRect = rDoc.GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(),
1918 aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), bHiddenAsZero );
1919 rAnchor.maStartOffset.Y() = aObjRect.Top()-aCellRect.Top();
1920 if (!rDoc.IsNegativePage(nTab))
1921 rAnchor.maStartOffset.X() = aObjRect.Left()-aCellRect.Left();
1922 else
1923 rAnchor.maStartOffset.X() = aCellRect.Right()-aObjRect.Right();
1925 rAnchor.maEnd = aRange.aEnd;
1926 aCellRect = rDoc.GetMMRect( aRange.aEnd.Col(), aRange.aEnd.Row(),
1927 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), bHiddenAsZero );
1928 rAnchor.maEndOffset.Y() = aObjRect.Bottom()-aCellRect.Top();
1929 if (!rDoc.IsNegativePage(nTab))
1930 rAnchor.maEndOffset.X() = aObjRect.Right()-aCellRect.Left();
1931 else
1932 rAnchor.maEndOffset.X() = aCellRect.Right()-aObjRect.Left();
1936 void ScDrawLayer::UpdateCellAnchorFromPositionEnd( SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect )
1938 Rectangle aObjRect(bUseLogicRect ? rObj.GetLogicRect() : rObj.GetSnapRect());
1939 ScRange aRange = rDoc.GetRange( nTab, aObjRect );
1941 ScDrawObjData* pAnchor = &rAnchor;
1942 pAnchor->maEnd = aRange.aEnd;
1944 Rectangle aCellRect;
1945 aCellRect = rDoc.GetMMRect( aRange.aEnd.Col(), aRange.aEnd.Row(),
1946 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab() );
1947 pAnchor->maEndOffset.Y() = aObjRect.Bottom()-aCellRect.Top();
1948 if (!rDoc.IsNegativePage(nTab))
1949 pAnchor->maEndOffset.X() = aObjRect.Right()-aCellRect.Left();
1950 else
1951 pAnchor->maEndOffset.X() = aCellRect.Right()-aObjRect.Left();
1954 bool ScDrawLayer::IsCellAnchored( const SdrObject& rObj )
1956 // Cell anchored object always has a user data, to store the anchor cell
1957 // info. If it doesn't then it's page-anchored.
1958 return GetFirstUserDataOfType(&rObj, SC_UD_OBJDATA) != NULL;
1961 void ScDrawLayer::SetPageAnchored( SdrObject &rObj )
1963 DeleteFirstUserDataOfType(&rObj, SC_UD_OBJDATA);
1964 DeleteFirstUserDataOfType(&rObj, SC_UD_OBJDATA);
1967 ScAnchorType ScDrawLayer::GetAnchorType( const SdrObject &rObj )
1969 //If this object has a cell anchor associated with it
1970 //then its cell-anchored, otherwise its page-anchored
1971 return ScDrawLayer::GetObjData(const_cast<SdrObject*>(&rObj)) ? SCA_CELL : SCA_PAGE;
1974 ScDrawObjData* ScDrawLayer::GetNonRotatedObjData( SdrObject* pObj, bool bCreate )
1976 sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
1977 sal_uInt16 nFound = 0;
1978 for( sal_uInt16 i = 0; i < nCount; i++ )
1980 SdrObjUserData* pData = pObj->GetUserData( i );
1981 if( pData && pData->GetInventor() == SC_DRAWLAYER && pData->GetId() == SC_UD_OBJDATA && ++nFound == 2 )
1982 return static_cast<ScDrawObjData*>(pData);
1984 if( pObj && bCreate )
1986 ScDrawObjData* pData = new ScDrawObjData;
1987 pObj->AppendUserData(pData);
1988 return pData;
1990 return 0;
1993 ScDrawObjData* ScDrawLayer::GetObjData( SdrObject* pObj, bool bCreate )
1995 if (SdrObjUserData *pData = GetFirstUserDataOfType(pObj, SC_UD_OBJDATA))
1996 return static_cast<ScDrawObjData*>(pData);
1998 if( pObj && bCreate )
2000 ScDrawObjData* pData = new ScDrawObjData;
2001 pObj->AppendUserData(pData);
2002 return pData;
2004 return 0;
2007 ScDrawObjData* ScDrawLayer::GetObjDataTab( SdrObject* pObj, SCTAB nTab )
2009 ScDrawObjData* pData = GetObjData( pObj );
2010 if ( pData )
2012 if ( pData->maStart.IsValid() )
2013 pData->maStart.SetTab( nTab );
2014 if ( pData->maEnd.IsValid() )
2015 pData->maEnd.SetTab( nTab );
2017 return pData;
2020 bool ScDrawLayer::IsNoteCaption( SdrObject* pObj )
2022 ScDrawObjData* pData = pObj ? GetObjData( pObj ) : 0;
2023 return pData && pData->meType == ScDrawObjData::CellNote;
2026 ScDrawObjData* ScDrawLayer::GetNoteCaptionData( SdrObject* pObj, SCTAB nTab )
2028 ScDrawObjData* pData = pObj ? GetObjDataTab( pObj, nTab ) : 0;
2029 return (pData && pData->meType == ScDrawObjData::CellNote) ? pData : 0;
2032 ScIMapInfo* ScDrawLayer::GetIMapInfo( SdrObject* pObj )
2034 return static_cast<ScIMapInfo*>(GetFirstUserDataOfType(pObj, SC_UD_IMAPDATA));
2037 IMapObject* ScDrawLayer::GetHitIMapObject( SdrObject* pObj,
2038 const Point& rWinPoint, const vcl::Window& rCmpWnd )
2040 const MapMode aMap100( MAP_100TH_MM );
2041 MapMode aWndMode = rCmpWnd.GetMapMode();
2042 Point aRelPoint( rCmpWnd.LogicToLogic( rWinPoint, &aWndMode, &aMap100 ) );
2043 Rectangle aLogRect = rCmpWnd.LogicToLogic( pObj->GetLogicRect(), &aWndMode, &aMap100 );
2044 ScIMapInfo* pIMapInfo = GetIMapInfo( pObj );
2045 IMapObject* pIMapObj = NULL;
2047 if ( pIMapInfo )
2049 Size aGraphSize;
2050 ImageMap& rImageMap = (ImageMap&) pIMapInfo->GetImageMap();
2051 Graphic aGraphic;
2052 bool bObjSupported = false;
2054 if ( pObj->ISA( SdrGrafObj ) ) // Simple Graphics object
2056 const SdrGrafObj* pGrafObj = static_cast<const SdrGrafObj*>( pObj );
2057 const GeoStat& rGeo = pGrafObj->GetGeoStat();
2058 const Graphic& rGraphic = pGrafObj->GetGraphic();
2060 // Reverse rotation
2061 if ( rGeo.nRotationAngle )
2062 RotatePoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nSin, rGeo.nCos );
2064 // Reverse mirroring
2065 if ( static_cast<const SdrGrafObjGeoData*>( pGrafObj->GetGeoData() )->bMirrored )
2066 aRelPoint.X() = aLogRect.Right() + aLogRect.Left() - aRelPoint.X();
2068 // Possible Unshear:
2069 if ( rGeo.nShearAngle )
2070 ShearPoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nTan );
2072 if ( rGraphic.GetPrefMapMode().GetMapUnit() == MAP_PIXEL )
2073 aGraphSize = rCmpWnd.PixelToLogic( rGraphic.GetPrefSize(),
2074 aMap100 );
2075 else
2076 aGraphSize = OutputDevice::LogicToLogic( rGraphic.GetPrefSize(),
2077 rGraphic.GetPrefMapMode(),
2078 aMap100 );
2080 bObjSupported = true;
2082 else if ( pObj->ISA( SdrOle2Obj ) ) // OLE object
2084 // TODO/LEAN: working with visual area needs running state
2085 aGraphSize = static_cast<const SdrOle2Obj*>(pObj)->GetOrigObjSize();
2086 bObjSupported = true;
2089 // If everything has worked out, then perform HitTest
2090 if ( bObjSupported )
2092 // Calculate relative mouse point
2093 aRelPoint -= aLogRect.TopLeft();
2094 pIMapObj = rImageMap.GetHitIMapObject( aGraphSize, aLogRect.GetSize(), aRelPoint );
2098 return pIMapObj;
2101 ScMacroInfo* ScDrawLayer::GetMacroInfo( SdrObject* pObj, bool bCreate )
2103 if (SdrObjUserData *pData = GetFirstUserDataOfType(pObj, SC_UD_MACRODATA))
2104 return static_cast<ScMacroInfo*>(pData);
2106 if ( bCreate )
2108 ScMacroInfo* pData = new ScMacroInfo;
2109 pObj->AppendUserData(pData);
2110 return pData;
2112 return 0;
2115 ImageMap* ScDrawLayer::GetImageMapForObject(SdrObject* pObj)
2117 ScIMapInfo* pIMapInfo = const_cast<ScIMapInfo*>( GetIMapInfo( pObj ) );
2118 if ( pIMapInfo )
2120 return const_cast<ImageMap*>( &(pIMapInfo->GetImageMap()) );
2122 return NULL;
2125 sal_Int32 ScDrawLayer::GetHyperlinkCount(SdrObject* pObj)
2127 sal_Int32 nHLCount = 0;
2128 ScMacroInfo* pMacroInfo = GetMacroInfo(pObj, false);
2129 if (pMacroInfo)
2130 // MT IA2: GetHlink*( doesn't exist in DEV300 anymore...
2131 nHLCount = 0; // pMacroInfo->GetHlink().getLength() > 0 ? 1 : 0;
2132 return nHLCount;
2135 void ScDrawLayer::SetGlobalDrawPersist(SfxObjectShell* pPersist)
2137 OSL_ENSURE(!pGlobalDrawPersist,"Multiple SetGlobalDrawPersist");
2138 pGlobalDrawPersist = pPersist;
2141 void ScDrawLayer::SetChanged( bool bFlg /* = true */ )
2143 if ( bFlg && pDoc )
2144 pDoc->SetChartListenerCollectionNeedsUpdate( true );
2145 FmFormModel::SetChanged( bFlg );
2148 SdrLayerID ScDrawLayer::GetControlExportLayerId( const SdrObject & ) const
2150 // Layer for export of Form-Controls in Versions before 5.0 - always SC_LAYER_FRONT
2151 return SC_LAYER_FRONT;
2154 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > ScDrawLayer::createUnoModel()
2156 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet;
2157 if( pDoc && pDoc->GetDocumentShell() )
2158 xRet = pDoc->GetDocumentShell()->GetModel();
2160 return xRet;
2163 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */