LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / appl / shutdownicon.cxx
blob8d221e07d90e1816e1e7c33d132d92a67b7d5a4c
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 "shutdownicon.hxx"
24 #include <sfx2/strings.hrc>
25 #include <sfx2/app.hxx>
26 #include <osl/mutex.hxx>
27 #include <svtools/imagemgr.hxx>
28 #include <com/sun/star/task/InteractionHandler.hpp>
29 #include <com/sun/star/frame/Desktop.hpp>
30 #include <com/sun/star/frame/TerminationVetoException.hpp>
31 #include <com/sun/star/frame/XDispatchResultListener.hpp>
32 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
33 #include <com/sun/star/frame/XFramesSupplier.hpp>
34 #include <com/sun/star/frame/XFrame.hpp>
35 #include <com/sun/star/util/URLTransformer.hpp>
36 #include <com/sun/star/util/XURLTransformer.hpp>
37 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
38 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
39 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
40 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
41 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
42 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
43 #include <com/sun/star/document/MacroExecMode.hpp>
44 #include <com/sun/star/document/UpdateDocMode.hpp>
45 #include <sfx2/filedlghelper.hxx>
46 #include <sfx2/docfilt.hxx>
47 #include <sfx2/fcontnr.hxx>
48 #include <comphelper/processfactory.hxx>
49 #include <comphelper/propertyvalue.hxx>
50 #include <cppuhelper/implbase.hxx>
51 #include <cppuhelper/supportsservice.hxx>
52 #include <comphelper/extract.hxx>
53 #include <officecfg/Office/Common.hxx>
54 #include <tools/urlobj.hxx>
55 #include <tools/debug.hxx>
56 #include <osl/file.hxx>
57 #include <osl/module.hxx>
58 #include <rtl/ref.hxx>
59 #include <vcl/svapp.hxx>
61 #include <sfx2/sfxresid.hxx>
63 using namespace ::com::sun::star;
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::frame;
66 using namespace ::com::sun::star::container;
67 using namespace ::com::sun::star::lang;
68 using namespace ::com::sun::star::beans;
69 using namespace ::com::sun::star::util;
70 using namespace ::com::sun::star::ui::dialogs;
71 using namespace ::sfx2;
73 class SfxNotificationListener_Impl : public cppu::WeakImplHelper< XDispatchResultListener >
75 public:
76 virtual void SAL_CALL dispatchFinished( const DispatchResultEvent& aEvent ) override;
77 virtual void SAL_CALL disposing( const EventObject& aEvent ) override;
80 void SAL_CALL SfxNotificationListener_Impl::dispatchFinished( const DispatchResultEvent& )
82 ShutdownIcon::LeaveModalMode();
85 void SAL_CALL SfxNotificationListener_Impl::disposing( const EventObject& )
89 OUString SAL_CALL ShutdownIcon::getImplementationName()
91 return "com.sun.star.comp.desktop.QuickstartWrapper";
94 sal_Bool SAL_CALL ShutdownIcon::supportsService(OUString const & ServiceName)
96 return cppu::supportsService(this, ServiceName);
99 css::uno::Sequence<OUString> SAL_CALL ShutdownIcon::getSupportedServiceNames()
101 return { "com.sun.star.office.Quickstart" };
104 bool ShutdownIcon::bModalMode = false;
105 rtl::Reference<ShutdownIcon> ShutdownIcon::pShutdownIcon;
107 void ShutdownIcon::initSystray()
109 if (m_bInitialized)
110 return;
111 m_bInitialized = true;
113 #ifdef ENABLE_QUICKSTART_APPLET
114 # ifdef _WIN32
115 win32_init_sys_tray();
116 # elif defined MACOSX
117 aqua_init_systray();
118 # endif // MACOSX
119 #endif // ENABLE_QUICKSTART_APPLET
122 void ShutdownIcon::deInitSystray()
124 if (!m_bInitialized)
125 return;
127 #ifdef ENABLE_QUICKSTART_APPLET
128 # ifdef _WIN32
129 win32_shutdown_sys_tray();
130 # elif defined MACOSX
131 aqua_shutdown_systray();
132 # endif // MACOSX
133 #endif // ENABLE_QUICKSTART_APPLET
135 m_bVeto = false;
137 m_pFileDlg.reset();
138 m_bInitialized = false;
142 ShutdownIcon::ShutdownIcon( const css::uno::Reference< XComponentContext > & rxContext ) :
143 ShutdownIconServiceBase( m_aMutex ),
144 m_bVeto ( false ),
145 m_bListenForTermination ( false ),
146 m_bSystemDialogs( false ),
147 m_xContext( rxContext ),
148 m_bInitialized( false )
150 m_bSystemDialogs = officecfg::Office::Common::Misc::UseSystemFileDialog::get();
153 ShutdownIcon::~ShutdownIcon()
155 deInitSystray();
159 void ShutdownIcon::OpenURL( const OUString& aURL, const OUString& rTarget, const Sequence< PropertyValue >& aArgs )
161 if ( !getInstance() || !getInstance()->m_xDesktop.is() )
162 return;
164 css::uno::Reference < XDispatchProvider > xDispatchProvider = getInstance()->m_xDesktop;
165 if ( !xDispatchProvider.is() )
166 return;
168 css::util::URL aDispatchURL;
169 aDispatchURL.Complete = aURL;
171 css::uno::Reference< util::XURLTransformer > xURLTransformer( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
174 css::uno::Reference< css::frame::XDispatch > xDispatch;
176 xURLTransformer->parseStrict( aDispatchURL );
177 xDispatch = xDispatchProvider->queryDispatch( aDispatchURL, rTarget, 0 );
178 if ( xDispatch.is() )
179 xDispatch->dispatch( aDispatchURL, aArgs );
181 catch ( css::uno::RuntimeException& )
183 throw;
185 catch ( css::uno::Exception& )
191 void ShutdownIcon::FileOpen()
193 if ( getInstance() && getInstance()->m_xDesktop.is() )
195 ::SolarMutexGuard aGuard;
196 EnterModalMode();
197 getInstance()->StartFileDialog();
202 void ShutdownIcon::FromTemplate()
204 if ( !getInstance() || !getInstance()->m_xDesktop.is() )
205 return;
207 css::uno::Reference < css::frame::XFramesSupplier > xDesktop = getInstance()->m_xDesktop;
208 css::uno::Reference < css::frame::XFrame > xFrame( xDesktop->getActiveFrame() );
209 if ( !xFrame.is() )
210 xFrame = xDesktop;
212 URL aTargetURL;
213 aTargetURL.Complete = ".uno:NewDoc";
214 css::uno::Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
215 xTrans->parseStrict( aTargetURL );
217 css::uno::Reference < css::frame::XDispatchProvider > xProv( xFrame, UNO_QUERY );
218 css::uno::Reference < css::frame::XDispatch > xDisp;
219 if ( xProv.is() )
221 xDisp = xProv->queryDispatch( aTargetURL, "_self", 0 );
223 if ( !xDisp.is() )
224 return;
226 Sequence<PropertyValue> aArgs(1);
227 PropertyValue* pArg = aArgs.getArray();
228 pArg[0].Name = "Referer";
229 pArg[0].Value <<= OUString("private:user");
230 css::uno::Reference< css::frame::XNotifyingDispatch > xNotifier(xDisp, UNO_QUERY);
231 if (xNotifier.is())
233 EnterModalMode();
234 xNotifier->dispatchWithNotification(aTargetURL, aArgs, new SfxNotificationListener_Impl);
236 else
237 xDisp->dispatch( aTargetURL, aArgs );
240 OUString ShutdownIcon::GetUrlDescription( const OUString& aUrl )
242 ::SolarMutexGuard aGuard;
244 return SvFileInformationManager::GetDescription( INetURLObject( aUrl ) );
247 void ShutdownIcon::StartFileDialog()
249 ::SolarMutexGuard aGuard;
251 bool bDirty = ( m_bSystemDialogs != officecfg::Office::Common::Misc::UseSystemFileDialog::get() );
253 if ( m_pFileDlg && bDirty )
255 // Destroy instance as changing the system file dialog setting
256 // forces us to create a new FileDialogHelper instance!
257 m_pFileDlg.reset();
260 if ( !m_pFileDlg )
261 m_pFileDlg.reset( new FileDialogHelper(
262 ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
263 FileDialogFlags::MultiSelection, OUString(), SfxFilterFlags::NONE, SfxFilterFlags::NONE, nullptr ) );
264 m_pFileDlg->StartExecuteModal( LINK( this, ShutdownIcon, DialogClosedHdl_Impl ) );
267 IMPL_LINK( ShutdownIcon, DialogClosedHdl_Impl, FileDialogHelper*, /*unused*/, void )
269 DBG_ASSERT( m_pFileDlg, "ShutdownIcon, DialogClosedHdl_Impl(): no file dialog" );
271 // use constructor for filling up filters automatically!
272 if ( ERRCODE_NONE == m_pFileDlg->GetError() )
274 css::uno::Reference< XFilePicker3 > xPicker = m_pFileDlg->GetFilePicker();
279 if ( xPicker.is() )
282 css::uno::Reference < XFilePickerControlAccess > xPickerControls ( xPicker, UNO_QUERY );
284 Sequence< OUString > sFiles = xPicker->getSelectedFiles();
285 int nFiles = sFiles.getLength();
287 css::uno::Reference < css::task::XInteractionHandler2 > xInteraction(
288 task::InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) );
290 int nArgs=3;
291 Sequence< PropertyValue > aArgs{
292 comphelper::makePropertyValue("InteractionHandler", xInteraction),
293 comphelper::makePropertyValue("MacroExecutionMode", sal_Int16(css::document::MacroExecMode::USE_CONFIG)),
294 comphelper::makePropertyValue("UpdateDocMode", sal_Int16(css::document::UpdateDocMode::ACCORDING_TO_CONFIG))
297 // use the filedlghelper to get the current filter name,
298 // because it removes the extensions before you get the filter name.
299 OUString aFilterName( m_pFileDlg->GetCurrentFilter() );
301 if ( xPickerControls.is() )
304 // Set readonly flag
306 bool bReadOnly = false;
309 xPickerControls->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 ) >>= bReadOnly;
311 // Only set property if readonly is set to TRUE
313 if ( bReadOnly )
315 aArgs.realloc( ++nArgs );
316 auto pArgs = aArgs.getArray();
317 pArgs[nArgs-1].Name = "ReadOnly";
318 pArgs[nArgs-1].Value <<= bReadOnly;
321 // Get version string
323 sal_Int32 iVersion = -1;
325 xPickerControls->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION, ControlActions::GET_SELECTED_ITEM_INDEX ) >>= iVersion;
327 if ( iVersion >= 0 )
329 sal_Int16 uVersion = static_cast<sal_Int16>(iVersion);
331 aArgs.realloc( ++nArgs );
332 auto pArgs = aArgs.getArray();
333 pArgs[nArgs-1].Name = "Version";
334 pArgs[nArgs-1].Value <<= uVersion;
337 // Retrieve the current filter
339 if ( aFilterName.isEmpty() )
340 xPickerControls->getValue( CommonFilePickerElementIds::LISTBOX_FILTER, ControlActions::GET_SELECTED_ITEM ) >>= aFilterName;
345 // Convert UI filter name to internal filter name
347 if ( !aFilterName.isEmpty() )
349 std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4UIName( aFilterName, SfxFilterFlags::NONE, SfxFilterFlags::NOTINFILEDLG );
351 if ( pFilter )
353 aFilterName = pFilter->GetFilterName();
355 if ( !aFilterName.isEmpty() )
357 aArgs.realloc( ++nArgs );
358 auto pArgs = aArgs.getArray();
359 pArgs[nArgs-1].Name = "FilterName";
360 pArgs[nArgs-1].Value <<= aFilterName;
365 if ( 1 == nFiles )
366 OpenURL( sFiles[0], "_default", aArgs );
367 else
369 OUString aBaseDirURL = sFiles[0];
370 if ( !aBaseDirURL.isEmpty() && !aBaseDirURL.endsWith("/") )
371 aBaseDirURL += "/";
373 int iFiles;
374 for ( iFiles = 1; iFiles < nFiles; iFiles++ )
376 OUString aURL = aBaseDirURL + sFiles[iFiles];
377 OpenURL( aURL, "_default", aArgs );
382 catch ( ... )
387 #ifdef _WIN32
388 // Destroy dialog to prevent problems with custom controls
389 // This fix is dependent on the dialog settings. Destroying the dialog here will
390 // crash the non-native dialog implementation! Therefore make this dependent on
391 // the settings.
392 if ( officecfg::Office::Common::Misc::UseSystemFileDialog::get() )
394 m_pFileDlg.reset();
396 #endif
398 LeaveModalMode();
402 void ShutdownIcon::addTerminateListener()
404 ShutdownIcon* pInst = getInstance();
405 if ( ! pInst)
406 return;
408 if (pInst->m_bListenForTermination)
409 return;
411 css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
412 if ( ! xDesktop.is())
413 return;
415 xDesktop->addTerminateListener( pInst );
416 pInst->m_bListenForTermination = true;
420 void ShutdownIcon::terminateDesktop()
422 ShutdownIcon* pInst = getInstance();
423 if ( ! pInst)
424 return;
426 css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
427 if ( ! xDesktop.is())
428 return;
430 // always remove ourselves as listener
431 pInst->m_bListenForTermination = true;
432 xDesktop->removeTerminateListener( pInst );
434 // terminate desktop only if no tasks exist
435 css::uno::Reference< XIndexAccess > xTasks = xDesktop->getFrames();
436 if( xTasks.is() && xTasks->getCount() < 1 )
437 Application::Quit();
439 // remove the instance pointer
440 ShutdownIcon::pShutdownIcon = nullptr;
444 ShutdownIcon* ShutdownIcon::getInstance()
446 OSL_ASSERT( pShutdownIcon );
447 return pShutdownIcon.get();
451 ShutdownIcon* ShutdownIcon::createInstance()
453 if (pShutdownIcon)
454 return pShutdownIcon.get();
456 try {
457 rtl::Reference<ShutdownIcon> pIcon(new ShutdownIcon( comphelper::getProcessComponentContext() ));
458 pIcon->init ();
459 pShutdownIcon = pIcon;
460 } catch (...) {
463 return pShutdownIcon.get();
466 void ShutdownIcon::init()
468 css::uno::Reference < XDesktop2 > xDesktop = Desktop::create( m_xContext );
469 osl::MutexGuard aGuard(m_aMutex);
470 m_xDesktop = xDesktop;
474 void SAL_CALL ShutdownIcon::disposing()
476 m_xContext.clear();
477 m_xDesktop.clear();
479 deInitSystray();
483 // XEventListener
484 void SAL_CALL ShutdownIcon::disposing( const css::lang::EventObject& )
489 // XTerminateListener
490 void SAL_CALL ShutdownIcon::queryTermination( const css::lang::EventObject& )
492 SAL_INFO("sfx.appl", "ShutdownIcon::queryTermination: veto is " << m_bVeto);
493 osl::MutexGuard aGuard( m_aMutex );
495 if ( m_bVeto )
496 throw css::frame::TerminationVetoException();
500 void SAL_CALL ShutdownIcon::notifyTermination( const css::lang::EventObject& )
505 void SAL_CALL ShutdownIcon::initialize( const css::uno::Sequence< css::uno::Any>& aArguments )
507 ::osl::ResettableMutexGuard aGuard( m_aMutex );
509 // third argument only sets veto, everything else will be ignored!
510 if (aArguments.getLength() > 2)
512 bool bVeto = ::cppu::any2bool(aArguments[2]);
513 m_bVeto = bVeto;
514 return;
517 if ( aArguments.getLength() > 0 )
519 if ( !ShutdownIcon::pShutdownIcon )
523 bool bQuickstart = ::cppu::any2bool( aArguments[0] );
524 if( !bQuickstart && !GetAutostart() )
525 return;
526 aGuard.clear();
527 init ();
528 aGuard.reset();
529 if ( !m_xDesktop.is() )
530 return;
532 /* Create a sub-classed instance - foo */
533 ShutdownIcon::pShutdownIcon = this;
534 initSystray();
536 catch(const css::lang::IllegalArgumentException&)
541 if ( aArguments.getLength() > 1 )
543 bool bAutostart = ::cppu::any2bool( aArguments[1] );
544 if (bAutostart && !GetAutostart())
545 SetAutostart( true );
546 if (!bAutostart && GetAutostart())
547 SetAutostart( false );
553 void ShutdownIcon::EnterModalMode()
555 bModalMode = true;
559 void ShutdownIcon::LeaveModalMode()
561 bModalMode = false;
564 #ifdef _WIN32
565 // defined in shutdowniconw32.cxx
566 #elif defined MACOSX
567 // defined in shutdowniconaqua.cxx
568 #else
569 bool ShutdownIcon::IsQuickstarterInstalled()
571 return false;
573 #endif
576 #ifdef ENABLE_QUICKSTART_APPLET
577 #ifdef _WIN32
578 OUString ShutdownIcon::getShortcutName()
580 return GetAutostartFolderNameW32() + "\\" + SfxResId(STR_QUICKSTART_LNKNAME) + ".lnk";
582 #endif // _WIN32
583 #endif
585 bool ShutdownIcon::GetAutostart( )
587 #if defined MACOSX
588 return true;
589 #elif defined ENABLE_QUICKSTART_APPLET
590 bool bRet = false;
591 OUString aShortcut( getShortcutName() );
592 OUString aShortcutUrl;
593 osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
594 osl::File f( aShortcutUrl );
595 osl::File::RC error = f.open( osl_File_OpenFlag_Read );
596 if( error == osl::File::E_None )
598 f.close();
599 bRet = true;
601 return bRet;
602 #else // ENABLE_QUICKSTART_APPLET
603 return false;
604 #endif
607 void ShutdownIcon::SetAutostart( bool bActivate )
609 #ifdef ENABLE_QUICKSTART_APPLET
610 #ifndef MACOSX
611 OUString aShortcut( getShortcutName() );
612 #endif
614 if( bActivate && IsQuickstarterInstalled() )
616 #ifdef _WIN32
617 EnableAutostartW32( aShortcut );
618 #endif
620 else
622 #ifndef MACOSX
623 OUString aShortcutUrl;
624 ::osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
625 ::osl::File::remove( aShortcutUrl );
626 #endif
628 #else
629 (void)bActivate; // unused variable
630 #endif // ENABLE_QUICKSTART_APPLET
633 const ::sal_Int32 PROPHANDLE_TERMINATEVETOSTATE = 0;
635 // XFastPropertySet
636 void SAL_CALL ShutdownIcon::setFastPropertyValue( ::sal_Int32 nHandle,
637 const css::uno::Any& aValue )
639 switch(nHandle)
641 case PROPHANDLE_TERMINATEVETOSTATE :
643 // use new value in case it's a valid information only
644 bool bState( false );
645 if (! (aValue >>= bState))
646 return;
648 m_bVeto = bState;
649 if (m_bVeto && ! m_bListenForTermination)
650 addTerminateListener();
652 break;
654 default :
655 throw css::beans::UnknownPropertyException(OUString::number(nHandle));
659 // XFastPropertySet
660 css::uno::Any SAL_CALL ShutdownIcon::getFastPropertyValue( ::sal_Int32 nHandle )
662 css::uno::Any aValue;
663 switch(nHandle)
665 case PROPHANDLE_TERMINATEVETOSTATE :
667 bool bState = (m_bListenForTermination && m_bVeto);
668 aValue <<= bState;
670 break;
672 default :
673 throw css::beans::UnknownPropertyException(OUString::number(nHandle));
676 return aValue;
679 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
680 com_sun_star_comp_desktop_QuickstartWrapper_get_implementation(
681 css::uno::XComponentContext *context,
682 css::uno::Sequence<css::uno::Any> const &)
684 return cppu::acquire(new ShutdownIcon(context));
687 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */