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

Quelle  textfld.cxx   Sprache: C

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


#include <com/sun/star/beans/PropertyValues.hpp>
#include <AnnotationWin.hxx>
#include <comphelper/lok.hxx>
#include <hintids.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/lnkbase.hxx>
#include <txtfld.hxx>
#include <svl/itempool.hxx>
#include <svl/numformat.hxx>
#include <editeng/editobj.hxx>
#include <tools/lineend.hxx>
#include <svl/whiter.hxx>
#include <svl/eitem.hxx>
#include <svl/macitem.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/request.hxx>
#include <svx/postattr.hxx>
#include <svx/hlnkitem.hxx>
#include <svx/svxdlg.hxx>
#include <osl/diagnose.h>
#include <charatr.hxx>
#include <fmtfsize.hxx>
#include <fmthdft.hxx>
#include <fmtinfmt.hxx>
#include <fldwrap.hxx>
#include <frmatr.hxx>
#include <hfspacingitem.hxx>
#include <redline.hxx>
#include <swfont.hxx>
#include <view.hxx>
#include <viewopt.hxx>
#include <wrtsh.hxx>
#include <textsh.hxx>
#include <docufld.hxx>
#include <ddefld.hxx>
#include <fldmgr.hxx>
#include <uitool.hxx>
#include <cmdid.h>
#include <strings.hrc>
#include <sfx2/event.hxx>
#include <swabstdlg.hxx>
#include <doc.hxx>
#include <PostItMgr.hxx>
#include <swmodule.hxx>
#include <svtools/strings.hrc>
#include <svtools/svtresid.hxx>

#include <xmloff/odffields.hxx>
#include <IDocumentContentOperations.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentUndoRedo.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <svx/xfillit0.hxx>
#include <svx/pageitem.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <IMark.hxx>
#include <officecfg/Office/Common.hxx>
#include <officecfg/Office/Compatibility.hxx>
#include <ndtxt.hxx>
#include <translatehelper.hxx>
#include <sfx2/dispatch.hxx>


using namespace nsSwDocInfoSubType;

static OUString lcl_BuildTitleWithRedline( const SwRangeRedline *pRedline )
{
    const OUString sTitle(SwResId(STR_REDLINE_COMMENT));

    TranslateId pResId;
    switch( pRedline->GetType() )
    {
        case RedlineType::Insert:
            pResId = STR_REDLINE_INSERTED;
            break;
        case RedlineType::Delete:
            pResId = STR_REDLINE_DELETED;
            break;
        case RedlineType::Format:
        case RedlineType::ParagraphFormat:
            pResId = STR_REDLINE_FORMATTED;
            break;
        case RedlineType::Table:
            pResId = STR_REDLINE_TABLECHG;
            break;
        case RedlineType::FmtColl:
            pResId = STR_REDLINE_FMTCOLLSET;
            break;
        default:
            return sTitle;
    }

    return sTitle + SwResId(pResId);
}

static bool lcl_canUserModifyAnnotation(const SwView& rView, std::u16string_view sAuthor)
{
    return !comphelper::LibreOfficeKit::isActive() || !rView.IsLokReadOnlyView()
           || sAuthor == rView.GetRedlineAuthor();
}

static bool lcl_canUserModifyAnnotation(const SwView& rView,
                                        const sw::annotation::SwAnnotationWin* pAnnotationWin)
{
    return pAnnotationWin && lcl_canUserModifyAnnotation(rView, pAnnotationWin->GetAuthor());
}

static bool lcl_canUserModifyAnnotation(const SwView& rView, sal_uInt32 nPostItId)
{
    return lcl_canUserModifyAnnotation(rView, rView.GetPostItMgr()->GetAnnotationWin(nPostItId));
}

void SwTextShell::ExecField(SfxRequest &rReq)
{
    SwWrtShell& rSh = GetShell();
    const SfxPoolItem* pItem = nullptr;

    sal_uInt16 nSlot = rReq.GetSlot();
    const SfxItemSet* pArgs = rReq.GetArgs();
    if(pArgs)
        pArgs->GetItemState(GetPool().GetWhichIDFromSlotID(nSlot), false, &pItem);

    bool bMore = false;
    bool bIsText = true;
    SwFieldTypesEnum nInsertType = SwFieldTypesEnum::Date;
    sal_uInt16 nInsertSubType = 0;
    sal_uInt32 nInsertFormat = 0;

    switch(nSlot)
    {
        case FN_EDIT_FIELD:
        {
            SwField* pField = rSh.GetCurField(true);
            if( pField )
            {
                switch ( pField->GetTypeId() )
                {
                    case SwFieldTypesEnum::DDE:
                    {
                        ::sfx2::SvBaseLink& rLink = static_cast<SwDDEFieldType*>(pField->GetTyp())->
                                                GetBaseLink();
                        if(rLink.IsVisible())
                        {
                            if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
                            {
                                std::unique_ptr<weld::MessageDialog> xError(
                                    Application::CreateMessageDialog(
                                        nullptr, VclMessageType::Warning, VclButtonsType::Ok,
                                        SvtResId(STR_WARNING_EXTERNAL_LINK_EDIT_DISABLED)));
                                xError->run();
                                break;
                            }

                            SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
                            VclPtr<SfxAbstractLinksDialog> pDlg(pFact->CreateLinksDialog(GetView().GetFrameWeld(), &rSh.GetLinkManager(), false, &rLink));
                            pDlg->StartExecuteAsync(
                                [pDlg] (sal_Int32 /*nResult*/)->void
                                {
                                    pDlg->disposeOnce();
                                }
                            );
                        }
                        break;
                    }
                    default:
                    {
                        SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
                        VclPtr<SfxAbstractDialog> pDlg(pFact->CreateSwFieldEditDlg( GetView() ));
                        // without TabPage no dialog
                        if (pDlg)
                            pDlg->StartExecuteAsync(
                                [pDlg] (sal_Int32 /*nResult*/)->void
                                {
                                    pDlg->disposeOnce();
                                }
                            );
                    }
                }
            }
            break;
        }
        case FN_COPY_FIELD:
        {
            //call copy field dialog with field string - if there is any!
            SwField* pField = rSh.GetCurField(true);
            if( pField && pField->ExpandField(true, nullptr).getLength())
            {
                SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
                VclPtr<AbstractCopyFieldDlg> pDlg(pFact->CreateCopyFieldDlg(
                    GetView().GetFrameWeld(), pField->ExpandField(true, nullptr)));
                pDlg->StartExecuteAsync(
                    [pDlg] (sal_Int32 /*nResult*/)->void
                    {
                        pDlg->disposeOnce();
                    }
                );
            }
            break;
        }
        case FN_UPDATE_SEL_FIELD:
        {
            SwField *pField = rSh.GetCurField();

            if (pField)
            {
               rSh.UpdateOneField(*pField);
            }
            break;
        }
        case FN_CONVERT_SEL_FIELD:
        {
            SwField* pField = rSh.GetCurField();
            if (pField)
            {
               rSh.ConvertOneFieldToText(*pField);
            }
            break;
        }
        case FN_EXECUTE_MACROFIELD:
        {
            SwField* pField = rSh.GetCurField();
            if(pField && pField->GetTyp()->Which() == SwFieldIds::Macro)
            {

                const OUString& rMacro = static_cast<SwMacroField*>(pField)->GetMacro();
                sal_Int32 nPos = rMacro.indexOf('.');
                if(nPos != -1)
                {
                    SvxMacro aMacro( rMacro.copy(nPos + 1), rMacro.copy(0,nPos), STARBASIC );
                    rSh.ExecMacro(aMacro);
                }
            }
        }
        break;

        case FN_GOTO_NEXT_INPUTFLD:
        case FN_GOTO_PREV_INPUTFLD:
            {
                bool bRet = false;
                SwFieldType* pField = rSh.GetFieldType( 0, SwFieldIds::Input );
                const bool bAddSetExpressionFields = !( rSh.GetViewOptions()->IsReadonly() );
                if ( pField != nullptr
                     && rSh.MoveFieldType(
                            pField,
                            FN_GOTO_NEXT_INPUTFLD == nSlot,
                            SwFieldIds::Unknown,
                            bAddSetExpressionFields ) )
                {
                    rSh.ClearMark();
                    if (!rSh.IsMultiSelection()
                        && (nullptr != dynamic_cast<const SwTextInputField*>(
                               SwCursorShell::GetTextFieldAtCursor(rSh.GetCursor(), ::sw::GetTextAttrMode::Default))))
                    {
                        rSh.SttSelect();
                        rSh.SelectTextModel(
                            SwCursorShell::StartOfInputFieldAtPos( *(rSh.GetCursor()->Start()) ) + 1,
                            SwCursorShell::EndOfInputFieldAtPos( *(rSh.GetCursor()->Start()) ) - 1 );
                    }
                    else if (SwField* pCurrentField = rSh.GetCurField(true))
                    {
                        rSh.StartInputFieldDlg(pCurrentField, falsefalse, GetView().GetFrameWeld());
                    }
                    bRet = true;
                }

                rReq.SetReturnValue( SfxBoolItem( nSlot, bRet ));
            }
            break;

        case FN_GOTO_MARK:
        {
            const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(FN_GOTO_MARK);
            if (pName)
            {
                rSh.GotoMark(SwMarkName(pName->GetValue()));
            }
        }
        break;
        default:
            bMore = true;
    }
    if(!bMore)
        return;

    // Here come the slots with FieldMgr.
    SwFieldMgr aFieldMgr(GetShellPtr());
    switch(nSlot)
    {
        case FN_INSERT_DBFIELD:
        {
            bool bRes = false;
            if( pItem )
            {
                sal_uInt32 nFormat = 0;
                SwFieldTypesEnum nType = SwFieldTypesEnum::Date;
                OUString aPar1 = static_cast<const SfxStringItem *>(pItem)->GetValue();
                OUString aPar2;
                sal_Int32 nCommand = 0;

                ifconst SfxUInt16Item* pFieldItem = pArgs->GetItemIfSet( FN_PARAM_FIELD_TYPE,
                                                            false ))
                    nType = static_cast<SwFieldTypesEnum>(pFieldItem->GetValue());
                aPar1 += OUStringChar(DB_DELIM);
                if( SfxItemState::SET == pArgs->GetItemState(
                                    FN_PARAM_1, false, &pItem ))
                {
                    aPar1 += static_cast<const SfxStringItem *>(pItem)->GetValue();
                }
                if( SfxItemState::SET == pArgs->GetItemState(
                                    FN_PARAM_3, false, &pItem ))
                    nCommand = static_cast<const SfxInt32Item*>(pItem)->GetValue();
                aPar1 += OUStringChar(DB_DELIM)
                    + OUString::number(nCommand)
                    + OUStringChar(DB_DELIM);
                if( SfxItemState::SET == pArgs->GetItemState(
                                    FN_PARAM_2, false, &pItem ))
                {
                    aPar1 += static_cast<const SfxStringItem *>(pItem)->GetValue();
                }
                ifconst SfxStringItem* pContentItem = pArgs->GetItemIfSet(
                                    FN_PARAM_FIELD_CONTENT, false ))
                    aPar2 = pContentItem->GetValue();
                ifconst SfxUInt32Item* pFormatItem = pArgs->GetItemIfSet(
                                    FN_PARAM_FIELD_FORMAT, false ))
                    nFormat = pFormatItem->GetValue();
                OSL_FAIL("Command is not yet used");
                SwInsertField_Data aData(nType, 0, aPar1, aPar2, nFormat, GetShellPtr(), ' '/*separator*/ );
                bRes = aFieldMgr.InsertField(aData);
            }
            rReq.SetReturnValue(SfxBoolItem( nSlot, bRes ));
        }
        break;
        case FN_INSERT_FIELD_CTRL:
        case FN_INSERT_FIELD:
        {
            bool bRes = false;
            if( pItem && nSlot != FN_INSERT_FIELD_CTRL)
            {
                sal_uInt32 nFormat = 0;
                SwFieldTypesEnum nType = SwFieldTypesEnum::Date;
                sal_uInt16 nSubType = 0;
                OUString aPar1 = static_cast<const SfxStringItem *>(pItem)->GetValue();
                OUString aPar2;
                sal_Unicode cSeparator = ' ';

                ifconst SfxUInt16Item* pTypeItem = pArgs->GetItemIfSet( FN_PARAM_FIELD_TYPE,
                                                            false ))
                    nType = static_cast<SwFieldTypesEnum>(pTypeItem->GetValue());
                else if (pArgs->GetItemState(FN_PARAM_4, false, &pItem) == SfxItemState::SET)
                {
                    const OUString& rTypeName = static_cast<const SfxStringItem *>(pItem)->GetValue();
                    nType = SwFieldTypeFromString(rTypeName);
                }
                ifconst SfxUInt16Item* pSubtypeItem = pArgs->GetItemIfSet( FN_PARAM_FIELD_SUBTYPE,
                                                            false ))
                    nSubType = pSubtypeItem->GetValue();
                ifconst SfxStringItem* pContentItem = pArgs->GetItemIfSet(
                                    FN_PARAM_FIELD_CONTENT, false ))
                    aPar2 = pContentItem->GetValue();
                ifconst SfxUInt32Item* pFormatItem = pArgs->GetItemIfSet(
                                    FN_PARAM_FIELD_FORMAT, false ))
                    nFormat = pFormatItem->GetValue();
                if( SfxItemState::SET == pArgs->GetItemState(
                                    FN_PARAM_3, false, &pItem ))
                {
                    OUString sTmp = static_cast<const SfxStringItem *>(pItem)->GetValue();
                    if(!sTmp.isEmpty())
                        cSeparator = sTmp[0];
                }
                if (pArgs->GetItemState(FN_PARAM_5, false, &pItem) == SfxItemState::SET)
                {
                    // Wrap the field in the requested container instead of inserting it
                    // directly at the cursor position.
                    const OUString& rWrapper = static_cast<const SfxStringItem *>(pItem)->GetValue();
                    if (rWrapper == "Footnote")
                    {
                        GetShellPtr()->InsertFootnote(OUString());
                    }
                    else if (rWrapper == "Endnote")
                    {
                        GetShellPtr()->InsertFootnote(OUString(), /*bEndNote=*/true);
                    }
                }
                bool bNeverExpand = false;
                const SfxBoolItem* pNeverExpand = rReq.GetArg<SfxBoolItem>(FN_PARAM_6);
                if (pNeverExpand)
                {
                    bNeverExpand = pNeverExpand->GetValue();
                }
                SwInsertField_Data aData(nType, nSubType, aPar1, aPar2, nFormat, GetShellPtr(),
                                         cSeparator, true, bNeverExpand);
                bRes = aFieldMgr.InsertField( aData );
            }
            else
            {
                //#i5788# prevent closing of the field dialog while a modal dialog ( Input field dialog ) is active
                if(!GetView().GetViewFrame().IsInModalMode())
                {
                    SfxViewFrame& rVFrame = GetView().GetViewFrame();
                    rVFrame.ToggleChildWindow(FN_INSERT_FIELD);
                    bRes = rVFrame.GetChildWindow( nSlot ) != nullptr;
                    Invalidate(rReq.GetSlot());
                    Invalidate(FN_INSERT_FIELD_CTRL);
                    rReq.Ignore();
                }
            }
            rReq.SetReturnValue(SfxBoolItem( nSlot, bRes ));
        }
        break;

        case FN_INSERT_REF_FIELD:
        {
            SfxViewFrame& rVFrame = GetView().GetViewFrame();
            if (!rVFrame.HasChildWindow(FN_INSERT_FIELD))
                rVFrame.ToggleChildWindow(FN_INSERT_FIELD);    // Show dialog

            // Switch Fielddlg at a new TabPage
            sal_uInt16 nId = SwFieldDlgWrapper::GetChildWindowId();
            SwFieldDlgWrapper *pWrp = static_cast<SwFieldDlgWrapper*>(rVFrame.GetChildWindow(nId));
            if (pWrp)
                pWrp->ShowReferencePage();
            rReq.Ignore();
        }
        break;
        case FN_DELETE_COMMENT:
        {
            const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
            if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
            {
                sal_uInt32 nPostItId = pIdItem->GetValue().toUInt32();
                if (lcl_canUserModifyAnnotation(GetView(), nPostItId))
                    GetView().GetPostItMgr()->Delete(nPostItId);
            }
            else if ( GetView().GetPostItMgr() &&
                      GetView().GetPostItMgr()->HasActiveSidebarWin() )
            {
                sw::annotation::SwAnnotationWin* pAnnotationWin
                    = GetView().GetPostItMgr()->GetActiveSidebarWin();
                if (lcl_canUserModifyAnnotation(GetView(), pAnnotationWin))
                    GetView().GetPostItMgr()->DeleteActiveSidebarWin();
            }
            break;
        }
        case FN_DELETE_COMMENT_THREAD:
        {
            const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
            if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
            {
                sal_uInt32 nPostItId = pIdItem->GetValue().toUInt32();
                if (lcl_canUserModifyAnnotation(GetView(), nPostItId))
                    GetView().GetPostItMgr()->DeleteCommentThread(nPostItId);
            }
            else if (GetView().GetPostItMgr() && GetView().GetPostItMgr()->HasActiveSidebarWin())
            {
                sw::annotation::SwAnnotationWin* pAnnotationWin
                    = GetView().GetPostItMgr()->GetActiveSidebarWin();
                if (lcl_canUserModifyAnnotation(GetView(), pAnnotationWin))
                    GetView().GetPostItMgr()->DeleteActiveSidebarWin();
            }
            break;
        }
        case FN_RESOLVE_NOTE:
        {
            const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
            if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
            {
                GetView().GetPostItMgr()->ToggleResolved(pIdItem->GetValue().toUInt32());
            }
            break;
        }
        case FN_RESOLVE_NOTE_THREAD:
        {
            const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
            if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
            {
                GetView().GetPostItMgr()->ToggleResolvedForThread(pIdItem->GetValue().toUInt32());
            }
            break;
        }
        case FN_DELETE_ALL_NOTES:
            if ( GetView().GetPostItMgr() )
                GetView().GetPostItMgr()->Delete();
        break;
        case FN_FORMAT_ALL_NOTES:
        {
            SwPostItMgr* pPostItMgr = GetView().GetPostItMgr();
            if (pPostItMgr)
                pPostItMgr->ExecuteFormatAllDialog(GetView());
        }
        break;
        case FN_DELETE_NOTE_AUTHOR:
        {
            const SfxStringItem* pNoteItem = rReq.GetArg<SfxStringItem>(nSlot);
            if (pNoteItem && GetView().GetPostItMgr()
                && lcl_canUserModifyAnnotation(GetView(), pNoteItem->GetValue()))
                GetView().GetPostItMgr()->Delete(pNoteItem->GetValue());
        }
        break;
        case FN_HIDE_NOTE:
            if ( GetView().GetPostItMgr() &&
                 GetView().GetPostItMgr()->HasActiveSidebarWin() )
            {
                GetView().GetPostItMgr()->HideActiveSidebarWin();
            }
        break;
        case FN_HIDE_ALL_NOTES:
            if ( GetView().GetPostItMgr() )
                GetView().GetPostItMgr()->Hide();
        break;
        case FN_HIDE_NOTE_AUTHOR:
        {
            const SfxStringItem* pNoteItem = rReq.GetArg<SfxStringItem>(nSlot);
            if ( pNoteItem && GetView().GetPostItMgr() )
                GetView().GetPostItMgr()->Hide( pNoteItem->GetValue() );
        }
        break;
        case FN_REPLY:
        {
            const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
            if (pIdItem && !pIdItem->GetValue().isEmpty())
            {
                SwFieldType* pType = rSh.GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(), false);
                if(pType->FindFormatForPostItId(pIdItem->GetValue().toUInt32()))
                {
                    auto pMgr = GetView().GetPostItMgr();
                    auto pWin = pMgr->GetAnnotationWin(pIdItem->GetValue().toUInt32());
                    if(pWin)
                    {
                        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());
                            if (std::optional<OutlinerParaObject> oPara = aOutliner.CreateParaObject())
                                pMgr->RegisterAnswer(oPara.value());
                        }

                        OUString sText;
                        if(const auto pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT))
                            sText = pTextItem->GetValue();
                        pMgr->RegisterAnswerText(sText);
                        pWin->ExecuteCommand(nSlot);
                    }
                }
            }
        }
        break;
        case FN_POSTIT:
        {
            rSh.InsertPostIt(aFieldMgr, rReq);
        }
        break;
        case SID_EDIT_POSTIT:
        {
            const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
            if (pIdItem && !pIdItem->GetValue().isEmpty())
            {
                sw::annotation::SwAnnotationWin* pAnnotationWin = GetView().GetPostItMgr()->GetAnnotationWin(pIdItem->GetValue().toUInt32());
                if (pAnnotationWin && lcl_canUserModifyAnnotation(GetView(), pAnnotationWin))
                {
                    if (const SvxPostItTextItem* pHtmlItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_HTML))
                        pAnnotationWin->UpdateHTML(pHtmlItem->GetValue());
                    else
                    {
                        const SvxPostItTextItem* pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT);
                        OUString sText;
                        if (pTextItem)
                            sText = pTextItem->GetValue();
                        pAnnotationWin->UpdateText(sText);
                    }

                    // explicit state update to get the Undo state right
                    GetView().AttrChangedNotify(nullptr);
                }
            }
        }
        break;
        case FN_PROMOTE_COMMENT:
        {
            const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
            if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
            {
                GetView().GetPostItMgr()->PromoteToRoot(pIdItem->GetValue().toUInt32());
            }
            break;
        }
        case FN_REDLINE_COMMENT:
        {
            const SwRangeRedline *pRedline = rSh.GetCurrRedline();
            SwDoc *pDoc = rSh.GetDoc();
            // If index is specified, goto and select the appropriate redline
            if (pArgs && pArgs->GetItemState(nSlot, false, &pItem) == SfxItemState::SET)
            {
                const sal_uInt32 nChangeId = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
                const SwRedlineTable& rRedlineTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
                for (SwRedlineTable::size_type nRedline = 0; nRedline < rRedlineTable.size(); ++nRedline)
                {
                    if (nChangeId == rRedlineTable[nRedline]->GetId())
                        pRedline = rSh.GotoRedline(nRedline, true);
                }
            }

            OUString sCommentText;
            const SfxStringItem* pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT);
            if (pTextItem)
                sCommentText = pTextItem->GetValue();

            if (pRedline)
            {
                // In case of LOK and comment text is already provided, skip
                // dialog creation and just change the redline comment directly
                if (comphelper::LibreOfficeKit::isActive() && !sCommentText.isEmpty())
                {
                    rSh.SetRedlineComment(sCommentText);
                    GetView().AttrChangedNotify(nullptr);
                    MaybeNotifyRedlineModification(const_cast<SwRangeRedline&>(*pRedline), pRedline->GetDoc());
                    break;
                }

                OUString sComment = convertLineEnd(pRedline->GetComment(), GetSystemLineEnd());

                bool bTravel = false;

                SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
                ::DialogGetRanges fnGetRange = pFact->GetDialogGetRangesFunc();
                SfxItemSet aSet(GetPool(), fnGetRange());
                aSet.Put(SvxPostItTextItem(sComment, SID_ATTR_POSTIT_TEXT));
                aSet.Put(SvxPostItAuthorItem(pRedline->GetAuthorString(), SID_ATTR_POSTIT_AUTHOR));

                aSet.Put( SvxPostItDateItem( GetAppLangDateTimeString(
                            pRedline->GetRedlineData().GetTimeStamp() ),
                            SID_ATTR_POSTIT_DATE ));

                // Traveling only if more than one field.
                rSh.StartAction();

                rSh.Push();
                const SwRangeRedline *pActRed = rSh.SelPrevRedline();

                if (pActRed == pRedline)
                {   // New cursor is at the beginning of the current redlines.
                    rSh.Pop();  // Throw old cursor away
                    rSh.Push();
                    pActRed = rSh.SelPrevRedline();
                }

                bool bPrev = pActRed != nullptr;
                rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
                rSh.EndAction();

                rSh.ClearMark();
                // Select current redline.
                pActRed = rSh.SelNextRedline();
                if (pActRed != pRedline)
                    rSh.SelPrevRedline();

                rSh.StartAction();
                rSh.Push();
                pActRed = rSh.SelNextRedline();
                bool bNext = pActRed != nullptr;
                rSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore cursor position

                if( rSh.IsCursorPtAtEnd() )
                    rSh.SwapPam();

                rSh.EndAction();

                bTravel |= bNext || bPrev;

                SvxAbstractDialogFactory* pFact2 = SvxAbstractDialogFactory::Create();
                ScopedVclPtr<AbstractSvxPostItDialog> pDlg(pFact2->CreateSvxPostItDialog(GetView().GetFrameWeld(), aSet, bTravel));
                pDlg->HideAuthor();

                pDlg->SetText(lcl_BuildTitleWithRedline(pRedline));

                if (bTravel)
                {
                    pDlg->EnableTravel(bNext, bPrev);
                    pDlg->SetPrevHdl(LINK(this, SwTextShell, RedlinePrevHdl));
                    pDlg->SetNextHdl(LINK(this, SwTextShell, RedlineNextHdl));
                }

                SwViewShell::SetCareDialog(pDlg->GetDialog());
                g_bNoInterrupt = true;

                if ( pDlg->Execute() == RET_OK )
                {
                    const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
                    OUString sMsg(pOutSet->Get(SID_ATTR_POSTIT_TEXT).GetValue());

                    // Insert or change a comment
                    rSh.SetRedlineComment(sMsg);
                }

                SwViewShell::SetCareDialog(nullptr);
                pDlg.disposeAndClear();
                g_bNoInterrupt = false;
                rSh.ClearMark();
                GetView().AttrChangedNotify(nullptr);
            }
        }
        break;

        case FN_JAVAEDIT:
        {
            OUString aType, aText;
            bool bIsUrl=false;
            bool bNew=false;
            bool bUpdate = false;
            SwFieldMgr aMgr;
            if ( pItem )
            {
                aText = static_cast<const SfxStringItem*>(pItem)->GetValue();
                const SfxStringItem* pType = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
                const SfxBoolItem* pIsUrl = rReq.GetArg<SfxBoolItem>(FN_PARAM_1);
                if ( pType )
                    aType = pType->GetValue();
                if ( pIsUrl )
                    bIsUrl = pIsUrl->GetValue();

                SwScriptField* pField = static_cast<SwScriptField*>(aMgr.GetCurField());
                bNew = !pField || (pField->GetTyp()->Which() != SwFieldIds::Script);
                bUpdate = pField && ( bIsUrl != static_cast<bool>(pField->GetFormat()) || pField->GetPar2() != aType || pField->GetPar1() != aText );
            }
            else
            {
                SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
                ScopedVclPtr<AbstractJavaEditDialog> pDlg(pFact->CreateJavaEditDialog(GetView().GetFrameWeld(), &rSh));
                if ( pDlg->Execute() )
                {
                    aType = pDlg->GetScriptType();
                    aText = pDlg->GetScriptText();
                    bIsUrl = pDlg->IsUrl();
                    bNew = pDlg->IsNew();
                    bUpdate = pDlg->IsUpdate();
                    rReq.AppendItem( SfxStringItem( FN_JAVAEDIT, aText ) );
                    rReq.AppendItem( SfxStringItem( FN_PARAM_2, aType ) );
                    rReq.AppendItem( SfxBoolItem( FN_PARAM_1, bIsUrl ) );
                }
            }

            if( bNew )
            {
                SwInsertField_Data aData(SwFieldTypesEnum::Script, 0, aType, aText, bIsUrl ? 1 : 0);
                aMgr.InsertField(aData);
                rReq.Done();
            }
            else if( bUpdate )
            {
                aMgr.UpdateCurField( bIsUrl ? 1 : 0, aType, aText );
                rSh.SetUndoNoResetModified();
                rReq.Done();
            }
            else
                rReq.Ignore();
        }
        break;

        case FN_INSERT_FLD_DATE    :
        case FN_INSERT_FLD_DATE_VAR:
        {
            nInsertType = SwFieldTypesEnum::Date;
            nInsertSubType = nSlot == FN_INSERT_FLD_DATE ? 0 : 1;
            bIsText = false;
            // use long date format for Hungarian
            SwPaM* pCursorPos = rSh.GetCursor();
            if( pCursorPos )
            {
                LanguageType nLang = pCursorPos->GetPoint()->GetNode().GetTextNode()->GetLang(pCursorPos->GetPoint()->GetContentIndex());
                if (nLang == LANGUAGE_HUNGARIAN)
                    nInsertFormat = rSh.GetNumberFormatter()->GetFormatIndex(NF_DATE_SYSTEM_LONG, nLang);
            }
            goto FIELD_INSERT;
        }
        case FN_INSERT_FLD_TIME    :
        case FN_INSERT_FLD_TIME_VAR:
            nInsertType = SwFieldTypesEnum::Time;
            nInsertSubType = nSlot == FN_INSERT_FLD_TIME ? 0 : 1;
            bIsText = false;
            goto FIELD_INSERT;
        case FN_INSERT_FLD_PGNUMBER:
            nInsertType = SwFieldTypesEnum::PageNumber;
            nInsertFormat = SVX_NUM_PAGEDESC; // Like page template
            bIsText = false;
            goto FIELD_INSERT;
        case FN_INSERT_FLD_PGCOUNT :
        case FN_INSERT_FLD_RANGE_PGCOUNT:
            nInsertType = SwFieldTypesEnum::DocumentStatistics;
            nInsertSubType = FN_INSERT_FLD_RANGE_PGCOUNT == nSlot ? 1 : 0;
            bIsText = false;
            nInsertFormat = SVX_NUM_PAGEDESC;
            goto FIELD_INSERT;
        case FN_INSERT_FLD_TOPIC   :
            nInsertType = SwFieldTypesEnum::DocumentInfo;
            nInsertSubType = DI_SUBJECT;
            goto FIELD_INSERT;
        case FN_INSERT_FLD_TITLE   :
            nInsertType = SwFieldTypesEnum::DocumentInfo;
            nInsertSubType = DI_TITLE;
            goto FIELD_INSERT;
        case FN_INSERT_FLD_AUTHOR  :
            nInsertType = SwFieldTypesEnum::DocumentInfo;
            nInsertSubType = DI_CREATE|DI_SUB_AUTHOR;

FIELD_INSERT:
        {
            //format conversion should only be done for number formatter formats
            if(!nInsertFormat)
                nInsertFormat = aFieldMgr.GetDefaultFormat(nInsertType, bIsText, rSh.GetNumberFormatter());
            SwInsertField_Data aData(nInsertType, nInsertSubType,
                                OUString(), OUString(), nInsertFormat);
            aFieldMgr.InsertField(aData);
            rReq.Done();
        }
        break;

        case FN_INSERT_TEXT_FORMFIELD:
        {
            OUString aFieldType(ODF_FORMTEXT);
            const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
            if (pFieldType)
            {
                // Allow overwriting the default type.
                aFieldType = pFieldType->GetValue();
            }

            OUString aFieldCode;
            const SfxStringItem* pFieldCode = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
            if (pFieldCode)
            {
                // Allow specifying a field code/command.
                aFieldCode = pFieldCode->GetValue();
            }

            if (rSh.HasReadonlySel())
            {
                // Inform the user that the request has been ignored.
                auto xInfo = std::make_shared<weld::GenericDialogController>(
                    GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui",
                    "InfoReadonlyDialog");
                weld::DialogController::runAsync(xInfo, [](sal_Int32 /*nResult*/) {});
                break;
            }

            rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);

            SwPaM* pCursorPos = rSh.GetCursor();
            if(pCursorPos)
            {
                // Insert five En Space into the text field so the field has extent
                OUString aFieldResult(vEnSpaces);
                const SfxStringItem* pFieldResult = rReq.GetArg<SfxStringItem>(FN_PARAM_3);
                if (pFieldResult)
                {
                    // Allow specifying a field result / expanded value.
                    aFieldResult = pFieldResult->GetValue();
                }

                const SfxStringItem* pWrapper = rReq.GetArg<SfxStringItem>(FN_PARAM_4);
                if (pWrapper)
                {
                    // Wrap the fieldmark in the requested container instead of inserting it
                    // directly at the cursor position.
                    OUString aWrapper = pWrapper->GetValue();
                    if (aWrapper == "Footnote")
                    {
                        rSh.InsertFootnote(OUString());
                    }
                    else if (aWrapper == "Endnote")
                    {
                        // It's important that there is no Start/EndAction() around this, so the
                        // inner EndAction() triggers a layout update and the cursor can jump to the
                        // created SwFootnoteFrame.
                        rSh.InsertFootnote(OUString(), /*bEndNote=*/true);
                    }
                }

                // Don't update the layout after inserting content and before deleting temporary
                // text nodes.
                rSh.StartAction();

                // Split node to remember where the start position is.
                bool bSuccess = rSh.GetDoc()->getIDocumentContentOperations().SplitNode(
                    *pCursorPos->GetPoint(), false);
                if(bSuccess)
                {
                    SwPaM aFieldPam(*pCursorPos->GetPoint());
                    aFieldPam.Move(fnMoveBackward, GoInContent);
                    if (pFieldResult)
                    {
                        // Paste HTML content.
                        SwTranslateHelper::PasteHTMLToPaM(rSh, pCursorPos, aFieldResult.toUtf8());
                        if (pCursorPos->GetPoint()->GetContentIndex() == 0)
                        {
                            // The paste created a last empty text node, remove it.
                            SwPaM aPam(*pCursorPos->GetPoint());
                            aPam.SetMark();
                            aPam.Move(fnMoveBackward, GoInContent);
                            rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPam);
                        }
                    }
                    else
                    {
                        // Insert default placeholder.
                        rSh.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos,
                                                                                   aFieldResult);
                    }
                    // Undo the above SplitNode().
                    aFieldPam.SetMark();
                    aFieldPam.Move(fnMoveForward, GoInContent);
                    rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aFieldPam);
                    *aFieldPam.GetMark() = *pCursorPos->GetPoint();

                    IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
                    sw::mark::Fieldmark* pFieldmark = pMarksAccess->makeFieldBookmark(
                        aFieldPam, SwMarkName(), aFieldType, aFieldPam.Start());
                    if (pFieldmark && !aFieldCode.isEmpty())
                    {
                        pFieldmark->GetParameters()->insert(
                            std::pair<OUString, uno::Any>(ODF_CODE_PARAM, uno::Any(aFieldCode)));
                    }
                }
                rSh.EndAction();
            }

            rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
            rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO );
        }
        break;
        case FN_INSERT_CHECKBOX_FORMFIELD:
        {
            rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);

            SwPaM* pCursorPos = rSh.GetCursor();
            if(pCursorPos)
            {
                IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
                pMarksAccess->makeNoTextFieldBookmark(*pCursorPos, SwMarkName(), ODF_FORMCHECKBOX);
            }

            rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
            rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO );
        }
        break;
        case FN_INSERT_DROPDOWN_FORMFIELD:
        {
            rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);

            SwPaM* pCursorPos = rSh.GetCursor();
            if(pCursorPos)
            {
                IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
                pMarksAccess->makeNoTextFieldBookmark(*pCursorPos, SwMarkName(), ODF_FORMDROPDOWN);
            }

            rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
            rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO );
        }
        break;
    case FN_INSERT_DATE_FORMFIELD:
    {
        rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);

        SwPaM* pCursorPos = rSh.GetCursor();
        if(pCursorPos)
        {
            // Insert five enspaces into the text field so the field has extent
            bool bSuccess = rSh.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos, vEnSpaces);
            if(bSuccess)
            {
                IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
                SwPaM aFieldPam(pCursorPos->GetPoint()->GetNode(), pCursorPos->GetPoint()->GetContentIndex() - ODF_FORMFIELD_DEFAULT_LENGTH,
                                pCursorPos->GetPoint()->GetNode(), pCursorPos->GetPoint()->GetContentIndex());
                sw::mark::Fieldmark* pFieldBM = pMarksAccess->makeFieldBookmark(aFieldPam, SwMarkName(), ODF_FORMDATE,
                            aFieldPam.Start());

                // Use a default date format and language
                sw::mark::Fieldmark::parameter_map_t* pParameters = pFieldBM->GetParameters();
                SvNumberFormatter* pFormatter = rSh.GetDoc()->GetNumberFormatter();
                sal_uInt32 nStandardFormat = pFormatter->GetStandardFormat(SvNumFormatType::DATE);
                const SvNumberformat* pFormat = pFormatter->GetEntry(nStandardFormat);

                (*pParameters)[ODF_FORMDATE_DATEFORMAT] <<= pFormat->GetFormatstring();
                (*pParameters)[ODF_FORMDATE_DATEFORMAT_LANGUAGE] <<= LanguageTag(pFormat->GetLanguage()).getBcp47();
            }
        }

        rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
        rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO );
    }
    break;
    case FN_UPDATE_TEXT_FORMFIELDS:
    {
        // This updates multiple fieldmarks in a document, based on their field name & field command
        // prefix.
        OUString aFieldType;
        const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
        if (pFieldType)
        {
            aFieldType = pFieldType->GetValue();
        }
        OUString aFieldCommandPrefix;
        const SfxStringItem* pFieldCommandPrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
        if (pFieldCommandPrefix)
        {
            aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
        }
        uno::Sequence<beans::PropertyValues> aFields;
        const SfxUnoAnyItem* pFields = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
        if (pFields)
        {
            pFields->GetValue() >>= aFields;
        }

        rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::UPDATE_FORM_FIELDS, nullptr);
        rSh.StartAction();

        IDocumentMarkAccess* pMarkAccess = rSh.GetDoc()->getIDocumentMarkAccess();
        sal_Int32 nFieldIndex = 0;
        for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
        {
            sw::mark::Fieldmark* pFieldmark = *it;
            assert(pFieldmark);
            if (pFieldmark->GetFieldname() != aFieldType)
            {
                continue;
            }

            auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
            if (itParam == pFieldmark->GetParameters()->end())
            {
                continue;
            }

            OUString aCommand;
            itParam->second >>= aCommand;
            if (!aCommand.startsWith(aFieldCommandPrefix))
            {
                continue;
            }

            if (aFields.getLength() <= nFieldIndex)
            {
                continue;
            }

            comphelper::SequenceAsHashMap aMap(aFields[nFieldIndex++]);
            itParam->second = aMap[u"FieldCommand"_ustr];
            SwPaM aPaM(pFieldmark->GetMarkPos(), pFieldmark->GetOtherMarkPos());
            aPaM.Normalize();
            // Skip field start & separator.
            aPaM.GetPoint()->AdjustContent(2);
            // Skip field end.
            aPaM.GetMark()->AdjustContent(-1);
            rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPaM);
            OUString aFieldResult;
            aMap[u"FieldResult"_ustr] >>= aFieldResult;
            SwTranslateHelper::PasteHTMLToPaM(rSh, &aPaM, aFieldResult.toUtf8());
        }

        rSh.EndAction();
        rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::UPDATE_FORM_FIELDS, nullptr);
    }
    break;
    case FN_DELETE_TEXT_FORMFIELDS:
    {
        // This deletes all fieldmarks that match the provided field type & field command prefix.
        OUString aFieldType;
        const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
        if (pFieldType)
        {
            aFieldType = pFieldType->GetValue();
        }
        OUString aFieldCommandPrefix;
        const SfxStringItem* pFieldCommandPrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
        if (pFieldCommandPrefix)
        {
            aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
        }
        rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELETE_FORM_FIELDS, nullptr);
        rSh.StartAction();

        IDocumentMarkAccess* pMarkAccess = rSh.GetDoc()->getIDocumentMarkAccess();
        std::vector<sw::mark::MarkBase*> aRemovals;
        for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
        {
            sw::mark::Fieldmark* pFieldmark = *it;
            assert(pFieldmark);
            if (pFieldmark->GetFieldname() != aFieldType)
            {
                continue;
            }

            if (!aFieldCommandPrefix.isEmpty())
            {
                auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
                if (itParam == pFieldmark->GetParameters()->end())
                {
                    continue;
                }

                OUString aCommand;
                itParam->second >>= aCommand;
                if (!aCommand.startsWith(aFieldCommandPrefix))
                {
                    continue;
                }
            }

            aRemovals.push_back(pFieldmark);
        }

        for (const auto& pMark : aRemovals)
        {
            pMarkAccess->deleteMark(pMark);
        }

        rSh.EndAction();
        rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELETE_FORM_FIELDS, nullptr);
    }
    break;
    case FN_PGNUMBER_WIZARD:
    {
        SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
        VclPtr<AbstractSwPageNumberDlg> pDlg(
                pFact->CreateSwPageNumberDlg(GetView().GetFrameWeld()));
        auto pShell = GetShellPtr();

        const SwPageDesc& rCurrDesc = rSh.GetPageDesc(rSh.GetCurPageDesc());
        pDlg->SetPageNumberType(rCurrDesc.GetNumType().GetNumberingType());

        pDlg->StartExecuteAsync([pShell, &rSh, pDlg](int nResult) {
            if ( nResult == RET_OK )
            {
                auto& rDoc = *rSh.GetDoc();

                rSh.LockView(true);
                rSh.StartAllAction();
                rSh.SwCursorShell::Push();
                rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_PAGE_NUMBER, nullptr);

                const size_t nPageDescIndex = rSh.GetCurPageDesc();
                const SwPageDesc& rDesc = rSh.GetPageDesc(nPageDescIndex);
                const bool bHeader = !pDlg->GetPageNumberPosition();
                const bool bHeaderAlreadyOn = rDesc.GetMaster().GetHeader().IsActive();
                const bool bFooterAlreadyOn = rDesc.GetMaster().GetFooter().IsActive();
                const bool bIsSinglePage = rDesc.GetFollow() != &rDesc;
                const size_t nMirrorPagesNeeded = rDesc.IsFirstShared() ? 2 : 3;
                const OUString sBookmarkName(OUString::Concat("PageNumWizard_")
                    + (bHeader ? "HEADER" : "FOOTER") + "_" + rDesc.GetName().toString());
                IDocumentMarkAccess& rIDMA = *rSh.getIDocumentMarkAccess();

                // Allow wizard to be re-run: delete previously wizard-inserted page number.
                // Try before creating non-shared header: avoid copying ODD bookmark onto EVEN page.
                SwMarkName sBookmarkOddPage(sBookmarkName + OUString::number(rSh.GetVirtPageNum()));
                auto ppMark = rIDMA.findMark(sBookmarkOddPage);
                if (ppMark != rIDMA.getAllMarksEnd() && *ppMark)
                {
                    SwPaM aDeleteOldPageNum((*ppMark)->GetMarkStart(), (*ppMark)->GetMarkEnd());
                    rDoc.getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum);
                }

                SwPageDesc aNewDesc(rDesc);
                bool bChangePageDesc = false;
                if (pDlg->GetPageNumberType() != aNewDesc.GetNumType().GetNumberingType())
                {
                    bChangePageDesc = true;
                    SvxNumberType aNewType(rDesc.GetNumType());
                    aNewType.SetNumberingType(pDlg->GetPageNumberType());
                    aNewDesc.SetNumType(aNewType);
                }

                // Insert header/footer
                if ((bHeader && !bHeaderAlreadyOn) || (!bHeader && !bFooterAlreadyOn))
                {
                    bChangePageDesc = true;
                    SwFrameFormat &rMaster = aNewDesc.GetMaster();
                    if (bHeader)
                        rMaster.SetFormatAttr(SwFormatHeader(/*On=*/true));
                    else
                        rMaster.SetFormatAttr(SwFormatFooter(/*On=*/true));

                    // Init copied from ChangeHeaderOrFooter: keep in sync
                    constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm);
                    const SvxULSpaceItem aUL(bHeader ? 0 : constTwips_5mm,
                                             bHeader ? constTwips_5mm : 0,
                                             RES_UL_SPACE);
                    const XFillStyleItem aFill(drawing::FillStyle_NONE);
                    SwFrameFormat& rFormat
                        = bHeader
                              ? const_cast<SwFrameFormat&>(*rMaster.GetHeader().GetHeaderFormat())
                              : const_cast<SwFrameFormat&>(*rMaster.GetFooter().GetFooterFormat());
                    rFormat.SetFormatAttr(aUL);
                    rFormat.SetFormatAttr(aFill);

                    if (pDlg->GetFitIntoExistingMargins())
                    {
                        SvxULSpaceItem aPageUL(aNewDesc.GetMaster().GetULSpace());
                        tools::Long nPageMargin = bHeader ? aPageUL.GetUpper() : aPageUL.GetLower();

                        // most printers can't print to paper edge - use arbitrary ~14pt as minimum
                        if (nPageMargin > constTwips_5mm)
                        {
                            // reduce existing margin by the "Spacing"
                            nPageMargin -= constTwips_5mm;

                            // also reduce by the "Height" (as calculated from the font)
                            tools::Long nFontHeight = constTwips_5mm; // appropriate for 12pt font
                            const OutputDevice* pOutDev = Application::GetDefaultDevice();
                            const SwViewShell* pViewSh
                                = rDoc.getIDocumentLayoutAccess().GetCurrentViewShell();
                            UIName sParaStyle(bHeader ? "Header" : "Footer");
                            SwTextFormatColl* pStyle = rDoc.FindTextFormatCollByName(sParaStyle);
                            if (pStyle && pOutDev)
                            {
                                SwFont aFont(
                                    &pStyle->GetAttrSet(), /*IDocumentSettingAccess=*/nullptr);

                                // sledgehammer approach: since the in-use-font (Latin/CTL/CKJ)
                                // is not known, use the tallest of the three just to ensure fit.
                                sal_uInt16 nHeight = aFont.GetHeight(pViewSh, *pOutDev); // Latin

                                aFont.SetActual(SwFontScript::CTL);
                                nHeight = std::max(nHeight, aFont.GetHeight(pViewSh, *pOutDev));

                                aFont.SetActual(SwFontScript::CJK);
                                nFontHeight = std::max(nHeight, aFont.GetHeight(pViewSh, *pOutDev));

                                // Spacing: above and below paragraph
                                const SvxULSpaceItem& rParaStyleUL = pStyle->GetULSpace();
                                nFontHeight += rParaStyleUL.GetUpper() + rParaStyleUL.GetLower();

                                // Border padding: top and bottom
                                const SvxBoxItem rBorders = pStyle->GetBox();
                                nFontHeight += rBorders.CalcLineSpace(SvxBoxItemLine::TOP, true);
                                nFontHeight += rBorders.CalcLineSpace(SvxBoxItemLine::BOTTOM, true);
                            }
                            nPageMargin -= nFontHeight;

                            nPageMargin = std::max(nPageMargin, constTwips_5mm);
                            if (bHeader)
                                aPageUL.SetUpper(nPageMargin);
                            else
                                aPageUL.SetLower(nPageMargin);
                            aNewDesc.GetMaster().SetFormatAttr(aPageUL);

                            // force aggressively calculated font height as minimum to ensure
                            // effective margin stays the same (instead of getting smaller)
                            SwFormatFrameSize aSize(rFormat.GetFrameSize());
                            aSize.SetHeightSizeType(SwFrameSize::Minimum);
                            // frame size property includes both Spacing + Height
                            aSize.SetHeight(constTwips_5mm + nFontHeight);
                            rFormat.SetFormatAttr(aSize);

                            // in case the calculated font height isn't actually large enough,
                            // eat into spacing first before pushing into the content area.
                            rFormat.SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
                                RES_HEADER_FOOTER_EAT_SPACING, true));
                        }
                    }

                    // Might as well turn on margin mirroring too - if appropriate
                    if (pDlg->GetMirrorOnEvenPages() && !bHeaderAlreadyOn && !bFooterAlreadyOn
                        && !bIsSinglePage
                        && (aNewDesc.ReadUseOn() & UseOnPage::Mirror) == UseOnPage::All)
                    {
                        aNewDesc.WriteUseOn(rDesc.ReadUseOn() | UseOnPage::Mirror);
                    }
                }

                const bool bCreateMirror = !bIsSinglePage && pDlg->GetMirrorOnEvenPages()
                    && nMirrorPagesNeeded <= rSh.GetPageCnt();
                if (bCreateMirror)
                {
                    // Use different left/right header/footer
                    if ((bHeader && rDesc.IsHeaderShared()) || (!bHeader && rDesc.IsFooterShared()))
                    {
                        bChangePageDesc = true;
                        if (bHeader)
                            aNewDesc.ChgHeaderShare(/*Share=*/false);
                        else
                            aNewDesc.ChgFooterShare(/*Share=*/false);
                    }
                }

                if (bChangePageDesc)
                    rSh.ChgPageDesc(nPageDescIndex, aNewDesc);

                // Go to the header or footer insert position
                bool bInHF = false;
                bool bSkipMirror = true;
                size_t nEvenPage = 0;
                if (bCreateMirror || !rSh.GetCurrFrame())
                {
                    // Come here if Currframe can't be found, otherwise Goto*Text will crash.
                    // Get*PageNum will also be invalid (0), so we have no idea where we are.
                    // (Since not asking for mirror, the likelihood is that the bHeader is shared,
                    // in which case it doesn't matter anyway, and we just hope for the best.)
                    // Read the code in this block assuming that bCreateMirror is true.

                    // There are enough pages that there probably is a valid odd page.
                    // However, that is not guaranteed: perhaps the page style switched,
                    // or a blank page was forced, or some other complexity.
                    bInHF = rSh.SetCursorInHdFt(nPageDescIndex, bHeader, /*Even=*/true);
                    if (bInHF)
                    {
                        // Remember valid EVEN page. Mirror it if also a valid ODD or FIRST page
                        nEvenPage = rSh.GetVirtPageNum();
                        assert (nEvenPage && "couldn't find page number. Use a bool instead");
                    }

                    bInHF = rSh.SetCursorInHdFt(nPageDescIndex, bHeader, /*Even=*/false);
                    if (bInHF && nEvenPage)
                    {
                        // Even though the cursor may be on a FIRST page,
                        // the user requested mirrored pages, and we have both ODD and EVEN,
                        // so set page numbers on these two pages, and leave FIRST alone.
                        bSkipMirror = false;
                    }
                    if (!bInHF)
                    {
                        // no ODD page, look for FIRST page
                        bInHF = rSh.SetCursorInHdFt(nPageDescIndex, bHeader, false/*First=*/true);
                        if (bInHF && nEvenPage)
                        {
                            // Unlikely but valid situation: EVEN and FIRST pages, but no ODD page.
                            // In this case, the first header gets the specified page number
                            // and the even header is mirrored, with an empty odd header,
                            // as the user (somewhat) requested.
                            bSkipMirror = false;
                        }
                    }
                    assert((bInHF || nEvenPage) && "Impossible - why couldn't the move happen?");
                    assert((bInHF || nEvenPage == rSh.GetVirtPageNum()) && "Unexpected move");
                }
                else
                {
                    if (bHeader)
                        bInHF = rSh.GotoHeaderText();
                    else
                        bInHF = rSh.GotoFooterText();
                    assert(bInHF && "shouldn't have a problem going to text when no mirroring");
                }

                // Allow wizard to be re-run: delete previously wizard-inserted page number.
                // Now that the cursor may have moved to a different page, try delete again.
                sBookmarkOddPage
                    = SwMarkName(sBookmarkName + OUString::number(rSh.GetVirtPageNum()));
                ppMark = rIDMA.findMark(sBookmarkOddPage);
                if (ppMark != rIDMA.getAllMarksEnd() && *ppMark)
                {
                    SwPaM aDeleteOldPageNum((*ppMark)->GetMarkStart(), (*ppMark)->GetMarkEnd());
                    rDoc.getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum);
                }

                SwTextNode* pTextNode = rSh.GetCursor()->GetPoint()->GetNode().GetTextNode();

                // Insert new line if there is already text in header/footer
                if (pTextNode && !pTextNode->GetText().isEmpty())
                {
                    rDoc.getIDocumentContentOperations().SplitNode(*rSh.GetCursor()->GetPoint(), false);

                    // Go back to start of header/footer
                    if (bHeader)
                        rSh.GotoHeaderText();
                    else
                        rSh.GotoFooterText();
                }

                // Set alignment for the new line
                switch (pDlg->GetPageNumberAlignment())
                {
                    case 0:
                    {
                        SvxAdjustItem aAdjustItem(SvxAdjust::Left, RES_PARATR_ADJUST);
                        rSh.SetAttrItem(aAdjustItem);
                        break;
                    }
                    case 1:
                    {
                        SvxAdjustItem aAdjustItem(SvxAdjust::Center, RES_PARATR_ADJUST);
                        rSh.SetAttrItem(aAdjustItem);
                        break;
                    }
                    case 2:
                    {
                        SvxAdjustItem aAdjustItem(SvxAdjust::Right, RES_PARATR_ADJUST);
                        rSh.SetAttrItem(aAdjustItem);
                        break;
                    }
                }

                sal_Int32 nStartContentIndex = rSh.GetCursor()->Start()->GetContentIndex();
                assert(!nStartContentIndex && "earlier split node if not empty, but not zero?");

                // Insert page number
                SwFieldMgr aMgr(pShell);
                SwInsertField_Data aData(SwFieldTypesEnum::PageNumber, 0,
                            OUString(), OUString(), SVX_NUM_PAGEDESC);
                aMgr.InsertField(aData);
                if (pDlg->GetIncludePageTotal() ||
                    pDlg->GetIncludePageRangeTotal())
                {
                    rDoc.getIDocumentContentOperations().InsertString(*rSh.GetCursor(), u" / "_ustr);
                    SwInsertField_Data aPageTotalData(SwFieldTypesEnum::DocumentStatistics,
                        pDlg->GetIncludePageTotal() ? DS_PAGE : DS_PAGE_RANGE,
                        OUString(), OUString(), SVX_NUM_PAGEDESC);
                    aMgr.InsertField(aPageTotalData);
                }

                // Mark inserted fields with a bookmark - so it can be found/removed if re-run
                SwPaM aNewBookmarkPaM(*rSh.GetCursor()->Start());
                aNewBookmarkPaM.SetMark();
                assert(aNewBookmarkPaM.GetPointContentNode() && "only SetContent on content node");
                aNewBookmarkPaM.Start()->SetContent(nStartContentIndex);
                rIDMA.makeMark(aNewBookmarkPaM,
                               sBookmarkOddPage,
                               IDocumentMarkAccess::MarkType::BOOKMARK,
                               sw::mark::InsertMode::New);

                // Mirror on the even pages
                if (!bSkipMirror && bCreateMirror
                    && rSh.SetCursorInHdFt(nPageDescIndex, bHeader, /*Even=*/true))
                {
                    assert(nEvenPage && "what? no even page and yet we got here?");
                    SwMarkName sBookmarkEvenPage(
                        sBookmarkName + OUString::number(rSh.GetVirtPageNum()));
                    ppMark = rIDMA.findMark(sBookmarkEvenPage);
                    if (ppMark != rIDMA.getAllMarksEnd() && *ppMark)
                    {
                        SwPaM aDeleteOldPageNum((*ppMark)->GetMarkStart(), (*ppMark)->GetMarkEnd());
                        rDoc.getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum);
                    }

                    pTextNode = rSh.GetCursor()->GetPoint()->GetNode().GetTextNode();

                    // Insert new line if there is already text in header/footer
                    if (pTextNode && !pTextNode->GetText().isEmpty())
                    {
                        rDoc.getIDocumentContentOperations().SplitNode(
                            *rSh.GetCursor()->GetPoint(), false);
                        // Go back to start of header/footer
                        rSh.SetCursorInHdFt(nPageDescIndex, bHeader, /*Even=*/true);
                    }

                    // mirror the adjustment
                    assert(pDlg->GetPageNumberAlignment() != 1 && "cannot have Center and bMirror");
                    SvxAdjust eAdjust = SvxAdjust::Left;
                    if (!pDlg->GetPageNumberAlignment())
                        eAdjust = SvxAdjust::Right;
                    SvxAdjustItem aMirrorAdjustItem(eAdjust, RES_PARATR_ADJUST);
                    rSh.SetAttrItem(aMirrorAdjustItem);

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

--> maximum size reached

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

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

¤ Dauer der Verarbeitung: 0.26 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.