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