1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
28 #include <svl/itempool.hxx>
29 #include <svl/numformat.hxx>
30 #include <tools/lineend.hxx>
31 #include <svl/whiter.hxx>
32 #include <svl/eitem.hxx>
33 #include <svl/macitem.hxx>
34 #include <sfx2/viewfrm.hxx>
35 #include <sfx2/request.hxx>
36 #include <svx/postattr.hxx>
37 #include <svx/hlnkitem.hxx>
38 #include <svx/svxdlg.hxx>
39 #include <osl/diagnose.h>
40 #include <fmthdft.hxx>
41 #include <fmtinfmt.hxx>
42 #include <fldwrap.hxx>
43 #include <redline.hxx>
45 #include <viewopt.hxx>
48 #include <docufld.hxx>
53 #include <strings.hrc>
54 #include <sfx2/event.hxx>
55 #include <swabstdlg.hxx>
57 #include <PostItMgr.hxx>
58 #include <swmodule.hxx>
60 #include <editeng/ulspitem.hxx>
61 #include <xmloff/odffields.hxx>
62 #include <IDocumentContentOperations.hxx>
63 #include <IDocumentRedlineAccess.hxx>
64 #include <IDocumentUndoRedo.hxx>
65 #include <svl/zforlist.hxx>
66 #include <svl/zformat.hxx>
67 #include <svx/xfillit0.hxx>
68 #include <svx/pageitem.hxx>
69 #include <comphelper/sequenceashashmap.hxx>
71 #include <officecfg/Office/Compatibility.hxx>
73 #include <translatehelper.hxx>
74 #include <sfx2/dispatch.hxx>
77 using namespace nsSwDocInfoSubType
;
79 static OUString
lcl_BuildTitleWithRedline( const SwRangeRedline
*pRedline
)
81 const OUString
sTitle(SwResId(STR_REDLINE_COMMENT
));
84 switch( pRedline
->GetType() )
86 case RedlineType::Insert
:
87 pResId
= STR_REDLINE_INSERTED
;
89 case RedlineType::Delete
:
90 pResId
= STR_REDLINE_DELETED
;
92 case RedlineType::Format
:
93 case RedlineType::ParagraphFormat
:
94 pResId
= STR_REDLINE_FORMATTED
;
96 case RedlineType::Table
:
97 pResId
= STR_REDLINE_TABLECHG
;
99 case RedlineType::FmtColl
:
100 pResId
= STR_REDLINE_FMTCOLLSET
;
106 return sTitle
+ SwResId(pResId
);
109 void SwTextShell::ExecField(SfxRequest
&rReq
)
111 SwWrtShell
& rSh
= GetShell();
112 const SfxPoolItem
* pItem
= nullptr;
114 sal_uInt16 nSlot
= rReq
.GetSlot();
115 const SfxItemSet
* pArgs
= rReq
.GetArgs();
117 pArgs
->GetItemState(GetPool().GetWhich(nSlot
), false, &pItem
);
121 SwFieldTypesEnum nInsertType
= SwFieldTypesEnum::Date
;
122 sal_uInt16 nInsertSubType
= 0;
123 sal_uInt32 nInsertFormat
= 0;
129 SwField
* pField
= rSh
.GetCurField(true);
132 switch ( pField
->GetTypeId() )
134 case SwFieldTypesEnum::DDE
:
136 ::sfx2::SvBaseLink
& rLink
= static_cast<SwDDEFieldType
*>(pField
->GetTyp())->
138 if(rLink
.IsVisible())
140 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
141 ScopedVclPtr
<SfxAbstractLinksDialog
> pDlg(pFact
->CreateLinksDialog(GetView().GetFrameWeld(), &rSh
.GetLinkManager(), false, &rLink
));
148 SwAbstractDialogFactory
* pFact
= SwAbstractDialogFactory::Create();
149 ScopedVclPtr
<SfxAbstractDialog
> pDlg(pFact
->CreateSwFieldEditDlg( GetView() ));
156 case FN_UPDATE_SEL_FIELD
:
158 SwField
*pField
= rSh
.GetCurField();
162 rSh
.UpdateOneField(*pField
);
166 case FN_EXECUTE_MACROFIELD
:
168 SwField
* pField
= rSh
.GetCurField();
169 if(pField
&& pField
->GetTyp()->Which() == SwFieldIds::Macro
)
172 const OUString
& rMacro
= static_cast<SwMacroField
*>(pField
)->GetMacro();
173 sal_Int32 nPos
= rMacro
.indexOf('.');
176 SvxMacro
aMacro( rMacro
.copy(nPos
+ 1), rMacro
.copy(0,nPos
), STARBASIC
);
177 rSh
.ExecMacro(aMacro
);
183 case FN_GOTO_NEXT_INPUTFLD
:
184 case FN_GOTO_PREV_INPUTFLD
:
187 SwFieldType
* pField
= rSh
.GetFieldType( 0, SwFieldIds::Input
);
188 const bool bAddSetExpressionFields
= !( rSh
.GetViewOptions()->IsReadonly() );
189 if ( pField
!= nullptr
190 && rSh
.MoveFieldType(
192 FN_GOTO_NEXT_INPUTFLD
== nSlot
,
194 bAddSetExpressionFields
) )
197 if (!rSh
.IsMultiSelection()
198 && (nullptr != dynamic_cast<const SwTextInputField
*>(
199 SwCursorShell::GetTextFieldAtCursor(rSh
.GetCursor(), ::sw::GetTextAttrMode::Default
))))
203 SwCursorShell::StartOfInputFieldAtPos( *(rSh
.GetCursor()->Start()) ) + 1,
204 SwCursorShell::EndOfInputFieldAtPos( *(rSh
.GetCursor()->Start()) ) - 1 );
206 else if (SwField
* pCurrentField
= rSh
.GetCurField(true))
208 rSh
.StartInputFieldDlg(pCurrentField
, false, false, GetView().GetFrameWeld());
213 rReq
.SetReturnValue( SfxBoolItem( nSlot
, bRet
));
219 const SfxStringItem
* pName
= rReq
.GetArg
<SfxStringItem
>(FN_GOTO_MARK
);
222 rSh
.GotoMark(pName
->GetValue());
232 // Here come the slots with FieldMgr.
233 SwFieldMgr
aFieldMgr(GetShellPtr());
236 case FN_INSERT_DBFIELD
:
241 sal_uInt32 nFormat
= 0;
242 SwFieldTypesEnum nType
= SwFieldTypesEnum::Date
;
243 OUString aPar1
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
245 sal_Int32 nCommand
= 0;
247 if( const SfxUInt16Item
* pFieldItem
= pArgs
->GetItemIfSet( FN_PARAM_FIELD_TYPE
,
249 nType
= static_cast<SwFieldTypesEnum
>(pFieldItem
->GetValue());
250 aPar1
+= OUStringChar(DB_DELIM
);
251 if( SfxItemState::SET
== pArgs
->GetItemState(
252 FN_PARAM_1
, false, &pItem
))
254 aPar1
+= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
256 if( SfxItemState::SET
== pArgs
->GetItemState(
257 FN_PARAM_3
, false, &pItem
))
258 nCommand
= static_cast<const SfxInt32Item
*>(pItem
)->GetValue();
259 aPar1
+= OUStringChar(DB_DELIM
)
260 + OUString::number(nCommand
)
261 + OUStringChar(DB_DELIM
);
262 if( SfxItemState::SET
== pArgs
->GetItemState(
263 FN_PARAM_2
, false, &pItem
))
265 aPar1
+= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
267 if( const SfxStringItem
* pContentItem
= pArgs
->GetItemIfSet(
268 FN_PARAM_FIELD_CONTENT
, false ))
269 aPar2
= pContentItem
->GetValue();
270 if( const SfxUInt32Item
* pFormatItem
= pArgs
->GetItemIfSet(
271 FN_PARAM_FIELD_FORMAT
, false ))
272 nFormat
= pFormatItem
->GetValue();
273 OSL_FAIL("Command is not yet used");
274 SwInsertField_Data
aData(nType
, 0, aPar1
, aPar2
, nFormat
, GetShellPtr(), ' '/*separator*/ );
275 bRes
= aFieldMgr
.InsertField(aData
);
277 rReq
.SetReturnValue(SfxBoolItem( nSlot
, bRes
));
280 case FN_INSERT_FIELD_CTRL
:
281 case FN_INSERT_FIELD
:
284 if( pItem
&& nSlot
!= FN_INSERT_FIELD_CTRL
)
286 sal_uInt32 nFormat
= 0;
287 SwFieldTypesEnum nType
= SwFieldTypesEnum::Date
;
288 sal_uInt16 nSubType
= 0;
289 OUString aPar1
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
291 sal_Unicode cSeparator
= ' ';
293 if( const SfxUInt16Item
* pTypeItem
= pArgs
->GetItemIfSet( FN_PARAM_FIELD_TYPE
,
295 nType
= static_cast<SwFieldTypesEnum
>(pTypeItem
->GetValue());
296 else if (pArgs
->GetItemState(FN_PARAM_4
, false, &pItem
) == SfxItemState::SET
)
298 const OUString
& rTypeName
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
299 nType
= SwFieldTypeFromString(rTypeName
);
301 if( const SfxUInt16Item
* pSubtypeItem
= pArgs
->GetItemIfSet( FN_PARAM_FIELD_SUBTYPE
,
303 nSubType
= pSubtypeItem
->GetValue();
304 if( const SfxStringItem
* pContentItem
= pArgs
->GetItemIfSet(
305 FN_PARAM_FIELD_CONTENT
, false ))
306 aPar2
= pContentItem
->GetValue();
307 if( const SfxUInt32Item
* pFormatItem
= pArgs
->GetItemIfSet(
308 FN_PARAM_FIELD_FORMAT
, false ))
309 nFormat
= pFormatItem
->GetValue();
310 if( SfxItemState::SET
== pArgs
->GetItemState(
311 FN_PARAM_3
, false, &pItem
))
313 OUString sTmp
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
315 cSeparator
= sTmp
[0];
317 if (pArgs
->GetItemState(FN_PARAM_5
, false, &pItem
) == SfxItemState::SET
)
319 // Wrap the field in the requested container instead of inserting it
320 // directly at the cursor position.
321 const OUString
& rWrapper
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
322 if (rWrapper
== "Footnote")
324 GetShellPtr()->InsertFootnote(OUString());
326 else if (rWrapper
== "Endnote")
328 GetShellPtr()->InsertFootnote(OUString(), /*bEndNote=*/true);
331 SwInsertField_Data
aData(nType
, nSubType
, aPar1
, aPar2
, nFormat
, GetShellPtr(), cSeparator
);
332 bRes
= aFieldMgr
.InsertField( aData
);
336 //#i5788# prevent closing of the field dialog while a modal dialog ( Input field dialog ) is active
337 if(!GetView().GetViewFrame().IsInModalMode())
339 SfxViewFrame
& rVFrame
= GetView().GetViewFrame();
340 rVFrame
.ToggleChildWindow(FN_INSERT_FIELD
);
341 bRes
= rVFrame
.GetChildWindow( nSlot
) != nullptr;
342 Invalidate(rReq
.GetSlot());
343 Invalidate(FN_INSERT_FIELD_CTRL
);
347 rReq
.SetReturnValue(SfxBoolItem( nSlot
, bRes
));
351 case FN_INSERT_REF_FIELD
:
353 SfxViewFrame
& rVFrame
= GetView().GetViewFrame();
354 if (!rVFrame
.HasChildWindow(FN_INSERT_FIELD
))
355 rVFrame
.ToggleChildWindow(FN_INSERT_FIELD
); // Show dialog
357 // Switch Fielddlg at a new TabPage
358 sal_uInt16 nId
= SwFieldDlgWrapper::GetChildWindowId();
359 SwFieldDlgWrapper
*pWrp
= static_cast<SwFieldDlgWrapper
*>(rVFrame
.GetChildWindow(nId
));
361 pWrp
->ShowReferencePage();
365 case FN_DELETE_COMMENT
:
367 const SvxPostItIdItem
* pIdItem
= rReq
.GetArg
<SvxPostItIdItem
>(SID_ATTR_POSTIT_ID
);
368 if (pIdItem
&& !pIdItem
->GetValue().isEmpty() && GetView().GetPostItMgr())
370 GetView().GetPostItMgr()->Delete(pIdItem
->GetValue().toUInt32());
372 else if ( GetView().GetPostItMgr() &&
373 GetView().GetPostItMgr()->HasActiveSidebarWin() )
375 GetView().GetPostItMgr()->DeleteActiveSidebarWin();
379 case FN_DELETE_COMMENT_THREAD
:
381 const SvxPostItIdItem
* pIdItem
= rReq
.GetArg
<SvxPostItIdItem
>(SID_ATTR_POSTIT_ID
);
382 if (pIdItem
&& !pIdItem
->GetValue().isEmpty() && GetView().GetPostItMgr())
384 GetView().GetPostItMgr()->DeleteCommentThread(pIdItem
->GetValue().toUInt32());
386 else if ( GetView().GetPostItMgr() &&
387 GetView().GetPostItMgr()->HasActiveSidebarWin() )
389 GetView().GetPostItMgr()->DeleteActiveSidebarWin();
393 case FN_RESOLVE_NOTE
:
395 const SvxPostItIdItem
* pIdItem
= rReq
.GetArg
<SvxPostItIdItem
>(SID_ATTR_POSTIT_ID
);
396 if (pIdItem
&& !pIdItem
->GetValue().isEmpty() && GetView().GetPostItMgr())
398 GetView().GetPostItMgr()->ToggleResolved(pIdItem
->GetValue().toUInt32());
402 case FN_RESOLVE_NOTE_THREAD
:
404 const SvxPostItIdItem
* pIdItem
= rReq
.GetArg
<SvxPostItIdItem
>(SID_ATTR_POSTIT_ID
);
405 if (pIdItem
&& !pIdItem
->GetValue().isEmpty() && GetView().GetPostItMgr())
407 GetView().GetPostItMgr()->ToggleResolvedForThread(pIdItem
->GetValue().toUInt32());
411 case FN_DELETE_ALL_NOTES
:
412 if ( GetView().GetPostItMgr() )
413 GetView().GetPostItMgr()->Delete();
415 case FN_FORMAT_ALL_NOTES
:
417 SwPostItMgr
* pPostItMgr
= GetView().GetPostItMgr();
419 pPostItMgr
->ExecuteFormatAllDialog(GetView());
422 case FN_DELETE_NOTE_AUTHOR
:
424 const SfxStringItem
* pNoteItem
= rReq
.GetArg
<SfxStringItem
>(nSlot
);
425 if ( pNoteItem
&& GetView().GetPostItMgr() )
426 GetView().GetPostItMgr()->Delete( pNoteItem
->GetValue() );
430 if ( GetView().GetPostItMgr() &&
431 GetView().GetPostItMgr()->HasActiveSidebarWin() )
433 GetView().GetPostItMgr()->HideActiveSidebarWin();
436 case FN_HIDE_ALL_NOTES
:
437 if ( GetView().GetPostItMgr() )
438 GetView().GetPostItMgr()->Hide();
440 case FN_HIDE_NOTE_AUTHOR
:
442 const SfxStringItem
* pNoteItem
= rReq
.GetArg
<SfxStringItem
>(nSlot
);
443 if ( pNoteItem
&& GetView().GetPostItMgr() )
444 GetView().GetPostItMgr()->Hide( pNoteItem
->GetValue() );
449 const SvxPostItIdItem
* pIdItem
= rReq
.GetArg
<SvxPostItIdItem
>(SID_ATTR_POSTIT_ID
);
450 if (pIdItem
&& !pIdItem
->GetValue().isEmpty())
452 SwFieldType
* pType
= rSh
.GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit
, OUString(), false);
453 if(pType
->FindFormatForPostItId(pIdItem
->GetValue().toUInt32()))
455 auto pMgr
= GetView().GetPostItMgr();
456 auto pWin
= pMgr
->GetAnnotationWin(pIdItem
->GetValue().toUInt32());
460 if(const auto pTextItem
= rReq
.GetArg
<SvxPostItTextItem
>(SID_ATTR_POSTIT_TEXT
))
461 sText
= pTextItem
->GetValue();
462 pMgr
->RegisterAnswerText(sText
);
463 pWin
->ExecuteCommand(nSlot
);
471 rSh
.InsertPostIt(aFieldMgr
, rReq
);
474 case SID_EDIT_POSTIT
:
476 const SvxPostItIdItem
* pIdItem
= rReq
.GetArg
<SvxPostItIdItem
>(SID_ATTR_POSTIT_ID
);
477 if (pIdItem
&& !pIdItem
->GetValue().isEmpty())
479 const SvxPostItTextItem
* pTextItem
= rReq
.GetArg
<SvxPostItTextItem
>(SID_ATTR_POSTIT_TEXT
);
482 sText
= pTextItem
->GetValue();
484 sw::annotation::SwAnnotationWin
* pAnnotationWin
= GetView().GetPostItMgr()->GetAnnotationWin(pIdItem
->GetValue().toUInt32());
487 pAnnotationWin
->UpdateText(sText
);
489 // explicit state update to get the Undo state right
490 GetView().AttrChangedNotify(nullptr);
495 case FN_REDLINE_COMMENT
:
497 /* this code can be used once we want redline comments in the margin, all other stuff can
500 const SwRangeRedline *pRedline = rSh.GetCurrRedline();
504 sComment = pRedline->GetComment();
505 if ( !sComment.Len() )
506 GetView().GetDocShell()->Broadcast(SwRedlineHint(pRedline,SWREDLINE_INSERTED));
507 const_cast<SwRangeRedline*>(pRedline)->Broadcast(SwRedlineHint(pRedline,SWREDLINE_FOCUS,&GetView()));
511 const SwRangeRedline
*pRedline
= rSh
.GetCurrRedline();
512 SwDoc
*pDoc
= rSh
.GetDoc();
513 // If index is specified, goto and select the appropriate redline
514 if (pArgs
&& pArgs
->GetItemState(nSlot
, false, &pItem
) == SfxItemState::SET
)
516 const sal_uInt32 nChangeId
= static_cast<const SfxUInt32Item
*>(pItem
)->GetValue();
517 const SwRedlineTable
& rRedlineTable
= pDoc
->getIDocumentRedlineAccess().GetRedlineTable();
518 for (SwRedlineTable::size_type nRedline
= 0; nRedline
< rRedlineTable
.size(); ++nRedline
)
520 if (nChangeId
== rRedlineTable
[nRedline
]->GetId())
521 pRedline
= rSh
.GotoRedline(nRedline
, true);
525 OUString sCommentText
;
526 const SfxStringItem
* pTextItem
= rReq
.GetArg
<SvxPostItTextItem
>(SID_ATTR_POSTIT_TEXT
);
528 sCommentText
= pTextItem
->GetValue();
532 // In case of LOK and comment text is already provided, skip
533 // dialog creation and just change the redline comment directly
534 if (comphelper::LibreOfficeKit::isActive() && !sCommentText
.isEmpty())
536 rSh
.SetRedlineComment(sCommentText
);
537 GetView().AttrChangedNotify(nullptr);
538 MaybeNotifyRedlineModification(const_cast<SwRangeRedline
&>(*pRedline
), pRedline
->GetDoc());
542 OUString sComment
= convertLineEnd(pRedline
->GetComment(), GetSystemLineEnd());
544 bool bTravel
= false;
546 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
547 ::DialogGetRanges fnGetRange
= pFact
->GetDialogGetRangesFunc();
548 SfxItemSet
aSet(GetPool(), fnGetRange());
549 aSet
.Put(SvxPostItTextItem(sComment
, SID_ATTR_POSTIT_TEXT
));
550 aSet
.Put(SvxPostItAuthorItem(pRedline
->GetAuthorString(), SID_ATTR_POSTIT_AUTHOR
));
552 aSet
.Put( SvxPostItDateItem( GetAppLangDateTimeString(
553 pRedline
->GetRedlineData().GetTimeStamp() ),
554 SID_ATTR_POSTIT_DATE
));
556 // Traveling only if more than one field.
560 const SwRangeRedline
*pActRed
= rSh
.SelPrevRedline();
562 if (pActRed
== pRedline
)
563 { // New cursor is at the beginning of the current redlines.
564 rSh
.Pop(); // Throw old cursor away
566 pActRed
= rSh
.SelPrevRedline();
569 bool bPrev
= pActRed
!= nullptr;
570 rSh
.Pop(SwCursorShell::PopMode::DeleteCurrent
);
574 // Select current redline.
575 pActRed
= rSh
.SelNextRedline();
576 if (pActRed
!= pRedline
)
577 rSh
.SelPrevRedline();
581 pActRed
= rSh
.SelNextRedline();
582 bool bNext
= pActRed
!= nullptr;
583 rSh
.Pop(SwCursorShell::PopMode::DeleteCurrent
); // Restore cursor position
585 if( rSh
.IsCursorPtAtEnd() )
590 bTravel
|= bNext
|| bPrev
;
592 SvxAbstractDialogFactory
* pFact2
= SvxAbstractDialogFactory::Create();
593 ScopedVclPtr
<AbstractSvxPostItDialog
> pDlg(pFact2
->CreateSvxPostItDialog(GetView().GetFrameWeld(), aSet
, bTravel
));
596 pDlg
->SetText(lcl_BuildTitleWithRedline(pRedline
));
600 pDlg
->EnableTravel(bNext
, bPrev
);
601 pDlg
->SetPrevHdl(LINK(this, SwTextShell
, RedlinePrevHdl
));
602 pDlg
->SetNextHdl(LINK(this, SwTextShell
, RedlineNextHdl
));
605 SwViewShell::SetCareDialog(pDlg
->GetDialog());
606 g_bNoInterrupt
= true;
608 if ( pDlg
->Execute() == RET_OK
)
610 const SfxItemSet
* pOutSet
= pDlg
->GetOutputItemSet();
611 OUString
sMsg(pOutSet
->Get(SID_ATTR_POSTIT_TEXT
).GetValue());
613 // Insert or change a comment
614 rSh
.SetRedlineComment(sMsg
);
617 SwViewShell::SetCareDialog(nullptr);
618 pDlg
.disposeAndClear();
619 g_bNoInterrupt
= false;
621 GetView().AttrChangedNotify(nullptr);
628 OUString aType
, aText
;
631 bool bUpdate
= false;
635 aText
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
636 const SfxStringItem
* pType
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_2
);
637 const SfxBoolItem
* pIsUrl
= rReq
.GetArg
<SfxBoolItem
>(FN_PARAM_1
);
639 aType
= pType
->GetValue();
641 bIsUrl
= pIsUrl
->GetValue();
643 SwScriptField
* pField
= static_cast<SwScriptField
*>(aMgr
.GetCurField());
644 bNew
= !pField
|| (pField
->GetTyp()->Which() != SwFieldIds::Script
);
645 bUpdate
= pField
&& ( bIsUrl
!= static_cast<bool>(pField
->GetFormat()) || pField
->GetPar2() != aType
|| pField
->GetPar1() != aText
);
649 SwAbstractDialogFactory
* pFact
= SwAbstractDialogFactory::Create();
650 ScopedVclPtr
<AbstractJavaEditDialog
> pDlg(pFact
->CreateJavaEditDialog(GetView().GetFrameWeld(), &rSh
));
651 if ( pDlg
->Execute() )
653 aType
= pDlg
->GetScriptType();
654 aText
= pDlg
->GetScriptText();
655 bIsUrl
= pDlg
->IsUrl();
656 bNew
= pDlg
->IsNew();
657 bUpdate
= pDlg
->IsUpdate();
658 rReq
.AppendItem( SfxStringItem( FN_JAVAEDIT
, aText
) );
659 rReq
.AppendItem( SfxStringItem( FN_PARAM_2
, aType
) );
660 rReq
.AppendItem( SfxBoolItem( FN_PARAM_1
, bIsUrl
) );
666 SwInsertField_Data
aData(SwFieldTypesEnum::Script
, 0, aType
, aText
, bIsUrl
? 1 : 0);
667 aMgr
.InsertField(aData
);
672 aMgr
.UpdateCurField( bIsUrl
? 1 : 0, aType
, aText
);
673 rSh
.SetUndoNoResetModified();
681 case FN_INSERT_FLD_DATE
:
683 nInsertType
= SwFieldTypesEnum::Date
;
685 // use long date format for Hungarian
686 SwPaM
* pCursorPos
= rSh
.GetCursor();
689 LanguageType nLang
= pCursorPos
->GetPoint()->GetNode().GetTextNode()->GetLang(pCursorPos
->GetPoint()->GetContentIndex());
690 if (nLang
== LANGUAGE_HUNGARIAN
)
691 nInsertFormat
= rSh
.GetNumberFormatter()->GetFormatIndex(NF_DATE_SYSTEM_LONG
, nLang
);
695 case FN_INSERT_FLD_TIME
:
696 nInsertType
= SwFieldTypesEnum::Time
;
699 case FN_INSERT_FLD_PGNUMBER
:
700 nInsertType
= SwFieldTypesEnum::PageNumber
;
701 nInsertFormat
= SVX_NUM_PAGEDESC
; // Like page template
704 case FN_INSERT_FLD_PGCOUNT
:
705 nInsertType
= SwFieldTypesEnum::DocumentStatistics
;
708 nInsertFormat
= SVX_NUM_PAGEDESC
;
710 case FN_INSERT_FLD_TOPIC
:
711 nInsertType
= SwFieldTypesEnum::DocumentInfo
;
712 nInsertSubType
= DI_SUBJECT
;
714 case FN_INSERT_FLD_TITLE
:
715 nInsertType
= SwFieldTypesEnum::DocumentInfo
;
716 nInsertSubType
= DI_TITLE
;
718 case FN_INSERT_FLD_AUTHOR
:
719 nInsertType
= SwFieldTypesEnum::DocumentInfo
;
720 nInsertSubType
= DI_CREATE
|DI_SUB_AUTHOR
;
724 //format conversion should only be done for number formatter formats
726 nInsertFormat
= aFieldMgr
.GetDefaultFormat(nInsertType
, bIsText
, rSh
.GetNumberFormatter());
727 SwInsertField_Data
aData(nInsertType
, nInsertSubType
,
728 OUString(), OUString(), nInsertFormat
);
729 aFieldMgr
.InsertField(aData
);
734 case FN_INSERT_TEXT_FORMFIELD
:
736 OUString
aFieldType(ODF_FORMTEXT
);
737 const SfxStringItem
* pFieldType
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_1
);
740 // Allow overwriting the default type.
741 aFieldType
= pFieldType
->GetValue();
745 const SfxStringItem
* pFieldCode
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_2
);
748 // Allow specifying a field code/command.
749 aFieldCode
= pFieldCode
->GetValue();
752 if (rSh
.HasReadonlySel())
754 // Inform the user that the request has been ignored.
755 auto xInfo
= std::make_shared
<weld::GenericDialogController
>(
756 GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui",
757 "InfoReadonlyDialog");
758 weld::DialogController::runAsync(xInfo
, [](sal_Int32
/*nResult*/) {});
762 rSh
.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD
, nullptr);
764 SwPaM
* pCursorPos
= rSh
.GetCursor();
767 // Insert five En Space into the text field so the field has extent
768 static constexpr OUStringLiteral vEnSpaces
= u
"\u2002\u2002\u2002\u2002\u2002";
769 OUString
aFieldResult(vEnSpaces
);
770 const SfxStringItem
* pFieldResult
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_3
);
773 // Allow specifying a field result / expanded value.
774 aFieldResult
= pFieldResult
->GetValue();
777 const SfxStringItem
* pWrapper
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_4
);
780 // Wrap the fieldmark in the requested container instead of inserting it
781 // directly at the cursor position.
782 OUString aWrapper
= pWrapper
->GetValue();
783 if (aWrapper
== "Footnote")
785 rSh
.InsertFootnote(OUString());
787 else if (aWrapper
== "Endnote")
789 // It's important that there is no Start/EndAction() around this, so the
790 // inner EndAction() triggers a layout update and the cursor can jump to the
791 // created SwFootnoteFrame.
792 rSh
.InsertFootnote(OUString(), /*bEndNote=*/true);
796 // Don't update the layout after inserting content and before deleting temporary
800 // Split node to remember where the start position is.
801 bool bSuccess
= rSh
.GetDoc()->getIDocumentContentOperations().SplitNode(
802 *pCursorPos
->GetPoint(), false);
805 SwPaM
aFieldPam(*pCursorPos
->GetPoint());
806 aFieldPam
.Move(fnMoveBackward
, GoInContent
);
809 // Paste HTML content.
810 SwTranslateHelper::PasteHTMLToPaM(rSh
, pCursorPos
, aFieldResult
.toUtf8(),
812 if (pCursorPos
->GetPoint()->GetContentIndex() == 0)
814 // The paste created a last empty text node, remove it.
815 SwPaM
aPam(*pCursorPos
->GetPoint());
817 aPam
.Move(fnMoveBackward
, GoInContent
);
818 rSh
.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPam
);
823 // Insert default placeholder.
824 rSh
.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos
,
827 // Undo the above SplitNode().
829 aFieldPam
.Move(fnMoveForward
, GoInContent
);
830 rSh
.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aFieldPam
);
831 *aFieldPam
.GetMark() = *pCursorPos
->GetPoint();
833 IDocumentMarkAccess
* pMarksAccess
= rSh
.GetDoc()->getIDocumentMarkAccess();
834 sw::mark::IFieldmark
* pFieldmark
= pMarksAccess
->makeFieldBookmark(
835 aFieldPam
, OUString(), aFieldType
, aFieldPam
.Start());
836 if (pFieldmark
&& !aFieldCode
.isEmpty())
838 pFieldmark
->GetParameters()->insert(
839 std::pair
<OUString
, uno::Any
>(ODF_CODE_PARAM
, uno::Any(aFieldCode
)));
845 rSh
.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD
, nullptr);
846 rSh
.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO
);
849 case FN_INSERT_CHECKBOX_FORMFIELD
:
851 rSh
.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD
, nullptr);
853 SwPaM
* pCursorPos
= rSh
.GetCursor();
856 IDocumentMarkAccess
* pMarksAccess
= rSh
.GetDoc()->getIDocumentMarkAccess();
857 pMarksAccess
->makeNoTextFieldBookmark(*pCursorPos
, OUString(), ODF_FORMCHECKBOX
);
860 rSh
.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD
, nullptr);
861 rSh
.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO
);
864 case FN_INSERT_DROPDOWN_FORMFIELD
:
866 rSh
.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD
, nullptr);
868 SwPaM
* pCursorPos
= rSh
.GetCursor();
871 IDocumentMarkAccess
* pMarksAccess
= rSh
.GetDoc()->getIDocumentMarkAccess();
872 pMarksAccess
->makeNoTextFieldBookmark(*pCursorPos
, OUString(), ODF_FORMDROPDOWN
);
875 rSh
.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD
, nullptr);
876 rSh
.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO
);
879 case FN_INSERT_DATE_FORMFIELD
:
881 rSh
.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD
, nullptr);
883 SwPaM
* pCursorPos
= rSh
.GetCursor();
886 // Insert five enspaces into the text field so the field has extent
887 sal_Unicode vEnSpaces
[ODF_FORMFIELD_DEFAULT_LENGTH
] = {8194, 8194, 8194, 8194, 8194};
888 bool bSuccess
= rSh
.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos
, OUString(vEnSpaces
, ODF_FORMFIELD_DEFAULT_LENGTH
));
891 IDocumentMarkAccess
* pMarksAccess
= rSh
.GetDoc()->getIDocumentMarkAccess();
892 SwPaM
aFieldPam(pCursorPos
->GetPoint()->GetNode(), pCursorPos
->GetPoint()->GetContentIndex() - ODF_FORMFIELD_DEFAULT_LENGTH
,
893 pCursorPos
->GetPoint()->GetNode(), pCursorPos
->GetPoint()->GetContentIndex());
894 sw::mark::IFieldmark
* pFieldBM
= pMarksAccess
->makeFieldBookmark(aFieldPam
, OUString(), ODF_FORMDATE
,
897 // Use a default date format and language
898 sw::mark::IFieldmark::parameter_map_t
* pParameters
= pFieldBM
->GetParameters();
899 SvNumberFormatter
* pFormatter
= rSh
.GetDoc()->GetNumberFormatter();
900 sal_uInt32 nStandardFormat
= pFormatter
->GetStandardFormat(SvNumFormatType::DATE
);
901 const SvNumberformat
* pFormat
= pFormatter
->GetEntry(nStandardFormat
);
903 (*pParameters
)[ODF_FORMDATE_DATEFORMAT
] <<= pFormat
->GetFormatstring();
904 (*pParameters
)[ODF_FORMDATE_DATEFORMAT_LANGUAGE
] <<= LanguageTag(pFormat
->GetLanguage()).getBcp47();
908 rSh
.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD
, nullptr);
909 rSh
.GetView().GetViewFrame().GetBindings().Invalidate( SID_UNDO
);
912 case FN_UPDATE_TEXT_FORMFIELDS
:
914 // This updates multiple fieldmarks in a document, based on their field name & field command
917 const SfxStringItem
* pFieldType
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_1
);
920 aFieldType
= pFieldType
->GetValue();
922 OUString aFieldCommandPrefix
;
923 const SfxStringItem
* pFieldCommandPrefix
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_2
);
924 if (pFieldCommandPrefix
)
926 aFieldCommandPrefix
= pFieldCommandPrefix
->GetValue();
928 uno::Sequence
<beans::PropertyValues
> aFields
;
929 const SfxUnoAnyItem
* pFields
= rReq
.GetArg
<SfxUnoAnyItem
>(FN_PARAM_3
);
932 pFields
->GetValue() >>= aFields
;
935 rSh
.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::UPDATE_FORM_FIELDS
, nullptr);
938 IDocumentMarkAccess
* pMarkAccess
= rSh
.GetDoc()->getIDocumentMarkAccess();
939 sal_Int32 nFieldIndex
= 0;
940 for (auto it
= pMarkAccess
->getFieldmarksBegin(); it
!= pMarkAccess
->getFieldmarksEnd(); ++it
)
942 auto pFieldmark
= dynamic_cast<sw::mark::IFieldmark
*>(*it
);
944 if (pFieldmark
->GetFieldname() != aFieldType
)
949 auto itParam
= pFieldmark
->GetParameters()->find(ODF_CODE_PARAM
);
950 if (itParam
== pFieldmark
->GetParameters()->end())
956 itParam
->second
>>= aCommand
;
957 if (!aCommand
.startsWith(aFieldCommandPrefix
))
962 if (aFields
.getLength() <= nFieldIndex
)
967 comphelper::SequenceAsHashMap
aMap(aFields
[nFieldIndex
++]);
968 itParam
->second
= aMap
["FieldCommand"];
969 SwPaM
aPaM(pFieldmark
->GetMarkPos(), pFieldmark
->GetOtherMarkPos());
971 // Skip field start & separator.
972 aPaM
.GetPoint()->AdjustContent(2);
974 aPaM
.GetMark()->AdjustContent(-1);
975 rSh
.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPaM
);
976 OUString aFieldResult
;
977 aMap
["FieldResult"] >>= aFieldResult
;
978 SwTranslateHelper::PasteHTMLToPaM(rSh
, &aPaM
, aFieldResult
.toUtf8(), true);
982 rSh
.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::UPDATE_FORM_FIELDS
, nullptr);
985 case FN_DELETE_TEXT_FORMFIELDS
:
987 // This deletes all fieldmarks that match the provided field type & field command prefix.
989 const SfxStringItem
* pFieldType
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_1
);
992 aFieldType
= pFieldType
->GetValue();
994 OUString aFieldCommandPrefix
;
995 const SfxStringItem
* pFieldCommandPrefix
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_2
);
996 if (pFieldCommandPrefix
)
998 aFieldCommandPrefix
= pFieldCommandPrefix
->GetValue();
1000 rSh
.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELETE_FORM_FIELDS
, nullptr);
1003 IDocumentMarkAccess
* pMarkAccess
= rSh
.GetDoc()->getIDocumentMarkAccess();
1004 std::vector
<sw::mark::IMark
*> aRemovals
;
1005 for (auto it
= pMarkAccess
->getFieldmarksBegin(); it
!= pMarkAccess
->getFieldmarksEnd(); ++it
)
1007 auto pFieldmark
= dynamic_cast<sw::mark::IFieldmark
*>(*it
);
1009 if (pFieldmark
->GetFieldname() != aFieldType
)
1014 if (!aFieldCommandPrefix
.isEmpty())
1016 auto itParam
= pFieldmark
->GetParameters()->find(ODF_CODE_PARAM
);
1017 if (itParam
== pFieldmark
->GetParameters()->end())
1023 itParam
->second
>>= aCommand
;
1024 if (!aCommand
.startsWith(aFieldCommandPrefix
))
1030 aRemovals
.push_back(pFieldmark
);
1033 for (const auto& pMark
: aRemovals
)
1035 pMarkAccess
->deleteMark(pMark
);
1039 rSh
.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELETE_FORM_FIELDS
, nullptr);
1042 case FN_PGNUMBER_WIZARD
:
1044 SwAbstractDialogFactory
* pFact
= SwAbstractDialogFactory::Create();
1045 VclPtr
<AbstractSwPageNumberDlg
> pDlg(
1046 pFact
->CreateSwPageNumberDlg(GetView().GetFrameWeld()));
1047 auto pShell
= GetShellPtr();
1049 const SwPageDesc
& rCurrDesc
= rSh
.GetPageDesc(rSh
.GetCurPageDesc());
1050 pDlg
->SetPageNumberType(rCurrDesc
.GetNumType().GetNumberingType());
1052 pDlg
->StartExecuteAsync([pShell
, &rSh
, pDlg
](int nResult
) {
1053 if ( nResult
== RET_OK
)
1055 auto rDoc
= rSh
.GetDoc();
1058 rSh
.StartAllAction();
1059 rSh
.SwCursorShell::Push();
1060 rDoc
->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_PAGE_NUMBER
, nullptr);
1062 const size_t nPageDescIndex
= rSh
.GetCurPageDesc();
1063 const SwPageDesc
& rDesc
= rSh
.GetPageDesc(nPageDescIndex
);
1064 const bool bHeader
= !pDlg
->GetPageNumberPosition();
1065 const bool bHeaderAlreadyOn
= rDesc
.GetMaster().GetHeader().IsActive();
1066 const bool bFooterAlreadyOn
= rDesc
.GetMaster().GetFooter().IsActive();
1067 const bool bIsSinglePage
= rDesc
.GetFollow() != &rDesc
;
1068 const size_t nMirrorPagesNeeded
= rDesc
.IsFirstShared() ? 2 : 3;
1069 const OUString sBookmarkName
= OUString::Concat("PageNumWizard_")
1070 + (bHeader
? "HEADER" : "FOOTER") + "_" + rDesc
.GetName();
1071 IDocumentMarkAccess
& rIDMA
= *rSh
.getIDocumentMarkAccess();
1073 // Allow wizard to be re-run: delete previously wizard-inserted page number.
1074 // Try before creating non-shared header: avoid copying ODD bookmark onto EVEN page.
1075 IDocumentMarkAccess::const_iterator_t ppMark
= rIDMA
.findMark(
1076 sBookmarkName
+ OUString::number(rSh
.GetVirtPageNum()));
1077 if (ppMark
!= rIDMA
.getAllMarksEnd() && *ppMark
)
1079 SwPaM
aDeleteOldPageNum((*ppMark
)->GetMarkStart(), (*ppMark
)->GetMarkEnd());
1080 rDoc
->getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum
);
1083 SwPageDesc
aNewDesc(rDesc
);
1084 bool bChangePageDesc
= false;
1085 if (pDlg
->GetPageNumberType() != aNewDesc
.GetNumType().GetNumberingType())
1087 bChangePageDesc
= true;
1088 SvxNumberType
aNewType(rDesc
.GetNumType());
1089 aNewType
.SetNumberingType(pDlg
->GetPageNumberType());
1090 aNewDesc
.SetNumType(aNewType
);
1093 // Insert header/footer
1094 if ((bHeader
&& !bHeaderAlreadyOn
) || (!bHeader
&& !bFooterAlreadyOn
))
1096 bChangePageDesc
= true;
1097 SwFrameFormat
&rMaster
= aNewDesc
.GetMaster();
1099 rMaster
.SetFormatAttr(SwFormatHeader(/*On=*/true));
1101 rMaster
.SetFormatAttr(SwFormatFooter(/*On=*/true));
1103 // Init copied from ChangeHeaderOrFooter: keep in sync
1104 constexpr tools::Long constTwips_5mm
= o3tl::toTwips(5, o3tl::Length::mm
);
1105 const SvxULSpaceItem
aUL(bHeader
? 0 : constTwips_5mm
,
1106 bHeader
? constTwips_5mm
: 0,
1108 const XFillStyleItem
aFill(drawing::FillStyle_NONE
);
1109 SwFrameFormat
& rFormat
1111 ? const_cast<SwFrameFormat
&>(*rMaster
.GetHeader().GetHeaderFormat())
1112 : const_cast<SwFrameFormat
&>(*rMaster
.GetFooter().GetFooterFormat());
1113 rFormat
.SetFormatAttr(aUL
);
1114 rFormat
.SetFormatAttr(aFill
);
1116 // Might as well turn on margin mirroring too - if appropriate
1117 if (pDlg
->GetMirrorOnEvenPages() && !bHeaderAlreadyOn
&& !bFooterAlreadyOn
1119 && (aNewDesc
.ReadUseOn() & UseOnPage::Mirror
) == UseOnPage::All
)
1121 aNewDesc
.WriteUseOn(rDesc
.ReadUseOn() | UseOnPage::Mirror
);
1125 const bool bCreateMirror
= !bIsSinglePage
&& pDlg
->GetMirrorOnEvenPages()
1126 && nMirrorPagesNeeded
<= rSh
.GetPageCnt();
1129 // Use different left/right header/footer
1130 if ((bHeader
&& rDesc
.IsHeaderShared()) || (!bHeader
&& rDesc
.IsFooterShared()))
1132 bChangePageDesc
= true;
1134 aNewDesc
.ChgHeaderShare(/*Share=*/false);
1136 aNewDesc
.ChgFooterShare(/*Share=*/false);
1140 if (bChangePageDesc
)
1141 rSh
.ChgPageDesc(nPageDescIndex
, aNewDesc
);
1143 // Go to the header or footer insert position
1145 bool bSkipMirror
= true;
1146 size_t nEvenPage
= 0;
1147 if (bCreateMirror
|| !rSh
.GetCurrFrame())
1149 // Come here if Currframe can't be found, otherwise Goto*Text will crash.
1150 // Get*PageNum will also be invalid (0), so we have no idea where we are.
1151 // (Since not asking for mirror, the likelihood is that the bHeader is shared,
1152 // in which case it doesn't matter anyway, and we just hope for the best.)
1153 // Read the code in this block assuming that bCreateMirror is true.
1155 // There are enough pages that there probably is a valid odd page.
1156 // However, that is not guaranteed: perhaps the page style switched,
1157 // or a blank page was forced, or some other complexity.
1158 bInHF
= rSh
.SetCursorInHdFt(nPageDescIndex
, bHeader
, /*Even=*/true);
1161 // Remember valid EVEN page. Mirror it if also a valid ODD or FIRST page
1162 nEvenPage
= rSh
.GetVirtPageNum();
1163 assert (nEvenPage
&& "couldn't find page number. Use a bool instead");
1166 bInHF
= rSh
.SetCursorInHdFt(nPageDescIndex
, bHeader
, /*Even=*/false);
1167 if (bInHF
&& nEvenPage
)
1169 // Even though the cursor may be on a FIRST page,
1170 // the user requested mirrored pages, and we have both ODD and EVEN,
1171 // so set page numbers on these two pages, and leave FIRST alone.
1172 bSkipMirror
= false;
1176 // no ODD page, look for FIRST page
1177 bInHF
= rSh
.SetCursorInHdFt(nPageDescIndex
, bHeader
, false, /*First=*/true);
1178 if (bInHF
&& nEvenPage
)
1180 // Unlikely but valid situation: EVEN and FIRST pages, but no ODD page.
1181 // In this case, the first header gets the specified page number
1182 // and the even header is mirrored, with an empty odd header,
1183 // as the user (somewhat) requested.
1184 bSkipMirror
= false;
1187 assert((bInHF
|| nEvenPage
) && "Impossible - why couldn't the move happen?");
1188 assert((bInHF
|| nEvenPage
== rSh
.GetVirtPageNum()) && "Unexpected move");
1193 bInHF
= rSh
.GotoHeaderText();
1195 bInHF
= rSh
.GotoFooterText();
1196 assert(bInHF
&& "shouldn't have a problem going to text when no mirroring");
1199 // Allow wizard to be re-run: delete previously wizard-inserted page number.
1200 // Now that the cursor may have moved to a different page, try delete again.
1201 ppMark
= rIDMA
.findMark(sBookmarkName
+ OUString::number(rSh
.GetVirtPageNum()));
1202 if (ppMark
!= rIDMA
.getAllMarksEnd() && *ppMark
)
1204 SwPaM
aDeleteOldPageNum((*ppMark
)->GetMarkStart(), (*ppMark
)->GetMarkEnd());
1205 rDoc
->getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum
);
1208 SwTextNode
* pTextNode
= rSh
.GetCursor()->GetPoint()->GetNode().GetTextNode();
1210 // Insert new line if there is already text in header/footer
1211 if (pTextNode
&& !pTextNode
->GetText().isEmpty())
1213 rDoc
->getIDocumentContentOperations().SplitNode(*rSh
.GetCursor()->GetPoint(), false);
1215 // Go back to start of header/footer
1217 rSh
.GotoHeaderText();
1219 rSh
.GotoFooterText();
1222 // Set alignment for the new line
1223 switch (pDlg
->GetPageNumberAlignment())
1227 SvxAdjustItem
aAdjustItem(SvxAdjust::Left
, RES_PARATR_ADJUST
);
1228 rSh
.SetAttrItem(aAdjustItem
);
1233 SvxAdjustItem
aAdjustItem(SvxAdjust::Center
, RES_PARATR_ADJUST
);
1234 rSh
.SetAttrItem(aAdjustItem
);
1239 SvxAdjustItem
aAdjustItem(SvxAdjust::Right
, RES_PARATR_ADJUST
);
1240 rSh
.SetAttrItem(aAdjustItem
);
1245 sal_Int32 nStartContentIndex
= rSh
.GetCursor()->Start()->GetContentIndex();
1246 assert(!nStartContentIndex
&& "earlier split node if not empty, but not zero?");
1248 // Insert page number
1249 SwFieldMgr
aMgr(pShell
);
1250 SwInsertField_Data
aData(SwFieldTypesEnum::PageNumber
, 0,
1251 OUString(), OUString(), SVX_NUM_PAGEDESC
);
1252 aMgr
.InsertField(aData
);
1253 if (pDlg
->GetIncludePageTotal())
1255 rDoc
->getIDocumentContentOperations().InsertString(*rSh
.GetCursor(), " / ");
1256 SwInsertField_Data
aPageTotalData(SwFieldTypesEnum::DocumentStatistics
, DS_PAGE
,
1257 OUString(), OUString(), SVX_NUM_PAGEDESC
);
1258 aMgr
.InsertField(aPageTotalData
);
1261 // Mark inserted fields with a bookmark - so it can be found/removed if re-run
1262 SwPaM
aNewBookmarkPaM(*rSh
.GetCursor()->Start());
1263 aNewBookmarkPaM
.SetMark();
1264 assert(aNewBookmarkPaM
.GetPointContentNode() && "only SetContent on content node");
1265 aNewBookmarkPaM
.Start()->SetContent(nStartContentIndex
);
1266 rIDMA
.makeMark(aNewBookmarkPaM
,
1267 sBookmarkName
+ OUString::number(rSh
.GetVirtPageNum()),
1268 IDocumentMarkAccess::MarkType::BOOKMARK
,
1269 sw::mark::InsertMode::New
);
1271 // Mirror on the even pages
1272 if (!bSkipMirror
&& bCreateMirror
1273 && rSh
.SetCursorInHdFt(nPageDescIndex
, bHeader
, /*Even=*/true))
1275 assert(nEvenPage
&& "what? no even page and yet we got here?");
1276 ppMark
= rIDMA
.findMark(sBookmarkName
+ OUString::number(rSh
.GetVirtPageNum()));
1277 if (ppMark
!= rIDMA
.getAllMarksEnd() && *ppMark
)
1279 SwPaM
aDeleteOldPageNum((*ppMark
)->GetMarkStart(), (*ppMark
)->GetMarkEnd());
1280 rDoc
->getIDocumentContentOperations().DeleteAndJoin(aDeleteOldPageNum
);
1283 pTextNode
= rSh
.GetCursor()->GetPoint()->GetNode().GetTextNode();
1285 // Insert new line if there is already text in header/footer
1286 if (pTextNode
&& !pTextNode
->GetText().isEmpty())
1288 rDoc
->getIDocumentContentOperations().SplitNode(
1289 *rSh
.GetCursor()->GetPoint(), false);
1290 // Go back to start of header/footer
1291 rSh
.SetCursorInHdFt(nPageDescIndex
, bHeader
, /*Even=*/true);
1294 // mirror the adjustment
1295 assert(pDlg
->GetPageNumberAlignment() != 1 && "cannot have Center and bMirror");
1296 SvxAdjust eAdjust
= SvxAdjust::Left
;
1297 if (!pDlg
->GetPageNumberAlignment())
1298 eAdjust
= SvxAdjust::Right
;
1299 SvxAdjustItem
aMirrorAdjustItem(eAdjust
, RES_PARATR_ADJUST
);
1300 rSh
.SetAttrItem(aMirrorAdjustItem
);
1302 nStartContentIndex
= rSh
.GetCursor()->Start()->GetContentIndex();
1304 // Insert page number
1305 SwFieldMgr
aEvenMgr(pShell
);
1306 aEvenMgr
.InsertField(aData
);
1307 if (pDlg
->GetIncludePageTotal())
1309 rDoc
->getIDocumentContentOperations().InsertString(*rSh
.GetCursor(), " / ");
1310 SwInsertField_Data
aPageTotalData(SwFieldTypesEnum::DocumentStatistics
,
1311 DS_PAGE
, OUString(), OUString(),
1313 aMgr
.InsertField(aPageTotalData
);
1316 // Mark inserted fields with a bookmark - so it can be found/removed if re-run
1317 SwPaM
aNewEvenBookmarkPaM(*rSh
.GetCursor()->Start());
1318 aNewEvenBookmarkPaM
.SetMark();
1319 aNewEvenBookmarkPaM
.Start()->SetContent(nStartContentIndex
);
1320 rIDMA
.makeMark(aNewEvenBookmarkPaM
,
1321 sBookmarkName
+ OUString::number(rSh
.GetVirtPageNum()),
1322 IDocumentMarkAccess::MarkType::BOOKMARK
,
1323 sw::mark::InsertMode::New
);
1326 rSh
.SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent
);
1328 rSh
.LockView(false);
1329 rDoc
->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_PAGE_NUMBER
, nullptr);
1331 pDlg
->disposeOnce();
1336 case FN_UPDATE_TEXT_FORMFIELD
:
1338 // This updates a single fieldmark under the current cursor.
1339 OUString aFieldType
;
1340 const SfxStringItem
* pFieldType
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_1
);
1343 aFieldType
= pFieldType
->GetValue();
1345 OUString aFieldCommandPrefix
;
1346 const SfxStringItem
* pFieldCommandPrefix
= rReq
.GetArg
<SfxStringItem
>(FN_PARAM_2
);
1347 if (pFieldCommandPrefix
)
1349 aFieldCommandPrefix
= pFieldCommandPrefix
->GetValue();
1351 uno::Sequence
<beans::PropertyValue
> aField
;
1352 const SfxUnoAnyItem
* pFields
= rReq
.GetArg
<SfxUnoAnyItem
>(FN_PARAM_3
);
1355 pFields
->GetValue() >>= aField
;
1358 IDocumentMarkAccess
& rIDMA
= *rSh
.getIDocumentMarkAccess();
1359 SwPosition
& rCursor
= *rSh
.GetCursor()->GetPoint();
1360 sw::mark::IFieldmark
* pFieldmark
= rIDMA
.getInnerFieldmarkFor(rCursor
);
1366 if (pFieldmark
->GetFieldname() != aFieldType
)
1371 auto itParam
= pFieldmark
->GetParameters()->find(ODF_CODE_PARAM
);
1372 if (itParam
== pFieldmark
->GetParameters()->end())
1378 itParam
->second
>>= aCommand
;
1379 if (!aCommand
.startsWith(aFieldCommandPrefix
))
1384 rSh
.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::UPDATE_FORM_FIELD
, nullptr);
1386 comphelper::SequenceAsHashMap
aMap(aField
);
1387 itParam
->second
= aMap
["FieldCommand"];
1388 SwPaM
aPaM(pFieldmark
->GetMarkPos(), pFieldmark
->GetOtherMarkPos());
1390 // Skip field start & separator.
1391 aPaM
.GetPoint()->AdjustContent(2);
1393 aPaM
.GetMark()->AdjustContent(-1);
1394 rSh
.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPaM
);
1395 OUString aFieldResult
;
1396 aMap
["FieldResult"] >>= aFieldResult
;
1397 SwTranslateHelper::PasteHTMLToPaM(rSh
, &aPaM
, aFieldResult
.toUtf8(), true);
1400 rSh
.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::UPDATE_FORM_FIELD
, nullptr);
1404 OSL_FAIL("wrong dispatcher");
1409 void SwTextShell::StateField( SfxItemSet
&rSet
)
1411 SwWrtShell
& rSh
= GetShell();
1412 SfxWhichIter
aIter( rSet
);
1413 const SwField
* pField
= nullptr;
1414 bool bGetField
= false;
1415 sal_uInt16 nWhich
= aIter
.FirstWhich();
1421 case FN_DELETE_COMMENT
:
1422 case FN_DELETE_NOTE_AUTHOR
:
1423 case FN_DELETE_ALL_NOTES
:
1424 case FN_FORMAT_ALL_NOTES
:
1426 case FN_HIDE_NOTE_AUTHOR
:
1427 case FN_HIDE_ALL_NOTES
:
1429 SwPostItMgr
* pPostItMgr
= GetView().GetPostItMgr();
1431 rSet
.InvalidateItem( nWhich
);
1432 else if ( !pPostItMgr
->HasActiveSidebarWin() )
1434 rSet
.InvalidateItem( FN_DELETE_COMMENT
);
1435 rSet
.InvalidateItem( FN_HIDE_NOTE
);
1437 // tdf#137568 do not offer comment formatting, if no comments are present
1438 if (!pPostItMgr
|| !pPostItMgr
->HasNotes())
1439 rSet
.DisableItem( FN_FORMAT_ALL_NOTES
);
1447 pField
= rSh
.GetCurField(true);
1451 SwFieldIds nTempWhich
= pField
? pField
->GetTyp()->Which() : SwFieldIds::Unknown
;
1452 if( SwFieldIds::Unknown
== nTempWhich
||
1453 SwFieldIds::Postit
== nTempWhich
||
1454 SwFieldIds::Script
== nTempWhich
||
1455 SwFieldIds::TableOfAuthorities
== nTempWhich
)
1456 rSet
.DisableItem( nWhich
);
1457 else if( SwFieldIds::Dde
== nTempWhich
&&
1458 !static_cast<SwDDEFieldType
*>(pField
->GetTyp())->GetBaseLink().IsVisible())
1460 // nested links cannot be edited
1461 rSet
.DisableItem( nWhich
);
1466 case FN_UPDATE_SEL_FIELD
:
1468 pField
= rSh
.GetCurField();
1471 rSet
.DisableItem( nWhich
);
1476 case FN_EXECUTE_MACROFIELD
:
1480 pField
= rSh
.GetCurField();
1483 if(!pField
|| pField
->GetTyp()->Which() != SwFieldIds::Macro
)
1484 rSet
.DisableItem(nWhich
);
1488 case FN_INSERT_FIELD
:
1490 if ( rSh
.CursorInsideInputField() )
1492 rSet
.DisableItem(nWhich
);
1496 SfxViewFrame
& rVFrame
= GetView().GetViewFrame();
1497 //#i5788# prevent closing of the field dialog while a modal dialog ( Input field dialog ) is active
1498 if(!rVFrame
.IsInModalMode() &&
1499 rVFrame
.KnowsChildWindow(FN_INSERT_FIELD
) && !rVFrame
.HasChildWindow(FN_INSERT_FIELD_DATA_ONLY
) )
1500 rSet
.Put(SfxBoolItem( FN_INSERT_FIELD
, rVFrame
.HasChildWindow(nWhich
)));
1502 rSet
.DisableItem(FN_INSERT_FIELD
);
1507 case FN_INSERT_REF_FIELD
:
1509 SfxViewFrame
& rVFrame
= GetView().GetViewFrame();
1510 if ( !rVFrame
.KnowsChildWindow(FN_INSERT_FIELD
)
1511 || rSh
.CursorInsideInputField() )
1513 rSet
.DisableItem(FN_INSERT_REF_FIELD
);
1518 case FN_INSERT_FIELD_CTRL
:
1519 if ( rSh
.CursorInsideInputField() )
1521 rSet
.DisableItem(nWhich
);
1525 rSet
.Put(SfxBoolItem( nWhich
, GetView().GetViewFrame().HasChildWindow(FN_INSERT_FIELD
)));
1529 case FN_REDLINE_COMMENT
:
1530 if (!comphelper::LibreOfficeKit::isActive() && !rSh
.GetCurrRedline())
1531 rSet
.DisableItem(nWhich
);
1535 if (!comphelper::LibreOfficeKit::isActive())
1536 rSet
.DisableItem(nWhich
);
1542 bool bCurField
= false;
1543 pField
= rSh
.GetCurField();
1544 if(nWhich
== FN_POSTIT
)
1545 bCurField
= pField
&& pField
->GetTyp()->Which() == SwFieldIds::Postit
;
1547 bCurField
= pField
&& pField
->GetTyp()->Which() == SwFieldIds::Script
;
1549 if( !bCurField
&& rSh
.IsReadOnlyAvailable() && rSh
.HasReadonlySel() )
1551 rSet
.DisableItem(nWhich
);
1553 else if ( rSh
.CursorInsideInputField() )
1555 rSet
.DisableItem(nWhich
);
1557 // tdf#86188, tdf#135794: Allow disabling comment insertion
1558 // on footnote/endnote/header/frames for better OOXML interoperability
1559 else if (!officecfg::Office::Compatibility::View::AllowCommentsInFootnotes::get() &&
1560 (rSh
.IsCursorInFootnote() || rSh
.IsInHeaderFooter() ||
1561 rSh
.GetCurrFlyFrame(/*bCalcFrame=*/false)))
1563 rSet
.DisableItem(nWhich
);
1569 case FN_INSERT_FLD_AUTHOR
:
1570 case FN_INSERT_FLD_DATE
:
1571 case FN_INSERT_FLD_PGCOUNT
:
1572 case FN_INSERT_FLD_PGNUMBER
:
1573 case FN_INSERT_FLD_TIME
:
1574 case FN_INSERT_FLD_TITLE
:
1575 case FN_INSERT_FLD_TOPIC
:
1576 case FN_INSERT_DBFIELD
:
1577 if ( rSh
.CursorInsideInputField() )
1579 rSet
.DisableItem(nWhich
);
1583 case FN_INSERT_TEXT_FORMFIELD
:
1584 case FN_INSERT_CHECKBOX_FORMFIELD
:
1585 case FN_INSERT_DROPDOWN_FORMFIELD
:
1586 case FN_INSERT_DATE_FORMFIELD
:
1587 if ( rSh
.CursorInsideInputField() )
1589 rSet
.DisableItem(nWhich
);
1593 // Check whether we are in a text form field
1594 SwPosition
aCursorPos(*rSh
.GetCursor()->GetPoint());
1595 sw::mark::IFieldmark
* pFieldBM
= GetShell().getIDocumentMarkAccess()->getInnerFieldmarkFor(aCursorPos
);
1596 if ((!pFieldBM
|| pFieldBM
->GetFieldname() != ODF_FORMTEXT
)
1597 && aCursorPos
.GetContentIndex() > 0)
1599 SwPosition
aPos(*aCursorPos
.GetContentNode(), aCursorPos
.GetContentIndex() - 1);
1600 pFieldBM
= GetShell().getIDocumentMarkAccess()->getInnerFieldmarkFor(aPos
);
1602 if (pFieldBM
&& pFieldBM
->GetFieldname() == ODF_FORMTEXT
&&
1603 (aCursorPos
> pFieldBM
->GetMarkStart() && aCursorPos
< pFieldBM
->GetMarkEnd() ))
1605 rSet
.DisableItem(nWhich
);
1611 nWhich
= aIter
.NextWhich();
1615 void SwTextShell::InsertHyperlink(const SvxHyperlinkItem
& rHlnkItem
)
1617 const OUString
& rName
= rHlnkItem
.GetName();
1618 const OUString
& rURL
= rHlnkItem
.GetURL();
1619 const OUString
& rTarget
= rHlnkItem
.GetTargetFrame();
1620 const OUString
& rReplacementText
= rHlnkItem
.GetReplacementText();
1621 sal_uInt16 nType
= o3tl::narrowing
<sal_uInt16
>(rHlnkItem
.GetInsertMode());
1622 nType
&= ~HLINK_HTMLMODE
;
1623 const SvxMacroTableDtor
* pMacroTable
= rHlnkItem
.GetMacroTable();
1625 SwWrtShell
& rSh
= GetShell();
1627 if( !(rSh
.GetSelectionType() & SelectionType::Text
) )
1631 SfxItemSetFixed
<RES_TXTATR_INETFMT
, RES_TXTATR_INETFMT
> aSet(GetPool());
1632 rSh
.GetCurAttr( aSet
);
1634 if(SfxItemState::SET
== aSet
.GetItemState(RES_TXTATR_INETFMT
, false))
1637 rSh
.SwCursorShell::SelectTextAttr(RES_TXTATR_INETFMT
, false);
1644 SwFormatINetFormat
aINetFormat( rURL
, rTarget
);
1645 aINetFormat
.SetName(rHlnkItem
.GetIntName());
1648 const SvxMacro
*pMacro
= pMacroTable
->Get( SvMacroItemId::OnMouseOver
);
1650 aINetFormat
.SetMacro(SvMacroItemId::OnMouseOver
, *pMacro
);
1651 pMacro
= pMacroTable
->Get( SvMacroItemId::OnClick
);
1653 aINetFormat
.SetMacro(SvMacroItemId::OnClick
, *pMacro
);
1654 pMacro
= pMacroTable
->Get( SvMacroItemId::OnMouseOut
);
1656 aINetFormat
.SetMacro(SvMacroItemId::OnMouseOut
, *pMacro
);
1659 // inserting mention
1660 if (comphelper::LibreOfficeKit::isActive() && !rReplacementText
.isEmpty())
1662 SwPaM
* pCursorPos
= rSh
.GetCursor();
1663 // move cursor backwards to select @mention
1664 for(int i
=0; i
< rReplacementText
.getLength(); i
++)
1665 pCursorPos
->Move(fnMoveBackward
);
1666 rSh
.InsertURL( aINetFormat
, rName
, false );
1670 rSh
.InsertURL( aINetFormat
, rName
, true );
1677 bool bSel
= rSh
.HasSelection();
1680 InsertURLButton( rURL
, rTarget
, rName
);
1687 IMPL_LINK( SwTextShell
, RedlineNextHdl
, AbstractSvxPostItDialog
&, rDlg
, void )
1689 SwWrtShell
* pSh
= GetShellPtr();
1691 // Insert or change a comment.
1692 pSh
->SetRedlineComment(rDlg
.GetNote());
1694 const SwRangeRedline
*pRedline
= pSh
->GetCurrRedline();
1699 // Traveling only if more than one field.
1700 if( !pSh
->IsCursorPtAtEnd() )
1701 pSh
->SwapPam(); // Move the cursor behind the Redline.
1704 const SwRangeRedline
*pActRed
= pSh
->SelNextRedline();
1705 pSh
->Pop((pActRed
!= nullptr) ? SwCursorShell::PopMode::DeleteStack
: SwCursorShell::PopMode::DeleteCurrent
);
1707 bool bEnable
= false;
1713 bEnable
= pSh
->SelNextRedline() != nullptr;
1714 pSh
->Pop(SwCursorShell::PopMode::DeleteCurrent
);
1718 rDlg
.EnableTravel(bEnable
, true);
1720 if( pSh
->IsCursorPtAtEnd() )
1723 pRedline
= pSh
->GetCurrRedline();
1724 OUString sComment
= convertLineEnd(pRedline
->GetComment(), GetSystemLineEnd());
1726 rDlg
.SetNote(sComment
);
1727 rDlg
.ShowLastAuthor( pRedline
->GetAuthorString(),
1728 GetAppLangDateTimeString(
1729 pRedline
->GetRedlineData().GetTimeStamp() ));
1731 rDlg
.SetText(lcl_BuildTitleWithRedline(pRedline
));
1735 IMPL_LINK( SwTextShell
, RedlinePrevHdl
, AbstractSvxPostItDialog
&, rDlg
, void )
1737 SwWrtShell
* pSh
= GetShellPtr();
1739 // Insert or change a comment.
1740 pSh
->SetRedlineComment(rDlg
.GetNote());
1742 const SwRangeRedline
*pRedline
= pSh
->GetCurrRedline();
1747 // Traveling only if more than one field.
1749 const SwRangeRedline
*pActRed
= pSh
->SelPrevRedline();
1750 pSh
->Pop((pActRed
!= nullptr) ? SwCursorShell::PopMode::DeleteStack
: SwCursorShell::PopMode::DeleteCurrent
);
1752 bool bEnable
= false;
1758 bEnable
= pSh
->SelPrevRedline() != nullptr;
1759 pSh
->Pop(SwCursorShell::PopMode::DeleteCurrent
);
1763 rDlg
.EnableTravel(true, bEnable
);
1765 pRedline
= pSh
->GetCurrRedline();
1766 OUString sComment
= convertLineEnd(pRedline
->GetComment(), GetSystemLineEnd());
1768 rDlg
.SetNote(sComment
);
1769 rDlg
.ShowLastAuthor(pRedline
->GetAuthorString(),
1770 GetAppLangDateTimeString(
1771 pRedline
->GetRedlineData().GetTimeStamp() ));
1773 rDlg
.SetText(lcl_BuildTitleWithRedline(pRedline
));
1777 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */