1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
29 #include "docundomanager.hxx"
30 #include "sfx2/sfxbasemodel.hxx"
31 #include "sfx2/objsh.hxx"
32 #include "sfx2/viewfrm.hxx"
33 #include "sfx2/viewsh.hxx"
34 #include "sfx2/bindings.hxx"
36 /** === begin UNO includes === **/
37 #include <com/sun/star/lang/XComponent.hpp>
38 /** === end UNO includes === **/
40 #include <comphelper/anytostring.hxx>
41 #include <comphelper/flagguard.hxx>
42 #include <svl/undo.hxx>
43 #include <tools/diagnose_ex.h>
44 #include <framework/undomanagerhelper.hxx>
46 #include <boost/noncopyable.hpp>
49 //......................................................................................................................
52 //......................................................................................................................
54 /** === begin UNO using === **/
55 using ::com::sun::star::uno::Reference
;
56 using ::com::sun::star::uno::XInterface
;
57 using ::com::sun::star::uno::UNO_QUERY
;
58 using ::com::sun::star::uno::UNO_QUERY_THROW
;
59 using ::com::sun::star::uno::UNO_SET_THROW
;
60 using ::com::sun::star::uno::Exception
;
61 using ::com::sun::star::uno::RuntimeException
;
62 using ::com::sun::star::uno::Any
;
63 using ::com::sun::star::uno::makeAny
;
64 using ::com::sun::star::uno::Sequence
;
65 using ::com::sun::star::uno::Type
;
66 using ::com::sun::star::util::InvalidStateException
;
67 using ::com::sun::star::document::EmptyUndoStackException
;
68 using ::com::sun::star::util::NotLockedException
;
69 using ::com::sun::star::document::UndoContextNotClosedException
;
70 using ::com::sun::star::document::XUndoAction
;
71 using ::com::sun::star::document::XUndoManagerSupplier
;
72 using ::com::sun::star::lang::XComponent
;
73 using ::com::sun::star::lang::IllegalArgumentException
;
74 using ::com::sun::star::lang::NotInitializedException
;
75 using ::com::sun::star::lang::EventObject
;
76 using ::com::sun::star::document::UndoManagerEvent
;
77 using ::com::sun::star::document::XUndoManagerListener
;
78 using ::com::sun::star::document::UndoFailedException
;
79 using ::com::sun::star::document::XUndoManager
;
80 using ::com::sun::star::lang::NoSupportException
;
81 using ::com::sun::star::frame::XModel
;
82 /** === end UNO using === **/
84 using ::svl::IUndoManager
;
86 //==================================================================================================================
87 //= DocumentUndoManager_Impl
88 //==================================================================================================================
89 struct DocumentUndoManager_Impl
: public ::framework::IUndoManagerImplementation
91 DocumentUndoManager
& rAntiImpl
;
92 IUndoManager
* pUndoManager
;
93 ::framework::UndoManagerHelper aUndoHelper
;
95 DocumentUndoManager_Impl( DocumentUndoManager
& i_antiImpl
)
96 :rAntiImpl( i_antiImpl
)
97 ,pUndoManager( impl_retrieveUndoManager( i_antiImpl
.getBaseModel() ) )
98 // do this *before* the construction of aUndoHelper (which actually means: put pUndoManager before
99 // aUndoHelper in the member list)!
100 ,aUndoHelper( *this )
104 virtual ~DocumentUndoManager_Impl()
108 const SfxObjectShell
* getObjectShell() const { return rAntiImpl
.getBaseModel().GetObjectShell(); }
109 SfxObjectShell
* getObjectShell() { return rAntiImpl
.getBaseModel().GetObjectShell(); }
111 // IUndoManagerImplementation
112 virtual ::svl::IUndoManager
& getImplUndoManager();
113 virtual Reference
< XUndoManager
> getThis();
117 aUndoHelper
.disposing();
118 ENSURE_OR_RETURN_VOID( pUndoManager
, "DocumentUndoManager_Impl::disposing: already disposed!" );
122 void invalidateXDo_nolck();
125 static IUndoManager
* impl_retrieveUndoManager( SfxBaseModel
& i_baseModel
)
127 IUndoManager
* pUndoManager( NULL
);
128 SfxObjectShell
* pObjectShell
= i_baseModel
.GetObjectShell();
129 if ( pObjectShell
!= NULL
)
130 pUndoManager
= pObjectShell
->GetUndoManager();
132 throw NotInitializedException( ::rtl::OUString(), *&i_baseModel
);
137 //------------------------------------------------------------------------------------------------------------------
138 ::svl::IUndoManager
& DocumentUndoManager_Impl::getImplUndoManager()
140 ENSURE_OR_THROW( pUndoManager
!= NULL
, "DocumentUndoManager_Impl::getImplUndoManager: no access to the doc's UndoManager implementation!" );
142 #if OSL_DEBUG_LEVEL > 0
143 // in a non-product build, assert if the current UndoManager at the shell is not the same we obtained
144 // (and cached) at construction time
145 SfxObjectShell
* pObjectShell
= rAntiImpl
.getBaseModel().GetObjectShell();
146 OSL_ENSURE( ( pObjectShell
!= NULL
) && ( pUndoManager
== pObjectShell
->GetUndoManager() ),
147 "DocumentUndoManager_Impl::getImplUndoManager: the UndoManager changed meanwhile - what about our listener?" );
150 return *pUndoManager
;
153 //------------------------------------------------------------------------------------------------------------------
154 Reference
< XUndoManager
> DocumentUndoManager_Impl::getThis()
156 return static_cast< XUndoManager
* >( &rAntiImpl
);
159 //------------------------------------------------------------------------------------------------------------------
160 void DocumentUndoManager_Impl::invalidateXDo_nolck()
162 SfxModelGuard
aGuard( rAntiImpl
);
164 const SfxObjectShell
* pDocShell
= getObjectShell();
165 ENSURE_OR_THROW( pDocShell
!= NULL
, "lcl_invalidateUndo: no access to the doc shell!" );
166 SfxViewFrame
* pViewFrame
= SfxViewFrame::GetFirst( pDocShell
);
169 pViewFrame
->GetBindings().Invalidate( SID_UNDO
);
170 pViewFrame
->GetBindings().Invalidate( SID_REDO
);
171 pViewFrame
= SfxViewFrame::GetNext( *pViewFrame
, pDocShell
);
175 //==================================================================================================================
177 //==================================================================================================================
178 /** a facade for the SolarMutex, implementing ::framework::IMutex (as opposed to ::vos::IMutex)
180 class SolarMutexFacade
: public ::framework::IMutex
187 virtual ~SolarMutexFacade() {}
189 virtual void acquire()
191 Application::GetSolarMutex().acquire();
194 virtual void release()
196 Application::GetSolarMutex().release();
200 //==================================================================================================================
202 //==================================================================================================================
203 class UndoManagerGuard
:public ::framework::IMutexGuard
204 ,public ::boost::noncopyable
207 UndoManagerGuard( DocumentUndoManager
& i_undoManager
)
208 :m_guard( i_undoManager
)
209 ,m_solarMutexFacade()
213 virtual ~UndoManagerGuard()
227 virtual ::framework::IMutex
& getGuardedMutex()
229 // note that this means that we *know* that SfxModelGuard also locks the SolarMutex (nothing more, nothing less).
230 // If this ever changes, we need to adjust this code here, too.
231 return m_solarMutexFacade
;
235 SfxModelGuard m_guard
;
236 SolarMutexFacade m_solarMutexFacade
;
239 //==================================================================================================================
240 //= DocumentUndoManager
241 //==================================================================================================================
242 //------------------------------------------------------------------------------------------------------------------
243 DocumentUndoManager::DocumentUndoManager( SfxBaseModel
& i_document
)
244 :SfxModelSubComponent( i_document
)
245 ,m_pImpl( new DocumentUndoManager_Impl( *this ) )
249 //------------------------------------------------------------------------------------------------------------------
250 DocumentUndoManager::~DocumentUndoManager()
254 //------------------------------------------------------------------------------------------------------------------
255 void DocumentUndoManager::disposing()
257 m_pImpl
->disposing();
260 //------------------------------------------------------------------------------------------------------------------
261 bool DocumentUndoManager::isInContext() const
263 // No mutex locking within this method, no disposal check - this is the responsibility of the owner.
264 return m_pImpl
->getImplUndoManager().IsInListAction();
267 //------------------------------------------------------------------------------------------------------------------
268 void SAL_CALL
DocumentUndoManager::acquire( ) throw ()
270 SfxModelSubComponent::acquire();
273 //------------------------------------------------------------------------------------------------------------------
274 void SAL_CALL
DocumentUndoManager::release( ) throw ()
276 SfxModelSubComponent::release();
279 //------------------------------------------------------------------------------------------------------------------
280 void SAL_CALL
DocumentUndoManager::enterUndoContext( const ::rtl::OUString
& i_title
) throw (RuntimeException
)
283 UndoManagerGuard
aGuard( *this );
284 m_pImpl
->aUndoHelper
.enterUndoContext( i_title
, aGuard
);
286 m_pImpl
->invalidateXDo_nolck();
289 //------------------------------------------------------------------------------------------------------------------
290 void SAL_CALL
DocumentUndoManager::enterHiddenUndoContext( ) throw (EmptyUndoStackException
, RuntimeException
)
293 UndoManagerGuard
aGuard( *this );
294 m_pImpl
->aUndoHelper
.enterHiddenUndoContext( aGuard
);
296 m_pImpl
->invalidateXDo_nolck();
299 //------------------------------------------------------------------------------------------------------------------
300 void SAL_CALL
DocumentUndoManager::leaveUndoContext( ) throw (InvalidStateException
, RuntimeException
)
303 UndoManagerGuard
aGuard( *this );
304 m_pImpl
->aUndoHelper
.leaveUndoContext( aGuard
);
306 m_pImpl
->invalidateXDo_nolck();
309 //------------------------------------------------------------------------------------------------------------------
310 void SAL_CALL
DocumentUndoManager::addUndoAction( const Reference
< XUndoAction
>& i_action
) throw (RuntimeException
, IllegalArgumentException
)
313 UndoManagerGuard
aGuard( *this );
314 m_pImpl
->aUndoHelper
.addUndoAction( i_action
, aGuard
);
316 m_pImpl
->invalidateXDo_nolck();
319 //------------------------------------------------------------------------------------------------------------------
320 void SAL_CALL
DocumentUndoManager::undo( ) throw (EmptyUndoStackException
, UndoContextNotClosedException
, UndoFailedException
, RuntimeException
)
323 UndoManagerGuard
aGuard( *this );
324 m_pImpl
->aUndoHelper
.undo( aGuard
);
326 m_pImpl
->invalidateXDo_nolck();
329 //------------------------------------------------------------------------------------------------------------------
330 void SAL_CALL
DocumentUndoManager::redo( ) throw (EmptyUndoStackException
, UndoContextNotClosedException
, UndoFailedException
, RuntimeException
)
333 UndoManagerGuard
aGuard( *this );
334 m_pImpl
->aUndoHelper
.redo( aGuard
);
336 m_pImpl
->invalidateXDo_nolck();
339 //------------------------------------------------------------------------------------------------------------------
340 ::sal_Bool SAL_CALL
DocumentUndoManager::isUndoPossible( ) throw (RuntimeException
)
342 UndoManagerGuard
aGuard( *this );
343 return m_pImpl
->aUndoHelper
.isUndoPossible();
346 //------------------------------------------------------------------------------------------------------------------
347 ::sal_Bool SAL_CALL
DocumentUndoManager::isRedoPossible( ) throw (RuntimeException
)
349 UndoManagerGuard
aGuard( *this );
350 return m_pImpl
->aUndoHelper
.isRedoPossible();
353 //------------------------------------------------------------------------------------------------------------------
354 ::rtl::OUString SAL_CALL
DocumentUndoManager::getCurrentUndoActionTitle( ) throw (EmptyUndoStackException
, RuntimeException
)
356 UndoManagerGuard
aGuard( *this );
357 return m_pImpl
->aUndoHelper
.getCurrentUndoActionTitle();
360 //------------------------------------------------------------------------------------------------------------------
361 ::rtl::OUString SAL_CALL
DocumentUndoManager::getCurrentRedoActionTitle( ) throw (EmptyUndoStackException
, RuntimeException
)
363 UndoManagerGuard
aGuard( *this );
364 return m_pImpl
->aUndoHelper
.getCurrentRedoActionTitle();
367 //------------------------------------------------------------------------------------------------------------------
368 Sequence
< ::rtl::OUString
> SAL_CALL
DocumentUndoManager::getAllUndoActionTitles( ) throw (RuntimeException
)
370 UndoManagerGuard
aGuard( *this );
371 return m_pImpl
->aUndoHelper
.getAllUndoActionTitles();
374 //------------------------------------------------------------------------------------------------------------------
375 Sequence
< ::rtl::OUString
> SAL_CALL
DocumentUndoManager::getAllRedoActionTitles( ) throw (RuntimeException
)
377 UndoManagerGuard
aGuard( *this );
378 return m_pImpl
->aUndoHelper
.getAllRedoActionTitles();
381 //------------------------------------------------------------------------------------------------------------------
382 void SAL_CALL
DocumentUndoManager::clear( ) throw (UndoContextNotClosedException
, RuntimeException
)
385 UndoManagerGuard
aGuard( *this );
386 m_pImpl
->aUndoHelper
.clear( aGuard
);
388 m_pImpl
->invalidateXDo_nolck();
391 //------------------------------------------------------------------------------------------------------------------
392 void SAL_CALL
DocumentUndoManager::clearRedo( ) throw (UndoContextNotClosedException
, RuntimeException
)
395 UndoManagerGuard
aGuard( *this );
396 m_pImpl
->aUndoHelper
.clearRedo( aGuard
);
398 m_pImpl
->invalidateXDo_nolck();
401 //------------------------------------------------------------------------------------------------------------------
402 void SAL_CALL
DocumentUndoManager::reset() throw (RuntimeException
)
405 UndoManagerGuard
aGuard( *this );
406 m_pImpl
->aUndoHelper
.reset( aGuard
);
408 m_pImpl
->invalidateXDo_nolck();
411 //------------------------------------------------------------------------------------------------------------------
412 void SAL_CALL
DocumentUndoManager::lock( ) throw (RuntimeException
)
414 UndoManagerGuard
aGuard( *this );
415 m_pImpl
->aUndoHelper
.lock();
418 //------------------------------------------------------------------------------------------------------------------
419 void SAL_CALL
DocumentUndoManager::unlock( ) throw (RuntimeException
, NotLockedException
)
421 UndoManagerGuard
aGuard( *this );
422 m_pImpl
->aUndoHelper
.unlock();
425 //------------------------------------------------------------------------------------------------------------------
426 ::sal_Bool SAL_CALL
DocumentUndoManager::isLocked( ) throw (RuntimeException
)
428 UndoManagerGuard
aGuard( *this );
429 return m_pImpl
->aUndoHelper
.isLocked();
432 //------------------------------------------------------------------------------------------------------------------
433 void SAL_CALL
DocumentUndoManager::addUndoManagerListener( const Reference
< XUndoManagerListener
>& i_listener
) throw (RuntimeException
)
435 UndoManagerGuard
aGuard( *this );
436 return m_pImpl
->aUndoHelper
.addUndoManagerListener( i_listener
);
439 //------------------------------------------------------------------------------------------------------------------
440 void SAL_CALL
DocumentUndoManager::removeUndoManagerListener( const Reference
< XUndoManagerListener
>& i_listener
) throw (RuntimeException
)
442 UndoManagerGuard
aGuard( *this );
443 return m_pImpl
->aUndoHelper
.removeUndoManagerListener( i_listener
);
446 //------------------------------------------------------------------------------------------------------------------
447 Reference
< XInterface
> SAL_CALL
DocumentUndoManager::getParent( ) throw (RuntimeException
)
449 UndoManagerGuard
aGuard( *this );
450 return static_cast< XModel
* >( &getBaseModel() );
453 //------------------------------------------------------------------------------------------------------------------
454 void SAL_CALL
DocumentUndoManager::setParent( const Reference
< XInterface
>& i_parent
) throw (NoSupportException
, RuntimeException
)
457 throw NoSupportException( ::rtl::OUString(), m_pImpl
->getThis() );
460 //......................................................................................................................
462 //......................................................................................................................
464 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */