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
UpdateLockManager(ViewShellBase & rBase)129cdf0e10cSrcweir UpdateLockManager::UpdateLockManager (ViewShellBase& rBase)
130cdf0e10cSrcweir : mpImpl(new Implementation(rBase))
131cdf0e10cSrcweir {
132cdf0e10cSrcweir mpImpl->acquire();
133cdf0e10cSrcweir }
134cdf0e10cSrcweir
135cdf0e10cSrcweir
136cdf0e10cSrcweir
~UpdateLockManager(void)137cdf0e10cSrcweir UpdateLockManager::~UpdateLockManager (void)
138cdf0e10cSrcweir {
139cdf0e10cSrcweir if (mpImpl != NULL)
140cdf0e10cSrcweir {
141cdf0e10cSrcweir mpImpl->ForceUnlock();
142cdf0e10cSrcweir mpImpl->release();
143cdf0e10cSrcweir }
144cdf0e10cSrcweir }
145cdf0e10cSrcweir
146cdf0e10cSrcweir
147cdf0e10cSrcweir
148cdf0e10cSrcweir
Disable(void)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
Lock(void)162cdf0e10cSrcweir void UpdateLockManager::Lock (void)
163cdf0e10cSrcweir {
164cdf0e10cSrcweir if (mpImpl != NULL)
165cdf0e10cSrcweir mpImpl->Lock();
166cdf0e10cSrcweir }
167cdf0e10cSrcweir
168cdf0e10cSrcweir
169cdf0e10cSrcweir
170cdf0e10cSrcweir
Unlock(void)171cdf0e10cSrcweir void UpdateLockManager::Unlock (void)
172cdf0e10cSrcweir {
173cdf0e10cSrcweir if (mpImpl != NULL)
174cdf0e10cSrcweir mpImpl->Unlock();
175cdf0e10cSrcweir }
176cdf0e10cSrcweir
177cdf0e10cSrcweir
178cdf0e10cSrcweir
179cdf0e10cSrcweir
IsLocked(void) const180cdf0e10cSrcweir 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
Implementation(ViewShellBase & rBase)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
~Implementation(void)206cdf0e10cSrcweir UpdateLockManager::Implementation::~Implementation (void)
207cdf0e10cSrcweir {
208cdf0e10cSrcweir OSL_ASSERT(mnLockDepth==0);
209cdf0e10cSrcweir ForceUnlock();
210cdf0e10cSrcweir }
211cdf0e10cSrcweir
212cdf0e10cSrcweir
213cdf0e10cSrcweir
214cdf0e10cSrcweir
Lock(void)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
Unlock(void)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
IsLocked(void) const297cdf0e10cSrcweir bool UpdateLockManager::Implementation::IsLocked (void) const
298cdf0e10cSrcweir {
299cdf0e10cSrcweir return (mnLockDepth > 0);
300cdf0e10cSrcweir }
301cdf0e10cSrcweir
302cdf0e10cSrcweir
303cdf0e10cSrcweir
304cdf0e10cSrcweir
ForceUnlock(void)305cdf0e10cSrcweir void UpdateLockManager::Implementation::ForceUnlock (void)
306cdf0e10cSrcweir {
307cdf0e10cSrcweir while (IsLocked())
308cdf0e10cSrcweir Unlock();
309cdf0e10cSrcweir }
310cdf0e10cSrcweir
311cdf0e10cSrcweir
312cdf0e10cSrcweir
313cdf0e10cSrcweir
layoutEvent(const lang::EventObject &,sal_Int16 eLayoutEvent,const Any & rInfo)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
disposing(const lang::EventObject &)361cdf0e10cSrcweir void SAL_CALL UpdateLockManager::Implementation::disposing (const lang::EventObject& )
362cdf0e10cSrcweir throw (::com::sun::star::uno::RuntimeException)
363cdf0e10cSrcweir {
364cdf0e10cSrcweir }
365cdf0e10cSrcweir
366cdf0e10cSrcweir
367cdf0e10cSrcweir
368cdf0e10cSrcweir
disposing(void)369cdf0e10cSrcweir void SAL_CALL UpdateLockManager::Implementation::disposing (void)
370cdf0e10cSrcweir {
371cdf0e10cSrcweir }
372cdf0e10cSrcweir
373cdf0e10cSrcweir
374cdf0e10cSrcweir
375cdf0e10cSrcweir
IMPL_LINK(UpdateLockManager::Implementation,Timeout,void *,EMPTYARG)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>
GetLayoutManager(void)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