diff options
Diffstat (limited to 'sw/source/core/unocore/unodraw.cxx')
-rw-r--r-- | sw/source/core/unocore/unodraw.cxx | 2876 |
1 files changed, 2876 insertions, 0 deletions
diff --git a/sw/source/core/unocore/unodraw.cxx b/sw/source/core/unocore/unodraw.cxx new file mode 100644 index 0000000000..5bb5621d95 --- /dev/null +++ b/sw/source/core/unocore/unodraw.cxx @@ -0,0 +1,2876 @@ +/* -*- 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 <sal/config.h> + +#include <initializer_list> +#include <memory> +#include <string_view> + +#include <sal/log.hxx> + +#include <cmdid.h> +#include <unomid.h> + +#include <drawdoc.hxx> +#include <unodraw.hxx> +#include <unoframe.hxx> +#include <unoparagraph.hxx> +#include <unotextrange.hxx> +#include <svx/svditer.hxx> +#include <swunohelper.hxx> +#include <textboxhelper.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <fmtcntnt.hxx> +#include <fmtflcnt.hxx> +#include <txatbase.hxx> +#include <docsh.hxx> +#include <unomap.hxx> +#include <unoport.hxx> +#include <TextCursorHelper.hxx> +#include <dflyobj.hxx> +#include <ndtxt.hxx> +#include <svx/svdview.hxx> +#include <svx/unoshape.hxx> +#include <dcontact.hxx> +#include <fmtornt.hxx> +#include <fmtsrnd.hxx> +#include <fmtfollowtextflow.hxx> +#include <rootfrm.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> +#include <crstate.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/profilezone.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <svx/scene3d.hxx> +#include <tools/UnitConversion.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <fmtwrapinfluenceonobjpos.hxx> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <docmodel/uno/UnoTheme.hxx> + +using namespace ::com::sun::star; + +class SwShapeDescriptor_Impl +{ + bool m_isInReading; + std::unique_ptr<SwFormatHoriOrient> m_pHOrient; + std::unique_ptr<SwFormatVertOrient> m_pVOrient; + std::unique_ptr<SwFormatAnchor> m_pAnchor; + std::unique_ptr<SwFormatSurround> m_pSurround; + std::unique_ptr<SvxULSpaceItem> m_pULSpace; + std::unique_ptr<SvxLRSpaceItem> m_pLRSpace; + bool m_bOpaque; + uno::Reference< text::XTextRange > m_xTextRange; + // #i26791# + std::unique_ptr<SwFormatFollowTextFlow> m_pFollowTextFlow; + // #i28701# + std::unique_ptr<SwFormatWrapInfluenceOnObjPos> m_pWrapInfluenceOnObjPos; + // #i28749# + sal_Int16 mnPositionLayoutDir; + + SwShapeDescriptor_Impl(const SwShapeDescriptor_Impl&) = delete; + SwShapeDescriptor_Impl& operator=(const SwShapeDescriptor_Impl&) = delete; + +public: + SwShapeDescriptor_Impl(SwDoc const*const pDoc) + : m_isInReading(pDoc && pDoc->IsInReading()) + // #i32349# - no defaults, in order to determine on + // adding a shape, if positioning attributes are set or not. + , m_bOpaque(false) + // #i26791# + , m_pFollowTextFlow( new SwFormatFollowTextFlow(false) ) + // #i28701# #i35017# + , m_pWrapInfluenceOnObjPos( new SwFormatWrapInfluenceOnObjPos( + text::WrapInfluenceOnPosition::ONCE_CONCURRENT) ) + // #i28749# + , mnPositionLayoutDir(text::PositionLayoutDir::PositionInLayoutDirOfAnchor) + {} + + SwFormatAnchor* GetAnchor(bool bCreate = false) + { + if (bCreate && !m_pAnchor) + { + m_pAnchor.reset(new SwFormatAnchor(RndStdIds::FLY_AS_CHAR)); + } + return m_pAnchor.get(); + } + SwFormatHoriOrient* GetHOrient(bool bCreate = false) + { + if (bCreate && !m_pHOrient) + { + // #i26791# + m_pHOrient.reset(new SwFormatHoriOrient(0, text::HoriOrientation::NONE, text::RelOrientation::FRAME)); + } + return m_pHOrient.get(); + } + SwFormatVertOrient* GetVOrient(bool bCreate = false) + { + if (bCreate && !m_pVOrient) + { + if (m_isInReading && // tdf#113938 extensions might rely on old default + (!GetAnchor(true) || m_pAnchor->GetAnchorId() == RndStdIds::FLY_AS_CHAR)) + { // for as-char, NONE ("from-top") is not a good default + m_pVOrient.reset(new SwFormatVertOrient(0, text::VertOrientation::TOP, text::RelOrientation::FRAME)); + } + else + { // #i26791# + m_pVOrient.reset(new SwFormatVertOrient(0, text::VertOrientation::NONE, text::RelOrientation::FRAME)); + } + } + return m_pVOrient.get(); + } + + SwFormatSurround* GetSurround(bool bCreate = false) + { + if (bCreate && !m_pSurround) + { + m_pSurround.reset(new SwFormatSurround()); + } + return m_pSurround.get(); + } + SvxLRSpaceItem* GetLRSpace(bool bCreate = false) + { + if (bCreate && !m_pLRSpace) + { + m_pLRSpace.reset(new SvxLRSpaceItem(RES_LR_SPACE)); + } + return m_pLRSpace.get(); + } + SvxULSpaceItem* GetULSpace(bool bCreate = false) + { + if (bCreate && !m_pULSpace) + { + m_pULSpace.reset(new SvxULSpaceItem(RES_UL_SPACE)); + } + return m_pULSpace.get(); + } + uno::Reference< text::XTextRange > & GetTextRange() + { + return m_xTextRange; + } + bool IsOpaque() const + { + return m_bOpaque; + } + const bool& GetOpaque() const + { + return m_bOpaque; + } + void RemoveHOrient() { m_pHOrient.reset(); } + void RemoveVOrient() { m_pVOrient.reset(); } + void RemoveAnchor() { m_pAnchor.reset(); } + void RemoveSurround() { m_pSurround.reset(); } + void RemoveULSpace() { m_pULSpace.reset(); } + void RemoveLRSpace() { m_pLRSpace.reset(); } + void SetOpaque(bool bSet){m_bOpaque = bSet;} + + // #i26791# + SwFormatFollowTextFlow* GetFollowTextFlow( bool _bCreate = false ) + { + if (_bCreate && !m_pFollowTextFlow) + { + m_pFollowTextFlow.reset(new SwFormatFollowTextFlow(false)); + } + return m_pFollowTextFlow.get(); + } + void RemoveFollowTextFlow() + { + m_pFollowTextFlow.reset(); + } + + // #i28749# + sal_Int16 GetPositionLayoutDir() const + { + return mnPositionLayoutDir; + } + void SetPositionLayoutDir( sal_Int16 _nPositionLayoutDir ) + { + switch ( _nPositionLayoutDir ) + { + case text::PositionLayoutDir::PositionInHoriL2R: + case text::PositionLayoutDir::PositionInLayoutDirOfAnchor: + { + mnPositionLayoutDir = _nPositionLayoutDir; + } + break; + default: + { + OSL_FAIL( "<SwShapeDescriptor_Impl::SetPositionLayoutDir(..)> - invalid attribute value." ); + } + } + } + + // #i28701# + SwFormatWrapInfluenceOnObjPos* GetWrapInfluenceOnObjPos( + const bool _bCreate = false ) + { + if (_bCreate && !m_pWrapInfluenceOnObjPos) + { + m_pWrapInfluenceOnObjPos.reset(new SwFormatWrapInfluenceOnObjPos( + // #i35017# + text::WrapInfluenceOnPosition::ONCE_CONCURRENT)); + } + return m_pWrapInfluenceOnObjPos.get(); + } + void RemoveWrapInfluenceOnObjPos() + { + m_pWrapInfluenceOnObjPos.reset(); + } +}; + +SwFmDrawPage::SwFmDrawPage( SwDoc* pDoc, SdrPage* pPage ) + : SwFmDrawPage_Base(pPage) + , m_pDoc(pDoc) + , m_pPageView(nullptr) + , m_pPropertySet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_PAGE)) +{ +} + +SwFmDrawPage::~SwFmDrawPage() noexcept +{ + while (!m_vShapes.empty()) + m_vShapes.back()->dispose(); + RemovePageView(); +} + +const SdrMarkList& SwFmDrawPage::PreGroup(const uno::Reference< drawing::XShapes > & xShapes) +{ + SelectObjectsInView( xShapes, GetPageView() ); + const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); + return rMarkList; +} + +void SwFmDrawPage::PreUnGroup(const uno::Reference< drawing::XShapeGroup >& rShapeGroup) +{ + SelectObjectInView( rShapeGroup, GetPageView() ); +} + +SdrPageView* SwFmDrawPage::GetPageView() +{ + if(!m_pPageView) + m_pPageView = mpView->ShowSdrPage( mpPage ); + return m_pPageView; +} + +void SwFmDrawPage::RemovePageView() +{ + if(m_pPageView && mpView) + mpView->HideSdrPage(); + m_pPageView = nullptr; +} + +uno::Reference<drawing::XShape> SwFmDrawPage::GetShape(SdrObject* pObj) +{ + if(!pObj) + return nullptr; + SwFrameFormat* pFormat = ::FindFrameFormat( pObj ); + // TODO see comment at + // <https://gerrit.libreoffice.org/c/core/+/78734/4#message-5ee4e724a8073c5c475f07da0b5d79bc34e61de5> + // "make page bookkeep the SwXShapes" [-loplugin:crosscast]: + SwFmDrawPage* pPage = dynamic_cast<SwFmDrawPage*>(pFormat); + if(!pPage || pPage->m_vShapes.empty()) + return uno::Reference<drawing::XShape>(pObj->getUnoShape(), uno::UNO_QUERY); + for(const auto & pShape : pPage->m_vShapes) + { + SvxShape* pSvxShape = pShape->GetSvxShape(); + if (pSvxShape && pSvxShape->GetSdrObject() == pObj) + return pShape; + } + return nullptr; +} + +uno::Reference<drawing::XShapeGroup> SwFmDrawPage::GetShapeGroup(SdrObject* pObj) +{ + return uno::Reference<drawing::XShapeGroup>(GetShape(pObj), uno::UNO_QUERY); +} + +uno::Reference< drawing::XShape > SwFmDrawPage::CreateShape( SdrObject *pObj ) const +{ + uno::Reference< drawing::XShape > xRet; + if(dynamic_cast<const SwVirtFlyDrawObj*>( pObj) != nullptr || pObj->GetObjInventor() == SdrInventor::Swg) + { + SwFlyDrawContact* pFlyContact = static_cast<SwFlyDrawContact*>(pObj->GetUserCall()); + if(pFlyContact) + { + SwFrameFormat* pFlyFormat = pFlyContact->GetFormat(); + SwDoc* pDoc = pFlyFormat->GetDoc(); + const SwNodeIndex* pIdx; + if( RES_FLYFRMFMT == pFlyFormat->Which() + && nullptr != ( pIdx = pFlyFormat->GetContent().GetContentIdx() ) + && pIdx->GetNodes().IsDocNodes() + ) + { + const SwNode* pNd = pDoc->GetNodes()[ pIdx->GetIndex() + 1 ]; + if(!pNd->IsNoTextNode()) + { + xRet.set(cppu::getXWeak(SwXTextFrame::CreateXTextFrame(*pDoc, pFlyFormat).get()), + uno::UNO_QUERY); + } + else if( pNd->IsGrfNode() ) + { + xRet.set(cppu::getXWeak(SwXTextGraphicObject::CreateXTextGraphicObject( + *pDoc, pFlyFormat).get()), uno::UNO_QUERY); + } + else if( pNd->IsOLENode() ) + { + xRet.set(cppu::getXWeak(SwXTextEmbeddedObject::CreateXTextEmbeddedObject( + *pDoc, pFlyFormat).get()), uno::UNO_QUERY); + } + } + else + { + OSL_FAIL( "<SwFmDrawPage::CreateShape(..)> - could not retrieve type. Thus, no shape created." ); + return xRet; + } + } + } + else + { + // own block - temporary object has to be destroyed before + // the delegator is set #81670# + { + xRet = SvxDrawPage::CreateShape( pObj ); + } + uno::Reference< XUnoTunnel > xShapeTunnel(xRet, uno::UNO_QUERY); + //don't create an SwXShape if it already exists + rtl::Reference<SwXShape> pShape = comphelper::getFromUnoTunnel<SwXShape>(xShapeTunnel); + if(!pShape) + { + xShapeTunnel = nullptr; + uno::Reference< uno::XInterface > xCreate(xRet, uno::UNO_QUERY); + xRet = nullptr; + if ( pObj->IsGroupObject() && (!pObj->Is3DObj() || DynCastE3dScene(pObj)) ) + pShape = new SwXGroupShape(xCreate, nullptr); + else + pShape = new SwXShape(xCreate, nullptr); + xRet = pShape; + } + const_cast<std::vector<rtl::Reference<SwXShape>>*>(&m_vShapes)->push_back(pShape); + pShape->m_pPage = this; + } + return xRet; +} + +uno::Reference<beans::XPropertySetInfo> SwFmDrawPage::getPropertySetInfo() +{ + static uno::Reference<beans::XPropertySetInfo> xRet = m_pPropertySet->getPropertySetInfo(); + return xRet; +} + +void SwFmDrawPage::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName(rPropertyName); + + switch (pEntry ? pEntry->nWID : -1) + { + case WID_PAGE_THEME: + { + SdrPage* pPage = GetSdrPage(); + css::uno::Reference<css::util::XTheme> xTheme; + if (aValue >>= xTheme) + { + auto& rUnoTheme = dynamic_cast<UnoTheme&>(*xTheme); + pPage->getSdrModelFromSdrPage().setTheme(rUnoTheme.getTheme()); + } + } + break; + case WID_PAGE_BOTTOM: + case WID_PAGE_LEFT: + case WID_PAGE_RIGHT: + case WID_PAGE_TOP: + case WID_PAGE_WIDTH: + case WID_PAGE_HEIGHT: + case WID_PAGE_NUMBER: + case WID_PAGE_ORIENT: + case WID_PAGE_USERATTRIBS: + case WID_PAGE_ISDARK: + case WID_NAVORDER: + case WID_PAGE_BACKFULL: + break; + + default: + throw beans::UnknownPropertyException(rPropertyName, getXWeak()); + } +} + +uno::Any SwFmDrawPage::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + const SfxItemPropertyMapEntry* pEntry = m_pPropertySet->getPropertyMap().getByName( rPropertyName); + + uno::Any aAny; + + switch (pEntry ? pEntry->nWID : -1) + { + case WID_PAGE_THEME: + { + css::uno::Reference<css::util::XTheme> xTheme; + + auto pTheme = GetSdrPage()->getSdrModelFromSdrPage().getTheme(); + if (pTheme) + xTheme = model::theme::createXTheme(pTheme); + aAny <<= xTheme; + } + break; + + case WID_PAGE_NUMBER: + { + const sal_uInt16 nPageNumber(GetSdrPage()->GetPageNum()); + aAny <<= o3tl::narrowing<sal_Int16>(nPageNumber); + } + break; + + case WID_PAGE_BOTTOM: + case WID_PAGE_LEFT: + case WID_PAGE_RIGHT: + case WID_PAGE_TOP: + case WID_PAGE_WIDTH: + case WID_PAGE_HEIGHT: + case WID_PAGE_ORIENT: + case WID_PAGE_USERATTRIBS: + case WID_PAGE_ISDARK: + case WID_NAVORDER: + case WID_PAGE_BACKFULL: + break; + + default: + throw beans::UnknownPropertyException(rPropertyName, getXWeak()); + } + return aAny; +} + +void SwFmDrawPage::addPropertyChangeListener(const OUString& /*PropertyName*/, + const uno::Reference<beans::XPropertyChangeListener> & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwFmDrawPage::removePropertyChangeListener(const OUString& /*PropertyName*/, + const uno::Reference<beans::XPropertyChangeListener> & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwFmDrawPage::addVetoableChangeListener(const OUString& /*PropertyName*/, + const uno::Reference<beans::XVetoableChangeListener> & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwFmDrawPage::removeVetoableChangeListener(const OUString& /*PropertyName*/, + const uno::Reference<beans::XVetoableChangeListener> & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +namespace +{ + class SwXShapesEnumeration + : public SwSimpleEnumeration_Base + { + private: + std::vector< css::uno::Any > m_aShapes; + protected: + virtual ~SwXShapesEnumeration() override {}; + public: + explicit SwXShapesEnumeration(SwFmDrawPage* const pDrawPage); + + //XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements() override; + virtual uno::Any SAL_CALL nextElement() override; + + //XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + }; +} + +SwXShapesEnumeration::SwXShapesEnumeration(SwFmDrawPage* const pDrawPage) +{ + SolarMutexGuard aGuard; + sal_Int32 nCount = pDrawPage->getCount(); + m_aShapes.reserve(nCount); + for(sal_Int32 nIdx = 0; nIdx < nCount; nIdx++) + { + uno::Reference<drawing::XShape> xShape(pDrawPage->getByIndex(nIdx), uno::UNO_QUERY); + m_aShapes.push_back(uno::Any(xShape)); + } +} + +sal_Bool SwXShapesEnumeration::hasMoreElements() +{ + SolarMutexGuard aGuard; + return !m_aShapes.empty(); +} + +uno::Any SwXShapesEnumeration::nextElement() +{ + SolarMutexGuard aGuard; + if(m_aShapes.empty()) + throw container::NoSuchElementException(); + uno::Any aResult = m_aShapes.back(); + m_aShapes.pop_back(); + return aResult; +} + +OUString SwXShapesEnumeration::getImplementationName() +{ + return "SwXShapeEnumeration"; +} + +sal_Bool SwXShapesEnumeration::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +uno::Sequence< OUString > SwXShapesEnumeration::getSupportedServiceNames() +{ + return { OUString("com.sun.star.container.XEnumeration") }; +} + +uno::Reference< container::XEnumeration > SwFmDrawPage::createEnumeration() +{ + SolarMutexGuard aGuard; + return uno::Reference< container::XEnumeration >( + new SwXShapesEnumeration(this)); +} + +OUString SwFmDrawPage::getImplementationName() +{ + return "SwFmDrawPage"; +} + +sal_Bool SwFmDrawPage::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwFmDrawPage::getSupportedServiceNames() +{ + return { "com.sun.star.drawing.GenericDrawPage" }; +} + +sal_Int32 SwFmDrawPage::getCount() +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(!m_pDoc->getIDocumentDrawModelAccess().GetDrawModel()) + return 0; + else + return SwTextBoxHelper::getCount(GetSdrPage()); +} + +uno::Any SwFmDrawPage::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(!m_pDoc->getIDocumentDrawModelAccess().GetDrawModel()) + throw lang::IndexOutOfBoundsException(); + + return SwTextBoxHelper::getByIndex(GetSdrPage(), nIndex); +} + +uno::Type SwFmDrawPage::getElementType() +{ + return cppu::UnoType<drawing::XShape>::get(); +} + +sal_Bool SwFmDrawPage::hasElements() +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + if(!m_pDoc->getIDocumentDrawModelAccess().GetDrawModel()) + return false; + return SvxDrawPage::hasElements(); +} + +void SwFmDrawPage::add(const uno::Reference< drawing::XShape > & xShape) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + uno::Reference< lang::XUnoTunnel > xShapeTunnel(xShape, uno::UNO_QUERY); + SwXShape* pShape = comphelper::getFromUnoTunnel<SwXShape>(xShapeTunnel); + SvxShape* pSvxShape = comphelper::getFromUnoTunnel<SvxShape>(xShapeTunnel); + + // this is not a writer shape + if(!pShape) + throw uno::RuntimeException("illegal object", + getXWeak() ); + + // we're already registered in the model / SwXDrawPage::add() already called + if(pShape->m_pPage || !pShape->m_bDescriptor ) + return; + + // we're inserted elsewhere already + if ( pSvxShape->GetSdrObject() ) + { + if ( pSvxShape->GetSdrObject()->IsInserted() ) + { + return; + } + } + SvxDrawPage::add(xShape); + + OSL_ENSURE(pSvxShape, "Why is here no SvxShape?"); + // this position is definitely in 1/100 mm + awt::Point aMM100Pos(pSvxShape->getPosition()); + + // now evaluate the properties of SwShapeDescriptor_Impl + SwShapeDescriptor_Impl* pDesc = pShape->GetDescImpl(); + + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aSet( m_pDoc->GetAttrPool() ); + SwFormatAnchor aAnchor( RndStdIds::FLY_AS_CHAR ); + bool bOpaque = false; + if( pDesc ) + { + if(pDesc->GetSurround()) + aSet.Put( *pDesc->GetSurround()); + // all items are already in Twip + if(pDesc->GetLRSpace()) + { + aSet.Put(*pDesc->GetLRSpace()); + } + if(pDesc->GetULSpace()) + { + aSet.Put(*pDesc->GetULSpace()); + } + if(pDesc->GetAnchor()) + aAnchor = *pDesc->GetAnchor(); + + // #i32349# - if no horizontal position exists, create one + if ( !pDesc->GetHOrient() ) + { + SwFormatHoriOrient* pHori = pDesc->GetHOrient( true ); + SwTwips nHoriPos = o3tl::toTwips(aMM100Pos.X, o3tl::Length::mm100); + pHori->SetPos( nHoriPos ); + } + { + if(pDesc->GetHOrient()->GetHoriOrient() == text::HoriOrientation::NONE) + aMM100Pos.X = convertTwipToMm100(pDesc->GetHOrient()->GetPos()); + aSet.Put( *pDesc->GetHOrient() ); + } + // #i32349# - if no vertical position exists, create one + if ( !pDesc->GetVOrient() ) + { + SwFormatVertOrient* pVert = pDesc->GetVOrient( true ); + SwTwips nVertPos = o3tl::toTwips(aMM100Pos.Y, o3tl::Length::mm100); + pVert->SetPos( nVertPos ); + } + { + if(pDesc->GetVOrient()->GetVertOrient() == text::VertOrientation::NONE) + aMM100Pos.Y = convertTwipToMm100(pDesc->GetVOrient()->GetPos()); + aSet.Put( *pDesc->GetVOrient() ); + } + + if(pDesc->GetSurround()) + aSet.Put( *pDesc->GetSurround()); + bOpaque = pDesc->IsOpaque(); + + // #i26791# + if ( pDesc->GetFollowTextFlow() ) + { + aSet.Put( *pDesc->GetFollowTextFlow() ); + } + + // #i28701# + if ( pDesc->GetWrapInfluenceOnObjPos() ) + { + aSet.Put( *pDesc->GetWrapInfluenceOnObjPos() ); + } + } + + pSvxShape->setPosition(aMM100Pos); + SdrObject* pObj = pSvxShape->GetSdrObject(); + // #108784# - set layer of new drawing object to corresponding + // invisible layer. + if(SdrInventor::FmForm != pObj->GetObjInventor()) + pObj->SetLayer( bOpaque ? m_pDoc->getIDocumentDrawModelAccess().GetInvisibleHeavenId() : m_pDoc->getIDocumentDrawModelAccess().GetInvisibleHellId() ); + else + pObj->SetLayer(m_pDoc->getIDocumentDrawModelAccess().GetInvisibleControlsId()); + + std::optional<SwPaM> pPam(m_pDoc->GetNodes().GetEndOfContent()); + std::unique_ptr<SwUnoInternalPaM> pInternalPam; + uno::Reference< text::XTextRange > xRg; + if( pDesc && (xRg = pDesc->GetTextRange()).is() ) + { + pInternalPam.reset(new SwUnoInternalPaM(*m_pDoc)); + if (!::sw::XTextRangeToSwPaM(*pInternalPam, xRg)) + throw uno::RuntimeException(); + + if(RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId() && + !pInternalPam->GetPointNode().FindFlyStartNode()) + { + aAnchor.SetType(RndStdIds::FLY_AS_CHAR); + } + else if (RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId() + && 0 == aAnchor.GetPageNum()) + { + aAnchor.SetAnchor(pInternalPam->Start()); + aAnchor.SetType(RndStdIds::FLY_AT_CHAR); // convert invalid at-page + } + + } + else if ((aAnchor.GetAnchorId() != RndStdIds::FLY_AT_PAGE) && m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()) + { + SwCursorMoveState aState( CursorMoveState::SetOnlyText ); + Point aTmp(o3tl::toTwips(aMM100Pos.X, o3tl::Length::mm100), o3tl::toTwips(aMM100Pos.Y, o3tl::Length::mm100)); + m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( pPam->GetPoint(), aTmp, &aState ); + aAnchor.SetAnchor( pPam->GetPoint() ); + + // #i32349# - adjustment of vertical positioning + // attributes no longer needed, because it's already got a default. + } + else + { + aAnchor.SetType(RndStdIds::FLY_AT_PAGE); + + // #i32349# - adjustment of vertical positioning + // attributes no longer needed, because it's already got a default. + } + aSet.Put(aAnchor); + SwPaM* pTemp = pInternalPam.get(); + if ( !pTemp ) + pTemp = &*pPam; + UnoActionContext aAction(m_pDoc); + m_pDoc->getIDocumentContentOperations().InsertDrawObj( *pTemp, *pObj, aSet ); + + if (pSvxShape->GetSdrObject()->GetName().isEmpty()) + { + pSvxShape->GetSdrObject()->SetName(m_pDoc->GetUniqueShapeName()); + } + + SwFrameFormat* pFormat = ::FindFrameFormat( pObj ); + if (pFormat) + { + if (pFormat->GetName().isEmpty()) + { + pFormat->SetFormatName(pSvxShape->GetSdrObject()->GetName(), false); + } + } + pShape->m_bDescriptor = false; + + pPam.reset(); + pInternalPam.reset(); +} + +void SwFmDrawPage::remove(const uno::Reference< drawing::XShape > & xShape) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + // tdf#41466 remove TextFrame too which is belonged to the actual shape + auto xTextFrame = SwTextBoxHelper::getUnoTextFrame(xShape); + if (xTextFrame) + { + uno::Reference<lang::XComponent> xComp(xTextFrame, uno::UNO_QUERY); + if (xComp) + xComp->dispose(); + } + // remove shape + uno::Reference<lang::XComponent> xComp(xShape, uno::UNO_QUERY); + xComp->dispose(); +} + +uno::Reference< drawing::XShapeGroup > SwFmDrawPage::group(const uno::Reference< drawing::XShapes > & xShapes) +{ + SolarMutexGuard aGuard; + if(!m_pDoc || !xShapes.is()) + throw uno::RuntimeException(); + uno::Reference< drawing::XShapeGroup > xRet; + // mark and return MarkList + const SdrMarkList& rMarkList = PreGroup(xShapes); + if ( rMarkList.GetMarkCount() > 0 ) + { + for (size_t i = 0; i < rMarkList.GetMarkCount(); ++i) + { + const SdrObject *pObj = rMarkList.GetMark( i )->GetMarkedSdrObj(); + if (RndStdIds::FLY_AS_CHAR == ::FindFrameFormat(const_cast<SdrObject*>( + pObj))->GetAnchor().GetAnchorId()) + { + throw lang::IllegalArgumentException( + "Shape must not have 'as character' anchor!", nullptr, 0); + } + } + + UnoActionContext aContext(m_pDoc); + m_pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + + SwDrawContact* pContact = m_pDoc->GroupSelection( *GetDrawView() ); + m_pDoc->ChgAnchor( + GetDrawView()->GetMarkedObjectList(), + RndStdIds::FLY_AT_PARA, + true, false ); + + GetDrawView()->UnmarkAll(); + if(pContact) + xRet = SwFmDrawPage::GetShapeGroup( pContact->GetMaster() ); + m_pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + } + RemovePageView(); + return xRet; +} + +void SwFmDrawPage::ungroup(const uno::Reference< drawing::XShapeGroup > & rShapeGroup) +{ + SolarMutexGuard aGuard; + if(!m_pDoc) + throw uno::RuntimeException(); + + PreUnGroup(rShapeGroup); + UnoActionContext aContext(m_pDoc); + m_pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + + m_pDoc->UnGroupSelection( *GetDrawView() ); + m_pDoc->ChgAnchor( GetDrawView()->GetMarkedObjectList(), + RndStdIds::FLY_AT_PARA, + true, false ); + m_pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + RemovePageView(); +} + +/** + * Renamed and outlined to detect where it's called + */ +void SwFmDrawPage::InvalidateSwDoc() +{ + m_pDoc = nullptr; +} + +const uno::Sequence< sal_Int8 > & SwXShape::getUnoTunnelId() +{ + static const comphelper::UnoIdInit theSwXShapeUnoTunnelId; + return theSwXShapeUnoTunnelId.getSeq(); +} + +sal_Int64 SAL_CALL SwXShape::getSomething( const uno::Sequence< sal_Int8 >& rId ) +{ + if( comphelper::isUnoTunnelId<SwXShape>(rId) ) + { + return comphelper::getSomething_cast(this); + } + + if( m_xShapeAgg.is() ) + { + const uno::Type& rTunnelType = cppu::UnoType<lang::XUnoTunnel>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rTunnelType ); + if(auto xAggTunnel = o3tl::tryAccess<uno::Reference<lang::XUnoTunnel>>( + aAgg)) + { + if(xAggTunnel->is()) + return (*xAggTunnel)->getSomething(rId); + } + } + return 0; +} + +SwXShape::SwXShape( + uno::Reference<uno::XInterface> & xShape, + SwDoc const*const pDoc) + : m_pPage(nullptr) + , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_SHAPE)) + , m_pPropertyMapEntries(aSwMapProvider.GetPropertyMapEntries(PROPERTY_MAP_TEXT_SHAPE)) + , m_pImpl(new SwShapeDescriptor_Impl(pDoc)) + , m_bDescriptor(true) +{ + if(!xShape.is()) // default Ctor + return; + + const uno::Type& rAggType = cppu::UnoType<uno::XAggregation>::get(); + //aAgg contains a reference of the SvxShape! + { + uno::Any aAgg = xShape->queryInterface(rAggType); + aAgg >>= m_xShapeAgg; + // #i31698# + if ( m_xShapeAgg.is() ) + { + m_xShapeAgg->queryAggregation( cppu::UnoType<drawing::XShape>::get()) >>= mxShape; + OSL_ENSURE( mxShape.is(), + "<SwXShape::SwXShape(..)> - no XShape found at <xShapeAgg>" ); + } + } + xShape = nullptr; + osl_atomic_increment(&m_refCount); + if( m_xShapeAgg.is() ) + m_xShapeAgg->setDelegator( getXWeak() ); + osl_atomic_decrement(&m_refCount); +} + +SwFrameFormat* SwXShape::GetFrameFormat() const +{ + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(m_xShapeAgg); + if(pObj) + return ::FindFrameFormat( pObj ); + return nullptr; +} + +void SwXShape::AddExistingShapeToFormat( SdrObject const & _rObj ) +{ + SdrObjListIter aIter( _rObj, SdrIterMode::DeepNoGroups ); + while ( aIter.IsMore() ) + { + SdrObject* pCurrent = aIter.Next(); + OSL_ENSURE( pCurrent, "SwXShape::AddExistingShapeToFormat: invalid object list element!" ); + if ( !pCurrent ) + continue; + + auto pSwShape = comphelper::getFromUnoTunnel<SwXShape>(pCurrent->getWeakUnoShape()); + if ( pSwShape ) + { + if ( pSwShape->m_bDescriptor ) + pSwShape->m_bDescriptor = false; + } + } +} + +SwXShape::~SwXShape() +{ + SolarMutexGuard aGuard; + + if (m_xShapeAgg.is()) + { + uno::Reference< uno::XInterface > xRef; + m_xShapeAgg->setDelegator(xRef); + } + m_pImpl.reset(); + if(m_pPage) + const_cast<SwFmDrawPage*>(m_pPage)->RemoveShape(this); +} + +uno::Any SwXShape::queryInterface( const uno::Type& aType ) +{ + uno::Any aRet; + SdrObject* pObj = nullptr; + + if ((aType == cppu::UnoType<text::XText>::get()) + || (aType == cppu::UnoType<text::XTextRange>::get()) + || (aType == cppu::UnoType<text::XTextAppend>::get())) + { + pObj = SdrObject::getSdrObjectFromXShape(mxShape); + + aRet = SwTextBoxHelper::queryInterface(GetFrameFormat(), aType, pObj); + if (aRet.hasValue()) + return aRet; + } + aRet = SwXShapeBaseClass::queryInterface(aType); + // #i53320# - follow-up of #i31698# + // interface drawing::XShape is overloaded. Thus, provide + // correct object instance. + if(!aRet.hasValue() && m_xShapeAgg.is()) + { + if(aType == cppu::UnoType<XShape>::get()) + aRet <<= uno::Reference<XShape>(this); + else + aRet = m_xShapeAgg->queryAggregation(aType); + } + return aRet; +} + +uno::Sequence< uno::Type > SwXShape::getTypes( ) +{ + uno::Sequence< uno::Type > aRet = SwXShapeBaseClass::getTypes(); + if(m_xShapeAgg.is()) + { + uno::Any aProv = m_xShapeAgg->queryAggregation(cppu::UnoType<XTypeProvider>::get()); + if(aProv.hasValue()) + { + uno::Reference< XTypeProvider > xAggProv; + aProv >>= xAggProv; + return comphelper::concatSequences(aRet, xAggProv->getTypes()); + } + } + return aRet; +} + +uno::Sequence< sal_Int8 > SwXShape::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Reference< beans::XPropertySetInfo > SwXShape::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + if (!mxPropertySetInfo) + { + if(m_xShapeAgg.is()) + { + const uno::Type& rPropSetType = cppu::UnoType<beans::XPropertySet>::get(); + uno::Any aPSet = m_xShapeAgg->queryAggregation( rPropSetType ); + if(auto xPrSet = o3tl::tryAccess<uno::Reference<beans::XPropertySet>>( + aPSet)) + { + uno::Reference< beans::XPropertySetInfo > xInfo = (*xPrSet)->getPropertySetInfo(); + // Expand PropertySetInfo! + const uno::Sequence<beans::Property> aPropSeq = xInfo->getProperties(); + mxPropertySetInfo = new SfxExtItemPropertySetInfo( m_pPropertyMapEntries, aPropSeq ); + } + } + if(!mxPropertySetInfo) + mxPropertySetInfo = m_pPropSet->getPropertySetInfo(); + } + return mxPropertySetInfo; +} + +void SwXShape::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if(!m_xShapeAgg.is()) + return; + + if(pEntry) + { + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw beans::PropertyVetoException ("Property is read-only: " + rPropertyName, getXWeak() ); + // with the layout it is possible to move the anchor without changing the position + if(pFormat) + { + SwAttrSet aSet(pFormat->GetAttrSet()); + SwDoc* pDoc = pFormat->GetDoc(); + if(RES_ANCHOR == pEntry->nWID && MID_ANCHOR_ANCHORFRAME == pEntry->nMemberId) + { + bool bDone = false; + uno::Reference<text::XTextFrame> xFrame; + if(aValue >>= xFrame) + { + SwXFrame* pFrame = dynamic_cast<SwXFrame*>(xFrame.get()); + if(pFrame && pFrame->GetFrameFormat() && + pFrame->GetFrameFormat()->GetDoc() == pDoc) + { + UnoActionContext aCtx(pDoc); + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END - 1> aItemSet( pDoc->GetAttrPool() ); + aItemSet.SetParent(&pFormat->GetAttrSet()); + SwFormatAnchor aAnchor = static_cast<const SwFormatAnchor&>(aItemSet.Get(pEntry->nWID)); + SwPosition aPos(*pFrame->GetFrameFormat()->GetContent().GetContentIdx()); + aAnchor.SetAnchor(&aPos); + aAnchor.SetType(RndStdIds::FLY_AT_FLY); + aItemSet.Put(aAnchor); + pFormat->SetFormatAttr(aItemSet); + bDone = true; + } + } + if(!bDone) + throw lang::IllegalArgumentException(); + } + else if(RES_OPAQUE == pEntry->nWID) + { + SvxShape* pSvxShape = GetSvxShape(); + SAL_WARN_IF(!pSvxShape, "sw.uno", "No SvxShape found!"); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + // set layer of new drawing + // object to corresponding invisible layer. + bool bIsVisible = pDoc->getIDocumentDrawModelAccess().IsVisibleLayerId( pObj->GetLayer() ); + if(SdrInventor::FmForm != pObj->GetObjInventor()) + { + pObj->SetLayer( *o3tl::doAccess<bool>(aValue) + ? ( bIsVisible ? pDoc->getIDocumentDrawModelAccess().GetHeavenId() : pDoc->getIDocumentDrawModelAccess().GetInvisibleHeavenId() ) + : ( bIsVisible ? pDoc->getIDocumentDrawModelAccess().GetHellId() : pDoc->getIDocumentDrawModelAccess().GetInvisibleHellId() )); + } + else + { + pObj->SetLayer( bIsVisible ? pDoc->getIDocumentDrawModelAccess().GetControlsId() : pDoc->getIDocumentDrawModelAccess().GetInvisibleControlsId()); + } + + } + + } + // #i26791# - special handling for property FN_TEXT_RANGE + else if ( FN_TEXT_RANGE == pEntry->nWID ) + { + SwFormatAnchor aAnchor( aSet.Get( RES_ANCHOR ) ); + if (aAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { + // set property <TextRange> not valid for to-page anchored shapes + throw lang::IllegalArgumentException(); + } + + std::unique_ptr<SwUnoInternalPaM> pInternalPam( + new SwUnoInternalPaM( *(pFormat->GetDoc()) )); + uno::Reference< text::XTextRange > xRg; + aValue >>= xRg; + if (!::sw::XTextRangeToSwPaM(*pInternalPam, xRg) ) + { + throw uno::RuntimeException(); + } + + if (aAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR) + { + //delete old SwFormatFlyCnt + //With AnchorAsCharacter the current TextAttribute has to be deleted. + //Tbis removes the frame format too. + //To prevent this the connection between format and attribute has to be broken before. + SwTextNode *pTextNode = aAnchor.GetAnchorNode()->GetTextNode(); + SAL_WARN_IF( !pTextNode->HasHints(), "sw.uno", "Missing FlyInCnt-Hint." ); + const sal_Int32 nIdx = aAnchor.GetAnchorContentOffset(); + SwTextAttr * const pHint = + pTextNode->GetTextAttrForCharAt( + nIdx, RES_TXTATR_FLYCNT ); + assert(pHint && "Missing Hint."); + SAL_WARN_IF( pHint->Which() != RES_TXTATR_FLYCNT, + "sw.uno", "Missing FlyInCnt-Hint." ); + SAL_WARN_IF( pHint->GetFlyCnt().GetFrameFormat() != pFormat, + "sw.uno", "Wrong TextFlyCnt-Hint." ); + const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()) + .SetFlyFormat(); + + //The connection is removed now the attribute can be deleted. + pTextNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx ); + //create a new one + SwTextNode *pNd = pInternalPam->GetPointNode().GetTextNode(); + SAL_WARN_IF( !pNd, "sw.uno", "Cursor not at TextNode." ); + SwFormatFlyCnt aFormat( pFormat ); + pNd->InsertItem(aFormat, pInternalPam->GetPoint() + ->GetContentIndex(), 0 ); + //Refetch in case SwTextNode::InsertItem causes it to be deleted + pFormat = GetFrameFormat(); + } + else + { + aAnchor.SetAnchor( pInternalPam->GetPoint() ); + aSet.Put(aAnchor); + pFormat->SetFormatAttr(aSet); + } + } + else if (pEntry->nWID == FN_TEXT_BOX) + { + auto pObj = SdrObject::getSdrObjectFromXShape(mxShape); + if (pEntry->nMemberId == MID_TEXT_BOX) + { + bool bValue(false); + aValue >>= bValue; + + if (bValue) + SwTextBoxHelper::create(pFormat, pObj); + else + SwTextBoxHelper::destroy(pFormat, pObj); + } + else if (pEntry->nMemberId == MID_TEXT_BOX_CONTENT) + { + if (aValue.getValueType() + == cppu::UnoType<uno::Reference<text::XTextFrame>>::get()) + SwTextBoxHelper::set(pFormat, pObj, + aValue.get<uno::Reference<text::XTextFrame>>()); + else + SAL_WARN( "sw.uno", "This is not a TextFrame!" ); + } + } + else if (pEntry->nWID == RES_CHAIN) + { + if (pEntry->nMemberId == MID_CHAIN_NEXTNAME || pEntry->nMemberId == MID_CHAIN_PREVNAME) + SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aValue, + SdrObject::getSdrObjectFromXShape(mxShape)); + } + // #i28749# + else if ( FN_SHAPE_POSITION_LAYOUT_DIR == pEntry->nWID ) + { + sal_Int16 nPositionLayoutDir = 0; + aValue >>= nPositionLayoutDir; + pFormat->SetPositionLayoutDir( nPositionLayoutDir ); + } + else if( pDoc->getIDocumentLayoutAccess().GetCurrentLayout()) + { + UnoActionContext aCtx(pDoc); + if(RES_ANCHOR == pEntry->nWID && MID_ANCHOR_ANCHORTYPE == pEntry->nMemberId) + { + SdrObject* pObj = pFormat->FindSdrObject(); + SdrMarkList aList; + SdrMark aMark(pObj); + aList.InsertEntry(aMark); + sal_Int32 nAnchor = 0; + cppu::enum2int( nAnchor, aValue ); + pDoc->ChgAnchor( aList, static_cast<RndStdIds>(nAnchor), + false, true ); + } + else + { + m_pPropSet->setPropertyValue(*pEntry, aValue, aSet); + pFormat->SetFormatAttr(aSet); + } + } + else if( RES_FRM_SIZE == pEntry->nWID && + ( pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT || pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH + || pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT_RELATION + || pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH_RELATION ) ) + { + SvxShape* pSvxShape = GetSvxShape(); + SAL_WARN_IF(!pSvxShape, "sw.uno", "No SvxShape found!"); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + sal_Int16 nPercent(100); + aValue >>= nPercent; + switch (pEntry->nMemberId) + { + case MID_FRMSIZE_REL_WIDTH: + pObj->SetRelativeWidth( nPercent / 100.0 ); + break; + case MID_FRMSIZE_REL_HEIGHT: + pObj->SetRelativeHeight( nPercent / 100.0 ); + break; + case MID_FRMSIZE_REL_WIDTH_RELATION: + pObj->SetRelativeWidthRelation(nPercent); + break; + case MID_FRMSIZE_REL_HEIGHT_RELATION: + pObj->SetRelativeHeightRelation(nPercent); + break; + } + } + } + else if (pEntry->nWID == RES_HORI_ORIENT + && pEntry->nMemberId == MID_HORIORIENT_RELATION + && aSet.Get(RES_ANCHOR).GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { + uno::Any value(aValue); + sal_Int16 nRelOrient(text::RelOrientation::PAGE_FRAME); + aValue >>= nRelOrient; + if (sw::GetAtPageRelOrientation(nRelOrient, true)) + { + SAL_WARN("sw.core", "SwXShape: fixing invalid horizontal RelOrientation for at-page anchor"); + value <<= nRelOrient; + } + m_pPropSet->setPropertyValue( *pEntry, value, aSet ); + pFormat->SetFormatAttr(aSet); + } + else + { + m_pPropSet->setPropertyValue( *pEntry, aValue, aSet ); + + if(RES_ANCHOR == pEntry->nWID && MID_ANCHOR_ANCHORTYPE == pEntry->nMemberId) + { + bool bSetAttr = true; + text::TextContentAnchorType eNewAnchor = static_cast<text::TextContentAnchorType>(SWUnoHelper::GetEnumAsInt32( aValue )); + + //if old anchor was in_cntnt the related text attribute has to be removed + const SwFormatAnchor& rOldAnchor = pFormat->GetAnchor(); + RndStdIds eOldAnchorId = rOldAnchor.GetAnchorId(); + SdrObject* pObj = pFormat->FindSdrObject(); + SwFrameFormat *pFlyFormat = FindFrameFormat( pObj ); + pFlyFormat->DelFrames(); + if( text::TextContentAnchorType_AS_CHARACTER != eNewAnchor && + (RndStdIds::FLY_AS_CHAR == eOldAnchorId)) + { + //With AnchorAsCharacter the current TextAttribute has to be deleted. + //Tbis removes the frame format too. + //To prevent this the connection between format and attribute has to be broken before. + SwTextNode *pTextNode = rOldAnchor.GetAnchorNode()->GetTextNode(); + SAL_WARN_IF( !pTextNode->HasHints(), "sw.uno", "Missing FlyInCnt-Hint." ); + const sal_Int32 nIdx = rOldAnchor.GetAnchorContentOffset(); + SwTextAttr * const pHint = + pTextNode->GetTextAttrForCharAt( + nIdx, RES_TXTATR_FLYCNT ); + assert(pHint && "Missing Hint."); + SAL_WARN_IF( pHint->Which() != RES_TXTATR_FLYCNT, + "sw.uno", "Missing FlyInCnt-Hint." ); + SAL_WARN_IF( pHint->GetFlyCnt().GetFrameFormat() != pFlyFormat, + "sw.uno", "Wrong TextFlyCnt-Hint." ); + const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()) + .SetFlyFormat(); + + //The connection is removed now the attribute can be deleted. + pTextNode->DeleteAttributes(RES_TXTATR_FLYCNT, nIdx); + } + else if( text::TextContentAnchorType_AT_PAGE != eNewAnchor && + (RndStdIds::FLY_AT_PAGE == eOldAnchorId)) + { + SwFormatAnchor aNewAnchor( aSet.Get( RES_ANCHOR ) ); + //if the fly has been anchored at page then it needs to be connected + //to the content position + SwPaM aPam(pDoc->GetNodes().GetEndOfContent()); + if( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() ) + { + SwCursorMoveState aState( CursorMoveState::SetOnlyText ); + Point aTmp( pObj->GetSnapRect().TopLeft() ); + pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aTmp, &aState ); + } + else + { + //without access to the layout the last node of the body will be used as anchor position + aPam.Move( fnMoveBackward, GoInDoc ); + } + //anchor position has to be inserted after the text attribute has been inserted + aNewAnchor.SetAnchor( aPam.GetPoint() ); + aSet.Put( aNewAnchor ); + pFormat->SetFormatAttr(aSet); + bSetAttr = false; + } + if( text::TextContentAnchorType_AS_CHARACTER == eNewAnchor && + (RndStdIds::FLY_AS_CHAR != eOldAnchorId)) + { + SwPaM aPam(pDoc->GetNodes().GetEndOfContent()); + if( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() ) + { + SwCursorMoveState aState( CursorMoveState::SetOnlyText ); + Point aTmp( pObj->GetSnapRect().TopLeft() ); + pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aTmp, &aState ); + } + else + { + //without access to the layout the last node of the body will be used as anchor position + aPam.Move( fnMoveBackward, GoInDoc ); + } + //the RES_TXTATR_FLYCNT needs to be added now + SwTextNode *pNd = aPam.GetPointNode().GetTextNode(); + SAL_WARN_IF( !pNd, "sw.uno", "Cursor is not in a TextNode." ); + SwFormatFlyCnt aFormat( pFlyFormat ); + pNd->InsertItem(aFormat, + aPam.GetPoint()->GetContentIndex(), 0 ); + aPam.GetPoint()->AdjustContent(-1); // InsertItem moved it + SwFormatAnchor aNewAnchor( + aSet.Get(RES_ANCHOR)); + aNewAnchor.SetAnchor( aPam.GetPoint() ); + aSet.Put( aNewAnchor ); + } + if( bSetAttr ) + pFormat->SetFormatAttr(aSet); + + // If this property is an anchor change, and there is a group shape with textboxes + // do anchor sync in time unless the anchor sync in the porfly will cause crash during + // layout calculation (When importing an inline shape in docx via dmapper). + if (pFormat->Which() == RES_DRAWFRMFMT && pFormat->GetOtherTextBoxFormats()) + { + SwTextBoxHelper::synchronizeGroupTextBoxProperty( + SwTextBoxHelper::changeAnchor, pFormat, + SdrObject::getSdrObjectFromXShape(mxShape)); + } + } + else + pFormat->SetFormatAttr(aSet); + } + + // We have a pFormat and a pEntry as well: try to sync TextBox property. + SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aValue, + SdrObject::getSdrObjectFromXShape(mxShape)); + } + else + { + SfxPoolItem* pItem = nullptr; + switch(pEntry->nWID) + { + case RES_ANCHOR: + pItem = m_pImpl->GetAnchor(true); + break; + case RES_HORI_ORIENT: + pItem = m_pImpl->GetHOrient(true); + break; + case RES_VERT_ORIENT: + pItem = m_pImpl->GetVOrient(true); + break; + case RES_LR_SPACE: + pItem = m_pImpl->GetLRSpace(true); + break; + case RES_UL_SPACE: + pItem = m_pImpl->GetULSpace(true); + break; + case RES_SURROUND: + pItem = m_pImpl->GetSurround(true); + break; + case FN_TEXT_RANGE: + if(auto tr = o3tl::tryAccess< + uno::Reference<text::XTextRange>>(aValue)) + { + uno::Reference< text::XTextRange > & rRange = m_pImpl->GetTextRange(); + rRange = *tr; + } + break; + case RES_OPAQUE : + m_pImpl->SetOpaque(*o3tl::doAccess<bool>(aValue)); + break; + // #i26791# + case RES_FOLLOW_TEXT_FLOW: + { + pItem = m_pImpl->GetFollowTextFlow( true ); + } + break; + // #i28701# + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + pItem = m_pImpl->GetWrapInfluenceOnObjPos( true ); + } + break; + // #i28749# + case FN_SHAPE_POSITION_LAYOUT_DIR : + { + sal_Int16 nPositionLayoutDir = 0; + aValue >>= nPositionLayoutDir; + m_pImpl->SetPositionLayoutDir( nPositionLayoutDir ); + } + break; + } + if(pItem) + pItem->PutValue(aValue, pEntry->nMemberId); + } + } + else + { + const uno::Type& rPSetType = + cppu::UnoType<beans::XPropertySet>::get(); + uno::Any aPSet = m_xShapeAgg->queryAggregation(rPSetType); + auto xPrSet = o3tl::tryAccess<uno::Reference<beans::XPropertySet>>( + aPSet); + if(!xPrSet) + throw uno::RuntimeException(); + // #i31698# - setting the caption point of a + // caption object doesn't have to change the object position. + // Thus, keep the position, before the caption point is set and + // restore it afterwards. + awt::Point aKeepedPosition( 0, 0 ); + if ( rPropertyName == "CaptionPoint" && getShapeType() == "com.sun.star.drawing.CaptionShape" ) + { + aKeepedPosition = getPosition(); + } + if( pFormat && pFormat->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell() ) + { + UnoActionContext aCtx(pFormat->GetDoc()); + (*xPrSet)->setPropertyValue(rPropertyName, aValue); + } + else + (*xPrSet)->setPropertyValue(rPropertyName, aValue); + + if (pFormat) + { + // We have a pFormat (but no pEntry): try to sync TextBox property. + SwTextBoxHelper::syncProperty(pFormat, rPropertyName, aValue, + SdrObject::getSdrObjectFromXShape(mxShape)); + } + + // #i31698# - restore object position, if caption point is set. + if ( rPropertyName == "CaptionPoint" && getShapeType() == "com.sun.star.drawing.CaptionShape" ) + { + setPosition( aKeepedPosition ); + } + } +} + +uno::Any SwXShape::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + SwFrameFormat* pFormat = GetFrameFormat(); + if(m_xShapeAgg.is()) + { + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if(pEntry) + { + if(pFormat) + { + if(RES_OPAQUE == pEntry->nWID) + { + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE(pSvxShape, "No SvxShape found!"); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + // consider invisible layers + aRet <<= + ( pObj->GetLayer() != pFormat->GetDoc()->getIDocumentDrawModelAccess().GetHellId() && + pObj->GetLayer() != pFormat->GetDoc()->getIDocumentDrawModelAccess().GetInvisibleHellId() ); + } + } + else if(FN_ANCHOR_POSITION == pEntry->nWID) + { + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE(pSvxShape, "No SvxShape found!"); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + Point aPt = pObj->GetAnchorPos(); + awt::Point aPoint( convertTwipToMm100( aPt.X() ), + convertTwipToMm100( aPt.Y() ) ); + aRet <<= aPoint; + } + } + // #i26791# - special handling for FN_TEXT_RANGE + else if ( FN_TEXT_RANGE == pEntry->nWID ) + { + const SwFormatAnchor aAnchor = pFormat->GetAnchor(); + if (aAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { + // return nothing, because property <TextRange> isn't + // valid for to-page anchored shapes + uno::Any aAny; + aRet = aAny; + } + else + { + if ( aAnchor.GetAnchorNode() ) + { + const rtl::Reference<SwXTextRange> xTextRange + = SwXTextRange::CreateXTextRange( + *pFormat->GetDoc(), + *aAnchor.GetContentAnchor(), + nullptr ); + aRet <<= uno::Reference<text::XTextRange>(xTextRange); + } + else + { + // return nothing + uno::Any aAny; + aRet = aAny; + } + } + } + else if (pEntry->nWID == FN_TEXT_BOX) + { + if (pEntry->nMemberId == MID_TEXT_BOX) + { + auto pSvxShape = GetSvxShape(); + bool bValue = SwTextBoxHelper::isTextBox( + pFormat, RES_DRAWFRMFMT, + ((pSvxShape && pSvxShape->GetSdrObject()) ? pSvxShape->GetSdrObject() + : pFormat->FindRealSdrObject())); + aRet <<= bValue; + } + else if (pEntry->nMemberId == MID_TEXT_BOX_CONTENT) + { + auto pObj = SdrObject::getSdrObjectFromXShape(mxShape); + auto xRange = SwTextBoxHelper::queryInterface( + pFormat, cppu::UnoType<text::XText>::get(), + pObj ? pObj : pFormat->FindRealSdrObject()); + uno::Reference<text::XTextFrame> xFrame(xRange, uno::UNO_QUERY); + if (xFrame.is()) + aRet <<= xFrame; + } + } + else if (pEntry->nWID == RES_CHAIN) + { + switch (pEntry->nMemberId) + { + case MID_CHAIN_PREVNAME: + case MID_CHAIN_NEXTNAME: + case MID_CHAIN_NAME: + SwTextBoxHelper::getProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aRet); + break; + } + } + // #i28749# + else if ( FN_SHAPE_TRANSFORMATION_IN_HORI_L2R == pEntry->nWID ) + { + // get property <::drawing::Shape::Transformation> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "Transformation" ); + } + else if ( FN_SHAPE_POSITION_LAYOUT_DIR == pEntry->nWID ) + { + aRet <<= pFormat->GetPositionLayoutDir(); + } + // #i36248# + else if ( FN_SHAPE_STARTPOSITION_IN_HORI_L2R == pEntry->nWID ) + { + // get property <::drawing::Shape::StartPosition> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "StartPosition" ); + } + else if ( FN_SHAPE_ENDPOSITION_IN_HORI_L2R == pEntry->nWID ) + { + // get property <::drawing::Shape::EndPosition> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "EndPosition" ); + } + else if (pEntry->nWID == RES_FRM_SIZE && + (pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT || + pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH || + pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT_RELATION || + pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH_RELATION)) + { + SvxShape* pSvxShape = GetSvxShape(); + SAL_WARN_IF(!pSvxShape, "sw.uno", "No SvxShape found!"); + sal_Int16 nRet = 0; + if (pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + switch (pEntry->nMemberId) + { + case MID_FRMSIZE_REL_WIDTH: + if (pObj->GetRelativeWidth()) + nRet = *pObj->GetRelativeWidth() * 100; + break; + case MID_FRMSIZE_REL_HEIGHT: + if (pObj->GetRelativeHeight()) + nRet = *pObj->GetRelativeHeight() * 100; + break; + case MID_FRMSIZE_REL_WIDTH_RELATION: + nRet = pObj->GetRelativeWidthRelation(); + break; + case MID_FRMSIZE_REL_HEIGHT_RELATION: + nRet = pObj->GetRelativeHeightRelation(); + break; + } + } + aRet <<= nRet; + } + else + { + const SwAttrSet& rSet = pFormat->GetAttrSet(); + m_pPropSet->getPropertyValue(*pEntry, rSet, aRet); + } + } + else + { + SfxPoolItem* pItem = nullptr; + switch(pEntry->nWID) + { + case RES_ANCHOR: + pItem = m_pImpl->GetAnchor(); + break; + case RES_HORI_ORIENT: + pItem = m_pImpl->GetHOrient(); + break; + case RES_VERT_ORIENT: + pItem = m_pImpl->GetVOrient(); + break; + case RES_LR_SPACE: + pItem = m_pImpl->GetLRSpace(); + break; + case RES_UL_SPACE: + pItem = m_pImpl->GetULSpace(); + break; + case RES_SURROUND: + pItem = m_pImpl->GetSurround(); + break; + case FN_TEXT_RANGE : + aRet <<= m_pImpl->GetTextRange(); + break; + case RES_OPAQUE : + aRet <<= m_pImpl->GetOpaque(); + break; + case FN_ANCHOR_POSITION : + { + aRet <<= awt::Point(); + } + break; + // #i26791# + case RES_FOLLOW_TEXT_FLOW : + { + pItem = m_pImpl->GetFollowTextFlow(); + } + break; + // #i28701# + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + pItem = m_pImpl->GetWrapInfluenceOnObjPos(); + } + break; + // #i28749# + case FN_SHAPE_TRANSFORMATION_IN_HORI_L2R: + { + // get property <::drawing::Shape::Transformation> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "Transformation" ); + } + break; + case FN_SHAPE_POSITION_LAYOUT_DIR: + { + aRet <<= m_pImpl->GetPositionLayoutDir(); + } + break; + // #i36248# + case FN_SHAPE_STARTPOSITION_IN_HORI_L2R: + { + // get property <::drawing::Shape::StartPosition> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "StartPosition" ); + } + break; + case FN_SHAPE_ENDPOSITION_IN_HORI_L2R: + { + // get property <::drawing::Shape::StartPosition> + // without conversion to layout direction as below + aRet = _getPropAtAggrObj( "EndPosition" ); + } + break; + } + if(pItem) + pItem->QueryValue(aRet, pEntry->nMemberId); + } + } + else + { + aRet = _getPropAtAggrObj( rPropertyName ); + + // #i31698# - convert the position (translation) + // of the drawing object in the transformation + if ( rPropertyName == "Transformation" ) + { + drawing::HomogenMatrix3 aMatrix; + aRet >>= aMatrix; + aRet <<= ConvertTransformationToLayoutDir( aMatrix ); + } + // #i36248# + else if ( rPropertyName == "StartPosition" ) + { + awt::Point aStartPos; + aRet >>= aStartPos; + // #i59051# + aRet <<= ConvertStartOrEndPosToLayoutDir( aStartPos ); + } + else if ( rPropertyName == "EndPosition" ) + { + awt::Point aEndPos; + aRet >>= aEndPos; + // #i59051# + aRet <<= ConvertStartOrEndPosToLayoutDir( aEndPos ); + } + // #i59051# + else if ( rPropertyName == "PolyPolygonBezier" ) + { + drawing::PolyPolygonBezierCoords aPath; + aRet >>= aPath; + aRet <<= ConvertPolyPolygonBezierToLayoutDir( aPath ); + } + else if (rPropertyName == "ZOrder") + { + // Convert the real draw page position to the logical one that ignores textboxes. + if (pFormat) + { + const SdrObject* pObj = pFormat->FindRealSdrObject(); + if (pObj) + { + bool bConvert = true; + if (SvxShape* pSvxShape = GetSvxShape()) + // In case of group shapes, pSvxShape points to the child shape, while pObj points to the outermost group shape. + if (pSvxShape->GetSdrObject() != pObj) + // Textboxes are not expected inside group shapes, so no conversion is necessary there. + bConvert = false; + if (bConvert) + { + aRet <<= SwTextBoxHelper::getOrdNum(pObj); + } + } + } + } + } + } + return aRet; +} + +uno::Any SwXShape::_getPropAtAggrObj( const OUString& _rPropertyName ) +{ + uno::Any aRet; + + const uno::Type& rPSetType = + cppu::UnoType<beans::XPropertySet>::get(); + uno::Any aPSet = m_xShapeAgg->queryAggregation(rPSetType); + auto xPrSet = o3tl::tryAccess<uno::Reference<beans::XPropertySet>>(aPSet); + if ( !xPrSet ) + { + throw uno::RuntimeException(); + } + aRet = (*xPrSet)->getPropertyValue( _rPropertyName ); + + return aRet; +} + +beans::PropertyState SwXShape::getPropertyState( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + uno::Sequence< OUString > aNames { rPropertyName }; + uno::Sequence< beans::PropertyState > aStates = getPropertyStates(aNames); + return aStates.getConstArray()[0]; +} + +uno::Sequence< beans::PropertyState > SwXShape::getPropertyStates( + const uno::Sequence< OUString >& aPropertyNames ) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + uno::Sequence< beans::PropertyState > aRet(aPropertyNames.getLength()); + if(!m_xShapeAgg.is()) + throw uno::RuntimeException(); + + SvxShape* pSvxShape = GetSvxShape(); + bool bGroupMember = false; + bool bFormControl = false; + SdrObject* pObject = pSvxShape ? pSvxShape->GetSdrObject() : nullptr; + if(pObject) + { + bGroupMember = pObject->getParentSdrObjectFromSdrObject() != nullptr; + bFormControl = pObject->GetObjInventor() == SdrInventor::FmForm; + } + const OUString* pNames = aPropertyNames.getConstArray(); + beans::PropertyState* pRet = aRet.getArray(); + uno::Reference< XPropertyState > xShapePrState; + for(sal_Int32 nProperty = 0; nProperty < aPropertyNames.getLength(); nProperty++) + { + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( pNames[nProperty] ); + if(pEntry) + { + if(RES_OPAQUE == pEntry->nWID) + pRet[nProperty] = bFormControl ? + beans::PropertyState_DEFAULT_VALUE : beans::PropertyState_DIRECT_VALUE; + else if(FN_ANCHOR_POSITION == pEntry->nWID) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else if(FN_TEXT_RANGE == pEntry->nWID) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else if(bGroupMember) + pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE; + else if (pEntry->nWID == RES_FRM_SIZE && + (pEntry->nMemberId == MID_FRMSIZE_REL_HEIGHT_RELATION || + pEntry->nMemberId == MID_FRMSIZE_REL_WIDTH_RELATION)) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else if (pEntry->nWID == FN_TEXT_BOX) + { + // The TextBox property is set, if we can find a textbox for this shape. + if (pFormat + && SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, + SdrObject::getSdrObjectFromXShape(mxShape))) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else + pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE; + } + else if(pFormat) + { + const SwAttrSet& rSet = pFormat->GetAttrSet(); + SfxItemState eItemState = rSet.GetItemState(pEntry->nWID, false); + + if(SfxItemState::SET == eItemState) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else if(SfxItemState::DEFAULT == eItemState) + pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE; + else + pRet[nProperty] = beans::PropertyState_AMBIGUOUS_VALUE; + } + else + { + SfxPoolItem* pItem = nullptr; + switch(pEntry->nWID) + { + case RES_ANCHOR: + pItem = m_pImpl->GetAnchor(); + break; + case RES_HORI_ORIENT: + pItem = m_pImpl->GetHOrient(); + break; + case RES_VERT_ORIENT: + pItem = m_pImpl->GetVOrient(); + break; + case RES_LR_SPACE: + pItem = m_pImpl->GetLRSpace(); + break; + case RES_UL_SPACE: + pItem = m_pImpl->GetULSpace(); + break; + case RES_SURROUND: + pItem = m_pImpl->GetSurround(); + break; + // #i28701# + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + pItem = m_pImpl->GetWrapInfluenceOnObjPos(); + } + break; + } + if(pItem) + pRet[nProperty] = beans::PropertyState_DIRECT_VALUE; + else + pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE; + } + } + else + { + if(!xShapePrState.is()) + { + const uno::Type& rPStateType = cppu::UnoType<XPropertyState>::get(); + uno::Any aPState = m_xShapeAgg->queryAggregation(rPStateType); + auto ps = o3tl::tryAccess<uno::Reference<XPropertyState>>( + aPState); + if(!ps) + throw uno::RuntimeException(); + xShapePrState = *ps; + } + pRet[nProperty] = xShapePrState->getPropertyState(pNames[nProperty]); + } + } + + return aRet; +} + +void SwXShape::setPropertyToDefault( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(!m_xShapeAgg.is()) + throw uno::RuntimeException(); + + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if(pEntry) + { + if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) + throw uno::RuntimeException("Property is read-only: " + rPropertyName, getXWeak() ); + if(pFormat) + { + const SfxItemSet& rSet = pFormat->GetAttrSet(); + SfxItemSet aSet(pFormat->GetDoc()->GetAttrPool(), pEntry->nWID, pEntry->nWID); + aSet.SetParent(&rSet); + aSet.ClearItem(pEntry->nWID); + pFormat->GetDoc()->SetAttr(aSet, *pFormat); + } + else + { + switch(pEntry->nWID) + { + case RES_ANCHOR: m_pImpl->RemoveAnchor(); break; + case RES_HORI_ORIENT: m_pImpl->RemoveHOrient(); break; + case RES_VERT_ORIENT: m_pImpl->RemoveVOrient(); break; + case RES_LR_SPACE: m_pImpl->RemoveLRSpace(); break; + case RES_UL_SPACE: m_pImpl->RemoveULSpace(); break; + case RES_SURROUND: m_pImpl->RemoveSurround();break; + case RES_OPAQUE : m_pImpl->SetOpaque(false); break; + case FN_TEXT_RANGE : + break; + // #i26791# + case RES_FOLLOW_TEXT_FLOW: + { + m_pImpl->RemoveFollowTextFlow(); + } + break; + // #i28701# + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + m_pImpl->RemoveWrapInfluenceOnObjPos(); + } + break; + } + } + } + else + { + const uno::Type& rPStateType = cppu::UnoType<XPropertyState>::get(); + uno::Any aPState = m_xShapeAgg->queryAggregation(rPStateType); + auto xShapePrState = o3tl::tryAccess<uno::Reference<XPropertyState>>( + aPState); + if(!xShapePrState) + throw uno::RuntimeException(); + (*xShapePrState)->setPropertyToDefault( rPropertyName ); + } + +} + +uno::Any SwXShape::getPropertyDefault( const OUString& rPropertyName ) +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + uno::Any aRet; + if(!m_xShapeAgg.is()) + throw uno::RuntimeException(); + + const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName ); + if(pEntry) + { + if(!(pEntry->nWID < RES_FRMATR_END && pFormat)) + throw uno::RuntimeException(); + + const SfxPoolItem& rDefItem = + pFormat->GetDoc()->GetAttrPool().GetDefaultItem(pEntry->nWID); + rDefItem.QueryValue(aRet, pEntry->nMemberId); + + } + else + { + const uno::Type& rPStateType = cppu::UnoType<XPropertyState>::get(); + uno::Any aPState = m_xShapeAgg->queryAggregation(rPStateType); + auto xShapePrState = o3tl::tryAccess<uno::Reference<XPropertyState>>( + aPState); + if(!xShapePrState) + throw uno::RuntimeException(); + (*xShapePrState)->getPropertyDefault( rPropertyName ); + } + + return aRet; +} + +void SwXShape::addPropertyChangeListener( + const OUString& _propertyName, + const uno::Reference< beans::XPropertyChangeListener > & _listener ) +{ + if ( !m_xShapeAgg.is() ) + throw uno::RuntimeException("no shape aggregate", *this ); + + // must be handled by the aggregate + uno::Reference< beans::XPropertySet > xShapeProps; + if ( m_xShapeAgg->queryAggregation( cppu::UnoType<beans::XPropertySet>::get() ) >>= xShapeProps ) + xShapeProps->addPropertyChangeListener( _propertyName, _listener ); +} + +void SwXShape::removePropertyChangeListener( + const OUString& _propertyName, + const uno::Reference< beans::XPropertyChangeListener > & _listener) +{ + if ( !m_xShapeAgg.is() ) + throw uno::RuntimeException("no shape aggregate", *this ); + + // must be handled by the aggregate + uno::Reference< beans::XPropertySet > xShapeProps; + if ( m_xShapeAgg->queryAggregation( cppu::UnoType<beans::XPropertySet>::get() ) >>= xShapeProps ) + xShapeProps->removePropertyChangeListener( _propertyName, _listener ); +} + +void SwXShape::addVetoableChangeListener( + const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} + +void SwXShape::removeVetoableChangeListener( + const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + OSL_FAIL("not implemented"); +} + +void SwXShape::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard aGuard; + + // get access to SwDoc + // (see also SwXTextRange::XTextRangeToSwPaM) + const SwDoc* pDoc = nullptr; + if (auto pRange = dynamic_cast<SwXTextRange*>(xTextRange.get())) + pDoc = &pRange->GetDoc(); + else if (auto pText = dynamic_cast<SwXText*>(xTextRange.get())) + pDoc = pText->GetDoc(); + else if (auto pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get())) + pDoc = pCursor->GetDoc(); + else if (auto pPortion = dynamic_cast<SwXTextPortion*>(xTextRange.get())) + pDoc = &pPortion->GetCursor().GetDoc(); + else if (auto pParagraph = dynamic_cast<SwXParagraph*>(xTextRange.get()); + pParagraph && pParagraph->GetTextNode()) + pDoc = &pParagraph->GetTextNode()->GetDoc(); + + if(!pDoc) + throw uno::RuntimeException(); + const SwDocShell* pDocSh = pDoc->GetDocShell(); + if (!pDocSh) + return; + + uno::Reference<frame::XModel> xModel = pDocSh->GetModel(); + uno::Reference< drawing::XDrawPageSupplier > xDPS(xModel, uno::UNO_QUERY); + if (xDPS.is()) + { + uno::Reference< drawing::XDrawPage > xDP( xDPS->getDrawPage() ); + if (xDP.is()) + { + uno::Any aPos; + aPos <<= xTextRange; + setPropertyValue("TextRange", aPos); + uno::Reference< drawing::XShape > xTemp( getXWeak(), uno::UNO_QUERY ); + xDP->add( xTemp ); + } + } +} + +uno::Reference< text::XTextRange > SwXShape::getAnchor() +{ + SolarMutexGuard aGuard; + uno::Reference< text::XTextRange > aRef; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + const SwFormatAnchor& rAnchor = pFormat->GetAnchor(); + // return an anchor for non-page bound frames + // and for page bound frames that have a page no == NULL and a content position + if ((rAnchor.GetAnchorId() != RndStdIds::FLY_AT_PAGE) || + (rAnchor.GetAnchorNode() && !rAnchor.GetPageNum())) + { + if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA) + { // ensure that SwXTextRange has SwContentIndex + const SwNode* pAnchorNode = rAnchor.GetAnchorNode(); + aRef = SwXTextRange::CreateXTextRange(*pFormat->GetDoc(), SwPosition(*pAnchorNode), nullptr); + } + else + { + aRef = SwXTextRange::CreateXTextRange(*pFormat->GetDoc(), *rAnchor.GetContentAnchor(), nullptr); + } + } + } + else + aRef = m_pImpl->GetTextRange().get(); + return aRef; +} + +void SwXShape::dispose() +{ + SolarMutexGuard aGuard; + SwFrameFormat* pFormat = GetFrameFormat(); + if(pFormat) + { + // determine correct <SdrObject> + SvxShape* pSvxShape = GetSvxShape(); + SdrObject* pObj = pSvxShape ? pSvxShape->GetSdrObject() : nullptr; + // safety assertion: + // <pObj> must be the same as <pFormat->FindSdrObject()>, if <pObj> isn't + // a 'virtual' drawing object. + // correct assertion and refine it for safety reason. + OSL_ENSURE( !pObj || + dynamic_cast<const SwDrawVirtObj*>( pObj) != nullptr || + pObj->getParentSdrObjectFromSdrObject() || + pObj == pFormat->FindSdrObject(), + "<SwXShape::dispose(..) - different 'master' drawing objects!!" ); + // perform delete of draw frame format *not* + // for 'virtual' drawing objects. + // no delete of draw format for members + // of a group + if ( pObj && + dynamic_cast<const SwDrawVirtObj*>( pObj) == nullptr && + !pObj->getParentSdrObjectFromSdrObject() && + pObj->IsInserted() ) + { + const SwFormatAnchor& rFormatAnchor = pFormat->GetAnchor(); + if (rFormatAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR) + { + SwTextNode *pTextNode = rFormatAnchor.GetAnchorNode()->GetTextNode(); + const sal_Int32 nIdx = rFormatAnchor.GetAnchorContentOffset(); + pTextNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx ); + } + else + pFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pFormat ); + } + } + if(m_xShapeAgg.is()) + { + uno::Any aAgg(m_xShapeAgg->queryAggregation( cppu::UnoType<XComponent>::get())); + uno::Reference<XComponent> xComp; + aAgg >>= xComp; + if(xComp.is()) + xComp->dispose(); + } + if(m_pPage) + { + auto pPage = const_cast<SwFmDrawPage*>(m_pPage); + m_pPage = nullptr; + pPage->RemoveShape(this); + } +} + +void SwXShape::addEventListener( + const uno::Reference< lang::XEventListener > & aListener) +{ + SvxShape* pSvxShape = GetSvxShape(); + if(pSvxShape) + pSvxShape->addEventListener(aListener); +} + +void SwXShape::removeEventListener( + const uno::Reference< lang::XEventListener > & aListener) +{ + SvxShape* pSvxShape = GetSvxShape(); + if(pSvxShape) + pSvxShape->removeEventListener(aListener); +} + +OUString SwXShape::getImplementationName() +{ + return "SwXShape"; +} + +sal_Bool SwXShape::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SwXShape::getSupportedServiceNames() +{ + uno::Sequence< OUString > aSeq; + if (SvxShape* pSvxShape = GetSvxShape()) + aSeq = pSvxShape->getSupportedServiceNames(); + return comphelper::concatSequences( + aSeq, std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.Shape" }); +} + +SvxShape* SwXShape::GetSvxShape() +{ + if(m_xShapeAgg.is()) + return comphelper::getFromUnoTunnel<SvxShape>(m_xShapeAgg); + return nullptr; +} + +// #i31698# +// implementation of virtual methods from drawing::XShape +awt::Point SAL_CALL SwXShape::getPosition() +{ + awt::Point aPos( GetAttrPosition() ); + + // handle group members + SvxShape* pSvxShape = GetSvxShape(); + if ( pSvxShape ) + { + SdrObject* pTopGroupObj = GetTopGroupObj( pSvxShape ); + if ( pTopGroupObj ) + { + // #i34750# - get attribute position of top group + // shape and add offset between top group object and group member + uno::Reference< drawing::XShape > xGroupShape( pTopGroupObj->getUnoShape(), uno::UNO_QUERY ); + aPos = xGroupShape->getPosition(); + // add offset between top group object and group member + // to the determined attribute position + // #i34750#: + // consider the layout direction + const tools::Rectangle aMemberObjRect = GetSvxShape()->GetSdrObject()->GetSnapRect(); + const tools::Rectangle aGroupObjRect = pTopGroupObj->GetSnapRect(); + // #i53320# - relative position of group member and + // top group object is always given in horizontal left-to-right layout. + awt::Point aOffset( 0, 0 ); + { + aOffset.X = ( aMemberObjRect.Left() - aGroupObjRect.Left() ); + aOffset.Y = ( aMemberObjRect.Top() - aGroupObjRect.Top() ); + } + aOffset.X = convertTwipToMm100(aOffset.X); + aOffset.Y = convertTwipToMm100(aOffset.Y); + aPos.X += aOffset.X; + aPos.Y += aOffset.Y; + } + } + + return aPos; +} + +void SAL_CALL SwXShape::setPosition( const awt::Point& aPosition ) +{ + SdrObject* pTopGroupObj = GetTopGroupObj(); + if ( !pTopGroupObj ) + { + // #i37877# - no adjustment of position attributes, + // if the position also has to be applied at the drawing object and + // a contact object is already registered at the drawing object. + bool bApplyPosAtDrawObj(false); + bool bNoAdjustOfPosProp(false); + // #i35798# - apply position also to drawing object, + // if drawing object has no anchor position set. + if ( mxShape.is() ) + { + SvxShape* pSvxShape = GetSvxShape(); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + if ( pObj && + pObj->GetAnchorPos().X() == 0 && + pObj->GetAnchorPos().Y() == 0 ) + { + bApplyPosAtDrawObj = true; + if ( pObj->GetUserCall() && + dynamic_cast<const SwDrawContact*>( pObj->GetUserCall()) != nullptr ) + { + bNoAdjustOfPosProp = true; + } + } + } + } + // shape isn't a group member. Thus, set positioning attributes + if ( !bNoAdjustOfPosProp ) + { + AdjustPositionProperties( aPosition ); + } + if ( bApplyPosAtDrawObj ) + { + mxShape->setPosition( aPosition ); + } + } + else if ( mxShape.is() ) + { + // shape is a member of a group. Thus, set its position. + awt::Point aNewPos( aPosition ); + // The given position is given in the according layout direction. Thus, + // it has to be converted to a position in horizontal left-to-right + // layout. + // convert given absolute attribute position in layout direction into + // position in horizontal left-to-right layout. + { + aNewPos = ConvertPositionToHoriL2R( aNewPos, getSize() ); + } + // Convert given absolute position in horizontal left-to-right + // layout into relative position in horizontal left-to-right layout. + uno::Reference< drawing::XShape > xGroupShape( pTopGroupObj->getUnoShape(), uno::UNO_QUERY ); + { + // #i34750# + // use method <xGroupShape->getPosition()> to get the correct + // position of the top group object. + awt::Point aAttrPosInHoriL2R( + ConvertPositionToHoriL2R( xGroupShape->getPosition(), + xGroupShape->getSize() ) ); + aNewPos.X = o3tl::saturating_sub(aNewPos.X, aAttrPosInHoriL2R.X); + aNewPos.Y = o3tl::saturating_sub(aNewPos.Y, aAttrPosInHoriL2R.Y); + } + // convert relative position in horizontal left-to-right layout into + // absolute position in horizontal left-to-right layout + { + // #i34750# + // use method <SvxShape->getPosition()> to get the correct + // 'Drawing layer' position of the top group shape. + auto pSvxGroupShape = comphelper::getFromUnoTunnel<SvxShape>(pTopGroupObj->getUnoShape()); + const awt::Point aGroupPos = pSvxGroupShape->getPosition(); + aNewPos.X = o3tl::saturating_add(aNewPos.X, aGroupPos.X); + aNewPos.Y = o3tl::saturating_add(aNewPos.Y, aGroupPos.Y); + } + // set position + mxShape->setPosition( aNewPos ); + } +} + +awt::Size SAL_CALL SwXShape::getSize() +{ + awt::Size aSize; + if ( mxShape.is() ) + { + aSize = mxShape->getSize(); + } + return aSize; +} + +void SAL_CALL SwXShape::setSize( const awt::Size& aSize ) +{ + comphelper::ProfileZone aZone("SwXShape::setSize"); + + if ( mxShape.is() ) + { + mxShape->setSize( aSize ); + } + SwTextBoxHelper::syncProperty(GetFrameFormat(), RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::Any(aSize)); +} +// #i31698# +// implementation of virtual methods from drawing::XShapeDescriptor +OUString SAL_CALL SwXShape::getShapeType() +{ + if ( mxShape.is() ) + { + return mxShape->getShapeType(); + } + return OUString(); +} +/** method to determine top group object + #i31698# +*/ +SdrObject* SwXShape::GetTopGroupObj( SvxShape* _pSvxShape ) +{ + SdrObject* pTopGroupObj( nullptr ); + + SvxShape* pSvxShape = _pSvxShape ? _pSvxShape : GetSvxShape(); + if ( pSvxShape ) + { + SdrObject* pSdrObj = pSvxShape->GetSdrObject(); + if ( pSdrObj && pSdrObj->getParentSdrObjectFromSdrObject() ) + { + pTopGroupObj = pSdrObj->getParentSdrObjectFromSdrObject(); + while ( pTopGroupObj->getParentSdrObjectFromSdrObject() ) + { + pTopGroupObj = pTopGroupObj->getParentSdrObjectFromSdrObject(); + } + } + } + + return pTopGroupObj; +} + +/** method to determine position according to the positioning attributes + #i31698# +*/ +awt::Point SwXShape::GetAttrPosition() +{ + awt::Point aAttrPos; + + uno::Any aHoriPos( getPropertyValue("HoriOrientPosition") ); + aHoriPos >>= aAttrPos.X; + uno::Any aVertPos( getPropertyValue("VertOrientPosition") ); + aVertPos >>= aAttrPos.Y; + // #i35798# - fallback, if attribute position is (0,0) + // and no anchor position is applied to the drawing object + SvxShape* pSvxShape = GetSvxShape(); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + if ( pObj && + pObj->GetAnchorPos().X() == 0 && + pObj->GetAnchorPos().Y() == 0 && + aAttrPos.X == 0 && aAttrPos.Y == 0 ) + { + const tools::Rectangle aObjRect = pObj->GetSnapRect(); + aAttrPos.X = convertTwipToMm100(aObjRect.Left()); + aAttrPos.Y = convertTwipToMm100(aObjRect.Top()); + } + } + // #i35007# - If drawing object is anchored as-character, + // it's x-position isn't sensible. Thus, return the x-position as zero in this case. + text::TextContentAnchorType eTextAnchorType = + text::TextContentAnchorType_AT_PARAGRAPH; + { + uno::Any aAny = getPropertyValue( "AnchorType" ); + aAny >>= eTextAnchorType; + } + if ( eTextAnchorType == text::TextContentAnchorType_AS_CHARACTER ) + { + aAttrPos.X = 0; + } + + return aAttrPos; +} + +/** method to convert the position (translation) of the drawing object to + the layout direction horizontal left-to-right. + #i31698# +*/ +awt::Point SwXShape::ConvertPositionToHoriL2R( const awt::Point& rObjPos, + const awt::Size& rObjSize ) +{ + awt::Point aObjPosInHoriL2R( rObjPos ); + + SwFrameFormat* pFrameFormat = GetFrameFormat(); + if ( pFrameFormat ) + { + SwFrameFormat::tLayoutDir eLayoutDir = pFrameFormat->GetLayoutDir(); + switch ( eLayoutDir ) + { + case SwFrameFormat::HORI_L2R: + { + // nothing to do + } + break; + case SwFrameFormat::HORI_R2L: + { + aObjPosInHoriL2R.X = -rObjPos.X - rObjSize.Width; + } + break; + case SwFrameFormat::VERT_R2L: + { + aObjPosInHoriL2R.X = -rObjPos.Y - rObjSize.Width; + aObjPosInHoriL2R.Y = rObjPos.X; + } + break; + default: + { + OSL_FAIL( "<SwXShape::ConvertPositionToHoriL2R(..)> - unsupported layout direction" ); + } + } + } + + return aObjPosInHoriL2R; +} + +/** method to convert the transformation of the drawing object to the layout + direction, the drawing object is in + #i31698# +*/ +drawing::HomogenMatrix3 SwXShape::ConvertTransformationToLayoutDir( + const drawing::HomogenMatrix3& rMatrixInHoriL2R ) +{ + drawing::HomogenMatrix3 aMatrix(rMatrixInHoriL2R); + + // #i44334#, #i44681# - direct manipulation of the + // transformation structure isn't valid, if it contains rotation. + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE( pSvxShape, + "<SwXShape::ConvertTransformationToLayoutDir(..)> - no SvxShape found!"); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + OSL_ENSURE( pObj, + "<SwXShape::ConvertTransformationToLayoutDir(..)> - no SdrObject found!"); + if ( pObj ) + { + // get position of object in Writer coordinate system. + awt::Point aPos( getPosition() ); + // get position of object in Drawing layer coordinate system + const Point aTmpObjPos( pObj->GetSnapRect().TopLeft() ); + const awt::Point aObjPos( + convertTwipToMm100( aTmpObjPos.X() - pObj->GetAnchorPos().X() ), + convertTwipToMm100( aTmpObjPos.Y() - pObj->GetAnchorPos().Y() ) ); + // determine difference between these positions according to the + // Writer coordinate system + const awt::Point aTranslateDiff( aPos.X - aObjPos.X, + aPos.Y - aObjPos.Y ); + // apply translation difference to transformation matrix. + if ( aTranslateDiff.X != 0 || aTranslateDiff.Y != 0 ) + { + // #i73079# - use correct matrix type + ::basegfx::B2DHomMatrix aTempMatrix; + + aTempMatrix.set(0, 0, aMatrix.Line1.Column1 ); + aTempMatrix.set(0, 1, aMatrix.Line1.Column2 ); + aTempMatrix.set(0, 2, aMatrix.Line1.Column3 ); + aTempMatrix.set(1, 0, aMatrix.Line2.Column1 ); + aTempMatrix.set(1, 1, aMatrix.Line2.Column2 ); + aTempMatrix.set(1, 2, aMatrix.Line2.Column3 ); + // For this to be a valid 2D transform matrix, the last row must be [0,0,1] + assert( aMatrix.Line3.Column1 == 0 ); + assert( aMatrix.Line3.Column2 == 0 ); + assert( aMatrix.Line3.Column3 == 1 ); + // #i73079# + aTempMatrix.translate( aTranslateDiff.X, aTranslateDiff.Y ); + aMatrix.Line1.Column1 = aTempMatrix.get(0, 0); + aMatrix.Line1.Column2 = aTempMatrix.get(0, 1); + aMatrix.Line1.Column3 = aTempMatrix.get(0, 2); + aMatrix.Line2.Column1 = aTempMatrix.get(1, 0); + aMatrix.Line2.Column2 = aTempMatrix.get(1, 1); + aMatrix.Line2.Column3 = aTempMatrix.get(1, 2); + aMatrix.Line3.Column1 = 0; + aMatrix.Line3.Column2 = 0; + aMatrix.Line3.Column3 = 1; + } + } + } + + return aMatrix; +} + +/** method to adjust the positioning properties + #i31698# +*/ +void SwXShape::AdjustPositionProperties( const awt::Point& rPosition ) +{ + // handle x-position + // #i35007# - no handling of x-position, if drawing + // object is anchored as-character, because it doesn't make sense. + text::TextContentAnchorType eTextAnchorType = + text::TextContentAnchorType_AT_PARAGRAPH; + { + uno::Any aAny = getPropertyValue( "AnchorType" ); + aAny >>= eTextAnchorType; + } + if ( eTextAnchorType != text::TextContentAnchorType_AS_CHARACTER ) + { + // determine current x-position + static constexpr OUString aHoriPosPropStr(u"HoriOrientPosition"_ustr); + uno::Any aHoriPos( getPropertyValue( aHoriPosPropStr ) ); + sal_Int32 dCurrX = 0; + aHoriPos >>= dCurrX; + // change x-position attribute, if needed + if ( dCurrX != rPosition.X ) + { + // adjust x-position orientation to text::HoriOrientation::NONE, if needed + // Note: has to be done before setting x-position attribute + static constexpr OUString aHoriOrientPropStr(u"HoriOrient"_ustr); + uno::Any aHoriOrient( getPropertyValue( aHoriOrientPropStr ) ); + sal_Int16 eHoriOrient; + if (aHoriOrient >>= eHoriOrient) // may be void + { + if ( eHoriOrient != text::HoriOrientation::NONE ) + { + eHoriOrient = text::HoriOrientation::NONE; + aHoriOrient <<= eHoriOrient; + setPropertyValue( aHoriOrientPropStr, aHoriOrient ); + } + } + // set x-position attribute + aHoriPos <<= rPosition.X; + setPropertyValue( aHoriPosPropStr, aHoriPos ); + } + } + + // handle y-position + { + // determine current y-position + static constexpr OUString aVertPosPropStr(u"VertOrientPosition"_ustr); + uno::Any aVertPos( getPropertyValue( aVertPosPropStr ) ); + sal_Int32 dCurrY = 0; + aVertPos >>= dCurrY; + // change y-position attribute, if needed + if ( dCurrY != rPosition.Y ) + { + // adjust y-position orientation to text::VertOrientation::NONE, if needed + // Note: has to be done before setting y-position attribute + static constexpr OUString aVertOrientPropStr(u"VertOrient"_ustr); + uno::Any aVertOrient( getPropertyValue( aVertOrientPropStr ) ); + sal_Int16 eVertOrient; + if (aVertOrient >>= eVertOrient) // may be void + { + if ( eVertOrient != text::VertOrientation::NONE ) + { + eVertOrient = text::VertOrientation::NONE; + aVertOrient <<= eVertOrient; + setPropertyValue( aVertOrientPropStr, aVertOrient ); + } + } + // set y-position attribute + aVertPos <<= rPosition.Y; + setPropertyValue( aVertPosPropStr, aVertPos ); + } + } +} + +/** method to convert start or end position of the drawing object to the + Writer specific position, which is the attribute position in layout direction + #i59051# +*/ +css::awt::Point SwXShape::ConvertStartOrEndPosToLayoutDir( + const css::awt::Point& aStartOrEndPos ) +{ + awt::Point aConvertedPos( aStartOrEndPos ); + + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE( pSvxShape, + "<SwXShape::ConvertStartOrEndPosToLayoutDir(..)> - no SvxShape found!"); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + OSL_ENSURE( pObj, + "<SwXShape::ConvertStartOrEndPosToLayoutDir(..)> - no SdrObject found!"); + if ( pObj ) + { + // get position of object in Writer coordinate system. + awt::Point aPos( getPosition() ); + // get position of object in Drawing layer coordinate system + const Point aTmpObjPos( pObj->GetSnapRect().TopLeft() ); + const awt::Point aObjPos( + convertTwipToMm100( aTmpObjPos.X() - pObj->GetAnchorPos().X() ), + convertTwipToMm100( aTmpObjPos.Y() - pObj->GetAnchorPos().Y() ) ); + // determine difference between these positions according to the + // Writer coordinate system + const awt::Point aTranslateDiff( aPos.X - aObjPos.X, + aPos.Y - aObjPos.Y ); + // apply translation difference to transformation matrix. + if ( aTranslateDiff.X != 0 || aTranslateDiff.Y != 0 ) + { + aConvertedPos.X = aConvertedPos.X + aTranslateDiff.X; + aConvertedPos.Y = aConvertedPos.Y + aTranslateDiff.Y; + } + } + } + + return aConvertedPos; +} + +css::drawing::PolyPolygonBezierCoords SwXShape::ConvertPolyPolygonBezierToLayoutDir( + const css::drawing::PolyPolygonBezierCoords& aPath ) +{ + drawing::PolyPolygonBezierCoords aConvertedPath( aPath ); + + SvxShape* pSvxShape = GetSvxShape(); + OSL_ENSURE( pSvxShape, + "<SwXShape::ConvertStartOrEndPosToLayoutDir(..)> - no SvxShape found!"); + if ( pSvxShape ) + { + const SdrObject* pObj = pSvxShape->GetSdrObject(); + OSL_ENSURE( pObj, + "<SwXShape::ConvertStartOrEndPosToLayoutDir(..)> - no SdrObject found!"); + if ( pObj ) + { + // get position of object in Writer coordinate system. + awt::Point aPos( getPosition() ); + // get position of object in Drawing layer coordinate system + const Point aTmpObjPos( pObj->GetSnapRect().TopLeft() ); + const awt::Point aObjPos( + convertTwipToMm100( aTmpObjPos.X() - pObj->GetAnchorPos().X() ), + convertTwipToMm100( aTmpObjPos.Y() - pObj->GetAnchorPos().Y() ) ); + // determine difference between these positions according to the + // Writer coordinate system + const awt::Point aTranslateDiff( aPos.X - aObjPos.X, + aPos.Y - aObjPos.Y ); + // apply translation difference to PolyPolygonBezier. + if ( aTranslateDiff.X != 0 || aTranslateDiff.Y != 0 ) + { + const basegfx::B2DHomMatrix aMatrix(basegfx::utils::createTranslateB2DHomMatrix( + aTranslateDiff.X, aTranslateDiff.Y)); + + for(drawing::PointSequence& rInnerSequence : asNonConstRange(aConvertedPath.Coordinates)) + { + for(awt::Point& rPoint : asNonConstRange(rInnerSequence)) + { + basegfx::B2DPoint aNewCoordinatePair(rPoint.X, rPoint.Y); + aNewCoordinatePair *= aMatrix; + rPoint.X = basegfx::fround(aNewCoordinatePair.getX()); + rPoint.Y = basegfx::fround(aNewCoordinatePair.getY()); + } + } + } + } + } + + return aConvertedPath; +} + +SwXGroupShape::SwXGroupShape(uno::Reference<XInterface> & xShape, + SwDoc const*const pDoc) + : SwXShape(xShape, pDoc) +{ +#if OSL_DEBUG_LEVEL > 0 + uno::Reference<XShapes> xShapes(m_xShapeAgg, uno::UNO_QUERY); + OSL_ENSURE(xShapes.is(), "no SvxShape found or shape is not a group shape"); +#endif +} + +SwXGroupShape::~SwXGroupShape() +{ +} + +uno::Any SwXGroupShape::queryInterface( const uno::Type& rType ) +{ + uno::Any aRet; + if(rType == cppu::UnoType<XShapes>::get()) + aRet <<= uno::Reference<XShapes>(this); + else + aRet = SwXShape::queryInterface(rType); + return aRet; +} + +void SwXGroupShape::acquire( ) noexcept +{ + SwXShape::acquire(); +} + +void SwXGroupShape::release( ) noexcept +{ + SwXShape::release(); +} + +void SwXGroupShape::add( const uno::Reference< XShape >& xShape ) +{ + SolarMutexGuard aGuard; + SvxShape* pSvxShape = GetSvxShape(); + SwFrameFormat* pFormat = GetFrameFormat(); + if(!(pSvxShape && pFormat)) + throw uno::RuntimeException(); + + uno::Reference<XShapes> xShapes; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XShapes>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xShapes; + } + if(!xShapes.is()) + throw uno::RuntimeException(); + + xShapes->add(xShape); + + + uno::Reference<lang::XUnoTunnel> xTunnel(xShape, uno::UNO_QUERY); + SwXShape* pSwShape = comphelper::getFromUnoTunnel<SwXShape>(xTunnel); + if(!(pSwShape && pSwShape->m_bDescriptor)) + return; + + SvxShape* pAddShape = comphelper::getFromUnoTunnel<SvxShape>(xTunnel); + if(pAddShape) + { + SdrObject* pObj = pAddShape->GetSdrObject(); + if(pObj) + { + SwDoc* pDoc = pFormat->GetDoc(); + // set layer of new drawing + // object to corresponding invisible layer. + if( SdrInventor::FmForm != pObj->GetObjInventor()) + { + pObj->SetLayer( pSwShape->m_pImpl->GetOpaque() + ? pDoc->getIDocumentDrawModelAccess().GetInvisibleHeavenId() + : pDoc->getIDocumentDrawModelAccess().GetInvisibleHellId() ); + } + else + { + pObj->SetLayer(pDoc->getIDocumentDrawModelAccess().GetInvisibleControlsId()); + } + } + } + pSwShape->m_bDescriptor = false; +} + +void SwXGroupShape::remove( const uno::Reference< XShape >& xShape ) +{ + SolarMutexGuard aGuard; + uno::Reference<XShapes> xShapes; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XShapes>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xShapes; + } + if(!xShapes.is()) + throw uno::RuntimeException(); + xShapes->remove(xShape); +} + +sal_Int32 SwXGroupShape::getCount() +{ + SolarMutexGuard aGuard; + uno::Reference<XIndexAccess> xAcc; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XIndexAccess>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xAcc; + } + if(!xAcc.is()) + throw uno::RuntimeException(); + return xAcc->getCount(); +} + +uno::Any SwXGroupShape::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + uno::Reference<XIndexAccess> xAcc; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XIndexAccess>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xAcc; + } + if(!xAcc.is()) + throw uno::RuntimeException(); + return xAcc->getByIndex(nIndex); +} + +uno::Type SwXGroupShape::getElementType( ) +{ + SolarMutexGuard aGuard; + uno::Reference<XIndexAccess> xAcc; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XIndexAccess>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xAcc; + } + if(!xAcc.is()) + throw uno::RuntimeException(); + return xAcc->getElementType(); +} + +sal_Bool SwXGroupShape::hasElements( ) +{ + SolarMutexGuard aGuard; + uno::Reference<XIndexAccess> xAcc; + if( m_xShapeAgg.is() ) + { + const uno::Type& rType = cppu::UnoType<XIndexAccess>::get(); + uno::Any aAgg = m_xShapeAgg->queryAggregation( rType ); + aAgg >>= xAcc; + } + if(!xAcc.is()) + throw uno::RuntimeException(); + return xAcc->hasElements(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |