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