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/unorefmk.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/unorefmk.cxx')
-rw-r--r-- | sw/source/core/unocore/unorefmk.cxx | 1475 |
1 files changed, 1475 insertions, 0 deletions
diff --git a/sw/source/core/unocore/unorefmk.cxx b/sw/source/core/unocore/unorefmk.cxx new file mode 100644 index 0000000000..43b0690ecb --- /dev/null +++ b/sw/source/core/unocore/unorefmk.cxx @@ -0,0 +1,1475 @@ +/* -*- 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 <memory> +#include <utility> + +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <sal/config.h> +#include <svl/listener.hxx> +#include <vcl/svapp.hxx> +#include <sal/log.hxx> + +#include <unotextrange.hxx> +#include <unorefmark.hxx> +#include <unotextcursor.hxx> +#include <unomap.hxx> +#include <unocrsrhelper.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <fmtrfmrk.hxx> +#include <txtrfmrk.hxx> +#include <unometa.hxx> +#include <unotext.hxx> +#include <unoport.hxx> +#include <txtatr.hxx> +#include <fmtmeta.hxx> +#include <docsh.hxx> + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/rdf/Statement.hpp> +#include <com/sun/star/rdf/URI.hpp> +#include <com/sun/star/rdf/URIs.hpp> +#include <com/sun/star/rdf/XLiteral.hpp> +#include <com/sun/star/rdf/XRepositorySupplier.hpp> +#include <com/sun/star/lang/DisposedException.hpp> + +using namespace ::com::sun::star; + +class SwXReferenceMark::Impl + : public SvtListener +{ +public: + unotools::WeakReference<SwXReferenceMark> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + bool m_bIsDescriptor; + SwDoc* m_pDoc; + const SwFormatRefMark* m_pMarkFormat; + OUString m_sMarkName; + + Impl(SwDoc* const pDoc, SwFormatRefMark* const pRefMark) + : m_bIsDescriptor(nullptr == pRefMark) + , m_pDoc(pDoc) + , m_pMarkFormat(pRefMark) + { + if (pRefMark) + { + StartListening(pRefMark->GetNotifier()); + m_sMarkName = pRefMark->GetRefName(); + } + } + + bool IsValid() const { return m_pMarkFormat; } + void InsertRefMark( SwPaM & rPam, SwXTextCursor const*const pCursor ); + void Invalidate(); +protected: + virtual void Notify(const SfxHint&) override; + +}; + +void SwXReferenceMark::Impl::Invalidate() +{ + EndListeningAll(); + m_pDoc = nullptr; + m_pMarkFormat = nullptr; + 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); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); +} + +void SwXReferenceMark::Impl::Notify(const SfxHint& rHint) +{ + if(rHint.GetId() == SfxHintId::Dying) + Invalidate(); +} + +SwXReferenceMark::SwXReferenceMark( + SwDoc *const pDoc, SwFormatRefMark *const pRefMark) + : m_pImpl( new SwXReferenceMark::Impl(pDoc, pRefMark) ) +{ +} + +SwXReferenceMark::~SwXReferenceMark() +{ +} + +rtl::Reference<SwXReferenceMark> +SwXReferenceMark::CreateXReferenceMark( + SwDoc & rDoc, SwFormatRefMark *const pMarkFormat) +{ + // i#105557: do not iterate over the registered clients: race condition + rtl::Reference<SwXReferenceMark> xMark; + if (pMarkFormat) + { + xMark = pMarkFormat->GetXRefMark(); + } + if (!xMark.is()) + { + xMark = new SwXReferenceMark(&rDoc, pMarkFormat); + if (pMarkFormat) + { + pMarkFormat->SetXRefMark(xMark); + } + // need a permanent Reference to initialize m_wThis + xMark->m_pImpl->m_wThis = xMark.get(); + } + return xMark; +} + +OUString SAL_CALL SwXReferenceMark::getImplementationName() +{ + return "SwXReferenceMark"; +} + +sal_Bool SAL_CALL +SwXReferenceMark::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXReferenceMark::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.ReferenceMark" + }; +} + +namespace { + +template<typename T> struct NotContainedIn +{ + std::vector<T> const& m_rVector; + explicit NotContainedIn(std::vector<T> const& rVector) + : m_rVector(rVector) { } + bool operator() (T const& rT) { + return std::find(m_rVector.begin(), m_rVector.end(), rT) + == m_rVector.end(); + } +}; + +} + +void SwXReferenceMark::Impl::InsertRefMark(SwPaM& rPam, + SwXTextCursor const*const pCursor) +{ + //! in some cases when this function is called the pDoc pointer member may have become + //! invalid/deleted thus we obtain the document pointer from rPaM where it should always + //! be valid. + SwDoc& rDoc2 = rPam.GetDoc(); + + UnoActionContext aCont(&rDoc2); + SwFormatRefMark aRefMark(m_sMarkName); + bool bMark = *rPam.GetPoint() != *rPam.GetMark(); + + const bool bForceExpandHints( !bMark && pCursor && pCursor->IsAtEndOfMeta() ); + const SetAttrMode nInsertFlags = bForceExpandHints + ? ( SetAttrMode::FORCEHINTEXPAND + | SetAttrMode::DONTEXPAND) + : SetAttrMode::DONTEXPAND; + + std::vector<SwTextAttr *> oldMarks; + if (bMark) + { + oldMarks = rPam.GetPointNode().GetTextNode()->GetTextAttrsAt( + rPam.GetPoint()->GetContentIndex(), RES_TXTATR_REFMARK); + } + + rDoc2.getIDocumentContentOperations().InsertPoolItem( rPam, aRefMark, nInsertFlags ); + + if( bMark && *rPam.GetPoint() > *rPam.GetMark()) + { + rPam.Exchange(); + } + + // aRefMark was copied into the document pool; now retrieve real format... + SwTextAttr * pTextAttr(nullptr); + if (bMark) + { + // #i107672# + // ensure that we do not retrieve a different mark at the same position + std::vector<SwTextAttr *> const newMarks( + rPam.GetPointNode().GetTextNode()->GetTextAttrsAt( + rPam.GetPoint()->GetContentIndex(), RES_TXTATR_REFMARK)); + std::vector<SwTextAttr *>::const_iterator const iter( + std::find_if(newMarks.begin(), newMarks.end(), + NotContainedIn<SwTextAttr *>(oldMarks))); + assert(newMarks.end() != iter); + if (newMarks.end() != iter) + { + pTextAttr = *iter; + } + } + else + { + SwTextNode *pTextNd = rPam.GetPointNode().GetTextNode(); + assert(pTextNd); + pTextAttr = pTextNd ? rPam.GetPointNode().GetTextNode()->GetTextAttrForCharAt( + rPam.GetPoint()->GetContentIndex() - 1, RES_TXTATR_REFMARK) : nullptr; + } + + if (!pTextAttr) + { + throw uno::RuntimeException( + "SwXReferenceMark::InsertRefMark(): cannot insert attribute", nullptr); + } + + m_pMarkFormat = &pTextAttr->GetRefMark(); + EndListeningAll(); + StartListening(const_cast<SwFormatRefMark*>(m_pMarkFormat)->GetNotifier()); +} + +void SAL_CALL +SwXReferenceMark::attach(const uno::Reference< text::XTextRange > & xTextRange) +{ + SolarMutexGuard aGuard; + + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException(); + } + SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xTextRange.get()); + OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get()); + SwDoc *const pDocument = + pRange ? &pRange->GetDoc() : (pCursor ? pCursor->GetDoc() : nullptr); + if (!pDocument) + { + throw lang::IllegalArgumentException(); + } + + SwUnoInternalPaM aPam(*pDocument); + // this now needs to return TRUE + ::sw::XTextRangeToSwPaM(aPam, xTextRange); + m_pImpl->InsertRefMark(aPam, dynamic_cast<SwXTextCursor*>(pCursor)); + m_pImpl->m_bIsDescriptor = false; + m_pImpl->m_pDoc = pDocument; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXReferenceMark::getAnchor() +{ + SolarMutexGuard aGuard; + + if (m_pImpl->IsValid()) + { + SwFormatRefMark const*const pNewMark = + m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName); + if (pNewMark && SfxPoolItem::areSame(pNewMark, m_pImpl->m_pMarkFormat)) + { + SwTextRefMark const*const pTextMark = + m_pImpl->m_pMarkFormat->GetTextRefMark(); + if (pTextMark && + (&pTextMark->GetTextNode().GetNodes() == + &m_pImpl->m_pDoc->GetNodes())) + { + SwTextNode const& rTextNode = pTextMark->GetTextNode(); + std::optional<SwPaM> pPam; + if ( pTextMark->End() ) + pPam.emplace( rTextNode, *pTextMark->End(), + rTextNode, pTextMark->GetStart()); + else + pPam.emplace( rTextNode, pTextMark->GetStart()); + + return SwXTextRange::CreateXTextRange( + *m_pImpl->m_pDoc, *pPam->Start(), pPam->End()); + } + } + } + return nullptr; +} + +void SAL_CALL SwXReferenceMark::dispose() +{ + SolarMutexGuard aGuard; + if (m_pImpl->IsValid()) + { + SwFormatRefMark const*const pNewMark = + m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName); + if (pNewMark && SfxPoolItem::areSame(pNewMark, m_pImpl->m_pMarkFormat)) + { + SwTextRefMark const*const pTextMark = + m_pImpl->m_pMarkFormat->GetTextRefMark(); + if (pTextMark && + (&pTextMark->GetTextNode().GetNodes() == + &m_pImpl->m_pDoc->GetNodes())) + { + SwTextNode const& rTextNode = pTextMark->GetTextNode(); + const sal_Int32 nStt = pTextMark->GetStart(); + const sal_Int32 nEnd = pTextMark->End() + ? *pTextMark->End() + : nStt + 1; + + SwPaM aPam( rTextNode, nStt, rTextNode, nEnd ); + m_pImpl->m_pDoc->getIDocumentContentOperations().DeleteAndJoin( aPam ); + } + } + } + else if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->Invalidate(); + } +} + +void SAL_CALL SwXReferenceMark::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 SwXReferenceMark::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); +} + +OUString SAL_CALL SwXReferenceMark::getName() +{ + SolarMutexGuard aGuard; + if (!m_pImpl->IsValid() || + !m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName)) + { + throw uno::RuntimeException(); + } + return m_pImpl->m_sMarkName; +} + +void SAL_CALL SwXReferenceMark::setName(const OUString& rName) +{ + SolarMutexGuard aGuard; + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_sMarkName = rName; + } + else + { + if (!m_pImpl->IsValid() + || !m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName) + || m_pImpl->m_pDoc->GetRefMark(rName)) + { + throw uno::RuntimeException(); + } + SwFormatRefMark const*const pCurMark = + m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName); + if ((rName != m_pImpl->m_sMarkName) + && pCurMark && SfxPoolItem::areSame(pCurMark, m_pImpl->m_pMarkFormat)) + { + const UnoActionContext aCont(m_pImpl->m_pDoc); + SwTextRefMark const*const pTextMark = + m_pImpl->m_pMarkFormat->GetTextRefMark(); + if (pTextMark && + (&pTextMark->GetTextNode().GetNodes() == + &m_pImpl->m_pDoc->GetNodes())) + { + SwTextNode const& rTextNode = pTextMark->GetTextNode(); + const sal_Int32 nStt = pTextMark->GetStart(); + const sal_Int32 nEnd = pTextMark->End() + ? *pTextMark->End() + : nStt + 1; + + SwPaM aPam( rTextNode, nStt, rTextNode, nEnd ); + // deletes the m_pImpl->m_pDoc member in the SwXReferenceMark! + m_pImpl->m_pDoc->getIDocumentContentOperations().DeleteAndJoin( aPam ); + // The aPam will keep the correct and functional doc though + + m_pImpl->m_sMarkName = rName; + //create a new one + m_pImpl->InsertRefMark( aPam, nullptr ); + m_pImpl->m_pDoc = &aPam.GetDoc(); + } + } + } +} + +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXReferenceMark::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xRef = + aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH_EXTENSIONS) + ->getPropertySetInfo(); + return xRef; +} + +void SAL_CALL SwXReferenceMark::setPropertyValue( + const OUString& /*rPropertyName*/, const uno::Any& /*rValue*/ ) +{ + throw lang::IllegalArgumentException(); +} + +uno::Any SAL_CALL +SwXReferenceMark::getPropertyValue(const OUString& rPropertyName) +{ + // does not seem to need SolarMutex + uno::Any aRet; + if (! ::sw::GetDefaultTextContentValue(aRet, rPropertyName)) + { + throw beans::UnknownPropertyException(rPropertyName); + } + return aRet; +} + +void SAL_CALL SwXReferenceMark::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXReferenceMark::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL SwXReferenceMark::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXReferenceMark::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL SwXReferenceMark::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXReferenceMark::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL SwXReferenceMark::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXReferenceMark::removeVetoableChangeListener(): not implemented"); +} + +namespace { + +class SwXMetaText : public cppu::OWeakObject, public SwXText +{ +private: + SwXMeta & m_rMeta; + + virtual void PrepareForAttach(uno::Reference< text::XTextRange > & xRange, + const SwPaM & rPam) override; + + virtual bool CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb) override; + +protected: + virtual const SwStartNode *GetStartNode() const override; + +public: + SwXMetaText(SwDoc & rDoc, SwXMeta & rMeta); + + /// make available for SwXMeta + using SwXText::Invalidate; + + // XInterface + virtual void SAL_CALL acquire() noexcept override { cppu::OWeakObject::acquire(); } + virtual void SAL_CALL release() noexcept override { cppu::OWeakObject::release(); } + + // XTypeProvider + virtual uno::Sequence< sal_Int8 > SAL_CALL + getImplementationId() override; + + // XText + virtual rtl::Reference< SwXTextCursor > createXTextCursor() override; + virtual rtl::Reference< SwXTextCursor > createXTextCursorByRange( + const ::css::uno::Reference< ::css::text::XTextRange >& aTextPosition ) override; +}; + +} + +SwXMetaText::SwXMetaText(SwDoc & rDoc, SwXMeta & rMeta) + : SwXText(&rDoc, CursorType::Meta) + , m_rMeta(rMeta) +{ +} + +const SwStartNode *SwXMetaText::GetStartNode() const +{ + SwXText const * const pParent = m_rMeta.GetParentText().get(); + return pParent ? pParent->GetStartNode() : nullptr; +} + +void SwXMetaText::PrepareForAttach( uno::Reference<text::XTextRange> & xRange, + const SwPaM & rPam) +{ + // create a new cursor to prevent modifying SwXTextRange + xRange = static_cast<text::XWordCursor*>( + new SwXTextCursor(*GetDoc(), &m_rMeta, CursorType::Meta, *rPam.GetPoint(), + (rPam.HasMark()) ? rPam.GetMark() : nullptr)); +} + +bool SwXMetaText::CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb) +{ + return m_rMeta.CheckForOwnMemberMeta(rPam, bAbsorb); +} + +rtl::Reference< SwXTextCursor > SwXMetaText::createXTextCursor() +{ + rtl::Reference< SwXTextCursor > xRet; + if (IsValid()) + { + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess( + m_rMeta.SetContentRange(pTextNode, nMetaStart, nMetaEnd) ); + if (bSuccess) + { + SwPosition aPos(*pTextNode, nMetaStart); + xRet = new SwXTextCursor(*GetDoc(), &m_rMeta, CursorType::Meta, aPos); + } + } + return xRet; +} + +uno::Sequence<sal_Int8> SAL_CALL +SwXMetaText::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// XText + +rtl::Reference< SwXTextCursor > +SwXMetaText::createXTextCursorByRange( + const uno::Reference<text::XTextRange> & xTextPosition) +{ + const rtl::Reference< SwXTextCursor > xCursor( createXTextCursor() ); + xCursor->gotoRange(xTextPosition, false); + return xCursor; +} + +/** + * the Meta has a cached list of text portions for its contents + * this list is created by SwXTextPortionEnumeration + * the Meta listens at the SwTextNode and throws away the cache when it changes + * + * This inner part of SwXMeta is deleted with a locked SolarMutex. + */ +class SwXMeta::Impl : public SvtListener +{ +public: + unotools::WeakReference<SwXMeta> m_wThis; + std::mutex m_Mutex; // just for OInterfaceContainerHelper4 + ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners; + std::unique_ptr<const TextRangeList_t> m_pTextPortions; + // 3 possible states: not attached, attached, disposed + bool m_bIsDisposed; + bool m_bIsDescriptor; + css::uno::Reference<SwXText> m_xParentText; + rtl::Reference<SwXMetaText> m_xText; + sw::Meta* m_pMeta; + + Impl(SwXMeta& rThis, SwDoc& rDoc, + ::sw::Meta* const pMeta, + css::uno::Reference<SwXText> xParentText, + std::unique_ptr<TextRangeList_t const> pPortions) + : m_pTextPortions(std::move(pPortions)) + , m_bIsDisposed(false) + , m_bIsDescriptor(nullptr == pMeta) + , m_xParentText(std::move(xParentText)) + , m_xText(new SwXMetaText(rDoc, rThis)) + , m_pMeta(pMeta) + { + !m_bIsDescriptor && StartListening(m_pMeta->GetNotifier()); + } + + inline const ::sw::Meta* GetMeta() const; + // only for SwXMetaField! + inline const ::sw::MetaField* GetMetaField() const; +protected: + virtual void Notify(const SfxHint& rHint) override; + +}; + +inline const ::sw::Meta* SwXMeta::Impl::GetMeta() const +{ + return m_pMeta; +} + +// sw::BroadcastingModify +void SwXMeta::Impl::Notify(const SfxHint& rHint) +{ + m_pTextPortions.reset(); // throw away cache (SwTextNode changed) + if(rHint.GetId() != SfxHintId::Dying && rHint.GetId() != SfxHintId::Deinitializing) + return; + + m_bIsDisposed = true; + m_pMeta = nullptr; + m_xText->Invalidate(); + 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); + std::unique_lock aGuard(m_Mutex); + m_EventListeners.disposeAndClear(aGuard, ev); +} + +css::uno::Reference<SwXText> const & SwXMeta::GetParentText() const +{ + return m_pImpl->m_xParentText; +} + +SwXMeta::SwXMeta(SwDoc *const pDoc, ::sw::Meta *const pMeta, + css::uno::Reference<SwXText> const& xParentText, + std::unique_ptr<TextRangeList_t const> pPortions) + : m_pImpl( new SwXMeta::Impl(*this, *pDoc, pMeta, xParentText, std::move(pPortions)) ) +{ +} + +SwXMeta::SwXMeta(SwDoc *const pDoc) + : m_pImpl( new SwXMeta::Impl(*this, *pDoc, nullptr, nullptr, nullptr) ) +{ +} + +SwXMeta::~SwXMeta() +{ +} + +rtl::Reference<SwXMeta> +SwXMeta::CreateXMeta(SwDoc & rDoc, bool const isField) +{ + // this is why the constructor is private: need to acquire pXMeta here + rtl::Reference<SwXMeta> xMeta(isField + ? new SwXMetaField(& rDoc) : new SwXMeta(& rDoc)); + // need a permanent Reference to initialize m_wThis + xMeta->m_pImpl->m_wThis = xMeta.get(); + return xMeta; +} + +rtl::Reference<SwXMeta> +SwXMeta::CreateXMeta(::sw::Meta & rMeta, + css::uno::Reference<SwXText> i_xParent, + std::unique_ptr<TextRangeList_t const> && pPortions) +{ + // re-use existing SwXMeta + // #i105557#: do not iterate over the registered clients: race condition + rtl::Reference<SwXMeta> xMeta(rMeta.GetXMeta()); + if (xMeta.is()) + { + if (pPortions) // set cache in the XMeta to the given portions + { + // NB: the meta must always be created with the complete content + // if SwXTextPortionEnumeration is created for a selection, + // it must be checked that the Meta is contained in the selection! + xMeta->m_pImpl->m_pTextPortions = std::move(pPortions); + // ??? is this necessary? + if (xMeta->m_pImpl->m_xParentText.get() != i_xParent.get()) + { + SAL_WARN("sw.uno", "SwXMeta with different parent?"); + xMeta->m_pImpl->m_xParentText = i_xParent; + } + } + return xMeta; + } + + // create new SwXMeta + SwTextNode * const pTextNode( rMeta.GetTextNode() ); + SAL_WARN_IF(!pTextNode, "sw.uno", "CreateXMeta: no text node?"); + if (!pTextNode) { return nullptr; } + css::uno::Reference<SwXText> xParentText(i_xParent); + if (!xParentText.is()) + { + SwTextMeta * const pTextAttr( rMeta.GetTextAttr() ); + SAL_WARN_IF(!pTextAttr, "sw.uno", "CreateXMeta: no text attr?"); + if (!pTextAttr) { return nullptr; } + const SwPosition aPos(*pTextNode, pTextAttr->GetStart()); + xParentText = ::sw::CreateParentXText(pTextNode->GetDoc(), aPos); + } + if (!xParentText.is()) { return nullptr; } + // this is why the constructor is private: need to acquire pXMeta here + xMeta = (RES_TXTATR_META == rMeta.GetFormatMeta()->Which()) + ? new SwXMeta (&pTextNode->GetDoc(), &rMeta, xParentText, + std::move(pPortions)) + : new SwXMetaField(&pTextNode->GetDoc(), &rMeta, xParentText, + std::move(pPortions)); + // in order to initialize the weak pointer cache in the core object + rMeta.SetXMeta(xMeta); + // need a permanent Reference to initialize m_wThis + xMeta->m_pImpl->m_wThis = xMeta.get(); + return xMeta; +} + +bool SwXMeta::SetContentRange( + SwTextNode *& rpNode, sal_Int32 & rStart, sal_Int32 & rEnd ) const +{ + ::sw::Meta const * const pMeta( m_pImpl->GetMeta() ); + if (pMeta) + { + SwTextMeta const * const pTextAttr( pMeta->GetTextAttr() ); + if (pTextAttr) + { + rpNode = pMeta->GetTextNode(); + if (rpNode) + { + // rStart points at the first position _within_ the meta! + rStart = pTextAttr->GetStart() + 1; + rEnd = *pTextAttr->End(); + return true; + } + } + } + return false; +} + +bool SwXMeta::CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb) +{ + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess( SetContentRange(pTextNode, nMetaStart, nMetaEnd) ); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) + throw lang::DisposedException(); + + SwPosition const * const pStartPos( rPam.Start() ); + if (&pStartPos->GetNode() != pTextNode) + { + throw lang::IllegalArgumentException( + "trying to insert into a nesting text content, but start " + "of text range not in same paragraph as text content", + nullptr, 0); + } + bool bForceExpandHints(false); + const sal_Int32 nStartPos(pStartPos->GetContentIndex()); + // not <= but < because nMetaStart is behind dummy char! + // not >= but > because == means insert at end! + if ((nStartPos < nMetaStart) || (nStartPos > nMetaEnd)) + { + throw lang::IllegalArgumentException( + "trying to insert into a nesting text content, but start " + "of text range not inside text content", + nullptr, 0); + } + else if (nStartPos == nMetaEnd) + { + bForceExpandHints = true; + } + if (rPam.HasMark() && bAbsorb) + { + SwPosition const * const pEndPos( rPam.End() ); + if (&pEndPos->GetNode() != pTextNode) + { + throw lang::IllegalArgumentException( + "trying to insert into a nesting text content, but end " + "of text range not in same paragraph as text content", + nullptr, 0); + } + const sal_Int32 nEndPos(pEndPos->GetContentIndex()); + // not <= but < because nMetaStart is behind dummy char! + // not >= but > because == means insert at end! + if ((nEndPos < nMetaStart) || (nEndPos > nMetaEnd)) + { + throw lang::IllegalArgumentException( + "trying to insert into a nesting text content, but end " + "of text range not inside text content", + nullptr, 0); + } + else if (nEndPos == nMetaEnd) + { + bForceExpandHints = true; + } + } + return bForceExpandHints; +} + +// XServiceInfo +OUString SAL_CALL +SwXMeta::getImplementationName() +{ + return "SwXMeta"; +} + +sal_Bool SAL_CALL +SwXMeta::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXMeta::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.InContentMetadata" + }; +} + +// XComponent +void SAL_CALL +SwXMeta::addEventListener( + uno::Reference< lang::XEventListener> const & 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 +SwXMeta::removeEventListener( + uno::Reference< lang::XEventListener> const & 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); +} + +void SAL_CALL +SwXMeta::dispose() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_pTextPortions.reset(); + lang::EventObject const ev(getXWeak()); + std::unique_lock aGuard(m_pImpl->m_Mutex); + m_pImpl->m_EventListeners.disposeAndClear(aGuard, ev); + m_pImpl->m_bIsDisposed = true; + m_pImpl->m_xText->Invalidate(); + } + else if (!m_pImpl->m_bIsDisposed) + { + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess(SetContentRange(pTextNode, nMetaStart, nMetaEnd)); + OSL_ENSURE(bSuccess, "no pam?"); + if (bSuccess) + { + // -1 because of CH_TXTATR + SwPaM aPam( *pTextNode, nMetaStart - 1, *pTextNode, nMetaEnd ); + SwDoc& rDoc( pTextNode->GetDoc() ); + rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); + + // removal should call Modify and do the dispose + assert(m_pImpl->m_bIsDisposed); + } + } +} + +void +SwXMeta::AttachImpl(const uno::Reference< text::XTextRange > & i_xTextRange, + const sal_uInt16 i_nWhich) +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (!m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException( + "SwXMeta::attach(): already attached", + getXWeak()); + } + + SwXTextRange *const pRange(dynamic_cast<SwXTextRange*>(i_xTextRange.get())); + OTextCursorHelper *const pCursor(dynamic_cast<OTextCursorHelper*>(i_xTextRange.get())); + if (!pRange && !pCursor) + { + throw lang::IllegalArgumentException( + "SwXMeta::attach(): argument not supported type", + getXWeak(), 0); + } + + SwDoc * const pDoc( + pRange ? &pRange->GetDoc() : pCursor->GetDoc()); + if (!pDoc) + { + throw lang::IllegalArgumentException( + "SwXMeta::attach(): argument has no SwDoc", + getXWeak(), 0); + } + + SwUnoInternalPaM aPam(*pDoc); + ::sw::XTextRangeToSwPaM(aPam, i_xTextRange); + + UnoActionContext aContext(pDoc); + + SwXTextCursor const*const pTextCursor( + dynamic_cast<SwXTextCursor*>(pCursor)); + const bool bForceExpandHints(pTextCursor && pTextCursor->IsAtEndOfMeta()); + const SetAttrMode nInsertFlags( bForceExpandHints + ? ( SetAttrMode::FORCEHINTEXPAND + | SetAttrMode::DONTEXPAND) + : SetAttrMode::DONTEXPAND ); + + const std::shared_ptr< ::sw::Meta> pMeta( (RES_TXTATR_META == i_nWhich) + ? std::make_shared< ::sw::Meta>( nullptr ) + : std::shared_ptr< ::sw::Meta>( + pDoc->GetMetaFieldManager().makeMetaField()) ); + SwFormatMeta meta(pMeta, i_nWhich); // this is cloned by Insert! + const bool bSuccess( pDoc->getIDocumentContentOperations().InsertPoolItem( aPam, meta, nInsertFlags ) ); + SwTextAttr * const pTextAttr( pMeta->GetTextAttr() ); + if (!bSuccess) + { + throw lang::IllegalArgumentException( + "SwXMeta::attach(): cannot create meta: range invalid?", + getXWeak(), 1); + } + if (!pTextAttr) + { + OSL_FAIL("meta inserted, but has no text attribute?"); + throw uno::RuntimeException( + "SwXMeta::attach(): cannot create meta", + getXWeak()); + } + + m_pImpl->EndListeningAll(); + m_pImpl->m_pMeta = pMeta.get(); + m_pImpl->StartListening(pMeta->GetNotifier()); + pMeta->SetXMeta(this); + + m_pImpl->m_xParentText = ::sw::CreateParentXText(*pDoc, *aPam.GetPoint()); + + m_pImpl->m_bIsDescriptor = false; +} + +// XTextContent +void SAL_CALL +SwXMeta::attach(const uno::Reference< text::XTextRange > & i_xTextRange) +{ + return SwXMeta::AttachImpl(i_xTextRange, RES_TXTATR_META); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXMeta::getAnchor() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException( + "SwXMeta::getAnchor(): not inserted", + getXWeak()); + } + + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess(SetContentRange(pTextNode, nMetaStart, nMetaEnd)); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) + { + throw lang::DisposedException( + "SwXMeta::getAnchor(): not attached", + getXWeak()); + } + + const SwPosition start(*pTextNode, nMetaStart - 1); // -1 due to CH_TXTATR + const SwPosition end(*pTextNode, nMetaEnd); + return SwXTextRange::CreateXTextRange(pTextNode->GetDoc(), start, &end); +} + +// XTextRange +uno::Reference< text::XText > SAL_CALL +SwXMeta::getText() +{ + return this; +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXMeta::getStart() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getStart(); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXMeta::getEnd() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getEnd(); +} + +OUString SAL_CALL +SwXMeta::getString() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->getString(); +} + +void SAL_CALL +SwXMeta::setString(const OUString& rString) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->setString(rString); +} + +// XSimpleText +uno::Reference< text::XTextCursor > SAL_CALL +SwXMeta::createTextCursor() +{ + SolarMutexGuard g; + return m_pImpl->m_xText->createTextCursor(); +} + +uno::Reference< text::XTextCursor > SAL_CALL +SwXMeta::createTextCursorByRange( + const uno::Reference<text::XTextRange> & xTextPosition) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->createTextCursorByRange(xTextPosition); +} + +void SAL_CALL +SwXMeta::insertString(const uno::Reference<text::XTextRange> & xRange, + const OUString& rString, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertString(xRange, rString, bAbsorb); +} + +void SAL_CALL +SwXMeta::insertControlCharacter(const uno::Reference<text::XTextRange> & xRange, + sal_Int16 nControlCharacter, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertControlCharacter(xRange, nControlCharacter, + bAbsorb); +} + +// XText +void SAL_CALL +SwXMeta::insertTextContent( const uno::Reference<text::XTextRange> & xRange, + const uno::Reference<text::XTextContent> & xContent, sal_Bool bAbsorb) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->insertTextContent(xRange, xContent, bAbsorb); +} + +void SAL_CALL +SwXMeta::removeTextContent( + const uno::Reference< text::XTextContent > & xContent) +{ + SolarMutexGuard g; + return m_pImpl->m_xText->removeTextContent(xContent); +} + +// XChild +uno::Reference< uno::XInterface > SAL_CALL +SwXMeta::getParent() +{ + SolarMutexGuard g; + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + bool const bSuccess( SetContentRange(pTextNode, nMetaStart, nMetaEnd) ); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) { throw lang::DisposedException(); } + // in order to prevent getting this meta, subtract 1 from nMetaStart; + // so we get the index of the dummy character, and we exclude it + // by calling GetTextAttrAt(_, _, PARENT) in GetNestedTextContent + uno::Reference<text::XTextContent> const xRet( + SwUnoCursorHelper::GetNestedTextContent(*pTextNode, nMetaStart - 1, + true) ); + return xRet; +} + +void SAL_CALL +SwXMeta::setParent(uno::Reference< uno::XInterface > const& /*xParent*/) +{ + throw lang::NoSupportException("setting parent not supported", *this); +} + +// XElementAccess +uno::Type SAL_CALL +SwXMeta::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SwXMeta::hasElements() +{ + SolarMutexGuard g; + return m_pImpl->m_pMeta != nullptr; +} + +// XEnumerationAccess +uno::Reference< container::XEnumeration > SAL_CALL +SwXMeta::createEnumeration() +{ + SolarMutexGuard g; + + if (m_pImpl->m_bIsDisposed) + { + throw lang::DisposedException(); + } + if (m_pImpl->m_bIsDescriptor) + { + throw uno::RuntimeException( + "createEnumeration(): not inserted", + getXWeak()); + } + + SwTextNode * pTextNode; + sal_Int32 nMetaStart; + sal_Int32 nMetaEnd; + const bool bSuccess(SetContentRange(pTextNode, nMetaStart, nMetaEnd)); + OSL_ENSURE(bSuccess, "no pam?"); + if (!bSuccess) + throw lang::DisposedException(); + + SwPaM aPam(*pTextNode, nMetaStart); + + if (!m_pImpl->m_pTextPortions) + { + return new SwXTextPortionEnumeration( + aPam, GetParentText(), nMetaStart, nMetaEnd); + } + else // cached! + { + return new SwXTextPortionEnumeration(aPam, std::deque(*m_pImpl->m_pTextPortions)); + } +} + +// MetadatableMixin +::sfx2::Metadatable* SwXMeta::GetCoreObject() +{ + return const_cast< ::sw::Meta * >(m_pImpl->GetMeta()); +} + +uno::Reference<frame::XModel> SwXMeta::GetModel() +{ + ::sw::Meta const * const pMeta( m_pImpl->GetMeta() ); + if (pMeta) + { + SwTextNode const * const pTextNode( pMeta->GetTextNode() ); + if (pTextNode) + { + SwDocShell const * const pShell(pTextNode->GetDoc().GetDocShell()); + return pShell ? pShell->GetModel() : nullptr; + } + } + return nullptr; +} + +inline const ::sw::MetaField* SwXMeta::Impl::GetMetaField() const +{ + return dynamic_cast<sw::MetaField*>(m_pMeta); +} + +SwXMetaField::SwXMetaField(SwDoc *const pDoc, ::sw::Meta *const pMeta, + css::uno::Reference<SwXText> const& xParentText, + std::unique_ptr<TextRangeList_t const> pPortions) + : SwXMetaField_Base(pDoc, pMeta, xParentText, std::move(pPortions)) +{ + assert(dynamic_cast< ::sw::MetaField* >(pMeta) && "SwXMetaField created for wrong hint!"); +} + +SwXMetaField::SwXMetaField(SwDoc *const pDoc) + : SwXMetaField_Base(pDoc) +{ +} + +SwXMetaField::~SwXMetaField() +{ +} + +// XServiceInfo +OUString SAL_CALL +SwXMetaField::getImplementationName() +{ + return "SwXMetaField"; +} + +sal_Bool SAL_CALL +SwXMetaField::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL +SwXMetaField::getSupportedServiceNames() +{ + return { + "com.sun.star.text.TextContent", + "com.sun.star.text.TextField", + "com.sun.star.text.textfield.MetadataField" + }; +} + +// XComponent +void SAL_CALL +SwXMetaField::addEventListener( + uno::Reference< lang::XEventListener> const & xListener ) +{ + return SwXMeta::addEventListener(xListener); +} + +void SAL_CALL +SwXMetaField::removeEventListener( + uno::Reference< lang::XEventListener> const & xListener ) +{ + return SwXMeta::removeEventListener(xListener); +} + +void SAL_CALL +SwXMetaField::dispose() +{ + return SwXMeta::dispose(); +} + +// XTextContent +void SAL_CALL +SwXMetaField::attach(const uno::Reference< text::XTextRange > & i_xTextRange) +{ + return SwXMeta::AttachImpl(i_xTextRange, RES_TXTATR_METAFIELD); +} + +uno::Reference< text::XTextRange > SAL_CALL +SwXMetaField::getAnchor() +{ + return SwXMeta::getAnchor(); +} + +// XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXMetaField::getPropertySetInfo() +{ + SolarMutexGuard g; + + static uno::Reference< beans::XPropertySetInfo > xRef( + aSwMapProvider.GetPropertySet(PROPERTY_MAP_METAFIELD) + ->getPropertySetInfo() ); + return xRef; +} + +void SAL_CALL +SwXMetaField::setPropertyValue( + const OUString& rPropertyName, const uno::Any& rValue) +{ + SolarMutexGuard g; + + ::sw::MetaField * const pMeta( + const_cast< ::sw::MetaField * >(m_pImpl->GetMetaField()) ); + if (!pMeta) + throw lang::DisposedException(); + + if ( rPropertyName == "NumberFormat" ) + { + sal_Int32 nNumberFormat(0); + if (rValue >>= nNumberFormat) + { + pMeta->SetNumberFormat(static_cast<sal_uInt32>(nNumberFormat)); + } + } + else if ( rPropertyName == "IsFixedLanguage" ) + { + bool b(false); + if (rValue >>= b) + { + pMeta->SetIsFixedLanguage(b); + } + } + else + { + throw beans::UnknownPropertyException(rPropertyName); + } +} + +uno::Any SAL_CALL +SwXMetaField::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard g; + + ::sw::MetaField const * const pMeta( m_pImpl->GetMetaField() ); + if (!pMeta) + throw lang::DisposedException(); + + uno::Any any; + + if ( rPropertyName == "NumberFormat" ) + { + const OUString text( getPresentation(false) ); + any <<= static_cast<sal_Int32>(pMeta->GetNumberFormat(text)); + } + else if ( rPropertyName == "IsFixedLanguage" ) + { + any <<= pMeta->IsFixedLanguage(); + } + else + { + throw beans::UnknownPropertyException(rPropertyName); + } + + return any; +} + +void SAL_CALL +SwXMetaField::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXMetaField::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXMetaField::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXMetaField::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXMetaField::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXMetaField::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXMetaField::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + OSL_FAIL("SwXMetaField::removeVetoableChangeListener(): not implemented"); +} + +static uno::Reference<rdf::XURI> const& +lcl_getURI(const sal_Int16 eKnown) +{ + static uno::Reference< uno::XComponentContext > xContext( + ::comphelper::getProcessComponentContext()); + static uno::Reference< rdf::XURI > xOdfPrefix( + rdf::URI::createKnown(xContext, rdf::URIs::ODF_PREFIX), + uno::UNO_SET_THROW); + static uno::Reference< rdf::XURI > xOdfSuffix( + rdf::URI::createKnown(xContext, rdf::URIs::ODF_SUFFIX), + uno::UNO_SET_THROW); + static uno::Reference< rdf::XURI > xOdfShading( + rdf::URI::createKnown(xContext, rdf::URIs::LO_EXT_SHADING), + uno::UNO_SET_THROW); + switch (eKnown) + { + case rdf::URIs::ODF_PREFIX: + return xOdfPrefix; + case rdf::URIs::ODF_SUFFIX: + return xOdfSuffix; + default: + return xOdfShading; + } +} + +static OUString +lcl_getPrefixOrSuffix( + uno::Reference<rdf::XRepository> const & xRepository, + uno::Reference<rdf::XResource> const & xMetaField, + uno::Reference<rdf::XURI> const & xPredicate) +{ + const uno::Reference<container::XEnumeration> xEnum( + xRepository->getStatements(xMetaField, xPredicate, nullptr), + uno::UNO_SET_THROW); + while (xEnum->hasMoreElements()) { + rdf::Statement stmt; + if (!(xEnum->nextElement() >>= stmt)) { + throw uno::RuntimeException(); + } + const uno::Reference<rdf::XLiteral> xObject(stmt.Object, + uno::UNO_QUERY); + if (!xObject.is()) continue; + if (xEnum->hasMoreElements()) { + SAL_INFO("sw.uno", "ignoring other odf:Prefix/odf:Suffix statements"); + } + return xObject->getValue(); + } + return OUString(); +} + +void +getPrefixAndSuffix( + const uno::Reference<frame::XModel>& xModel, + const uno::Reference<rdf::XMetadatable>& xMetaField, + OUString *const o_pPrefix, OUString *const o_pSuffix, OUString *const o_pShadingColor) +{ + try { + const uno::Reference<rdf::XRepositorySupplier> xRS( + xModel, uno::UNO_QUERY_THROW); + const uno::Reference<rdf::XRepository> xRepo( + xRS->getRDFRepository(), uno::UNO_SET_THROW); + const uno::Reference<rdf::XResource> xMeta( + xMetaField, uno::UNO_QUERY_THROW); + if (o_pPrefix) + { + *o_pPrefix = lcl_getPrefixOrSuffix(xRepo, xMeta, lcl_getURI(rdf::URIs::ODF_PREFIX)); + } + if (o_pSuffix) + { + *o_pSuffix = lcl_getPrefixOrSuffix(xRepo, xMeta, lcl_getURI(rdf::URIs::ODF_SUFFIX)); + } + if (o_pShadingColor) + { + *o_pShadingColor = lcl_getPrefixOrSuffix(xRepo, xMeta, lcl_getURI(rdf::URIs::LO_EXT_SHADING)); + } + } catch (uno::RuntimeException &) { + throw; + } catch (const uno::Exception &) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("getPrefixAndSuffix: exception", nullptr, anyEx); + } +} + +// XTextField +OUString SAL_CALL +SwXMetaField::getPresentation(sal_Bool bShowCommand) +{ + SolarMutexGuard g; + + if (bShowCommand) + { +//FIXME ? + return OUString(); + } + else + { + // getString should check if this is invalid + const OUString content( getString() ); + OUString prefix; + OUString suffix; + getPrefixAndSuffix(GetModel(), this, &prefix, &suffix, nullptr); + return prefix + content + suffix; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |