merge the formfield patch from ooo-build
[ooovba.git] / framework / source / helper / statusindicatorfactory.cxx
bloba6256c73e19dc2bec3eb62bbdc6e288db1326d4c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: statusindicatorfactory.cxx,v $
10 * $Revision: 1.26 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
34 //-----------------------------------------------
35 // my own includes
37 #include <algorithm>
38 #include <helper/statusindicatorfactory.hxx>
39 #include <helper/statusindicator.hxx>
40 #include <helper/vclstatusindicator.hxx>
41 #include <threadhelp/writeguard.hxx>
42 #include <threadhelp/readguard.hxx>
43 #include <services.h>
44 #include <properties.h>
46 //-----------------------------------------------
47 // interface includes
48 #include <com/sun/star/awt/Rectangle.hpp>
50 #ifndef _COM_SUN_STAR_AWT_XCONTROLS_HPP_
51 #include <com/sun/star/awt/XControl.hpp>
52 #endif
53 #include <com/sun/star/awt/XLayoutConstrains.hpp>
54 #include <com/sun/star/awt/DeviceInfo.hpp>
55 #include <com/sun/star/awt/PosSize.hpp>
56 #include <com/sun/star/awt/WindowAttribute.hpp>
57 #include <com/sun/star/awt/XTopWindow.hpp>
58 #include <com/sun/star/awt/XWindow2.hpp>
59 #include <com/sun/star/beans/XPropertySet.hpp>
60 #include <com/sun/star/frame/XLayoutManager.hpp>
62 #ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
63 #include <toolkit/unohlp.hxx>
64 #endif
66 //-----------------------------------------------
67 // includes of other projects
68 #include <comphelper/sequenceashashmap.hxx>
69 #include <comphelper/mediadescriptor.hxx>
70 #include <vcl/svapp.hxx>
71 #include <vos/mutex.hxx>
73 //-----------------------------------------------
74 // namespace
76 namespace framework{
78 //-----------------------------------------------
79 // definitions
81 sal_Int32 StatusIndicatorFactory::m_nInReschedule = 0; /// static counter for rescheduling
82 static ::rtl::OUString PROGRESS_RESOURCE = ::rtl::OUString::createFromAscii("private:resource/progressbar/progressbar");
84 //-----------------------------------------------
85 DEFINE_XINTERFACE_5(StatusIndicatorFactory ,
86 OWeakObject ,
87 DIRECT_INTERFACE(css::lang::XTypeProvider ),
88 DIRECT_INTERFACE(css::lang::XServiceInfo ),
89 DIRECT_INTERFACE(css::lang::XInitialization ),
90 DIRECT_INTERFACE(css::task::XStatusIndicatorFactory),
91 DIRECT_INTERFACE(css::util::XUpdatable ))
93 DEFINE_XTYPEPROVIDER_5(StatusIndicatorFactory ,
94 css::lang::XTypeProvider ,
95 css::lang::XServiceInfo ,
96 css::lang::XInitialization ,
97 css::task::XStatusIndicatorFactory,
98 css::util::XUpdatable )
100 DEFINE_XSERVICEINFO_MULTISERVICE(StatusIndicatorFactory ,
101 ::cppu::OWeakObject ,
102 SERVICENAME_STATUSINDICATORFACTORY ,
103 IMPLEMENTATIONNAME_STATUSINDICATORFACTORY)
105 DEFINE_INIT_SERVICE(StatusIndicatorFactory,
107 /*Attention
108 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
109 to create a new instance of this class by our own supported service factory.
110 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
115 //-----------------------------------------------
116 StatusIndicatorFactory::StatusIndicatorFactory(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
117 : ThreadHelpBase ( )
118 , ::cppu::OWeakObject ( )
119 , m_xSMGR (xSMGR )
120 , m_pWakeUp (0 )
121 , m_bAllowReschedule (sal_False)
122 , m_bAllowParentShow (sal_False)
123 , m_bDisableReschedule(sal_False)
127 //-----------------------------------------------
128 StatusIndicatorFactory::~StatusIndicatorFactory()
130 impl_stopWakeUpThread();
133 //-----------------------------------------------
134 void SAL_CALL StatusIndicatorFactory::initialize(const css::uno::Sequence< css::uno::Any >& lArguments)
135 throw(css::uno::Exception ,
136 css::uno::RuntimeException)
138 ::comphelper::SequenceAsHashMap lArgs(lArguments);
140 // SAFE -> ----------------------------------
141 WriteGuard aWriteLock(m_aLock);
143 m_xFrame = lArgs.getUnpackedValueOrDefault(STATUSINDICATORFACTORY_PROPNAME_FRAME , css::uno::Reference< css::frame::XFrame >());
144 m_xPluggWindow = lArgs.getUnpackedValueOrDefault(STATUSINDICATORFACTORY_PROPNAME_WINDOW , css::uno::Reference< css::awt::XWindow >() );
145 m_bAllowParentShow = lArgs.getUnpackedValueOrDefault(STATUSINDICATORFACTORY_PROPNAME_ALLOWPARENTSHOW , (sal_Bool)sal_False );
146 m_bDisableReschedule = lArgs.getUnpackedValueOrDefault(STATUSINDICATORFACTORY_PROPNAME_DISABLERESCHEDULE, (sal_Bool)sal_False );
148 aWriteLock.unlock();
149 // <- SAFE ----------------------------------
151 impl_createProgress();
154 //-----------------------------------------------
155 css::uno::Reference< css::task::XStatusIndicator > SAL_CALL StatusIndicatorFactory::createStatusIndicator()
156 throw(css::uno::RuntimeException)
158 StatusIndicator* pIndicator = new StatusIndicator(this);
159 css::uno::Reference< css::task::XStatusIndicator > xIndicator(static_cast< ::cppu::OWeakObject* >(pIndicator), css::uno::UNO_QUERY_THROW);
161 return xIndicator;
164 //-----------------------------------------------
165 void SAL_CALL StatusIndicatorFactory::update()
166 throw(css::uno::RuntimeException)
168 // SAFE -> ----------------------------------
169 WriteGuard aWriteLock(m_aLock);
170 m_bAllowReschedule = sal_True;
171 aWriteLock.unlock();
172 // <- SAFE ----------------------------------
175 //-----------------------------------------------
176 void StatusIndicatorFactory::start(const css::uno::Reference< css::task::XStatusIndicator >& xChild,
177 const ::rtl::OUString& sText ,
178 sal_Int32 nRange)
180 // SAFE -> ----------------------------------
181 WriteGuard aWriteLock(m_aLock);
183 // create new info structure for this child or move it to the front of our stack
184 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
185 if (pItem != m_aStack.end())
186 m_aStack.erase(pItem);
187 IndicatorInfo aInfo(xChild, sText, nRange);
188 m_aStack.push_back (aInfo );
190 m_xActiveChild = xChild;
191 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
193 aWriteLock.unlock();
194 // <- SAFE ----------------------------------
196 implts_makeParentVisibleIfAllowed();
198 if (xProgress.is())
199 xProgress->start(sText, nRange);
201 impl_startWakeUpThread();
202 impl_reschedule(sal_True);
205 //-----------------------------------------------
206 void StatusIndicatorFactory::reset(const css::uno::Reference< css::task::XStatusIndicator >& xChild)
208 // SAFE -> ----------------------------------
209 ReadGuard aReadLock(m_aLock);
211 // reset the internal info structure related to this child
212 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
213 if (pItem != m_aStack.end())
215 pItem->m_nValue = 0;
216 pItem->m_sText = ::rtl::OUString();
219 css::uno::Reference< css::task::XStatusIndicator > xActive = m_xActiveChild;
220 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
222 aReadLock.unlock();
223 // <- SAFE ----------------------------------
225 // not the top most child => dont change UI
226 // But dont forget Reschedule!
227 if (
228 (xChild == xActive) &&
229 (xProgress.is() )
231 xProgress->reset();
233 impl_reschedule(sal_True);
236 //-----------------------------------------------
237 void StatusIndicatorFactory::end(const css::uno::Reference< css::task::XStatusIndicator >& xChild)
239 // SAFE -> ----------------------------------
240 WriteGuard aWriteLock(m_aLock);
242 // remove this child from our stack
243 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
244 if (pItem != m_aStack.end())
245 m_aStack.erase(pItem);
247 // activate next child ... or finish the progress if there is no further one.
248 m_xActiveChild.clear();
249 ::rtl::OUString sText;
250 sal_Int32 nValue = 0;
251 IndicatorStack::reverse_iterator pNext = m_aStack.rbegin();
252 if (pNext != m_aStack.rend())
254 m_xActiveChild = pNext->m_xIndicator;
255 sText = pNext->m_sText;
256 nValue = pNext->m_nValue;
259 css::uno::Reference< css::task::XStatusIndicator > xActive = m_xActiveChild;
260 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
262 aWriteLock.unlock();
263 // <- SAFE ----------------------------------
265 if (xActive.is())
267 // There is at least one further child indicator.
268 // Actualize our progress, so it shows these values from now.
269 if (xProgress.is())
271 xProgress->setText (sText );
272 xProgress->setValue(nValue);
275 else
277 // Our stack is empty. No further child exists.
278 // Se we must "end" our progress realy
279 if (xProgress.is())
280 xProgress->end();
281 // Now hide the progress bar again.
282 impl_hideProgress();
284 impl_stopWakeUpThread();
287 impl_reschedule(sal_True);
290 //-----------------------------------------------
291 void StatusIndicatorFactory::setText(const css::uno::Reference< css::task::XStatusIndicator >& xChild,
292 const ::rtl::OUString& sText )
294 // SAFE -> ----------------------------------
295 WriteGuard aWriteLock(m_aLock);
297 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
298 if (pItem != m_aStack.end())
299 pItem->m_sText = sText;
301 css::uno::Reference< css::task::XStatusIndicator > xActive = m_xActiveChild;
302 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
304 aWriteLock.unlock();
305 // SAFE -> ----------------------------------
307 // paint only the top most indicator
308 // but dont forget to Reschedule!
309 if (
310 (xChild == xActive) &&
311 (xProgress.is() )
314 xProgress->setText(sText);
317 impl_reschedule(sal_True);
320 //-----------------------------------------------
321 void StatusIndicatorFactory::setValue( const css::uno::Reference< css::task::XStatusIndicator >& xChild ,
322 sal_Int32 nValue )
324 // SAFE -> ----------------------------------
325 WriteGuard aWriteLock(m_aLock);
327 sal_Int32 nOldValue = 0;
328 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
329 if (pItem != m_aStack.end())
331 nOldValue = pItem->m_nValue;
332 pItem->m_nValue = nValue;
335 css::uno::Reference< css::task::XStatusIndicator > xActive = m_xActiveChild;
336 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
338 aWriteLock.unlock();
339 // SAFE -> ----------------------------------
341 if (
342 (xChild == xActive) &&
343 (nOldValue != nValue ) &&
344 (xProgress.is() )
347 xProgress->setValue(nValue);
350 impl_reschedule(sal_False);
353 //-----------------------------------------------
354 void StatusIndicatorFactory::implts_makeParentVisibleIfAllowed()
356 // SAFE -> ----------------------------------
357 ReadGuard aReadLock(m_aLock);
359 if (!m_bAllowParentShow)
360 return;
362 css::uno::Reference< css::frame::XFrame > xFrame (m_xFrame.get() , css::uno::UNO_QUERY);
363 css::uno::Reference< css::awt::XWindow > xPluggWindow(m_xPluggWindow.get(), css::uno::UNO_QUERY);
365 aReadLock.unlock();
366 // <- SAFE ----------------------------------
368 css::uno::Reference< css::awt::XWindow > xParentWindow;
369 if (xFrame.is())
370 xParentWindow = xFrame->getContainerWindow();
371 else
372 xParentWindow = xPluggWindow;
374 // dont disturb user in case he put the loading document into the background!
375 // Supress any setVisible() or toFront() call in case the initial show was
376 // already made.
377 css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(xParentWindow, css::uno::UNO_QUERY);
378 sal_Bool bIsVisible = sal_False;
379 if (xVisibleCheck.is())
380 bIsVisible = xVisibleCheck->isVisible();
382 if (bIsVisible)
384 impl_showProgress();
385 return;
388 // Check if the layout manager has been set to invisible state. It this case we are also
389 // not allowed to set the frame visible!
390 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
391 if (xPropSet.is())
393 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
394 xPropSet->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER) >>= xLayoutManager;
395 if (xLayoutManager.is())
397 if ( !xLayoutManager->isVisible() )
398 return;
402 // Ok the window should be made visible ... becuase it isnt currently visible.
403 // BUT ..!
404 // We need a Hack for our applications: They get her progress from the frame directly
405 // on saving documents. Because there is no progress set on the MediaDescriptor.
406 // But that's wrong. In case the document was opened hidden, they shouldnt use any progress .-(
407 // They only possible workaround: dont show the parent window here, if the document was opened hidden.
408 sal_Bool bHiddenDoc = sal_False;
409 if (xFrame.is())
411 css::uno::Reference< css::frame::XController > xController;
412 css::uno::Reference< css::frame::XModel > xModel ;
413 xController = xFrame->getController();
414 if (xController.is())
415 xModel = xController->getModel();
416 if (xModel.is())
418 ::comphelper::MediaDescriptor lDocArgs(xModel->getArgs());
419 bHiddenDoc = lDocArgs.getUnpackedValueOrDefault(
420 ::comphelper::MediaDescriptor::PROP_HIDDEN(),
421 (sal_Bool)sal_False);
425 if (bHiddenDoc)
426 return;
428 // OK: The document was not opened in hidden mode ...
429 // and the window isnt already visible.
430 // Show it and bring it to front.
431 // But before we have to be sure, that our internal used helper progress
432 // is visible too.
433 impl_showProgress();
435 if (xParentWindow.is())
436 xParentWindow->setVisible(sal_True);
438 #i75167# dont disturb window manager handling .-)
439 css::uno::Reference< css::awt::XTopWindow > xParentWindowTop(xParentWindow, css::uno::UNO_QUERY);
440 if (xParentWindowTop.is())
441 xParentWindowTop->toFront();
445 //-----------------------------------------------
446 void StatusIndicatorFactory::impl_createProgress()
448 // SAFE -> ----------------------------------
449 ReadGuard aReadLock(m_aLock);
451 css::uno::Reference< css::frame::XFrame > xFrame (m_xFrame.get() , css::uno::UNO_QUERY);
452 css::uno::Reference< css::awt::XWindow > xWindow(m_xPluggWindow.get(), css::uno::UNO_QUERY);
453 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
455 aReadLock.lock();
456 // <- SAFE ----------------------------------
458 css::uno::Reference< css::task::XStatusIndicator > xProgress;
460 if (xWindow.is())
462 // use vcl based progress implementation in plugged mode
463 VCLStatusIndicator* pVCLProgress = new VCLStatusIndicator(xSMGR, xWindow);
464 xProgress = css::uno::Reference< css::task::XStatusIndicator >(static_cast< css::task::XStatusIndicator* >(pVCLProgress), css::uno::UNO_QUERY);
466 else
467 if (xFrame.is())
469 // use frame layouted progress implementation
470 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
471 if (xPropSet.is())
473 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
474 xPropSet->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER) >>= xLayoutManager;
475 if (xLayoutManager.is())
477 xLayoutManager->lock();
478 xLayoutManager->createElement( PROGRESS_RESOURCE );
479 xLayoutManager->hideElement( PROGRESS_RESOURCE );
481 css::uno::Reference< css::ui::XUIElement > xProgressBar = xLayoutManager->getElement(PROGRESS_RESOURCE);
482 if (xProgressBar.is())
483 xProgress = css::uno::Reference< css::task::XStatusIndicator >(xProgressBar->getRealInterface(), css::uno::UNO_QUERY);
484 xLayoutManager->unlock();
489 // SAFE -> ----------------------------------
490 WriteGuard aWriteLock(m_aLock);
491 m_xProgress = xProgress;
492 aWriteLock.lock();
493 // <- SAFE ----------------------------------
496 //-----------------------------------------------
497 void StatusIndicatorFactory::impl_showProgress()
499 // SAFE -> ----------------------------------
500 ReadGuard aReadLock(m_aLock);
502 css::uno::Reference< css::frame::XFrame > xFrame (m_xFrame.get() , css::uno::UNO_QUERY);
503 css::uno::Reference< css::awt::XWindow > xWindow(m_xPluggWindow.get(), css::uno::UNO_QUERY);
504 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
506 aReadLock.lock();
507 // <- SAFE ----------------------------------
509 css::uno::Reference< css::task::XStatusIndicator > xProgress;
511 if (xFrame.is())
513 // use frame layouted progress implementation
514 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
515 if (xPropSet.is())
517 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
518 xPropSet->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER) >>= xLayoutManager;
519 if (xLayoutManager.is())
521 // Be sure that we have always a progress. It can be that our frame
522 // was recycled and therefore the progress was destroyed!
523 // CreateElement does nothing if there is already a valid progress.
524 xLayoutManager->createElement( PROGRESS_RESOURCE );
525 xLayoutManager->showElement( PROGRESS_RESOURCE );
527 css::uno::Reference< css::ui::XUIElement > xProgressBar = xLayoutManager->getElement(PROGRESS_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( 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