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 96 kB image not shown  

Quelle  unoobj.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 <com/sun/star/table/TableSortField.hpp>
#include <cppuhelper/exc_hlp.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <svl/itemprop.hxx>
#include <o3tl/any.hxx>
#include <o3tl/safeint.hxx>
#include <osl/endian.h>
#include <unotools/collatorwrapper.hxx>
#include <editeng/memberids.h>

#include <autostyle_helper.hxx>
#include <swtypes.hxx>
#include <hintids.hxx>
#include <cmdid.h>
#include <unomid.h>
#include <hints.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <istyleaccess.hxx>
#include <ndtxt.hxx>
#include <unocrsr.hxx>
#include <unocrsrhelper.hxx>
#include <unoport.hxx>
#include <swundo.hxx>
#include <rootfrm.hxx>
#include <paratr.hxx>
#include <pam.hxx>
#include <shellio.hxx>
#include <unotbl.hxx>
#include <fmtruby.hxx>
#include <docsh.hxx>
#include <docstyle.hxx>
#include <fmtpdsc.hxx>
#include <pagedesc.hxx>
#include <edimp.hxx>
#include <fchrfmt.hxx>
#include <fmtautofmt.hxx>
#include <unotextrange.hxx>
#include <unotextcursor.hxx>
#include <unomap.hxx>
#include <unoprnms.hxx>
#include <unometa.hxx>
#include <unocontentcontrol.hxx>
#include <unotext.hxx>
#include <com/sun/star/text/TextMarkupType.hpp>
#include <utility>
#include <vcl/svapp.hxx>
#include <unotools/syslocale.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <SwStyleNameMapper.hxx>
#include <sortopt.hxx>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/i18n/WordType.hpp>
#include <memory>
#include <unoparaframeenum.hxx>
#include <unoparagraph.hxx>
#include <iodetect.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/servicehelper.hxx>
#include <comphelper/profilezone.hxx>
#include <comphelper/flagguard.hxx>
#include <swmodule.hxx>
#include <names.hxx>

using namespace ::com::sun::star;

// Helper classes
SwUnoInternalPaM::SwUnoInternalPaM(SwDoc& rDoc) :
    SwPaM(rDoc.GetNodes())
{
}

SwUnoInternalPaM::~SwUnoInternalPaM()
{
    while( GetNext() != this)
    {
        // coverity[deref_arg] - the delete moves a new entry into GetNext()
        delete GetNext();
    }
}

SwUnoInternalPaM&   SwUnoInternalPaM::operator=(const SwPaM& rPaM)
{
    const SwPaM* pTmp = &rPaM;
    *GetPoint() = *rPaM.GetPoint();
    if(rPaM.HasMark())
    {
        SetMark();
        *GetMark() = *rPaM.GetMark();
    }
    else
        DeleteMark();
    while(&rPaM != (pTmp = pTmp->GetNext()))
    {
        if(pTmp->HasMark())
            new SwPaM(*pTmp->GetMark(), *pTmp->GetPoint(), this);
        else
            new SwPaM(*pTmp->GetPoint(), this);
    }
    return *this;
}

void SwUnoCursorHelper::SelectPam(SwPaM & rPam, const bool bExpand)
{
    if (bExpand)
    {
        if (!rPam.HasMark())
        {
            rPam.SetMark();
        }
    }
    else if (rPam.HasMark())
    {
        rPam.DeleteMark();
    }
}

void SwUnoCursorHelper::GetTextFromPam(SwPaM & rPam, OUString & rBuffer,
        SwRootFrame const*const pLayout)
{
    if (!rPam.HasMark())
    {
        return;
    }
    SvMemoryStream aStream;
#ifdef OSL_BIGENDIAN
    aStream.SetEndian( SvStreamEndian::BIG );
#else
    aStream.SetEndian( SvStreamEndian::LITTLE );
#endif
    WriterRef xWrt;
    // TODO/MBA: looks like a BaseURL doesn't make sense here
    SwReaderWriter::GetWriter( FILTER_TEXT_DLG, OUString(), xWrt );
    if( !xWrt.is() )
        return;

    SwWriter aWriter( aStream, rPam );
    xWrt->m_bASCII_NoLastLineEnd = true;
    xWrt->m_bExportParagraphNumbering = false;
    SwAsciiOptions aOpt = xWrt->GetAsciiOptions();
    aOpt.SetCharSet( RTL_TEXTENCODING_UNICODE );
    xWrt->SetAsciiOptions( aOpt );
    xWrt->m_bUCS2_WithStartChar = false;
    // #i68522#
    const bool bOldShowProgress = xWrt->m_bShowProgress;
    xWrt->m_bShowProgress = false;
    xWrt->m_bHideDeleteRedlines = pLayout && pLayout->IsHideRedlines();
    // tdf#155951 SwWriter::Write calls EndAllAction, and that
    // called SelectShell(), triggering selection change event, which
    // resulted infinite recursion, if selectionChanged() calls
    // XTextRange::getString() e.g. on the selected range.
    ::comphelper::FlagRestorationGuard g(g_bNoInterrupt, true);

    if( ! aWriter.Write( xWrt ).IsError() )
    {
        const sal_uInt64 lUniLen = aStream.GetSize()/sizeof( sal_Unicode );
        if (lUniLen < o3tl::make_unsigned(SAL_MAX_INT32-1))
        {
            aStream.WriteUInt16( '\0' );

            aStream.Seek( 0 );
            aStream.ResetError();

            rtl_uString *pStr = rtl_uString_alloc(lUniLen);
            aStream.ReadBytes(pStr->buffer, lUniLen * sizeof(sal_Unicode));
            rBuffer = OUString(pStr, SAL_NO_ACQUIRE);
        }
    }
    xWrt->m_bShowProgress = bOldShowProgress;

}

namespace SwUnoCursorHelper
{
/// @throws lang::IllegalArgumentException
/// @throws uno::RuntimeException
void
SetCharStyle(SwDoc& rDoc, const uno::Any & rValue, SfxItemSet & rSet)
{
    SwDocShell *const pDocSh = rDoc.GetDocShell();
    if(!pDocSh)
        return;

    OUString uStyle;
    if (!(rValue >>= uStyle))
    {
        throw lang::IllegalArgumentException();
    }
    UIName sStyle;
    SwStyleNameMapper::FillUIName(ProgName(uStyle), sStyle,
            SwGetPoolIdFromName::ChrFmt);
    SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>(
        pDocSh->GetStyleSheetPool()->Find(sStyle.toString(), SfxStyleFamily::Char));
    if (!pStyle)
    {
        throw lang::IllegalArgumentException();
    }
    const SwFormatCharFormat aFormat(pStyle->GetCharFormat());
    rSet.Put(aFormat);
};
}

/// @throws lang::IllegalArgumentException
static void
lcl_setAutoStyle(IStyleAccess & rStyleAccess, const uno::Any & rValue,
        SfxItemSet & rSet, const bool bPara)
{
    OUString uStyle;
    if (!(rValue >>= uStyle))
    {
         throw lang::IllegalArgumentException();
    }
    std::shared_ptr<SfxItemSet> pStyle = bPara ?
        rStyleAccess.getByName(uStyle, IStyleAccess::AUTO_STYLE_PARA ):
        rStyleAccess.getByName(uStyle, IStyleAccess::AUTO_STYLE_CHAR );
    if(!pStyle)
    {
         throw lang::IllegalArgumentException();
    }

    SwFormatAutoFormat aFormat( bPara
        ? sal::static_int_cast< sal_uInt16 >(RES_AUTO_STYLE)
        : sal::static_int_cast< sal_uInt16 >(RES_TXTATR_AUTOFMT) );
    aFormat.SetStyleHandle( pStyle );
    rSet.Put(aFormat);
};

void
SwUnoCursorHelper::SetTextFormatColl(const uno::Any & rAny, SwPaM & rPaM)
{
    SwDoc& rDoc = rPaM.GetDoc();
    SwDocShell *const pDocSh = rDoc.GetDocShell();
    if(!pDocSh)
        return;
    OUString uStyle;
    rAny >>= uStyle;
    UIName sStyle;
    SwStyleNameMapper::FillUIName(ProgName(uStyle), sStyle,
            SwGetPoolIdFromName::TxtColl );
    SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>(
            pDocSh->GetStyleSheetPool()->Find(sStyle.toString(), SfxStyleFamily::Para));
    if (!pStyle)
    {
        throw lang::IllegalArgumentException();
    }

    SwTextFormatColl *const pLocal = pStyle->GetCollection();
    UnoActionContext aAction(&rDoc);
    rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
    SwPaM *pTmpCursor = &rPaM;
    do {
        rDoc.SetTextFormatColl(*pTmpCursor, pLocal);
        pTmpCursor = pTmpCursor->GetNext();
    } while ( pTmpCursor != &rPaM );
    rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
}

bool
SwUnoCursorHelper::SetPageDesc(
        const uno::Any& rValue, SwDoc & rDoc, SfxItemSet & rSet)
{
    OUString uDescName;
    if (!(rValue >>= uDescName))
    {
        return false;
    }
    std::unique_ptr<SwFormatPageDesc> pNewDesc;
    if(const SwFormatPageDesc* pItem = rSet.GetItemIfSet( RES_PAGEDESC ))
    {
        pNewDesc.reset(new SwFormatPageDesc(*pItem));
    }
    if (!pNewDesc)
    {
        pNewDesc.reset(new SwFormatPageDesc());
    }
    UIName sDescName;
    SwStyleNameMapper::FillUIName(ProgName(uDescName), sDescName,
            SwGetPoolIdFromName::PageDesc);
    if (!pNewDesc->GetPageDesc() ||
        (pNewDesc->GetPageDesc()->GetName() != sDescName))
    {
        bool bPut = false;
        if (!sDescName.isEmpty())
        {
            SwPageDesc *const pPageDesc = SwPageDesc::GetByName(rDoc, sDescName);
            if (!pPageDesc)
            {
                throw lang::IllegalArgumentException();
            }
            pNewDesc->RegisterToPageDesc(*pPageDesc);
            bPut = true;
        }
        if(!bPut)
        {
            rSet.ClearItem(RES_BREAK);
            rSet.Put(SwFormatPageDesc());
        }
        else
        {
            rSet.Put(std::move(pNewDesc));
        }
    }
    return true;
}

static void
lcl_SetNodeNumStart(SwPaM & rCursor, uno::Any const& rValue)
{
    sal_Int16 nTmp = 1;
    rValue >>= nTmp;
    sal_uInt16 nStt = (nTmp < 0 ? USHRT_MAX : o3tl::narrowing<sal_uInt16>(nTmp));
    SwDoc& rDoc = rCursor.GetDoc();
    UnoActionContext aAction(&rDoc);

    if( rCursor.GetNext() != &rCursor )         // MultiSelection?
    {
        rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
        SwPamRanges aRangeArr( rCursor );
        SwPaM aPam( *rCursor.GetPoint() );
        for( size_t n = 0; n < aRangeArr.Count(); ++n )
        {
          rDoc.SetNumRuleStart(*aRangeArr.SetPam( n, aPam ).GetPoint());
          rDoc.SetNodeNumStart(*aRangeArr.SetPam( n, aPam ).GetPoint(),
                    nStt );
        }
        rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
    }
    else
    {
        rDoc.SetNumRuleStart( *rCursor.GetPoint());
        rDoc.SetNodeNumStart( *rCursor.GetPoint(), nStt );
    }
}

static bool
lcl_setCharFormatSequence(SwPaM & rPam, uno::Any const& rValue)
{
    uno::Sequence<OUString> aCharStyles;
    if (!(rValue >>= aCharStyles))
    {
        return false;
    }

    for (sal_Int32 nStyle = 0; nStyle < aCharStyles.getLength(); nStyle++)
    {
        uno::Any aStyle;
        rPam.GetDoc().GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr);
        aStyle <<= aCharStyles.getConstArray()[nStyle];
        // create a local set and apply each format directly
        SfxItemSetFixed<RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT> aSet(rPam.GetDoc().GetAttrPool());
        SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), aStyle, aSet);
        // the first style should replace the current attributes,
        // all other have to be added
        SwUnoCursorHelper::SetCursorAttr(rPam, aSet, nStyle
                ? SetAttrMode::DONTREPLACE
                : SetAttrMode::DEFAULT);
        rPam.GetDoc().GetIDocumentUndoRedo().EndUndo(SwUndoId::START, nullptr);
    }
    return true;
}

static void
lcl_setDropcapCharStyle(SwPaM const & rPam, SfxItemSet & rItemSet,
        uno::Any const& rValue)
{
    OUString uStyle;
    if (!(rValue >>= uStyle))
    {
        throw lang::IllegalArgumentException();
    }
    UIName sStyle;
    SwStyleNameMapper::FillUIName(ProgName(uStyle), sStyle,
            SwGetPoolIdFromName::ChrFmt);
    SwDoc& rDoc = rPam.GetDoc();
    //default character style must not be set as default format
    SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>(
            rDoc.GetDocShell()
            ->GetStyleSheetPool()->Find(sStyle.toString(), SfxStyleFamily::Char));
    if (!pStyle || pStyle->GetCharFormat() == rDoc.GetDfltCharFormat())
    {
        throw lang::IllegalArgumentException();
    }
    std::unique_ptr<SwFormatDrop> pDrop;
    if (const SwFormatDrop* pItem = rItemSet.GetItemIfSet(RES_PARATR_DROP))
    {
        pDrop.reset(new SwFormatDrop(*pItem));
    }
    if (!pDrop)
    {
        pDrop.reset(new SwFormatDrop);
    }
    const rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*pStyle));
    pDrop->SetCharFormat(xStyle->GetCharFormat());
    rItemSet.Put(std::move(pDrop));
}

static void
lcl_setRubyCharstyle(SfxItemSet & rItemSet, uno::Any const& rValue)
{
    OUString sTmp;
    if (!(rValue >>= sTmp))
    {
        throw lang::IllegalArgumentException();
    }

    std::unique_ptr<SwFormatRuby> pRuby;
    if (const SwFormatRuby* pItem = rItemSet.GetItemIfSet(RES_TXTATR_CJK_RUBY))
    {
        pRuby.reset(new SwFormatRuby(*pItem));
    }
    if (!pRuby)
    {
        pRuby.reset(new SwFormatRuby(OUString()));
    }
    UIName sStyle;
    SwStyleNameMapper::FillUIName(ProgName(sTmp), sStyle,
            SwGetPoolIdFromName::ChrFmt);
    pRuby->SetCharFormatName(sStyle);
    pRuby->SetCharFormatId(0);
    if (!sStyle.isEmpty())
    {
        const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName(
                sStyle, SwGetPoolIdFromName::ChrFmt);
        pRuby->SetCharFormatId(nId);
    }
    rItemSet.Put(std::move(pRuby));
}

bool
SwUnoCursorHelper::SetCursorPropertyValue(
        SfxItemPropertyMapEntry const& rEntry, const uno::Any& rValue,
        SwPaM & rPam, SfxItemSet & rItemSet)
{
    if (!(rEntry.nFlags & beans::PropertyAttribute::MAYBEVOID) &&
        (rValue.getValueType() == cppu::UnoType<void>::get()))
    {
        return false;
    }
    bool bRet = true;
    switch (rEntry.nWID)
    {
        case RES_TXTATR_CHARFMT:
            SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), rValue, rItemSet);
        break;
        case RES_TXTATR_AUTOFMT:
            lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(),
                    rValue, rItemSet, false);
        break;
        case FN_UNO_CHARFMT_SEQUENCE:
            lcl_setCharFormatSequence(rPam, rValue);
        break;
        case FN_UNO_PARA_STYLE :
            SwUnoCursorHelper::SetTextFormatColl(rValue, rPam);
        break;
        case RES_AUTO_STYLE:
            lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(),
                    rValue, rItemSet, true);
        break;
        case FN_UNO_PAGE_STYLE:
            //FIXME nothing here?
        break;
        case FN_UNO_NUM_START_VALUE:
            lcl_SetNodeNumStart( rPam, rValue );
        break;
        case FN_UNO_NUM_LEVEL:
        // #i91601#
        case FN_UNO_LIST_ID:
        case FN_UNO_IS_NUMBER:
        case FN_UNO_PARA_NUM_AUTO_FORMAT:
        {
            // multi selection is not considered
            SwTextNode *const pTextNd = rPam.GetPointNode().GetTextNode();
            if (!pTextNd)
            {
                throw lang::IllegalArgumentException();
            }
            if (FN_UNO_NUM_LEVEL == rEntry.nWID)
            {
                sal_Int16 nLevel = 0;
                if (rValue >>= nLevel)
                {
                    if (nLevel < 0 || MAXLEVEL <= nLevel)
                    {
                        throw lang::IllegalArgumentException(
                            u"invalid NumberingLevel"_ustr, nullptr, 0);
                    }
                    pTextNd->SetAttrListLevel(nLevel);
                }
            }
            // #i91601#
            else if (FN_UNO_LIST_ID == rEntry.nWID)
            {
                OUString sListId;
                if (rValue >>= sListId)
                {
                    pTextNd->SetListId( sListId );
                }
            }
            else if (FN_UNO_IS_NUMBER == rEntry.nWID)
            {
                bool bIsNumber(false);
                if ((rValue >>= bIsNumber) && !bIsNumber)
                {
                    pTextNd->SetCountedInList( false );
                }
            }
            else if (FN_UNO_PARA_NUM_AUTO_FORMAT == rEntry.nWID)
            {
                std::shared_ptr<SfxItemSet> pAutoStyle;
                if (uno::Sequence<beans::NamedValue> props; rValue >>= props)
                {
                    // TODO create own map for this, it contains UNO_NAME_DISPLAY_NAME? or make property readable so ODF export can map it to a automatic style?
                    SfxItemPropertySet const& rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE));
                    SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap());
                    SfxItemSetFixed
                        <RES_CHRATR_BEGIN, RES_CHRATR_END-1,
                            RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
                            RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1>
                         items( rPam.GetDoc().GetAttrPool() );

                    for (beans::NamedValue const& prop : props)
                    {
                        SfxItemPropertyMapEntry const*const pEntry =
                            rMap.getByName(prop.Name);
                        if (!pEntry)
                        {
                            throw beans::UnknownPropertyException(
                                "Unknown property: " + prop.Name);
                        }
                        if (pEntry->nFlags & beans::PropertyAttribute::READONLY)
                        {
                            throw beans::PropertyVetoException(
                                "Property is read-only: " + prop.Name);
                        }
                        if (prop.Name == "CharStyleName")
                        {
                            SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), prop.Value, items);
                        }
                        else
                        {
                            SfxItemPropertySet::setPropertyValue(*pEntry, prop.Value, items);
                        }
                    }

                    IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess();
                    // Add it to the autostyle pool, needed by the ODT export.
                    pAutoStyle = rStyleAccess.getAutomaticStyle(items, IStyleAccess::AUTO_STYLE_CHAR);
                }
                else if (OUString styleName; rValue >>= styleName)
                {
                    IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess();
                    pAutoStyle = rStyleAccess.getByName(styleName, IStyleAccess::AUTO_STYLE_CHAR);
                }
                if (pAutoStyle)
                {
                    SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT);
                    // note: paragraph auto styles have ParaStyleName property for the parent style; character auto styles currently do not because there's a separate hint, but for this it would be a good way to add it in order to export it as style:parent-style-name, see XMLTextParagraphExport::Add()
                    item.SetStyleHandle(pAutoStyle);
                    pTextNd->SetAttr(item);
                }
            }
            //PROPERTY_MAYBEVOID!
        }
        break;
        case FN_NUMBER_NEWSTART:
        {
            bool bVal = false;
            if (!(rValue >>= bVal))
            {
                throw lang::IllegalArgumentException();
            }
            rPam.GetDoc().SetNumRuleStart(*rPam.GetPoint(), bVal);
        }
        break;
        case FN_UNO_NUM_RULES:
            SwUnoCursorHelper::setNumberingProperty(rValue, rPam);
        break;
        case RES_PARATR_DROP:
        {
            if (MID_DROPCAP_CHAR_STYLE_NAME == rEntry.nMemberId)
            {
                lcl_setDropcapCharStyle(rPam, rItemSet, rValue);
            }
            else
            {
                bRet = false;
            }
        }
        break;
        case RES_TXTATR_CJK_RUBY:
        {
            if (MID_RUBY_CHARSTYLE == rEntry.nMemberId)
            {
                lcl_setRubyCharstyle(rItemSet, rValue);
            }
            else
            {
                bRet = false;
            }
        }
        break;
        case RES_PAGEDESC:
        {
            if (MID_PAGEDESC_PAGEDESCNAME == rEntry.nMemberId)
            {
                SwUnoCursorHelper::SetPageDesc(
                        rValue, rPam.GetDoc(), rItemSet);
            }
            else
            {
                bRet = false;
            }
        }
        break;
        default:
            bRet = false;
    }
    return bRet;
}

SwFormatColl *
SwUnoCursorHelper::GetCurTextFormatColl(SwPaM & rPaM, const bool bConditional)
{
    static constexpr sal_Int32 nMaxLookup = 1000;
    SwFormatColl *pFormat = nullptr;
    bool bError = false;
    SwPaM *pTmpCursor = &rPaM;
    do
    {
        const SwNodeOffset nSttNd = pTmpCursor->Start()->GetNodeIndex();
        const SwNodeOffset nEndNd = pTmpCursor->End()->GetNodeIndex();

        if( nEndNd - nSttNd >= SwNodeOffset(nMaxLookup) )
        {
            pFormat = nullptr;
            break;
        }

        const SwNodes& rNds = rPaM.GetDoc().GetNodes();
        for( SwNodeOffset n = nSttNd; n <= nEndNd; ++n )
        {
            SwTextNode const*const pNd = rNds[ n ]->GetTextNode();
            if( pNd )
            {
                SwFormatColl *const pNdFormat = bConditional
                    ? pNd->GetFormatColl() : &pNd->GetAnyFormatColl();
                if( !pFormat )
                {
                    pFormat = pNdFormat;
                }
                else if( pFormat != pNdFormat )
                {
                    bError = true;
                    break;
                }
            }
        }

        pTmpCursor = pTmpCursor->GetNext();
    } while ( pTmpCursor != &rPaM );
    return bError ? nullptr : pFormat;
}

SwUnoCursor& SwXTextCursor::GetCursor()
    { return *m_pUnoCursor; }

SwPaM const* SwXTextCursor::GetPaM() const
    { return m_pUnoCursor.get(); }

SwPaM* SwXTextCursor::GetPaM()
    { return m_pUnoCursor.get(); }

SwDoc const* SwXTextCursor::GetDoc() const
    { return m_pUnoCursor ? &m_pUnoCursor->GetDoc() : nullptr; }

SwDoc* SwXTextCursor::GetDoc()
    { return m_pUnoCursor ? &m_pUnoCursor->GetDoc() : nullptr; }

SwXTextCursor::SwXTextCursor(
        SwDoc & rDoc,
        uno::Reference< text::XText > xParent,
        const CursorType eType,
        const SwPosition& rPos,
        SwPosition const*const pMark)
    : m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR))
    , m_eType(eType)
    , m_xParentText(std::move(xParent))
    , m_pUnoCursor(rDoc.CreateUnoCursor(rPos))
{
    if (pMark)
    {
        m_pUnoCursor->SetMark();
        *m_pUnoCursor->GetMark() = *pMark;
    }
}

SwXTextCursor::SwXTextCursor(uno::Reference< text::XText > xParent,
        SwPaM const& rSourceCursor, const CursorType eType)
    : m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR))
    , m_eType(eType)
    , m_xParentText(std::move(xParent))
    , m_pUnoCursor(rSourceCursor.GetDoc().CreateUnoCursor(*rSourceCursor.GetPoint()))
{
    if (rSourceCursor.HasMark())
    {
        m_pUnoCursor->SetMark();
        *m_pUnoCursor->GetMark() = *rSourceCursor.GetMark();
    }
}

SwXTextCursor::~SwXTextCursor()
{
    SolarMutexGuard g; // #i105557#: call dtor with locked solar mutex
    m_pUnoCursor.reset(nullptr); // need to delete this with SolarMutex held
}

void SwXTextCursor::DeleteAndInsert(std::u16string_view aText,
        ::sw::DeleteAndInsertMode const eMode)
{
    auto pUnoCursor = static_cast<SwCursor*>(m_pUnoCursor.get());
    if (!pUnoCursor)
        return;

    // Start/EndAction
    SwDoc& rDoc = pUnoCursor->GetDoc();
    UnoActionContext aAction(&rDoc);
    const sal_Int32 nTextLen = aText.size();
    rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr);
    auto pCurrent = pUnoCursor;
    do
    {
        if (pCurrent->HasMark())
        {
            rDoc.getIDocumentContentOperations().DeleteAndJoin(*pCurrent,
                // is it "delete" or "replace"?
                (nTextLen != 0 || eMode & ::sw::DeleteAndInsertMode::ForceReplace) ? SwDeleteFlags::ArtificialSelection : SwDeleteFlags::Default);
        }
        if(nTextLen)
        {
            // Store node and content indexes prior to insertion: to select the inserted text,
            // we need to account for possible surrogate pairs, combining characters, etc.; it
            // is easier to just restore the correct position from the indexes.
            const auto start = pCurrent->Start();
            const auto nodeIndex = start->GetNodeIndex();
            const auto contentIndex = start->GetContentIndex();
            const bool bSuccess(
                SwUnoCursorHelper::DocInsertStringSplitCR(
                    rDoc, SwPaM(*start, pCurrent), aText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints)));
            OSL_ENSURE( bSuccess, "Doc->Insert(Str) failed." );

            pCurrent->SetMark();
            pCurrent->GetPoint()->Assign(nodeIndex, contentIndex);
        }
        pCurrent = pCurrent->GetNext();
    } while (pCurrent != pUnoCursor);
    rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr);
}

namespace {

enum ForceIntoMetaMode { META_CHECK_BOTH, META_INIT_START, META_INIT_END };

enum ForceIntoContentControlMode
{
    CONTENT_CONTROL_CHECK_BOTH,
    CONTENT_CONTROL_INIT_START,
    CONTENT_CONTROL_INIT_END
};
}

static bool
lcl_ForceIntoMeta(SwPaM & rCursor,
        uno::Reference<text::XText> const & xParentText,
        const enum ForceIntoMetaMode eMode)
{
    bool bRet( true ); // means not forced in META_CHECK_BOTH
    SwXMeta const * const pXMeta( dynamic_cast<SwXMeta*>(xParentText.get()) );
    OSL_ENSURE(pXMeta, "no parent?");
    if (!pXMeta)
        throw uno::RuntimeException();
    SwTextNode * pTextNode;
    sal_Int32 nStart;
    sal_Int32 nEnd;
    const bool bSuccess( pXMeta->SetContentRange(pTextNode, nStart, nEnd) );
    OSL_ENSURE(bSuccess, "no pam?");
    if (!bSuccess)
        throw uno::RuntimeException();
    // force the cursor back into the meta if it has moved outside
    SwPosition start(*pTextNode, nStart);
    SwPosition end(*pTextNode, nEnd);
    switch (eMode)
    {
        case META_INIT_START:
            *rCursor.GetPoint() = start;
            break;
        case META_INIT_END:
            *rCursor.GetPoint() = end;
            break;
        case META_CHECK_BOTH:
            if (*rCursor.Start() < start)
            {
                *rCursor.Start() = std::move(start);
                bRet = false;
            }
            if (*rCursor.End() > end)
            {
                *rCursor.End() = std::move(end);
                bRet = false;
            }
            break;
    }
    return bRet;
}

namespace
{
bool lcl_ForceIntoContentControl(SwPaM& rCursor, const uno::Reference<text::XText>&&nbsp;xParentText,
                                 ForceIntoContentControlMode eMode)
{
    bool bRet = true// means not forced in CONTENT_CONTROL_CHECK_BOTH
    auto pXContentControl = dynamic_cast<SwXContentControl*>(xParentText.get());
    if (!pXContentControl)
    {
        SAL_WARN("sw.core""lcl_ForceIntoContentControl: no parent text");
        throw uno::RuntimeException();
    }

    SwTextNode* pTextNode;
    sal_Int32 nStart;
    sal_Int32 nEnd;
    bool bSuccess = pXContentControl->SetContentRange(pTextNode, nStart, nEnd);
    if (!bSuccess)
    {
        SAL_WARN("sw.core""lcl_ForceIntoContentControl: SetContentRange() failed");
        throw uno::RuntimeException();
    }

    // Force the cursor back into the content control if it has moved outside.
    SwPosition aStart(*pTextNode, nStart);
    SwPosition aEnd(*pTextNode, nEnd);
    switch (eMode)
    {
        case CONTENT_CONTROL_INIT_START:
            *rCursor.GetPoint() = aStart;
            break;

        case CONTENT_CONTROL_INIT_END:
            *rCursor.GetPoint() = aEnd;
            break;

        case CONTENT_CONTROL_CHECK_BOTH:
            if (*rCursor.Start() < aStart)
            {
                *rCursor.Start() = std::move(aStart);
                bRet = false;
            }

            if (*rCursor.End() > aEnd)
            {
                *rCursor.End() = std::move(aEnd);
                bRet = false;
            }
            break;
    }

    return bRet;
}
}

bool SwXTextCursor::IsAtEndOfMeta() const
{
    if (CursorType::Meta == m_eType)
    {
        sw::UnoCursorPointer pCursor( m_pUnoCursor );
        SwXMeta const*const pXMeta(
                dynamic_cast<SwXMeta*>(m_xParentText.get()) );
        OSL_ENSURE(pXMeta, "no meta?");
        if (pCursor && pXMeta)
        {
            SwTextNode * pTextNode;
            sal_Int32 nStart;
            sal_Int32 nEnd;
            const bool bSuccess(
                    pXMeta->SetContentRange(pTextNode, nStart, nEnd) );
            OSL_ENSURE(bSuccess, "no pam?");
            if (bSuccess)
            {
                const SwPosition end(*pTextNode, nEnd);
                if (   (*pCursor->GetPoint() == end)
                    || (*pCursor->GetMark()  == end))
                {
                    return true;
                }
            }
        }
    }
    return false;
}

bool SwXTextCursor::IsAtEndOfContentControl() const
{
    if (CursorType::ContentControl == m_eType)
    {
        sw::UnoCursorPointer pCursor( m_pUnoCursor );
        auto pXContentControl(
                dynamic_cast<SwXContentControl*>(m_xParentText.get()) );
        if (!pXContentControl)
        {
            SAL_WARN("sw.core""SwXTextCursor::IsAtEndOfContentControl: no content control");
        }
        if (pCursor && pXContentControl)
        {
            SwTextNode * pTextNode;
            sal_Int32 nStart;
            sal_Int32 nEnd;
            const bool bSuccess(
                    pXContentControl->SetContentRange(pTextNode, nStart, nEnd) );
            if (!bSuccess)
            {
                SAL_WARN("sw.core""SwXTextCursor::IsAtEndOfContentControl: no pam");
            }
            else
            {
                const SwPosition end(*pTextNode, nEnd);
                if (   (*pCursor->GetPoint() == end)
                    || (*pCursor->GetMark()  == end))
                {
                    return true;
                }
            }
        }
    }
    return false;
}

OUString SwXTextCursor::getImplementationName()
{
    return u"SwXTextCursor"_ustr;
}

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

uno::Sequence< OUString > SAL_CALL
SwXTextCursor::getSupportedServiceNames()
{
    return {
        u"com.sun.star.text.TextCursor"_ustr,
        u"com.sun.star.style.CharacterProperties"_ustr,
        u"com.sun.star.style.CharacterPropertiesAsian"_ustr,
        u"com.sun.star.style.CharacterPropertiesComplex"_ustr,
        u"com.sun.star.style.ParagraphProperties"_ustr,
        u"com.sun.star.style.ParagraphPropertiesAsian"_ustr,
        u"com.sun.star.style.ParagraphPropertiesComplex"_ustr,
        u"com.sun.star.text.TextSortable"_ustr
    };
}

void SAL_CALL SwXTextCursor::collapseToStart()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    if (rUnoCursor.HasMark())
    {
        if (*rUnoCursor.GetPoint() > *rUnoCursor.GetMark())
        {
            rUnoCursor.Exchange();
        }
        rUnoCursor.DeleteMark();
    }
}

void SAL_CALL SwXTextCursor::collapseToEnd()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    if (rUnoCursor.HasMark())
    {
        if (*rUnoCursor.GetPoint() < *rUnoCursor.GetMark())
        {
            rUnoCursor.Exchange();
        }
        rUnoCursor.DeleteMark();
    }
}

sal_Bool SAL_CALL SwXTextCursor::isCollapsed()
{
    SolarMutexGuard aGuard;

    bool bRet = true;
    sw::UnoCursorPointer pUnoCursor(m_pUnoCursor);
    if(pUnoCursor && pUnoCursor->GetMark())
    {
        bRet = (*pUnoCursor->GetPoint() == *pUnoCursor->GetMark());
    }
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::goLeft(sal_Int16 nCount, sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    bool bRet = rUnoCursor.Left( nCount);
    if (CursorType::Meta == m_eType)
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH)
            && bRet;
    }
    else if (m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
               && bRet;
    }
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::goRight(sal_Int16 nCount, sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    bool bRet = rUnoCursor.Right(nCount);
    if (CursorType::Meta == m_eType)
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH)
            && bRet;
    }
    else if (m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
               && bRet;
    }
    return bRet;
}

void SAL_CALL
SwXTextCursor::gotoStart(sal_Bool Expand)
{
    SolarMutexGuard aGuard;
    comphelper::ProfileZone aZone("gotoStart");

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    if (CursorType::Body == m_eType)
    {
        rUnoCursor.Move( fnMoveBackward, GoInDoc );
        //check, that the cursor is not in a table
        SwTableNode * pTableNode = rUnoCursor.GetPointNode().FindTableNode();
        while (pTableNode)
        {
            rUnoCursor.GetPoint()->Assign( *pTableNode->EndOfSectionNode() );
            SwContentNode* pCNode = SwNodes::GoNext(rUnoCursor.GetPoint());
            pTableNode = pCNode ? pCNode->FindTableNode() : nullptr;
        }
        SwStartNode const*const pTmp =
            rUnoCursor.GetPointNode().StartOfSectionNode();
        if (pTmp->IsSectionNode())
        {
            SwSectionNode const*const pSectionStartNode =
                static_cast<SwSectionNode const*>(pTmp);
            if (pSectionStartNode->GetSection().IsHiddenFlag())
            {
                SwNodes::GoNextSection(
                        rUnoCursor.GetPoint(), truefalse);
            }
        }
    }
    else if (   (CursorType::Frame   == m_eType)
            ||  (CursorType::TableText == m_eType)
            ||  (CursorType::Header  == m_eType)
            ||  (CursorType::Footer  == m_eType)
            ||  (CursorType::Footnote== m_eType)
            ||  (CursorType::Redline == m_eType))
    {
        rUnoCursor.MoveSection(GoCurrSection, fnSectionStart);
    }
    else if (CursorType::Meta == m_eType)
    {
        lcl_ForceIntoMeta(rUnoCursor, m_xParentText, META_INIT_START);
    }
    else if (m_eType == CursorType::ContentControl)
    {
        lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_INIT_START);
    }
}

void SAL_CALL
SwXTextCursor::gotoEnd(sal_Bool Expand)
{
    SolarMutexGuard aGuard;
    comphelper::ProfileZone aZone("gotoEnd");

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    if (CursorType::Body == m_eType)
    {
        rUnoCursor.Move( fnMoveForward, GoInDoc );
    }
    else if (   (CursorType::Frame   == m_eType)
            ||  (CursorType::TableText == m_eType)
            ||  (CursorType::Header  == m_eType)
            ||  (CursorType::Footer  == m_eType)
            ||  (CursorType::Footnote== m_eType)
            ||  (CursorType::Redline == m_eType))
    {
        rUnoCursor.MoveSection( GoCurrSection, fnSectionEnd);
    }
    else if (CursorType::Meta == m_eType)
    {
        lcl_ForceIntoMeta(rUnoCursor, m_xParentText, META_INIT_END);
    }
    else if (m_eType == CursorType::ContentControl)
    {
        lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_INIT_END);
    }
}

void SAL_CALL
SwXTextCursor::gotoRange(
    const uno::Reference< text::XTextRange > & xRange, sal_Bool bExpand)
{
    SolarMutexGuard aGuard;
    if (!xRange.is())
    {
        throw uno::RuntimeException();
    }
    SwXTextRange* pRange = dynamic_cast<SwXTextRange*>(xRange.get());
    OTextCursorHelper* pCursor = dynamic_cast<OTextCursorHelper*>(xRange.get());
    if (!pRange && !pCursor)
    {
        throw uno::RuntimeException();
    }

    gotoRangeImpl(pRange, pCursor, bExpand);
}

void
SwXTextCursor::gotoRangeImpl(
    const SwXTextRange* pRange,
    OTextCursorHelper* pCursor,
    bool bExpand)
{
    DBG_TESTSOLARMUTEX();
    assert((pRange || pCursor) && "one of these parameters must be non-null");

    SwUnoCursor & rOwnCursor( GetCursorOrThrow() );

    SwPaM aPam(GetDoc()->GetNodes());
    const SwPaM * pPam(nullptr);
    if (pCursor)
    {
        pPam = pCursor->GetPaM();
    }
    else
    {
        if (pRange->GetPositions(aPam))
        {
            pPam = & aPam;
        }
    }

    if (!pPam)
    {
        throw uno::RuntimeException();
    }

    {
        SwStartNodeType eSearchNodeType = SwNormalStartNode;
        switch (m_eType)
        {
        case CursorType::Frame:      eSearchNodeType = SwFlyStartNode;       break;
        case CursorType::TableText:    eSearchNodeType = SwTableBoxStartNode;  break;
        case CursorType::Footnote:   eSearchNodeType = SwFootnoteStartNode;  break;
        case CursorType::Header:     eSearchNodeType = SwHeaderStartNode;    break;
        case CursorType::Footer:     eSearchNodeType = SwFooterStartNode;    break;
            //case CURSOR_INVALID:
            //case CursorType::Body:
        default:
            ;
        }

        const SwStartNode* pOwnStartNode = rOwnCursor.GetPointNode().FindStartNodeByType(eSearchNodeType);
        while ( pOwnStartNode != nullptr
                && pOwnStartNode->IsSectionNode())
        {
            pOwnStartNode = pOwnStartNode->StartOfSectionNode();
        }

        const SwStartNode* pTmp =
            pPam->GetPointNode().FindStartNodeByType(eSearchNodeType);
        while ( pTmp != nullptr
                && pTmp->IsSectionNode() )
        {
            pTmp = pTmp->StartOfSectionNode();
        }

        if ( eSearchNodeType == SwTableBoxStartNode )
        {
            if (!pOwnStartNode || !pTmp)
            {
                throw uno::RuntimeException();
            }

            if ( pOwnStartNode->FindTableNode() != pTmp->FindTableNode() )
            {
                throw uno::RuntimeException();
            }
        }
        else
        {
            if ( pOwnStartNode != pTmp )
            {
                throw uno::RuntimeException();
            }
        }
    }

    if (CursorType::Meta == m_eType)
    {
        SwPaM CopyPam(*pPam->GetMark(), *pPam->GetPoint());
        const bool bNotForced( lcl_ForceIntoMeta(
                    CopyPam, m_xParentText, META_CHECK_BOTH) );
        if (!bNotForced)
        {
            throw uno::RuntimeException(
                u"gotoRange: parameter range not contained in nesting"
                    " text content for which this cursor was created"_ustr,
                static_cast<text::XWordCursor*>(this));
        }
    }
    else if (m_eType == CursorType::ContentControl)
    {
        SwPaM aPaM(*pPam->GetMark(), *pPam->GetPoint());
        if (!lcl_ForceIntoContentControl(aPaM, m_xParentText, CONTENT_CONTROL_CHECK_BOTH))
        {
            throw uno::RuntimeException(u"gotoRange: xRange is out of bounds of the content control"_ustr,
                                        static_cast<text::XWordCursor*>(this));
        }
    }

    // selection has to be expanded here
    if(bExpand)
    {
        // cursor should include its previous range plus the given range
        const SwPosition aOwnLeft(*rOwnCursor.Start());
        const SwPosition aOwnRight(*rOwnCursor.End());
        SwPosition const& rParamLeft  = *pPam->Start();
        SwPosition const& rParamRight = *pPam->End();

        // now there are four SwPositions,
        // two of them are going to be used, but which ones?
        if (aOwnRight > rParamRight)
            *rOwnCursor.GetPoint() = aOwnRight;
        else
            *rOwnCursor.GetPoint() = rParamRight;
        rOwnCursor.SetMark();
        if (aOwnLeft < rParamLeft)
            *rOwnCursor.GetMark() = aOwnLeft;
        else
            *rOwnCursor.GetMark() = rParamLeft;
    }
    else
    {
        // cursor should be the given range
        *rOwnCursor.GetPoint() = *pPam->GetPoint();
        if (pPam->HasMark())
        {
            rOwnCursor.SetMark();
            *rOwnCursor.GetMark() = *pPam->GetMark();
        }
        else
        {
            rOwnCursor.DeleteMark();
        }
    }
}

sal_Bool SAL_CALL SwXTextCursor::isStartOfWord()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    const bool bRet =
        rUnoCursor.IsStartWordWT( i18n::WordType::DICTIONARY_WORD );
    return bRet;
}

sal_Bool SAL_CALL SwXTextCursor::isEndOfWord()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    const bool bRet =
        rUnoCursor.IsEndWordWT( i18n::WordType::DICTIONARY_WORD );
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoNextWord(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    // problems arise when a paragraph starts with something other than a word
    bool bRet = false;
    // remember old position to check if cursor has moved
    // since the called functions are sometimes a bit unreliable
    // in specific cases...
    SwPosition  *const pPoint     = rUnoCursor.GetPoint();
    SwNode      *const pOldNode   = &pPoint->GetNode();
    sal_Int32 const nOldIndex  = pPoint->GetContentIndex();

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    // end of paragraph
    if (rUnoCursor.GetPointContentNode() &&
            (pPoint->GetContentIndex() == rUnoCursor.GetPointContentNode()->Len()))
    {
        rUnoCursor.Right(1);
    }
    else
    {
        const bool bTmp =
            rUnoCursor.GoNextWordWT( i18n::WordType::DICTIONARY_WORD );
        // if there is no next word within the current paragraph
        // try to go to the start of the next paragraph
        if (!bTmp)
        {
            rUnoCursor.MovePara(GoNextPara, fnParaStart);
        }
    }

    // return true if cursor has moved
    bRet =  (&pPoint->GetNode() != pOldNode)  ||
            (pPoint->GetContentIndex() != nOldIndex);
    if (bRet && (CursorType::Meta == m_eType))
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH);
    }
    else if (bRet && m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
    }

    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoPreviousWord(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    // white spaces create problems on the paragraph start
    bool bRet = false;
    SwPosition  *const pPoint     = rUnoCursor.GetPoint();
    SwNode      *const pOldNode   = &pPoint->GetNode();
    sal_Int32 const nOldIndex  = pPoint->GetContentIndex();

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    // start of paragraph?
    if (pPoint->GetContentIndex() == 0)
    {
        rUnoCursor.Left(1);
    }
    else
    {
        rUnoCursor.GoPrevWordWT( i18n::WordType::DICTIONARY_WORD );
        if (pPoint->GetContentIndex() == 0)
        {
            rUnoCursor.Left(1);
        }
    }

    // return true if cursor has moved
    bRet =  (&pPoint->GetNode() != pOldNode)  ||
            (pPoint->GetContentIndex() != nOldIndex);
    if (bRet && (CursorType::Meta == m_eType))
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH);
    }
    else if (bRet && m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
    }

    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoEndOfWord(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    bool bRet = false;
    SwPosition  *const pPoint     = rUnoCursor.GetPoint();
    SwNode      &      rOldNode   = pPoint->GetNode();
    sal_Int32 const nOldIndex  = pPoint->GetContentIndex();

    const sal_Int16 nWordType = i18n::WordType::DICTIONARY_WORD;
    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    if (!rUnoCursor.IsEndWordWT( nWordType ))
    {
        rUnoCursor.GoEndWordWT( nWordType );
    }

    // restore old cursor if we are not at the end of a word by now
    // otherwise use current one
    bRet = rUnoCursor.IsEndWordWT( nWordType );
    if (!bRet)
    {
        pPoint->Assign(rOldNode, nOldIndex);
    }
    else if (CursorType::Meta == m_eType)
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH);
    }
    else if (m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
    }

    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoStartOfWord(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    bool bRet = false;
    SwPosition  *const pPoint     = rUnoCursor.GetPoint();
    SwNode      &      rOldNode   = pPoint->GetNode();
    sal_Int32 const nOldIndex  = pPoint->GetContentIndex();

    const sal_Int16 nWordType = i18n::WordType::DICTIONARY_WORD;
    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    if (!rUnoCursor.IsStartWordWT( nWordType ))
    {
        rUnoCursor.GoStartWordWT( nWordType );
    }

    // restore old cursor if we are not at the start of a word by now
    // otherwise use current one
    bRet = rUnoCursor.IsStartWordWT( nWordType );
    if (!bRet)
    {
        pPoint->Assign(rOldNode, nOldIndex);
    }
    else if (CursorType::Meta == m_eType)
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH);
    }
    else if (m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
    }

    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::isStartOfSentence()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    // start of paragraph?
    bool bRet = rUnoCursor.GetPoint()->GetContentIndex() == 0;
    // with mark ->no sentence start
    // (check if cursor is no selection, i.e. it does not have
    // a mark or else point and mark are identical)
    if (!bRet && (!rUnoCursor.HasMark() ||
                    *rUnoCursor.GetPoint() == *rUnoCursor.GetMark()))
    {
        SwCursor aCursor(*rUnoCursor.GetPoint(),nullptr);
        SwPosition aOrigPos = *aCursor.GetPoint();
        aCursor.GoSentence(SwCursor::START_SENT );
        bRet = aOrigPos == *aCursor.GetPoint();
    }
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::isEndOfSentence()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    // end of paragraph?
    bool bRet = rUnoCursor.GetPointContentNode() &&
        (rUnoCursor.GetPoint()->GetContentIndex() == rUnoCursor.GetPointContentNode()->Len());
    // with mark->no sentence end
    // (check if cursor is no selection, i.e. it does not have
    // a mark or else point and mark are identical)
    if (!bRet && (!rUnoCursor.HasMark() ||
                    *rUnoCursor.GetPoint() == *rUnoCursor.GetMark()))
    {
        SwCursor aCursor(*rUnoCursor.GetPoint(), nullptr);
        SwPosition aOrigPos = *aCursor.GetPoint();
        aCursor.GoSentence(SwCursor::END_SENT);
        bRet = aOrigPos == *aCursor.GetPoint();
    }
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoNextSentence(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    const bool bWasEOS = isEndOfSentence();
    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    bool bRet = rUnoCursor.GoSentence(SwCursor::NEXT_SENT);
    if (!bRet)
    {
        bRet = rUnoCursor.MovePara(GoNextPara, fnParaStart);
    }

    // if at the end of the sentence (i.e. at the space after the '.')
    // advance to next word in order for GoSentence to work properly
    // next time and have isStartOfSentence return true after this call
    if (!rUnoCursor.IsStartWordWT(css::i18n::WordType::ANYWORD_IGNOREWHITESPACES))
    {
        const bool bNextWord = rUnoCursor.GoNextWordWT(i18n::WordType::ANYWORD_IGNOREWHITESPACES);
        if (bWasEOS && !bNextWord)
        {
            bRet = false;
        }
    }
    if (CursorType::Meta == m_eType)
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH)
            && bRet;
    }
    else if (m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
               && bRet;
    }
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoPreviousSentence(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    bool bRet = rUnoCursor.GoSentence(SwCursor::PREV_SENT);
    if (!bRet)
    {
        bRet = rUnoCursor.MovePara(GoPrevPara, fnParaStart);
        if (bRet)
        {
            rUnoCursor.MovePara(GoCurrPara, fnParaEnd);
            // at the end of a paragraph move to the sentence end again
            rUnoCursor.GoSentence(SwCursor::PREV_SENT);
        }
    }
    if (CursorType::Meta == m_eType)
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH)
            && bRet;
    }
    else if (m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
               && bRet;
    }
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoStartOfSentence(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    // if we're at the para start then we won't move
    // but bRet is also true if GoSentence failed but
    // the start of the sentence is reached
    bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor)
        || rUnoCursor.GoSentence(SwCursor::START_SENT)
        || SwUnoCursorHelper::IsStartOfPara(rUnoCursor);
    if (CursorType::Meta == m_eType)
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH)
            && bRet;
    }
    else if (m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
               && bRet;
    }
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoEndOfSentence(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    // bRet is true if GoSentence() succeeded or if the
    // MovePara() succeeded while the end of the para is
    // not reached already
    bool bAlreadyParaEnd = SwUnoCursorHelper::IsEndOfPara(rUnoCursor);
    bool bRet = !bAlreadyParaEnd
            &&  (rUnoCursor.GoSentence(SwCursor::END_SENT)
                 || rUnoCursor.MovePara(GoCurrPara, fnParaEnd));
    if (CursorType::Meta == m_eType)
    {
        bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
                    META_CHECK_BOTH)
            && bRet;
    }
    else if (m_eType == CursorType::ContentControl)
    {
        bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
               && bRet;
    }
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::isStartOfParagraph()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    const bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor);
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::isEndOfParagraph()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    const bool bRet = SwUnoCursorHelper::IsEndOfPara(rUnoCursor);
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoStartOfParagraph(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    if (CursorType::Meta == m_eType)
    {
        return false;
    }
    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor);
    if (!bRet)
    {
        bRet = rUnoCursor.MovePara(GoCurrPara, fnParaStart);
    }

    // since MovePara(GoCurrPara, fnParaStart) only returns false
    // if we were already at the start of the paragraph this function
    // should always complete successfully.
    OSL_ENSURE( bRet, "gotoStartOfParagraph failed" );
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoEndOfParagraph(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    if (CursorType::Meta == m_eType)
    {
        return false;
    }
    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    bool bRet = SwUnoCursorHelper::IsEndOfPara(rUnoCursor);
    if (!bRet)
    {
        bRet = rUnoCursor.MovePara(GoCurrPara, fnParaEnd);
    }

    // since MovePara(GoCurrPara, fnParaEnd) only returns false
    // if we were already at the end of the paragraph this function
    // should always complete successfully.
    OSL_ENSURE( bRet, "gotoEndOfParagraph failed" );
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoNextParagraph(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    if (CursorType::Meta == m_eType)
    {
        return false;
    }
    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    const bool bRet = rUnoCursor.MovePara(GoNextPara, fnParaStart);
    return bRet;
}

sal_Bool SAL_CALL
SwXTextCursor::gotoPreviousParagraph(sal_Bool Expand)
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    if (CursorType::Meta == m_eType)
    {
        return false;
    }
    SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
    const bool bRet = rUnoCursor.MovePara(GoPrevPara, fnParaStart);
    return bRet;
}

uno::Reference< text::XText > SAL_CALL
SwXTextCursor::getText()
{
    SolarMutexGuard g;

    return m_xParentText;
}

uno::Reference< text::XTextRange > SAL_CALL
SwXTextCursor::getStart()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    uno::Reference< text::XTextRange > xRet;
    SwPaM aPam(*rUnoCursor.Start());
    const uno::Reference< text::XText >  xParent = getText();
    if (CursorType::Meta == m_eType)
    {
        // return cursor to prevent modifying SwXTextRange for META
        rtl::Reference<SwXTextCursor> pXCursor(
            new SwXTextCursor(rUnoCursor.GetDoc(), xParent, CursorType::Meta,
                *rUnoCursor.GetPoint()) );
        pXCursor->gotoStart(false);
        xRet = static_cast<text::XWordCursor*>(pXCursor.get());
    }
    else
    {
        xRet = new SwXTextRange(aPam, xParent);
    }
    return xRet;
}

uno::Reference< text::XTextRange > SAL_CALL
SwXTextCursor::getEnd()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    uno::Reference< text::XTextRange >  xRet;
    SwPaM aPam(*rUnoCursor.End());
    const uno::Reference< text::XText >  xParent = getText();
    if (CursorType::Meta == m_eType)
    {
        // return cursor to prevent modifying SwXTextRange for META
        rtl::Reference<SwXTextCursor> pXCursor(
            new SwXTextCursor(rUnoCursor.GetDoc(), xParent, CursorType::Meta,
                *rUnoCursor.GetPoint()) );
        pXCursor->gotoEnd(false);
        xRet = static_cast<text::XWordCursor*>(pXCursor.get());
    }
    else
    {
        xRet = new SwXTextRange(aPam, xParent);
    }
    return xRet;
}

OUString SAL_CALL SwXTextCursor::getString()
{
    SolarMutexGuard aGuard;

    SwUnoCursor & rUnoCursor( GetCursorOrThrow() );

    OUString aText;
    SwUnoCursorHelper::GetTextFromPam(rUnoCursor, aText);
    return aText;
}

void SAL_CALL
SwXTextCursor::setString(const OUString& aString)
{
    SolarMutexGuard aGuard;

    GetCursorOrThrow(); // just to check if valid

    const bool bForceExpandHints( (CursorType::Meta == m_eType)
        && dynamic_cast<SwXMeta&>(*m_xParentText)
                .CheckForOwnMemberMeta(*GetPaM(), true) );
    DeleteAndInsert(aString, bForceExpandHints ? ::sw::DeleteAndInsertMode::ForceExpandHints : ::sw::DeleteAndInsertMode::Default);
}

uno::Any SwUnoCursorHelper::GetPropertyValue(
    SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
    std::u16string_view rPropertyName)
{
    uno::Any aAny;
    SfxItemPropertyMapEntry const*const pEntry =
        rPropSet.getPropertyMap().getByName(rPropertyName);

    if (!pEntry)
    {
        throw beans::UnknownPropertyException(
            OUString::Concat("Unknown property: ") + rPropertyName);
    }

    beans::PropertyState eTemp;
    const bool bDone = SwUnoCursorHelper::getCursorPropertyValue(
            *pEntry, rPaM, &aAny, eTemp );

    if (!bDone)
    {
        SfxItemSetFixed<
                RES_CHRATR_BEGIN, RES_FRMATR_END - 1,
                RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER>
            aSet(rPaM.GetDoc().GetAttrPool());

        SwUnoCursorHelper::GetCursorAttr(rPaM, aSet);

        SfxItemPropertySet::getPropertyValue(*pEntry, aSet, aAny);
    }

    return aAny;
}

void SwUnoCursorHelper::SetPropertyValue(
    SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
    const OUString& rPropertyName,
    const uno::Any& rValue,
    const SetAttrMode nAttrMode)
{
    beans::PropertyValue aVal { comphelper::makePropertyValue(rPropertyName, rValue) };
    SetPropertyValues(rPaM, rPropSet, std::span<beans::PropertyValue>(&aVal, 1), nAttrMode);
}

// FN_UNO_PARA_STYLE is known to set attributes for nodes, inside
// SwUnoCursorHelper::SetTextFormatColl, instead of extending item set.
// We need to get them from nodes in next call to GetCursorAttr.
// The rest could cause similar problems in theory, so we just list them here.
static bool propertyCausesSideEffectsInNodes(sal_uInt16 nWID)
{
    return nWID == FN_UNO_PARA_STYLE ||
           nWID == FN_UNO_CHARFMT_SEQUENCE ||
           nWID == FN_UNO_NUM_START_VALUE ||
           nWID == FN_UNO_NUM_RULES;
}

void SwUnoCursorHelper::SetPropertyValues(
    SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
    const uno::Sequence< beans::PropertyValue > &rPropertyValues,
    const SetAttrMode nAttrMode)
{
    SetPropertyValues(rPaM, rPropSet,
        std::span<const beans::PropertyValue>(rPropertyValues.getConstArray(), rPropertyValues.getLength()),
        nAttrMode);
}

void SwUnoCursorHelper::SetPropertyValues(
    SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
    std::span< const beans::PropertyValue > aPropertyValues,
    const SetAttrMode nAttrMode)
{
    if (aPropertyValues.empty())
        return;

    SwDoc& rDoc = rPaM.GetDoc();
    OUString aUnknownExMsg, aPropertyVetoExMsg;

    // Build set of attributes we want to fetch
    WhichRangesContainer aRanges;
    std::vector<std::pair<const SfxItemPropertyMapEntry*, const uno::Any&>> aSideEffectsEntries;
    std::vector<std::pair<const SfxItemPropertyMapEntry*, const uno::Any&>> aEntries;
    aEntries.reserve(aPropertyValues.size());
    for (const auto& rPropVal : aPropertyValues)
    {
        const OUString &rPropertyName = rPropVal.Name;

        SfxItemPropertyMapEntry const* pEntry =
            rPropSet.getPropertyMap().getByName(rPropertyName);

        // Queue up any exceptions until the end ...
        if (!pEntry)
        {
            aUnknownExMsg += "Unknown property: '" + rPropertyName + "' ";
            continue;
        }
        else if (pEntry->nFlags & beans::PropertyAttribute::READONLY)
        {
            aPropertyVetoExMsg += "Property is read-only: '" + rPropertyName + "' ";
            continue;
        }
        if (propertyCausesSideEffectsInNodes(pEntry->nWID))
        {
            aSideEffectsEntries.emplace_back(pEntry, rPropVal.Value);
        }
        else
        {
            aRanges = aRanges.MergeRange(pEntry->nWID, pEntry->nWID);
            aEntries.emplace_back(pEntry, rPropVal.Value);
        }
    }

    // Entries with side effects first, using dedicated one-element SfxItemSet for each
    for (const auto& [pEntry, rValue] : aSideEffectsEntries)
    {
        SfxItemSet aItemSet(rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID);
        // we need to get up-to-date item set from nodes
        SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet);
        // this can set some attributes in nodes' mpAttrSet
        if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, rPaM, aItemSet))
            SfxItemPropertySet::setPropertyValue(*pEntry, rValue, aItemSet);
        SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, false /*bTableMode*/);
    }

    if (!aEntries.empty())
    {
        // Fetch, overwrite, and re-set the attributes from the core
        SfxItemSet aItemSet(rDoc.GetAttrPool(), std::move(aRanges));
        // we need to get up-to-date item set from nodes
        SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet);

        for (const auto& [pEntry, rValue] : aEntries)
        {
            // this can set some attributes in nodes' mpAttrSet
            if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, rPaM, aItemSet))
                SfxItemPropertySet::setPropertyValue(*pEntry, rValue, aItemSet);
        }

        SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, false /*bTableMode*/);
    }

    if (!aUnknownExMsg.isEmpty())
        throw beans::UnknownPropertyException(aUnknownExMsg);
    if (!aPropertyVetoExMsg.isEmpty())
        throw beans::PropertyVetoException(aPropertyVetoExMsg);
}

namespace
{
    bool NotInRange(sal_uInt16 nWID, sal_uInt16 nStart, sal_uInt16 nEnd)
    {
        return nWID < nStart || nWID > nEnd;
    }
}

uno::Sequence< beans::PropertyState >
SwUnoCursorHelper::GetPropertyStates(
            SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
            const uno::Sequence< OUString >& rPropertyNames,
            const SwGetPropertyStatesCaller eCaller)
{
    const OUString* pNames = rPropertyNames.getConstArray();
    uno::Sequence< beans::PropertyState > aRet(rPropertyNames.getLength());
    beans::PropertyState* pStates = aRet.getArray();
    const SfxItemPropertyMap &rMap = rPropSet.getPropertyMap();
    std::optional<SfxItemSet> oSet;
    std::optional<SfxItemSet> oSetParent;

    for (sal_Int32 i = 0, nEnd = rPropertyNames.getLength(); i < nEnd; i++)
    {
        SfxItemPropertyMapEntry const*const pEntry =
                rMap.getByName( pNames[i] );
        if(!pEntry)
        {
            if (pNames[i] == UNO_NAME_IS_SKIP_HIDDEN_TEXT ||
                pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT ||
                pNames[i] == UNO_NAME_NO_FORMAT_ATTR)
            {
                pStates[i] = beans::PropertyState_DEFAULT_VALUE;
                continue;
            }
            else if (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT ==
                        eCaller)
            {
                //this values marks the element as unknown property
                pStates[i] = beans::PropertyState::PropertyState_MAKE_FIXED_SIZE;
                continue;
            }
            else
            {
                throw beans::UnknownPropertyException(
                    "Unknown property: " + pNames[i]);
            }
        }
        if (((SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION == eCaller)  ||
             (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT == eCaller)) &&
            NotInRange(pEntry->nWID, FN_UNO_RANGE_BEGIN, FN_UNO_RANGE_END) &&
            NotInRange(pEntry->nWID, RES_CHRATR_BEGIN, RES_TXTATR_END) )
        {
            pStates[i] = beans::PropertyState_DEFAULT_VALUE;
        }
        else
        {
            if ( pEntry->nWID >= FN_UNO_RANGE_BEGIN &&
                 pEntry->nWID <= FN_UNO_RANGE_END )
            {
                (void)SwUnoCursorHelper::getCursorPropertyValue(
                    *pEntry, rPaM, nullptr, pStates[i] );
            }
            else
            {
                if (!oSet)
                {
                    switch ( eCaller )
                    {
                        case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT:
                        case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION:
                            oSet.emplace( rPaM.GetDoc().GetAttrPool(),
                                    svl::Items<RES_CHRATR_BEGIN,   RES_TXTATR_END> );
                        break;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.25 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.