fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / framework / source / helper / statusindicatorfactory.cxx
blob854972315585cc394c72169c82389bd0648a5502
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 <services.h>
25 #include <properties.h>
27 #include <com/sun/star/awt/Rectangle.hpp>
29 #include <com/sun/star/awt/XControl.hpp>
30 #include <com/sun/star/awt/XLayoutConstrains.hpp>
31 #include <com/sun/star/awt/DeviceInfo.hpp>
32 #include <com/sun/star/awt/PosSize.hpp>
33 #include <com/sun/star/awt/WindowAttribute.hpp>
34 #include <com/sun/star/awt/XTopWindow.hpp>
35 #include <com/sun/star/awt/XWindow2.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/frame/XLayoutManager2.hpp>
39 #include <toolkit/helper/vclunohelper.hxx>
41 #include <comphelper/sequenceashashmap.hxx>
42 #include <unotools/mediadescriptor.hxx>
43 #include <vcl/svapp.hxx>
44 #include <osl/mutex.hxx>
45 #include <rtl/ref.hxx>
47 #include <officecfg/Office/Common.hxx>
49 namespace framework{
51 sal_Int32 StatusIndicatorFactory::m_nInReschedule = 0; ///< static counter for rescheduling
52 struct RescheduleLock: public rtl::Static<osl::Mutex, RescheduleLock> {}; ///< mutex to guard the m_nInReschedule
54 const char PROGRESS_RESOURCE[] = "private:resource/progressbar/progressbar";
56 StatusIndicatorFactory::StatusIndicatorFactory(const css::uno::Reference< css::uno::XComponentContext >& xContext)
57 : m_xContext (xContext )
58 , m_bAllowReschedule (false)
59 , m_bAllowParentShow (false)
60 , m_bDisableReschedule(false)
64 StatusIndicatorFactory::~StatusIndicatorFactory()
66 impl_stopWakeUpThread();
69 void SAL_CALL StatusIndicatorFactory::initialize(const css::uno::Sequence< css::uno::Any >& lArguments)
70 throw(css::uno::Exception ,
71 css::uno::RuntimeException, std::exception)
73 if (lArguments.getLength() > 0) {
74 osl::MutexGuard g(m_mutex);
76 css::uno::Reference< css::frame::XFrame > xTmpFrame;
77 css::uno::Reference< css::awt::XWindow > xTmpWindow;
78 bool b1 = lArguments[0] >>= xTmpFrame;
79 bool b2 = lArguments[0] >>= xTmpWindow;
80 if (lArguments.getLength() == 3 && b1) {
81 // it's the first service constructor "createWithFrame"
82 m_xFrame = xTmpFrame;
83 lArguments[1] >>= m_bDisableReschedule;
84 lArguments[2] >>= m_bAllowParentShow;
85 } else if (lArguments.getLength() == 3 && b2) {
86 // it's the second service constructor "createWithWindow"
87 m_xPluggWindow = xTmpWindow;
88 lArguments[1] >>= m_bDisableReschedule;
89 lArguments[2] >>= m_bAllowParentShow;
90 } else {
91 // it's an old-style initialisation using properties
92 ::comphelper::SequenceAsHashMap lArgs(lArguments);
94 m_xFrame = lArgs.getUnpackedValueOrDefault("Frame" , css::uno::Reference< css::frame::XFrame >());
95 m_xPluggWindow = lArgs.getUnpackedValueOrDefault("Window" , css::uno::Reference< css::awt::XWindow >() );
96 m_bAllowParentShow = lArgs.getUnpackedValueOrDefault("AllowParentShow" , false );
97 m_bDisableReschedule = lArgs.getUnpackedValueOrDefault("DisableReschedule", false );
101 impl_createProgress();
104 css::uno::Reference< css::task::XStatusIndicator > SAL_CALL StatusIndicatorFactory::createStatusIndicator()
105 throw(css::uno::RuntimeException, std::exception)
107 StatusIndicator* pIndicator = new StatusIndicator(this);
108 css::uno::Reference< css::task::XStatusIndicator > xIndicator(static_cast< ::cppu::OWeakObject* >(pIndicator), css::uno::UNO_QUERY_THROW);
110 return xIndicator;
113 void SAL_CALL StatusIndicatorFactory::update()
114 throw(css::uno::RuntimeException, std::exception)
116 osl::MutexGuard g(m_mutex);
117 m_bAllowReschedule = true;
120 void StatusIndicatorFactory::start(const css::uno::Reference< css::task::XStatusIndicator >& xChild,
121 const OUString& sText ,
122 sal_Int32 nRange)
124 // SAFE -> ----------------------------------
125 osl::ClearableMutexGuard aWriteLock(m_mutex);
127 // create new info structure for this child or move it to the front of our stack
128 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
129 if (pItem != m_aStack.end())
130 m_aStack.erase(pItem);
131 IndicatorInfo aInfo(xChild, sText, nRange);
132 m_aStack.push_back (aInfo );
134 m_xActiveChild = xChild;
135 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
137 aWriteLock.clear();
138 // <- SAFE ----------------------------------
140 implts_makeParentVisibleIfAllowed();
142 if (xProgress.is())
143 xProgress->start(sText, nRange);
145 impl_startWakeUpThread();
146 impl_reschedule(true);
149 void StatusIndicatorFactory::reset(const css::uno::Reference< css::task::XStatusIndicator >& xChild)
151 // SAFE -> ----------------------------------
152 osl::ClearableMutexGuard aReadLock(m_mutex);
154 // reset the internal info structure related to this child
155 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
156 if (pItem != m_aStack.end())
158 pItem->m_nValue = 0;
159 (pItem->m_sText).clear();
162 css::uno::Reference< css::task::XStatusIndicator > xActive = m_xActiveChild;
163 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
165 aReadLock.clear();
166 // <- SAFE ----------------------------------
168 // not the top most child => dont change UI
169 // But dont forget Reschedule!
170 if (
171 (xChild == xActive) &&
172 (xProgress.is() )
174 xProgress->reset();
176 impl_reschedule(true);
179 void StatusIndicatorFactory::end(const css::uno::Reference< css::task::XStatusIndicator >& xChild)
181 // SAFE -> ----------------------------------
182 osl::ClearableMutexGuard aWriteLock(m_mutex);
184 // remove this child from our stack
185 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
186 if (pItem != m_aStack.end())
187 m_aStack.erase(pItem);
189 // activate next child ... or finish the progress if there is no further one.
190 m_xActiveChild.clear();
191 OUString sText;
192 sal_Int32 nValue = 0;
193 IndicatorStack::reverse_iterator pNext = m_aStack.rbegin();
194 if (pNext != m_aStack.rend())
196 m_xActiveChild = pNext->m_xIndicator;
197 sText = pNext->m_sText;
198 nValue = pNext->m_nValue;
201 css::uno::Reference< css::task::XStatusIndicator > xActive = m_xActiveChild;
202 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
204 aWriteLock.clear();
205 // <- SAFE ----------------------------------
207 if (xActive.is())
209 // There is at least one further child indicator.
210 // Actualize our progress, so it shows these values from now.
211 if (xProgress.is())
213 xProgress->setText (sText );
214 xProgress->setValue(nValue);
217 else
219 // Our stack is empty. No further child exists.
220 // Se we must "end" our progress really
221 if (xProgress.is())
222 xProgress->end();
223 // Now hide the progress bar again.
224 impl_hideProgress();
226 impl_stopWakeUpThread();
229 impl_reschedule(true);
232 void StatusIndicatorFactory::setText(const css::uno::Reference< css::task::XStatusIndicator >& xChild,
233 const OUString& sText )
235 // SAFE -> ----------------------------------
236 osl::ClearableMutexGuard aWriteLock(m_mutex);
238 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
239 if (pItem != m_aStack.end())
240 pItem->m_sText = sText;
242 css::uno::Reference< css::task::XStatusIndicator > xActive = m_xActiveChild;
243 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
245 aWriteLock.clear();
246 // SAFE -> ----------------------------------
248 // paint only the top most indicator
249 // but dont forget to Reschedule!
250 if (
251 (xChild == xActive) &&
252 (xProgress.is() )
255 xProgress->setText(sText);
258 impl_reschedule(true);
261 void StatusIndicatorFactory::setValue( const css::uno::Reference< css::task::XStatusIndicator >& xChild ,
262 sal_Int32 nValue )
264 // SAFE -> ----------------------------------
265 osl::ClearableMutexGuard aWriteLock(m_mutex);
267 sal_Int32 nOldValue = 0;
268 IndicatorStack::iterator pItem = ::std::find(m_aStack.begin(), m_aStack.end(), xChild);
269 if (pItem != m_aStack.end())
271 nOldValue = pItem->m_nValue;
272 pItem->m_nValue = nValue;
275 css::uno::Reference< css::task::XStatusIndicator > xActive = m_xActiveChild;
276 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_xProgress;
278 aWriteLock.clear();
279 // SAFE -> ----------------------------------
281 if (
282 (xChild == xActive) &&
283 (nOldValue != nValue ) &&
284 (xProgress.is() )
287 xProgress->setValue(nValue);
290 impl_reschedule(false);
293 void StatusIndicatorFactory::implts_makeParentVisibleIfAllowed()
295 // SAFE -> ----------------------------------
296 osl::ClearableMutexGuard aReadLock(m_mutex);
298 if (!m_bAllowParentShow)
299 return;
301 css::uno::Reference< css::frame::XFrame > xFrame (m_xFrame.get() , css::uno::UNO_QUERY);
302 css::uno::Reference< css::awt::XWindow > xPluggWindow(m_xPluggWindow.get(), css::uno::UNO_QUERY);
303 css::uno::Reference< css::uno::XComponentContext > xContext( m_xContext);
305 aReadLock.clear();
306 // <- SAFE ----------------------------------
308 css::uno::Reference< css::awt::XWindow > xParentWindow;
309 if (xFrame.is())
310 xParentWindow = xFrame->getContainerWindow();
311 else
312 xParentWindow = xPluggWindow;
314 // dont disturb user in case he put the loading document into the background!
315 // Suppress any setVisible() or toFront() call in case the initial show was
316 // already made.
317 css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(xParentWindow, css::uno::UNO_QUERY);
318 bool bIsVisible = false;
319 if (xVisibleCheck.is())
320 bIsVisible = xVisibleCheck->isVisible();
322 if (bIsVisible)
324 impl_showProgress();
325 return;
328 // Check if the layout manager has been set to invisible state. It this case we are also
329 // not allowed to set the frame visible!
330 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
331 if (xPropSet.is())
333 css::uno::Reference< css::frame::XLayoutManager2 > xLayoutManager;
334 xPropSet->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER) >>= xLayoutManager;
335 if (xLayoutManager.is())
337 if ( !xLayoutManager->isVisible() )
338 return;
342 // Ok the window should be made visible... because it is not currently visible.
343 // BUT..!
344 // We need a Hack for our applications: They get her progress from the frame directly
345 // on saving documents. Because there is no progress set on the MediaDescriptor.
346 // But that's wrong. In case the document was opened hidden, they should not use any progress .-(
347 // They only possible workaround: dont show the parent window here, if the document was opened hidden.
348 bool bHiddenDoc = false;
349 if (xFrame.is())
351 css::uno::Reference< css::frame::XController > xController;
352 css::uno::Reference< css::frame::XModel > xModel;
353 xController = xFrame->getController();
354 if (xController.is())
355 xModel = xController->getModel();
356 if (xModel.is())
358 utl::MediaDescriptor lDocArgs(xModel->getArgs());
359 bHiddenDoc = lDocArgs.getUnpackedValueOrDefault(
360 utl::MediaDescriptor::PROP_HIDDEN(),
361 false);
365 if (bHiddenDoc)
366 return;
368 // OK: The document was not opened in hidden mode ...
369 // and the window isn't already visible.
370 // Show it and bring it to front.
371 // But before we have to be sure, that our internal used helper progress
372 // is visible too.
373 impl_showProgress();
375 SolarMutexGuard aSolarGuard;
376 vcl::Window* pWindow = VCLUnoHelper::GetWindow(xParentWindow);
377 if ( pWindow )
379 bool bForceFrontAndFocus(officecfg::Office::Common::View::NewDocumentHandling::ForceFocusAndToFront::get(xContext));
380 pWindow->Show(true, bForceFrontAndFocus ? SHOW_FOREGROUNDTASK : 0 );
385 void StatusIndicatorFactory::impl_createProgress()
387 // SAFE -> ----------------------------------
388 osl::ClearableMutexGuard aReadLock(m_mutex);
390 css::uno::Reference< css::frame::XFrame > xFrame (m_xFrame.get() , css::uno::UNO_QUERY);
391 css::uno::Reference< css::awt::XWindow > xWindow(m_xPluggWindow.get(), css::uno::UNO_QUERY);
393 aReadLock.clear();
394 // <- SAFE ----------------------------------
396 css::uno::Reference< css::task::XStatusIndicator > xProgress;
398 if (xWindow.is())
400 // use vcl based progress implementation in plugged mode
401 VCLStatusIndicator* pVCLProgress = new VCLStatusIndicator(xWindow);
402 xProgress = css::uno::Reference< css::task::XStatusIndicator >(static_cast< css::task::XStatusIndicator* >(pVCLProgress), css::uno::UNO_QUERY);
404 else if (xFrame.is())
406 // use frame layouted progress implementation
407 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
408 if (xPropSet.is())
410 css::uno::Reference< css::frame::XLayoutManager2 > xLayoutManager;
411 xPropSet->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER) >>= xLayoutManager;
412 if (xLayoutManager.is())
414 xLayoutManager->lock();
415 OUString sPROGRESS_RESOURCE(PROGRESS_RESOURCE);
416 xLayoutManager->createElement( sPROGRESS_RESOURCE );
417 xLayoutManager->hideElement( sPROGRESS_RESOURCE );
419 css::uno::Reference< css::ui::XUIElement > xProgressBar = xLayoutManager->getElement(sPROGRESS_RESOURCE);
420 if (xProgressBar.is())
421 xProgress = css::uno::Reference< css::task::XStatusIndicator >(xProgressBar->getRealInterface(), css::uno::UNO_QUERY);
422 xLayoutManager->unlock();
427 osl::MutexGuard g(m_mutex);
428 m_xProgress = xProgress;
431 void StatusIndicatorFactory::impl_showProgress()
433 // SAFE -> ----------------------------------
434 osl::ClearableMutexGuard aReadLock(m_mutex);
436 css::uno::Reference< css::frame::XFrame > xFrame (m_xFrame.get() , css::uno::UNO_QUERY);
437 css::uno::Reference< css::awt::XWindow > xWindow(m_xPluggWindow.get(), css::uno::UNO_QUERY);
439 aReadLock.clear();
440 // <- SAFE ----------------------------------
442 css::uno::Reference< css::task::XStatusIndicator > xProgress;
444 if (xFrame.is())
446 // use frame layouted progress implementation
447 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
448 if (xPropSet.is())
450 css::uno::Reference< css::frame::XLayoutManager2 > xLayoutManager;
451 xPropSet->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER) >>= xLayoutManager;
452 if (xLayoutManager.is())
454 // Be sure that we have always a progress. It can be that our frame
455 // was recycled and therefore the progress was destroyed!
456 // CreateElement does nothing if there is already a valid progress.
457 OUString sPROGRESS_RESOURCE(PROGRESS_RESOURCE);
458 xLayoutManager->createElement( sPROGRESS_RESOURCE );
459 xLayoutManager->showElement( sPROGRESS_RESOURCE );
461 css::uno::Reference< css::ui::XUIElement > xProgressBar = xLayoutManager->getElement(sPROGRESS_RESOURCE);
462 if (xProgressBar.is())
463 xProgress = css::uno::Reference< css::task::XStatusIndicator >(xProgressBar->getRealInterface(), css::uno::UNO_QUERY);
467 osl::MutexGuard g(m_mutex);
468 m_xProgress = xProgress;
472 void StatusIndicatorFactory::impl_hideProgress()
474 // SAFE -> ----------------------------------
475 osl::ClearableMutexGuard aReadLock(m_mutex);
477 css::uno::Reference< css::frame::XFrame > xFrame (m_xFrame.get() , css::uno::UNO_QUERY);
478 css::uno::Reference< css::awt::XWindow > xWindow(m_xPluggWindow.get(), css::uno::UNO_QUERY);
480 aReadLock.clear();
481 // <- SAFE ----------------------------------
483 if (xFrame.is())
485 // use frame layouted progress implementation
486 css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
487 if (xPropSet.is())
489 css::uno::Reference< css::frame::XLayoutManager2 > xLayoutManager;
490 xPropSet->getPropertyValue(FRAME_PROPNAME_LAYOUTMANAGER) >>= xLayoutManager;
491 if (xLayoutManager.is())
492 xLayoutManager->hideElement( OUString(PROGRESS_RESOURCE) );
497 void StatusIndicatorFactory::impl_reschedule(bool bForce)
499 // SAFE ->
500 osl::ClearableMutexGuard aReadLock(m_mutex);
501 if (m_bDisableReschedule)
502 return;
503 aReadLock.clear();
504 // <- SAFE
506 bool bReschedule = bForce;
507 if (!bReschedule)
509 osl::MutexGuard g(m_mutex);
510 bReschedule = m_bAllowReschedule;
511 m_bAllowReschedule = false;
514 if (!bReschedule)
515 return;
517 // SAFE ->
518 osl::ResettableMutexGuard aRescheduleGuard(RescheduleLock::get());
520 if (m_nInReschedule == 0)
522 ++m_nInReschedule;
523 aRescheduleGuard.clear();
524 // <- SAFE
527 SolarMutexGuard g;
528 Application::Reschedule(true);
531 // SAFE ->
532 aRescheduleGuard.reset();
533 --m_nInReschedule;
537 void StatusIndicatorFactory::impl_startWakeUpThread()
539 osl::MutexGuard g(m_mutex);
541 if (m_bDisableReschedule)
542 return;
544 if (!m_pWakeUp.is())
546 m_pWakeUp = new WakeUpThread(this);
547 m_pWakeUp->launch();
551 void StatusIndicatorFactory::impl_stopWakeUpThread()
553 rtl::Reference<WakeUpThread> wakeUp;
555 osl::MutexGuard g(m_mutex);
556 wakeUp = m_pWakeUp;
558 if (wakeUp.is())
560 wakeUp->stop();
564 } // namespace framework
566 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
567 com_sun_star_comp_framework_StatusIndicatorFactory_get_implementation(
568 css::uno::XComponentContext *context,
569 css::uno::Sequence<css::uno::Any> const &)
571 return cppu::acquire(new framework::StatusIndicatorFactory(context));
574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */