Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/source/core/unocore/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 43 kB image not shown  

Quelle  unorefmk.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <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:
    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;
    SwMarkName m_sMarkName;

    Impl(SwDoc* const pDoc, SwFormatRefMark* const pRefMark)
        : m_bIsDescriptor(nullptr == pRefMark)
        , m_pDoc(pDoc)
        , m_pMarkFormat(pRefMark)
    {
        if (pRefMark)
        {
            m_sMarkName = pRefMark->GetRefName();
        }
    }

    bool IsValid() const { return m_pMarkFormat; }
    void InsertRefMark( SwPaM & rPam, SwXTextCursor const*const pCursor );
    void Invalidate();
};

void SwXReferenceMark::Impl::Invalidate()
{
    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::OnFormatRefMarkDeleted()
{
    m_pImpl->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 u"SwXReferenceMark"_ustr;
}

sal_Bool SAL_CALL
SwXReferenceMark::supportsService(const OUString& rServiceName)
{
    return cppu::supportsService(this, rServiceName);
}

uno::Sequence< OUString > SAL_CALL
SwXReferenceMark::getSupportedServiceNames()
{
    return {
        u"com.sun.star.text.TextContent"_ustr,
        u"com.sun.star.text.ReferenceMark"_ustr
    };
}

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(
            u"SwXReferenceMark::InsertRefMark(): cannot insert attribute"_ustr, nullptr);
    }

    m_pMarkFormat = &pTextAttr->GetRefMark();
    const_cast<SwFormatRefMark*>(m_pMarkFormat)->SetXRefMark(m_wThis.get());
}

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.toString();
}

void SAL_CALL SwXReferenceMark::setName(const OUString& rName)
{
    SolarMutexGuard aGuard;
    if (m_pImpl->m_bIsDescriptor)
    {
        m_pImpl->m_sMarkName = SwMarkName(rName);
    }
    else
    {
        if (!m_pImpl->IsValid()
            || !m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName)
            || m_pImpl->m_pDoc->GetRefMark(SwMarkName(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 = SwMarkName(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,
            const 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(
            u"trying to insert into a nesting text content, but start "
                "of text range not in same paragraph as text content"_ustr,
                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(
            u"trying to insert into a nesting text content, but start "
                "of text range not inside text content"_ustr,
                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(
                u"trying to insert into a nesting text content, but end "
                    "of text range not in same paragraph as text content"_ustr,
                    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(
                u"trying to insert into a nesting text content, but end "
                    "of text range not inside text content"_ustr,
                    nullptr, 0);
        }
        else if (nEndPos == nMetaEnd)
        {
            bForceExpandHints = true;
        }
    }
    return bForceExpandHints;
}

// XServiceInfo
OUString SAL_CALL
SwXMeta::getImplementationName()
{
    return u"SwXMeta"_ustr;
}

sal_Bool SAL_CALL
SwXMeta::supportsService(const OUString& rServiceName)
{
    return cppu::supportsService(this, rServiceName);
}

uno::Sequence< OUString > SAL_CALL
SwXMeta::getSupportedServiceNames()
{
    return {
        u"com.sun.star.text.TextContent"_ustr,
        u"com.sun.star.text.InContentMetadata"_ustr
    };
}

// 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(
            u"SwXMeta::attach(): already attached"_ustr,
            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(
            u"SwXMeta::attach(): argument not supported type"_ustr,
            getXWeak(), 0);
    }

    SwDoc * const pDoc(
            pRange ? &pRange->GetDoc() : pCursor->GetDoc());
    if (!pDoc)
    {
        throw lang::IllegalArgumentException(
            u"SwXMeta::attach(): argument has no SwDoc"_ustr,
            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(
            u"SwXMeta::attach(): cannot create meta: range invalid?"_ustr,
            getXWeak(), 1);
    }
    if (!pTextAttr)
    {
        OSL_FAIL("meta inserted, but has no text attribute?");
        throw uno::RuntimeException(
            u"SwXMeta::attach(): cannot create meta"_ustr,
            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(
                u"SwXMeta::getAnchor(): not inserted"_ustr,
                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(
                u"SwXMeta::getAnchor(): not attached"_ustr,
                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(u"setting parent not supported"_ustr, *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(
                u"createEnumeration(): not inserted"_ustr,
                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 u"SwXMetaField"_ustr;
}

sal_Bool SAL_CALL
SwXMetaField::supportsService(const OUString& rServiceName)
{
    return cppu::supportsService(this, rServiceName);
}

uno::Sequence< OUString > SAL_CALL
SwXMetaField::getSupportedServiceNames()
{
    return {
        u"com.sun.star.text.TextContent"_ustr,
        u"com.sun.star.text.TextField"_ustr,
        u"com.sun.star.text.textfield.MetadataField"_ustr
    };
}

// 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(u"getPrefixAndSuffix: exception"_ustr, 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: */

Messung V0.5
C=93 H=98 G=95

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.