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