Both are derived from SfxSetItem which means they contain a SfxItemSet themselves. That leads to problems since at their construction time a SfxItemPool has to be known and it *should* not be different to the one of the ItemSet that Item gets added later - that leads to the 2nd class of problems. In the long therm we should get rid of all SfxSetItems. This change simplifies already some stuff, including that the standard Items for DrawObjects reduces by two (and more due to containing a whole ItemSet) and e.g. the problem that these Items had to be converted to hard attributes in the done fixes for copy/pasting Slides. Signed-off-by: Armin Le Grand (collabora) <Armin.LeGrand@collabora.com> Change-Id: I8b1c6cabdaa43ed6062811b5508ab3dece47a755 Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/6795 Reviewed-by: Armin Le Grand <armin.legrand@collabora.com> Tested-by: Jenkins CPCI <releng@collaboraoffice.com> (cherry picked from commit e67458a9b769fe7a3a7ee0739ed6d5c46dbc0692) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211734 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
3744 lines
112 KiB
C++
3744 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 <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)
|
|
{
|
|
// 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: */
|