1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include "precompiled_framework.hxx" 25 26 #include "framework/documentundoguard.hxx" 27 28 /** === begin UNO includes === **/ 29 #include <com/sun/star/document/XUndoManagerSupplier.hpp> 30 /** === end UNO includes === **/ 31 32 #include <cppuhelper/implbase1.hxx> 33 #include <rtl/ref.hxx> 34 #include <tools/diagnose_ex.h> 35 36 //...................................................................................................................... 37 namespace framework 38 { 39 //...................................................................................................................... 40 41 /** === begin UNO using === **/ 42 using ::com::sun::star::uno::Reference; 43 using ::com::sun::star::uno::XInterface; 44 using ::com::sun::star::uno::UNO_QUERY; 45 using ::com::sun::star::uno::UNO_QUERY_THROW; 46 using ::com::sun::star::uno::Exception; 47 using ::com::sun::star::uno::RuntimeException; 48 using ::com::sun::star::uno::Any; 49 using ::com::sun::star::uno::makeAny; 50 using ::com::sun::star::uno::Sequence; 51 using ::com::sun::star::uno::Type; 52 using ::com::sun::star::document::XUndoManagerSupplier; 53 using ::com::sun::star::document::XUndoManager; 54 using ::com::sun::star::document::XUndoManagerListener; 55 using ::com::sun::star::document::UndoManagerEvent; 56 using ::com::sun::star::lang::EventObject; 57 /** === end UNO using === **/ 58 59 //================================================================================================================== 60 //= UndoManagerContextListener 61 //================================================================================================================== 62 typedef ::cppu::WeakImplHelper1 < XUndoManagerListener 63 > UndoManagerContextListener_Base; 64 class UndoManagerContextListener : public UndoManagerContextListener_Base 65 { 66 public: 67 UndoManagerContextListener( const Reference< XUndoManager >& i_undoManager ) 68 :m_xUndoManager( i_undoManager, UNO_QUERY_THROW ) 69 ,m_nRelativeContextDepth( 0 ) 70 ,m_documentDisposed( false ) 71 { 72 osl_incrementInterlockedCount( &m_refCount ); 73 { 74 m_xUndoManager->addUndoManagerListener( this ); 75 } 76 osl_decrementInterlockedCount( &m_refCount ); 77 } 78 79 UndoManagerContextListener() 80 { 81 } 82 83 void finish() 84 { 85 OSL_ENSURE( m_nRelativeContextDepth >= 0, "UndoManagerContextListener: more contexts left than entered?" ); 86 87 if ( m_documentDisposed ) 88 return; 89 90 // work with a copy of m_nRelativeContextDepth, to be independent from possible bugs in the 91 // listener notifications (where it would be decremented with every leaveUndoContext) 92 sal_Int32 nDepth = m_nRelativeContextDepth; 93 while ( nDepth-- > 0 ) 94 { 95 m_xUndoManager->leaveUndoContext(); 96 } 97 m_xUndoManager->removeUndoManagerListener( this ); 98 } 99 100 // XUndoManagerListener 101 virtual void SAL_CALL undoActionAdded( const UndoManagerEvent& i_event ) throw (RuntimeException); 102 virtual void SAL_CALL actionUndone( const UndoManagerEvent& i_event ) throw (RuntimeException); 103 virtual void SAL_CALL actionRedone( const UndoManagerEvent& i_event ) throw (RuntimeException); 104 virtual void SAL_CALL allActionsCleared( const EventObject& i_event ) throw (RuntimeException); 105 virtual void SAL_CALL redoActionsCleared( const EventObject& i_event ) throw (RuntimeException); 106 virtual void SAL_CALL resetAll( const EventObject& i_event ) throw (RuntimeException); 107 virtual void SAL_CALL enteredContext( const UndoManagerEvent& i_event ) throw (RuntimeException); 108 virtual void SAL_CALL enteredHiddenContext( const UndoManagerEvent& i_event ) throw (RuntimeException); 109 virtual void SAL_CALL leftContext( const UndoManagerEvent& i_event ) throw (RuntimeException); 110 virtual void SAL_CALL leftHiddenContext( const UndoManagerEvent& i_event ) throw (RuntimeException); 111 virtual void SAL_CALL cancelledContext( const UndoManagerEvent& i_event ) throw (RuntimeException); 112 113 // XEventListener 114 virtual void SAL_CALL disposing( const EventObject& i_event ) throw (RuntimeException); 115 116 private: 117 Reference< XUndoManager > const m_xUndoManager; 118 oslInterlockedCount m_nRelativeContextDepth; 119 bool m_documentDisposed; 120 }; 121 122 //------------------------------------------------------------------------------------------------------------------ 123 void SAL_CALL UndoManagerContextListener::undoActionAdded( const UndoManagerEvent& i_event ) throw (RuntimeException) 124 { 125 (void)i_event; 126 // not interested in 127 } 128 129 //------------------------------------------------------------------------------------------------------------------ 130 void SAL_CALL UndoManagerContextListener::actionUndone( const UndoManagerEvent& i_event ) throw (RuntimeException) 131 { 132 (void)i_event; 133 // not interested in 134 } 135 136 //------------------------------------------------------------------------------------------------------------------ 137 void SAL_CALL UndoManagerContextListener::actionRedone( const UndoManagerEvent& i_event ) throw (RuntimeException) 138 { 139 (void)i_event; 140 // not interested in 141 } 142 143 //------------------------------------------------------------------------------------------------------------------ 144 void SAL_CALL UndoManagerContextListener::allActionsCleared( const EventObject& i_event ) throw (RuntimeException) 145 { 146 (void)i_event; 147 // not interested in 148 } 149 150 //------------------------------------------------------------------------------------------------------------------ 151 void SAL_CALL UndoManagerContextListener::redoActionsCleared( const EventObject& i_event ) throw (RuntimeException) 152 { 153 (void)i_event; 154 // not interested in 155 } 156 157 //------------------------------------------------------------------------------------------------------------------ 158 void SAL_CALL UndoManagerContextListener::resetAll( const EventObject& i_event ) throw (RuntimeException) 159 { 160 (void)i_event; 161 m_nRelativeContextDepth = 0; 162 } 163 164 //------------------------------------------------------------------------------------------------------------------ 165 void SAL_CALL UndoManagerContextListener::enteredContext( const UndoManagerEvent& i_event ) throw (RuntimeException) 166 { 167 (void)i_event; 168 osl_incrementInterlockedCount( &m_nRelativeContextDepth ); 169 } 170 171 //------------------------------------------------------------------------------------------------------------------ 172 void SAL_CALL UndoManagerContextListener::enteredHiddenContext( const UndoManagerEvent& i_event ) throw (RuntimeException) 173 { 174 (void)i_event; 175 osl_incrementInterlockedCount( &m_nRelativeContextDepth ); 176 } 177 178 //------------------------------------------------------------------------------------------------------------------ 179 void SAL_CALL UndoManagerContextListener::leftContext( const UndoManagerEvent& i_event ) throw (RuntimeException) 180 { 181 (void)i_event; 182 osl_decrementInterlockedCount( &m_nRelativeContextDepth ); 183 } 184 185 //------------------------------------------------------------------------------------------------------------------ 186 void SAL_CALL UndoManagerContextListener::leftHiddenContext( const UndoManagerEvent& i_event ) throw (RuntimeException) 187 { 188 (void)i_event; 189 osl_decrementInterlockedCount( &m_nRelativeContextDepth ); 190 } 191 192 //------------------------------------------------------------------------------------------------------------------ 193 void SAL_CALL UndoManagerContextListener::cancelledContext( const UndoManagerEvent& i_event ) throw (RuntimeException) 194 { 195 (void)i_event; 196 osl_decrementInterlockedCount( &m_nRelativeContextDepth ); 197 } 198 199 //------------------------------------------------------------------------------------------------------------------ 200 void SAL_CALL UndoManagerContextListener::disposing( const EventObject& i_event ) throw (RuntimeException) 201 { 202 (void)i_event; 203 m_documentDisposed = true; 204 } 205 206 //================================================================================================================== 207 //= DocumentUndoGuard_Data 208 //================================================================================================================== 209 struct DocumentUndoGuard_Data 210 { 211 Reference< XUndoManager > xUndoManager; 212 ::rtl::Reference< UndoManagerContextListener > pContextListener; 213 }; 214 215 namespace 216 { 217 //-------------------------------------------------------------------------------------------------------------- 218 void lcl_init( DocumentUndoGuard_Data& i_data, const Reference< XInterface >& i_undoSupplierComponent ) 219 { 220 try 221 { 222 Reference< XUndoManagerSupplier > xUndoSupplier( i_undoSupplierComponent, UNO_QUERY ); 223 if ( xUndoSupplier.is() ) 224 i_data.xUndoManager.set( xUndoSupplier->getUndoManager(), UNO_QUERY_THROW ); 225 226 if ( i_data.xUndoManager.is() ) 227 i_data.pContextListener.set( new UndoManagerContextListener( i_data.xUndoManager ) ); 228 } 229 catch( const Exception& ) 230 { 231 DBG_UNHANDLED_EXCEPTION(); 232 } 233 } 234 235 //-------------------------------------------------------------------------------------------------------------- 236 void lcl_restore( DocumentUndoGuard_Data& i_data ) 237 { 238 try 239 { 240 if ( i_data.pContextListener.is() ) 241 i_data.pContextListener->finish(); 242 i_data.pContextListener.clear(); 243 } 244 catch( const Exception& ) 245 { 246 DBG_UNHANDLED_EXCEPTION(); 247 } 248 } 249 } 250 251 //================================================================================================================== 252 //= DocumentUndoGuard 253 //================================================================================================================== 254 //------------------------------------------------------------------------------------------------------------------ 255 DocumentUndoGuard::DocumentUndoGuard( const Reference< XInterface >& i_undoSupplierComponent ) 256 :m_pData( new DocumentUndoGuard_Data ) 257 { 258 lcl_init( *m_pData, i_undoSupplierComponent ); 259 } 260 261 DocumentUndoGuard::~DocumentUndoGuard() 262 { 263 lcl_restore( *m_pData ); 264 } 265 266 //...................................................................................................................... 267 } // namespace framework 268 //...................................................................................................................... 269