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