docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / sw / source / uibase / shells / textfld.cxx
blob42fd111f26840efb8948a6a059e281994410cda9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/beans/PropertyValues.hpp>
21 #include <AnnotationWin.hxx>
22 #include <comphelper/lok.hxx>
23 #include <hintids.hxx>
24 #include <IDocumentFieldsAccess.hxx>
25 #include <sfx2/bindings.hxx>
26 #include <sfx2/lnkbase.hxx>
27 #include <txtfld.hxx>
28 #include <svl/itempool.hxx>
29 #include <svl/numformat.hxx>
30 #include <editeng/editobj.hxx>
31 #include <tools/lineend.hxx>
32 #include <svl/whiter.hxx>
33 #include <svl/eitem.hxx>
34 #include <svl/macitem.hxx>
35 #include <sfx2/viewfrm.hxx>
36 #include <sfx2/request.hxx>
37 #include <svx/postattr.hxx>
38 #include <svx/hlnkitem.hxx>
39 #include <svx/svxdlg.hxx>
40 #include <osl/diagnose.h>
41 #include <charatr.hxx>
42 #include <fmtfsize.hxx>
43 #include <fmthdft.hxx>
44 #include <fmtinfmt.hxx>
45 #include <fldwrap.hxx>
46 #include <frmatr.hxx>
47 #include <hfspacingitem.hxx>
48 #include <redline.hxx>
49 #include <swfont.hxx>
50 #include <view.hxx>
51 #include <viewopt.hxx>
52 #include <wrtsh.hxx>
53 #include <textsh.hxx>
54 #include <docufld.hxx>
55 #include <ddefld.hxx>
56 #include <fldmgr.hxx>
57 #include <uitool.hxx>
58 #include <cmdid.h>
59 #include <strings.hrc>
60 #include <sfx2/event.hxx>
61 #include <swabstdlg.hxx>
62 #include <doc.hxx>
63 #include <PostItMgr.hxx>
64 #include <swmodule.hxx>
65 #include <svtools/strings.hrc>
66 #include <svtools/svtresid.hxx>
68 #include <xmloff/odffields.hxx>
69 #include <IDocumentContentOperations.hxx>
70 #include <IDocumentLayoutAccess.hxx>
71 #include <IDocumentRedlineAccess.hxx>
72 #include <IDocumentUndoRedo.hxx>
73 #include <svl/zforlist.hxx>
74 #include <svl/zformat.hxx>
75 #include <svx/xfillit0.hxx>
76 #include <svx/pageitem.hxx>
77 #include <comphelper/sequenceashashmap.hxx>
78 #include <IMark.hxx>
79 #include <officecfg/Office/Common.hxx>
80 #include <officecfg/Office/Compatibility.hxx>
81 #include <ndtxt.hxx>
82 #include <translatehelper.hxx>
83 #include <sfx2/dispatch.hxx>
86 using namespace nsSwDocInfoSubType;
88 static OUString lcl_BuildTitleWithRedline( const SwRangeRedline *pRedline )
90 const OUString sTitle(SwResId(STR_REDLINE_COMMENT));
92 TranslateId pResId;
93 switch( pRedline->GetType() )
95 case RedlineType::Insert:
96 pResId = STR_REDLINE_INSERTED;
97 break;
98 case RedlineType::Delete:
99 pResId = STR_REDLINE_DELETED;
100 break;
101 case RedlineType::Format:
102 case RedlineType::ParagraphFormat:
103 pResId = STR_REDLINE_FORMATTED;
104 break;
105 case RedlineType::Table:
106 pResId = STR_REDLINE_TABLECHG;
107 break;
108 case RedlineType::FmtColl:
109 pResId = STR_REDLINE_FMTCOLLSET;
110 break;
111 default:
112 return sTitle;
115 return sTitle + SwResId(pResId);
118 static bool lcl_canUserModifyAnnotation(const SwView& rView, std::u16string_view sAuthor)
120 return !comphelper::LibreOfficeKit::isActive() || !rView.IsLokReadOnlyView()
121 || sAuthor == rView.GetRedlineAuthor();
124 static bool lcl_canUserModifyAnnotation(const SwView& rView,
125 const sw::annotation::SwAnnotationWin* pAnnotationWin)
127 return pAnnotationWin && lcl_canUserModifyAnnotation(rView, pAnnotationWin->GetAuthor());
130 static bool lcl_canUserModifyAnnotation(const SwView& rView, sal_uInt32 nPostItId)
132 return lcl_canUserModifyAnnotation(rView, rView.GetPostItMgr()->GetAnnotationWin(nPostItId));
135 void SwTextShell::ExecField(SfxRequest &rReq)
137 SwWrtShell& rSh = GetShell();
138 const SfxPoolItem* pItem = nullptr;
140 sal_uInt16 nSlot = rReq.GetSlot();
141 const SfxItemSet* pArgs = rReq.GetArgs();
142 if(pArgs)
143 pArgs->GetItemState(GetPool().GetWhichIDFromSlotID(nSlot), false, &pItem);
145 bool bMore = false;
146 bool bIsText = true;
147 SwFieldTypesEnum nInsertType = SwFieldTypesEnum::Date;
148 sal_uInt16 nInsertSubType = 0;
149 sal_uInt32 nInsertFormat = 0;
151 switch(nSlot)
153 case FN_EDIT_FIELD:
155 SwField* pField = rSh.GetCurField(true);
156 if( pField )
158 switch ( pField->GetTypeId() )
160 case SwFieldTypesEnum::DDE:
162 ::sfx2::SvBaseLink& rLink = static_cast<SwDDEFieldType*>(pField->GetTyp())->
163 GetBaseLink();
164 if(rLink.IsVisible())
166 if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
168 std::unique_ptr<weld::MessageDialog> xError(
169 Application::CreateMessageDialog(
170 nullptr, VclMessageType::Warning, VclButtonsType::Ok,
171 SvtResId(STR_WARNING_EXTERNAL_LINK_EDIT_DISABLED)));
172 xError->run();
173 break;
176 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
177 VclPtr<SfxAbstractLinksDialog> pDlg(pFact->CreateLinksDialog(GetView().GetFrameWeld(), &rSh.GetLinkManager(), false, &rLink));
178 pDlg->StartExecuteAsync(
179 [pDlg] (sal_Int32 /*nResult*/)->void
181 pDlg->disposeOnce();
185 break;
187 default:
189 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
190 VclPtr<SfxAbstractDialog> pDlg(pFact->CreateSwFieldEditDlg( GetView() ));
191 // without TabPage no dialog
192 if (pDlg)
193 pDlg->StartExecuteAsync(
194 [pDlg] (sal_Int32 /*nResult*/)->void
196 pDlg->disposeOnce();
202 break;
204 case FN_UPDATE_SEL_FIELD:
206 SwField *pField = rSh.GetCurField();
208 if (pField)
210 rSh.UpdateOneField(*pField);
212 break;
214 case FN_EXECUTE_MACROFIELD:
216 SwField* pField = rSh.GetCurField();
217 if(pField && pField->GetTyp()->Which() == SwFieldIds::Macro)
220 const OUString& rMacro = static_cast<SwMacroField*>(pField)->GetMacro();
221 sal_Int32 nPos = rMacro.indexOf('.');
222 if(nPos != -1)
224 SvxMacro aMacro( rMacro.copy(nPos + 1), rMacro.copy(0,nPos), STARBASIC );
225 rSh.ExecMacro(aMacro);
229 break;
231 case FN_GOTO_NEXT_INPUTFLD:
232 case FN_GOTO_PREV_INPUTFLD:
234 bool bRet = false;
235 SwFieldType* pField = rSh.GetFieldType( 0, SwFieldIds::Input );
236 const bool bAddSetExpressionFields = !( rSh.GetViewOptions()->IsReadonly() );
237 if ( pField != nullptr
238 && rSh.MoveFieldType(
239 pField,
240 FN_GOTO_NEXT_INPUTFLD == nSlot,
241 SwFieldIds::Unknown,
242 bAddSetExpressionFields ) )
244 rSh.ClearMark();
245 if (!rSh.IsMultiSelection()
246 && (nullptr != dynamic_cast<const SwTextInputField*>(
247 SwCursorShell::GetTextFieldAtCursor(rSh.GetCursor(), ::sw::GetTextAttrMode::Default))))
249 rSh.SttSelect();
250 rSh.SelectTextModel(
251 SwCursorShell::StartOfInputFieldAtPos( *(rSh.GetCursor()->Start()) ) + 1,
252 SwCursorShell::EndOfInputFieldAtPos( *(rSh.GetCursor()->Start()) ) - 1 );
254 else if (SwField* pCurrentField = rSh.GetCurField(true))
256 rSh.StartInputFieldDlg(pCurrentField, false, false, GetView().GetFrameWeld());
258 bRet = true;
261 rReq.SetReturnValue( SfxBoolItem( nSlot, bRet ));
263 break;
265 case FN_GOTO_MARK:
267 const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(FN_GOTO_MARK);
268 if (pName)
270 rSh.GotoMark(pName->GetValue());
273 break;
274 default:
275 bMore = true;
277 if(!bMore)
278 return;
280 // Here come the slots with FieldMgr.
281 SwFieldMgr aFieldMgr(GetShellPtr());
282 switch(nSlot)
284 case FN_INSERT_DBFIELD:
286 bool bRes = false;
287 if( pItem )
289 sal_uInt32 nFormat = 0;
290 SwFieldTypesEnum nType = SwFieldTypesEnum::Date;
291 OUString aPar1 = static_cast<const SfxStringItem *>(pItem)->GetValue();
292 OUString aPar2;
293 sal_Int32 nCommand = 0;
295 if( const SfxUInt16Item* pFieldItem = pArgs->GetItemIfSet( FN_PARAM_FIELD_TYPE,
296 false ))
297 nType = static_cast<SwFieldTypesEnum>(pFieldItem->GetValue());
298 aPar1 += OUStringChar(DB_DELIM);
299 if( SfxItemState::SET == pArgs->GetItemState(
300 FN_PARAM_1, false, &pItem ))
302 aPar1 += static_cast<const SfxStringItem *>(pItem)->GetValue();
304 if( SfxItemState::SET == pArgs->GetItemState(
305 FN_PARAM_3, false, &pItem ))
306 nCommand = static_cast<const SfxInt32Item*>(pItem)->GetValue();
307 aPar1 += OUStringChar(DB_DELIM)
308 + OUString::number(nCommand)
309 + OUStringChar(DB_DELIM);
310 if( SfxItemState::SET == pArgs->GetItemState(
311 FN_PARAM_2, false, &pItem ))
313 aPar1 += static_cast<const SfxStringItem *>(pItem)->GetValue();
315 if( const SfxStringItem* pContentItem = pArgs->GetItemIfSet(
316 FN_PARAM_FIELD_CONTENT, false ))
317 aPar2 = pContentItem->GetValue();
318 if( const SfxUInt32Item* pFormatItem = pArgs->GetItemIfSet(
319 FN_PARAM_FIELD_FORMAT, false ))
320 nFormat = pFormatItem->GetValue();
321 OSL_FAIL("Command is not yet used");
322 SwInsertField_Data aData(nType, 0, aPar1, aPar2, nFormat, GetShellPtr(), ' '/*separator*/ );
323 bRes = aFieldMgr.InsertField(aData);
325 rReq.SetReturnValue(SfxBoolItem( nSlot, bRes ));
327 break;
328 case FN_INSERT_FIELD_CTRL:
329 case FN_INSERT_FIELD:
331 bool bRes = false;
332 if( pItem && nSlot != FN_INSERT_FIELD_CTRL)
334 sal_uInt32 nFormat = 0;
335 SwFieldTypesEnum nType = SwFieldTypesEnum::Date;
336 sal_uInt16 nSubType = 0;
337 OUString aPar1 = static_cast<const SfxStringItem *>(pItem)->GetValue();
338 OUString aPar2;
339 sal_Unicode cSeparator = ' ';
341 if( const SfxUInt16Item* pTypeItem = pArgs->GetItemIfSet( FN_PARAM_FIELD_TYPE,
342 false ))
343 nType = static_cast<SwFieldTypesEnum>(pTypeItem->GetValue());
344 else if (pArgs->GetItemState(FN_PARAM_4, false, &pItem) == SfxItemState::SET)
346 const OUString& rTypeName = static_cast<const SfxStringItem *>(pItem)->GetValue();
347 nType = SwFieldTypeFromString(rTypeName);
349 if( const SfxUInt16Item* pSubtypeItem = pArgs->GetItemIfSet( FN_PARAM_FIELD_SUBTYPE,
350 false ))
351 nSubType = pSubtypeItem->GetValue();
352 if( const SfxStringItem* pContentItem = pArgs->GetItemIfSet(
353 FN_PARAM_FIELD_CONTENT, false ))
354 aPar2 = pContentItem->GetValue();
355 if( const SfxUInt32Item* pFormatItem = pArgs->GetItemIfSet(
356 FN_PARAM_FIELD_FORMAT, false ))
357 nFormat = pFormatItem->GetValue();
358 if( SfxItemState::SET == pArgs->GetItemState(
359 FN_PARAM_3, false, &pItem ))
361 OUString sTmp = static_cast<const SfxStringItem *>(pItem)->GetValue();
362 if(!sTmp.isEmpty())
363 cSeparator = sTmp[0];
365 if (pArgs->GetItemState(FN_PARAM_5, false, &pItem) == SfxItemState::SET)
367 // Wrap the field in the requested container instead of inserting it
368 // directly at the cursor position.
369 const OUString& rWrapper = static_cast<const SfxStringItem *>(pItem)->GetValue();
370 if (rWrapper == "Footnote")
372 GetShellPtr()->InsertFootnote(OUString());
374 else if (rWrapper == "Endnote")
376 GetShellPtr()->InsertFootnote(OUString(), /*bEndNote=*/true);
379 SwInsertField_Data aData(nType, nSubType, aPar1, aPar2, nFormat, GetShellPtr(), cSeparator );
380 bRes = aFieldMgr.InsertField( aData );
382 else
384 //#i5788# prevent closing of the field dialog while a modal dialog ( Input field dialog ) is active
385 if(!GetView().GetViewFrame().IsInModalMode())
387 SfxViewFrame& rVFrame = GetView().GetViewFrame();
388 rVFrame.ToggleChildWindow(FN_INSERT_FIELD);
389 bRes = rVFrame.GetChildWindow( nSlot ) != nullptr;
390 Invalidate(rReq.GetSlot());
391 Invalidate(FN_INSERT_FIELD_CTRL);
392 rReq.Ignore();
395 rReq.SetReturnValue(SfxBoolItem( nSlot, bRes ));
397 break;
399 case FN_INSERT_REF_FIELD:
401 SfxViewFrame& rVFrame = GetView().GetViewFrame();
402 if (!rVFrame.HasChildWindow(FN_INSERT_FIELD))
403 rVFrame.ToggleChildWindow(FN_INSERT_FIELD); // Show dialog
405 // Switch Fielddlg at a new TabPage
406 sal_uInt16 nId = SwFieldDlgWrapper::GetChildWindowId();
407 SwFieldDlgWrapper *pWrp = static_cast<SwFieldDlgWrapper*>(rVFrame.GetChildWindow(nId));
408 if (pWrp)
409 pWrp->ShowReferencePage();
410 rReq.Ignore();
412 break;
413 case FN_DELETE_COMMENT:
415 const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
416 if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
418 sal_uInt32 nPostItId = pIdItem->GetValue().toUInt32();
419 if (lcl_canUserModifyAnnotation(GetView(), nPostItId))
420 GetView().GetPostItMgr()->Delete(nPostItId);
422 else if ( GetView().GetPostItMgr() &&
423 GetView().GetPostItMgr()->HasActiveSidebarWin() )
425 sw::annotation::SwAnnotationWin* pAnnotationWin
426 = GetView().GetPostItMgr()->GetActiveSidebarWin();
427 if (lcl_canUserModifyAnnotation(GetView(), pAnnotationWin))
428 GetView().GetPostItMgr()->DeleteActiveSidebarWin();
430 break;
432 case FN_DELETE_COMMENT_THREAD:
434 const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
435 if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
437 sal_uInt32 nPostItId = pIdItem->GetValue().toUInt32();
438 if (lcl_canUserModifyAnnotation(GetView(), nPostItId))
439 GetView().GetPostItMgr()->DeleteCommentThread(nPostItId);
441 else if (GetView().GetPostItMgr() && GetView().GetPostItMgr()->HasActiveSidebarWin())
443 sw::annotation::SwAnnotationWin* pAnnotationWin
444 = GetView().GetPostItMgr()->GetActiveSidebarWin();
445 if (lcl_canUserModifyAnnotation(GetView(), pAnnotationWin))
446 GetView().GetPostItMgr()->DeleteActiveSidebarWin();
448 break;
450 case FN_RESOLVE_NOTE:
452 const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
453 if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
455 GetView().GetPostItMgr()->ToggleResolved(pIdItem->GetValue().toUInt32());
457 break;
459 case FN_RESOLVE_NOTE_THREAD:
461 const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
462 if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
464 GetView().GetPostItMgr()->ToggleResolvedForThread(pIdItem->GetValue().toUInt32());
466 break;
468 case FN_DELETE_ALL_NOTES:
469 if ( GetView().GetPostItMgr() )
470 GetView().GetPostItMgr()->Delete();
471 break;
472 case FN_FORMAT_ALL_NOTES:
474 SwPostItMgr* pPostItMgr = GetView().GetPostItMgr();
475 if (pPostItMgr)
476 pPostItMgr->ExecuteFormatAllDialog(GetView());
478 break;
479 case FN_DELETE_NOTE_AUTHOR:
481 const SfxStringItem* pNoteItem = rReq.GetArg<SfxStringItem>(nSlot);
482 if (pNoteItem && GetView().GetPostItMgr()
483 && lcl_canUserModifyAnnotation(GetView(), pNoteItem->GetValue()))
484 GetView().GetPostItMgr()->Delete(pNoteItem->GetValue());
486 break;
487 case FN_HIDE_NOTE:
488 if ( GetView().GetPostItMgr() &&
489 GetView().GetPostItMgr()->HasActiveSidebarWin() )
491 GetView().GetPostItMgr()->HideActiveSidebarWin();
493 break;
494 case FN_HIDE_ALL_NOTES:
495 if ( GetView().GetPostItMgr() )
496 GetView().GetPostItMgr()->Hide();
497 break;
498 case FN_HIDE_NOTE_AUTHOR:
500 const SfxStringItem* pNoteItem = rReq.GetArg<SfxStringItem>(nSlot);
501 if ( pNoteItem && GetView().GetPostItMgr() )
502 GetView().GetPostItMgr()->Hide( pNoteItem->GetValue() );
504 break;
505 case FN_REPLY:
507 const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
508 if (pIdItem && !pIdItem->GetValue().isEmpty())
510 SwFieldType* pType = rSh.GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(), false);
511 if(pType->FindFormatForPostItId(pIdItem->GetValue().toUInt32()))
513 auto pMgr = GetView().GetPostItMgr();
514 auto pWin = pMgr->GetAnnotationWin(pIdItem->GetValue().toUInt32());
515 if(pWin)
517 if (const SvxPostItTextItem* pHtmlItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_HTML))
519 SwDocShell* pDocSh = GetView().GetDocShell();
520 Outliner aOutliner(&pDocSh->GetPool(), OutlinerMode::TextObject);
521 SwPostItHelper::ImportHTML(aOutliner, pHtmlItem->GetValue());
522 if (std::optional<OutlinerParaObject> oPara = aOutliner.CreateParaObject())
523 pMgr->RegisterAnswer(oPara.value());
526 OUString sText;
527 if(const auto pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT))
528 sText = pTextItem->GetValue();
529 pMgr->RegisterAnswerText(sText);
530 pWin->ExecuteCommand(nSlot);
535 break;
536 case FN_POSTIT:
538 rSh.InsertPostIt(aFieldMgr, rReq);
540 break;
541 case SID_EDIT_POSTIT:
543 const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
544 if (pIdItem && !pIdItem->GetValue().isEmpty())
546 sw::annotation::SwAnnotationWin* pAnnotationWin = GetView().GetPostItMgr()->GetAnnotationWin(pIdItem->GetValue().toUInt32());
547 if (pAnnotationWin && lcl_canUserModifyAnnotation(GetView(), pAnnotationWin))
549 if (const SvxPostItTextItem* pHtmlItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_HTML))
550 pAnnotationWin->UpdateHTML(pHtmlItem->GetValue());
551 else
553 const SvxPostItTextItem* pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT);
554 OUString sText;
555 if (pTextItem)
556 sText = pTextItem->GetValue();
557 pAnnotationWin->UpdateText(sText);
560 // explicit state update to get the Undo state right
561 GetView().AttrChangedNotify(nullptr);
565 break;
566 case FN_PROMOTE_COMMENT:
568 const SvxPostItIdItem* pIdItem = rReq.GetArg<SvxPostItIdItem>(SID_ATTR_POSTIT_ID);
569 if (pIdItem && !pIdItem->GetValue().isEmpty() && GetView().GetPostItMgr())
571 GetView().GetPostItMgr()->PromoteToRoot(pIdItem->GetValue().toUInt32());
573 break;
575 case FN_REDLINE_COMMENT:
577 const SwRangeRedline *pRedline = rSh.GetCurrRedline();
578 SwDoc *pDoc = rSh.GetDoc();
579 // If index is specified, goto and select the appropriate redline
580 if (pArgs && pArgs->GetItemState(nSlot, false, &pItem) == SfxItemState::SET)
582 const sal_uInt32 nChangeId = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
583 const SwRedlineTable& rRedlineTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
584 for (SwRedlineTable::size_type nRedline = 0; nRedline < rRedlineTable.size(); ++nRedline)
586 if (nChangeId == rRedlineTable[nRedline]->GetId())
587 pRedline = rSh.GotoRedline(nRedline, true);
591 OUString sCommentText;
592 const SfxStringItem* pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT);
593 if (pTextItem)
594 sCommentText = pTextItem->GetValue();
596 if (pRedline)
598 // In case of LOK and comment text is already provided, skip
599 // dialog creation and just change the redline comment directly
600 if (comphelper::LibreOfficeKit::isActive() && !sCommentText.isEmpty())
602 rSh.SetRedlineComment(sCommentText);
603 GetView().AttrChangedNotify(nullptr);
604 MaybeNotifyRedlineModification(const_cast<SwRangeRedline&>(*pRedline), pRedline->GetDoc());
605 break;
608 OUString sComment = convertLineEnd(pRedline->GetComment(), GetSystemLineEnd());
610 bool bTravel = false;
612 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
613 ::DialogGetRanges fnGetRange = pFact->GetDialogGetRangesFunc();
614 SfxItemSet aSet(GetPool(), fnGetRange());
615 aSet.Put(SvxPostItTextItem(sComment, SID_ATTR_POSTIT_TEXT));
616 aSet.Put(SvxPostItAuthorItem(pRedline->GetAuthorString(), SID_ATTR_POSTIT_AUTHOR));
618 aSet.Put( SvxPostItDateItem( GetAppLangDateTimeString(
619 pRedline->GetRedlineData().GetTimeStamp() ),
620 SID_ATTR_POSTIT_DATE ));
622 // Traveling only if more than one field.
623 rSh.StartAction();
625 rSh.Push();
626 const SwRangeRedline *pActRed = rSh.SelPrevRedline();
628 if (pActRed == pRedline)
629 { // New cursor is at the beginning of the current redlines.
630 rSh.Pop(); // Throw old cursor away
631 rSh.Push();
632 pActRed = rSh.SelPrevRedline();
635 bool bPrev = pActRed != nullptr;
636 rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
637 rSh.EndAction();
639 rSh.ClearMark();
640 // Select current redline.
641 pActRed = rSh.SelNextRedline();
642 if (pActRed != pRedline)
643 rSh.SelPrevRedline();
645 rSh.StartAction();
646 rSh.Push();
647 pActRed = rSh.SelNextRedline();
648 bool bNext = pActRed != nullptr;
649 rSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore cursor position
651 if( rSh.IsCursorPtAtEnd() )
652 rSh.SwapPam();
654 rSh.EndAction();
656 bTravel |= bNext || bPrev;
658 SvxAbstractDialogFactory* pFact2 = SvxAbstractDialogFactory::Create();
659 ScopedVclPtr<AbstractSvxPostItDialog> pDlg(pFact2->CreateSvxPostItDialog(GetView().GetFrameWeld(), aSet, bTravel));
660 pDlg->HideAuthor();
662 pDlg->SetText(lcl_BuildTitleWithRedline(pRedline));
664 if (bTravel)
666 pDlg->EnableTravel(bNext, bPrev);
667 pDlg->SetPrevHdl(LINK(this, SwTextShell, RedlinePrevHdl));
668 pDlg->SetNextHdl(LINK(this, SwTextShell, RedlineNextHdl));
671 SwViewShell::SetCareDialog(pDlg->GetDialog());
672 g_bNoInterrupt = true;
674 if ( pDlg->Execute() == RET_OK )
676 const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
677 OUString sMsg(pOutSet->Get(SID_ATTR_POSTIT_TEXT).GetValue());
679 // Insert or change a comment
680 rSh.SetRedlineComment(sMsg);
683 SwViewShell::SetCareDialog(nullptr);
684 pDlg.disposeAndClear();
685 g_bNoInterrupt = false;
686 rSh.ClearMark();
687 GetView().AttrChangedNotify(nullptr);
690 break;
692 case FN_JAVAEDIT:
694 OUString aType, aText;
695 bool bIsUrl=false;
696 bool bNew=false;
697 bool bUpdate = false;
698 SwFieldMgr aMgr;
699 if ( pItem )
701 aText = static_cast<const SfxStringItem*>(pItem)->GetValue();
702 const SfxStringItem* pType = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
703 const SfxBoolItem* pIsUrl = rReq.GetArg<SfxBoolItem>(FN_PARAM_1);
704 if ( pType )
705 aType = pType->GetValue();
706 if ( pIsUrl )
707 bIsUrl = pIsUrl->GetValue();
709 SwScriptField* pField = static_cast<SwScriptField*>(aMgr.GetCurField());
710 bNew = !pField || (pField->GetTyp()->Which() != SwFieldIds::Script);
711 bUpdate = pField && ( bIsUrl != static_cast<bool>(pField->GetFormat()) || pField->GetPar2() != aType || pField->GetPar1() != aText );
713 else
715 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
716 ScopedVclPtr<AbstractJavaEditDialog> pDlg(pFact->CreateJavaEditDialog(GetView().GetFrameWeld(), &rSh));
717 if ( pDlg->Execute() )
719 aType = pDlg->GetScriptType();
720 aText = pDlg->GetScriptText();
721 bIsUrl = pDlg->IsUrl();
722 bNew = pDlg->IsNew();
723 bUpdate = pDlg->IsUpdate();
724 rReq.AppendItem( SfxStringItem( FN_JAVAEDIT, aText ) );
725 rReq.AppendItem( SfxStringItem( FN_PARAM_2, aType ) );
726 rReq.AppendItem( SfxBoolItem( FN_PARAM_1, bIsUrl ) );
730 if( bNew )
732 SwInsertField_Data aData(SwFieldTypesEnum::Script, 0, aType, aText, bIsUrl ? 1 : 0);
733 aMgr.InsertField(aData);
734 rReq.Done();
736 else if( bUpdate )
738 aMgr.UpdateCurField( bIsUrl ? 1 : 0, aType, aText );
739 rSh.SetUndoNoResetModified();
740 rReq.Done();
742 else
743 rReq.Ignore();
745 break;
747 case FN_INSERT_FLD_DATE :
748 case FN_INSERT_FLD_DATE_VAR:
750 nInsertType = SwFieldTypesEnum::Date;
751 nInsertSubType = nSlot == FN_INSERT_FLD_DATE ? 0 : 1;
752 bIsText = false;
753 // use long date format for Hungarian
754 SwPaM* pCursorPos = rSh.GetCursor();
755 if( pCursorPos )
757 LanguageType nLang = pCursorPos->GetPoint()->GetNode().GetTextNode()->GetLang(pCursorPos->GetPoint()->GetContentIndex());
758 if (nLang == LANGUAGE_HUNGARIAN)
759 nInsertFormat = rSh.GetNumberFormatter()->GetFormatIndex(NF_DATE_SYSTEM_LONG, nLang);
761 goto FIELD_INSERT;
763 case FN_INSERT_FLD_TIME :
764 case FN_INSERT_FLD_TIME_VAR:
765 nInsertType = SwFieldTypesEnum::Time;
766 nInsertSubType = nSlot == FN_INSERT_FLD_TIME ? 0 : 1;
767 bIsText = false;
768 goto FIELD_INSERT;
769 case FN_INSERT_FLD_PGNUMBER:
770 nInsertType = SwFieldTypesEnum::PageNumber;
771 nInsertFormat = SVX_NUM_PAGEDESC; // Like page template
772 bIsText = false;
773 goto FIELD_INSERT;
774 case FN_INSERT_FLD_PGCOUNT :
775 nInsertType = SwFieldTypesEnum::DocumentStatistics;
776 nInsertSubType = 0;
777 bIsText = false;
778 nInsertFormat = SVX_NUM_PAGEDESC;
779 goto FIELD_INSERT;
780 case FN_INSERT_FLD_TOPIC :
781 nInsertType = SwFieldTypesEnum::DocumentInfo;
782 nInsertSubType = DI_SUBJECT;
783 goto FIELD_INSERT;
784 case FN_INSERT_FLD_TITLE :
785 nInsertType = SwFieldTypesEnum::DocumentInfo;
786 nInsertSubType = DI_TITLE;
787 goto FIELD_INSERT;
788 case FN_INSERT_FLD_AUTHOR :
789 nInsertType = SwFieldTypesEnum::DocumentInfo;
790 nInsertSubType = DI_CREATE|DI_SUB_AUTHOR;
792 FIELD_INSERT:
794 //format conversion should only be done for number formatter formats
795 if(!nInsertFormat)
796 nInsertFormat = aFieldMgr.GetDefaultFormat(nInsertType, bIsText, rSh.GetNumberFormatter());
797 SwInsertField_Data aData(nInsertType, nInsertSubType,
798 OUString(), OUString(), nInsertFormat);
799 aFieldMgr.InsertField(aData);
800 rReq.Done();
802 break;
804 case FN_INSERT_TEXT_FORMFIELD:
806 OUString aFieldType(ODF_FORMTEXT);
807 const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
808 if (pFieldType)
810 // Allow overwriting the default type.
811 aFieldType = pFieldType->GetValue();
814 OUString aFieldCode;
815 const SfxStringItem* pFieldCode = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
816 if (pFieldCode)
818 // Allow specifying a field code/command.
819 aFieldCode = pFieldCode->GetValue();
822 if (rSh.HasReadonlySel())
824 // Inform the user that the request has been ignored.
825 auto xInfo = std::make_shared<weld::GenericDialogController>(
826 GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui",
827 "InfoReadonlyDialog");
828 weld::DialogController::runAsync(xInfo, [](sal_Int32 /*nResult*/) {});
829 break;
832 rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
834 SwPaM* pCursorPos = rSh.GetCursor();
835 if(pCursorPos)
837 // Insert five En Space into the text field so the field has extent
838 OUString aFieldResult(vEnSpaces);
839 const SfxStringItem* pFieldResult = rReq.GetArg<SfxStringItem>(FN_PARAM_3);
840 if (pFieldResult)
842 // Allow specifying a field result / expanded value.
843 aFieldResult = pFieldResult->GetValue();
846 const SfxStringItem* pWrapper = rReq.GetArg<SfxStringItem>(FN_PARAM_4);
847 if (pWrapper)
849 // Wrap the fieldmark in the requested container instead of inserting it
850 // directly at the cursor position.
851 OUString aWrapper = pWrapper->GetValue();
852 if (aWrapper == "Footnote")
854 rSh.InsertFootnote(OUString());
856 else if (aWrapper == "Endnote")
858 // It's important that there is no Start/EndAction() around this, so the
859 // inner EndAction() triggers a layout update and the cursor can jump to the
860 // created SwFootnoteFrame.
861 rSh.InsertFootnote(OUString(), /*bEndNote=*/true);
865 // Don't update the layout after inserting content and before deleting temporary
866 // text nodes.
867 rSh.StartAction();
869 // Split node to remember where the start position is.
870 bool bSuccess = rSh.GetDoc()->getIDocumentContentOperations().SplitNode(
871 *pCursorPos->GetPoint(), false);
872 if(bSuccess)
874 SwPaM aFieldPam(*pCursorPos->GetPoint());
875 aFieldPam.Move(fnMoveBackward, GoInContent);
876 if (pFieldResult)
878 // Paste HTML content.
879 SwTranslateHelper::PasteHTMLToPaM(rSh, pCursorPos, aFieldResult.toUtf8());
880 if (pCursorPos->GetPoint()->GetContentIndex() == 0)
882 // The paste created a last empty text node, remove it.
883 SwPaM aPam(*pCursorPos->GetPoint());
884 aPam.SetMark();
885 aPam.Move(fnMoveBackward, GoInContent);
886 rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPam);
889 else
891 // Insert default placeholder.
892 rSh.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos,
893 aFieldResult);
895 // Undo the above SplitNode().
896 aFieldPam.SetMark();
897 aFieldPam.Move(fnMoveForward, GoInContent);
898 rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aFieldPam);
899 *aFieldPam.GetMark() = *pCursorPos->GetPoint();
901 IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
902 sw::mark::Fieldmark* pFieldmark = pMarksAccess->makeFieldBookmark(
903 aFieldPam, OUString(), aFieldType, aFieldPam.Start());
904 if (pFieldmark && !aFieldCode.isEmpty())
906 pFieldmark->GetParameters()->insert(
907 std::pair<OUString, uno::Any>(ODF_CODE_PARAM, uno::Any(aFieldCode)));
910 rSh.EndAction();
913 rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
914 rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO );
916 break;
917 case FN_INSERT_CHECKBOX_FORMFIELD:
919 rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
921 SwPaM* pCursorPos = rSh.GetCursor();
922 if(pCursorPos)
924 IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
925 pMarksAccess->makeNoTextFieldBookmark(*pCursorPos, OUString(), ODF_FORMCHECKBOX);
928 rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
929 rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO );
931 break;
932 case FN_INSERT_DROPDOWN_FORMFIELD:
934 rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
936 SwPaM* pCursorPos = rSh.GetCursor();
937 if(pCursorPos)
939 IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
940 pMarksAccess->makeNoTextFieldBookmark(*pCursorPos, OUString(), ODF_FORMDROPDOWN);
943 rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
944 rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO );
946 break;
947 case FN_INSERT_DATE_FORMFIELD:
949 rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
951 SwPaM* pCursorPos = rSh.GetCursor();
952 if(pCursorPos)
954 // Insert five enspaces into the text field so the field has extent
955 bool bSuccess = rSh.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos, vEnSpaces);
956 if(bSuccess)
958 IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
959 SwPaM aFieldPam(pCursorPos->GetPoint()->GetNode(), pCursorPos->GetPoint()->GetContentIndex() - ODF_FORMFIELD_DEFAULT_LENGTH,
960 pCursorPos->GetPoint()->GetNode(), pCursorPos->GetPoint()->GetContentIndex());
961 sw::mark::Fieldmark* pFieldBM = pMarksAccess->makeFieldBookmark(aFieldPam, OUString(), ODF_FORMDATE,
962 aFieldPam.Start());
964 // Use a default date format and language
965 sw::mark::Fieldmark::parameter_map_t* pParameters = pFieldBM->GetParameters();
966 SvNumberFormatter* pFormatter = rSh.GetDoc()->GetNumberFormatter();
967 sal_uInt32 nStandardFormat = pFormatter->GetStandardFormat(SvNumFormatType::DATE);
968 const SvNumberformat* pFormat = pFormatter->GetEntry(nStandardFormat);
970 (*pParameters)[ODF_FORMDATE_DATEFORMAT] <<= pFormat->GetFormatstring();
971 (*pParameters)[ODF_FORMDATE_DATEFORMAT_LANGUAGE] <<= LanguageTag(pFormat->GetLanguage()).getBcp47();
975 rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
976 rSh.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO );
978 break;
979 case FN_UPDATE_TEXT_FORMFIELDS:
981 // This updates multiple fieldmarks in a document, based on their field name & field command
982 // prefix.
983 OUString aFieldType;
984 const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
985 if (pFieldType)
987 aFieldType = pFieldType->GetValue();
989 OUString aFieldCommandPrefix;
990 const SfxStringItem* pFieldCommandPrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
991 if (pFieldCommandPrefix)
993 aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
995 uno::Sequence<beans::PropertyValues> aFields;
996 const SfxUnoAnyItem* pFields = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
997 if (pFields)
999 pFields->GetValue() >>= aFields;
1002 rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::UPDATE_FORM_FIELDS, nullptr);
1003 rSh.StartAction();
1005 IDocumentMarkAccess* pMarkAccess = rSh.GetDoc()->getIDocumentMarkAccess();
1006 sal_Int32 nFieldIndex = 0;
1007 for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
1009 sw::mark::Fieldmark* pFieldmark = *it;
1010 assert(pFieldmark);
1011 if (pFieldmark->GetFieldname() != aFieldType)
1013 continue;
1016 auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
1017 if (itParam == pFieldmark->GetParameters()->end())
1019 continue;
1022 OUString aCommand;
1023 itParam->second >>= aCommand;
1024 if (!aCommand.startsWith(aFieldCommandPrefix))
1026 continue;
1029 if (aFields.getLength() <= nFieldIndex)
1031 continue;
1034 comphelper::SequenceAsHashMap aMap(aFields[nFieldIndex++]);
1035 itParam->second = aMap[u"FieldCommand"_ustr];
1036 SwPaM aPaM(pFieldmark->GetMarkPos(), pFieldmark->GetOtherMarkPos());
1037 aPaM.Normalize();
1038 // Skip field start & separator.
1039 aPaM.GetPoint()->AdjustContent(2);
1040 // Skip field end.
1041 aPaM.GetMark()->AdjustContent(-1);
1042 rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPaM);
1043 OUString aFieldResult;
1044 aMap[u"FieldResult"_ustr] >>= aFieldResult;
1045 SwTranslateHelper::PasteHTMLToPaM(rSh, &aPaM, aFieldResult.toUtf8());
1048 rSh.EndAction();
1049 rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::UPDATE_FORM_FIELDS, nullptr);
1051 break;
1052 case FN_DELETE_TEXT_FORMFIELDS:
1054 // This deletes all fieldmarks that match the provided field type & field command prefix.
1055 OUString aFieldType;
1056 const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
1057 if (pFieldType)
1059 aFieldType = pFieldType->GetValue();
1061 OUString aFieldCommandPrefix;
1062 const SfxStringItem* pFieldCommandPrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
1063 if (pFieldCommandPrefix)
1065 aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
1067 rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELETE_FORM_FIELDS, nullptr);
1068 rSh.StartAction();
1070 IDocumentMarkAccess* pMarkAccess = rSh.GetDoc()->getIDocumentMarkAccess();
1071 std::vector<sw::mark::MarkBase*> aRemovals;
1072 for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
1074 sw::mark::Fieldmark* pFieldmark = *it;
1075 assert(pFieldmark);
1076 if (pFieldmark->GetFieldname() != aFieldType)
1078 continue;
1081 if (!aFieldCommandPrefix.isEmpty())
1083 auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
1084 if (itParam == pFieldmark->GetParameters()->end())
1086 continue;
1089 OUString aCommand;
1090 itParam->second >>= aCommand;
1091 if (!aCommand.startsWith(aFieldCommandPrefix))
1093 continue;
1097 aRemovals.push_back(pFieldmark);
1100 for (const auto& pMark : aRemovals)
1102 pMarkAccess->deleteMark(pMark);
1105 rSh.EndAction();
1106 rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELETE_FORM_FIELDS, nullptr);
1108 break;
1109 case FN_PGNUMBER_WIZARD:
1111 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
1112 VclPtr<AbstractSwPageNumberDlg> pDlg(
1113 pFact->CreateSwPageNumberDlg(GetView().GetFrameWeld()));
1114 auto pShell = GetShellPtr();
1116 const SwPageDesc& rCurrDesc = rSh.GetPageDesc(rSh.GetCurPageDesc());
1117 pDlg->SetPageNumberType(rCurrDesc.GetNumType().GetNumberingType());
1119 pDlg->StartExecuteAsync([pShell, &rSh, pDlg](int nResult) {
1120 if ( nResult == RET_OK )
1122 auto& rDoc = *rSh.GetDoc();
1124 rSh.LockView(true);
1125 rSh.StartAllAction();
1126 rSh.SwCursorShell::Push();
1127 rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_PAGE_NUMBER, nullptr);
1129 const size_t nPageDescIndex = rSh.GetCurPageDesc();
1130 const SwPageDesc& rDesc = rSh.GetPageDesc(nPageDescIndex);
1131 const bool bHeader = !pDlg->GetPageNumberPosition();
1132 const bool bHeaderAlreadyOn = rDesc.GetMaster().GetHeader().IsActive();
1133 const bool bFooterAlreadyOn = rDesc.GetMaster().GetFooter().IsActive();
1134 const bool bIsSinglePage = rDesc.GetFollow() != &rDesc;
1135 const size_t nMirrorPagesNeeded = rDesc.IsFirstShared() ? 2 : 3;
1136 const OUString sBookmarkName = OUString::Concat("PageNumWizard_")
1137 + (bHeader ? "HEADER" : "FOOTER") + "_" + rDesc.GetName()
1138 + OUString::number(rSh.GetVirtPageNum());
1139 IDocumentMarkAccess& rIDMA = *rSh.getIDocumentMarkAccess();
1141 // Allow wizard to be re-run: delete previously wizard-inserted page number.
1142 // Try before creating non-shared header: avoid copying ODD bookmark onto EVEN page.
1143 auto ppMark = rIDMA.findMark(sBookmarkName);
1144 if (ppMark != rIDMA.getAllMarksEnd() && *ppMark)
1146 SwPaM aDeleteOldPageNum((*ppMark)->GetMarkStart(), (*ppMark)->GetMarkEnd());
1147 rDoc.getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum);
1150 SwPageDesc aNewDesc(rDesc);
1151 bool bChangePageDesc = false;
1152 if (pDlg->GetPageNumberType() != aNewDesc.GetNumType().GetNumberingType())
1154 bChangePageDesc = true;
1155 SvxNumberType aNewType(rDesc.GetNumType());
1156 aNewType.SetNumberingType(pDlg->GetPageNumberType());
1157 aNewDesc.SetNumType(aNewType);
1160 // Insert header/footer
1161 if ((bHeader && !bHeaderAlreadyOn) || (!bHeader && !bFooterAlreadyOn))
1163 bChangePageDesc = true;
1164 SwFrameFormat &rMaster = aNewDesc.GetMaster();
1165 if (bHeader)
1166 rMaster.SetFormatAttr(SwFormatHeader(/*On=*/true));
1167 else
1168 rMaster.SetFormatAttr(SwFormatFooter(/*On=*/true));
1170 // Init copied from ChangeHeaderOrFooter: keep in sync
1171 constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm);
1172 const SvxULSpaceItem aUL(bHeader ? 0 : constTwips_5mm,
1173 bHeader ? constTwips_5mm : 0,
1174 RES_UL_SPACE);
1175 const XFillStyleItem aFill(drawing::FillStyle_NONE);
1176 SwFrameFormat& rFormat
1177 = bHeader
1178 ? const_cast<SwFrameFormat&>(*rMaster.GetHeader().GetHeaderFormat())
1179 : const_cast<SwFrameFormat&>(*rMaster.GetFooter().GetFooterFormat());
1180 rFormat.SetFormatAttr(aUL);
1181 rFormat.SetFormatAttr(aFill);
1183 if (pDlg->GetFitIntoExistingMargins())
1185 SvxULSpaceItem aPageUL(aNewDesc.GetMaster().GetULSpace());
1186 tools::Long nPageMargin = bHeader ? aPageUL.GetUpper() : aPageUL.GetLower();
1188 // most printers can't print to paper edge - use arbitrary ~14pt as minimum
1189 if (nPageMargin > constTwips_5mm)
1191 // reduce existing margin by the "Spacing"
1192 nPageMargin -= constTwips_5mm;
1194 // also reduce by the "Height" (as calculated from the font)
1195 tools::Long nFontHeight = constTwips_5mm; // appropriate for 12pt font
1196 const OutputDevice* pOutDev = Application::GetDefaultDevice();
1197 const SwViewShell* pViewSh
1198 = rDoc.getIDocumentLayoutAccess().GetCurrentViewShell();
1199 OUString sParaStyle(bHeader ? "Header" : "Footer");
1200 SwTextFormatColl* pStyle = rDoc.FindTextFormatCollByName(sParaStyle);
1201 if (pStyle && pOutDev)
1203 SwFont aFont(
1204 &pStyle->GetAttrSet(), /*IDocumentSettingAccess=*/nullptr);
1206 // sledgehammer approach: since the in-use-font (Latin/CTL/CKJ)
1207 // is not known, use the tallest of the three just to ensure fit.
1208 sal_uInt16 nHeight = aFont.GetHeight(pViewSh, *pOutDev); // Latin
1210 aFont.SetActual(SwFontScript::CTL);
1211 nHeight = std::max(nHeight, aFont.GetHeight(pViewSh, *pOutDev));
1213 aFont.SetActual(SwFontScript::CJK);
1214 nFontHeight = std::max(nHeight, aFont.GetHeight(pViewSh, *pOutDev));
1216 // Spacing: above and below paragraph
1217 const SvxULSpaceItem& rParaStyleUL = pStyle->GetULSpace();
1218 nFontHeight += rParaStyleUL.GetUpper() + rParaStyleUL.GetLower();
1220 // Border padding: top and bottom
1221 const SvxBoxItem rBorders = pStyle->GetBox();
1222 nFontHeight += rBorders.CalcLineSpace(SvxBoxItemLine::TOP, true);
1223 nFontHeight += rBorders.CalcLineSpace(SvxBoxItemLine::BOTTOM, true);
1225 nPageMargin -= nFontHeight;
1227 nPageMargin = std::max(nPageMargin, constTwips_5mm);
1228 if (bHeader)
1229 aPageUL.SetUpper(nPageMargin);
1230 else
1231 aPageUL.SetLower(nPageMargin);
1232 aNewDesc.GetMaster().SetFormatAttr(aPageUL);
1234 // force aggressively calculated font height as minimum to ensure
1235 // effective margin stays the same (instead of getting smaller)
1236 SwFormatFrameSize aSize(rFormat.GetFrameSize());
1237 aSize.SetHeightSizeType(SwFrameSize::Minimum);
1238 // frame size property includes both Spacing + Height
1239 aSize.SetHeight(constTwips_5mm + nFontHeight);
1240 rFormat.SetFormatAttr(aSize);
1242 // in case the calculated font height isn't actually large enough,
1243 // eat into spacing first before pushing into the content area.
1244 rFormat.SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
1245 RES_HEADER_FOOTER_EAT_SPACING, true));
1249 // Might as well turn on margin mirroring too - if appropriate
1250 if (pDlg->GetMirrorOnEvenPages() && !bHeaderAlreadyOn && !bFooterAlreadyOn
1251 && !bIsSinglePage
1252 && (aNewDesc.ReadUseOn() & UseOnPage::Mirror) == UseOnPage::All)
1254 aNewDesc.WriteUseOn(rDesc.ReadUseOn() | UseOnPage::Mirror);
1258 const bool bCreateMirror = !bIsSinglePage && pDlg->GetMirrorOnEvenPages()
1259 && nMirrorPagesNeeded <= rSh.GetPageCnt();
1260 if (bCreateMirror)
1262 // Use different left/right header/footer
1263 if ((bHeader && rDesc.IsHeaderShared()) || (!bHeader && rDesc.IsFooterShared()))
1265 bChangePageDesc = true;
1266 if (bHeader)
1267 aNewDesc.ChgHeaderShare(/*Share=*/false);
1268 else
1269 aNewDesc.ChgFooterShare(/*Share=*/false);
1273 if (bChangePageDesc)
1274 rSh.ChgPageDesc(nPageDescIndex, aNewDesc);
1276 // Go to the header or footer insert position
1277 bool bInHF = false;
1278 bool bSkipMirror = true;
1279 size_t nEvenPage = 0;
1280 if (bCreateMirror || !rSh.GetCurrFrame())
1282 // Come here if Currframe can't be found, otherwise Goto*Text will crash.
1283 // Get*PageNum will also be invalid (0), so we have no idea where we are.
1284 // (Since not asking for mirror, the likelihood is that the bHeader is shared,
1285 // in which case it doesn't matter anyway, and we just hope for the best.)
1286 // Read the code in this block assuming that bCreateMirror is true.
1288 // There are enough pages that there probably is a valid odd page.
1289 // However, that is not guaranteed: perhaps the page style switched,
1290 // or a blank page was forced, or some other complexity.
1291 bInHF = rSh.SetCursorInHdFt(nPageDescIndex, bHeader, /*Even=*/true);
1292 if (bInHF)
1294 // Remember valid EVEN page. Mirror it if also a valid ODD or FIRST page
1295 nEvenPage = rSh.GetVirtPageNum();
1296 assert (nEvenPage && "couldn't find page number. Use a bool instead");
1299 bInHF = rSh.SetCursorInHdFt(nPageDescIndex, bHeader, /*Even=*/false);
1300 if (bInHF && nEvenPage)
1302 // Even though the cursor may be on a FIRST page,
1303 // the user requested mirrored pages, and we have both ODD and EVEN,
1304 // so set page numbers on these two pages, and leave FIRST alone.
1305 bSkipMirror = false;
1307 if (!bInHF)
1309 // no ODD page, look for FIRST page
1310 bInHF = rSh.SetCursorInHdFt(nPageDescIndex, bHeader, false, /*First=*/true);
1311 if (bInHF && nEvenPage)
1313 // Unlikely but valid situation: EVEN and FIRST pages, but no ODD page.
1314 // In this case, the first header gets the specified page number
1315 // and the even header is mirrored, with an empty odd header,
1316 // as the user (somewhat) requested.
1317 bSkipMirror = false;
1320 assert((bInHF || nEvenPage) && "Impossible - why couldn't the move happen?");
1321 assert((bInHF || nEvenPage == rSh.GetVirtPageNum()) && "Unexpected move");
1323 else
1325 if (bHeader)
1326 bInHF = rSh.GotoHeaderText();
1327 else
1328 bInHF = rSh.GotoFooterText();
1329 assert(bInHF && "shouldn't have a problem going to text when no mirroring");
1332 // Allow wizard to be re-run: delete previously wizard-inserted page number.
1333 // Now that the cursor may have moved to a different page, try delete again.
1334 ppMark = rIDMA.findMark(sBookmarkName);
1335 if (ppMark != rIDMA.getAllMarksEnd() && *ppMark)
1337 SwPaM aDeleteOldPageNum((*ppMark)->GetMarkStart(), (*ppMark)->GetMarkEnd());
1338 rDoc.getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum);
1341 SwTextNode* pTextNode = rSh.GetCursor()->GetPoint()->GetNode().GetTextNode();
1343 // Insert new line if there is already text in header/footer
1344 if (pTextNode && !pTextNode->GetText().isEmpty())
1346 rDoc.getIDocumentContentOperations().SplitNode(*rSh.GetCursor()->GetPoint(), false);
1348 // Go back to start of header/footer
1349 if (bHeader)
1350 rSh.GotoHeaderText();
1351 else
1352 rSh.GotoFooterText();
1355 // Set alignment for the new line
1356 switch (pDlg->GetPageNumberAlignment())
1358 case 0:
1360 SvxAdjustItem aAdjustItem(SvxAdjust::Left, RES_PARATR_ADJUST);
1361 rSh.SetAttrItem(aAdjustItem);
1362 break;
1364 case 1:
1366 SvxAdjustItem aAdjustItem(SvxAdjust::Center, RES_PARATR_ADJUST);
1367 rSh.SetAttrItem(aAdjustItem);
1368 break;
1370 case 2:
1372 SvxAdjustItem aAdjustItem(SvxAdjust::Right, RES_PARATR_ADJUST);
1373 rSh.SetAttrItem(aAdjustItem);
1374 break;
1378 sal_Int32 nStartContentIndex = rSh.GetCursor()->Start()->GetContentIndex();
1379 assert(!nStartContentIndex && "earlier split node if not empty, but not zero?");
1381 // Insert page number
1382 SwFieldMgr aMgr(pShell);
1383 SwInsertField_Data aData(SwFieldTypesEnum::PageNumber, 0,
1384 OUString(), OUString(), SVX_NUM_PAGEDESC);
1385 aMgr.InsertField(aData);
1386 if (pDlg->GetIncludePageTotal())
1388 rDoc.getIDocumentContentOperations().InsertString(*rSh.GetCursor(), u" / "_ustr);
1389 SwInsertField_Data aPageTotalData(SwFieldTypesEnum::DocumentStatistics, DS_PAGE,
1390 OUString(), OUString(), SVX_NUM_PAGEDESC);
1391 aMgr.InsertField(aPageTotalData);
1394 // Mark inserted fields with a bookmark - so it can be found/removed if re-run
1395 SwPaM aNewBookmarkPaM(*rSh.GetCursor()->Start());
1396 aNewBookmarkPaM.SetMark();
1397 assert(aNewBookmarkPaM.GetPointContentNode() && "only SetContent on content node");
1398 aNewBookmarkPaM.Start()->SetContent(nStartContentIndex);
1399 sw::mark::MarkBase* pNewMark = rIDMA.makeMark(aNewBookmarkPaM,
1400 sBookmarkName,
1401 IDocumentMarkAccess::MarkType::BOOKMARK,
1402 sw::mark::InsertMode::New);
1404 // Mirror on the even pages
1405 if (!bSkipMirror && bCreateMirror
1406 && rSh.SetCursorInHdFt(nPageDescIndex, bHeader, /*Even=*/true))
1408 assert(nEvenPage && "what? no even page and yet we got here?");
1409 if (pNewMark)
1411 SwPaM aDeleteOldPageNum(pNewMark->GetMarkStart(), pNewMark->GetMarkEnd());
1412 rDoc.getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum);
1415 pTextNode = rSh.GetCursor()->GetPoint()->GetNode().GetTextNode();
1417 // Insert new line if there is already text in header/footer
1418 if (pTextNode && !pTextNode->GetText().isEmpty())
1420 rDoc.getIDocumentContentOperations().SplitNode(
1421 *rSh.GetCursor()->GetPoint(), false);
1422 // Go back to start of header/footer
1423 rSh.SetCursorInHdFt(nPageDescIndex, bHeader, /*Even=*/true);
1426 // mirror the adjustment
1427 assert(pDlg->GetPageNumberAlignment() != 1 && "cannot have Center and bMirror");
1428 SvxAdjust eAdjust = SvxAdjust::Left;
1429 if (!pDlg->GetPageNumberAlignment())
1430 eAdjust = SvxAdjust::Right;
1431 SvxAdjustItem aMirrorAdjustItem(eAdjust, RES_PARATR_ADJUST);
1432 rSh.SetAttrItem(aMirrorAdjustItem);
1434 nStartContentIndex = rSh.GetCursor()->Start()->GetContentIndex();
1436 // Insert page number
1437 SwFieldMgr aEvenMgr(pShell);
1438 aEvenMgr.InsertField(aData);
1439 if (pDlg->GetIncludePageTotal())
1441 rDoc.getIDocumentContentOperations().InsertString(*rSh.GetCursor(), u" / "_ustr);
1442 SwInsertField_Data aPageTotalData(SwFieldTypesEnum::DocumentStatistics,
1443 DS_PAGE, OUString(), OUString(),
1444 SVX_NUM_PAGEDESC);
1445 aMgr.InsertField(aPageTotalData);
1448 // Mark inserted fields with a bookmark - so it can be found/removed if re-run
1449 SwPaM aNewEvenBookmarkPaM(*rSh.GetCursor()->Start());
1450 aNewEvenBookmarkPaM.SetMark();
1451 aNewEvenBookmarkPaM.Start()->SetContent(nStartContentIndex);
1452 rIDMA.makeMark(aNewEvenBookmarkPaM,
1453 sBookmarkName,
1454 IDocumentMarkAccess::MarkType::BOOKMARK,
1455 sw::mark::InsertMode::New);
1458 rSh.SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
1459 rSh.EndAllAction();
1460 rSh.LockView(false);
1461 rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_PAGE_NUMBER, nullptr);
1463 pDlg->disposeOnce();
1465 rReq.Done();
1467 break;
1468 case FN_UPDATE_TEXT_FORMFIELD:
1470 // This updates a single fieldmark under the current cursor.
1471 OUString aFieldType;
1472 const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
1473 if (pFieldType)
1475 aFieldType = pFieldType->GetValue();
1477 OUString aFieldCommandPrefix;
1478 const SfxStringItem* pFieldCommandPrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
1479 if (pFieldCommandPrefix)
1481 aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
1483 uno::Sequence<beans::PropertyValue> aField;
1484 const SfxUnoAnyItem* pFields = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
1485 if (pFields)
1487 pFields->GetValue() >>= aField;
1490 IDocumentMarkAccess& rIDMA = *rSh.getIDocumentMarkAccess();
1491 SwPosition& rCursor = *rSh.GetCursor()->GetPoint();
1492 sw::mark::Fieldmark* pFieldmark = rIDMA.getInnerFieldmarkFor(rCursor);
1493 if (!pFieldmark)
1495 break;
1498 if (pFieldmark->GetFieldname() != aFieldType)
1500 break;
1503 auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
1504 if (itParam == pFieldmark->GetParameters()->end())
1506 break;
1509 OUString aCommand;
1510 itParam->second >>= aCommand;
1511 if (!aCommand.startsWith(aFieldCommandPrefix))
1513 break;
1516 rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::UPDATE_FORM_FIELD, nullptr);
1517 rSh.StartAction();
1518 comphelper::SequenceAsHashMap aMap(aField);
1519 itParam->second = aMap[u"FieldCommand"_ustr];
1520 SwPaM aPaM(pFieldmark->GetMarkPos(), pFieldmark->GetOtherMarkPos());
1521 aPaM.Normalize();
1522 // Skip field start & separator.
1523 aPaM.GetPoint()->AdjustContent(2);
1524 // Skip field end.
1525 aPaM.GetMark()->AdjustContent(-1);
1526 rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPaM);
1527 OUString aFieldResult;
1528 aMap[u"FieldResult"_ustr] >>= aFieldResult;
1529 SwTranslateHelper::PasteHTMLToPaM(rSh, &aPaM, aFieldResult.toUtf8());
1531 rSh.EndAction();
1532 rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::UPDATE_FORM_FIELD, nullptr);
1534 break;
1535 default:
1536 OSL_FAIL("wrong dispatcher");
1537 return;
1541 void SwTextShell::StateField( SfxItemSet &rSet )
1543 SwWrtShell& rSh = GetShell();
1544 SfxWhichIter aIter( rSet );
1545 const SwField* pField = nullptr;
1546 bool bGetField = false;
1547 sal_uInt16 nWhich = aIter.FirstWhich();
1549 while (nWhich)
1551 switch (nWhich)
1553 case FN_DELETE_COMMENT:
1554 case FN_DELETE_NOTE_AUTHOR:
1555 case FN_DELETE_ALL_NOTES:
1556 case FN_FORMAT_ALL_NOTES:
1557 case FN_HIDE_NOTE:
1558 case FN_HIDE_NOTE_AUTHOR:
1559 case FN_HIDE_ALL_NOTES:
1561 SwPostItMgr* pPostItMgr = GetView().GetPostItMgr();
1562 if ( !pPostItMgr )
1563 rSet.InvalidateItem( nWhich );
1564 else if ( !pPostItMgr->HasActiveSidebarWin() )
1566 rSet.InvalidateItem( FN_DELETE_COMMENT );
1567 rSet.InvalidateItem( FN_HIDE_NOTE );
1569 // tdf#137568 do not offer comment formatting, if no comments are present
1570 if (!pPostItMgr || !pPostItMgr->HasNotes())
1571 rSet.DisableItem( FN_FORMAT_ALL_NOTES );
1573 break;
1575 case FN_EDIT_FIELD:
1577 if( !bGetField )
1579 pField = rSh.GetCurField(true);
1580 bGetField = true;
1583 SwFieldIds nTempWhich = pField ? pField->GetTyp()->Which() : SwFieldIds::Unknown;
1584 if( SwFieldIds::Unknown == nTempWhich ||
1585 SwFieldIds::Postit == nTempWhich ||
1586 SwFieldIds::Script == nTempWhich ||
1587 SwFieldIds::TableOfAuthorities == nTempWhich )
1588 rSet.DisableItem( nWhich );
1589 else if( SwFieldIds::Dde == nTempWhich &&
1590 !static_cast<SwDDEFieldType*>(pField->GetTyp())->GetBaseLink().IsVisible())
1592 // nested links cannot be edited
1593 rSet.DisableItem( nWhich );
1596 break;
1598 case FN_UPDATE_SEL_FIELD:
1600 pField = rSh.GetCurField();
1602 if (!pField)
1603 rSet.DisableItem( nWhich );
1606 break;
1608 case FN_EXECUTE_MACROFIELD:
1610 if(!bGetField)
1612 pField = rSh.GetCurField();
1613 bGetField = true;
1615 if(!pField || pField->GetTyp()->Which() != SwFieldIds::Macro)
1616 rSet.DisableItem(nWhich);
1618 break;
1620 case FN_INSERT_FIELD:
1622 if ( rSh.CursorInsideInputField() )
1624 rSet.DisableItem(nWhich);
1626 else
1628 SfxViewFrame& rVFrame = GetView().GetViewFrame();
1629 //#i5788# prevent closing of the field dialog while a modal dialog ( Input field dialog ) is active
1630 if(!rVFrame.IsInModalMode() &&
1631 rVFrame.KnowsChildWindow(FN_INSERT_FIELD) && !rVFrame.HasChildWindow(FN_INSERT_FIELD_DATA_ONLY) )
1632 rSet.Put(SfxBoolItem( FN_INSERT_FIELD, rVFrame.HasChildWindow(nWhich)));
1633 else
1634 rSet.DisableItem(FN_INSERT_FIELD);
1637 break;
1639 case FN_INSERT_REF_FIELD:
1641 SfxViewFrame& rVFrame = GetView().GetViewFrame();
1642 if ( !rVFrame.KnowsChildWindow(FN_INSERT_FIELD)
1643 || rSh.CursorInsideInputField() )
1645 rSet.DisableItem(FN_INSERT_REF_FIELD);
1648 break;
1650 case FN_INSERT_FIELD_CTRL:
1651 if ( rSh.CursorInsideInputField() )
1653 rSet.DisableItem(nWhich);
1655 else
1657 rSet.Put(SfxBoolItem( nWhich, GetView().GetViewFrame().HasChildWindow(FN_INSERT_FIELD)));
1659 break;
1661 case FN_REDLINE_COMMENT:
1662 if (!comphelper::LibreOfficeKit::isActive() && !rSh.GetCurrRedline())
1663 rSet.DisableItem(nWhich);
1664 break;
1666 case FN_REPLY:
1667 if (!comphelper::LibreOfficeKit::isActive())
1668 rSet.DisableItem(nWhich);
1669 break;
1671 case FN_POSTIT :
1672 case FN_JAVAEDIT :
1674 bool bCurField = false;
1675 pField = rSh.GetCurField();
1676 if(nWhich == FN_POSTIT)
1677 bCurField = pField && pField->GetTyp()->Which() == SwFieldIds::Postit;
1678 else
1679 bCurField = pField && pField->GetTyp()->Which() == SwFieldIds::Script;
1681 if( !bCurField && rSh.IsReadOnlyAvailable() && rSh.HasReadonlySel() )
1683 rSet.DisableItem(nWhich);
1685 else if ( rSh.CursorInsideInputField() )
1687 rSet.DisableItem(nWhich);
1689 // tdf#86188, tdf#135794: Allow disabling comment insertion
1690 // on footnote/endnote/header/frames for better OOXML interoperability
1691 else if (!officecfg::Office::Compatibility::View::AllowCommentsInFootnotes::get() &&
1692 (rSh.IsCursorInFootnote() || rSh.IsInHeaderFooter() ||
1693 rSh.GetCurrFlyFrame(/*bCalcFrame=*/false)))
1695 rSet.DisableItem(nWhich);
1699 break;
1701 case FN_INSERT_FLD_AUTHOR:
1702 case FN_INSERT_FLD_DATE:
1703 case FN_INSERT_FLD_PGCOUNT:
1704 case FN_INSERT_FLD_PGNUMBER:
1705 case FN_INSERT_FLD_TIME:
1706 case FN_INSERT_FLD_TITLE:
1707 case FN_INSERT_FLD_TOPIC:
1708 case FN_INSERT_DBFIELD:
1709 if ( rSh.CursorInsideInputField() )
1711 rSet.DisableItem(nWhich);
1713 break;
1715 case FN_INSERT_TEXT_FORMFIELD:
1716 case FN_INSERT_CHECKBOX_FORMFIELD:
1717 case FN_INSERT_DROPDOWN_FORMFIELD:
1718 case FN_INSERT_DATE_FORMFIELD:
1719 if ( rSh.CursorInsideInputField() )
1721 rSet.DisableItem(nWhich);
1723 else
1725 // Check whether we are in a text form field
1726 SwPosition aCursorPos(*rSh.GetCursor()->GetPoint());
1727 sw::mark::Fieldmark* pFieldBM = GetShell().getIDocumentMarkAccess()->getInnerFieldmarkFor(aCursorPos);
1728 if ((!pFieldBM || pFieldBM->GetFieldname() != ODF_FORMTEXT)
1729 && aCursorPos.GetContentIndex() > 0)
1731 SwPosition aPos(*aCursorPos.GetContentNode(), aCursorPos.GetContentIndex() - 1);
1732 pFieldBM = GetShell().getIDocumentMarkAccess()->getInnerFieldmarkFor(aPos);
1734 if (pFieldBM && pFieldBM->GetFieldname() == ODF_FORMTEXT &&
1735 (aCursorPos > pFieldBM->GetMarkStart() && aCursorPos < pFieldBM->GetMarkEnd() ))
1737 rSet.DisableItem(nWhich);
1740 break;
1743 nWhich = aIter.NextWhich();
1747 void SwTextShell::InsertHyperlink(const SvxHyperlinkItem& rHlnkItem)
1749 const OUString& rName = rHlnkItem.GetName();
1750 const OUString& rURL = rHlnkItem.GetURL();
1751 const OUString& rTarget = rHlnkItem.GetTargetFrame();
1752 const OUString& rReplacementText = rHlnkItem.GetReplacementText();
1753 sal_uInt16 nType = o3tl::narrowing<sal_uInt16>(rHlnkItem.GetInsertMode());
1754 nType &= ~HLINK_HTMLMODE;
1755 const SvxMacroTableDtor* pMacroTable = rHlnkItem.GetMacroTable();
1757 SwWrtShell& rSh = GetShell();
1759 if( !(rSh.GetSelectionType() & SelectionType::Text) )
1760 return;
1762 rSh.StartAction();
1763 SfxItemSetFixed<RES_TXTATR_INETFMT, RES_TXTATR_INETFMT> aSet(GetPool());
1764 rSh.GetCurAttr( aSet );
1766 if(SfxItemState::SET == aSet.GetItemState(RES_TXTATR_INETFMT, false))
1768 // Select links
1769 rSh.SwCursorShell::SelectTextAttr(RES_TXTATR_INETFMT, false);
1771 switch (nType)
1773 case HLINK_DEFAULT:
1774 case HLINK_FIELD:
1776 SwFormatINetFormat aINetFormat( rURL, rTarget );
1777 aINetFormat.SetName(rHlnkItem.GetIntName());
1778 if(pMacroTable)
1780 const SvxMacro *pMacro = pMacroTable->Get( SvMacroItemId::OnMouseOver );
1781 if( pMacro )
1782 aINetFormat.SetMacro(SvMacroItemId::OnMouseOver, *pMacro);
1783 pMacro = pMacroTable->Get( SvMacroItemId::OnClick );
1784 if( pMacro )
1785 aINetFormat.SetMacro(SvMacroItemId::OnClick, *pMacro);
1786 pMacro = pMacroTable->Get( SvMacroItemId::OnMouseOut );
1787 if( pMacro )
1788 aINetFormat.SetMacro(SvMacroItemId::OnMouseOut, *pMacro);
1790 rSh.SttSelect();
1791 // inserting mention
1792 if (comphelper::LibreOfficeKit::isActive() && !rReplacementText.isEmpty())
1794 SwPaM* pCursorPos = rSh.GetCursor();
1795 // move cursor backwards to select @mention
1796 for(int i=0; i < rReplacementText.getLength(); i++)
1797 pCursorPos->Move(fnMoveBackward);
1798 rSh.InsertURL( aINetFormat, rName, false );
1800 else
1802 rSh.InsertURL( aINetFormat, rName, true );
1804 rSh.EndSelect();
1806 break;
1808 case HLINK_BUTTON:
1809 bool bSel = rSh.HasSelection();
1810 if(bSel)
1811 rSh.DelRight();
1812 InsertURLButton( rURL, rTarget, rName );
1813 rSh.EnterStdMode();
1814 break;
1816 rSh.EndAction();
1819 IMPL_LINK( SwTextShell, RedlineNextHdl, AbstractSvxPostItDialog&, rDlg, void )
1821 SwWrtShell* pSh = GetShellPtr();
1823 // Insert or change a comment.
1824 pSh->SetRedlineComment(rDlg.GetNote());
1826 const SwRangeRedline *pRedline = pSh->GetCurrRedline();
1828 if (!pRedline)
1829 return;
1831 // Traveling only if more than one field.
1832 if( !pSh->IsCursorPtAtEnd() )
1833 pSh->SwapPam(); // Move the cursor behind the Redline.
1835 pSh->Push();
1836 const SwRangeRedline *pActRed = pSh->SelNextRedline();
1837 pSh->Pop((pActRed != nullptr) ? SwCursorShell::PopMode::DeleteStack : SwCursorShell::PopMode::DeleteCurrent);
1839 bool bEnable = false;
1841 if (pActRed)
1843 pSh->StartAction();
1844 pSh->Push();
1845 bEnable = pSh->SelNextRedline() != nullptr;
1846 pSh->Pop(SwCursorShell::PopMode::DeleteCurrent);
1847 pSh->EndAction();
1850 rDlg.EnableTravel(bEnable, true);
1852 if( pSh->IsCursorPtAtEnd() )
1853 pSh->SwapPam();
1855 pRedline = pSh->GetCurrRedline();
1856 OUString sComment = convertLineEnd(pRedline->GetComment(), GetSystemLineEnd());
1858 rDlg.SetNote(sComment);
1859 rDlg.ShowLastAuthor( pRedline->GetAuthorString(),
1860 GetAppLangDateTimeString(
1861 pRedline->GetRedlineData().GetTimeStamp() ));
1863 rDlg.SetText(lcl_BuildTitleWithRedline(pRedline));
1867 IMPL_LINK( SwTextShell, RedlinePrevHdl, AbstractSvxPostItDialog&, rDlg, void )
1869 SwWrtShell* pSh = GetShellPtr();
1871 // Insert or change a comment.
1872 pSh->SetRedlineComment(rDlg.GetNote());
1874 const SwRangeRedline *pRedline = pSh->GetCurrRedline();
1876 if (!pRedline)
1877 return;
1879 // Traveling only if more than one field.
1880 pSh->Push();
1881 const SwRangeRedline *pActRed = pSh->SelPrevRedline();
1882 pSh->Pop((pActRed != nullptr) ? SwCursorShell::PopMode::DeleteStack : SwCursorShell::PopMode::DeleteCurrent);
1884 bool bEnable = false;
1886 if (pActRed)
1888 pSh->StartAction();
1889 pSh->Push();
1890 bEnable = pSh->SelPrevRedline() != nullptr;
1891 pSh->Pop(SwCursorShell::PopMode::DeleteCurrent);
1892 pSh->EndAction();
1895 rDlg.EnableTravel(true, bEnable);
1897 pRedline = pSh->GetCurrRedline();
1898 OUString sComment = convertLineEnd(pRedline->GetComment(), GetSystemLineEnd());
1900 rDlg.SetNote(sComment);
1901 rDlg.ShowLastAuthor(pRedline->GetAuthorString(),
1902 GetAppLangDateTimeString(
1903 pRedline->GetRedlineData().GetTimeStamp() ));
1905 rDlg.SetText(lcl_BuildTitleWithRedline(pRedline));
1909 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */