LibreOffice Module sc (master)  1
drwlayer.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <com/sun/star/uno/Reference.hxx>
21 #include <com/sun/star/chart/XChartDocument.hpp>
22 #include <com/sun/star/chart2/XChartDocument.hpp>
23 #include <com/sun/star/embed/XClassifiedObject.hpp>
24 #include <com/sun/star/embed/XEmbeddedObject.hpp>
25 
26 #include <scitems.hxx>
27 #include <editeng/eeitem.hxx>
28 #include <editeng/frmdiritem.hxx>
29 #include <sot/exchange.hxx>
30 #include <svx/objfac3d.hxx>
31 #include <svx/xtable.hxx>
32 #include <svx/svdoutl.hxx>
33 #include <svx/svditer.hxx>
34 #include <svx/svdlayer.hxx>
35 #include <svx/svdoashp.hxx>
36 #include <svx/svdobj.hxx>
37 #include <svx/svdocapt.hxx>
38 #include <svx/svdomeas.hxx>
39 #include <svx/svdoole2.hxx>
40 #include <svx/svdopath.hxx>
41 #include <svx/svdundo.hxx>
42 #include <svx/sdsxyitm.hxx>
43 #include <svx/svxids.hrc>
44 #include <i18nlangtag/mslangid.hxx>
45 #include <editeng/unolingu.hxx>
46 #include <svx/drawitem.hxx>
47 #include <editeng/fhgtitem.hxx>
49 #include <sfx2/objsh.hxx>
50 #include <svl/itempool.hxx>
51 #include <vcl/canvastools.hxx>
52 #include <vcl/svapp.hxx>
53 #include <vcl/settings.hxx>
54 #include <tools/globname.hxx>
55 
58 
59 #include <drwlayer.hxx>
60 #include <drawpage.hxx>
61 #include <global.hxx>
62 #include <document.hxx>
63 #include <userdat.hxx>
64 #include <markdata.hxx>
65 #include <globstr.hrc>
66 #include <scresid.hxx>
67 #include <scmod.hxx>
68 #include <postit.hxx>
69 #include <attrib.hxx>
70 #include <charthelper.hxx>
71 #include <table.hxx>
73 
74 #include <vcl/fieldvalues.hxx>
75 #include <memory>
76 #include <algorithm>
77 #include <cstdlib>
78 
79 namespace com::sun::star::embed { class XEmbeddedObject; }
80 
81 #define DET_ARROW_OFFSET 1000
82 
83 using namespace ::com::sun::star;
84 
85 static E3dObjFactory* pF3d = nullptr;
86 static sal_uInt16 nInst = 0;
87 
89 
90 bool bDrawIsInUndo = false; //TODO: Member
91 
93  const ScAddress& rNS, const ScAddress& rNE ) :
94  SdrUndoObj( *pObjP ),
95  aOldStt( rOS ),
96  aOldEnd( rOE ),
97  aNewStt( rNS ),
98  aNewEnd( rNE )
99 {
100 }
101 
103 {
104 }
105 
107 {
109  OSL_ENSURE(pData,"ScUndoObjData: Data missing");
110  if (pData)
111  {
112  pData->maStart = aOldStt;
113  pData->maEnd = aOldEnd;
114  }
115 
116  // Undo also an untransformed anchor
118  if (pData)
119  {
120  pData->maStart = aOldStt;
121  pData->maEnd = aOldEnd;
122  }
123 }
124 
126 {
128  OSL_ENSURE(pData,"ScUndoObjData: Data missing");
129  if (pData)
130  {
131  pData->maStart = aNewStt;
132  pData->maEnd = aNewEnd;
133  }
134 
135  // Redo also an untransformed anchor
137  if (pData)
138  {
139  pData->maStart = aNewStt;
140  pData->maEnd = aNewEnd;
141  }
142 }
143 
145  SdrUndoObj( *pObjP ),
146  mpDoc( pDoc ),
147  mnTab( nTab )
148 {
151 }
152 
154 {
155 }
156 
158 {
159  // Trigger Object Change
161  {
162  SdrHint aHint(SdrHintKind::ObjectChange, *pObj);
163  pObj->getSdrModelFromSdrObject().Broadcast(aHint);
164  }
165 
166  if (mbWasCellAnchored)
168  else
170 }
171 
173 {
174  if (mbWasCellAnchored)
176  else
178 
179  // Trigger Object Change
181  {
182  SdrHint aHint(SdrHintKind::ObjectChange, *pObj);
183  pObj->getSdrModelFromSdrObject().Broadcast(aHint);
184  }
185 }
186 
188  nTab( nTabNo )
189 {
190 }
191 
193 {
194 }
195 
197  nTab( nTabNo )
198 {
199 }
200 
202 {
203 }
204 
205 #define MAXMM 10000000
206 
208 {
209  return static_cast< tools::Long >( vcl::ConvertDoubleValue (static_cast<sal_Int64>(nVal), 0, 0,
210  FieldUnit::TWIP, FieldUnit::MM_100TH) );
211 }
212 
214 {
215  return static_cast< tools::Long > ( vcl::ConvertDoubleValue (static_cast<sal_Int64>(nVal), 0, 0,
216  FieldUnit::MM_100TH, FieldUnit::TWIP) );
217 }
218 
220 {
221  rRect.SetLeft( HmmToTwips( rRect.Left() ) );
222  rRect.SetRight( HmmToTwips( rRect.Right() ) );
223  rRect.SetTop( HmmToTwips( rRect.Top()) );
224  rRect.SetBottom( HmmToTwips(rRect.Bottom()) );
225 }
226 
228 {
229  if (!pClipDoc)
230  return ScRange();
231 
232  SCCOL nClipStartX;
233  SCROW nClipStartY;
234  SCCOL nClipEndX;
235  SCROW nClipEndY;
236  pClipDoc->GetClipStart(nClipStartX, nClipStartY);
237  pClipDoc->GetClipArea(nClipEndX, nClipEndY, true);
238  nClipEndX = nClipEndX + nClipStartX;
239  nClipEndY += nClipStartY; // GetClipArea returns the difference
240 
241  return ScRange(nClipStartX, nClipStartY, nClipTab, nClipEndX, nClipEndY, nClipTab);
242 }
243 
244 ScDrawLayer::ScDrawLayer( ScDocument* pDocument, const OUString& rName ) :
245  FmFormModel(
246  nullptr,
247  pGlobalDrawPersist ? pGlobalDrawPersist : (pDocument ? pDocument->GetDocumentShell() : nullptr)),
248  aName( rName ),
249  pDoc( pDocument ),
250  bRecording( false ),
251  bAdjustEnabled( true ),
252  bHyphenatorSet( false )
253 {
254  pGlobalDrawPersist = nullptr; // Only use once
255 
256  SfxObjectShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : nullptr;
258  if ( pObjSh )
259  {
260  SetObjectShell( pObjSh );
261 
262  // set color table
263  const SvxColorListItem* pColItem = pObjSh->GetItem( SID_COLOR_TABLE );
264  if ( pColItem )
265  pXCol = pColItem->GetColorList();
266  }
267  SetPropertyList( static_cast<XPropertyList *> (pXCol.get()) );
268 
269  SetSwapGraphics();
270 
271  SetScaleUnit(MapUnit::Map100thMM);
272  SfxItemPool& rPool = GetItemPool();
273  rPool.SetDefaultMetric(MapUnit::Map100thMM);
274  SvxFrameDirectionItem aModeItem( SvxFrameDirection::Environment, EE_PARA_WRITINGDIR );
275  rPool.SetPoolDefaultItem( aModeItem );
276 
277  // #i33700#
278  // Set shadow distance defaults as PoolDefaultItems. Details see bug.
281 
282  // default for script spacing depends on locale, see SdDrawDocument ctor in sd
284  if (MsLangId::isKorean(eOfficeLanguage) || eOfficeLanguage == LANGUAGE_JAPANESE)
285  {
286  // secondary is edit engine pool
288  }
289 
290  rPool.FreezeIdRanges(); // the pool is also used directly
291 
292  SdrLayerAdmin& rAdmin = GetLayerAdmin();
293  rAdmin.NewLayer("vorne", sal_uInt8(SC_LAYER_FRONT));
294  rAdmin.NewLayer("hinten", sal_uInt8(SC_LAYER_BACK));
295  rAdmin.NewLayer("intern", sal_uInt8(SC_LAYER_INTERN));
296  rAdmin.NewLayer("Controls", sal_uInt8(SC_LAYER_CONTROLS));
297  rAdmin.SetControlLayerName("Controls");
298  rAdmin.NewLayer("hidden", sal_uInt8(SC_LAYER_HIDDEN));
299  // "Controls" is new - must also be created when loading
300 
301  // Set link for URL-Fields
302  ScModule* pScMod = SC_MOD();
303  Outliner& rOutliner = GetDrawOutliner();
304  rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
305 
306  Outliner& rHitOutliner = GetHitTestOutliner();
307  rHitOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
308 
309  // set FontHeight pool defaults without changing static SdrEngineDefaults
310  SfxItemPool* pOutlinerPool = rOutliner.GetEditTextObjectPool();
311  if ( pOutlinerPool )
312  {
316  }
317  SfxItemPool* pHitOutlinerPool = rHitOutliner.GetEditTextObjectPool();
318  if ( pHitOutlinerPool )
319  {
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
323  }
324 
325  // initial undo mode as in Calc document
326  if( pDoc )
328 
329  // URL-Buttons have no handler anymore, all is done by themselves
330 
331  if( !nInst++ )
332  {
333  pF3d = new E3dObjFactory;
334  }
335 }
336 
338 {
339  Broadcast(SdrHint(SdrHintKind::ModelCleared));
340 
341  ClearModel(true);
342 
343  pUndoGroup.reset();
344  if( !--nInst )
345  {
346  delete pF3d;
347  pF3d = nullptr;
348  }
349 }
350 
352 {
353  if (!bHyphenatorSet)
354  {
355  css::uno::Reference< css::linguistic2::XHyphenator >
356  xHyphenator = LinguMgr::GetHyphenator();
357 
358  GetDrawOutliner().SetHyphenator( xHyphenator );
359  GetHitTestOutliner().SetHyphenator( xHyphenator );
360 
361  bHyphenatorSet = true;
362  }
363 }
364 
365 SdrPage* ScDrawLayer::AllocPage(bool bMasterPage)
366 {
367  return new ScDrawPage(*this, bMasterPage);
368 }
369 
371 {
372  bool bFound = false;
373 
374  sal_uInt16 nCount = GetPageCount();
375  for (sal_uInt16 i=0; i<nCount && !bFound; i++)
376  if (GetPage(i)->GetObjCount())
377  bFound = true;
378 
379  return bFound;
380 }
381 
383 {
384  // Allocated model (for clipboard etc) must not have a pointer
385  // to the original model's document, pass NULL as document:
386 
387  return new ScDrawLayer( nullptr, aName );
388 }
389 
391 {
392  if (bDrawIsInUndo)
393  return false; // not inserted
394 
395  ScDrawPage* pPage = static_cast<ScDrawPage*>(AllocPage( false ));
396  InsertPage(pPage, static_cast<sal_uInt16>(nTab));
397  if (bRecording)
398  AddCalcUndo(std::make_unique<SdrUndoNewPage>(*pPage));
399 
400  ResetTab(nTab, pDoc->GetTableCount()-1);
401  return true; // inserted
402 }
403 
405 {
406  if (bDrawIsInUndo)
407  return;
408 
409  Broadcast( ScTabDeletedHint( nTab ) );
410  if (bRecording)
411  {
412  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
413  AddCalcUndo(std::make_unique<SdrUndoDelPage>(*pPage)); // Undo-Action becomes the page owner
414  RemovePage( static_cast<sal_uInt16>(nTab) ); // just deliver, not deleting
415  }
416  else
417  DeletePage( static_cast<sal_uInt16>(nTab) ); // just get rid of it
418 
419  ResetTab(nTab, pDoc->GetTableCount()-1);
420 }
421 
422 void ScDrawLayer::ScRenamePage( SCTAB nTab, const OUString& rNewName )
423 {
424  ScDrawPage* pPage = static_cast<ScDrawPage*>( GetPage(static_cast<sal_uInt16>(nTab)) );
425  if (pPage)
426  pPage->SetName(rNewName);
427 }
428 
429 void ScDrawLayer::ScMovePage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
430 {
431  MovePage( nOldPos, nNewPos );
432  sal_uInt16 nMinPos = std::min(nOldPos, nNewPos);
433  ResetTab(nMinPos, pDoc->GetTableCount()-1);
434 }
435 
436 void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos )
437 {
438  if (bDrawIsInUndo)
439  return;
440 
441  SdrPage* pOldPage = GetPage(nOldPos);
442  SdrPage* pNewPage = GetPage(nNewPos);
443 
444  // Copying
445 
446  if (pOldPage && pNewPage)
447  {
448  SCTAB nOldTab = static_cast<SCTAB>(nOldPos);
449  SCTAB nNewTab = static_cast<SCTAB>(nNewPos);
450 
451  SdrObjListIter aIter( pOldPage, SdrIterMode::Flat );
452  SdrObject* pOldObject = aIter.Next();
453  while (pOldObject)
454  {
455  ScDrawObjData* pOldData = GetObjData(pOldObject);
456  if (pOldData)
457  {
458  pOldData->maStart.SetTab(nOldTab);
459  pOldData->maEnd.SetTab(nOldTab);
460  }
461 
462  // Clone to target SdrModel
463  SdrObject* pNewObject(pOldObject->CloneSdrObject(*this));
464  pNewObject->NbcMove(Size(0,0));
465  pNewPage->InsertObject( pNewObject );
466  ScDrawObjData* pNewData = GetObjData(pNewObject);
467  if (pNewData)
468  {
469  pNewData->maStart.SetTab(nNewTab);
470  pNewData->maEnd.SetTab(nNewTab);
471  }
472 
473  if (bRecording)
474  AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pNewObject ) );
475 
476  pOldObject = aIter.Next();
477  }
478  }
479 
480  ResetTab(static_cast<SCTAB>(nNewPos), pDoc->GetTableCount()-1);
481 }
482 
483 void ScDrawLayer::ResetTab( SCTAB nStart, SCTAB nEnd )
484 {
485  SCTAB nPageSize = static_cast<SCTAB>(GetPageCount());
486  if (nPageSize < 0)
487  // No drawing pages exist.
488  return;
489 
490  if (nEnd >= nPageSize)
491  // Avoid iterating beyond the last existing page.
492  nEnd = nPageSize - 1;
493 
494  for (SCTAB i = nStart; i <= nEnd; ++i)
495  {
496  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(i));
497  if (!pPage)
498  continue;
499 
500  SdrObjListIter aIter(pPage, SdrIterMode::Flat);
501  for (SdrObject* pObj = aIter.Next(); pObj; pObj = aIter.Next())
502  {
503  ScDrawObjData* pData = GetObjData(pObj);
504  if (!pData)
505  continue;
506 
507  pData->maStart.SetTab(i);
508  pData->maEnd.SetTab(i);
509  }
510  }
511 }
512 
513 static bool IsInBlock( const ScAddress& rPos, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2 )
514 {
515  return rPos.Col() >= nCol1 && rPos.Col() <= nCol2 &&
516  rPos.Row() >= nRow1 && rPos.Row() <= nRow2;
517 }
518 
519 void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
520  SCCOL nDx,SCROW nDy, bool bUpdateNoteCaptionPos )
521 {
522  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
523  OSL_ENSURE(pPage,"Page not found");
524  if (!pPage)
525  return;
526 
527  bool bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
528 
529  const size_t nCount = pPage->GetObjCount();
530  for ( size_t i = 0; i < nCount; ++i )
531  {
532  SdrObject* pObj = pPage->GetObj( i );
533  ScDrawObjData* pData = GetObjDataTab( pObj, nTab );
534  if( pData )
535  {
536  const ScAddress aOldStt = pData->maStart;
537  const ScAddress aOldEnd = pData->maEnd;
538  bool bChange = false;
539  if ( aOldStt.IsValid() && IsInBlock( aOldStt, nCol1,nRow1, nCol2,nRow2 ) )
540  {
541  pData->maStart.IncCol( nDx );
542  pData->maStart.IncRow( nDy );
543  bChange = true;
544  }
545  if ( aOldEnd.IsValid() && IsInBlock( aOldEnd, nCol1,nRow1, nCol2,nRow2 ) )
546  {
547  pData->maEnd.IncCol( nDx );
548  pData->maEnd.IncRow( nDy );
549  bChange = true;
550  }
551  if (bChange)
552  {
553  if ( dynamic_cast<const SdrRectObj*>( pObj) != nullptr && pData->maStart.IsValid() && pData->maEnd.IsValid() )
554  pData->maStart.PutInOrder( pData->maEnd );
555 
556  // Update also an untransformed anchor that's what we stored ( and still do ) to xml
557  ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData( pObj );
558  if ( pNoRotatedAnchor )
559  {
560  pNoRotatedAnchor->maStart.IncCol(nDx);
561  pNoRotatedAnchor->maStart.IncRow(nDy);
562  pNoRotatedAnchor->maEnd.IncCol(nDx);
563  pNoRotatedAnchor->maEnd.IncRow(nDy);
564  }
565 
566  AddCalcUndo( std::make_unique<ScUndoObjData>( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd ) );
567  RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
568  }
569  }
570  }
571 }
572 
573 void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos )
574 {
575  SdrPage* pPage = GetPage(nPageNo);
576  if (!pPage)
577  return;
578 
579  if ( rSize != pPage->GetSize() )
580  {
581  pPage->SetSize( rSize );
582  Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) ); // SetWorkArea() on the views
583  }
584 
585  // Implement Detective lines (adjust to new heights / widths)
586  // even if size is still the same
587  // (individual rows/columns can have been changed))
588 
589  // Do not call RecalcPos while loading, because row height is not finished, when SetPageSize
590  // is called first time. Instead the objects are initialized from ScXMLImport::endDocument() and
591  // RecalcPos is called from there.
592  if (!pDoc || pDoc->IsImportingXML())
593  return;
594 
595  bool bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
596 
597  // Disable mass broadcasts from drawing objects' position changes.
598  bool bWasLocked = isLocked();
599  setLock(true);
600  const size_t nCount = pPage->GetObjCount();
601  for ( size_t i = 0; i < nCount; ++i )
602  {
603  SdrObject* pObj = pPage->GetObj( i );
604  ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
605  if( pData )
606  RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
607  }
608  setLock(bWasLocked);
609 
610 }
611 
612 namespace
613 {
614  //Can't have a zero width dimension
615  tools::Rectangle lcl_makeSafeRectangle(const tools::Rectangle &rNew)
616  {
617  tools::Rectangle aRect = rNew;
618  if (aRect.Bottom() == aRect.Top())
619  aRect.SetBottom( aRect.Top()+1 );
620  if (aRect.Right() == aRect.Left())
621  aRect.SetRight( aRect.Left()+1 );
622  return aRect;
623  }
624 
625  Point lcl_calcAvailableDiff(const ScDocument &rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const Point &aWantedDiff)
626  {
627  Point aAvailableDiff(aWantedDiff);
628  tools::Long nHeight = static_cast<tools::Long>(rDoc.GetRowHeight( nRow, nTab ) * HMM_PER_TWIPS);
629  tools::Long nWidth = static_cast<tools::Long>(rDoc.GetColWidth( nCol, nTab ) * HMM_PER_TWIPS);
630  if (aAvailableDiff.Y() > nHeight)
631  aAvailableDiff.setY( nHeight );
632  if (aAvailableDiff.X() > nWidth)
633  aAvailableDiff.setX( nWidth );
634  return aAvailableDiff;
635  }
636 
637  tools::Rectangle lcl_UpdateCalcPoly(basegfx::B2DPolygon &rCalcPoly, int nWhichPoint, const Point &rPos)
638  {
639  rCalcPoly.setB2DPoint(nWhichPoint, basegfx::B2DPoint(rPos.X(), rPos.Y()));
640  basegfx::B2DRange aRange(basegfx::utils::getRange(rCalcPoly));
641  return tools::Rectangle(static_cast<tools::Long>(aRange.getMinX()), static_cast<tools::Long>(aRange.getMinY()),
642  static_cast<tools::Long>(aRange.getMaxX()), static_cast<tools::Long>(aRange.getMaxY()));
643  }
644 
645 bool lcl_AreRectanglesApproxEqual(const tools::Rectangle& rRectA, const tools::Rectangle& rRectB)
646 {
647  // Twips <-> Hmm conversions introduce +-1 differences although there are no real changes in the object.
648  // Therefore test with == is not appropriate in some cases.
649  if (std::abs(rRectA.Left() - rRectB.Left()) > 1)
650  return false;
651  if (std::abs(rRectA.Top() - rRectB.Top()) > 1)
652  return false;
653  if (std::abs(rRectA.Right() - rRectB.Right()) > 1)
654  return false;
655  if (std::abs(rRectA.Bottom() - rRectB.Bottom()) > 1)
656  return false;
657  return true;
658 }
659 
660 bool lcl_NeedsMirrorYCorrection(SdrObject* pObj)
661 {
662  return pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE
663  && static_cast<SdrObjCustomShape*>(pObj)->IsMirroredY();
664 }
665 
666 void lcl_SetLogicRectFromAnchor(SdrObject* pObj, ScDrawObjData& rAnchor, ScDocument* pDoc)
667 {
668  // This is only used during initialization. At that time, shape handling is always LTR. No need
669  // to consider negative page.
670  if (!pObj || !pDoc || !rAnchor.maEnd.IsValid() || !rAnchor.maStart.IsValid())
671  return;
672 
673  // In case of a vertical mirrored custom shape, LibreOffice uses internally an additional 180deg
674  // in aGeo.nRotationAngle and in turn has a different logic rectangle position. We remove flip,
675  // set the logic rectangle, and apply flip again. You cannot simple use a 180deg-rotated
676  // rectangle, because custom shape mirroring is internally applied after the other
677  // transformations.
678  const bool bNeedsMirrorYCorrection = lcl_NeedsMirrorYCorrection(pObj); // remember state
679  if (bNeedsMirrorYCorrection)
680  {
681  const tools::Rectangle aRect(pObj->GetSnapRect());
682  const Point aLeft(aRect.Left(), (aRect.Top() + aRect.Bottom()) >> 1);
683  const Point aRight(aLeft.X() + 1000, aLeft.Y());
684  pObj->NbcMirror(aLeft, aRight);
685  }
686 
687  // Build full sized logic rectangle from start and end given in anchor.
688  const tools::Rectangle aStartCellRect(
689  pDoc->GetMMRect(rAnchor.maStart.Col(), rAnchor.maStart.Row(), rAnchor.maStart.Col(),
690  rAnchor.maStart.Row(), rAnchor.maStart.Tab(), false /*bHiddenAsZero*/));
691  Point aStartPoint(aStartCellRect.Left(), aStartCellRect.Top());
692  aStartPoint.AdjustX(rAnchor.maStartOffset.getX());
693  aStartPoint.AdjustY(rAnchor.maStartOffset.getY());
694 
695  const tools::Rectangle aEndCellRect(
696  pDoc->GetMMRect(rAnchor.maEnd.Col(), rAnchor.maEnd.Row(), rAnchor.maEnd.Col(),
697  rAnchor.maEnd.Row(), rAnchor.maEnd.Tab(), false /*bHiddenAsZero*/));
698  Point aEndPoint(aEndCellRect.Left(), aEndCellRect.Top());
699  aEndPoint.AdjustX(rAnchor.maEndOffset.getX());
700  aEndPoint.AdjustY(rAnchor.maEndOffset.getY());
701 
702  // Set this as new, full sized logical rectangle
703  tools::Rectangle aNewRectangle(aStartPoint, aEndPoint);
704  aNewRectangle.Justify();
705  if (!lcl_AreRectanglesApproxEqual(pObj->GetLogicRect(), aNewRectangle))
706  pObj->NbcSetLogicRect(lcl_makeSafeRectangle(aNewRectangle));
707 
708  // The shape has the correct logical rectangle now. Reapply the above removed mirroring.
709  if (bNeedsMirrorYCorrection)
710  {
711  const tools::Rectangle aRect(pObj->GetSnapRect());
712  const Point aLeft(aRect.Left(), (aRect.Top() + aRect.Bottom()) >> 1);
713  const Point aRight(aLeft.X() + 1000, aLeft.Y());
714  pObj->NbcMirror(aLeft, aRight);
715  }
716 }
717 
718 } // namespace
719 
721  bool bUseLogicRect, bool bNegativePage, bool bCanResize)
722 {
723  tools::Rectangle aRect = bUseLogicRect ? pObj->GetLogicRect() : pObj->GetSnapRect();
724  SCCOL nCol1 = rData.maStart.Col();
725  SCROW nRow1 = rData.maStart.Row();
726  SCTAB nTab1 = rData.maStart.Tab();
727  SCCOL nCol2 = rData.maEnd.Col();
728  SCROW nRow2 = rData.maEnd.Row();
729  SCTAB nTab2 = rData.maEnd.Tab();
730  Point aPos(pDoc->GetColOffset(nCol1, nTab1, /*bHiddenAsZero*/true),
731  pDoc->GetRowOffset(nRow1, nTab1, /*bHiddenAsZero*/true));
732  aPos.setX(TwipsToHmm(aPos.X()));
733  aPos.setY(TwipsToHmm(aPos.Y()));
734  aPos += lcl_calcAvailableDiff(*pDoc, nCol1, nRow1, nTab1, rData.maStartOffset);
735 
736  // this sets the needed changed position (translation)
737  aRect.SetPos(aPos);
738 
739  if (bCanResize)
740  {
741  // all this stuff is additional stuff to evtl. not only translate the
742  // range (Rectangle), but also check for and evtl. do corrections for it's size
743  const tools::Rectangle aLastCellRect(rData.getLastCellRect());
744 
745  // If the row was hidden before, or we don't have a valid cell rect, calculate the
746  // new rect based on the end point.
747  // Also when the end point is set, we need to consider it.
748  if (rData.mbWasInHiddenRow || aLastCellRect.IsEmpty() || nRow1 != nRow2 || nCol1 != nCol2)
749  {
750  Point aEnd(pDoc->GetColOffset(nCol2, nTab2, /*bHiddenAsZero*/true),
751  pDoc->GetRowOffset(nRow2, nTab2, /*bHiddenAsZero*/true));
752  aEnd.setX(TwipsToHmm(aEnd.X()));
753  aEnd.setY(TwipsToHmm(aEnd.Y()));
754  aEnd += lcl_calcAvailableDiff(*pDoc, nCol2, nRow2, nTab2, rData.maEndOffset);
755 
756  aRect = tools::Rectangle(aPos, aEnd);
757  }
758  else if (!aLastCellRect.IsEmpty())
759  {
760  // We calculate based on the last cell rect to be able to scale the image
761  // as much as the cell was scaled.
762  // Still, we keep the image in its current cell (to keep start anchor == end anchor)
763  const tools::Rectangle aCurrentCellRect(GetCellRect(*GetDocument(), rData.maStart, true));
764  tools::Long nCurrentWidth(aCurrentCellRect.GetWidth());
765  tools::Long nCurrentHeight(aCurrentCellRect.GetHeight());
766  const tools::Long nLastWidth(aLastCellRect.GetWidth());
767  const tools::Long nLastHeight(aLastCellRect.GetHeight());
768 
769  // tdf#116931 Avoid and correct nifty numerical problems with the integer
770  // based and converted values (GetCellRect uses multiplies with HMM_PER_TWIPS)
771  if(nCurrentWidth + 1 == nLastWidth || nCurrentWidth == nLastWidth + 1)
772  {
773  nCurrentWidth = nLastWidth;
774  }
775 
776  if(nCurrentHeight + 1 == nLastHeight || nCurrentHeight == nLastHeight + 1)
777  {
778  nCurrentHeight = nLastHeight;
779  }
780 
781  // get initial ScalingFactors
782  double fWidthFactor(nCurrentWidth == nLastWidth || 0 == nLastWidth
783  ? 1.0
784  : static_cast<double>(nCurrentWidth) / static_cast<double>(nLastWidth));
785  double fHeightFactor(nCurrentHeight == nLastHeight || 0 == nLastHeight
786  ? 1.0
787  : static_cast<double>(nCurrentHeight) / static_cast<double>(nLastHeight));
788 
789  // check if we grow or shrink - and at all
790  const bool bIsGrowing(nCurrentWidth > nLastWidth || nCurrentHeight > nLastHeight);
791  const bool bIsShrinking(nCurrentWidth < nLastWidth || nCurrentHeight < nLastHeight);
792  const bool bIsSizeChanged(bIsGrowing || bIsShrinking);
793 
794  // handle AspectRatio, only needed if size does change
795  if(bIsSizeChanged && pObj->shouldKeepAspectRatio())
796  {
797  tools::Rectangle aRectIncludingOffset = aRect;
798  aRectIncludingOffset.setWidth(aRect.GetWidth() + rData.maStartOffset.X());
799  aRectIncludingOffset.setHeight(aRect.GetHeight() + rData.maStartOffset.Y());
800  tools::Long nWidth = aRectIncludingOffset.GetWidth();
801  assert(nWidth && "div-by-zero");
802  double fMaxWidthFactor = static_cast<double>(nCurrentWidth)
803  / static_cast<double>(nWidth);
804  tools::Long nHeight = aRectIncludingOffset.GetHeight();
805  assert(nHeight && "div-by-zero");
806  double fMaxHeightFactor = static_cast<double>(nCurrentHeight)
807  / static_cast<double>(nHeight);
808  double fMaxFactor = std::min(fMaxHeightFactor, fMaxWidthFactor);
809 
810  if(bIsGrowing) // cell is growing larger
811  {
812  // To actually grow the image, we need to take the max
813  fWidthFactor = std::max(fWidthFactor, fHeightFactor);
814  }
815  else if(bIsShrinking) // cell is growing smaller, take the min
816  {
817  fWidthFactor = std::min(fWidthFactor, fHeightFactor);
818  }
819 
820  // We don't want the image to become larger than the current cell
821  fWidthFactor = fHeightFactor = std::min(fWidthFactor, fMaxFactor);
822  }
823 
824  if(bIsSizeChanged)
825  {
826  // tdf#116931 re-organized scaling (if needed)
827  // Check if we need to scale at all. Always scale on growing.
828  bool bNeedToScale(bIsGrowing);
829 
830  if(!bNeedToScale && bIsShrinking)
831  {
832  // Check if original still fits into space. Do *not* forget to
833  // compare with evtl. numerically corrected aCurrentCellRect
834  const bool bFitsInX(aRect.Right() <= aCurrentCellRect.Left() + nCurrentWidth);
835  const bool bFitsInY(aRect.Bottom() <= aCurrentCellRect.Top() + nCurrentHeight);
836 
837  // If the image still fits in the smaller cell, don't resize it at all
838  bNeedToScale = (!bFitsInX || !bFitsInY);
839  }
840 
841  if(bNeedToScale)
842  {
843  // tdf#116931 use transformations now. Translation is already applied
844  // (see aRect.SetPos above), so only scale needs to be applied - relative
845  // to *new* CellRect (which is aCurrentCellRect).
846  // Prepare scale relative to top-left of aCurrentCellRect
847  basegfx::B2DHomMatrix aChange;
848 
849  aChange.translate(-aCurrentCellRect.getX(), -aCurrentCellRect.getY());
850  aChange.scale(fWidthFactor, fHeightFactor);
851  aChange.translate(aCurrentCellRect.getX(), aCurrentCellRect.getY());
852 
853  // create B2DRange and transform by prepared scale
855 
856  aNewRange.transform(aChange);
857 
858  // apply to aRect
859  aRect = tools::Rectangle(
860  basegfx::fround(aNewRange.getMinX()), basegfx::fround(aNewRange.getMinY()),
861  basegfx::fround(aNewRange.getMaxX()), basegfx::fround(aNewRange.getMaxY()));
862  }
863  }
864  }
865  }
866 
867  if (bNegativePage)
868  MirrorRectRTL(aRect);
869 
870  rData.setShapeRect(GetDocument(), lcl_makeSafeRectangle(aRect), pObj->IsVisible());
871 }
872 
874 {
875  // This is called from ScXMLImport::endDocument()
876  if (!pDoc || !pObj)
877  return;
878  if (!rData.getShapeRect().IsEmpty())
879  return; // already initialized, should not happen
882  return; // handled in RecalcPos
883 
884  // Prevent multiple broadcasts during the series of changes.
885  bool bWasLocked = pObj->getSdrModelFromSdrObject().isLocked();
886  pObj->getSdrModelFromSdrObject().setLock(true);
887 
888  // rNoRotatedAnchor refers in its start and end addresses and its start and end offsets to
889  // the logic rectangle of the object. The values are so, as if no hidden columns and rows
890  // exists and if it is a LTR sheet. These values are directly used for XML in ODF file.
891  // ToDO: Check whether its maShapeRect member is actually used.
892  ScDrawObjData& rNoRotatedAnchor = *GetNonRotatedObjData(pObj, true /*bCreate*/);
893 
894  // From XML import, rData contains temporarily the anchor information as they are given in
895  // XML. Copy it to rNoRotatedAnchor, where it belongs. rData will later contain the anchor
896  // of the transformed object as visible on screen.
897  rNoRotatedAnchor.maStart = rData.maStart;
898  rNoRotatedAnchor.maEnd = rData.maEnd;
899  rNoRotatedAnchor.maStartOffset = rData.maStartOffset;
900  rNoRotatedAnchor.maEndOffset = rData.maEndOffset;
901 
902  SCCOL nCol1 = rNoRotatedAnchor.maStart.Col();
903  SCROW nRow1 = rNoRotatedAnchor.maStart.Row();
904  SCTAB nTab1 = rNoRotatedAnchor.maStart.Tab(); // Used as parameter several times
905 
906  // Object has coordinates relative to left/top of containing cell in XML. Change object to
907  // absolute coordinates as internally used.
908  const tools::Rectangle aRect(
909  pDoc->GetMMRect(nCol1, nRow1, nCol1, nRow1, nTab1, false /*bHiddenAsZero*/));
910  const Size aShift(aRect.Left(), aRect.Top());
911  pObj->NbcMove(aShift);
912 
913  const ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj);
914  if (aAnchorType == SCA_CELL_RESIZE)
915  {
916  if (pObj->GetObjIdentifier() == OBJ_LINE)
917  {
918  // Horizontal lines might have wrong start and end anchor because of erroneously applied
919  // 180deg rotation (tdf#137446). Other lines have wrong end anchor. Coordinates in
920  // object are correct. Use them for recreating the anchor.
921  const basegfx::B2DPolygon aPoly(
922  static_cast<SdrPathObj*>(pObj)->GetPathPoly().getB2DPolygon(0));
923  const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0));
924  const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1));
925  const Point aPointLT(FRound(std::min(aB2DPoint0.getX(), aB2DPoint1.getX())),
926  FRound(std::min(aB2DPoint0.getY(), aB2DPoint1.getY())));
927  const Point aPointRB(FRound(std::max(aB2DPoint0.getX(), aB2DPoint1.getX())),
928  FRound(std::max(aB2DPoint0.getY(), aB2DPoint1.getY())));
929  const tools::Rectangle aObjRect(aPointLT, aPointRB);
930  GetCellAnchorFromPosition(aObjRect, rNoRotatedAnchor, *pDoc, nTab1,
931  false /*bHiddenAsZero*/);
932  }
933  else if (pObj->GetObjIdentifier() == OBJ_MEASURE)
934  {
935  // Measure lines might have got wrong start and end anchor from XML import. Recreate
936  // anchor from start and end point.
937  SdrMeasureObj* pMeasureObj = static_cast<SdrMeasureObj*>(pObj);
938  // tdf#137576. The logic rectangle has likely no current values here, but only the
939  // 1cm x 1cm default size. The call of TakeUnrotatedSnapRect is currently (LO 7.2)
940  // the only way to force a recalc of the logic rectangle.
941  tools::Rectangle aObjRect;
942  pMeasureObj->TakeUnrotatedSnapRect(aObjRect);
943  GetCellAnchorFromPosition(aObjRect, rNoRotatedAnchor, *pDoc, rData.maStart.Tab(),
944  false /*bHiddenAsZero*/);
945  }
946  else
947  {
948  // In case there are hidden rows or cols, versions 7.0 and earlier have written width and
949  // height in file so that hidden row or col are count as zero. XML import bases the
950  // logical rectangle of the object on it. Shapes have at least wrong size, when row or col
951  // are shown. We try to regenerate the logic rectangle as far as possible from the anchor.
952  // ODF specifies anyway, that the size has to be ignored, if end cell attributes exist.
953  lcl_SetLogicRectFromAnchor(pObj, rNoRotatedAnchor, pDoc);
954  }
955  }
956  else // aAnchorType == SCA_CELL, other types will not occur here.
957  {
958  // XML has no end cell address in this case. We generate it from position.
959  UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1,
960  true /*bUseLogicRect*/);
961  }
962 
963  // Make sure maShapeRect of rNoRotatedAnchor is not empty. ToDo: Really used?
964  // Currently ScExportTest::testMoveCellAnchoredShapesODS checks it.
965  rNoRotatedAnchor.setShapeRect(GetDocument(), pObj->GetLogicRect(), true);
966 
967  // Start and end addresses and offsets in rData refer to the actual snap rectangle of the
968  // shape. We initialize them here based on the "full" sized object. Adaptation to reduced size
969  // (by hidden row/col) is done later in RecalcPos.
970  GetCellAnchorFromPosition(pObj->GetSnapRect(), rData, *pDoc, nTab1, false /*bHiddenAsZero*/);
971 
972  // As of ODF 1.3 strict there is no attribute to store whether an object is hidden. So a "visible"
973  // object might actually be hidden by being in hidden row or column. We detect it here.
974  // Note, that visibility by hidden row or column refers to the snap rectangle.
975  if (pObj->IsVisible()
976  && (pDoc->RowHidden(rData.maStart.Row(), rData.maStart.Tab())
977  || pDoc->ColHidden(rData.maStart.Col(), rData.maStart.Tab())))
978  pObj->SetVisible(false);
979 
980  // Set visibility. ToDo: Really used?
981  rNoRotatedAnchor.setShapeRect(GetDocument(), pObj->GetLogicRect(), pObj->IsVisible());
982 
983  // And set maShapeRect in rData. It stores not only the current rectangles, but currently,
984  // existence of maShapeRect is the flag for initialization is done.
985  rData.setShapeRect(GetDocument(), pObj->GetSnapRect(), pObj->IsVisible());
986 
987  pObj->getSdrModelFromSdrObject().setLock(bWasLocked);
988 }
989 
990 void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegativePage, bool bUpdateNoteCaptionPos )
991 {
992  OSL_ENSURE( pDoc, "ScDrawLayer::RecalcPos - missing document" );
993  if( !pDoc )
994  return;
995 
996  if (rData.meType == ScDrawObjData::CellNote)
997  {
998  OSL_ENSURE( rData.maStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
999  /* #i109372# On insert/remove rows/columns/cells: Updating the caption
1000  position must not be done, if the cell containing the note has not
1001  been moved yet in the document. The calling code now passes an
1002  additional boolean stating if the cells are already moved. */
1003  if( bUpdateNoteCaptionPos )
1004  /* When inside an undo action, there may be pending note captions
1005  where cell note is already deleted (thus document cannot find
1006  the note object anymore). The caption will be deleted later
1007  with drawing undo. */
1008  if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
1009  pNote->UpdateCaptionPos( rData.maStart );
1010  return;
1011  }
1012 
1013  bool bValid1 = rData.maStart.IsValid();
1014  SCCOL nCol1 = rData.maStart.Col();
1015  SCROW nRow1 = rData.maStart.Row();
1016  SCTAB nTab1 = rData.maStart.Tab();
1017  bool bValid2 = rData.maEnd.IsValid();
1018  SCCOL nCol2 = rData.maEnd.Col();
1019  SCROW nRow2 = rData.maEnd.Row();
1020  SCTAB nTab2 = rData.maEnd.Tab();
1021 
1023  {
1024  // Validation circle for detective.
1025  rData.setShapeRect(GetDocument(), pObj->GetLogicRect());
1026 
1027  tools::Rectangle aRect = GetCellRect(*GetDocument(), rData.maStart, true);
1028  aRect.AdjustLeft( -250 );
1029  aRect.AdjustRight(250 );
1030  aRect.AdjustTop( -70 );
1031  aRect.AdjustBottom(70 );
1032  if ( bNegativePage )
1033  MirrorRectRTL( aRect );
1034 
1035  if ( pObj->GetLogicRect() != aRect )
1036  {
1037  if (bRecording)
1038  AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
1039  rData.setShapeRect(GetDocument(), lcl_makeSafeRectangle(aRect));
1040  pObj->SetLogicRect(rData.getShapeRect());
1041  }
1042  }
1043  else if (rData.meType == ScDrawObjData::DetectiveArrow)
1044  {
1045  rData.setShapeRect(GetDocument(), pObj->GetLogicRect());
1046  basegfx::B2DPolygon aCalcPoly;
1047  Point aOrigStartPos(pObj->GetPoint(0));
1048  Point aOrigEndPos(pObj->GetPoint(1));
1049  aCalcPoly.append(basegfx::B2DPoint(aOrigStartPos.X(), aOrigStartPos.Y()));
1050  aCalcPoly.append(basegfx::B2DPoint(aOrigEndPos.X(), aOrigEndPos.Y()));
1051  //TODO: do not create multiple Undos for one object (last one can be omitted then)
1052 
1053  SCCOL nLastCol;
1054  SCROW nLastRow;
1055  if( bValid1 )
1056  {
1057  Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
1058  if (!pDoc->ColHidden(nCol1, nTab1, nullptr, &nLastCol))
1059  aPos.AdjustX(pDoc->GetColWidth( nCol1, nTab1 ) / 4 );
1060  if (!pDoc->RowHidden(nRow1, nTab1, nullptr, &nLastRow))
1061  aPos.AdjustY(pDoc->GetRowHeight( nRow1, nTab1 ) / 2 );
1062  aPos.setX(TwipsToHmm( aPos.X() ));
1063  aPos.setY(TwipsToHmm( aPos.Y() ));
1064  Point aStartPos = aPos;
1065  if ( bNegativePage )
1066  aStartPos.setX( -aStartPos.X() ); // don't modify aPos - used below
1067  if ( pObj->GetPoint( 0 ) != aStartPos )
1068  {
1069  if (bRecording)
1070  AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
1071 
1072  rData.setShapeRect(GetDocument(), lcl_UpdateCalcPoly(aCalcPoly, 0, aStartPos));
1073  pObj->SetPoint( aStartPos, 0 );
1074  }
1075 
1076  if( !bValid2 )
1077  {
1078  Point aEndPos( aPos.X() + DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
1079  if (aEndPos.Y() < 0)
1080  aEndPos.AdjustY(2 * DET_ARROW_OFFSET);
1081  if ( bNegativePage )
1082  aEndPos.setX( -aEndPos.X() );
1083  if ( pObj->GetPoint( 1 ) != aEndPos )
1084  {
1085  if (bRecording)
1086  AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
1087 
1088  rData.setShapeRect(GetDocument(), lcl_UpdateCalcPoly(aCalcPoly, 1, aEndPos));
1089  pObj->SetPoint( aEndPos, 1 );
1090  }
1091  }
1092  }
1093  if( bValid2 )
1094  {
1095  Point aPos( pDoc->GetColOffset( nCol2, nTab2 ), pDoc->GetRowOffset( nRow2, nTab2 ) );
1096  if (!pDoc->ColHidden(nCol2, nTab2, nullptr, &nLastCol))
1097  aPos.AdjustX(pDoc->GetColWidth( nCol2, nTab2 ) / 4 );
1098  if (!pDoc->RowHidden(nRow2, nTab2, nullptr, &nLastRow))
1099  aPos.AdjustY(pDoc->GetRowHeight( nRow2, nTab2 ) / 2 );
1100  aPos.setX(TwipsToHmm( aPos.X() ));
1101  aPos.setY(TwipsToHmm( aPos.Y() ));
1102  Point aEndPos = aPos;
1103  if ( bNegativePage )
1104  aEndPos.setX( -aEndPos.X() ); // don't modify aPos - used below
1105  if ( pObj->GetPoint( 1 ) != aEndPos )
1106  {
1107  if (bRecording)
1108  AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
1109 
1110  rData.setShapeRect(GetDocument(), lcl_UpdateCalcPoly(aCalcPoly, 1, aEndPos));
1111  pObj->SetPoint( aEndPos, 1 );
1112  }
1113 
1114  if( !bValid1 )
1115  {
1116  Point aStartPos( aPos.X() - DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
1117  if (aStartPos.X() < 0)
1118  aStartPos.AdjustX(2 * DET_ARROW_OFFSET);
1119  if (aStartPos.Y() < 0)
1120  aStartPos.AdjustY(2 * DET_ARROW_OFFSET);
1121  if ( bNegativePage )
1122  aStartPos.setX( -aStartPos.X() );
1123  if ( pObj->GetPoint( 0 ) != aStartPos )
1124  {
1125  if (bRecording)
1126  AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
1127 
1128  rData.setShapeRect(GetDocument(), lcl_UpdateCalcPoly(aCalcPoly, 0, aStartPos));
1129  pObj->SetPoint( aStartPos, 0 );
1130  }
1131  }
1132  }
1133  } // end ScDrawObjData::DetectiveArrow
1134  else // start ScDrawObjData::DrawingObject
1135  {
1136  // Do not change hidden objects. That would produce zero height or width and loss of offsets.
1137  if (!pObj->IsVisible())
1138  return;
1139 
1140  // Prevent multiple broadcasts during the series of changes.
1141  bool bWasLocked = pObj->getSdrModelFromSdrObject().isLocked();
1142  pObj->getSdrModelFromSdrObject().setLock(true);
1143 
1144  bool bCanResize = bValid2 && !pObj->IsResizeProtect() && rData.mbResizeWithCell;
1145 
1146  // update anchor with snap rect
1147  ResizeLastRectFromAnchor( pObj, rData, false, bNegativePage, bCanResize );
1148 
1149  ScDrawObjData& rNoRotatedAnchor = *GetNonRotatedObjData( pObj, true /*bCreate*/);
1150 
1151  if( bCanResize )
1152  {
1153  tools::Rectangle aNew = rData.getShapeRect();
1154  tools::Rectangle aOld(pObj->GetSnapRect());
1155  if (!lcl_AreRectanglesApproxEqual(aNew, aOld))
1156  {
1157  if (bRecording)
1158  AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
1159 
1160  // ToDo: Implement NbcSetSnapRect of SdrMeasureObj. Then this can be removed.
1161  tools::Long nOldWidth = aOld.GetWidth();
1162  tools::Long nOldHeight = aOld.GetHeight();
1163  if (pObj->IsPolyObj() && nOldWidth && nOldHeight)
1164  {
1165  // Polyline objects need special treatment.
1166  Size aSizeMove(aNew.Left()-aOld.Left(), aNew.Top()-aOld.Top());
1167  pObj->NbcMove(aSizeMove);
1168 
1169  double fXFrac = static_cast<double>(aNew.GetWidth()) / static_cast<double>(nOldWidth);
1170  double fYFrac = static_cast<double>(aNew.GetHeight()) / static_cast<double>(nOldHeight);
1171  pObj->NbcResize(aNew.TopLeft(), Fraction(fXFrac), Fraction(fYFrac));
1172  }
1173 
1174  rData.setShapeRect(GetDocument(), lcl_makeSafeRectangle(rData.getShapeRect()), pObj->IsVisible());
1175  if (pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE)
1176  pObj->AdjustToMaxRect(rData.getShapeRect());
1177  else
1178  pObj->SetSnapRect(rData.getShapeRect());
1179 
1180  // update 'unrotated anchor' it's the anchor we persist, it must be kept in sync
1181  // with the normal Anchor
1182  // ToDo: Is maShapeRect of rNoRotatedAnchor used at all?
1183  ResizeLastRectFromAnchor(pObj, rNoRotatedAnchor, true, bNegativePage, bCanResize);
1184  }
1185  }
1186  else
1187  {
1188  Point aPos( rData.getShapeRect().getX(), rData.getShapeRect().getY() );
1189  if ( pObj->GetRelativePos() != aPos )
1190  {
1191  if (bRecording)
1192  AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
1193  pObj->SetRelativePos( aPos );
1194  }
1195  }
1196  /*
1197  * If we were not allowed resize the object, then the end cell anchor
1198  * is possibly incorrect now, and if the object has no end-cell (e.g.
1199  * missing in original .xml) we are also forced to generate one
1200  */
1201  bool bEndAnchorIsBad = !bValid2 || pObj->IsResizeProtect();
1202  if (bEndAnchorIsBad)
1203  {
1204  // update 'rotated' anchor
1205  ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, rData, *pDoc, nTab1, false);
1206  // update 'unrotated' anchor
1207  ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1 );
1208  }
1209 
1210  // End prevent multiple broadcasts during the series of changes.
1211  pObj->getSdrModelFromSdrObject().setLock(bWasLocked);
1212  if (!bWasLocked)
1213  pObj->BroadcastObjectChange();
1214  } // end ScDrawObjData::DrawingObject
1215 }
1216 
1217 bool ScDrawLayer::GetPrintArea( ScRange& rRange, bool bSetHor, bool bSetVer ) const
1218 {
1219  OSL_ENSURE( pDoc, "ScDrawLayer::GetPrintArea without document" );
1220  if ( !pDoc )
1221  return false;
1222 
1223  SCTAB nTab = rRange.aStart.Tab();
1224  OSL_ENSURE( rRange.aEnd.Tab() == nTab, "GetPrintArea: Tab differ" );
1225 
1226  bool bNegativePage = pDoc->IsNegativePage( nTab );
1227 
1228  bool bAny = false;
1229  tools::Long nEndX = 0;
1230  tools::Long nEndY = 0;
1231  tools::Long nStartX = LONG_MAX;
1232  tools::Long nStartY = LONG_MAX;
1233 
1234  // Calculate borders
1235 
1236  if (!bSetHor)
1237  {
1238  nStartX = 0;
1239  SCCOL nStartCol = rRange.aStart.Col();
1240  SCCOL i;
1241  for (i=0; i<nStartCol; i++)
1242  nStartX +=pDoc->GetColWidth(i,nTab);
1243  nEndX = nStartX;
1244  SCCOL nEndCol = rRange.aEnd.Col();
1245  for (i=nStartCol; i<=nEndCol; i++)
1246  nEndX += pDoc->GetColWidth(i,nTab);
1247  nStartX = TwipsToHmm( nStartX );
1248  nEndX = TwipsToHmm( nEndX );
1249  }
1250  if (!bSetVer)
1251  {
1252  nStartY = pDoc->GetRowHeight( 0, rRange.aStart.Row()-1, nTab);
1253  nEndY = nStartY + pDoc->GetRowHeight( rRange.aStart.Row(),
1254  rRange.aEnd.Row(), nTab);
1255  nStartY = TwipsToHmm( nStartY );
1256  nEndY = TwipsToHmm( nEndY );
1257  }
1258 
1259  if ( bNegativePage )
1260  {
1261  nStartX = -nStartX; // positions are negative, swap start/end so the same comparisons work
1262  nEndX = -nEndX;
1263  ::std::swap( nStartX, nEndX );
1264  }
1265 
1266  const SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1267  OSL_ENSURE(pPage,"Page not found");
1268  if (pPage)
1269  {
1270  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
1271  SdrObject* pObject = aIter.Next();
1272  while (pObject)
1273  {
1274  //TODO: test Flags (hidden?)
1275 
1276  tools::Rectangle aObjRect = pObject->GetCurrentBoundRect();
1277  bool bFit = true;
1278  if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
1279  bFit = false;
1280  if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
1281  bFit = false;
1282  // #i104716# don't include hidden note objects
1283  if ( bFit && pObject->GetLayer() != SC_LAYER_HIDDEN )
1284  {
1285  if (bSetHor)
1286  {
1287  if (aObjRect.Left() < nStartX) nStartX = aObjRect.Left();
1288  if (aObjRect.Right() > nEndX) nEndX = aObjRect.Right();
1289  }
1290  if (bSetVer)
1291  {
1292  if (aObjRect.Top() < nStartY) nStartY = aObjRect.Top();
1293  if (aObjRect.Bottom() > nEndY) nEndY = aObjRect.Bottom();
1294  }
1295  bAny = true;
1296  }
1297 
1298  pObject = aIter.Next();
1299  }
1300  }
1301 
1302  if ( bNegativePage )
1303  {
1304  nStartX = -nStartX; // reverse transformation, so the same cell address calculation works
1305  nEndX = -nEndX;
1306  ::std::swap( nStartX, nEndX );
1307  }
1308 
1309  if (bAny)
1310  {
1311  OSL_ENSURE( nStartX<=nEndX && nStartY<=nEndY, "Start/End wrong in ScDrawLayer::GetPrintArea" );
1312 
1313  if (bSetHor)
1314  {
1315  nStartX = HmmToTwips( nStartX );
1316  nEndX = HmmToTwips( nEndX );
1317  tools::Long nWidth;
1318 
1319  nWidth = 0;
1320  rRange.aStart.SetCol( 0 );
1321  if (nWidth <= nStartX)
1322  {
1323  for (SCCOL nCol : pDoc->GetColumnsRange(nTab, 0, MAXCOL))
1324  {
1325  nWidth += pDoc->GetColWidth(nCol,nTab);
1326  if (nWidth > nStartX)
1327  {
1328  rRange.aStart.SetCol( nCol );
1329  break;
1330  }
1331  }
1332  }
1333 
1334  nWidth = 0;
1335  rRange.aEnd.SetCol( 0 );
1336  if (nWidth <= nEndX)
1337  {
1338  for (SCCOL nCol : pDoc->GetColumnsRange(nTab, 0, MAXCOL)) //TODO: start at Start
1339  {
1340  nWidth += pDoc->GetColWidth(nCol,nTab);
1341  if (nWidth > nEndX)
1342  {
1343  rRange.aEnd.SetCol( nCol );
1344  break;
1345  }
1346  }
1347  }
1348  }
1349 
1350  if (bSetVer)
1351  {
1352  nStartY = HmmToTwips( nStartY );
1353  nEndY = HmmToTwips( nEndY );
1354  SCROW nRow = pDoc->GetRowForHeight( nTab, nStartY);
1355  rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
1356  nRow = pDoc->GetRowForHeight( nTab, nEndY);
1357  rRange.aEnd.SetRow( nRow == MAXROW ? MAXROW :
1358  (nRow>0 ? (nRow-1) : 0));
1359  }
1360  }
1361  else
1362  {
1363  if (bSetHor)
1364  {
1365  rRange.aStart.SetCol(0);
1366  rRange.aEnd.SetCol(0);
1367  }
1368  if (bSetVer)
1369  {
1370  rRange.aStart.SetRow(0);
1371  rRange.aEnd.SetRow(0);
1372  }
1373  }
1374  return bAny;
1375 }
1376 
1377 void ScDrawLayer::AddCalcUndo( std::unique_ptr<SdrUndoAction> pUndo )
1378 {
1379  if (bRecording)
1380  {
1381  if (!pUndoGroup)
1382  pUndoGroup.reset(new SdrUndoGroup(*this));
1383 
1384  pUndoGroup->AddAction( std::move(pUndo) );
1385  }
1386 }
1387 
1388 void ScDrawLayer::BeginCalcUndo(bool bDisableTextEditUsesCommonUndoManager)
1389 {
1390  SetDisableTextEditUsesCommonUndoManager(bDisableTextEditUsesCommonUndoManager);
1391  pUndoGroup.reset();
1392  bRecording = true;
1393 }
1394 
1395 std::unique_ptr<SdrUndoGroup> ScDrawLayer::GetCalcUndo()
1396 {
1397  std::unique_ptr<SdrUndoGroup> pRet = std::move(pUndoGroup);
1398  bRecording = false;
1400  return pRet;
1401 }
1402 
1403 void ScDrawLayer::MoveArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
1404  SCCOL nDx,SCROW nDy, bool bInsDel, bool bUpdateNoteCaptionPos )
1405 {
1406  OSL_ENSURE( pDoc, "ScDrawLayer::MoveArea without document" );
1407  if ( !pDoc )
1408  return;
1409 
1410  if (!bAdjustEnabled)
1411  return;
1412 
1413  bool bNegativePage = pDoc->IsNegativePage( nTab );
1414 
1415  tools::Rectangle aRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1416  lcl_ReverseTwipsToMM( aRect );
1417  //TODO: use twips directly?
1418 
1419  Point aMove;
1420 
1421  if (nDx > 0)
1422  for (SCCOL s=0; s<nDx; s++)
1423  aMove.AdjustX(pDoc->GetColWidth(s+nCol1,nTab) );
1424  else
1425  for (SCCOL s=-1; s>=nDx; s--)
1426  aMove.AdjustX( -(pDoc->GetColWidth(s+nCol1,nTab)) );
1427  if (nDy > 0)
1428  aMove.AdjustY(pDoc->GetRowHeight( nRow1, nRow1+nDy-1, nTab) );
1429  else
1430  aMove.AdjustY( -sal_Int16(pDoc->GetRowHeight( nRow1+nDy, nRow1-1, nTab)) );
1431 
1432  if ( bNegativePage )
1433  aMove.setX( -aMove.X() );
1434 
1435  Point aTopLeft = aRect.TopLeft(); // Beginning when zoomed out
1436  if (bInsDel)
1437  {
1438  if ( aMove.X() != 0 && nDx < 0 ) // nDx counts cells, sign is independent of RTL
1439  aTopLeft.AdjustX(aMove.X() );
1440  if ( aMove.Y() < 0 )
1441  aTopLeft.AdjustY(aMove.Y() );
1442  }
1443 
1444  // Detectiv arrows: Adjust cell position
1445 
1446  MoveCells( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy, bUpdateNoteCaptionPos );
1447 }
1448 
1449 bool ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow )
1450 {
1451  OSL_ENSURE( pDoc, "ScDrawLayer::HasObjectsInRows without document" );
1452  if ( !pDoc )
1453  return false;
1454 
1455  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1456  OSL_ENSURE(pPage,"Page not found");
1457  if (!pPage)
1458  return false;
1459 
1460  // for an empty page, there's no need to calculate the row heights
1461  if (!pPage->GetObjCount())
1462  return false;
1463 
1464  tools::Rectangle aTestRect;
1465 
1466  aTestRect.AdjustTop(pDoc->GetRowHeight( 0, nStartRow-1, nTab) );
1467 
1468  if (nEndRow==MAXROW)
1469  aTestRect.SetBottom( MAXMM );
1470  else
1471  {
1472  aTestRect.SetBottom( aTestRect.Top() );
1473  aTestRect.AdjustBottom(pDoc->GetRowHeight( nStartRow, nEndRow, nTab) );
1474  aTestRect.SetBottom(TwipsToHmm( aTestRect.Bottom() ));
1475  }
1476 
1477  aTestRect.SetTop(TwipsToHmm( aTestRect.Top() ));
1478 
1479  aTestRect.SetLeft( 0 );
1480  aTestRect.SetRight( MAXMM );
1481 
1482  bool bNegativePage = pDoc->IsNegativePage( nTab );
1483  if ( bNegativePage )
1484  MirrorRectRTL( aTestRect );
1485 
1486  bool bFound = false;
1487 
1488  tools::Rectangle aObjRect;
1489  SdrObjListIter aIter( pPage );
1490  SdrObject* pObject = aIter.Next();
1491  while ( pObject && !bFound )
1492  {
1493  aObjRect = pObject->GetSnapRect(); //TODO: GetLogicRect ?
1494  if (aTestRect.IsInside(aObjRect.TopLeft()) || aTestRect.IsInside(aObjRect.BottomLeft()))
1495  bFound = true;
1496 
1497  pObject = aIter.Next();
1498  }
1499 
1500  return bFound;
1501 }
1502 
1504  SCCOL nCol2,SCROW nRow2, bool bAnchored )
1505 {
1506  OSL_ENSURE( pDoc, "ScDrawLayer::DeleteObjectsInArea without document" );
1507  if ( !pDoc )
1508  return;
1509 
1510  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1511  OSL_ENSURE(pPage,"Page ?");
1512  if (!pPage)
1513  return;
1514 
1515  pPage->RecalcObjOrdNums();
1516 
1517  const size_t nObjCount = pPage->GetObjCount();
1518  if (!nObjCount)
1519  return;
1520 
1521  size_t nDelCount = 0;
1522  tools::Rectangle aDelRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1523  tools::Rectangle aDelCircle = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
1524  aDelCircle.AdjustLeft(-250);
1525  aDelCircle.AdjustRight(250);
1526  aDelCircle.AdjustTop(-70);
1527  aDelCircle.AdjustBottom(70);
1528 
1529  std::unique_ptr<SdrObject*[]> ppObj(new SdrObject*[nObjCount]);
1530 
1531  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
1532  SdrObject* pObject = aIter.Next();
1533  while (pObject)
1534  {
1535  // do not delete note caption, they are always handled by the cell note
1536  // TODO: detective objects are still deleted, is this desired?
1537  if (!IsNoteCaption( pObject ))
1538  {
1539  tools::Rectangle aObjRect;
1540  ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObject);
1541  if (pObjData && pObjData->meType == ScDrawObjData::ValidationCircle)
1542  {
1543  aObjRect = pObject->GetLogicRect();
1544  if(aDelCircle.IsInside(aObjRect))
1545  ppObj[nDelCount++] = pObject;
1546  }
1547  else
1548  {
1549  aObjRect = pObject->GetCurrentBoundRect();
1550  if (aDelRect.IsInside(aObjRect))
1551  {
1552  if (bAnchored)
1553  {
1554  ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObject);
1555  if (aAnchorType == SCA_CELL || aAnchorType == SCA_CELL_RESIZE)
1556  ppObj[nDelCount++] = pObject;
1557  }
1558  else
1559  ppObj[nDelCount++] = pObject;
1560  }
1561  }
1562  }
1563 
1564  pObject = aIter.Next();
1565  }
1566 
1567  if (bRecording)
1568  for (size_t i=1; i<=nDelCount; ++i)
1569  AddCalcUndo( std::make_unique<SdrUndoRemoveObj>( *ppObj[nDelCount-i] ) );
1570 
1571  for (size_t i=1; i<=nDelCount; ++i)
1572  pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1573 }
1574 
1576 {
1577  OSL_ENSURE( pDoc, "ScDrawLayer::DeleteObjectsInSelection without document" );
1578  if ( !pDoc )
1579  return;
1580 
1581  if ( !rMark.IsMultiMarked() )
1582  return;
1583 
1584  ScRange aMarkRange;
1585  rMark.GetMultiMarkArea( aMarkRange );
1586 
1587  SCTAB nTabCount = pDoc->GetTableCount();
1588  for (const SCTAB nTab : rMark)
1589  {
1590  if (nTab >= nTabCount)
1591  break;
1592 
1593  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
1594  if (pPage)
1595  {
1596  pPage->RecalcObjOrdNums();
1597  const size_t nObjCount = pPage->GetObjCount();
1598  if (nObjCount)
1599  {
1600  size_t nDelCount = 0;
1601  // Rectangle around the whole selection
1602  tools::Rectangle aMarkBound = pDoc->GetMMRect(
1603  aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
1604  aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab );
1605 
1606  std::unique_ptr<SdrObject*[]> ppObj(new SdrObject*[nObjCount]);
1607 
1608  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
1609  SdrObject* pObject = aIter.Next();
1610  while (pObject)
1611  {
1612  // do not delete note caption, they are always handled by the cell note
1613  // TODO: detective objects are still deleted, is this desired?
1614  if (!IsNoteCaption( pObject ))
1615  {
1616  tools::Rectangle aObjRect = pObject->GetCurrentBoundRect();
1617  ScRange aRange = pDoc->GetRange(nTab, aObjRect);
1618  bool bObjectInMarkArea =
1619  aMarkBound.IsInside(aObjRect) && rMark.IsAllMarked(aRange);
1620  const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObject);
1621  ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObject);
1622  bool bObjectAnchoredToMarkedCell
1623  = ((aAnchorType == SCA_CELL || aAnchorType == SCA_CELL_RESIZE)
1624  && pObjData && rMark.IsCellMarked(pObjData->maStart.Col(),
1625  pObjData->maStart.Row()));
1626  if (bObjectInMarkArea || bObjectAnchoredToMarkedCell)
1627  {
1628  ppObj[nDelCount++] = pObject;
1629  }
1630  }
1631 
1632  pObject = aIter.Next();
1633  }
1634 
1635  // Delete objects (backwards)
1636 
1637  if (bRecording)
1638  for (size_t i=1; i<=nDelCount; ++i)
1639  AddCalcUndo( std::make_unique<SdrUndoRemoveObj>( *ppObj[nDelCount-i] ) );
1640 
1641  for (size_t i=1; i<=nDelCount; ++i)
1642  pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1643  }
1644  }
1645  else
1646  {
1647  OSL_FAIL("pPage?");
1648  }
1649  }
1650 }
1651 
1652 void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const tools::Rectangle& rRange )
1653 {
1654  // copy everything in the specified range into the same page (sheet) in the clipboard doc
1655 
1656  SdrPage* pSrcPage = GetPage(static_cast<sal_uInt16>(nTab));
1657  if (!pSrcPage)
1658  return;
1659 
1660  ScDrawLayer* pDestModel = nullptr;
1661  SdrPage* pDestPage = nullptr;
1662 
1663  SdrObjListIter aIter( pSrcPage, SdrIterMode::Flat );
1664  SdrObject* pOldObject = aIter.Next();
1665  while (pOldObject)
1666  {
1667  tools::Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1668 
1669  bool bObjectInArea = rRange.IsInside(aObjRect);
1670  const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pOldObject);
1671  if (pObjData)
1672  {
1673  ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nTab);
1674  bObjectInArea = bObjectInArea || aClipRange.In(pObjData->maStart);
1675  }
1676 
1677  // do not copy internal objects (detective) and note captions
1678  if (bObjectInArea && pOldObject->GetLayer() != SC_LAYER_INTERN
1679  && !IsNoteCaption(pOldObject))
1680  {
1681  if ( !pDestModel )
1682  {
1683  pDestModel = pClipDoc->GetDrawLayer(); // does the document already have a drawing layer?
1684  if ( !pDestModel )
1685  {
1686  // allocate drawing layer in clipboard document only if there are objects to copy
1687 
1688  pClipDoc->InitDrawLayer(); //TODO: create contiguous pages
1689  pDestModel = pClipDoc->GetDrawLayer();
1690  }
1691  if (pDestModel)
1692  pDestPage = pDestModel->GetPage( static_cast<sal_uInt16>(nTab) );
1693  }
1694 
1695  OSL_ENSURE( pDestPage, "no page" );
1696  if (pDestPage)
1697  {
1698  // Clone to target SdrModel
1699  SdrObject* pNewObject(pOldObject->CloneSdrObject(*pDestModel));
1700 
1701  uno::Reference< chart2::XChartDocument > xOldChart( ScChartHelper::GetChartFromSdrObject( pOldObject ) );
1702  if(!xOldChart.is())//#i110034# do not move charts as they lose all their data references otherwise
1703  pNewObject->NbcMove(Size(0,0));
1704  pDestPage->InsertObject( pNewObject );
1705 
1706  // no undo needed in clipboard document
1707  // charts are not updated
1708  }
1709  }
1710 
1711  pOldObject = aIter.Next();
1712  }
1713 }
1714 
1715 static bool lcl_IsAllInRange( const ::std::vector< ScRangeList >& rRangesVector, const ScRange& rClipRange )
1716 {
1717  // check if every range of rRangesVector is completely in rClipRange
1718 
1719  for( const ScRangeList& rRanges : rRangesVector )
1720  {
1721  for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
1722  {
1723  const ScRange & rRange = rRanges[ i ];
1724  if ( !rClipRange.In( rRange ) )
1725  {
1726  return false; // at least one range is not valid
1727  }
1728  }
1729  }
1730 
1731  return true; // everything is fine
1732 }
1733 
1734 static bool lcl_MoveRanges( ::std::vector< ScRangeList >& rRangesVector, const ScRange& rSourceRange, const ScAddress& rDestPos )
1735 {
1736  bool bChanged = false;
1737 
1738  ScRange aErrorRange( ScAddress::UNINITIALIZED );
1739  for( ScRangeList& rRanges : rRangesVector )
1740  {
1741  for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
1742  {
1743  ScRange & rRange = rRanges[ i ];
1744  if ( rSourceRange.In( rRange ) )
1745  {
1746  SCCOL nDiffX = rDestPos.Col() - rSourceRange.aStart.Col();
1747  SCROW nDiffY = rDestPos.Row() - rSourceRange.aStart.Row();
1748  SCTAB nDiffZ = rDestPos.Tab() - rSourceRange.aStart.Tab();
1749  if (!rRange.Move( nDiffX, nDiffY, nDiffZ, aErrorRange))
1750  {
1751  assert(!"can't move range");
1752  }
1753  bChanged = true;
1754  }
1755  }
1756  }
1757 
1758  return bChanged;
1759 }
1760 
1761 void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const tools::Rectangle& rSourceRange,
1762  const ScAddress& rDestPos, const tools::Rectangle& rDestRange )
1763 {
1764  OSL_ENSURE( pDoc, "ScDrawLayer::CopyFromClip without document" );
1765  if ( !pDoc )
1766  return;
1767 
1768  if (!pClipModel)
1769  return;
1770 
1771  if (bDrawIsInUndo) //TODO: can this happen?
1772  {
1773  OSL_FAIL("CopyFromClip, bDrawIsInUndo");
1774  return;
1775  }
1776 
1777  bool bMirrorObj = ( rSourceRange.Left() < 0 && rSourceRange.Right() < 0 &&
1778  rDestRange.Left() > 0 && rDestRange.Right() > 0 ) ||
1779  ( rSourceRange.Left() > 0 && rSourceRange.Right() > 0 &&
1780  rDestRange.Left() < 0 && rDestRange.Right() < 0 );
1781  tools::Rectangle aMirroredSource = rSourceRange;
1782  if ( bMirrorObj )
1783  MirrorRectRTL( aMirroredSource );
1784 
1785  SCTAB nDestTab = rDestPos.Tab();
1786 
1787  SdrPage* pSrcPage = pClipModel->GetPage(static_cast<sal_uInt16>(nSourceTab));
1788  SdrPage* pDestPage = GetPage(static_cast<sal_uInt16>(nDestTab));
1789  OSL_ENSURE( pSrcPage && pDestPage, "draw page missing" );
1790  if ( !pSrcPage || !pDestPage )
1791  return;
1792 
1793  SdrObjListIter aIter( pSrcPage, SdrIterMode::Flat );
1794  SdrObject* pOldObject = aIter.Next();
1795 
1796  ScDocument* pClipDoc = pClipModel->GetDocument();
1797  // a clipboard document and its source share the same document item pool,
1798  // so the pointers can be compared to see if this is copy&paste within
1799  // the same document
1800  bool bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
1801  bool bDestClip = pDoc && pDoc->IsClipboard();
1802 
1803  //#i110034# charts need correct sheet names for xml range conversion during load
1804  //so the target sheet name is temporarily renamed (if we have any SdrObjects)
1805  OUString aDestTabName;
1806  bool bRestoreDestTabName = false;
1807  if( pOldObject && !bSameDoc && !bDestClip )
1808  {
1809  if( pDoc && pClipDoc )
1810  {
1811  OUString aSourceTabName;
1812  if( pClipDoc->GetName( nSourceTab, aSourceTabName )
1813  && pDoc->GetName( nDestTab, aDestTabName ) )
1814  {
1815  if( aSourceTabName != aDestTabName &&
1816  pDoc->ValidNewTabName(aSourceTabName) )
1817  {
1818  bRestoreDestTabName = pDoc->RenameTab( nDestTab, aSourceTabName );
1819  }
1820  }
1821  }
1822  }
1823 
1824  // first mirror, then move
1825  Size aMove( rDestRange.Left() - aMirroredSource.Left(), rDestRange.Top() - aMirroredSource.Top() );
1826 
1827  tools::Long nDestWidth = rDestRange.GetWidth();
1828  tools::Long nDestHeight = rDestRange.GetHeight();
1829  tools::Long nSourceWidth = rSourceRange.GetWidth();
1830  tools::Long nSourceHeight = rSourceRange.GetHeight();
1831 
1832  tools::Long nWidthDiff = nDestWidth - nSourceWidth;
1833  tools::Long nHeightDiff = nDestHeight - nSourceHeight;
1834 
1835  Fraction aHorFract(1,1);
1836  Fraction aVerFract(1,1);
1837  bool bResize = false;
1838  // sizes can differ by 1 from twips->1/100mm conversion for equal cell sizes,
1839  // don't resize to empty size when pasting into hidden columns or rows
1840  if ( std::abs(nWidthDiff) > 1 && nDestWidth > 1 && nSourceWidth > 1 )
1841  {
1842  aHorFract = Fraction( nDestWidth, nSourceWidth );
1843  bResize = true;
1844  }
1845  if ( std::abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
1846  {
1847  aVerFract = Fraction( nDestHeight, nSourceHeight );
1848  bResize = true;
1849  }
1850  Point aRefPos = rDestRange.TopLeft(); // for resizing (after moving)
1851 
1852  while (pOldObject)
1853  {
1854  tools::Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
1855  // do not copy internal objects (detective) and note captions
1856 
1857  SCTAB nClipTab = bRestoreDestTabName ? nDestTab : nSourceTab;
1858  ScRange aClipRange = lcl_getClipRangeFromClipDoc(pClipDoc, nClipTab);
1859 
1860  bool bObjectInArea = rSourceRange.IsInside(aObjRect);
1861  const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pOldObject);
1862  if (pObjData) // Consider images anchored to the copied cell
1863  bObjectInArea = bObjectInArea || aClipRange.In(pObjData->maStart);
1864  if (bObjectInArea && (pOldObject->GetLayer() != SC_LAYER_INTERN)
1865  && !IsNoteCaption(pOldObject))
1866  {
1867  // Clone to target SdrModel
1868  SdrObject* pNewObject(pOldObject->CloneSdrObject(*this));
1869 
1870  if ( bMirrorObj )
1871  MirrorRTL( pNewObject ); // first mirror, then move
1872 
1873  pNewObject->NbcMove( aMove );
1874  if ( bResize )
1875  pNewObject->NbcResize( aRefPos, aHorFract, aVerFract );
1876 
1877  pDestPage->InsertObject( pNewObject );
1878  if (bRecording)
1879  AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pNewObject ) );
1880 
1881  //#i110034# handle chart data references (after InsertObject)
1882 
1883  if ( pNewObject->GetObjIdentifier() == OBJ_OLE2 )
1884  {
1885  uno::Reference< embed::XEmbeddedObject > xIPObj = static_cast<SdrOle2Obj*>(pNewObject)->GetObjRef();
1886  uno::Reference< embed::XClassifiedObject > xClassified = xIPObj;
1887  SvGlobalName aObjectClassName;
1888  if ( xClassified.is() )
1889  {
1890  try {
1891  aObjectClassName = SvGlobalName( xClassified->getClassID() );
1892  } catch( uno::Exception& )
1893  {
1894  // TODO: handle error?
1895  }
1896  }
1897 
1898  if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
1899  {
1900  uno::Reference< chart2::XChartDocument > xNewChart( ScChartHelper::GetChartFromSdrObject( pNewObject ) );
1901  if( xNewChart.is() && !xNewChart->hasInternalDataProvider() )
1902  {
1903  OUString aChartName = static_cast<SdrOle2Obj*>(pNewObject)->GetPersistName();
1904  ::std::vector< ScRangeList > aRangesVector;
1905  pDoc->GetChartRanges( aChartName, aRangesVector, *pDoc );
1906  if( !aRangesVector.empty() )
1907  {
1908  bool bInSourceRange = false;
1909  if ( pClipDoc )
1910  {
1911  bInSourceRange = lcl_IsAllInRange( aRangesVector, aClipRange );
1912  }
1913 
1914  // always lose references when pasting into a clipboard document (transpose)
1915  if ( ( bInSourceRange || bSameDoc ) && !bDestClip )
1916  {
1917  if ( bInSourceRange )
1918  {
1919  if ( rDestPos != aClipRange.aStart )
1920  {
1921  // update the data ranges to the new (copied) position
1922  if ( lcl_MoveRanges( aRangesVector, aClipRange, rDestPos ) )
1923  pDoc->SetChartRanges( aChartName, aRangesVector );
1924  }
1925  }
1926  else
1927  {
1928  // leave the ranges unchanged
1929  }
1930  }
1931  else
1932  {
1933  // pasting into a new document without the complete source data
1934  // -> break connection to source data and switch to own data
1935 
1936  uno::Reference< chart::XChartDocument > xOldChartDoc( ScChartHelper::GetChartFromSdrObject( pOldObject ), uno::UNO_QUERY );
1937  uno::Reference< chart::XChartDocument > xNewChartDoc( xNewChart, uno::UNO_QUERY );
1938  if( xOldChartDoc.is() && xNewChartDoc.is() )
1939  xNewChartDoc->attachData( xOldChartDoc->getData() );
1940 
1941  // (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
1942  }
1943  }
1944  }
1945  }
1946  }
1947  }
1948 
1949  pOldObject = aIter.Next();
1950  }
1951 
1952  if( bRestoreDestTabName )
1953  pDoc->RenameTab( nDestTab, aDestTabName );
1954 }
1955 
1957 {
1958  sal_uInt16 nIdent = pObj->GetObjIdentifier();
1959 
1960  // don't mirror OLE or graphics, otherwise ask the object
1961  // if it can be mirrored
1962  bool bCanMirror = ( nIdent != OBJ_GRAF && nIdent != OBJ_OLE2 );
1963  if (bCanMirror)
1964  {
1965  SdrObjTransformInfoRec aInfo;
1966  pObj->TakeObjInfo( aInfo );
1967  bCanMirror = aInfo.bMirror90Allowed;
1968  }
1969 
1970  if (bCanMirror)
1971  {
1972  Point aRef1( 0, 0 );
1973  Point aRef2( 0, 1 );
1974  if (bRecording)
1975  AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
1976  pObj->Mirror( aRef1, aRef2 );
1977  }
1978  else
1979  {
1980  // Move instead of mirroring:
1981  // New start position is negative of old end position
1982  // -> move by sum of start and end position
1983  tools::Rectangle aObjRect = pObj->GetLogicRect();
1984  Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
1985  if (bRecording)
1986  AddCalcUndo( std::make_unique<SdrUndoMoveObj>( *pObj, aMoveSize ) );
1987  pObj->Move( aMoveSize );
1988  }
1989 }
1990 
1992 {
1993  // mirror and swap left/right
1994  tools::Long nTemp = rRect.Left();
1995  rRect.SetLeft( -rRect.Right() );
1996  rRect.SetRight( -nTemp );
1997 }
1998 
1999 tools::Rectangle ScDrawLayer::GetCellRect( const ScDocument& rDoc, const ScAddress& rPos, bool bMergedCell )
2000 {
2001  tools::Rectangle aCellRect;
2002  OSL_ENSURE( rDoc.ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ), "ScDrawLayer::GetCellRect - invalid cell address" );
2003  if( rDoc.ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ) )
2004  {
2005  // find top left position of passed cell address
2006  Point aTopLeft;
2007  for( SCCOL nCol = 0; nCol < rPos.Col(); ++nCol )
2008  aTopLeft.AdjustX(rDoc.GetColWidth( nCol, rPos.Tab() ) );
2009  if( rPos.Row() > 0 )
2010  aTopLeft.AdjustY(rDoc.GetRowHeight( 0, rPos.Row() - 1, rPos.Tab() ) );
2011 
2012  // find bottom-right position of passed cell address
2013  ScAddress aEndPos = rPos;
2014  if( bMergedCell )
2015  {
2016  const ScMergeAttr* pMerge = rDoc.GetAttr( rPos, ATTR_MERGE );
2017  if( pMerge->GetColMerge() > 1 )
2018  aEndPos.IncCol( pMerge->GetColMerge() - 1 );
2019  if( pMerge->GetRowMerge() > 1 )
2020  aEndPos.IncRow( pMerge->GetRowMerge() - 1 );
2021  }
2022  Point aBotRight = aTopLeft;
2023  for( SCCOL nCol = rPos.Col(); nCol <= aEndPos.Col(); ++nCol )
2024  aBotRight.AdjustX(rDoc.GetColWidth( nCol, rPos.Tab() ) );
2025  aBotRight.AdjustY(rDoc.GetRowHeight( rPos.Row(), aEndPos.Row(), rPos.Tab() ) );
2026 
2027  // twips -> 1/100 mm
2028  aTopLeft.setX( static_cast< tools::Long >( aTopLeft.X() * HMM_PER_TWIPS ) );
2029  aTopLeft.setY( static_cast< tools::Long >( aTopLeft.Y() * HMM_PER_TWIPS ) );
2030  aBotRight.setX( static_cast< tools::Long >( aBotRight.X() * HMM_PER_TWIPS ) );
2031  aBotRight.setY( static_cast< tools::Long >( aBotRight.Y() * HMM_PER_TWIPS ) );
2032 
2033  aCellRect = tools::Rectangle( aTopLeft, aBotRight );
2034  if( rDoc.IsNegativePage( rPos.Tab() ) )
2035  MirrorRectRTL( aCellRect );
2036  }
2037  return aCellRect;
2038 }
2039 
2041 {
2042  OUString aName = pObj->GetName();
2043  if ( pObj->GetObjIdentifier() == OBJ_OLE2 )
2044  {
2045  // For OLE, the user defined name (GetName) is used
2046  // if it's not empty (accepting possibly duplicate names),
2047  // otherwise the persist name is used so every object appears
2048  // in the Navigator at all.
2049 
2050  if ( aName.isEmpty() )
2051  aName = static_cast<const SdrOle2Obj*>(pObj)->GetPersistName();
2052  }
2053  return aName;
2054 }
2055 
2056 static bool IsNamedObject( const SdrObject* pObj, std::u16string_view rName )
2057 {
2058  // sal_True if rName is the object's Name or PersistName
2059  // (used to find a named object)
2060 
2061  return ( pObj->GetName() == rName ||
2062  ( pObj->GetObjIdentifier() == OBJ_OLE2 &&
2063  static_cast<const SdrOle2Obj*>(pObj)->GetPersistName() == rName ) );
2064 }
2065 
2066 SdrObject* ScDrawLayer::GetNamedObject( std::u16string_view rName, sal_uInt16 nId, SCTAB& rFoundTab ) const
2067 {
2068  sal_uInt16 nTabCount = GetPageCount();
2069  for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
2070  {
2071  const SdrPage* pPage = GetPage(nTab);
2072  OSL_ENSURE(pPage,"Page ?");
2073  if (pPage)
2074  {
2075  SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
2076  SdrObject* pObject = aIter.Next();
2077  while (pObject)
2078  {
2079  if ( nId == 0 || pObject->GetObjIdentifier() == nId )
2080  if ( IsNamedObject( pObject, rName ) )
2081  {
2082  rFoundTab = static_cast<SCTAB>(nTab);
2083  return pObject;
2084  }
2085 
2086  pObject = aIter.Next();
2087  }
2088  }
2089  }
2090 
2091  return nullptr;
2092 }
2093 
2094 OUString ScDrawLayer::GetNewGraphicName( tools::Long* pnCounter ) const
2095 {
2096  OUString aBase = ScResId(STR_GRAPHICNAME) + " ";
2097 
2098  bool bThere = true;
2099  OUString aGraphicName;
2100  SCTAB nDummy;
2101  tools::Long nId = pnCounter ? *pnCounter : 0;
2102  while (bThere)
2103  {
2104  ++nId;
2105  aGraphicName = aBase + OUString::number( nId );
2106  bThere = ( GetNamedObject( aGraphicName, 0, nDummy ) != nullptr );
2107  }
2108 
2109  if ( pnCounter )
2110  *pnCounter = nId;
2111 
2112  return aGraphicName;
2113 }
2114 
2116 {
2117  // make sure all graphic objects have names (after Excel import etc.)
2118 
2119  sal_uInt16 nTabCount = GetPageCount();
2120  for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
2121  {
2122  SdrPage* pPage = GetPage(nTab);
2123  OSL_ENSURE(pPage,"Page ?");
2124  if (pPage)
2125  {
2126  SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
2127  SdrObject* pObject = aIter.Next();
2128 
2129  /* The index passed to GetNewGraphicName() will be set to
2130  the used index in each call. This prevents the repeated search
2131  for all names from 1 to current index. */
2132  tools::Long nCounter = 0;
2133 
2134  while (pObject)
2135  {
2136  if ( pObject->GetObjIdentifier() == OBJ_GRAF && pObject->GetName().isEmpty())
2137  pObject->SetName( GetNewGraphicName( &nCounter ) );
2138 
2139  pObject = aIter.Next();
2140  }
2141  }
2142  }
2143 }
2144 
2145 namespace
2146 {
2147  SdrObjUserData* GetFirstUserDataOfType(const SdrObject *pObj, sal_uInt16 nId)
2148  {
2149  sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
2150  for( sal_uInt16 i = 0; i < nCount; i++ )
2151  {
2152  SdrObjUserData* pData = pObj->GetUserData( i );
2153  if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw && pData->GetId() == nId )
2154  return pData;
2155  }
2156  return nullptr;
2157  }
2158 
2159  void DeleteFirstUserDataOfType(SdrObject *pObj, sal_uInt16 nId)
2160  {
2161  sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
2162  for( sal_uInt16 i = nCount; i > 0; i-- )
2163  {
2164  SdrObjUserData* pData = pObj->GetUserData( i-1 );
2165  if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw && pData->GetId() == nId )
2166  pObj->DeleteUserData(i-1);
2167  }
2168  }
2169 }
2170 
2172 {
2173  ScDrawObjData* pAnchor = GetNonRotatedObjData( &rObj, true );
2174  pAnchor->maStart = rAnchor.maStart;
2175  pAnchor->maEnd = rAnchor.maEnd;
2176  pAnchor->maStartOffset = rAnchor.maStartOffset;
2177  pAnchor->maEndOffset = rAnchor.maEndOffset;
2178  pAnchor->mbResizeWithCell = rAnchor.mbResizeWithCell;
2179 }
2180 
2182 {
2183  ScDrawObjData* pAnchor = GetObjData( &rObj, true );
2184  pAnchor->maStart = rAnchor.maStart;
2185  pAnchor->maEnd = rAnchor.maEnd;
2186  pAnchor->maStartOffset = rAnchor.maStartOffset;
2187  pAnchor->maEndOffset = rAnchor.maEndOffset;
2188  pAnchor->mbResizeWithCell = rAnchor.mbResizeWithCell;
2189 }
2190 
2192  bool bResizeWithCell )
2193 {
2194  if (!rObj.IsVisible())
2195  return;
2196  ScDrawObjData aAnchor;
2197  // set anchor in terms of the visual ( SnapRect )
2198  // object ( e.g. for when object is rotated )
2199  const tools::Rectangle aObjRect(rObj.GetSnapRect());
2201  aObjRect,
2202  aAnchor,
2203  rDoc,
2204  nTab);
2205 
2206  aAnchor.mbResizeWithCell = bResizeWithCell;
2207  SetCellAnchored( rObj, aAnchor );
2208 
2209  // absolutely necessary to set flag, ScDrawLayer::RecalcPos expects it.
2210  if ( ScDrawObjData* pAnchor = GetObjData( &rObj ) )
2211  {
2212  pAnchor->setShapeRect(&rDoc, rObj.GetSnapRect());
2213  }
2214 
2215  // - keep also an anchor in terms of the Logic ( untransformed ) object
2216  // because that's what we stored ( and still do ) to xml
2217 
2218  // Vertical flipped custom shapes need special treatment, see comment in
2219  // lcl_SetLogicRectFromAnchor
2220  tools::Rectangle aObjRect2;
2221  if (lcl_NeedsMirrorYCorrection(&rObj))
2222  {
2223  const tools::Rectangle aRect(rObj.GetSnapRect());
2224  const Point aLeft(aRect.Left(), (aRect.Top() + aRect.Bottom()) >> 1);
2225  const Point aRight(aLeft.X() + 1000, aLeft.Y());
2226  rObj.NbcMirror(aLeft, aRight);
2227  aObjRect2 = rObj.GetLogicRect();
2228  rObj.NbcMirror(aLeft, aRight);
2229  }
2230  else if (rObj.GetObjIdentifier() == OBJ_MEASURE)
2231  {
2232  // tdf#137576. A SdrMeasureObj might have a wrong logic rect here. TakeUnrotatedSnapRect
2233  // calculates the current unrotated snap rectangle, sets logic rectangle and returns it.
2234  static_cast<SdrMeasureObj&>(rObj).TakeUnrotatedSnapRect(aObjRect2);
2235  }
2236  else
2237  aObjRect2 = rObj.GetLogicRect();
2238 
2239  ScDrawObjData aVisAnchor;
2241  aObjRect2,
2242  aVisAnchor,
2243  rDoc,
2244  nTab, false);
2245 
2246  aVisAnchor.mbResizeWithCell = bResizeWithCell;
2247  SetVisualCellAnchored( rObj, aVisAnchor );
2248 }
2249 
2251  const tools::Rectangle &rObjRect,
2252  ScDrawObjData &rAnchor,
2253  const ScDocument &rDoc,
2254  SCTAB nTab,
2255  bool bHiddenAsZero)
2256 {
2257  ScRange aRange = rDoc.GetRange( nTab, rObjRect, bHiddenAsZero );
2258 
2259  tools::Rectangle aCellRect;
2260 
2261  rAnchor.maStart = aRange.aStart;
2262  aCellRect = rDoc.GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(),
2263  aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), bHiddenAsZero );
2264  rAnchor.maStartOffset.setY( rObjRect.Top()-aCellRect.Top() );
2265  if (!rDoc.IsNegativePage(nTab))
2266  rAnchor.maStartOffset.setX( rObjRect.Left()-aCellRect.Left() );
2267  else
2268  rAnchor.maStartOffset.setX( aCellRect.Right()-rObjRect.Right() );
2269 
2270  rAnchor.maEnd = aRange.aEnd;
2271  aCellRect = rDoc.GetMMRect( aRange.aEnd.Col(), aRange.aEnd.Row(),
2272  aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), bHiddenAsZero );
2273  if (!rObjRect.IsEmpty())
2274  rAnchor.maEndOffset.setY( rObjRect.Bottom()-aCellRect.Top() );
2275  if (!rDoc.IsNegativePage(nTab))
2276  {
2277  if (!rObjRect.IsEmpty())
2278  rAnchor.maEndOffset.setX( rObjRect.Right()-aCellRect.Left() );
2279  }
2280  else
2281  rAnchor.maEndOffset.setX( aCellRect.Right()-rObjRect.Left() );
2282 }
2283 
2284 void ScDrawLayer::UpdateCellAnchorFromPositionEnd( const SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect )
2285 {
2286  tools::Rectangle aObjRect(bUseLogicRect ? rObj.GetLogicRect() : rObj.GetSnapRect());
2287  ScRange aRange = rDoc.GetRange( nTab, aObjRect );
2288 
2289  ScDrawObjData* pAnchor = &rAnchor;
2290  pAnchor->maEnd = aRange.aEnd;
2291 
2292  tools::Rectangle aCellRect = rDoc.GetMMRect( aRange.aEnd.Col(), aRange.aEnd.Row(),
2293  aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab() );
2294  pAnchor->maEndOffset.setY( aObjRect.Bottom()-aCellRect.Top() );
2295  if (!rDoc.IsNegativePage(nTab))
2296  pAnchor->maEndOffset.setX( aObjRect.Right()-aCellRect.Left() );
2297  else
2298  pAnchor->maEndOffset.setX( aCellRect.Right()-aObjRect.Left() );
2299 }
2300 
2302 {
2303  // Cell anchored object always has a user data, to store the anchor cell
2304  // info. If it doesn't then it's page-anchored.
2305  return GetFirstUserDataOfType(&rObj, SC_UD_OBJDATA) != nullptr;
2306 }
2307 
2309 {
2310  // Cell anchored object always has a user data, to store the anchor cell
2311  // info. If it doesn't then it's page-anchored.
2312  ScDrawObjData* pDrawObjData = GetObjData(const_cast<SdrObject*>(&rObj));
2313  if (!pDrawObjData)
2314  return false;
2315 
2316  return pDrawObjData->mbResizeWithCell;
2317 }
2318 
2320 {
2321  DeleteFirstUserDataOfType(&rObj, SC_UD_OBJDATA);
2322  DeleteFirstUserDataOfType(&rObj, SC_UD_OBJDATA);
2323 }
2324 
2326 {
2327  //If this object has a cell anchor associated with it
2328  //then it's cell-anchored, otherwise it's page-anchored
2329  const ScDrawObjData* pObjData = ScDrawLayer::GetObjData(const_cast<SdrObject*>(&rObj));
2330 
2331  // When there is no cell anchor, it is page anchored.
2332  if (!pObjData)
2333  return SCA_PAGE;
2334 
2335  // It's cell-anchored, check if the object resizes with the cell
2336  if (pObjData->mbResizeWithCell)
2337  return SCA_CELL_RESIZE;
2338 
2339  return SCA_CELL;
2340 }
2341 
2342 std::vector<SdrObject*>
2344 {
2345  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
2346  if (!pPage || pPage->GetObjCount() < 1)
2347  return std::vector<SdrObject*>();
2348 
2349  std::vector<SdrObject*> aObjects;
2350  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
2351  SdrObject* pObject = aIter.Next();
2352  ScRange aRange( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab);
2353  while (pObject)
2354  {
2355  if (!dynamic_cast<SdrCaptionObj*>(pObject)) // Caption objects are handled differently
2356  {
2357  ScDrawObjData* pObjData = GetObjData(pObject);
2358  if (pObjData && aRange.In(pObjData->maStart))
2359  aObjects.push_back(pObject);
2360  }
2361  pObject = aIter.Next();
2362  }
2363  return aObjects;
2364 }
2365 
2366 std::map<SCROW, std::vector<SdrObject*>>
2368 {
2369  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
2370  if (!pPage || pPage->GetObjCount() < 1)
2371  return std::map<SCROW, std::vector<SdrObject*>>();
2372 
2373  std::map<SCROW, std::vector<SdrObject*>> aRowObjects;
2374  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
2375  SdrObject* pObject = aIter.Next();
2376  ScRange aRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab);
2377  while (pObject)
2378  {
2379  if (!dynamic_cast<SdrCaptionObj*>(pObject)) // Caption objects are handled differently
2380  {
2381  ScDrawObjData* pObjData = GetObjData(pObject);
2382  if (pObjData && aRange.In(pObjData->maStart))
2383  aRowObjects[pObjData->maStart.Row()].push_back(pObject);
2384  }
2385  pObject = aIter.Next();
2386  }
2387  return aRowObjects;
2388 }
2389 
2391 {
2392  // This only works for one table at a time
2393  assert(rRange.aStart.Tab() == rRange.aEnd.Tab());
2394 
2395  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(rRange.aStart.Tab()));
2396  if (!pPage || pPage->GetObjCount() < 1)
2397  return false;
2398 
2399  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
2400  SdrObject* pObject = aIter.Next();
2401  while (pObject)
2402  {
2403  if (!dynamic_cast<SdrCaptionObj*>(pObject)) // Caption objects are handled differently
2404  {
2405  ScDrawObjData* pObjData = GetObjData(pObject);
2406  if (pObjData && rRange.In(pObjData->maStart)) // Object is in given range
2407  return true;
2408  }
2409  pObject = aIter.Next();
2410  }
2411  return false;
2412 }
2413 
2414 std::vector<SdrObject*> ScDrawLayer::GetObjectsAnchoredToCols(SCTAB nTab, SCCOL nStartCol,
2415  SCCOL nEndCol)
2416 {
2417  SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
2418  if (!pPage || pPage->GetObjCount() < 1)
2419  return std::vector<SdrObject*>();
2420 
2421  std::vector<SdrObject*> aObjects;
2422  SdrObjListIter aIter(pPage, SdrIterMode::Flat);
2423  SdrObject* pObject = aIter.Next();
2424  ScRange aRange(nStartCol, 0, nTab, nEndCol, MAXROW, nTab);
2425  while (pObject)
2426  {
2427  if (!dynamic_cast<SdrCaptionObj*>(pObject)) // Caption objects are handled differently
2428  {
2429  ScDrawObjData* pObjData = GetObjData(pObject);
2430  if (pObjData && aRange.In(pObjData->maStart))
2431  aObjects.push_back(pObject);
2432  }
2433  pObject = aIter.Next();
2434  }
2435  return aObjects;
2436 }
2437 
2438 void ScDrawLayer::MoveObject(SdrObject* pObject, const ScAddress& rNewPosition)
2439 {
2440  // Get anchor data
2441  ScDrawObjData* pObjData = GetObjData(pObject, false);
2442  if (!pObjData)
2443  return;
2444  const ScAddress aOldStart = pObjData->maStart;
2445  const ScAddress aOldEnd = pObjData->maEnd;
2446 
2447  // Set start address
2448  pObjData->maStart = rNewPosition;
2449 
2450  // Set end address
2451  const SCCOL nObjectColSpan = aOldEnd.Col() - aOldStart.Col();
2452  const SCROW nObjectRowSpan = aOldEnd.Row() - aOldStart.Row();
2453  ScAddress aNewEnd = rNewPosition;
2454  aNewEnd.IncRow(nObjectRowSpan);
2455  aNewEnd.IncCol(nObjectColSpan);
2456  pObjData->maEnd = aNewEnd;
2457 
2458  // Update draw object according to new anchor
2459  RecalcPos(pObject, *pObjData, false, false);
2460 }
2461 
2463 {
2464  sal_uInt16 nCount = pObj ? pObj->GetUserDataCount() : 0;
2465  sal_uInt16 nFound = 0;
2466  for( sal_uInt16 i = 0; i < nCount; i++ )
2467  {
2468  SdrObjUserData* pData = pObj->GetUserData( i );
2469  if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw && pData->GetId() == SC_UD_OBJDATA && ++nFound == 2 )
2470  return static_cast<ScDrawObjData*>(pData);
2471  }
2472  if( pObj && bCreate )
2473  {
2474  ScDrawObjData* pData = new ScDrawObjData;
2475  pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(pData));
2476  return pData;
2477  }
2478  return nullptr;
2479 }
2480 
2482 {
2483  if (SdrObjUserData *pData = GetFirstUserDataOfType(pObj, SC_UD_OBJDATA))
2484  return static_cast<ScDrawObjData*>(pData);
2485 
2486  if( pObj && bCreate )
2487  {
2488  ScDrawObjData* pData = new ScDrawObjData;
2489  pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(pData));
2490  return pData;
2491  }
2492  return nullptr;
2493 }
2494 
2496 {
2497  ScDrawObjData* pData = GetObjData( pObj );
2498  if ( pData )
2499  {
2500  if ( pData->maStart.IsValid() )
2501  pData->maStart.SetTab( nTab );
2502  if ( pData->maEnd.IsValid() )
2503  pData->maEnd.SetTab( nTab );
2504  }
2505  return pData;
2506 }
2507 
2509 {
2510  ScDrawObjData* pData = pObj ? GetObjData( pObj ) : nullptr;
2511  return pData && pData->meType == ScDrawObjData::CellNote;
2512 }
2513 
2515 {
2516  ScDrawObjData* pData = pObj ? GetObjDataTab( pObj, nTab ) : nullptr;
2517  return (pData && pData->meType == ScDrawObjData::CellNote) ? pData : nullptr;
2518 }
2519 
2521 {
2522  if (SdrObjUserData *pData = GetFirstUserDataOfType(pObj, SC_UD_MACRODATA))
2523  return static_cast<ScMacroInfo*>(pData);
2524 
2525  if ( bCreate )
2526  {
2527  ScMacroInfo* pData = new ScMacroInfo;
2528  pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(pData));
2529  return pData;
2530  }
2531  return nullptr;
2532 }
2533 
2535 {
2536  OSL_ENSURE(!pGlobalDrawPersist,"Multiple SetGlobalDrawPersist");
2537  pGlobalDrawPersist = pPersist;
2538 }
2539 
2540 void ScDrawLayer::SetChanged( bool bFlg /* = true */ )
2541 {
2542  if ( bFlg && pDoc )
2544  FmFormModel::SetChanged( bFlg );
2545 }
2546 
2547 css::uno::Reference< css::uno::XInterface > ScDrawLayer::createUnoModel()
2548 {
2549  css::uno::Reference< css::uno::XInterface > xRet;
2550  if( pDoc && pDoc->GetDocumentShell() )
2551  xRet = pDoc->GetDocumentShell()->GetModel();
2552 
2553  return xRet;
2554 }
2555 
2556 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SdrOutliner & GetDrawOutliner(const SdrTextObj *pObj=nullptr) const
void BeginCalcUndo(bool bDisableTextEditUsesCommonUndoManager)
Definition: drwlayer.cxx:1388
Point TopLeft() const
std::map< SCROW, std::vector< SdrObject * > > GetObjectsAnchoredToRange(SCTAB nTab, SCCOL nCol, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:2367
bool mbWasCellAnchored
Definition: drwlayer.hxx:77
void SetPos(const Point &rPoint)
bool bAdjustEnabled
Definition: drwlayer.hxx:96
void EnsureGraphicNames()
Definition: drwlayer.cxx:2115
SCCOL GetColMerge() const
Definition: attrib.hxx:69
static void GetCellAnchorFromPosition(const tools::Rectangle &rRectangle, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bHiddenAsZero=true)
Definition: drwlayer.cxx:2250
static SfxObjectShell * pGlobalDrawPersist
Definition: drwlayer.hxx:214
virtual void TakeObjInfo(SdrObjTransformInfoRec &rInfo) const
SdrMetricItem makeSdrShadowYDistItem(tools::Long nDist)
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
constexpr TypedWhichId< SvxScriptSpaceItem > EE_PARA_ASIANCJKSPACING(EE_PARA_START+4)
static void SetVisualCellAnchored(SdrObject &, const ScDrawObjData &rAnchor)
Definition: drwlayer.cxx:2171
void GetClipStart(SCCOL &nClipX, SCROW &nClipY)
Definition: document.cxx:3168
ScAddress aStart
Definition: address.hxx:500
virtual void SetSize(const Size &aSiz)
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
virtual const tools::Rectangle & GetCurrentBoundRect() const
std::vector< SdrObject * > GetObjectsAnchoredToRows(SCTAB nTab, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:2343
SC_DLLPUBLIC bool IsNegativePage(SCTAB nTab) const
Definition: document.cxx:1000
void SetPoint(const Point &rPnt, sal_uInt32 i)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
SCROW Row() const
Definition: address.hxx:262
void MirrorRTL(SdrObject *pObj)
Definition: drwlayer.cxx:1956
std::unique_ptr< ContentProperties > pData
virtual ~ScDrawLayer() override
Definition: drwlayer.cxx:337
void SetName(const OUString &rStr, const bool bSetChanged=true)
virtual bool IsPolyObj() const
virtual void NbcResize(const Point &rRef, const Fraction &xFact, const Fraction &yFact)
static css::uno::Reference< css::chart2::XChartDocument > GetChartFromSdrObject(const SdrObject *pObject)
static void SetPageAnchored(SdrObject &)
Definition: drwlayer.cxx:2319
void ResizeLastRectFromAnchor(const SdrObject *pObj, ScDrawObjData &rData, bool bUseLogicRect, bool bNegativePage, bool bCanResize)
Definition: drwlayer.cxx:720
LanguageType getLanguageType(bool bResolveSystem=true) const
Point BottomLeft() const
ScUndoObjData(SdrObject *pObj, const ScAddress &rOS, const ScAddress &rOE, const ScAddress &rNS, const ScAddress &rNE)
Definition: drwlayer.cxx:92
static ScMacroInfo * GetMacroInfo(SdrObject *pObj, bool bCreate=false)
Definition: drwlayer.cxx:2520
long Long
void ResetTab(SCTAB nStart, SCTAB nEnd)
Definition: drwlayer.cxx:483
static const AllSettings & GetSettings()
OBJ_LINE
virtual Point GetRelativePos() const
SC_DLLPUBLIC bool ValidNewTabName(const OUString &rName) const
Definition: document.cxx:372
virtual void SetChanged(bool bFlg=true) override
Definition: drwlayer.cxx:2540
static ScDrawObjData * GetObjData(SdrObject *pObj, bool bCreate=false)
Definition: drwlayer.cxx:2481
#define DET_ARROW_OFFSET
Definition: drwlayer.cxx:81
SdrObject * GetObj(size_t nNum) const
void RecalcObjOrdNums()
bool IsInserted() const
static bool IsCellAnchored(const SdrObject &rObj)
Definition: drwlayer.cxx:2301
static bool lcl_MoveRanges(::std::vector< ScRangeList > &rRangesVector, const ScRange &rSourceRange, const ScAddress &rDestPos)
Definition: drwlayer.cxx:1734
size_t GetObjCount() const
tools::Long getY() const
void PutInOrder(ScAddress &rAddress)
Definition: address.hxx:384
void DeleteObjectsInArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bAnchored=false)
Definition: drwlayer.cxx:1503
sal_Int16 nId
void SetSwapGraphics()
static void lcl_ReverseTwipsToMM(tools::Rectangle &rRect)
Definition: drwlayer.cxx:219
SC_DLLPUBLIC bool Move(SCCOL aDeltaX, SCROW aDeltaY, SCTAB aDeltaZ, ScRange &rErrorRange, const ScDocument *pDocument=nullptr)
Definition: address.cxx:2372
bool HasObjectsInRows(SCTAB nTab, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:1449
constexpr SdrLayerID SC_LAYER_BACK(1)
tools::Long GetWidth() const
std::vector< SdrObject * > GetObjectsAnchoredToCols(SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol)
Definition: drwlayer.cxx:2414
ScAddress aEnd
Definition: address.hxx:501
void CopyFromClip(ScDrawLayer *pClipModel, SCTAB nSourceTab, const tools::Rectangle &rSourceRange, const ScAddress &rDestPos, const tools::Rectangle &rDestRange)
Definition: drwlayer.cxx:1761
ScAddress aNewStt
Definition: drwlayer.hxx:63
static tools::Rectangle GetCellRect(const ScDocument &rDoc, const ScAddress &rPos, bool bMergedCell)
Returns the rectangle for the passed cell address in 1/100 mm.
Definition: drwlayer.cxx:1999
void RecalcPos(SdrObject *pObj, ScDrawObjData &rData, bool bNegativePage, bool bUpdateNoteCaptionPos)
Definition: drwlayer.cxx:990
void UseHyphenator()
Definition: drwlayer.cxx:351
css::uno::Reference< css::frame::XModel > GetModel() const
virtual ~ScTabDeletedHint() override
Definition: drwlayer.cxx:192
SC_DLLPUBLIC ScRange GetRange(SCTAB nTab, const tools::Rectangle &rMMRect, bool bHiddenAsZero=true) const
Definition: documen3.cxx:1781
virtual SdrObjKind GetObjIdentifier() const
void DeleteObjectsInSelection(const ScMarkData &rMark)
Definition: drwlayer.cxx:1575
virtual void InsertObject(SdrObject *pObj, size_t nPos=SAL_MAX_SIZE)
EmbeddedObjectRef * pObject
ScAddress maStart
Definition: userdat.hxx:37
void FreezeIdRanges()
void GetClipArea(SCCOL &nClipX, SCROW &nClipY, bool bIncludeFiltered)
Definition: document.cxx:3116
bool ValidColRowTab(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.hxx:875
double getMaxX() const
constexpr TypedWhichId< SvxFontHeightItem > EE_CHAR_FONTHEIGHT(EE_CHAR_START+2)
void SetRight(tools::Long v)
static sal_uInt16 IsChart(const SvGlobalName &rName)
virtual void Redo() override
Definition: drwlayer.cxx:172
void MoveArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCCOL nDx, SCROW nDy, bool bInsDel, bool bUpdateNoteCaptionPos)
Definition: drwlayer.cxx:1403
constexpr TypedWhichId< SvxFrameDirectionItem > EE_PARA_WRITINGDIR(EE_PARA_START+0)
constexpr TypedWhichId< ScMergeAttr > ATTR_MERGE(144)
SC_DLLPUBLIC sal_uInt16 GetRowHeight(SCROW nRow, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4159
virtual const tools::Rectangle & GetSnapRect() const
virtual css::uno::Reference< css::uno::XInterface > createUnoModel() override
Definition: drwlayer.cxx:2547
bool IsVisible() const
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6054
bool IsEmpty() const
SC_DLLPUBLIC ScPostIt * GetNote(const ScAddress &rPos)
Notes.
Definition: document.cxx:6501
static void SetGlobalDrawPersist(SfxObjectShell *pPersist)
Definition: drwlayer.cxx:2534
void setShapeRect(const ScDocument *rDoc, tools::Rectangle rNewRect, bool bIsVisible=true)
Definition: userdat.hxx:49
static bool lcl_IsAllInRange(const ::std::vector< ScRangeList > &rRangesVector, const ScRange &rClipRange)
Definition: drwlayer.cxx:1715
void EnableUndo(bool bEnable)
void SetChartListenerCollectionNeedsUpdate(bool bFlg)
Definition: document.hxx:2147
virtual ~ScUndoObjData() override
Definition: drwlayer.cxx:102
SC_DLLPUBLIC bool RenameTab(SCTAB nTab, const OUString &rName, bool bExternalDocument=false)
Definition: document.cxx:851
ScUndoAnchorData(SdrObject *pObj, ScDocument *pDoc, SCTAB nTab)
Definition: drwlayer.cxx:144
tools::Long Left() const
virtual SdrPage * AllocPage(bool bMasterPage) override
Definition: drwlayer.cxx:365
SdrPage * getSdrPageFromSdrObject() const
void SetLeft(tools::Long v)
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:312
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
Additional class containing cell annotation data.
Definition: postit.hxx:160
bool IsMultiMarked() const
Definition: markdata.hxx:83
int nCount
const SCROW MAXROW
Definition: address.hxx:69
tools::Long Bottom() const
bool isLocked() const
void setB2DPoint(sal_uInt32 nIndex, const basegfx::B2DPoint &rValue)
#define HMM_PER_TWIPS
Definition: global.hxx:93
SCTAB Tab() const
Definition: address.hxx:271
void SetRow(SCROW nRowP)
Definition: address.hxx:275
Point maEndOffset
Definition: userdat.hxx:40
bool mbWasInHiddenRow
Definition: userdat.hxx:43
tools::Long getX() const
double getMaxY() const
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
virtual void SetChanged(bool bFlg=true)
void SetName(const OUString &rName)
void SetCol(SCCOL nColP)
Definition: address.hxx:279
bool HasObjects() const
Definition: drwlayer.cxx:370
B2IRange fround(const B2DRange &rRange)
virtual void TakeUnrotatedSnapRect(tools::Rectangle &rRect) const override
SC_DLLPUBLIC const SfxPoolItem * GetAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: document.cxx:4712
static XColorListRef GetStdColorList()
void ScMovePage(sal_uInt16 nOldPos, sal_uInt16 nNewPos)
Definition: drwlayer.cxx:429
const LanguageTag & GetLanguageTag() const
SdrOutliner & GetHitTestOutliner() const
bool IsClipboard() const
Definition: document.hxx:1527
bool IsValid() const
Definition: address.hxx:293
virtual void DeletePage(sal_uInt16 nPgNum)
virtual void Redo() override
Definition: drwlayer.cxx:125
bool mbResizeWithCell
Definition: userdat.hxx:42
ScDocument * GetDocument() const
Definition: drwlayer.hxx:122
const SfxPoolItem * GetItem(sal_uInt16 nSlotId) const
const tools::Rectangle & getShapeRect() const
Definition: userdat.hxx:47
void SetTab(SCTAB nTabP)
Definition: address.hxx:283
bool bDrawIsInUndo
Definition: drwlayer.cxx:90
ScAnchorType
Definition: global.hxx:384
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1056
void SetPageSize(sal_uInt16 nPageNo, const Size &rSize, bool bUpdateNoteCaptionPos)
Definition: drwlayer.cxx:573
virtual void InsertPage(SdrPage *pPage, sal_uInt16 nPos=0xFFFF) override
bool bRecording
Definition: drwlayer.hxx:95
SC_DLLPUBLIC bool ColHidden(SCCOL nCol, SCTAB nTab, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: document.cxx:4443
bool GetPrintArea(ScRange &rRange, bool bSetHor, bool bSetVer) const
Definition: drwlayer.cxx:1217
SC_DLLPUBLIC void InitDrawLayer(SfxObjectShell *pDocShell=nullptr)
Definition: documen9.cxx:96
static void SetCellAnchored(SdrObject &, const ScDrawObjData &rAnchor)
Definition: drwlayer.cxx:2181
bool IsImportingXML() const
Definition: document.hxx:2134
int i
ScAddress aOldStt
Definition: drwlayer.hxx:61
void IncCol(SCCOL nDelta=1)
Definition: address.hxx:304
tools::Long FRound(double fVal)
virtual void NbcMirror(const Point &rRef1, const Point &rRef2)
ScDrawLayer(ScDocument *pDocument, const OUString &rName)
Definition: drwlayer.cxx:244
static ScAnchorType GetAnchorType(const SdrObject &)
Definition: drwlayer.cxx:2325
sal_Int16 SCCOL
Definition: types.hxx:22
static ScDrawObjData * GetNoteCaptionData(SdrObject *pObj, SCTAB nTab)
Returns the object data, if the passed object is a cell note caption.
Definition: drwlayer.cxx:2514
static void SetCellAnchoredFromPosition(SdrObject &rObj, const ScDocument &rDoc, SCTAB nTab, bool bResizeWithCell)
Definition: drwlayer.cxx:2191
#define SC_MOD()
Definition: scmod.hxx:250
virtual void AdjustToMaxRect(const tools::Rectangle &rMaxRect, bool bShrinkOnly=false)
Size GetSize() const
static ScRange lcl_getClipRangeFromClipDoc(ScDocument *pClipDoc, SCTAB nClipTab)
Definition: drwlayer.cxx:227
const SCCOL MAXCOL
Definition: address.hxx:70
static css::uno::Reference< css::linguistic2::XHyphenator > GetHyphenator()
void BroadcastObjectChange() const
virtual ~ScUndoAnchorData() override
Definition: drwlayer.cxx:153
ScDocument * pDoc
Definition: drwlayer.hxx:93
OBJ_GRAF
const SdrPage * GetPage(sal_uInt16 nPgNum) const
SdrLayer * NewLayer(const OUString &rName, sal_uInt16 nPos=0xFFFF)
static bool IsNamedObject(const SdrObject *pObj, std::u16string_view rName)
Definition: drwlayer.cxx:2056
void SetCalcFieldValueHdl(const Link< EditFieldInfo *, void > &rLink)
void IncRow(SCROW nDelta=1)
Definition: address.hxx:300
bool ScAddPage(SCTAB nTab)
Definition: drwlayer.cxx:390
static tools::Long TwipsToHmm(tools::Long nVal)
Definition: drwlayer.cxx:207
void DeleteUserData(sal_uInt16 nNum)
OUString ScResId(const char *pId)
Definition: scdll.cxx:89
void scale(double fX, double fY)
SdrModel & getSdrModelFromSdrObject() const
void MoveObject(SdrObject *pObj, const ScAddress &rNewPosition)
Definition: drwlayer.cxx:2438
void AddCalcUndo(std::unique_ptr< SdrUndoAction > pUndo)
Definition: drwlayer.cxx:1377
void SetVisible(bool bVisible)
bool IsInside(const Point &rPOINT) const
virtual void SetLogicRect(const tools::Rectangle &rRect)
OUString GetNewGraphicName(tools::Long *pnCounter=nullptr) const
Definition: drwlayer.cxx:2094
void SetTop(tools::Long v)
Point maStartOffset
Definition: userdat.hxx:39
virtual void Move(const Size &rSiz)
void SetBottom(tools::Long v)
SdrObject * pObj
SfxItemPool * GetEditTextObjectPool() const
static bool IsInBlock(const ScAddress &rPos, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: drwlayer.cxx:513
bool IsResizeProtect() const
SC_DLLPUBLIC tools::Rectangle GetMMRect(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: documen3.cxx:1971
const XColorListRef & GetColorList() const
virtual void Undo() override
Definition: drwlayer.cxx:106
virtual void SetRelativePos(const Point &rPnt)
SCROW GetRowForHeight(SCTAB nTab, sal_uLong nHeight) const
Given the height i.e.
Definition: document.cxx:4191
bool In(const ScAddress &) const
is Address& in Range?
Definition: address.hxx:733
tools::Long Top() const
virtual SdrObject * RemoveObject(size_t nObjNum)
virtual void Mirror(const Point &rRef1, const Point &rRef2)
OUString GetName() const
const long LONG_MAX
SCCOL Col() const
Definition: address.hxx:267
B2DRange getRange(const B2DPolygon &rCandidate)
void AppendUserData(std::unique_ptr< SdrObjUserData > pData)
virtual SdrLayerID GetLayer() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
SfxItemPool * GetSecondaryPool() const
SdrObject * GetNamedObject(std::u16string_view rName, sal_uInt16 nId, SCTAB &rFoundTab) const
Definition: drwlayer.cxx:2066
SfxItemPool * m_pItemPool
void MoveCells(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCCOL nDx, SCROW nDy, bool bUpdateNoteCaptionPos)
Definition: drwlayer.cxx:519
void setLock(bool bLock)
SdrObject * Next()
bool bHyphenatorSet
Definition: drwlayer.hxx:97
sal_Int32 SCROW
Definition: types.hxx:18
virtual void Undo() override
Definition: drwlayer.cxx:157
double getMinY() const
void SetDefaultMetric(MapUnit eNewMetric)
constexpr SdrLayerID SC_LAYER_HIDDEN(4)
void ScRenamePage(SCTAB nTab, const OUString &rNewName)
Definition: drwlayer.cxx:422
std::unique_ptr< SdrUndoGroup > GetCalcUndo()
Definition: drwlayer.cxx:1395
constexpr TypedWhichId< SvxFontHeightItem > EE_CHAR_FONTHEIGHT_CTL(EE_CHAR_START+20)
unsigned char sal_uInt8
virtual void NbcSetLogicRect(const tools::Rectangle &rRect)
SdrMetricItem makeSdrShadowXDistItem(tools::Long nDist)
void setWidth(tools::Long n)
sal_uInt16 GetId() const
static ScDrawObjData * GetObjDataTab(SdrObject *pObj, SCTAB nTab)
Definition: drwlayer.cxx:2495
OBJ_MEASURE
#define MAXMM
Definition: drwlayer.cxx:205
void SetObjectShell(SfxObjectShell *pShell)
virtual void NbcMove(const Size &rSiz)
constexpr SdrLayerID SC_LAYER_FRONT(0)
static ScDrawObjData * GetNonRotatedObjData(SdrObject *pObj, bool bCreate=false)
Definition: drwlayer.cxx:2462
OUString aName
SdrObjUserData * GetUserData(sal_uInt16 nNum) const
#define SC_UD_MACRODATA
Definition: userdat.hxx:30
constexpr SdrLayerID SC_LAYER_INTERN(2)
static void MirrorRectRTL(tools::Rectangle &rRect)
Definition: drwlayer.cxx:1991
static void UpdateCellAnchorFromPositionEnd(const SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect=true)
Definition: drwlayer.cxx:2284
virtual SdrObject * CloneSdrObject(SdrModel &rTargetModel) const
static OUString GetVisibleName(const SdrObject *pObj)
Definition: drwlayer.cxx:2040
std::unique_ptr< SdrUndoGroup > pUndoGroup
Definition: drwlayer.hxx:94
virtual SdrPage * RemovePage(sal_uInt16 nPgNum) override
void InitializeCellAnchoredObj(SdrObject *pObj, ScDrawObjData &rData)
Definition: drwlayer.cxx:873
static bool isKorean(LanguageType nLang)
SC_DLLPUBLIC void GetChartRanges(std::u16string_view rChartName, std::vector< ScRangeList > &rRanges, const ScDocument &rSheetNameDoc)
Definition: documen5.cxx:167
OUString aName
Definition: drwlayer.hxx:92
sal_uInt16 GetUserDataCount() const
void translate(double fX, double fY)
virtual ~ScTabSizeChangedHint() override
Definition: drwlayer.cxx:201
ScAddress aNewEnd
Definition: drwlayer.hxx:64
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4427
virtual void MovePage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
OBJ_CUSTOMSHAPE
void SetControlLayerName(const OUString &rNewName)
SC_DLLPUBLIC ScColumnsRange GetColumnsRange(SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const
Definition: document.cxx:2519
#define SC_UD_OBJDATA
Definition: userdat.hxx:28
bool HasObjectsAnchoredInRange(const ScRange &rRange)
Definition: drwlayer.cxx:2390
tools::Long GetHeight() const
bool mbWasResizeWithCell
Definition: drwlayer.hxx:78
virtual void SetSnapRect(const tools::Rectangle &rRect)
virtual bool shouldKeepAspectRatio() const
static bool IsNoteCaption(SdrObject *pObj)
Returns true, if the passed object is the caption of a cell note.
Definition: drwlayer.cxx:2508
double ConvertDoubleValue(double nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, FieldUnit eInUnit, FieldUnit eOutUnit)
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1055
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
ScAddress aOldEnd
Definition: drwlayer.hxx:62
bool IsUndoEnabled() const
Definition: document.hxx:1528
constexpr TypedWhichId< SvxFontHeightItem > EE_CHAR_FONTHEIGHT_CJK(EE_CHAR_START+19)
const SfxItemPool & GetItemPool() const
double getMinX() const
SCROW GetRowMerge() const
Definition: attrib.hxx:70
void SetScaleUnit(MapUnit eMap)
void GetMultiMarkArea(ScRange &rRange) const
Definition: markdata.cxx:117
virtual const tools::Rectangle & GetLogicRect() const
void ScCopyPage(sal_uInt16 nOldPos, sal_uInt16 nNewPos)
Definition: drwlayer.cxx:436
ScTabDeletedHint(SCTAB nTabNo)
Definition: drwlayer.cxx:187
static E3dObjFactory * pF3d
Definition: drwlayer.cxx:85
void SetDisableTextEditUsesCommonUndoManager(bool bNew)
static sal_uInt16 nInst
Definition: drwlayer.cxx:86
const SdrLayerAdmin & GetLayerAdmin() const
SC_DLLPUBLIC sal_uInt16 GetColWidth(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4118
void SetChartRanges(std::u16string_view rChartName, const std::vector< ScRangeList > &rRanges)
Definition: documen5.cxx:184
ScAddress maEnd
Definition: userdat.hxx:38
SdrInventor GetInventor() const
static tools::Long HmmToTwips(tools::Long nVal)
Definition: drwlayer.cxx:213
void SetPropertyList(XPropertyListRef const &p)
virtual Point GetPoint(sal_uInt32 i) const
OBJ_OLE2
#define LANGUAGE_JAPANESE
void ClearModel(bool bCalledFromDestructor)
void ScRemovePage(SCTAB nTab)
Definition: drwlayer.cxx:404
constexpr SdrLayerID SC_LAYER_CONTROLS(3)
const tools::Rectangle & getLastCellRect() const
Definition: userdat.hxx:48
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:211
ScTabSizeChangedHint(SCTAB nTabNo)
Definition: drwlayer.cxx:196
tools::Long Right() const
SC_DLLPUBLIC sal_uLong GetColOffset(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4222
static bool IsResizeWithCell(const SdrObject &rObj)
Definition: drwlayer.cxx:2308
ScDocument * mpDoc
Definition: drwlayer.hxx:79
sal_uInt16 GetPageCount() const
void setHeight(tools::Long n)
sal_Int16 SCTAB
Definition: types.hxx:23
SC_DLLPUBLIC sal_uLong GetRowOffset(SCROW nRow, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4230
void SetPoolDefaultItem(const SfxPoolItem &)
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
void CopyToClip(ScDocument *pClipDoc, SCTAB nTab, const tools::Rectangle &rRange)
Definition: drwlayer.cxx:1652
virtual SdrModel * AllocModel() const override
Definition: drwlayer.cxx:382