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