1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <helper/statusindicatorfactory.hxx>
23 #include <helper/statusindicator.hxx>
24 #include <helper/vclstatusindicator.hxx>
26 #include <properties.h>
28 #include <com/sun/star/awt/Rectangle.hpp>
30 #include <com/sun/star/awt/XControl.hpp>
31 #include <com/sun/star/awt/XLayoutConstrains.hpp>
32 #include <com/sun/star/awt/DeviceInfo.hpp>
33 #include <com/sun/star/awt/PosSize.hpp>
34 #include <com/sun/star/awt/WindowAttribute.hpp>
35 #include <com/sun/star/awt/XTopWindow.hpp>
36 #include <com/sun/star/awt/XWindow2.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/frame/XLayoutManager2.hpp>
40 #include <toolkit/helper/vclunohelper.hxx>
42 #include <comphelper/sequenceashashmap.hxx>
43 #include <unotools/mediadescriptor.hxx>
44 #include <vcl/svapp.hxx>
45 #include <osl/mutex.hxx>
46 #include <rtl/ref.hxx>
48 #include <officecfg/Office/Common.hxx>
52 sal_Int32
StatusIndicatorFactory::m_nInReschedule
= 0; ///< static counter for rescheduling
53 struct RescheduleLock
: public rtl::Static
<osl::Mutex
, RescheduleLock
> {}; ///< mutex to guard the m_nInReschedule
55 const char PROGRESS_RESOURCE
[] = "private:resource/progressbar/progressbar";
57 StatusIndicatorFactory::StatusIndicatorFactory(const css::uno::Reference
< css::uno::XComponentContext
>& xContext
)
58 : m_xContext (xContext
)
59 , m_bAllowReschedule (false)
60 , m_bAllowParentShow (false)
61 , m_bDisableReschedule(false)
65 StatusIndicatorFactory::~StatusIndicatorFactory()
67 impl_stopWakeUpThread();
70 void SAL_CALL
StatusIndicatorFactory::initialize(const css::uno::Sequence
< css::uno::Any
>& lArguments
)
72 if (lArguments
.hasElements()) {
73 osl::MutexGuard
g(m_mutex
);
75 css::uno::Reference
< css::frame::XFrame
> xTmpFrame
;
76 css::uno::Reference
< css::awt::XWindow
> xTmpWindow
;
77 bool b1
= lArguments
[0] >>= xTmpFrame
;
78 bool b2
= lArguments
[0] >>= xTmpWindow
;
79 if (lArguments
.getLength() == 3 && b1
) {
80 // it's the first service constructor "createWithFrame"
82 lArguments
[1] >>= m_bDisableReschedule
;
83 lArguments
[2] >>= m_bAllowParentShow
;
84 } else if (lArguments
.getLength() == 3 && b2
) {
85 // it's the second service constructor "createWithWindow"
86 m_xPluggWindow
= xTmpWindow
;
87 lArguments
[1] >>= m_bDisableReschedule
;
88 lArguments
[2] >>= m_bAllowParentShow
;
90 // it's an old-style initialisation using properties
91 ::comphelper::SequenceAsHashMap
lArgs(lArguments
);
93 m_xFrame
= lArgs
.getUnpackedValueOrDefault("Frame" , css::uno::Reference
< css::frame::XFrame
>());
94 m_xPluggWindow
= lArgs
.getUnpackedValueOrDefault("Window" , css::uno::Reference
< css::awt::XWindow
>() );
95 m_bAllowParentShow
= lArgs
.getUnpackedValueOrDefault("AllowParentShow" , false );
96 m_bDisableReschedule
= lArgs
.getUnpackedValueOrDefault("DisableReschedule", false );
100 impl_createProgress();
103 css::uno::Reference
< css::task::XStatusIndicator
> SAL_CALL
StatusIndicatorFactory::createStatusIndicator()
105 StatusIndicator
* pIndicator
= new StatusIndicator(this);
106 css::uno::Reference
< css::task::XStatusIndicator
> xIndicator(static_cast< ::cppu::OWeakObject
* >(pIndicator
), css::uno::UNO_QUERY_THROW
);
111 void SAL_CALL
StatusIndicatorFactory::update()
113 osl::MutexGuard
g(m_mutex
);
114 m_bAllowReschedule
= true;
117 void StatusIndicatorFactory::start(const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
,
118 const OUString
& sText
,
121 // SAFE -> ----------------------------------
122 osl::ClearableMutexGuard
aWriteLock(m_mutex
);
124 // create new info structure for this child or move it to the front of our stack
125 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
126 if (pItem
!= m_aStack
.end())
127 m_aStack
.erase(pItem
);
128 IndicatorInfo
aInfo(xChild
, sText
);
129 m_aStack
.push_back (aInfo
);
131 m_xActiveChild
= xChild
;
132 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
135 // <- SAFE ----------------------------------
137 implts_makeParentVisibleIfAllowed();
140 xProgress
->start(sText
, nRange
);
142 impl_startWakeUpThread();
143 impl_reschedule(true);
146 void StatusIndicatorFactory::reset(const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
)
148 // SAFE -> ----------------------------------
149 osl::ClearableMutexGuard
aReadLock(m_mutex
);
151 // reset the internal info structure related to this child
152 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
153 if (pItem
!= m_aStack
.end())
156 pItem
->m_sText
.clear();
159 css::uno::Reference
< css::task::XStatusIndicator
> xActive
= m_xActiveChild
;
160 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
163 // <- SAFE ----------------------------------
165 // not the top most child => don't change UI
166 // But don't forget Reschedule!
168 (xChild
== xActive
) &&
173 impl_reschedule(true);
176 void StatusIndicatorFactory::end(const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
)
178 // SAFE -> ----------------------------------
179 osl::ClearableMutexGuard
aWriteLock(m_mutex
);
181 // remove this child from our stack
182 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
183 if (pItem
!= m_aStack
.end())
184 m_aStack
.erase(pItem
);
186 // activate next child ... or finish the progress if there is no further one.
187 m_xActiveChild
.clear();
189 sal_Int32 nValue
= 0;
190 IndicatorStack::reverse_iterator pNext
= m_aStack
.rbegin();
191 if (pNext
!= m_aStack
.rend())
193 m_xActiveChild
= pNext
->m_xIndicator
;
194 sText
= pNext
->m_sText
;
195 nValue
= pNext
->m_nValue
;
198 css::uno::Reference
< css::task::XStatusIndicator
> xActive
= m_xActiveChild
;
199 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
202 // <- SAFE ----------------------------------
206 // There is at least one further child indicator.
207 // Actualize our progress, so it shows these values from now.
210 xProgress
->setText (sText
);
211 xProgress
->setValue(nValue
);
216 // Our stack is empty. No further child exists.
217 // Se we must "end" our progress really
220 // Now hide the progress bar again.
223 impl_stopWakeUpThread();
226 impl_reschedule(true);
229 void StatusIndicatorFactory::setText(const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
,
230 const OUString
& sText
)
232 // SAFE -> ----------------------------------
233 osl::ClearableMutexGuard
aWriteLock(m_mutex
);
235 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
236 if (pItem
!= m_aStack
.end())
237 pItem
->m_sText
= sText
;
239 css::uno::Reference
< css::task::XStatusIndicator
> xActive
= m_xActiveChild
;
240 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
243 // SAFE -> ----------------------------------
245 // paint only the top most indicator
246 // but don't forget to Reschedule!
248 (xChild
== xActive
) &&
252 xProgress
->setText(sText
);
255 impl_reschedule(true);
258 void StatusIndicatorFactory::setValue( const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
,
261 // SAFE -> ----------------------------------
262 osl::ClearableMutexGuard
aWriteLock(m_mutex
);
264 sal_Int32 nOldValue
= 0;
265 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
266 if (pItem
!= m_aStack
.end())
268 nOldValue
= pItem
->m_nValue
;
269 pItem
->m_nValue
= nValue
;
272 css::uno::Reference
< css::task::XStatusIndicator
> xActive
= m_xActiveChild
;
273 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
276 // SAFE -> ----------------------------------
279 (xChild
== xActive
) &&
280 (nOldValue
!= nValue
) &&
284 xProgress
->setValue(nValue
);
287 impl_reschedule(false);
290 void StatusIndicatorFactory::implts_makeParentVisibleIfAllowed()
292 // SAFE -> ----------------------------------
293 osl::ClearableMutexGuard
aReadLock(m_mutex
);
295 if (!m_bAllowParentShow
)
298 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xFrame
.get() , css::uno::UNO_QUERY
);
299 css::uno::Reference
< css::awt::XWindow
> xPluggWindow(m_xPluggWindow
.get(), css::uno::UNO_QUERY
);
300 css::uno::Reference
< css::uno::XComponentContext
> xContext( m_xContext
);
303 // <- SAFE ----------------------------------
305 css::uno::Reference
< css::awt::XWindow
> xParentWindow
;
307 xParentWindow
= xFrame
->getContainerWindow();
309 xParentWindow
= xPluggWindow
;
311 // don't disturb user in case he put the loading document into the background!
312 // Suppress any setVisible() or toFront() call in case the initial show was
314 css::uno::Reference
< css::awt::XWindow2
> xVisibleCheck(xParentWindow
, css::uno::UNO_QUERY
);
315 bool bIsVisible
= false;
316 if (xVisibleCheck
.is())
317 bIsVisible
= xVisibleCheck
->isVisible();
325 // Check if the layout manager has been set to invisible state. It this case we are also
326 // not allowed to set the frame visible!
327 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
330 css::uno::Reference
< css::frame::XLayoutManager2
> xLayoutManager
;
331 xPropSet
->getPropertyValue(FRAME_PROPNAME_ASCII_LAYOUTMANAGER
) >>= xLayoutManager
;
332 if (xLayoutManager
.is())
334 if ( !xLayoutManager
->isVisible() )
339 // Ok the window should be made visible... because it is not currently visible.
341 // We need a Hack for our applications: They get her progress from the frame directly
342 // on saving documents. Because there is no progress set on the MediaDescriptor.
343 // But that's wrong. In case the document was opened hidden, they should not use any progress .-(
344 // They only possible workaround: don't show the parent window here, if the document was opened hidden.
345 bool bHiddenDoc
= false;
348 css::uno::Reference
< css::frame::XController
> xController
;
349 css::uno::Reference
< css::frame::XModel
> xModel
;
350 xController
= xFrame
->getController();
351 if (xController
.is())
352 xModel
= xController
->getModel();
355 utl::MediaDescriptor
lDocArgs(xModel
->getArgs());
356 bHiddenDoc
= lDocArgs
.getUnpackedValueOrDefault(
357 utl::MediaDescriptor::PROP_HIDDEN(),
365 // OK: The document was not opened in hidden mode ...
366 // and the window isn't already visible.
367 // Show it and bring it to front.
368 // But before we have to be sure, that our internal used helper progress
372 SolarMutexGuard aSolarGuard
;
373 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow(xParentWindow
);
376 bool bForceFrontAndFocus(officecfg::Office::Common::View::NewDocumentHandling::ForceFocusAndToFront::get(xContext
));
377 pWindow
->Show(true, bForceFrontAndFocus
? ShowFlags::ForegroundTask
: ShowFlags::NONE
);
382 void StatusIndicatorFactory::impl_createProgress()
384 // SAFE -> ----------------------------------
385 osl::ClearableMutexGuard
aReadLock(m_mutex
);
387 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xFrame
.get() , css::uno::UNO_QUERY
);
388 css::uno::Reference
< css::awt::XWindow
> xWindow(m_xPluggWindow
.get(), css::uno::UNO_QUERY
);
391 // <- SAFE ----------------------------------
393 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
;
397 // use vcl based progress implementation in plugged mode
398 VCLStatusIndicator
* pVCLProgress
= new VCLStatusIndicator(xWindow
);
399 xProgress
.set(static_cast< css::task::XStatusIndicator
* >(pVCLProgress
), css::uno::UNO_QUERY
);
401 else if (xFrame
.is())
403 // use frame layouted progress implementation
404 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
407 css::uno::Reference
< css::frame::XLayoutManager2
> xLayoutManager
;
408 xPropSet
->getPropertyValue(FRAME_PROPNAME_ASCII_LAYOUTMANAGER
) >>= xLayoutManager
;
409 if (xLayoutManager
.is())
411 xLayoutManager
->lock();
412 OUString
sPROGRESS_RESOURCE(PROGRESS_RESOURCE
);
413 xLayoutManager
->createElement( sPROGRESS_RESOURCE
);
414 xLayoutManager
->hideElement( sPROGRESS_RESOURCE
);
416 css::uno::Reference
< css::ui::XUIElement
> xProgressBar
= xLayoutManager
->getElement(sPROGRESS_RESOURCE
);
417 if (xProgressBar
.is())
418 xProgress
.set(xProgressBar
->getRealInterface(), css::uno::UNO_QUERY
);
419 xLayoutManager
->unlock();
424 osl::MutexGuard
g(m_mutex
);
425 m_xProgress
= xProgress
;
428 void StatusIndicatorFactory::impl_showProgress()
430 // SAFE -> ----------------------------------
431 osl::ClearableMutexGuard
aReadLock(m_mutex
);
433 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xFrame
.get() , css::uno::UNO_QUERY
);
436 // <- SAFE ----------------------------------
438 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
;
442 // use frame layouted progress implementation
443 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
446 css::uno::Reference
< css::frame::XLayoutManager2
> xLayoutManager
;
447 xPropSet
->getPropertyValue(FRAME_PROPNAME_ASCII_LAYOUTMANAGER
) >>= xLayoutManager
;
448 if (xLayoutManager
.is())
450 // Be sure that we have always a progress. It can be that our frame
451 // was recycled and therefore the progress was destroyed!
452 // CreateElement does nothing if there is already a valid progress.
453 OUString
sPROGRESS_RESOURCE(PROGRESS_RESOURCE
);
454 xLayoutManager
->createElement( sPROGRESS_RESOURCE
);
455 xLayoutManager
->showElement( sPROGRESS_RESOURCE
);
457 css::uno::Reference
< css::ui::XUIElement
> xProgressBar
= xLayoutManager
->getElement(sPROGRESS_RESOURCE
);
458 if (xProgressBar
.is())
459 xProgress
.set(xProgressBar
->getRealInterface(), css::uno::UNO_QUERY
);
463 osl::MutexGuard
g(m_mutex
);
464 m_xProgress
= xProgress
;
468 void StatusIndicatorFactory::impl_hideProgress()
470 // SAFE -> ----------------------------------
471 osl::ClearableMutexGuard
aReadLock(m_mutex
);
473 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xFrame
.get() , css::uno::UNO_QUERY
);
476 // <- SAFE ----------------------------------
480 // use frame layouted progress implementation
481 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
484 css::uno::Reference
< css::frame::XLayoutManager2
> xLayoutManager
;
485 xPropSet
->getPropertyValue(FRAME_PROPNAME_ASCII_LAYOUTMANAGER
) >>= xLayoutManager
;
486 if (xLayoutManager
.is())
487 xLayoutManager
->hideElement( PROGRESS_RESOURCE
);
492 void StatusIndicatorFactory::impl_reschedule(bool bForce
)
496 osl::MutexGuard
aReadLock(m_mutex
);
497 if (m_bDisableReschedule
)
502 bool bReschedule
= bForce
;
505 osl::MutexGuard
g(m_mutex
);
506 bReschedule
= m_bAllowReschedule
;
507 m_bAllowReschedule
= false;
514 osl::ResettableMutexGuard
aRescheduleGuard(RescheduleLock::get());
516 if (m_nInReschedule
== 0)
519 aRescheduleGuard
.clear();
524 Application::Reschedule(true);
528 aRescheduleGuard
.reset();
533 void StatusIndicatorFactory::impl_startWakeUpThread()
535 osl::MutexGuard
g(m_mutex
);
537 if (m_bDisableReschedule
)
542 m_pWakeUp
= new WakeUpThread(this);
547 void StatusIndicatorFactory::impl_stopWakeUpThread()
549 rtl::Reference
<WakeUpThread
> wakeUp
;
551 osl::MutexGuard
g(m_mutex
);
552 std::swap(wakeUp
, m_pWakeUp
);
560 } // namespace framework
562 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
563 com_sun_star_comp_framework_StatusIndicatorFactory_get_implementation(
564 css::uno::XComponentContext
*context
,
565 css::uno::Sequence
<css::uno::Any
> const &)
567 return cppu::acquire(new framework::StatusIndicatorFactory(context
));
570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */