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