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 1 : DocumentUndoManager_Impl( DocumentUndoManager& i_antiImpl )
86 : :rAntiImpl( i_antiImpl )
87 1 : ,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 2 : ,aUndoHelper( *this )
91 : {
92 1 : }
93 :
94 0 : virtual ~DocumentUndoManager_Impl()
95 0 : {
96 0 : };
97 :
98 : const SfxObjectShell* getObjectShell() const { return rAntiImpl.getBaseModel().GetObjectShell(); }
99 0 : SfxObjectShell* getObjectShell() { return rAntiImpl.getBaseModel().GetObjectShell(); }
100 :
101 : // IUndoManagerImplementation
102 : virtual ::svl::IUndoManager& getImplUndoManager();
103 : virtual Reference< XUndoManager > getThis();
104 :
105 1 : void disposing()
106 : {
107 1 : aUndoHelper.disposing();
108 2 : ENSURE_OR_RETURN_VOID( pUndoManager, "DocumentUndoManager_Impl::disposing: already disposed!" );
109 1 : pUndoManager = NULL;
110 : }
111 :
112 : void invalidateXDo_nolck();
113 :
114 : private:
115 1 : static IUndoManager* impl_retrieveUndoManager( SfxBaseModel& i_baseModel )
116 : {
117 1 : IUndoManager* pUndoManager( NULL );
118 1 : SfxObjectShell* pObjectShell = i_baseModel.GetObjectShell();
119 1 : if ( pObjectShell != NULL )
120 1 : pUndoManager = pObjectShell->GetUndoManager();
121 1 : if ( !pUndoManager )
122 0 : throw NotInitializedException( ::rtl::OUString(), *&i_baseModel );
123 1 : return pUndoManager;
124 : }
125 : };
126 :
127 : //------------------------------------------------------------------------------------------------------------------
128 2 : ::svl::IUndoManager& DocumentUndoManager_Impl::getImplUndoManager()
129 : {
130 2 : 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 2 : return *pUndoManager;
141 : }
142 :
143 : //------------------------------------------------------------------------------------------------------------------
144 1 : Reference< XUndoManager > DocumentUndoManager_Impl::getThis()
145 : {
146 1 : return static_cast< XUndoManager* >( &rAntiImpl );
147 : }
148 :
149 : //------------------------------------------------------------------------------------------------------------------
150 0 : void DocumentUndoManager_Impl::invalidateXDo_nolck()
151 : {
152 0 : SfxModelGuard aGuard( rAntiImpl );
153 :
154 0 : const SfxObjectShell* pDocShell = getObjectShell();
155 0 : ENSURE_OR_THROW( pDocShell != NULL, "lcl_invalidateUndo: no access to the doc shell!" );
156 0 : SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( pDocShell );
157 0 : while ( pViewFrame )
158 : {
159 0 : pViewFrame->GetBindings().Invalidate( SID_UNDO );
160 0 : pViewFrame->GetBindings().Invalidate( SID_REDO );
161 0 : pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDocShell );
162 0 : }
163 0 : }
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 2 : SolarMutexFacade()
174 2 : {
175 2 : }
176 :
177 2 : virtual ~SolarMutexFacade() {}
178 :
179 0 : virtual void acquire()
180 : {
181 0 : Application::GetSolarMutex().acquire();
182 0 : }
183 :
184 0 : virtual void release()
185 : {
186 0 : Application::GetSolarMutex().release();
187 0 : }
188 : };
189 :
190 : //==================================================================================================================
191 : //= UndoManagerGuard
192 : //==================================================================================================================
193 : class UndoManagerGuard :public ::framework::IMutexGuard
194 : ,public ::boost::noncopyable
195 : {
196 : public:
197 2 : UndoManagerGuard( DocumentUndoManager& i_undoManager )
198 : :m_guard( i_undoManager )
199 2 : ,m_solarMutexFacade()
200 : {
201 2 : }
202 :
203 2 : virtual ~UndoManagerGuard()
204 2 : {
205 2 : }
206 :
207 0 : virtual void reset()
208 : {
209 0 : m_guard.reset();
210 0 : }
211 :
212 0 : virtual void clear()
213 : {
214 0 : m_guard.clear();
215 0 : }
216 :
217 0 : 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 0 : return m_solarMutexFacade;
222 : }
223 :
224 : private:
225 : SfxModelGuard m_guard;
226 : SolarMutexFacade m_solarMutexFacade;
227 : };
228 :
229 : //==================================================================================================================
230 : //= DocumentUndoManager
231 : //==================================================================================================================
232 : //------------------------------------------------------------------------------------------------------------------
233 1 : DocumentUndoManager::DocumentUndoManager( SfxBaseModel& i_document )
234 : :SfxModelSubComponent( i_document )
235 1 : ,m_pImpl( new DocumentUndoManager_Impl( *this ) )
236 : {
237 1 : }
238 :
239 : //------------------------------------------------------------------------------------------------------------------
240 0 : DocumentUndoManager::~DocumentUndoManager()
241 : {
242 0 : }
243 :
244 : //------------------------------------------------------------------------------------------------------------------
245 1 : void DocumentUndoManager::disposing()
246 : {
247 1 : m_pImpl->disposing();
248 1 : }
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 6 : void SAL_CALL DocumentUndoManager::acquire( ) throw ()
259 : {
260 6 : SfxModelSubComponent::acquire();
261 6 : }
262 :
263 : //------------------------------------------------------------------------------------------------------------------
264 6 : void SAL_CALL DocumentUndoManager::release( ) throw ()
265 : {
266 6 : SfxModelSubComponent::release();
267 6 : }
268 :
269 : //------------------------------------------------------------------------------------------------------------------
270 0 : void SAL_CALL DocumentUndoManager::enterUndoContext( const ::rtl::OUString& i_title ) throw (RuntimeException)
271 : {
272 : // SYNCHRONIZED --->
273 0 : UndoManagerGuard aGuard( *this );
274 0 : m_pImpl->aUndoHelper.enterUndoContext( i_title, aGuard );
275 : // <--- SYNCHRONIZED
276 0 : m_pImpl->invalidateXDo_nolck();
277 0 : }
278 :
279 : //------------------------------------------------------------------------------------------------------------------
280 0 : void SAL_CALL DocumentUndoManager::enterHiddenUndoContext( ) throw (EmptyUndoStackException, RuntimeException)
281 : {
282 : // SYNCHRONIZED --->
283 0 : UndoManagerGuard aGuard( *this );
284 0 : m_pImpl->aUndoHelper.enterHiddenUndoContext( aGuard );
285 : // <--- SYNCHRONIZED
286 0 : m_pImpl->invalidateXDo_nolck();
287 0 : }
288 :
289 : //------------------------------------------------------------------------------------------------------------------
290 0 : void SAL_CALL DocumentUndoManager::leaveUndoContext( ) throw (InvalidStateException, RuntimeException)
291 : {
292 : // SYNCHRONIZED --->
293 0 : UndoManagerGuard aGuard( *this );
294 0 : m_pImpl->aUndoHelper.leaveUndoContext( aGuard );
295 : // <--- SYNCHRONIZED
296 0 : m_pImpl->invalidateXDo_nolck();
297 0 : }
298 :
299 : //------------------------------------------------------------------------------------------------------------------
300 0 : void SAL_CALL DocumentUndoManager::addUndoAction( const Reference< XUndoAction >& i_action ) throw (RuntimeException, IllegalArgumentException)
301 : {
302 : // SYNCHRONIZED --->
303 0 : UndoManagerGuard aGuard( *this );
304 0 : m_pImpl->aUndoHelper.addUndoAction( i_action, aGuard );
305 : // <--- SYNCHRONIZED
306 0 : m_pImpl->invalidateXDo_nolck();
307 0 : }
308 :
309 : //------------------------------------------------------------------------------------------------------------------
310 0 : void SAL_CALL DocumentUndoManager::undo( ) throw (EmptyUndoStackException, UndoContextNotClosedException, UndoFailedException, RuntimeException)
311 : {
312 : // SYNCHRONIZED --->
313 0 : UndoManagerGuard aGuard( *this );
314 0 : m_pImpl->aUndoHelper.undo( aGuard );
315 : // <--- SYNCHRONIZED
316 0 : m_pImpl->invalidateXDo_nolck();
317 0 : }
318 :
319 : //------------------------------------------------------------------------------------------------------------------
320 0 : void SAL_CALL DocumentUndoManager::redo( ) throw (EmptyUndoStackException, UndoContextNotClosedException, UndoFailedException, RuntimeException)
321 : {
322 : // SYNCHRONIZED --->
323 0 : UndoManagerGuard aGuard( *this );
324 0 : m_pImpl->aUndoHelper.redo( aGuard );
325 : // <--- SYNCHRONIZED
326 0 : m_pImpl->invalidateXDo_nolck();
327 0 : }
328 :
329 : //------------------------------------------------------------------------------------------------------------------
330 0 : ::sal_Bool SAL_CALL DocumentUndoManager::isUndoPossible( ) throw (RuntimeException)
331 : {
332 0 : UndoManagerGuard aGuard( *this );
333 0 : return m_pImpl->aUndoHelper.isUndoPossible();
334 : }
335 :
336 : //------------------------------------------------------------------------------------------------------------------
337 0 : ::sal_Bool SAL_CALL DocumentUndoManager::isRedoPossible( ) throw (RuntimeException)
338 : {
339 0 : UndoManagerGuard aGuard( *this );
340 0 : return m_pImpl->aUndoHelper.isRedoPossible();
341 : }
342 :
343 : //------------------------------------------------------------------------------------------------------------------
344 0 : ::rtl::OUString SAL_CALL DocumentUndoManager::getCurrentUndoActionTitle( ) throw (EmptyUndoStackException, RuntimeException)
345 : {
346 0 : UndoManagerGuard aGuard( *this );
347 0 : return m_pImpl->aUndoHelper.getCurrentUndoActionTitle();
348 : }
349 :
350 : //------------------------------------------------------------------------------------------------------------------
351 0 : ::rtl::OUString SAL_CALL DocumentUndoManager::getCurrentRedoActionTitle( ) throw (EmptyUndoStackException, RuntimeException)
352 : {
353 0 : UndoManagerGuard aGuard( *this );
354 0 : return m_pImpl->aUndoHelper.getCurrentRedoActionTitle();
355 : }
356 :
357 : //------------------------------------------------------------------------------------------------------------------
358 0 : Sequence< ::rtl::OUString > SAL_CALL DocumentUndoManager::getAllUndoActionTitles( ) throw (RuntimeException)
359 : {
360 0 : UndoManagerGuard aGuard( *this );
361 0 : return m_pImpl->aUndoHelper.getAllUndoActionTitles();
362 : }
363 :
364 : //------------------------------------------------------------------------------------------------------------------
365 0 : Sequence< ::rtl::OUString > SAL_CALL DocumentUndoManager::getAllRedoActionTitles( ) throw (RuntimeException)
366 : {
367 0 : UndoManagerGuard aGuard( *this );
368 0 : return m_pImpl->aUndoHelper.getAllRedoActionTitles();
369 : }
370 :
371 : //------------------------------------------------------------------------------------------------------------------
372 0 : void SAL_CALL DocumentUndoManager::clear( ) throw (UndoContextNotClosedException, RuntimeException)
373 : {
374 : // SYNCHRONIZED --->
375 0 : UndoManagerGuard aGuard( *this );
376 0 : m_pImpl->aUndoHelper.clear( aGuard );
377 : // <--- SYNCHRONIZED
378 0 : m_pImpl->invalidateXDo_nolck();
379 0 : }
380 :
381 : //------------------------------------------------------------------------------------------------------------------
382 0 : void SAL_CALL DocumentUndoManager::clearRedo( ) throw (UndoContextNotClosedException, RuntimeException)
383 : {
384 : // SYNCHRONIZED --->
385 0 : UndoManagerGuard aGuard( *this );
386 0 : m_pImpl->aUndoHelper.clearRedo( aGuard );
387 : // <--- SYNCHRONIZED
388 0 : m_pImpl->invalidateXDo_nolck();
389 0 : }
390 :
391 : //------------------------------------------------------------------------------------------------------------------
392 0 : void SAL_CALL DocumentUndoManager::reset() throw (RuntimeException)
393 : {
394 : // SYNCHRONIZED --->
395 0 : UndoManagerGuard aGuard( *this );
396 0 : m_pImpl->aUndoHelper.reset( aGuard );
397 : // <--- SYNCHRONIZED
398 0 : m_pImpl->invalidateXDo_nolck();
399 0 : }
400 :
401 : //------------------------------------------------------------------------------------------------------------------
402 0 : void SAL_CALL DocumentUndoManager::lock( ) throw (RuntimeException)
403 : {
404 0 : UndoManagerGuard aGuard( *this );
405 0 : m_pImpl->aUndoHelper.lock();
406 0 : }
407 :
408 : //------------------------------------------------------------------------------------------------------------------
409 0 : void SAL_CALL DocumentUndoManager::unlock( ) throw (RuntimeException, NotLockedException)
410 : {
411 0 : UndoManagerGuard aGuard( *this );
412 0 : m_pImpl->aUndoHelper.unlock();
413 0 : }
414 :
415 : //------------------------------------------------------------------------------------------------------------------
416 0 : ::sal_Bool SAL_CALL DocumentUndoManager::isLocked( ) throw (RuntimeException)
417 : {
418 0 : UndoManagerGuard aGuard( *this );
419 0 : return m_pImpl->aUndoHelper.isLocked();
420 : }
421 :
422 : //------------------------------------------------------------------------------------------------------------------
423 1 : void SAL_CALL DocumentUndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) throw (RuntimeException)
424 : {
425 1 : UndoManagerGuard aGuard( *this );
426 1 : return m_pImpl->aUndoHelper.addUndoManagerListener( i_listener );
427 : }
428 :
429 : //------------------------------------------------------------------------------------------------------------------
430 1 : void SAL_CALL DocumentUndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) throw (RuntimeException)
431 : {
432 1 : UndoManagerGuard aGuard( *this );
433 1 : return m_pImpl->aUndoHelper.removeUndoManagerListener( i_listener );
434 : }
435 :
436 : //------------------------------------------------------------------------------------------------------------------
437 0 : Reference< XInterface > SAL_CALL DocumentUndoManager::getParent( ) throw (RuntimeException)
438 : {
439 0 : UndoManagerGuard aGuard( *this );
440 0 : 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 66 : } // namespace sfx2
452 : //......................................................................................................................
453 :
454 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|