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