/* -*- 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, ::std::optional<SwPosition> *const poAnchorStart)
{
ResetCursorStack();
if (!CanInsert())
return false ;
return InsertField2Impl(rField, pAnnotationRange, poAnchorStart);
}
bool SwWrtShell::InsertField2Impl(SwField const & rField,
SwPaM* pAnnotationRange, ::std::optional<SwPosition> *const poAnchorStart)
{
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();
auto pMark{pMarksAccess->makeAnnotationMark(*pAnnotationTextRange, SwMarkName())};
if (poAnchorStart)
{
poAnchorStart->emplace(pMark->GetMarkStart());
}
}
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 bool LoadURL(const SfxViewShell& rView, const OUString& rURL, LoadUrlFlags nFilter,
const OUString& rTargetFrameName)
{
SfxViewFrame& rViewFrame = rView.GetViewFrame();
SfxObjectShell* pDShell = rViewFrame.GetObjectShell();
OSL_ENSURE( pDShell, "No DocShell?!" );
if (!SfxObjectShell::AllowedLinkProtocolFromDocument(rURL, pDShell, rViewFrame.GetFrameWeld()))
return false ;
// 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 true ;
}
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 );
const SfxPoolItem* aArr[] = {
&aName,
&aNewView, /*&aSilent,*/
&aReferer,
&aView, &aTargetFrameName,
&aBrowse,
nullptr
};
rViewFrame.GetDispatcher()->GetBindings()->Execute(
SID_OPENDOC, aArr, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
return true ;
}
bool LoadURL( SwWrtShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
const OUString& rTargetFrameName )
{
OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
if ( rURL.isEmpty() )
return false ;
return ::LoadURL(rVSh.GetView(), rURL, nFilter, rTargetFrameName);
}
bool LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
const OUString& rTargetFrameName )
{
if (auto pSh = dynamic_cast <SwWrtShell*>(&rVSh))
return ::LoadURL(*pSh, rURL, nFilter, rTargetFrameName);
return false ;
}
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, UIName(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(false && "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: */
Messung V0.5 in Prozent C=94 H=98 G=95
¤ Dauer der Verarbeitung: 0.5 Sekunden
(vorverarbeitet am 2026-10-03)
¤
*© Formatika GbR, Deutschland