| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sd.hxx" |
| |
| #include "UpdateLockManager.hxx" |
| |
| #include "MutexOwner.hxx" |
| #include "ViewShellBase.hxx" |
| #include <com/sun/star/frame/XLayoutManager.hpp> |
| #include <com/sun/star/frame/XLayoutManagerEventBroadcaster.hpp> |
| #include <com/sun/star/frame/LayoutManagerEvents.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <cppuhelper/compbase1.hxx> |
| |
| #include <vcl/timer.hxx> |
| #include <sfx2/viewfrm.hxx> |
| |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star; |
| |
| namespace { |
| typedef cppu::WeakComponentImplHelper1<frame::XLayoutManagerListener> InterfaceBase; |
| } |
| |
| namespace sd { |
| |
| |
| /** This implementation class not only implements the Lock() and Unlock() |
| methods but as well listens for the right combination of events to call |
| Unlock() when all is ready after the PaneManager has switched (some of) |
| its view shells. |
| */ |
| |
| class UpdateLockManager::Implementation |
| : protected MutexOwner, |
| public InterfaceBase |
| { |
| public: |
| Implementation (ViewShellBase& rBase); |
| virtual ~Implementation (void); |
| |
| void Lock (void); |
| void Unlock (void); |
| bool IsLocked (void) const; |
| |
| /** Unlock regardless of the current lock level. |
| */ |
| void ForceUnlock (void); |
| |
| private: |
| ViewShellBase& mrBase; |
| /// A lock level greater than 0 indicates that the ViewShellBase is locked. |
| sal_Int32 mnLockDepth; |
| /// The emergency timer to unlock the ViewShellBase when all else fails. |
| Timer maTimer; |
| /// Remember when to unlock after a layout event from frame::XLayoutManager |
| bool mbUnlockOnNextLayout; |
| /// Remember whether we are listening to the frame::XLayoutManager |
| bool mbListenerIsRegistered; |
| /// Remember whether the frame::XLayoutManager is locked. |
| bool mbLayouterIsLocked; |
| /** We hold a weak reference to the layout manager in order to have |
| access to it even when the ViewShellBase object is not valid anymore |
| and can not be used to obtain the layout manager. |
| */ |
| WeakReference<frame::XLayoutManager> mxLayoutManager; |
| |
| //===== frame::XLayoutEventListener ===================================== |
| |
| /** The event of the layouter are observed to find the best moment for |
| unlocking. This is the first layout after the lock level of the |
| layouter drops to one (we hold a lock to it ourselves which we |
| release when unlocking). |
| */ |
| virtual void SAL_CALL layoutEvent ( |
| const lang::EventObject& xSource, |
| sal_Int16 eLayoutEvent, |
| const Any& rInfo) |
| throw (uno::RuntimeException); |
| |
| //===== lang::XEventListener ============================================ |
| virtual void SAL_CALL |
| disposing (const lang::EventObject& rEventObject) |
| throw (::com::sun::star::uno::RuntimeException); |
| |
| virtual void SAL_CALL disposing (void); |
| |
| /** This is only a fallback to make the office usable when for some |
| reason the intended way of unlocking it failed. |
| */ |
| DECL_LINK(Timeout, void*); |
| |
| /** Convenience method that finds the layout manager associated with the |
| frame that shows the ViewShellBase. |
| */ |
| Reference<frame::XLayoutManager> GetLayoutManager (void); |
| |
| Implementation (const Implementation&); // Not implemented. |
| Implementation& operator= (const Implementation&); // Not implemented. |
| }; |
| |
| |
| |
| |
| //===== UpdateLockManager ===================================================== |
| |
| UpdateLockManager::UpdateLockManager (ViewShellBase& rBase) |
| : mpImpl(new Implementation(rBase)) |
| { |
| mpImpl->acquire(); |
| } |
| |
| |
| |
| UpdateLockManager::~UpdateLockManager (void) |
| { |
| if (mpImpl != NULL) |
| { |
| mpImpl->ForceUnlock(); |
| mpImpl->release(); |
| } |
| } |
| |
| |
| |
| |
| void UpdateLockManager::Disable (void) |
| { |
| if (mpImpl != NULL) |
| { |
| mpImpl->ForceUnlock(); |
| mpImpl->release(); |
| mpImpl = NULL; |
| } |
| } |
| |
| |
| |
| |
| void UpdateLockManager::Lock (void) |
| { |
| if (mpImpl != NULL) |
| mpImpl->Lock(); |
| } |
| |
| |
| |
| |
| void UpdateLockManager::Unlock (void) |
| { |
| if (mpImpl != NULL) |
| mpImpl->Unlock(); |
| } |
| |
| |
| |
| |
| bool UpdateLockManager::IsLocked (void) const |
| { |
| if (mpImpl != NULL) |
| return mpImpl->IsLocked(); |
| else |
| return false; |
| } |
| |
| |
| |
| //===== UpdateLock::Implementation ============================================ |
| |
| UpdateLockManager::Implementation::Implementation (ViewShellBase& rBase) |
| : InterfaceBase(maMutex), |
| mrBase(rBase), |
| mnLockDepth(0), |
| maTimer(), |
| mbUnlockOnNextLayout(false), |
| mbListenerIsRegistered(false), |
| mbLayouterIsLocked(false) |
| { |
| } |
| |
| |
| |
| |
| UpdateLockManager::Implementation::~Implementation (void) |
| { |
| OSL_ASSERT(mnLockDepth==0); |
| ForceUnlock(); |
| } |
| |
| |
| |
| |
| void UpdateLockManager::Implementation::Lock (void) |
| { |
| ++mnLockDepth; |
| if (mnLockDepth == 1) |
| { |
| Reference<frame::XLayoutManager> xLayouter (GetLayoutManager()); |
| if (xLayouter.is()) |
| { |
| // Register as event listener. |
| Reference<frame::XLayoutManagerEventBroadcaster> xBroadcaster ( |
| xLayouter, UNO_QUERY); |
| if (xBroadcaster.is()) |
| { |
| mbListenerIsRegistered = true; |
| xBroadcaster->addLayoutManagerEventListener( |
| Reference<frame::XLayoutManagerListener> ( |
| static_cast<XWeak*>(this), UNO_QUERY) ); |
| } |
| |
| // Lock the layout manager. |
| mbLayouterIsLocked = true; |
| xLayouter->lock(); |
| } |
| |
| // As a fallback, when the notification mechanism does not work (or is |
| // incorrectly used) we use a timer that will unlock us eventually. |
| maTimer.SetTimeout(5000 /*ms*/); |
| maTimer.SetTimeoutHdl(LINK(this,UpdateLockManager::Implementation,Timeout)); |
| maTimer.Start(); |
| } |
| } |
| |
| |
| |
| |
| void UpdateLockManager::Implementation::Unlock (void) |
| { |
| --mnLockDepth; |
| |
| if (mnLockDepth == 0) |
| { |
| // Stop the timer. We don't need it anymore. |
| maTimer.Stop(); |
| |
| try |
| { |
| Reference<frame::XLayoutManager> xLayouter (GetLayoutManager()); |
| if (xLayouter.is()) |
| { |
| // Detach from the layouter. |
| if (mbListenerIsRegistered) |
| { |
| Reference<frame::XLayoutManagerEventBroadcaster> xBroadcaster ( |
| xLayouter, UNO_QUERY); |
| if (xBroadcaster.is()) |
| { |
| mbListenerIsRegistered = false; |
| xBroadcaster->removeLayoutManagerEventListener( |
| Reference<frame::XLayoutManagerListener> ( |
| static_cast<XWeak*>(this), UNO_QUERY) ); |
| } |
| } |
| |
| // Unlock the layouter. |
| if (mbLayouterIsLocked) |
| { |
| mbLayouterIsLocked = false; |
| xLayouter->unlock(); |
| } |
| } |
| } |
| catch (RuntimeException) |
| { } |
| |
| // Force a rearrangement of the UI elements of the views. |
| mrBase.Rearrange(); |
| } |
| } |
| |
| |
| |
| |
| bool UpdateLockManager::Implementation::IsLocked (void) const |
| { |
| return (mnLockDepth > 0); |
| } |
| |
| |
| |
| |
| void UpdateLockManager::Implementation::ForceUnlock (void) |
| { |
| while (IsLocked()) |
| Unlock(); |
| } |
| |
| |
| |
| |
| void SAL_CALL UpdateLockManager::Implementation::layoutEvent ( |
| const lang::EventObject&, |
| sal_Int16 eLayoutEvent, |
| const Any& rInfo) |
| throw (uno::RuntimeException) |
| { |
| switch (eLayoutEvent) |
| { |
| case frame::LayoutManagerEvents::LOCK: |
| { |
| sal_Int32 nLockCount; |
| rInfo >>= nLockCount; |
| } |
| break; |
| |
| case frame::LayoutManagerEvents::UNLOCK: |
| { |
| sal_Int32 nLockCount = 0; |
| rInfo >>= nLockCount; |
| if (nLockCount == 1) |
| { |
| // The lock count dropped to one. This means that we are |
| // the only one that still holds a lock to the layout |
| // manager. We unlock the layout manager now and the |
| // ViewShellBase on the next layout of the layout manager. |
| mbUnlockOnNextLayout = true; |
| Reference<frame::XLayoutManager> xLayouter (GetLayoutManager()); |
| if (xLayouter.is() && mbLayouterIsLocked) |
| { |
| mbLayouterIsLocked = false; |
| xLayouter->unlock(); |
| } |
| } |
| } |
| break; |
| |
| case frame::LayoutManagerEvents::LAYOUT: |
| // Unlock when the layout manager is not still locked. |
| if (mbUnlockOnNextLayout) |
| Unlock(); |
| break; |
| } |
| } |
| |
| |
| |
| |
| void SAL_CALL UpdateLockManager::Implementation::disposing (const lang::EventObject& ) |
| throw (::com::sun::star::uno::RuntimeException) |
| { |
| } |
| |
| |
| |
| |
| void SAL_CALL UpdateLockManager::Implementation::disposing (void) |
| { |
| } |
| |
| |
| |
| |
| IMPL_LINK(UpdateLockManager::Implementation, Timeout, void*, EMPTYARG) |
| { |
| // This method is only called when all else failed. We unlock |
| // regardless of how deep the lock depth. |
| while (mnLockDepth > 0) |
| Unlock(); |
| return 1; |
| } |
| |
| |
| |
| |
| Reference< ::com::sun::star::frame::XLayoutManager> |
| UpdateLockManager::Implementation::GetLayoutManager (void) |
| { |
| Reference<frame::XLayoutManager> xLayoutManager; |
| |
| if (mxLayoutManager.get() == NULL) |
| { |
| if (mrBase.GetViewFrame()!=NULL) |
| { |
| Reference<beans::XPropertySet> xFrameProperties ( |
| mrBase.GetViewFrame()->GetFrame().GetFrameInterface(), |
| UNO_QUERY); |
| if (xFrameProperties.is()) |
| { |
| try |
| { |
| Any aValue (xFrameProperties->getPropertyValue( |
| ::rtl::OUString::createFromAscii("LayoutManager"))); |
| aValue >>= xLayoutManager; |
| } |
| catch (const beans::UnknownPropertyException& rException) |
| { |
| (void)rException; |
| } |
| } |
| mxLayoutManager = xLayoutManager; |
| } |
| } |
| else |
| xLayoutManager = mxLayoutManager; |
| |
| return xLayoutManager; |
| } |
| |
| |
| |
| |
| } // end of anonymous namespace |