nss: upgrade to release 3.73
[LibreOffice.git] / svx / source / svdraw / svdobj.cxx
blob5480ac1d86ce7dfc9dc07ec1b4c8fd40fe28bbd7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svx/svdobj.hxx>
21 #include <config_features.h>
23 #include <sal/config.h>
24 #include <sal/log.hxx>
25 #include <rtl/ustrbuf.hxx>
27 #include <com/sun/star/lang/XComponent.hpp>
28 #include <com/sun/star/text/RelOrientation.hpp>
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 #include <basegfx/matrix/b2dhommatrixtools.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
34 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
35 #include <basegfx/polygon/b2dpolypolygontools.hxx>
36 #include <basegfx/range/b2drange.hxx>
37 #include <drawinglayer/processor2d/contourextractor2d.hxx>
38 #include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
39 #include <editeng/editeng.hxx>
40 #include <editeng/outlobj.hxx>
41 #include <o3tl/deleter.hxx>
42 #include <math.h>
43 #include <svl/grabbagitem.hxx>
44 #include <tools/bigint.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <tools/helpers.hxx>
47 #include <unotools/configmgr.hxx>
48 #include <vcl/canvastools.hxx>
49 #include <vcl/ptrstyle.hxx>
50 #include <vector>
52 #include <svx/shapepropertynotifier.hxx>
53 #include <svx/svdotable.hxx>
55 #include <svx/sdr/contact/displayinfo.hxx>
56 #include <sdr/contact/objectcontactofobjlistpainter.hxx>
57 #include <svx/sdr/contact/viewcontactofsdrobj.hxx>
58 #include <sdr/properties/emptyproperties.hxx>
59 #include <svx/sdrhittesthelper.hxx>
60 #include <svx/sdrobjectuser.hxx>
61 #include <svx/sdrobjectfilter.hxx>
62 #include <svx/svddrag.hxx>
63 #include <svx/svdetc.hxx>
64 #include <svx/svdhdl.hxx>
65 #include <svx/svditer.hxx>
66 #include <svx/svdmodel.hxx>
67 #include <svx/svdoashp.hxx>
68 #include <svx/svdocapt.hxx>
69 #include <svx/svdocirc.hxx>
70 #include <svx/svdoedge.hxx>
71 #include <svx/svdograf.hxx>
72 #include <svx/svdogrp.hxx>
73 #include <svx/svdomeas.hxx>
74 #include <svx/svdomedia.hxx>
75 #include <svx/svdoole2.hxx>
76 #include <svx/svdopage.hxx>
77 #include <svx/svdopath.hxx>
78 #include <svx/svdorect.hxx>
79 #include <svx/svdotext.hxx>
80 #include <svx/svdouno.hxx>
81 #include <svx/svdovirt.hxx>
82 #include <svx/svdpage.hxx>
83 #include <svx/svdpool.hxx>
84 #include <svx/strings.hrc>
85 #include <svx/dialmgr.hxx>
86 #include <svx/svdtrans.hxx>
87 #include <svx/svdundo.hxx>
88 #include <svx/svdview.hxx>
89 #include <sxlayitm.hxx>
90 #include <sxlogitm.hxx>
91 #include <sxmovitm.hxx>
92 #include <sxoneitm.hxx>
93 #include <sxopitm.hxx>
94 #include <sxreoitm.hxx>
95 #include <sxrooitm.hxx>
96 #include <sxsaitm.hxx>
97 #include <sxsoitm.hxx>
98 #include <sxtraitm.hxx>
99 #include <svx/unopage.hxx>
100 #include <svx/unoshape.hxx>
101 #include <svx/xfillit0.hxx>
102 #include <svx/xflclit.hxx>
103 #include <svx/xfltrit.hxx>
104 #include <svx/xlineit0.hxx>
105 #include <svx/xlnclit.hxx>
106 #include <svx/xlnedwit.hxx>
107 #include <svx/xlnstwit.hxx>
108 #include <svx/xlntrit.hxx>
109 #include <svx/xlnwtit.hxx>
110 #include <svx/svdglue.hxx>
111 #include <svx/svdsob.hxx>
112 #include <svdobjplusdata.hxx>
113 #include <svdobjuserdatalist.hxx>
115 #include <unordered_set>
117 #include <optional>
118 #include <libxml/xmlwriter.h>
119 #include <memory>
121 using namespace ::com::sun::star;
124 SdrObjUserCall::~SdrObjUserCall()
128 void SdrObjUserCall::Changed(const SdrObject& /*rObj*/, SdrUserCallType /*eType*/, const tools::Rectangle& /*rOldBoundRect*/)
132 SdrObjMacroHitRec::SdrObjMacroHitRec() :
133 pVisiLayer(nullptr),
134 pPageView(nullptr),
135 nTol(0) {}
138 SdrObjUserData::SdrObjUserData(SdrInventor nInv, sal_uInt16 nId) :
139 nInventor(nInv),
140 nIdentifier(nId) {}
142 SdrObjUserData::SdrObjUserData(const SdrObjUserData& rData) :
143 nInventor(rData.nInventor),
144 nIdentifier(rData.nIdentifier) {}
146 SdrObjUserData::~SdrObjUserData() {}
148 SdrObjGeoData::SdrObjGeoData():
149 bMovProt(false),
150 bSizProt(false),
151 bNoPrint(false),
152 bClosedObj(false),
153 mbVisible(true),
154 mnLayerID(0)
158 SdrObjGeoData::~SdrObjGeoData()
162 SdrObjTransformInfoRec::SdrObjTransformInfoRec() :
163 bMoveAllowed(true),
164 bResizeFreeAllowed(true),
165 bResizePropAllowed(true),
166 bRotateFreeAllowed(true),
167 bRotate90Allowed(true),
168 bMirrorFreeAllowed(true),
169 bMirror45Allowed(true),
170 bMirror90Allowed(true),
171 bTransparenceAllowed(true),
172 bShearAllowed(true),
173 bEdgeRadiusAllowed(true),
174 bNoOrthoDesired(true),
175 bNoContortion(true),
176 bCanConvToPath(true),
177 bCanConvToPoly(true),
178 bCanConvToContour(false),
179 bCanConvToPathLineToArea(true),
180 bCanConvToPolyLineToArea(true) {}
182 struct SdrObject::Impl
184 sdr::ObjectUserVector maObjectUsers;
185 std::shared_ptr<DiagramDataInterface> mpDiagramData;
186 std::optional<double> mnRelativeWidth;
187 std::optional<double> mnRelativeHeight;
188 sal_Int16 meRelativeWidthRelation;
189 sal_Int16 meRelativeHeightRelation;
191 Impl() :
192 meRelativeWidthRelation(text::RelOrientation::PAGE_FRAME),
193 meRelativeHeightRelation(text::RelOrientation::PAGE_FRAME) {}
197 // BaseProperties section
199 std::unique_ptr<sdr::properties::BaseProperties> SdrObject::CreateObjectSpecificProperties()
201 return std::make_unique<sdr::properties::EmptyProperties>(*this);
204 sdr::properties::BaseProperties& SdrObject::GetProperties() const
206 if(!mpProperties)
208 // CAUTION(!) Do *not* call this during SdrObject construction,
209 // that will lead to wrong type-casts (dependent on constructor-level)
210 // and thus eventually create the wrong sdr::properties (!). Is there
211 // a way to check if on the stack is a SdrObject-constructor (?)
212 const_cast< SdrObject* >(this)->mpProperties =
213 const_cast< SdrObject* >(this)->CreateObjectSpecificProperties();
216 return *mpProperties;
220 // ObjectUser section
222 void SdrObject::AddObjectUser(sdr::ObjectUser& rNewUser)
224 mpImpl->maObjectUsers.push_back(&rNewUser);
227 void SdrObject::RemoveObjectUser(sdr::ObjectUser& rOldUser)
229 const sdr::ObjectUserVector::iterator aFindResult =
230 std::find(mpImpl->maObjectUsers.begin(), mpImpl->maObjectUsers.end(), &rOldUser);
231 if (aFindResult != mpImpl->maObjectUsers.end())
233 mpImpl->maObjectUsers.erase(aFindResult);
238 // DrawContact section
240 std::unique_ptr<sdr::contact::ViewContact> SdrObject::CreateObjectSpecificViewContact()
242 return std::make_unique<sdr::contact::ViewContactOfSdrObj>(*this);
245 sdr::contact::ViewContact& SdrObject::GetViewContact() const
247 if(!mpViewContact)
249 const_cast< SdrObject* >(this)->mpViewContact =
250 const_cast< SdrObject* >(this)->CreateObjectSpecificViewContact();
253 return *mpViewContact;
256 // DrawContact support: Methods for handling Object changes
257 void SdrObject::ActionChanged() const
259 // Do necessary ViewContact actions
260 GetViewContact().ActionChanged();
263 SdrPage* SdrObject::getSdrPageFromSdrObject() const
265 if(getParentSdrObjListFromSdrObject())
267 return getParentSdrObjListFromSdrObject()->getSdrPageFromSdrObjList();
270 return nullptr;
273 SdrModel& SdrObject::getSdrModelFromSdrObject() const
275 return mrSdrModelFromSdrObject;
278 void SdrObject::setParentOfSdrObject(SdrObjList* pNewObjList)
280 if(getParentSdrObjListFromSdrObject() == pNewObjList)
281 return;
283 // remember current page
284 SdrPage* pOldPage(getSdrPageFromSdrObject());
286 // set new parent
287 mpParentOfSdrObject = pNewObjList;
289 // get new page
290 SdrPage* pNewPage(getSdrPageFromSdrObject());
292 // broadcast page change over objects if needed
293 if(pOldPage != pNewPage)
295 handlePageChange(pOldPage, pNewPage);
299 SdrObjList* SdrObject::getParentSdrObjListFromSdrObject() const
301 return mpParentOfSdrObject;
304 SdrObjList* SdrObject::getChildrenOfSdrObject() const
306 // default has no children
307 return nullptr;
310 void SdrObject::SetBoundRectDirty()
312 aOutRect = tools::Rectangle();
315 #ifdef DBG_UTIL
316 // SdrObjectLifetimeWatchDog:
317 void impAddIncarnatedSdrObjectToSdrModel(const SdrObject& rSdrObject, SdrModel& rSdrModel)
319 rSdrModel.maAllIncarnatedObjects.insert(&rSdrObject);
321 void impRemoveIncarnatedSdrObjectToSdrModel(const SdrObject& rSdrObject, SdrModel& rSdrModel)
323 if(!rSdrModel.maAllIncarnatedObjects.erase(&rSdrObject))
325 SAL_WARN("svx","SdrObject::~SdrObject: Destructed incarnation of SdrObject not member of this SdrModel (!)");
328 #endif
330 SdrObject::SdrObject(SdrModel& rSdrModel)
331 : mpFillGeometryDefiningShape(nullptr)
332 ,mrSdrModelFromSdrObject(rSdrModel)
333 ,pUserCall(nullptr)
334 ,mpImpl(new Impl)
335 ,mpParentOfSdrObject(nullptr)
336 ,nOrdNum(0)
337 ,mnNavigationPosition(SAL_MAX_UINT32)
338 ,mnLayerID(0)
339 ,mpSvxShape( nullptr )
340 ,maWeakUnoShape()
341 ,mbDoNotInsertIntoPageAutomatically(false)
343 bVirtObj =false;
344 bSnapRectDirty =true;
345 bMovProt =false;
346 bSizProt =false;
347 bNoPrint =false;
348 bEmptyPresObj =false;
349 bNotVisibleAsMaster=false;
350 bClosedObj =false;
351 mbVisible = true;
353 // #i25616#
354 mbLineIsOutsideGeometry = false;
356 // #i25616#
357 mbSupportTextIndentingOnLineWidthChange = false;
359 bIsEdge=false;
360 bIs3DObj=false;
361 bMarkProt=false;
362 bIsUnoObj=false;
363 #ifdef DBG_UTIL
364 // SdrObjectLifetimeWatchDog:
365 impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
366 #endif
369 SdrObject::~SdrObject()
371 // Tell all the registered ObjectUsers that the page is in destruction.
372 // And clear the vector. This means that user do not need to call RemoveObjectUser()
373 // when they get called from ObjectInDestruction().
374 sdr::ObjectUserVector aList;
375 aList.swap(mpImpl->maObjectUsers);
376 for(sdr::ObjectUser* pObjectUser : aList)
378 DBG_ASSERT(pObjectUser, "SdrObject::~SdrObject: corrupt ObjectUser list (!)");
379 pObjectUser->ObjectInDestruction(*this);
382 // UserCall
383 SendUserCall(SdrUserCallType::Delete, GetLastBoundRect());
384 o3tl::reset_preserve_ptr_during(pPlusData);
386 pGrabBagItem.reset();
387 mpProperties.reset();
388 mpViewContact.reset();
390 #ifdef DBG_UTIL
391 // SdrObjectLifetimeWatchDog:
392 impRemoveIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
393 #endif
396 void SdrObject::Free( SdrObject*& _rpObject )
398 SdrObject* pObject = _rpObject; _rpObject = nullptr;
400 if(nullptr == pObject)
402 // nothing to do
403 return;
406 SvxShape* pShape(pObject->getSvxShape());
408 if(pShape)
410 if(pShape->HasSdrObjectOwnership())
412 // only the SvxShape is allowed to delete me, and will reset
413 // the ownership before doing so
414 return;
416 else
418 // not only delete pObject, but also need to dispose uno shape
421 pShape->InvalidateSdrObject();
422 uno::Reference< lang::XComponent > xShapeComp( pObject->getWeakUnoShape(), uno::UNO_QUERY_THROW );
423 xShapeComp->dispose();
425 catch( const uno::Exception& )
427 DBG_UNHANDLED_EXCEPTION("svx");
432 delete pObject;
435 void SdrObject::SetRectsDirty(bool bNotMyself, bool bRecursive)
437 if (!bNotMyself)
439 SetBoundRectDirty();
440 bSnapRectDirty=true;
443 if (bRecursive && nullptr != getParentSdrObjListFromSdrObject())
445 getParentSdrObjListFromSdrObject()->SetSdrObjListRectsDirty();
449 void SdrObject::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
451 // The creation of the UNO shape in SdrObject::getUnoShape is influenced
452 // by pPage, so when the page changes we need to discard the cached UNO
453 // shape so that a new one will be created.
454 // If the page is changing to another page with the same model, we
455 // assume they create compatible UNO shape objects so we shouldn't have
456 // to invalidate.
457 // TTTT: This causes quite some problems in SvxDrawPage::add when used
458 // e.g. from Writer - the SdrObject may be cloned to target model, and
459 // the xShape was added to it by purpose (see there). Thus it will be
460 // good to think about if this is really needed - it *seems* to be intended
461 // for a xShape being a on-demand-creatable resource - with the argument that
462 // the SdrPage/UnoPage used influences the SvxShape creation. This uses
463 // resources and would be nice to get rid of anyways.
464 if(nullptr == pOldPage || nullptr == pNewPage)
466 SvxShape* const pShape(getSvxShape());
468 if (pShape && !pShape->HasSdrObjectOwnership())
470 setUnoShape(nullptr);
475 // init global static itempool
476 SdrItemPool* SdrObject::mpGlobalItemPool = nullptr;
478 SdrItemPool& SdrObject::GetGlobalDrawObjectItemPool()
480 if(!mpGlobalItemPool)
482 mpGlobalItemPool = new SdrItemPool();
483 SfxItemPool* pGlobalOutlPool = EditEngine::CreatePool();
484 mpGlobalItemPool->SetSecondaryPool(pGlobalOutlPool);
485 mpGlobalItemPool->SetDefaultMetric(SdrEngineDefaults::GetMapUnit());
486 mpGlobalItemPool->FreezeIdRanges();
489 return *mpGlobalItemPool;
492 void SdrObject::SetRelativeWidth( double nValue )
494 mpImpl->mnRelativeWidth = nValue;
497 void SdrObject::SetRelativeWidthRelation( sal_Int16 eValue )
499 mpImpl->meRelativeWidthRelation = eValue;
502 void SdrObject::SetRelativeHeight( double nValue )
504 mpImpl->mnRelativeHeight = nValue;
507 void SdrObject::SetRelativeHeightRelation( sal_Int16 eValue )
509 mpImpl->meRelativeHeightRelation = eValue;
512 const double* SdrObject::GetRelativeWidth( ) const
514 if (!mpImpl->mnRelativeWidth)
515 return nullptr;
517 return &*mpImpl->mnRelativeWidth;
520 sal_Int16 SdrObject::GetRelativeWidthRelation() const
522 return mpImpl->meRelativeWidthRelation;
525 const double* SdrObject::GetRelativeHeight( ) const
527 if (!mpImpl->mnRelativeHeight)
528 return nullptr;
530 return &*mpImpl->mnRelativeHeight;
533 sal_Int16 SdrObject::GetRelativeHeightRelation() const
535 return mpImpl->meRelativeHeightRelation;
538 void SdrObject::SetDiagramData(std::shared_ptr<DiagramDataInterface> pDiagramData)
540 mpImpl->mpDiagramData = pDiagramData;
543 std::shared_ptr<DiagramDataInterface> SdrObject::GetDiagramData() const
545 return mpImpl->mpDiagramData;
548 SfxItemPool& SdrObject::GetObjectItemPool() const
550 return getSdrModelFromSdrObject().GetItemPool();
553 SdrInventor SdrObject::GetObjInventor() const
555 return SdrInventor::Default;
558 SdrObjKind SdrObject::GetObjIdentifier() const
560 return OBJ_NONE;
563 void SdrObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
565 rInfo.bRotateFreeAllowed=false;
566 rInfo.bMirrorFreeAllowed=false;
567 rInfo.bTransparenceAllowed = false;
568 rInfo.bShearAllowed =false;
569 rInfo.bEdgeRadiusAllowed=false;
570 rInfo.bCanConvToPath =false;
571 rInfo.bCanConvToPoly =false;
572 rInfo.bCanConvToContour = false;
573 rInfo.bCanConvToPathLineToArea=false;
574 rInfo.bCanConvToPolyLineToArea=false;
577 SdrLayerID SdrObject::GetLayer() const
579 return mnLayerID;
582 void SdrObject::getMergedHierarchySdrLayerIDSet(SdrLayerIDSet& rSet) const
584 rSet.Set(GetLayer());
585 SdrObjList* pOL=GetSubList();
586 if (pOL!=nullptr) {
587 const size_t nObjCount = pOL->GetObjCount();
588 for (size_t nObjNum = 0; nObjNum<nObjCount; ++nObjNum) {
589 pOL->GetObj(nObjNum)->getMergedHierarchySdrLayerIDSet(rSet);
594 void SdrObject::NbcSetLayer(SdrLayerID nLayer)
596 mnLayerID = nLayer;
599 void SdrObject::SetLayer(SdrLayerID nLayer)
601 NbcSetLayer(nLayer);
602 SetChanged();
603 BroadcastObjectChange();
606 void SdrObject::AddListener(SfxListener& rListener)
608 ImpForcePlusData();
609 if (pPlusData->pBroadcast==nullptr) pPlusData->pBroadcast.reset(new SfxBroadcaster);
611 // SdrEdgeObj may be connected to same SdrObject on both ends so allow it
612 // to listen twice
613 SdrEdgeObj const*const pEdge(dynamic_cast<SdrEdgeObj const*>(&rListener));
614 rListener.StartListening(*pPlusData->pBroadcast, pEdge ? DuplicateHandling::Allow : DuplicateHandling::Unexpected);
617 void SdrObject::RemoveListener(SfxListener& rListener)
619 if (pPlusData!=nullptr && pPlusData->pBroadcast!=nullptr) {
620 rListener.EndListening(*pPlusData->pBroadcast);
621 if (!pPlusData->pBroadcast->HasListeners()) {
622 pPlusData->pBroadcast.reset();
627 const SfxBroadcaster* SdrObject::GetBroadcaster() const
629 return pPlusData!=nullptr ? pPlusData->pBroadcast.get() : nullptr;
632 void SdrObject::AddReference(SdrVirtObj& rVrtObj)
634 AddListener(rVrtObj);
637 void SdrObject::DelReference(SdrVirtObj& rVrtObj)
639 RemoveListener(rVrtObj);
642 bool SdrObject::IsGroupObject() const
644 return GetSubList()!=nullptr;
647 SdrObjList* SdrObject::GetSubList() const
649 return nullptr;
652 SdrObject* SdrObject::getParentSdrObjectFromSdrObject() const
654 SdrObjList* pParent(getParentSdrObjListFromSdrObject());
656 if(nullptr == pParent)
658 return nullptr;
661 return pParent->getSdrObjectFromSdrObjList();
664 void SdrObject::SetName(const OUString& rStr)
666 if (!rStr.isEmpty() && !pPlusData)
668 ImpForcePlusData();
671 if(!(pPlusData && pPlusData->aObjName != rStr))
672 return;
674 // Undo/Redo for setting object's name (#i73249#)
675 bool bUndo( false );
676 if ( getSdrModelFromSdrObject().IsUndoEnabled() )
678 bUndo = true;
679 std::unique_ptr<SdrUndoAction> pUndoAction =
680 SdrUndoFactory::CreateUndoObjectStrAttr(
681 *this,
682 SdrUndoObjStrAttr::ObjStrAttrType::Name,
683 GetName(),
684 rStr );
685 getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
686 getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
688 pPlusData->aObjName = rStr;
689 // Undo/Redo for setting object's name (#i73249#)
690 if ( bUndo )
692 getSdrModelFromSdrObject().EndUndo();
694 SetChanged();
695 BroadcastObjectChange();
698 OUString SdrObject::GetName() const
700 if(pPlusData)
702 return pPlusData->aObjName;
705 return OUString();
708 void SdrObject::SetTitle(const OUString& rStr)
710 if (!rStr.isEmpty() && !pPlusData)
712 ImpForcePlusData();
715 if(!(pPlusData && pPlusData->aObjTitle != rStr))
716 return;
718 // Undo/Redo for setting object's title (#i73249#)
719 bool bUndo( false );
720 if ( getSdrModelFromSdrObject().IsUndoEnabled() )
722 bUndo = true;
723 std::unique_ptr<SdrUndoAction> pUndoAction =
724 SdrUndoFactory::CreateUndoObjectStrAttr(
725 *this,
726 SdrUndoObjStrAttr::ObjStrAttrType::Title,
727 GetTitle(),
728 rStr );
729 getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
730 getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
732 pPlusData->aObjTitle = rStr;
733 // Undo/Redo for setting object's title (#i73249#)
734 if ( bUndo )
736 getSdrModelFromSdrObject().EndUndo();
738 SetChanged();
739 BroadcastObjectChange();
742 OUString SdrObject::GetTitle() const
744 if(pPlusData)
746 return pPlusData->aObjTitle;
749 return OUString();
752 void SdrObject::SetDescription(const OUString& rStr)
754 if (!rStr.isEmpty() && !pPlusData)
756 ImpForcePlusData();
759 if(!(pPlusData && pPlusData->aObjDescription != rStr))
760 return;
762 // Undo/Redo for setting object's description (#i73249#)
763 bool bUndo( false );
764 if ( getSdrModelFromSdrObject().IsUndoEnabled() )
766 bUndo = true;
767 std::unique_ptr<SdrUndoAction> pUndoAction =
768 SdrUndoFactory::CreateUndoObjectStrAttr(
769 *this,
770 SdrUndoObjStrAttr::ObjStrAttrType::Description,
771 GetDescription(),
772 rStr );
773 getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
774 getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
776 pPlusData->aObjDescription = rStr;
777 // Undo/Redo for setting object's description (#i73249#)
778 if ( bUndo )
780 getSdrModelFromSdrObject().EndUndo();
782 SetChanged();
783 BroadcastObjectChange();
786 OUString SdrObject::GetDescription() const
788 if(pPlusData)
790 return pPlusData->aObjDescription;
793 return OUString();
796 sal_uInt32 SdrObject::GetOrdNum() const
798 if (nullptr != getParentSdrObjListFromSdrObject())
800 if (getParentSdrObjListFromSdrObject()->IsObjOrdNumsDirty())
802 getParentSdrObjListFromSdrObject()->RecalcObjOrdNums();
804 } else const_cast<SdrObject*>(this)->nOrdNum=0;
805 return nOrdNum;
809 void SdrObject::SetOrdNum(sal_uInt32 nNum)
811 nOrdNum = nNum;
814 void SdrObject::GetGrabBagItem(css::uno::Any& rVal) const
816 if (pGrabBagItem != nullptr)
817 pGrabBagItem->QueryValue(rVal);
818 else
819 rVal <<= uno::Sequence<beans::PropertyValue>();
822 void SdrObject::SetGrabBagItem(const css::uno::Any& rVal)
824 if (pGrabBagItem == nullptr)
825 pGrabBagItem.reset(new SfxGrabBagItem);
827 pGrabBagItem->PutValue(rVal, 0);
829 SetChanged();
830 BroadcastObjectChange();
833 sal_uInt32 SdrObject::GetNavigationPosition() const
835 if (nullptr != getParentSdrObjListFromSdrObject() && getParentSdrObjListFromSdrObject()->RecalcNavigationPositions())
837 return mnNavigationPosition;
839 else
840 return GetOrdNum();
844 void SdrObject::SetNavigationPosition (const sal_uInt32 nNewPosition)
846 mnNavigationPosition = nNewPosition;
850 // To make clearer that this method may trigger RecalcBoundRect and thus may be
851 // expensive and sometimes problematic (inside a bigger object change you will get
852 // non-useful BoundRects sometimes) I rename that method from GetBoundRect() to
853 // GetCurrentBoundRect().
854 const tools::Rectangle& SdrObject::GetCurrentBoundRect() const
856 if(aOutRect.IsEmpty())
858 const_cast< SdrObject* >(this)->RecalcBoundRect();
861 return aOutRect;
864 // To have a possibility to get the last calculated BoundRect e.g for producing
865 // the first rectangle for repaints (old and new need to be used) without forcing
866 // a RecalcBoundRect (which may be problematical and expensive sometimes) I add here
867 // a new method for accessing the last BoundRect.
868 const tools::Rectangle& SdrObject::GetLastBoundRect() const
870 return aOutRect;
873 void SdrObject::RecalcBoundRect()
875 // #i101680# suppress BoundRect calculations on import(s)
876 if ((getSdrModelFromSdrObject().isLocked()) || utl::ConfigManager::IsFuzzing())
877 return;
879 // central new method which will calculate the BoundRect using primitive geometry
880 if(!aOutRect.IsEmpty())
881 return;
883 // Use view-independent data - we do not want any connections
884 // to e.g. GridOffset in SdrObject-level
885 const drawinglayer::primitive2d::Primitive2DContainer& xPrimitives(GetViewContact().getViewIndependentPrimitive2DContainer());
887 if(xPrimitives.empty())
888 return;
890 // use neutral ViewInformation and get the range of the primitives
891 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
892 const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
894 if(!aRange.isEmpty())
896 aOutRect = tools::Rectangle(
897 static_cast<tools::Long>(floor(aRange.getMinX())),
898 static_cast<tools::Long>(floor(aRange.getMinY())),
899 static_cast<tools::Long>(ceil(aRange.getMaxX())),
900 static_cast<tools::Long>(ceil(aRange.getMaxY())));
901 return;
905 void SdrObject::BroadcastObjectChange() const
907 if ((getSdrModelFromSdrObject().isLocked()) || utl::ConfigManager::IsFuzzing())
908 return;
910 bool bPlusDataBroadcast(pPlusData && pPlusData->pBroadcast);
911 bool bObjectChange(IsInserted());
913 if(!(bPlusDataBroadcast || bObjectChange))
914 return;
916 SdrHint aHint(SdrHintKind::ObjectChange, *this);
918 if(bPlusDataBroadcast)
920 pPlusData->pBroadcast->Broadcast(aHint);
923 if(bObjectChange)
925 getSdrModelFromSdrObject().Broadcast(aHint);
929 void SdrObject::SetChanged()
931 // For testing purposes, use the new ViewContact for change
932 // notification now.
933 ActionChanged();
935 // TTTT Need to check meaning/usage of IsInserted in one
936 // of the next changes. It should not mean to have a SdrModel
937 // set (this is guaranteed now), but should be connected to
938 // being added to a SdrPage (?)
939 // TTTT tdf#120066 Indeed - This triggers e.g. by CustomShape
940 // geometry-presenting SdrObjects that are in a SdrObjGroup,
941 // but the SdrObjGroup is *by purpose* not inserted.
942 // Need to check deeper and maybe identify all ::IsInserted()
943 // calls by rename and let the compiler work...
944 if(nullptr != getSdrPageFromSdrObject())
946 getSdrModelFromSdrObject().SetChanged();
950 // tooling for painting a single object to an OutputDevice.
951 void SdrObject::SingleObjectPainter(OutputDevice& rOut) const
953 sdr::contact::SdrObjectVector aObjectVector;
954 aObjectVector.push_back(const_cast< SdrObject* >(this));
956 sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, aObjectVector, getSdrPageFromSdrObject());
957 sdr::contact::DisplayInfo aDisplayInfo;
959 aPainter.ProcessDisplay(aDisplayInfo);
962 bool SdrObject::LineGeometryUsageIsNecessary() const
964 drawing::LineStyle eXLS = GetMergedItem(XATTR_LINESTYLE).GetValue();
965 return (eXLS != drawing::LineStyle_NONE);
968 bool SdrObject::HasLimitedRotation() const
970 // RotGrfFlyFrame: Default is false, support full rotation
971 return false;
974 SdrObject* SdrObject::CloneSdrObject(SdrModel& rTargetModel) const
976 return CloneHelper< SdrObject >(rTargetModel);
979 SdrObject& SdrObject::operator=(const SdrObject& rObj)
981 if( this == &rObj )
982 return *this;
984 mpProperties.reset();
985 mpViewContact.reset();
987 // The CloneSdrObject() method uses the local copy constructor from the individual
988 // sdr::properties::BaseProperties class. Since the target class maybe for another
989 // draw object, an SdrObject needs to be provided, as in the normal constructor.
990 mpProperties = rObj.GetProperties().Clone(*this);
992 aOutRect=rObj.aOutRect;
993 mnLayerID = rObj.mnLayerID;
994 aAnchor =rObj.aAnchor;
995 bVirtObj=rObj.bVirtObj;
996 bSizProt=rObj.bSizProt;
997 bMovProt=rObj.bMovProt;
998 bNoPrint=rObj.bNoPrint;
999 mbVisible=rObj.mbVisible;
1000 bMarkProt=rObj.bMarkProt;
1001 bEmptyPresObj =rObj.bEmptyPresObj;
1002 bNotVisibleAsMaster=rObj.bNotVisibleAsMaster;
1003 bSnapRectDirty=true;
1004 pPlusData.reset();
1005 if (rObj.pPlusData!=nullptr) {
1006 pPlusData.reset(rObj.pPlusData->Clone(this));
1008 if (pPlusData!=nullptr && pPlusData->pBroadcast!=nullptr) {
1009 pPlusData->pBroadcast.reset(); // broadcaster isn't copied
1012 pGrabBagItem.reset();
1013 if (rObj.pGrabBagItem!=nullptr)
1014 pGrabBagItem.reset(rObj.pGrabBagItem->Clone());
1015 return *this;
1018 OUString SdrObject::TakeObjNameSingul() const
1020 OUStringBuffer sName(SvxResId(STR_ObjNameSingulNONE));
1022 OUString aName(GetName());
1023 if (!aName.isEmpty())
1025 sName.append(' ');
1026 sName.append('\'');
1027 sName.append(aName);
1028 sName.append('\'');
1030 return sName.makeStringAndClear();
1033 OUString SdrObject::TakeObjNamePlural() const
1035 return SvxResId(STR_ObjNamePluralNONE);
1038 OUString SdrObject::ImpGetDescriptionStr(const char* pStrCacheID) const
1040 OUString aStr = SvxResId(pStrCacheID);
1041 sal_Int32 nPos = aStr.indexOf("%1");
1042 if (nPos >= 0)
1044 // Replace '%1' with the object name.
1045 OUString aObjName(TakeObjNameSingul());
1046 aStr = aStr.replaceAt(nPos, 2, aObjName);
1049 nPos = aStr.indexOf("%2");
1050 if (nPos >= 0)
1051 // Replace '%2' with the passed value.
1052 aStr = aStr.replaceAt(nPos, 2, "0");
1053 return aStr;
1056 void SdrObject::ImpForcePlusData()
1058 if (!pPlusData)
1059 pPlusData.reset( new SdrObjPlusData );
1062 OUString SdrObject::GetMetrStr(tools::Long nVal) const
1064 return getSdrModelFromSdrObject().GetMetricString(nVal);
1067 basegfx::B2DPolyPolygon SdrObject::TakeXorPoly() const
1069 basegfx::B2DPolyPolygon aRetval;
1070 const tools::Rectangle aR(GetCurrentBoundRect());
1071 aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aR)));
1073 return aRetval;
1076 basegfx::B2DPolyPolygon SdrObject::TakeContour() const
1078 basegfx::B2DPolyPolygon aRetval;
1080 // create cloned object without text, but with drawing::LineStyle_SOLID,
1081 // COL_BLACK as line color and drawing::FillStyle_NONE
1082 SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
1084 if(pClone)
1086 const SdrTextObj* pTextObj = dynamic_cast< const SdrTextObj* >(this);
1088 if(pTextObj)
1090 // no text and no text animation
1091 pClone->SetMergedItem(SdrTextAniKindItem(SdrTextAniKind::NONE));
1092 pClone->SetOutlinerParaObject(nullptr);
1095 const SdrEdgeObj* pEdgeObj = dynamic_cast< const SdrEdgeObj* >(this);
1097 if(pEdgeObj)
1099 // create connections if connector, will be cleaned up when
1100 // deleting the connector again
1101 SdrObject* pLeft = pEdgeObj->GetConnectedNode(true);
1102 SdrObject* pRight = pEdgeObj->GetConnectedNode(false);
1104 if(pLeft)
1106 pClone->ConnectToNode(true, pLeft);
1109 if(pRight)
1111 pClone->ConnectToNode(false, pRight);
1115 SfxItemSet aNewSet(GetObjectItemPool());
1117 // #i101980# ignore LineWidth; that's what the old implementation
1118 // did. With line width, the result may be huge due to fat/thick
1119 // line decompositions
1120 aNewSet.Put(XLineWidthItem(0));
1122 // solid black lines and no fill
1123 aNewSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
1124 aNewSet.Put(XLineColorItem(OUString(), COL_BLACK));
1125 aNewSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
1126 pClone->SetMergedItemSet(aNewSet);
1128 // get sequence from clone
1129 const sdr::contact::ViewContact& rVC(pClone->GetViewContact());
1130 const drawinglayer::primitive2d::Primitive2DContainer& xSequence(rVC.getViewIndependentPrimitive2DContainer());
1132 if(!xSequence.empty())
1134 // use neutral ViewInformation
1135 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
1137 // create extractor, process and get result (with hairlines as opened polygons)
1138 drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, false);
1139 aExtractor.process(xSequence);
1140 const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour());
1141 const sal_uInt32 nSize(rResult.size());
1143 // when count is one, it is implied that the object has only its normal
1144 // contour anyways and TakeContour() is to return an empty PolyPolygon
1145 // (see old implementation for historical reasons)
1146 if(nSize > 1)
1148 // the topology for contour is correctly a vector of PolyPolygons; for
1149 // historical reasons cut it back to a single tools::PolyPolygon here
1150 for(sal_uInt32 a(0); a < nSize; a++)
1152 aRetval.append(rResult[a]);
1157 // Always use SdrObject::Free to delete SdrObjects (!)
1158 SdrObject::Free(pClone);
1161 return aRetval;
1164 sal_uInt32 SdrObject::GetHdlCount() const
1166 return 8;
1169 void SdrObject::AddToHdlList(SdrHdlList& rHdlList) const
1171 const tools::Rectangle& rR=GetSnapRect();
1172 for (sal_uInt32 nHdlNum=0; nHdlNum<8; ++nHdlNum)
1174 std::unique_ptr<SdrHdl> pH;
1175 switch (nHdlNum) {
1176 case 0: pH.reset(new SdrHdl(rR.TopLeft(), SdrHdlKind::UpperLeft)); break;
1177 case 1: pH.reset(new SdrHdl(rR.TopCenter(), SdrHdlKind::Upper)); break;
1178 case 2: pH.reset(new SdrHdl(rR.TopRight(), SdrHdlKind::UpperRight)); break;
1179 case 3: pH.reset(new SdrHdl(rR.LeftCenter(), SdrHdlKind::Left )); break;
1180 case 4: pH.reset(new SdrHdl(rR.RightCenter(), SdrHdlKind::Right)); break;
1181 case 5: pH.reset(new SdrHdl(rR.BottomLeft(), SdrHdlKind::LowerLeft)); break;
1182 case 6: pH.reset(new SdrHdl(rR.BottomCenter(),SdrHdlKind::Lower)); break;
1183 case 7: pH.reset(new SdrHdl(rR.BottomRight(), SdrHdlKind::LowerRight)); break;
1185 rHdlList.AddHdl(std::move(pH));
1189 void SdrObject::AddToPlusHdlList(SdrHdlList&, SdrHdl&) const
1193 void SdrObject::addCropHandles(SdrHdlList& /*rTarget*/) const
1195 // Default implementation, does nothing. Overloaded in
1196 // SdrGrafObj and SwVirtFlyDrawObj
1199 tools::Rectangle SdrObject::ImpDragCalcRect(const SdrDragStat& rDrag) const
1201 tools::Rectangle aTmpRect(GetSnapRect());
1202 tools::Rectangle aRect(aTmpRect);
1203 const SdrHdl* pHdl=rDrag.GetHdl();
1204 SdrHdlKind eHdl=pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind();
1205 bool bEcke=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::LowerLeft || eHdl==SdrHdlKind::LowerRight);
1206 bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
1207 bool bBigOrtho=bEcke && bOrtho && rDrag.GetView()->IsBigOrtho();
1208 Point aPos(rDrag.GetNow());
1209 bool bLft=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::LowerLeft);
1210 bool bRgt=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerRight);
1211 bool bTop=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperLeft);
1212 bool bBtm=(eHdl==SdrHdlKind::LowerRight || eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerLeft);
1213 if (bLft) aTmpRect.SetLeft(aPos.X() );
1214 if (bRgt) aTmpRect.SetRight(aPos.X() );
1215 if (bTop) aTmpRect.SetTop(aPos.Y() );
1216 if (bBtm) aTmpRect.SetBottom(aPos.Y() );
1217 if (bOrtho) { // Ortho
1218 tools::Long nWdt0=aRect.Right() -aRect.Left();
1219 tools::Long nHgt0=aRect.Bottom()-aRect.Top();
1220 tools::Long nXMul=aTmpRect.Right() -aTmpRect.Left();
1221 tools::Long nYMul=aTmpRect.Bottom()-aTmpRect.Top();
1222 tools::Long nXDiv=nWdt0;
1223 tools::Long nYDiv=nHgt0;
1224 bool bXNeg=(nXMul<0)!=(nXDiv<0);
1225 bool bYNeg=(nYMul<0)!=(nYDiv<0);
1226 nXMul=std::abs(nXMul);
1227 nYMul=std::abs(nYMul);
1228 nXDiv=std::abs(nXDiv);
1229 nYDiv=std::abs(nYDiv);
1230 Fraction aXFact(nXMul,nXDiv); // fractions for canceling
1231 Fraction aYFact(nYMul,nYDiv); // and for comparing
1232 nXMul=aXFact.GetNumerator();
1233 nYMul=aYFact.GetNumerator();
1234 nXDiv=aXFact.GetDenominator();
1235 nYDiv=aYFact.GetDenominator();
1236 if (bEcke) { // corner point handles
1237 bool bUseX=(aXFact<aYFact) != bBigOrtho;
1238 if (bUseX) {
1239 tools::Long nNeed=tools::Long(BigInt(nHgt0)*BigInt(nXMul)/BigInt(nXDiv));
1240 if (bYNeg) nNeed=-nNeed;
1241 if (bTop) aTmpRect.SetTop(aTmpRect.Bottom()-nNeed );
1242 if (bBtm) aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
1243 } else {
1244 tools::Long nNeed=tools::Long(BigInt(nWdt0)*BigInt(nYMul)/BigInt(nYDiv));
1245 if (bXNeg) nNeed=-nNeed;
1246 if (bLft) aTmpRect.SetLeft(aTmpRect.Right()-nNeed );
1247 if (bRgt) aTmpRect.SetRight(aTmpRect.Left()+nNeed );
1249 } else { // apex handles
1250 if ((bLft || bRgt) && nXDiv!=0) {
1251 tools::Long nHgt0b=aRect.Bottom()-aRect.Top();
1252 tools::Long nNeed=tools::Long(BigInt(nHgt0b)*BigInt(nXMul)/BigInt(nXDiv));
1253 aTmpRect.AdjustTop( -((nNeed-nHgt0b)/2) );
1254 aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
1256 if ((bTop || bBtm) && nYDiv!=0) {
1257 tools::Long nWdt0b=aRect.Right()-aRect.Left();
1258 tools::Long nNeed=tools::Long(BigInt(nWdt0b)*BigInt(nYMul)/BigInt(nYDiv));
1259 aTmpRect.AdjustLeft( -((nNeed-nWdt0b)/2) );
1260 aTmpRect.SetRight(aTmpRect.Left()+nNeed );
1264 aTmpRect.Justify();
1265 return aTmpRect;
1269 bool SdrObject::hasSpecialDrag() const
1271 return false;
1274 bool SdrObject::supportsFullDrag() const
1276 return true;
1279 SdrObjectUniquePtr SdrObject::getFullDragClone() const
1281 // default uses simple clone
1282 return SdrObjectUniquePtr(CloneSdrObject(getSdrModelFromSdrObject()));
1285 bool SdrObject::beginSpecialDrag(SdrDragStat& rDrag) const
1287 const SdrHdl* pHdl = rDrag.GetHdl();
1289 SdrHdlKind eHdl = (pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind();
1291 return eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperRight ||
1292 eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerLeft ||
1293 eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerRight;
1296 bool SdrObject::applySpecialDrag(SdrDragStat& rDrag)
1298 tools::Rectangle aNewRect(ImpDragCalcRect(rDrag));
1300 if(aNewRect != GetSnapRect())
1302 NbcSetSnapRect(aNewRect);
1305 return true;
1308 OUString SdrObject::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
1310 return OUString();
1313 basegfx::B2DPolyPolygon SdrObject::getSpecialDragPoly(const SdrDragStat& /*rDrag*/) const
1315 // default has nothing to add
1316 return basegfx::B2DPolyPolygon();
1320 // Create
1321 bool SdrObject::BegCreate(SdrDragStat& rStat)
1323 rStat.SetOrtho4Possible();
1324 tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
1325 aRect1.Justify();
1326 rStat.SetActionRect(aRect1);
1327 aOutRect = aRect1;
1328 return true;
1331 bool SdrObject::MovCreate(SdrDragStat& rStat)
1333 rStat.TakeCreateRect(aOutRect);
1334 rStat.SetActionRect(aOutRect);
1335 aOutRect.Justify();
1337 return true;
1340 bool SdrObject::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
1342 rStat.TakeCreateRect(aOutRect);
1343 aOutRect.Justify();
1345 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
1348 void SdrObject::BrkCreate(SdrDragStat& /*rStat*/)
1352 bool SdrObject::BckCreate(SdrDragStat& /*rStat*/)
1354 return false;
1357 basegfx::B2DPolyPolygon SdrObject::TakeCreatePoly(const SdrDragStat& rDrag) const
1359 tools::Rectangle aRect1;
1360 rDrag.TakeCreateRect(aRect1);
1361 aRect1.Justify();
1363 basegfx::B2DPolyPolygon aRetval;
1364 aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aRect1)));
1365 return aRetval;
1368 PointerStyle SdrObject::GetCreatePointer() const
1370 return PointerStyle::Cross;
1373 // transformations
1374 void SdrObject::NbcMove(const Size& rSiz)
1376 aOutRect.Move(rSiz);
1377 SetRectsDirty();
1380 void SdrObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1382 bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
1383 bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
1384 if (bXMirr || bYMirr) {
1385 Point aRef1(GetSnapRect().Center());
1386 if (bXMirr) {
1387 Point aRef2(aRef1);
1388 aRef2.AdjustY( 1 );
1389 NbcMirrorGluePoints(aRef1,aRef2);
1391 if (bYMirr) {
1392 Point aRef2(aRef1);
1393 aRef2.AdjustX( 1 );
1394 NbcMirrorGluePoints(aRef1,aRef2);
1397 ResizeRect(aOutRect,rRef,xFact,yFact);
1398 SetRectsDirty();
1401 void SdrObject::NbcRotate(const Point& rRef, tools::Long nAngle, double sn, double cs)
1403 SetGlueReallyAbsolute(true);
1404 aOutRect.Move(-rRef.X(),-rRef.Y());
1405 tools::Rectangle R(aOutRect);
1406 if (sn==1.0 && cs==0.0) { // 90deg
1407 aOutRect.SetLeft(-R.Bottom() );
1408 aOutRect.SetRight(-R.Top() );
1409 aOutRect.SetTop(R.Left() );
1410 aOutRect.SetBottom(R.Right() );
1411 } else if (sn==0.0 && cs==-1.0) { // 180deg
1412 aOutRect.SetLeft(-R.Right() );
1413 aOutRect.SetRight(-R.Left() );
1414 aOutRect.SetTop(-R.Bottom() );
1415 aOutRect.SetBottom(-R.Top() );
1416 } else if (sn==-1.0 && cs==0.0) { // 270deg
1417 aOutRect.SetLeft(R.Top() );
1418 aOutRect.SetRight(R.Bottom() );
1419 aOutRect.SetTop(-R.Right() );
1420 aOutRect.SetBottom(-R.Left() );
1422 aOutRect.Move(rRef.X(),rRef.Y());
1423 aOutRect.Justify(); // just in case
1424 SetRectsDirty();
1425 NbcRotateGluePoints(rRef,nAngle,sn,cs);
1426 SetGlueReallyAbsolute(false);
1429 void SdrObject::NbcMirror(const Point& rRef1, const Point& rRef2)
1431 SetGlueReallyAbsolute(true);
1432 aOutRect.Move(-rRef1.X(),-rRef1.Y());
1433 tools::Rectangle R(aOutRect);
1434 tools::Long dx=rRef2.X()-rRef1.X();
1435 tools::Long dy=rRef2.Y()-rRef1.Y();
1436 if (dx==0) { // vertical axis
1437 aOutRect.SetLeft(-R.Right() );
1438 aOutRect.SetRight(-R.Left() );
1439 } else if (dy==0) { // horizontal axis
1440 aOutRect.SetTop(-R.Bottom() );
1441 aOutRect.SetBottom(-R.Top() );
1442 } else if (dx==dy) { // 45deg axis
1443 aOutRect.SetLeft(R.Top() );
1444 aOutRect.SetRight(R.Bottom() );
1445 aOutRect.SetTop(R.Left() );
1446 aOutRect.SetBottom(R.Right() );
1447 } else if (dx==-dy) { // 45deg axis
1448 aOutRect.SetLeft(-R.Bottom() );
1449 aOutRect.SetRight(-R.Top() );
1450 aOutRect.SetTop(-R.Right() );
1451 aOutRect.SetBottom(-R.Left() );
1453 aOutRect.Move(rRef1.X(),rRef1.Y());
1454 aOutRect.Justify(); // just in case
1455 SetRectsDirty();
1456 NbcMirrorGluePoints(rRef1,rRef2);
1457 SetGlueReallyAbsolute(false);
1460 void SdrObject::NbcShear(const Point& rRef, tools::Long /*nAngle*/, double tn, bool bVShear)
1462 SetGlueReallyAbsolute(true);
1463 NbcShearGluePoints(rRef,tn,bVShear);
1464 SetGlueReallyAbsolute(false);
1467 void SdrObject::Move(const Size& rSiz)
1469 if (rSiz.Width()!=0 || rSiz.Height()!=0) {
1470 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1471 NbcMove(rSiz);
1472 SetChanged();
1473 BroadcastObjectChange();
1474 SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1478 void SdrObject::NbcCrop(const basegfx::B2DPoint& /*aRef*/, double /*fxFact*/, double /*fyFact*/)
1480 // Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrDragCrop::EndSdrDrag.
1481 // Where SwVirtFlyDrawObj is the only real user of it to do something local
1484 void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
1486 if (xFact.GetNumerator() == xFact.GetDenominator() && yFact.GetNumerator() == yFact.GetDenominator())
1487 return;
1489 if (bUnsetRelative)
1491 mpImpl->mnRelativeWidth.reset();
1492 mpImpl->meRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
1493 mpImpl->meRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
1494 mpImpl->mnRelativeHeight.reset();
1496 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1497 NbcResize(rRef,xFact,yFact);
1498 SetChanged();
1499 BroadcastObjectChange();
1500 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1503 void SdrObject::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
1505 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1506 NbcCrop(rRef, fxFact, fyFact);
1507 SetChanged();
1508 BroadcastObjectChange();
1509 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1512 void SdrObject::Rotate(const Point& rRef, tools::Long nAngle, double sn, double cs)
1514 if (nAngle!=0) {
1515 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1516 NbcRotate(rRef,nAngle,sn,cs);
1517 SetChanged();
1518 BroadcastObjectChange();
1519 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1523 void SdrObject::Mirror(const Point& rRef1, const Point& rRef2)
1525 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1526 NbcMirror(rRef1,rRef2);
1527 SetChanged();
1528 BroadcastObjectChange();
1529 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1532 void SdrObject::Shear(const Point& rRef, tools::Long nAngle, double tn, bool bVShear)
1534 if (nAngle!=0) {
1535 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1536 NbcShear(rRef,nAngle,tn,bVShear);
1537 SetChanged();
1538 BroadcastObjectChange();
1539 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1543 void SdrObject::NbcSetRelativePos(const Point& rPnt)
1545 Point aRelPos0(GetSnapRect().TopLeft()-aAnchor);
1546 Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
1547 NbcMove(aSiz); // This also calls SetRectsDirty()
1550 void SdrObject::SetRelativePos(const Point& rPnt)
1552 if (rPnt!=GetRelativePos()) {
1553 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1554 NbcSetRelativePos(rPnt);
1555 SetChanged();
1556 BroadcastObjectChange();
1557 SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1561 Point SdrObject::GetRelativePos() const
1563 return GetSnapRect().TopLeft()-aAnchor;
1566 void SdrObject::ImpSetAnchorPos(const Point& rPnt)
1568 aAnchor = rPnt;
1571 void SdrObject::NbcSetAnchorPos(const Point& rPnt)
1573 Size aSiz(rPnt.X()-aAnchor.X(),rPnt.Y()-aAnchor.Y());
1574 aAnchor=rPnt;
1575 NbcMove(aSiz); // This also calls SetRectsDirty()
1578 void SdrObject::SetAnchorPos(const Point& rPnt)
1580 if (rPnt!=aAnchor) {
1581 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1582 NbcSetAnchorPos(rPnt);
1583 SetChanged();
1584 BroadcastObjectChange();
1585 SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1589 const Point& SdrObject::GetAnchorPos() const
1591 return aAnchor;
1594 void SdrObject::RecalcSnapRect()
1598 const tools::Rectangle& SdrObject::GetSnapRect() const
1600 return aOutRect;
1603 void SdrObject::NbcSetSnapRect(const tools::Rectangle& rRect)
1605 aOutRect=rRect;
1608 const tools::Rectangle& SdrObject::GetLogicRect() const
1610 return GetSnapRect();
1613 void SdrObject::NbcSetLogicRect(const tools::Rectangle& rRect)
1615 NbcSetSnapRect(rRect);
1618 void SdrObject::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
1620 SetLogicRect( rMaxRect );
1623 void SdrObject::SetSnapRect(const tools::Rectangle& rRect)
1625 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1626 NbcSetSnapRect(rRect);
1627 SetChanged();
1628 BroadcastObjectChange();
1629 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1632 void SdrObject::SetLogicRect(const tools::Rectangle& rRect)
1634 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1635 NbcSetLogicRect(rRect);
1636 SetChanged();
1637 BroadcastObjectChange();
1638 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1641 tools::Long SdrObject::GetRotateAngle() const
1643 return 0;
1646 tools::Long SdrObject::GetShearAngle(bool /*bVertical*/) const
1648 return 0;
1651 sal_uInt32 SdrObject::GetSnapPointCount() const
1653 return GetPointCount();
1656 Point SdrObject::GetSnapPoint(sal_uInt32 i) const
1658 return GetPoint(i);
1661 bool SdrObject::IsPolyObj() const
1663 return false;
1666 sal_uInt32 SdrObject::GetPointCount() const
1668 return 0;
1671 Point SdrObject::GetPoint(sal_uInt32 /*i*/) const
1673 return Point();
1676 void SdrObject::SetPoint(const Point& rPnt, sal_uInt32 i)
1678 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1679 NbcSetPoint(rPnt, i);
1680 SetChanged();
1681 BroadcastObjectChange();
1682 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1685 void SdrObject::NbcSetPoint(const Point& /*rPnt*/, sal_uInt32 /*i*/)
1689 bool SdrObject::HasTextEdit() const
1691 return false;
1694 bool SdrObject::Equals(const SdrObject& rOtherObj) const
1696 return (aAnchor.X() == rOtherObj.aAnchor.X() && aAnchor.Y() == rOtherObj.aAnchor.Y() &&
1697 nOrdNum == rOtherObj.nOrdNum && mnNavigationPosition == rOtherObj.mnNavigationPosition &&
1698 mbSupportTextIndentingOnLineWidthChange == rOtherObj.mbSupportTextIndentingOnLineWidthChange &&
1699 mbLineIsOutsideGeometry == rOtherObj.mbLineIsOutsideGeometry && bMarkProt == rOtherObj.bMarkProt &&
1700 bIs3DObj == rOtherObj.bIs3DObj && bIsEdge == rOtherObj.bIsEdge && bClosedObj == rOtherObj.bClosedObj &&
1701 bNotVisibleAsMaster == rOtherObj.bNotVisibleAsMaster && bEmptyPresObj == rOtherObj.bEmptyPresObj &&
1702 mbVisible == rOtherObj.mbVisible && bNoPrint == rOtherObj.bNoPrint && bSizProt == rOtherObj.bSizProt &&
1703 bMovProt == rOtherObj.bMovProt && bVirtObj == rOtherObj.bVirtObj &&
1704 mnLayerID == rOtherObj.mnLayerID && GetMergedItemSet().Equals(rOtherObj.GetMergedItemSet(), false) );
1707 void SdrObject::dumpAsXml(xmlTextWriterPtr pWriter) const
1709 xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObject"));
1710 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1711 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name()));
1712 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("name"), "%s", BAD_CAST(GetName().toUtf8().getStr()));
1713 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("title"), "%s", BAD_CAST(GetTitle().toUtf8().getStr()));
1714 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("description"), "%s", BAD_CAST(GetDescription().toUtf8().getStr()));
1715 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("nOrdNum"), "%" SAL_PRIuUINT32, GetOrdNumDirect());
1716 xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aOutRect"), BAD_CAST(aOutRect.toString().getStr()));
1718 if (pGrabBagItem)
1720 pGrabBagItem->dumpAsXml(pWriter);
1723 if (mpProperties)
1725 mpProperties->dumpAsXml(pWriter);
1728 if (const OutlinerParaObject* pOutliner = GetOutlinerParaObject())
1729 pOutliner->dumpAsXml(pWriter);
1731 xmlTextWriterEndElement(pWriter);
1734 void SdrObject::SetOutlinerParaObject(std::unique_ptr<OutlinerParaObject> pTextObject)
1736 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1737 NbcSetOutlinerParaObject(std::move(pTextObject));
1738 SetChanged();
1739 BroadcastObjectChange();
1740 if (GetCurrentBoundRect()!=aBoundRect0) {
1741 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1744 if (getSdrModelFromSdrObject().IsUndoEnabled())
1746 // Don't do this during import.
1747 SdrObject* pTopGroupObj = nullptr;
1748 if (getParentSdrObjectFromSdrObject())
1750 pTopGroupObj = getParentSdrObjectFromSdrObject();
1751 while (pTopGroupObj->getParentSdrObjectFromSdrObject())
1753 pTopGroupObj = pTopGroupObj->getParentSdrObjectFromSdrObject();
1756 if (pTopGroupObj)
1758 // A shape was modified, which is in a group shape. Empty the group shape's grab-bag,
1759 // which potentially contains the old text of the shapes in case of diagrams.
1760 pTopGroupObj->SetGrabBagItem(uno::makeAny(uno::Sequence<beans::PropertyValue>()));
1765 void SdrObject::NbcSetOutlinerParaObject(std::unique_ptr<OutlinerParaObject> /*pTextObject*/)
1769 OutlinerParaObject* SdrObject::GetOutlinerParaObject() const
1771 return nullptr;
1774 void SdrObject::NbcReformatText()
1778 void SdrObject::BurnInStyleSheetAttributes()
1780 GetProperties().ForceStyleToHardAttributes();
1783 bool SdrObject::HasMacro() const
1785 return false;
1788 SdrObject* SdrObject::CheckMacroHit(const SdrObjMacroHitRec& rRec) const
1790 if(rRec.pPageView)
1792 return SdrObjectPrimitiveHit(*this, rRec.aPos, rRec.nTol, *rRec.pPageView, rRec.pVisiLayer, false);
1795 return nullptr;
1798 PointerStyle SdrObject::GetMacroPointer(const SdrObjMacroHitRec&) const
1800 return PointerStyle::RefHand;
1803 void SdrObject::PaintMacro(OutputDevice& rOut, const tools::Rectangle& , const SdrObjMacroHitRec& ) const
1805 const RasterOp eRop(rOut.GetRasterOp());
1806 const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
1808 rOut.SetLineColor(COL_BLACK);
1809 rOut.SetFillColor();
1810 rOut.SetRasterOp(RasterOp::Invert);
1812 for(auto const& rPolygon : aPolyPolygon)
1814 rOut.DrawPolyLine(rPolygon);
1817 rOut.SetRasterOp(eRop);
1820 bool SdrObject::DoMacro(const SdrObjMacroHitRec&)
1822 return false;
1825 bool SdrObject::IsMacroHit(const SdrObjMacroHitRec& rRec) const
1827 return CheckMacroHit(rRec) != nullptr;
1831 SdrObjGeoData* SdrObject::NewGeoData() const
1833 return new SdrObjGeoData;
1836 void SdrObject::SaveGeoData(SdrObjGeoData& rGeo) const
1838 rGeo.aBoundRect =GetCurrentBoundRect();
1839 rGeo.aAnchor =aAnchor ;
1840 rGeo.bMovProt =bMovProt ;
1841 rGeo.bSizProt =bSizProt ;
1842 rGeo.bNoPrint =bNoPrint ;
1843 rGeo.mbVisible =mbVisible ;
1844 rGeo.bClosedObj =bClosedObj ;
1845 rGeo.mnLayerID = mnLayerID;
1847 // user-defined glue points
1848 if (pPlusData!=nullptr && pPlusData->pGluePoints!=nullptr) {
1849 if (rGeo.pGPL!=nullptr) {
1850 *rGeo.pGPL=*pPlusData->pGluePoints;
1851 } else {
1852 rGeo.pGPL.reset( new SdrGluePointList(*pPlusData->pGluePoints) );
1854 } else {
1855 rGeo.pGPL.reset();
1859 void SdrObject::RestGeoData(const SdrObjGeoData& rGeo)
1861 SetRectsDirty();
1862 aOutRect =rGeo.aBoundRect ;
1863 aAnchor =rGeo.aAnchor ;
1864 bMovProt =rGeo.bMovProt ;
1865 bSizProt =rGeo.bSizProt ;
1866 bNoPrint =rGeo.bNoPrint ;
1867 mbVisible =rGeo.mbVisible ;
1868 bClosedObj =rGeo.bClosedObj ;
1869 mnLayerID = rGeo.mnLayerID;
1871 // user-defined glue points
1872 if (rGeo.pGPL!=nullptr) {
1873 ImpForcePlusData();
1874 if (pPlusData->pGluePoints!=nullptr) {
1875 *pPlusData->pGluePoints=*rGeo.pGPL;
1876 } else {
1877 pPlusData->pGluePoints.reset(new SdrGluePointList(*rGeo.pGPL));
1879 } else {
1880 if (pPlusData!=nullptr && pPlusData->pGluePoints!=nullptr) {
1881 pPlusData->pGluePoints.reset();
1886 SdrObjGeoData* SdrObject::GetGeoData() const
1888 SdrObjGeoData* pGeo=NewGeoData();
1889 SaveGeoData(*pGeo);
1890 return pGeo;
1893 void SdrObject::SetGeoData(const SdrObjGeoData& rGeo)
1895 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1896 RestGeoData(rGeo);
1897 SetChanged();
1898 BroadcastObjectChange();
1899 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1903 // ItemSet access
1905 const SfxItemSet& SdrObject::GetObjectItemSet() const
1907 return GetProperties().GetObjectItemSet();
1910 const SfxItemSet& SdrObject::GetMergedItemSet() const
1912 return GetProperties().GetMergedItemSet();
1915 void SdrObject::SetObjectItem(const SfxPoolItem& rItem)
1917 GetProperties().SetObjectItem(rItem);
1920 void SdrObject::SetMergedItem(const SfxPoolItem& rItem)
1922 GetProperties().SetMergedItem(rItem);
1925 void SdrObject::ClearMergedItem(const sal_uInt16 nWhich)
1927 GetProperties().ClearMergedItem(nWhich);
1930 void SdrObject::SetObjectItemSet(const SfxItemSet& rSet)
1932 GetProperties().SetObjectItemSet(rSet);
1935 void SdrObject::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
1937 GetProperties().SetMergedItemSet(rSet, bClearAllItems);
1940 const SfxPoolItem& SdrObject::GetObjectItem(const sal_uInt16 nWhich) const
1942 return GetObjectItemSet().Get(nWhich);
1945 const SfxPoolItem& SdrObject::GetMergedItem(const sal_uInt16 nWhich) const
1947 return GetMergedItemSet().Get(nWhich);
1950 void SdrObject::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems)
1952 GetProperties().SetMergedItemSetAndBroadcast(rSet, bClearAllItems);
1955 void SdrObject::ApplyNotPersistAttr(const SfxItemSet& rAttr)
1957 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1958 NbcApplyNotPersistAttr(rAttr);
1959 SetChanged();
1960 BroadcastObjectChange();
1961 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1964 void SdrObject::NbcApplyNotPersistAttr(const SfxItemSet& rAttr)
1966 const tools::Rectangle& rSnap=GetSnapRect();
1967 const tools::Rectangle& rLogic=GetLogicRect();
1968 Point aRef1(rSnap.Center());
1969 const SfxPoolItem *pPoolItem=nullptr;
1970 if (rAttr.GetItemState(SDRATTR_TRANSFORMREF1X,true,&pPoolItem)==SfxItemState::SET) {
1971 aRef1.setX(static_cast<const SdrTransformRef1XItem*>(pPoolItem)->GetValue() );
1973 if (rAttr.GetItemState(SDRATTR_TRANSFORMREF1Y,true,&pPoolItem)==SfxItemState::SET) {
1974 aRef1.setY(static_cast<const SdrTransformRef1YItem*>(pPoolItem)->GetValue() );
1977 tools::Rectangle aNewSnap(rSnap);
1978 if (rAttr.GetItemState(SDRATTR_MOVEX,true,&pPoolItem)==SfxItemState::SET) {
1979 tools::Long n=static_cast<const SdrMoveXItem*>(pPoolItem)->GetValue();
1980 aNewSnap.Move(n,0);
1982 if (rAttr.GetItemState(SDRATTR_MOVEY,true,&pPoolItem)==SfxItemState::SET) {
1983 tools::Long n=static_cast<const SdrMoveYItem*>(pPoolItem)->GetValue();
1984 aNewSnap.Move(0,n);
1986 if (rAttr.GetItemState(SDRATTR_ONEPOSITIONX,true,&pPoolItem)==SfxItemState::SET) {
1987 tools::Long n=static_cast<const SdrOnePositionXItem*>(pPoolItem)->GetValue();
1988 aNewSnap.Move(n-aNewSnap.Left(),0);
1990 if (rAttr.GetItemState(SDRATTR_ONEPOSITIONY,true,&pPoolItem)==SfxItemState::SET) {
1991 tools::Long n=static_cast<const SdrOnePositionYItem*>(pPoolItem)->GetValue();
1992 aNewSnap.Move(0,n-aNewSnap.Top());
1994 if (rAttr.GetItemState(SDRATTR_ONESIZEWIDTH,true,&pPoolItem)==SfxItemState::SET) {
1995 tools::Long n=static_cast<const SdrOneSizeWidthItem*>(pPoolItem)->GetValue();
1996 aNewSnap.SetRight(aNewSnap.Left()+n );
1998 if (rAttr.GetItemState(SDRATTR_ONESIZEHEIGHT,true,&pPoolItem)==SfxItemState::SET) {
1999 tools::Long n=static_cast<const SdrOneSizeHeightItem*>(pPoolItem)->GetValue();
2000 aNewSnap.SetBottom(aNewSnap.Top()+n );
2002 if (aNewSnap!=rSnap) {
2003 if (aNewSnap.GetSize()==rSnap.GetSize()) {
2004 NbcMove(Size(aNewSnap.Left()-rSnap.Left(),aNewSnap.Top()-rSnap.Top()));
2005 } else {
2006 NbcSetSnapRect(aNewSnap);
2010 if (rAttr.GetItemState(SDRATTR_SHEARANGLE,true,&pPoolItem)==SfxItemState::SET) {
2011 tools::Long n=static_cast<const SdrShearAngleItem*>(pPoolItem)->GetValue();
2012 n-=GetShearAngle();
2013 if (n!=0) {
2014 double nTan = tan(n * F_PI18000);
2015 NbcShear(aRef1,n,nTan,false);
2018 if (rAttr.GetItemState(SDRATTR_ROTATEANGLE,true,&pPoolItem)==SfxItemState::SET) {
2019 tools::Long n=static_cast<const SdrAngleItem*>(pPoolItem)->GetValue();
2020 n-=GetRotateAngle();
2021 if (n!=0) {
2022 double nSin = sin(n * F_PI18000);
2023 double nCos = cos(n * F_PI18000);
2024 NbcRotate(aRef1,n,nSin,nCos);
2027 if (rAttr.GetItemState(SDRATTR_ROTATEONE,true,&pPoolItem)==SfxItemState::SET) {
2028 tools::Long n=static_cast<const SdrRotateOneItem*>(pPoolItem)->GetValue();
2029 double nSin = sin(n * F_PI18000);
2030 double nCos = cos(n * F_PI18000);
2031 NbcRotate(aRef1,n,nSin,nCos);
2033 if (rAttr.GetItemState(SDRATTR_HORZSHEARONE,true,&pPoolItem)==SfxItemState::SET) {
2034 tools::Long n=static_cast<const SdrHorzShearOneItem*>(pPoolItem)->GetValue();
2035 double nTan = tan(n * F_PI18000);
2036 NbcShear(aRef1,n,nTan,false);
2038 if (rAttr.GetItemState(SDRATTR_VERTSHEARONE,true,&pPoolItem)==SfxItemState::SET) {
2039 tools::Long n=static_cast<const SdrVertShearOneItem*>(pPoolItem)->GetValue();
2040 double nTan = tan(n * F_PI18000);
2041 NbcShear(aRef1,n,nTan,true);
2044 if (rAttr.GetItemState(SDRATTR_OBJMOVEPROTECT,true,&pPoolItem)==SfxItemState::SET) {
2045 bool b=static_cast<const SdrYesNoItem*>(pPoolItem)->GetValue();
2046 SetMoveProtect(b);
2048 if (rAttr.GetItemState(SDRATTR_OBJSIZEPROTECT,true,&pPoolItem)==SfxItemState::SET) {
2049 bool b=static_cast<const SdrYesNoItem*>(pPoolItem)->GetValue();
2050 SetResizeProtect(b);
2053 /* move protect always sets size protect */
2054 if( IsMoveProtect() )
2055 SetResizeProtect( true );
2057 if (rAttr.GetItemState(SDRATTR_OBJPRINTABLE,true,&pPoolItem)==SfxItemState::SET) {
2058 bool b=static_cast<const SdrObjPrintableItem*>(pPoolItem)->GetValue();
2059 SetPrintable(b);
2062 if (rAttr.GetItemState(SDRATTR_OBJVISIBLE,true,&pPoolItem)==SfxItemState::SET) {
2063 bool b=static_cast<const SdrObjVisibleItem*>(pPoolItem)->GetValue();
2064 SetVisible(b);
2067 SdrLayerID nLayer=SDRLAYER_NOTFOUND;
2068 if (rAttr.GetItemState(SDRATTR_LAYERID,true,&pPoolItem)==SfxItemState::SET) {
2069 nLayer=static_cast<const SdrLayerIdItem*>(pPoolItem)->GetValue();
2071 if (rAttr.GetItemState(SDRATTR_LAYERNAME,true,&pPoolItem)==SfxItemState::SET)
2073 OUString aLayerName = static_cast<const SdrLayerNameItem*>(pPoolItem)->GetValue();
2074 const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
2075 ? getSdrPageFromSdrObject()->GetLayerAdmin()
2076 : getSdrModelFromSdrObject().GetLayerAdmin());
2077 const SdrLayer* pLayer = rLayAd.GetLayer(aLayerName);
2079 if(nullptr != pLayer)
2081 nLayer=pLayer->GetID();
2084 if (nLayer!=SDRLAYER_NOTFOUND) {
2085 NbcSetLayer(nLayer);
2088 if (rAttr.GetItemState(SDRATTR_OBJECTNAME,true,&pPoolItem)==SfxItemState::SET) {
2089 OUString aName=static_cast<const SfxStringItem*>(pPoolItem)->GetValue();
2090 SetName(aName);
2092 tools::Rectangle aNewLogic(rLogic);
2093 if (rAttr.GetItemState(SDRATTR_LOGICSIZEWIDTH,true,&pPoolItem)==SfxItemState::SET) {
2094 tools::Long n=static_cast<const SdrLogicSizeWidthItem*>(pPoolItem)->GetValue();
2095 aNewLogic.SetRight(aNewLogic.Left()+n );
2097 if (rAttr.GetItemState(SDRATTR_LOGICSIZEHEIGHT,true,&pPoolItem)==SfxItemState::SET) {
2098 tools::Long n=static_cast<const SdrLogicSizeHeightItem*>(pPoolItem)->GetValue();
2099 aNewLogic.SetBottom(aNewLogic.Top()+n );
2101 if (aNewLogic!=rLogic) {
2102 NbcSetLogicRect(aNewLogic);
2104 Fraction aResizeX(1,1);
2105 Fraction aResizeY(1,1);
2106 if (rAttr.GetItemState(SDRATTR_RESIZEXONE,true,&pPoolItem)==SfxItemState::SET) {
2107 aResizeX*=static_cast<const SdrResizeXOneItem*>(pPoolItem)->GetValue();
2109 if (rAttr.GetItemState(SDRATTR_RESIZEYONE,true,&pPoolItem)==SfxItemState::SET) {
2110 aResizeY*=static_cast<const SdrResizeYOneItem*>(pPoolItem)->GetValue();
2112 if (aResizeX!=Fraction(1,1) || aResizeY!=Fraction(1,1)) {
2113 NbcResize(aRef1,aResizeX,aResizeY);
2117 void SdrObject::TakeNotPersistAttr(SfxItemSet& rAttr) const
2119 const tools::Rectangle& rSnap=GetSnapRect();
2120 const tools::Rectangle& rLogic=GetLogicRect();
2121 rAttr.Put(SdrYesNoItem(SDRATTR_OBJMOVEPROTECT, IsMoveProtect()));
2122 rAttr.Put(SdrYesNoItem(SDRATTR_OBJSIZEPROTECT, IsResizeProtect()));
2123 rAttr.Put(SdrObjPrintableItem(IsPrintable()));
2124 rAttr.Put(SdrObjVisibleItem(IsVisible()));
2125 rAttr.Put(SdrAngleItem(SDRATTR_ROTATEANGLE, GetRotateAngle()));
2126 rAttr.Put(SdrShearAngleItem(GetShearAngle()));
2127 rAttr.Put(SdrOneSizeWidthItem(rSnap.GetWidth()-1));
2128 rAttr.Put(SdrOneSizeHeightItem(rSnap.GetHeight()-1));
2129 rAttr.Put(SdrOnePositionXItem(rSnap.Left()));
2130 rAttr.Put(SdrOnePositionYItem(rSnap.Top()));
2131 if (rLogic.GetWidth()!=rSnap.GetWidth()) {
2132 rAttr.Put(SdrLogicSizeWidthItem(rLogic.GetWidth()-1));
2134 if (rLogic.GetHeight()!=rSnap.GetHeight()) {
2135 rAttr.Put(SdrLogicSizeHeightItem(rLogic.GetHeight()-1));
2137 OUString aName(GetName());
2139 if (!aName.isEmpty())
2141 rAttr.Put(SfxStringItem(SDRATTR_OBJECTNAME, aName));
2144 rAttr.Put(SdrLayerIdItem(GetLayer()));
2145 const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
2146 ? getSdrPageFromSdrObject()->GetLayerAdmin()
2147 : getSdrModelFromSdrObject().GetLayerAdmin());
2148 const SdrLayer* pLayer = rLayAd.GetLayerPerID(GetLayer());
2149 if(nullptr != pLayer)
2151 rAttr.Put(SdrLayerNameItem(pLayer->GetName()));
2153 Point aRef1(rSnap.Center());
2154 Point aRef2(aRef1); aRef2.AdjustY( 1 );
2155 rAttr.Put(SdrTransformRef1XItem(aRef1.X()));
2156 rAttr.Put(SdrTransformRef1YItem(aRef1.Y()));
2157 rAttr.Put(SdrTransformRef2XItem(aRef2.X()));
2158 rAttr.Put(SdrTransformRef2YItem(aRef2.Y()));
2161 SfxStyleSheet* SdrObject::GetStyleSheet() const
2163 return GetProperties().GetStyleSheet();
2166 void SdrObject::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
2168 tools::Rectangle aBoundRect0;
2170 if(pUserCall)
2171 aBoundRect0 = GetLastBoundRect();
2173 NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
2174 SetChanged();
2175 BroadcastObjectChange();
2176 SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect0);
2179 void SdrObject::NbcSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
2181 GetProperties().SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
2184 // Broadcasting while setting attributes is managed by the AttrObj.
2187 SdrGluePoint SdrObject::GetVertexGluePoint(sal_uInt16 nPosNum) const
2189 // #i41936# Use SnapRect for default GluePoints
2190 const tools::Rectangle aR(GetSnapRect());
2191 Point aPt;
2193 switch(nPosNum)
2195 case 0 : aPt = aR.TopCenter(); break;
2196 case 1 : aPt = aR.RightCenter(); break;
2197 case 2 : aPt = aR.BottomCenter(); break;
2198 case 3 : aPt = aR.LeftCenter(); break;
2201 aPt -= aR.Center();
2202 SdrGluePoint aGP(aPt);
2203 aGP.SetPercent(false);
2205 return aGP;
2208 SdrGluePoint SdrObject::GetCornerGluePoint(sal_uInt16 nPosNum) const
2210 tools::Rectangle aR(GetCurrentBoundRect());
2211 Point aPt;
2212 switch (nPosNum) {
2213 case 0 : aPt=aR.TopLeft(); break;
2214 case 1 : aPt=aR.TopRight(); break;
2215 case 2 : aPt=aR.BottomRight(); break;
2216 case 3 : aPt=aR.BottomLeft(); break;
2218 aPt-=GetSnapRect().Center();
2219 SdrGluePoint aGP(aPt);
2220 aGP.SetPercent(false);
2221 return aGP;
2224 const SdrGluePointList* SdrObject::GetGluePointList() const
2226 if (pPlusData!=nullptr) return pPlusData->pGluePoints.get();
2227 return nullptr;
2231 SdrGluePointList* SdrObject::ForceGluePointList()
2233 ImpForcePlusData();
2234 if (pPlusData->pGluePoints==nullptr) {
2235 pPlusData->pGluePoints.reset(new SdrGluePointList);
2237 return pPlusData->pGluePoints.get();
2240 void SdrObject::SetGlueReallyAbsolute(bool bOn)
2242 // First a const call to see whether there are any glue points.
2243 // Force const call!
2244 if (GetGluePointList()!=nullptr) {
2245 SdrGluePointList* pGPL=ForceGluePointList();
2246 pGPL->SetReallyAbsolute(bOn,*this);
2250 void SdrObject::NbcRotateGluePoints(const Point& rRef, tools::Long nAngle, double sn, double cs)
2252 // First a const call to see whether there are any glue points.
2253 // Force const call!
2254 if (GetGluePointList()!=nullptr) {
2255 SdrGluePointList* pGPL=ForceGluePointList();
2256 pGPL->Rotate(rRef,nAngle,sn,cs,this);
2260 void SdrObject::NbcMirrorGluePoints(const Point& rRef1, const Point& rRef2)
2262 // First a const call to see whether there are any glue points.
2263 // Force const call!
2264 if (GetGluePointList()!=nullptr) {
2265 SdrGluePointList* pGPL=ForceGluePointList();
2266 pGPL->Mirror(rRef1,rRef2,this);
2270 void SdrObject::NbcShearGluePoints(const Point& rRef, double tn, bool bVShear)
2272 // First a const call to see whether there are any glue points.
2273 // Force const call!
2274 if (GetGluePointList()!=nullptr) {
2275 SdrGluePointList* pGPL=ForceGluePointList();
2276 pGPL->Shear(rRef,tn,bVShear,this);
2280 void SdrObject::ConnectToNode(bool /*bTail1*/, SdrObject* /*pObj*/)
2284 void SdrObject::DisconnectFromNode(bool /*bTail1*/)
2288 SdrObject* SdrObject::GetConnectedNode(bool /*bTail1*/) const
2290 return nullptr;
2294 static void extractLineContourFromPrimitive2DSequence(
2295 const drawinglayer::primitive2d::Primitive2DContainer& rxSequence,
2296 basegfx::B2DPolygonVector& rExtractedHairlines,
2297 basegfx::B2DPolyPolygonVector& rExtractedLineFills)
2299 rExtractedHairlines.clear();
2300 rExtractedLineFills.clear();
2302 if(rxSequence.empty())
2303 return;
2305 // use neutral ViewInformation
2306 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
2308 // create extractor, process and get result
2309 drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
2310 aExtractor.process(rxSequence);
2312 // copy line results
2313 rExtractedHairlines = aExtractor.getExtractedHairlines();
2315 // copy fill rsults
2316 rExtractedLineFills = aExtractor.getExtractedLineFills();
2320 SdrObject* SdrObject::ImpConvertToContourObj(bool bForceLineDash)
2322 SdrObject* pRetval(nullptr);
2324 if(LineGeometryUsageIsNecessary())
2326 basegfx::B2DPolyPolygon aMergedLineFillPolyPolygon;
2327 basegfx::B2DPolyPolygon aMergedHairlinePolyPolygon;
2328 const drawinglayer::primitive2d::Primitive2DContainer & xSequence(GetViewContact().getViewIndependentPrimitive2DContainer());
2330 if(!xSequence.empty())
2332 basegfx::B2DPolygonVector aExtractedHairlines;
2333 basegfx::B2DPolyPolygonVector aExtractedLineFills;
2335 extractLineContourFromPrimitive2DSequence(xSequence, aExtractedHairlines, aExtractedLineFills);
2337 // for SdrObject creation, just copy all to a single Hairline-PolyPolygon
2338 for(const basegfx::B2DPolygon & rExtractedHairline : aExtractedHairlines)
2340 aMergedHairlinePolyPolygon.append(rExtractedHairline);
2343 // check for fill rsults
2344 if (!aExtractedLineFills.empty() && !utl::ConfigManager::IsFuzzing())
2346 // merge to a single tools::PolyPolygon (OR)
2347 aMergedLineFillPolyPolygon = basegfx::utils::mergeToSinglePolyPolygon(aExtractedLineFills);
2351 if(aMergedLineFillPolyPolygon.count() || (bForceLineDash && aMergedHairlinePolyPolygon.count()))
2353 SfxItemSet aSet(GetMergedItemSet());
2354 drawing::FillStyle eOldFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue();
2355 SdrPathObj* aLinePolygonPart = nullptr;
2356 SdrPathObj* aLineHairlinePart = nullptr;
2357 bool bBuildGroup(false);
2359 if(aMergedLineFillPolyPolygon.count())
2361 // create SdrObject for filled line geometry
2362 aLinePolygonPart = new SdrPathObj(
2363 getSdrModelFromSdrObject(),
2364 OBJ_PATHFILL,
2365 aMergedLineFillPolyPolygon);
2367 // correct item properties
2368 aSet.Put(XLineWidthItem(0));
2369 aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
2370 Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue();
2371 sal_uInt16 nTransLine = aSet.Get(XATTR_LINETRANSPARENCE).GetValue();
2372 aSet.Put(XFillColorItem(OUString(), aColorLine));
2373 aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
2374 aSet.Put(XFillTransparenceItem(nTransLine));
2376 aLinePolygonPart->SetMergedItemSet(aSet);
2379 if(aMergedHairlinePolyPolygon.count())
2381 // create SdrObject for hairline geometry
2382 // OBJ_PATHLINE is necessary here, not OBJ_PATHFILL. This is intended
2383 // to get a non-filled object. If the poly is closed, the PathObj takes care for
2384 // the correct closed state.
2385 aLineHairlinePart = new SdrPathObj(
2386 getSdrModelFromSdrObject(),
2387 OBJ_PATHLINE,
2388 aMergedHairlinePolyPolygon);
2390 aSet.Put(XLineWidthItem(0));
2391 aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
2392 aSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
2394 // it is also necessary to switch off line start and ends here
2395 aSet.Put(XLineStartWidthItem(0));
2396 aSet.Put(XLineEndWidthItem(0));
2398 aLineHairlinePart->SetMergedItemSet(aSet);
2400 if(aLinePolygonPart)
2402 bBuildGroup = true;
2406 // check if original geometry should be added (e.g. filled and closed)
2407 bool bAddOriginalGeometry(false);
2408 SdrPathObj* pPath = dynamic_cast<SdrPathObj*>(this);
2410 if(pPath && pPath->IsClosed())
2412 if(eOldFillStyle != drawing::FillStyle_NONE)
2414 bAddOriginalGeometry = true;
2418 // do we need a group?
2419 if(bBuildGroup || bAddOriginalGeometry)
2421 SdrObject* pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
2423 if(bAddOriginalGeometry)
2425 // Add a clone of the original geometry.
2426 aSet.ClearItem();
2427 aSet.Put(GetMergedItemSet());
2428 aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
2429 aSet.Put(XLineWidthItem(0));
2431 SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
2432 pClone->SetMergedItemSet(aSet);
2434 pGroup->GetSubList()->NbcInsertObject(pClone);
2437 if(aLinePolygonPart)
2439 pGroup->GetSubList()->NbcInsertObject(aLinePolygonPart);
2442 if(aLineHairlinePart)
2444 pGroup->GetSubList()->NbcInsertObject(aLineHairlinePart);
2447 pRetval = pGroup;
2449 else
2451 if(aLinePolygonPart)
2453 pRetval = aLinePolygonPart;
2455 else if(aLineHairlinePart)
2457 pRetval = aLineHairlinePart;
2463 if(nullptr == pRetval)
2465 // due to current method usage, create and return a clone when nothing has changed
2466 SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
2467 pRetval = pClone;
2470 return pRetval;
2474 void SdrObject::SetMarkProtect(bool bProt)
2476 bMarkProt = bProt;
2480 void SdrObject::SetEmptyPresObj(bool bEpt)
2482 bEmptyPresObj = bEpt;
2486 void SdrObject::SetNotVisibleAsMaster(bool bFlg)
2488 bNotVisibleAsMaster=bFlg;
2492 // convert this path object to contour object, even when it is a group
2493 SdrObject* SdrObject::ConvertToContourObj(SdrObject* pRet, bool bForceLineDash) const
2495 if(dynamic_cast<const SdrObjGroup*>( pRet) != nullptr)
2497 SdrObjList* pObjList2 = pRet->GetSubList();
2498 SdrObject* pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
2500 for(size_t a=0; a<pObjList2->GetObjCount(); ++a)
2502 SdrObject* pIterObj = pObjList2->GetObj(a);
2503 pGroup->GetSubList()->NbcInsertObject(ConvertToContourObj(pIterObj, bForceLineDash));
2506 pRet = pGroup;
2508 else
2510 if (SdrPathObj *pPathObj = dynamic_cast<SdrPathObj*>(pRet))
2512 // bezier geometry got created, even for straight edges since the given
2513 // object is a result of DoConvertToPolyObj. For conversion to contour
2514 // this is not really needed and can be reduced again AFAP
2515 pPathObj->SetPathPoly(basegfx::utils::simplifyCurveSegments(pPathObj->GetPathPoly()));
2518 pRet = pRet->ImpConvertToContourObj(bForceLineDash);
2521 // #i73441# preserve LayerID
2522 if(pRet && pRet->GetLayer() != GetLayer())
2524 pRet->SetLayer(GetLayer());
2527 return pRet;
2531 SdrObjectUniquePtr SdrObject::ConvertToPolyObj(bool bBezier, bool bLineToArea) const
2533 SdrObjectUniquePtr pRet = DoConvertToPolyObj(bBezier, true);
2535 if(pRet && bLineToArea)
2537 SdrObject* pNewRet = ConvertToContourObj(pRet.get());
2538 pRet.reset(pNewRet);
2541 // #i73441# preserve LayerID
2542 if(pRet && pRet->GetLayer() != GetLayer())
2544 pRet->SetLayer(GetLayer());
2547 return pRet;
2551 SdrObjectUniquePtr SdrObject::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
2553 return nullptr;
2557 void SdrObject::InsertedStateChange()
2559 const bool bIsInserted(nullptr != getParentSdrObjListFromSdrObject());
2560 const tools::Rectangle aBoundRect0(GetLastBoundRect());
2562 if(bIsInserted)
2564 SendUserCall(SdrUserCallType::Inserted, aBoundRect0);
2566 else
2568 SendUserCall(SdrUserCallType::Removed, aBoundRect0);
2571 if(nullptr != pPlusData && nullptr != pPlusData->pBroadcast)
2573 SdrHint aHint(bIsInserted ? SdrHintKind::ObjectInserted : SdrHintKind::ObjectRemoved, *this);
2574 pPlusData->pBroadcast->Broadcast(aHint);
2578 void SdrObject::SetMoveProtect(bool bProt)
2580 if(IsMoveProtect() != bProt)
2582 // #i77187# secured and simplified
2583 bMovProt = bProt;
2584 SetChanged();
2585 BroadcastObjectChange();
2589 void SdrObject::SetResizeProtect(bool bProt)
2591 if(IsResizeProtect() != bProt)
2593 // #i77187# secured and simplified
2594 bSizProt = bProt;
2595 SetChanged();
2596 BroadcastObjectChange();
2600 void SdrObject::SetPrintable(bool bPrn)
2602 if( bPrn == bNoPrint )
2604 bNoPrint=!bPrn;
2605 SetChanged();
2606 if (IsInserted())
2608 SdrHint aHint(SdrHintKind::ObjectChange, *this);
2609 getSdrModelFromSdrObject().Broadcast(aHint);
2614 void SdrObject::SetVisible(bool bVisible)
2616 if( bVisible != mbVisible )
2618 mbVisible = bVisible;
2619 SetChanged();
2620 if (IsInserted())
2622 SdrHint aHint(SdrHintKind::ObjectChange, *this);
2623 getSdrModelFromSdrObject().Broadcast(aHint);
2629 sal_uInt16 SdrObject::GetUserDataCount() const
2631 if (pPlusData==nullptr || pPlusData->pUserDataList==nullptr) return 0;
2632 return pPlusData->pUserDataList->GetUserDataCount();
2635 SdrObjUserData* SdrObject::GetUserData(sal_uInt16 nNum) const
2637 if (pPlusData==nullptr || pPlusData->pUserDataList==nullptr) return nullptr;
2638 return &pPlusData->pUserDataList->GetUserData(nNum);
2641 void SdrObject::AppendUserData(std::unique_ptr<SdrObjUserData> pData)
2643 if (!pData)
2645 OSL_FAIL("SdrObject::AppendUserData(): pData is NULL pointer.");
2646 return;
2649 ImpForcePlusData();
2650 if (!pPlusData->pUserDataList)
2651 pPlusData->pUserDataList.reset( new SdrObjUserDataList );
2653 pPlusData->pUserDataList->AppendUserData(std::move(pData));
2656 void SdrObject::DeleteUserData(sal_uInt16 nNum)
2658 sal_uInt16 nCount=GetUserDataCount();
2659 if (nNum<nCount) {
2660 pPlusData->pUserDataList->DeleteUserData(nNum);
2661 if (nCount==1) {
2662 pPlusData->pUserDataList.reset();
2664 } else {
2665 OSL_FAIL("SdrObject::DeleteUserData(): Invalid Index.");
2669 void SdrObject::SetUserCall(SdrObjUserCall* pUser)
2671 pUserCall = pUser;
2675 void SdrObject::SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle& rBoundRect) const
2677 SdrObject* pGroup(getParentSdrObjectFromSdrObject());
2679 if ( pUserCall )
2681 pUserCall->Changed( *this, eUserCall, rBoundRect );
2684 if(nullptr != pGroup && pGroup->GetUserCall())
2686 // broadcast to group
2687 SdrUserCallType eChildUserType = SdrUserCallType::ChildChangeAttr;
2689 switch( eUserCall )
2691 case SdrUserCallType::MoveOnly:
2692 eChildUserType = SdrUserCallType::ChildMoveOnly;
2693 break;
2695 case SdrUserCallType::Resize:
2696 eChildUserType = SdrUserCallType::ChildResize;
2697 break;
2699 case SdrUserCallType::ChangeAttr:
2700 eChildUserType = SdrUserCallType::ChildChangeAttr;
2701 break;
2703 case SdrUserCallType::Delete:
2704 eChildUserType = SdrUserCallType::ChildDelete;
2705 break;
2707 case SdrUserCallType::Inserted:
2708 eChildUserType = SdrUserCallType::ChildInserted;
2709 break;
2711 case SdrUserCallType::Removed:
2712 eChildUserType = SdrUserCallType::ChildRemoved;
2713 break;
2715 default: break;
2718 pGroup->GetUserCall()->Changed( *this, eChildUserType, rBoundRect );
2721 // notify our UNO shape listeners
2722 switch ( eUserCall )
2724 case SdrUserCallType::Resize:
2725 notifyShapePropertyChange( svx::ShapeProperty::Size );
2726 [[fallthrough]]; // RESIZE might also imply a change of the position
2727 case SdrUserCallType::MoveOnly:
2728 notifyShapePropertyChange( svx::ShapeProperty::Position );
2729 break;
2730 default:
2731 // not interested in
2732 break;
2736 void SdrObject::impl_setUnoShape( const uno::Reference< uno::XInterface >& _rxUnoShape )
2738 const uno::Reference< uno::XInterface>& xOldUnoShape( maWeakUnoShape );
2739 // the UNO shape would be gutted by the following code; return early
2740 if ( _rxUnoShape == xOldUnoShape )
2742 if ( !xOldUnoShape.is() )
2744 // make sure there is no stale impl. pointer if the UNO
2745 // shape was destroyed meanwhile (remember we only hold weak
2746 // reference to it!)
2747 mpSvxShape = nullptr;
2749 return;
2752 bool bTransferOwnership( false );
2753 if ( xOldUnoShape.is() )
2755 bTransferOwnership = mpSvxShape->HasSdrObjectOwnership();
2756 // Remove yourself from the current UNO shape. Its destructor
2757 // will reset our UNO shape otherwise.
2758 mpSvxShape->InvalidateSdrObject();
2761 maWeakUnoShape = _rxUnoShape;
2762 mpSvxShape = comphelper::getUnoTunnelImplementation<SvxShape>( _rxUnoShape );
2764 // I think this may never happen... But I am not sure enough .-)
2765 if ( bTransferOwnership )
2767 if (mpSvxShape)
2768 mpSvxShape->TakeSdrObjectOwnership();
2769 SAL_WARN( "svx.uno", "a UNO shape took over an SdrObject previously owned by another UNO shape!");
2773 /** only for internal use! */
2774 SvxShape* SdrObject::getSvxShape()
2776 DBG_TESTSOLARMUTEX();
2777 // retrieving the impl pointer and subsequently using it is not thread-safe, of course, so it needs to be
2778 // guarded by the SolarMutex
2780 uno::Reference< uno::XInterface > xShape( maWeakUnoShape );
2781 #if OSL_DEBUG_LEVEL > 0
2782 OSL_ENSURE( !( !xShape.is() && mpSvxShape ),
2783 "SdrObject::getSvxShape: still having IMPL-Pointer to dead object!" );
2784 #endif
2785 //#113608#, make sure mpSvxShape is always synchronized with maWeakUnoShape
2786 if ( mpSvxShape && !xShape.is() )
2787 mpSvxShape = nullptr;
2789 return mpSvxShape;
2792 css::uno::Reference< css::uno::XInterface > SdrObject::getUnoShape()
2794 // try weak reference first
2795 uno::Reference< uno::XInterface > xShape( getWeakUnoShape() );
2796 if( !xShape.is() )
2798 OSL_ENSURE( mpSvxShape == nullptr, "SdrObject::getUnoShape: XShape already dead, but still an IMPL pointer!" );
2800 // try to access SdrPage from this SdrObject. This will only exist if the SdrObject is
2801 // inserted in a SdrObjList (page/group/3dScene)
2802 SdrPage* pPageCandidate(getSdrPageFromSdrObject());
2804 // tdf#12152, tdf#120728
2806 // With the paradigm change to only get a SdrPage for a SdrObject when the SdrObject
2807 // is *inserted*, the functionality for creating 1:1 associated UNO API implementation
2808 // SvxShapes was partially broken: The used ::CreateShape relies on the SvxPage being
2809 // derived and the CreateShape method overloaded, implementing additional SdrInventor
2810 // types as needed.
2812 // The fallback to use SvxDrawPage::CreateShapeByTypeAndInventor is a trap: It's only
2813 // a static fallback that handles the SdrInventor types SdrInventor::E3d and
2814 // SdrInventor::Default. Due to that, e.g. the ReportDesigner broke in various conditions.
2816 // That again has to do with the ReportDesigner being implemented using the UNO API
2817 // aspects of SdrObjects early during their construction, not just after these are
2818 // inserted to a SdrPage - but that is not illegal or wrong, the SdrObject exists already.
2820 // As a current solution, use the (now always available) SdrModel and any of the
2821 // existing SdrPages. The only important thing is to get a SdrPage where ::CreateShape is
2822 // overloaded and implemented as needed.
2824 // Note for the future:
2825 // In a more ideal world there would be only one factory method for creating SdrObjects (not
2826 // ::CreateShape and ::CreateShapeByTypeAndInventor). This also would not be placed at
2827 // SdrPage/SvxPage at all, but at the Model where it belongs - where else would you expect
2828 // objects for the current Model to be constructed? To have this at the Page only would make
2829 // sense if different shapes would need to be constructed for different Pages in the same Model
2830 // - this is never the case.
2831 // At that Model extended functionality for that factory (or overloads and implementations)
2832 // should be placed. But to be realistic, migrating the factories to Model now is too much
2833 // work - maybe over time when melting SdrObject/SvxObject one day...
2834 if(nullptr == pPageCandidate)
2836 // If not inserted, alternatively access a SdrPage using the SdrModel. There is
2837 // no reason not to create and return a UNO API XShape when the SdrObject is not
2838 // inserted - it may be in construction. Main paradigm is that it exists.
2839 if(0 != getSdrModelFromSdrObject().GetPageCount())
2841 // Take 1st SdrPage. That may be e.g. a special page (in SD), but the
2842 // to-be-used method ::CreateShape will be correctly overloaded in
2843 // all cases
2844 pPageCandidate = getSdrModelFromSdrObject().GetPage(0);
2848 if(nullptr != pPageCandidate)
2850 uno::Reference< uno::XInterface > xPage(pPageCandidate->getUnoPage());
2851 if( xPage.is() )
2853 SvxDrawPage* pDrawPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>(xPage);
2854 if( pDrawPage )
2856 // create one
2857 xShape = pDrawPage->CreateShape( this );
2858 impl_setUnoShape( xShape );
2862 else
2864 // Fallback to static base functionality. CAUTION: This will only support
2865 // the most basic stuff like SdrInventor::E3d and SdrInventor::Default. All
2866 // the other SdrInventor enum entries are from overloads and are *not accessible*
2867 // using this fallback (!) - what a bad trap
2868 mpSvxShape = SvxDrawPage::CreateShapeByTypeAndInventor( GetObjIdentifier(), GetObjInventor(), this );
2869 maWeakUnoShape = xShape = static_cast< ::cppu::OWeakObject* >( mpSvxShape );
2873 return xShape;
2876 void SdrObject::setUnoShape(const uno::Reference<uno::XInterface >& _rxUnoShape)
2878 impl_setUnoShape( _rxUnoShape );
2881 svx::PropertyChangeNotifier& SdrObject::getShapePropertyChangeNotifier()
2883 DBG_TESTSOLARMUTEX();
2885 SvxShape* pSvxShape = getSvxShape();
2886 ENSURE_OR_THROW( pSvxShape, "no SvxShape, yet!" );
2887 return pSvxShape->getShapePropertyChangeNotifier();
2890 void SdrObject::notifyShapePropertyChange( const svx::ShapeProperty _eProperty ) const
2892 DBG_TESTSOLARMUTEX();
2894 SvxShape* pSvxShape = const_cast< SdrObject* >( this )->getSvxShape();
2895 if ( pSvxShape )
2896 return pSvxShape->getShapePropertyChangeNotifier().notifyPropertyChange( _eProperty );
2900 // transformation interface for StarOfficeAPI. This implements support for
2901 // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
2902 // moment it contains a shearX, rotation and translation, but for setting all linear
2903 // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
2906 // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
2907 // with the base geometry and returns TRUE. Otherwise it returns FALSE.
2908 bool SdrObject::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
2910 // any kind of SdrObject, just use SnapRect
2911 tools::Rectangle aRectangle(GetSnapRect());
2913 // convert to transformation values
2914 basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
2915 basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());
2917 // position maybe relative to anchorpos, convert
2918 if(getSdrModelFromSdrObject().IsWriter())
2920 if(GetAnchorPos().X() || GetAnchorPos().Y())
2922 aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
2926 // build matrix
2927 rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
2929 return false;
2932 // sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
2933 // If it's an SdrPathObj it will use the provided geometry information. The Polygon has
2934 // to use (0,0) as upper left and will be scaled to the given size in the matrix.
2935 void SdrObject::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
2937 // break up matrix
2938 basegfx::B2DTuple aScale;
2939 basegfx::B2DTuple aTranslate;
2940 double fRotate, fShearX;
2941 rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
2943 // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
2944 // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
2945 if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
2947 aScale.setX(fabs(aScale.getX()));
2948 aScale.setY(fabs(aScale.getY()));
2951 // if anchor is used, make position relative to it
2952 if(getSdrModelFromSdrObject().IsWriter())
2954 if(GetAnchorPos().X() || GetAnchorPos().Y())
2956 aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
2960 // build BaseRect
2961 Point aPoint(FRound(aTranslate.getX()), FRound(aTranslate.getY()));
2962 tools::Rectangle aBaseRect(aPoint, Size(FRound(aScale.getX()), FRound(aScale.getY())));
2964 // set BaseRect
2965 SetSnapRect(aBaseRect);
2968 // Give info if object is in destruction
2969 bool SdrObject::IsInDestruction() const
2971 return getSdrModelFromSdrObject().IsInDestruction();
2974 // return if fill is != drawing::FillStyle_NONE
2975 bool SdrObject::HasFillStyle() const
2977 return GetObjectItem(XATTR_FILLSTYLE).GetValue() != drawing::FillStyle_NONE;
2980 bool SdrObject::HasLineStyle() const
2982 return GetObjectItem(XATTR_LINESTYLE).GetValue() != drawing::LineStyle_NONE;
2986 // #i52224#
2987 // on import of OLE object from MS documents the BLIP size might be retrieved,
2988 // the following four methods are used to control it;
2989 // usually this data makes no sense after the import is finished, since the object
2990 // might be resized
2993 void SdrObject::SetBLIPSizeRectangle( const tools::Rectangle& aRect )
2995 maBLIPSizeRectangle = aRect;
2998 void SdrObject::SetContextWritingMode( const sal_Int16 /*_nContextWritingMode*/ )
3000 // this base class does not support different writing modes, so ignore the call
3003 void SdrObject::SetDoNotInsertIntoPageAutomatically(const bool bSet)
3005 mbDoNotInsertIntoPageAutomatically = bSet;
3009 // #i121917#
3010 bool SdrObject::HasText() const
3012 return false;
3015 bool SdrObject::IsTextBox() const
3017 return false;
3020 void SdrObject::MakeNameUnique()
3022 std::unordered_set<OUString> aNameSet;
3023 MakeNameUnique(aNameSet);
3026 void SdrObject::MakeNameUnique(std::unordered_set<OUString>& rNameSet)
3028 if (GetName().isEmpty())
3029 return;
3031 if (rNameSet.empty())
3033 SdrPage* pPage;
3034 SdrObject* pObj;
3035 for (sal_uInt16 nPage(0); nPage < mrSdrModelFromSdrObject.GetPageCount(); ++nPage)
3037 pPage = mrSdrModelFromSdrObject.GetPage(nPage);
3038 SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
3039 while (aIter.IsMore())
3041 pObj = aIter.Next();
3042 if (pObj != this)
3043 rNameSet.insert(pObj->GetName());
3048 OUString sName(GetName());
3049 OUString sRootName(GetName());
3050 sal_Int32 index = sName.lastIndexOf("_");
3051 if ( index > 0)
3052 sRootName = sRootName.copy(0, index);
3054 sal_uInt32 n = 0;
3055 while (rNameSet.find(sName) != rNameSet.end())
3057 sName = sRootName + "_" + OUString::number(n++);
3059 rNameSet.insert(sName);
3061 SetName(sName);
3064 SdrObject* SdrObjFactory::CreateObjectFromFactory(SdrModel& rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier)
3066 SdrObjCreatorParams aParams { nInventor, nObjIdentifier, rSdrModel };
3067 for (const auto & i : ImpGetUserMakeObjHdl()) {
3068 SdrObject* pObj = i.Call(aParams);
3069 if (pObj) {
3070 return pObj;
3073 return nullptr;
3076 SdrObject* SdrObjFactory::MakeNewObject(
3077 SdrModel& rSdrModel,
3078 SdrInventor nInventor,
3079 SdrObjKind nIdentifier,
3080 const tools::Rectangle* pSnapRect)
3082 SdrObject* pObj(nullptr);
3083 bool bSetSnapRect(nullptr != pSnapRect);
3085 if (nInventor == SdrInventor::Default)
3087 switch (nIdentifier)
3089 case OBJ_MEASURE:
3091 if(nullptr != pSnapRect)
3093 pObj = new SdrMeasureObj(
3094 rSdrModel,
3095 pSnapRect->TopLeft(),
3096 pSnapRect->BottomRight());
3098 else
3100 pObj = new SdrMeasureObj(rSdrModel);
3103 break;
3104 case OBJ_LINE:
3106 if(nullptr != pSnapRect)
3108 basegfx::B2DPolygon aPoly;
3110 aPoly.append(
3111 basegfx::B2DPoint(
3112 pSnapRect->Left(),
3113 pSnapRect->Top()));
3114 aPoly.append(
3115 basegfx::B2DPoint(
3116 pSnapRect->Right(),
3117 pSnapRect->Bottom()));
3118 pObj = new SdrPathObj(
3119 rSdrModel,
3120 OBJ_LINE,
3121 basegfx::B2DPolyPolygon(aPoly));
3123 else
3125 pObj = new SdrPathObj(
3126 rSdrModel,
3127 OBJ_LINE);
3130 break;
3131 case OBJ_TEXT:
3132 case OBJ_TITLETEXT:
3133 case OBJ_OUTLINETEXT:
3135 if(nullptr != pSnapRect)
3137 pObj = new SdrRectObj(
3138 rSdrModel,
3139 nIdentifier,
3140 *pSnapRect);
3141 bSetSnapRect = false;
3143 else
3145 pObj = new SdrRectObj(
3146 rSdrModel,
3147 nIdentifier);
3150 break;
3151 case OBJ_CIRC:
3152 case OBJ_SECT:
3153 case OBJ_CARC:
3154 case OBJ_CCUT:
3156 SdrCircKind eCircKind = ToSdrCircKind(nIdentifier);
3157 if(nullptr != pSnapRect)
3159 pObj = new SdrCircObj(rSdrModel, eCircKind, *pSnapRect);
3160 bSetSnapRect = false;
3162 else
3164 pObj = new SdrCircObj(rSdrModel, eCircKind);
3167 break;
3168 case OBJ_NONE : pObj=new SdrObject(rSdrModel); break;
3169 case OBJ_GRUP : pObj=new SdrObjGroup(rSdrModel); break;
3170 case OBJ_POLY : pObj=new SdrPathObj(rSdrModel, OBJ_POLY ); break;
3171 case OBJ_PLIN : pObj=new SdrPathObj(rSdrModel, OBJ_PLIN ); break;
3172 case OBJ_PATHLINE : pObj=new SdrPathObj(rSdrModel, OBJ_PATHLINE ); break;
3173 case OBJ_PATHFILL : pObj=new SdrPathObj(rSdrModel, OBJ_PATHFILL ); break;
3174 case OBJ_FREELINE : pObj=new SdrPathObj(rSdrModel, OBJ_FREELINE ); break;
3175 case OBJ_FREEFILL : pObj=new SdrPathObj(rSdrModel, OBJ_FREEFILL ); break;
3176 case OBJ_PATHPOLY : pObj=new SdrPathObj(rSdrModel, OBJ_POLY ); break;
3177 case OBJ_PATHPLIN : pObj=new SdrPathObj(rSdrModel, OBJ_PLIN ); break;
3178 case OBJ_EDGE : pObj=new SdrEdgeObj(rSdrModel); break;
3179 case OBJ_RECT : pObj=new SdrRectObj(rSdrModel); break;
3180 case OBJ_GRAF : pObj=new SdrGrafObj(rSdrModel); break;
3181 case OBJ_OLE2 : pObj=new SdrOle2Obj(rSdrModel); break;
3182 case OBJ_FRAME : pObj=new SdrOle2Obj(rSdrModel, true); break;
3183 case OBJ_CAPTION : pObj=new SdrCaptionObj(rSdrModel); break;
3184 case OBJ_PAGE : pObj=new SdrPageObj(rSdrModel); break;
3185 case OBJ_UNO : pObj=new SdrUnoObj(rSdrModel, OUString()); break;
3186 case OBJ_CUSTOMSHAPE: pObj=new SdrObjCustomShape(rSdrModel); break;
3187 #if HAVE_FEATURE_AVMEDIA
3188 case OBJ_MEDIA : pObj=new SdrMediaObj(rSdrModel); break;
3189 #endif
3190 case OBJ_TABLE : pObj=new sdr::table::SdrTableObj(rSdrModel); break;
3191 default: break;
3195 if (!pObj)
3197 pObj = CreateObjectFromFactory(rSdrModel, nInventor, nIdentifier);
3200 if (!pObj)
3202 // Well, if no one wants it...
3203 return nullptr;
3206 if(bSetSnapRect && nullptr != pSnapRect)
3208 pObj->SetSnapRect(*pSnapRect);
3211 return pObj;
3214 void SdrObjFactory::InsertMakeObjectHdl(Link<SdrObjCreatorParams, SdrObject*> const & rLink)
3216 std::vector<Link<SdrObjCreatorParams, SdrObject*>>& rLL=ImpGetUserMakeObjHdl();
3217 auto it = std::find(rLL.begin(), rLL.end(), rLink);
3218 if (it != rLL.end()) {
3219 OSL_FAIL("SdrObjFactory::InsertMakeObjectHdl(): Link already in place.");
3220 } else {
3221 rLL.push_back(rLink);
3225 void SdrObjFactory::RemoveMakeObjectHdl(Link<SdrObjCreatorParams, SdrObject*> const & rLink)
3227 std::vector<Link<SdrObjCreatorParams, SdrObject*>>& rLL=ImpGetUserMakeObjHdl();
3228 auto it = std::find(rLL.begin(), rLL.end(), rLink);
3229 if (it != rLL.end())
3230 rLL.erase(it);
3233 namespace svx
3235 ISdrObjectFilter::~ISdrObjectFilter()
3240 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */