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