Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/doc/docundomanager.cxx
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
20
21
#include <docundomanager.hxx>
22
#include <sfx2/sfxbasemodel.hxx>
23
#include <sfx2/objsh.hxx>
24
#include <sfx2/viewfrm.hxx>
25
#include <sfx2/viewsh.hxx>
26
#include <sfx2/bindings.hxx>
27
#include <sfx2/sfxsids.hrc>
28
#include <com/sun/star/lang/NoSupportException.hpp>
29
#include <com/sun/star/lang/NotInitializedException.hpp>
30
#include <svl/undo.hxx>
31
#include <comphelper/diagnose_ex.hxx>
32
#include <framework/undomanagerhelper.hxx>
33
#include <framework/imutex.hxx>
34
35
36
namespace sfx2
37
{
38
39
40
    using ::com::sun::star::uno::Reference;
41
    using ::com::sun::star::uno::XInterface;
42
    using ::com::sun::star::uno::Sequence;
43
    using ::com::sun::star::document::XUndoAction;
44
    using ::com::sun::star::lang::NotInitializedException;
45
    using ::com::sun::star::document::XUndoManagerListener;
46
    using ::com::sun::star::document::XUndoManager;
47
    using ::com::sun::star::lang::NoSupportException;
48
    using ::com::sun::star::frame::XModel;
49
50
    //= DocumentUndoManager_Impl
51
52
    struct DocumentUndoManager_Impl : public ::framework::IUndoManagerImplementation
53
    {
54
        DocumentUndoManager&                rAntiImpl;
55
        SfxUndoManager*                     pUndoManager;
56
        ::framework::UndoManagerHelper      aUndoHelper;
57
58
        explicit DocumentUndoManager_Impl( DocumentUndoManager& i_antiImpl )
59
2.97k
            :rAntiImpl( i_antiImpl )
60
2.97k
            ,pUndoManager( impl_retrieveUndoManager( i_antiImpl.getBaseModel() ) )
61
                // do this *before* the construction of aUndoHelper (which actually means: put pUndoManager before
62
                // aUndoHelper in the member list)!
63
2.97k
            ,aUndoHelper( *this )
64
2.97k
        {
65
2.97k
        }
66
67
        virtual ~DocumentUndoManager_Impl()
68
2.97k
        {
69
2.97k
        };
70
71
        // IUndoManagerImplementation
72
        virtual SfxUndoManager&        getImplUndoManager() override;
73
        virtual Reference< XUndoManager >   getThis() override;
74
75
        void disposing()
76
2.97k
        {
77
2.97k
            aUndoHelper.disposing();
78
2.97k
            ENSURE_OR_RETURN_VOID( pUndoManager, "DocumentUndoManager_Impl::disposing: already disposed!" );
79
2.97k
            pUndoManager = nullptr;
80
2.97k
        }
81
82
        void invalidateXDo_nolck();
83
84
    private:
85
        static SfxUndoManager* impl_retrieveUndoManager( SfxBaseModel& i_baseModel )
86
2.97k
        {
87
2.97k
            SfxUndoManager* pUndoManager( nullptr );
88
2.97k
            SfxObjectShell* pObjectShell = i_baseModel.GetObjectShell();
89
2.97k
            if ( pObjectShell != nullptr )
90
2.97k
                pUndoManager = pObjectShell->GetUndoManager();
91
2.97k
            if ( !pUndoManager )
92
0
                throw NotInitializedException( OUString(), i_baseModel );
93
2.97k
            return pUndoManager;
94
2.97k
        }
95
    };
96
97
98
    SfxUndoManager& DocumentUndoManager_Impl::getImplUndoManager()
99
14.4k
    {
100
14.4k
        ENSURE_OR_THROW( pUndoManager != nullptr, "DocumentUndoManager_Impl::getImplUndoManager: no access to the doc's UndoManager implementation!" );
101
102
#if OSL_DEBUG_LEVEL > 0
103
        // in a non-product build, assert if the current UndoManager at the shell is not the same we obtained
104
        // (and cached) at construction time
105
        SfxObjectShell* pObjectShell = rAntiImpl.getBaseModel().GetObjectShell();
106
        OSL_ENSURE( ( pObjectShell != nullptr ) && ( pUndoManager == pObjectShell->GetUndoManager() ),
107
            "DocumentUndoManager_Impl::getImplUndoManager: the UndoManager changed meanwhile - what about our listener?" );
108
#endif
109
110
14.4k
        return *pUndoManager;
111
14.4k
    }
112
113
114
    Reference< XUndoManager > DocumentUndoManager_Impl::getThis()
115
2.97k
    {
116
2.97k
        return static_cast< XUndoManager* >( &rAntiImpl );
117
2.97k
    }
118
119
120
    void DocumentUndoManager_Impl::invalidateXDo_nolck()
121
0
    {
122
0
        SfxModelGuard aGuard( rAntiImpl );
123
124
0
        const SfxObjectShell* pDocShell = rAntiImpl.getBaseModel().GetObjectShell();
125
0
        ENSURE_OR_THROW( pDocShell != nullptr, "lcl_invalidateUndo: no access to the doc shell!" );
126
0
        SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( pDocShell );
127
0
        while ( pViewFrame )
128
0
        {
129
0
            pViewFrame->GetBindings().Invalidate( SID_UNDO );
130
0
            pViewFrame->GetBindings().Invalidate( SID_REDO );
131
0
            pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDocShell );
132
0
        }
133
0
    }
134
135
136
    //= SolarMutexFacade
137
138
    namespace {
139
140
    /** a facade for the SolarMutex, implementing ::framework::IMutex
141
    */
142
    class SolarMutexFacade : public ::framework::IMutex
143
    {
144
    public:
145
        SolarMutexFacade()
146
8.53k
        {
147
8.53k
        }
148
149
0
        virtual ~SolarMutexFacade() {}
150
151
        virtual void acquire() override
152
0
        {
153
0
            Application::GetSolarMutex().acquire();
154
0
        }
155
156
        virtual void release() override
157
0
        {
158
0
            Application::GetSolarMutex().release();
159
0
        }
160
    };
161
162
163
    //= UndoManagerGuard
164
165
    class UndoManagerGuard  :public ::framework::IMutexGuard
166
    {
167
    public:
168
        explicit UndoManagerGuard( DocumentUndoManager& i_undoManager )
169
8.53k
            :m_guard( i_undoManager )
170
8.53k
        {
171
8.53k
        }
172
173
        virtual ~UndoManagerGuard()
174
8.53k
        {
175
8.53k
        }
176
177
        UndoManagerGuard(const UndoManagerGuard&) = delete;
178
        UndoManagerGuard& operator=(const UndoManagerGuard&) = delete;
179
180
        virtual void clear() override
181
0
        {
182
0
            m_guard.clear();
183
0
        }
184
185
        virtual ::framework::IMutex& getGuardedMutex() override
186
0
        {
187
            // note that this means that we *know* that SfxModelGuard also locks the SolarMutex (nothing more, nothing less).
188
            // If this ever changes, we need to adjust this code here, too.
189
0
            return m_solarMutexFacade;
190
0
        }
191
192
    private:
193
        SfxModelGuard       m_guard;
194
        SolarMutexFacade    m_solarMutexFacade;
195
    };
196
197
    }
198
199
    //= DocumentUndoManager
200
201
202
    DocumentUndoManager::DocumentUndoManager( SfxBaseModel& i_document )
203
2.97k
        :SfxModelSubComponent( i_document )
204
2.97k
        ,m_pImpl( new DocumentUndoManager_Impl( *this ) )
205
2.97k
    {
206
2.97k
    }
207
208
    DocumentUndoManager::~DocumentUndoManager()
209
2.97k
    {
210
2.97k
    }
211
212
    void DocumentUndoManager::disposing()
213
2.97k
    {
214
2.97k
        m_pImpl->disposing();
215
2.97k
    }
216
217
218
    bool DocumentUndoManager::isInContext() const
219
0
    {
220
        // No mutex locking within this method, no disposal check - this is the responsibility of the owner.
221
0
        return m_pImpl->getImplUndoManager().IsInListAction();
222
0
    }
223
224
225
    void SAL_CALL DocumentUndoManager::acquire() noexcept
226
14.8k
    {
227
14.8k
        OWeakObject::acquire();
228
14.8k
        SfxModelSubComponent::acquireModel();
229
14.8k
    }
230
231
232
    void SAL_CALL DocumentUndoManager::release() noexcept
233
14.8k
    {
234
14.8k
        SfxModelSubComponent::releaseModel();
235
14.8k
        OWeakObject::release();
236
14.8k
    }
237
238
239
    void SAL_CALL DocumentUndoManager::enterUndoContext( const OUString& i_title )
240
0
    {
241
        // SYNCHRONIZED --->
242
0
        UndoManagerGuard aGuard( *this );
243
0
        m_pImpl->aUndoHelper.enterUndoContext( i_title, aGuard );
244
        // <--- SYNCHRONIZED
245
0
        m_pImpl->invalidateXDo_nolck();
246
0
    }
247
248
249
    void SAL_CALL DocumentUndoManager::enterHiddenUndoContext(  )
250
0
    {
251
        // SYNCHRONIZED --->
252
0
        UndoManagerGuard aGuard( *this );
253
0
        m_pImpl->aUndoHelper.enterHiddenUndoContext( aGuard );
254
        // <--- SYNCHRONIZED
255
0
        m_pImpl->invalidateXDo_nolck();
256
0
    }
257
258
259
    void SAL_CALL DocumentUndoManager::leaveUndoContext(  )
260
0
    {
261
        // SYNCHRONIZED --->
262
0
        UndoManagerGuard aGuard( *this );
263
0
        m_pImpl->aUndoHelper.leaveUndoContext( aGuard );
264
        // <--- SYNCHRONIZED
265
0
        m_pImpl->invalidateXDo_nolck();
266
0
    }
267
268
269
    void SAL_CALL DocumentUndoManager::addUndoAction( const Reference< XUndoAction >& i_action )
270
0
    {
271
        // SYNCHRONIZED --->
272
0
        UndoManagerGuard aGuard( *this );
273
0
        m_pImpl->aUndoHelper.addUndoAction( i_action, aGuard );
274
        // <--- SYNCHRONIZED
275
0
        m_pImpl->invalidateXDo_nolck();
276
0
    }
277
278
279
    void SAL_CALL DocumentUndoManager::undo(  )
280
0
    {
281
        // SYNCHRONIZED --->
282
0
        UndoManagerGuard aGuard( *this );
283
0
        m_pImpl->aUndoHelper.undo( aGuard );
284
        // <--- SYNCHRONIZED
285
0
        m_pImpl->invalidateXDo_nolck();
286
0
    }
287
288
289
    void SAL_CALL DocumentUndoManager::redo(  )
290
0
    {
291
        // SYNCHRONIZED --->
292
0
        UndoManagerGuard aGuard( *this );
293
0
        m_pImpl->aUndoHelper.redo( aGuard );
294
        // <--- SYNCHRONIZED
295
0
        m_pImpl->invalidateXDo_nolck();
296
0
    }
297
298
299
    sal_Bool SAL_CALL DocumentUndoManager::isUndoPossible(  )
300
0
    {
301
0
        UndoManagerGuard aGuard( *this );
302
0
        return m_pImpl->aUndoHelper.isUndoPossible();
303
0
    }
304
305
306
    sal_Bool SAL_CALL DocumentUndoManager::isRedoPossible(  )
307
0
    {
308
0
        UndoManagerGuard aGuard( *this );
309
0
        return m_pImpl->aUndoHelper.isRedoPossible();
310
0
    }
311
312
313
    OUString SAL_CALL DocumentUndoManager::getCurrentUndoActionTitle(  )
314
0
    {
315
0
        UndoManagerGuard aGuard( *this );
316
0
        return m_pImpl->aUndoHelper.getCurrentUndoActionTitle();
317
0
    }
318
319
320
    OUString SAL_CALL DocumentUndoManager::getCurrentRedoActionTitle(  )
321
0
    {
322
0
        UndoManagerGuard aGuard( *this );
323
0
        return m_pImpl->aUndoHelper.getCurrentRedoActionTitle();
324
0
    }
325
326
327
    Sequence< OUString > SAL_CALL DocumentUndoManager::getAllUndoActionTitles(  )
328
0
    {
329
0
        UndoManagerGuard aGuard( *this );
330
0
        return m_pImpl->aUndoHelper.getAllUndoActionTitles();
331
0
    }
332
333
334
    Sequence< OUString > SAL_CALL DocumentUndoManager::getAllRedoActionTitles(  )
335
0
    {
336
0
        UndoManagerGuard aGuard( *this );
337
0
        return m_pImpl->aUndoHelper.getAllRedoActionTitles();
338
0
    }
339
340
341
    void SAL_CALL DocumentUndoManager::clear(  )
342
0
    {
343
        // SYNCHRONIZED --->
344
0
        UndoManagerGuard aGuard( *this );
345
0
        m_pImpl->aUndoHelper.clear( aGuard );
346
        // <--- SYNCHRONIZED
347
0
        m_pImpl->invalidateXDo_nolck();
348
0
    }
349
350
351
    void SAL_CALL DocumentUndoManager::clearRedo(  )
352
0
    {
353
        // SYNCHRONIZED --->
354
0
        UndoManagerGuard aGuard( *this );
355
0
        m_pImpl->aUndoHelper.clearRedo( aGuard );
356
        // <--- SYNCHRONIZED
357
0
        m_pImpl->invalidateXDo_nolck();
358
0
    }
359
360
361
    void SAL_CALL DocumentUndoManager::reset()
362
0
    {
363
        // SYNCHRONIZED --->
364
0
        UndoManagerGuard aGuard( *this );
365
0
        m_pImpl->aUndoHelper.reset( aGuard );
366
        // <--- SYNCHRONIZED
367
0
        m_pImpl->invalidateXDo_nolck();
368
0
    }
369
370
371
    void SAL_CALL DocumentUndoManager::lock(  )
372
2.97k
    {
373
2.97k
        UndoManagerGuard aGuard( *this );
374
2.97k
        m_pImpl->aUndoHelper.lock();
375
2.97k
    }
376
377
378
    void SAL_CALL DocumentUndoManager::unlock(  )
379
2.57k
    {
380
2.57k
        UndoManagerGuard aGuard( *this );
381
2.57k
        m_pImpl->aUndoHelper.unlock();
382
2.57k
    }
383
384
385
    sal_Bool SAL_CALL DocumentUndoManager::isLocked(  )
386
2.97k
    {
387
2.97k
        UndoManagerGuard aGuard( *this );
388
2.97k
        return m_pImpl->aUndoHelper.isLocked();
389
2.97k
    }
390
391
392
    void SAL_CALL DocumentUndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
393
0
    {
394
0
        UndoManagerGuard aGuard( *this );
395
0
        return m_pImpl->aUndoHelper.addUndoManagerListener( i_listener );
396
0
    }
397
398
399
    void SAL_CALL DocumentUndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
400
0
    {
401
0
        UndoManagerGuard aGuard( *this );
402
0
        return m_pImpl->aUndoHelper.removeUndoManagerListener( i_listener );
403
0
    }
404
405
406
    Reference< XInterface > SAL_CALL DocumentUndoManager::getParent(  )
407
0
    {
408
0
        UndoManagerGuard aGuard( *this );
409
0
        return static_cast< XModel* >( &getBaseModel() );
410
0
    }
411
412
413
    void SAL_CALL DocumentUndoManager::setParent( const Reference< XInterface >& )
414
0
    {
415
0
        throw NoSupportException( OUString(), m_pImpl->getThis() );
416
0
    }
417
418
419
} // namespace sfx2
420
421
422
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */