diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/unocore/unoparagraph.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/unocore/unoparagraph.cxx')
-rw-r--r-- | sw/source/core/unocore/unoparagraph.cxx | 1457 |
1 files changed, 1457 insertions, 0 deletions
diff --git a/sw/source/core/unocore/unoparagraph.cxx b/sw/source/core/unocore/unoparagraph.cxx new file mode 100644 index 0000000000..dab5270588 --- /dev/null +++ b/sw/source/core/unocore/unoparagraph.cxx @@ -0,0 +1,1457 @@ +/* -*- 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 <unoparagraph.hxx> + +#include <comphelper/interfacecontainer4.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/diagnose.h> +#include <comphelper/diagnose_ex.hxx> + +#include <cmdid.h> +#include <fmtautofmt.hxx> +#include <unomid.h> +#include <unoparaframeenum.hxx> +#include <unotext.hxx> +#include <unotextrange.hxx> +#include <unoport.hxx> +#include <unomap.hxx> +#include <unocrsr.hxx> +#include <unoprnms.hxx> +#include <unocrsrhelper.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <algorithm> +#include <utility> +#include <vcl/svapp.hxx> +#include <docsh.hxx> +#include <swunohelper.hxx> + +#include <com/sun/star/beans/SetPropertyTolerantFailed.hpp> +#include <com/sun/star/beans/GetPropertyTolerantResult.hpp> +#include <com/sun/star/beans/TolerantPropertySetResultType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> + +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <editeng/unoipset.hxx> +#include <svl/listener.hxx> +#include <svx/unobrushitemhelper.hxx> +#include <svx/xflbmtit.hxx> +#include <svx/xflbstit.hxx> + +using namespace ::com::sun::star; + +namespace { + +class SwParaSelection +{ + SwCursor & m_rCursor; +public: + explicit SwParaSelection(SwCursor & rCursor); + ~SwParaSelection(); +}; + +} + +SwParaSelection::SwParaSelection(SwCursor & rCursor) + : m_rCursor(rCursor) +{ + if (m_rCursor.HasMark()) + { + m_rCursor.DeleteMark(); + } + // is it at the start? + if (m_rCursor.GetPoint()->GetContentIndex() != 0) + { + m_rCursor.MovePara(GoCurrPara, fnParaStart); + } + // or at the end already? + if (m_rCursor.GetPoint()->GetContentIndex() != m_rCursor.GetPointContentNode()->Len()) + { + m_rCursor.SetMark(); + m_rCursor.MovePara(GoCurrPara, fnParaEnd); + } +} + +SwParaSelection::~SwParaSelection() +{ + if (m_rCursor.GetPoint()->GetContentIndex() != 0) + { + m_rCursor.DeleteMark(); + m_rCursor.MovePara(GoCurrPara, fnParaStart); + } +} + +/// @throws beans::UnknownPropertyException +/// @throws uno::RuntimeException +static beans::PropertyState lcl_SwXParagraph_getPropertyState( + const SwTextNode& rTextNode, + const SwAttrSet** ppSet, + const SfxItemPropertyMapEntry& rEntry, + bool &rAttrSetFetched ); + +class SwXParagraph::Impl + : public SvtListener +{ +public: + SwXParagraph& m_rThis; + unotools::WeakReference<SwXParagraph> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + SfxItemPropertySet const& m_rPropSet; + bool m_bIsDescriptor; + sal_Int32 m_nSelectionStartPos; + sal_Int32 m_nSelectionEndPos; + OUString m_sText; + css::uno::Reference<SwXText> m_xParentText; + SwTextNode* m_pTextNode; + + Impl(SwXParagraph& rThis, + SwTextNode* const pTextNode = nullptr, css::uno::Reference<SwXText> xParent = nullptr, + const sal_Int32 nSelStart = -1, const sal_Int32 nSelEnd = -1) + : m_rThis(rThis) + , m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH)) + , m_bIsDescriptor(nullptr == pTextNode) + , m_nSelectionStartPos(nSelStart) + , m_nSelectionEndPos(nSelEnd) + , m_xParentText(std::move(xParent)) + , m_pTextNode(pTextNode) + { + m_pTextNode && StartListening(m_pTextNode->GetNotifier()); + } + + SwTextNode* GetTextNode() { + return m_pTextNode; + } + + SwTextNode& GetTextNodeOrThrow() { + if (!m_pTextNode) { + throw uno::RuntimeException("SwXParagraph: disposed or invalid", nullptr); + } + return *m_pTextNode; + } + + bool IsDescriptor() const { return m_bIsDescriptor; } + + /// @throws beans::UnknownPropertyException + /// @throws beans::PropertyVetoException + /// @throws lang::IllegalArgumentException + /// @throws lang::WrappedTargetException + /// @throws uno::RuntimeException + void SetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues); + + /// @throws beans::UnknownPropertyException + /// @throws lang::WrappedTargetException + /// @throws uno::RuntimeException + uno::Sequence< uno::Any > + GetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames); + + /// @throws uno::RuntimeException + void GetSinglePropertyValue_Impl( + const SfxItemPropertyMapEntry& rEntry, + const SfxItemSet& rSet, + uno::Any& rAny ) const; + + /// @throws uno::RuntimeException + uno::Sequence< beans::GetDirectPropertyTolerantResult > + GetPropertyValuesTolerant_Impl( + const uno::Sequence< OUString >& rPropertyNames, + bool bDirectValuesOnly); +protected: + virtual void Notify(const SfxHint& rHint) override; + +}; + +void SwXParagraph::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + m_pTextNode = nullptr; + std::unique_lock aGuard(m_Mutex); + if (m_EventListeners.getLength(aGuard) != 0) + { + // fdo#72695: if UNO object is already dead, don't revive it with event + // The specific pattern we are guarding against is this: + // [1] Thread1 takes the SolarMutex + // [2] Thread2 decrements the SwXParagraph reference count, and calls the + // SwXParagraph destructor, which tries to take the SolarMutex, and blocks + // [3] Thread1 destroys a SwTextNode, which calls this Notify event, which results + // in a double-free if we construct the xThis object. + uno::Reference<uno::XInterface> const xThis(m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + m_EventListeners.disposeAndClear(aGuard, ev); + } + } +} + +SwXParagraph::SwXParagraph() + : m_pImpl( new SwXParagraph::Impl(*this) ) +{ +} + +SwXParagraph::SwXParagraph( + css::uno::Reference< SwXText > const & xParent, + SwTextNode & rTextNode, + const sal_Int32 nSelStart, const sal_Int32 nSelEnd) + : m_pImpl( + new SwXParagraph::Impl(*this, &rTextNode, xParent, nSelStart, nSelEnd)) +{ +} + +SwXParagraph::~SwXParagraph() +{ +} + +const SwTextNode * SwXParagraph::GetTextNode() const +{ + return m_pImpl->GetTextNode(); +} + +bool SwXParagraph::IsDescriptor() const +{ + return m_pImpl->IsDescriptor(); +} + +rtl::Reference<SwXParagraph> +SwXParagraph::CreateXParagraph(SwDoc & rDoc, SwTextNode *const pTextNode, + css::uno::Reference< SwXText> const& i_xParent, + const sal_Int32 nSelStart, const sal_Int32 nSelEnd) +{ + // re-use existing SwXParagraph + // #i105557#: do not iterate over the registered clients: race condition + rtl::Reference<SwXParagraph> xParagraph; + if (pTextNode && (-1 == nSelStart) && (-1 == nSelEnd)) + { // only use cache if no selection! + xParagraph = pTextNode->GetXParagraph(); + } + if (xParagraph.is()) + { + return xParagraph; + } + + // create new SwXParagraph + css::uno::Reference<SwXText> xParentText(i_xParent); + if (!xParentText.is() && pTextNode) + { + SwPosition Pos(*pTextNode); + xParentText = ::sw::CreateParentXText( rDoc, Pos ); + } + SwXParagraph *const pXPara( pTextNode + ? new SwXParagraph(xParentText, *pTextNode, nSelStart, nSelEnd) + : new SwXParagraph); + // this is why the constructor is private: need to acquire pXPara here + xParagraph.set(pXPara); + // in order to initialize the weak pointer cache in the core object + if (pTextNode && (-1 == nSelStart) && (-1 == nSelEnd)) + { + pTextNode->SetXParagraph(xParagraph); + } + // need a permanent Reference to initialize m_wThis + pXPara->m_pImpl->m_wThis = xParagraph.get(); + return xParagraph; +} + +bool SwXParagraph::SelectPaM(SwPaM & rPaM) +{ + SwTextNode const*const pTextNode( GetTextNode() ); + + if (!pTextNode) + { + return false; + } + + rPaM.GetPoint()->Assign( *pTextNode ); + // set selection to the whole paragraph + rPaM.SetMark(); + rPaM.GetMark()->SetContent( pTextNode->GetText().getLength() ); + return true; +} + +OUString SAL_CALL +SwXParagraph::getImplementationName() +{ + return "SwXParagraph"; +} + +sal_Bool SAL_CALL +SwXParagraph::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXParagraph::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.Paragraph", + "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesAsian", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.style.ParagraphPropertiesComplex" + }; +} + +void +SwXParagraph::attachToText(SwXText & rParent, SwTextNode & rTextNode) +{ + OSL_ENSURE(m_pImpl->m_bIsDescriptor, "Paragraph is not a descriptor"); + if (!m_pImpl->m_bIsDescriptor) + return; + + m_pImpl->m_bIsDescriptor = false; + m_pImpl->EndListeningAll(); + m_pImpl->StartListening(rTextNode.GetNotifier()); + rTextNode.SetXParagraph(this); + m_pImpl->m_xParentText = &rParent; + if (!m_pImpl->m_sText.isEmpty()) + { + try { setString(m_pImpl->m_sText); } + catch(...){} + m_pImpl->m_sText.clear(); + } +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXParagraph::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xRef = + m_pImpl->m_rPropSet.getPropertySetInfo(); + return xRef; +} + +void SAL_CALL +SwXParagraph::setPropertyValue(const OUString& rPropertyName, + const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + m_pImpl->SetPropertyValues_Impl( { rPropertyName }, { rValue } ); +} + +uno::Any +SwXParagraph::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + uno::Sequence<OUString> aPropertyNames { rPropertyName }; + const uno::Sequence< uno::Any > aRet = + m_pImpl->GetPropertyValues_Impl(aPropertyNames); + return aRet.getConstArray()[0]; +} + +void SwXParagraph::Impl::SetPropertyValues_Impl( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + SwTextNode & rTextNode(GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + + uno::Sequence< beans::PropertyValue > aValues( rPropertyNames.getLength() ); + std::transform( + rPropertyNames.begin(), rPropertyNames.end(), rValues.begin(), aValues.getArray(), + [&rMap = m_rPropSet.getPropertyMap(), this](const OUString& name, const uno::Any& value) + { + if (SfxItemPropertyMapEntry const* const pEntry = rMap.getByName(name); !pEntry) + { + throw beans::UnknownPropertyException("Unknown property: " + name, + m_rThis.getXWeak()); + } + else if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw beans::PropertyVetoException("Property is read-only: " + name, + m_rThis.getXWeak()); + } + return comphelper::makePropertyValue(name, value); + }); + SwUnoCursorHelper::SetPropertyValues(aCursor, m_rPropSet, aValues); +} + +void SAL_CALL SwXParagraph::setPropertyValues( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + if (rPropertyNames.getLength() != rValues.getLength()) + throw lang::IllegalArgumentException("lengths do not match", + getXWeak(), -1); + + SolarMutexGuard aGuard; + + // workaround for bad designed API + try + { + m_pImpl->SetPropertyValues_Impl( rPropertyNames, rValues ); + } + catch (const beans::UnknownPropertyException &rException) + { + // wrap the original (here not allowed) exception in + // a lang::WrappedTargetException that gets thrown instead. + lang::WrappedTargetException aWExc; + aWExc.TargetException <<= rException; + throw aWExc; + } +} + +// Support for DrawingLayer FillStyles for GetPropertyValue() usages +void SwXParagraph::Impl::GetSinglePropertyValue_Impl( + const SfxItemPropertyMapEntry& rEntry, + const SfxItemSet& rSet, + uno::Any& rAny ) const +{ + bool bDone(false); + + switch(rEntry.nWID) + { + case RES_BACKGROUND: + { + const std::unique_ptr<SvxBrushItem> aOriginalBrushItem(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND)); + + if(!aOriginalBrushItem->QueryValue(rAny, rEntry.nMemberId)) + { + OSL_ENSURE(false, "Error getting attribute from RES_BACKGROUND (!)"); + } + + bDone = true; + break; + } + case OWN_ATTR_FILLBMP_MODE: + { + if (rSet.Get(XATTR_FILLBMP_TILE).GetValue()) + { + rAny <<= drawing::BitmapMode_REPEAT; + } + else if (rSet.Get(XATTR_FILLBMP_STRETCH).GetValue()) + { + rAny <<= drawing::BitmapMode_STRETCH; + } + else + { + rAny <<= drawing::BitmapMode_NO_REPEAT; + } + + bDone = true; + break; + } + default: break; + } + + if(bDone) + return; + + // fallback to standard get value implementation used before this helper was created + m_rPropSet.getPropertyValue(rEntry, rSet, rAny); + + if(rEntry.aType == cppu::UnoType<sal_Int16>::get() && rEntry.aType != rAny.getValueType()) + { + // since the sfx uInt16 item now exports a sal_Int32, we may have to fix this here + sal_Int32 nValue(0); + + if (rAny >>= nValue) + { + rAny <<= static_cast<sal_Int16>(nValue); + } + } + + // check for needed metric translation + if(!(rEntry.nMoreFlags & PropertyMoreFlags::METRIC_ITEM)) + return; + + bool bDoIt(true); + + if(XATTR_FILLBMP_SIZEX == rEntry.nWID || XATTR_FILLBMP_SIZEY == rEntry.nWID) + { + // exception: If these ItemTypes are used, do not convert when these are negative + // since this means they are intended as percent values + sal_Int32 nValue = 0; + + if(rAny >>= nValue) + { + bDoIt = nValue > 0; + } + } + + if(bDoIt) + { + const MapUnit eMapUnit(rSet.GetPool()->GetMetric(rEntry.nWID)); + + if(eMapUnit != MapUnit::Map100thMM) + { + SvxUnoConvertToMM(eMapUnit, rAny); + } + } +} + +uno::Sequence< uno::Any > SwXParagraph::Impl::GetPropertyValues_Impl( + const uno::Sequence< OUString > & rPropertyNames ) +{ + SwTextNode & rTextNode(GetTextNodeOrThrow()); + + uno::Sequence< uno::Any > aValues(rPropertyNames.getLength()); + SwPaM aPam( rTextNode ); + uno::Any* pValues = aValues.getArray(); + const OUString* pPropertyNames = rPropertyNames.getConstArray(); + const SfxItemPropertyMap &rMap = m_rPropSet.getPropertyMap(); + const SwAttrSet& rAttrSet( rTextNode.GetSwAttrSet() ); + for (sal_Int32 nProp = 0; nProp < rPropertyNames.getLength(); nProp++) + { + if (pPropertyNames[nProp] == "ParaMarkerAutoStyleSpan") + { + // A hack to tunnel the fake text span to ODF export + // see XMLTextParagraphExport::exportParagraph + if (rTextNode.GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle()) + { + SwUnoCursor aEndCursor(*aPam.GetMark()); + css::uno::Reference<css::beans::XPropertySet> xFakeSpan( + new SwXTextPortion(&aEndCursor, {}, PORTION_LIST_AUTOFMT)); + pValues[nProp] <<= xFakeSpan; + } + continue; + } + + if (pPropertyNames[nProp] == "ODFExport_NodeIndex") + { + // A hack to avoid writing random list ids to ODF when they are not referred later + // see XMLTextParagraphExport::DocumentListNodes::ShouldSkipListId + pValues[nProp] <<= rTextNode.GetIndex().get(); + continue; + } + + if (pPropertyNames[nProp] == "OOXMLImport_AnchoredShapes") + { + // A hack to provide list of anchored objects fast + // See reanchorObjects in writerfilter/source/dmapper/DomainMapper_Impl.cxx + FrameClientSortList_t aFrames; + CollectFrameAtNode(rTextNode, aFrames, false); // Frames anchored to paragraph + CollectFrameAtNode(rTextNode, aFrames, true); // Frames anchored to character + std::vector<uno::Reference<text::XTextContent>> aRet; + aRet.reserve(aFrames.size()); + for (const auto& rFrame : aFrames) + if (auto xContent = FrameClientToXTextContent(rFrame.pFrameClient.get())) + aRet.push_back(xContent); + + pValues[nProp] <<= comphelper::containerToSequence(aRet); + continue; + } + + SfxItemPropertyMapEntry const*const pEntry = + rMap.getByName( pPropertyNames[nProp] ); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + pPropertyNames[nProp], + m_rThis.getXWeak()); + } + if (! ::sw::GetDefaultTextContentValue( + pValues[nProp], pPropertyNames[nProp], pEntry->nWID)) + { + beans::PropertyState eTemp; + const bool bDone = SwUnoCursorHelper::getCursorPropertyValue( + *pEntry, aPam, &(pValues[nProp]), eTemp, &rTextNode ); + if (!bDone) + { + GetSinglePropertyValue_Impl(*pEntry, rAttrSet, pValues[nProp]); + } + } + } + return aValues; +} + +uno::Sequence< uno::Any > SAL_CALL +SwXParagraph::getPropertyValues(const uno::Sequence< OUString >& rPropertyNames) +{ + SolarMutexGuard aGuard; + uno::Sequence< uno::Any > aValues; + + // workaround for bad designed API + try + { + aValues = m_pImpl->GetPropertyValues_Impl( rPropertyNames ); + } + catch (beans::UnknownPropertyException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("Unknown property exception caught", + getXWeak(), anyEx ); + } + catch (lang::WrappedTargetException &) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("WrappedTargetException caught", + getXWeak(), anyEx ); + } + + return aValues; +} + +void SAL_CALL SwXParagraph::addPropertiesChangeListener( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXParagraph::addPropertiesChangeListener(): not implemented"); +} + +void SAL_CALL SwXParagraph::removePropertiesChangeListener( + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXParagraph::removePropertiesChangeListener(): not implemented"); +} + +void SAL_CALL SwXParagraph::firePropertiesChangeEvent( + const uno::Sequence< OUString >& /*aPropertyNames*/, + const uno::Reference< beans::XPropertiesChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("SwXParagraph::firePropertiesChangeEvent(): not implemented"); +} + +/* disabled for #i46921# */ + +uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL +SwXParagraph::setPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames, + const uno::Sequence< uno::Any >& rValues ) +{ + SolarMutexGuard aGuard; + + if (rPropertyNames.getLength() != rValues.getLength()) + { + throw lang::IllegalArgumentException(); + } + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + //SwNode& rTextNode = pUnoCursor->GetPoint()->GetNode(); + //const SwAttrSet& rAttrSet = static_cast<SwTextNode&>(rTextNode).GetSwAttrSet(); + //sal_uInt16 nAttrCount = rAttrSet.Count(); + + const sal_Int32 nProps = rPropertyNames.getLength(); + const OUString *pProp = rPropertyNames.getConstArray(); + + //sal_Int32 nVals = rValues.getLength(); + const uno::Any *pValue = rValues.getConstArray(); + + sal_Int32 nFailed = 0; + uno::Sequence< beans::SetPropertyTolerantFailed > aFailed( nProps ); + beans::SetPropertyTolerantFailed *pFailed = aFailed.getArray(); + + // get entry to start with + const SfxItemPropertyMap &rPropMap = + m_pImpl->m_rPropSet.getPropertyMap(); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + for (sal_Int32 i = 0; i < nProps; ++i) + { + try + { + pFailed[ nFailed ].Name = pProp[i]; + + SfxItemPropertyMapEntry const*const pEntry = + rPropMap.getByName( pProp[i] ); + if (!pEntry) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + else + { + // set property value + // (compare to SwXParagraph::setPropertyValues) + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::PROPERTY_VETO; + } + else + { + SwUnoCursorHelper::SetPropertyValue( + aCursor, m_pImpl->m_rPropSet, pProp[i], pValue[i]); + } + } + } + catch (beans::UnknownPropertyException &) + { + // should not occur because property was searched for before + TOOLS_WARN_EXCEPTION( "sw", "unexpected exception caught" ); + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + catch (lang::IllegalArgumentException &) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT; + } + catch (beans::PropertyVetoException &) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::PROPERTY_VETO; + } + catch (lang::WrappedTargetException &) + { + pFailed[ nFailed++ ].Result = + beans::TolerantPropertySetResultType::WRAPPED_TARGET; + } + } + + aFailed.realloc( nFailed ); + return aFailed; +} + +uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL +SwXParagraph::getPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames ) +{ + SolarMutexGuard aGuard; + + const uno::Sequence< beans::GetDirectPropertyTolerantResult > aTmpRes( + m_pImpl->GetPropertyValuesTolerant_Impl( rPropertyNames, false ) ); + + // copy temporary result to final result type + const sal_Int32 nLen = aTmpRes.getLength(); + uno::Sequence< beans::GetPropertyTolerantResult > aRes( nLen ); + std::copy(aTmpRes.begin(), aTmpRes.end(), aRes.getArray()); + return aRes; +} + +uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL +SwXParagraph::getDirectPropertyValuesTolerant( + const uno::Sequence< OUString >& rPropertyNames ) +{ + SolarMutexGuard aGuard; + + return m_pImpl->GetPropertyValuesTolerant_Impl( rPropertyNames, true ); +} + +uno::Sequence< beans::GetDirectPropertyTolerantResult > +SwXParagraph::Impl::GetPropertyValuesTolerant_Impl( + const uno::Sequence< OUString >& rPropertyNames, + bool bDirectValuesOnly ) +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(GetTextNodeOrThrow()); + + // #i46786# Use SwAttrSet pointer for determining the state. + // Use the value SwAttrSet (from the paragraph OR the style) + // for determining the actual value(s). + const SwAttrSet* pAttrSet = rTextNode.GetpSwAttrSet(); + const SwAttrSet& rValueAttrSet = rTextNode.GetSwAttrSet(); + + sal_Int32 nProps = rPropertyNames.getLength(); + + uno::Sequence< beans::GetDirectPropertyTolerantResult > aResult( nProps ); + beans::GetDirectPropertyTolerantResult *pResult = aResult.getArray(); + sal_Int32 nIdx = 0; + + // get entry to start with + const SfxItemPropertyMap &rPropMap = m_rPropSet.getPropertyMap(); + + for (const OUString& rProp : rPropertyNames) + { + OSL_ENSURE( nIdx < nProps, "index out of bounds" ); + beans::GetDirectPropertyTolerantResult &rResult = pResult[nIdx]; + + try + { + rResult.Name = rProp; + + SfxItemPropertyMapEntry const*const pEntry = + rPropMap.getByName( rProp ); + if (!pEntry) // property available? + { + rResult.Result = + beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + else + { + // get property state + // (compare to SwXParagraph::getPropertyState) + bool bAttrSetFetched = true; + beans::PropertyState eState = lcl_SwXParagraph_getPropertyState( + rTextNode, &pAttrSet, *pEntry, bAttrSetFetched ); + rResult.State = eState; + + rResult.Result = beans::TolerantPropertySetResultType::UNKNOWN_FAILURE; + if (!bDirectValuesOnly || + (beans::PropertyState_DIRECT_VALUE == eState)) + { + // get property value + // (compare to SwXParagraph::getPropertyValue(s)) + uno::Any aValue; + if (! ::sw::GetDefaultTextContentValue( + aValue, rProp, pEntry->nWID ) ) + { + SwPaM aPam( rTextNode ); + // handle properties that are not part of the attribute + // and thus only pretended to be paragraph attributes + beans::PropertyState eTemp; + const bool bDone = + SwUnoCursorHelper::getCursorPropertyValue( + *pEntry, aPam, &aValue, eTemp, &rTextNode ); + + // if not found try the real paragraph attributes... + if (!bDone) + { + GetSinglePropertyValue_Impl(*pEntry, rValueAttrSet, aValue); + } + } + + rResult.Value = aValue; + rResult.Result = beans::TolerantPropertySetResultType::SUCCESS; + + nIdx++; + } + // this assertion should never occur! + OSL_ENSURE( nIdx < 1 || pResult[nIdx - 1].Result != beans::TolerantPropertySetResultType::UNKNOWN_FAILURE, + "unknown failure while retrieving property" ); + + } + } + catch (beans::UnknownPropertyException &) + { + // should not occur because property was searched for before + TOOLS_WARN_EXCEPTION( "sw", "unexpected exception caught" ); + rResult.Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY; + } + catch (lang::IllegalArgumentException &) + { + rResult.Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT; + } + catch (beans::PropertyVetoException &) + { + rResult.Result = beans::TolerantPropertySetResultType::PROPERTY_VETO; + } + catch (lang::WrappedTargetException &) + { + rResult.Result = beans::TolerantPropertySetResultType::WRAPPED_TARGET; + } + } + + // resize to actually used size + aResult.realloc( nIdx ); + + return aResult; +} + +bool ::sw::GetDefaultTextContentValue( + uno::Any& rAny, std::u16string_view rPropertyName, sal_uInt16 nWID) +{ + if(!nWID) + { + if(rPropertyName == UNO_NAME_ANCHOR_TYPE) + nWID = FN_UNO_ANCHOR_TYPE; + else if(rPropertyName == UNO_NAME_ANCHOR_TYPES) + nWID = FN_UNO_ANCHOR_TYPES; + else if(rPropertyName == UNO_NAME_TEXT_WRAP) + nWID = FN_UNO_TEXT_WRAP; + else + return false; + } + + switch(nWID) + { + case FN_UNO_TEXT_WRAP: rAny <<= text::WrapTextMode_NONE; break; + case FN_UNO_ANCHOR_TYPE: rAny <<= text::TextContentAnchorType_AT_PARAGRAPH; break; + case FN_UNO_ANCHOR_TYPES: + { uno::Sequence<text::TextContentAnchorType> aTypes { text::TextContentAnchorType_AT_PARAGRAPH }; + rAny <<= aTypes; + } + break; + default: + return false; + } + return true; +} + +void SAL_CALL +SwXParagraph::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXParagraph::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXParagraph::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXParagraph::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXParagraph::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXParagraph::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXParagraph::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXParagraph::removeVetoableChangeListener(): not implemented"); +} + +static beans::PropertyState lcl_SwXParagraph_getPropertyState( + const SwTextNode& rTextNode, + const SwAttrSet** ppSet, + const SfxItemPropertyMapEntry& rEntry, + bool &rAttrSetFetched) +{ + beans::PropertyState eRet(beans::PropertyState_DEFAULT_VALUE); + + if(!(*ppSet) && !rAttrSetFetched) + { + (*ppSet) = rTextNode.GetpSwAttrSet(); + rAttrSetFetched = true; + } + + SwPosition aPos(rTextNode); + SwPaM aPam(aPos); + bool bDone(false); + + switch(rEntry.nWID) + { + case FN_UNO_NUM_RULES: + { + // if numbering is set, return it; else do nothing + SwUnoCursorHelper::getNumberingProperty(aPam,eRet,nullptr); + bDone = true; + break; + } + case FN_UNO_ANCHOR_TYPES: + { + bDone = true; + break; + } + case RES_ANCHOR: + { + bDone = (MID_SURROUND_SURROUNDTYPE == rEntry.nMemberId); + break; + } + case RES_SURROUND: + { + bDone = (MID_ANCHOR_ANCHORTYPE == rEntry.nMemberId); + break; + } + case FN_UNO_PARA_STYLE: + case FN_UNO_PARA_CONDITIONAL_STYLE_NAME: + { + SwFormatColl* pFormat = SwUnoCursorHelper::GetCurTextFormatColl(aPam,rEntry.nWID == FN_UNO_PARA_CONDITIONAL_STYLE_NAME); + eRet = pFormat ? beans::PropertyState_DIRECT_VALUE : beans::PropertyState_AMBIGUOUS_VALUE; + bDone = true; + break; + } + case FN_UNO_PAGE_STYLE: + { + OUString sVal; + SwUnoCursorHelper::GetCurPageStyle( aPam, sVal ); + eRet = !sVal.isEmpty() ? beans::PropertyState_DIRECT_VALUE + : beans::PropertyState_AMBIGUOUS_VALUE; + bDone = true; + break; + } + + // DrawingLayer PropertyStyle support + case OWN_ATTR_FILLBMP_MODE: + { + if(*ppSet) + { + if(SfxItemState::SET == (*ppSet)->GetItemState(XATTR_FILLBMP_STRETCH, false) + || SfxItemState::SET == (*ppSet)->GetItemState(XATTR_FILLBMP_TILE, false)) + { + eRet = beans::PropertyState_DIRECT_VALUE; + } + else + { + eRet = beans::PropertyState_AMBIGUOUS_VALUE; + } + + bDone = true; + } + break; + } + case RES_BACKGROUND: + { + if(*ppSet) + { + if (SWUnoHelper::needToMapFillItemsToSvxBrushItemTypes(**ppSet, + rEntry.nMemberId)) + { + eRet = beans::PropertyState_DIRECT_VALUE; + } + bDone = true; + } + break; + } + } + + if(!bDone) + { + if((*ppSet) && SfxItemState::SET == (*ppSet)->GetItemState(rEntry.nWID, false)) + { + eRet = beans::PropertyState_DIRECT_VALUE; + } + } + + return eRet; +} + +beans::PropertyState SAL_CALL +SwXParagraph::getPropertyState(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + const SwAttrSet* pSet = nullptr; + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + bool bDummy = false; + const beans::PropertyState eRet = + lcl_SwXParagraph_getPropertyState(rTextNode, &pSet, *pEntry, bDummy); + return eRet; +} + +uno::Sequence< beans::PropertyState > SAL_CALL +SwXParagraph::getPropertyStates( + const uno::Sequence< OUString >& PropertyNames) +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + const OUString* pNames = PropertyNames.getConstArray(); + uno::Sequence< beans::PropertyState > aRet(PropertyNames.getLength()); + beans::PropertyState* pStates = aRet.getArray(); + const SfxItemPropertyMap &rMap = m_pImpl->m_rPropSet.getPropertyMap(); + const SwAttrSet* pSet = nullptr; + bool bAttrSetFetched = false; + + for (sal_Int32 i = 0, nEnd = PropertyNames.getLength(); i < nEnd; + ++i, ++pStates, ++pNames) + { + SfxItemPropertyMapEntry const*const pEntry = + rMap.getByName( *pNames ); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + *pNames, + getXWeak()); + } + + if (bAttrSetFetched && !pSet && isATR(pEntry->nWID)) + { + *pStates = beans::PropertyState_DEFAULT_VALUE; + } + else + { + *pStates = lcl_SwXParagraph_getPropertyState( + rTextNode, &pSet, *pEntry, bAttrSetFetched ); + } + } + + return aRet; +} + +void SAL_CALL +SwXParagraph::setPropertyToDefault(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + if (rPropertyName == UNO_NAME_ANCHOR_TYPE || + rPropertyName == UNO_NAME_ANCHOR_TYPES || + rPropertyName == UNO_NAME_TEXT_WRAP) + { + return; + } + + // select paragraph + SwParaSelection aParaSel( aCursor ); + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName( rPropertyName ); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + { + throw uno::RuntimeException( + "Property is read-only: " + rPropertyName, + getXWeak()); + } + + const bool bBelowFrameAtrEnd(pEntry->nWID < RES_FRMATR_END); + const bool bDrawingLayerRange(XATTR_FILL_FIRST <= pEntry->nWID && XATTR_FILL_LAST >= pEntry->nWID); + + if(bBelowFrameAtrEnd || bDrawingLayerRange) + { + o3tl::sorted_vector<sal_uInt16> aWhichIds; + + // For FillBitmapMode two IDs have to be reset (!) + if(OWN_ATTR_FILLBMP_MODE == pEntry->nWID) + { + aWhichIds.insert(XATTR_FILLBMP_STRETCH); + aWhichIds.insert(XATTR_FILLBMP_TILE); + } + else + { + aWhichIds.insert(pEntry->nWID); + } + + if (pEntry->nWID < RES_PARATR_BEGIN) + { + aCursor.GetDoc().ResetAttrs(aCursor, true, aWhichIds); + } + else + { + // for paragraph attributes the selection must be extended + // to paragraph boundaries + SwPosition aStart( *aCursor.Start() ); + SwPosition aEnd ( *aCursor.End() ); + auto pTemp( aCursor.GetDoc().CreateUnoCursor(aStart) ); + if(!SwUnoCursorHelper::IsStartOfPara(*pTemp)) + { + pTemp->MovePara(GoCurrPara, fnParaStart); + } + + pTemp->SetMark(); + *pTemp->GetPoint() = aEnd; + + SwUnoCursorHelper::SelectPam(*pTemp, true); + + if (!SwUnoCursorHelper::IsEndOfPara(*pTemp)) + { + pTemp->MovePara(GoCurrPara, fnParaEnd); + } + + + pTemp->GetDoc().ResetAttrs(*pTemp, true, aWhichIds); + } + } + else + { + SwUnoCursorHelper::resetCursorPropertyValue(*pEntry, aCursor); + } +} + +uno::Any SAL_CALL +SwXParagraph::getPropertyDefault(const OUString& rPropertyName) +{ + SolarMutexGuard g; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + uno::Any aRet; + if (::sw::GetDefaultTextContentValue(aRet, rPropertyName)) + { + return aRet; + } + + SfxItemPropertyMapEntry const*const pEntry = + m_pImpl->m_rPropSet.getPropertyMap().getByName(rPropertyName); + if (!pEntry) + { + throw beans::UnknownPropertyException( + "Unknown property: " + rPropertyName, + getXWeak()); + } + + const bool bBelowFrameAtrEnd(pEntry->nWID < RES_FRMATR_END); + const bool bDrawingLayerRange(XATTR_FILL_FIRST <= pEntry->nWID && XATTR_FILL_LAST >= pEntry->nWID); + + if(bBelowFrameAtrEnd || bDrawingLayerRange) + { + const SfxPoolItem& rDefItem = rTextNode.GetDoc().GetAttrPool().GetDefaultItem(pEntry->nWID); + + rDefItem.QueryValue(aRet, pEntry->nMemberId); + } + + return aRet; +} + +void SAL_CALL +SwXParagraph::attach(const uno::Reference< text::XTextRange > & /*xTextRange*/) +{ + // SwXParagraph will only created in order to be inserted by + // 'insertTextContentBefore' or 'insertTextContentAfter' therefore + // they cannot be attached + throw uno::RuntimeException(); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXParagraph::getAnchor() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + // select paragraph + SwParaSelection aParaSel( aCursor ); + const uno::Reference< text::XTextRange > xRet = + new SwXTextRange(aCursor, m_pImpl->m_xParentText); + return xRet; +} + +void SAL_CALL SwXParagraph::dispose() +{ + SolarMutexGuard aGuard; + + SwTextNode *const pTextNode( m_pImpl->GetTextNode() ); + if (pTextNode) + { + SwCursor aCursor( SwPosition( *pTextNode ), nullptr ); + pTextNode->GetDoc().getIDocumentContentOperations().DelFullPara(aCursor); + lang::EventObject const ev(getXWeak()); + std::unique_lock aGuard2(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.disposeAndClear(aGuard2, ev); + } +} + +void SAL_CALL SwXParagraph::addEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SwXParagraph::removeEventListener( + const uno::Reference< lang::XEventListener > & xListener) +{ + // no need to lock here as m_pImpl is const and container threadsafe + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.removeInterface(aGuard, xListener); +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXParagraph::createEnumeration() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPaM aPam ( rTextNode ); + const uno::Reference< container::XEnumeration > xRef = + new SwXTextPortionEnumeration(aPam, m_pImpl->m_xParentText, + m_pImpl->m_nSelectionStartPos, m_pImpl->m_nSelectionEndPos); + return xRef; +} + + /// tries to return less data, but may return more than just text fields +rtl::Reference< SwXTextPortionEnumeration > +SwXParagraph::createTextFieldsEnumeration() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + SwPaM aPam ( rTextNode ); + + return new SwXTextPortionEnumeration(aPam, m_pImpl->m_xParentText, + m_pImpl->m_nSelectionStartPos, m_pImpl->m_nSelectionEndPos, /*bOnlyTextFields*/true); +} + +uno::Type SAL_CALL SwXParagraph::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SwXParagraph::hasElements() +{ + SolarMutexGuard aGuard; + return GetTextNode() != nullptr; +} + +uno::Reference< text::XText > SAL_CALL +SwXParagraph::getText() +{ + SolarMutexGuard g; + + return m_pImpl->m_xParentText; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXParagraph::getStart() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + SwPaM aPam( *aCursor.Start() ); + uno::Reference< text::XText > xParent = getText(); + const uno::Reference< text::XTextRange > xRet = + new SwXTextRange(aPam, xParent); + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXParagraph::getEnd() +{ + SolarMutexGuard aGuard; + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPosition aPos( rTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + SwPaM aPam( *aCursor.End() ); + uno::Reference< text::XText > xParent = getText(); + const uno::Reference< text::XTextRange > xRet = + new SwXTextRange(aPam, xParent); + return xRet; +} + +OUString SAL_CALL SwXParagraph::getString() +{ + SolarMutexGuard aGuard; + OUString aRet; + SwTextNode const*const pTextNode( GetTextNode() ); + if (pTextNode) + { + SwPosition aPos( *pTextNode ); + SwCursor aCursor( aPos, nullptr ); + SwParaSelection aParaSel( aCursor ); + SwUnoCursorHelper::GetTextFromPam(aCursor, aRet); + } + else if (m_pImpl->IsDescriptor()) + { + aRet = m_pImpl->m_sText; + } + else + { + // Seems object is being disposed or some other problem occurs. + // Anyway from user point of view object still exist, so on that level this is not an error + SAL_WARN("sw.uno", "getString() for invalid paragraph called. Returning empty string."); + } + return aRet; +} + +void SAL_CALL SwXParagraph::setString(const OUString& aString) +{ + SolarMutexGuard aGuard; + + SwTextNode const*const pTextNode( GetTextNode() ); + if (pTextNode) + { + SwPosition aPos( *pTextNode ); + SwCursor aCursor( aPos, nullptr ); + if (!SwUnoCursorHelper::IsStartOfPara(aCursor)) { + aCursor.MovePara(GoCurrPara, fnParaStart); + } + SwUnoCursorHelper::SelectPam(aCursor, true); + if (pTextNode->GetText().getLength()) { + aCursor.MovePara(GoCurrPara, fnParaEnd); + } + SwUnoCursorHelper::SetString(aCursor, aString); + SwUnoCursorHelper::SelectPam(aCursor, false); + } + else if (m_pImpl->IsDescriptor()) + { + m_pImpl->m_sText = aString; + } + else + { + throw uno::RuntimeException(); + } +} + +uno::Reference< container::XEnumeration > SAL_CALL +SwXParagraph::createContentEnumeration(const OUString& rServiceName) +{ + SolarMutexGuard g; + + if ( rServiceName != "com.sun.star.text.TextContent" ) + { + throw uno::RuntimeException(); + } + + SwTextNode & rTextNode(m_pImpl->GetTextNodeOrThrow()); + + SwPaM aPam( rTextNode ); + uno::Reference< container::XEnumeration > xRet = + SwXParaFrameEnumeration::Create(aPam, PARAFRAME_PORTION_PARAGRAPH); + return xRet; +} + +uno::Sequence< OUString > SAL_CALL +SwXParagraph::getAvailableServiceNames() +{ + uno::Sequence<OUString> aRet { "com.sun.star.text.TextContent" }; + return aRet; +} + +// MetadatableMixin +::sfx2::Metadatable* SwXParagraph::GetCoreObject() +{ + SwTextNode *const pTextNode( m_pImpl->GetTextNode() ); + return pTextNode; +} + +uno::Reference<frame::XModel> SwXParagraph::GetModel() +{ + SwTextNode *const pTextNode( m_pImpl->GetTextNode() ); + if (pTextNode) + { + SwDocShell const*const pShell( pTextNode->GetDoc().GetDocShell() ); + return pShell ? pShell->GetModel() : nullptr; + } + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |