bump product version to 4.1.6.2
[LibreOffice.git] / framework / source / helper / statusindicatorfactory.cxx
bloba87f441ffefb9071dc7d8fb321c52e6769f006ae
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <algorithm>
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>
26 #include <services.h>
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>
50 namespace framework{
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 ,
58 OWeakObject ,
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 ,
73 ::cppu::OWeakObject ,
74 OUString("com.sun.star.task.StatusIndicatorFactory"),
75 OUString("com.sun.star.comp.framework.StatusIndicatorFactory"))
77 DEFINE_INIT_SERVICE(StatusIndicatorFactory,
79 /*Attention
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)
89 : ThreadHelpBase ( )
90 , ::cppu::OWeakObject ( )
91 , m_xSMGR (xSMGR )
92 , m_pWakeUp (0 )
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;
128 } else {
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 );
137 aWriteLock.unlock();
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);
152 return xIndicator;
155 //-----------------------------------------------
156 void SAL_CALL StatusIndicatorFactory::update()
157 throw(css::uno::RuntimeException)
159 // SAFE -> ----------------------------------
160 WriteGuard aWriteLock(m_aLock);
161 m_bAllowReschedule = sal_True;
162 aWriteLock.unlock();
163 // <- SAFE ----------------------------------
166 //-----------------------------------------------
167 void StatusIndicatorFactory::start(const css::uno::Reference< css::task::XStatusIndicator >& xChild,
168 const OUString& sText ,
169 sal_Int32 nRange)
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;
184 aWriteLock.unlock();
185 // <- SAFE ----------------------------------
187 implts_makeParentVisibleIfAllowed();
189 if (xProgress.is())
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())
206 pItem->m_nValue = 0;
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;
213 aReadLock.unlock();
214 // <- SAFE ----------------------------------
216 // not the top most child => dont change UI
217 // But dont forget Reschedule!
218 if (
219 (xChild == xActive) &&
220 (xProgress.is() )
222 xProgress->reset();
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();
240 OUString sText;
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;
253 aWriteLock.unlock();
254 // <- SAFE ----------------------------------
256 if (xActive.is())
258 // There is at least one further child indicator.
259 // Actualize our progress, so it shows these values from now.
260 if (xProgress.is())
262 xProgress->setText (sText );
263 xProgress->setValue(nValue);
266 else
268 // Our stack is empty. No further child exists.
269 // Se we must "end" our progress realy
270 if (xProgress.is())
271 xProgress->end();
272 // Now hide the progress bar again.
273 impl_hideProgress();
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;
295 aWriteLock.unlock();
296 // SAFE -> ----------------------------------
298 // paint only the top most indicator
299 // but dont forget to Reschedule!
300 if (
301 (xChild == xActive) &&
302 (xProgress.is() )
305 xProgress->setText(sText);
308 impl_reschedule(sal_True);
311 //-----------------------------------------------
312 void StatusIndicatorFactory::setValue( const css::uno::Reference< css::task::XStatusIndicator >& xChild ,
313 sal_Int32 nValue )
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;
329 aWriteLock.unlock();
330 // SAFE -> ----------------------------------
332 if (
333 (xChild == xActive) &&
334 (nOldValue != nValue ) &&
335 (xProgress.is() )
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)
351 return;
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);
357 aReadLock.unlock();
358 // <- SAFE ----------------------------------
360 css::uno::Reference< css::awt::XWindow > xParentWindow;
361 if (xFrame.is())
362 xParentWindow = xFrame->getContainerWindow();
363 else
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
368 // already made.
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();
374 if (bIsVisible)
376 impl_showProgress();
377 return;
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);
383 if (xPropSet.is())
385 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
386 xPropSet->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER) >>= xLayoutManager;
387 if (xLayoutManager.is())
389 if ( !xLayoutManager->isVisible() )
390 return;
394 // Ok the window should be made visible ... because it isnt currently visible.
395 // BUT ..!
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;
401 if (xFrame.is())
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();
408 if (xModel.is())
410 ::comphelper::MediaDescriptor lDocArgs(xModel->getArgs());
411 bHiddenDoc = lDocArgs.getUnpackedValueOrDefault(
412 ::comphelper::MediaDescriptor::PROP_HIDDEN(),
413 (sal_Bool)sal_False);
417 if (bHiddenDoc)
418 return;
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
424 // is visible too.
425 impl_showProgress();
427 SolarMutexGuard aSolarGuard;
428 Window* pWindow = VCLUnoHelper::GetWindow(xParentWindow);
429 if ( pWindow )
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;
454 aReadLock.lock();
455 // <- SAFE ----------------------------------
457 css::uno::Reference< css::task::XStatusIndicator > xProgress;
459 if (xWindow.is())
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);
469 if (xPropSet.is())
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;
491 aWriteLock.lock();
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;
505 aReadLock.lock();
506 // <- SAFE ----------------------------------
508 css::uno::Reference< css::task::XStatusIndicator > xProgress;
510 if (xFrame.is())
512 // use frame layouted progress implementation
513 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
514 if (xPropSet.is())
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;
536 aWriteLock.lock();
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;
551 aReadLock.lock();
552 // <- SAFE ----------------------------------
554 if (xFrame.is())
556 // use frame layouted progress implementation
557 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
558 if (xPropSet.is())
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)
571 // SAFE ->
572 ReadGuard aReadLock(m_aLock);
573 if (m_bDisableReschedule)
574 return;
575 aReadLock.unlock();
576 // <- SAFE
578 sal_Bool bReschedule = bForce;
579 if (!bReschedule)
581 // SAFE ->
582 WriteGuard aWriteLock(m_aLock);
583 bReschedule = m_bAllowReschedule;
584 m_bAllowReschedule = sal_False;
585 aWriteLock.unlock();
586 // <- SAFE
589 if (!bReschedule)
590 return;
592 // SAFE ->
593 WriteGuard aGlobalLock(LockHelper::getGlobalLock());
595 if (m_nInReschedule == 0)
597 ++m_nInReschedule;
598 aGlobalLock.unlock();
599 // <- SAFE
601 Application::Reschedule(true);
603 // SAFE ->
604 aGlobalLock.lock();
605 --m_nInReschedule;
609 //-----------------------------------------------
610 void StatusIndicatorFactory::impl_startWakeUpThread()
612 // SAFE ->
613 WriteGuard aWriteLock(m_aLock);
615 if (m_bDisableReschedule)
616 return;
618 if (!m_pWakeUp)
620 m_pWakeUp = new WakeUpThread(this);
621 m_pWakeUp->create();
623 aWriteLock.unlock();
624 // <- SAFE
627 //-----------------------------------------------
628 void StatusIndicatorFactory::impl_stopWakeUpThread()
630 // SAFE ->
631 WriteGuard aWriteLock(m_aLock);
632 if (m_pWakeUp)
634 // Thread kill itself after terminate()!
635 m_pWakeUp->terminate();
636 m_pWakeUp = 0;
638 aWriteLock.unlock();
639 // <- SAFE
642 } // namespace framework
644 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */