diff options
Diffstat (limited to 'sw/source/uibase/shells/textfld.cxx')
-rw-r--r-- | sw/source/uibase/shells/textfld.cxx | 836 |
1 files changed, 765 insertions, 71 deletions
diff --git a/sw/source/uibase/shells/textfld.cxx b/sw/source/uibase/shells/textfld.cxx index 158ba5626915..cec8afc3f76c 100644 --- a/sw/source/uibase/shells/textfld.cxx +++ b/sw/source/uibase/shells/textfld.cxx @@ -17,6 +17,7 @@ * 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> @@ -25,6 +26,7 @@ #include <sfx2/lnkbase.hxx> #include <txtfld.hxx> #include <svl/itempool.hxx> +#include <svl/numformat.hxx> #include <tools/lineend.hxx> #include <svl/whiter.hxx> #include <svl/eitem.hxx> @@ -35,6 +37,7 @@ #include <svx/hlnkitem.hxx> #include <svx/svxdlg.hxx> #include <osl/diagnose.h> +#include <fmthdft.hxx> #include <fmtinfmt.hxx> #include <fldwrap.hxx> #include <redline.hxx> @@ -53,15 +56,25 @@ #include <doc.hxx> #include <PostItMgr.hxx> #include <swmodule.hxx> +#include <svtools/strings.hrc> +#include <svtools/svtresid.hxx> + +#include <editeng/ulspitem.hxx> #include <xmloff/odffields.hxx> #include <IDocumentContentOperations.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; @@ -70,7 +83,7 @@ static OUString lcl_BuildTitleWithRedline( const SwRangeRedline *pRedline ) { const OUString sTitle(SwResId(STR_REDLINE_COMMENT)); - const char* pResId = nullptr; + TranslateId pResId; switch( pRedline->GetType() ) { case RedlineType::Insert: @@ -104,7 +117,7 @@ void SwTextShell::ExecField(SfxRequest &rReq) sal_uInt16 nSlot = rReq.GetSlot(); const SfxItemSet* pArgs = rReq.GetArgs(); if(pArgs) - pArgs->GetItemState(GetPool().GetWhich(nSlot), false, &pItem); + pArgs->GetItemState(GetPool().GetWhichIDFromSlotID(nSlot), false, &pItem); bool bMore = false; bool bIsText = true; @@ -127,22 +140,54 @@ void SwTextShell::ExecField(SfxRequest &rReq) 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(); - ScopedVclPtr<SfxAbstractLinksDialog> pDlg(pFact->CreateLinksDialog(GetView().GetFrameWeld(), &rSh.GetLinkManager(), false, &rLink)); - pDlg->Execute(); + 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(); - ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateSwFieldEditDlg( GetView() )); - pDlg->Execute(); + VclPtr<SfxAbstractDialog> pDlg(pFact->CreateSwFieldEditDlg( GetView() )); + // without TabPage no dialog + if (pDlg) + 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_EXECUTE_MACROFIELD: { SwField* pField = rSh.GetCurField(); @@ -176,16 +221,16 @@ void SwTextShell::ExecField(SfxRequest &rReq) rSh.ClearMark(); if (!rSh.IsMultiSelection() && (nullptr != dynamic_cast<const SwTextInputField*>( - SwCursorShell::GetTextFieldAtCursor(rSh.GetCursor(), true)))) + SwCursorShell::GetTextFieldAtCursor(rSh.GetCursor(), ::sw::GetTextAttrMode::Default)))) { rSh.SttSelect(); - rSh.SelectText( + rSh.SelectTextModel( SwCursorShell::StartOfInputFieldAtPos( *(rSh.GetCursor()->Start()) ) + 1, SwCursorShell::EndOfInputFieldAtPos( *(rSh.GetCursor()->Start()) ) - 1 ); } - else + else if (SwField* pCurrentField = rSh.GetCurField(true)) { - rSh.StartInputFieldDlg(rSh.GetCurField(true), false, false, GetView().GetFrameWeld()); + rSh.StartInputFieldDlg(pCurrentField, false, false, GetView().GetFrameWeld()); } bRet = true; } @@ -194,6 +239,15 @@ void SwTextShell::ExecField(SfxRequest &rReq) } break; + case FN_GOTO_MARK: + { + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(FN_GOTO_MARK); + if (pName) + { + rSh.GotoMark(pName->GetValue()); + } + } + break; default: bMore = true; } @@ -215,9 +269,9 @@ void SwTextShell::ExecField(SfxRequest &rReq) OUString aPar2; sal_Int32 nCommand = 0; - if( SfxItemState::SET == pArgs->GetItemState( FN_PARAM_FIELD_TYPE, - false, &pItem )) - nType = static_cast<SwFieldTypesEnum>(static_cast<const SfxUInt16Item *>(pItem)->GetValue()); + if( const 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 )) @@ -235,12 +289,12 @@ void SwTextShell::ExecField(SfxRequest &rReq) { aPar1 += static_cast<const SfxStringItem *>(pItem)->GetValue(); } - if( SfxItemState::SET == pArgs->GetItemState( - FN_PARAM_FIELD_CONTENT, false, &pItem )) - aPar2 = static_cast<const SfxStringItem *>(pItem)->GetValue(); - if( SfxItemState::SET == pArgs->GetItemState( - FN_PARAM_FIELD_FORMAT, false, &pItem )) - nFormat = static_cast<const SfxUInt32Item *>(pItem)->GetValue(); + if( const SfxStringItem* pContentItem = pArgs->GetItemIfSet( + FN_PARAM_FIELD_CONTENT, false )) + aPar2 = pContentItem->GetValue(); + if( const 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); @@ -261,18 +315,23 @@ void SwTextShell::ExecField(SfxRequest &rReq) OUString aPar2; sal_Unicode cSeparator = ' '; - if( SfxItemState::SET == pArgs->GetItemState( FN_PARAM_FIELD_TYPE, - false, &pItem )) - nType = static_cast<SwFieldTypesEnum>(static_cast<const SfxUInt16Item *>(pItem)->GetValue()); - if( SfxItemState::SET == pArgs->GetItemState( FN_PARAM_FIELD_SUBTYPE, - false, &pItem )) - nSubType = static_cast<const SfxUInt16Item *>(pItem)->GetValue(); - if( SfxItemState::SET == pArgs->GetItemState( - FN_PARAM_FIELD_CONTENT, false, &pItem )) - aPar2 = static_cast<const SfxStringItem *>(pItem)->GetValue(); - if( SfxItemState::SET == pArgs->GetItemState( - FN_PARAM_FIELD_FORMAT, false, &pItem )) - nFormat = static_cast<const SfxUInt32Item *>(pItem)->GetValue(); + if( const 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); + } + if( const SfxUInt16Item* pSubtypeItem = pArgs->GetItemIfSet( FN_PARAM_FIELD_SUBTYPE, + false )) + nSubType = pSubtypeItem->GetValue(); + if( const SfxStringItem* pContentItem = pArgs->GetItemIfSet( + FN_PARAM_FIELD_CONTENT, false )) + aPar2 = pContentItem->GetValue(); + if( const SfxUInt32Item* pFormatItem = pArgs->GetItemIfSet( + FN_PARAM_FIELD_FORMAT, false )) + nFormat = pFormatItem->GetValue(); if( SfxItemState::SET == pArgs->GetItemState( FN_PARAM_3, false, &pItem )) { @@ -280,17 +339,31 @@ void SwTextShell::ExecField(SfxRequest &rReq) 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); + } + } SwInsertField_Data aData(nType, nSubType, aPar1, aPar2, nFormat, GetShellPtr(), cSeparator ); 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()) + if(!GetView().GetViewFrame().IsInModalMode()) { - SfxViewFrame* pVFrame = GetView().GetViewFrame(); - pVFrame->ToggleChildWindow(FN_INSERT_FIELD); - bRes = pVFrame->GetChildWindow( nSlot ) != nullptr; + SfxViewFrame& rVFrame = GetView().GetViewFrame(); + rVFrame.ToggleChildWindow(FN_INSERT_FIELD); + bRes = rVFrame.GetChildWindow( nSlot ) != nullptr; Invalidate(rReq.GetSlot()); Invalidate(FN_INSERT_FIELD_CTRL); rReq.Ignore(); @@ -302,13 +375,13 @@ void SwTextShell::ExecField(SfxRequest &rReq) case FN_INSERT_REF_FIELD: { - SfxViewFrame* pVFrame = GetView().GetViewFrame(); - if (!pVFrame->HasChildWindow(FN_INSERT_FIELD)) - pVFrame->ToggleChildWindow(FN_INSERT_FIELD); // Show dialog + 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*>(pVFrame->GetChildWindow(nId)); + SwFieldDlgWrapper *pWrp = static_cast<SwFieldDlgWrapper*>(rVFrame.GetChildWindow(nId)); if (pWrp) pWrp->ShowReferencePage(); rReq.Ignore(); @@ -413,6 +486,18 @@ void SwTextShell::ExecField(SfxRequest &rReq) sText = pTextItem->GetValue(); pMgr->RegisterAnswerText(sText); pWin->ExecuteCommand(nSlot); + + SwPostItField* pLatestPostItField = pMgr->GetLatestPostItField(); + if (pLatestPostItField) + { + // Set the parent postit id of the reply. + pLatestPostItField->SetParentPostItId(pIdItem->GetValue().toUInt32()); + + // If name of the replied comment is empty, we need to set a name in order to connect them in the xml file. + pWin->GeneratePostItName(); // Generates a name if the current name is empty. + + pLatestPostItField->SetParentName(pWin->GetPostItField()->GetName()); + } } } } @@ -631,21 +716,25 @@ void SwTextShell::ExecField(SfxRequest &rReq) 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()->nNode.GetNode().GetTextNode()->GetLang(pCursorPos->GetPoint()->nContent.GetIndex()); + 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: @@ -685,6 +774,32 @@ FIELD_INSERT: 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(); @@ -692,19 +807,83 @@ FIELD_INSERT: { // Insert five En Space into the text field so the field has extent static constexpr OUStringLiteral vEnSpaces = u"\u2002\u2002\u2002\u2002\u2002"; - bool bSuccess = rSh.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos, vEnSpaces); + 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(); - SwPaM aFieldPam(pCursorPos->GetPoint()->nNode, pCursorPos->GetPoint()->nContent.GetIndex() - vEnSpaces.getLength(), - pCursorPos->GetPoint()->nNode, pCursorPos->GetPoint()->nContent.GetIndex()); - pMarksAccess->makeFieldBookmark(aFieldPam, OUString(), ODF_FORMTEXT, - aFieldPam.Start()); + sw::mark::IFieldmark* pFieldmark = pMarksAccess->makeFieldBookmark( + aFieldPam, OUString(), 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 ); + rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO ); } break; case FN_INSERT_CHECKBOX_FORMFIELD: @@ -719,7 +898,7 @@ FIELD_INSERT: } rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr); - rSh.GetView().GetViewFrame()->GetBindings().Invalidate( SID_UNDO ); + rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO ); } break; case FN_INSERT_DROPDOWN_FORMFIELD: @@ -734,7 +913,7 @@ FIELD_INSERT: } rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr); - rSh.GetView().GetViewFrame()->GetBindings().Invalidate( SID_UNDO ); + rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO ); } break; case FN_INSERT_DATE_FORMFIELD: @@ -750,8 +929,8 @@ FIELD_INSERT: if(bSuccess) { IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess(); - SwPaM aFieldPam(pCursorPos->GetPoint()->nNode, pCursorPos->GetPoint()->nContent.GetIndex() - ODF_FORMFIELD_DEFAULT_LENGTH, - pCursorPos->GetPoint()->nNode, pCursorPos->GetPoint()->nContent.GetIndex()); + SwPaM aFieldPam(pCursorPos->GetPoint()->GetNode(), pCursorPos->GetPoint()->GetContentIndex() - ODF_FORMFIELD_DEFAULT_LENGTH, + pCursorPos->GetPoint()->GetNode(), pCursorPos->GetPoint()->GetContentIndex()); sw::mark::IFieldmark* pFieldBM = pMarksAccess->makeFieldBookmark(aFieldPam, OUString(), ODF_FORMDATE, aFieldPam.Start()); @@ -767,7 +946,498 @@ FIELD_INSERT: } rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr); - rSh.GetView().GetViewFrame()->GetBindings().Invalidate( SID_UNDO ); + 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) + { + auto pFieldmark = dynamic_cast<sw::mark::IFieldmark*>(*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["FieldCommand"]; + 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["FieldResult"] >>= 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::IMark*> aRemovals; + for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it) + { + auto pFieldmark = dynamic_cast<sw::mark::IFieldmark*>(*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(); + 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. + IDocumentMarkAccess::const_iterator_t ppMark = rIDMA.findMark( + sBookmarkName + OUString::number(rSh.GetVirtPageNum())); + 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); + + // 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. + ppMark = rIDMA.findMark(sBookmarkName + OUString::number(rSh.GetVirtPageNum())); + 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()) + { + rDoc->getIDocumentContentOperations().InsertString(*rSh.GetCursor(), " / "); + SwInsertField_Data aPageTotalData(SwFieldTypesEnum::DocumentStatistics, DS_PAGE, + 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, + sBookmarkName + OUString::number(rSh.GetVirtPageNum()), + 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?"); + ppMark = rIDMA.findMark(sBookmarkName + OUString::number(rSh.GetVirtPageNum())); + 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); + + nStartContentIndex = rSh.GetCursor()->Start()->GetContentIndex(); + + // Insert page number + SwFieldMgr aEvenMgr(pShell); + aEvenMgr.InsertField(aData); + if (pDlg->GetIncludePageTotal()) + { + rDoc->getIDocumentContentOperations().InsertString(*rSh.GetCursor(), " / "); + SwInsertField_Data aPageTotalData(SwFieldTypesEnum::DocumentStatistics, + DS_PAGE, OUString(), OUString(), + SVX_NUM_PAGEDESC); + aMgr.InsertField(aPageTotalData); + } + + // Mark inserted fields with a bookmark - so it can be found/removed if re-run + SwPaM aNewEvenBookmarkPaM(*rSh.GetCursor()->Start()); + aNewEvenBookmarkPaM.SetMark(); + aNewEvenBookmarkPaM.Start()->SetContent(nStartContentIndex); + rIDMA.makeMark(aNewEvenBookmarkPaM, + sBookmarkName + OUString::number(rSh.GetVirtPageNum()), + IDocumentMarkAccess::MarkType::BOOKMARK, + sw::mark::InsertMode::New); + } + + rSh.SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent); + rSh.EndAllAction(); + rSh.LockView(false); + rDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_PAGE_NUMBER, nullptr); + } + pDlg->disposeOnce(); + }); + rReq.Done(); + } + break; + case FN_UPDATE_TEXT_FORMFIELD: + { + // This updates a single fieldmark under the current cursor. + 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::PropertyValue> aField; + const SfxUnoAnyItem* pFields = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3); + if (pFields) + { + pFields->GetValue() >>= aField; + } + + IDocumentMarkAccess& rIDMA = *rSh.getIDocumentMarkAccess(); + SwPosition& rCursor = *rSh.GetCursor()->GetPoint(); + sw::mark::IFieldmark* pFieldmark = rIDMA.getInnerFieldmarkFor(rCursor); + if (!pFieldmark) + { + break; + } + + if (pFieldmark->GetFieldname() != aFieldType) + { + break; + } + + auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM); + if (itParam == pFieldmark->GetParameters()->end()) + { + break; + } + + OUString aCommand; + itParam->second >>= aCommand; + if (!aCommand.startsWith(aFieldCommandPrefix)) + { + break; + } + + rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::UPDATE_FORM_FIELD, nullptr); + rSh.StartAction(); + comphelper::SequenceAsHashMap aMap(aField); + itParam->second = aMap["FieldCommand"]; + 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["FieldResult"] >>= aFieldResult; + SwTranslateHelper::PasteHTMLToPaM(rSh, &aPaM, aFieldResult.toUtf8()); + + rSh.EndAction(); + rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::UPDATE_FORM_FIELD, nullptr); } break; default: @@ -804,7 +1474,7 @@ void SwTextShell::StateField( SfxItemSet &rSet ) rSet.InvalidateItem( FN_DELETE_COMMENT ); rSet.InvalidateItem( FN_HIDE_NOTE ); } - // tdf#137568 do not offer comment formating, if no comments are present + // tdf#137568 do not offer comment formatting, if no comments are present if (!pPostItMgr || !pPostItMgr->HasNotes()) rSet.DisableItem( FN_FORMAT_ALL_NOTES ); } @@ -833,6 +1503,16 @@ void SwTextShell::StateField( SfxItemSet &rSet ) } break; + case FN_UPDATE_SEL_FIELD: + { + pField = rSh.GetCurField(); + + if (!pField) + rSet.DisableItem( nWhich ); + } + + break; + case FN_EXECUTE_MACROFIELD: { if(!bGetField) @@ -853,11 +1533,11 @@ void SwTextShell::StateField( SfxItemSet &rSet ) } else { - SfxViewFrame* pVFrame = GetView().GetViewFrame(); + SfxViewFrame& rVFrame = GetView().GetViewFrame(); //#i5788# prevent closing of the field dialog while a modal dialog ( Input field dialog ) is active - if(!pVFrame->IsInModalMode() && - pVFrame->KnowsChildWindow(FN_INSERT_FIELD) && !pVFrame->HasChildWindow(FN_INSERT_FIELD_DATA_ONLY) ) - rSet.Put(SfxBoolItem( FN_INSERT_FIELD, pVFrame->HasChildWindow(nWhich))); + if(!rVFrame.IsInModalMode() && + rVFrame.KnowsChildWindow(FN_INSERT_FIELD) && !rVFrame.HasChildWindow(FN_INSERT_FIELD_DATA_ONLY) ) + rSet.Put(SfxBoolItem( FN_INSERT_FIELD, rVFrame.HasChildWindow(nWhich))); else rSet.DisableItem(FN_INSERT_FIELD); } @@ -866,8 +1546,8 @@ void SwTextShell::StateField( SfxItemSet &rSet ) case FN_INSERT_REF_FIELD: { - SfxViewFrame* pVFrame = GetView().GetViewFrame(); - if ( !pVFrame->KnowsChildWindow(FN_INSERT_FIELD) + SfxViewFrame& rVFrame = GetView().GetViewFrame(); + if ( !rVFrame.KnowsChildWindow(FN_INSERT_FIELD) || rSh.CursorInsideInputField() ) { rSet.DisableItem(FN_INSERT_REF_FIELD); @@ -882,7 +1562,7 @@ void SwTextShell::StateField( SfxItemSet &rSet ) } else { - rSet.Put(SfxBoolItem( nWhich, GetView().GetViewFrame()->HasChildWindow(FN_INSERT_FIELD))); + rSet.Put(SfxBoolItem( nWhich, GetView().GetViewFrame().HasChildWindow(FN_INSERT_FIELD))); } break; @@ -914,8 +1594,11 @@ void SwTextShell::StateField( SfxItemSet &rSet ) { rSet.DisableItem(nWhich); } - // tdf#86188 Allow disabling comment insertion on footnote/endnote for better OOXML interoperability - else if ( rSh.IsCursorInFootnote() && !officecfg::Office::Compatibility::View::AllowCommentsInFootnotes::get() ) + // tdf#86188, tdf#135794: Allow disabling comment insertion + // on footnote/endnote/header/frames for better OOXML interoperability + else if (!officecfg::Office::Compatibility::View::AllowCommentsInFootnotes::get() && + (rSh.IsCursorInFootnote() || rSh.IsInHeaderFooter() || + rSh.GetCurrFlyFrame(/*bCalcFrame=*/false))) { rSet.DisableItem(nWhich); } @@ -949,13 +1632,12 @@ void SwTextShell::StateField( SfxItemSet &rSet ) { // Check whether we are in a text form field SwPosition aCursorPos(*rSh.GetCursor()->GetPoint()); - sw::mark::IFieldmark* pFieldBM = GetShell().getIDocumentMarkAccess()->getFieldmarkFor(aCursorPos); + sw::mark::IFieldmark* pFieldBM = GetShell().getIDocumentMarkAccess()->getInnerFieldmarkFor(aCursorPos); if ((!pFieldBM || pFieldBM->GetFieldname() != ODF_FORMTEXT) - && aCursorPos.nContent.GetIndex() > 0) + && aCursorPos.GetContentIndex() > 0) { - SwPosition aPos(aCursorPos); - --aPos.nContent; - pFieldBM = GetShell().getIDocumentMarkAccess()->getFieldmarkFor(aPos); + SwPosition aPos(*aCursorPos.GetContentNode(), aCursorPos.GetContentIndex() - 1); + pFieldBM = GetShell().getIDocumentMarkAccess()->getInnerFieldmarkFor(aPos); } if (pFieldBM && pFieldBM->GetFieldname() == ODF_FORMTEXT && (aCursorPos > pFieldBM->GetMarkStart() && aCursorPos < pFieldBM->GetMarkEnd() )) @@ -975,7 +1657,8 @@ void SwTextShell::InsertHyperlink(const SvxHyperlinkItem& rHlnkItem) const OUString& rName = rHlnkItem.GetName(); const OUString& rURL = rHlnkItem.GetURL(); const OUString& rTarget = rHlnkItem.GetTargetFrame(); - sal_uInt16 nType = static_cast<sal_uInt16>(rHlnkItem.GetInsertMode()); + const OUString& rReplacementText = rHlnkItem.GetReplacementText(); + sal_uInt16 nType = o3tl::narrowing<sal_uInt16>(rHlnkItem.GetInsertMode()); nType &= ~HLINK_HTMLMODE; const SvxMacroTableDtor* pMacroTable = rHlnkItem.GetMacroTable(); @@ -985,11 +1668,10 @@ void SwTextShell::InsertHyperlink(const SvxHyperlinkItem& rHlnkItem) return; rSh.StartAction(); - SfxItemSet aSet(GetPool(), svl::Items<RES_TXTATR_INETFMT, RES_TXTATR_INETFMT>{}); + SfxItemSetFixed<RES_TXTATR_INETFMT, RES_TXTATR_INETFMT> aSet(GetPool()); rSh.GetCurAttr( aSet ); - const SfxPoolItem* pItem; - if(SfxItemState::SET == aSet.GetItemState(RES_TXTATR_INETFMT, false, &pItem)) + if(SfxItemState::SET == aSet.GetItemState(RES_TXTATR_INETFMT, false)) { // Select links rSh.SwCursorShell::SelectTextAttr(RES_TXTATR_INETFMT, false); @@ -1014,7 +1696,19 @@ void SwTextShell::InsertHyperlink(const SvxHyperlinkItem& rHlnkItem) aINetFormat.SetMacro(SvMacroItemId::OnMouseOut, *pMacro); } rSh.SttSelect(); - rSh.InsertURL( aINetFormat, rName, true ); + // inserting mention + if (comphelper::LibreOfficeKit::isActive() && !rReplacementText.isEmpty()) + { + SwPaM* pCursorPos = rSh.GetCursor(); + // move cursor backwards to select @mention + for(int i=0; i < rReplacementText.getLength(); i++) + pCursorPos->Move(fnMoveBackward); + rSh.InsertURL( aINetFormat, rName, false ); + } + else + { + rSh.InsertURL( aINetFormat, rName, true ); + } rSh.EndSelect(); } break; |