Coverage Report

Created: 2026-08-14 10:22

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