1 /************************************************************************* 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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sd.hxx" 30 31 #include "UpdateLockManager.hxx" 32 33 #include "MutexOwner.hxx" 34 #include "ViewShellBase.hxx" 35 #include <com/sun/star/frame/XLayoutManager.hpp> 36 #include <com/sun/star/frame/XLayoutManagerEventBroadcaster.hpp> 37 #include <com/sun/star/frame/LayoutManagerEvents.hpp> 38 #include <com/sun/star/beans/XPropertySet.hpp> 39 #include <cppuhelper/compbase1.hxx> 40 41 #include <vcl/timer.hxx> 42 #include <sfx2/viewfrm.hxx> 43 44 using namespace ::com::sun::star::uno; 45 using namespace ::com::sun::star; 46 47 namespace { 48 typedef cppu::WeakComponentImplHelper1<frame::XLayoutManagerListener> InterfaceBase; 49 } 50 51 namespace sd { 52 53 54 /** This implementation class not only implements the Lock() and Unlock() 55 methods but as well listens for the right combination of events to call 56 Unlock() when all is ready after the PaneManager has switched (some of) 57 its view shells. 58 */ 59 60 class UpdateLockManager::Implementation 61 : protected MutexOwner, 62 public InterfaceBase 63 { 64 public: 65 Implementation (ViewShellBase& rBase); 66 virtual ~Implementation (void); 67 68 void Lock (void); 69 void Unlock (void); 70 bool IsLocked (void) const; 71 72 /** Unlock regardless of the current lock level. 73 */ 74 void ForceUnlock (void); 75 76 private: 77 ViewShellBase& mrBase; 78 /// A lock level greater than 0 indicates that the ViewShellBase is locked. 79 sal_Int32 mnLockDepth; 80 /// The emergency timer to unlock the ViewShellBase when all else fails. 81 Timer maTimer; 82 /// Remember when to unlock after a layout event from frame::XLayoutManager 83 bool mbUnlockOnNextLayout; 84 /// Remember whether we are listening to the frame::XLayoutManager 85 bool mbListenerIsRegistered; 86 /// Remember whether the frame::XLayoutManager is locked. 87 bool mbLayouterIsLocked; 88 /** We hold a weak reference to the layout manager in order to have 89 access to it even when the ViewShellBase object is not valid anymore 90 and can not be used to obtain the layout manager. 91 */ 92 WeakReference<frame::XLayoutManager> mxLayoutManager; 93 94 //===== frame::XLayoutEventListener ===================================== 95 96 /** The event of the layouter are observed to find the best moment for 97 unlocking. This is the first layout after the lock level of the 98 layouter drops to one (we hold a lock to it ourselves which we 99 release when unlocking). 100 */ 101 virtual void SAL_CALL layoutEvent ( 102 const lang::EventObject& xSource, 103 sal_Int16 eLayoutEvent, 104 const Any& rInfo) 105 throw (uno::RuntimeException); 106 107 //===== lang::XEventListener ============================================ 108 virtual void SAL_CALL 109 disposing (const lang::EventObject& rEventObject) 110 throw (::com::sun::star::uno::RuntimeException); 111 112 virtual void SAL_CALL disposing (void); 113 114 /** This is only a fallback to make the office usable when for some 115 reason the intended way of unlocking it failed. 116 */ 117 DECL_LINK(Timeout, void*); 118 119 /** Convenience method that finds the layout manager associated with the 120 frame that shows the ViewShellBase. 121 */ 122 Reference<frame::XLayoutManager> GetLayoutManager (void); 123 124 Implementation (const Implementation&); // Not implemented. 125 Implementation& operator= (const Implementation&); // Not implemented. 126 }; 127 128 129 130 131 //===== UpdateLockManager ===================================================== 132 133 UpdateLockManager::UpdateLockManager (ViewShellBase& rBase) 134 : mpImpl(new Implementation(rBase)) 135 { 136 mpImpl->acquire(); 137 } 138 139 140 141 UpdateLockManager::~UpdateLockManager (void) 142 { 143 if (mpImpl != NULL) 144 { 145 mpImpl->ForceUnlock(); 146 mpImpl->release(); 147 } 148 } 149 150 151 152 153 void UpdateLockManager::Disable (void) 154 { 155 if (mpImpl != NULL) 156 { 157 mpImpl->ForceUnlock(); 158 mpImpl->release(); 159 mpImpl = NULL; 160 } 161 } 162 163 164 165 166 void UpdateLockManager::Lock (void) 167 { 168 if (mpImpl != NULL) 169 mpImpl->Lock(); 170 } 171 172 173 174 175 void UpdateLockManager::Unlock (void) 176 { 177 if (mpImpl != NULL) 178 mpImpl->Unlock(); 179 } 180 181 182 183 184 bool UpdateLockManager::IsLocked (void) const 185 { 186 if (mpImpl != NULL) 187 return mpImpl->IsLocked(); 188 else 189 return false; 190 } 191 192 193 194 //===== UpdateLock::Implementation ============================================ 195 196 UpdateLockManager::Implementation::Implementation (ViewShellBase& rBase) 197 : InterfaceBase(maMutex), 198 mrBase(rBase), 199 mnLockDepth(0), 200 maTimer(), 201 mbUnlockOnNextLayout(false), 202 mbListenerIsRegistered(false), 203 mbLayouterIsLocked(false) 204 { 205 } 206 207 208 209 210 UpdateLockManager::Implementation::~Implementation (void) 211 { 212 OSL_ASSERT(mnLockDepth==0); 213 ForceUnlock(); 214 } 215 216 217 218 219 void UpdateLockManager::Implementation::Lock (void) 220 { 221 ++mnLockDepth; 222 if (mnLockDepth == 1) 223 { 224 Reference<frame::XLayoutManager> xLayouter (GetLayoutManager()); 225 if (xLayouter.is()) 226 { 227 // Register as event listener. 228 Reference<frame::XLayoutManagerEventBroadcaster> xBroadcaster ( 229 xLayouter, UNO_QUERY); 230 if (xBroadcaster.is()) 231 { 232 mbListenerIsRegistered = true; 233 xBroadcaster->addLayoutManagerEventListener( 234 Reference<frame::XLayoutManagerListener> ( 235 static_cast<XWeak*>(this), UNO_QUERY) ); 236 } 237 238 // Lock the layout manager. 239 mbLayouterIsLocked = true; 240 xLayouter->lock(); 241 } 242 243 // As a fallback, when the notification mechanism does not work (or is 244 // incorrectly used) we use a timer that will unlock us eventually. 245 maTimer.SetTimeout(5000 /*ms*/); 246 maTimer.SetTimeoutHdl(LINK(this,UpdateLockManager::Implementation,Timeout)); 247 maTimer.Start(); 248 } 249 } 250 251 252 253 254 void UpdateLockManager::Implementation::Unlock (void) 255 { 256 --mnLockDepth; 257 258 if (mnLockDepth == 0) 259 { 260 // Stop the timer. We don't need it anymore. 261 maTimer.Stop(); 262 263 try 264 { 265 Reference<frame::XLayoutManager> xLayouter (GetLayoutManager()); 266 if (xLayouter.is()) 267 { 268 // Detach from the layouter. 269 if (mbListenerIsRegistered) 270 { 271 Reference<frame::XLayoutManagerEventBroadcaster> xBroadcaster ( 272 xLayouter, UNO_QUERY); 273 if (xBroadcaster.is()) 274 { 275 mbListenerIsRegistered = false; 276 xBroadcaster->removeLayoutManagerEventListener( 277 Reference<frame::XLayoutManagerListener> ( 278 static_cast<XWeak*>(this), UNO_QUERY) ); 279 } 280 } 281 282 // Unlock the layouter. 283 if (mbLayouterIsLocked) 284 { 285 mbLayouterIsLocked = false; 286 xLayouter->unlock(); 287 } 288 } 289 } 290 catch (RuntimeException) 291 { } 292 293 // Force a rearrangement of the UI elements of the views. 294 mrBase.Rearrange(); 295 } 296 } 297 298 299 300 301 bool UpdateLockManager::Implementation::IsLocked (void) const 302 { 303 return (mnLockDepth > 0); 304 } 305 306 307 308 309 void UpdateLockManager::Implementation::ForceUnlock (void) 310 { 311 while (IsLocked()) 312 Unlock(); 313 } 314 315 316 317 318 void SAL_CALL UpdateLockManager::Implementation::layoutEvent ( 319 const lang::EventObject&, 320 sal_Int16 eLayoutEvent, 321 const Any& rInfo) 322 throw (uno::RuntimeException) 323 { 324 switch (eLayoutEvent) 325 { 326 case frame::LayoutManagerEvents::LOCK: 327 { 328 sal_Int32 nLockCount; 329 rInfo >>= nLockCount; 330 } 331 break; 332 333 case frame::LayoutManagerEvents::UNLOCK: 334 { 335 sal_Int32 nLockCount = 0; 336 rInfo >>= nLockCount; 337 if (nLockCount == 1) 338 { 339 // The lock count dropped to one. This means that we are 340 // the only one that still holds a lock to the layout 341 // manager. We unlock the layout manager now and the 342 // ViewShellBase on the next layout of the layout manager. 343 mbUnlockOnNextLayout = true; 344 Reference<frame::XLayoutManager> xLayouter (GetLayoutManager()); 345 if (xLayouter.is() && mbLayouterIsLocked) 346 { 347 mbLayouterIsLocked = false; 348 xLayouter->unlock(); 349 } 350 } 351 } 352 break; 353 354 case frame::LayoutManagerEvents::LAYOUT: 355 // Unlock when the layout manager is not still locked. 356 if (mbUnlockOnNextLayout) 357 Unlock(); 358 break; 359 } 360 } 361 362 363 364 365 void SAL_CALL UpdateLockManager::Implementation::disposing (const lang::EventObject& ) 366 throw (::com::sun::star::uno::RuntimeException) 367 { 368 } 369 370 371 372 373 void SAL_CALL UpdateLockManager::Implementation::disposing (void) 374 { 375 } 376 377 378 379 380 IMPL_LINK(UpdateLockManager::Implementation, Timeout, void*, EMPTYARG) 381 { 382 // This method is only called when all else failed. We unlock 383 // regardless of how deep the lock depth. 384 while (mnLockDepth > 0) 385 Unlock(); 386 return 1; 387 } 388 389 390 391 392 Reference< ::com::sun::star::frame::XLayoutManager> 393 UpdateLockManager::Implementation::GetLayoutManager (void) 394 { 395 Reference<frame::XLayoutManager> xLayoutManager; 396 397 if (mxLayoutManager.get() == NULL) 398 { 399 if (mrBase.GetViewFrame()!=NULL) 400 { 401 Reference<beans::XPropertySet> xFrameProperties ( 402 mrBase.GetViewFrame()->GetFrame().GetFrameInterface(), 403 UNO_QUERY); 404 if (xFrameProperties.is()) 405 { 406 try 407 { 408 Any aValue (xFrameProperties->getPropertyValue( 409 ::rtl::OUString::createFromAscii("LayoutManager"))); 410 aValue >>= xLayoutManager; 411 } 412 catch (const beans::UnknownPropertyException& rException) 413 { 414 (void)rException; 415 } 416 } 417 mxLayoutManager = xLayoutManager; 418 } 419 } 420 else 421 xLayoutManager = mxLayoutManager; 422 423 return xLayoutManager; 424 } 425 426 427 428 429 } // end of anonymous namespace 430