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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
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
>
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;
110 static void disabled_initSystray() { }
111 static void disabled_deInitSystray() { }
116 boost::logic::tribool
loaded(boost::logic::indeterminate
); // loplugin:constvars:ignore
117 oslGenericFunction pInitSystray
= disabled_initSystray
;
118 oslGenericFunction pDeInitSystray
= disabled_deInitSystray
;
122 if (boost::logic::indeterminate(loaded
))
124 #ifdef ENABLE_QUICKSTART_APPLET
126 pInitSystray
= win32_init_sys_tray
;
127 pDeInitSystray
= win32_shutdown_sys_tray
;
129 # elif defined MACOSX
130 pInitSystray
= aqua_init_systray
;
131 pDeInitSystray
= aqua_shutdown_systray
;
134 #endif // ENABLE_QUICKSTART_APPLET
136 assert(!boost::logic::indeterminate(loaded
));
142 void ShutdownIcon::initSystray()
146 m_bInitialized
= true;
153 void ShutdownIcon::deInitSystray()
162 pInitSystray
= nullptr;
163 pDeInitSystray
= nullptr;
166 m_bInitialized
= false;
170 ShutdownIcon::ShutdownIcon( const css::uno::Reference
< XComponentContext
> & rxContext
) :
171 ShutdownIconServiceBase( m_aMutex
),
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()
187 void ShutdownIcon::OpenURL( const OUString
& aURL
, const OUString
& rTarget
, const Sequence
< PropertyValue
>& aArgs
)
189 if ( !getInstance() || !getInstance()->m_xDesktop
.is() )
192 css::uno::Reference
< XDispatchProvider
> xDispatchProvider
= getInstance()->m_xDesktop
;
193 if ( !xDispatchProvider
.is() )
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
& )
213 catch ( css::uno::Exception
& )
219 void ShutdownIcon::FileOpen()
221 if ( getInstance() && getInstance()->m_xDesktop
.is() )
223 ::SolarMutexGuard aGuard
;
225 getInstance()->StartFileDialog();
230 void ShutdownIcon::FromTemplate()
232 if ( !getInstance() || !getInstance()->m_xDesktop
.is() )
235 css::uno::Reference
< css::frame::XFramesSupplier
> xDesktop
= getInstance()->m_xDesktop
;
236 css::uno::Reference
< css::frame::XFrame
> xFrame( xDesktop
->getActiveFrame() );
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
;
249 xDisp
= xProv
->queryDispatch( aTargetURL
, "_self", 0 );
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
);
262 xNotifier
->dispatchWithNotification(aTargetURL
, aArgs
, new SfxNotificationListener_Impl
);
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!
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();
310 css::uno::Reference
< XFilePickerControlAccess
> xPickerControls ( xPicker
, UNO_QUERY
);
312 Sequence
< OUString
> sFiles
= xPicker
->getSelectedFiles();
313 int nFiles
= sFiles
.getLength();
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() )
339 bool bReadOnly
= false;
342 xPickerControls
->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY
, 0 ) >>= bReadOnly
;
344 // Only set property if readonly is set to TRUE
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
;
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
);
384 aFilterName
= pFilter
->GetFilterName();
386 if ( !aFilterName
.isEmpty() )
388 aArgs
.realloc( ++nArgs
);
389 aArgs
[nArgs
-1].Name
= "FilterName";
390 aArgs
[nArgs
-1].Value
<<= aFilterName
;
396 OpenURL( sFiles
[0], "_default", aArgs
);
399 OUString aBaseDirURL
= sFiles
[0];
400 if ( !aBaseDirURL
.isEmpty() && !aBaseDirURL
.endsWith("/") )
404 for ( iFiles
= 1; iFiles
< nFiles
; iFiles
++ )
406 OUString aURL
= aBaseDirURL
+ sFiles
[iFiles
];
407 OpenURL( aURL
, "_default", aArgs
);
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
422 if ( officecfg::Office::Common::Misc::UseSystemFileDialog::get() )
432 void ShutdownIcon::addTerminateListener()
434 ShutdownIcon
* pInst
= getInstance();
438 if (pInst
->m_bListenForTermination
)
441 css::uno::Reference
< XDesktop2
> xDesktop
= pInst
->m_xDesktop
;
442 if ( ! xDesktop
.is())
445 xDesktop
->addTerminateListener( pInst
);
446 pInst
->m_bListenForTermination
= true;
450 void ShutdownIcon::terminateDesktop()
452 ShutdownIcon
* pInst
= getInstance();
456 css::uno::Reference
< XDesktop2
> xDesktop
= pInst
->m_xDesktop
;
457 if ( ! xDesktop
.is())
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 )
469 // remove the instance pointer
470 ShutdownIcon::pShutdownIcon
= nullptr;
474 ShutdownIcon
* ShutdownIcon::getInstance()
476 OSL_ASSERT( pShutdownIcon
);
477 return pShutdownIcon
;
481 ShutdownIcon
* ShutdownIcon::createInstance()
484 return pShutdownIcon
;
487 std::unique_ptr
<ShutdownIcon
> pIcon(new ShutdownIcon( comphelper::getProcessComponentContext() ));
489 pShutdownIcon
= pIcon
.release();
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()
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
);
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]);
547 if ( aArguments
.getLength() > 0 )
549 if ( !ShutdownIcon::pShutdownIcon
)
553 bool bQuickstart
= ::cppu::any2bool( aArguments
[0] );
554 if( !bQuickstart
&& !GetAutostart() )
559 if ( !m_xDesktop
.is() )
562 /* Create a sub-classed instance - foo */
563 ShutdownIcon::pShutdownIcon
= this;
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()
589 void ShutdownIcon::LeaveModalMode()
595 // defined in shutdowniconw32.cxx
597 // defined in shutdowniconaqua.cxx
599 bool ShutdownIcon::IsQuickstarterInstalled()
606 #ifdef ENABLE_QUICKSTART_APPLET
608 OUString
ShutdownIcon::getShortcutName()
610 return GetAutostartFolderNameW32() + "\\" + SfxResId(STR_QUICKSTART_LNKNAME
) + ".lnk";
615 bool ShutdownIcon::GetAutostart( )
619 #elif defined ENABLE_QUICKSTART_APPLET
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
)
632 #else // ENABLE_QUICKSTART_APPLET
637 void ShutdownIcon::SetAutostart( bool bActivate
)
639 #ifdef ENABLE_QUICKSTART_APPLET
641 OUString
aShortcut( getShortcutName() );
644 if( bActivate
&& IsQuickstarterInstalled() )
647 EnableAutostartW32( aShortcut
);
653 OUString aShortcutUrl
;
654 ::osl::File::getFileURLFromSystemPath( aShortcut
, aShortcutUrl
);
655 ::osl::File::remove( aShortcutUrl
);
659 (void)bActivate
; // unused variable
660 #endif // ENABLE_QUICKSTART_APPLET
663 const ::sal_Int32 PROPHANDLE_TERMINATEVETOSTATE
= 0;
666 void SAL_CALL
ShutdownIcon::setFastPropertyValue( ::sal_Int32 nHandle
,
667 const css::uno::Any
& aValue
)
671 case PROPHANDLE_TERMINATEVETOSTATE
:
673 // use new value in case it's a valid information only
674 bool bState( false );
675 if (! (aValue
>>= bState
))
679 if (m_bVeto
&& ! m_bListenForTermination
)
680 addTerminateListener();
685 throw css::beans::UnknownPropertyException(OUString::number(nHandle
));
690 css::uno::Any SAL_CALL
ShutdownIcon::getFastPropertyValue( ::sal_Int32 nHandle
)
692 css::uno::Any aValue
;
695 case PROPHANDLE_TERMINATEVETOSTATE
:
697 bool bState
= (m_bListenForTermination
&& m_bVeto
);
703 throw css::beans::UnknownPropertyException(OUString::number(nHandle
));
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
;
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: */