Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/svl/undo.hxx
Line
Count
Source
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
#ifndef INCLUDED_SVL_UNDO_HXX
20
#define INCLUDED_SVL_UNDO_HXX
21
22
#include <svl/svldllapi.h>
23
#include <rtl/ustring.hxx>
24
#include <tools/datetime.hxx>
25
#include <o3tl/strong_int.hxx>
26
27
#include <memory>
28
#include <vector>
29
30
typedef o3tl::strong_int<sal_Int32, struct ViewShellIdTag> ViewShellId;
31
32
typedef struct _xmlTextWriter* xmlTextWriterPtr;
33
34
class SVL_DLLPUBLIC SAL_LOPLUGIN_ANNOTATE("crosscast") SfxRepeatTarget
35
{
36
public:
37
    virtual             ~SfxRepeatTarget() = 0;
38
};
39
40
41
class SVL_DLLPUBLIC SfxUndoContext
42
{
43
public:
44
    /**
45
     * Don't undo the top undo action, but an earlier one. It's the caller's responsibility to
46
     * ensure that the earlier undo action is independent from the following ones.
47
     */
48
0
    virtual size_t GetUndoOffset() { return 0; }
49
50
    virtual             ~SfxUndoContext() = 0;
51
};
52
53
54
class SVL_DLLPUBLIC SfxUndoAction
55
{
56
public:
57
                            SfxUndoAction();
58
    virtual                 ~SfxUndoAction() COVERITY_NOEXCEPT_FALSE;
59
60
    virtual void            Undo();
61
    virtual void            UndoWithContext( SfxUndoContext& i_context );
62
    virtual void            Redo();
63
    virtual void            RedoWithContext( SfxUndoContext& i_context );
64
    virtual void            Repeat(SfxRepeatTarget&);
65
    virtual bool            CanRepeat(SfxRepeatTarget&) const;
66
67
    virtual bool            Merge( SfxUndoAction *pNextAction );
68
69
    virtual OUString    GetComment() const;
70
    virtual OUString    GetRepeatComment(SfxRepeatTarget&) const;
71
    /// ID of the view shell that created this undo action.
72
    virtual ViewShellId GetViewShellId() const;
73
    /// Timestamp when this undo item was created.
74
    const DateTime& GetDateTime() const;
75
    virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
76
77
private:
78
    SfxUndoAction( const SfxUndoAction& ) = delete;
79
    SfxUndoAction& operator=( const SfxUndoAction& ) = delete;
80
81
    DateTime m_aDateTime;
82
};
83
84
85
/// is a mark on the Undo stack
86
typedef sal_Int32 UndoStackMark;
87
28.9M
#define MARK_INVALID    ::std::numeric_limits< UndoStackMark >::max()
88
89
struct MarkedUndoAction
90
{
91
    std::unique_ptr<SfxUndoAction>  pAction;
92
    ::std::vector< UndoStackMark >  aMarks;
93
94
6.23M
    MarkedUndoAction(std::unique_ptr<SfxUndoAction> p) : pAction(std::move(p)) {}
95
};
96
97
/** do not make use of these implementation details, unless you
98
    really really have to! */
99
struct SVL_DLLPUBLIC SfxUndoArray
100
{
101
    std::vector<MarkedUndoAction> maUndoActions;
102
    size_t                  nMaxUndoActions;
103
    size_t                  nCurUndoAction;
104
    SfxUndoArray            *pFatherUndoArray;
105
106
    SfxUndoArray(size_t nMax=0) :
107
4.17M
        nMaxUndoActions(nMax), nCurUndoAction(0), pFatherUndoArray(nullptr) {}
108
    virtual ~SfxUndoArray();
109
110
    SfxUndoArray& operator=( SfxUndoArray const & ) = delete; // MSVC2017 workaround
111
    SfxUndoArray( SfxUndoArray const & ) = delete; // MSVC2017 workaround
112
113
0
    SfxUndoAction* GetUndoAction(size_t idx) { return maUndoActions[idx].pAction.get(); }
114
    std::unique_ptr<SfxUndoAction> Remove(int idx);
115
    void Remove( size_t i_pos, size_t i_count );
116
    void Insert( std::unique_ptr<SfxUndoAction> i_action, size_t i_pos );
117
};
118
119
120
/** do not make use of these implementation details, unless you
121
    really really have to! */
122
class SVL_DLLPUBLIC SfxListUndoAction final : public SfxUndoAction, public SfxUndoArray
123
124
/*  [Explanation]
125
126
    UndoAction to composite multiple Undos in one UndoAction.
127
    These actions are used by SfxUndomanager. With < SfxUndoManager::EnterListAction >
128
    you can go one composite level down and with < SfxUndoManager::LeaveListAction > up again.
129
    Redo and Undo work element wise on SfxListUndoActions.
130
*/
131
{
132
    struct Impl;
133
    std::unique_ptr<Impl> mpImpl;
134
135
public:
136
137
    SfxListUndoAction(
138
        const OUString &rComment, const OUString& rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId, SfxUndoArray *pFather );
139
    virtual ~SfxListUndoAction() override;
140
141
    virtual void            Undo() override;
142
    virtual void            UndoWithContext( SfxUndoContext& i_context ) override;
143
    virtual void            Redo() override;
144
    virtual void            RedoWithContext( SfxUndoContext& i_context ) override;
145
    virtual void            Repeat(SfxRepeatTarget&) override;
146
    virtual bool            CanRepeat(SfxRepeatTarget&) const override;
147
148
    virtual bool            Merge( SfxUndoAction *pNextAction ) override;
149
150
    virtual OUString        GetComment() const override;
151
    /// See SfxUndoAction::GetViewShellId().
152
    ViewShellId GetViewShellId() const override;
153
    virtual OUString        GetRepeatComment(SfxRepeatTarget&) const override;
154
    sal_uInt16              GetId() const;
155
156
    void SetComment(const OUString& rComment);
157
    void dumpAsXml(xmlTextWriterPtr pWriter) const override;
158
};
159
160
161
/**  is a callback interface for notifications about state changes of an SfxUndoManager
162
*/
163
class SAL_NO_VTABLE SfxUndoListener
164
{
165
public:
166
    virtual void actionUndone( const OUString& i_actionComment ) = 0;
167
    virtual void actionRedone( const OUString& i_actionComment ) = 0;
168
    virtual void undoActionAdded( const OUString& i_actionComment ) = 0;
169
    virtual void cleared() = 0;
170
    virtual void clearedRedo() = 0;
171
    virtual void resetAll() = 0;
172
    virtual void listActionEntered( const OUString& i_comment ) = 0;
173
    virtual void listActionLeft( const OUString& i_comment ) = 0;
174
    virtual void listActionCancelled() = 0;
175
176
protected:
177
2.71k
    ~SfxUndoListener() {}
178
};
179
180
181
namespace svl::undo::impl
182
{
183
    class UndoManagerGuard;
184
    class LockGuard;
185
}
186
187
struct SfxUndoManager_Data;
188
class SVL_DLLPUBLIC SfxUndoManager
189
{
190
    std::unique_ptr< SfxUndoManager_Data >
191
                            m_xData;
192
public:
193
    static bool const CurrentLevel = true;
194
    static bool const TopLevel = false;
195
196
                            SfxUndoManager( size_t nMaxUndoActionCount = 20 );
197
    virtual                 ~SfxUndoManager();
198
199
    void                    SetMaxUndoActionCount( size_t nMaxUndoActionCount );
200
    size_t                  GetMaxUndoActionCount() const;
201
    virtual void            AddUndoAction( std::unique_ptr<SfxUndoAction> pAction, bool bTryMerg=false );
202
    virtual size_t          GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const;
203
    OUString                GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const;
204
    SfxUndoAction*          GetUndoAction( size_t nNo=0 ) const;
205
    /// Get info about all undo actions (comment, view shell id, etc.)
206
    OUString                GetUndoActionsInfo() const;
207
    virtual size_t          GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const;
208
    OUString                GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const;
209
    SfxUndoAction* GetRedoAction(size_t nNo = 0) const;
210
    /// Get info about all redo actions (comment, view shell id, etc.)
211
    OUString                GetRedoActionsInfo() const;
212
    virtual bool            Undo();
213
    virtual bool            Redo();
214
    /** Clears both the Redo and the Undo stack.
215
        Will assert and bail out when called while within a list action (<member>IsInListAction</member>).
216
    */
217
    virtual void            Clear();
218
    /** Clears the Redo stack.
219
        Will assert and bail out when called while within a list action (<member>IsInListAction</member>).
220
    */
221
    virtual void            ClearRedo();
222
223
    /** leaves any possible open list action (<member>IsInListAction</member>), and clears both the Undo and the
224
        Redo stack.
225
226
        Effectively, calling this method is equivalent to <code>while ( IsInListAction() ) LeaveListAction();</code>,
227
        followed by <code>Clear()</code>. The only difference to this calling sequence is that Reset is an
228
        atomic operation, also resulting in only one notification.
229
    */
230
    void                    Reset();
231
    /** determines whether an Undo or Redo is currently running
232
    */
233
    bool                    IsDoing() const;
234
    size_t                  GetRepeatActionCount() const;
235
    OUString                GetRepeatActionComment( SfxRepeatTarget &rTarget) const;
236
    bool                    Repeat( SfxRepeatTarget &rTarget );
237
    bool                    CanRepeat( SfxRepeatTarget &rTarget ) const;
238
    virtual void            EnterListAction(const OUString &rComment, const OUString& rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId);
239
    /** Leaves the list action entered with EnterListAction
240
        @return the number of the sub actions in the list which has just been left. Note that in case no such
241
            actions exist, the list action does not contribute to the Undo stack, but is silently removed.
242
    */
243
    size_t                  LeaveListAction();
244
245
    /** Leaves the list action entered with EnterListAction, and forcefully merges the previous
246
        action on the stack into the newly created list action.
247
248
        Say you have an Undo action A on the stack, then call EnterListAction, followed by one or more calls to
249
        AddUndoAction, followed by a call to LeaveAndMergeListAction. In opposite to LeaveListAction, your Undo
250
        stack will now still contain one undo action: the newly created list action, whose first child is the
251
        original A, whose other children are those you added via AddUndoAction, and whose comment is the same as
252
        the comment of A.
253
254
        Effectively, this means that all actions added between EnterListAction and LeaveAndMergeListAction are
255
        hidden from the user.
256
257
        @return the number of the sub actions in the list which has just been left. Note that in case no such
258
            actions exist, the list action does not contribute to the Undo stack, but is silently removed.
259
    */
260
    size_t                  LeaveAndMergeListAction();
261
    /// determines whether we're within a ListAction context, i.e. a LeaveListAction/LeaveAndMergeListAction call is pending
262
    bool                    IsInListAction() const;
263
    /// Determines how many nested list actions are currently open
264
    size_t                  GetListActionDepth() const;
265
    /** Clears the redo stack and removes the top undo action */
266
    void                    RemoveLastUndoAction();
267
    /** enables (true) or disables (false) recording of undo actions
268
269
        If undo actions are added while undo is disabled, they are deleted.
270
        Disabling undo does not clear the current undo buffer!
271
272
        Multiple calls to <code>EnableUndo</code> are not cumulative. That is, calling <code>EnableUndo( false )</code>
273
        twice, and then calling <code>EnableUndo( true )</code> means that Undo is enable afterwards.
274
    */
275
    void                    EnableUndo( bool bEnable );
276
    /// returns true if undo is currently enabled.
277
    /// This returns false if undo was disabled using EnableUndo( false ) and
278
    /// also during the runtime of the Undo() and Redo() methods.
279
    bool                    IsUndoEnabled() const;
280
    /// Adds a new listener to be notified about changes in the UndoManager's state
281
    void                    AddUndoListener( SfxUndoListener& i_listener );
282
    void                    RemoveUndoListener( SfxUndoListener& i_listener );
283
    bool                    IsEmptyActions() const;
284
285
286
    /** marks the current top-level element of the Undo stack, and returns a unique ID for it
287
    */
288
    UndoStackMark   MarkTopUndoAction();
289
290
    /** removes a mark given by its ID.
291
        After the call, the mark ID is invalid.
292
293
        @return the index at which the mark was removed, or std::numeric_limits<size_t>::max()
294
                if failed
295
    */
296
    size_t RemoveMark(UndoStackMark const i_mark);
297
298
    /** determines whether the top action on the Undo stack has a given mark
299
    */
300
    bool            HasTopUndoActionMark( UndoStackMark const i_mark );
301
302
    /** removes the oldest Undo actions from the stack
303
    * @returns false if it could not do anything (can happen when the action is very large)
304
    */
305
    [[nodiscard]]
306
    bool            RemoveOldestUndoAction();
307
308
    void dumpAsXml(xmlTextWriterPtr pWriter) const;
309
310
protected:
311
    bool    UndoWithContext( SfxUndoContext& i_context );
312
    bool    RedoWithContext( SfxUndoContext& i_context );
313
314
    // Undoes a specific mark on the undo stack, and removes it from the undo/redo stack,
315
    // but only in case when the redo stack is empty. This is a dangerous operation, because
316
    // it undoes out of order.
317
    void UndoMark(UndoStackMark i_mark);
318
319
    void    ImplClearRedo_NoLock( bool const i_currentLevel );
320
321
    /** clears all undo actions on the current level, plus all undo actions on superordinate levels,
322
        as soon as those levels are reached.
323
324
        If no list action is active currently, i.e. we're on the top level already, this method is equivalent to
325
        ->Clear.
326
327
        Otherwise, the Undo actions on the current level are removed. Upon leaving the current list action, all
328
        undo actions on the then-current level are removed, too. This is continued until the top level is reached.
329
    */
330
    void    ClearAllLevels();
331
    virtual void EmptyActionsChanged();
332
333
private:
334
    SAL_DLLPRIVATE size_t  ImplLeaveListAction( const bool i_merge, ::svl::undo::impl::UndoManagerGuard& i_guard );
335
    SAL_DLLPRIVATE bool    ImplAddUndoAction_NoNotify( std::unique_ptr<SfxUndoAction> pAction, bool bTryMerge, bool bClearRedo, ::svl::undo::impl::UndoManagerGuard& i_guard );
336
    SAL_DLLPRIVATE void    ImplClearRedo( ::svl::undo::impl::UndoManagerGuard& i_guard, bool const i_currentLevel );
337
    SAL_DLLPRIVATE void    ImplClearUndo( ::svl::undo::impl::UndoManagerGuard& i_guard );
338
    SAL_DLLPRIVATE void    ImplClearCurrentLevel_NoNotify( ::svl::undo::impl::UndoManagerGuard& i_guard );
339
    SAL_DLLPRIVATE size_t  ImplGetRedoActionCount_Lock( bool const i_currentLevel = CurrentLevel ) const;
340
    SAL_DLLPRIVATE bool    ImplIsUndoEnabled_Lock() const;
341
    SAL_DLLPRIVATE bool    ImplIsInListAction_Lock() const;
342
    SAL_DLLPRIVATE void    ImplEnableUndo_Lock( bool const i_enable );
343
344
    SAL_DLLPRIVATE bool    ImplUndo( SfxUndoContext* i_contextOrNull );
345
    SAL_DLLPRIVATE bool    ImplRedo( SfxUndoContext* i_contextOrNull );
346
    SAL_DLLPRIVATE void    ImplCheckEmptyActions();
347
    inline  bool    ImplIsEmptyActions() const;
348
349
    friend class ::svl::undo::impl::LockGuard;
350
};
351
352
#endif
353
354
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */