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