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 371 : DocumentUndoManager_Impl( DocumentUndoManager& i_antiImpl )
83 : :rAntiImpl( i_antiImpl )
84 371 : ,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 742 : ,aUndoHelper( *this )
88 : {
89 371 : }
90 :
91 68 : virtual ~DocumentUndoManager_Impl()
92 34 : {
93 68 : };
94 :
95 576 : 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 371 : void disposing()
102 : {
103 371 : aUndoHelper.disposing();
104 742 : ENSURE_OR_RETURN_VOID( pUndoManager, "DocumentUndoManager_Impl::disposing: already disposed!" );
105 371 : pUndoManager = NULL;
106 : }
107 :
108 : void invalidateXDo_nolck();
109 :
110 : private:
111 371 : static IUndoManager* impl_retrieveUndoManager( SfxBaseModel& i_baseModel )
112 : {
113 371 : IUndoManager* pUndoManager( NULL );
114 371 : SfxObjectShell* pObjectShell = i_baseModel.GetObjectShell();
115 371 : if ( pObjectShell != NULL )
116 371 : pUndoManager = pObjectShell->GetUndoManager();
117 371 : if ( !pUndoManager )
118 0 : throw NotInitializedException( OUString(), *&i_baseModel );
119 371 : return pUndoManager;
120 : }
121 : };
122 :
123 :
124 27634 : ::svl::IUndoManager& DocumentUndoManager_Impl::getImplUndoManager()
125 : {
126 27634 : 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 27634 : return *pUndoManager;
137 : }
138 :
139 :
140 64864 : Reference< XUndoManager > DocumentUndoManager_Impl::getThis()
141 : {
142 64864 : return static_cast< XUndoManager* >( &rAntiImpl );
143 : }
144 :
145 :
146 576 : void DocumentUndoManager_Impl::invalidateXDo_nolck()
147 : {
148 576 : SfxModelGuard aGuard( rAntiImpl );
149 :
150 576 : const SfxObjectShell* pDocShell = getObjectShell();
151 576 : ENSURE_OR_THROW( pDocShell != NULL, "lcl_invalidateUndo: no access to the doc shell!" );
152 576 : SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( pDocShell );
153 1731 : while ( pViewFrame )
154 : {
155 579 : pViewFrame->GetBindings().Invalidate( SID_UNDO );
156 579 : pViewFrame->GetBindings().Invalidate( SID_REDO );
157 579 : pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDocShell );
158 576 : }
159 576 : }
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 1011 : SolarMutexFacade()
170 1011 : {
171 1011 : }
172 :
173 1011 : virtual ~SolarMutexFacade() {}
174 :
175 178 : virtual void acquire() SAL_OVERRIDE
176 : {
177 178 : Application::GetSolarMutex().acquire();
178 178 : }
179 :
180 178 : virtual void release() SAL_OVERRIDE
181 : {
182 178 : Application::GetSolarMutex().release();
183 178 : }
184 : };
185 :
186 :
187 : //= UndoManagerGuard
188 :
189 : class UndoManagerGuard :public ::framework::IMutexGuard
190 : ,public ::boost::noncopyable
191 : {
192 : public:
193 1011 : UndoManagerGuard( DocumentUndoManager& i_undoManager )
194 : :m_guard( i_undoManager )
195 1011 : ,m_solarMutexFacade()
196 : {
197 1011 : }
198 :
199 1011 : virtual ~UndoManagerGuard()
200 1011 : {
201 1011 : }
202 :
203 609 : virtual void clear() SAL_OVERRIDE
204 : {
205 609 : m_guard.clear();
206 609 : }
207 :
208 178 : 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 178 : return m_solarMutexFacade;
213 : }
214 :
215 : private:
216 : SfxModelGuard m_guard;
217 : SolarMutexFacade m_solarMutexFacade;
218 : };
219 :
220 :
221 : //= DocumentUndoManager
222 :
223 :
224 371 : DocumentUndoManager::DocumentUndoManager( SfxBaseModel& i_document )
225 : :SfxModelSubComponent( i_document )
226 371 : ,m_pImpl( new DocumentUndoManager_Impl( *this ) )
227 : {
228 371 : }
229 :
230 68 : DocumentUndoManager::~DocumentUndoManager()
231 : {
232 68 : }
233 :
234 371 : void DocumentUndoManager::disposing()
235 : {
236 371 : m_pImpl->disposing();
237 371 : }
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 131539 : void SAL_CALL DocumentUndoManager::acquire() throw()
248 : {
249 131539 : OWeakObject::acquire();
250 131539 : SfxModelSubComponent::acquireModel();
251 131539 : }
252 :
253 :
254 131202 : void SAL_CALL DocumentUndoManager::release() throw()
255 : {
256 131202 : SfxModelSubComponent::releaseModel();
257 131202 : OWeakObject::release();
258 131202 : }
259 :
260 :
261 43 : void SAL_CALL DocumentUndoManager::enterUndoContext( const OUString& i_title ) throw (RuntimeException, std::exception)
262 : {
263 : // SYNCHRONIZED --->
264 43 : UndoManagerGuard aGuard( *this );
265 43 : m_pImpl->aUndoHelper.enterUndoContext( i_title, aGuard );
266 : // <--- SYNCHRONIZED
267 43 : m_pImpl->invalidateXDo_nolck();
268 43 : }
269 :
270 :
271 24 : void SAL_CALL DocumentUndoManager::enterHiddenUndoContext( ) throw (EmptyUndoStackException, RuntimeException, std::exception)
272 : {
273 : // SYNCHRONIZED --->
274 24 : UndoManagerGuard aGuard( *this );
275 24 : m_pImpl->aUndoHelper.enterHiddenUndoContext( aGuard );
276 : // <--- SYNCHRONIZED
277 24 : m_pImpl->invalidateXDo_nolck();
278 18 : }
279 :
280 :
281 54 : void SAL_CALL DocumentUndoManager::leaveUndoContext( ) throw (InvalidStateException, RuntimeException, std::exception)
282 : {
283 : // SYNCHRONIZED --->
284 54 : UndoManagerGuard aGuard( *this );
285 54 : m_pImpl->aUndoHelper.leaveUndoContext( aGuard );
286 : // <--- SYNCHRONIZED
287 54 : m_pImpl->invalidateXDo_nolck();
288 51 : }
289 :
290 :
291 241 : void SAL_CALL DocumentUndoManager::addUndoAction( const Reference< XUndoAction >& i_action ) throw (RuntimeException, IllegalArgumentException, std::exception)
292 : {
293 : // SYNCHRONIZED --->
294 241 : UndoManagerGuard aGuard( *this );
295 241 : m_pImpl->aUndoHelper.addUndoAction( i_action, aGuard );
296 : // <--- SYNCHRONIZED
297 241 : m_pImpl->invalidateXDo_nolck();
298 238 : }
299 :
300 :
301 166 : void SAL_CALL DocumentUndoManager::undo( ) throw (EmptyUndoStackException, UndoContextNotClosedException, UndoFailedException, RuntimeException, std::exception)
302 : {
303 : // SYNCHRONIZED --->
304 166 : UndoManagerGuard aGuard( *this );
305 166 : m_pImpl->aUndoHelper.undo( aGuard );
306 : // <--- SYNCHRONIZED
307 166 : m_pImpl->invalidateXDo_nolck();
308 157 : }
309 :
310 :
311 12 : void SAL_CALL DocumentUndoManager::redo( ) throw (EmptyUndoStackException, UndoContextNotClosedException, UndoFailedException, RuntimeException, std::exception)
312 : {
313 : // SYNCHRONIZED --->
314 12 : UndoManagerGuard aGuard( *this );
315 12 : m_pImpl->aUndoHelper.redo( aGuard );
316 : // <--- SYNCHRONIZED
317 12 : m_pImpl->invalidateXDo_nolck();
318 3 : }
319 :
320 :
321 72 : sal_Bool SAL_CALL DocumentUndoManager::isUndoPossible( ) throw (RuntimeException, std::exception)
322 : {
323 72 : UndoManagerGuard aGuard( *this );
324 72 : return m_pImpl->aUndoHelper.isUndoPossible();
325 : }
326 :
327 :
328 66 : sal_Bool SAL_CALL DocumentUndoManager::isRedoPossible( ) throw (RuntimeException, std::exception)
329 : {
330 66 : UndoManagerGuard aGuard( *this );
331 66 : return m_pImpl->aUndoHelper.isRedoPossible();
332 : }
333 :
334 :
335 6 : OUString SAL_CALL DocumentUndoManager::getCurrentUndoActionTitle( ) throw (EmptyUndoStackException, RuntimeException, std::exception)
336 : {
337 6 : UndoManagerGuard aGuard( *this );
338 6 : return m_pImpl->aUndoHelper.getCurrentUndoActionTitle();
339 : }
340 :
341 :
342 3 : OUString SAL_CALL DocumentUndoManager::getCurrentRedoActionTitle( ) throw (EmptyUndoStackException, RuntimeException, std::exception)
343 : {
344 3 : UndoManagerGuard aGuard( *this );
345 3 : return m_pImpl->aUndoHelper.getCurrentRedoActionTitle();
346 : }
347 :
348 :
349 21 : Sequence< OUString > SAL_CALL DocumentUndoManager::getAllUndoActionTitles( ) throw (RuntimeException, std::exception)
350 : {
351 21 : UndoManagerGuard aGuard( *this );
352 21 : return m_pImpl->aUndoHelper.getAllUndoActionTitles();
353 : }
354 :
355 :
356 27 : Sequence< OUString > SAL_CALL DocumentUndoManager::getAllRedoActionTitles( ) throw (RuntimeException, std::exception)
357 : {
358 27 : UndoManagerGuard aGuard( *this );
359 27 : return m_pImpl->aUndoHelper.getAllRedoActionTitles();
360 : }
361 :
362 :
363 18 : void SAL_CALL DocumentUndoManager::clear( ) throw (UndoContextNotClosedException, RuntimeException, std::exception)
364 : {
365 : // SYNCHRONIZED --->
366 18 : UndoManagerGuard aGuard( *this );
367 18 : m_pImpl->aUndoHelper.clear( aGuard );
368 : // <--- SYNCHRONIZED
369 18 : m_pImpl->invalidateXDo_nolck();
370 15 : }
371 :
372 :
373 6 : void SAL_CALL DocumentUndoManager::clearRedo( ) throw (UndoContextNotClosedException, RuntimeException, std::exception)
374 : {
375 : // SYNCHRONIZED --->
376 6 : UndoManagerGuard aGuard( *this );
377 6 : m_pImpl->aUndoHelper.clearRedo( aGuard );
378 : // <--- SYNCHRONIZED
379 6 : m_pImpl->invalidateXDo_nolck();
380 3 : }
381 :
382 :
383 48 : void SAL_CALL DocumentUndoManager::reset() throw (RuntimeException, std::exception)
384 : {
385 : // SYNCHRONIZED --->
386 48 : UndoManagerGuard aGuard( *this );
387 48 : m_pImpl->aUndoHelper.reset( aGuard );
388 : // <--- SYNCHRONIZED
389 48 : m_pImpl->invalidateXDo_nolck();
390 48 : }
391 :
392 :
393 9 : void SAL_CALL DocumentUndoManager::lock( ) throw (RuntimeException, std::exception)
394 : {
395 9 : UndoManagerGuard aGuard( *this );
396 9 : m_pImpl->aUndoHelper.lock();
397 9 : }
398 :
399 :
400 12 : void SAL_CALL DocumentUndoManager::unlock( ) throw (RuntimeException, NotLockedException, std::exception)
401 : {
402 12 : UndoManagerGuard aGuard( *this );
403 15 : m_pImpl->aUndoHelper.unlock();
404 9 : }
405 :
406 :
407 15 : sal_Bool SAL_CALL DocumentUndoManager::isLocked( ) throw (RuntimeException, std::exception)
408 : {
409 15 : UndoManagerGuard aGuard( *this );
410 15 : return m_pImpl->aUndoHelper.isLocked();
411 : }
412 :
413 :
414 84 : void SAL_CALL DocumentUndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) throw (RuntimeException, std::exception)
415 : {
416 84 : UndoManagerGuard aGuard( *this );
417 84 : return m_pImpl->aUndoHelper.addUndoManagerListener( i_listener );
418 : }
419 :
420 :
421 79 : void SAL_CALL DocumentUndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) throw (RuntimeException, std::exception)
422 : {
423 79 : UndoManagerGuard aGuard( *this );
424 79 : return m_pImpl->aUndoHelper.removeUndoManagerListener( i_listener );
425 : }
426 :
427 :
428 5 : Reference< XInterface > SAL_CALL DocumentUndoManager::getParent( ) throw (RuntimeException, std::exception)
429 : {
430 5 : UndoManagerGuard aGuard( *this );
431 5 : 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 648 : } // namespace sfx2
443 :
444 :
445 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|