1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <svl/macitem.hxx>
21 #include <sfx2/frame.hxx>
22 #include <svl/eitem.hxx>
23 #include <svl/listener.hxx>
24 #include <svl/stritem.hxx>
25 #include <sfx2/docfile.hxx>
26 #include <sfx2/dispatch.hxx>
27 #include <sfx2/linkmgr.hxx>
28 #include <sfx2/viewfrm.hxx>
29 #include <sot/exchange.hxx>
30 #include <osl/diagnose.h>
31 #include <fmtinfmt.hxx>
32 #include <wrtsh.hxx>
33 #include <docsh.hxx>
34 #include <fldbas.hxx>
35 #include <expfld.hxx>
36 #include <docufld.hxx>
37 #include <reffld.hxx>
38 #include <swundo.hxx>
39 #include <doc.hxx>
40 #include <frmfmt.hxx>
41 #include <fmtfld.hxx>
42 #include <view.hxx>
43 #include <swevent.hxx>
44 #include <section.hxx>
45 #include <navicont.hxx>
46 #include <txtinet.hxx>
47 #include <cmdid.h>
48 #include <swabstdlg.hxx>
49 #include <SwRewriter.hxx>
50 #include <authfld.hxx>
51 
52 #include <com/sun/star/document/XDocumentProperties.hpp>
53 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
54 
55 #include <memory>
56 
57 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
58 #include <comphelper/lok.hxx>
59 #include <sfx2/event.hxx>
60 #include <sal/log.hxx>
61 
InsertField2(SwField const & rField,SwPaM * pAnnotationRange)62 bool SwWrtShell::InsertField2(SwField const& rField, SwPaM* pAnnotationRange)
63 {
64     ResetCursorStack();
65     if(!CanInsert())
66         return false;
67     StartAllAction();
68 
69     SwRewriter aRewriter;
70     aRewriter.AddRule(UndoArg1, rField.GetDescription());
71 
72     StartUndo(SwUndoId::INSERT, &aRewriter);
73 
74     bool bDeleted = false;
75     std::unique_ptr<SwPaM> pAnnotationTextRange;
76     if (pAnnotationRange)
77     {
78         pAnnotationTextRange.reset(new SwPaM(*pAnnotationRange->Start(), *pAnnotationRange->End()));
79     }
80 
81     if ( HasSelection() )
82     {
83         if ( rField.GetTyp()->Which() == SwFieldIds::Postit )
84         {
85             // for annotation fields:
86             // - keep the current selection in order to create a corresponding annotation mark
87             // - collapse cursor to its end
88             if ( IsTableMode() )
89             {
90                 GetTableCrs()->Normalize( false );
91                 const SwPosition rStartPos( *(GetTableCrs()->GetMark()->nNode.GetNode().GetContentNode()), 0 );
92                 KillPams();
93                 if ( !IsEndOfPara() )
94                 {
95                     EndPara();
96                 }
97                 const SwPosition rEndPos( *GetCurrentShellCursor().GetPoint() );
98                 pAnnotationTextRange.reset(new SwPaM( rStartPos, rEndPos ));
99             }
100             else
101             {
102                 NormalizePam( false );
103                 const SwPaM& rCurrPaM = GetCurrentShellCursor();
104                 pAnnotationTextRange.reset(new SwPaM( *rCurrPaM.GetPoint(), *rCurrPaM.GetMark() ));
105                 ClearMark();
106             }
107         }
108         else
109         {
110             bDeleted = DelRight();
111         }
112     }
113 
114     bool const isSuccess = SwEditShell::InsertField(rField, bDeleted);
115 
116     if ( pAnnotationTextRange )
117     {
118         if ( GetDoc() != nullptr )
119         {
120             const SwPaM& rCurrPaM = GetCurrentShellCursor();
121             if (*rCurrPaM.Start() == *pAnnotationTextRange->Start()
122                 && *rCurrPaM.End() == *pAnnotationTextRange->End())
123             {
124                 // Annotation range was passed in externally, and inserting the postit field shifted
125                 // its start/end positions right by one. Restore the original position for the range
126                 // start. This allows commenting on the placeholder character of the field.
127                 SwIndex& rRangeStart = pAnnotationTextRange->Start()->nContent;
128                 if (rRangeStart.GetIndex() > 0)
129                     --rRangeStart;
130             }
131             IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess();
132             pMarksAccess->makeAnnotationMark( *pAnnotationTextRange, OUString() );
133         }
134         pAnnotationTextRange.reset();
135     }
136 
137     EndUndo();
138     EndAllAction();
139 
140     return isSuccess;
141 }
142 
143 // Start the field update
144 
UpdateInputFields(SwInputFieldList * pLst)145 void SwWrtShell::UpdateInputFields( SwInputFieldList* pLst )
146 {
147     // Go through the list of fields and updating
148     std::unique_ptr<SwInputFieldList> pTmp;
149     if (!pLst)
150     {
151         pTmp.reset(new SwInputFieldList( this ));
152         pLst = pTmp.get();
153     }
154 
155     const size_t nCnt = pLst->Count();
156     if(!nCnt)
157         return;
158 
159     pLst->PushCursor();
160 
161     bool bCancel = false;
162 
163     size_t nIndex = 0;
164     FieldDialogPressedButton ePressedButton = FieldDialogPressedButton::NONE;
165 
166     SwField* pField = GetCurField();
167     if (pField)
168     {
169         for (size_t i = 0; i < nCnt; i++)
170         {
171             if (pField == pLst->GetField(i))
172             {
173                 nIndex = i;
174                 break;
175             }
176         }
177     }
178 
179     while (!bCancel)
180     {
181         bool bPrev = nIndex > 0;
182         bool bNext = nIndex < nCnt - 1;
183         pLst->GotoFieldPos(nIndex);
184         pField = pLst->GetField(nIndex);
185         if (pField->GetTyp()->Which() == SwFieldIds::Dropdown)
186         {
187             bCancel = StartDropDownFieldDlg(pField, bPrev, bNext, GetView().GetFrameWeld(), &ePressedButton);
188         }
189         else
190             bCancel = StartInputFieldDlg(pField, bPrev, bNext, GetView().GetFrameWeld(), &ePressedButton);
191 
192         if (!bCancel)
193         {
194             // Otherwise update error at multi-selection:
195             pLst->GetField(nIndex)->GetTyp()->UpdateFields();
196 
197             if (ePressedButton == FieldDialogPressedButton::Previous && nIndex > 0)
198                 nIndex--;
199             else if (ePressedButton == FieldDialogPressedButton::Next && nIndex < nCnt - 1)
200                 nIndex++;
201             else
202                 bCancel = true;
203         }
204     }
205 
206     pLst->PopCursor();
207 }
208 
209 namespace {
210 
211 // Listener class: will close InputField dialog if input field(s)
212 // is(are) deleted (for instance, by an extension) after the dialog shows up.
213 // Otherwise, the for loop in SwWrtShell::UpdateInputFields will crash when doing:
214 //         'pTmp->GetField( i )->GetTyp()->UpdateFields();'
215 // on a deleted field.
216 class FieldDeletionListener : public SvtListener
217 {
218     public:
FieldDeletionListener(AbstractFieldInputDlg * pInputFieldDlg,SwField * pField)219         FieldDeletionListener(AbstractFieldInputDlg* pInputFieldDlg, SwField* pField)
220             : mpInputFieldDlg(pInputFieldDlg)
221             , mpFormatField(nullptr)
222         {
223             SwInputField *const pInputField(dynamic_cast<SwInputField*>(pField));
224             SwSetExpField *const pSetExpField(dynamic_cast<SwSetExpField*>(pField));
225 
226             if (pInputField && pInputField->GetFormatField())
227             {
228                 mpFormatField = pInputField->GetFormatField();
229             }
230             else if (pSetExpField && pSetExpField->GetFormatField())
231             {
232                 mpFormatField = pSetExpField->GetFormatField();
233             }
234 
235             // Register for possible field deletion while dialog is open
236             if (mpFormatField)
237                 StartListening(mpFormatField->GetNotifier());
238         }
239 
~FieldDeletionListener()240         virtual ~FieldDeletionListener() override
241         {
242             // Dialog closed, remove modification listener
243             EndListeningAll();
244         }
245 
Notify(const SfxHint & rHint)246         virtual void Notify(const SfxHint& rHint) override
247         {
248             // Input field has been deleted: better to close the dialog
249             if(rHint.GetId() == SfxHintId::Dying)
250             {
251                 mpFormatField = nullptr;
252                 mpInputFieldDlg->EndDialog(RET_CANCEL);
253             }
254         }
255     private:
256         VclPtr<AbstractFieldInputDlg> mpInputFieldDlg;
257         SwFormatField* mpFormatField;
258 };
259 
260 }
261 
262 // Start input dialog for a specific field
StartInputFieldDlg(SwField * pField,bool bPrevButton,bool bNextButton,weld::Widget * pParentWin,SwWrtShell::FieldDialogPressedButton * pPressedButton)263 bool SwWrtShell::StartInputFieldDlg(SwField* pField, bool bPrevButton, bool bNextButton,
264                                     weld::Widget* pParentWin, SwWrtShell::FieldDialogPressedButton* pPressedButton)
265 {
266 
267     SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
268     ScopedVclPtr<AbstractFieldInputDlg> pDlg(pFact->CreateFieldInputDlg(pParentWin, *this, pField, bPrevButton, bNextButton));
269 
270     bool bRet;
271 
272     {
273         FieldDeletionListener aModify(pDlg.get(), pField);
274         bRet = RET_CANCEL == pDlg->Execute();
275     }
276 
277     if (pPressedButton)
278     {
279         if (pDlg->PrevButtonPressed())
280             *pPressedButton = FieldDialogPressedButton::Previous;
281         else if (pDlg->NextButtonPressed())
282             *pPressedButton = FieldDialogPressedButton::Next;
283     }
284 
285     pDlg.disposeAndClear();
286     GetWin()->PaintImmediately();
287     return bRet;
288 }
289 
StartDropDownFieldDlg(SwField * pField,bool bPrevButton,bool bNextButton,weld::Widget * pParentWin,SwWrtShell::FieldDialogPressedButton * pPressedButton)290 bool SwWrtShell::StartDropDownFieldDlg(SwField* pField, bool bPrevButton, bool bNextButton,
291                                        weld::Widget* pParentWin, SwWrtShell::FieldDialogPressedButton* pPressedButton)
292 {
293     SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
294     ScopedVclPtr<AbstractDropDownFieldDialog> pDlg(pFact->CreateDropDownFieldDialog(pParentWin, *this, pField, bPrevButton, bNextButton));
295     const short nRet = pDlg->Execute();
296 
297     if (pPressedButton)
298     {
299         if (pDlg->PrevButtonPressed())
300             *pPressedButton = FieldDialogPressedButton::Previous;
301         else if (pDlg->NextButtonPressed())
302             *pPressedButton = FieldDialogPressedButton::Next;
303     }
304 
305     pDlg.disposeAndClear();
306     bool bRet = RET_CANCEL == nRet;
307     GetWin()->PaintImmediately();
308     if(RET_YES == nRet)
309     {
310         GetView().GetViewFrame()->GetDispatcher()->Execute(FN_EDIT_FIELD, SfxCallMode::SYNCHRON);
311     }
312     return bRet;
313 }
314 
315 // Insert directory - remove selection
316 
InsertTableOf(const SwTOXBase & rTOX,const SfxItemSet * pSet)317 void SwWrtShell::InsertTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
318 {
319     if(!CanInsert())
320         return;
321 
322     if(HasSelection())
323         DelRight();
324 
325     SwEditShell::InsertTableOf(rTOX, pSet);
326 }
327 
328 // Update directory - remove selection
329 
UpdateTableOf(const SwTOXBase & rTOX,const SfxItemSet * pSet)330 void SwWrtShell::UpdateTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
331 {
332     if(CanInsert())
333     {
334         SwEditShell::UpdateTableOf(rTOX, pSet);
335     }
336 }
337 
338 // handler for click on the field given as parameter.
339 // the cursor is positioned on the field.
340 
ClickToField(const SwField & rField,bool bExecHyperlinks)341 void SwWrtShell::ClickToField(const SwField& rField, bool bExecHyperlinks)
342 {
343     // cross reference field must not be selected because it moves the cursor
344     if (SwFieldIds::GetRef != rField.GetTyp()->Which())
345     {
346         StartAllAction();
347         Right( CRSR_SKIP_CHARS, true, 1, false ); // Select the field.
348         NormalizePam();
349         EndAllAction();
350     }
351 
352     m_bIsInClickToEdit = true;
353     switch( rField.GetTyp()->Which() )
354     {
355     case SwFieldIds::JumpEdit:
356         {
357             sal_uInt16 nSlotId = 0;
358             switch( rField.GetFormat() )
359             {
360             case JE_FMT_TABLE:
361                 nSlotId = FN_INSERT_TABLE;
362                 break;
363 
364             case JE_FMT_FRAME:
365                 nSlotId = FN_INSERT_FRAME;
366                 break;
367 
368             case JE_FMT_GRAPHIC:    nSlotId = SID_INSERT_GRAPHIC;       break;
369             case JE_FMT_OLE:        nSlotId = SID_INSERT_OBJECT;        break;
370 
371             }
372 
373             if( nSlotId )
374             {
375                 StartUndo( SwUndoId::START );
376                 //#97295# immediately select the right shell
377                 GetView().StopShellTimer();
378                 GetView().GetViewFrame()->GetDispatcher()->Execute( nSlotId,
379                             SfxCallMode::SYNCHRON|SfxCallMode::RECORD );
380                 EndUndo( SwUndoId::END );
381             }
382         }
383         break;
384 
385     case SwFieldIds::Macro:
386         {
387             const SwMacroField *pField = static_cast<const SwMacroField*>(&rField);
388             const OUString sText( rField.GetPar2() );
389             OUString sRet( sText );
390             ExecMacro( pField->GetSvxMacro(), &sRet );
391 
392             // return value changed?
393             if( sRet != sText )
394             {
395                 StartAllAction();
396                 const_cast<SwField&>(rField).SetPar2( sRet );
397                 rField.GetTyp()->UpdateFields();
398                 EndAllAction();
399             }
400         }
401         break;
402 
403     case SwFieldIds::TableOfAuthorities:
404         {
405             if (!bExecHyperlinks)
406             {
407                 break;
408             }
409 
410             auto pField = static_cast<const SwAuthorityField*>(&rField);
411             if (!pField->HasURL())
412             {
413                 break;
414             }
415 
416             const OUString& rURL = pField->GetAbsoluteURL();
417             ::LoadURL(*this, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
418         }
419         break;
420 
421     case SwFieldIds::GetRef:
422         StartAllAction();
423         SwCursorShell::GotoRefMark( static_cast<const SwGetRefField&>(rField).GetSetRefName(),
424                                     static_cast<const SwGetRefField&>(rField).GetSubType(),
425                                     static_cast<const SwGetRefField&>(rField).GetSeqNo() );
426         EndAllAction();
427         break;
428 
429     case SwFieldIds::Input:
430         {
431             const SwInputField* pInputField = dynamic_cast<const SwInputField*>(&rField);
432             if ( pInputField == nullptr )
433             {
434                 StartInputFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
435             }
436         }
437         break;
438 
439     case SwFieldIds::SetExp:
440         if( static_cast<const SwSetExpField&>(rField).GetInputFlag() )
441             StartInputFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
442         break;
443     case SwFieldIds::Dropdown :
444         StartDropDownFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
445     break;
446     default:
447         SAL_WARN_IF(rField.IsClickable(), "sw", "unhandled clickable field!");
448     }
449 
450     m_bIsInClickToEdit = false;
451 }
452 
ClickToINetAttr(const SwFormatINetFormat & rItem,LoadUrlFlags nFilter)453 void SwWrtShell::ClickToINetAttr( const SwFormatINetFormat& rItem, LoadUrlFlags nFilter )
454 {
455     if( rItem.GetValue().isEmpty() )
456         return ;
457 
458     m_bIsInClickToEdit = true;
459 
460     // At first run the possibly set ObjectSelect Macro
461     const SvxMacro* pMac = rItem.GetMacro( SvMacroItemId::OnClick );
462     if( pMac )
463     {
464         SwCallMouseEvent aCallEvent;
465         aCallEvent.Set( &rItem );
466         GetDoc()->CallEvent( SvMacroItemId::OnClick, aCallEvent );
467     }
468 
469     // So that the implementation of templates is displayed immediately
470     ::LoadURL( *this, rItem.GetValue(), nFilter, rItem.GetTargetFrame() );
471     const SwTextINetFormat* pTextAttr = rItem.GetTextINetFormat();
472     if( pTextAttr )
473     {
474         const_cast<SwTextINetFormat*>(pTextAttr)->SetVisited( true );
475         const_cast<SwTextINetFormat*>(pTextAttr)->SetVisitedValid( true );
476     }
477 
478     m_bIsInClickToEdit = false;
479 }
480 
ClickToINetGrf(const Point & rDocPt,LoadUrlFlags nFilter)481 bool SwWrtShell::ClickToINetGrf( const Point& rDocPt, LoadUrlFlags nFilter )
482 {
483     bool bRet = false;
484     OUString sURL;
485     OUString sTargetFrameName;
486     const SwFrameFormat* pFnd = IsURLGrfAtPos( rDocPt, &sURL, &sTargetFrameName );
487     if( pFnd && !sURL.isEmpty() )
488     {
489         bRet = true;
490         // At first run the possibly set ObjectSelect Macro
491         SwCallMouseEvent aCallEvent;
492         aCallEvent.Set(EVENT_OBJECT_URLITEM, pFnd);
493         GetDoc()->CallEvent(SvMacroItemId::OnClick, aCallEvent);
494 
495         ::LoadURL(*this, sURL, nFilter, sTargetFrameName);
496     }
497     return bRet;
498 }
499 
LoadURL(SwViewShell & rVSh,const OUString & rURL,LoadUrlFlags nFilter,const OUString & rTargetFrameName)500 void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
501               const OUString& rTargetFrameName )
502 {
503     OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
504     if( rURL.isEmpty() )
505         return ;
506 
507     // The shell could be 0 also!!!!!
508     if ( dynamic_cast<const SwCursorShell*>( &rVSh) ==  nullptr )
509         return;
510 
511     // We are doing tiledRendering, let the client handles the URL loading,
512     // unless we are jumping to a TOC mark.
513     if (comphelper::LibreOfficeKit::isActive() && !rURL.startsWith("#"))
514     {
515         rVSh.GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, rURL.toUtf8().getStr());
516         return;
517     }
518 
519     //A CursorShell is always a WrtShell
520     SwWrtShell &rSh = static_cast<SwWrtShell&>(rVSh);
521 
522     SwDocShell* pDShell = rSh.GetView().GetDocShell();
523     OSL_ENSURE( pDShell, "No DocShell?!");
524     OUString sTargetFrame(rTargetFrameName);
525     if (sTargetFrame.isEmpty() && pDShell)
526     {
527         using namespace ::com::sun::star;
528         uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
529             pDShell->GetModel(), uno::UNO_QUERY_THROW);
530         uno::Reference<document::XDocumentProperties> xDocProps
531             = xDPS->getDocumentProperties();
532         sTargetFrame = xDocProps->getDefaultTarget();
533     }
534 
535     OUString sReferer;
536     if( pDShell && pDShell->GetMedium() )
537         sReferer = pDShell->GetMedium()->GetName();
538     SfxViewFrame* pViewFrame = rSh.GetView().GetViewFrame();
539     SfxFrameItem aView( SID_DOCFRAME, pViewFrame );
540     SfxStringItem aName( SID_FILE_NAME, rURL );
541     SfxStringItem aTargetFrameName( SID_TARGETNAME, sTargetFrame );
542     SfxStringItem aReferer( SID_REFERER, sReferer );
543 
544     SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, false );
545     //#39076# Silent can be removed accordingly to SFX.
546     SfxBoolItem aBrowse( SID_BROWSE, true );
547 
548     if ((nFilter & LoadUrlFlags::NewView) && !comphelper::LibreOfficeKit::isActive())
549         aTargetFrameName.SetValue( "_blank" );
550 
551     const SfxPoolItem* aArr[] = {
552                 &aName,
553                 &aNewView, /*&aSilent,*/
554                 &aReferer,
555                 &aView, &aTargetFrameName,
556                 &aBrowse,
557                 nullptr
558     };
559 
560     pViewFrame->GetDispatcher()->GetBindings()->Execute( SID_OPENDOC, aArr,
561             SfxCallMode::ASYNCHRON|SfxCallMode::RECORD );
562 }
563 
NavigatorPaste(const NaviContentBookmark & rBkmk,const sal_uInt16 nAction)564 void SwWrtShell::NavigatorPaste( const NaviContentBookmark& rBkmk,
565                                     const sal_uInt16 nAction )
566 {
567     if( EXCHG_IN_ACTION_COPY == nAction )
568     {
569         // Insert
570         OUString sURL = rBkmk.GetURL();
571         // Is this is a jump within the current Doc?
572         const SwDocShell* pDocShell = GetView().GetDocShell();
573         if(pDocShell->HasName())
574         {
575             const OUString rName = pDocShell->GetMedium()->GetURLObject().GetURLNoMark();
576 
577             if (sURL.startsWith(rName))
578             {
579                 if (sURL.getLength()>rName.getLength())
580                 {
581                     sURL = sURL.copy(rName.getLength());
582                 }
583                 else
584                 {
585                     sURL.clear();
586                 }
587             }
588         }
589         SwFormatINetFormat aFormat( sURL, OUString() );
590         InsertURL( aFormat, rBkmk.GetDescription() );
591     }
592     else
593     {
594         SwSectionData aSection( SectionType::FileLink, GetUniqueSectionName() );
595         OUString aLinkFile = rBkmk.GetURL().getToken(0, '#')
596             + OUStringChar(sfx2::cTokenSeparator)
597             + OUStringChar(sfx2::cTokenSeparator)
598             + rBkmk.GetURL().getToken(1, '#');
599         aSection.SetLinkFileName( aLinkFile );
600         aSection.SetProtectFlag( true );
601         const SwSection* pIns = InsertSection( aSection );
602         if( EXCHG_IN_ACTION_MOVE == nAction && pIns )
603         {
604             aSection = SwSectionData(*pIns);
605             aSection.SetLinkFileName( OUString() );
606             aSection.SetType( SectionType::Content );
607             aSection.SetProtectFlag( false );
608 
609             // the update of content from linked section at time delete
610             // the undostack. Then the change of the section don't create
611             // any undoobject. -  BUG 69145
612             bool bDoesUndo = DoesUndo();
613             SwUndoId nLastUndoId(SwUndoId::EMPTY);
614             if (GetLastUndoInfo(nullptr, & nLastUndoId))
615             {
616                 if (SwUndoId::INSSECTION != nLastUndoId)
617                 {
618                     DoUndo(false);
619                 }
620             }
621             UpdateSection( GetSectionFormatPos( *pIns->GetFormat() ), aSection );
622             DoUndo( bDoesUndo );
623         }
624     }
625 }
626 
627 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
628