/* -*- 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/beans/XPropertySet.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/embed/EmbedMisc.hpp>
#include <com/sun/star/embed/EmbedStates.hpp>
#include <com/sun/star/embed/EmbedVerbs.hpp>
#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
#include <com/sun/star/chart2/XChartDocument.hpp>
#include <com/sun/star/util/XModifiable.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
 
#include <hintids.hxx>
#include <sot/exchange.hxx>
#include <svx/xfillit0.hxx>
#include <svx/hdft.hxx>
#include <svx/svdview.hxx>
#include <svl/itemiter.hxx>
#include <tools/bigint.hxx>
#include <svtools/insdlg.hxx>
#include <sfx2/ipclient.hxx>
#include <editeng/editobj.hxx>
#include <editeng/formatbreakitem.hxx>
#include <editeng/svxacorr.hxx>
#include <editeng/ulspitem.hxx>
#include <vcl/graph.hxx>
#include <unotools/charclass.hxx>
#include <comphelper/storagehelper.hxx>
#include <comphelper/random.hxx>
#include <svx/svxdlg.hxx>
#include <svx/extrusionbar.hxx>
#include <svx/fontworkbar.hxx>
#include <dialoghelp.hxx>
#include <frmfmt.hxx>
#include <fmtftn.hxx>
#include <fmthdft.hxx>
#include <fmtpdsc.hxx>
#include <txtfrm.hxx>
#include <wdocsh.hxx>
#include <swmodule.hxx>
#include <wrtsh.hxx>
#include <view.hxx>
#include <cmdid.h>
#include <pagedesc.hxx>
#include <frmmgr.hxx>
#include <swundo.hxx>
#include <swcli.hxx>
#include <poolfmt.hxx>
#include <postithelper.hxx>
#include <edtwin.hxx>
#include <fmtcol.hxx>
#include <swtable.hxx>
#include <viscrs.hxx>
#include <swdtflvr.hxx>
#include <doc.hxx>
#include <IDocumentSettingAccess.hxx>
#include <SwCapObjType.hxx>
#include <SwStyleNameMapper.hxx>
#include <sfx2/request.hxx>
#include <paratr.hxx>
#include <ndtxt.hxx>
#include <editeng/acorrcfg.hxx>
#include <IMark.hxx>
#include <sfx2/bindings.hxx>
#include <flyfrm.hxx>
 
// -> #111827#
#include <SwRewriter.hxx>
#include <strings.hrc>
// <- #111827#
 
#include <toolkit/helper/vclunohelper.hxx>
#include <sfx2/viewfrm.hxx>
#include <vcl/uitest/logger.hxx>
#include <vcl/uitest/eventdescription.hxx>
#include <osl/diagnose.h>
#include <o3tl/unit_conversion.hxx>
#include <officecfg/Office/Common.hxx>
 
#include <PostItMgr.hxx>
#include <FrameControlsManager.hxx>
#include <fldmgr.hxx>
#include <docufld.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <fmtfld.hxx>
 
#include <sfx2/msgpool.hxx>
#include <sfx2/msg.hxx>
#include <svtools/embedhlp.hxx>
#include <svtools/strings.hrc>
#include <svtools/svtresid.hxx>
#include <svx/postattr.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/propertyvalue.hxx>
#include <svtools/optionsdrawinglayer.hxx>
#include <svl/numformat.hxx>
#include <svl/zformat.hxx>
#include <memory>
 
#include "../../core/crsr/callnk.hxx"
#include <frmtool.hxx>
#include <viewopt.hxx>
 
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentUndoRedo.hxx>
#include <UndoInsert.hxx>
#include <UndoCore.hxx>
#include <formatlinebreak.hxx>
#include <formatcontentcontrol.hxx>
#include <textcontentcontrol.hxx>
 
using namespace sw::mark;
using namespace com::sun::star;
namespace {
 
void collectUIInformation(const OUString& rAction, const OUString& aParameters)
{
    EventDescription aDescription;
    aDescription.aAction = rAction;
    aDescription.aParameters = {{"parameters", aParameters}};
    aDescription.aID = "writer_edit";
    aDescription.aKeyWord = "SwEditWinUIObject";
    aDescription.aParent = "MainWindow";
    UITestLogger::getInstance().logEvent(aDescription);
}
 
}
 
sal_uInt32 MakeAllOutlineContentTemporarilyVisible::nLock = 0;
 
static bool lcl_IsAllowed(const SwWrtShell* rSh)
{
    if (rSh->GetViewOptions()->IsShowOutlineContentVisibilityButton() && rSh->IsEndPara())
    {
        SwTextNode* pTextNode = rSh->GetCursor()->GetPointNode().GetTextNode();
        if (pTextNode && pTextNode->IsOutline())
        {
            // disallow if this is an outline node having folded content
            bool bVisible = true;
            pTextNode->GetAttrOutlineContentVisible(bVisible);
            if (!bVisible)
                return false;
        }
    }
    return true;
}
 
#define BITFLD_INI_LIST \
        m_bClearMark = \
        m_bIns = true;\
        m_bAddMode = \
        m_bBlockMode = \
        m_bExtMode = \
        m_bInSelect = \
        m_bLayoutMode = \
        m_bSelWrd = \
        m_bSelLn = \
        m_bRetainSelection = false; \
        m_bIsInClickToEdit = false;
 
static SvxAutoCorrect* lcl_IsAutoCorr()
{
    SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
    if( pACorr && !pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
                            ACFlags::AddNonBrkSpace | ACFlags::ChgOrdinalNumber | ACFlags::TransliterateRTL |
                            ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr | ACFlags::Autocorrect |
                            ACFlags::SetDOIAttr ))
        pACorr = nullptr;
    return pACorr;
}
 
void SwWrtShell::NoEdit(bool bHideCursor)
{
    if(bHideCursor)
        HideCursor();
}
 
void SwWrtShell::Edit()
{
    if (CanInsert())
    {
        ShowCursor();
    }
}
 
bool SwWrtShell::IsEndWrd()
{
    SwMvContext aMvContext(this);
    if(IsEndPara() && !IsSttPara())
        return true;
 
    return IsEndWord();
}
 
// Insert string
void SwWrtShell::InsertByWord( const OUString & rStr)
{
    if( rStr.isEmpty() )
        return;
 
    bool bDelim = GetAppCharClass().isLetterNumeric( rStr, 0 );
    sal_Int32 nPos = 0, nStt = 0;
    for( ; nPos < rStr.getLength(); nPos++ )
    {
        bool bTmpDelim = GetAppCharClass().isLetterNumeric( rStr, nPos );
        if( bTmpDelim != bDelim )
        {
            Insert( rStr.copy( nStt, nPos - nStt ));
            nStt = nPos;
        }
    }
    if( nStt != nPos )
        Insert( rStr.copy( nStt, nPos - nStt ));
}
 
void SwWrtShell::Insert( const OUString &rStr )
{
    ResetCursorStack();
    if( !CanInsert() )
        return;
 
    bool bStarted = false;
    bool bHasSel = HasSelection(),
         bCallIns = m_bIns /*|| bHasSel*/;
    bool bDeleted = false;
 
    if( bHasSel || ( !m_bIns && IsInHiddenRange(/*bSelect=*/true) ) )
    {
            // Only here parenthesizing, because the normal
            // insert is already in parentheses at Editshell.
        StartAllAction();
 
        SwRewriter aRewriter;
 
        aRewriter.AddRule(UndoArg1, GetCursorDescr());
        aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
        {
            OUString aTmpStr = SwResId(STR_START_QUOTE) +
                rStr + SwResId(STR_END_QUOTE);
 
            aRewriter.AddRule(UndoArg3, aTmpStr);
        }
 
        StartUndo(SwUndoId::REPLACE, &aRewriter);
        bStarted = true;
        Push();
        // let's interpret a selection within the same node as "replace"
        bDeleted = DelRight(GetCursor()->GetPoint()->GetNode() == GetCursor()->GetMark()->GetNode());
        Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore selection (if tracking changes)
        NormalizePam(false); // tdf#127635 put point at the end of deletion
        ClearMark();
    }
 
    bCallIns ?
        SwEditShell::Insert2( rStr, bDeleted ) : SwEditShell::Overwrite( rStr );
 
    // Check whether node is content control
    SwTextContentControl* pTextContentControl = CursorInsideContentControl();
    if (pTextContentControl)
    {
        std::shared_ptr<SwContentControl> pContentControl =
            pTextContentControl->GetContentControl().GetContentControl();
        if (pContentControl)
        {
            // Set showingPlcHdr to false as node has been edited
            pContentControl->SetShowingPlaceHolder(false);
        }
    }
 
    if( bStarted )
    {
        EndUndo();
        EndAllAction();
    }
}
 
// Maximum height limit not possible, because the maximum height
// of the current frame can not be obtained.
 
void SwWrtShell::InsertGraphic( const OUString &rPath, const OUString &rFilter,
                                const Graphic &rGrf, SwFlyFrameAttrMgr *pFrameMgr,
                                RndStdIds nAnchorType )
{
    ResetCursorStack();
    if ( !CanInsert() )
        return;
 
    StartAllAction();
 
    SwRewriter aRewriter;
    aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC));
 
    StartUndo(SwUndoId::INSERT, &aRewriter);
 
    if ( HasSelection() )
        DelRight();
        // Inserted graphics in its own paragraph,
        // if at the end of a non-empty paragraph.
    //For i120928,avoid to split node
 
    EnterSelFrameMode();
 
    bool bSetGrfSize = true;
    bool bOwnMgr     = false;
 
    if ( !pFrameMgr )
    {
        bOwnMgr = true;
        pFrameMgr = new SwFlyFrameAttrMgr( true, this, Frmmgr_Type::GRF, nullptr );
 
        // CAUTION
        // GetAttrSet makes an adjustment
        // While pasting is a SwFrameSize present
        // because of the DEF-Framesize
        // These must be removed explicitly for the optimal size.
        pFrameMgr->DelAttr(RES_FRM_SIZE);
 
        if (nAnchorType != RndStdIds::FLY_AT_PARA)
            // Something other than at-para was requested.
            pFrameMgr->SetAnchor(nAnchorType);
    }
    else
    {
        Size aSz( pFrameMgr->GetSize() );
        if ( !aSz.Width() || !aSz.Height() )
        {
            aSz.setWidth(o3tl::toTwips(1, o3tl::Length::cm));
            aSz.setHeight(o3tl::toTwips(1, o3tl::Length::cm));
            pFrameMgr->SetSize( aSz );
        }
        else if ( aSz.Width() != DFLT_WIDTH && aSz.Height() != DFLT_HEIGHT )
            bSetGrfSize = false;
 
        pFrameMgr->SetHeightSizeType(SwFrameSize::Fixed);
    }
 
    // during change tracking, insert the image anchored as character
    // (to create an SwRangeRedline on its anchor point)
    if ( IsRedlineOn() && nAnchorType != RndStdIds::FLY_AS_CHAR )
        pFrameMgr->SetAnchor( RndStdIds::FLY_AS_CHAR );
 
    // Insert the graphic
    SwFEShell::Insert(rPath, rFilter, &rGrf, &pFrameMgr->GetAttrSet());
    if ( bOwnMgr )
        pFrameMgr->UpdateAttrMgr();
 
    if( bSetGrfSize )
    {
        Size aSizePixel = rGrf.GetSizePixel();
        Size aBound = GetGraphicDefaultSize();
 
        sal_Int32 nPreferredDPI = mxDoc->getIDocumentSettingAccess().getImagePreferredDPI();
        Size aGrfSize;
 
        if (nPreferredDPI > 0)
        {
            auto nWidth = o3tl::toTwips(aSizePixel.Width() / double(nPreferredDPI), o3tl::Length::in);
            auto nHeight = o3tl::toTwips(aSizePixel.Height() / double(nPreferredDPI), o3tl::Length::in);
            aGrfSize = Size(nWidth, nHeight);
        }
        else
        {
            GetGrfSize(aGrfSize);
        }
 
        // Add the margin attributes to GrfSize,
        // because these counts at the margin additionally
        aGrfSize.AdjustWidth(pFrameMgr->CalcWidthBorder() );
        aGrfSize.AdjustHeight(pFrameMgr->CalcHeightBorder() );
 
        const BigInt aTempWidth( aGrfSize.Width() );
        const BigInt aTempHeight( aGrfSize.Height());
 
        // Fit width if necessary, scale down the height proportional thereafter.
        if( aGrfSize.Width() > aBound.Width() )
        {
            aGrfSize.setWidth( aBound.Width() );
            aGrfSize.setHeight( BigInt(aBound.Width()) * aTempHeight / aTempWidth );
        }
        // Fit height if necessary, scale down the width proportional thereafter.
        if( aGrfSize.Height() > aBound.Height() )
        {
            aGrfSize.setHeight( aBound.Height() );
            aGrfSize.setWidth(  BigInt(aBound.Height()) * aTempWidth / aTempHeight );
        }
        pFrameMgr->SetSize( aGrfSize );
        pFrameMgr->UpdateFlyFrame();
    }
    if ( bOwnMgr )
        delete pFrameMgr;
 
    EndUndo();
    EndAllAction();
}
 
// Insert an OLE-Object into the CORE.
// if no object is transferred, then one will be created.
 
void SwWrtShell::InsertObject( const svt::EmbeddedObjectRef& xRef, SvGlobalName const *pName,
                               sal_uInt16 nSlotId )
{
    ResetCursorStack();
    if( !CanInsert() )
        return;
 
    if( !xRef.is() )
    {
        // temporary storage
        svt::EmbeddedObjectRef xObj;
        uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetTemporaryStorage();
        bool bDoVerb = true;
        if ( pName )
        {
            comphelper::EmbeddedObjectContainer aCnt( xStor );
            OUString aName;
            // TODO/LATER: get aspect?
            xObj.Assign( aCnt.CreateEmbeddedObject( pName->GetByteSequence(), aName ), embed::Aspects::MSOLE_CONTENT );
        }
        else
        {
            SvObjectServerList aServerList;
            switch (nSlotId)
            {
                case SID_INSERT_OBJECT:
                {
                    if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
                    {
                        std::unique_ptr<weld::MessageDialog> xError(
                            Application::CreateMessageDialog(
                                nullptr, VclMessageType::Warning, VclButtonsType::Ok,
                                SvtResId(STR_WARNING_ACTIVE_CONTENT_DISABLED)));
                        xError->run();
                        break;
                    }
                    aServerList.FillInsertObjects();
                    aServerList.Remove( SwDocShell::Factory().GetClassId() );
                    [[fallthrough]];
                }
 
                // TODO/LATER: recording! Convert properties to items
                case SID_INSERT_FLOATINGFRAME:
                {
                    SfxSlotPool* pSlotPool = SW_MOD()->GetSlotPool();
                    const SfxSlot* pSlot = pSlotPool->GetSlot(nSlotId);
                    OUString aCmd = pSlot->GetCommand();
                    SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
                    ScopedVclPtr<SfxAbstractInsertObjectDialog> pDlg(pFact->CreateInsertObjectDialog(GetFrameWeld(mxDoc->GetDocShell()),
                                aCmd, xStor, &aServerList));
                    if (pDlg)
                    {
                        pDlg->Execute();
                        bDoVerb = pDlg->IsCreateNew();
                        OUString aIconMediaType;
                        uno::Reference< io::XInputStream > xIconMetaFile = pDlg->GetIconIfIconified( &aIconMediaType );
                        xObj.Assign( pDlg->GetObject(),
                                     xIconMetaFile.is() ? embed::Aspects::MSOLE_ICON : embed::Aspects::MSOLE_CONTENT );
                        if ( xIconMetaFile.is() )
                            xObj.SetGraphicStream( xIconMetaFile, aIconMediaType );
                    }
 
                    break;
                }
 
                default:
                    break;
            }
        }
 
        if ( xObj.is() )
        {
            if( InsertOleObject( xObj ) && bDoVerb )
            {
                SfxInPlaceClient* pClient = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin() );
                if ( !pClient )
                {
                    pClient = new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
                    SetCheckForOLEInCaption( true );
                }
 
                if ( xObj.GetViewAspect() == embed::Aspects::MSOLE_ICON )
                {
                    SwRect aArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() );
                    aArea.Pos() += GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, xObj.GetObject() ).Pos();
                    MapMode aMapMode( MapUnit::MapTwip );
                    Size aSize = xObj.GetSize( &aMapMode );
                    aArea.Width( aSize.Width() );
                    aArea.Height( aSize.Height() );
                    RequestObjectResize( aArea, xObj.GetObject() );
                }
                else
                    CalcAndSetScale( xObj );
 
                //#50270# We don't need to handle error, this is handled by the
                //DoVerb in the SfxViewShell
                pClient->DoVerb(embed::EmbedVerbs::MS_OLEVERB_SHOW);
 
                // TODO/LATER: set document name - should be done in Client
            }
        }
    }
    else
    {
        if( HasSelection() )
            DelRight();
        InsertOleObject( xRef );
    }
}
 
// Insert object into the Core.
// From ClipBoard or Insert
 
bool SwWrtShell::InsertOleObject( const svt::EmbeddedObjectRef& xRef, SwFlyFrameFormat **pFlyFrameFormat )
{
    //tdf#125100 Ensure that ole object is initially shown as pictogram
    comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = mxDoc->GetDocShell()->getEmbeddedObjectContainer();
    bool bSaveUserAllowsLinkUpdate = rEmbeddedObjectContainer.getUserAllowsLinkUpdate();
    rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
 
    ResetCursorStack();
    StartAllAction();
 
    StartUndo(SwUndoId::INSERT);
 
    //Some differences between StarMath and any other objects:
    //1. Selections should be deleted. For StarMath the Text should be
    //   passed to the Object
    //2. If the cursor is at the end of a non empty paragraph a paragraph
    //   break should be inserted. StarMath objects are character bound and
    //   no break should be inserted.
    //3. If an selection is passed to a StarMath object, this object should
    //   not be activated. false should be returned then.
    bool bStarMath = true;
    bool bActivate = true;
 
    // set parent to get correct VisArea(in case of object needing parent printer)
    uno::Reference < container::XChild > xChild( xRef.GetObject(), uno::UNO_QUERY );
    if ( xChild.is() )
        xChild->setParent( mxDoc->GetDocShell()->GetModel() );
 
    SvGlobalName aCLSID( xRef->getClassID() );
    bStarMath = ( SotExchange::IsMath( aCLSID ) != 0 );
    if( IsSelection() )
    {
        if( bStarMath )
        {
            OUString aMathData;
            GetSelectedText( aMathData, ParaBreakType::ToOnlyCR );
 
            if( !aMathData.isEmpty() && svt::EmbeddedObjectRef::TryRunningState( xRef.GetObject() ) )
            {
                uno::Reference < beans::XPropertySet > xSet( xRef->getComponent(), uno::UNO_QUERY );
                if ( xSet.is() )
                {
                    try
                    {
                        xSet->setPropertyValue(u"Formula"_ustr, uno::Any( aMathData ) );
                        bActivate = false;
                    }
                    catch (const uno::Exception&)
                    {
                    }
                }
            }
        }
        DelRight();
    }
 
    if ( !bStarMath )
        SwFEShell::SplitNode( false, false );
 
    EnterSelFrameMode();
 
    const SvGlobalName* pName = nullptr;
    SvGlobalName aObjClsId;
    if (xRef.is())
    {
        aObjClsId = SvGlobalName(xRef.GetObject()->getClassID());
        pName = &aObjClsId;
    }
    SwFlyFrameAttrMgr aFrameMgr( true, this, Frmmgr_Type::OLE, pName );
    aFrameMgr.SetHeightSizeType(SwFrameSize::Fixed);
 
    SwRect aBound;
    CalcBoundRect( aBound, aFrameMgr.GetAnchor() );
 
    //The Size should be suggested by the OLE server
    MapMode aMapMode( MapUnit::MapTwip );
    Size aSz = xRef.GetSize( &aMapMode );
 
    //Object size can be limited
    if ( aSz.Width() > aBound.Width() )
    {
        //Always limit proportional.
        aSz.setHeight( aSz.Height() * aBound.Width() / aSz.Width() );
        aSz.setWidth( aBound.Width() );
    }
    aFrameMgr.SetSize( aSz );
    SwFlyFrameFormat *pFormat = SwFEShell::InsertObject( xRef, &aFrameMgr.GetAttrSet() );
 
    // --> #i972#
    if ( bStarMath && mxDoc->getIDocumentSettingAccess().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT ) )
        AlignFormulaToBaseline( xRef.GetObject() );
 
    if (pFlyFrameFormat)
        *pFlyFrameFormat = pFormat;
 
    if ( SotExchange::IsChart( aCLSID ) )
    {
        const uno::Reference< embed::XEmbeddedObject >& xEmbeddedObj = xRef.GetObject();
        if ( xEmbeddedObj.is() )
        {
            bool bDisableDataTableDialog = false;
            svt::EmbeddedObjectRef::TryRunningState( xEmbeddedObj );
            uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
            if ( xProps.is() &&
                 ( xProps->getPropertyValue(u"DisableDataTableDialog"_ustr) >>= bDisableDataTableDialog ) &&
                 bDisableDataTableDialog )
            {
                xProps->setPropertyValue(u"DisableDataTableDialog"_ustr,
                    uno::Any( false ) );
                xProps->setPropertyValue(u"DisableComplexChartTypes"_ustr,
                    uno::Any( false ) );
                uno::Reference< util::XModifiable > xModifiable( xProps, uno::UNO_QUERY );
                if ( xModifiable.is() )
                {
                    xModifiable->setModified( true );
                }
            }
        }
    }
 
    EndAllAction();
    GetView().AutoCaption(OLE_CAP, &aCLSID);
 
    SwRewriter aRewriter;
 
    if ( bStarMath )
        aRewriter.AddRule(UndoArg1, SwResId(STR_MATH_FORMULA));
    else if ( SotExchange::IsChart( aCLSID ) )
        aRewriter.AddRule(UndoArg1, SwResId(STR_CHART));
    else
        aRewriter.AddRule(UndoArg1, SwResId(STR_OLE));
 
    EndUndo(SwUndoId::INSERT, &aRewriter);
 
    rEmbeddedObjectContainer.setUserAllowsLinkUpdate(bSaveUserAllowsLinkUpdate);
 
    return bActivate;
}
 
// The current selected OLE object will be loaded with the
// verb into the server.
void SwWrtShell::LaunchOLEObj(sal_Int32 nVerb)
{
    if ( GetCntType() != CNT_OLE ||
         GetView().GetViewFrame().GetFrame().IsInPlace() )
        return;
 
    svt::EmbeddedObjectRef& xRef = GetOLEObject();
    OSL_ENSURE( xRef.is(), "OLE not found" );
 
    // LOK: we don't want to handle any other embedded objects than
    // charts, there are too many problems with eg. embedded spreadsheets
    // (like it creates a separate view for the calc sheet)
    if (comphelper::LibreOfficeKit::isActive())
    {
        const auto classId = xRef->getClassID();
        if (!SotExchange::IsChart(classId) && !SotExchange::IsMath(classId))
            return;
    }
 
    SfxInPlaceClient* pCli = GetView().FindIPClient( xRef.GetObject(), &GetView().GetEditWin() );
    if ( !pCli )
        pCli = new SwOleClient( &GetView(), &GetView().GetEditWin(), xRef );
 
    uno::Reference<lang::XInitialization> xOLEInit(xRef.GetObject(), uno::UNO_QUERY);
    if (xOLEInit.is())
    {
        uno::Sequence<beans::PropertyValue> aArguments
            = { comphelper::makePropertyValue(u"ReadOnly"_ustr, pCli->IsProtected()) };
        xOLEInit->initialize({ uno::Any(aArguments) });
    }
 
    static_cast<SwOleClient*>(pCli)->SetInDoVerb( true );
 
    CalcAndSetScale( xRef );
    pCli->DoVerb( nVerb );
 
    static_cast<SwOleClient*>(pCli)->SetInDoVerb( false );
    CalcAndSetScale( xRef );
}
 
void SwWrtShell::MoveObjectIfActive( svt::EmbeddedObjectRef& xObj, const Point& rOffset )
{
    try
    {
        sal_Int32 nState = xObj->getCurrentState();
        if ( nState == css::embed::EmbedStates::INPLACE_ACTIVE
          || nState == css::embed::EmbedStates::UI_ACTIVE )
        {
            SfxInPlaceClient* pCli =
                GetView().FindIPClient( xObj.GetObject(), &(GetView().GetEditWin()) );
            if ( pCli )
            {
                tools::Rectangle aArea = pCli->GetObjArea();
                aArea += rOffset;
                pCli->SetObjArea( aArea );
            }
        }
    }
    catch (const uno::Exception&)
    {
    }
}
 
void SwWrtShell::CalcAndSetScale( svt::EmbeddedObjectRef& xObj,
                                  const SwRect *pFlyPrtRect,
                                  const SwRect *pFlyFrameRect,
                                  const bool bNoTextFramePrtAreaChanged )
{
    // Setting the scale of the client. This arises from the difference
    // between the VisArea of the object and the ObjArea.
    OSL_ENSURE( xObj.is(), "ObjectRef not  valid" );
 
    sal_Int64 nAspect = xObj.GetViewAspect();
    if ( nAspect == embed::Aspects::MSOLE_ICON )
        return; // the replacement image is completely controlled by container in this case
 
    sal_Int64 nMisc = 0;
    bool bLinkingChart = false;
 
    try
    {
        nMisc = xObj->getStatus( nAspect );
 
        // This can surely only be a non-active object, if desired they
        // get the new size set as VisArea (StarChart).
        if( embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE & nMisc )
        {
            // TODO/MBA: testing
            SwRect aRect( pFlyPrtRect ? *pFlyPrtRect
                        : GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ));
            if( !aRect.IsEmpty() )
            {
                // TODO/LEAN: getMapUnit can switch object to running state
                // xObj.TryRunningState();
 
                MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
 
                // TODO/LATER: needs complete VisArea?!
                Size aSize( OutputDevice::LogicToLogic(aRect.SVRect(), MapMode(MapUnit::MapTwip), MapMode(aUnit)).GetSize() );
                awt::Size aSz;
                aSz.Width = aSize.Width();
                aSz.Height = aSize.Height();
 
                // Action 'setVisualAreaSize' doesn't have to turn on the
                // modified state of the document, either.
                bool bModified = false;
                uno::Reference<util::XModifiable> xModifiable(xObj->getComponent(), uno::UNO_QUERY);
                if (xModifiable.is())
                    bModified = xModifiable->isModified();
                xObj->setVisualAreaSize( nAspect, aSz );
                xModifiable.set(xObj->getComponent(), uno::UNO_QUERY);
                if (xModifiable.is() && xModifiable->isModified() && !bModified)
                    xModifiable->setModified(bModified);
 
                // #i48419# - action 'UpdateReplacement' doesn't
                // have to change the modified state of the document.
                // This is only a workaround for the defect, that this action
                // modifies a document after load, because unnecessarily the
                // replacement graphic is updated, in spite of the fact that
                // nothing has been changed.
                // If the replacement graphic changes by this action, the document
                // will be already modified via other mechanisms.
                {
                    bool bResetEnableSetModified(false);
                    if ( GetDoc()->GetDocShell()->IsEnableSetModified() )
                    {
                        GetDoc()->GetDocShell()->EnableSetModified( false );
                        bResetEnableSetModified = true;
                    }
 
                    //#i79576# don't destroy chart replacement images on load
                    //#i79578# don't request a new replacement image for charts to often
                    //a chart sends a modified call to the framework if it was changed
                    //thus the replacement update is already handled elsewhere
                    if ( !SotExchange::IsChart( xObj->getClassID() ) )
                        xObj.UpdateReplacement();
 
                    if ( bResetEnableSetModified )
                    {
                        GetDoc()->GetDocShell()->EnableSetModified();
                    }
                }
            }
 
            // TODO/LATER: this is only a workaround,
            uno::Reference< chart2::XChartDocument > xChartDocument( xObj->getComponent(), uno::UNO_QUERY );
            bLinkingChart = ( xChartDocument.is() && !xChartDocument->hasInternalDataProvider() );
        }
    }
    catch (const uno::Exception&)
    {
        // TODO/LATER: handle the error
        return;
    }
 
    SfxInPlaceClient* pCli = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin() );
    if ( !pCli )
    {
        if ( (embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY & nMisc)
             || bLinkingChart
             // --> OD #i117189# - refine condition for non-resizable objects
             // non-resizable objects need to be set the size back by this method
             || ( bNoTextFramePrtAreaChanged && nMisc & embed::EmbedMisc::EMBED_NEVERRESIZE ) )
        {
            pCli = new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
        }
        else
            return;
    }
 
    // TODO/LEAN: getMapUnit can switch object to running state
    // xObj.TryRunningState();
 
    awt::Size aSize;
    try
    {
        aSize = xObj->getVisualAreaSize( nAspect );
    }
    catch (const embed::NoVisualAreaSizeException&)
    {
        OSL_FAIL("Can't get visual area size!" );
        // the scaling will not be done
    }
    catch (const uno::Exception&)
    {
        // TODO/LATER: handle the error
        OSL_FAIL("Can't get visual area size!" );
        return;
    }
 
    Size _aVisArea( aSize.Width, aSize.Height );
 
    Fraction aScaleWidth( 1, 1 );
    Fraction aScaleHeight( 1, 1 );
 
    bool bUseObjectSize = false;
 
    // As long as there comes no reasonable size from the object,
    // nothing can be scaled.
    if( _aVisArea.Width() && _aVisArea.Height() )
    {
        const MapMode aTmp( MapUnit::MapTwip );
        MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
        _aVisArea = OutputDevice::LogicToLogic(_aVisArea, MapMode(aUnit), aTmp);
        Size aObjArea;
        if ( pFlyPrtRect )
            aObjArea = pFlyPrtRect->SSize();
        else
            aObjArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ).SSize();
 
        // differ the aObjArea and _aVisArea by 1 Pixel then set new VisArea
        tools::Long nX, nY;
        SwSelPaintRects::Get1PixelInLogic( *this, &nX, &nY );
        if( !( _aVisArea.Width() - nX <= aObjArea.Width() &&
               _aVisArea.Width() + nX >= aObjArea.Width() &&
               _aVisArea.Height()- nY <= aObjArea.Height()&&
               _aVisArea.Height()+ nY >= aObjArea.Height() ))
        {
            if ( nMisc & embed::EmbedMisc::EMBED_NEVERRESIZE )
            {
                // the object must not be scaled,
                // the size stored in object must be used for restoring
                bUseObjectSize = true;
            }
            else
            {
                aScaleWidth = Fraction( aObjArea.Width(),   _aVisArea.Width() );
                aScaleHeight = Fraction( aObjArea.Height(), _aVisArea.Height());
            }
        }
    }
 
    // Now is the favorable time to set the ObjArea.
    // The Scaling must be considered.
    SwRect aArea;
    if ( pFlyPrtRect )
    {
        aArea = *pFlyPrtRect;
        aArea += pFlyFrameRect->Pos();
    }
    else
    {
        aArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() );
        aArea.Pos() += GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, xObj.GetObject() ).Pos();
    }
 
    if ( bUseObjectSize )
    {
        // --> this moves non-resizable object so that when adding borders the baseline remains the same
        const SwFlyFrameFormat *pFlyFrameFormat = dynamic_cast< const SwFlyFrameFormat * >( GetFlyFrameFormat() );
        OSL_ENSURE( pFlyFrameFormat, "Could not find fly frame." );
        if ( pFlyFrameFormat )
        {
            const Point &rPoint = pFlyFrameFormat->GetLastFlyFramePrtRectPos();
            SwRect aRect( pFlyPrtRect ? *pFlyPrtRect
                        : GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ));
            aArea += rPoint - aRect.Pos(); // adjust area by diff of printing area position in order to keep baseline alignment correct.
        }
        aArea.Width ( _aVisArea.Width() );
        aArea.Height( _aVisArea.Height() );
        RequestObjectResize( aArea, xObj.GetObject() );
    }
    else
    {
        double nWidth(pCli->GetScaleWidth());
        double nHeight(pCli->GetScaleHeight());
        if (nWidth && nHeight)
        {
            aArea.Width ( aArea.Width()  / nWidth );
            aArea.Height( aArea.Height() / nHeight );
        }
    }
 
    pCli->SetObjAreaAndScale( aArea.SVRect(), aScaleWidth, aScaleHeight );
}
 
void SwWrtShell::ConnectObj( svt::EmbeddedObjectRef& xObj, const SwRect &rPrt,
                            const SwRect &rFrame )
{
    SfxInPlaceClient* pCli = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin());
    if ( !pCli )
        new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
    CalcAndSetScale( xObj, &rPrt, &rFrame );
}
 
// Insert hard page break;
// Selections will be overwritten
void SwWrtShell::InsertPageBreak(const OUString *pPageDesc, const ::std::optional<sal_uInt16>& oPgNum )
{
    if (!lcl_IsAllowed(this))
        return;
 
    ResetCursorStack();
    if( CanInsert() )
    {
        SwActContext aActContext(this);
        StartUndo(SwUndoId::UI_INSERT_PAGE_BREAK);
 
        if ( !IsCursorInTable() )
        {
            if(HasSelection())
                DelRight();
            SwFEShell::SplitNode();
            // delete the numbered attribute of the last line if the last line is empty
            GetDoc()->ClearLineNumAttrs( *GetCursor()->GetPoint() );
        }
 
        const SwPageDesc *pDesc = pPageDesc
                                ? FindPageDescByName( *pPageDesc, true ) : nullptr;
        if( pDesc )
        {
            SwFormatPageDesc aDesc( pDesc );
            aDesc.SetNumOffset( oPgNum );
            SetAttrItem( aDesc );
        }
        else
            SetAttrItem( SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK) );
        EndUndo(SwUndoId::UI_INSERT_PAGE_BREAK);
    }
    collectUIInformation(u"BREAK_PAGE"_ustr, u"parameter"_ustr);
}
 
// Insert enclosing characters
// Selections will be overwritten
void SwWrtShell::InsertEnclosingChars(std::u16string_view sStartStr, std::u16string_view sEndStr)
{
    for (SwPaM& rPaM : SwWrtShell::GetCursor()->GetRingContainer())
    {
        const OUString aStr = sStartStr + rPaM.GetText() + sEndStr;
        SwViewShell::getIDocumentContentOperations().ReplaceRange(rPaM, aStr, false);
    }
}
 
// Insert hard page break;
// Selections will be overwritten
 
void SwWrtShell::InsertLineBreak(std::optional<SwLineBreakClear> oClear)
{
    if (!lcl_IsAllowed(this))
        return;
 
    ResetCursorStack();
    if( CanInsert() )
    {
        if(HasSelection())
            DelRight();
 
        const sal_Unicode cIns = 0x0A;
        SwLineBreakClear eClear = SwLineBreakClear::NONE;
        if (oClear.has_value())
        {
            eClear = *oClear;
        }
        SvxAutoCorrect* pACorr = lcl_IsAutoCorr();
        if (pACorr && eClear == SwLineBreakClear::NONE)
            AutoCorrect( *pACorr, cIns );
        else
        {
            if (eClear == SwLineBreakClear::NONE)
            {
                SwWrtShell::Insert(OUString(cIns));
            }
            else
            {
                SwFormatLineBreak aLineBreak(eClear);
                SetAttrItem(aLineBreak);
            }
        }
    }
}
 
// Insert hard column break;
// Selections will be overwritten
 
void SwWrtShell::InsertColumnBreak()
{
    if (!lcl_IsAllowed(this))
        return;
 
    SwActContext aActContext(this);
    ResetCursorStack();
    if( !CanInsert() )
        return;
 
    StartUndo(SwUndoId::UI_INSERT_COLUMN_BREAK);
 
    if ( !IsCursorInTable() )
    {
        if(HasSelection())
            DelRight();
        SwFEShell::SplitNode( false, false );
    }
    SetAttrItem(SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
 
    EndUndo(SwUndoId::UI_INSERT_COLUMN_BREAK);
}
 
void SwWrtShell::InsertContentControl(SwContentControlType eType)
{
    if (!lcl_IsAllowed(this))
    {
        return;
    }
 
    ResetCursorStack();
    if (!CanInsert())
    {
        return;
    }
 
    auto pContentControl = std::make_shared<SwContentControl>(nullptr);
 
    // Make Random ID... check if it is unique
    // warning: possible infinite loop if there would be billions of content controls.
    SwContentControlManager& pManager = GetDoc()->GetContentControlManager();
    size_t nCCCount = pManager.GetCount();
    sal_Int32 nIdToCheck;
    nIdToCheck
        = comphelper::rng::uniform_uint_distribution(1, std::numeric_limits<sal_Int32>::max());
    size_t nIdx = 0;
    while (nIdx < nCCCount)
    {
        sal_Int32 nID
            = pManager.UnsortedGet(nIdx)->GetContentControl().GetContentControl()->GetId();
        if (nID == nIdToCheck)
        {
            nIdToCheck = comphelper::rng::uniform_uint_distribution(
                1, std::numeric_limits<sal_Int32>::max());
            nIdx = 0;
        }
        else
            nIdx++;
    }
    pContentControl->SetId(nIdToCheck);
 
    OUString aPlaceholder;
    switch (eType)
    {
        case SwContentControlType::RICH_TEXT:
        case SwContentControlType::PLAIN_TEXT:
        {
            pContentControl->SetShowingPlaceHolder(true);
            if (eType == SwContentControlType::PLAIN_TEXT)
            {
                pContentControl->SetPlainText(true);
            }
            if (!HasSelection())
            {
                aPlaceholder = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER);
            }
            break;
        }
        case SwContentControlType::CHECKBOX:
        {
            pContentControl->SetCheckbox(true);
            // Ballot Box with X
            pContentControl->SetCheckedState(u"\u2612"_ustr);
            // Ballot Box
            pContentControl->SetUncheckedState(u"\u2610"_ustr);
            aPlaceholder = u"\u2610"_ustr;
            break;
        }
        case SwContentControlType::COMBO_BOX:
        case SwContentControlType::DROP_DOWN_LIST:
        {
            if (eType == SwContentControlType::COMBO_BOX)
            {
                pContentControl->SetComboBox(true);
            }
            else if (eType == SwContentControlType::DROP_DOWN_LIST)
            {
                pContentControl->SetDropDown(true);
            }
 
            pContentControl->SetShowingPlaceHolder(true);
            if (!HasSelection())
            {
                aPlaceholder = SwResId(STR_DROPDOWN_CONTENT_CONTROL_PLACEHOLDER);
            }
            SwContentControlListItem aListItem;
            aListItem.m_aValue = aPlaceholder;
            pContentControl->SetListItems({ std::move(aListItem) });
            break;
        }
        case SwContentControlType::PICTURE:
        {
            // Set up the picture content control.
            pContentControl->SetShowingPlaceHolder(true);
            pContentControl->SetPicture(true);
 
            // Create the placeholder bitmap.
            BitmapEx aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP);
            Color aColor = SvtOptionsDrawinglayer::getHilightColor();
            aColor.IncreaseLuminance(255 * 0.75);
            aBitmap.Erase(aColor);
            SwRewriter aRewriter;
            aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC_DEFNAME));
            StartUndo(SwUndoId::INSERT, &aRewriter);
            LockPaint(LockPaintReason::InsertGraphic);
            StartAction();
            InsertGraphic(OUString(), OUString(), aBitmap, nullptr, RndStdIds::FLY_AS_CHAR);
 
            // Set properties on the bitmap.
            SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aSet(GetDoc()->GetAttrPool());
            GetFlyFrameAttr(aSet);
            SwFormatFrameSize aSize(SwFrameSize::Fixed, 3000, 3000);
            aSet.Put(aSize);
            SetFlyFrameAttr(aSet);
            SwFrameFormat* pFrameFormat = GetFlyFrameFormat();
            EndAction();
            UnlockPaint();
            EndUndo();
 
            // Go after the anchor position.
            UnSelectFrame();
            LeaveSelFrameMode();
            {
                SwCursor* pCursor = getShellCursor(true);
                pCursor->DeleteMark();
                const SwFormatAnchor& rFormatAnchor = pFrameFormat->GetAnchor();
                pCursor->GetPoint()->Assign( *rFormatAnchor.GetAnchorContentNode(), rFormatAnchor.GetAnchorContentOffset() + 1);
            }
 
            // Select before the anchor position.
            Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
            break;
        }
        case SwContentControlType::DATE:
        {
            pContentControl->SetShowingPlaceHolder(true);
            pContentControl->SetDate(true);
            SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
            sal_uInt32 nStandardFormat = pFormatter->GetStandardFormat(SvNumFormatType::DATE);
            const SvNumberformat* pFormat = pFormatter->GetEntry(nStandardFormat);
            pContentControl->SetDateFormat(pFormat->GetFormatstring());
            pContentControl->SetDateLanguage(LanguageTag(pFormat->GetLanguage()).getBcp47());
            if (!HasSelection())
            {
                aPlaceholder = SwResId(STR_DATE_CONTENT_CONTROL_PLACEHOLDER);
            }
            break;
        }
    }
    if (aPlaceholder.getLength())
    {
        Insert(aPlaceholder);
        Left(SwCursorSkipMode::Chars, /*bSelect=*/true, aPlaceholder.getLength(),
                /*bBasicCall=*/false);
    }
 
    const RedlineFlags oldRedlineFlags = getIDocumentRedlineAccess().GetRedlineFlags();
    getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::Ignore);
    SwFormatContentControl aContentControl(pContentControl, RES_TXTATR_CONTENTCONTROL);
    SetAttrItem(aContentControl);
    getIDocumentRedlineAccess().SetRedlineFlags(oldRedlineFlags);
}
 
// Insert footnote
// rStr - optional footnote mark
 
void SwWrtShell::InsertFootnote(const OUString &rStr, bool bEndNote, bool bEdit )
{
    ResetCursorStack();
    if( !CanInsert() )
        return;
 
    if(HasSelection())
    {
        //collapse cursor to the end
        if(!IsCursorPtAtEnd())
            SwapPam();
        ClearMark();
    }
    SwPosition aPos = *GetCursor()->GetPoint();
    SwFormatFootnote aFootNote( bEndNote );
    if(!rStr.isEmpty())
        aFootNote.SetNumStr( rStr );
 
    SetAttrItem(aFootNote);
 
    if( bEdit )
    {
        // For editing the footnote text.
        Left(SwCursorSkipMode::Chars, false, 1, false );
        GotoFootnoteText();
    }
    m_aNavigationMgr.addEntry(aPos);
}
 
// tdf#141634
static bool lcl_FoldedOutlineNodeEndOfParaSplit(SwWrtShell *pThis)
{
    SwTextNode* pTextNode = pThis->GetCursor()->GetPointNode().GetTextNode();
    if (pTextNode && pTextNode->IsOutline())
    {
        bool bVisible = true;
        pTextNode->GetAttrOutlineContentVisible(bVisible);
        if (!bVisible)
        {
            const SwNodes& rNodes = pThis->GetNodes();
            const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
            SwOutlineNodes::size_type nPos;
            (void) rOutlineNodes.Seek_Entry(pTextNode, &nPos);
 
            SwNode* pSttNd = rOutlineNodes[nPos];
 
            // determine end node of folded outline content
            SwNode* pEndNd = &rNodes.GetEndOfContent();
            if (rOutlineNodes.size() > nPos + 1)
                pEndNd = rOutlineNodes[nPos + 1];
 
            if (pThis->GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
            {
                // get the next outline node after the folded outline content (iPos)
                // it is the next outline node with the same level or less
                int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
                SwOutlineNodes::size_type iPos = nPos;
                while (++iPos < rOutlineNodes.size() &&
                       rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel);
 
                // get the correct end node
                // the outline node may be in frames, headers, footers special section of doc model
                SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
                while (pStartOfSectionNodeSttNd->StartOfSectionNode()
                       != pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
                {
                    pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
                }
                pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
 
                if (iPos < rOutlineNodes.size())
                {
                    SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
                    while (pStartOfSectionNode->StartOfSectionNode()
                           != pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
                    {
                        pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
                    }
                    if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
                        pEndNd = rOutlineNodes[iPos];
                }
            }
 
            // table, text box, header, footer
            if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
            {
                // insert before section end node
                if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
                {
                    SwNodeIndex aIdx(*pSttNd->EndOfSectionNode());
                    while (aIdx.GetNode().IsEndNode())
                        --aIdx;
                    ++aIdx;
                    pEndNd = &aIdx.GetNode();
                }
            }
            // if pSttNd isn't in table but pEndNd is then insert after table
            else if (pEndNd->GetTableBox())
            {
                pEndNd = pEndNd->FindTableNode();
                SwNodeIndex aIdx(*pEndNd, -1);
                // account for nested tables
                while (aIdx.GetNode().GetTableBox())
                {
                    pEndNd = aIdx.GetNode().FindTableNode();
                    aIdx.Assign(*pEndNd, -1);
                }
                aIdx.Assign(*pEndNd->EndOfSectionNode(), +1);
                pEndNd = &aIdx.GetNode();
            }
            // end node determined
 
            // now insert the new outline node
            SwDoc* pDoc = pThis->GetDoc();
 
            // insert at end of tablebox doesn't work correct without
            MakeAllOutlineContentTemporarilyVisible a(pDoc);
 
            SwTextNode* pNd = pDoc->GetNodes().MakeTextNode(*pEndNd, pTextNode->GetTextColl(), true);
 
            (void) rOutlineNodes.Seek_Entry(pNd, &nPos);
            pThis->GotoOutline(nPos);
 
            if (pDoc->GetIDocumentUndoRedo().DoesUndo())
            {
                pDoc->GetIDocumentUndoRedo().ClearRedo();
                pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsert>(*pNd));
                pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoFormatColl>
                                                        (SwPaM(*pNd), pNd->GetTextColl(), true, true));
            }
 
            pThis->SetModified();
            return true;
        }
    }
    return false;
}
 
// SplitNode; also, because
//                  - of deleting selected content;
//                  - of reset of the Cursorstack if necessary.
 
void SwWrtShell::SplitNode( bool bAutoFormat )
{
    ResetCursorStack();
    if( !CanInsert() )
        return;
 
    SwActContext aActContext(this);
 
    m_rView.GetEditWin().FlushInBuffer();
    StartUndo(SwUndoId::SPLITNODE);
 
    bool bHasSel = HasSelection();
    if (bHasSel)
        DelRight();
 
    bool bHandled = false;
    if (GetViewOptions()->IsShowOutlineContentVisibilityButton() && IsEndPara())
        bHandled = lcl_FoldedOutlineNodeEndOfParaSplit(this);
 
    if (!bHandled)
        SwFEShell::SplitNode( bAutoFormat );
 
    EndUndo(SwUndoId::SPLITNODE);
}
 
// Turn on numbering
// Parameter:   Optional specification of a name for the named list;
//              this indicates a position if it is possible to convert them
//              into a number and less than nMaxRules.
 
// To test the CharFormats at the numbering
// external void SetNumChrFormat( SwWrtShell*, SwNumRules& );
 
// -> #i40041#
// Preconditions (as far as OD has figured out):
// - <SwEditShell::HasNumber()> is false, if <bNum> is true
// - <SwEditShell::HasBullet()> is false, if <bNum> is false
// Behavior of method is determined by the current situation at the current
// cursor position in the document.
void SwWrtShell::NumOrBulletOn(bool bNum)
{
    StartUndo(SwUndoId::NUMORNONUM);
 
    const SwNumRule* pNumRule = GetNumRuleAtCurrCursorPos();
 
    // - activate outline rule respectively turning on outline rule for
    //   current text node. But, only for turning on a numbering (<bNum> == true).
    // - overwrite found numbering rule at current cursor position, if
    //   no numbering rule can be retrieved from the paragraph style.
    bool bContinueFoundNumRule( false );
    bool bActivateOutlineRule( false );
    int nActivateOutlineLvl( MAXLEVEL );    // only relevant, if <bActivateOutlineRule> == true
    SwTextFormatColl * pColl = GetCurTextFormatColl();
    if ( pColl )
    {
        // retrieve numbering rule at paragraph
        // style, which is found at current cursor position in the document.
        SwNumRule* pCollRule = mxDoc->FindNumRulePtr(pColl->GetNumRule().GetValue());
        // #125993# - The outline numbering rule isn't allowed
        // to be derived from a parent paragraph style to a derived one.
        // Thus check, if the found outline numbering rule is directly
        // set at the paragraph style <pColl>. If not, set <pCollRule> to NULL
        if ( pCollRule && pCollRule == GetDoc()->GetOutlineNumRule() )
        {
            const SwNumRule* pDirectCollRule =
                    mxDoc->FindNumRulePtr(pColl->GetNumRule( false ).GetValue());
            if ( !pDirectCollRule )
            {
                pCollRule = nullptr;
            }
        }
 
        if ( !pCollRule )
        {
            pNumRule = pCollRule;
        }
        // no activation or continuation of outline numbering in Writer/Web document
        else if ( bNum &&
                  !dynamic_cast<SwWebDocShell*>(GetDoc()->GetDocShell()) &&
                  pCollRule == GetDoc()->GetOutlineNumRule() )
        {
            if ( pNumRule == pCollRule )
            {
                // check, if text node at current cursor positioned is counted.
                // If not, let it been counted. Then it has to be checked,
                // of the outline numbering has to be activated or continued.
                SwTextNode const*const pTextNode = sw::GetParaPropsNode(
                        *GetLayout(), GetCursor()->GetPoint()->GetNode());
                if ( pTextNode && !pTextNode->IsCountedInList() )
                {
                    // check, if numbering of the outline level of the paragraph
                    // style is active. If not, activate this outline level.
                    nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
                    OSL_ENSURE( pColl->IsAssignedToListLevelOfOutlineStyle(),
                            "<SwWrtShell::NumOrBulletOn(..)> - paragraph style with outline rule, but no outline level" );
                    if ( pColl->IsAssignedToListLevelOfOutlineStyle() &&
                         pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
                            == SVX_NUM_NUMBER_NONE )
                    {
                        // activate outline numbering
                        bActivateOutlineRule = true;
                    }
                    else
                    {
                        // turning on outline numbering at current cursor position
                        bContinueFoundNumRule = true;
                    }
                }
                else
                {
                    // #i101234#
                    // activate outline numbering, because from the precondition
                    // it's known, that <SwEdit::HasNumber()> == false
                    bActivateOutlineRule = true;
                    nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
                }
            }
            else if ( !pNumRule )
            {
                // #i101234#
                // Check, if corresponding list level of the outline numbering
                // has already a numbering format set.
                nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
                if ( pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
                                == SVX_NUM_NUMBER_NONE )
                {
                    // activate outline numbering, because from the precondition
                    // it's known, that <SwEdit::HasNumber()> == false
                    bActivateOutlineRule = true;
                }
                else
                {
                    // turning on outline numbering at current cursor position
                    bContinueFoundNumRule = true;
                }
            }
            else
            {
                // check, if numbering of the outline level of the paragraph
                // style is active. If not, activate this outline level.
                nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
                OSL_ENSURE( pColl->IsAssignedToListLevelOfOutlineStyle(),
                        "<SwWrtShell::NumOrBulletOn(..)> - paragraph style with outline rule, but no outline level" );
                if ( pColl->IsAssignedToListLevelOfOutlineStyle() &&
                     pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
                        == SVX_NUM_NUMBER_NONE )
                {
                    // activate outline numbering
                    bActivateOutlineRule = true;
                }
                else
                {
                    // turning on outline numbering at current cursor position
                    bContinueFoundNumRule = true;
                }
            }
            pNumRule = pCollRule;
        }
    }
 
    // Only automatic numbering/bullet rules should be changed.
    // Note: The outline numbering rule is also an automatic one. It's only
    //       changed, if it has to be activated.
    if ( pNumRule )
    {
        if ( !pNumRule->IsAutoRule() )
        {
            pNumRule = nullptr;
        }
        else if ( pNumRule == GetDoc()->GetOutlineNumRule() &&
                  !bActivateOutlineRule && !bContinueFoundNumRule )
        {
            pNumRule = nullptr;
        }
    }
 
    // Search for a previous numbering/bullet rule to continue it.
    OUString sContinuedListId;
    if ( !pNumRule )
    {
        pNumRule = GetDoc()->SearchNumRule( *GetCursor()->GetPoint(),
                                            false, bNum, false, 0,
                                            sContinuedListId, GetLayout() );
        bContinueFoundNumRule = pNumRule != nullptr;
    }
 
    if (pNumRule)
    {
        SwNumRule aNumRule(*pNumRule);
 
        // do not change found numbering/bullet rule, if it should only be continued.
        if ( !bContinueFoundNumRule )
        {
            SwTextNode const*const pTextNode = sw::GetParaPropsNode(
                    *GetLayout(), GetCursor()->GetPoint()->GetNode());
 
            if (pTextNode)
            {
                // use above retrieve outline level, if outline numbering has to be activated.
                int nLevel = bActivateOutlineRule
                              ? nActivateOutlineLvl
                              : pTextNode->GetActualListLevel();
 
                if (nLevel < 0)
                    nLevel = 0;
 
                if (nLevel >= MAXLEVEL)
                    nLevel = MAXLEVEL - 1;
 
                SwNumFormat aFormat(aNumRule.Get(o3tl::narrowing<sal_uInt16>(nLevel)));
 
                if (bNum)
                    aFormat.SetNumberingType(SVX_NUM_ARABIC);
                else
                {
                    // #i63395# Only apply user defined default bullet font
                    if ( numfunc::IsDefBulletFontUserDefined() )
                    {
                        const vcl::Font* pFnt = &numfunc::GetDefBulletFont();
                        aFormat.SetBulletFont( pFnt );
                    }
                    aFormat.SetBulletChar( numfunc::GetBulletChar(static_cast<sal_uInt8>(nLevel)));
                    aFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
                    // #i93908# clear suffix for bullet lists
                    aFormat.SetListFormat(u""_ustr, u""_ustr, nLevel);
                }
                aNumRule.Set(o3tl::narrowing<sal_uInt16>(nLevel), aFormat);
            }
        }
 
        // reset indent attribute on applying list style
        SetCurNumRule( aNumRule, false, sContinuedListId, true );
    }
    else
    {
        // #i95907#
        const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode(
                                    numfunc::GetDefaultPositionAndSpaceMode() );
        SwNumRule aNumRule( GetUniqueNumRuleName(), ePosAndSpaceMode );
        // Append the character template at the numbering.
        SwCharFormat* pChrFormat;
        SwDocShell* pDocSh = GetView().GetDocShell();
 
        if (bNum)
        {
            pChrFormat = GetCharFormatFromPool( RES_POOLCHR_NUM_LEVEL );
        }
        else
        {
            pChrFormat = GetCharFormatFromPool( RES_POOLCHR_BULLET_LEVEL );
        }
 
        const SwTextNode *const pTextNode = sw::GetParaPropsNode(*GetLayout(),
                GetCursor()->GetPoint()->GetNode());
        const SwTwips nWidthOfTabs = pTextNode
                                     ? pTextNode->GetWidthOfLeadingTabs()
                                     : 0;
        GetDoc()->getIDocumentContentOperations().RemoveLeadingWhiteSpace(*GetCursor());
 
        const bool bHtml = dynamic_cast<SwWebDocShell*>( pDocSh ) !=  nullptr;
        const bool bRightToLeft = IsInRightToLeftText();
        for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
        {
            SwNumFormat aFormat( aNumRule.Get( nLvl ) );
            aFormat.SetCharFormat( pChrFormat );
 
            if (! bNum)
            {
                uno::Sequence<OUString> aBulletSymbols(
                    officecfg::Office::Common::BulletsNumbering::DefaultBullets::get());
                uno::Sequence<OUString> aBulletSymbolsFonts(
                    officecfg::Office::Common::BulletsNumbering::DefaultBulletsFonts::get());
                aFormat.SetBulletChar(aBulletSymbols[0].toChar());
                vcl::Font aFont;
                aFont.SetFamilyName(aBulletSymbolsFonts[0]);
                aFormat.SetBulletFont(&aFont);
                aFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
                // #i93908# clear suffix for bullet lists
                aFormat.SetListFormat(u""_ustr, u""_ustr, nLvl);
            }
 
            // #i95907#
            if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
            {
                if(bHtml && nLvl)
                {
                    // 1/2" for HTML
                    aFormat.SetAbsLSpace(nLvl * 720);
                }
                else if ( nWidthOfTabs > 0 )
                {
                    aFormat.SetAbsLSpace(nWidthOfTabs + nLvl * 720);
                }
            }
 
            // #i38904#  Default alignment for
            // numbering/bullet should be rtl in rtl paragraph:
            if ( bRightToLeft )
            {
                aFormat.SetNumAdjust( SvxAdjust::Right );
            }
 
            aNumRule.Set( nLvl, aFormat );
        }
 
        // #i95907#
        if ( pTextNode &&
             ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
        {
 
            const SwTwips nTextNodeIndent = pTextNode->GetAdditionalIndentForStartingNewList();
            if ( ( nTextNodeIndent + nWidthOfTabs ) != 0 )
            {
                // #i111172#/fdo#85666
                // If text node is already inside a list, assure that the indents
                // are the same. Thus, adjust the indent change value by subtracting
                // indents of to be applied list style.
                SwTwips nIndentChange = nTextNodeIndent + nWidthOfTabs;
                if ( pTextNode->GetNumRule() )
                {
                    int nLevel = pTextNode->GetActualListLevel();
 
                    if (nLevel < 0)
                        nLevel = 0;
 
                    if (nLevel >= MAXLEVEL)
                        nLevel = MAXLEVEL - 1;
 
                    const SwNumFormat& aFormat( aNumRule.Get( nLevel ) );
                    if ( aFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
                    {
                        nIndentChange -= aFormat.GetIndentAt() + aFormat.GetFirstLineIndent();
                    }
                }
                aNumRule.ChangeIndent( nIndentChange );
            }
        }
        // reset indent attribute on applying list style
        // start new list
        SetCurNumRule( aNumRule, true, OUString(), true );
    }
 
    EndUndo(SwUndoId::NUMORNONUM);
}
// <- #i40041#
 
void SwWrtShell::NumOn()
{
    NumOrBulletOn(true);
}
 
void SwWrtShell::NumOrBulletOff()
{
    const SwNumRule * pCurNumRule = GetNumRuleAtCurrCursorPos();
 
    if (!pCurNumRule)
        return;
 
    DelNumRules();
 
    // #126346# - Cursor can not be anymore in front of
    // a label, because numbering/bullet is switched off.
    SetInFrontOfLabel( false );
}
// <- #i29560#
 
// Request Default-Bulletlist
 
void SwWrtShell::BulletOn()
{
    NumOrBulletOn(false);
}
 
SelectionType SwWrtShell::GetSelectionType() const
{
    // ContentType cannot be determined within a Start-/EndAction.
    // Because there is no invalid value TEXT will be returned.
    // The value does not matter, it may be updated in EndAction anyway.
 
    if (ActionPend())
        return IsSelFrameMode() ? SelectionType::Frame : SelectionType::Text;
 
    SwView &_rView = const_cast<SwView&>(GetView());
    if (_rView.GetPostItMgr() && _rView.GetPostItMgr()->HasActiveSidebarWin() )
        return SelectionType::PostIt;
 
    // Inserting a frame is not a DrawMode
    SelectionType nCnt;
    if ( !_rView.GetEditWin().IsFrameAction() &&
        (IsObjSelected() || (_rView.IsDrawMode() && !IsFrameSelected()) ))
    {
        if (GetDrawView()->IsTextEdit())
            nCnt = SelectionType::DrawObjectEditMode;
        else
        {
            if (GetView().IsFormMode()) // Only Form selected
                nCnt = SelectionType::DbForm;
            else
                nCnt = SelectionType::DrawObject;            // Any draw object
 
            if (_rView.IsBezierEditMode())
                nCnt |= SelectionType::Ornament;
            else if( GetDrawView()->GetContext() == SdrViewContext::Media )
                nCnt |= SelectionType::Media;
 
            if (svx::checkForSelectedCustomShapes( GetDrawView(), true /* bOnlyExtruded */ ))
            {
                nCnt |= SelectionType::ExtrudedCustomShape;
            }
 
            if (svx::checkForSelectedFontWork( GetDrawView() ))
            {
                nCnt |= SelectionType::FontWork;
            }
        }
 
        return nCnt;
    }
 
    nCnt = static_cast<SelectionType>(GetCntType());
 
    if ( IsFrameSelected() )
    {
        if (_rView.IsDrawMode())
            _rView.LeaveDrawCreate();   // clean up (Bug #45639)
        if ( !(nCnt & (SelectionType::Graphic | SelectionType::Ole)) )
            return SelectionType::Frame;
    }
 
    if ( IsCursorInTable() )
        nCnt |= SelectionType::Table;
 
    if ( IsTableMode() )
    {
        nCnt |= SelectionType::Table | SelectionType::TableCell;
        SwTable::SearchType eTableSel = GetEnhancedTableSelection();
        if ( eTableSel == SwTable::SEARCH_ROW )
            nCnt |= SelectionType::TableRow;
        else if ( eTableSel == SwTable::SEARCH_COL )
            nCnt |= SelectionType::TableCol;
    }
 
    // Do not pop up numbering toolbar, if the text node has a numbering of type SVX_NUM_NUMBER_NONE.
    const SwNumRule* pNumRule = GetNumRuleAtCurrCursorPos();
    if ( pNumRule )
    {
        const SwTextNode* pTextNd =
            sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->GetNode());
 
        if ( pTextNd && pTextNd->IsInList() )
        {
            int nLevel = pTextNd->GetActualListLevel();
 
            if (nLevel < 0)
                nLevel = 0;
 
            if (nLevel >= MAXLEVEL)
                nLevel = MAXLEVEL - 1;
 
            const SwNumFormat& rFormat = pNumRule->Get(nLevel);
            if ( SVX_NUM_NUMBER_NONE != rFormat.GetNumberingType() )
                nCnt |= SelectionType::NumberList;
        }
    }
 
    return nCnt;
}
 
// Find the text collection with the name rCollname
// Returns:   Pointer at the collection or 0, if no
//            text collection with this name exists, or
//            this is a default template.
 
SwTextFormatColl *SwWrtShell::GetParaStyle(const OUString &rCollName, GetStyle eCreate )
{
    SwTextFormatColl* pColl = FindTextFormatCollByName( rCollName );
    if( !pColl && GETSTYLE_NOCREATE != eCreate )
    {
        sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rCollName, SwGetPoolIdFromName::TxtColl );
        if( USHRT_MAX != nId || GETSTYLE_CREATEANY == eCreate )
            pColl = GetTextCollFromPool( nId );
    }
    return pColl;
}
 
// Find the text collection with the name rCollname
// Returns:   Pointer at the collection or 0, if no
//            character template with this name exists, or
//            this is a default template or template is automatic.
 
SwCharFormat *SwWrtShell::GetCharStyle(const OUString &rFormatName, GetStyle eCreate )
{
    SwCharFormat* pFormat = FindCharFormatByName( rFormatName );
    if( !pFormat && GETSTYLE_NOCREATE != eCreate )
    {
        sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rFormatName, SwGetPoolIdFromName::ChrFmt );
        if( USHRT_MAX != nId || GETSTYLE_CREATEANY == eCreate )
            pFormat = static_cast<SwCharFormat*>(GetFormatFromPool( nId ));
    }
    return pFormat;
}
 
// Find the table format with the name rFormatname
// Returns:   Pointer at the collection or 0, if no
//            frame format with this name exists or
//            this is a default format or the format is automatic.
 
SwFrameFormat *SwWrtShell::GetTableStyle(std::u16string_view rFormatName)
{
    for( size_t i = GetTableFrameFormatCount(); i; )
    {
        SwFrameFormat *pFormat = &GetTableFrameFormat( --i );
        if( !pFormat->IsDefault() &&
            pFormat->GetName() == rFormatName && IsUsed( *pFormat ) )
            return pFormat;
    }
    return nullptr;
}
 
void SwWrtShell::addCurrentPosition() {
    SwPaM* pPaM = GetCursor();
    m_aNavigationMgr.addEntry(*pPaM->GetPoint());
}
 
// Applying templates
 
void SwWrtShell::SetPageStyle(const OUString &rCollName)
{
    if( !SwCursorShell::HasSelection() && !IsSelFrameMode() && !IsObjSelected() )
    {
        SwPageDesc* pDesc = FindPageDescByName( rCollName, true );
        if( pDesc )
            ChgCurPageDesc( *pDesc );
    }
}
 
// Access templates
 
OUString const & SwWrtShell::GetCurPageStyle() const
{
    return GetPageDesc(GetCurPageDesc( false/*bCalcFrame*/ )).GetName();
}
 
// Change the current template referring to the existing change.
 
void SwWrtShell::QuickUpdateStyle()
{
    SwTextFormatColl *pColl = GetCurTextFormatColl();
 
    // Default cannot be changed
    if(pColl && !pColl->IsDefault())
    {
        FillByEx(pColl);
            // Also apply the template to remove hard attribute assignment.
        SetTextFormatColl(pColl);
    }
}
 
void SwWrtShell::AutoUpdatePara(SwTextFormatColl* pColl, const SfxItemSet& rStyleSet, SwPaM* pPaM )
{
    SwPaM* pCursor = pPaM ? pPaM : GetCursor( );
    SfxItemSetFixed<
            RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
            RES_PARATR_BEGIN, RES_PARATR_END - 1,
            RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
            SID_ATTR_TABSTOP_DEFAULTS,SID_ATTR_TABSTOP_OFFSET,
            SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER,
            SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP,
            SID_ATTR_PARA_PAGENUM, SID_ATTR_PARA_PAGENUM>  aCoreSet( GetAttrPool() );
    GetPaMAttr( pCursor, aCoreSet );
    bool bReset = false;
 
    // ITEM: SfxItemIter and removing SfxPoolItems:
    std::vector<sal_uInt16> aDeleteWhichIDs;
 
    for (SfxItemIter aIter(aCoreSet); !aIter.IsAtEnd(); aIter.NextItem())
    {
        if(!IsInvalidItem(aIter.GetCurItem()))
        {
            if (SfxItemState::SET == aIter.GetItemState() &&
                SfxItemState::SET == rStyleSet.GetItemState(aIter.GetCurWhich()))
            {
                aDeleteWhichIDs.push_back(aIter.GetCurWhich());
                bReset = true;
            }
        }
    }
 
    for (auto nDelWhich : aDeleteWhichIDs)
        aCoreSet.ClearItem(nDelWhich);
 
    StartAction();
    if(bReset)
    {
        ResetAttr({}, pCursor);
        SetAttrSet(aCoreSet, SetAttrMode::DEFAULT, pCursor);
    }
    mxDoc->ChgFormat(*pColl, rStyleSet );
    EndAction();
}
 
void SwWrtShell::AutoUpdateFrame( SwFrameFormat* pFormat, const SfxItemSet& rStyleSet )
{
    StartAction();
 
    ResetFlyFrameAttr( &rStyleSet );
    pFormat->SetFormatAttr( rStyleSet );
 
    EndAction();
}
 
void SwWrtShell::AutoCorrect( SvxAutoCorrect& rACorr, sal_Unicode cChar )
{
    ResetCursorStack();
    if(!CanInsert())
        return;
 
    bool bStarted = false;
    SwRewriter aRewriter;
 
    if(HasSelection())
    {
            // Only parentheses here, because the regular insert
            // is already clipped to the editshell
        StartAllAction();
 
        OUString aTmpStr1 = SwResId(STR_START_QUOTE) +
            GetSelText() +
            SwResId(STR_END_QUOTE);
        OUString aTmpStr3 = SwResId(STR_START_QUOTE) +
            OUStringChar(cChar) +
            SwResId(STR_END_QUOTE);
        aRewriter.AddRule( UndoArg1, aTmpStr1 );
        aRewriter.AddRule( UndoArg2, SwResId(STR_YIELDS) );
        aRewriter.AddRule( UndoArg3, aTmpStr3 );
 
        StartUndo( SwUndoId::REPLACE, &aRewriter );
        bStarted = true;
        DelRight(true);
    }
    SwEditShell::AutoCorrect( rACorr, IsInsMode(), cChar );
 
    if(bStarted)
    {
        EndAllAction();
        EndUndo( SwUndoId::REPLACE, &aRewriter );
    }
}
 
// Some kind of controlled copy ctor
 
SwWrtShell::SwWrtShell( SwWrtShell& rSh, vcl::Window *_pWin, SwView &rShell )
    : SwFEShell(rSh, _pWin)
    , m_rView(rShell)
    , m_aNavigationMgr(*this)
{
    BITFLD_INI_LIST
    CurrShell aCurr( this );
 
    SetSfxViewShell( static_cast<SfxViewShell *>(&rShell) );
    SetFlyMacroLnk( LINK(this, SwWrtShell, ExecFlyMac) );
 
    // place the cursor on the first field...
    Fieldmark *pBM = nullptr;
    if (IsFormProtected() && (pBM = GetFieldmarkAfter()) !=nullptr) {
        GotoFieldmark(pBM);
    }
}
 
SwWrtShell::SwWrtShell( SwDoc& rDoc, vcl::Window *_pWin, SwView &rShell,
                        const SwViewOption *pViewOpt )
    : SwFEShell(rDoc, _pWin, pViewOpt)
    , m_rView(rShell)
    , m_aNavigationMgr(*this)
{
    BITFLD_INI_LIST
    CurrShell aCurr( this );
    SetSfxViewShell( static_cast<SfxViewShell *>(&rShell) );
    SetFlyMacroLnk( LINK(this, SwWrtShell, ExecFlyMac) );
 
    // place the cursor on the first field...
    Fieldmark *pBM = nullptr;
    if (IsFormProtected() && (pBM = GetFieldmarkAfter()) !=nullptr) {
        GotoFieldmark(pBM);
    }
}
 
SwWrtShell::~SwWrtShell()
{
    CurrShell aCurr( this );
    while(IsModePushed())
        PopMode();
    while(PopCursor(false))
        ;
    SwTransferable::ClearSelection( *this );
}
 
bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete)
{
    ::std::optional<SwCallLink> aLink(std::in_place, *this);
    return Pop(eDelete, aLink);
}
 
bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete, ::std::optional<SwCallLink>& roLink)
{
    bool bRet = SwCursorShell::Pop(eDelete, roLink);
    if( bRet && IsSelection() )
    {
        m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
        m_fnKillSel = &SwWrtShell::ResetSelect;
    }
    return bRet;
}
 
bool SwWrtShell::CanInsert()
{
    if(IsSelFrameMode())
    {
        return false;
    }
 
    if(IsObjSelected())
    {
        return false;
    }
 
    if(GetView().GetDrawFuncPtr())
    {
        return false;
    }
 
    if(GetView().GetPostItMgr()->GetActiveSidebarWin())
    {
        return false;
    }
 
    return true;
}
 
void SwWrtShell::ChgDBData(const SwDBData& aDBData)
{
    SwEditShell::ChgDBData(aDBData);
    //notify the db-beamer if available
    GetView().NotifyDBChanged();
}
 
OUString SwWrtShell::GetSelDescr() const
{
    OUString aResult;
 
    SelectionType nSelType = GetSelectionType();
    switch (nSelType)
    {
    case SelectionType::Graphic:
        aResult = SwResId(STR_GRAPHIC);
 
        break;
    case SelectionType::Frame:
        {
            const SwFrameFormat * pFrameFormat = GetSelectedFrameFormat();
 
            if (pFrameFormat)
                aResult = pFrameFormat->GetDescription();
        }
        break;
    case SelectionType::DrawObject:
        {
            aResult = SwResId(STR_DRAWING_OBJECTS);
        }
        break;
    default:
        if (mxDoc)
            aResult = GetCursorDescr();
    }
 
    return aResult;
}
 
void SwWrtShell::ApplyViewOptions( const SwViewOption &rOpt )
{
    SwFEShell::ApplyViewOptions( rOpt );
    //#i115062# invalidate meta character slot
    GetView().GetViewFrame().GetBindings().Invalidate( FN_VIEW_META_CHARS );
}
 
void SwWrtShell::SetReadonlyOption(bool bSet)
{
    GetView().GetEditWin().GetFrameControlsManager().SetReadonlyControls( bSet );
    SwViewShell::SetReadonlyOption( bSet );
}
 
// Switch on/off header or footer of a page style - if an empty name is
// given all styles are changed
 
void SwWrtShell::ChangeHeaderOrFooter(
    std::u16string_view rStyleName, bool bHeader, bool bOn, bool bShowWarning)
{
    SdrView *const pSdrView = GetDrawView();
    if (pSdrView && pSdrView->IsTextEdit())
    {   // tdf#107474 deleting header may delete active drawing object
        pSdrView->SdrEndTextEdit(true);
    }
    addCurrentPosition();
    StartAllAction();
    StartUndo( SwUndoId::HEADER_FOOTER ); // #i7983#
    bool bExecute = true;
    bool bCursorSet = false;
    for( size_t nFrom = 0, nTo = GetPageDescCnt();
            nFrom < nTo; ++nFrom )
    {
        SwPageDesc aDesc( GetPageDesc( nFrom ));
        OUString sTmp(aDesc.GetName());
        if( rStyleName.empty() || rStyleName == sTmp )
        {
            bool bChgd = false;
 
            if( bShowWarning && !bOn && GetActiveView() && GetActiveView() == &GetView() &&
                ( (bHeader && aDesc.GetMaster().GetHeader().IsActive()) ||
                  (!bHeader && aDesc.GetMaster().GetFooter().IsActive()) ) )
            {
                bShowWarning = false;
                //Actions have to be closed while the dialog is showing
                EndAllAction();
 
                weld::Window* pParent = GetView().GetFrameWeld();
                short nResult;
                if (bHeader) {
                    nResult = DeleteHeaderDialog(pParent).run();
                } else {
                    nResult = DeleteFooterDialog(pParent).run();
                }
 
                bExecute = nResult == RET_YES;
                StartAllAction();
                if (nResult == RET_YES)
                    ToggleHeaderFooterEdit();
            }
            if( bExecute )
            {
                bChgd = true;
                SwFrameFormat &rMaster = aDesc.GetMaster();
                if(bHeader)
                    rMaster.SetFormatAttr( SwFormatHeader( bOn ));
                else
                    rMaster.SetFormatAttr( SwFormatFooter( bOn ));
                if( bOn )
                {
                    // keep in sync with FN_PGNUMBER_WIZARD
                    constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm);
                    SvxULSpaceItem aUL(bHeader ? 0 : constTwips_5mm, bHeader ? constTwips_5mm : 0, RES_UL_SPACE );
                    SwFrameFormat* pFormat = bHeader ?
                        const_cast<SwFrameFormat*>(rMaster.GetHeader().GetHeaderFormat()) :
                        const_cast<SwFrameFormat*>(rMaster.GetFooter().GetFooterFormat());
                    pFormat->SetFormatAttr( aUL );
                    XFillStyleItem aFill(drawing::FillStyle_NONE);
                    pFormat->SetFormatAttr(aFill);
                }
            }
            if( bChgd )
            {
                ChgPageDesc( nFrom, aDesc );
 
                if( !bCursorSet && bOn )
                {
                    if ( !IsHeaderFooterEdit() )
                        ToggleHeaderFooterEdit();
                    bCursorSet = SetCursorInHdFt(
                            rStyleName.empty() ? SIZE_MAX : nFrom,
                            bHeader );
                }
            }
        }
    }
    EndUndo( SwUndoId::HEADER_FOOTER ); // #i7983#
    EndAllAction();
}
 
void SwWrtShell::SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow )
{
    SwViewShell::SetShowHeaderFooterSeparator( eControl, bShow );
    if ( !bShow )
        GetView().GetEditWin().GetFrameControlsManager().HideControls( eControl );
}
 
void SwWrtShell::InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq)
{
    SwPostItField* pPostIt = dynamic_cast<SwPostItField*>(rFieldMgr.GetCurField());
 
    {
        const SvxPostItAuthorItem* pAuthorItem = rReq.GetArg<SvxPostItAuthorItem>(SID_ATTR_POSTIT_AUTHOR);
        OUString sAuthor;
        if ( pAuthorItem )
            sAuthor = pAuthorItem->GetValue();
        else
        {
            std::size_t nAuthor = SW_MOD()->GetRedlineAuthor();
            sAuthor = SW_MOD()->GetRedlineAuthor(nAuthor);
        }
 
        const SvxPostItTextItem* pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT);
        OUString sText;
        if ( pTextItem )
            sText = pTextItem->GetValue();
 
        std::optional<OutlinerParaObject> oTextPara;
        if (const SvxPostItTextItem* pHtmlItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_HTML))
        {
            SwDocShell* pDocSh = GetView().GetDocShell();
            Outliner aOutliner(&pDocSh->GetPool(), OutlinerMode::TextObject);
            SwPostItHelper::ImportHTML(aOutliner, pHtmlItem->GetValue());
            oTextPara = aOutliner.CreateParaObject();
        }
 
        // If we have a text already registered for answer, use that
        SwPostItMgr* pPostItMgr = GetView().GetPostItMgr();
        if (OutlinerParaObject* pAnswer = pPostItMgr->IsAnswer())
        {
            if (!pPostItMgr->GetAnswerText().isEmpty())
            {
                sText = GetView().GetPostItMgr()->GetAnswerText();
                pPostItMgr->RegisterAnswerText(OUString());
            }
            const EditTextObject& rTextObject = pAnswer->GetTextObject();
            if (rTextObject.GetParagraphCount() != 1 || !rTextObject.GetText(0).isEmpty())
                oTextPara = *pAnswer;
        }
 
        if ( HasSelection() && !IsTableMode() )
        {
            KillPams();
        }
 
        // #i120513# Inserting a comment into an autocompletion crashes
        // --> suggestion has to be removed before
        GetView().GetEditWin().StopQuickHelp();
 
        SwInsertField_Data aData(SwFieldTypesEnum::Postit, 0, sAuthor, sText, 0);
 
        if (IsSelFrameMode())
        {
            SwFlyFrame* pFly = GetSelectedFlyFrame();
 
            // Remember the anchor of the selected object before deletion.
            std::optional<SwPosition> oAnchor;
            if (pFly)
            {
                SwFrameFormat* pFormat = pFly->GetFormat();
                if (pFormat)
                {
                    RndStdIds eAnchorId = pFormat->GetAnchor().GetAnchorId();
                    if ((eAnchorId == RndStdIds::FLY_AS_CHAR || eAnchorId == RndStdIds::FLY_AT_CHAR) && pFormat->GetAnchor().GetAnchorNode())
                    {
                        oAnchor.emplace(*pFormat->GetAnchor().GetContentAnchor());
                    }
                }
            }
 
            // A frame is selected, end frame selection.
            EnterStdMode();
            GetView().AttrChangedNotify(nullptr);
 
            // Set up text selection, so the anchor of the frame will be the anchor of the
            // comment.
            if (pFly)
            {
                if (oAnchor)
                    *GetCurrentShellCursor().GetPoint() = *oAnchor;
                SwFrameFormat* pFormat = pFly->GetFormat();
                if (pFormat && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
                {
                    Right(SwCursorSkipMode::Cells, /*bSelect=*/true, 1, /*bBasicCall=*/false, /*bVisual=*/true);
                }
                else if (pFormat && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR)
                {
                    aData.m_oAnnotationRange.emplace(*GetCurrentShellCursor().Start(),
                                                     *GetCurrentShellCursor().End());
                }
            }
        }
 
        rFieldMgr.InsertField( aData );
 
        Push();
        SwCursorShell::Left(1, SwCursorSkipMode::Chars);
        pPostIt = static_cast<SwPostItField*>(rFieldMgr.GetCurField());
 
        if (pPostIt && oTextPara)
        {
            pPostIt->SetTextObject(*oTextPara);
        }
 
        Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore cursor position
    }
 
    // Client has disabled annotations rendering, no need to
    // focus the postit field
    if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
        return;
 
    if (pPostIt)
    {
        SwFieldType* pType = GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(), false);
        if(auto pFormat = pType->FindFormatForField(pPostIt))
            pFormat->Broadcast( SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::FOCUS, &GetView() ) );
    }
}
 
bool SwWrtShell::IsOutlineContentVisible(const size_t nPos)
{
    const SwOutlineNodes& rOutlineNodes = GetDoc()->GetNodes().GetOutLineNds();
    const SwNode* pOutlineNode = rOutlineNodes[nPos];
 
    // no layout frame means outline folding is set to include sub levels and the outline node has
    // a parent outline node with outline content visible attribute false (folded outline content)
    if (!pOutlineNode->GetTextNode()->getLayoutFrame(GetLayout()))
        return false;
 
    // try the next node to determine if this outline node has visible content
    SwNodeIndex aIdx(*pOutlineNode, +1);
    if (aIdx.GetNode() == aIdx.GetNodes().GetEndOfContent()) // end of regular content
        return false;
 
    if (aIdx.GetNode().IsTextNode() || aIdx.GetNode().IsTableNode() ||
            aIdx.GetNode().IsSectionNode())
    {
        // * sublevels treated as outline content
        //     If next node (aIdx) doesn't have a layout frame
        //     then this outline node does not have visible outline content.
        // * sublevels NOT treated as outline content
        //     If the next node (aIdx) is the next outline node
        //     then return the outline content visible attribute value.
        if (!GetViewOptions()->IsTreatSubOutlineLevelsAsContent() &&
                nPos + 1 < rOutlineNodes.size() &&
                rOutlineNodes[nPos + 1] == &aIdx.GetNode())
            return GetAttrOutlineContentVisible(nPos);
 
        if (aIdx.GetNode().IsTextNode())
            return aIdx.GetNode().GetTextNode()->getLayoutFrame(GetLayout());
        if (aIdx.GetNode().IsTableNode())
        {
            SwTable& rTable = aIdx.GetNode().GetTableNode()->GetTable();
            return rTable.HasLayout();
        }
        if (aIdx.GetNode().IsSectionNode())
        {
            const auto pFormat = aIdx.GetNode().GetSectionNode()->GetSection().GetFormat();
            return pFormat && pFormat->IsVisible();
        }
    }
 
    return true;
}
 
void SwWrtShell::MakeOutlineLevelsVisible(const int nLevel)
{
    MakeAllOutlineContentTemporarilyVisible a(GetDoc());
 
    m_rView.SetMaxOutlineLevelShown(nLevel);
 
    bool bDocChanged = false;
 
    const SwOutlineNodes& rOutlineNodes = GetNodes().GetOutLineNds();
 
    // Make all missing frames.
    for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos)
    {
        SwNode* pNode = rOutlineNodes[nPos];
        if (!pNode->GetTextNode()->getLayoutFrame(GetLayout()))
        {
            SwNodeIndex aIdx(*pNode, +1);
            // Make the outline paragraph frame
            MakeFrames(GetDoc(), *pNode, aIdx.GetNode());
            // Make the outline content visible but don't set the outline visible attribute and
            // don't make outline content made visible not visible that have outline visible
            // attribute false. Visibility will be taken care of when
            // MakeAllOutlineContentTemporarilyVisible goes out of scope.
            MakeOutlineContentVisible(nPos, true, false);
            bDocChanged = true;
        }
    }
    // Remove outline paragraph frame and outline content frames above given level.
    for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos)
    {
        SwNode* pNode = rOutlineNodes[nPos];
        auto nOutlineLevel = pNode->GetTextNode()->GetAttrOutlineLevel();
        if (nOutlineLevel > nLevel)
        {
            // Remove the outline content but don't set the outline visible attribute. Visibility
            // will be taken care of when MakeAllOutlineContentTemporarilyVisible goes out of scope.
            MakeOutlineContentVisible(nPos, false, false);
            // Remove the outline paragraph frame.
            pNode->GetTextNode()->DelFrames(GetLayout());
            bDocChanged = true;
        }
    }
 
    // Broadcast DocChanged if document layout has changed so the Navigator will be updated.
    if (bDocChanged)
        GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
}
 
void SwWrtShell::MakeOutlineContentVisible(const size_t nPos, bool bMakeVisible, bool bSetAttrOutlineVisibility)
{
    const SwNodes& rNodes = GetNodes();
    const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
 
    SwNode* pSttNd = rOutlineNodes[nPos];
 
    // determine end node
    SwNode* pEndNd = &rNodes.GetEndOfContent();
    if (rOutlineNodes.size() > nPos + 1)
        pEndNd = rOutlineNodes[nPos + 1];
 
    if (GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
    {
        // get the last outline node to include (iPos)
        int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
        int nMaxOutlineLevelShown = m_rView.GetMaxOutlineLevelShown();
        SwOutlineNodes::size_type iPos = nPos;
        while (++iPos < rOutlineNodes.size() &&
               rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel &&
               rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() <= nMaxOutlineLevelShown);
 
        // get the correct end node
        // the outline node may be in frames, headers, footers special section of doc model
        SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
        while (pStartOfSectionNodeSttNd->StartOfSectionNode()
               != pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
        {
            pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
        }
        pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
 
        if (iPos < rOutlineNodes.size())
        {
            SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
            while (pStartOfSectionNode->StartOfSectionNode()
                   != pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
            {
                pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
            }
            if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
                pEndNd = rOutlineNodes[iPos];
        }
    }
 
    // table, text box, header, footer
    if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
    {
        // limit to within section
        if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
            pEndNd = pSttNd->EndOfSectionNode();
    }
    // if pSttNd isn't in table but pEndNd is, skip over all outline nodes in table
    else if (pEndNd->GetTableBox())
    {
        pEndNd = &rNodes.GetEndOfContent();
        for (size_t nOutlinePos = nPos + 2; nOutlinePos < rOutlineNodes.size(); nOutlinePos++)
        {
            if (!(rOutlineNodes[nOutlinePos]->GetTableBox()))
            {
                pEndNd = rOutlineNodes[nOutlinePos];
                break;
            }
        }
    }
    // end node determined
 
    // Remove content frames from the next node after the starting outline node to
    // the determined ending node. Always do this to prevent the chance of duplicate
    // frames being made. They will be remade below if needed.
    SwNodeIndex aIdx(*pSttNd, +1);
    while (aIdx != *pEndNd)
    {
        SwNode* pNd = &aIdx.GetNode();
        if (pNd->IsContentNode())
            pNd->GetContentNode()->DelFrames(nullptr);
        else if (pNd->IsTableNode())
            pNd->GetTableNode()->DelFrames(nullptr);
        ++aIdx;
    }
 
    if (bMakeVisible) // make outline nodes outline content visible
    {
        // reset the index marker and make frames
        aIdx.Assign(*pSttNd, +1);
        MakeFrames(GetDoc(), aIdx.GetNode(), *pEndNd);
 
        if (bSetAttrOutlineVisibility)
        {
            pSttNd->GetTextNode()->SetAttrOutlineContentVisible(true);
 
            // make outline content made visible that have outline visible attribute false not visible
            while (aIdx != *pEndNd)
            {
                SwNode* pNd = &aIdx.GetNode();
                if (pNd->IsTextNode() && pNd->GetTextNode()->IsOutline())
                {
                    SwTextNode* pTextNd = pNd->GetTextNode();
                    bool bOutlineContentVisibleAttr = true;
                    pTextNd->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
                    if (!bOutlineContentVisibleAttr)
                    {
                        SwOutlineNodes::size_type iPos;
                        if (rOutlineNodes.Seek_Entry(pTextNd, &iPos))
                        {
                            if (pTextNd->getLayoutFrame(nullptr))
                                MakeOutlineContentVisible(iPos, false);
                        }
                    }
                }
                ++aIdx;
            }
        }
    }
    else if (bSetAttrOutlineVisibility)
        pSttNd->GetTextNode()->SetAttrOutlineContentVisible(false);
}
 
// make content visible or not visible only if needed
void SwWrtShell::InvalidateOutlineContentVisibility()
{
    GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
 
    const SwOutlineNodes& rOutlineNds = GetNodes().GetOutLineNds();
    for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
    {
        bool bIsOutlineContentVisible = IsOutlineContentVisible(nPos);
        bool bOutlineContentVisibleAttr = true;
        rOutlineNds[nPos]->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
        if (!bIsOutlineContentVisible && bOutlineContentVisibleAttr)
            MakeOutlineContentVisible(nPos);
        else if (bIsOutlineContentVisible && !bOutlineContentVisibleAttr)
            MakeOutlineContentVisible(nPos, false);
    }
}
 
void SwWrtShell::MakeAllFoldedOutlineContentVisible(bool bMakeVisible)
{
    if (bMakeVisible)
    {
        // make all content visible
 
        // When shortcut is assigned to the show outline content visibility button and used to
        // toggle the feature and the mouse pointer is on an outline frame the button will not
        // be removed. An easy way to make sure the button does not remain shown is to use the
        // HideControls function.
        GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
 
        // temporarily set outline content visible attribute true for folded outline nodes
        std::vector<SwNode*> aFoldedOutlineNodeArray;
        for (SwNode* pNd: GetNodes().GetOutLineNds())
        {
            bool bOutlineContentVisibleAttr = true;
            pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
            if (!bOutlineContentVisibleAttr)
            {
                aFoldedOutlineNodeArray.push_back(pNd);
                pNd->GetTextNode()->SetAttrOutlineContentVisible(true);
            }
        }
 
        StartAction();
        InvalidateOutlineContentVisibility();
        EndAction();
 
        // restore outline content visible attribute for folded outline nodes
        for (SwNode* pNd: aFoldedOutlineNodeArray)
            pNd->GetTextNode()->SetAttrOutlineContentVisible(false);
    }
    else
    {
        AssureStdMode();
 
        // Get the outline position of the cursor so the cursor can be place at a visible outline
        // node if it is not visible after InvalidateOutlineContentVisiblity below.
        SwOutlineNodes::size_type nPos = GetOutlinePos();
 
        StartAction();
        InvalidateOutlineContentVisibility();
        EndAction();
 
        // If needed, find a visible outline node to place the cursor.
        if (nPos != SwOutlineNodes::npos && !IsOutlineContentVisible(nPos))
        {
            while (nPos != SwOutlineNodes::npos &&
                   !GetNodes().GetOutLineNds()[nPos]->GetTextNode()->getLayoutFrame(GetLayout()))
                --nPos;
            if (nPos != SwOutlineNodes::npos)
                GotoOutline(nPos);
        }
    }
    GetView().GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
}
 
bool SwWrtShell::GetAttrOutlineContentVisible(const size_t nPos) const
{
    bool bVisibleAttr = true;
    GetNodes().GetOutLineNds()[nPos]->GetTextNode()->GetAttrOutlineContentVisible(bVisibleAttr);
    return bVisibleAttr;
}
 
bool SwWrtShell::HasFoldedOutlineContentSelected() const
{
    // No need to check for selection over folded outline content when there are no outline nodes.
    if (GetDoc()->GetNodes().GetOutLineNds().empty())
        return false;
    for(const SwPaM& rPaM : GetCursor()->GetRingContainer())
    {
        SwPaM aPaM(*rPaM.GetMark(), *rPaM.GetPoint());
        aPaM.Normalize();
        SwNodeIndex aPointIdx(aPaM.GetPoint()->GetNode());
        SwNodeIndex aMarkIdx(aPaM.GetMark()->GetNode());
        // Prevent crash in the for loop below by adjusting the mark if it is set to the end of
        // content node.
        if (aMarkIdx.GetNode() == GetDoc()->GetNodes().GetEndOfContent())
            --aMarkIdx;
        if (aPointIdx == aMarkIdx)
            continue;
        // Return true if any nodes in PaM are folded outline content nodes.
        SwOutlineNodes::size_type nPos;
        for (SwNodeIndex aIdx = aPointIdx; aIdx <= aMarkIdx; ++aIdx)
        {
            // To allow delete when the start of the selection is at the start of a
            // paragraph and the end of the selection is at the start of a paragraph and there
            // are no folded outline content nodes in between.
            if (aIdx == aMarkIdx && aPaM.GetPoint()->GetContentIndex() == 0 &&
                    aPaM.GetMark()->GetContentIndex() == 0)
                return false;
 
            if (GetDoc()->GetNodes().GetOutLineNds().Seek_Entry(&(aIdx.GetNode()), &nPos) &&
                    !GetAttrOutlineContentVisible(nPos))
                return true;
        }
    }
    return false;
}
 
void SwWrtShell::InfoReadOnlyDialog(bool bAsync) const
{
    if (bAsync)
    {
        auto xInfo = std::make_shared<weld::MessageDialogController>(
                    GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui", "InfoReadonlyDialog");
        if (GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
                HasFoldedOutlineContentSelected())
        {
            xInfo->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
            xInfo->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
        }
        weld::DialogController::runAsync(xInfo, [](int) {});
    }
    else
    {
        std::unique_ptr<weld::Builder>
                xBuilder(Application::CreateBuilder(GetView().GetFrameWeld(),
                                                    u"modules/swriter/ui/inforeadonlydialog.ui"_ustr));
        std::unique_ptr<weld::MessageDialog>
                xInfo(xBuilder->weld_message_dialog(u"InfoReadonlyDialog"_ustr));
        if (GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
                HasFoldedOutlineContentSelected())
        {
            xInfo->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
            xInfo->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
        }
        xInfo->run();
    }
}
 
bool SwWrtShell::WarnHiddenSectionDialog() const
{
    std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(
        GetView().GetFrameWeld(), u"modules/swriter/ui/warnhiddensectiondialog.ui"_ustr));
    std::unique_ptr<weld::MessageDialog> xQuery(
        xBuilder->weld_message_dialog(u"WarnHiddenSectionDialog"_ustr));
    if (GetViewOptions()->IsShowOutlineContentVisibilityButton()
        && HasFoldedOutlineContentSelected())
    {
        xQuery->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
        xQuery->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
    }
 
    return (RET_YES == xQuery->run());
}
 
bool SwWrtShell::WarnSwitchToDesignModeDialog() const
{
    std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(nullptr,
        VclMessageType::Question, VclButtonsType::YesNo, SwResId(STR_A11Y_DESIGN_MODE_PRIMARY)));
    xQuery->set_default_response(RET_YES);
    xQuery->set_title(SwResId(STR_A11Y_DESIGN_MODE_TITLE));
    xQuery->set_secondary_text(SwResId(STR_A11Y_DESIGN_MODE_SECONDARY));
 
    return (RET_YES == xQuery->run());
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'RequestObjectResize' is required to be utilized.

V530 The return value of function 'DoVerb' is required to be utilized.

V530 The return value of function 'DoVerb' is required to be utilized.

V530 The return value of function 'RequestObjectResize' is required to be utilized.

V530 The return value of function 'Assign' is required to be utilized.

V530 The return value of function 'Assign' is required to be utilized.

V530 The return value of function 'Assign' is required to be utilized.

V773 Visibility scope of the 'pClient' pointer was exited without releasing the memory. A memory leak is possible.

V773 Visibility scope of the 'pCli' pointer was exited without releasing the memory. A memory leak is possible.

V773 The function was exited without releasing the 'pCli' pointer. A memory leak is possible.

V1019 Compound assignment expression is used inside condition.