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