/* -*- 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 <svl/macitem.hxx>
#include <sfx2/frame.hxx>
#include <svl/eitem.hxx>
#include <svl/listener.hxx>
#include <svl/stritem.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/linkmgr.hxx>
#include <sfx2/viewfrm.hxx>
#include <sot/exchange.hxx>
#include <osl/diagnose.h>
#include <o3tl/string_view.hxx>
#include <fmtinfmt.hxx>
#include <wrtsh.hxx>
#include <docsh.hxx>
#include <fldbas.hxx>
#include <expfld.hxx>
#include <docufld.hxx>
#include <reffld.hxx>
#include <swundo.hxx>
#include <doc.hxx>
#include <frmfmt.hxx>
#include <fmtfld.hxx>
#include <view.hxx>
#include <swevent.hxx>
#include <section.hxx>
#include <navicont.hxx>
#include <txtinet.hxx>
#include <cmdid.h>
#include <swabstdlg.hxx>
#include <SwRewriter.hxx>
#include <authfld.hxx>
#include <ndtxt.hxx>
 
#include <com/sun/star/document/XDocumentProperties.hpp>
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
 
#include <memory>
 
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/lok.hxx>
#include <sfx2/event.hxx>
#include <sal/log.hxx>
 
#include <fldmgr.hxx>
#include <vcl/weldutils.hxx>
#include <strings.hrc>
#include <officecfg/Office/Common.hxx>
 
bool SwWrtShell::InsertField2(SwField const& rField, SwPaM* pAnnotationRange)
{
    ResetCursorStack();
    if(!CanInsert())
        return false;
    StartAllAction();
 
    SwRewriter aRewriter;
    aRewriter.AddRule(UndoArg1, rField.GetDescription());
 
    StartUndo(SwUndoId::INSERT, &aRewriter);
 
    bool bDeleted = false;
    std::optional<SwPaM> pAnnotationTextRange;
    if (pAnnotationRange)
    {
        pAnnotationTextRange.emplace(*pAnnotationRange->Start(), *pAnnotationRange->End());
    }
 
    if ( HasSelection() )
    {
        if ( rField.GetTyp()->Which() == SwFieldIds::Postit )
        {
            // for annotation fields:
            // - keep the current selection in order to create a corresponding annotation mark
            // - collapse cursor to its end
            if ( IsTableMode() )
            {
                GetTableCrs()->Normalize( false );
                const SwPosition rStartPos( *(GetTableCrs()->GetMark()->GetNode().GetContentNode()), 0 );
                KillPams();
                if ( !IsEndOfPara() )
                {
                    EndPara();
                }
                const SwPosition rEndPos( *GetCurrentShellCursor().GetPoint() );
                pAnnotationTextRange.emplace( rStartPos, rEndPos );
            }
            else
            {
                NormalizePam( false );
                const SwPaM& rCurrPaM = GetCurrentShellCursor();
                pAnnotationTextRange.emplace( *rCurrPaM.GetPoint(), *rCurrPaM.GetMark() );
                ClearMark();
            }
        }
        else
        {
            bDeleted = DelRight();
        }
    }
 
    bool const isSuccess = SwEditShell::InsertField(rField, bDeleted);
 
    if ( pAnnotationTextRange )
    {
        if ( GetDoc() != nullptr )
        {
            const SwPaM& rCurrPaM = GetCurrentShellCursor();
            if (*rCurrPaM.Start() == *pAnnotationTextRange->Start()
                && *rCurrPaM.End() == *pAnnotationTextRange->End())
            {
                // Annotation range was passed in externally, and inserting the postit field shifted
                // its start/end positions right by one. Restore the original position for the range
                // start. This allows commenting on the placeholder character of the field.
                if (pAnnotationTextRange->Start()->GetContentIndex() > 0)
                    pAnnotationTextRange->Start()->AdjustContent(-1);
            }
            IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess();
            pMarksAccess->makeAnnotationMark( *pAnnotationTextRange, OUString() );
        }
        pAnnotationTextRange.reset();
    }
 
    EndUndo();
    EndAllAction();
 
    return isSuccess;
}
 
// Start the field update
 
void SwWrtShell::UpdateInputFields( SwInputFieldList* pLst )
{
    // Go through the list of fields and updating
    std::unique_ptr<SwInputFieldList> pTmp;
    if (!pLst)
    {
        pTmp.reset(new SwInputFieldList( this ));
        pLst = pTmp.get();
    }
 
    const size_t nCnt = pLst->Count();
    if(!nCnt)
        return;
 
    pLst->PushCursor();
 
    bool bCancel = false;
 
    size_t nIndex = 0;
    FieldDialogPressedButton ePressedButton = FieldDialogPressedButton::NONE;
 
    SwField* pField = GetCurField();
    if (pField)
    {
        for (size_t i = 0; i < nCnt; i++)
        {
            if (pField == pLst->GetField(i))
            {
                nIndex = i;
                break;
            }
        }
    }
 
    while (!bCancel)
    {
        bool bPrev = nIndex > 0;
        bool bNext = nIndex < nCnt - 1;
        pLst->GotoFieldPos(nIndex);
        pField = pLst->GetField(nIndex);
        if (pField->GetTyp()->Which() == SwFieldIds::Dropdown)
        {
            bCancel = StartDropDownFieldDlg(pField, bPrev, bNext, GetView().GetFrameWeld(), &ePressedButton);
        }
        else
            bCancel = StartInputFieldDlg(pField, bPrev, bNext, GetView().GetFrameWeld(), &ePressedButton);
 
        if (!bCancel)
        {
            // Otherwise update error at multi-selection:
            pLst->GetField(nIndex)->GetTyp()->UpdateFields();
 
            if (ePressedButton == FieldDialogPressedButton::Previous && nIndex > 0)
                nIndex--;
            else if (ePressedButton == FieldDialogPressedButton::Next && nIndex < nCnt - 1)
                nIndex++;
            else
                bCancel = true;
        }
    }
 
    pLst->PopCursor();
}
 
namespace {
 
// Listener class: will close InputField dialog if input field(s)
// is(are) deleted (for instance, by an extension) after the dialog shows up.
// Otherwise, the for loop in SwWrtShell::UpdateInputFields will crash when doing:
//         'pTmp->GetField( i )->GetTyp()->UpdateFields();'
// on a deleted field.
class FieldDeletionListener : public SvtListener
{
    public:
        FieldDeletionListener(AbstractFieldInputDlg* pInputFieldDlg, SwField* pField)
            : mpInputFieldDlg(pInputFieldDlg)
            , mpFormatField(nullptr)
        {
            SwInputField *const pInputField(dynamic_cast<SwInputField*>(pField));
            SwSetExpField *const pSetExpField(dynamic_cast<SwSetExpField*>(pField));
 
            if (pInputField && pInputField->GetFormatField())
            {
                mpFormatField = pInputField->GetFormatField();
            }
            else if (pSetExpField && pSetExpField->GetFormatField())
            {
                mpFormatField = pSetExpField->GetFormatField();
            }
 
            // Register for possible field deletion while dialog is open
            if (mpFormatField)
                StartListening(mpFormatField->GetNotifier());
        }
 
        virtual ~FieldDeletionListener() override
        {
            // Dialog closed, remove modification listener
            EndListeningAll();
        }
 
        virtual void Notify(const SfxHint& rHint) override
        {
            // Input field has been deleted: better to close the dialog
            if(rHint.GetId() == SfxHintId::Dying)
            {
                mpFormatField = nullptr;
                mpInputFieldDlg->EndDialog(RET_CANCEL);
            }
        }
    private:
        VclPtr<AbstractFieldInputDlg> mpInputFieldDlg;
        SwFormatField* mpFormatField;
};
 
}
 
// Start input dialog for a specific field
bool SwWrtShell::StartInputFieldDlg(SwField* pField, bool bPrevButton, bool bNextButton,
                                    weld::Widget* pParentWin, SwWrtShell::FieldDialogPressedButton* pPressedButton)
{
 
    SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
    ScopedVclPtr<AbstractFieldInputDlg> pDlg(pFact->CreateFieldInputDlg(pParentWin, *this, pField, bPrevButton, bNextButton));
 
    bool bRet;
 
    {
        FieldDeletionListener aModify(pDlg.get(), pField);
        bRet = RET_CANCEL == pDlg->Execute();
    }
 
    if (pPressedButton)
    {
        if (pDlg->PrevButtonPressed())
            *pPressedButton = FieldDialogPressedButton::Previous;
        else if (pDlg->NextButtonPressed())
            *pPressedButton = FieldDialogPressedButton::Next;
    }
 
    pDlg.disposeAndClear();
    GetWin()->PaintImmediately();
    return bRet;
}
 
bool SwWrtShell::StartDropDownFieldDlg(SwField* pField, bool bPrevButton, bool bNextButton,
                                       weld::Widget* pParentWin, SwWrtShell::FieldDialogPressedButton* pPressedButton)
{
    SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
    ScopedVclPtr<AbstractDropDownFieldDialog> pDlg(pFact->CreateDropDownFieldDialog(pParentWin, *this, pField, bPrevButton, bNextButton));
    const short nRet = pDlg->Execute();
 
    if (pPressedButton)
    {
        if (pDlg->PrevButtonPressed())
            *pPressedButton = FieldDialogPressedButton::Previous;
        else if (pDlg->NextButtonPressed())
            *pPressedButton = FieldDialogPressedButton::Next;
    }
 
    pDlg.disposeAndClear();
    bool bRet = RET_CANCEL == nRet;
    GetWin()->PaintImmediately();
    if(RET_YES == nRet)
    {
        GetView().GetViewFrame().GetDispatcher()->Execute(FN_EDIT_FIELD, SfxCallMode::SYNCHRON);
    }
    return bRet;
}
 
// Insert directory - remove selection
 
void SwWrtShell::InsertTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
{
    if(!CanInsert())
        return;
 
    if(HasSelection())
        DelRight();
 
    SwEditShell::InsertTableOf(rTOX, pSet);
}
 
// Update directory - remove selection
 
void SwWrtShell::UpdateTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
{
    if(CanInsert())
    {
        SwEditShell::UpdateTableOf(rTOX, pSet);
    }
}
 
// handler for click on the field given as parameter.
// the cursor is positioned on the field.
 
void SwWrtShell::ClickToField(const SwField& rField, bool bExecHyperlinks)
{
    addCurrentPosition();
 
    // Since the cross reference and bibliography mark move the cursor,
    //  only select the field if it's not a Ctrl+Click
    if (!bExecHyperlinks
        || (SwFieldIds::GetRef != rField.GetTyp()->Which()
            && SwFieldIds::TableOfAuthorities != rField.GetTyp()->Which()))
    {
        StartAllAction();
        Right( SwCursorSkipMode::Chars, true, 1, false ); // Select the field.
        NormalizePam();
        EndAllAction();
    }
 
    m_bIsInClickToEdit = true;
    switch( rField.GetTyp()->Which() )
    {
    case SwFieldIds::JumpEdit:
        {
            sal_uInt16 nSlotId = 0;
            switch( rField.GetFormat() )
            {
            case JE_FMT_TABLE:
                nSlotId = FN_INSERT_TABLE;
                break;
 
            case JE_FMT_FRAME:
                nSlotId = FN_INSERT_FRAME;
                break;
 
            case JE_FMT_GRAPHIC:    nSlotId = SID_INSERT_GRAPHIC;       break;
            case JE_FMT_OLE:        nSlotId = SID_INSERT_OBJECT;        break;
 
            }
 
            if( nSlotId )
            {
                StartUndo( SwUndoId::START );
                //#97295# immediately select the right shell
                GetView().StopShellTimer();
                GetView().GetViewFrame().GetDispatcher()->Execute( nSlotId,
                            SfxCallMode::SYNCHRON|SfxCallMode::RECORD );
                EndUndo( SwUndoId::END );
            }
        }
        break;
 
    case SwFieldIds::Macro:
        {
            const SwMacroField *pField = static_cast<const SwMacroField*>(&rField);
            const OUString sText( rField.GetPar2() );
            OUString sRet( sText );
            ExecMacro( pField->GetSvxMacro(), &sRet );
 
            // return value changed?
            if( sRet != sText )
            {
                StartAllAction();
                const_cast<SwField&>(rField).SetPar2( sRet );
                rField.GetTyp()->UpdateFields();
                EndAllAction();
            }
        }
        break;
 
    case SwFieldIds::TableOfAuthorities:
        {
            if (!bExecHyperlinks)
                break; // Since it's not a Ctrl+Click, do not jump anywhere
 
            Point vStartPoint = GetCursor_()->GetPtPos();
            const SwAuthorityField* pField = static_cast<const SwAuthorityField*>(&rField);
 
            if (auto targetType = pField->GetTargetType();
                targetType == SwAuthorityField::TargetType::UseDisplayURL
                || targetType == SwAuthorityField::TargetType::UseTargetURL)
            {
                // Since the user selected target type with URL, try to use it if not empty
                if (const OUString aURL = pField->GetAbsoluteURL();
                    aURL.getLength() > 0)
                    ::LoadURL(*this, aURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
            }
            else if (targetType == SwAuthorityField::TargetType::BibliographyTableRow)
            {
                // Since the user selected to target Bibliography Table Row,
                //  try finding matching bibliography table line
 
                const bool bWasViewLocked = IsViewLocked();
                LockView(true);
 
                // Note: This way of iterating doesn't seem to take into account TOXes
                //          that are in a frame, probably in some other cases too
                GotoPage(1);
                while (GotoNextTOXBase())
                {
                    const SwTOXBase* pIteratedTOX = nullptr;
                    const SwTOXBase* pPreviousTOX = nullptr;
                    OUString vFieldText;
                    while ((pIteratedTOX = GetCurTOX()) != nullptr
                           && pIteratedTOX->GetType() == TOX_AUTHORITIES)
                    {
                        if (pIteratedTOX != pPreviousTOX)
                            vFieldText = pField->GetAuthority(GetLayout(), &pIteratedTOX->GetTOXForm());
 
                        if (const SwNode& rCurrentNode = GetCursor()->GetPoint()->GetNode();
                            rCurrentNode.GetNodeType() == SwNodeType::Text
                            && (GetCursor()->GetPoint()->GetNode().FindSectionNode()->GetSection().GetType()
                                == SectionType::ToxContent) // this checks it's not a heading
                            && static_cast<const SwTextNode*>(&rCurrentNode)->GetText() == vFieldText)
                        {
                            // Since a node has been found that is a text node, isn't a heading,
                            //  and has text matching to text generated by the field, jump to it
                            LockView(bWasViewLocked);
                            ShowCursor();
                            return;
                        }
                        pPreviousTOX = pIteratedTOX;
                        FwdPara();
                    }
                }
                // Since a matching node has not been found, return to original position
                SetCursor(&vStartPoint);
                LockView(bWasViewLocked);
            }
        }
        break;
 
    case SwFieldIds::GetRef:
        if (!bExecHyperlinks)
            break;
 
        StartAllAction();
        SwCursorShell::GotoRefMark( static_cast<const SwGetRefField&>(rField).GetSetRefName(),
                                    static_cast<const SwGetRefField&>(rField).GetSubType(),
                                    static_cast<const SwGetRefField&>(rField).GetSeqNo(),
                                    static_cast<const SwGetRefField&>(rField).GetFlags() );
        EndAllAction();
        break;
 
    case SwFieldIds::Input:
        {
            const SwInputField* pInputField = dynamic_cast<const SwInputField*>(&rField);
            if ( pInputField == nullptr )
            {
                StartInputFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
            }
        }
        break;
 
    case SwFieldIds::SetExp:
        if( static_cast<const SwSetExpField&>(rField).GetInputFlag() )
            StartInputFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
        break;
    case SwFieldIds::Dropdown :
        StartDropDownFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
    break;
    default:
        SAL_WARN_IF(rField.IsClickable(), "sw", "unhandled clickable field!");
    }
 
    m_bIsInClickToEdit = false;
}
 
void SwWrtShell::ClickToINetAttr( const SwFormatINetFormat& rItem, LoadUrlFlags nFilter )
{
    addCurrentPosition();
 
    if( rItem.GetValue().isEmpty() )
        return ;
 
    m_bIsInClickToEdit = true;
 
    // At first run the possibly set ObjectSelect Macro
    const SvxMacro* pMac = rItem.GetMacro( SvMacroItemId::OnClick );
    if( pMac )
    {
        SwCallMouseEvent aCallEvent;
        aCallEvent.Set( &rItem );
        GetDoc()->CallEvent( SvMacroItemId::OnClick, aCallEvent );
    }
 
    // So that the implementation of templates is displayed immediately
    ::LoadURL( *this, rItem.GetValue(), nFilter, rItem.GetTargetFrame() );
    const SwTextINetFormat* pTextAttr = rItem.GetTextINetFormat();
    if( pTextAttr )
    {
        const_cast<SwTextINetFormat*>(pTextAttr)->SetVisited( true );
        const_cast<SwTextINetFormat*>(pTextAttr)->SetVisitedValid( true );
    }
 
    m_bIsInClickToEdit = false;
}
 
bool SwWrtShell::ClickToINetGrf( const Point& rDocPt, LoadUrlFlags nFilter )
{
    bool bRet = false;
    OUString sURL;
    OUString sTargetFrameName;
    const SwFrameFormat* pFnd = IsURLGrfAtPos( rDocPt, &sURL, &sTargetFrameName );
    if( pFnd && !sURL.isEmpty() )
    {
        bRet = true;
        // At first run the possibly set ObjectSelect Macro
        SwCallMouseEvent aCallEvent;
        aCallEvent.Set(EVENT_OBJECT_URLITEM, pFnd);
        GetDoc()->CallEvent(SvMacroItemId::OnClick, aCallEvent);
 
        ::LoadURL(*this, sURL, nFilter, sTargetFrameName);
    }
    return bRet;
}
 
static void LoadURL(SwView& rView, const OUString& rURL, LoadUrlFlags nFilter,
                    const OUString& rTargetFrameName)
{
    SwDocShell* pDShell = rView.GetDocShell();
    OSL_ENSURE( pDShell, "No DocShell?!");
    SfxViewFrame& rViewFrame = rView.GetViewFrame();
 
    if (!SfxObjectShell::AllowedLinkProtocolFromDocument(rURL, pDShell, rViewFrame.GetFrameWeld()))
        return;
 
    // We are doing tiledRendering, let the client handles the URL loading,
    // unless we are jumping to a TOC mark.
    if (comphelper::LibreOfficeKit::isActive() && !rURL.startsWith("#"))
    {
        rView.libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, rURL.toUtf8());
        return;
    }
 
    OUString sTargetFrame(rTargetFrameName);
    if (sTargetFrame.isEmpty() && pDShell)
    {
        using namespace ::com::sun::star;
        uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
            pDShell->GetModel(), uno::UNO_QUERY_THROW);
        uno::Reference<document::XDocumentProperties> xDocProps
            = xDPS->getDocumentProperties();
        sTargetFrame = xDocProps->getDefaultTarget();
    }
 
    OUString sReferer;
    if( pDShell && pDShell->GetMedium() )
        sReferer = pDShell->GetMedium()->GetName();
    SfxFrameItem aView( SID_DOCFRAME, &rViewFrame );
    SfxStringItem aName( SID_FILE_NAME, rURL );
    SfxStringItem aTargetFrameName( SID_TARGETNAME, sTargetFrame );
    SfxStringItem aReferer( SID_REFERER, sReferer );
 
    SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, false );
    //#39076# Silent can be removed accordingly to SFX.
    SfxBoolItem aBrowse( SID_BROWSE, true );
 
    if ((nFilter & LoadUrlFlags::NewView) && !comphelper::LibreOfficeKit::isActive())
        aTargetFrameName.SetValue( u"_blank"_ustr );
 
    rViewFrame.GetDispatcher()->ExecuteList(SID_OPENDOC,
            SfxCallMode::ASYNCHRON|SfxCallMode::RECORD,
            {
                &aName,
                &aNewView, /*&aSilent,*/
                &aReferer,
                &aView, &aTargetFrameName,
                &aBrowse
            });
}
 
void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
              const OUString& rTargetFrameName )
{
    OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
    if( rURL.isEmpty() )
        return ;
 
    // The shell could be 0 also!!!!!
    if (auto pSh = dynamic_cast<SwWrtShell*>(&rVSh))
        ::LoadURL(pSh->GetView(), rURL, nFilter, rTargetFrameName);
}
 
void SwWrtShell::NavigatorPaste(const NaviContentBookmark& rBkmk)
{
    const OUString& rsCrossRef = rBkmk.GetCrossRef();
    const OUString& rsURL = rBkmk.GetURL();
 
    if (rsURL.isEmpty() && rsCrossRef.isEmpty())
        return;
 
    bool bSensitiveHyperlinkEntry = false;
    bool bSensitiveSectionLinkEntry = false;
    bool bSensitiveSectionCopyEntry = false;
    bool bSensitiveRefPageEntry = false;
    bool bSensitiveRefChapterEntry = false;
    bool bSensitiveRefContentEntry = false;
    bool bSensitiveRefUpDownEntry = false;
    bool bSensitiveRefPagePgDscEntry = false;
    bool bSensitiveRefNumberEntry = false;
    bool bSensitiveRefNumberNoContextEntry = false;
    bool bSensitiveRefNumberFullContextEntry = false;
    bool bSensitiveRefOnlyNumberEntry = false;
    bool bSensitiveRefOnlyCaptionEntry = false;
    bool bSensitiveRefOnlySeqNoEntry = false;
 
    if (!rsURL.isEmpty())
    {
        bSensitiveHyperlinkEntry = true;
 
        OUString sType = rsURL.getToken(1, '|');
        if (sType == "outline" || sType == "table")
        {
            bSensitiveSectionLinkEntry = true;
            bSensitiveSectionCopyEntry = true;
        }
    }
 
    std::optional<REFERENCESUBTYPE> oeRefSubType;
    std::optional<OUString> osName;
    std::optional<OUString> osVal;
 
    if (!rsCrossRef.isEmpty())
    {
        sal_Int32 nPos = 0;
        oeRefSubType = static_cast<REFERENCESUBTYPE>(
                    o3tl::toInt32(o3tl::getToken(rsCrossRef, 0, '|', nPos)));
        osName = rsCrossRef.getToken(0, '|', nPos);
        if (oeRefSubType == REFERENCESUBTYPE::REF_SEQUENCEFLD
                || oeRefSubType == REFERENCESUBTYPE::REF_FOOTNOTE
                || oeRefSubType == REFERENCESUBTYPE::REF_ENDNOTE)
        {
            // sequence number
            osVal = rsCrossRef.getToken(0, '|', nPos);
        }
        else
            osVal = rBkmk.GetDescription();
 
        bSensitiveRefPageEntry = true;
        bSensitiveRefChapterEntry = true;
        bSensitiveRefContentEntry = true;
        bSensitiveRefUpDownEntry = true;
        bSensitiveRefPagePgDscEntry = true;
 
        if (oeRefSubType == REFERENCESUBTYPE::REF_OUTLINE)
        {
            bSensitiveRefNumberEntry = true;
            bSensitiveRefNumberNoContextEntry = true;
            bSensitiveRefNumberFullContextEntry = true;
        }
        if (oeRefSubType == REFERENCESUBTYPE::REF_SEQUENCEFLD)
        {
            bSensitiveRefOnlyNumberEntry = true;
            bSensitiveRefOnlyCaptionEntry = true;
            bSensitiveRefOnlySeqNoEntry = true;
        }
    }
 
    vcl::Window* pWin = GetWin();
 
    std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(
        pWin->GetFrameWeld(), u"modules/swriter/ui/navigatordraginsertmenu.ui"_ustr));
    std::unique_ptr<weld::Menu> xPop = xBuilder->weld_menu(u"insertmenu"_ustr);
 
    xPop->append(u"hyperlink"_ustr, SwResId(STR_HYPERLINK));
    xPop->append(u"sectionlink"_ustr, SwResId(STR_SECTIONLINK));
    xPop->append(u"sectioncopy"_ustr, SwResId(STR_SECTIONCOPY));
    xPop->append(u"refpage"_ustr, SwResId(FMT_REF_PAGE));
    xPop->append(u"refchapter"_ustr, SwResId(FMT_REF_CHAPTER));
    xPop->append(u"refcontent"_ustr, SwResId(FMT_REF_TEXT));
    xPop->append(u"refupdown"_ustr, SwResId(FMT_REF_UPDOWN));
    xPop->append(u"refpagepgdsc"_ustr, SwResId(FMT_REF_PAGE_PGDSC));
    xPop->append(u"refnumberentry"_ustr, SwResId(FMT_REF_NUMBER));
    xPop->append(u"refnumbernocontext"_ustr, SwResId(FMT_REF_NUMBER_NO_CONTEXT));
    xPop->append(u"refnumberfullcontext"_ustr, SwResId(FMT_REF_NUMBER_FULL_CONTEXT));
    xPop->append(u"refonlynumber"_ustr, SwResId(FMT_REF_ONLYNUMBER));
    xPop->append(u"refonlycaption"_ustr, SwResId(FMT_REF_ONLYCAPTION));
    xPop->append(u"refonlyseqnoentry"_ustr, SwResId(FMT_REF_ONLYSEQNO));
 
    if (!officecfg::Office::Common::View::Menu::DontHideDisabledEntry::get()
            || Application::GetSettings().GetStyleSettings().GetHideDisabledMenuItems())
    {
        xPop->set_visible(u"hyperlink"_ustr, bSensitiveHyperlinkEntry);
        xPop->set_visible(u"sectionlink"_ustr, bSensitiveSectionLinkEntry);
        xPop->set_visible(u"sectioncopy"_ustr, bSensitiveSectionCopyEntry);
        xPop->set_visible(u"refpage"_ustr, bSensitiveRefPageEntry);
        xPop->set_visible(u"refchapter"_ustr, bSensitiveRefChapterEntry);
        xPop->set_visible(u"refcontent"_ustr, bSensitiveRefContentEntry);
        xPop->set_visible(u"refupdown"_ustr, bSensitiveRefUpDownEntry);
        xPop->set_visible(u"refpagepgdsc"_ustr, bSensitiveRefPagePgDscEntry);
        xPop->set_visible(u"refnumberentry"_ustr, bSensitiveRefNumberEntry);
        xPop->set_visible(u"refnumbernocontext"_ustr, bSensitiveRefNumberNoContextEntry);
        xPop->set_visible(u"refnumberfullcontext"_ustr, bSensitiveRefNumberFullContextEntry);
        xPop->set_visible(u"refonlynumber"_ustr, bSensitiveRefOnlyNumberEntry);
        xPop->set_visible(u"refonlycaption"_ustr, bSensitiveRefOnlyCaptionEntry);
        xPop->set_visible(u"refonlyseqnoentry"_ustr, bSensitiveRefOnlySeqNoEntry);
    }
    else
    {
        xPop->set_sensitive(u"hyperlink"_ustr, bSensitiveHyperlinkEntry);
        xPop->set_sensitive(u"sectionlink"_ustr, bSensitiveSectionLinkEntry);
        xPop->set_sensitive(u"sectioncopy"_ustr, bSensitiveSectionCopyEntry);
        xPop->set_sensitive(u"refpage"_ustr, bSensitiveRefPageEntry);
        xPop->set_sensitive(u"refchapter"_ustr, bSensitiveRefChapterEntry);
        xPop->set_sensitive(u"refcontent"_ustr, bSensitiveRefContentEntry);
        xPop->set_sensitive(u"refupdown"_ustr, bSensitiveRefUpDownEntry);
        xPop->set_sensitive(u"refpagepgdsc"_ustr, bSensitiveRefPagePgDscEntry);
        xPop->set_sensitive(u"refnumberentry"_ustr, bSensitiveRefNumberEntry);
        xPop->set_sensitive(u"refnumbernocontext"_ustr, bSensitiveRefNumberNoContextEntry);
        xPop->set_sensitive(u"refnumberfullcontext"_ustr, bSensitiveRefNumberFullContextEntry);
        xPop->set_sensitive(u"refonlynumber"_ustr, bSensitiveRefOnlyNumberEntry);
        xPop->set_sensitive(u"refonlycaption"_ustr, bSensitiveRefOnlyCaptionEntry);
        xPop->set_sensitive(u"refonlyseqnoentry"_ustr, bSensitiveRefOnlySeqNoEntry);
    }
 
    tools::Rectangle aRect(pWin->LogicToPixel(GetCursorDocPos()), Size(1, 1));
    weld::Window* pParent = weld::GetPopupParent(*pWin, aRect);
 
    OUString sInsert = xPop->popup_at_rect(pParent, aRect);
 
    if (sInsert.isEmpty())
        return;
 
    pWin->GrabFocus();
 
    if (sInsert == "hyperlink")
    {
        OUString sURL = rBkmk.GetURL();
        // Is this is a jump within the current Doc?
        const SwDocShell* pDocShell = GetView().GetDocShell();
        if(pDocShell->HasName())
        {
            const OUString aName = pDocShell->GetMedium()->GetURLObject().GetURLNoMark();
 
            if (sURL.startsWith(aName))
            {
                if (sURL.getLength()>aName.getLength())
                {
                    sURL = sURL.copy(aName.getLength());
                }
                else
                {
                    sURL.clear();
                }
            }
        }
        SwFormatINetFormat aFormat( sURL, OUString() );
        InsertURL( aFormat, rBkmk.GetDescription() );
    }
    else if (sInsert == "sectionlink" || sInsert == "sectioncopy")
    {
        SwSectionData aSection( SectionType::FileLink, GetUniqueSectionName() );
        OUString aLinkFile = o3tl::getToken(rsURL, 0, '#')
                + OUStringChar(sfx2::cTokenSeparator)
                + OUStringChar(sfx2::cTokenSeparator)
                + o3tl::getToken(rsURL, 1, '#');
        aSection.SetLinkFileName( aLinkFile );
        aSection.SetProtectFlag( true );
        const SwSection* pIns = InsertSection( aSection );
        if (sInsert == "sectioncopy" && pIns)
        {
            aSection = SwSectionData(*pIns);
            aSection.SetLinkFileName( OUString() );
            aSection.SetType( SectionType::Content );
            aSection.SetProtectFlag( false );
 
            // the update of content from linked section at time delete
            // the undostack. Then the change of the section don't create
            // any undoobject. -  BUG 69145
            bool bDoesUndo = DoesUndo();
            SwUndoId nLastUndoId(SwUndoId::EMPTY);
            if (GetLastUndoInfo(nullptr, & nLastUndoId))
            {
                if (SwUndoId::INSSECTION != nLastUndoId)
                {
                    DoUndo(false);
                }
            }
            UpdateSection( GetSectionFormatPos( *pIns->GetFormat() ), aSection );
            DoUndo( bDoesUndo );
        }
    }
    else // insert is for a reference mark type
    {
        REFERENCEMARK eRefMarkType;
 
        if (sInsert == "refpage")
            eRefMarkType = REFERENCEMARK::REF_PAGE;
        else if (sInsert == "refchapter")
            eRefMarkType = REFERENCEMARK::REF_CHAPTER;
        else if (sInsert == "refcontent")
            eRefMarkType = REFERENCEMARK::REF_CONTENT;
        else if (sInsert == "refupdown")
            eRefMarkType = REFERENCEMARK::REF_UPDOWN;
        else if (sInsert == "refpagepgdsc")
            eRefMarkType = REFERENCEMARK::REF_PAGE_PGDESC;
        else if (sInsert == "refnumberentry")
            eRefMarkType = REFERENCEMARK::REF_NUMBER;
        else if (sInsert == "refnumbernocontext")
            eRefMarkType = REFERENCEMARK::REF_NUMBER_NO_CONTEXT;
        else if (sInsert == "refnumberfullcontext")
            eRefMarkType = REFERENCEMARK::REF_NUMBER_FULL_CONTEXT;
        else if (sInsert == "refonlynumber")
            eRefMarkType = REFERENCEMARK::REF_ONLYNUMBER;
        else if (sInsert == "refonlycaption")
            eRefMarkType = REFERENCEMARK::REF_ONLYCAPTION;
        else if (sInsert == "refonlyseqnoentry")
            eRefMarkType = REFERENCEMARK::REF_ONLYSEQNO;
        else
        {
            assert(!"unknown reference mark type");
            return;
        }
 
        // Change REFERENCESUBTYPE_OUTLINE to REFERENCESUBTYPE::BOOKMARK. It is used to show
        // different options for headings reference and a regular bookmark in the reference mark
        // type popup menu. See related comment in SwContentTree::FillTransferData.
        if (oeRefSubType == REFERENCESUBTYPE::REF_OUTLINE)
            oeRefSubType = REFERENCESUBTYPE::REF_BOOKMARK;
 
        SwInsertField_Data aData(SwFieldTypesEnum::GetRef, oeRefSubType.value(), osName.value(),
                                 osVal.value(), eRefMarkType);
        SwFieldMgr aFieldMgr(this);
        aFieldMgr.InsertField(aData);
    }
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

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

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

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

V547 Expression '!"unknown reference mark type"' is always false.

V1007 The value from the potentially uninitialized optional 'oeRefSubType' is used. Probably it is a mistake.

V1007 The value from the potentially uninitialized optional 'osName' is used. Probably it is a mistake.

V1007 The value from the potentially uninitialized optional 'osVal' is used. Probably it is a mistake.