Files
odfstudio/svx/source/svdraw/svdobj.cxx
T
Armin Le Grand (collabora) 5519a3d407 Correct StyleSheet handling when cloning to different Model II
Until now the 'local' StyleSheet got set, but that may
not be the same as the original. It was/gets identified just
by searching by name and type, not comparing content.

What to do? We could...

(a) the Style-Friendly way:
 - check if StyleSheet is identical
  - if not, create a new in-between StyleSheet hosting missing Items
  - if yes, use, done.

(b) the pragmatic/practical way:
 - Just hard-attribute the Items that are detected as different
   similar to what BurnInStyleSheetAttributes does/did, but only
   for a view differing Items

(b) is the most simple for now, but will lead to more hard
attributes. The other possibilities will be better in the
long term. For now, I will use (b).

Note that there are more cases in that VERY complex and grown
stuff emerging from SdDrawDocument::PasteBookmarkAsPage. More
things will need to be fixed, see this as a 1st step.

Needed to adapt postProcessAfterCloneToDifferentModel due to
UT testTdf96206 failing, see comment there for details.

That 1st implementation showed weaknesses with those Items
critical and only on MasterPages, so decided to give up on
that and implement ContentCompare to SdPage::Equals. That
was easier than thought: No parameter needed, only used by
InsertBookmarkAsPage_FindDuplicateLayouts::operator(). Thus,
SdPage::Equals needs no change, just SdrObject::Equals.

Due to still problems with Items corrected in Objects on
MasterPages I will for now exclude this.

Could now isolate remaining problems, these are defaults
and/or PresObj things on MasterPages. Important is that I can
completely correct all Items for all Objects in
postProcessAfterCloneToDifferentModel. I can react to these
false-positives in the ContentCompare in SdrObject::Equals.

Signed-off-by: Armin Le Grand (collabora) <Armin.LeGrand@collabora.com>
Change-Id: I10e17c8d6a893dbe92ab716182f07bafce1f3284
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/6595
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Armin Le Grand <armin.legrand@collabora.com>
(cherry picked from commit 92ffaeac04c5c8586006b026f29ce12fba3674f1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211729
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-10-05 08:52:54 +02:00

3753 lines
112 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <svx/svdobj.hxx>
#include <config_features.h>
#include <sal/config.h>
#include <com/sun/star/text/RelOrientation.hpp>
#include <com/sun/star/frame/XTerminateListener.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/range/b2drange.hxx>
#include <drawinglayer/processor2d/contourextractor2d.hxx>
#include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/sequence.hxx>
#include <editeng/editeng.hxx>
#include <editeng/outlobj.hxx>
#include <o3tl/deleter.hxx>
#include <math.h>
#include <svl/grabbagitem.hxx>
#include <tools/bigint.hxx>
#include <tools/helpers.hxx>
#include <comphelper/configuration.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/ptrstyle.hxx>
#include <vector>
#include <svx/svdotable.hxx>
#include <svx/diagram/DiagramHelper_svx.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <sdr/contact/objectcontactofobjlistpainter.hxx>
#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
#include <sdr/properties/emptyproperties.hxx>
#include <svx/annotation/ObjectAnnotationData.hxx>
#include <svx/sdrhittesthelper.hxx>
#include <svx/sdrobjectuser.hxx>
#include <svx/sdrobjectfilter.hxx>
#include <svx/svddrag.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdhdl.hxx>
#include <svx/svditer.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdoashp.hxx>
#include <svx/svdocapt.hxx>
#include <svx/svdocirc.hxx>
#include <svx/svdoedge.hxx>
#include <svx/svdograf.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdomeas.hxx>
#include <svx/svdomedia.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdopage.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdotext.hxx>
#include <svx/svdouno.hxx>
#include <svx/svdovirt.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpool.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdundo.hxx>
#include <svx/svdview.hxx>
#include <sxlayitm.hxx>
#include <sxlogitm.hxx>
#include <sxmovitm.hxx>
#include <sxoneitm.hxx>
#include <sxopitm.hxx>
#include <sxreoitm.hxx>
#include <sxrooitm.hxx>
#include <sxsaitm.hxx>
#include <sxsoitm.hxx>
#include <sxtraitm.hxx>
#include <svx/unopage.hxx>
#include <svx/unoshape.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xflclit.hxx>
#include <svx/xfltrit.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xlnclit.hxx>
#include <svx/xlnedwit.hxx>
#include <svx/xlnstwit.hxx>
#include <svx/xlntrit.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/svdglue.hxx>
#include <svx/svdsob.hxx>
#include <svl/whiter.hxx>
#include <svdobjplusdata.hxx>
#include <svdobjuserdatalist.hxx>
#include <svx/xfillit0.hxx>
#include <optional>
#include <libxml/xmlwriter.h>
#include <memory>
#include <svx/scene3d.hxx>
#include <rtl/character.hxx>
#include <tools/debug.hxx>
#include <tools/UnitConversion.hxx>
#include <o3tl/string_view.hxx>
#include <tools/lazydelete.hxx>
using namespace ::com::sun::star;
SdrObjUserCall::~SdrObjUserCall()
{
}
void SdrObjUserCall::Changed(const SdrObject& /*rObj*/, SdrUserCallType /*eType*/, const tools::Rectangle& /*rOldBoundRect*/)
{
}
void const* SdrObjUserCall::GetPDFAnchorStructureElementKey(SdrObject const&)
{
return nullptr;
}
SdrObjMacroHitRec::SdrObjMacroHitRec() :
pVisiLayer(nullptr),
pPageView(nullptr),
nTol(0) {}
SdrObjUserData::SdrObjUserData(SdrInventor nInv, sal_uInt16 nId) :
m_nInventor(nInv),
m_nIdentifier(nId) {}
SdrObjUserData::SdrObjUserData(const SdrObjUserData& rData) :
m_nInventor(rData.m_nInventor),
m_nIdentifier(rData.m_nIdentifier) {}
SdrObjUserData::~SdrObjUserData() {}
SdrObjGeoData::SdrObjGeoData():
bMovProt(false),
bSizProt(false),
bNoPrint(false),
bClosedObj(false),
mbVisible(true),
mnLayerID(0)
{
}
SdrObjGeoData::~SdrObjGeoData()
{
}
SdrObjTransformInfoRec::SdrObjTransformInfoRec() :
bMoveAllowed(true),
bResizeFreeAllowed(true),
bResizePropAllowed(true),
bRotateFreeAllowed(true),
bRotate90Allowed(true),
bMirrorFreeAllowed(true),
bMirror45Allowed(true),
bMirror90Allowed(true),
bTransparenceAllowed(true),
bShearAllowed(true),
bEdgeRadiusAllowed(true),
bNoOrthoDesired(true),
bNoContortion(true),
bCanConvToPath(true),
bCanConvToPoly(true),
bCanConvToContour(false),
bCanConvToPathLineToArea(true),
bCanConvToPolyLineToArea(true) {}
struct SdrObject::Impl
{
sdr::ObjectUserVector maObjectUsers;
std::optional<double> mnRelativeWidth;
std::optional<double> mnRelativeHeight;
sal_Int16 meRelativeWidthRelation;
sal_Int16 meRelativeHeightRelation;
Impl() :
meRelativeWidthRelation(text::RelOrientation::PAGE_FRAME),
meRelativeHeightRelation(text::RelOrientation::PAGE_FRAME) {}
};
bool SdrObject::ObjectNameIsDiagramModelID()
{
if (!m_pPlusData)
return false;
const OUString& rStr(m_pPlusData->aObjName);
if (rStr.isEmpty())
return false;
// length is fixed (38 chars)
if (38 != rStr.getLength())
return false;
// starts and ends with curly braces
const sal_Unicode* pStr(rStr.getStr());
if (pStr[0] != '{' || pStr[37] != '}')
return false;
// has 'minus' signs at positions 9, 14, 19 and 24
const char minus('-');
if (pStr[9] != minus || pStr[14] != minus || pStr[19] != minus || pStr[24] != minus)
return false;
// we could also check for upper-case hex alphabet (0..9, A..F) for
// the rest of characters, but should be safe enough already
return true;
}
void SdrObject::setDiagramDataModelID(const OUString& rID)
{
if (!m_pPlusData)
ImpForcePlusData();
m_pPlusData->aObjName = rID;
}
const OUString& SdrObject::getDiagramDataModelID() const
{
if(m_pPlusData)
return m_pPlusData->aObjName;
return EMPTY_OUSTRING;
}
bool SdrObject::isDiagramBackgroundShape() const
{
const OUString& rID(getDiagramDataModelID());
if (rID.isEmpty())
return false;
const std::shared_ptr< svx::diagram::DiagramHelper_svx >& rDiagramHelper(getDiagramHelper());
if (!rDiagramHelper)
return false;
return rID == rDiagramHelper->getBackgroundShapeModelID();
}
bool SdrObject::isDiagramTextNode() const
{
const OUString& rID(getDiagramDataModelID());
if (rID.isEmpty())
return false;
const std::shared_ptr< svx::diagram::DiagramHelper_svx >& rDiagramHelper(getDiagramHelper());
if (!rDiagramHelper)
return false;
return rDiagramHelper->isTextNodeModelID(rID);
}
bool SdrObject::removeDiagramNode()
{
const OUString& rID(getDiagramDataModelID());
if (rID.isEmpty())
return false;
const std::shared_ptr< svx::diagram::DiagramHelper_svx >& rDiagramHelper(getDiagramHelper());
if (!rDiagramHelper)
return false;
return rDiagramHelper->removeDiagramNode(rID, getSdrModelFromSdrObject());
}
void SdrObject::resetViewContact()
{
mpViewContact.reset();
}
bool SdrObject::isDiagram() const
{
return false;
}
bool SdrObject::useAdvancedDiagramFeatures()
{
static bool bChecked(false);
static bool bUse(false);
if (!bChecked)
{
// NOTE: We could also use
// officecfg::Office::Common::Misc::ExperimentalMode::get()
// but for now env var will do...
bUse = (nullptr != std::getenv("ACTIVATE_ADVANCED_DIAGRAM_FEATURES"));
bChecked = true;
}
return bUse;
}
const std::shared_ptr< svx::diagram::DiagramHelper_svx >& SdrObject::getDiagramHelper() const
{
const SdrObject* pCurrent(this);
do
{
if (pCurrent->isDiagram())
return pCurrent->getDiagramHelper();
pCurrent = pCurrent->getParentSdrObjectFromSdrObject();
}
while(nullptr != pCurrent);
static std::shared_ptr< svx::diagram::DiagramHelper_svx > aEmpty;
return aEmpty;
}
SdrObject* SdrObject::getDiagramSubSelection()
{
return this;
}
// BaseProperties section
sdr::properties::BaseProperties& SdrObject::GetProperties() const
{
if(!mpProperties)
{
// CAUTION(!) Do *not* call this during SdrObject construction,
// that will lead to wrong type-casts (dependent on constructor-level)
// and thus eventually create the wrong sdr::properties (!). Is there
// a way to check if on the stack is a SdrObject-constructor (?)
const_cast< SdrObject* >(this)->mpProperties =
const_cast< SdrObject* >(this)->CreateObjectSpecificProperties();
}
return *mpProperties;
}
// ObjectUser section
void SdrObject::AddObjectUser(sdr::ObjectUser& rNewUser)
{
mpImpl->maObjectUsers.push_back(&rNewUser);
}
void SdrObject::RemoveObjectUser(sdr::ObjectUser& rOldUser)
{
const sdr::ObjectUserVector::iterator aFindResult =
std::find(mpImpl->maObjectUsers.begin(), mpImpl->maObjectUsers.end(), &rOldUser);
if (aFindResult != mpImpl->maObjectUsers.end())
{
mpImpl->maObjectUsers.erase(aFindResult);
}
}
// DrawContact section
std::unique_ptr<sdr::contact::ViewContact> SdrObject::CreateObjectSpecificViewContact()
{
return std::make_unique<sdr::contact::ViewContactOfSdrObj>(*this);
}
sdr::contact::ViewContact& SdrObject::GetViewContact() const
{
if(!mpViewContact)
{
const_cast< SdrObject* >(this)->mpViewContact =
const_cast< SdrObject* >(this)->CreateObjectSpecificViewContact();
}
return *mpViewContact;
}
// DrawContact support: Methods for handling Object changes
void SdrObject::ActionChanged() const
{
// Do necessary ViewContact actions
GetViewContact().ActionChanged();
}
SdrPage* SdrObject::getSdrPageFromSdrObject() const
{
if (SdrObjList* pParentList = getParentSdrObjListFromSdrObject())
{
return pParentList->getSdrPageFromSdrObjList();
}
return nullptr;
}
SdrModel& SdrObject::getSdrModelFromSdrObject() const
{
return mrSdrModelFromSdrObject;
}
void SdrObject::setParentOfSdrObject(SdrObjList* pNewObjList)
{
assert(!pNewObjList || mpParentOfSdrObject != pNewObjList);
if(mpParentOfSdrObject == pNewObjList)
return;
// we need to be removed from the old parent before we are attached to the new parent
assert(bool(mpParentOfSdrObject) != bool(pNewObjList) && "may only transition empty->full or full->empty");
// remember current page
SdrPage* pOldPage(getSdrPageFromSdrObject());
// set new parent
mpParentOfSdrObject = pNewObjList;
// get new page
SdrPage* pNewPage(getSdrPageFromSdrObject());
// broadcast page change over objects if needed
if(pOldPage != pNewPage)
{
handlePageChange(pOldPage, pNewPage);
}
}
SdrObjList* SdrObject::getParentSdrObjListFromSdrObject() const
{
return mpParentOfSdrObject;
}
SdrObjList* SdrObject::getChildrenOfSdrObject() const
{
// default has no children
return nullptr;
}
void SdrObject::SetBoundRectDirty()
{
resetOutRectangle();
}
void impAddIncarnatedSdrObjectToSdrModel(SdrObject& rSdrObject, SdrModel& rSdrModel)
{
rSdrModel.maAllIncarnatedObjects.insert(&rSdrObject);
}
void impRemoveIncarnatedSdrObjectToSdrModel(SdrObject& rSdrObject, SdrModel& rSdrModel)
{
if(!rSdrModel.maAllIncarnatedObjects.erase(&rSdrObject))
{
assert(false && "SdrObject::~SdrObject: Destructed incarnation of SdrObject not member of this SdrModel (!)");
}
}
SdrObject::SdrObject(SdrModel& rSdrModel)
: mpFillGeometryDefiningShape(nullptr)
, mrSdrModelFromSdrObject(rSdrModel)
, m_pUserCall(nullptr)
, mpImpl(new Impl)
, mpParentOfSdrObject(nullptr)
, m_nOrdNum(0)
, mnNavigationPosition(SAL_MAX_UINT32)
, mnLayerID(0)
, mpSvxShape( nullptr )
, mbDoNotInsertIntoPageAutomatically(false)
, msHyperlink()
{
m_bVirtObj =false;
m_bSnapRectDirty =true;
m_bMovProt =false;
m_bSizProt =false;
m_bDelProt =false;
m_bNoPrint =false;
m_bEmptyPresObj =false;
m_bNotVisibleAsMaster=false;
m_bClosedObj =false;
mbVisible = true;
// #i25616#
mbLineIsOutsideGeometry = false;
// #i25616#
mbSupportTextIndentingOnLineWidthChange = false;
m_bIsEdge=false;
m_bIs3DObj=false;
m_bMarkProt=false;
m_bIsUnoObj=false;
impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
}
SdrObject::SdrObject(SdrModel& rSdrModel, SdrObject const & rSource)
: mpFillGeometryDefiningShape(nullptr)
, mrSdrModelFromSdrObject(rSdrModel)
, m_pUserCall(nullptr)
, mpImpl(new Impl)
, mpParentOfSdrObject(nullptr)
, m_nOrdNum(0)
, mnNavigationPosition(SAL_MAX_UINT32)
, mnLayerID(0)
, mpSvxShape( nullptr )
, mbDoNotInsertIntoPageAutomatically(false)
, msHyperlink()
{
m_bVirtObj =false;
m_bSnapRectDirty =true;
m_bMovProt =false;
m_bDelProt =false;
m_bSizProt =false;
m_bNoPrint =false;
m_bEmptyPresObj =false;
m_bNotVisibleAsMaster=false;
m_bClosedObj =false;
mbVisible = true;
// #i25616#
mbLineIsOutsideGeometry = false;
// #i25616#
mbSupportTextIndentingOnLineWidthChange = false;
m_bIsEdge=false;
m_bIs3DObj=false;
m_bMarkProt=false;
m_bIsUnoObj=false;
mpProperties.reset();
resetViewContact();
// The CloneSdrObject() method uses the local copy constructor from the individual
// sdr::properties::BaseProperties class. Since the target class maybe for another
// draw object, an SdrObject needs to be provided, as in the normal constructor.
mpProperties = rSource.GetProperties().Clone(*this);
setOutRectangle(rSource.getOutRectangle());
mnLayerID = rSource.mnLayerID;
m_aAnchor =rSource.m_aAnchor;
m_bVirtObj=rSource.m_bVirtObj;
m_bSizProt=rSource.m_bSizProt;
m_bMovProt=rSource.m_bMovProt;
m_bNoPrint=rSource.m_bNoPrint;
mbVisible=rSource.mbVisible;
m_bMarkProt=rSource.m_bMarkProt;
m_bEmptyPresObj =rSource.m_bEmptyPresObj;
m_bNotVisibleAsMaster=rSource.m_bNotVisibleAsMaster;
m_bSnapRectDirty=true;
m_pPlusData.reset();
if (rSource.m_pPlusData!=nullptr) {
m_pPlusData.reset(rSource.m_pPlusData->Clone(this));
}
if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) {
m_pPlusData->pBroadcast.reset(); // broadcaster isn't copied
}
m_bHorizontalRule = rSource.m_bHorizontalRule;
m_pGrabBagItem.reset();
if (rSource.m_pGrabBagItem!=nullptr)
m_pGrabBagItem.reset(rSource.m_pGrabBagItem->Clone());
impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
}
SdrObject::~SdrObject()
{
#ifdef DBG_UTIL
// see logic in SdrObject::release
assert(m_refCount == -1);
#endif
// Tell all the registered ObjectUsers that the page is in destruction.
// And clear the vector. This means that user do not need to call RemoveObjectUser()
// when they get called from ObjectInDestruction().
sdr::ObjectUserVector aList;
aList.swap(mpImpl->maObjectUsers);
for(sdr::ObjectUser* pObjectUser : aList)
{
DBG_ASSERT(pObjectUser, "SdrObject::~SdrObject: corrupt ObjectUser list (!)");
pObjectUser->ObjectInDestruction(*this);
}
// UserCall
SendUserCall(SdrUserCallType::Delete, GetLastBoundRect());
o3tl::reset_preserve_ptr_during(m_pPlusData);
m_pGrabBagItem.reset();
mpProperties.reset();
resetViewContact();
impRemoveIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
}
void SdrObject::acquire() noexcept
{
#ifdef DBG_UTIL
assert(m_refCount != -1);
#endif
osl_atomic_increment( &m_refCount );
}
void SdrObject::release() noexcept
{
oslInterlockedCount x = osl_atomic_decrement( &m_refCount );
if ( x == 0 )
{
disposeWeakConnectionPoint();
#ifdef DBG_UTIL
// make sure it doesn't accidentally come back to life, see assert in acquire()
osl_atomic_decrement( &m_refCount );
#endif
delete this;
}
}
void SdrObject::SetBoundAndSnapRectsDirty(bool bNotMyself, bool bRecursive)
{
if (!bNotMyself)
{
SetBoundRectDirty();
m_bSnapRectDirty=true;
}
if (bRecursive && nullptr != getParentSdrObjListFromSdrObject())
{
getParentSdrObjListFromSdrObject()->SetSdrObjListRectsDirty();
}
}
void SdrObject::handlePageChange(SdrPage*, SdrPage* )
{
}
// init global static itempool
SdrItemPool& SdrObject::GetGlobalDrawObjectItemPool()
{
static tools::DeleteRtlReferenceOnDeinit<SdrItemPool> xGlobalItemPool( []() {
rtl::Reference<SdrItemPool> xNewPool(new SdrItemPool());
rtl::Reference<SfxItemPool> pGlobalOutlPool = EditEngine::CreatePool();
xNewPool->SetSecondaryPool(pGlobalOutlPool.get());
xNewPool->SetDefaultMetric(SdrEngineDefaults::GetMapUnit());
if (comphelper::IsFuzzing())
xNewPool->acquire();
return xNewPool;
}() );
return *xGlobalItemPool.get();
}
void SdrObject::SetRelativeWidth( double nValue )
{
mpImpl->mnRelativeWidth = nValue;
}
void SdrObject::SetRelativeWidthRelation( sal_Int16 eValue )
{
mpImpl->meRelativeWidthRelation = eValue;
}
void SdrObject::SetRelativeHeight( double nValue )
{
mpImpl->mnRelativeHeight = nValue;
}
void SdrObject::SetRelativeHeightRelation( sal_Int16 eValue )
{
mpImpl->meRelativeHeightRelation = eValue;
}
const double* SdrObject::GetRelativeWidth( ) const
{
if (!mpImpl->mnRelativeWidth)
return nullptr;
return &*mpImpl->mnRelativeWidth;
}
sal_Int16 SdrObject::GetRelativeWidthRelation() const
{
return mpImpl->meRelativeWidthRelation;
}
const double* SdrObject::GetRelativeHeight( ) const
{
if (!mpImpl->mnRelativeHeight)
return nullptr;
return &*mpImpl->mnRelativeHeight;
}
sal_Int16 SdrObject::GetRelativeHeightRelation() const
{
return mpImpl->meRelativeHeightRelation;
}
SfxItemPool& SdrObject::GetObjectItemPool() const
{
return getSdrModelFromSdrObject().GetItemPool();
}
SdrInventor SdrObject::GetObjInventor() const
{
return SdrInventor::Default;
}
SdrObjKind SdrObject::GetObjIdentifier() const
{
return SdrObjKind::NONE;
}
void SdrObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
{
rInfo.bRotateFreeAllowed=false;
rInfo.bMirrorFreeAllowed=false;
rInfo.bTransparenceAllowed = false;
rInfo.bShearAllowed =false;
rInfo.bEdgeRadiusAllowed=false;
rInfo.bCanConvToPath =false;
rInfo.bCanConvToPoly =false;
rInfo.bCanConvToContour = false;
rInfo.bCanConvToPathLineToArea=false;
rInfo.bCanConvToPolyLineToArea=false;
}
SdrLayerID SdrObject::GetLayer() const
{
return mnLayerID;
}
bool SdrObject::isVisibleOnAnyOfTheseLayers(const SdrLayerIDSet& rSet) const
{
if (rSet.IsSet(GetLayer()))
return true;
SdrObjList* pOL=GetSubList();
if (!pOL)
return false;
for (const rtl::Reference<SdrObject>& pObject : *pOL)
if (pObject->isVisibleOnAnyOfTheseLayers(rSet))
return true;
return false;
}
void SdrObject::NbcSetLayer(SdrLayerID nLayer)
{
mnLayerID = nLayer;
}
void SdrObject::SetLayer(SdrLayerID nLayer)
{
NbcSetLayer(nLayer);
SetChanged();
BroadcastObjectChange();
}
void SdrObject::AddListener(SfxListener& rListener)
{
ImpForcePlusData();
if (m_pPlusData->pBroadcast==nullptr) m_pPlusData->pBroadcast.reset(new SfxBroadcaster);
// SdrEdgeObj may be connected to same SdrObject on both ends so allow it
// to listen twice
SdrEdgeObj const*const pEdge(dynamic_cast<SdrEdgeObj const*>(&rListener));
rListener.StartListening(*m_pPlusData->pBroadcast, pEdge ? DuplicateHandling::Allow : DuplicateHandling::Unexpected);
}
void SdrObject::RemoveListener(SfxListener& rListener)
{
if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) {
rListener.EndListening(*m_pPlusData->pBroadcast);
if (!m_pPlusData->pBroadcast->HasListeners()) {
m_pPlusData->pBroadcast.reset();
}
}
}
SfxBroadcaster* SdrObject::GetBroadcaster() const
{
return m_pPlusData!=nullptr ? m_pPlusData->pBroadcast.get() : nullptr;
}
void SdrObject::AddReference(SdrVirtObj& rVrtObj)
{
AddListener(rVrtObj);
}
void SdrObject::DelReference(SdrVirtObj& rVrtObj)
{
RemoveListener(rVrtObj);
}
bool SdrObject::IsGroupObject() const
{
return GetSubList()!=nullptr;
}
SdrObjList* SdrObject::GetSubList() const
{
return nullptr;
}
SdrObject* SdrObject::getParentSdrObjectFromSdrObject() const
{
SdrObjList* pParent(getParentSdrObjListFromSdrObject());
if(nullptr == pParent)
{
return nullptr;
}
return pParent->getSdrObjectFromSdrObjList();
}
void SdrObject::SetName(const OUString& rStr, const bool bSetChanged)
{
if (!rStr.isEmpty() && !m_pPlusData)
{
ImpForcePlusData();
}
if(!(m_pPlusData && m_pPlusData->aObjName != rStr))
return;
// Undo/Redo for setting object's name (#i73249#)
bool bUndo( false );
if ( getSdrModelFromSdrObject().IsUndoEnabled() )
{
bUndo = true;
std::unique_ptr<SdrUndoAction> pUndoAction =
SdrUndoFactory::CreateUndoObjectStrAttr(
*this,
SdrUndoObjStrAttr::ObjStrAttrType::Name,
GetName(),
rStr );
getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
}
m_pPlusData->aObjName = rStr;
// Undo/Redo for setting object's name (#i73249#)
if ( bUndo )
{
getSdrModelFromSdrObject().EndUndo();
}
if (bSetChanged)
{
SetChanged();
BroadcastObjectChange();
}
}
const OUString & SdrObject::GetName() const
{
if(m_pPlusData)
{
return m_pPlusData->aObjName;
}
return EMPTY_OUSTRING;
}
void SdrObject::SetTitle(const OUString& rStr)
{
if (!rStr.isEmpty() && !m_pPlusData)
{
ImpForcePlusData();
}
if(!(m_pPlusData && m_pPlusData->aObjTitle != rStr))
return;
// Undo/Redo for setting object's title (#i73249#)
bool bUndo( false );
if ( getSdrModelFromSdrObject().IsUndoEnabled() )
{
bUndo = true;
std::unique_ptr<SdrUndoAction> pUndoAction =
SdrUndoFactory::CreateUndoObjectStrAttr(
*this,
SdrUndoObjStrAttr::ObjStrAttrType::Title,
GetTitle(),
rStr );
getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
}
m_pPlusData->aObjTitle = rStr;
// Undo/Redo for setting object's title (#i73249#)
if ( bUndo )
{
getSdrModelFromSdrObject().EndUndo();
}
SetChanged();
BroadcastObjectChange();
}
OUString SdrObject::GetTitle() const
{
if(m_pPlusData)
{
return m_pPlusData->aObjTitle;
}
return OUString();
}
void SdrObject::SetDescription(const OUString& rStr)
{
if (!rStr.isEmpty() && !m_pPlusData)
{
ImpForcePlusData();
}
if(!(m_pPlusData && m_pPlusData->aObjDescription != rStr))
return;
// Undo/Redo for setting object's description (#i73249#)
bool bUndo( false );
if ( getSdrModelFromSdrObject().IsUndoEnabled() )
{
bUndo = true;
std::unique_ptr<SdrUndoAction> pUndoAction =
SdrUndoFactory::CreateUndoObjectStrAttr(
*this,
SdrUndoObjStrAttr::ObjStrAttrType::Description,
GetDescription(),
rStr );
getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
}
m_pPlusData->aObjDescription = rStr;
// Undo/Redo for setting object's description (#i73249#)
if ( bUndo )
{
getSdrModelFromSdrObject().EndUndo();
}
SetChanged();
BroadcastObjectChange();
}
OUString SdrObject::GetDescription() const
{
if(m_pPlusData)
{
return m_pPlusData->aObjDescription;
}
return OUString();
}
void SdrObject::SetDecorative(bool const isDecorative)
{
ImpForcePlusData();
if (m_pPlusData->isDecorative == isDecorative)
{
return;
}
if (getSdrModelFromSdrObject().IsUndoEnabled())
{
std::unique_ptr<SdrUndoAction> pUndoAction(
SdrUndoFactory::CreateUndoObjectDecorative(
*this, m_pPlusData->isDecorative));
getSdrModelFromSdrObject().BegUndo(pUndoAction->GetComment());
getSdrModelFromSdrObject().AddUndo(std::move(pUndoAction));
}
m_pPlusData->isDecorative = isDecorative;
if (getSdrModelFromSdrObject().IsUndoEnabled())
{
getSdrModelFromSdrObject().EndUndo();
}
SetChanged();
BroadcastObjectChange();
}
bool SdrObject::IsDecorative() const
{
return m_pPlusData == nullptr ? false : m_pPlusData->isDecorative;
}
void SdrObject::setAsAnnotationObject()
{
if (!mpAnnotationData)
mpAnnotationData = std::make_unique<sdr::annotation::ObjectAnnotationData>();
}
std::unique_ptr<sdr::annotation::ObjectAnnotationData>& SdrObject::getAnnotationData()
{
return mpAnnotationData;
}
sal_uInt32 SdrObject::GetOrdNum() const
{
if (SdrObjList* pParentList = getParentSdrObjListFromSdrObject())
{
if (pParentList->IsObjOrdNumsDirty())
{
pParentList->RecalcObjOrdNums();
}
} else const_cast<SdrObject*>(this)->m_nOrdNum=0;
return m_nOrdNum;
}
void SdrObject::SetOrdNum(sal_uInt32 nNum)
{
m_nOrdNum = nNum;
}
/// Try to ensure the desired result __without__ triggering RecalcObjOrdNums
void SdrObject::ensureSortedImmediatelyAfter(const SdrObject& rFirst)
{
SdrObjList* pParentList = getParentSdrObjListFromSdrObject();
assert(pParentList == rFirst.getParentSdrObjListFromSdrObject());
bool bDirty = pParentList->IsObjOrdNumsDirty();
if (!bDirty)
{
pParentList->SetObjectOrdNum(GetOrdNum(), rFirst.GetOrdNum() + 1);
}
else
{
std::optional<decltype(pParentList->begin())> itFound1, itFound2;
for (auto it = pParentList->begin(), itEnd = pParentList->end(); it != itEnd; ++it)
{
if (*it == this)
itFound1 = it;
else if (*it == &rFirst)
itFound2 = it;
if (itFound1 && itFound2)
{
auto ord1 = std::distance(pParentList->begin(), *itFound1);
auto ord2 = std::distance(pParentList->begin(), *itFound2);
pParentList->SetObjectOrdNum(ord1, ord2 + 1);
break;
}
}
}
}
void SdrObject::GetGrabBagItem(css::uno::Any& rVal) const
{
if (m_pGrabBagItem != nullptr)
m_pGrabBagItem->QueryValue(rVal);
else
rVal <<= uno::Sequence<beans::PropertyValue>();
}
void SdrObject::SetGrabBagItem(const css::uno::Any& rVal)
{
if (m_pGrabBagItem == nullptr)
m_pGrabBagItem.reset(new SfxGrabBagItem);
m_pGrabBagItem->PutValue(rVal, 0);
SetChanged();
BroadcastObjectChange();
}
sal_uInt32 SdrObject::GetNavigationPosition() const
{
if (nullptr != getParentSdrObjListFromSdrObject() && getParentSdrObjListFromSdrObject()->RecalcNavigationPositions())
{
return mnNavigationPosition;
}
else
return GetOrdNum();
}
void SdrObject::SetNavigationPosition (const sal_uInt32 nNewPosition)
{
mnNavigationPosition = nNewPosition;
}
// To make clearer that this method may trigger RecalcBoundRect and thus may be
// expensive and sometimes problematic (inside a bigger object change you will get
// non-useful BoundRects sometimes) I rename that method from GetBoundRect() to
// GetCurrentBoundRect().
const tools::Rectangle& SdrObject::GetCurrentBoundRect() const
{
auto const& rRectangle = getOutRectangle();
if (rRectangle.IsEmpty())
{
const_cast< SdrObject* >(this)->RecalcBoundRect();
}
return rRectangle;
}
// To have a possibility to get the last calculated BoundRect e.g for producing
// the first rectangle for repaints (old and new need to be used) without forcing
// a RecalcBoundRect (which may be problematical and expensive sometimes) I add here
// a new method for accessing the last BoundRect.
const tools::Rectangle& SdrObject::GetLastBoundRect() const
{
return getOutRectangle();
}
void SdrObject::RecalcBoundRect()
{
// #i101680# suppress BoundRect calculations on import(s)
if ((getSdrModelFromSdrObject().isLocked()) || comphelper::IsFuzzing())
return;
auto const& rRectangle = getOutRectangle();
// central new method which will calculate the BoundRect using primitive geometry
if (!rRectangle.IsEmpty())
return;
// Use view-independent data - we do not want any connections
// to e.g. GridOffset in SdrObject-level
drawinglayer::primitive2d::Primitive2DContainer xPrimitives;
GetViewContact().getViewIndependentPrimitive2DContainer(xPrimitives);
if (xPrimitives.empty())
return;
// use neutral ViewInformation and get the range of the primitives
const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
if (!aRange.isEmpty())
{
tools::Rectangle aNewRectangle(
tools::Long(floor(aRange.getMinX())),
tools::Long(floor(aRange.getMinY())),
tools::Long(ceil(aRange.getMaxX())),
tools::Long(ceil(aRange.getMaxY())));
setOutRectangle(aNewRectangle);
return;
}
}
void SdrObject::BroadcastObjectChange() const
{
if (getSdrModelFromSdrObject().IsInDestruction() || comphelper::IsFuzzing())
return;
bool bPlusDataBroadcast(m_pPlusData && m_pPlusData->pBroadcast);
bool bObjectChange(IsInserted());
if(!(bPlusDataBroadcast || bObjectChange))
return;
// Only check if we want to defer, after we decided that we really need to broadcast something
if (getSdrModelFromSdrObject().isLocked())
{
getSdrModelFromSdrObject().addDeferredObjectChanges(this);
return;
}
SdrHint aHint(SdrHintKind::ObjectChange, *this);
if(bPlusDataBroadcast)
{
m_pPlusData->pBroadcast->Broadcast(aHint);
}
if(bObjectChange)
{
getSdrModelFromSdrObject().Broadcast(aHint);
}
}
void SdrObject::SetChanged()
{
// For testing purposes, use the new ViewContact for change
// notification now.
ActionChanged();
// TTTT Need to check meaning/usage of IsInserted in one
// of the next changes. It should not mean to have a SdrModel
// set (this is guaranteed now), but should be connected to
// being added to a SdrPage (?)
// TTTT tdf#120066 Indeed - This triggers e.g. by CustomShape
// geometry-presenting SdrObjects that are in a SdrObjGroup,
// but the SdrObjGroup is *by purpose* not inserted.
// Need to check deeper and maybe identify all ::IsInserted()
// calls by rename and let the compiler work...
if(nullptr != getSdrPageFromSdrObject())
{
getSdrModelFromSdrObject().SetChanged();
}
}
// tooling for painting a single object to an OutputDevice.
void SdrObject::SingleObjectPainter(OutputDevice& rOut) const
{
sdr::contact::SdrObjectVector aObjectVector;
aObjectVector.push_back(const_cast< SdrObject* >(this));
sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, std::move(aObjectVector), getSdrPageFromSdrObject());
sdr::contact::DisplayInfo aDisplayInfo;
aPainter.ProcessDisplay(aDisplayInfo);
}
bool SdrObject::LineGeometryUsageIsNecessary() const
{
drawing::LineStyle eXLS = GetMergedItem(XATTR_LINESTYLE).GetValue();
return (eXLS != drawing::LineStyle_NONE);
}
bool SdrObject::HasLimitedRotation() const
{
// RotGrfFlyFrame: Default is false, support full rotation
return false;
}
rtl::Reference<SdrObject> SdrObject::CloneSdrObject(SdrModel& rTargetModel) const
{
if (&rTargetModel == &getSdrModelFromSdrObject())
// clone to same model, simple method
return implCloneSdrObject(rTargetModel);
// clone to different model, need to do more for creating a valid
// Style and Properties
rtl::Reference<SdrObject> aRetval(implCloneSdrObject(rTargetModel));
aRetval->GetProperties().postProcessAfterCloneToDifferentModel(*this);
return aRetval;
}
OUString SdrObject::TakeObjNameSingul() const
{
OUString sName(SvxResId(STR_ObjNameSingulNONE));
OUString aName(GetName());
if (!aName.isEmpty())
sName += " '" + aName + "'";
return sName;
}
OUString SdrObject::TakeObjNamePlural() const
{
return SvxResId(STR_ObjNamePluralNONE);
}
OUString SdrObject::ImpGetDescriptionStr(TranslateId pStrCacheID) const
{
OUString aStr = SvxResId(pStrCacheID);
sal_Int32 nPos = aStr.indexOf("%1");
if (nPos >= 0)
{
// Replace '%1' with the object name.
OUString aObjName(TakeObjNameSingul());
aStr = aStr.replaceAt(nPos, 2, aObjName);
}
nPos = aStr.indexOf("%2");
if (nPos >= 0)
// Replace '%2' with the passed value.
aStr = aStr.replaceAt(nPos, 2, u"0");
return aStr;
}
void SdrObject::ImpForcePlusData()
{
if (!m_pPlusData)
m_pPlusData.reset( new SdrObjPlusData );
}
OUString SdrObject::GetMetrStr(tools::Long nVal) const
{
return getSdrModelFromSdrObject().GetMetricString(nVal);
}
basegfx::B2DPolyPolygon SdrObject::TakeXorPoly() const
{
basegfx::B2DPolyPolygon aRetval;
const tools::Rectangle aR(GetCurrentBoundRect());
aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aR)));
return aRetval;
}
basegfx::B2DPolyPolygon SdrObject::TakeContour() const
{
basegfx::B2DPolyPolygon aRetval;
// create cloned object without text, but with drawing::LineStyle_SOLID,
// COL_BLACK as line color and drawing::FillStyle_NONE
rtl::Reference<SdrObject> pClone(CloneSdrObject(getSdrModelFromSdrObject()));
if(pClone)
{
const SdrTextObj* pTextObj = DynCastSdrTextObj(this);
if(pTextObj)
{
// no text and no text animation
pClone->SetMergedItem(SdrTextAniKindItem(SdrTextAniKind::NONE));
pClone->SetOutlinerParaObject(std::nullopt);
}
const SdrEdgeObj* pEdgeObj = dynamic_cast< const SdrEdgeObj* >(this);
if(pEdgeObj)
{
// create connections if connector, will be cleaned up when
// deleting the connector again
SdrObject* pLeft = pEdgeObj->GetConnectedNode(true);
SdrObject* pRight = pEdgeObj->GetConnectedNode(false);
if(pLeft)
{
pClone->ConnectToNode(true, pLeft);
}
if(pRight)
{
pClone->ConnectToNode(false, pRight);
}
}
SfxItemSet aNewSet(GetObjectItemPool());
// #i101980# ignore LineWidth; that's what the old implementation
// did. With line width, the result may be huge due to fat/thick
// line decompositions
aNewSet.Put(XLineWidthItem(0));
// solid black lines and no fill
aNewSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
aNewSet.Put(XLineColorItem(OUString(), COL_BLACK));
aNewSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
pClone->SetMergedItemSet(aNewSet);
// get sequence from clone
const sdr::contact::ViewContact& rVC(pClone->GetViewContact());
drawinglayer::primitive2d::Primitive2DContainer xSequence;
rVC.getViewIndependentPrimitive2DContainer(xSequence);
if(!xSequence.empty())
{
// use neutral ViewInformation
const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
// create extractor, process and get result (with hairlines as opened polygons)
drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, false);
aExtractor.process(xSequence);
const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour());
// when count is one, it is implied that the object has only its normal
// contour anyways and TakeContour() is to return an empty PolyPolygon
// (see old implementation for historical reasons)
if(rResult.size() > 1)
{
// the topology for contour is correctly a vector of PolyPolygons; for
// historical reasons cut it back to a single tools::PolyPolygon here
for (auto const &rPoly : rResult)
{
aRetval.append(rPoly);
}
}
}
}
return aRetval;
}
sal_uInt32 SdrObject::GetHdlCount() const
{
return 8;
}
void SdrObject::AddToHdlList(SdrHdlList& rHdlList) const
{
const tools::Rectangle& rR=GetSnapRect();
for (sal_uInt32 nHdlNum=0; nHdlNum<8; ++nHdlNum)
{
std::unique_ptr<SdrHdl> pH;
switch (nHdlNum) {
case 0: pH.reset(new SdrHdl(rR.TopLeft(), SdrHdlKind::UpperLeft)); break;
case 1: pH.reset(new SdrHdl(rR.TopCenter(), SdrHdlKind::Upper)); break;
case 2: pH.reset(new SdrHdl(rR.TopRight(), SdrHdlKind::UpperRight)); break;
case 3: pH.reset(new SdrHdl(rR.LeftCenter(), SdrHdlKind::Left )); break;
case 4: pH.reset(new SdrHdl(rR.RightCenter(), SdrHdlKind::Right)); break;
case 5: pH.reset(new SdrHdl(rR.BottomLeft(), SdrHdlKind::LowerLeft)); break;
case 6: pH.reset(new SdrHdl(rR.BottomCenter(),SdrHdlKind::Lower)); break;
case 7: pH.reset(new SdrHdl(rR.BottomRight(), SdrHdlKind::LowerRight)); break;
}
rHdlList.AddHdl(std::move(pH));
}
}
void SdrObject::AddToPlusHdlList(SdrHdlList&, SdrHdl&) const
{
}
void SdrObject::addCropHandles(SdrHdlList& /*rTarget*/) const
{
// Default implementation, does nothing. Overloaded in
// SdrGrafObj and SwVirtFlyDrawObj
}
void SdrObject::ImpCommonDragCalcRect(const SdrDragStat& rDrag, tools::Rectangle& rTmpRect, const Point& rPos)
{
const tools::Rectangle aRect(rTmpRect);
const SdrHdl* pHdl = rDrag.GetHdl();
SdrHdlKind eHdl = (pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind());
bool bCorner = (eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::LowerLeft || eHdl==SdrHdlKind::LowerRight);
bool bOrtho = rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
bool bBigOrtho = bCorner && bOrtho && rDrag.GetView()->IsBigOrtho();
bool bLft = (eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::LowerLeft);
bool bRgt = (eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerRight);
bool bTop = (eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperLeft);
bool bBtm = (eHdl==SdrHdlKind::LowerRight || eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerLeft);
if (bLft)
rTmpRect.SetLeft( rPos.X() );
else if (bRgt)
rTmpRect.SetRight( rPos.X() );
if (bTop)
rTmpRect.SetTop( rPos.Y() );
else if (bBtm)
rTmpRect.SetBottom( rPos.Y() );
if (bOrtho) // Ortho
{
tools::Long nWdt0 = aRect.Right() - aRect.Left();
tools::Long nHgt0 = aRect.Bottom()- aRect.Top();
double nX = double(rTmpRect.Right() - rTmpRect.Left()) / nWdt0;
double nY = double(rTmpRect.Bottom()- rTmpRect.Top()) / nHgt0;
if (bCorner) // corner point handles
{
bool bUseX = ((std::abs(nX)<std::abs(nY)) != bBigOrtho);
if (bUseX)
{
tools::Long nNeed = tools::Long( nHgt0 * nX );
if (bTop)
rTmpRect.SetTop( rTmpRect.Bottom() - nNeed );
else if (bBtm)
rTmpRect.SetBottom( rTmpRect.Top() + nNeed );
}
else
{
tools::Long nNeed = tools::Long( nWdt0 * nY );
if (bLft)
rTmpRect.SetLeft(rTmpRect.Right()-nNeed );
else if (bRgt)
rTmpRect.SetRight(rTmpRect.Left()+nNeed );
}
}
else // apex handles
{
if (bLft || bRgt)
{
tools::Long nHgt0b = aRect.Bottom() - aRect.Top();
tools::Long nNeed = tools::Long( nHgt0b * nX ) ;
rTmpRect.AdjustTop( -((nNeed-nHgt0b)/2) );
rTmpRect.SetBottom( rTmpRect.Top() + nNeed );
}
else if (bTop || bBtm)
{
tools::Long nWdt0b = aRect.Right() - aRect.Left();
tools::Long nNeed = tools::Long( nWdt0b * nY );
rTmpRect.AdjustLeft( -((nNeed-nWdt0b)/2) );
rTmpRect.SetRight( rTmpRect.Left() + nNeed );
}
}
}
}
tools::Rectangle SdrObject::ImpDragCalcRect(const SdrDragStat& rDrag) const
{
tools::Rectangle aTmpRect(GetSnapRect());
Point aPos(rDrag.GetNow());
ImpCommonDragCalcRect( rDrag, aTmpRect, aPos );
aTmpRect.Normalize();
return aTmpRect;
}
bool SdrObject::hasSpecialDrag() const
{
return false;
}
bool SdrObject::supportsFullDrag() const
{
return true;
}
rtl::Reference<SdrObject> SdrObject::getFullDragClone() const
{
// default uses simple clone
return CloneSdrObject(getSdrModelFromSdrObject());
}
bool SdrObject::beginSpecialDrag(SdrDragStat& rDrag) const
{
const SdrHdl* pHdl = rDrag.GetHdl();
SdrHdlKind eHdl = (pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind();
return eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperRight ||
eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerLeft ||
eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerRight;
}
bool SdrObject::applySpecialDrag(SdrDragStat& rDrag)
{
tools::Rectangle aNewRect(ImpDragCalcRect(rDrag));
if(aNewRect != GetSnapRect())
{
NbcSetSnapRect(aNewRect);
}
return true;
}
OUString SdrObject::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
{
return OUString();
}
basegfx::B2DPolyPolygon SdrObject::getSpecialDragPoly(const SdrDragStat& /*rDrag*/) const
{
// default has nothing to add
return basegfx::B2DPolyPolygon();
}
// Create
bool SdrObject::BegCreate(SdrDragStat& rStat)
{
rStat.SetOrtho4Possible();
tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
aRect1.Normalize();
rStat.SetActionRect(aRect1);
setOutRectangle(aRect1);
return true;
}
bool SdrObject::MovCreate(SdrDragStat& rStat)
{
tools::Rectangle aRectangle;
rStat.TakeCreateRect(aRectangle);
rStat.SetActionRect(aRectangle);
aRectangle.Normalize();
setOutRectangle(aRectangle);
return true;
}
bool SdrObject::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
{
tools::Rectangle aRectangle;
rStat.TakeCreateRect(aRectangle);
aRectangle.Normalize();
setOutRectangle(aRectangle);
return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
}
void SdrObject::BrkCreate(SdrDragStat& /*rStat*/)
{
}
bool SdrObject::BckCreate(SdrDragStat& /*rStat*/)
{
return false;
}
basegfx::B2DPolyPolygon SdrObject::TakeCreatePoly(const SdrDragStat& rDrag) const
{
tools::Rectangle aRect1;
rDrag.TakeCreateRect(aRect1);
aRect1.Normalize();
basegfx::B2DPolyPolygon aRetval;
aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aRect1)));
return aRetval;
}
PointerStyle SdrObject::GetCreatePointer() const
{
return PointerStyle::Cross;
}
// transformations
void SdrObject::NbcMove(const Size& rSize)
{
moveOutRectangle(rSize.Width(), rSize.Height());
SetBoundAndSnapRectsDirty();
}
void SdrObject::NbcResize(const Point& rRef, double xFact, double yFact)
{
bool bXMirr = (xFact<0);
bool bYMirr = (yFact<0);
if (bXMirr || bYMirr) {
Point aRef1(GetSnapRect().Center());
if (bXMirr) {
Point aRef2(aRef1);
aRef2.AdjustY( 1 );
NbcMirrorGluePoints(aRef1,aRef2);
}
if (bYMirr) {
Point aRef2(aRef1);
aRef2.AdjustX( 1 );
NbcMirrorGluePoints(aRef1,aRef2);
}
}
auto aRectangle = getOutRectangle();
ResizeRect(aRectangle, rRef, xFact, yFact);
setOutRectangle(aRectangle);
SetBoundAndSnapRectsDirty();
}
bool SdrObject::IsSizeValid(Size /* aTargetSize */)
{
return true;
}
void SdrObject::NbcRotate(const Point& rRef, Degree100 nAngle)
{
if (nAngle)
{
double a = toRadians(nAngle);
NbcRotate( rRef, nAngle, sin( a ), cos( a ) );
}
}
namespace
{
tools::Rectangle lclMirrorRectangle(tools::Rectangle const& rRectangle, Point const& rRef1, Point const& rRef2)
{
tools::Rectangle aRectangle(rRectangle);
aRectangle.Move(-rRef1.X(),-rRef1.Y());
tools::Rectangle R(aRectangle);
tools::Long dx=rRef2.X()-rRef1.X();
tools::Long dy=rRef2.Y()-rRef1.Y();
if (dx==0) { // vertical axis
aRectangle.SetLeft(-R.Right() );
aRectangle.SetRight(-R.Left() );
} else if (dy==0) { // horizontal axis
aRectangle.SetTop(-R.Bottom() );
aRectangle.SetBottom(-R.Top() );
} else if (dx==dy) { // 45deg axis
aRectangle.SetLeft(R.Top() );
aRectangle.SetRight(R.Bottom() );
aRectangle.SetTop(R.Left() );
aRectangle.SetBottom(R.Right() );
} else if (dx==-dy) { // 45deg axis
aRectangle.SetLeft(-R.Bottom() );
aRectangle.SetRight(-R.Top() );
aRectangle.SetTop(-R.Right() );
aRectangle.SetBottom(-R.Left() );
}
aRectangle.Move(rRef1.X(),rRef1.Y());
aRectangle.Normalize(); // just in case
return aRectangle;
}
} // end anonymous namespace
void SdrObject::NbcMirror(const Point& rRef1, const Point& rRef2)
{
SetGlueReallyAbsolute(true);
tools::Rectangle aRectangle = getOutRectangle();
aRectangle = lclMirrorRectangle(aRectangle, rRef1, rRef2);
setOutRectangle(aRectangle);
SetBoundAndSnapRectsDirty();
NbcMirrorGluePoints(rRef1,rRef2);
SetGlueReallyAbsolute(false);
}
void SdrObject::NbcShear(const Point& rRef, Degree100 /*nAngle*/, double tn, bool bVShear)
{
SetGlueReallyAbsolute(true);
NbcShearGluePoints(rRef,tn,bVShear);
SetGlueReallyAbsolute(false);
}
void SdrObject::Move(const Size& rSize)
{
if (rSize.Width() == 0 && rSize.Height() == 0)
return;
tools::Rectangle aBoundRect0;
if (m_pUserCall != nullptr)
aBoundRect0 = GetLastBoundRect();
NbcMove(rSize);
if (isAnnotationObject())
{
css::geometry::RealPoint2D aNewPosition(
GetLogicRect().Left() / 100.0,
GetLogicRect().Top() / 100.0);
getAnnotationData()->mxAnnotation->SetPosition(aNewPosition);
}
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::MoveOnly, aBoundRect0);
}
void SdrObject::NbcCrop(const basegfx::B2DPoint& /*aRef*/, double /*fxFact*/, double /*fyFact*/)
{
// Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrDragCrop::EndSdrDrag.
// Where SwVirtFlyDrawObj is the only real user of it to do something local
}
void SdrObject::Resize(const Point& rRef, double xFact, double yFact, bool bUnsetRelative)
{
if (xFact == 1.0 && yFact == 1.0)
return;
if (bUnsetRelative)
{
mpImpl->mnRelativeWidth.reset();
mpImpl->meRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
mpImpl->meRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
mpImpl->mnRelativeHeight.reset();
}
tools::Rectangle aBoundRect0;
if (m_pUserCall != nullptr)
aBoundRect0 = GetLastBoundRect();
NbcResize(rRef, xFact, yFact);
if (isAnnotationObject())
{
auto& rRect = GetCurrentBoundRect();
css::geometry::RealSize2D aNewSize(rRect.GetWidth() / 100.0, rRect.GetHeight() / 100.0);
getAnnotationData()->mxAnnotation->SetSize(aNewSize);
}
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize, aBoundRect0);
}
void SdrObject::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
{
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcCrop(rRef, fxFact, fyFact);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
void SdrObject::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
{
if (nAngle) {
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcRotate(rRef,nAngle,sn,cs);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
}
void SdrObject::Mirror(const Point& rRef1, const Point& rRef2)
{
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcMirror(rRef1,rRef2);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
void SdrObject::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
{
if (nAngle) {
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcShear(rRef,nAngle,tn,bVShear);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
}
void SdrObject::NbcSetRelativePos(const Point& rPnt)
{
Point aRelPos0(GetSnapRect().TopLeft()-m_aAnchor);
Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
NbcMove(aSiz); // This also calls SetRectsDirty()
}
void SdrObject::SetRelativePos(const Point& rPnt)
{
if (rPnt!=GetRelativePos()) {
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcSetRelativePos(rPnt);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
}
}
Point SdrObject::GetRelativePos() const
{
return GetSnapRect().TopLeft()-m_aAnchor;
}
void SdrObject::ImpSetAnchorPos(const Point& rPnt)
{
m_aAnchor = rPnt;
}
void SdrObject::NbcSetAnchorPos(const Point& rPnt)
{
Size aSiz(rPnt.X()-m_aAnchor.X(),rPnt.Y()-m_aAnchor.Y());
m_aAnchor=rPnt;
NbcMove(aSiz); // This also calls SetRectsDirty()
}
void SdrObject::SetAnchorPos(const Point& rPnt)
{
if (rPnt!=m_aAnchor) {
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcSetAnchorPos(rPnt);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
}
}
const Point& SdrObject::GetAnchorPos() const
{
return m_aAnchor;
}
void SdrObject::RecalcSnapRect()
{
}
const tools::Rectangle& SdrObject::GetSnapRect() const
{
return getOutRectangle();
}
void SdrObject::NbcSetSnapRect(const tools::Rectangle& rRect)
{
setOutRectangle(rRect);
}
const tools::Rectangle& SdrObject::GetLogicRect() const
{
return GetSnapRect();
}
void SdrObject::NbcSetLogicRect(const tools::Rectangle& rRect, bool /*bAdaptTextMinSize*/)
{
NbcSetSnapRect(rRect);
}
void SdrObject::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
{
SetLogicRect( rMaxRect );
}
void SdrObject::SetSnapRect(const tools::Rectangle& rRect)
{
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcSetSnapRect(rRect);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
void SdrObject::SetLogicRect(const tools::Rectangle& rRect)
{
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcSetLogicRect(rRect);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
Degree100 SdrObject::GetRotateAngle() const
{
return 0_deg100;
}
Degree100 SdrObject::GetShearAngle(bool /*bVertical*/) const
{
return 0_deg100;
}
sal_uInt32 SdrObject::GetSnapPointCount() const
{
return GetPointCount();
}
Point SdrObject::GetSnapPoint(sal_uInt32 i) const
{
return GetPoint(i);
}
bool SdrObject::IsPolyObj() const
{
return false;
}
sal_uInt32 SdrObject::GetPointCount() const
{
return 0;
}
Point SdrObject::GetPoint(sal_uInt32 /*i*/) const
{
return Point();
}
void SdrObject::SetPoint(const Point& rPnt, sal_uInt32 i)
{
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcSetPoint(rPnt, i);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
void SdrObject::NbcSetPoint(const Point& /*rPnt*/, sal_uInt32 /*i*/)
{
}
bool SdrObject::HasTextEdit() const
{
return false;
}
bool SdrObject::Equals(const SdrObject& rOtherObj) const
{
const bool bEqual(m_aAnchor.X() == rOtherObj.m_aAnchor.X() && m_aAnchor.Y() == rOtherObj.m_aAnchor.Y() &&
m_nOrdNum == rOtherObj.m_nOrdNum && mnNavigationPosition == rOtherObj.mnNavigationPosition &&
mbSupportTextIndentingOnLineWidthChange == rOtherObj.mbSupportTextIndentingOnLineWidthChange &&
m_aCustomPromptText == rOtherObj.m_aCustomPromptText &&
mbLineIsOutsideGeometry == rOtherObj.mbLineIsOutsideGeometry && m_bMarkProt == rOtherObj.m_bMarkProt &&
m_bIs3DObj == rOtherObj.m_bIs3DObj && m_bIsEdge == rOtherObj.m_bIsEdge && m_bClosedObj == rOtherObj.m_bClosedObj &&
m_bNotVisibleAsMaster == rOtherObj.m_bNotVisibleAsMaster && m_bEmptyPresObj == rOtherObj.m_bEmptyPresObj &&
mbVisible == rOtherObj.mbVisible && m_bNoPrint == rOtherObj.m_bNoPrint && m_bSizProt == rOtherObj.m_bSizProt &&
m_bMovProt == rOtherObj.m_bMovProt && m_bVirtObj == rOtherObj.m_bVirtObj &&
mnLayerID == rOtherObj.mnLayerID && IsGroupObject() == rOtherObj.IsGroupObject());
if (!bEqual)
// compare results *without* Items are already not equal, done
return false;
if (IsGroupObject())
{
// for GroupObjects, do what was done before. NOTE: This will create
// merged ItemSets for Group content, not sure if that is needed.
// It would also be possible to enter content & compare recursively
return GetMergedItemSet().Equals(rOtherObj.GetMergedItemSet(), false);
}
// Do ContentCompare - Items are compared including parent e.g. Styles.
// The check above what was done before is more 'hard' in the sense that
// it WILL fail for same Item content when e.g. count of hard Items differs,
// but with parent ItemSet is actually equal. ContentCompare is necessary
// after e.g. in AttributeProperties::postProcessAfterCloneToDifferentModel
// the Items of an Object were hard-set/corrected
const SfxItemSet& rSrcItemSet(GetObjectItemSet());
const SfxItemSet& rDstItemSet(rOtherObj.GetObjectItemSet());
SfxWhichIter aIter(rSrcItemSet);
const SdrPage* pPage(getSdrPageFromSdrObject());
const bool bOnMasterPage(nullptr != pPage && pPage->IsMasterPage());
for (sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich())
{
const SfxPoolItem& rOld(rSrcItemSet.Get(nWhich));
const SfxPoolItem& rNew(rDstItemSet.Get(nWhich));
if (!SfxPoolItem::areSame(rOld, rNew))
{
if (bOnMasterPage)
{
// we have strange effects for Items in Objects on MasterPages on
// some Items that seem to be corrected/set different due to being
// PresObjs or defaults or similar on MasterPage. React on those
// on MasterPages
switch (nWhich)
{
case XATTRSET_LINE:
case XATTRSET_FILL:
// these Items are not really used (maybe removed),
// ignore. Diffs come from these being SfxSetItems
// on different models with slightly different defaults
// in the contained complete default SfxItemSet
continue;
// somewhere defaults for some objects seem to be set on MasterPages
// that define Items (here: for XATTR_FILLGRADIENT and FillStyle_BITMAP).
// These can be ignored when the FillStyle does not *use* these anyways.
// Better do this already for all FillStyles, you never know.
case XATTR_FILLCOLOR:
if (drawing::FillStyle_SOLID != rSrcItemSet.Get(XATTR_FILLSTYLE).GetValue())
continue;
break;
case XATTR_FILLGRADIENT:
if (drawing::FillStyle_GRADIENT != rSrcItemSet.Get(XATTR_FILLSTYLE).GetValue())
continue;
break;
case XATTR_FILLHATCH:
if (drawing::FillStyle_HATCH != rSrcItemSet.Get(XATTR_FILLSTYLE).GetValue())
continue;
break;
case XATTR_FILLBITMAP:
if (drawing::FillStyle_BITMAP != rSrcItemSet.Get(XATTR_FILLSTYLE).GetValue())
continue;
break;
default: break;
}
}
// Item is different, done
return false;
}
}
// all Items are Content-Equal
return true;
}
void SdrObject::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObject"));
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name()));
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("name"), "%s", BAD_CAST(GetName().toUtf8().getStr()));
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("title"), "%s", BAD_CAST(GetTitle().toUtf8().getStr()));
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("description"), "%s", BAD_CAST(GetDescription().toUtf8().getStr()));
(void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("nOrdNum"), "%" SAL_PRIuUINT32, GetOrdNumDirect());
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aOutRect"), BAD_CAST(getOutRectangle().toString().getStr()));
if (m_pGrabBagItem)
{
m_pGrabBagItem->dumpAsXml(pWriter);
}
if (mpProperties)
{
mpProperties->dumpAsXml(pWriter);
}
if (const OutlinerParaObject* pOutliner = GetOutlinerParaObject())
pOutliner->dumpAsXml(pWriter);
(void)xmlTextWriterEndElement(pWriter);
}
void SdrObject::SetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject)
{
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcSetOutlinerParaObject(std::move(pTextObject));
SetChanged();
BroadcastObjectChange();
if (GetCurrentBoundRect()!=aBoundRect0) {
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
}
void SdrObject::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> /*pTextObject*/, bool /*bAdjustTextFrameWidthAndHeight = true*/)
{
}
OutlinerParaObject* SdrObject::GetOutlinerParaObject() const
{
return nullptr;
}
void SdrObject::NbcReformatText()
{
}
void SdrObject::BurnInStyleSheetAttributes()
{
GetProperties().ForceStyleToHardAttributes();
}
bool SdrObject::HasMacro() const
{
return false;
}
SdrObject* SdrObject::CheckMacroHit(const SdrObjMacroHitRec& rRec) const
{
if(rRec.pPageView)
{
return SdrObjectPrimitiveHit(*this, rRec.aPos, {static_cast<double>(rRec.nTol), static_cast<double>(rRec.nTol)}, *rRec.pPageView, rRec.pVisiLayer, false);
}
return nullptr;
}
PointerStyle SdrObject::GetMacroPointer(const SdrObjMacroHitRec&) const
{
return PointerStyle::RefHand;
}
void SdrObject::PaintMacro(OutputDevice& rOut, const tools::Rectangle& , const SdrObjMacroHitRec& ) const
{
const RasterOp eRop(rOut.GetRasterOp());
const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
rOut.SetLineColor(COL_BLACK);
rOut.SetFillColor();
rOut.SetRasterOp(RasterOp::Invert);
for(auto const& rPolygon : aPolyPolygon)
{
rOut.DrawPolyLine(rPolygon);
}
rOut.SetRasterOp(eRop);
}
bool SdrObject::DoMacro(const SdrObjMacroHitRec&)
{
return false;
}
bool SdrObject::IsMacroHit(const SdrObjMacroHitRec& rRec) const
{
return CheckMacroHit(rRec) != nullptr;
}
std::unique_ptr<SdrObjGeoData> SdrObject::NewGeoData() const
{
return std::make_unique<SdrObjGeoData>();
}
void SdrObject::SaveGeoData(SdrObjGeoData& rGeo) const
{
rGeo.aBoundRect =GetCurrentBoundRect();
rGeo.aAnchor =m_aAnchor ;
rGeo.bMovProt =m_bMovProt ;
rGeo.bSizProt =m_bSizProt ;
rGeo.bNoPrint =m_bNoPrint ;
rGeo.mbVisible =mbVisible ;
rGeo.bClosedObj =m_bClosedObj ;
rGeo.mnLayerID = mnLayerID;
// user-defined gluepoints
if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) {
rGeo.moGluePoints = *m_pPlusData->pGluePoints;
} else {
rGeo.moGluePoints.reset();
}
}
void SdrObject::RestoreGeoData(const SdrObjGeoData& rGeo)
{
SetBoundAndSnapRectsDirty();
setOutRectangle(rGeo.aBoundRect);
m_aAnchor =rGeo.aAnchor ;
m_bMovProt =rGeo.bMovProt ;
m_bSizProt =rGeo.bSizProt ;
m_bNoPrint =rGeo.bNoPrint ;
mbVisible =rGeo.mbVisible ;
m_bClosedObj =rGeo.bClosedObj ;
mnLayerID = rGeo.mnLayerID;
// user-defined gluepoints
if (rGeo.moGluePoints) {
ImpForcePlusData();
if (m_pPlusData->pGluePoints!=nullptr) {
*m_pPlusData->pGluePoints=*rGeo.moGluePoints;
} else {
m_pPlusData->pGluePoints.reset(new SdrGluePointList(*rGeo.moGluePoints));
}
} else {
if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) {
m_pPlusData->pGluePoints.reset();
}
}
}
std::unique_ptr<SdrObjGeoData> SdrObject::GetGeoData() const
{
std::unique_ptr<SdrObjGeoData> pGeo = NewGeoData();
SaveGeoData(*pGeo);
return pGeo;
}
void SdrObject::SetGeoData(const SdrObjGeoData& rGeo)
{
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
RestoreGeoData(rGeo);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
// ItemSet access
const SfxItemSet& SdrObject::GetObjectItemSet() const
{
return GetProperties().GetObjectItemSet();
}
const SfxItemSet& SdrObject::GetMergedItemSet() const
{
return GetProperties().GetMergedItemSet();
}
void SdrObject::SetObjectItem(const SfxPoolItem& rItem)
{
GetProperties().SetObjectItem(rItem);
}
void SdrObject::SetMergedItem(const SfxPoolItem& rItem)
{
GetProperties().SetMergedItem(rItem);
}
void SdrObject::ClearMergedItem(const sal_uInt16 nWhich)
{
GetProperties().ClearMergedItem(nWhich);
}
void SdrObject::SetObjectItemSet(const SfxItemSet& rSet)
{
GetProperties().SetObjectItemSet(rSet);
}
void SdrObject::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems, bool bAdjustTextFrameWidthAndHeight)
{
GetProperties().SetMergedItemSet(rSet, bClearAllItems, bAdjustTextFrameWidthAndHeight);
}
const SfxPoolItem& SdrObject::GetObjectItem(const sal_uInt16 nWhich) const
{
return GetObjectItemSet().Get(nWhich);
}
const SfxPoolItem& SdrObject::GetMergedItem(const sal_uInt16 nWhich) const
{
return GetMergedItemSet().Get(nWhich);
}
void SdrObject::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems)
{
GetProperties().SetMergedItemSetAndBroadcast(rSet, bClearAllItems);
const SdrMetricItem* pItem;
const bool bSetSoftEdge
= (SfxItemState::SET == rSet.GetItemState(SDRATTR_SOFTEDGE_RADIUS, true, &pItem)
&& pItem->GetValue() > 0);
if (bSetSoftEdge)
{
// Remove 3D grabbag
try
{
css::uno::Any aAnyGrabBag;
GetGrabBagItem(aAnyGrabBag);
uno::Sequence<beans::PropertyValue> aSeqGrabBag
= aAnyGrabBag.get<uno::Sequence<beans::PropertyValue>>();
auto it = std::find_if(aSeqGrabBag.begin(), aSeqGrabBag.end(),
[](const beans::PropertyValue& rProp) {
return rProp.Name == u"3DEffectProperties"_ustr;
});
if (it == aSeqGrabBag.end())
return;
comphelper::removeElementAt(aSeqGrabBag, it - aSeqGrabBag.begin());
SetGrabBagItem(css::uno::Any(aSeqGrabBag));
}
catch (const css::uno::Exception&)
{
// Grab bag not found, nothing to do
}
}
}
void SdrObject::ApplyNotPersistAttr(const SfxItemSet& rAttr)
{
tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
NbcApplyNotPersistAttr(rAttr);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}
void SdrObject::NbcApplyNotPersistAttr(const SfxItemSet& rAttr)
{
const tools::Rectangle& rSnap=GetSnapRect();
const tools::Rectangle& rLogic=GetLogicRect();
Point aRef1(rSnap.Center());
if (const SdrTransformRef1XItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1X))
{
aRef1.setX(pPoolItem->GetValue() );
}
if (const SdrTransformRef1YItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1Y))
{
aRef1.setY(pPoolItem->GetValue() );
}
tools::Rectangle aNewSnap(rSnap);
if (const SdrMoveXItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_MOVEX))
{
tools::Long n = pPoolItem->GetValue();
aNewSnap.Move(n,0);
}
if (const SdrMoveYItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_MOVEY))
{
tools::Long n = pPoolItem->GetValue();
aNewSnap.Move(0,n);
}
if (const SdrOnePositionXItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONEPOSITIONX))
{
tools::Long n = pPoolItem->GetValue();
aNewSnap.Move(n-aNewSnap.Left(),0);
}
if (const SdrOnePositionYItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONEPOSITIONY))
{
tools::Long n = pPoolItem->GetValue();
aNewSnap.Move(0,n-aNewSnap.Top());
}
if (const SdrOneSizeWidthItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONESIZEWIDTH))
{
tools::Long n = pPoolItem->GetValue();
aNewSnap.SetRight(aNewSnap.Left()+n );
}
if (const SdrOneSizeHeightItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONESIZEHEIGHT))
{
tools::Long n = pPoolItem->GetValue();
aNewSnap.SetBottom(aNewSnap.Top()+n );
}
if (aNewSnap!=rSnap) {
if (aNewSnap.GetSize()==rSnap.GetSize()) {
NbcMove(Size(aNewSnap.Left()-rSnap.Left(),aNewSnap.Top()-rSnap.Top()));
} else {
NbcSetSnapRect(aNewSnap);
}
}
if (const SdrShearAngleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_SHEARANGLE))
{
Degree100 n = pPoolItem->GetValue();
n-=GetShearAngle();
if (n) {
double nTan = tan(toRadians(n));
NbcShear(aRef1,n,nTan,false);
}
}
if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ROTATEANGLE))
{
Degree100 n = pPoolItem->GetValue();
n-=GetRotateAngle();
if (n) {
NbcRotate(aRef1,n);
}
}
if (const SdrRotateOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ROTATEONE))
{
Degree100 n = pPoolItem->GetValue();
NbcRotate(aRef1,n);
}
if (const SdrHorzShearOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_HORZSHEARONE))
{
Degree100 n = pPoolItem->GetValue();
double nTan = tan(toRadians(n));
NbcShear(aRef1,n,nTan,false);
}
if (const SdrVertShearOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_VERTSHEARONE))
{
Degree100 n = pPoolItem->GetValue();
double nTan = tan(toRadians(n));
NbcShear(aRef1,n,nTan,true);
}
if (const SdrYesNoItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJMOVEPROTECT))
{
bool b = pPoolItem->GetValue();
SetMoveProtect(b);
}
if (const SdrYesNoItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJSIZEPROTECT))
{
bool b = pPoolItem->GetValue();
SetResizeProtect(b);
}
/* move protect always sets size protect */
if( IsMoveProtect() )
SetResizeProtect( true );
if (const SdrObjPrintableItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJPRINTABLE))
{
bool b = pPoolItem->GetValue();
SetPrintable(b);
}
if (const SdrObjVisibleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJVISIBLE))
{
bool b = pPoolItem->GetValue();
SetVisible(b);
}
SdrLayerID nLayer=SDRLAYER_NOTFOUND;
if (const SdrLayerIdItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERID))
{
nLayer = pPoolItem->GetValue();
}
if (const SdrLayerNameItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERNAME))
{
OUString aLayerName = pPoolItem->GetValue();
const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
? getSdrPageFromSdrObject()->GetLayerAdmin()
: getSdrModelFromSdrObject().GetLayerAdmin());
const SdrLayer* pLayer = rLayAd.GetLayer(aLayerName);
if(nullptr != pLayer)
{
nLayer=pLayer->GetID();
}
}
if (nLayer!=SDRLAYER_NOTFOUND) {
NbcSetLayer(nLayer);
}
if (const SfxStringItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJECTNAME))
{
OUString aName = pPoolItem->GetValue();
SetName(aName);
}
tools::Rectangle aNewLogic(rLogic);
if (const SdrLogicSizeWidthItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LOGICSIZEWIDTH))
{
tools::Long n = pPoolItem->GetValue();
aNewLogic.SetRight(aNewLogic.Left()+n );
}
if (const SdrLogicSizeHeightItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LOGICSIZEHEIGHT))
{
tools::Long n = pPoolItem->GetValue();
aNewLogic.SetBottom(aNewLogic.Top()+n );
}
if (aNewLogic!=rLogic) {
NbcSetLogicRect(aNewLogic);
}
double fResizeX = 1.0;
double fResizeY = 1.0;
if (const SdrResizeXOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEXONE))
{
fResizeX *= pPoolItem->GetValue();
}
if (const SdrResizeYOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEYONE))
{
fResizeY *= pPoolItem->GetValue();
}
if (fResizeX!=1.0 || fResizeY!=1.0) {
NbcResize(aRef1, fResizeX, fResizeY);
}
}
void SdrObject::TakeNotPersistAttr(SfxItemSet& rAttr) const
{
const tools::Rectangle& rSnap=GetSnapRect();
const tools::Rectangle& rLogic=GetLogicRect();
rAttr.Put(SdrYesNoItem(SDRATTR_OBJMOVEPROTECT, IsMoveProtect()));
rAttr.Put(SdrYesNoItem(SDRATTR_OBJSIZEPROTECT, IsResizeProtect()));
rAttr.Put(SdrObjPrintableItem(IsPrintable()));
rAttr.Put(SdrObjVisibleItem(IsVisible()));
rAttr.Put(SdrAngleItem(SDRATTR_ROTATEANGLE, GetRotateAngle()));
rAttr.Put(SdrShearAngleItem(GetShearAngle()));
rAttr.Put(SdrOneSizeWidthItem(rSnap.GetWidth()-1));
rAttr.Put(SdrOneSizeHeightItem(rSnap.GetHeight()-1));
rAttr.Put(SdrOnePositionXItem(rSnap.Left()));
rAttr.Put(SdrOnePositionYItem(rSnap.Top()));
if (rLogic.GetWidth()!=rSnap.GetWidth()) {
rAttr.Put(SdrLogicSizeWidthItem(rLogic.GetWidth()-1));
}
if (rLogic.GetHeight()!=rSnap.GetHeight()) {
rAttr.Put(SdrLogicSizeHeightItem(rLogic.GetHeight()-1));
}
OUString aName(GetName());
if (!aName.isEmpty())
{
rAttr.Put(SfxStringItem(SDRATTR_OBJECTNAME, aName));
}
rAttr.Put(SdrLayerIdItem(GetLayer()));
const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
? getSdrPageFromSdrObject()->GetLayerAdmin()
: getSdrModelFromSdrObject().GetLayerAdmin());
const SdrLayer* pLayer = rLayAd.GetLayerPerID(GetLayer());
if(nullptr != pLayer)
{
rAttr.Put(SdrLayerNameItem(pLayer->GetName()));
}
Point aRef1(rSnap.Center());
Point aRef2(aRef1); aRef2.AdjustY( 1 );
rAttr.Put(SdrTransformRef1XItem(aRef1.X()));
rAttr.Put(SdrTransformRef1YItem(aRef1.Y()));
rAttr.Put(SdrTransformRef2XItem(aRef2.X()));
rAttr.Put(SdrTransformRef2YItem(aRef2.Y()));
}
SfxStyleSheet* SdrObject::GetStyleSheet() const
{
return GetProperties().GetStyleSheet();
}
void SdrObject::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
{
tools::Rectangle aBoundRect0;
if(m_pUserCall)
aBoundRect0 = GetLastBoundRect();
InternalSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, true);
SetChanged();
BroadcastObjectChange();
SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect0);
}
void SdrObject::NbcSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr, bool bAdjustTextFrameWidthAndHeight)
{
InternalSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, false, bAdjustTextFrameWidthAndHeight);
}
void SdrObject::InternalSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr, bool bBroadcast, bool bAdjustTextFrameWidthAndHeight)
{
GetProperties().SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast, bAdjustTextFrameWidthAndHeight);
}
// Broadcasting while setting attributes is managed by the AttrObj.
SdrGluePoint SdrObject::GetVertexGluePoint(sal_uInt16 nPosNum) const
{
// #i41936# Use SnapRect for default GluePoints
const tools::Rectangle aR(GetSnapRect());
Point aPt;
switch(nPosNum)
{
case 0 : aPt = aR.TopCenter(); break;
case 1 : aPt = aR.RightCenter(); break;
case 2 : aPt = aR.BottomCenter(); break;
case 3 : aPt = aR.LeftCenter(); break;
}
aPt -= aR.Center();
SdrGluePoint aGP(aPt);
aGP.SetPercent(false);
return aGP;
}
SdrGluePoint SdrObject::GetCornerGluePoint(sal_uInt16 nPosNum) const
{
tools::Rectangle aR(GetCurrentBoundRect());
Point aPt;
switch (nPosNum) {
case 0 : aPt=aR.TopLeft(); break;
case 1 : aPt=aR.TopRight(); break;
case 2 : aPt=aR.BottomRight(); break;
case 3 : aPt=aR.BottomLeft(); break;
}
aPt-=GetSnapRect().Center();
SdrGluePoint aGP(aPt);
aGP.SetPercent(false);
return aGP;
}
const SdrGluePointList* SdrObject::GetGluePointList() const
{
if (m_pPlusData!=nullptr) return m_pPlusData->pGluePoints.get();
return nullptr;
}
SdrGluePointList* SdrObject::ForceGluePointList()
{
ImpForcePlusData();
if (m_pPlusData->pGluePoints==nullptr) {
m_pPlusData->pGluePoints.reset(new SdrGluePointList);
}
return m_pPlusData->pGluePoints.get();
}
void SdrObject::SetGlueReallyAbsolute(bool bOn)
{
// First a const call to see whether there are any gluepoints.
// Force const call!
if (GetGluePointList()!=nullptr) {
SdrGluePointList* pGPL=ForceGluePointList();
pGPL->SetReallyAbsolute(bOn,*this);
}
}
void SdrObject::NbcRotateGluePoints(const Point& rRef, Degree100 nAngle, double sn, double cs)
{
// First a const call to see whether there are any gluepoints.
// Force const call!
if (GetGluePointList()!=nullptr) {
SdrGluePointList* pGPL=ForceGluePointList();
pGPL->Rotate(rRef,nAngle,sn,cs,this);
}
}
void SdrObject::NbcMirrorGluePoints(const Point& rRef1, const Point& rRef2)
{
// First a const call to see whether there are any gluepoints.
// Force const call!
if (GetGluePointList()!=nullptr) {
SdrGluePointList* pGPL=ForceGluePointList();
pGPL->Mirror(rRef1,rRef2,this);
}
}
void SdrObject::NbcShearGluePoints(const Point& rRef, double tn, bool bVShear)
{
// First a const call to see whether there are any gluepoints.
// Force const call!
if (GetGluePointList()!=nullptr) {
SdrGluePointList* pGPL=ForceGluePointList();
pGPL->Shear(rRef,tn,bVShear,this);
}
}
void SdrObject::ConnectToNode(bool /*bTail1*/, SdrObject* /*pObj*/)
{
}
void SdrObject::DisconnectFromNode(bool /*bTail1*/)
{
}
SdrObject* SdrObject::GetConnectedNode(bool /*bTail1*/) const
{
return nullptr;
}
static void extractLineContourFromPrimitive2DSequence(
const drawinglayer::primitive2d::Primitive2DContainer& rxSequence,
basegfx::B2DPolygonVector& rExtractedHairlines,
basegfx::B2DPolyPolygonVector& rExtractedLineFills)
{
rExtractedHairlines.clear();
rExtractedLineFills.clear();
if(rxSequence.empty())
return;
// use neutral ViewInformation
const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
// create extractor, process and get result
drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
aExtractor.process(rxSequence);
// copy line results
rExtractedHairlines = aExtractor.getExtractedHairlines();
// copy fill results
rExtractedLineFills = aExtractor.getExtractedLineFills();
}
rtl::Reference<SdrObject> SdrObject::ImpConvertToContourObj(bool bForceLineDash)
{
rtl::Reference<SdrObject> pRetval;
if(LineGeometryUsageIsNecessary())
{
basegfx::B2DPolyPolygon aMergedLineFillPolyPolygon;
basegfx::B2DPolyPolygon aMergedHairlinePolyPolygon;
drawinglayer::primitive2d::Primitive2DContainer xSequence;
GetViewContact().getViewIndependentPrimitive2DContainer(xSequence);
if(!xSequence.empty())
{
basegfx::B2DPolygonVector aExtractedHairlines;
basegfx::B2DPolyPolygonVector aExtractedLineFills;
extractLineContourFromPrimitive2DSequence(xSequence, aExtractedHairlines, aExtractedLineFills);
// for SdrObject creation, just copy all to a single Hairline-PolyPolygon
for(const basegfx::B2DPolygon & rExtractedHairline : aExtractedHairlines)
{
aMergedHairlinePolyPolygon.append(rExtractedHairline);
}
// check for fill results
if (!aExtractedLineFills.empty() && !comphelper::IsFuzzing())
{
// merge to a single tools::PolyPolygon (OR)
aMergedLineFillPolyPolygon = basegfx::utils::mergeToSinglePolyPolygon(std::move(aExtractedLineFills));
}
}
if(aMergedLineFillPolyPolygon.count() || (bForceLineDash && aMergedHairlinePolyPolygon.count()))
{
SfxItemSet aSet(GetMergedItemSet());
drawing::FillStyle eOldFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue();
rtl::Reference<SdrPathObj> aLinePolygonPart;
rtl::Reference<SdrPathObj> aLineHairlinePart;
bool bBuildGroup(false);
if(aMergedLineFillPolyPolygon.count())
{
// create SdrObject for filled line geometry
aLinePolygonPart = new SdrPathObj(
getSdrModelFromSdrObject(),
SdrObjKind::PathFill,
std::move(aMergedLineFillPolyPolygon));
// correct item properties
aSet.Put(XLineWidthItem(0));
aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue();
sal_uInt16 nTransLine = aSet.Get(XATTR_LINETRANSPARENCE).GetValue();
aSet.Put(XFillColorItem(OUString(), aColorLine));
aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
aSet.Put(XFillTransparenceItem(nTransLine));
aLinePolygonPart->SetMergedItemSet(aSet);
}
if(aMergedHairlinePolyPolygon.count())
{
// create SdrObject for hairline geometry
// OBJ_PATHLINE is necessary here, not OBJ_PATHFILL. This is intended
// to get a non-filled object. If the poly is closed, the PathObj takes care for
// the correct closed state.
aLineHairlinePart = new SdrPathObj(
getSdrModelFromSdrObject(),
SdrObjKind::PathLine,
std::move(aMergedHairlinePolyPolygon));
aSet.Put(XLineWidthItem(0));
aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
aSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
// it is also necessary to switch off line start and ends here
aSet.Put(XLineStartWidthItem(0));
aSet.Put(XLineEndWidthItem(0));
aLineHairlinePart->SetMergedItemSet(aSet);
if(aLinePolygonPart)
{
bBuildGroup = true;
}
}
// check if original geometry should be added (e.g. filled and closed)
bool bAddOriginalGeometry(false);
SdrPathObj* pPath = dynamic_cast<SdrPathObj*>(this);
if(pPath && pPath->IsClosed())
{
if(eOldFillStyle != drawing::FillStyle_NONE)
{
bAddOriginalGeometry = true;
}
}
// do we need a group?
if(bBuildGroup || bAddOriginalGeometry)
{
rtl::Reference<SdrObject> xGroup = new SdrObjGroup(getSdrModelFromSdrObject());
if(bAddOriginalGeometry)
{
// Add a clone of the original geometry.
aSet.ClearItem();
aSet.Put(GetMergedItemSet());
aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
aSet.Put(XLineWidthItem(0));
rtl::Reference<SdrObject> pClone(CloneSdrObject(getSdrModelFromSdrObject()));
pClone->SetMergedItemSet(aSet);
xGroup->GetSubList()->NbcInsertObject(pClone.get());
}
if(aLinePolygonPart)
{
xGroup->GetSubList()->NbcInsertObject(aLinePolygonPart.get());
}
if(aLineHairlinePart)
{
xGroup->GetSubList()->NbcInsertObject(aLineHairlinePart.get());
}
pRetval = std::move(xGroup);
}
else
{
if(aLinePolygonPart)
{
pRetval = aLinePolygonPart;
}
else if(aLineHairlinePart)
{
pRetval = aLineHairlinePart;
}
}
}
}
if(!pRetval)
{
// due to current method usage, create and return a clone when nothing has changed
pRetval = CloneSdrObject(getSdrModelFromSdrObject());
}
return pRetval;
}
void SdrObject::SetMarkProtect(bool bProt)
{
m_bMarkProt = bProt;
}
void SdrObject::SetEmptyPresObj(bool bEpt)
{
const bool bWasEmpty = m_bEmptyPresObj;
m_bEmptyPresObj = bEpt;
// Whatever put the content there - typing, a filter, the API - the page hears about it once.
if (bWasEmpty && !bEpt)
{
if (SdrPage* pPage = getSdrPageFromSdrObject())
pPage->onEmptyPresObjFilled(*this);
}
}
void SdrObject::SetCustomPromptText(const OUString& rVal)
{
m_aCustomPromptText = rVal;
}
void SdrObject::SetNotVisibleAsMaster(bool bFlg)
{
m_bNotVisibleAsMaster=bFlg;
}
// convert this path object to contour object, even when it is a group
rtl::Reference<SdrObject> SdrObject::ConvertToContourObj(SdrObject* pRet1, bool bForceLineDash) const
{
rtl::Reference<SdrObject> pRet = pRet1;
if(dynamic_cast<const SdrObjGroup*>( pRet.get()) != nullptr)
{
SdrObjList* pObjList2 = pRet->GetSubList();
rtl::Reference<SdrObject> pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
for (const rtl::Reference<SdrObject>& pIterObj : *pObjList2)
pGroup->GetSubList()->NbcInsertObject(ConvertToContourObj(pIterObj.get(), bForceLineDash).get());
pRet = std::move(pGroup);
}
else
{
if (SdrPathObj *pPathObj = dynamic_cast<SdrPathObj*>(pRet.get()))
{
// bezier geometry got created, even for straight edges since the given
// object is a result of DoConvertToPolyObj. For conversion to contour
// this is not really needed and can be reduced again AFAP
pPathObj->SetPathPoly(basegfx::utils::simplifyCurveSegments(pPathObj->GetPathPoly()));
}
pRet = pRet->ImpConvertToContourObj(bForceLineDash);
}
// #i73441# preserve LayerID
if(pRet && pRet->GetLayer() != GetLayer())
{
pRet->SetLayer(GetLayer());
}
return pRet;
}
rtl::Reference<SdrObject> SdrObject::ConvertToPolyObj(bool bBezier, bool bLineToArea) const
{
rtl::Reference<SdrObject> pRet = DoConvertToPolyObj(bBezier, true);
if(pRet && bLineToArea)
{
pRet = ConvertToContourObj(pRet.get());
}
// #i73441# preserve LayerID
if(pRet && pRet->GetLayer() != GetLayer())
{
pRet->SetLayer(GetLayer());
}
return pRet;
}
rtl::Reference<SdrObject> SdrObject::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
{
return nullptr;
}
void SdrObject::InsertedStateChange()
{
const bool bIsInserted(nullptr != getParentSdrObjListFromSdrObject());
const tools::Rectangle aBoundRect0(GetLastBoundRect());
if(bIsInserted)
{
SendUserCall(SdrUserCallType::Inserted, aBoundRect0);
}
else
{
SendUserCall(SdrUserCallType::Removed, aBoundRect0);
}
if(nullptr != m_pPlusData && nullptr != m_pPlusData->pBroadcast)
{
SdrHint aHint(bIsInserted ? SdrHintKind::ObjectInserted : SdrHintKind::ObjectRemoved, *this);
m_pPlusData->pBroadcast->Broadcast(aHint);
}
}
void SdrObject::SetMoveProtect(bool bProt)
{
if(IsMoveProtect() != bProt)
{
// #i77187# secured and simplified
m_bMovProt = bProt;
SetChanged();
BroadcastObjectChange();
}
}
void SdrObject::SetResizeProtect(bool bProt)
{
if(IsResizeProtect() != bProt)
{
// #i77187# secured and simplified
m_bSizProt = bProt;
SetChanged();
BroadcastObjectChange();
}
}
void SdrObject::SetDeleteProtect(bool bProt)
{
if (IsDeleteProtect() != bProt)
{
m_bDelProt = bProt;
SetChanged();
BroadcastObjectChange();
}
}
bool SdrObject::IsPrintable() const
{
return !m_bNoPrint;
}
void SdrObject::SetPrintable(bool bPrn)
{
if( bPrn == m_bNoPrint )
{
m_bNoPrint=!bPrn;
SetChanged();
if (IsInserted())
{
SdrHint aHint(SdrHintKind::ObjectChange, *this);
getSdrModelFromSdrObject().Broadcast(aHint);
}
}
}
bool SdrObject::IsVisible() const
{
return mbVisible;
}
void SdrObject::SetVisible(bool bVisible)
{
if( bVisible != mbVisible )
{
mbVisible = bVisible;
SetChanged();
if (IsInserted())
{
SdrHint aHint(SdrHintKind::ObjectChange, *this);
getSdrModelFromSdrObject().Broadcast(aHint);
}
}
}
sal_uInt16 SdrObject::GetUserDataCount() const
{
if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return 0;
return m_pPlusData->pUserDataList->GetUserDataCount();
}
SdrObjUserData* SdrObject::GetUserData(sal_uInt16 nNum) const
{
if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return nullptr;
return &m_pPlusData->pUserDataList->GetUserData(nNum);
}
void SdrObject::AppendUserData(std::unique_ptr<SdrObjUserData> pData)
{
if (!pData)
{
OSL_FAIL("SdrObject::AppendUserData(): pData is NULL pointer.");
return;
}
ImpForcePlusData();
if (!m_pPlusData->pUserDataList)
m_pPlusData->pUserDataList.reset( new SdrObjUserDataList );
m_pPlusData->pUserDataList->AppendUserData(std::move(pData));
}
void SdrObject::DeleteUserData(sal_uInt16 nNum)
{
sal_uInt16 nCount=GetUserDataCount();
if (nNum<nCount) {
m_pPlusData->pUserDataList->DeleteUserData(nNum);
if (nCount==1) {
m_pPlusData->pUserDataList.reset();
}
} else {
OSL_FAIL("SdrObject::DeleteUserData(): Invalid Index.");
}
}
void SdrObject::SetUserCall(SdrObjUserCall* pUser)
{
m_pUserCall = pUser;
}
void SdrObject::SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle& rBoundRect) const
{
SdrObject* pGroup(getParentSdrObjectFromSdrObject());
if ( m_pUserCall )
{
m_pUserCall->Changed( *this, eUserCall, rBoundRect );
}
if(nullptr != pGroup && pGroup->GetUserCall())
{
// broadcast to group
SdrUserCallType eChildUserType = SdrUserCallType::ChildChangeAttr;
switch( eUserCall )
{
case SdrUserCallType::MoveOnly:
eChildUserType = SdrUserCallType::ChildMoveOnly;
break;
case SdrUserCallType::Resize:
eChildUserType = SdrUserCallType::ChildResize;
break;
case SdrUserCallType::ChangeAttr:
eChildUserType = SdrUserCallType::ChildChangeAttr;
break;
case SdrUserCallType::Delete:
eChildUserType = SdrUserCallType::ChildDelete;
break;
case SdrUserCallType::Inserted:
eChildUserType = SdrUserCallType::ChildInserted;
break;
case SdrUserCallType::Removed:
eChildUserType = SdrUserCallType::ChildRemoved;
break;
default: break;
}
pGroup->GetUserCall()->Changed( *this, eChildUserType, rBoundRect );
}
// notify our UNO shape listeners
switch ( eUserCall )
{
case SdrUserCallType::Resize:
notifyShapePropertyChange( u"Size"_ustr );
[[fallthrough]]; // RESIZE might also imply a change of the position
case SdrUserCallType::MoveOnly:
notifyShapePropertyChange( u"Position"_ustr );
break;
default:
// not interested in
break;
}
}
void SdrObject::setUnoShape( const uno::Reference< drawing::XShape >& _rxUnoShape )
{
const uno::Reference< uno::XInterface> xOldUnoShape( maWeakUnoShape );
// the UNO shape would be gutted by the following code; return early
if ( _rxUnoShape == xOldUnoShape )
{
if ( !xOldUnoShape.is() )
{
// make sure there is no stale impl. pointer if the UNO
// shape was destroyed meanwhile (remember we only hold weak
// reference to it!)
mpSvxShape = nullptr;
}
return;
}
if ( xOldUnoShape.is() )
{
// Remove yourself from the current UNO shape. Its destructor
// will reset our UNO shape otherwise.
mpSvxShape->InvalidateSdrObject();
}
maWeakUnoShape = _rxUnoShape;
mpSvxShape = comphelper::getFromUnoTunnel<SvxShape>( _rxUnoShape );
}
/** only for internal use! */
SvxShape* SdrObject::getSvxShape()
{
DBG_TESTSOLARMUTEX();
// retrieving the impl pointer and subsequently using it is not thread-safe, of course, so it needs to be
// guarded by the SolarMutex
uno::Reference< uno::XInterface > xShape( maWeakUnoShape );
//#113608#, make sure mpSvxShape is always synchronized with maWeakUnoShape
if ( mpSvxShape && !xShape )
mpSvxShape = nullptr;
return mpSvxShape;
}
css::uno::Reference< css::drawing::XShape > SdrObject::getUnoShape()
{
// try weak reference first
uno::Reference< css::drawing::XShape > xShape = maWeakUnoShape;
if (xShape)
return xShape;
// try to access SdrPage from this SdrObject. This will only exist if the SdrObject is
// inserted in a SdrObjList (page/group/3dScene)
SdrPage* pPageCandidate(getSdrPageFromSdrObject());
// tdf#12152, tdf#120728
//
// With the paradigm change to only get a SdrPage for a SdrObject when the SdrObject
// is *inserted*, the functionality for creating 1:1 associated UNO API implementation
// SvxShapes was partially broken: The used ::CreateShape relies on the SvxPage being
// derived and the CreateShape method overloaded, implementing additional SdrInventor
// types as needed.
//
// The fallback to use SvxDrawPage::CreateShapeByTypeAndInventor is a trap: It's only
// a static fallback that handles the SdrInventor types SdrInventor::E3d and
// SdrInventor::Default. Due to that, e.g. the ReportDesigner broke in various conditions.
//
// That again has to do with the ReportDesigner being implemented using the UNO API
// aspects of SdrObjects early during their construction, not just after these are
// inserted to a SdrPage - but that is not illegal or wrong, the SdrObject exists already.
//
// As a current solution, use the (now always available) SdrModel and any of the
// existing SdrPages. The only important thing is to get a SdrPage where ::CreateShape is
// overloaded and implemented as needed.
//
// Note for the future:
// In a more ideal world there would be only one factory method for creating SdrObjects (not
// ::CreateShape and ::CreateShapeByTypeAndInventor). This also would not be placed at
// SdrPage/SvxPage at all, but at the Model where it belongs - where else would you expect
// objects for the current Model to be constructed? To have this at the Page only would make
// sense if different shapes would need to be constructed for different Pages in the same Model
// - this is never the case.
// At that Model extended functionality for that factory (or overloads and implementations)
// should be placed. But to be realistic, migrating the factories to Model now is too much
// work - maybe over time when melting SdrObject/SvxObject one day...
//
// More Note (added by noel grandin)
// Except that sd/ is being naughty and doing all kinds of magic during CreateShape that
// requires knowing which page the object is being created for. Fixing that would require
// moving a bunch of nasty logic from object creation time, to the point in time when
// it is actually added to a page.
if(nullptr == pPageCandidate)
{
// If not inserted, alternatively access a SdrPage using the SdrModel. There is
// no reason not to create and return a UNO API XShape when the SdrObject is not
// inserted - it may be in construction. Main paradigm is that it exists.
if(0 != getSdrModelFromSdrObject().GetPageCount())
{
// Take 1st SdrPage. That may be e.g. a special page (in SD), but the
// to-be-used method ::CreateShape will be correctly overloaded in
// all cases
pPageCandidate = getSdrModelFromSdrObject().GetPage(0);
}
}
if(nullptr != pPageCandidate)
{
uno::Reference< uno::XInterface > xPage(pPageCandidate->getUnoPage());
if( xPage.is() )
{
SvxDrawPage* pDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>(xPage);
if( pDrawPage )
{
// create one
xShape = pDrawPage->CreateShape( this );
assert(xShape);
setUnoShape( xShape );
}
}
}
else
{
// Fallback to static base functionality. CAUTION: This will only support
// the most basic stuff like SdrInventor::E3d and SdrInventor::Default. All
// the other SdrInventor enum entries are from overloads and are *not accessible*
// using this fallback (!) - what a bad trap
rtl::Reference<SvxShape> xNewShape = SvxDrawPage::CreateShapeByTypeAndInventor( GetObjIdentifier(), GetObjInventor(), this );
mpSvxShape = xNewShape.get();
maWeakUnoShape = xShape = mpSvxShape;
}
return xShape;
}
void SdrObject::notifyShapePropertyChange( const OUString& rPropName ) const
{
DBG_TESTSOLARMUTEX();
SvxShape* pSvxShape = const_cast< SdrObject* >( this )->getSvxShape();
if ( pSvxShape )
return pSvxShape->notifyPropertyChange( rPropName );
}
// transformation interface for StarOfficeAPI. This implements support for
// homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
// moment it contains a shearX, rotation and translation, but for setting all linear
// transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
// gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
// with the base geometry and returns TRUE. Otherwise it returns FALSE.
bool SdrObject::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
{
// any kind of SdrObject, just use SnapRect
tools::Rectangle aRectangle(GetSnapRect());
// convert to transformation values
basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());
// position maybe relative to anchorpos, convert
if(getSdrModelFromSdrObject().IsWriter())
{
if(GetAnchorPos().X() || GetAnchorPos().Y())
{
aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
}
}
// build matrix
rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
return false;
}
// sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
// If it's an SdrPathObj it will use the provided geometry information. The Polygon has
// to use (0,0) as upper left and will be scaled to the given size in the matrix.
void SdrObject::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
{
// break up matrix
basegfx::B2DTuple aScale;
basegfx::B2DTuple aTranslate;
double fRotate, fShearX;
rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
// #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
// in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
if(aScale.getX() < 0.0 && aScale.getY() < 0.0)
{
aScale.setX(fabs(aScale.getX()));
aScale.setY(fabs(aScale.getY()));
}
// if anchor is used, make position relative to it
if(getSdrModelFromSdrObject().IsWriter())
{
if(GetAnchorPos().X() || GetAnchorPos().Y())
{
aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
}
}
// build BaseRect
Point aPoint(basegfx::fround<tools::Long>(aTranslate.getX()),
basegfx::fround<tools::Long>(aTranslate.getY()));
tools::Rectangle aBaseRect(aPoint, Size(basegfx::fround<tools::Long>(aScale.getX()),
basegfx::fround<tools::Long>(aScale.getY())));
// set BaseRect
SetSnapRect(aBaseRect);
}
// Give info if object is in destruction
bool SdrObject::IsInDestruction() const
{
return getSdrModelFromSdrObject().IsInDestruction();
}
// return if fill is != drawing::FillStyle_NONE
bool SdrObject::HasFillStyle() const
{
return GetObjectItem(XATTR_FILLSTYLE).GetValue() != drawing::FillStyle_NONE;
}
bool SdrObject::HasLineStyle() const
{
return GetObjectItem(XATTR_LINESTYLE).GetValue() != drawing::LineStyle_NONE;
}
// #i52224#
// on import of OLE object from MS documents the BLIP size might be retrieved,
// the following four methods are used to control it;
// usually this data makes no sense after the import is finished, since the object
// might be resized
void SdrObject::SetBLIPSizeRectangle( const tools::Rectangle& aRect )
{
maBLIPSizeRectangle = aRect;
}
void SdrObject::SetContextWritingMode( const sal_Int16 /*_nContextWritingMode*/ )
{
// this base class does not support different writing modes, so ignore the call
}
void SdrObject::SetDoNotInsertIntoPageAutomatically(const bool bSet)
{
mbDoNotInsertIntoPageAutomatically = bSet;
}
// #i121917#
bool SdrObject::HasText() const
{
return false;
}
bool SdrObject::IsTextBox() const
{
return false;
}
void SdrObject::MakeNameUnique()
{
if (GetName().isEmpty())
{
OUString aName;
if (const E3dScene* pE3dObj = DynCastE3dScene(this))
{
SdrObjList* pObjList = pE3dObj->GetSubList();
if (pObjList)
{
SdrObject* pObj0 = pObjList->GetObj(0);
if (pObj0)
aName = pObj0->TakeObjNameSingul();
}
}
else
aName = TakeObjNameSingul();
SetName(aName + " 1");
}
std::unordered_set<OUString> aNameSet;
MakeNameUnique(aNameSet);
}
void SdrObject::MakeNameUnique(std::unordered_set<OUString>& rNameSet)
{
if (GetName().isEmpty())
return;
if (ObjectNameIsDiagramModelID())
// do not make name unique for DiagramModelID's
return;
OUString sName(GetName().trim());
OUString sRootName(sName);
if (!sName.isEmpty() && rtl::isAsciiDigit(sName[sName.getLength() - 1]))
{
sal_Int32 nPos(sName.getLength() - 1);
while (nPos > 0 && rtl::isAsciiDigit(sName[--nPos]));
sRootName = o3tl::trim(sName.subView(0, nPos + 1));
}
if (rNameSet.empty())
{
SdrPage* pPage;
SdrObject* pObj;
for (sal_uInt16 nPage(0); nPage < mrSdrModelFromSdrObject.GetPageCount(); ++nPage)
{
pPage = mrSdrModelFromSdrObject.GetPage(nPage);
SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
while (aIter.IsMore())
{
pObj = aIter.Next();
if (pObj != this)
{
auto rName = pObj->GetName();
if (rName.startsWith(sRootName))
rNameSet.insert(rName);
}
}
}
}
for (sal_uInt32 n = 1; rNameSet.contains(sName); n++)
sName = sRootName + " " + OUString::number(n);
rNameSet.insert(sName);
SetName(sName);
}
void SdrObject::ForceMetricToItemPoolMetric(basegfx::B2DPolyPolygon& rPolyPolygon) const noexcept
{
MapUnit eMapUnit(getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
if(eMapUnit == MapUnit::Map100thMM)
return;
if (const auto eTo = MapToO3tlLength(eMapUnit); eTo != o3tl::Length::invalid)
{
const double fConvert(o3tl::convert(1.0, o3tl::Length::mm100, eTo));
rPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(fConvert, fConvert));
}
else
{
OSL_FAIL("Missing unit translation to PoolMetric!");
}
}
const tools::Rectangle& SdrObject::getOutRectangle() const
{
return m_aOutRect;
}
void SdrObject::setOutRectangleConst(tools::Rectangle const& rRectangle) const
{
m_aOutRect = rRectangle;
}
void SdrObject::setOutRectangle(tools::Rectangle const& rRectangle)
{
m_aOutRect = rRectangle;
}
void SdrObject::resetOutRectangle()
{
m_aOutRect = tools::Rectangle();
}
void SdrObject::moveOutRectangle(sal_Int32 nXDelta, sal_Int32 nYDelta)
{
m_aOutRect.Move(nXDelta, nYDelta);
}
E3dScene* DynCastE3dScene(SdrObject* pObj)
{
if( pObj && pObj->GetObjInventor() == SdrInventor::E3d && pObj->GetObjIdentifier() == SdrObjKind::E3D_Scene )
return static_cast<E3dScene*>(pObj);
return nullptr;
}
E3dObject* DynCastE3dObject(SdrObject* pObj)
{
if( pObj && pObj->GetObjInventor() == SdrInventor::E3d )
return static_cast<E3dObject*>(pObj);
return nullptr;
}
SdrTextObj* DynCastSdrTextObj(SdrObject* pObj)
{
// SdrTextObj has a lot of subclasses, with lots of SdrObjKind identifiers, so use a virtual method
// to be safer.
if( pObj && pObj->IsSdrTextObj() )
return static_cast<SdrTextObj*>(pObj);
return nullptr;
}
SdrOle2Obj* DynCastSdrOle2Obj(SdrObject* pObj)
{
// SdrTextObj has subclasses, with lots of SdrObjKind identifiers, so use a virtual method
// to be safer.
if( pObj && pObj->IsSdrOle2Obj() )
return static_cast<SdrOle2Obj*>(pObj);
return nullptr;
}
rtl::Reference<SdrObject> SdrObjFactory::CreateObjectFromFactory(SdrModel& rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier)
{
SdrObjCreatorParams aParams { nInventor, nObjIdentifier, rSdrModel };
for (const auto & i : ImpGetUserMakeObjHdl()) {
rtl::Reference<SdrObject> pObj = i.Call(aParams);
if (pObj) {
return pObj;
}
}
return nullptr;
}
namespace
{
// SdrObject subclass, which represents an empty object of a
// certain type (kind).
template <SdrObjKind OBJECT_KIND, SdrInventor OBJECT_INVENTOR>
class EmptyObject final : public SdrObject
{
private:
virtual ~EmptyObject() override
{}
public:
EmptyObject(SdrModel& rSdrModel)
: SdrObject(rSdrModel)
{
}
EmptyObject(SdrModel& rSdrModel, EmptyObject const& rSource)
: SdrObject(rSdrModel, rSource)
{
}
rtl::Reference<SdrObject> implCloneSdrObject(SdrModel& rTargetModel) const override
{
return new EmptyObject(rTargetModel, *this);
}
virtual std::unique_ptr<sdr::properties::BaseProperties> CreateObjectSpecificProperties() override
{
return std::make_unique<sdr::properties::EmptyProperties>(*this);
}
SdrInventor GetObjInventor() const override
{
return OBJECT_INVENTOR;
}
SdrObjKind GetObjIdentifier() const override
{
return OBJECT_KIND;
}
void NbcRotate(const Point& /*rRef*/, Degree100 /*nAngle*/, double /*sinAngle*/, double /*cosAngle*/) override
{
assert(false); // should not be called for this kind of objects
}
};
} // end anonymous namespace
rtl::Reference<SdrObject> SdrObjFactory::MakeNewObject(
SdrModel& rSdrModel,
SdrInventor nInventor,
SdrObjKind nIdentifier,
const tools::Rectangle* pSnapRect)
{
rtl::Reference<SdrObject> pObj;
bool bSetSnapRect(nullptr != pSnapRect);
if (nInventor == SdrInventor::Default)
{
switch (nIdentifier)
{
case SdrObjKind::Measure:
{
if(nullptr != pSnapRect)
{
pObj = new SdrMeasureObj(
rSdrModel,
pSnapRect->TopLeft(),
pSnapRect->BottomRight());
}
else
{
pObj = new SdrMeasureObj(rSdrModel);
}
}
break;
case SdrObjKind::Line:
{
if(nullptr != pSnapRect)
{
basegfx::B2DPolygon aPoly;
aPoly.append(
basegfx::B2DPoint(
pSnapRect->Left(),
pSnapRect->Top()));
aPoly.append(
basegfx::B2DPoint(
pSnapRect->Right(),
pSnapRect->Bottom()));
pObj = new SdrPathObj(
rSdrModel,
SdrObjKind::Line,
basegfx::B2DPolyPolygon(aPoly));
}
else
{
pObj = new SdrPathObj(
rSdrModel,
SdrObjKind::Line);
}
}
break;
case SdrObjKind::Text:
case SdrObjKind::TitleText:
case SdrObjKind::OutlineText:
{
if(nullptr != pSnapRect)
{
pObj = new SdrRectObj(
rSdrModel, *pSnapRect, nIdentifier);
bSetSnapRect = false;
}
else
{
pObj = new SdrRectObj(
rSdrModel, tools::Rectangle(), nIdentifier);
}
}
break;
case SdrObjKind::CircleOrEllipse:
case SdrObjKind::CircleSection:
case SdrObjKind::CircleArc:
case SdrObjKind::CircleCut:
{
SdrCircKind eCircKind = ToSdrCircKind(nIdentifier);
if(nullptr != pSnapRect)
{
pObj = new SdrCircObj(rSdrModel, eCircKind, *pSnapRect);
bSetSnapRect = false;
}
else
{
pObj = new SdrCircObj(rSdrModel, eCircKind);
}
}
break;
case SdrObjKind::NONE: pObj = nullptr; break;
case SdrObjKind::Group : pObj=new SdrObjGroup(rSdrModel); break;
case SdrObjKind::Polygon : pObj=new SdrPathObj(rSdrModel, SdrObjKind::Polygon ); break;
case SdrObjKind::PolyLine : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PolyLine ); break;
case SdrObjKind::PathLine : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PathLine ); break;
case SdrObjKind::PathFill : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PathFill ); break;
case SdrObjKind::FreehandLine : pObj=new SdrPathObj(rSdrModel, SdrObjKind::FreehandLine ); break;
case SdrObjKind::FreehandFill : pObj=new SdrPathObj(rSdrModel, SdrObjKind::FreehandFill ); break;
case SdrObjKind::PathPoly : pObj=new SdrPathObj(rSdrModel, SdrObjKind::Polygon ); break;
case SdrObjKind::PathPolyLine : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PolyLine ); break;
case SdrObjKind::Edge : pObj=new SdrEdgeObj(rSdrModel); break;
case SdrObjKind::Rectangle : pObj=new SdrRectObj(rSdrModel); break;
case SdrObjKind::Graphic : pObj=new SdrGrafObj(rSdrModel); break;
case SdrObjKind::OLE2 : pObj=new SdrOle2Obj(rSdrModel); break;
case SdrObjKind::OLEPluginFrame : pObj=new SdrOle2Obj(rSdrModel, true); break;
case SdrObjKind::Caption : pObj=new SdrCaptionObj(rSdrModel); break;
case SdrObjKind::Page : pObj=new SdrPageObj(rSdrModel); break;
case SdrObjKind::UNO : pObj=new SdrUnoObj(rSdrModel, OUString()); break;
case SdrObjKind::CustomShape: pObj=new SdrObjCustomShape(rSdrModel); break;
#if HAVE_FEATURE_AVMEDIA
case SdrObjKind::Media : pObj=new SdrMediaObj(rSdrModel); break;
#endif
case SdrObjKind::Table : pObj=new sdr::table::SdrTableObj(rSdrModel); break;
case SdrObjKind::NewFrame: // used for frame creation in writer
pObj = new EmptyObject<SdrObjKind::NewFrame, SdrInventor::Default>(rSdrModel);
break;
default:
break;
}
}
if (!pObj)
{
pObj = CreateObjectFromFactory(rSdrModel, nInventor, nIdentifier);
}
if (!pObj)
{
// Well, if no one wants it...
return nullptr;
}
if(bSetSnapRect && nullptr != pSnapRect)
{
pObj->NbcSetSnapRect(*pSnapRect);
}
return pObj;
}
void SdrObjFactory::InsertMakeObjectHdl(Link<SdrObjCreatorParams, rtl::Reference<SdrObject>> const & rLink)
{
std::vector<Link<SdrObjCreatorParams, rtl::Reference<SdrObject>>>& rLL=ImpGetUserMakeObjHdl();
auto it = std::find(rLL.begin(), rLL.end(), rLink);
if (it != rLL.end()) {
OSL_FAIL("SdrObjFactory::InsertMakeObjectHdl(): Link already in place.");
} else {
rLL.push_back(rLink);
}
}
void SdrObjFactory::RemoveMakeObjectHdl(Link<SdrObjCreatorParams, rtl::Reference<SdrObject>> const & rLink)
{
std::vector<Link<SdrObjCreatorParams, rtl::Reference<SdrObject>>>& rLL=ImpGetUserMakeObjHdl();
auto it = std::find(rLL.begin(), rLL.end(), rLink);
if (it != rLL.end())
rLL.erase(it);
}
namespace svx
{
ISdrObjectFilter::~ISdrObjectFilter()
{
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */