1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25  ************************************************************************/
26 
27 #include "precompiled_framework.hxx"
28 
29 #include "framework/documentundoguard.hxx"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/document/XUndoManagerSupplier.hpp>
33 /** === end UNO includes === **/
34 
35 #include <cppuhelper/implbase1.hxx>
36 #include <rtl/ref.hxx>
37 #include <tools/diagnose_ex.h>
38 
39 //......................................................................................................................
40 namespace framework
41 {
42 //......................................................................................................................
43 
44 	/** === begin UNO using === **/
45 	using ::com::sun::star::uno::Reference;
46 	using ::com::sun::star::uno::XInterface;
47 	using ::com::sun::star::uno::UNO_QUERY;
48 	using ::com::sun::star::uno::UNO_QUERY_THROW;
49 	using ::com::sun::star::uno::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::document::XUndoManagerSupplier;
56     using ::com::sun::star::document::XUndoManager;
57     using ::com::sun::star::document::XUndoManagerListener;
58     using ::com::sun::star::document::UndoManagerEvent;
59     using ::com::sun::star::lang::EventObject;
60 	/** === end UNO using === **/
61 
62 	//==================================================================================================================
63 	//= UndoManagerContextListener
64 	//==================================================================================================================
65     typedef ::cppu::WeakImplHelper1 <   XUndoManagerListener
66                                     >   UndoManagerContextListener_Base;
67     class UndoManagerContextListener : public UndoManagerContextListener_Base
68     {
69     public:
70         UndoManagerContextListener( const Reference< XUndoManager >& i_undoManager )
71             :m_xUndoManager( i_undoManager, UNO_QUERY_THROW )
72             ,m_nRelativeContextDepth( 0 )
73             ,m_documentDisposed( false )
74         {
75             osl_incrementInterlockedCount( &m_refCount );
76             {
77                 m_xUndoManager->addUndoManagerListener( this );
78             }
79             osl_decrementInterlockedCount( &m_refCount );
80         }
81 
82         UndoManagerContextListener()
83         {
84         }
85 
86         void finish()
87         {
88             OSL_ENSURE( m_nRelativeContextDepth >= 0, "UndoManagerContextListener: more contexts left than entered?" );
89 
90             if ( m_documentDisposed )
91                 return;
92 
93             // work with a copy of m_nRelativeContextDepth, to be independent from possible bugs in the
94             // listener notifications (where it would be decremented with every leaveUndoContext)
95             sal_Int32 nDepth = m_nRelativeContextDepth;
96             while ( nDepth-- > 0 )
97             {
98                 m_xUndoManager->leaveUndoContext();
99             }
100             m_xUndoManager->removeUndoManagerListener( this );
101         }
102 
103         // XUndoManagerListener
104         virtual void SAL_CALL undoActionAdded( const UndoManagerEvent& i_event ) throw (RuntimeException);
105         virtual void SAL_CALL actionUndone( const UndoManagerEvent& i_event ) throw (RuntimeException);
106         virtual void SAL_CALL actionRedone( const UndoManagerEvent& i_event ) throw (RuntimeException);
107         virtual void SAL_CALL allActionsCleared( const EventObject& i_event ) throw (RuntimeException);
108         virtual void SAL_CALL redoActionsCleared( const EventObject& i_event ) throw (RuntimeException);
109         virtual void SAL_CALL resetAll( const EventObject& i_event ) throw (RuntimeException);
110         virtual void SAL_CALL enteredContext( const UndoManagerEvent& i_event ) throw (RuntimeException);
111         virtual void SAL_CALL enteredHiddenContext( const UndoManagerEvent& i_event ) throw (RuntimeException);
112         virtual void SAL_CALL leftContext( const UndoManagerEvent& i_event ) throw (RuntimeException);
113         virtual void SAL_CALL leftHiddenContext( const UndoManagerEvent& i_event ) throw (RuntimeException);
114         virtual void SAL_CALL cancelledContext( const UndoManagerEvent& i_event ) throw (RuntimeException);
115 
116         // XEventListener
117         virtual void SAL_CALL disposing( const EventObject& i_event ) throw (RuntimeException);
118 
119     private:
120         Reference< XUndoManager > const m_xUndoManager;
121         oslInterlockedCount             m_nRelativeContextDepth;
122         bool                            m_documentDisposed;
123     };
124 
125     //------------------------------------------------------------------------------------------------------------------
126     void SAL_CALL UndoManagerContextListener::undoActionAdded( const UndoManagerEvent& i_event ) throw (RuntimeException)
127     {
128         (void)i_event;
129         // not interested in
130     }
131 
132     //------------------------------------------------------------------------------------------------------------------
133     void SAL_CALL UndoManagerContextListener::actionUndone( const UndoManagerEvent& i_event ) throw (RuntimeException)
134     {
135         (void)i_event;
136         // not interested in
137     }
138 
139     //------------------------------------------------------------------------------------------------------------------
140     void SAL_CALL UndoManagerContextListener::actionRedone( const UndoManagerEvent& i_event ) throw (RuntimeException)
141     {
142         (void)i_event;
143         // not interested in
144     }
145 
146     //------------------------------------------------------------------------------------------------------------------
147     void SAL_CALL UndoManagerContextListener::allActionsCleared( const EventObject& i_event ) throw (RuntimeException)
148     {
149         (void)i_event;
150         // not interested in
151     }
152 
153     //------------------------------------------------------------------------------------------------------------------
154     void SAL_CALL UndoManagerContextListener::redoActionsCleared( const EventObject& i_event ) throw (RuntimeException)
155     {
156         (void)i_event;
157         // not interested in
158     }
159 
160     //------------------------------------------------------------------------------------------------------------------
161     void SAL_CALL UndoManagerContextListener::resetAll( const EventObject& i_event ) throw (RuntimeException)
162     {
163         (void)i_event;
164         m_nRelativeContextDepth = 0;
165     }
166 
167     //------------------------------------------------------------------------------------------------------------------
168     void SAL_CALL UndoManagerContextListener::enteredContext( const UndoManagerEvent& i_event ) throw (RuntimeException)
169     {
170         (void)i_event;
171         osl_incrementInterlockedCount( &m_nRelativeContextDepth );
172     }
173 
174     //------------------------------------------------------------------------------------------------------------------
175     void SAL_CALL UndoManagerContextListener::enteredHiddenContext( const UndoManagerEvent& i_event ) throw (RuntimeException)
176     {
177         (void)i_event;
178         osl_incrementInterlockedCount( &m_nRelativeContextDepth );
179     }
180 
181     //------------------------------------------------------------------------------------------------------------------
182     void SAL_CALL UndoManagerContextListener::leftContext( const UndoManagerEvent& i_event ) throw (RuntimeException)
183     {
184         (void)i_event;
185         osl_decrementInterlockedCount( &m_nRelativeContextDepth );
186     }
187 
188     //------------------------------------------------------------------------------------------------------------------
189     void SAL_CALL UndoManagerContextListener::leftHiddenContext( const UndoManagerEvent& i_event ) throw (RuntimeException)
190     {
191         (void)i_event;
192         osl_decrementInterlockedCount( &m_nRelativeContextDepth );
193     }
194 
195     //------------------------------------------------------------------------------------------------------------------
196     void SAL_CALL UndoManagerContextListener::cancelledContext( const UndoManagerEvent& i_event ) throw (RuntimeException)
197     {
198         (void)i_event;
199         osl_decrementInterlockedCount( &m_nRelativeContextDepth );
200     }
201 
202     //------------------------------------------------------------------------------------------------------------------
203     void SAL_CALL UndoManagerContextListener::disposing( const EventObject& i_event ) throw (RuntimeException)
204     {
205         (void)i_event;
206         m_documentDisposed = true;
207     }
208 
209 	//==================================================================================================================
210 	//= DocumentUndoGuard_Data
211 	//==================================================================================================================
212     struct DocumentUndoGuard_Data
213     {
214         Reference< XUndoManager >                       xUndoManager;
215         ::rtl::Reference< UndoManagerContextListener >  pContextListener;
216     };
217 
218     namespace
219     {
220 	    //--------------------------------------------------------------------------------------------------------------
221         void lcl_init( DocumentUndoGuard_Data& i_data, const Reference< XInterface >& i_undoSupplierComponent )
222         {
223             try
224             {
225                 Reference< XUndoManagerSupplier > xUndoSupplier( i_undoSupplierComponent, UNO_QUERY );
226                 if ( xUndoSupplier.is() )
227                     i_data.xUndoManager.set( xUndoSupplier->getUndoManager(), UNO_QUERY_THROW );
228 
229                 if ( i_data.xUndoManager.is() )
230                     i_data.pContextListener.set( new UndoManagerContextListener( i_data.xUndoManager ) );
231             }
232             catch( const Exception& )
233             {
234         	    DBG_UNHANDLED_EXCEPTION();
235             }
236         }
237 
238         //--------------------------------------------------------------------------------------------------------------
239         void lcl_restore( DocumentUndoGuard_Data& i_data )
240         {
241             try
242             {
243                 if ( i_data.pContextListener.is() )
244                     i_data.pContextListener->finish();
245                 i_data.pContextListener.clear();
246             }
247             catch( const Exception& )
248             {
249             	DBG_UNHANDLED_EXCEPTION();
250             }
251         }
252     }
253 
254 	//==================================================================================================================
255 	//= DocumentUndoGuard
256 	//==================================================================================================================
257 	//------------------------------------------------------------------------------------------------------------------
258     DocumentUndoGuard::DocumentUndoGuard( const Reference< XInterface >& i_undoSupplierComponent )
259         :m_pData( new DocumentUndoGuard_Data )
260     {
261         lcl_init( *m_pData, i_undoSupplierComponent );
262     }
263 
264     DocumentUndoGuard::~DocumentUndoGuard()
265     {
266         lcl_restore( *m_pData );
267     }
268 
269 //......................................................................................................................
270 } // namespace framework
271 //......................................................................................................................
272