Branch data Line data Source code
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.
4 : : *
5 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
6 : : *
7 : : * OpenOffice.org - a multi-platform office productivity suite
8 : : *
9 : : * This file is part of OpenOffice.org.
10 : : *
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.
14 : : *
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).
20 : : *
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.
25 : : *
26 : : ************************************************************************/
27 : :
28 : :
29 : : #include "framework/undomanagerhelper.hxx"
30 : :
31 : : #include <com/sun/star/lang/XComponent.hpp>
32 : :
33 : : #include <cppuhelper/interfacecontainer.hxx>
34 : : #include <cppuhelper/exc_hlp.hxx>
35 : : #include <comphelper/flagguard.hxx>
36 : : #include <comphelper/asyncnotification.hxx>
37 : : #include <svl/undo.hxx>
38 : : #include <tools/diagnose_ex.h>
39 : : #include <osl/conditn.hxx>
40 : :
41 : : #include <stack>
42 : : #include <queue>
43 : : #include <boost/function.hpp>
44 : :
45 : : //......................................................................................................................
46 : : namespace framework
47 : : {
48 : : //......................................................................................................................
49 : :
50 : : /** === begin UNO using === **/
51 : : using ::com::sun::star::uno::Reference;
52 : : using ::com::sun::star::uno::XInterface;
53 : : using ::com::sun::star::uno::UNO_QUERY;
54 : : using ::com::sun::star::uno::UNO_QUERY_THROW;
55 : : using ::com::sun::star::uno::UNO_SET_THROW;
56 : : using ::com::sun::star::uno::Exception;
57 : : using ::com::sun::star::uno::RuntimeException;
58 : : using ::com::sun::star::uno::Any;
59 : : using ::com::sun::star::uno::makeAny;
60 : : using ::com::sun::star::uno::Sequence;
61 : : using ::com::sun::star::uno::Type;
62 : : using ::com::sun::star::document::XUndoManagerListener;
63 : : using ::com::sun::star::document::UndoManagerEvent;
64 : : using ::com::sun::star::document::EmptyUndoStackException;
65 : : using ::com::sun::star::document::UndoContextNotClosedException;
66 : : using ::com::sun::star::document::UndoFailedException;
67 : : using ::com::sun::star::util::NotLockedException;
68 : : using ::com::sun::star::lang::EventObject;
69 : : using ::com::sun::star::document::XUndoAction;
70 : : using ::com::sun::star::lang::XComponent;
71 : : using ::com::sun::star::document::XUndoManager;
72 : : using ::com::sun::star::util::InvalidStateException;
73 : : using ::com::sun::star::lang::IllegalArgumentException;
74 : : using ::com::sun::star::util::XModifyListener;
75 : : /** === end UNO using === **/
76 : : using ::svl::IUndoManager;
77 : :
78 : : //==================================================================================================================
79 : : //= UndoActionWrapper
80 : : //==================================================================================================================
81 : : class UndoActionWrapper : public SfxUndoAction
82 : : {
83 : : public:
84 : : UndoActionWrapper(
85 : : Reference< XUndoAction > const& i_undoAction
86 : : );
87 : : virtual ~UndoActionWrapper();
88 : :
89 : : virtual rtl::OUString GetComment() const;
90 : : virtual void Undo();
91 : : virtual void Redo();
92 : : virtual sal_Bool CanRepeat(SfxRepeatTarget&) const;
93 : :
94 : : private:
95 : : const Reference< XUndoAction > m_xUndoAction;
96 : : };
97 : :
98 : : //------------------------------------------------------------------------------------------------------------------
99 : 554 : UndoActionWrapper::UndoActionWrapper( Reference< XUndoAction > const& i_undoAction )
100 : : :SfxUndoAction()
101 : 554 : ,m_xUndoAction( i_undoAction )
102 : : {
103 [ # # ][ # # ]: 554 : ENSURE_OR_THROW( m_xUndoAction.is(), "illegal undo action" );
[ # # ][ - + ]
104 : 554 : }
105 : :
106 : : //------------------------------------------------------------------------------------------------------------------
107 : 546 : UndoActionWrapper::~UndoActionWrapper()
108 : : {
109 : : try
110 : : {
111 [ + - ]: 546 : Reference< XComponent > xComponent( m_xUndoAction, UNO_QUERY );
112 [ + + ]: 546 : if ( xComponent.is() )
113 [ + - ][ + - ]: 546 : xComponent->dispose();
[ # # ]
114 : : }
115 [ # # ]: 0 : catch( const Exception& )
116 : : {
117 : : DBG_UNHANDLED_EXCEPTION();
118 : : }
119 [ - + ]: 1092 : }
120 : :
121 : : //------------------------------------------------------------------------------------------------------------------
122 : 1173 : rtl::OUString UndoActionWrapper::GetComment() const
123 : : {
124 : 1173 : rtl::OUString sComment;
125 : : try
126 : : {
127 [ + - ][ + - ]: 1173 : sComment = m_xUndoAction->getTitle();
128 : : }
129 [ # # ]: 0 : catch( const Exception& )
130 : : {
131 : : DBG_UNHANDLED_EXCEPTION();
132 : : }
133 [ # # ]: 1173 : return sComment;
134 : : }
135 : :
136 : : //------------------------------------------------------------------------------------------------------------------
137 : 432 : void UndoActionWrapper::Undo()
138 : : {
139 : 432 : m_xUndoAction->undo();
140 : 416 : }
141 : :
142 : : //------------------------------------------------------------------------------------------------------------------
143 : 22 : void UndoActionWrapper::Redo()
144 : : {
145 : 22 : m_xUndoAction->redo();
146 : 6 : }
147 : :
148 : : //------------------------------------------------------------------------------------------------------------------
149 : 0 : sal_Bool UndoActionWrapper::CanRepeat(SfxRepeatTarget&) const
150 : : {
151 : 0 : return sal_False;
152 : : }
153 : :
154 : : //==================================================================================================================
155 : : //= UndoManagerRequest
156 : : //==================================================================================================================
157 : : class UndoManagerRequest : public ::comphelper::AnyEvent
158 : : {
159 : : public:
160 : 1494 : UndoManagerRequest( ::boost::function0< void > const& i_request )
161 : : :m_request( i_request )
162 : : ,m_caughtException()
163 [ + - ][ + - ]: 1494 : ,m_finishCondition()
164 : : {
165 [ + - ]: 1494 : m_finishCondition.reset();
166 : 1494 : }
167 : :
168 : 1494 : void execute()
169 : : {
170 : : try
171 : : {
172 [ + + ]: 1494 : m_request();
173 : : }
174 [ - + ]: 184 : catch( const Exception& )
175 : : {
176 [ - + ]: 92 : m_caughtException = ::cppu::getCaughtException();
177 : : }
178 : 1494 : m_finishCondition.set();
179 : 1494 : }
180 : :
181 : 1552 : void wait()
182 : : {
183 : 1552 : m_finishCondition.wait();
184 [ + + ]: 1552 : if ( m_caughtException.hasValue() )
185 : 92 : ::cppu::throwException( m_caughtException );
186 : 1460 : }
187 : :
188 : 0 : void cancel( const Reference< XInterface >& i_context )
189 : : {
190 : : m_caughtException <<= RuntimeException(
191 : : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Concurrency error: an ealier operation on the stack failed." ) ),
192 : : i_context
193 [ # # ][ # # ]: 0 : );
[ # # ]
194 : 0 : m_finishCondition.set();
195 : 0 : }
196 : :
197 : : protected:
198 : 2988 : ~UndoManagerRequest()
199 [ + - ][ + - ]: 1494 : {
200 [ - + ]: 2988 : }
201 : :
202 : : private:
203 : : ::boost::function0< void > m_request;
204 : : Any m_caughtException;
205 : : ::osl::Condition m_finishCondition;
206 : : };
207 : :
208 : : //------------------------------------------------------------------------------------------------------------------
209 : :
210 : : //==================================================================================================================
211 : : //= UndoManagerHelper_Impl
212 : : //==================================================================================================================
213 : : class UndoManagerHelper_Impl : public SfxUndoListener
214 : : {
215 : : private:
216 : : ::osl::Mutex m_aMutex;
217 : : ::osl::Mutex m_aQueueMutex;
218 : : bool m_disposed;
219 : : bool m_bAPIActionRunning;
220 : : bool m_bProcessingEvents;
221 : : sal_Int32 m_nLockCount;
222 : : ::cppu::OInterfaceContainerHelper m_aUndoListeners;
223 : : ::cppu::OInterfaceContainerHelper m_aModifyListeners;
224 : : IUndoManagerImplementation& m_rUndoManagerImplementation;
225 : : ::std::stack< bool > m_aContextVisibilities;
226 : : #if OSL_DEBUG_LEVEL > 0
227 : : ::std::stack< bool > m_aContextAPIFlags;
228 : : #endif
229 : : ::std::queue< ::rtl::Reference< UndoManagerRequest > >
230 : : m_aEventQueue;
231 : :
232 : : public:
233 : 1930 : ::osl::Mutex& getMutex() { return m_aMutex; }
234 : :
235 : : public:
236 : 55 : UndoManagerHelper_Impl( IUndoManagerImplementation& i_undoManagerImpl )
237 : : :m_aMutex()
238 : : ,m_aQueueMutex()
239 : : ,m_disposed( false )
240 : : ,m_bAPIActionRunning( false )
241 : : ,m_bProcessingEvents( false )
242 : : ,m_nLockCount( 0 )
243 : : ,m_aUndoListeners( m_aMutex )
244 : : ,m_aModifyListeners( m_aMutex )
245 [ + - ][ + - ]: 55 : ,m_rUndoManagerImplementation( i_undoManagerImpl )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
246 : : {
247 [ + - ][ + - ]: 55 : getUndoManager().AddUndoListener( *this );
248 : 55 : }
249 : :
250 : 0 : virtual ~UndoManagerHelper_Impl()
251 [ # # ][ # # ]: 0 : {
[ # # ][ # # ]
252 [ # # ]: 0 : }
253 : :
254 : : //..............................................................................................................
255 : 4393 : IUndoManager& getUndoManager() const
256 : : {
257 : 4393 : return m_rUndoManagerImplementation.getImplUndoManager();
258 : : }
259 : :
260 : : //..............................................................................................................
261 : 3661 : Reference< XUndoManager > getXUndoManager() const
262 : : {
263 : 3661 : return m_rUndoManagerImplementation.getThis();
264 : : }
265 : :
266 : : // SfxUndoListener
267 : : virtual void actionUndone( const String& i_actionComment );
268 : : virtual void actionRedone( const String& i_actionComment );
269 : : virtual void undoActionAdded( const String& i_actionComment );
270 : : virtual void cleared();
271 : : virtual void clearedRedo();
272 : : virtual void resetAll();
273 : : virtual void listActionEntered( const String& i_comment );
274 : : virtual void listActionLeft( const String& i_comment );
275 : : virtual void listActionLeftAndMerged();
276 : : virtual void listActionCancelled();
277 : : virtual void undoManagerDying();
278 : :
279 : : // public operations
280 : : void disposing();
281 : :
282 : : void enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden, IMutexGuard& i_instanceLock );
283 : : void leaveUndoContext( IMutexGuard& i_instanceLock );
284 : : void addUndoAction( const Reference< XUndoAction >& i_action, IMutexGuard& i_instanceLock );
285 : : void undo( IMutexGuard& i_instanceLock );
286 : : void redo( IMutexGuard& i_instanceLock );
287 : : void clear( IMutexGuard& i_instanceLock );
288 : : void clearRedo( IMutexGuard& i_instanceLock );
289 : : void reset( IMutexGuard& i_instanceLock );
290 : :
291 : : void lock();
292 : : void unlock();
293 : :
294 : 29 : void addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
295 : : {
296 : 29 : m_aUndoListeners.addInterface( i_listener );
297 : 29 : }
298 : :
299 : 17 : void removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
300 : : {
301 : 17 : m_aUndoListeners.removeInterface( i_listener );
302 : 17 : }
303 : :
304 : 34 : void addModifyListener( const Reference< XModifyListener >& i_listener )
305 : : {
306 : 34 : m_aModifyListeners.addInterface( i_listener );
307 : 34 : }
308 : :
309 : 34 : void removeModifyListener( const Reference< XModifyListener >& i_listener )
310 : : {
311 : 34 : m_aModifyListeners.removeInterface( i_listener );
312 : 34 : }
313 : :
314 : : UndoManagerEvent
315 : : buildEvent( ::rtl::OUString const& i_title ) const;
316 : :
317 : : void impl_notifyModified();
318 : : void notify( ::rtl::OUString const& i_title,
319 : : void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& )
320 : : );
321 : 0 : void notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) )
322 : : {
323 [ # # ]: 0 : notify( ::rtl::OUString(), i_notificationMethod );
324 : 0 : }
325 : :
326 : : void notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ) );
327 : :
328 : : private:
329 : : /// adds a function to be called to the request processor's queue
330 : : void impl_processRequest( ::boost::function0< void > const& i_request, IMutexGuard& i_instanceLock );
331 : :
332 : : /// impl-versions of the XUndoManager API.
333 : : void impl_enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden );
334 : : void impl_leaveUndoContext();
335 : : void impl_addUndoAction( const Reference< XUndoAction >& i_action );
336 : : void impl_doUndoRedo( IMutexGuard& i_externalLock, const bool i_undo );
337 : : void impl_clear();
338 : : void impl_clearRedo();
339 : : void impl_reset();
340 : : };
341 : :
342 : : //------------------------------------------------------------------------------------------------------------------
343 : 55 : void UndoManagerHelper_Impl::disposing()
344 : : {
345 [ + - ]: 55 : EventObject aEvent;
346 [ + - ][ + - ]: 55 : aEvent.Source = getXUndoManager();
347 [ + - ]: 55 : m_aUndoListeners.disposeAndClear( aEvent );
348 [ + - ]: 55 : m_aModifyListeners.disposeAndClear( aEvent );
349 : :
350 [ + - ]: 55 : ::osl::MutexGuard aGuard( m_aMutex );
351 : :
352 [ + - ][ + - ]: 55 : getUndoManager().RemoveUndoListener( *this );
353 : :
354 [ + - ][ + - ]: 55 : m_disposed = true;
355 : 55 : }
356 : :
357 : : //------------------------------------------------------------------------------------------------------------------
358 : 867 : UndoManagerEvent UndoManagerHelper_Impl::buildEvent( ::rtl::OUString const& i_title ) const
359 : : {
360 : 867 : UndoManagerEvent aEvent;
361 [ + - ][ + - ]: 867 : aEvent.Source = getXUndoManager();
362 : 867 : aEvent.UndoActionTitle = i_title;
363 [ + - ][ + - ]: 867 : aEvent.UndoContextDepth = getUndoManager().GetListActionDepth();
364 : 867 : return aEvent;
365 : : }
366 : :
367 : : //------------------------------------------------------------------------------------------------------------------
368 : 1423 : void UndoManagerHelper_Impl::impl_notifyModified()
369 : : {
370 [ + - ][ + - ]: 1423 : const EventObject aEvent( getXUndoManager() );
371 [ + - ][ + - ]: 1423 : m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
372 : 1423 : }
373 : :
374 : : //------------------------------------------------------------------------------------------------------------------
375 : 51 : void UndoManagerHelper_Impl::notify( ::rtl::OUString const& i_title,
376 : : void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) )
377 : : {
378 [ + - ]: 51 : const UndoManagerEvent aEvent( buildEvent( i_title ) );
379 : :
380 : : // TODO: this notification method here is used by UndoManagerHelper_Impl, to multiplex the notifications we
381 : : // receive from the IUndoManager. Those notitications are sent with a locked SolarMutex, which means
382 : : // we're doing the multiplexing here with a locked SM, too. Which is Bad (TM).
383 : : // Fixing this properly would require outsourcing all the notifications into an own thread - which might lead
384 : : // to problems of its own, since clients might expect synchronous notifications.
385 : :
386 [ + - ]: 51 : m_aUndoListeners.notifyEach( i_notificationMethod, aEvent );
387 [ + - ][ + - ]: 51 : impl_notifyModified();
388 : 51 : }
389 : :
390 : : //------------------------------------------------------------------------------------------------------------------
391 : 4 : void UndoManagerHelper_Impl::notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ) )
392 : : {
393 [ + - ][ + - ]: 4 : const EventObject aEvent( getXUndoManager() );
394 : :
395 : : // TODO: the same comment as in the other notify, regarding SM locking applies here ...
396 : :
397 [ + - ]: 4 : m_aUndoListeners.notifyEach( i_notificationMethod, aEvent );
398 [ + - ][ + - ]: 4 : impl_notifyModified();
399 : 4 : }
400 : :
401 : : //------------------------------------------------------------------------------------------------------------------
402 : 176 : void UndoManagerHelper_Impl::enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden, IMutexGuard& i_instanceLock )
403 : : {
404 : : impl_processRequest(
405 : : ::boost::bind(
406 : : &UndoManagerHelper_Impl::impl_enterUndoContext,
407 : : this,
408 : : ::boost::cref( i_title ),
409 : : i_hidden
410 : : ),
411 : : i_instanceLock
412 [ + + ]: 176 : );
413 : 160 : }
414 : :
415 : : //------------------------------------------------------------------------------------------------------------------
416 : 142 : void UndoManagerHelper_Impl::leaveUndoContext( IMutexGuard& i_instanceLock )
417 : : {
418 : : impl_processRequest(
419 : : ::boost::bind(
420 : : &UndoManagerHelper_Impl::impl_leaveUndoContext,
421 : : this
422 : : ),
423 : : i_instanceLock
424 [ + + ]: 142 : );
425 : 134 : }
426 : :
427 : : //------------------------------------------------------------------------------------------------------------------
428 : 576 : void UndoManagerHelper_Impl::addUndoAction( const Reference< XUndoAction >& i_action, IMutexGuard& i_instanceLock )
429 : : {
430 [ + + ]: 576 : if ( !i_action.is() )
431 : : throw IllegalArgumentException(
432 : : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "illegal undo action object" ) ),
433 : : getXUndoManager(),
434 : : 1
435 [ + - ][ + - ]: 8 : );
[ + - ]
436 : :
437 : : impl_processRequest(
438 : : ::boost::bind(
439 : : &UndoManagerHelper_Impl::impl_addUndoAction,
440 : : this,
441 : : ::boost::ref( i_action )
442 : : ),
443 : : i_instanceLock
444 [ + - ]: 568 : );
445 : 568 : }
446 : :
447 : : //------------------------------------------------------------------------------------------------------------------
448 : 48 : void UndoManagerHelper_Impl::clear( IMutexGuard& i_instanceLock )
449 : : {
450 : : impl_processRequest(
451 : : ::boost::bind(
452 : : &UndoManagerHelper_Impl::impl_clear,
453 : : this
454 : : ),
455 : : i_instanceLock
456 [ + + ]: 48 : );
457 : 40 : }
458 : :
459 : : //------------------------------------------------------------------------------------------------------------------
460 : 16 : void UndoManagerHelper_Impl::clearRedo( IMutexGuard& i_instanceLock )
461 : : {
462 : : impl_processRequest(
463 : : ::boost::bind(
464 : : &UndoManagerHelper_Impl::impl_clearRedo,
465 : : this
466 : : ),
467 : : i_instanceLock
468 [ + + ]: 16 : );
469 : 8 : }
470 : :
471 : : //------------------------------------------------------------------------------------------------------------------
472 : 128 : void UndoManagerHelper_Impl::reset( IMutexGuard& i_instanceLock )
473 : : {
474 : : impl_processRequest(
475 : : ::boost::bind(
476 : : &UndoManagerHelper_Impl::impl_reset,
477 : : this
478 : : ),
479 : : i_instanceLock
480 [ + - ]: 128 : );
481 : 128 : }
482 : :
483 : : //------------------------------------------------------------------------------------------------------------------
484 : 24 : void UndoManagerHelper_Impl::lock()
485 : : {
486 : : // SYNCHRONIZED --->
487 [ + - ]: 24 : ::osl::MutexGuard aGuard( getMutex() );
488 : :
489 [ + - ]: 24 : if ( ++m_nLockCount == 1 )
490 : : {
491 [ + - ]: 24 : IUndoManager& rUndoManager = getUndoManager();
492 [ + - ]: 24 : rUndoManager.EnableUndo( false );
493 [ + - ]: 24 : }
494 : : // <--- SYNCHRONIZED
495 : 24 : }
496 : :
497 : : //------------------------------------------------------------------------------------------------------------------
498 : 32 : void UndoManagerHelper_Impl::unlock()
499 : : {
500 : : // SYNCHRONIZED --->
501 [ + - ]: 32 : ::osl::MutexGuard aGuard( getMutex() );
502 : :
503 [ + + ]: 32 : if ( m_nLockCount == 0 )
504 [ + - ][ + - ]: 8 : throw NotLockedException( "Undo manager is not locked", getXUndoManager() );
505 : :
506 [ + - ]: 24 : if ( --m_nLockCount == 0 )
507 : : {
508 [ + - ]: 24 : IUndoManager& rUndoManager = getUndoManager();
509 [ + - ]: 24 : rUndoManager.EnableUndo( true );
510 [ + - ]: 32 : }
511 : : // <--- SYNCHRONIZED
512 : 24 : }
513 : :
514 : : //------------------------------------------------------------------------------------------------------------------
515 : 1494 : void UndoManagerHelper_Impl::impl_processRequest( ::boost::function0< void > const& i_request, IMutexGuard& i_instanceLock )
516 : : {
517 : : // create the request, and add it to our queue
518 [ + - ][ + - ]: 1494 : ::rtl::Reference< UndoManagerRequest > pRequest( new UndoManagerRequest( i_request ) );
[ + - ]
519 : : {
520 [ + - ]: 1494 : ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
521 [ + - ][ + - ]: 1494 : m_aEventQueue.push( pRequest );
522 : : }
523 : :
524 [ + - ]: 1494 : i_instanceLock.clear();
525 : :
526 [ + + ]: 1494 : if ( m_bProcessingEvents )
527 : : {
528 : : // another thread is processing the event queue currently => it will also process the event which we just added
529 [ + - ]: 58 : pRequest->wait();
530 : : return;
531 : : }
532 : :
533 : 1436 : m_bProcessingEvents = true;
534 : 1402 : do
535 : : {
536 [ + - ]: 2838 : pRequest.clear();
537 : : {
538 [ + - ]: 2838 : ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
539 [ + + ]: 2838 : if ( m_aEventQueue.empty() )
540 : : {
541 : : // reset the flag before releasing the queue mutex, otherwise it's possible that another thread
542 : : // could add an event after we release the mutex, but before we reset the flag. If then this other
543 : : // thread checks the flag before be reset it, this thread's event would starve.
544 : 1344 : m_bProcessingEvents = false;
545 : : return;
546 : : }
547 [ + - ][ + - ]: 1494 : pRequest = m_aEventQueue.front();
548 [ + - ][ + - ]: 2838 : m_aEventQueue.pop();
[ + + ]
549 : : }
550 : : try
551 : : {
552 [ + - ]: 2838 : pRequest->execute();
553 [ + + ]: 1494 : pRequest->wait();
554 : : }
555 : 184 : catch( ... )
556 : : {
557 : : {
558 : : // no chance to process further requests, if the current one failed
559 : : // => discard them
560 [ - + ]: 92 : ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
561 [ - + ]: 92 : while ( !m_aEventQueue.empty() )
562 : : {
563 [ # # # # ]: 0 : pRequest = m_aEventQueue.front();
564 [ # # ]: 0 : m_aEventQueue.pop();
565 [ # # # # ]: 0 : pRequest->cancel( getXUndoManager() );
566 : : }
567 [ - + ]: 92 : m_bProcessingEvents = false;
568 : : }
569 : : // re-throw the error
570 : 92 : throw;
571 : : }
572 : : }
573 [ + - ]: 1494 : while ( true );
574 : : }
575 : :
576 : : //------------------------------------------------------------------------------------------------------------------
577 : 176 : void UndoManagerHelper_Impl::impl_enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden )
578 : : {
579 : : // SYNCHRONIZED --->
580 [ + - ]: 176 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
581 : :
582 [ + - ]: 176 : IUndoManager& rUndoManager = getUndoManager();
583 [ + - ][ + + ]: 176 : if ( !rUndoManager.IsUndoEnabled() )
584 : : // ignore this request if the manager is locked
585 : 160 : return;
586 : :
587 [ + + ][ + - ]: 160 : if ( i_hidden && ( rUndoManager.GetUndoActionCount( IUndoManager::CurrentLevel ) == 0 ) )
[ + + ][ + + ]
588 : : throw EmptyUndoStackException(
589 : : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "can't enter a hidden context without a previous Undo action" ) ),
590 : 16 : m_rUndoManagerImplementation.getThis()
591 [ + - ][ + - ]: 16 : );
[ + - ]
592 : :
593 : : {
594 [ + - ]: 144 : ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
595 [ + - ][ + - ]: 144 : rUndoManager.EnterListAction( i_title, ::rtl::OUString() );
[ + - ][ + - ]
[ + - ][ + - ]
596 : : }
597 : :
598 [ + - ]: 144 : m_aContextVisibilities.push( i_hidden );
599 : :
600 [ + - ]: 144 : const UndoManagerEvent aEvent( buildEvent( i_title ) );
601 [ + - ]: 144 : aGuard.clear();
602 : : // <--- SYNCHRONIZED
603 : :
604 [ + + ][ + - ]: 144 : m_aUndoListeners.notifyEach( i_hidden ? &XUndoManagerListener::enteredHiddenContext : &XUndoManagerListener::enteredContext, aEvent );
605 [ + - ][ + - ]: 176 : impl_notifyModified();
[ + - ][ + + ]
606 : : }
607 : :
608 : : //------------------------------------------------------------------------------------------------------------------
609 : 142 : void UndoManagerHelper_Impl::impl_leaveUndoContext()
610 : : {
611 : : // SYNCHRONIZED --->
612 [ + - ]: 142 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
613 : :
614 [ + - ]: 142 : IUndoManager& rUndoManager = getUndoManager();
615 [ + - ][ + + ]: 142 : if ( !rUndoManager.IsUndoEnabled() )
616 : : // ignore this request if the manager is locked
617 : 134 : return;
618 : :
619 [ + - ][ + + ]: 126 : if ( !rUndoManager.IsInListAction() )
620 : : throw InvalidStateException(
621 : : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no active undo context" ) ),
622 : : getXUndoManager()
623 [ + - ][ + - ]: 8 : );
[ + - ]
624 : :
625 : 118 : size_t nContextElements = 0;
626 : :
627 [ + - ]: 118 : const bool isHiddenContext = m_aContextVisibilities.top();;
628 [ + - ]: 118 : m_aContextVisibilities.pop();
629 : :
630 [ + - ]: 118 : const bool bHadRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0 );
631 : : {
632 [ + - ]: 118 : ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
633 [ + + ]: 118 : if ( isHiddenContext )
634 [ + - ]: 32 : nContextElements = rUndoManager.LeaveAndMergeListAction();
635 : : else
636 [ + - ][ + - ]: 118 : nContextElements = rUndoManager.LeaveListAction();
637 : : }
638 [ + - ]: 118 : const bool bHasRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0 );
639 : :
640 : : // prepare notification
641 : 118 : void ( SAL_CALL XUndoManagerListener::*notificationMethod )( const UndoManagerEvent& ) = NULL;
642 : :
643 [ + - ]: 118 : UndoManagerEvent aContextEvent( buildEvent( ::rtl::OUString() ) );
644 [ + - ][ + - ]: 118 : const EventObject aClearedEvent( getXUndoManager() );
645 [ + + ]: 118 : if ( nContextElements == 0 )
646 : : {
647 : 38 : notificationMethod = &XUndoManagerListener::cancelledContext;
648 : : }
649 [ + + ]: 80 : else if ( isHiddenContext )
650 : : {
651 : 16 : notificationMethod = &XUndoManagerListener::leftHiddenContext;
652 : : }
653 : : else
654 : : {
655 [ + - ]: 64 : aContextEvent.UndoActionTitle = rUndoManager.GetUndoActionComment( 0, IUndoManager::CurrentLevel );
656 : 64 : notificationMethod = &XUndoManagerListener::leftContext;
657 : : }
658 : :
659 [ + - ]: 118 : aGuard.clear();
660 : : // <--- SYNCHRONIZED
661 : :
662 [ + + ][ + + ]: 118 : if ( bHadRedoActions && !bHasRedoActions )
663 [ + - ]: 14 : m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aClearedEvent );
664 [ + - ]: 118 : m_aUndoListeners.notifyEach( notificationMethod, aContextEvent );
665 [ + - ][ + - ]: 142 : impl_notifyModified();
[ + - ][ + - ]
[ + + ]
666 : : }
667 : :
668 : : //------------------------------------------------------------------------------------------------------------------
669 : 416 : void UndoManagerHelper_Impl::impl_doUndoRedo( IMutexGuard& i_externalLock, const bool i_undo )
670 : : {
671 [ + - ][ + - ]: 416 : ::osl::Guard< ::framework::IMutex > aExternalGuard( i_externalLock.getGuardedMutex() );
672 : : // note that this assumes that the mutex has been released in the thread which added the
673 : : // Undo/Redo request, so we can successfully acquire it
674 : :
675 : : // SYNCHRONIZED --->
676 [ + - ]: 416 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
677 : :
678 [ + - ]: 416 : IUndoManager& rUndoManager = getUndoManager();
679 [ + - ][ + + ]: 416 : if ( rUndoManager.IsInListAction() )
680 [ + - ][ + - ]: 16 : throw UndoContextNotClosedException( ::rtl::OUString(), getXUndoManager() );
681 : :
682 : : const size_t nElements = i_undo
683 : 374 : ? rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
684 [ + + ][ + - ]: 400 : : rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
[ + - ]
685 [ + + ]: 400 : if ( nElements == 0 )
686 [ + - ][ + - ]: 16 : throw EmptyUndoStackException( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "stack is empty" )), getXUndoManager() );
[ + - ]
687 : :
688 [ + - ]: 384 : aGuard.clear();
689 : : // <--- SYNCHRONIZED
690 : :
691 : : try
692 : : {
693 [ + + ]: 384 : if ( i_undo )
694 [ + + ]: 366 : rUndoManager.Undo();
695 : : else
696 [ + + ]: 18 : rUndoManager.Redo();
697 : : }
698 : 0 : catch( const RuntimeException& ) { /* allowed to leave here */ throw; }
699 : 20 : catch( const UndoFailedException& ) { /* allowed to leave here */ throw; }
700 [ - - + - ]: 20 : catch( const Exception& )
701 : : {
702 : : // not allowed to leave
703 [ # # ]: 0 : const Any aError( ::cppu::getCaughtException() );
704 [ # # # # ]: 0 : throw UndoFailedException( ::rtl::OUString(), getXUndoManager(), aError );
705 [ + - ][ + - ]: 416 : }
706 : :
707 : : // note that in opposite to all of the other methods, we do *not* have our mutex locked when calling
708 : : // into the IUndoManager implementation. This ensures that an actual XUndoAction::undo/redo is also
709 : : // called without our mutex being locked.
710 : : // As a consequence, we do not set m_bAPIActionRunning here. Instead, our actionUndone/actionRedone methods
711 : : // *always* multiplex the event to our XUndoManagerListeners, not only when m_bAPIActionRunning is FALSE (This
712 : : // again is different from all other SfxUndoListener methods).
713 : : // So, we do not need to do this notification here ourself.
714 : 364 : }
715 : :
716 : : //------------------------------------------------------------------------------------------------------------------
717 : 568 : void UndoManagerHelper_Impl::impl_addUndoAction( const Reference< XUndoAction >& i_action )
718 : : {
719 : : // SYNCHRONIZED --->
720 [ + - ]: 568 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
721 : :
722 [ + - ]: 568 : IUndoManager& rUndoManager = getUndoManager();
723 [ + - ][ + + ]: 568 : if ( !rUndoManager.IsUndoEnabled() )
724 : : // ignore the request if the manager is locked
725 : 568 : return;
726 : :
727 [ + - ][ + - ]: 554 : const UndoManagerEvent aEventAdd( buildEvent( i_action->getTitle() ) );
[ + - ]
728 [ + - ][ + - ]: 554 : const EventObject aEventClear( getXUndoManager() );
729 : :
730 [ + - ]: 554 : const bool bHadRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 );
731 : : {
732 [ + - ]: 554 : ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
733 [ + - ][ + - ]: 554 : rUndoManager.AddUndoAction( new UndoActionWrapper( i_action ) );
[ + - ][ + - ]
734 : : }
735 [ + - ]: 554 : const bool bHasRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 );
736 : :
737 [ + - ]: 554 : aGuard.clear();
738 : : // <--- SYNCHRONIZED
739 : :
740 [ + - ]: 554 : m_aUndoListeners.notifyEach( &XUndoManagerListener::undoActionAdded, aEventAdd );
741 [ + + ][ + - ]: 554 : if ( bHadRedoActions && !bHasRedoActions )
742 [ + - ]: 16 : m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aEventClear );
743 [ + - ][ + - ]: 568 : impl_notifyModified();
[ + - ][ + - ]
[ + + ]
744 : : }
745 : :
746 : : //------------------------------------------------------------------------------------------------------------------
747 : 48 : void UndoManagerHelper_Impl::impl_clear()
748 : : {
749 : : // SYNCHRONIZED --->
750 [ + - ]: 48 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
751 : :
752 [ + - ]: 48 : IUndoManager& rUndoManager = getUndoManager();
753 [ + - ][ + + ]: 48 : if ( rUndoManager.IsInListAction() )
754 [ + - ][ + - ]: 8 : throw UndoContextNotClosedException( ::rtl::OUString(), getXUndoManager() );
755 : :
756 : : {
757 [ + - ]: 40 : ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
758 [ + - ][ + - ]: 40 : rUndoManager.Clear();
759 : : }
760 : :
761 [ + - ][ + - ]: 40 : const EventObject aEvent( getXUndoManager() );
762 [ + - ]: 40 : aGuard.clear();
763 : : // <--- SYNCHRONIZED
764 : :
765 [ + - ]: 40 : m_aUndoListeners.notifyEach( &XUndoManagerListener::allActionsCleared, aEvent );
766 [ + - ][ + - ]: 48 : impl_notifyModified();
[ + - ]
767 : 40 : }
768 : :
769 : : //------------------------------------------------------------------------------------------------------------------
770 : 16 : void UndoManagerHelper_Impl::impl_clearRedo()
771 : : {
772 : : // SYNCHRONIZED --->
773 [ + - ]: 16 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
774 : :
775 [ + - ]: 16 : IUndoManager& rUndoManager = getUndoManager();
776 [ + - ][ + + ]: 16 : if ( rUndoManager.IsInListAction() )
777 [ + - ][ + - ]: 8 : throw UndoContextNotClosedException( ::rtl::OUString(), getXUndoManager() );
778 : :
779 : : {
780 [ + - ]: 8 : ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
781 [ + - ][ + - ]: 8 : rUndoManager.ClearRedo();
782 : : }
783 : :
784 [ + - ][ + - ]: 8 : const EventObject aEvent( getXUndoManager() );
785 [ + - ]: 8 : aGuard.clear();
786 : : // <--- SYNCHRONIZED
787 : :
788 [ + - ]: 8 : m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aEvent );
789 [ + - ][ + - ]: 16 : impl_notifyModified();
[ + - ]
790 : 8 : }
791 : :
792 : : //------------------------------------------------------------------------------------------------------------------
793 : 128 : void UndoManagerHelper_Impl::impl_reset()
794 : : {
795 : : // SYNCHRONIZED --->
796 [ + - ]: 128 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
797 : :
798 [ + - ]: 128 : IUndoManager& rUndoManager = getUndoManager();
799 : : {
800 [ + - ]: 128 : ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
801 [ + - ][ + - ]: 128 : rUndoManager.Reset();
802 : : }
803 : :
804 [ + - ][ + - ]: 128 : const EventObject aEvent( getXUndoManager() );
805 [ + - ]: 128 : aGuard.clear();
806 : : // <--- SYNCHRONIZED
807 : :
808 [ + - ]: 128 : m_aUndoListeners.notifyEach( &XUndoManagerListener::resetAll, aEvent );
809 [ + - ][ + - ]: 128 : impl_notifyModified();
[ + - ]
810 : 128 : }
811 : :
812 : : //------------------------------------------------------------------------------------------------------------------
813 : 368 : void UndoManagerHelper_Impl::actionUndone( const String& i_actionComment )
814 : : {
815 [ + - ]: 368 : UndoManagerEvent aEvent;
816 [ + - ][ + - ]: 368 : aEvent.Source = getXUndoManager();
817 [ + - ]: 368 : aEvent.UndoActionTitle = i_actionComment;
818 : 368 : aEvent.UndoContextDepth = 0; // Undo can happen on level 0 only
819 [ + - ]: 368 : m_aUndoListeners.notifyEach( &XUndoManagerListener::actionUndone, aEvent );
820 [ + - ][ + - ]: 368 : impl_notifyModified();
821 : 368 : }
822 : :
823 : : //------------------------------------------------------------------------------------------------------------------
824 : 8 : void UndoManagerHelper_Impl::actionRedone( const String& i_actionComment )
825 : : {
826 [ + - ]: 8 : UndoManagerEvent aEvent;
827 [ + - ][ + - ]: 8 : aEvent.Source = getXUndoManager();
828 [ + - ]: 8 : aEvent.UndoActionTitle = i_actionComment;
829 : 8 : aEvent.UndoContextDepth = 0; // Redo can happen on level 0 only
830 [ + - ]: 8 : m_aUndoListeners.notifyEach( &XUndoManagerListener::actionRedone, aEvent );
831 [ + - ][ + - ]: 8 : impl_notifyModified();
832 : 8 : }
833 : :
834 : : //------------------------------------------------------------------------------------------------------------------
835 : 585 : void UndoManagerHelper_Impl::undoActionAdded( const String& i_actionComment )
836 : : {
837 [ + + ]: 585 : if ( m_bAPIActionRunning )
838 : 585 : return;
839 : :
840 [ + - ]: 31 : notify( i_actionComment, &XUndoManagerListener::undoActionAdded );
841 : : }
842 : :
843 : : //------------------------------------------------------------------------------------------------------------------
844 : 40 : void UndoManagerHelper_Impl::cleared()
845 : : {
846 [ + - ]: 40 : if ( m_bAPIActionRunning )
847 : 40 : return;
848 : :
849 : 0 : notify( &XUndoManagerListener::allActionsCleared );
850 : : }
851 : :
852 : : //------------------------------------------------------------------------------------------------------------------
853 : 6 : void UndoManagerHelper_Impl::clearedRedo()
854 : : {
855 [ + + ]: 6 : if ( m_bAPIActionRunning )
856 : 6 : return;
857 : :
858 : 4 : notify( &XUndoManagerListener::redoActionsCleared );
859 : : }
860 : :
861 : : //------------------------------------------------------------------------------------------------------------------
862 : 128 : void UndoManagerHelper_Impl::resetAll()
863 : : {
864 [ + - ]: 128 : if ( m_bAPIActionRunning )
865 : 128 : return;
866 : :
867 : 0 : notify( &XUndoManagerListener::resetAll );
868 : : }
869 : :
870 : : //------------------------------------------------------------------------------------------------------------------
871 : 154 : void UndoManagerHelper_Impl::listActionEntered( const String& i_comment )
872 : : {
873 : : #if OSL_DEBUG_LEVEL > 0
874 : : m_aContextAPIFlags.push( m_bAPIActionRunning );
875 : : #endif
876 : :
877 [ + + ]: 154 : if ( m_bAPIActionRunning )
878 : 154 : return;
879 : :
880 [ + - ]: 10 : notify( i_comment, &XUndoManagerListener::enteredContext );
881 : : }
882 : :
883 : : //------------------------------------------------------------------------------------------------------------------
884 : 90 : void UndoManagerHelper_Impl::listActionLeft( const String& i_comment )
885 : : {
886 : : #if OSL_DEBUG_LEVEL > 0
887 : : const bool bCurrentContextIsAPIContext = m_aContextAPIFlags.top();
888 : : m_aContextAPIFlags.pop();
889 : : OSL_ENSURE( bCurrentContextIsAPIContext == m_bAPIActionRunning, "UndoManagerHelper_Impl::listActionLeft: API and non-API contexts interwoven!" );
890 : : #endif
891 : :
892 [ + + ]: 90 : if ( m_bAPIActionRunning )
893 : 90 : return;
894 : :
895 [ + - ]: 10 : notify( i_comment, &XUndoManagerListener::leftContext );
896 : : }
897 : :
898 : : //------------------------------------------------------------------------------------------------------------------
899 : 0 : void UndoManagerHelper_Impl::listActionLeftAndMerged()
900 : : {
901 : : #if OSL_DEBUG_LEVEL > 0
902 : : const bool bCurrentContextIsAPIContext = m_aContextAPIFlags.top();
903 : : m_aContextAPIFlags.pop();
904 : : OSL_ENSURE( bCurrentContextIsAPIContext == m_bAPIActionRunning, "UndoManagerHelper_Impl::listActionLeftAndMerged: API and non-API contexts interwoven!" );
905 : : #endif
906 : :
907 [ # # ]: 0 : if ( m_bAPIActionRunning )
908 : 0 : return;
909 : :
910 : 0 : notify( &XUndoManagerListener::leftHiddenContext );
911 : : }
912 : :
913 : : //------------------------------------------------------------------------------------------------------------------
914 : 38 : void UndoManagerHelper_Impl::listActionCancelled()
915 : : {
916 : : #if OSL_DEBUG_LEVEL > 0
917 : : const bool bCurrentContextIsAPIContext = m_aContextAPIFlags.top();
918 : : m_aContextAPIFlags.pop();
919 : : OSL_ENSURE( bCurrentContextIsAPIContext == m_bAPIActionRunning, "UndoManagerHelper_Impl::listActionCancelled: API and non-API contexts interwoven!" );
920 : : #endif
921 : :
922 [ + - ]: 38 : if ( m_bAPIActionRunning )
923 : 38 : return;
924 : :
925 : 0 : notify( &XUndoManagerListener::cancelledContext );
926 : : }
927 : :
928 : : //------------------------------------------------------------------------------------------------------------------
929 : 0 : void UndoManagerHelper_Impl::undoManagerDying()
930 : : {
931 : : // TODO: do we need to care? Or is this the responsibility of our owner?
932 : 0 : }
933 : :
934 : : //==================================================================================================================
935 : : //= UndoManagerHelper
936 : : //==================================================================================================================
937 : : //------------------------------------------------------------------------------------------------------------------
938 : 55 : UndoManagerHelper::UndoManagerHelper( IUndoManagerImplementation& i_undoManagerImpl )
939 [ + - ]: 55 : :m_pImpl( new UndoManagerHelper_Impl( i_undoManagerImpl ) )
940 : : {
941 : 55 : }
942 : :
943 : : //------------------------------------------------------------------------------------------------------------------
944 : 0 : UndoManagerHelper::~UndoManagerHelper()
945 : : {
946 : 0 : }
947 : :
948 : : //------------------------------------------------------------------------------------------------------------------
949 : 55 : void UndoManagerHelper::disposing()
950 : : {
951 : 55 : m_pImpl->disposing();
952 : 55 : }
953 : :
954 : : //------------------------------------------------------------------------------------------------------------------
955 : 112 : void UndoManagerHelper::enterUndoContext( const ::rtl::OUString& i_title, IMutexGuard& i_instanceLock )
956 : : {
957 : 112 : m_pImpl->enterUndoContext( i_title, false, i_instanceLock );
958 : 112 : }
959 : :
960 : : //------------------------------------------------------------------------------------------------------------------
961 : 64 : void UndoManagerHelper::enterHiddenUndoContext( IMutexGuard& i_instanceLock )
962 : : {
963 [ + + ]: 64 : m_pImpl->enterUndoContext( ::rtl::OUString(), true, i_instanceLock );
964 : 48 : }
965 : :
966 : : //------------------------------------------------------------------------------------------------------------------
967 : 142 : void UndoManagerHelper::leaveUndoContext( IMutexGuard& i_instanceLock )
968 : : {
969 : 142 : m_pImpl->leaveUndoContext( i_instanceLock );
970 : 134 : }
971 : :
972 : : //------------------------------------------------------------------------------------------------------------------
973 : 382 : void UndoManagerHelper_Impl::undo( IMutexGuard& i_instanceLock )
974 : : {
975 : : impl_processRequest(
976 : : ::boost::bind(
977 : : &UndoManagerHelper_Impl::impl_doUndoRedo,
978 : : this,
979 : : ::boost::ref( i_instanceLock ),
980 : : true
981 : : ),
982 : : i_instanceLock
983 [ + + ]: 382 : );
984 : 356 : }
985 : :
986 : : //------------------------------------------------------------------------------------------------------------------
987 : 34 : void UndoManagerHelper_Impl::redo( IMutexGuard& i_instanceLock )
988 : : {
989 : : impl_processRequest(
990 : : ::boost::bind(
991 : : &UndoManagerHelper_Impl::impl_doUndoRedo,
992 : : this,
993 : : ::boost::ref( i_instanceLock ),
994 : : false
995 : : ),
996 : : i_instanceLock
997 [ + + ]: 34 : );
998 : 8 : }
999 : :
1000 : : //------------------------------------------------------------------------------------------------------------------
1001 : 576 : void UndoManagerHelper::addUndoAction( const Reference< XUndoAction >& i_action, IMutexGuard& i_instanceLock )
1002 : : {
1003 : 576 : m_pImpl->addUndoAction( i_action, i_instanceLock );
1004 : 568 : }
1005 : :
1006 : : //------------------------------------------------------------------------------------------------------------------
1007 : 382 : void UndoManagerHelper::undo( IMutexGuard& i_instanceLock )
1008 : : {
1009 : 382 : m_pImpl->undo( i_instanceLock );
1010 : 356 : }
1011 : :
1012 : : //------------------------------------------------------------------------------------------------------------------
1013 : 34 : void UndoManagerHelper::redo( IMutexGuard& i_instanceLock )
1014 : : {
1015 : 34 : m_pImpl->redo( i_instanceLock );
1016 : 8 : }
1017 : :
1018 : : //------------------------------------------------------------------------------------------------------------------
1019 : 770 : ::sal_Bool UndoManagerHelper::isUndoPossible() const
1020 : : {
1021 : : // SYNCHRONIZED --->
1022 [ + - ]: 770 : ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
1023 [ + - ]: 770 : IUndoManager& rUndoManager = m_pImpl->getUndoManager();
1024 [ + - ][ + + ]: 770 : if ( rUndoManager.IsInListAction() )
1025 : 144 : return sal_False;
1026 [ + - ][ + - ]: 770 : return rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) > 0;
1027 : : // <--- SYNCHRONIZED
1028 : : }
1029 : :
1030 : : //------------------------------------------------------------------------------------------------------------------
1031 : 754 : ::sal_Bool UndoManagerHelper::isRedoPossible() const
1032 : : {
1033 : : // SYNCHRONIZED --->
1034 [ + - ]: 754 : ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
1035 [ + - ]: 754 : const IUndoManager& rUndoManager = m_pImpl->getUndoManager();
1036 [ + - ][ + + ]: 754 : if ( rUndoManager.IsInListAction() )
1037 : 144 : return sal_False;
1038 [ + - ][ + - ]: 754 : return rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0;
1039 : : // <--- SYNCHRONIZED
1040 : : }
1041 : :
1042 : : //------------------------------------------------------------------------------------------------------------------
1043 : : namespace
1044 : : {
1045 : : //..............................................................................................................
1046 : 182 : ::rtl::OUString lcl_getCurrentActionTitle( UndoManagerHelper_Impl& i_impl, const bool i_undo )
1047 : : {
1048 : : // SYNCHRONIZED --->
1049 [ + - ]: 182 : ::osl::MutexGuard aGuard( i_impl.getMutex() );
1050 : :
1051 [ + - ]: 182 : const IUndoManager& rUndoManager = i_impl.getUndoManager();
1052 : : const size_t nActionCount = i_undo
1053 : 128 : ? rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
1054 [ + + ][ + - ]: 182 : : rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
[ + - ]
1055 [ + + ]: 182 : if ( nActionCount == 0 )
1056 : : throw EmptyUndoStackException(
1057 : : i_undo ? ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no action on the undo stack" ) )
1058 : : : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no action on the redo stack" ) ),
1059 : : i_impl.getXUndoManager()
1060 [ + - ][ + + ]: 16 : );
[ + - ][ + - ]
[ + - ]
1061 : : return i_undo
1062 : 120 : ? rUndoManager.GetUndoActionComment( 0, IUndoManager::TopLevel )
1063 [ + + ][ + - ]: 182 : : rUndoManager.GetRedoActionComment( 0, IUndoManager::TopLevel );
[ + - ][ + - ]
1064 : : // <--- SYNCHRONIZED
1065 : : }
1066 : :
1067 : : //..............................................................................................................
1068 : 128 : Sequence< ::rtl::OUString > lcl_getAllActionTitles( UndoManagerHelper_Impl& i_impl, const bool i_undo )
1069 : : {
1070 : : // SYNCHRONIZED --->
1071 [ + - ]: 128 : ::osl::MutexGuard aGuard( i_impl.getMutex() );
1072 : :
1073 [ + - ]: 128 : const IUndoManager& rUndoManager = i_impl.getUndoManager();
1074 : : const size_t nCount = i_undo
1075 : 56 : ? rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
1076 [ + + ][ + - ]: 128 : : rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
[ + - ]
1077 : :
1078 [ + - ]: 128 : Sequence< ::rtl::OUString > aTitles( nCount );
1079 [ + + ]: 248 : for ( size_t i=0; i<nCount; ++i )
1080 : : {
1081 [ + - ]: 120 : aTitles[i] = i_undo
1082 : 64 : ? rUndoManager.GetUndoActionComment( i, IUndoManager::TopLevel )
1083 [ + + ][ + - ]: 240 : : rUndoManager.GetRedoActionComment( i, IUndoManager::TopLevel );
[ + - ]
1084 : : }
1085 [ + - ]: 128 : return aTitles;
1086 : : // <--- SYNCHRONIZED
1087 : : }
1088 : : }
1089 : :
1090 : : //------------------------------------------------------------------------------------------------------------------
1091 : 128 : ::rtl::OUString UndoManagerHelper::getCurrentUndoActionTitle() const
1092 : : {
1093 : 128 : return lcl_getCurrentActionTitle( *m_pImpl, true );
1094 : : }
1095 : :
1096 : : //------------------------------------------------------------------------------------------------------------------
1097 : 54 : ::rtl::OUString UndoManagerHelper::getCurrentRedoActionTitle() const
1098 : : {
1099 : 54 : return lcl_getCurrentActionTitle( *m_pImpl, false );
1100 : : }
1101 : :
1102 : : //------------------------------------------------------------------------------------------------------------------
1103 : 56 : Sequence< ::rtl::OUString > UndoManagerHelper::getAllUndoActionTitles() const
1104 : : {
1105 : 56 : return lcl_getAllActionTitles( *m_pImpl, true );
1106 : : }
1107 : :
1108 : : //------------------------------------------------------------------------------------------------------------------
1109 : 72 : Sequence< ::rtl::OUString > UndoManagerHelper::getAllRedoActionTitles() const
1110 : : {
1111 : 72 : return lcl_getAllActionTitles( *m_pImpl, false );
1112 : : }
1113 : :
1114 : : //------------------------------------------------------------------------------------------------------------------
1115 : 48 : void UndoManagerHelper::clear( IMutexGuard& i_instanceLock )
1116 : : {
1117 : 48 : m_pImpl->clear( i_instanceLock );
1118 : 40 : }
1119 : :
1120 : : //------------------------------------------------------------------------------------------------------------------
1121 : 16 : void UndoManagerHelper::clearRedo( IMutexGuard& i_instanceLock )
1122 : : {
1123 : 16 : m_pImpl->clearRedo( i_instanceLock );
1124 : 8 : }
1125 : :
1126 : : //------------------------------------------------------------------------------------------------------------------
1127 : 128 : void UndoManagerHelper::reset( IMutexGuard& i_instanceLock )
1128 : : {
1129 : 128 : m_pImpl->reset( i_instanceLock );
1130 : 128 : }
1131 : :
1132 : : //------------------------------------------------------------------------------------------------------------------
1133 : 24 : void UndoManagerHelper::lock()
1134 : : {
1135 : 24 : m_pImpl->lock();
1136 : 24 : }
1137 : :
1138 : : //------------------------------------------------------------------------------------------------------------------
1139 : 32 : void UndoManagerHelper::unlock()
1140 : : {
1141 : 32 : m_pImpl->unlock();
1142 : 24 : }
1143 : :
1144 : : //------------------------------------------------------------------------------------------------------------------
1145 : 40 : ::sal_Bool UndoManagerHelper::isLocked()
1146 : : {
1147 : : // SYNCHRONIZED --->
1148 [ + - ]: 40 : ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
1149 : :
1150 [ + - ]: 40 : IUndoManager& rUndoManager = m_pImpl->getUndoManager();
1151 [ + - ][ + - ]: 40 : return !rUndoManager.IsUndoEnabled();
1152 : : // <--- SYNCHRONIZED
1153 : : }
1154 : :
1155 : : //------------------------------------------------------------------------------------------------------------------
1156 : 29 : void UndoManagerHelper::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
1157 : : {
1158 [ + - ]: 29 : if ( i_listener.is() )
1159 : 29 : m_pImpl->addUndoManagerListener( i_listener );
1160 : 29 : }
1161 : :
1162 : : //------------------------------------------------------------------------------------------------------------------
1163 : 17 : void UndoManagerHelper::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
1164 : : {
1165 [ + - ]: 17 : if ( i_listener.is() )
1166 : 17 : m_pImpl->removeUndoManagerListener( i_listener );
1167 : 17 : }
1168 : :
1169 : : //------------------------------------------------------------------------------------------------------------------
1170 : 34 : void UndoManagerHelper::addModifyListener( const Reference< XModifyListener >& i_listener )
1171 : : {
1172 [ + - ]: 34 : if ( i_listener.is() )
1173 : 34 : m_pImpl->addModifyListener( i_listener );
1174 : 34 : }
1175 : :
1176 : : //------------------------------------------------------------------------------------------------------------------
1177 : 34 : void UndoManagerHelper::removeModifyListener( const Reference< XModifyListener >& i_listener )
1178 : : {
1179 [ + - ]: 34 : if ( i_listener.is() )
1180 : 34 : m_pImpl->removeModifyListener( i_listener );
1181 : 34 : }
1182 : :
1183 : : //......................................................................................................................
1184 [ + - ][ + - ]: 735 : } // namespace framework
1185 : : //......................................................................................................................
1186 : :
1187 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|