summaryrefslogtreecommitdiffstats
path: root/sw/source/core/unocore/unorefmk.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/unocore/unorefmk.cxx
parentInitial commit. (diff)
downloadlibreoffice-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.cxx1475
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: */