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 <UndoManager.hxx>
21
22 #include <svx/svdmodel.hxx>
23 #include <swmodule.hxx>
24 #include <doc.hxx>
25 #include <docsh.hxx>
26 #include <view.hxx>
27 #include <drawdoc.hxx>
28 #include <ndarr.hxx>
29 #include <pam.hxx>
30 #include <ndtxt.hxx>
31 #include <swundo.hxx>
32 #include <UndoCore.hxx>
33 #include <rolbck.hxx>
34 #include <editsh.hxx>
35 #include <unobaseclass.hxx>
36 #include <limits>
37 #include <IDocumentDrawModelAccess.hxx>
38 #include <IDocumentRedlineAccess.hxx>
39 #include <IDocumentState.hxx>
40 #include <comphelper/lok.hxx>
41 #include <assert.h>
42
43 #include <sfx2/viewfrm.hxx>
44 #include <sfx2/bindings.hxx>
45
46 using namespace ::com::sun::star;
47
48 // the undo array should never grow beyond this limit:
49 #define UNDO_ACTION_LIMIT (USHRT_MAX - 1000)
50
51 namespace sw {
52
UndoManager(std::shared_ptr<SwNodes> const & xUndoNodes,IDocumentDrawModelAccess & rDrawModelAccess,IDocumentRedlineAccess & rRedlineAccess,IDocumentState & rState)53 UndoManager::UndoManager(std::shared_ptr<SwNodes> const & xUndoNodes,
54 IDocumentDrawModelAccess & rDrawModelAccess,
55 IDocumentRedlineAccess & rRedlineAccess,
56 IDocumentState & rState)
57 : m_rDrawModelAccess(rDrawModelAccess)
58 , m_rRedlineAccess(rRedlineAccess)
59 , m_rState(rState)
60 , m_xUndoNodes(xUndoNodes)
61 , m_bGroupUndo(true)
62 , m_bDrawUndo(true)
63 , m_bRepair(false)
64 , m_bLockUndoNoModifiedPosition(false)
65 , m_isAddWithIgnoreRepeat(false)
66 , m_UndoSaveMark(MARK_INVALID)
67 , m_pDocShell(nullptr)
68 , m_pView(nullptr)
69 {
70 assert(m_xUndoNodes.get());
71 // writer expects it to be disabled initially
72 // Undo is enabled by SwEditShell constructor
73 SdrUndoManager::EnableUndo(false);
74 }
75
GetUndoNodes() const76 SwNodes const& UndoManager::GetUndoNodes() const
77 {
78 return *m_xUndoNodes;
79 }
80
GetUndoNodes()81 SwNodes & UndoManager::GetUndoNodes()
82 {
83 return *m_xUndoNodes;
84 }
85
IsUndoNodes(SwNodes const & rNodes) const86 bool UndoManager::IsUndoNodes(SwNodes const& rNodes) const
87 {
88 return & rNodes == m_xUndoNodes.get();
89 }
90
SetDocShell(SwDocShell * pDocShell)91 void UndoManager::SetDocShell(SwDocShell* pDocShell)
92 {
93 m_pDocShell = pDocShell;
94 }
95
SetView(SwView * pView)96 void UndoManager::SetView(SwView* pView)
97 {
98 m_pView = pView;
99 }
100
GetUndoActionCount(const bool bCurrentLevel) const101 size_t UndoManager::GetUndoActionCount(const bool bCurrentLevel) const
102 {
103 size_t nRet = SdrUndoManager::GetUndoActionCount(bCurrentLevel);
104 if (!comphelper::LibreOfficeKit::isActive() || !m_pView)
105 return nRet;
106
107 if (!nRet || !SdrUndoManager::GetUndoActionCount())
108 return nRet;
109
110 const SfxUndoAction* pAction = SdrUndoManager::GetUndoAction();
111 if (!pAction)
112 return nRet;
113
114 if (!m_bRepair)
115 {
116 // If another view created the last undo action, prevent undoing it from this view.
117 ViewShellId nViewShellId = m_pView->GetViewShellId();
118 if (pAction->GetViewShellId() != nViewShellId)
119 nRet = 0;
120 }
121
122 return nRet;
123 }
124
GetRedoActionCount(const bool bCurrentLevel) const125 size_t UndoManager::GetRedoActionCount(const bool bCurrentLevel) const
126 {
127 size_t nRet = SdrUndoManager::GetRedoActionCount(bCurrentLevel);
128 if (!comphelper::LibreOfficeKit::isActive() || !m_pView)
129 return nRet;
130
131 if (!nRet || !SdrUndoManager::GetRedoActionCount())
132 return nRet;
133
134 const SfxUndoAction* pAction = SdrUndoManager::GetRedoAction();
135 if (!pAction)
136 return nRet;
137
138 if (!m_bRepair)
139 {
140 // If another view created the first redo action, prevent redoing it from this view.
141 ViewShellId nViewShellId = m_pView->GetViewShellId();
142 if (pAction->GetViewShellId() != nViewShellId)
143 nRet = 0;
144 }
145
146 return nRet;
147 }
148
DoUndo(bool const bDoUndo)149 void UndoManager::DoUndo(bool const bDoUndo)
150 {
151 if(!isTextEditActive())
152 {
153 EnableUndo(bDoUndo);
154
155 SwDrawModel*const pSdrModel = m_rDrawModelAccess.GetDrawModel();
156 if( pSdrModel )
157 {
158 pSdrModel->EnableUndo(bDoUndo);
159 }
160 }
161 }
162
DoesUndo() const163 bool UndoManager::DoesUndo() const
164 {
165 if(isTextEditActive())
166 {
167 return false;
168 }
169 else
170 {
171 return IsUndoEnabled();
172 }
173 }
174
DoGroupUndo(bool const bDoUndo)175 void UndoManager::DoGroupUndo(bool const bDoUndo)
176 {
177 m_bGroupUndo = bDoUndo;
178 }
179
DoesGroupUndo() const180 bool UndoManager::DoesGroupUndo() const
181 {
182 return m_bGroupUndo;
183 }
184
DoDrawUndo(bool const bDoUndo)185 void UndoManager::DoDrawUndo(bool const bDoUndo)
186 {
187 m_bDrawUndo = bDoUndo;
188 }
189
DoesDrawUndo() const190 bool UndoManager::DoesDrawUndo() const
191 {
192 return m_bDrawUndo;
193 }
194
DoRepair(bool bRepair)195 void UndoManager::DoRepair(bool bRepair)
196 {
197 m_bRepair = bRepair;
198 }
199
DoesRepair() const200 bool UndoManager::DoesRepair() const
201 {
202 return m_bRepair;
203 }
204
IsUndoNoResetModified() const205 bool UndoManager::IsUndoNoResetModified() const
206 {
207 return MARK_INVALID == m_UndoSaveMark;
208 }
209
SetUndoNoResetModified()210 void UndoManager::SetUndoNoResetModified()
211 {
212 if (MARK_INVALID != m_UndoSaveMark)
213 {
214 RemoveMark(m_UndoSaveMark);
215 m_UndoSaveMark = MARK_INVALID;
216 }
217 }
218
SetUndoNoModifiedPosition()219 void UndoManager::SetUndoNoModifiedPosition()
220 {
221 if (!m_bLockUndoNoModifiedPosition)
222 {
223 m_UndoSaveMark = MarkTopUndoAction();
224 }
225 }
226
LockUndoNoModifiedPosition()227 void UndoManager::LockUndoNoModifiedPosition()
228 {
229 m_bLockUndoNoModifiedPosition = true;
230 }
231
UnLockUndoNoModifiedPosition()232 void UndoManager::UnLockUndoNoModifiedPosition()
233 {
234 m_bLockUndoNoModifiedPosition = false;
235 }
236
GetLastUndo()237 SwUndo* UndoManager::GetLastUndo()
238 {
239 if (!SdrUndoManager::GetUndoActionCount())
240 {
241 return nullptr;
242 }
243 SfxUndoAction *const pAction( SdrUndoManager::GetUndoAction() );
244 return dynamic_cast<SwUndo*>(pAction);
245 }
246
AppendUndo(std::unique_ptr<SwUndo> pUndo)247 void UndoManager::AppendUndo(std::unique_ptr<SwUndo> pUndo)
248 {
249 AddUndoAction(std::move(pUndo));
250 }
251
ClearRedo()252 void UndoManager::ClearRedo()
253 {
254 return SdrUndoManager::ImplClearRedo_NoLock(TopLevel);
255 }
256
DelAllUndoObj()257 void UndoManager::DelAllUndoObj()
258 {
259 ::sw::UndoGuard const undoGuard(*this);
260
261 SdrUndoManager::ClearAllLevels();
262
263 m_UndoSaveMark = MARK_INVALID;
264 }
265
266 SwUndoId
StartUndo(SwUndoId const i_eUndoId,SwRewriter const * const pRewriter)267 UndoManager::StartUndo(SwUndoId const i_eUndoId,
268 SwRewriter const*const pRewriter)
269 {
270 if (!IsUndoEnabled())
271 {
272 return SwUndoId::EMPTY;
273 }
274
275 SwUndoId const eUndoId( (i_eUndoId == SwUndoId::EMPTY) ? SwUndoId::START : i_eUndoId );
276
277 assert(SwUndoId::END != eUndoId);
278 OUString comment( (SwUndoId::START == eUndoId)
279 ? OUString("??")
280 : GetUndoComment(eUndoId) );
281 if (pRewriter)
282 {
283 assert(SwUndoId::START != eUndoId);
284 comment = pRewriter->Apply(comment);
285 }
286
287 ViewShellId nViewShellId(-1);
288 if (m_pDocShell)
289 {
290 if (const SwView* pView = m_pDocShell->GetView())
291 nViewShellId = pView->GetViewShellId();
292 }
293 SdrUndoManager::EnterListAction(comment, comment, static_cast<sal_uInt16>(eUndoId), nViewShellId);
294
295 return eUndoId;
296 }
297
298 SwUndoId
EndUndo(SwUndoId eUndoId,SwRewriter const * const pRewriter)299 UndoManager::EndUndo(SwUndoId eUndoId, SwRewriter const*const pRewriter)
300 {
301 if (!IsUndoEnabled())
302 {
303 return SwUndoId::EMPTY;
304 }
305
306 if ((eUndoId == SwUndoId::EMPTY) || (SwUndoId::START == eUndoId))
307 eUndoId = SwUndoId::END;
308 OSL_ENSURE(!((SwUndoId::END == eUndoId) && pRewriter),
309 "EndUndo(): no Undo ID, but rewriter given?");
310
311 SfxUndoAction *const pLastUndo(
312 (0 == SdrUndoManager::GetUndoActionCount())
313 ? nullptr : SdrUndoManager::GetUndoAction() );
314
315 int const nCount = LeaveListAction();
316
317 if (nCount) // otherwise: empty list action not inserted!
318 {
319 assert(pLastUndo);
320 assert(SwUndoId::START != eUndoId);
321 auto pListAction = dynamic_cast<SfxListUndoAction*>(SdrUndoManager::GetUndoAction());
322 assert(pListAction);
323 if (SwUndoId::END != eUndoId)
324 {
325 OSL_ENSURE(static_cast<SwUndoId>(pListAction->GetId()) == eUndoId,
326 "EndUndo(): given ID different from StartUndo()");
327 // comment set by caller of EndUndo
328 OUString comment = GetUndoComment(eUndoId);
329 if (pRewriter)
330 {
331 comment = pRewriter->Apply(comment);
332 }
333 pListAction->SetComment(comment);
334 }
335 else if (SwUndoId::START != static_cast<SwUndoId>(pListAction->GetId()))
336 {
337 // comment set by caller of StartUndo: nothing to do here
338 }
339 else if (pLastUndo)
340 {
341 // comment was not set at StartUndo or EndUndo:
342 // take comment of last contained action
343 // (note that this works recursively, i.e. the last contained
344 // action may be a list action created by StartUndo/EndUndo)
345 OUString const comment(pLastUndo->GetComment());
346 pListAction->SetComment(comment);
347 }
348 else
349 {
350 OSL_ENSURE(false, "EndUndo(): no comment?");
351 }
352 }
353
354 return eUndoId;
355 }
356
357 bool
GetLastUndoInfo(OUString * const o_pStr,SwUndoId * const o_pId,const SwView * pView) const358 UndoManager::GetLastUndoInfo(
359 OUString *const o_pStr, SwUndoId *const o_pId, const SwView* pView) const
360 {
361 // this is actually expected to work on the current level,
362 // but that was really not obvious from the previous implementation...
363 if (!SdrUndoManager::GetUndoActionCount())
364 {
365 return false;
366 }
367
368 SfxUndoAction *const pAction( SdrUndoManager::GetUndoAction() );
369
370 if (comphelper::LibreOfficeKit::isActive() && !m_bRepair)
371 {
372 // If another view created the undo action, prevent undoing it from this view.
373 ViewShellId nViewShellId = pView ? pView->GetViewShellId() : m_pDocShell->GetView()->GetViewShellId();
374 if (pAction->GetViewShellId() != nViewShellId)
375 {
376 if (o_pId)
377 {
378 *o_pId = SwUndoId::CONFLICT;
379 }
380 return false;
381 }
382 }
383
384 if (o_pStr)
385 {
386 *o_pStr = pAction->GetComment();
387 }
388 if (o_pId)
389 {
390 if (auto pListAction = dynamic_cast<const SfxListUndoAction*>(pAction))
391 *o_pId = static_cast<SwUndoId>(pListAction->GetId());
392 else if (auto pSwAction = dynamic_cast<const SwUndo*>(pAction))
393 *o_pId = pSwAction->GetId();
394 else
395 *o_pId = SwUndoId::EMPTY;
396 }
397
398 return true;
399 }
400
GetUndoComments() const401 SwUndoComments_t UndoManager::GetUndoComments() const
402 {
403 OSL_ENSURE(!SdrUndoManager::IsInListAction(),
404 "GetUndoComments() called while in list action?");
405
406 SwUndoComments_t ret;
407 const size_t nUndoCount(SdrUndoManager::GetUndoActionCount(TopLevel));
408 for (size_t n = 0; n < nUndoCount; ++n)
409 {
410 OUString const comment(
411 SdrUndoManager::GetUndoActionComment(n, TopLevel));
412 ret.push_back(comment);
413 }
414
415 return ret;
416 }
417
GetFirstRedoInfo(OUString * const o_pStr,SwUndoId * const o_pId,const SwView * pView) const418 bool UndoManager::GetFirstRedoInfo(OUString *const o_pStr,
419 SwUndoId *const o_pId,
420 const SwView* pView) const
421 {
422 if (!SdrUndoManager::GetRedoActionCount())
423 {
424 return false;
425 }
426
427 SfxUndoAction *const pAction( SdrUndoManager::GetRedoAction() );
428 if ( pAction == nullptr )
429 {
430 return false;
431 }
432
433 if (comphelper::LibreOfficeKit::isActive() && !m_bRepair)
434 {
435 // If another view created the undo action, prevent redoing it from this view.
436 ViewShellId nViewShellId = pView ? pView->GetViewShellId() : m_pDocShell->GetView()->GetViewShellId();
437 if (pAction->GetViewShellId() != nViewShellId)
438 {
439 if (o_pId)
440 {
441 *o_pId = SwUndoId::CONFLICT;
442 }
443 return false;
444 }
445 }
446
447 if (o_pStr)
448 {
449 *o_pStr = pAction->GetComment();
450 }
451 if (o_pId)
452 {
453 if (auto pListAction = dynamic_cast<const SfxListUndoAction*>(pAction))
454 *o_pId = static_cast<SwUndoId>(pListAction->GetId());
455 else if (auto pSwAction = dynamic_cast<const SwUndo*>(pAction))
456 *o_pId = pSwAction->GetId();
457 else
458 *o_pId = SwUndoId::EMPTY;
459 }
460
461 return true;
462 }
463
GetRedoComments() const464 SwUndoComments_t UndoManager::GetRedoComments() const
465 {
466 OSL_ENSURE(!SdrUndoManager::IsInListAction(),
467 "GetRedoComments() called while in list action?");
468
469 SwUndoComments_t ret;
470 const size_t nRedoCount(SdrUndoManager::GetRedoActionCount(TopLevel));
471 for (size_t n = 0; n < nRedoCount; ++n)
472 {
473 OUString const comment(
474 SdrUndoManager::GetRedoActionComment(n, TopLevel));
475 ret.push_back(comment);
476 }
477
478 return ret;
479 }
480
GetRepeatInfo(OUString * const o_pStr) const481 SwUndoId UndoManager::GetRepeatInfo(OUString *const o_pStr) const
482 {
483 SwUndoId nRepeatId(SwUndoId::EMPTY);
484 GetLastUndoInfo(o_pStr, & nRepeatId);
485 if( SwUndoId::REPEAT_START <= nRepeatId && SwUndoId::REPEAT_END > nRepeatId )
486 {
487 return nRepeatId;
488 }
489 if (o_pStr) // not repeatable -> clear comment
490 {
491 o_pStr->clear();
492 }
493 return SwUndoId::EMPTY;
494 }
495
RemoveLastUndo()496 SwUndo * UndoManager::RemoveLastUndo()
497 {
498 if (SdrUndoManager::GetRedoActionCount() ||
499 SdrUndoManager::GetRedoActionCount(TopLevel))
500 {
501 OSL_ENSURE(false, "RemoveLastUndoAction(): there are Redo actions?");
502 return nullptr;
503 }
504 if (!SdrUndoManager::GetUndoActionCount())
505 {
506 OSL_ENSURE(false, "RemoveLastUndoAction(): no Undo actions");
507 return nullptr;
508 }
509 SfxUndoAction *const pLastUndo(GetUndoAction());
510 SdrUndoManager::RemoveLastUndoAction();
511 return dynamic_cast<SwUndo *>(pLastUndo);
512 }
513
514 // SfxUndoManager
515
AddUndoAction(std::unique_ptr<SfxUndoAction> pAction,bool bTryMerge)516 void UndoManager::AddUndoAction(std::unique_ptr<SfxUndoAction> pAction, bool bTryMerge)
517 {
518 SwUndo *const pUndo( dynamic_cast<SwUndo *>(pAction.get()) );
519 if (pUndo)
520 {
521 if (RedlineFlags::NONE == pUndo->GetRedlineFlags())
522 {
523 pUndo->SetRedlineFlags( m_rRedlineAccess.GetRedlineFlags() );
524 }
525 if (m_isAddWithIgnoreRepeat)
526 {
527 pUndo->IgnoreRepeat();
528 }
529 }
530 SdrUndoManager::AddUndoAction(std::move(pAction), bTryMerge);
531 if (m_pDocShell)
532 {
533 SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( m_pDocShell );
534 while ( pViewFrame )
535 {
536 pViewFrame->GetBindings().Invalidate( SID_UNDO );
537 pViewFrame->GetBindings().Invalidate( SID_REDO );
538 pViewFrame = SfxViewFrame::GetNext( *pViewFrame, m_pDocShell );
539 }
540 }
541
542 // if the undo nodes array is too large, delete some actions
543 while (UNDO_ACTION_LIMIT < GetUndoNodes().Count())
544 {
545 RemoveOldestUndoAction();
546 }
547 }
548
549 class CursorGuard
550 {
551 public:
CursorGuard(SwEditShell & rShell,bool const bSave)552 CursorGuard(SwEditShell & rShell, bool const bSave)
553 : m_rShell(rShell)
554 , m_bSaveCursor(bSave)
555 {
556 if (m_bSaveCursor)
557 {
558 m_rShell.Push(); // prevent modification of current cursor
559 }
560 }
~CursorGuard()561 ~CursorGuard() COVERITY_NOEXCEPT_FALSE
562 {
563 if (m_bSaveCursor)
564 {
565 m_rShell.Pop(SwCursorShell::PopMode::DeleteCurrent);
566 }
567 }
568 private:
569 SwEditShell & m_rShell;
570 bool const m_bSaveCursor;
571 };
572
impl_DoUndoRedo(UndoOrRedoType undoOrRedo)573 bool UndoManager::impl_DoUndoRedo(UndoOrRedoType undoOrRedo)
574 {
575 SwDoc & rDoc(*GetUndoNodes().GetDoc());
576
577 UnoActionContext c(& rDoc); // exception-safe StartAllAction/EndAllAction
578
579 SwEditShell *const pEditShell( rDoc.GetEditShell() );
580
581 OSL_ENSURE(pEditShell, "sw::UndoManager needs a SwEditShell!");
582 if (!pEditShell)
583 {
584 throw uno::RuntimeException();
585 }
586
587 // in case the model has controllers locked, the Undo should not
588 // change the view cursors!
589 bool const bSaveCursors(pEditShell->CursorsLocked());
590 CursorGuard aCursorGuard(*pEditShell, bSaveCursors);
591 if (!bSaveCursors)
592 {
593 // (in case Undo was called via API) clear the cursors:
594 pEditShell->KillPams();
595 pEditShell->SetMark();
596 pEditShell->ClearMark();
597 }
598
599 bool bRet(false);
600
601 ::sw::UndoRedoContext context(rDoc, *pEditShell);
602
603 // N.B. these may throw!
604 if (UndoOrRedoType::Undo == undoOrRedo)
605 {
606 bRet = SdrUndoManager::UndoWithContext(context);
607 }
608 else
609 {
610 bRet = SdrUndoManager::RedoWithContext(context);
611 }
612
613 if (bRet)
614 {
615 // if we are at the "last save" position, the document is not modified
616 if (SdrUndoManager::HasTopUndoActionMark(m_UndoSaveMark))
617 {
618 m_rState.ResetModified();
619 }
620 else
621 {
622 m_rState.SetModified();
623 }
624 }
625
626 pEditShell->HandleUndoRedoContext(context);
627
628 return bRet;
629 }
630
Undo()631 bool UndoManager::Undo()
632 {
633 if(isTextEditActive())
634 {
635 return SdrUndoManager::Undo();
636 }
637 else
638 {
639 return impl_DoUndoRedo(UndoOrRedoType::Undo);
640 }
641 }
642
Redo()643 bool UndoManager::Redo()
644 {
645 if(isTextEditActive())
646 {
647 return SdrUndoManager::Redo();
648 }
649 else
650 {
651 return impl_DoUndoRedo(UndoOrRedoType::Redo);
652 }
653 }
654
EmptyActionsChanged()655 void UndoManager::EmptyActionsChanged()
656 {
657 if (m_pDocShell)
658 {
659 m_pDocShell->Broadcast(SfxHint(SfxHintId::DocumentRepair));
660 }
661 }
662
663 /** N.B.: this does _not_ call SdrUndoManager::Repeat because it is not
664 possible to wrap a list action around it:
665 calling EnterListAction here will cause SdrUndoManager::Repeat
666 to repeat the list action!
667 */
Repeat(::sw::RepeatContext & rContext,sal_uInt16 const nRepeatCount)668 bool UndoManager::Repeat(::sw::RepeatContext & rContext,
669 sal_uInt16 const nRepeatCount)
670 {
671 if (SdrUndoManager::IsInListAction())
672 {
673 OSL_ENSURE(false, "repeat in open list action???");
674 return false;
675 }
676 if (!SdrUndoManager::GetUndoActionCount(TopLevel))
677 {
678 return false;
679 }
680 SfxUndoAction *const pRepeatAction(GetUndoAction());
681 assert(pRepeatAction);
682 if (!pRepeatAction->CanRepeat(rContext))
683 {
684 return false;
685 }
686
687 OUString const comment(pRepeatAction->GetComment());
688 OUString const rcomment(pRepeatAction->GetRepeatComment(rContext));
689 SwUndoId nId;
690 if (auto const* const pSwAction = dynamic_cast<SwUndo*>(pRepeatAction))
691 nId = pSwAction->GetId();
692 else if (auto const* const pListAction = dynamic_cast<SfxListUndoAction*>(pRepeatAction))
693 nId = static_cast<SwUndoId>(pListAction->GetId());
694 else
695 return false;
696 if (DoesUndo())
697 {
698 ViewShellId nViewShellId(-1);
699 if (m_pDocShell)
700 {
701 if (const SwView* pView = m_pDocShell->GetView())
702 nViewShellId = pView->GetViewShellId();
703 }
704 EnterListAction(comment, rcomment, static_cast<sal_uInt16>(nId), nViewShellId);
705 }
706
707 SwPaM* pTmp = rContext.m_pCurrentPaM;
708 for(SwPaM& rPaM : rContext.GetRepeatPaM().GetRingContainer())
709 { // iterate over ring
710 rContext.m_pCurrentPaM = &rPaM;
711 if (DoesUndo() && & rPaM != pTmp)
712 {
713 m_isAddWithIgnoreRepeat = true;
714 }
715 for (sal_uInt16 nRptCnt = nRepeatCount; nRptCnt > 0; --nRptCnt)
716 {
717 pRepeatAction->Repeat(rContext);
718 }
719 if (DoesUndo() && & rPaM != pTmp)
720 {
721 m_isAddWithIgnoreRepeat = false;
722 }
723 rContext.m_bDeleteRepeated = false; // reset for next PaM
724 }
725 rContext.m_pCurrentPaM = pTmp;
726
727 if (DoesUndo())
728 {
729 LeaveListAction();
730 }
731 return true;
732 }
733
734 } // namespace sw
735
736 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
737