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