Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / appl / shutdownicon.cxx
blob84d169cf708ae9f2d04ac96955528f6d0db4887d
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 <sal/config.h>
21 #include <sal/log.hxx>
23 #include <cassert>
25 #include <boost/logic/tribool.hpp>
26 #include "shutdownicon.hxx"
27 #include <sfx2/strings.hrc>
28 #include <sfx2/app.hxx>
29 #include <osl/mutex.hxx>
30 #include <svtools/imagemgr.hxx>
31 #include <com/sun/star/task/InteractionHandler.hpp>
32 #include <com/sun/star/frame/Desktop.hpp>
33 #include <com/sun/star/frame/TerminationVetoException.hpp>
34 #include <com/sun/star/frame/XDispatchResultListener.hpp>
35 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
36 #include <com/sun/star/frame/XFramesSupplier.hpp>
37 #include <com/sun/star/frame/XFrame.hpp>
38 #include <com/sun/star/util/URLTransformer.hpp>
39 #include <com/sun/star/util/XURLTransformer.hpp>
40 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
41 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
42 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
43 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
44 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
45 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
46 #include <com/sun/star/document/MacroExecMode.hpp>
47 #include <com/sun/star/document/UpdateDocMode.hpp>
48 #include <sfx2/filedlghelper.hxx>
49 #include <sfx2/docfilt.hxx>
50 #include <sfx2/fcontnr.hxx>
51 #include <comphelper/processfactory.hxx>
52 #include <cppuhelper/implbase.hxx>
53 #include <cppuhelper/supportsservice.hxx>
54 #include <comphelper/extract.hxx>
55 #include <officecfg/Office/Common.hxx>
56 #include <tools/urlobj.hxx>
57 #include <tools/debug.hxx>
58 #include <osl/file.hxx>
59 #include <osl/module.hxx>
60 #include <rtl/ref.hxx>
61 #include <vcl/svapp.hxx>
63 #include <sfx2/sfxresid.hxx>
65 using namespace ::com::sun::star;
66 using namespace ::com::sun::star::uno;
67 using namespace ::com::sun::star::frame;
68 using namespace ::com::sun::star::container;
69 using namespace ::com::sun::star::lang;
70 using namespace ::com::sun::star::beans;
71 using namespace ::com::sun::star::util;
72 using namespace ::com::sun::star::ui::dialogs;
73 using namespace ::sfx2;
75 class SfxNotificationListener_Impl : public cppu::WeakImplHelper< XDispatchResultListener >
77 public:
78 virtual void SAL_CALL dispatchFinished( const DispatchResultEvent& aEvent ) override;
79 virtual void SAL_CALL disposing( const EventObject& aEvent ) override;
82 void SAL_CALL SfxNotificationListener_Impl::dispatchFinished( const DispatchResultEvent& )
84 ShutdownIcon::LeaveModalMode();
87 void SAL_CALL SfxNotificationListener_Impl::disposing( const EventObject& )
91 OUString SAL_CALL ShutdownIcon::getImplementationName()
93 return "com.sun.star.comp.desktop.QuickstartWrapper";
96 sal_Bool SAL_CALL ShutdownIcon::supportsService(OUString const & ServiceName)
98 return cppu::supportsService(this, ServiceName);
101 css::uno::Sequence<OUString> SAL_CALL ShutdownIcon::getSupportedServiceNames()
103 return { "com.sun.star.office.Quickstart" };
106 bool ShutdownIcon::bModalMode = false;
107 ShutdownIcon* ShutdownIcon::pShutdownIcon = nullptr;
109 extern "C" {
110 static void disabled_initSystray() { }
111 static void disabled_deInitSystray() { }
114 namespace {
116 boost::logic::tribool loaded(boost::logic::indeterminate); // loplugin:constvars:ignore
117 oslGenericFunction pInitSystray = disabled_initSystray;
118 oslGenericFunction pDeInitSystray = disabled_deInitSystray;
120 bool LoadModule()
122 if (boost::logic::indeterminate(loaded))
124 #ifdef ENABLE_QUICKSTART_APPLET
125 # ifdef _WIN32
126 pInitSystray = win32_init_sys_tray;
127 pDeInitSystray = win32_shutdown_sys_tray;
128 loaded = true;
129 # elif defined MACOSX
130 pInitSystray = aqua_init_systray;
131 pDeInitSystray = aqua_shutdown_systray;
132 loaded = true;
133 # endif // MACOSX
134 #endif // ENABLE_QUICKSTART_APPLET
136 assert(!boost::logic::indeterminate(loaded));
137 return bool(loaded);
142 void ShutdownIcon::initSystray()
144 if (m_bInitialized)
145 return;
146 m_bInitialized = true;
148 (void) LoadModule();
149 m_bVeto = true;
150 pInitSystray();
153 void ShutdownIcon::deInitSystray()
155 if (!m_bInitialized)
156 return;
158 if (pDeInitSystray)
159 pDeInitSystray();
161 m_bVeto = false;
162 pInitSystray = nullptr;
163 pDeInitSystray = nullptr;
165 m_pFileDlg.reset();
166 m_bInitialized = false;
170 ShutdownIcon::ShutdownIcon( const css::uno::Reference< XComponentContext > & rxContext ) :
171 ShutdownIconServiceBase( m_aMutex ),
172 m_bVeto ( false ),
173 m_bListenForTermination ( false ),
174 m_bSystemDialogs( false ),
175 m_xContext( rxContext ),
176 m_bInitialized( false )
178 m_bSystemDialogs = officecfg::Office::Common::Misc::UseSystemFileDialog::get();
181 ShutdownIcon::~ShutdownIcon()
183 deInitSystray();
187 void ShutdownIcon::OpenURL( const OUString& aURL, const OUString& rTarget, const Sequence< PropertyValue >& aArgs )
189 if ( !getInstance() || !getInstance()->m_xDesktop.is() )
190 return;
192 css::uno::Reference < XDispatchProvider > xDispatchProvider = getInstance()->m_xDesktop;
193 if ( !xDispatchProvider.is() )
194 return;
196 css::util::URL aDispatchURL;
197 aDispatchURL.Complete = aURL;
199 css::uno::Reference< util::XURLTransformer > xURLTransformer( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
202 css::uno::Reference< css::frame::XDispatch > xDispatch;
204 xURLTransformer->parseStrict( aDispatchURL );
205 xDispatch = xDispatchProvider->queryDispatch( aDispatchURL, rTarget, 0 );
206 if ( xDispatch.is() )
207 xDispatch->dispatch( aDispatchURL, aArgs );
209 catch ( css::uno::RuntimeException& )
211 throw;
213 catch ( css::uno::Exception& )
219 void ShutdownIcon::FileOpen()
221 if ( getInstance() && getInstance()->m_xDesktop.is() )
223 ::SolarMutexGuard aGuard;
224 EnterModalMode();
225 getInstance()->StartFileDialog();
230 void ShutdownIcon::FromTemplate()
232 if ( !getInstance() || !getInstance()->m_xDesktop.is() )
233 return;
235 css::uno::Reference < css::frame::XFramesSupplier > xDesktop = getInstance()->m_xDesktop;
236 css::uno::Reference < css::frame::XFrame > xFrame( xDesktop->getActiveFrame() );
237 if ( !xFrame.is() )
238 xFrame = xDesktop;
240 URL aTargetURL;
241 aTargetURL.Complete = ".uno:NewDoc";
242 css::uno::Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
243 xTrans->parseStrict( aTargetURL );
245 css::uno::Reference < css::frame::XDispatchProvider > xProv( xFrame, UNO_QUERY );
246 css::uno::Reference < css::frame::XDispatch > xDisp;
247 if ( xProv.is() )
249 xDisp = xProv->queryDispatch( aTargetURL, "_self", 0 );
251 if ( !xDisp.is() )
252 return;
254 Sequence<PropertyValue> aArgs(1);
255 PropertyValue* pArg = aArgs.getArray();
256 pArg[0].Name = "Referer";
257 pArg[0].Value <<= OUString("private:user");
258 css::uno::Reference< css::frame::XNotifyingDispatch > xNotifier(xDisp, UNO_QUERY);
259 if (xNotifier.is())
261 EnterModalMode();
262 xNotifier->dispatchWithNotification(aTargetURL, aArgs, new SfxNotificationListener_Impl);
264 else
265 xDisp->dispatch( aTargetURL, aArgs );
268 OUString ShutdownIcon::GetUrlDescription( const OUString& aUrl )
270 ::SolarMutexGuard aGuard;
272 return SvFileInformationManager::GetDescription( INetURLObject( aUrl ) );
275 void ShutdownIcon::StartFileDialog()
277 ::SolarMutexGuard aGuard;
279 bool bDirty = ( m_bSystemDialogs != officecfg::Office::Common::Misc::UseSystemFileDialog::get() );
281 if ( m_pFileDlg && bDirty )
283 // Destroy instance as changing the system file dialog setting
284 // forces us to create a new FileDialogHelper instance!
285 m_pFileDlg.reset();
288 if ( !m_pFileDlg )
289 m_pFileDlg.reset( new FileDialogHelper(
290 ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
291 FileDialogFlags::MultiSelection, OUString(), SfxFilterFlags::NONE, SfxFilterFlags::NONE, nullptr ) );
292 m_pFileDlg->StartExecuteModal( LINK( this, ShutdownIcon, DialogClosedHdl_Impl ) );
295 IMPL_LINK( ShutdownIcon, DialogClosedHdl_Impl, FileDialogHelper*, /*unused*/, void )
297 DBG_ASSERT( m_pFileDlg, "ShutdownIcon, DialogClosedHdl_Impl(): no file dialog" );
299 // use constructor for filling up filters automatically!
300 if ( ERRCODE_NONE == m_pFileDlg->GetError() )
302 css::uno::Reference< XFilePicker3 > xPicker = m_pFileDlg->GetFilePicker();
307 if ( xPicker.is() )
310 css::uno::Reference < XFilePickerControlAccess > xPickerControls ( xPicker, UNO_QUERY );
312 Sequence< OUString > sFiles = xPicker->getSelectedFiles();
313 int nFiles = sFiles.getLength();
315 int nArgs=3;
316 Sequence< PropertyValue > aArgs(3);
318 css::uno::Reference < css::task::XInteractionHandler2 > xInteraction(
319 task::InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) );
321 aArgs[0].Name = "InteractionHandler";
322 aArgs[0].Value <<= xInteraction;
324 aArgs[1].Name = "MacroExecutionMode";
325 aArgs[1].Value <<= sal_Int16(css::document::MacroExecMode::USE_CONFIG);
327 aArgs[2].Name = "UpdateDocMode";
328 aArgs[2].Value <<= sal_Int16(css::document::UpdateDocMode::ACCORDING_TO_CONFIG);
330 // use the filedlghelper to get the current filter name,
331 // because it removes the extensions before you get the filter name.
332 OUString aFilterName( m_pFileDlg->GetCurrentFilter() );
334 if ( xPickerControls.is() )
337 // Set readonly flag
339 bool bReadOnly = false;
342 xPickerControls->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 ) >>= bReadOnly;
344 // Only set property if readonly is set to TRUE
346 if ( bReadOnly )
348 aArgs.realloc( ++nArgs );
349 aArgs[nArgs-1].Name = "ReadOnly";
350 aArgs[nArgs-1].Value <<= bReadOnly;
353 // Get version string
355 sal_Int32 iVersion = -1;
357 xPickerControls->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION, ControlActions::GET_SELECTED_ITEM_INDEX ) >>= iVersion;
359 if ( iVersion >= 0 )
361 sal_Int16 uVersion = static_cast<sal_Int16>(iVersion);
363 aArgs.realloc( ++nArgs );
364 aArgs[nArgs-1].Name = "Version";
365 aArgs[nArgs-1].Value <<= uVersion;
368 // Retrieve the current filter
370 if ( aFilterName.isEmpty() )
371 xPickerControls->getValue( CommonFilePickerElementIds::LISTBOX_FILTER, ControlActions::GET_SELECTED_ITEM ) >>= aFilterName;
376 // Convert UI filter name to internal filter name
378 if ( !aFilterName.isEmpty() )
380 std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4UIName( aFilterName, SfxFilterFlags::NONE, SfxFilterFlags::NOTINFILEDLG );
382 if ( pFilter )
384 aFilterName = pFilter->GetFilterName();
386 if ( !aFilterName.isEmpty() )
388 aArgs.realloc( ++nArgs );
389 aArgs[nArgs-1].Name = "FilterName";
390 aArgs[nArgs-1].Value <<= aFilterName;
395 if ( 1 == nFiles )
396 OpenURL( sFiles[0], "_default", aArgs );
397 else
399 OUString aBaseDirURL = sFiles[0];
400 if ( !aBaseDirURL.isEmpty() && !aBaseDirURL.endsWith("/") )
401 aBaseDirURL += "/";
403 int iFiles;
404 for ( iFiles = 1; iFiles < nFiles; iFiles++ )
406 OUString aURL = aBaseDirURL + sFiles[iFiles];
407 OpenURL( aURL, "_default", aArgs );
412 catch ( ... )
417 #ifdef _WIN32
418 // Destroy dialog to prevent problems with custom controls
419 // This fix is dependent on the dialog settings. Destroying the dialog here will
420 // crash the non-native dialog implementation! Therefore make this dependent on
421 // the settings.
422 if ( officecfg::Office::Common::Misc::UseSystemFileDialog::get() )
424 m_pFileDlg.reset();
426 #endif
428 LeaveModalMode();
432 void ShutdownIcon::addTerminateListener()
434 ShutdownIcon* pInst = getInstance();
435 if ( ! pInst)
436 return;
438 if (pInst->m_bListenForTermination)
439 return;
441 css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
442 if ( ! xDesktop.is())
443 return;
445 xDesktop->addTerminateListener( pInst );
446 pInst->m_bListenForTermination = true;
450 void ShutdownIcon::terminateDesktop()
452 ShutdownIcon* pInst = getInstance();
453 if ( ! pInst)
454 return;
456 css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
457 if ( ! xDesktop.is())
458 return;
460 // always remove ourselves as listener
461 pInst->m_bListenForTermination = true;
462 xDesktop->removeTerminateListener( pInst );
464 // terminate desktop only if no tasks exist
465 css::uno::Reference< XIndexAccess > xTasks = xDesktop->getFrames();
466 if( xTasks.is() && xTasks->getCount() < 1 )
467 Application::Quit();
469 // remove the instance pointer
470 ShutdownIcon::pShutdownIcon = nullptr;
474 ShutdownIcon* ShutdownIcon::getInstance()
476 OSL_ASSERT( pShutdownIcon );
477 return pShutdownIcon;
481 ShutdownIcon* ShutdownIcon::createInstance()
483 if (pShutdownIcon)
484 return pShutdownIcon;
486 try {
487 std::unique_ptr<ShutdownIcon> pIcon(new ShutdownIcon( comphelper::getProcessComponentContext() ));
488 pIcon->init ();
489 pShutdownIcon = pIcon.release();
490 } catch (...) {
493 return pShutdownIcon;
496 void ShutdownIcon::init()
498 css::uno::Reference < XDesktop2 > xDesktop = Desktop::create( m_xContext );
499 osl::MutexGuard aGuard(m_aMutex);
500 m_xDesktop = xDesktop;
504 void SAL_CALL ShutdownIcon::disposing()
506 m_xContext.clear();
507 m_xDesktop.clear();
509 deInitSystray();
513 // XEventListener
514 void SAL_CALL ShutdownIcon::disposing( const css::lang::EventObject& )
519 // XTerminateListener
520 void SAL_CALL ShutdownIcon::queryTermination( const css::lang::EventObject& )
522 SAL_INFO("sfx.appl", "ShutdownIcon::queryTermination: veto is " << m_bVeto);
523 osl::MutexGuard aGuard( m_aMutex );
525 if ( m_bVeto )
526 throw css::frame::TerminationVetoException();
530 void SAL_CALL ShutdownIcon::notifyTermination( const css::lang::EventObject& )
535 void SAL_CALL ShutdownIcon::initialize( const css::uno::Sequence< css::uno::Any>& aArguments )
537 ::osl::ResettableMutexGuard aGuard( m_aMutex );
539 // third argument only sets veto, everything else will be ignored!
540 if (aArguments.getLength() > 2)
542 bool bVeto = ::cppu::any2bool(aArguments[2]);
543 m_bVeto = bVeto;
544 return;
547 if ( aArguments.getLength() > 0 )
549 if ( !ShutdownIcon::pShutdownIcon )
553 bool bQuickstart = ::cppu::any2bool( aArguments[0] );
554 if( !bQuickstart && !GetAutostart() )
555 return;
556 aGuard.clear();
557 init ();
558 aGuard.reset();
559 if ( !m_xDesktop.is() )
560 return;
562 /* Create a sub-classed instance - foo */
563 ShutdownIcon::pShutdownIcon = this;
564 initSystray();
566 catch(const css::lang::IllegalArgumentException&)
571 if ( aArguments.getLength() > 1 )
573 bool bAutostart = ::cppu::any2bool( aArguments[1] );
574 if (bAutostart && !GetAutostart())
575 SetAutostart( true );
576 if (!bAutostart && GetAutostart())
577 SetAutostart( false );
583 void ShutdownIcon::EnterModalMode()
585 bModalMode = true;
589 void ShutdownIcon::LeaveModalMode()
591 bModalMode = false;
594 #ifdef _WIN32
595 // defined in shutdowniconw32.cxx
596 #elif defined MACOSX
597 // defined in shutdowniconaqua.cxx
598 #else
599 bool ShutdownIcon::IsQuickstarterInstalled()
601 return false;
603 #endif
606 #ifdef ENABLE_QUICKSTART_APPLET
607 #ifdef _WIN32
608 OUString ShutdownIcon::getShortcutName()
610 return GetAutostartFolderNameW32() + "\\" + SfxResId(STR_QUICKSTART_LNKNAME) + ".lnk";
612 #endif // _WIN32
613 #endif
615 bool ShutdownIcon::GetAutostart( )
617 #if defined MACOSX
618 return true;
619 #elif defined ENABLE_QUICKSTART_APPLET
620 bool bRet = false;
621 OUString aShortcut( getShortcutName() );
622 OUString aShortcutUrl;
623 osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
624 osl::File f( aShortcutUrl );
625 osl::File::RC error = f.open( osl_File_OpenFlag_Read );
626 if( error == osl::File::E_None )
628 f.close();
629 bRet = true;
631 return bRet;
632 #else // ENABLE_QUICKSTART_APPLET
633 return false;
634 #endif
637 void ShutdownIcon::SetAutostart( bool bActivate )
639 #ifdef ENABLE_QUICKSTART_APPLET
640 #ifndef MACOSX
641 OUString aShortcut( getShortcutName() );
642 #endif
644 if( bActivate && IsQuickstarterInstalled() )
646 #ifdef _WIN32
647 EnableAutostartW32( aShortcut );
648 #endif
650 else
652 #ifndef MACOSX
653 OUString aShortcutUrl;
654 ::osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
655 ::osl::File::remove( aShortcutUrl );
656 #endif
658 #else
659 (void)bActivate; // unused variable
660 #endif // ENABLE_QUICKSTART_APPLET
663 const ::sal_Int32 PROPHANDLE_TERMINATEVETOSTATE = 0;
665 // XFastPropertySet
666 void SAL_CALL ShutdownIcon::setFastPropertyValue( ::sal_Int32 nHandle,
667 const css::uno::Any& aValue )
669 switch(nHandle)
671 case PROPHANDLE_TERMINATEVETOSTATE :
673 // use new value in case it's a valid information only
674 bool bState( false );
675 if (! (aValue >>= bState))
676 return;
678 m_bVeto = bState;
679 if (m_bVeto && ! m_bListenForTermination)
680 addTerminateListener();
682 break;
684 default :
685 throw css::beans::UnknownPropertyException(OUString::number(nHandle));
689 // XFastPropertySet
690 css::uno::Any SAL_CALL ShutdownIcon::getFastPropertyValue( ::sal_Int32 nHandle )
692 css::uno::Any aValue;
693 switch(nHandle)
695 case PROPHANDLE_TERMINATEVETOSTATE :
697 bool bState = (m_bListenForTermination && m_bVeto);
698 aValue <<= bState;
700 break;
702 default :
703 throw css::beans::UnknownPropertyException(OUString::number(nHandle));
706 return aValue;
709 namespace {
711 struct Instance {
712 explicit Instance(
713 css::uno::Reference<css::uno::XComponentContext> const & context):
714 instance(static_cast<cppu::OWeakObject *>(new ShutdownIcon(context)))
717 rtl::Reference<css::uno::XInterface> instance;
720 struct Singleton:
721 public rtl::StaticWithArg<
722 Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton>
727 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
728 com_sun_star_comp_desktop_QuickstartWrapper_get_implementation(
729 css::uno::XComponentContext *context,
730 css::uno::Sequence<css::uno::Any> const &)
732 return cppu::acquire(static_cast<cppu::OWeakObject *>(
733 Singleton::get(context).instance.get()));
736 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */