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