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 .
21 #include <helper/statusindicatorfactory.hxx>
22 #include <helper/statusindicator.hxx>
23 #include <helper/vclstatusindicator.hxx>
24 #include <threadhelp/writeguard.hxx>
25 #include <threadhelp/readguard.hxx>
27 #include <properties.h>
29 #include <com/sun/star/awt/Rectangle.hpp>
31 #include <com/sun/star/awt/XControl.hpp>
32 #include <com/sun/star/awt/XLayoutConstrains.hpp>
33 #include <com/sun/star/awt/DeviceInfo.hpp>
34 #include <com/sun/star/awt/PosSize.hpp>
35 #include <com/sun/star/awt/WindowAttribute.hpp>
36 #include <com/sun/star/awt/XTopWindow.hpp>
37 #include <com/sun/star/awt/XWindow2.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/frame/XLayoutManager.hpp>
41 #include <toolkit/unohlp.hxx>
43 #include <comphelper/sequenceashashmap.hxx>
44 #include <comphelper/mediadescriptor.hxx>
45 #include <comphelper/configurationhelper.hxx>
46 #include <vcl/svapp.hxx>
47 #include <osl/mutex.hxx>
53 sal_Int32
StatusIndicatorFactory::m_nInReschedule
= 0; /// static counter for rescheduling
54 const char PROGRESS_RESOURCE
[] = "private:resource/progressbar/progressbar";
56 //-----------------------------------------------
57 DEFINE_XINTERFACE_5(StatusIndicatorFactory
,
59 DIRECT_INTERFACE(css::lang::XTypeProvider
),
60 DIRECT_INTERFACE(css::lang::XServiceInfo
),
61 DIRECT_INTERFACE(css::lang::XInitialization
),
62 DIRECT_INTERFACE(css::task::XStatusIndicatorFactory
),
63 DIRECT_INTERFACE(css::util::XUpdatable
))
65 DEFINE_XTYPEPROVIDER_5(StatusIndicatorFactory
,
66 css::lang::XTypeProvider
,
67 css::lang::XServiceInfo
,
68 css::lang::XInitialization
,
69 css::task::XStatusIndicatorFactory
,
70 css::util::XUpdatable
)
72 DEFINE_XSERVICEINFO_MULTISERVICE(StatusIndicatorFactory
,
74 OUString("com.sun.star.task.StatusIndicatorFactory"),
75 OUString("com.sun.star.comp.framework.StatusIndicatorFactory"))
77 DEFINE_INIT_SERVICE(StatusIndicatorFactory
,
80 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
81 to create a new instance of this class by our own supported service factory.
82 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further information!
87 //-----------------------------------------------
88 StatusIndicatorFactory::StatusIndicatorFactory(const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xSMGR
)
90 , ::cppu::OWeakObject ( )
93 , m_bAllowReschedule (sal_False
)
94 , m_bAllowParentShow (sal_False
)
95 , m_bDisableReschedule(sal_False
)
99 //-----------------------------------------------
100 StatusIndicatorFactory::~StatusIndicatorFactory()
102 impl_stopWakeUpThread();
105 //-----------------------------------------------
106 void SAL_CALL
StatusIndicatorFactory::initialize(const css::uno::Sequence
< css::uno::Any
>& lArguments
)
107 throw(css::uno::Exception
,
108 css::uno::RuntimeException
)
110 if (lArguments
.getLength() > 0) {
111 // SAFE -> ----------------------------------
112 WriteGuard
aWriteLock(m_aLock
);
114 css::uno::Reference
< css::frame::XFrame
> xTmpFrame
;
115 css::uno::Reference
< css::awt::XWindow
> xTmpWindow
;
116 bool b1
= lArguments
[0] >>= xTmpFrame
;
117 bool b2
= lArguments
[0] >>= xTmpWindow
;
118 if (lArguments
.getLength() == 3 && b1
) {
119 // it's the first service constructor "createWithFrame"
120 m_xFrame
= xTmpFrame
;
121 lArguments
[1] >>= m_bDisableReschedule
;
122 lArguments
[2] >>= m_bAllowParentShow
;
123 } else if (lArguments
.getLength() == 3 && b2
) {
124 // it's the second service constructor "createWithWindow"
125 m_xPluggWindow
= xTmpWindow
;
126 lArguments
[1] >>= m_bDisableReschedule
;
127 lArguments
[2] >>= m_bAllowParentShow
;
129 // it's an old-style initialisation using properties
130 ::comphelper::SequenceAsHashMap
lArgs(lArguments
);
132 m_xFrame
= lArgs
.getUnpackedValueOrDefault("Frame" , css::uno::Reference
< css::frame::XFrame
>());
133 m_xPluggWindow
= lArgs
.getUnpackedValueOrDefault("Window" , css::uno::Reference
< css::awt::XWindow
>() );
134 m_bAllowParentShow
= lArgs
.getUnpackedValueOrDefault("AllowParentShow" , (sal_Bool
)sal_False
);
135 m_bDisableReschedule
= lArgs
.getUnpackedValueOrDefault("DisableReschedule", (sal_Bool
)sal_False
);
138 // <- SAFE ----------------------------------
142 impl_createProgress();
145 //-----------------------------------------------
146 css::uno::Reference
< css::task::XStatusIndicator
> SAL_CALL
StatusIndicatorFactory::createStatusIndicator()
147 throw(css::uno::RuntimeException
)
149 StatusIndicator
* pIndicator
= new StatusIndicator(this);
150 css::uno::Reference
< css::task::XStatusIndicator
> xIndicator(static_cast< ::cppu::OWeakObject
* >(pIndicator
), css::uno::UNO_QUERY_THROW
);
155 //-----------------------------------------------
156 void SAL_CALL
StatusIndicatorFactory::update()
157 throw(css::uno::RuntimeException
)
159 // SAFE -> ----------------------------------
160 WriteGuard
aWriteLock(m_aLock
);
161 m_bAllowReschedule
= sal_True
;
163 // <- SAFE ----------------------------------
166 //-----------------------------------------------
167 void StatusIndicatorFactory::start(const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
,
168 const OUString
& sText
,
171 // SAFE -> ----------------------------------
172 WriteGuard
aWriteLock(m_aLock
);
174 // create new info structure for this child or move it to the front of our stack
175 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
176 if (pItem
!= m_aStack
.end())
177 m_aStack
.erase(pItem
);
178 IndicatorInfo
aInfo(xChild
, sText
, nRange
);
179 m_aStack
.push_back (aInfo
);
181 m_xActiveChild
= xChild
;
182 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
185 // <- SAFE ----------------------------------
187 implts_makeParentVisibleIfAllowed();
190 xProgress
->start(sText
, nRange
);
192 impl_startWakeUpThread();
193 impl_reschedule(sal_True
);
196 //-----------------------------------------------
197 void StatusIndicatorFactory::reset(const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
)
199 // SAFE -> ----------------------------------
200 ReadGuard
aReadLock(m_aLock
);
202 // reset the internal info structure related to this child
203 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
204 if (pItem
!= m_aStack
.end())
207 pItem
->m_sText
= OUString();
210 css::uno::Reference
< css::task::XStatusIndicator
> xActive
= m_xActiveChild
;
211 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
214 // <- SAFE ----------------------------------
216 // not the top most child => dont change UI
217 // But dont forget Reschedule!
219 (xChild
== xActive
) &&
224 impl_reschedule(sal_True
);
227 //-----------------------------------------------
228 void StatusIndicatorFactory::end(const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
)
230 // SAFE -> ----------------------------------
231 WriteGuard
aWriteLock(m_aLock
);
233 // remove this child from our stack
234 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
235 if (pItem
!= m_aStack
.end())
236 m_aStack
.erase(pItem
);
238 // activate next child ... or finish the progress if there is no further one.
239 m_xActiveChild
.clear();
241 sal_Int32 nValue
= 0;
242 IndicatorStack::reverse_iterator pNext
= m_aStack
.rbegin();
243 if (pNext
!= m_aStack
.rend())
245 m_xActiveChild
= pNext
->m_xIndicator
;
246 sText
= pNext
->m_sText
;
247 nValue
= pNext
->m_nValue
;
250 css::uno::Reference
< css::task::XStatusIndicator
> xActive
= m_xActiveChild
;
251 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
254 // <- SAFE ----------------------------------
258 // There is at least one further child indicator.
259 // Actualize our progress, so it shows these values from now.
262 xProgress
->setText (sText
);
263 xProgress
->setValue(nValue
);
268 // Our stack is empty. No further child exists.
269 // Se we must "end" our progress realy
272 // Now hide the progress bar again.
275 impl_stopWakeUpThread();
278 impl_reschedule(sal_True
);
281 //-----------------------------------------------
282 void StatusIndicatorFactory::setText(const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
,
283 const OUString
& sText
)
285 // SAFE -> ----------------------------------
286 WriteGuard
aWriteLock(m_aLock
);
288 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
289 if (pItem
!= m_aStack
.end())
290 pItem
->m_sText
= sText
;
292 css::uno::Reference
< css::task::XStatusIndicator
> xActive
= m_xActiveChild
;
293 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
296 // SAFE -> ----------------------------------
298 // paint only the top most indicator
299 // but dont forget to Reschedule!
301 (xChild
== xActive
) &&
305 xProgress
->setText(sText
);
308 impl_reschedule(sal_True
);
311 //-----------------------------------------------
312 void StatusIndicatorFactory::setValue( const css::uno::Reference
< css::task::XStatusIndicator
>& xChild
,
315 // SAFE -> ----------------------------------
316 WriteGuard
aWriteLock(m_aLock
);
318 sal_Int32 nOldValue
= 0;
319 IndicatorStack::iterator pItem
= ::std::find(m_aStack
.begin(), m_aStack
.end(), xChild
);
320 if (pItem
!= m_aStack
.end())
322 nOldValue
= pItem
->m_nValue
;
323 pItem
->m_nValue
= nValue
;
326 css::uno::Reference
< css::task::XStatusIndicator
> xActive
= m_xActiveChild
;
327 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_xProgress
;
330 // SAFE -> ----------------------------------
333 (xChild
== xActive
) &&
334 (nOldValue
!= nValue
) &&
338 xProgress
->setValue(nValue
);
341 impl_reschedule(sal_False
);
344 //-----------------------------------------------
345 void StatusIndicatorFactory::implts_makeParentVisibleIfAllowed()
347 // SAFE -> ----------------------------------
348 ReadGuard
aReadLock(m_aLock
);
350 if (!m_bAllowParentShow
)
353 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xFrame
.get() , css::uno::UNO_QUERY
);
354 css::uno::Reference
< css::awt::XWindow
> xPluggWindow(m_xPluggWindow
.get(), css::uno::UNO_QUERY
);
355 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR( m_xSMGR
.get(), css::uno::UNO_QUERY
);
358 // <- SAFE ----------------------------------
360 css::uno::Reference
< css::awt::XWindow
> xParentWindow
;
362 xParentWindow
= xFrame
->getContainerWindow();
364 xParentWindow
= xPluggWindow
;
366 // dont disturb user in case he put the loading document into the background!
367 // Supress any setVisible() or toFront() call in case the initial show was
369 css::uno::Reference
< css::awt::XWindow2
> xVisibleCheck(xParentWindow
, css::uno::UNO_QUERY
);
370 sal_Bool bIsVisible
= sal_False
;
371 if (xVisibleCheck
.is())
372 bIsVisible
= xVisibleCheck
->isVisible();
380 // Check if the layout manager has been set to invisible state. It this case we are also
381 // not allowed to set the frame visible!
382 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
385 css::uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
386 xPropSet
->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER
) >>= xLayoutManager
;
387 if (xLayoutManager
.is())
389 if ( !xLayoutManager
->isVisible() )
394 // Ok the window should be made visible ... because it isnt currently visible.
396 // We need a Hack for our applications: They get her progress from the frame directly
397 // on saving documents. Because there is no progress set on the MediaDescriptor.
398 // But that's wrong. In case the document was opened hidden, they shouldnt use any progress .-(
399 // They only possible workaround: dont show the parent window here, if the document was opened hidden.
400 sal_Bool bHiddenDoc
= sal_False
;
403 css::uno::Reference
< css::frame::XController
> xController
;
404 css::uno::Reference
< css::frame::XModel
> xModel
;
405 xController
= xFrame
->getController();
406 if (xController
.is())
407 xModel
= xController
->getModel();
410 ::comphelper::MediaDescriptor
lDocArgs(xModel
->getArgs());
411 bHiddenDoc
= lDocArgs
.getUnpackedValueOrDefault(
412 ::comphelper::MediaDescriptor::PROP_HIDDEN(),
413 (sal_Bool
)sal_False
);
420 // OK: The document was not opened in hidden mode ...
421 // and the window isnt already visible.
422 // Show it and bring it to front.
423 // But before we have to be sure, that our internal used helper progress
427 SolarMutexGuard aSolarGuard
;
428 Window
* pWindow
= VCLUnoHelper::GetWindow(xParentWindow
);
431 bool bForceFrontAndFocus(false);
432 ::comphelper::ConfigurationHelper::readDirectKey(
433 comphelper::getComponentContext(xSMGR
),
434 OUString("org.openoffice.Office.Common/View"),
435 OUString("NewDocumentHandling"),
436 OUString("ForceFocusAndToFront"),
437 ::comphelper::ConfigurationHelper::E_READONLY
) >>= bForceFrontAndFocus
;
439 pWindow
->Show(sal_True
, bForceFrontAndFocus
? SHOW_FOREGROUNDTASK
: 0 );
444 //-----------------------------------------------
445 void StatusIndicatorFactory::impl_createProgress()
447 // SAFE -> ----------------------------------
448 ReadGuard
aReadLock(m_aLock
);
450 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xFrame
.get() , css::uno::UNO_QUERY
);
451 css::uno::Reference
< css::awt::XWindow
> xWindow(m_xPluggWindow
.get(), css::uno::UNO_QUERY
);
452 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
455 // <- SAFE ----------------------------------
457 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
;
461 // use vcl based progress implementation in plugged mode
462 VCLStatusIndicator
* pVCLProgress
= new VCLStatusIndicator(xSMGR
, xWindow
);
463 xProgress
= css::uno::Reference
< css::task::XStatusIndicator
>(static_cast< css::task::XStatusIndicator
* >(pVCLProgress
), css::uno::UNO_QUERY
);
465 else if (xFrame
.is())
467 // use frame layouted progress implementation
468 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
471 css::uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
472 xPropSet
->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER
) >>= xLayoutManager
;
473 if (xLayoutManager
.is())
475 xLayoutManager
->lock();
476 OUString
sPROGRESS_RESOURCE(PROGRESS_RESOURCE
);
477 xLayoutManager
->createElement( sPROGRESS_RESOURCE
);
478 xLayoutManager
->hideElement( sPROGRESS_RESOURCE
);
480 css::uno::Reference
< css::ui::XUIElement
> xProgressBar
= xLayoutManager
->getElement(sPROGRESS_RESOURCE
);
481 if (xProgressBar
.is())
482 xProgress
= css::uno::Reference
< css::task::XStatusIndicator
>(xProgressBar
->getRealInterface(), css::uno::UNO_QUERY
);
483 xLayoutManager
->unlock();
488 // SAFE -> ----------------------------------
489 WriteGuard
aWriteLock(m_aLock
);
490 m_xProgress
= xProgress
;
492 // <- SAFE ----------------------------------
495 //-----------------------------------------------
496 void StatusIndicatorFactory::impl_showProgress()
498 // SAFE -> ----------------------------------
499 ReadGuard
aReadLock(m_aLock
);
501 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xFrame
.get() , css::uno::UNO_QUERY
);
502 css::uno::Reference
< css::awt::XWindow
> xWindow(m_xPluggWindow
.get(), css::uno::UNO_QUERY
);
503 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
506 // <- SAFE ----------------------------------
508 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
;
512 // use frame layouted progress implementation
513 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
516 css::uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
517 xPropSet
->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER
) >>= xLayoutManager
;
518 if (xLayoutManager
.is())
520 // Be sure that we have always a progress. It can be that our frame
521 // was recycled and therefore the progress was destroyed!
522 // CreateElement does nothing if there is already a valid progress.
523 OUString
sPROGRESS_RESOURCE(PROGRESS_RESOURCE
);
524 xLayoutManager
->createElement( sPROGRESS_RESOURCE
);
525 xLayoutManager
->showElement( sPROGRESS_RESOURCE
);
527 css::uno::Reference
< css::ui::XUIElement
> xProgressBar
= xLayoutManager
->getElement(sPROGRESS_RESOURCE
);
528 if (xProgressBar
.is())
529 xProgress
= css::uno::Reference
< css::task::XStatusIndicator
>(xProgressBar
->getRealInterface(), css::uno::UNO_QUERY
);
533 // SAFE -> ----------------------------------
534 WriteGuard
aWriteLock(m_aLock
);
535 m_xProgress
= xProgress
;
537 // <- SAFE ----------------------------------
541 //-----------------------------------------------
542 void StatusIndicatorFactory::impl_hideProgress()
544 // SAFE -> ----------------------------------
545 ReadGuard
aReadLock(m_aLock
);
547 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xFrame
.get() , css::uno::UNO_QUERY
);
548 css::uno::Reference
< css::awt::XWindow
> xWindow(m_xPluggWindow
.get(), css::uno::UNO_QUERY
);
549 css::uno::Reference
< css::lang::XMultiServiceFactory
> xSMGR
= m_xSMGR
;
552 // <- SAFE ----------------------------------
556 // use frame layouted progress implementation
557 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
560 css::uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
561 xPropSet
->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER
) >>= xLayoutManager
;
562 if (xLayoutManager
.is())
563 xLayoutManager
->hideElement( OUString(PROGRESS_RESOURCE
) );
568 //-----------------------------------------------
569 void StatusIndicatorFactory::impl_reschedule(sal_Bool bForce
)
572 ReadGuard
aReadLock(m_aLock
);
573 if (m_bDisableReschedule
)
578 sal_Bool bReschedule
= bForce
;
582 WriteGuard
aWriteLock(m_aLock
);
583 bReschedule
= m_bAllowReschedule
;
584 m_bAllowReschedule
= sal_False
;
593 WriteGuard
aGlobalLock(LockHelper::getGlobalLock());
595 if (m_nInReschedule
== 0)
598 aGlobalLock
.unlock();
601 Application::Reschedule(true);
609 //-----------------------------------------------
610 void StatusIndicatorFactory::impl_startWakeUpThread()
613 WriteGuard
aWriteLock(m_aLock
);
615 if (m_bDisableReschedule
)
620 m_pWakeUp
= new WakeUpThread(this);
627 //-----------------------------------------------
628 void StatusIndicatorFactory::impl_stopWakeUpThread()
631 WriteGuard
aWriteLock(m_aLock
);
634 // Thread kill itself after terminate()!
635 m_pWakeUp
->terminate();
642 } // namespace framework
644 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */