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