    /* -*- 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 <unocrsrhelper.hxx>

    #include <map>
    #include <algorithm>
    #include <memory>

    #include <com/sun/star/beans/PropertyState.hpp>
    #include <com/sun/star/embed/ElementModes.hpp>
    #include <com/sun/star/embed/XStorage.hpp>
    #include <com/sun/star/io/IOException.hpp>
    #include <com/sun/star/text/XTextSection.hpp>

    #include <svx/svxids.hrc>
    #include <svx/unoshape.hxx>

    #include <cmdid.h>
    #include <unotextrange.hxx>
    #include <unodraw.hxx>
    #include <unofootnote.hxx>
    #include <unobookmark.hxx>
    #include <unorefmark.hxx>
    #include <unostyle.hxx>
    #include <unoidx.hxx>
    #include <unofield.hxx>
    #include <unotbl.hxx>
    #include <unosett.hxx>
    #include <unoframe.hxx>
    #include <unocrsr.hxx>
    #include <doc.hxx>
    #include <IDocumentUndoRedo.hxx>
    #include <IDocumentRedlineAccess.hxx>
    #include <IDocumentLayoutAccess.hxx>
    #include <fmtftn.hxx>
    #include <fmtpdsc.hxx>
    #include <charfmt.hxx>
    #include <pagedesc.hxx>
    #include <docstyle.hxx>
    #include <ndtxt.hxx>
    #include <txtrfmrk.hxx>
    #include <fmtfld.hxx>
    #include <docsh.hxx>
    #include <section.hxx>
    #include <shellio.hxx>
    #include <edimp.hxx>
    #include <swundo.hxx>
    #include <cntfrm.hxx>
    #include <pagefrm.hxx>
    #include <svl/eitem.hxx>
    #include <docary.hxx>
    #include <swtable.hxx>
    #include <tox.hxx>
    #include <doctxm.hxx>
    #include <fchrfmt.hxx>
    #include <editeng/flstitem.hxx>
    #include <vcl/metric.hxx>
    #include <svtools/ctrltool.hxx>
    #include <sfx2/docfilt.hxx>
    #include <sfx2/docfile.hxx>
    #include <sfx2/fcontnr.hxx>
    #include <svl/stritem.hxx>
    #include <SwStyleNameMapper.hxx>
    #include <redline.hxx>
    #include <numrule.hxx>
    #include <comphelper/storagehelper.hxx>
    #include <unotools/mediadescriptor.hxx>
    #include <comphelper/sequenceashashmap.hxx>
    #include <SwNodeNum.hxx>
    #include <fmtmeta.hxx>
    #include <txtfld.hxx>
    #include <unoparagraph.hxx>
    #include <sal/log.hxx>

    using namespace ::com::sun::star;
    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::beans;
    using namespace ::com::sun::star::text;
    using namespace ::com::sun::star::table;
    using namespace ::com::sun::star::container;
    using namespace ::com::sun::star::lang;

    namespace SwUnoCursorHelper
    {

    static SwPaM* lcl_createPamCopy(const SwPaM& rPam)
    {
        SwPaM *const pRet = new SwPaM(*rPam.GetPoint());
        ::sw::DeepCopyPaM(rPam, *pRet);
        return pRet;
    }

    void GetSelectableFromAny(uno::Reference<uno::XInterface> const& xIfc,
            SwDoc & rTargetDoc,
            SwPaM *& o_rpPaM, std::pair<OUString, FlyCntType> & o_rFrame,
            OUString & o_rTableName, SwUnoTableCursor const*& o_rpTableCursor,
            ::sw::mark::IMark const*& o_rpMark,
            std::vector<SdrObject *> & o_rSdrObjects)
    {
        uno::Reference<drawing::XShapes> const xShapes(xIfc, UNO_QUERY);
        if (xShapes.is())
        {
            sal_Int32 nShapes(xShapes->getCount());
            for (sal_Int32 i = 0; i < nShapes; ++i)
            {
                uno::Reference<lang::XUnoTunnel> xShape;
                xShapes->getByIndex(i) >>= xShape;
                if (xShape.is())
                {
                    SvxShape *const pSvxShape(
                            ::sw::UnoTunnelGetImplementation<SvxShape>(xShape));
                    if (pSvxShape)
                    {
                        SdrObject *const pSdrObject = pSvxShape->GetSdrObject();
                        if (pSdrObject)
                        {   // hmm... needs view to verify it's in right doc...
                            o_rSdrObjects.push_back(pSdrObject);
                        }
                    }
                }
            }
            return;
        }

        uno::Reference<lang::XUnoTunnel> const xTunnel(xIfc, UNO_QUERY);
        if (!xTunnel.is()) // everything below needs tunnel
        {
            return;
        }

        SwXShape *const pShape(::sw::UnoTunnelGetImplementation<SwXShape>(xTunnel));
        if (pShape)
        {
            uno::Reference<uno::XAggregation> const xAgg(
                    pShape->GetAggregationInterface());
            if (xAgg.is())
            {
                SvxShape *const pSvxShape(
                        ::sw::UnoTunnelGetImplementation<SvxShape>(xTunnel));
                if (pSvxShape)
                {
                    SdrObject *const pSdrObject = pSvxShape->GetSdrObject();
                    if (pSdrObject)
                    {   // hmm... needs view to verify it's in right doc...
                        o_rSdrObjects.push_back(pSdrObject);
                    }
                }
            }
            return;
        }

        OTextCursorHelper *const pCursor(
            ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xTunnel));
        if (pCursor)
        {
            if (pCursor->GetDoc() == &rTargetDoc)
            {
                o_rpPaM = lcl_createPamCopy(*pCursor->GetPaM());
            }
            return;
        }

        SwXTextRanges* const pRanges(
            ::sw::UnoTunnelGetImplementation<SwXTextRanges>(xTunnel));
        if (pRanges)
        {
            SwUnoCursor const* pUnoCursor = pRanges->GetCursor();
            if (pUnoCursor && pUnoCursor->GetDoc() == &rTargetDoc)
            {
                o_rpPaM = lcl_createPamCopy(*pUnoCursor);
            }
            return;
        }

        // check these before Range to prevent misinterpretation of text frames
        // and cells also implement XTextRange
        SwXFrame *const pFrame(
            ::sw::UnoTunnelGetImplementation<SwXFrame>(xTunnel));
        if (pFrame)
        {
            const SwFrameFormat *const pFrameFormat(pFrame->GetFrameFormat());
            if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc)
            {
                o_rFrame = std::make_pair(pFrameFormat->GetName(), pFrame->GetFlyCntType());
            }
            return;
        }

        SwXTextTable *const pTextTable(
            ::sw::UnoTunnelGetImplementation<SwXTextTable>(xTunnel));
        if (pTextTable)
        {
            SwFrameFormat *const pFrameFormat(pTextTable->GetFrameFormat());
            if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc)
            {
                o_rTableName = pFrameFormat->GetName();
            }
            return;
        }

        SwXCell *const pCell(
            ::sw::UnoTunnelGetImplementation<SwXCell>(xTunnel));
        if (pCell)
        {
            SwFrameFormat *const pFrameFormat(pCell->GetFrameFormat());
            if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc)
            {
                SwTableBox * pBox = pCell->GetTableBox();
                SwTable *const pTable = SwTable::FindTable(pFrameFormat);
                // ??? what's the benefit of setting pBox in this convoluted way?
                pBox = pCell->FindBox(pTable, pBox);
                if (pBox)
                {
                    SwPosition const aPos(*pBox->GetSttNd());
                    SwPaM aPam(aPos);
                    aPam.Move(fnMoveForward, GoInNode);
                    o_rpPaM = lcl_createPamCopy(aPam);
                }
            }
            return;
        }

        uno::Reference<text::XTextRange> const xTextRange(xTunnel, UNO_QUERY);
        if (xTextRange.is())
        {
            SwUnoInternalPaM aPam(rTargetDoc);
            if (::sw::XTextRangeToSwPaM(aPam, xTextRange))
            {
                o_rpPaM = lcl_createPamCopy(aPam);
            }
            return;
        }

        SwXCellRange *const pCellRange(
            ::sw::UnoTunnelGetImplementation<SwXCellRange>(xTunnel));
        if (pCellRange)
        {
            SwUnoCursor const*const pUnoCursor(pCellRange->GetTableCursor());
            if (pUnoCursor && pUnoCursor->GetDoc() == &rTargetDoc)
            {
                // probably can't copy it to o_rpPaM for this since it's
                // a SwTableCursor
                o_rpTableCursor = dynamic_cast<SwUnoTableCursor const*>(pUnoCursor);
            }
            return;
        }

        ::sw::mark::IMark const*const pMark(
                SwXBookmark::GetBookmarkInDoc(& rTargetDoc, xTunnel));
        if (pMark)
        {
            o_rpMark = pMark;
            return;
        }
    }

    uno::Reference<text::XTextContent>
    GetNestedTextContent(SwTextNode const & rTextNode, sal_Int32 const nIndex,
            bool const bParent)
    {
        // these should be unambiguous because of the dummy character
        SwTextNode::GetTextAttrMode const eMode( bParent
            ? SwTextNode::PARENT : SwTextNode::EXPAND );
        SwTextAttr *const pMetaTextAttr =
            rTextNode.GetTextAttrAt(nIndex, RES_TXTATR_META, eMode);
        SwTextAttr *const pMetaFieldTextAttr =
            rTextNode.GetTextAttrAt(nIndex, RES_TXTATR_METAFIELD, eMode);
        // which is innermost?
        SwTextAttr *const pTextAttr = pMetaTextAttr
            ? (pMetaFieldTextAttr
                ? ((pMetaFieldTextAttr->GetStart() >
                        pMetaTextAttr->GetStart())
                    ? pMetaFieldTextAttr : pMetaTextAttr)
                : pMetaTextAttr)
            : pMetaFieldTextAttr;
        uno::Reference<XTextContent> xRet;
        if (pTextAttr)
        {
            ::sw::Meta *const pMeta(
                static_cast<SwFormatMeta &>(pTextAttr->GetAttr()).GetMeta());
            assert(pMeta);
            xRet.set(pMeta->MakeUnoObject(), uno::UNO_QUERY);
        }
        return xRet;
    }

    // Read the special properties of the cursor
    bool getCursorPropertyValue(const SfxItemPropertySimpleEntry& rEntry
                                            , SwPaM& rPam
                                            , Any *pAny
                                            , PropertyState& eState
                                            , const SwTextNode* pNode  )
    {
        PropertyState eNewState = PropertyState_DIRECT_VALUE;
        bool bDone = true;
        switch(rEntry.nWID)
        {
            case FN_UNO_PARA_CONT_PREV_SUBTREE:
                if (pAny)
                {
                    const SwTextNode * pTmpNode = pNode;

                    if (!pTmpNode)
                        pTmpNode = rPam.GetNode().GetTextNode();

                    bool bRet = false;

                    if ( pTmpNode &&
                         pTmpNode->GetNum() &&
                         pTmpNode->GetNum()->IsContinueingPreviousSubTree() )
                    {
                        bRet = true;
                    }

                    *pAny <<= bRet;
                }
            break;
            case FN_UNO_PARA_NUM_STRING:
                if (pAny)
                {
                    const SwTextNode * pTmpNode = pNode;

                    if (!pTmpNode)
                        pTmpNode = rPam.GetNode().GetTextNode();

                    OUString sRet;
                    if ( pTmpNode && pTmpNode->GetNum() )
                    {
                        sRet = pTmpNode->GetNumString();
                    }

                    *pAny <<= sRet;
                }
            break;
            case RES_PARATR_OUTLINELEVEL:
                if (pAny)
                {
                    const SwTextNode * pTmpNode = pNode;

                    if (!pTmpNode)
                        pTmpNode = rPam.GetNode().GetTextNode();

                    sal_Int16 nRet = -1;
                    if ( pTmpNode )
                        nRet = sal::static_int_cast< sal_Int16 >( pTmpNode->GetAttrOutlineLevel() );

                    *pAny <<= nRet;
                }
            break;
            case FN_UNO_PARA_CONDITIONAL_STYLE_NAME:
            case FN_UNO_PARA_STYLE :
            {
                SwFormatColl* pFormat = nullptr;
                if(pNode)
                    pFormat = FN_UNO_PARA_CONDITIONAL_STYLE_NAME == rEntry.nWID
                                ? pNode->GetFormatColl() : &pNode->GetAnyFormatColl();
                else
                {
                    pFormat = SwUnoCursorHelper::GetCurTextFormatColl(rPam,
                            FN_UNO_PARA_CONDITIONAL_STYLE_NAME == rEntry.nWID);
                }
                if(pFormat)
                {
                    if( pAny )
                    {
                        OUString sVal;
                        SwStyleNameMapper::FillProgName(pFormat->GetName(), sVal, SwGetPoolIdFromName::TxtColl );
                        *pAny <<= sVal;
                    }
                }
                else
                    eNewState = PropertyState_AMBIGUOUS_VALUE;
            }
            break;
            case FN_UNO_PAGE_STYLE :
            {
                OUString sVal;
                GetCurPageStyle(rPam, sVal);
                if( pAny )
                    *pAny <<= sVal;
                if(sVal.isEmpty())
                    eNewState = PropertyState_AMBIGUOUS_VALUE;
            }
            break;
            case FN_UNO_NUM_START_VALUE  :
                if( pAny )
                {
                    sal_Int16 nValue = IsNodeNumStart(rPam, eNewState);
                    *pAny <<= nValue;
                }
            break;
            case FN_UNO_NUM_LEVEL  :
            case FN_UNO_IS_NUMBER  :
            // #i91601#
            case FN_UNO_LIST_ID:
            case FN_NUMBER_NEWSTART:
            {
                // a multi selection is not considered
                const SwTextNode* pTextNd = rPam.GetNode().GetTextNode();
                if ( pTextNd && pTextNd->IsInList() )
                {
                    if( pAny )
                    {
                        if(rEntry.nWID == FN_UNO_NUM_LEVEL)
                            *pAny <<= static_cast<sal_Int16>(pTextNd->GetActualListLevel());
                        else if(rEntry.nWID == FN_UNO_IS_NUMBER)
                        {
                            *pAny <<= pTextNd->IsCountedInList();
                        }
                        // #i91601#
                        else if ( rEntry.nWID == FN_UNO_LIST_ID )
                        {
                            *pAny <<= pTextNd->GetListId();
                        }
                        else
                        {
                            *pAny <<= pTextNd->IsListRestart();
                        }
                    }
                }
                else
                {
                    eNewState = PropertyState_DEFAULT_VALUE;

                    if( pAny )
                    {
                        // #i30838# set default values for default properties
                        if(rEntry.nWID == FN_UNO_NUM_LEVEL)
                            *pAny <<= static_cast<sal_Int16>( 0 );
                        else if(rEntry.nWID == FN_UNO_IS_NUMBER)
                            *pAny <<= false;
                        // #i91601#
                        else if ( rEntry.nWID == FN_UNO_LIST_ID )
                        {
                            *pAny <<= OUString();
                        }
                        else
                            *pAny <<= false;
                    }
                }
                //PROPERTY_MAYBEVOID!
            }
            break;
            case FN_UNO_NUM_RULES  :
                if( pAny )
                    getNumberingProperty(rPam, eNewState, pAny);
                else
                {
                    if( !SwDoc::GetNumRuleAtPos( *rPam.GetPoint() ) )
                        eNewState = PropertyState_DEFAULT_VALUE;
                }
                break;
            case FN_UNO_DOCUMENT_INDEX_MARK:
            {
                std::vector<SwTextAttr *> marks;
                if (rPam.GetNode().IsTextNode())
                {
                    marks = rPam.GetNode().GetTextNode()->GetTextAttrsAt(
                        rPam.GetPoint()->nContent.GetIndex(), RES_TXTATR_TOXMARK);
                }
                if (marks.size())
                {
                    if( pAny )
                    {   // hmm... can only return 1 here
                        SwTOXMark & rMark =
                            static_cast<SwTOXMark &>((*marks.begin())->GetAttr());
                        const uno::Reference< text::XDocumentIndexMark > xRef =
                            SwXDocumentIndexMark::CreateXDocumentIndexMark(
                                *rPam.GetDoc(), &rMark);
                        (*pAny) <<= xRef;
                    }
                }
                else
                    //also here - indistinguishable
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_DOCUMENT_INDEX:
            {
                SwTOXBase* pBase = SwDoc::GetCurTOX(
                                                        *rPam.Start() );
                if( pBase )
                {
                    if( pAny )
                    {
                        const uno::Reference< text::XDocumentIndex > xRef =
                            SwXDocumentIndex::CreateXDocumentIndex(*rPam.GetDoc(),
                                static_cast<SwTOXBaseSection *>(pBase));
                        (*pAny) <<= xRef;
                    }
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_TEXT_FIELD:
            {
                const SwPosition *pPos = rPam.Start();
                const SwTextNode *pTextNd =
                    rPam.GetDoc()->GetNodes()[pPos->nNode.GetIndex()]->GetTextNode();
                const SwTextAttr* pTextAttr = pTextNd
                    ? pTextNd->GetFieldTextAttrAt( pPos->nContent.GetIndex(), true )
                    : nullptr;
                if ( pTextAttr != nullptr )
                {
                    if( pAny )
                    {
                        uno::Reference<text::XTextField> const xField(
                            SwXTextField::CreateXTextField(rPam.GetDoc(),
                               &pTextAttr->GetFormatField()));
                        *pAny <<= xField;
                    }
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_TEXT_TABLE:
            case FN_UNO_CELL:
            {
                SwStartNode* pSttNode = rPam.GetNode().StartOfSectionNode();
                SwStartNodeType eType = pSttNode->GetStartNodeType();
                if(SwTableBoxStartNode == eType)
                {
                    if( pAny )
                    {
                        const SwTableNode* pTableNode = pSttNode->FindTableNode();
                        SwFrameFormat* pTableFormat = static_cast<SwFrameFormat*>(pTableNode->GetTable().GetFrameFormat());
                        //SwTable& rTable = static_cast<SwTableNode*>(pSttNode)->GetTable();
                        if(FN_UNO_TEXT_TABLE == rEntry.nWID)
                        {
                            uno::Reference< XTextTable >  xTable = SwXTextTables::GetObject(*pTableFormat);
                            *pAny <<= xTable;
                        }
                        else
                        {
                            SwTableBox* pBox = pSttNode->GetTableBox();
                            uno::Reference< XCell >  xCell = SwXCell::CreateXCell(pTableFormat, pBox);
                            *pAny <<= xCell;
                        }
                    }
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_TEXT_FRAME:
            {
                SwStartNode* pSttNode = rPam.GetNode().StartOfSectionNode();
                SwStartNodeType eType = pSttNode->GetStartNodeType();

                SwFrameFormat* pFormat;
                if(eType == SwFlyStartNode && nullptr != (pFormat = pSttNode->GetFlyFormat()))
                {
                    if( pAny )
                    {
                        uno::Reference<XTextFrame> const xFrame(
                            SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat));
                        (*pAny) <<= xFrame;
                    }
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_TEXT_SECTION:
            {
                SwSection* pSect = SwDoc::GetCurrSection(*rPam.GetPoint());
                if(pSect)
                {
                    if( pAny )
                    {
                        uno::Reference< XTextSection >  xSect = SwXTextSections::GetObject( *pSect->GetFormat() );
                        *pAny <<= xSect;
                    }
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_TEXT_PARAGRAPH:
            {
                SwTextNode* pTextNode = rPam.GetPoint()->nNode.GetNode().GetTextNode();
                if (pTextNode)
                {
                    if (pAny)
                    {
                        uno::Reference<text::XTextContent> xParagraph = SwXParagraph::CreateXParagraph(*pTextNode->GetDoc(), pTextNode);
                        *pAny <<= xParagraph;
                    }
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_ENDNOTE:
            case FN_UNO_FOOTNOTE:
            {
                SwTextAttr *const pTextAttr = rPam.GetNode().IsTextNode() ?
                    rPam.GetNode().GetTextNode()->GetTextAttrForCharAt(
                        rPam.GetPoint()->nContent.GetIndex(), RES_TXTATR_FTN) : nullptr;
                if(pTextAttr)
                {
                    const SwFormatFootnote& rFootnote = pTextAttr->GetFootnote();
                    if(rFootnote.IsEndNote() == (FN_UNO_ENDNOTE == rEntry.nWID))
                    {
                        if( pAny )
                        {
                            const uno::Reference< text::XFootnote > xFootnote =
                                SwXFootnote::CreateXFootnote(*rPam.GetDoc(),
                                        &const_cast<SwFormatFootnote&>(rFootnote));
                            *pAny <<= xFootnote;
                        }
                    }
                    else
                        eNewState = PropertyState_DEFAULT_VALUE;
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_REFERENCE_MARK:
            {
                std::vector<SwTextAttr *> marks;
                if (rPam.GetNode().IsTextNode())
                {
                    marks = rPam.GetNode().GetTextNode()->GetTextAttrsAt(
                                rPam.GetPoint()->nContent.GetIndex(), RES_TXTATR_REFMARK);
                }
                if (marks.size())
                {
                    if( pAny )
                    {   // hmm... can only return 1 here
                        const SwFormatRefMark& rRef = (*marks.begin())->GetRefMark();
                        uno::Reference<XTextContent> const xRef =
                            SwXReferenceMark::CreateXReferenceMark(*rPam.GetDoc(),
                                    const_cast<SwFormatRefMark*>(&rRef));
                        *pAny <<= xRef;
                    }
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case FN_UNO_NESTED_TEXT_CONTENT:
            {
                uno::Reference<XTextContent> const xRet(rPam.GetNode().IsTextNode()
                    ? GetNestedTextContent(*rPam.GetNode().GetTextNode(),
                        rPam.GetPoint()->nContent.GetIndex(), false)
                    : nullptr);
                if (xRet.is())
                {
                    if (pAny)
                    {
                        (*pAny) <<= xRet;
                    }
                }
                else
                {
                    eNewState = PropertyState_DEFAULT_VALUE;
                }
            }
            break;
            case FN_UNO_CHARFMT_SEQUENCE:
            {

                SwTextNode *const pTextNode = rPam.GetNode().GetTextNode();
                if (&rPam.GetNode() == &rPam.GetNode(false)
                    && pTextNode && pTextNode->GetpSwpHints())
                {
                    sal_Int32 nPaMStart = rPam.GetPoint()->nContent.GetIndex();
                    sal_Int32 nPaMEnd = rPam.GetMark() ? rPam.GetMark()->nContent.GetIndex() : nPaMStart;
                    if(nPaMStart > nPaMEnd)
                    {
                        std::swap(nPaMStart, nPaMEnd);
                    }
                    Sequence< OUString> aCharStyles;
                    SwpHints* pHints = pTextNode->GetpSwpHints();
                    for( size_t nAttr = 0; nAttr < pHints->Count(); ++nAttr )
                    {
                        SwTextAttr* pAttr = pHints->Get( nAttr );
                        if(pAttr->Which() != RES_TXTATR_CHARFMT)
                            continue;
                        const sal_Int32 nAttrStart = pAttr->GetStart();
                        const sal_Int32 nAttrEnd = *pAttr->GetEnd();
                        //check if the attribute touches the selection
                        if( ( nAttrEnd > nPaMStart && nAttrStart < nPaMEnd ) ||
                            ( !nAttrStart && !nAttrEnd && !nPaMStart && !nPaMEnd ) )
                        {
                            //check for overlapping
                            if(nAttrStart > nPaMStart ||
                                        nAttrEnd < nPaMEnd)
                            {
                                aCharStyles.realloc(0);
                                break;
                            }
                            else
                            {
                                //now the attribute should start before or at the selection
                                //and it should end at the end of the selection or behind
                                OSL_ENSURE(nAttrStart <= nPaMStart && nAttrEnd >=nPaMEnd,
                                        "attribute overlaps or is outside");
                                //now the name of the style has to be added to the sequence
                                aCharStyles.realloc(aCharStyles.getLength() + 1);
                                OSL_ENSURE(pAttr->GetCharFormat().GetCharFormat(), "no character format set");
                                aCharStyles.getArray()[aCharStyles.getLength() - 1] =
                                            SwStyleNameMapper::GetProgName(
                                                pAttr->GetCharFormat().GetCharFormat()->GetName(), SwGetPoolIdFromName::ChrFmt);
                            }
                        }

                    }
                    eNewState =
                        aCharStyles.getLength() ?
                            PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
                    if(pAny)
                        (*pAny) <<= aCharStyles;
                }
                else
                    eNewState = PropertyState_DEFAULT_VALUE;
            }
            break;
            case RES_TXTATR_CHARFMT:
            // no break here!
            default: bDone = false;
        }
        if( bDone )
            eState = eNewState;
        return bDone;
    };

    sal_Int16 IsNodeNumStart(SwPaM const & rPam, PropertyState& eState)
    {
        const SwTextNode* pTextNd = rPam.GetNode().GetTextNode();
        // correction: check, if restart value is set at the text node and use
        // new method <SwTextNode::GetAttrListRestartValue()> to retrieve the value
        if ( pTextNd && pTextNd->GetNumRule() && pTextNd->IsListRestart() &&
             pTextNd->HasAttrListRestartValue() )
        {
            eState = PropertyState_DIRECT_VALUE;
            sal_Int16 nTmp = sal::static_int_cast< sal_Int16 >(pTextNd->GetAttrListRestartValue());
            return nTmp;
        }
        eState = PropertyState_DEFAULT_VALUE;
        return -1;
    }

    void setNumberingProperty(const Any& rValue, SwPaM& rPam)
    {
        uno::Reference<XIndexReplace> xIndexReplace;
        if(rValue >>= xIndexReplace)
        {
            SwXNumberingRules* pSwNum = nullptr;

            uno::Reference<XUnoTunnel> xNumTunnel(xIndexReplace, UNO_QUERY);
            if(xNumTunnel.is())
            {
                pSwNum = reinterpret_cast< SwXNumberingRules * >(
                    sal::static_int_cast< sal_IntPtr >( xNumTunnel->getSomething( SwXNumberingRules::getUnoTunnelId() )));
            }

            if(pSwNum)
            {
                SwDoc* pDoc = rPam.GetDoc();
                if(pSwNum->GetNumRule())
                {
                    SwNumRule aRule(*pSwNum->GetNumRule());
                    const OUString* pNewCharStyles =  pSwNum->GetNewCharStyleNames();
                    const OUString* pBulletFontNames = pSwNum->GetBulletFontNames();
                    for(sal_uInt16 i = 0; i < MAXLEVEL; i++)
                    {
                        SwNumFormat aFormat(aRule.Get( i ));
                        if (!pNewCharStyles[i].isEmpty() &&
                            !SwXNumberingRules::isInvalidStyle(pNewCharStyles[i]) &&
                            (!aFormat.GetCharFormat() || pNewCharStyles[i] != aFormat.GetCharFormat()->GetName()))
                        {
                            if (pNewCharStyles[i].isEmpty())
                            {
                                // FIXME
                                // Is something missing/wrong here?
                                // if condition is always false due to outer check!
                                aFormat.SetCharFormat(nullptr);
                            }
                            else
                            {

                                // get CharStyle and set the rule
                                const size_t nChCount = pDoc->GetCharFormats()->size();
                                SwCharFormat* pCharFormat = nullptr;
                                for(size_t nCharFormat = 0; nCharFormat < nChCount; ++nCharFormat)
                                {
                                    SwCharFormat& rChFormat = *((*(pDoc->GetCharFormats()))[nCharFormat]);
                                    if(rChFormat.GetName() == pNewCharStyles[i])
                                    {
                                        pCharFormat = &rChFormat;
                                        break;
                                    }
                                }

                                if(!pCharFormat)
                                {
                                    SfxStyleSheetBasePool* pPool = pDoc->GetDocShell()->GetStyleSheetPool();
                                    SfxStyleSheetBase* pBase;
                                    pBase = pPool->Find(pNewCharStyles[i], SfxStyleFamily::Char);
                                // shall it really be created?
                                    if(!pBase)
                                        pBase = &pPool->Make(pNewCharStyles[i], SfxStyleFamily::Page);
                                    pCharFormat = static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat();
                                }
                                if(pCharFormat)
                                    aFormat.SetCharFormat(pCharFormat);
                            }
                        }
                        //Now again for fonts
                        if(
                           !pBulletFontNames[i].isEmpty() &&
                           !SwXNumberingRules::isInvalidStyle(pBulletFontNames[i]) &&
                           (!aFormat.GetBulletFont() || aFormat.GetBulletFont()->GetFamilyName() != pBulletFontNames[i])
                          )
                        {
                            const SvxFontListItem* pFontListItem =
                                    static_cast<const SvxFontListItem* >(pDoc->GetDocShell()
                                                        ->GetItem( SID_ATTR_CHAR_FONTLIST ));
                            const FontList*  pList = pFontListItem->GetFontList();

                            FontMetric aFontMetric = pList->Get(
                                pBulletFontNames[i],WEIGHT_NORMAL, ITALIC_NONE);
                            vcl::Font aFont(aFontMetric);
                            aFormat.SetBulletFont(&aFont);
                        }
                        aRule.Set( i, aFormat );
                    }
                    UnoActionContext aAction(pDoc);

                    if( rPam.GetNext() != &rPam )           // Multiple selection?
                    {
                        pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
                        SwPamRanges aRangeArr( rPam );
                        SwPaM aPam( *rPam.GetPoint() );
                        for ( size_t n = 0; n < aRangeArr.Count(); ++n )
                        {
                            // no start of a new list
                            pDoc->SetNumRule( aRangeArr.SetPam( n, aPam ), aRule, false );
                        }
                        pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
                    }
                    else
                    {
                        // no start of a new list
                        pDoc->SetNumRule( rPam, aRule, false );
                    }

                }
                else if(!pSwNum->GetCreatedNumRuleName().isEmpty())
                {
                    UnoActionContext aAction( pDoc );
                    SwNumRule* pRule = pDoc->FindNumRulePtr( pSwNum->GetCreatedNumRuleName() );
                    if ( !pRule )
                        throw RuntimeException();
                    // no start of a new list
                    pDoc->SetNumRule( rPam, *pRule, false );
                }
                else
                {
                    // #i103817#
                    // outline numbering
                    UnoActionContext aAction(pDoc);
                    SwNumRule* pRule = pDoc->GetOutlineNumRule();
                    if(!pRule)
                        throw RuntimeException();
                    pDoc->SetNumRule( rPam, *pRule, false );
                }
            }
        }
        else if ( rValue.getValueType() == cppu::UnoType<void>::get() )
        {
            rPam.GetDoc()->DelNumRules(rPam);
        }
    }

    void  getNumberingProperty(SwPaM& rPam, PropertyState& eState, Any * pAny )
    {
        const SwNumRule* pNumRule = SwDoc::GetNumRuleAtPos( *rPam.GetPoint() );
        if(pNumRule)
        {
            uno::Reference< XIndexReplace >  xNum = new SwXNumberingRules(*pNumRule);
            if ( pAny )
                *pAny <<= xNum;
            eState = PropertyState_DIRECT_VALUE;
        }
        else
            eState = PropertyState_DEFAULT_VALUE;
    }

    void GetCurPageStyle(SwPaM const & rPaM, OUString &rString)
    {
        if (!rPaM.GetContentNode())
            return; // TODO: is there an easy way to get it for tables/sections?
        SwContentFrame* pFrame = rPaM.GetContentNode()->getLayoutFrame(rPaM.GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout());
        if(pFrame)
        {
            const SwPageFrame* pPage = pFrame->FindPageFrame();
            if(pPage)
            {
                SwStyleNameMapper::FillProgName(pPage->GetPageDesc()->GetName(),
                    rString, SwGetPoolIdFromName::PageDesc);
            }
        }
    }

    // reset special properties of the cursor
    void resetCursorPropertyValue(const SfxItemPropertySimpleEntry& rEntry, SwPaM& rPam)
    {
        SwDoc* pDoc = rPam.GetDoc();
        switch(rEntry.nWID)
        {
            case FN_UNO_PARA_STYLE :
            break;
            case FN_UNO_PAGE_STYLE :
            break;
            case FN_UNO_NUM_START_VALUE  :
            {
                UnoActionContext aAction(pDoc);

                if( rPam.GetNext() != &rPam )           // Multiple selection?
                {
                    pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
                    SwPamRanges aRangeArr( rPam );
                    SwPaM aPam( *rPam.GetPoint() );
                    for( size_t n = 0; n < aRangeArr.Count(); ++n )
                        pDoc->SetNodeNumStart( *aRangeArr.SetPam( n, aPam ).GetPoint(), 1 );
                    pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
                }
                else
                    pDoc->SetNodeNumStart( *rPam.GetPoint(), 0 );
            }

            break;
            case FN_UNO_NUM_LEVEL  :
            break;
            case FN_UNO_NUM_RULES:
            break;
            case FN_UNO_CHARFMT_SEQUENCE:
            {
                std::set<sal_uInt16> aWhichIds;
                aWhichIds.insert( RES_TXTATR_CHARFMT);
                pDoc->ResetAttrs(rPam, true, aWhichIds);
            }
            break;
        }
    }

    void InsertFile(SwUnoCursor* pUnoCursor, const OUString& rURL,
        const uno::Sequence< beans::PropertyValue >& rOptions)
    {
        std::unique_ptr<SfxMedium> pMed;
        SwDoc* pDoc = pUnoCursor->GetDoc();
        SwDocShell* pDocSh = pDoc->GetDocShell();
        utl::MediaDescriptor aMediaDescriptor( rOptions );
        OUString sFileName = rURL;
        OUString sFilterName, sFilterOptions, sPassword, sBaseURL;
        uno::Reference < io::XStream > xStream;
        uno::Reference < io::XInputStream > xInputStream;

        if( sFileName.isEmpty() )
            aMediaDescriptor[utl::MediaDescriptor::PROP_URL()] >>= sFileName;
        if( sFileName.isEmpty() )
            aMediaDescriptor[utl::MediaDescriptor::PROP_FILENAME()] >>= sFileName;
        aMediaDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream;
        aMediaDescriptor[utl::MediaDescriptor::PROP_STREAM()] >>= xStream;
        aMediaDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream;
        aMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] >>= sFilterName;
        aMediaDescriptor[utl::MediaDescriptor::PROP_FILTEROPTIONS()] >>= sFilterOptions;
        aMediaDescriptor[utl::MediaDescriptor::PROP_PASSWORD()] >>= sPassword;
        aMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= sBaseURL;
        if ( !xInputStream.is() && xStream.is() )
            xInputStream = xStream->getInputStream();

        if(!pDocSh || (sFileName.isEmpty() && !xInputStream.is()))
            return;

        SfxObjectFactory& rFact = pDocSh->GetFactory();
        std::shared_ptr<const SfxFilter> pFilter = rFact.GetFilterContainer()->GetFilter4FilterName( sFilterName );
        uno::Reference < embed::XStorage > xReadStorage;
        if( xInputStream.is() )
        {
            uno::Sequence< uno::Any > aArgs( 2 );
            aArgs[0] <<= xInputStream;
            aArgs[1] <<= embed::ElementModes::READ;
            try
            {
                xReadStorage.set( ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ),
                                  uno::UNO_QUERY );
            }
            catch( const io::IOException&) {}
        }
        if ( !pFilter )
        {
            if( xInputStream.is() && !xReadStorage.is())
            {
                pMed.reset(new SfxMedium);
                pMed->setStreamToLoadFrom(xInputStream, true );
            }
            else
                pMed.reset(xReadStorage.is() ?
                    new SfxMedium(xReadStorage, sBaseURL, nullptr ) :
                    new SfxMedium(sFileName, StreamMode::READ, nullptr, nullptr ));
            if( !sBaseURL.isEmpty() )
                pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, sBaseURL ) );

            SfxFilterMatcher aMatcher( rFact.GetFilterContainer()->GetName() );
            ErrCode nErr = aMatcher.GuessFilter(*pMed, pFilter, SfxFilterFlags::NONE);
            if ( nErr || !pFilter)
                return;
            pMed->SetFilter( pFilter );
        }
        else
        {
            if( xInputStream.is() && !xReadStorage.is())
            {
                pMed.reset(new SfxMedium);
                pMed->setStreamToLoadFrom(xInputStream, true );
                pMed->SetFilter( pFilter );
            }
            else
            {
                if( xReadStorage.is() )
                {
                    pMed.reset(new SfxMedium(xReadStorage, sBaseURL, nullptr ));
                    pMed->SetFilter( pFilter );
                }
                else
                    pMed.reset(new SfxMedium(sFileName, StreamMode::READ, pFilter, nullptr));
            }
            if(!sFilterOptions.isEmpty())
                pMed->GetItemSet()->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, sFilterOptions ) );
            if(!sBaseURL.isEmpty())
                pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, sBaseURL ) );
        }

        // this sourcecode is not responsible for the lifetime of the shell, SfxObjectShellLock should not be used
        SfxObjectShellRef aRef( pDocSh );

        pMed->Download();   // if necessary: start the download
        if( aRef.is() && 1 < aRef->GetRefCount() )  // Ref still valid?
        {
            SwReader* pRdr;
            SfxItemSet* pSet =  pMed->GetItemSet();
            pSet->Put(SfxBoolItem(FN_API_CALL, true));
            if(!sPassword.isEmpty())
                pSet->Put(SfxStringItem(SID_PASSWORD, sPassword));
            Reader *pRead = pDocSh->StartConvertFrom( *pMed, &pRdr, nullptr, pUnoCursor);
            if( pRead )
            {

                UnoActionContext aContext(pDoc);

                if(pUnoCursor->HasMark())
                    pDoc->getIDocumentContentOperations().DeleteAndJoin(*pUnoCursor);

                SwNodeIndex aSave(  pUnoCursor->GetPoint()->nNode, -1 );
                sal_Int32 nContent = pUnoCursor->GetPoint()->nContent.GetIndex();

                ErrCode nErrno = pRdr->Read( *pRead );   // and paste the document

                if(!nErrno)
                {
                    ++aSave;
                    pUnoCursor->SetMark();
                    pUnoCursor->GetMark()->nNode = aSave;

                    SwContentNode* pCntNode = aSave.GetNode().GetContentNode();
                    if( !pCntNode )
                        nContent = 0;
                    pUnoCursor->GetMark()->nContent.Assign( pCntNode, nContent );
                }

                delete pRdr;

            }
        }
    }

    // insert text and scan for CR characters in order to insert
    // paragraph breaks at those positions by calling SplitNode
    bool DocInsertStringSplitCR(
            SwDoc &rDoc,
            const SwPaM &rNewCursor,
            const OUString &rText,
            const bool bForceExpandHints )
    {
        bool bOK = true;

            const SwInsertFlags nInsertFlags =
                bForceExpandHints
                ? ( SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND)
                : SwInsertFlags::EMPTYEXPAND;

        // grouping done in InsertString is intended for typing, not API calls
        ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
        SwTextNode* const pTextNd =
            rNewCursor.GetPoint()->nNode.GetNode().GetTextNode();
        if (!pTextNd)
        {
            SAL_INFO("sw.uno", "DocInsertStringSplitCR: need a text node");
            return false;
        }
        OUString aText;
        sal_Int32 nStartIdx = 0;
        const sal_Int32 nMaxLength = COMPLETE_STRING - pTextNd->GetText().getLength();

        sal_Int32 nIdx = rText.indexOf( '\r', nStartIdx );
        if( ( nIdx == -1 && nMaxLength < rText.getLength() ) ||
            ( nIdx != -1 && nMaxLength < nIdx ) )
        {
            nIdx = nMaxLength;
        }
        while (nIdx != -1 )
        {
            OSL_ENSURE( nIdx - nStartIdx >= 0, "index negative!" );
            aText = rText.copy( nStartIdx, nIdx - nStartIdx );
            if (!aText.isEmpty() &&
                !rDoc.getIDocumentContentOperations().InsertString( rNewCursor, aText, nInsertFlags ))
            {
                OSL_FAIL( "Doc->Insert(Str) failed." );
                bOK = false;
            }
            if (!rDoc.getIDocumentContentOperations().SplitNode( *rNewCursor.GetPoint(), false ) )
            {
                OSL_FAIL( "SplitNode failed" );
                bOK = false;
            }
            nStartIdx = nIdx + 1;
            nIdx = rText.indexOf( '\r', nStartIdx );
        }
        aText = rText.copy( nStartIdx );
        if (!aText.isEmpty() &&
            !rDoc.getIDocumentContentOperations().InsertString( rNewCursor, aText, nInsertFlags ))
        {
            OSL_FAIL( "Doc->Insert(Str) failed." );
            bOK = false;
        }

        return bOK;
    }

    void makeRedline( SwPaM const & rPaM,
        const OUString& rRedlineType,
        const uno::Sequence< beans::PropertyValue >& rRedlineProperties )
    {
        IDocumentRedlineAccess* pRedlineAccess = &rPaM.GetDoc()->getIDocumentRedlineAccess();

        RedlineType_t eType;
        if      ( rRedlineType == "Insert" )
            eType = nsRedlineType_t::REDLINE_INSERT;
        else if ( rRedlineType == "Delete" )
            eType = nsRedlineType_t::REDLINE_DELETE;
        else if ( rRedlineType == "Format" )
            eType = nsRedlineType_t::REDLINE_FORMAT;
        else if ( rRedlineType == "TextTable" )
            eType = nsRedlineType_t::REDLINE_TABLE;
        else if ( rRedlineType == "ParagraphFormat" )
            eType = nsRedlineType_t::REDLINE_PARAGRAPH_FORMAT;
        else
            throw lang::IllegalArgumentException();

        //todo: what about REDLINE_FMTCOLL?
        comphelper::SequenceAsHashMap aPropMap( rRedlineProperties );
        std::size_t nAuthor = 0;
        OUString sAuthor;
        if( aPropMap.getValue("RedlineAuthor") >>= sAuthor )
            nAuthor = pRedlineAccess->InsertRedlineAuthor(sAuthor);

        OUString sComment;
        SwRedlineData aRedlineData( eType, nAuthor );
        if( aPropMap.getValue("RedlineComment") >>= sComment )
            aRedlineData.SetComment( sComment );

        ::util::DateTime aStamp;
        if( aPropMap.getValue("RedlineDateTime") >>= aStamp )
        {
            aRedlineData.SetTimeStamp( DateTime( aStamp));
        }

        SwRedlineExtraData_FormattingChanges* pRedlineExtraData = nullptr;

        // Read the 'Redline Revert Properties' from the parameters
        uno::Sequence< beans::PropertyValue > aRevertProperties;
        // Check if the value exists
        if ( aPropMap.getValue("RedlineRevertProperties") >>= aRevertProperties )
        {
            int nMap = 0;
            // Make sure that paragraph format gets its own map, otherwise e.g. fill attributes are not preserved.
            if (eType == nsRedlineType_t::REDLINE_PARAGRAPH_FORMAT)
                nMap = PROPERTY_MAP_PARAGRAPH;
            else
                nMap = PROPERTY_MAP_TEXTPORTION_EXTENSIONS;
            SfxItemPropertySet const& rPropSet = *aSwMapProvider.GetPropertySet(nMap);

            // Check if there are any properties
            if (aRevertProperties.getLength())
            {
                SwDoc *const pDoc = rPaM.GetDoc();

                // Build set of attributes we want to fetch
                std::vector<sal_uInt16> aWhichPairs;
                std::vector<SfxItemPropertySimpleEntry const*> aEntries;
                aEntries.reserve(aRevertProperties.getLength());
                for (sal_Int32 i = 0; i < aRevertProperties.getLength(); ++i)
                {
                    const OUString &rPropertyName = aRevertProperties[i].Name;
                    SfxItemPropertySimpleEntry const* pEntry = rPropSet.getPropertyMap().getByName(rPropertyName);

                    if (!pEntry)
                    {
                        // unknown property
                        break;
                    }
                    else if (pEntry->nFlags & beans::PropertyAttribute::READONLY)
                    {
                        break;
                    }
                    else
                    {
                        // FIXME: we should have some nice way of merging ranges surely ?
                        aWhichPairs.push_back(pEntry->nWID);
                        aWhichPairs.push_back(pEntry->nWID);
                    }
                    aEntries.push_back(pEntry);
                }

                if (!aWhichPairs.empty())
                {
                    aWhichPairs.push_back(0); // terminate
                    SfxItemSet aItemSet(pDoc->GetAttrPool(), &aWhichPairs[0]);

                    for (size_t i = 0; i < aEntries.size(); ++i)
                    {
                        SfxItemPropertySimpleEntry const*const pEntry = aEntries[i];
                        const uno::Any &rValue = aRevertProperties[i].Value;
                        rPropSet.setPropertyValue(*pEntry, rValue, aItemSet);
                    }
                    pRedlineExtraData = new SwRedlineExtraData_FormattingChanges( &aItemSet );
                }
            }
        }

        SwRangeRedline* pRedline = new SwRangeRedline( aRedlineData, rPaM );
        RedlineFlags nPrevMode = pRedlineAccess->GetRedlineFlags( );
        pRedline->SetExtraData( pRedlineExtraData );

        pRedlineAccess->SetRedlineFlags_intern(RedlineFlags::On);
        auto const result(pRedlineAccess->AppendRedline(pRedline, false));
        pRedlineAccess->SetRedlineFlags_intern( nPrevMode );
        if (IDocumentRedlineAccess::AppendResult::IGNORED == result)
            throw lang::IllegalArgumentException();
    }

    void makeTableRowRedline( SwTableLine& rTableLine,
        const OUString& rRedlineType,
        const uno::Sequence< beans::PropertyValue >& rRedlineProperties )
    {
        IDocumentRedlineAccess* pRedlineAccess = &rTableLine.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess();

        RedlineType_t eType;
        if ( rRedlineType == "TableRowInsert" )
        {
            eType = nsRedlineType_t::REDLINE_TABLE_ROW_INSERT;
        }
        else if ( rRedlineType == "TableRowDelete" )
        {
            eType = nsRedlineType_t::REDLINE_TABLE_ROW_DELETE;
        }
        else
        {
            throw lang::IllegalArgumentException();
        }

        comphelper::SequenceAsHashMap aPropMap( rRedlineProperties );
        std::size_t nAuthor = 0;
        OUString sAuthor;
        if( aPropMap.getValue("RedlineAuthor") >>= sAuthor )
            nAuthor = pRedlineAccess->InsertRedlineAuthor(sAuthor);

        OUString sComment;
        SwRedlineData aRedlineData( eType, nAuthor );
        if( aPropMap.getValue("RedlineComment") >>= sComment )
            aRedlineData.SetComment( sComment );

        ::util::DateTime aStamp;
        if( aPropMap.getValue("RedlineDateTime") >>= aStamp )
        {
           aRedlineData.SetTimeStamp(
            DateTime( Date( aStamp.Day, aStamp.Month, aStamp.Year ), tools::Time( aStamp.Hours, aStamp.Minutes, aStamp.Seconds ) ) );
        }

        SwTableRowRedline* pRedline = new SwTableRowRedline( aRedlineData, rTableLine );
        RedlineFlags nPrevMode = pRedlineAccess->GetRedlineFlags( );
        pRedline->SetExtraData( nullptr );

        pRedlineAccess->SetRedlineFlags_intern(RedlineFlags::On);
        bool bRet = pRedlineAccess->AppendTableRowRedline( pRedline, false );
        pRedlineAccess->SetRedlineFlags_intern( nPrevMode );
        if( !bRet )
            throw lang::IllegalArgumentException();
    }

    void makeTableCellRedline( SwTableBox& rTableBox,
        const OUString& rRedlineType,
        const uno::Sequence< beans::PropertyValue >& rRedlineProperties )
    {
        IDocumentRedlineAccess* pRedlineAccess = &rTableBox.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess();

        RedlineType_t eType;
        if ( rRedlineType == "TableCellInsert" )
        {
            eType = nsRedlineType_t::REDLINE_TABLE_CELL_INSERT;
        }
        else if ( rRedlineType == "TableCellDelete" )
        {
            eType = nsRedlineType_t::REDLINE_TABLE_CELL_DELETE;
        }
        else
        {
            throw lang::IllegalArgumentException();
        }

        comphelper::SequenceAsHashMap aPropMap( rRedlineProperties );
        std::size_t nAuthor = 0;
        OUString sAuthor;
        if( aPropMap.getValue("RedlineAuthor") >>= sAuthor )
            nAuthor = pRedlineAccess->InsertRedlineAuthor(sAuthor);

        OUString sComment;
        SwRedlineData aRedlineData( eType, nAuthor );
        if( aPropMap.getValue("RedlineComment") >>= sComment )
            aRedlineData.SetComment( sComment );

        ::util::DateTime aStamp;
        if( aPropMap.getValue("RedlineDateTime") >>= aStamp )
        {
           aRedlineData.SetTimeStamp(
            DateTime( Date( aStamp.Day, aStamp.Month, aStamp.Year ), tools::Time( aStamp.Hours, aStamp.Minutes, aStamp.Seconds ) ) );
        }

        SwTableCellRedline* pRedline = new SwTableCellRedline( aRedlineData, rTableBox );
        RedlineFlags nPrevMode = pRedlineAccess->GetRedlineFlags( );
        pRedline->SetExtraData( nullptr );

        pRedlineAccess->SetRedlineFlags_intern(RedlineFlags::On);
        bool bRet = pRedlineAccess->AppendTableCellRedline( pRedline, false );
        pRedlineAccess->SetRedlineFlags_intern( nPrevMode );
        if( !bRet )
            throw lang::IllegalArgumentException();
    }

    void SwAnyMapHelper::SetValue( sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rAny )
    {
        sal_uInt32 nKey = (nWhichId << 16) + nMemberId;
        auto aIt = m_Map.find( nKey );
        if (aIt != m_Map.end())
            aIt->second = rAny;
        else
            m_Map.insert(std::make_pair(nKey, rAny));
    }

    bool    SwAnyMapHelper::FillValue( sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& pAny )
    {
        bool bRet = false;
        sal_uInt32 nKey = (nWhichId << 16) + nMemberId;
        auto aIt = m_Map.find( nKey );
        if (aIt != m_Map.end())
        {
            pAny = & aIt->second;
            bRet = true;
        }
        return bRet;
    }

    }//namespace SwUnoCursorHelper

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V581 The conditional expressions of the 'if' statements situated alongside each other are identical. Check lines: 982, 984.