LibreOffice Module svl (master) 1
undo.cxx
Go to the documentation of this file.
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/undo.hxx>
21
22#include <osl/mutex.hxx>
23#include <sal/log.hxx>
26#include <tools/long.hxx>
27#include <libxml/xmlwriter.h>
28#include <boost/property_tree/json_parser.hpp>
29#include <unotools/datetime.hxx>
30
31#include <memory>
32#include <utility>
33#include <vector>
34#include <limits.h>
35#include <algorithm>
36
37
38SfxRepeatTarget::~SfxRepeatTarget()
39{
40}
41
42
44{
45}
46
47
48SfxUndoAction::~SfxUndoAction() COVERITY_NOEXCEPT_FALSE
49{
50}
51
52
54 : m_aDateTime(DateTime::SYSTEM)
55{
57}
58
59
61{
62 return false;
63}
64
65
67{
68 return OUString();
69}
70
71
73{
74 return ViewShellId(-1);
75}
76
78{
79 return m_aDateTime;
80}
81
82OUString SfxUndoAction::GetRepeatComment(SfxRepeatTarget&) const
83{
84 return GetComment();
85}
86
87
89{
90 // These are only conceptually pure virtual
91 assert(!"pure virtual function called: SfxUndoAction::Undo()");
92}
93
94
96{
97 Undo();
98}
99
100
102{
103 // These are only conceptually pure virtual
104 assert(!"pure virtual function called: SfxUndoAction::Redo()");
105}
106
107
109{
110 Redo();
111}
112
113
114void SfxUndoAction::Repeat(SfxRepeatTarget&)
115{
116 // These are only conceptually pure virtual
117 assert(!"pure virtual function called: SfxUndoAction::Repeat()");
118}
119
120
121bool SfxUndoAction::CanRepeat(SfxRepeatTarget&) const
122{
123 return true;
124}
125
127{
128 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxUndoAction"));
129 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
130 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("symbol"), BAD_CAST(typeid(*this).name()));
131 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("comment"), BAD_CAST(GetComment().toUtf8().getStr()));
132 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("viewShellId"), BAD_CAST(OString::number(static_cast<sal_Int32>(GetViewShellId())).getStr()));
133 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("dateTime"), BAD_CAST(utl::toISO8601(m_aDateTime.GetUNODateTime()).toUtf8().getStr()));
134 (void)xmlTextWriterEndElement(pWriter);
135}
136
137std::unique_ptr<SfxUndoAction> SfxUndoArray::Remove(int idx)
138{
139 auto ret = std::move(maUndoActions[idx].pAction);
140 maUndoActions.erase(maUndoActions.begin() + idx);
141 return ret;
142}
143
144void SfxUndoArray::Remove( size_t i_pos, size_t i_count )
145{
146 maUndoActions.erase(maUndoActions.begin() + i_pos, maUndoActions.begin() + i_pos + i_count);
147}
148
149void SfxUndoArray::Insert( std::unique_ptr<SfxUndoAction> i_action, size_t i_pos )
150{
151 maUndoActions.insert( maUndoActions.begin() + i_pos, MarkedUndoAction(std::move(i_action)) );
152}
153
154typedef ::std::vector< SfxUndoListener* > UndoListeners;
155
157{
158 ::osl::Mutex aMutex;
161
162 sal_Int32 mnMarks;
163 sal_Int32 mnEmptyMark;
168
170
171 explicit SfxUndoManager_Data( size_t i_nMaxUndoActionCount )
172 :maUndoArray( i_nMaxUndoActionCount )
173 ,pActUndoArray( nullptr )
174 ,mnMarks( 0 )
176 ,mbUndoEnabled( true )
177 ,mbDoing( false )
178 ,mbClearUntilTopLevel( false )
179 ,mbEmptyActions( true )
180 {
182 }
183
184 // Copy assignment is forbidden and not implemented.
187};
188
190{
192 {
193 public:
194 explicit LockGuard( SfxUndoManager& i_manager )
195 :m_manager( i_manager )
196 {
198 }
199
201 {
203 }
204
205 private:
207 };
208
210 typedef void ( SfxUndoListener::*UndoListenerStringMethod )( const OUString& );
211
212 namespace {
213
214 struct NotifyUndoListener
215 {
216 explicit NotifyUndoListener( UndoListenerVoidMethod i_notificationMethod )
217 :m_notificationMethod( i_notificationMethod )
218 ,m_altNotificationMethod( nullptr )
219 {
220 }
221
222 NotifyUndoListener( UndoListenerStringMethod i_notificationMethod, OUString i_actionComment )
223 :m_notificationMethod( nullptr )
224 ,m_altNotificationMethod( i_notificationMethod )
225 ,m_sActionComment(std::move( i_actionComment ))
226 {
227 }
228
229 bool is() const
230 {
231 return ( m_notificationMethod != nullptr ) || ( m_altNotificationMethod != nullptr );
232 }
233
234 void operator()( SfxUndoListener* i_listener ) const
235 {
236 assert( is() && "NotifyUndoListener: this will crash!" );
237 if ( m_altNotificationMethod != nullptr )
238 {
239 ( i_listener->*m_altNotificationMethod )( m_sActionComment );
240 }
241 else
242 {
243 ( i_listener->*m_notificationMethod )();
244 }
245 }
246
247 private:
251 };
252
253 }
254
256 {
257 public:
258 explicit UndoManagerGuard( SfxUndoManager_Data& i_managerData )
259 :m_rManagerData( i_managerData )
260 ,m_aGuard( i_managerData.aMutex )
261 {
262 }
263
265
266 struct ResetGuard {
267 ResetGuard(osl::ResettableMutexGuard& r) : rGuard(r) {}
268 ~ResetGuard() { rGuard.reset(); }
269 osl::ResettableMutexGuard& rGuard;
270 };
272 {
273 m_aGuard.clear();
274 return ResetGuard(m_aGuard);
275 }
276
278 {
279 m_notifiers.clear();
280 }
281
287 void markForDeletion( std::unique_ptr<SfxUndoAction> i_action )
288 {
289 // remember
290 assert ( i_action );
291 m_aUndoActionsCleanup.emplace_back( std::move(i_action) );
292 }
293
299 void scheduleNotification( UndoListenerVoidMethod i_notificationMethod )
300 {
301 m_notifiers.emplace_back( i_notificationMethod );
302 }
303
304 void scheduleNotification( UndoListenerStringMethod i_notificationMethod, const OUString& i_actionComment )
305 {
306 m_notifiers.emplace_back( i_notificationMethod, i_actionComment );
307 }
308
309 private:
311 ::osl::ResettableMutexGuard m_aGuard;
312 ::std::vector< std::unique_ptr<SfxUndoAction> > m_aUndoActionsCleanup;
313 ::std::vector< NotifyUndoListener > m_notifiers;
314 };
315
317 {
318 // copy members
319 UndoListeners aListenersCopy( m_rManagerData.aListeners );
320
321 // release mutex
322 m_aGuard.clear();
323
324 // delete all actions
325 m_aUndoActionsCleanup.clear();
326
327 // handle scheduled notification
328 for (auto const& notifier : m_notifiers)
329 {
330 if ( notifier.is() )
331 ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(), notifier );
332 }
333 }
334}
335
336using namespace ::svl::undo::impl;
337
338
339SfxUndoManager::SfxUndoManager( size_t nMaxUndoActionCount )
340 :m_xData( new SfxUndoManager_Data( nMaxUndoActionCount ) )
341{
342 m_xData->mbEmptyActions = !ImplIsEmptyActions();
343}
344
345
347{
348}
349
350
351void SfxUndoManager::EnableUndo( bool i_enable )
352{
353 UndoManagerGuard aGuard( *m_xData );
354 ImplEnableUndo_Lock( i_enable );
355
356}
357
358
359void SfxUndoManager::ImplEnableUndo_Lock( bool const i_enable )
360{
361 if ( m_xData->mbUndoEnabled == i_enable )
362 return;
363 m_xData->mbUndoEnabled = i_enable;
364}
365
366
368{
369 UndoManagerGuard aGuard( *m_xData );
370 return ImplIsUndoEnabled_Lock();
371}
372
373
375{
376 return m_xData->mbUndoEnabled;
377}
378
379void SfxUndoManager::SetMaxUndoActionCount( size_t nMaxUndoActionCount )
380{
381 UndoManagerGuard aGuard( *m_xData );
382
383 // Remove entries from the pActUndoArray when we have to reduce
384 // the number of entries due to a lower nMaxUndoActionCount.
385 // Both redo and undo action entries will be removed until we reached the
386 // new nMaxUndoActionCount.
387
388 tools::Long nNumToDelete = m_xData->pActUndoArray->maUndoActions.size() - nMaxUndoActionCount;
389 while ( nNumToDelete > 0 )
390 {
391 size_t nPos = m_xData->pActUndoArray->maUndoActions.size();
392 if ( nPos > m_xData->pActUndoArray->nCurUndoAction )
393 {
394 aGuard.markForDeletion( m_xData->pActUndoArray->Remove( nPos-1 ) );
395 --nNumToDelete;
396 }
397
398 if ( nNumToDelete > 0 && m_xData->pActUndoArray->nCurUndoAction > 0 )
399 {
400 aGuard.markForDeletion( m_xData->pActUndoArray->Remove(0) );
401 --m_xData->pActUndoArray->nCurUndoAction;
402 --nNumToDelete;
403 }
404
405 if ( nPos == m_xData->pActUndoArray->maUndoActions.size() )
406 break; // Cannot delete more entries
407 }
408
409 m_xData->pActUndoArray->nMaxUndoActions = nMaxUndoActionCount;
411}
412
414{
415 return m_xData->pActUndoArray->nMaxUndoActions;
416}
417
418void SfxUndoManager::ImplClearCurrentLevel_NoNotify( UndoManagerGuard& i_guard )
419{
420 // clear array
421 while ( !m_xData->pActUndoArray->maUndoActions.empty() )
422 {
423 size_t deletePos = m_xData->pActUndoArray->maUndoActions.size() - 1;
424 i_guard.markForDeletion( m_xData->pActUndoArray->Remove( deletePos ) );
425 }
426
427 m_xData->pActUndoArray->nCurUndoAction = 0;
428
429 m_xData->mnMarks = 0;
430 m_xData->mnEmptyMark = MARK_INVALID;
432}
433
434
436{
437 UndoManagerGuard aGuard( *m_xData );
438
440 "SfxUndoManager::Clear: suspicious call - do you really wish to clear the current level?" );
442
443 // notify listeners
444 aGuard.scheduleNotification( &SfxUndoListener::cleared );
445}
446
447
449{
450 UndoManagerGuard aGuard( *m_xData );
452
454 {
455 m_xData->mbClearUntilTopLevel = true;
456 }
457 else
458 {
459 aGuard.scheduleNotification( &SfxUndoListener::cleared );
460 }
461}
462
463
464void SfxUndoManager::ImplClearRedo_NoLock( bool const i_currentLevel )
465{
466 UndoManagerGuard aGuard( *m_xData );
467 ImplClearRedo( aGuard, i_currentLevel );
468}
469
470
472{
473 SAL_WARN_IF( IsInListAction(), "svl",
474 "SfxUndoManager::ClearRedo: suspicious call - do you really wish to clear the current level?" );
476}
477
478
480{
481 UndoManagerGuard aGuard( *m_xData );
482
483 // clear all locks
484 while ( !ImplIsUndoEnabled_Lock() )
485 ImplEnableUndo_Lock( true );
486
487 // cancel all list actions
488 while ( IsInListAction() )
489 ImplLeaveListAction( false, aGuard );
490
491 // clear both stacks
493
494 // cancel the notifications scheduled by ImplLeaveListAction,
495 // as we want to do an own, dedicated notification
496 aGuard.cancelNotifications();
497
498 // schedule notification
499 aGuard.scheduleNotification( &SfxUndoListener::resetAll );
500}
501
502
503void SfxUndoManager::ImplClearUndo( UndoManagerGuard& i_guard )
504{
505 while ( m_xData->pActUndoArray->nCurUndoAction > 0 )
506 {
507 i_guard.markForDeletion( m_xData->pActUndoArray->Remove( 0 ) );
508 --m_xData->pActUndoArray->nCurUndoAction;
509 }
511 // TODO: notifications? We don't have clearedUndo, only cleared and clearedRedo at the SfxUndoListener
512}
513
514
515void SfxUndoManager::ImplClearRedo( UndoManagerGuard& i_guard, bool const i_currentLevel )
516{
517 SfxUndoArray* pUndoArray = ( i_currentLevel == SfxUndoManager::CurrentLevel ) ? m_xData->pActUndoArray : &m_xData->maUndoArray;
518
519 // clearance
520 while ( pUndoArray->maUndoActions.size() > pUndoArray->nCurUndoAction )
521 {
522 size_t deletePos = pUndoArray->maUndoActions.size() - 1;
523 i_guard.markForDeletion( pUndoArray->Remove( deletePos ) );
524 }
525
527 // notification - only if the top level's stack was cleared
528 if ( i_currentLevel == SfxUndoManager::TopLevel )
529 i_guard.scheduleNotification( &SfxUndoListener::clearedRedo );
530}
531
532
533bool SfxUndoManager::ImplAddUndoAction_NoNotify( std::unique_ptr<SfxUndoAction> pAction, bool bTryMerge, bool bClearRedo, UndoManagerGuard& i_guard )
534{
535 if ( !ImplIsUndoEnabled_Lock() || ( m_xData->pActUndoArray->nMaxUndoActions == 0 ) )
536 {
537 i_guard.markForDeletion( std::move(pAction) );
538 return false;
539 }
540
541 // merge, if required
542 SfxUndoAction* pMergeWithAction = m_xData->pActUndoArray->nCurUndoAction ?
543 m_xData->pActUndoArray->maUndoActions[m_xData->pActUndoArray->nCurUndoAction-1].pAction.get() : nullptr;
544 if ( bTryMerge && pMergeWithAction )
545 {
546 bool bMerged = pMergeWithAction->Merge( pAction.get() );
547 if ( bMerged )
548 {
549 i_guard.markForDeletion( std::move(pAction) );
550 return false;
551 }
552 }
553
554 // clear redo stack, if requested
555 if ( bClearRedo && ( ImplGetRedoActionCount_Lock() > 0 ) )
557
558 // respect max number
559 if( m_xData->pActUndoArray == &m_xData->maUndoArray )
560 {
561 while(m_xData->pActUndoArray->maUndoActions.size() >= m_xData->pActUndoArray->nMaxUndoActions)
562 {
563 i_guard.markForDeletion( m_xData->pActUndoArray->Remove(0) );
564 if (m_xData->pActUndoArray->nCurUndoAction > 0)
565 {
566 --m_xData->pActUndoArray->nCurUndoAction;
567 }
568 else
569 {
570 assert(!"CurrentUndoAction going negative (!)");
571 }
572 // fdo#66071 invalidate the current empty mark when removing
573 --m_xData->mnEmptyMark;
574 }
575 }
576
577 // append new action
578 m_xData->pActUndoArray->Insert( std::move(pAction), m_xData->pActUndoArray->nCurUndoAction++ );
580 return true;
581}
582
583
584void SfxUndoManager::AddUndoAction( std::unique_ptr<SfxUndoAction> pAction, bool bTryMerge )
585{
586 UndoManagerGuard aGuard( *m_xData );
587
588 // add
589 auto pActionTmp = pAction.get();
590 if ( ImplAddUndoAction_NoNotify( std::move(pAction), bTryMerge, true, aGuard ) )
591 {
592 // notify listeners
593 aGuard.scheduleNotification( &SfxUndoListener::undoActionAdded, pActionTmp->GetComment() );
594 }
595}
596
597
598size_t SfxUndoManager::GetUndoActionCount( bool const i_currentLevel ) const
599{
600 UndoManagerGuard aGuard( *m_xData );
601 const SfxUndoArray* pUndoArray = i_currentLevel ? m_xData->pActUndoArray : &m_xData->maUndoArray;
602 return pUndoArray->nCurUndoAction;
603}
604
605
606OUString SfxUndoManager::GetUndoActionComment( size_t nNo, bool const i_currentLevel ) const
607{
608 UndoManagerGuard aGuard( *m_xData );
609
610 OUString sComment;
611 const SfxUndoArray* pUndoArray = i_currentLevel ? m_xData->pActUndoArray : &m_xData->maUndoArray;
612 assert(nNo < pUndoArray->nCurUndoAction);
613 if( nNo < pUndoArray->nCurUndoAction )
614 sComment = pUndoArray->maUndoActions[ pUndoArray->nCurUndoAction - 1 - nNo ].pAction->GetComment();
615 return sComment;
616}
617
618
620{
621 UndoManagerGuard aGuard( *m_xData );
622
623 assert(nNo < m_xData->pActUndoArray->nCurUndoAction);
624 if( nNo >= m_xData->pActUndoArray->nCurUndoAction )
625 return nullptr;
626 return m_xData->pActUndoArray->maUndoActions[m_xData->pActUndoArray->nCurUndoAction-1-nNo].pAction.get();
627}
628
629
632{
633 UndoManagerGuard aGuard( *m_xData );
634
635 ENSURE_OR_RETURN_VOID( m_xData->pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::RemoveLastUndoAction(), no action to remove?!" );
636
637 m_xData->pActUndoArray->nCurUndoAction--;
638
639 // delete redo-actions and top action
640 for ( size_t nPos = m_xData->pActUndoArray->maUndoActions.size(); nPos > m_xData->pActUndoArray->nCurUndoAction; --nPos )
641 {
642 aGuard.markForDeletion( std::move(m_xData->pActUndoArray->maUndoActions[nPos-1].pAction) );
643 }
644
645 m_xData->pActUndoArray->Remove(
646 m_xData->pActUndoArray->nCurUndoAction,
647 m_xData->pActUndoArray->maUndoActions.size() - m_xData->pActUndoArray->nCurUndoAction );
649}
650
651
653{
654 UndoManagerGuard aGuard( *m_xData );
655 return m_xData->mbDoing;
656}
657
658
660{
661 return ImplUndo( nullptr );
662}
663
664
666{
667 return ImplUndo( &i_context );
668}
669
670
672{
673 UndoManagerGuard aGuard( *m_xData );
674 assert( !IsDoing() && "SfxUndoManager::Undo: *nested* Undo/Redo actions? How this?" );
675
676 ::comphelper::FlagGuard aDoingGuard( m_xData->mbDoing );
677 LockGuard aLockGuard( *this );
678
680 {
681 assert(!"SfxUndoManager::Undo: not possible when within a list action!");
682 return false;
683 }
684
685 if ( m_xData->pActUndoArray->nCurUndoAction == 0 )
686 {
687 SAL_WARN("svl", "SfxUndoManager::Undo: undo stack is empty!" );
688 return false;
689 }
690
691 if (i_contextOrNull && i_contextOrNull->GetUndoOffset() > 0)
692 {
693 size_t nCurrent = m_xData->pActUndoArray->nCurUndoAction;
694 size_t nOffset = i_contextOrNull->GetUndoOffset();
695 if (nCurrent >= nOffset + 1)
696 {
697 // Move the action we want to execute to the top of the undo stack.
698 // data() + nCurrent - nOffset - 1 is the start, data() + nCurrent - nOffset is what we
699 // want to move to the top, maUndoActions.data() + nCurrent is past the end/top of the
700 // undo stack.
701 std::rotate(m_xData->pActUndoArray->maUndoActions.data() + nCurrent - nOffset - 1,
702 m_xData->pActUndoArray->maUndoActions.data() + nCurrent - nOffset,
703 m_xData->pActUndoArray->maUndoActions.data() + nCurrent);
704 }
705 }
706
707 SfxUndoAction* pAction = m_xData->pActUndoArray->maUndoActions[ --m_xData->pActUndoArray->nCurUndoAction ].pAction.get();
708 const OUString sActionComment = pAction->GetComment();
709 try
710 {
711 // clear the guard/mutex before calling into the SfxUndoAction - this can be an extension-implemented UNO component
712 // nowadays ...
713 auto aResetGuard(aGuard.clear());
714 if ( i_contextOrNull != nullptr )
715 pAction->UndoWithContext( *i_contextOrNull );
716 else
717 pAction->Undo();
718 }
719 catch( ... )
720 {
721 // in theory, somebody might have tampered with all of *m_xData while the mutex was unlocked. So, see if
722 // we still find pAction in our current Undo array
723 size_t nCurAction = 0;
724 while ( nCurAction < m_xData->pActUndoArray->maUndoActions.size() )
725 {
726 if ( m_xData->pActUndoArray->maUndoActions[ nCurAction++ ].pAction.get() == pAction )
727 {
728 // the Undo action is still there ...
729 // assume the error is a permanent failure, and clear the Undo stack
730 ImplClearUndo( aGuard );
731 throw;
732 }
733 }
734 SAL_WARN("svl", "SfxUndoManager::Undo: can't clear the Undo stack after the failure - some other party was faster ..." );
735 throw;
736 }
737
738 aGuard.scheduleNotification( &SfxUndoListener::actionUndone, sActionComment );
739
740 return true;
741}
742
743
744size_t SfxUndoManager::GetRedoActionCount( bool const i_currentLevel ) const
745{
746 UndoManagerGuard aGuard( *m_xData );
747 return ImplGetRedoActionCount_Lock( i_currentLevel );
748}
749
750
751size_t SfxUndoManager::ImplGetRedoActionCount_Lock( bool const i_currentLevel ) const
752{
753 const SfxUndoArray* pUndoArray = i_currentLevel ? m_xData->pActUndoArray : &m_xData->maUndoArray;
754 return pUndoArray->maUndoActions.size() - pUndoArray->nCurUndoAction;
755}
756
757
759{
760 UndoManagerGuard aGuard( *m_xData );
761
762 const SfxUndoArray* pUndoArray = m_xData->pActUndoArray;
763 if ( (pUndoArray->nCurUndoAction) > pUndoArray->maUndoActions.size() )
764 {
765 return nullptr;
766 }
767 return pUndoArray->maUndoActions[pUndoArray->nCurUndoAction + nNo].pAction.get();
768}
769
770
771OUString SfxUndoManager::GetRedoActionComment( size_t nNo, bool const i_currentLevel ) const
772{
773 OUString sComment;
774 UndoManagerGuard aGuard( *m_xData );
775 const SfxUndoArray* pUndoArray = i_currentLevel ? m_xData->pActUndoArray : &m_xData->maUndoArray;
776 if ( (pUndoArray->nCurUndoAction + nNo) < pUndoArray->maUndoActions.size() )
777 {
778 sComment = pUndoArray->maUndoActions[ pUndoArray->nCurUndoAction + nNo ].pAction->GetComment();
779 }
780 return sComment;
781}
782
783
785{
786 return ImplRedo( nullptr );
787}
788
789
791{
792 return ImplRedo( &i_context );
793}
794
795
797{
798 UndoManagerGuard aGuard( *m_xData );
799 assert( !IsDoing() && "SfxUndoManager::Redo: *nested* Undo/Redo actions? How this?" );
800
801 ::comphelper::FlagGuard aDoingGuard( m_xData->mbDoing );
802 LockGuard aLockGuard( *this );
803
805 {
806 assert(!"SfxUndoManager::Redo: not possible when within a list action!");
807 return false;
808 }
809
810 if ( m_xData->pActUndoArray->nCurUndoAction >= m_xData->pActUndoArray->maUndoActions.size() )
811 {
812 SAL_WARN("svl", "SfxUndoManager::Redo: redo stack is empty!");
813 return false;
814 }
815
816 SfxUndoAction* pAction = m_xData->pActUndoArray->maUndoActions[ m_xData->pActUndoArray->nCurUndoAction++ ].pAction.get();
817 const OUString sActionComment = pAction->GetComment();
818 try
819 {
820 // clear the guard/mutex before calling into the SfxUndoAction - this can be an extension-implemented UNO component
821 // nowadays ...
822 auto aResetGuard(aGuard.clear());
823 if ( i_contextOrNull != nullptr )
824 pAction->RedoWithContext( *i_contextOrNull );
825 else
826 pAction->Redo();
827 }
828 catch( ... )
829 {
830 // in theory, somebody might have tampered with all of *m_xData while the mutex was unlocked. So, see if
831 // we still find pAction in our current Undo array
832 size_t nCurAction = 0;
833 while ( nCurAction < m_xData->pActUndoArray->maUndoActions.size() )
834 {
835 if ( m_xData->pActUndoArray->maUndoActions[ nCurAction ].pAction.get() == pAction )
836 {
837 // the Undo action is still there ...
838 // assume the error is a permanent failure, and clear the Undo stack
840 throw;
841 }
842 ++nCurAction;
843 }
844 SAL_WARN("svl", "SfxUndoManager::Redo: can't clear the Undo stack after the failure - some other party was faster ..." );
845 throw;
846 }
847
849 aGuard.scheduleNotification( &SfxUndoListener::actionRedone, sActionComment );
850
851 return true;
852}
853
854
856{
857 UndoManagerGuard aGuard( *m_xData );
858 return m_xData->pActUndoArray->maUndoActions.size();
859}
860
861
862OUString SfxUndoManager::GetRepeatActionComment(SfxRepeatTarget &rTarget) const
863{
864 UndoManagerGuard aGuard( *m_xData );
865 return m_xData->pActUndoArray->maUndoActions[ m_xData->pActUndoArray->maUndoActions.size() - 1 ].pAction
866 ->GetRepeatComment(rTarget);
867}
868
869
870bool SfxUndoManager::Repeat( SfxRepeatTarget &rTarget )
871{
872 UndoManagerGuard aGuard( *m_xData );
873 if ( !m_xData->pActUndoArray->maUndoActions.empty() )
874 {
875 SfxUndoAction* pAction = m_xData->pActUndoArray->maUndoActions.back().pAction.get();
876 auto aResetGuard(aGuard.clear());
877 if ( pAction->CanRepeat( rTarget ) )
878 pAction->Repeat( rTarget );
879 return true;
880 }
881
882 return false;
883}
884
885
886bool SfxUndoManager::CanRepeat( SfxRepeatTarget &rTarget ) const
887{
888 UndoManagerGuard aGuard( *m_xData );
889 if ( !m_xData->pActUndoArray->maUndoActions.empty() )
890 {
891 size_t nActionNo = m_xData->pActUndoArray->maUndoActions.size() - 1;
892 return m_xData->pActUndoArray->maUndoActions[nActionNo].pAction->CanRepeat(rTarget);
893 }
894 return false;
895}
896
897
899{
900 UndoManagerGuard aGuard( *m_xData );
901 m_xData->aListeners.push_back( &i_listener );
902}
903
904
906{
907 UndoManagerGuard aGuard( *m_xData );
908 auto lookup = std::find(m_xData->aListeners.begin(), m_xData->aListeners.end(), &i_listener);
909 if (lookup != m_xData->aListeners.end())
910 m_xData->aListeners.erase( lookup );
911}
912
916void SfxUndoManager::EnterListAction( const OUString& rComment,
917 const OUString &rRepeatComment, sal_uInt16 nId,
918 ViewShellId nViewShellId )
919{
920 UndoManagerGuard aGuard( *m_xData );
921
923 return;
924
925 if ( !m_xData->maUndoArray.nMaxUndoActions )
926 return;
927
928 SfxListUndoAction* pAction = new SfxListUndoAction( rComment, rRepeatComment, nId, nViewShellId, m_xData->pActUndoArray );
929 OSL_VERIFY( ImplAddUndoAction_NoNotify( std::unique_ptr<SfxUndoAction>(pAction), false, false, aGuard ) );
930 // expected to succeed: all conditions under which it could fail should have been checked already
931 m_xData->pActUndoArray = pAction;
932
933 // notification
934 aGuard.scheduleNotification( &SfxUndoListener::listActionEntered, rComment );
935}
936
937
939{
940 UndoManagerGuard aGuard( *m_xData );
942}
943
944
946{
947 return m_xData->pActUndoArray != &m_xData->maUndoArray;
948}
949
950
952{
953 UndoManagerGuard aGuard( *m_xData );
954 size_t nDepth(0);
955
956 SfxUndoArray* pLookup( m_xData->pActUndoArray );
957 while ( pLookup != &m_xData->maUndoArray )
958 {
959 pLookup = pLookup->pFatherUndoArray;
960 ++nDepth;
961 }
962
963 return nDepth;
964}
965
966
968{
969 UndoManagerGuard aGuard( *m_xData );
970 size_t nCount = ImplLeaveListAction( false, aGuard );
971
972 if ( m_xData->mbClearUntilTopLevel )
973 {
976 {
977 m_xData->mbClearUntilTopLevel = false;
978 aGuard.scheduleNotification( &SfxUndoListener::cleared );
979 }
980 nCount = 0;
981 }
982
983 return nCount;
984}
985
986
988{
989 UndoManagerGuard aGuard( *m_xData );
990 return ImplLeaveListAction( true, aGuard );
991}
992
993
994size_t SfxUndoManager::ImplLeaveListAction( const bool i_merge, UndoManagerGuard& i_guard )
995{
996 if ( !ImplIsUndoEnabled_Lock() )
997 return 0;
998
999 if ( !m_xData->maUndoArray.nMaxUndoActions )
1000 return 0;
1001
1003 {
1004 SAL_WARN("svl", "svl::SfxUndoManager::ImplLeaveListAction, called without calling EnterListAction()!" );
1005 return 0;
1006 }
1007
1008 assert(m_xData->pActUndoArray->pFatherUndoArray);
1009
1010 // the array/level which we're about to leave
1011 SfxUndoArray* pArrayToLeave = m_xData->pActUndoArray;
1012 // one step up
1013 m_xData->pActUndoArray = m_xData->pActUndoArray->pFatherUndoArray;
1014
1015 // If no undo actions were added to the list, delete the list action
1016 const size_t nListActionElements = pArrayToLeave->nCurUndoAction;
1017 if ( nListActionElements == 0 )
1018 {
1019 i_guard.markForDeletion( m_xData->pActUndoArray->Remove( --m_xData->pActUndoArray->nCurUndoAction ) );
1020 i_guard.scheduleNotification( &SfxUndoListener::listActionCancelled );
1021 return 0;
1022 }
1023
1024 // now that it is finally clear the list action is non-trivial, and does participate in the Undo stack, clear
1025 // the redo stack
1027
1028 SfxUndoAction* pCurrentAction= m_xData->pActUndoArray->maUndoActions[ m_xData->pActUndoArray->nCurUndoAction-1 ].pAction.get();
1029 SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction * >( pCurrentAction );
1030 ENSURE_OR_RETURN( pListAction, "SfxUndoManager::ImplLeaveListAction: list action expected at this position!", nListActionElements );
1031
1032 if ( i_merge )
1033 {
1034 // merge the list action with its predecessor on the same level
1035 SAL_WARN_IF( m_xData->pActUndoArray->nCurUndoAction <= 1, "svl",
1036 "SfxUndoManager::ImplLeaveListAction: cannot merge the list action if there's no other action on the same level - check this beforehand!" );
1037 if ( m_xData->pActUndoArray->nCurUndoAction > 1 )
1038 {
1039 std::unique_ptr<SfxUndoAction> pPreviousAction = m_xData->pActUndoArray->Remove( m_xData->pActUndoArray->nCurUndoAction - 2 );
1040 --m_xData->pActUndoArray->nCurUndoAction;
1041 pListAction->SetComment( pPreviousAction->GetComment() );
1042 pListAction->Insert( std::move(pPreviousAction), 0 );
1043 ++pListAction->nCurUndoAction;
1044 }
1045 }
1046
1047 // if the undo array has no comment, try to get it from its children
1048 if ( pListAction->GetComment().isEmpty() )
1049 {
1050 for( size_t n = 0; n < pListAction->maUndoActions.size(); n++ )
1051 {
1052 if (!pListAction->maUndoActions[n].pAction->GetComment().isEmpty())
1053 {
1054 pListAction->SetComment( pListAction->maUndoActions[n].pAction->GetComment() );
1055 break;
1056 }
1057 }
1058 }
1059
1061 // notify listeners
1062 i_guard.scheduleNotification( &SfxUndoListener::listActionLeft, pListAction->GetComment() );
1063
1064 // outta here
1065 return nListActionElements;
1066}
1067
1069{
1070 UndoManagerGuard aGuard( *m_xData );
1071
1072 SAL_WARN_IF( IsInListAction(), "svl",
1073 "SfxUndoManager::MarkTopUndoAction(): suspicious call!" );
1074 assert((m_xData->mnMarks + 1) < (m_xData->mnEmptyMark - 1) &&
1075 "SfxUndoManager::MarkTopUndoAction(): mark overflow!");
1076
1077 size_t const nActionPos = m_xData->maUndoArray.nCurUndoAction;
1078 if (0 == nActionPos)
1079 {
1080 --m_xData->mnEmptyMark;
1081 return m_xData->mnEmptyMark;
1082 }
1083
1084 m_xData->maUndoArray.maUndoActions[ nActionPos-1 ].aMarks.push_back(
1085 ++m_xData->mnMarks );
1086 return m_xData->mnMarks;
1087}
1088
1090{
1091 UndoManagerGuard aGuard( *m_xData );
1092
1093 if ((m_xData->mnEmptyMark < i_mark) || (MARK_INVALID == i_mark))
1094 {
1095 return; // nothing to remove
1096 }
1097 else if (i_mark == m_xData->mnEmptyMark)
1098 {
1099 --m_xData->mnEmptyMark; // never returned from MarkTop => invalid
1100 return;
1101 }
1102
1103 for ( size_t i=0; i<m_xData->maUndoArray.maUndoActions.size(); ++i )
1104 {
1105 MarkedUndoAction& rAction = m_xData->maUndoArray.maUndoActions[i];
1106 auto markPos = std::find(rAction.aMarks.begin(), rAction.aMarks.end(), i_mark);
1107 if (markPos != rAction.aMarks.end())
1108 {
1109 rAction.aMarks.erase( markPos );
1110 return;
1111 }
1112 }
1113 SAL_WARN("svl", "SfxUndoManager::RemoveMark: mark not found!");
1114 // TODO: this might be too offensive. There are situations where we implicitly remove marks
1115 // without our clients, in particular the client which created the mark, having a chance to know
1116 // about this.
1117}
1118
1120{
1121 UndoManagerGuard aGuard( *m_xData );
1122
1123 size_t nActionPos = m_xData->maUndoArray.nCurUndoAction;
1124 if ( nActionPos == 0 )
1125 {
1126 return (i_mark == m_xData->mnEmptyMark);
1127 }
1128
1129 const MarkedUndoAction& rAction =
1130 m_xData->maUndoArray.maUndoActions[ nActionPos-1 ];
1131
1132 return std::find(rAction.aMarks.begin(), rAction.aMarks.end(), i_mark) != rAction.aMarks.end();
1133}
1134
1135
1137{
1138 UndoManagerGuard aGuard( *m_xData );
1139
1140 if ( IsInListAction() && ( m_xData->maUndoArray.nCurUndoAction == 1 ) )
1141 {
1142 assert(!"SfxUndoManager::RemoveOldestUndoActions: cannot remove a not-yet-closed list action!");
1143 return;
1144 }
1145
1146 aGuard.markForDeletion( m_xData->maUndoArray.Remove( 0 ) );
1147 --m_xData->maUndoArray.nCurUndoAction;
1149}
1150
1152{
1153 UndoManagerGuard aGuard(*m_xData);
1154
1155 bool bOwns = false;
1156 if (!pWriter)
1157 {
1158 pWriter = xmlNewTextWriterFilename("undo.xml", 0);
1159 xmlTextWriterSetIndent(pWriter,1);
1160 (void)xmlTextWriterSetIndentString(pWriter, BAD_CAST(" "));
1161 (void)xmlTextWriterStartDocument(pWriter, nullptr, nullptr, nullptr);
1162 bOwns = true;
1163 }
1164
1165 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxUndoManager"));
1166 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nUndoActionCount"), BAD_CAST(OString::number(GetUndoActionCount()).getStr()));
1167 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nRedoActionCount"), BAD_CAST(OString::number(GetRedoActionCount()).getStr()));
1168
1169 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("undoActions"));
1170 for (size_t i = 0; i < GetUndoActionCount(); ++i)
1171 {
1172 const SfxUndoArray* pUndoArray = m_xData->pActUndoArray;
1173 pUndoArray->maUndoActions[pUndoArray->nCurUndoAction - 1 - i].pAction->dumpAsXml(pWriter);
1174 }
1175 (void)xmlTextWriterEndElement(pWriter);
1176
1177 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("redoActions"));
1178 for (size_t i = 0; i < GetRedoActionCount(); ++i)
1179 {
1180 const SfxUndoArray* pUndoArray = m_xData->pActUndoArray;
1181 pUndoArray->maUndoActions[pUndoArray->nCurUndoAction + i].pAction->dumpAsXml(pWriter);
1182 }
1183 (void)xmlTextWriterEndElement(pWriter);
1184
1185 (void)xmlTextWriterEndElement(pWriter);
1186 if (bOwns)
1187 {
1188 (void)xmlTextWriterEndDocument(pWriter);
1189 xmlFreeTextWriter(pWriter);
1190 }
1191}
1192
1194static boost::property_tree::ptree lcl_ActionToJson(size_t nIndex, SfxUndoAction const * pAction)
1195{
1196 boost::property_tree::ptree aRet;
1197 aRet.put("index", nIndex);
1198 aRet.put("comment", pAction->GetComment().toUtf8().getStr());
1199 aRet.put("viewId", static_cast<sal_Int32>(pAction->GetViewShellId()));
1200 aRet.put("dateTime", utl::toISO8601(pAction->GetDateTime().GetUNODateTime()).toUtf8().getStr());
1201 return aRet;
1202}
1203
1205{
1206 boost::property_tree::ptree aActions;
1207 const SfxUndoArray* pUndoArray = m_xData->pActUndoArray;
1208 for (size_t i = 0; i < GetUndoActionCount(); ++i)
1209 {
1210 boost::property_tree::ptree aAction = lcl_ActionToJson(i, pUndoArray->maUndoActions[pUndoArray->nCurUndoAction - 1 - i].pAction.get());
1211 aActions.push_back(std::make_pair("", aAction));
1212 }
1213
1214 boost::property_tree::ptree aTree;
1215 aTree.add_child("actions", aActions);
1216 std::stringstream aStream;
1217 boost::property_tree::write_json(aStream, aTree);
1218 return OUString::fromUtf8(aStream.str());
1219}
1220
1222{
1223 boost::property_tree::ptree aActions;
1224 const SfxUndoArray* pUndoArray = m_xData->pActUndoArray;
1225 size_t nCount = GetRedoActionCount();
1226 for (size_t i = 0; i < nCount; ++i)
1227 {
1228 size_t nIndex = nCount - i - 1;
1229 boost::property_tree::ptree aAction = lcl_ActionToJson(nIndex, pUndoArray->maUndoActions[pUndoArray->nCurUndoAction + nIndex].pAction.get());
1230 aActions.push_back(std::make_pair("", aAction));
1231 }
1232
1233 boost::property_tree::ptree aTree;
1234 aTree.add_child("actions", aActions);
1235 std::stringstream aStream;
1236 boost::property_tree::write_json(aStream, aTree);
1237 return OUString::fromUtf8(aStream.str());
1238}
1239
1241{
1242 UndoManagerGuard aGuard(*m_xData);
1243
1244 return ImplIsEmptyActions();
1245}
1246
1248{
1249 return m_xData->maUndoArray.nCurUndoAction || m_xData->maUndoArray.maUndoActions.size() - m_xData->maUndoArray.nCurUndoAction;
1250}
1251
1253{
1254 bool bEmptyActions = ImplIsEmptyActions();
1255 if (m_xData->mbEmptyActions != bEmptyActions)
1256 {
1257 m_xData->mbEmptyActions = bEmptyActions;
1259 }
1260}
1261
1263{
1264
1265}
1266
1268{
1269 sal_uInt16 mnId;
1271
1272 OUString maComment;
1274
1275 Impl( sal_uInt16 nId, ViewShellId nViewShellId, OUString aComment, OUString aRepeatComment ) :
1276 mnId(nId), mnViewShellId(nViewShellId), maComment(std::move(aComment)), maRepeatComment(std::move(aRepeatComment)) {}
1277};
1278
1280{
1281 return mpImpl->mnId;
1282}
1283
1285{
1286 return mpImpl->maComment;
1287}
1288
1290{
1291 return mpImpl->mnViewShellId;
1292}
1293
1294void SfxListUndoAction::SetComment(const OUString& rComment)
1295{
1296 mpImpl->maComment = rComment;
1297}
1298
1299OUString SfxListUndoAction::GetRepeatComment(SfxRepeatTarget &) const
1300{
1301 return mpImpl->maRepeatComment;
1302}
1303
1305 const OUString &rComment,
1306 const OUString &rRepeatComment,
1307 sal_uInt16 nId,
1308 ViewShellId nViewShellId,
1309 SfxUndoArray *pFather ) :
1310 mpImpl(new Impl(nId, nViewShellId, rComment, rRepeatComment))
1311{
1312 pFatherUndoArray = pFather;
1313 nMaxUndoActions = USHRT_MAX;
1314}
1315
1317{
1318}
1319
1321{
1322 for(size_t i=nCurUndoAction;i>0;)
1323 maUndoActions[--i].pAction->Undo();
1325}
1326
1327
1329{
1330 for(size_t i=nCurUndoAction;i>0;)
1331 maUndoActions[--i].pAction->UndoWithContext( i_context );
1333}
1334
1335
1337{
1338 for(size_t i=nCurUndoAction;i<maUndoActions.size();i++)
1339 maUndoActions[i].pAction->Redo();
1341}
1342
1343
1345{
1346 for(size_t i=nCurUndoAction;i<maUndoActions.size();i++)
1347 maUndoActions[i].pAction->RedoWithContext( i_context );
1349}
1350
1351
1352void SfxListUndoAction::Repeat(SfxRepeatTarget&rTarget)
1353{
1354 for(size_t i=0;i<nCurUndoAction;i++)
1355 maUndoActions[i].pAction->Repeat(rTarget);
1356}
1357
1358
1359bool SfxListUndoAction::CanRepeat(SfxRepeatTarget&r) const
1360{
1361 for(size_t i=0;i<nCurUndoAction;i++)
1362 {
1363 if(!maUndoActions[i].pAction->CanRepeat(r))
1364 return false;
1365 }
1366 return true;
1367}
1368
1369
1371{
1372 return !maUndoActions.empty() && maUndoActions[maUndoActions.size()-1].pAction->Merge( pNextAction );
1373}
1374
1376{
1377 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxListUndoAction"));
1378 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("size"), BAD_CAST(OString::number(maUndoActions.size()).getStr()));
1379 SfxUndoAction::dumpAsXml(pWriter);
1380
1381 for (size_t i = 0; i < maUndoActions.size(); ++i)
1382 maUndoActions[i].pAction->dumpAsXml(pWriter);
1383
1384 (void)xmlTextWriterEndElement(pWriter);
1385}
1386
1388{
1389}
1390
1391/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void ConvertToUTC()
css::util::DateTime GetUNODateTime() const
do not make use of these implementation details, unless you really really have to!
Definition: undo.hxx:132
ViewShellId GetViewShellId() const override
See SfxUndoAction::GetViewShellId().
Definition: undo.cxx:1289
virtual OUString GetRepeatComment(SfxRepeatTarget &) const override
Definition: undo.cxx:1299
virtual void Repeat(SfxRepeatTarget &) override
Definition: undo.cxx:1352
void SetComment(const OUString &rComment)
Definition: undo.cxx:1294
void dumpAsXml(xmlTextWriterPtr pWriter) const override
Definition: undo.cxx:1375
SfxListUndoAction(const OUString &rComment, const OUString &rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId, SfxUndoArray *pFather)
Definition: undo.cxx:1304
virtual void Undo() override
Definition: undo.cxx:1320
virtual void UndoWithContext(SfxUndoContext &i_context) override
Definition: undo.cxx:1328
virtual void RedoWithContext(SfxUndoContext &i_context) override
Definition: undo.cxx:1344
virtual OUString GetComment() const override
Definition: undo.cxx:1284
virtual void Redo() override
Definition: undo.cxx:1336
std::unique_ptr< Impl > mpImpl
Definition: undo.hxx:133
virtual bool Merge(SfxUndoAction *pNextAction) override
Definition: undo.cxx:1370
virtual ~SfxListUndoAction() override
Definition: undo.cxx:1316
sal_uInt16 GetId() const
Definition: undo.cxx:1279
virtual bool CanRepeat(SfxRepeatTarget &) const override
Definition: undo.cxx:1359
virtual void Repeat(SfxRepeatTarget &)
Definition: undo.cxx:114
virtual OUString GetRepeatComment(SfxRepeatTarget &) const
Definition: undo.cxx:82
virtual ViewShellId GetViewShellId() const
ID of the view shell that created this undo action.
Definition: undo.cxx:72
SfxUndoAction()
Definition: undo.cxx:53
virtual void Redo()
Definition: undo.cxx:101
virtual void Undo()
Definition: undo.cxx:88
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: undo.cxx:126
const DateTime & GetDateTime() const
Timestamp when this undo item was created.
Definition: undo.cxx:77
virtual OUString GetComment() const
Definition: undo.cxx:66
virtual bool CanRepeat(SfxRepeatTarget &) const
Definition: undo.cxx:121
virtual void RedoWithContext(SfxUndoContext &i_context)
Definition: undo.cxx:108
virtual void UndoWithContext(SfxUndoContext &i_context)
Definition: undo.cxx:95
virtual ~SfxUndoAction() COVERITY_NOEXCEPT_FALSE
Definition: undo.cxx:48
virtual bool Merge(SfxUndoAction *pNextAction)
Definition: undo.cxx:60
DateTime m_aDateTime
Definition: undo.hxx:82
virtual ~SfxUndoContext()=0
Definition: undo.cxx:43
virtual size_t GetUndoOffset()
Don't undo the top undo action, but an earlier one.
Definition: undo.hxx:49
is a callback interface for notifications about state changes of an SfxUndoManager
Definition: undo.hxx:165
virtual void listActionEntered(const OUString &i_comment)=0
virtual void cleared()=0
virtual void actionUndone(const OUString &i_actionComment)=0
virtual void actionRedone(const OUString &i_actionComment)=0
virtual void listActionLeft(const OUString &i_comment)=0
virtual void clearedRedo()=0
virtual void resetAll()=0
virtual void listActionCancelled()=0
virtual void undoActionAdded(const OUString &i_actionComment)=0
size_t LeaveListAction()
Leaves the list action entered with EnterListAction.
Definition: undo.cxx:967
virtual bool Undo()
Definition: undo.cxx:659
size_t GetMaxUndoActionCount() const
Definition: undo.cxx:413
bool ImplIsUndoEnabled_Lock() const
Definition: undo.cxx:374
void AddUndoListener(SfxUndoListener &i_listener)
Adds a new listener to be notified about changes in the UndoManager's state.
Definition: undo.cxx:898
void ImplClearCurrentLevel_NoNotify(::svl::undo::impl::UndoManagerGuard &i_guard)
Definition: undo.cxx:418
void ImplClearRedo_NoLock(bool const i_currentLevel)
Definition: undo.cxx:464
void EnableUndo(bool bEnable)
enables (true) or disables (false) recording of undo actions
Definition: undo.cxx:351
void Reset()
leaves any possible open list action (<member>IsInListAction</member>), and clears both the Undo and ...
Definition: undo.cxx:479
virtual void Clear()
Clears both the Redo and the Undo stack.
Definition: undo.cxx:435
size_t ImplGetRedoActionCount_Lock(bool const i_currentLevel=CurrentLevel) const
Definition: undo.cxx:751
bool HasTopUndoActionMark(UndoStackMark const i_mark)
determines whether the top action on the Undo stack has a given mark
Definition: undo.cxx:1119
std::unique_ptr< SfxUndoManager_Data > m_xData
Definition: undo.hxx:192
SfxUndoAction * GetRedoAction(size_t nNo=0) const
Definition: undo.cxx:758
OUString GetUndoActionsInfo() const
Get info about all undo actions (comment, view shell id, etc.)
Definition: undo.cxx:1204
void ImplCheckEmptyActions()
Definition: undo.cxx:1252
virtual ~SfxUndoManager()
Definition: undo.cxx:346
OUString GetRedoActionComment(size_t nNo=0, bool const i_currentLevel=CurrentLevel) const
Definition: undo.cxx:771
bool IsInListAction() const
determines whether we're within a ListAction context, i.e. a LeaveListAction/LeaveAndMergeListAction ...
Definition: undo.cxx:938
bool ImplUndo(SfxUndoContext *i_contextOrNull)
Definition: undo.cxx:671
size_t LeaveAndMergeListAction()
Leaves the list action entered with EnterListAction, and forcefully merges the previous action on the...
Definition: undo.cxx:987
OUString GetUndoActionComment(size_t nNo=0, bool const i_currentLevel=CurrentLevel) const
Definition: undo.cxx:606
bool CanRepeat(SfxRepeatTarget &rTarget) const
Definition: undo.cxx:886
void RemoveMark(UndoStackMark const i_mark)
removes a mark given by its ID.
Definition: undo.cxx:1089
static bool const TopLevel
Definition: undo.hxx:195
virtual void EnterListAction(const OUString &rComment, const OUString &rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId)
Inserts a ListUndoAction and sets its UndoArray as current.
Definition: undo.cxx:916
bool Repeat(SfxRepeatTarget &rTarget)
Definition: undo.cxx:870
void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: undo.cxx:1151
void ImplClearRedo(::svl::undo::impl::UndoManagerGuard &i_guard, bool const i_currentLevel)
Definition: undo.cxx:515
virtual bool Redo()
Definition: undo.cxx:784
bool UndoWithContext(SfxUndoContext &i_context)
Definition: undo.cxx:665
OUString GetRedoActionsInfo() const
Get info about all redo actions (comment, view shell id, etc.)
Definition: undo.cxx:1221
size_t ImplLeaveListAction(const bool i_merge, ::svl::undo::impl::UndoManagerGuard &i_guard)
Definition: undo.cxx:994
void RemoveUndoListener(SfxUndoListener &i_listener)
Definition: undo.cxx:905
SfxUndoManager(size_t nMaxUndoActionCount=20)
Definition: undo.cxx:339
bool IsDoing() const
determines whether an Undo or Redo is currently running
Definition: undo.cxx:652
virtual size_t GetRedoActionCount(bool const i_currentLevel=CurrentLevel) const
Definition: undo.cxx:744
size_t GetListActionDepth() const
Determines how many nested list actions are currently open.
Definition: undo.cxx:951
virtual void ClearRedo()
Clears the Redo stack.
Definition: undo.cxx:471
void RemoveLastUndoAction()
Clears the redo stack and removes the top undo action.
Definition: undo.cxx:631
bool ImplIsEmptyActions() const
Definition: undo.cxx:1247
OUString GetRepeatActionComment(SfxRepeatTarget &rTarget) const
Definition: undo.cxx:862
void SetMaxUndoActionCount(size_t nMaxUndoActionCount)
Definition: undo.cxx:379
bool IsEmptyActions() const
Definition: undo.cxx:1240
bool IsUndoEnabled() const
returns true if undo is currently enabled.
Definition: undo.cxx:367
bool ImplAddUndoAction_NoNotify(std::unique_ptr< SfxUndoAction > pAction, bool bTryMerge, bool bClearRedo, ::svl::undo::impl::UndoManagerGuard &i_guard)
Definition: undo.cxx:533
void ImplEnableUndo_Lock(bool const i_enable)
Definition: undo.cxx:359
bool ImplIsInListAction_Lock() const
Definition: undo.cxx:945
UndoStackMark MarkTopUndoAction()
marks the current top-level element of the Undo stack, and returns a unique ID for it
Definition: undo.cxx:1068
virtual void AddUndoAction(std::unique_ptr< SfxUndoAction > pAction, bool bTryMerg=false)
Definition: undo.cxx:584
size_t GetRepeatActionCount() const
Definition: undo.cxx:855
virtual size_t GetUndoActionCount(bool const i_currentLevel=CurrentLevel) const
Definition: undo.cxx:598
void ImplClearUndo(::svl::undo::impl::UndoManagerGuard &i_guard)
Definition: undo.cxx:503
void RemoveOldestUndoAction()
removes the oldest Undo actions from the stack
Definition: undo.cxx:1136
bool RedoWithContext(SfxUndoContext &i_context)
Definition: undo.cxx:790
SfxUndoAction * GetUndoAction(size_t nNo=0) const
Definition: undo.cxx:619
static bool const CurrentLevel
Definition: undo.hxx:194
bool ImplRedo(SfxUndoContext *i_contextOrNull)
Definition: undo.cxx:796
virtual void EmptyActionsChanged()
Definition: undo.cxx:1262
void ClearAllLevels()
clears all undo actions on the current level, plus all undo actions on superordinate levels,...
Definition: undo.cxx:448
SfxUndoManager & m_manager
Definition: undo.cxx:206
LockGuard(SfxUndoManager &i_manager)
Definition: undo.cxx:194
void scheduleNotification(UndoListenerStringMethod i_notificationMethod, const OUString &i_actionComment)
Definition: undo.cxx:304
::std::vector< std::unique_ptr< SfxUndoAction > > m_aUndoActionsCleanup
Definition: undo.cxx:312
::osl::ResettableMutexGuard m_aGuard
Definition: undo.cxx:311
void scheduleNotification(UndoListenerVoidMethod i_notificationMethod)
schedules the given SfxUndoListener method to be called for all registered listeners.
Definition: undo.cxx:299
void markForDeletion(std::unique_ptr< SfxUndoAction > i_action)
marks the given Undo action for deletion
Definition: undo.cxx:287
SfxUndoManager_Data & m_rManagerData
Definition: undo.cxx:310
UndoManagerGuard(SfxUndoManager_Data &i_managerData)
Definition: undo.cxx:258
::std::vector< NotifyUndoListener > m_notifiers
Definition: undo.cxx:313
int nCount
#define ENSURE_OR_RETURN(c, m, r)
#define ENSURE_OR_RETURN_VOID(c, m)
FilterGroup & rTarget
struct _xmlTextWriter * xmlTextWriterPtr
const sal_uInt16 idx[]
sal_Int32 nIndex
sal_Int64 n
while(true)
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
int i
void(SfxUndoListener::* UndoListenerVoidMethod)()
Definition: undo.cxx:209
void(SfxUndoListener::* UndoListenerStringMethod)(const OUString &)
Definition: undo.cxx:210
long Long
OUString toISO8601(const css::util::DateTime &rDateTime)
std::mutex aMutex
sal_Int16 nId
::std::vector< UndoStackMark > aMarks
Definition: undo.hxx:93
Impl(sal_uInt16 nId, ViewShellId nViewShellId, OUString aComment, OUString aRepeatComment)
Definition: undo.cxx:1275
ViewShellId mnViewShellId
Definition: undo.cxx:1270
OUString maRepeatComment
Definition: undo.cxx:1273
do not make use of these implementation details, unless you really really have to!
Definition: undo.hxx:101
std::vector< MarkedUndoAction > maUndoActions
Definition: undo.hxx:102
void Insert(std::unique_ptr< SfxUndoAction > i_action, size_t i_pos)
Definition: undo.cxx:149
virtual ~SfxUndoArray()
Definition: undo.cxx:1387
std::unique_ptr< SfxUndoAction > Remove(int idx)
Definition: undo.cxx:137
size_t nMaxUndoActions
Definition: undo.hxx:103
size_t nCurUndoAction
Definition: undo.hxx:104
SfxUndoArray * pFatherUndoArray
Definition: undo.hxx:105
::osl::Mutex aMutex
Definition: undo.cxx:158
SfxUndoManager_Data(const SfxUndoManager_Data &)=delete
SfxUndoManager_Data(size_t i_nMaxUndoActionCount)
Definition: undo.cxx:171
SfxUndoManager_Data & operator=(const SfxUndoManager_Data &)=delete
SfxUndoArray * pActUndoArray
Definition: undo.cxx:160
sal_Int32 mnMarks
Definition: undo.cxx:162
sal_Int32 mnEmptyMark
Definition: undo.cxx:163
bool mbClearUntilTopLevel
Definition: undo.cxx:166
UndoListeners aListeners
Definition: undo.cxx:169
SfxUndoArray maUndoArray
Definition: undo.cxx:159
osl::ResettableMutexGuard & rGuard
Definition: undo.cxx:269
ResetGuard(osl::ResettableMutexGuard &r)
Definition: undo.cxx:267
::std::vector< SfxUndoListener * > UndoListeners
Definition: undo.cxx:154
static boost::property_tree::ptree lcl_ActionToJson(size_t nIndex, SfxUndoAction const *pAction)
Returns a JSON representation of pAction.
Definition: undo.cxx:1194
UndoListenerVoidMethod m_notificationMethod
Definition: undo.cxx:248
OUString m_sActionComment
Definition: undo.cxx:250
UndoListenerStringMethod m_altNotificationMethod
Definition: undo.cxx:249
#define MARK_INVALID
Definition: undo.hxx:88
o3tl::strong_int< sal_Int32, struct ViewShellIdTag > ViewShellId
Definition: undo.hxx:30
sal_Int32 UndoStackMark
is a mark on the Undo stack
Definition: undo.hxx:87