tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / sfx2 / source / appl / shutdownicon.cxx
blobb16be15bcf70205c530cb634c22e6caa1018285e
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 <svtools/imagemgr.hxx>
27 #include <com/sun/star/task/InteractionHandler.hpp>
28 #include <com/sun/star/frame/Desktop.hpp>
29 #include <com/sun/star/frame/TerminationVetoException.hpp>
30 #include <com/sun/star/frame/XDispatchResultListener.hpp>
31 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
32 #include <com/sun/star/frame/XFramesSupplier.hpp>
33 #include <com/sun/star/frame/XFrame.hpp>
34 #include <com/sun/star/util/URLTransformer.hpp>
35 #include <com/sun/star/util/XURLTransformer.hpp>
36 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
37 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
38 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
39 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
40 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
41 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
42 #include <com/sun/star/document/MacroExecMode.hpp>
43 #include <com/sun/star/document/UpdateDocMode.hpp>
44 #include <sfx2/filedlghelper.hxx>
45 #include <sfx2/docfilt.hxx>
46 #include <sfx2/fcontnr.hxx>
47 #include <comphelper/processfactory.hxx>
48 #include <comphelper/propertyvalue.hxx>
49 #include <cppuhelper/implbase.hxx>
50 #include <cppuhelper/supportsservice.hxx>
51 #include <comphelper/extract.hxx>
52 #include <officecfg/Office/Common.hxx>
53 #include <tools/urlobj.hxx>
54 #include <tools/debug.hxx>
55 #include <osl/diagnose.h>
56 #include <osl/file.hxx>
57 #include <osl/module.hxx>
58 #include <rtl/ref.hxx>
59 #include <utility>
60 #include <vcl/svapp.hxx>
62 #include <sfx2/sfxresid.hxx>
64 using namespace ::com::sun::star;
65 using namespace ::com::sun::star::uno;
66 using namespace ::com::sun::star::frame;
67 using namespace ::com::sun::star::container;
68 using namespace ::com::sun::star::lang;
69 using namespace ::com::sun::star::beans;
70 using namespace ::com::sun::star::util;
71 using namespace ::com::sun::star::ui::dialogs;
72 using namespace ::sfx2;
74 class SfxNotificationListener_Impl : public cppu::WeakImplHelper< XDispatchResultListener >
76 public:
77 virtual void SAL_CALL dispatchFinished( const DispatchResultEvent& aEvent ) override;
78 virtual void SAL_CALL disposing( const EventObject& aEvent ) override;
81 void SAL_CALL SfxNotificationListener_Impl::dispatchFinished( const DispatchResultEvent& )
83 ShutdownIcon::LeaveModalMode();
86 void SAL_CALL SfxNotificationListener_Impl::disposing( const EventObject& )
90 OUString SAL_CALL ShutdownIcon::getImplementationName()
92 return u"com.sun.star.comp.desktop.QuickstartWrapper"_ustr;
95 sal_Bool SAL_CALL ShutdownIcon::supportsService(OUString const & ServiceName)
97 return cppu::supportsService(this, ServiceName);
100 css::uno::Sequence<OUString> SAL_CALL ShutdownIcon::getSupportedServiceNames()
102 return { u"com.sun.star.office.Quickstart"_ustr };
105 bool ShutdownIcon::bModalMode = false;
106 rtl::Reference<ShutdownIcon> ShutdownIcon::pShutdownIcon;
108 void ShutdownIcon::initSystray()
110 if (m_bInitialized)
111 return;
112 m_bInitialized = true;
114 #ifdef ENABLE_QUICKSTART_APPLET
115 # ifdef _WIN32
116 win32_init_sys_tray();
117 # elif defined MACOSX
118 aqua_init_systray();
119 # endif // MACOSX
120 #endif // ENABLE_QUICKSTART_APPLET
123 void ShutdownIcon::deInitSystray()
125 if (!m_bInitialized)
126 return;
128 #ifdef ENABLE_QUICKSTART_APPLET
129 # ifdef _WIN32
130 win32_shutdown_sys_tray();
131 # elif defined MACOSX
132 aqua_shutdown_systray();
133 # endif // MACOSX
134 #endif // ENABLE_QUICKSTART_APPLET
136 m_bVeto = false;
138 m_pFileDlg.reset();
139 m_bInitialized = false;
142 static bool UseSystemFileDialog()
144 return !Application::IsHeadlessModeEnabled() && officecfg::Office::Common::Misc::UseSystemFileDialog::get();
147 ShutdownIcon::ShutdownIcon( css::uno::Reference< XComponentContext > xContext ) :
148 m_bVeto ( false ),
149 m_bListenForTermination ( false ),
150 m_bSystemDialogs(UseSystemFileDialog()),
151 m_xContext(std::move( xContext )),
152 m_bInitialized( false )
156 ShutdownIcon::~ShutdownIcon()
158 deInitSystray();
162 void ShutdownIcon::OpenURL( const OUString& aURL, const OUString& rTarget, const Sequence< PropertyValue >& aArgs )
164 if ( !getInstance() || !getInstance()->m_xDesktop.is() )
165 return;
167 css::uno::Reference < XDispatchProvider > xDispatchProvider = getInstance()->m_xDesktop;
168 if ( !xDispatchProvider.is() )
169 return;
171 css::util::URL aDispatchURL;
172 aDispatchURL.Complete = aURL;
174 css::uno::Reference< util::XURLTransformer > xURLTransformer( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
177 css::uno::Reference< css::frame::XDispatch > xDispatch;
179 xURLTransformer->parseStrict( aDispatchURL );
180 xDispatch = xDispatchProvider->queryDispatch( aDispatchURL, rTarget, 0 );
181 if ( xDispatch.is() )
182 xDispatch->dispatch( aDispatchURL, aArgs );
184 catch ( css::uno::RuntimeException& )
186 throw;
188 catch ( css::uno::Exception& )
194 void ShutdownIcon::FileOpen()
196 if ( getInstance() && getInstance()->m_xDesktop.is() )
198 ::SolarMutexGuard aGuard;
199 EnterModalMode();
200 getInstance()->StartFileDialog();
205 void ShutdownIcon::FromTemplate()
207 if ( !getInstance() || !getInstance()->m_xDesktop.is() )
208 return;
210 css::uno::Reference < css::frame::XFramesSupplier > xDesktop = getInstance()->m_xDesktop;
211 css::uno::Reference < css::frame::XFrame > xFrame( xDesktop->getActiveFrame() );
212 if ( !xFrame.is() )
213 xFrame = xDesktop;
215 URL aTargetURL;
216 aTargetURL.Complete = ".uno:NewDoc";
217 css::uno::Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
218 xTrans->parseStrict( aTargetURL );
220 css::uno::Reference < css::frame::XDispatchProvider > xProv( xFrame, UNO_QUERY );
221 css::uno::Reference < css::frame::XDispatch > xDisp;
222 if ( xProv.is() )
224 xDisp = xProv->queryDispatch( aTargetURL, u"_self"_ustr, 0 );
226 if ( !xDisp.is() )
227 return;
229 Sequence<PropertyValue> aArgs { comphelper::makePropertyValue(u"Referer"_ustr, u"private:user"_ustr) };
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( std::u16string_view aUrl )
242 return SvFileInformationManager::GetDescription( INetURLObject( aUrl ) );
245 void ShutdownIcon::StartFileDialog()
247 ::SolarMutexGuard aGuard;
249 bool bDirty = m_bSystemDialogs != UseSystemFileDialog();
251 if ( m_pFileDlg && bDirty )
253 // Destroy instance as changing the system file dialog setting
254 // forces us to create a new FileDialogHelper instance!
255 m_pFileDlg.reset();
258 if ( !m_pFileDlg )
259 m_pFileDlg.reset( new FileDialogHelper(
260 ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
261 FileDialogFlags::MultiSelection, OUString(), SfxFilterFlags::NONE, SfxFilterFlags::NONE, nullptr ) );
262 m_pFileDlg->StartExecuteModal( LINK( this, ShutdownIcon, DialogClosedHdl_Impl ) );
265 IMPL_LINK( ShutdownIcon, DialogClosedHdl_Impl, FileDialogHelper*, /*unused*/, void )
267 DBG_ASSERT( m_pFileDlg, "ShutdownIcon, DialogClosedHdl_Impl(): no file dialog" );
269 // use constructor for filling up filters automatically!
270 if ( ERRCODE_NONE == m_pFileDlg->GetError() )
272 css::uno::Reference< XFilePicker3 > xPicker = m_pFileDlg->GetFilePicker();
277 if ( xPicker.is() )
280 css::uno::Reference < XFilePickerControlAccess > xPickerControls ( xPicker, UNO_QUERY );
282 Sequence< OUString > sFiles = xPicker->getSelectedFiles();
283 int nFiles = sFiles.getLength();
285 css::uno::Reference < css::task::XInteractionHandler2 > xInteraction(
286 task::InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) );
288 int nArgs=3;
289 Sequence< PropertyValue > aArgs{
290 comphelper::makePropertyValue(u"InteractionHandler"_ustr, xInteraction),
291 comphelper::makePropertyValue(u"MacroExecutionMode"_ustr, sal_Int16(css::document::MacroExecMode::USE_CONFIG)),
292 comphelper::makePropertyValue(u"UpdateDocMode"_ustr, sal_Int16(css::document::UpdateDocMode::ACCORDING_TO_CONFIG))
295 // use the filedlghelper to get the current filter name,
296 // because it removes the extensions before you get the filter name.
297 OUString aFilterName( m_pFileDlg->GetCurrentFilter() );
299 if ( xPickerControls.is() )
302 // Set readonly flag
304 bool bReadOnly = false;
307 xPickerControls->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 ) >>= bReadOnly;
309 // Only set property if readonly is set to TRUE
311 if ( bReadOnly )
313 aArgs.realloc( ++nArgs );
314 auto pArgs = aArgs.getArray();
315 pArgs[nArgs-1].Name = "ReadOnly";
316 pArgs[nArgs-1].Value <<= bReadOnly;
319 // Get version string
321 sal_Int32 iVersion = -1;
323 xPickerControls->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION, ControlActions::GET_SELECTED_ITEM_INDEX ) >>= iVersion;
325 if ( iVersion >= 0 )
327 sal_Int16 uVersion = static_cast<sal_Int16>(iVersion);
329 aArgs.realloc( ++nArgs );
330 auto pArgs = aArgs.getArray();
331 pArgs[nArgs-1].Name = "Version";
332 pArgs[nArgs-1].Value <<= uVersion;
335 // Retrieve the current filter
337 if ( aFilterName.isEmpty() )
338 xPickerControls->getValue( CommonFilePickerElementIds::LISTBOX_FILTER, ControlActions::GET_SELECTED_ITEM ) >>= aFilterName;
343 // Convert UI filter name to internal filter name
345 if ( !aFilterName.isEmpty() )
347 std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4UIName( aFilterName, SfxFilterFlags::NONE, SfxFilterFlags::NOTINFILEDLG );
349 if ( pFilter )
351 aFilterName = pFilter->GetFilterName();
353 if ( !aFilterName.isEmpty() )
355 aArgs.realloc( ++nArgs );
356 auto pArgs = aArgs.getArray();
357 pArgs[nArgs-1].Name = "FilterName";
358 pArgs[nArgs-1].Value <<= aFilterName;
363 if ( 1 == nFiles )
364 OpenURL( sFiles[0], u"_default"_ustr, aArgs );
365 else
367 OUString aBaseDirURL = sFiles[0];
368 if ( !aBaseDirURL.isEmpty() && !aBaseDirURL.endsWith("/") )
369 aBaseDirURL += "/";
371 int iFiles;
372 for ( iFiles = 1; iFiles < nFiles; iFiles++ )
374 OUString aURL = aBaseDirURL + sFiles[iFiles];
375 OpenURL( aURL, u"_default"_ustr, aArgs );
380 catch ( ... )
385 #ifdef _WIN32
386 // Destroy dialog to prevent problems with custom controls
387 // This fix is dependent on the dialog settings. Destroying the dialog here will
388 // crash the non-native dialog implementation! Therefore make this dependent on
389 // the settings.
390 if (UseSystemFileDialog())
392 m_pFileDlg.reset();
394 #endif
396 LeaveModalMode();
400 void ShutdownIcon::addTerminateListener()
402 ShutdownIcon* pInst = getInstance();
403 if ( ! pInst)
404 return;
406 if (pInst->m_bListenForTermination)
407 return;
409 css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
410 if ( ! xDesktop.is())
411 return;
413 xDesktop->addTerminateListener( pInst );
414 pInst->m_bListenForTermination = true;
418 void ShutdownIcon::terminateDesktop()
420 ShutdownIcon* pInst = getInstance();
421 if ( ! pInst)
422 return;
424 css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
425 if ( ! xDesktop.is())
426 return;
428 // always remove ourselves as listener
429 pInst->m_bListenForTermination = true;
430 xDesktop->removeTerminateListener( pInst );
432 // terminate desktop only if no tasks exist
433 css::uno::Reference< XIndexAccess > xTasks = xDesktop->getFrames();
434 if( xTasks.is() && xTasks->getCount() < 1 )
435 Application::Quit();
437 // remove the instance pointer
438 ShutdownIcon::pShutdownIcon = nullptr;
442 ShutdownIcon* ShutdownIcon::getInstance()
444 OSL_ASSERT( pShutdownIcon );
445 return pShutdownIcon.get();
449 ShutdownIcon* ShutdownIcon::createInstance()
451 if (pShutdownIcon)
452 return pShutdownIcon.get();
454 try {
455 rtl::Reference<ShutdownIcon> pIcon(new ShutdownIcon( comphelper::getProcessComponentContext() ));
456 pIcon->init ();
457 pShutdownIcon = std::move(pIcon);
458 } catch (...) {
461 return pShutdownIcon.get();
464 void ShutdownIcon::init()
466 css::uno::Reference < XDesktop2 > xDesktop = Desktop::create( m_xContext );
467 std::unique_lock aGuard(m_aMutex);
468 m_xDesktop = std::move(xDesktop);
471 void ShutdownIcon::disposing(std::unique_lock<std::mutex>&)
473 m_xContext.clear();
474 m_xDesktop.clear();
476 deInitSystray();
479 // XEventListener
480 void SAL_CALL ShutdownIcon::disposing( const css::lang::EventObject& )
484 // XTerminateListener
485 void SAL_CALL ShutdownIcon::queryTermination( const css::lang::EventObject& )
487 SAL_INFO("sfx.appl", "ShutdownIcon::queryTermination: veto is " << m_bVeto);
488 std::unique_lock aGuard( m_aMutex );
490 if ( m_bVeto )
491 throw css::frame::TerminationVetoException();
495 void SAL_CALL ShutdownIcon::notifyTermination( const css::lang::EventObject& )
500 void SAL_CALL ShutdownIcon::initialize( const css::uno::Sequence< css::uno::Any>& aArguments )
502 std::unique_lock aGuard( m_aMutex );
504 // third argument only sets veto, everything else will be ignored!
505 if (aArguments.getLength() > 2)
507 bool bVeto = ::cppu::any2bool(aArguments[2]);
508 m_bVeto = bVeto;
509 return;
512 if ( aArguments.getLength() > 0 )
514 if ( !ShutdownIcon::pShutdownIcon )
518 bool bQuickstart = ::cppu::any2bool( aArguments[0] );
519 if( !bQuickstart && !GetAutostart() )
520 return;
521 aGuard.unlock();
522 init ();
523 aGuard.lock();
524 if ( !m_xDesktop.is() )
525 return;
527 /* Create a sub-classed instance - foo */
528 ShutdownIcon::pShutdownIcon = this;
529 initSystray();
531 catch(const css::lang::IllegalArgumentException&)
536 if ( aArguments.getLength() > 1 )
538 bool bAutostart = ::cppu::any2bool( aArguments[1] );
539 if (bAutostart && !GetAutostart())
540 SetAutostart( true );
541 if (!bAutostart && GetAutostart())
542 SetAutostart( false );
548 void ShutdownIcon::EnterModalMode()
550 bModalMode = true;
554 void ShutdownIcon::LeaveModalMode()
556 bModalMode = false;
559 #ifdef _WIN32
560 // defined in shutdowniconw32.cxx
561 #elif defined MACOSX
562 // defined in shutdowniconaqua.cxx
563 #else
564 bool ShutdownIcon::IsQuickstarterInstalled()
566 return false;
568 #endif
571 #ifdef ENABLE_QUICKSTART_APPLET
572 #ifdef _WIN32
573 OUString ShutdownIcon::getShortcutName()
575 return GetAutostartFolderNameW32() + "\\" + SfxResId(STR_QUICKSTART_LNKNAME) + ".lnk";
577 #endif // _WIN32
578 #endif
580 bool ShutdownIcon::GetAutostart( )
582 #if defined MACOSX
583 return true;
584 #elif defined ENABLE_QUICKSTART_APPLET
585 bool bRet = false;
586 OUString aShortcut( getShortcutName() );
587 OUString aShortcutUrl;
588 osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
589 osl::File f( aShortcutUrl );
590 osl::File::RC error = f.open( osl_File_OpenFlag_Read );
591 if( error == osl::File::E_None )
593 f.close();
594 bRet = true;
596 return bRet;
597 #else // ENABLE_QUICKSTART_APPLET
598 return false;
599 #endif
602 void ShutdownIcon::SetAutostart( bool bActivate )
604 #ifdef ENABLE_QUICKSTART_APPLET
605 #ifndef MACOSX
606 OUString aShortcut( getShortcutName() );
607 #endif
609 if( bActivate && IsQuickstarterInstalled() )
611 #ifdef _WIN32
612 EnableAutostartW32( aShortcut );
613 #endif
615 else
617 #ifndef MACOSX
618 OUString aShortcutUrl;
619 ::osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
620 ::osl::File::remove( aShortcutUrl );
621 #endif
623 #else
624 (void)bActivate; // unused variable
625 #endif // ENABLE_QUICKSTART_APPLET
628 const ::sal_Int32 PROPHANDLE_TERMINATEVETOSTATE = 0;
630 // XFastPropertySet
631 void SAL_CALL ShutdownIcon::setFastPropertyValue( ::sal_Int32 nHandle,
632 const css::uno::Any& aValue )
634 switch(nHandle)
636 case PROPHANDLE_TERMINATEVETOSTATE :
638 // use new value in case it's a valid information only
639 bool bState( false );
640 if (! (aValue >>= bState))
641 return;
643 m_bVeto = bState;
644 if (m_bVeto && ! m_bListenForTermination)
645 addTerminateListener();
647 break;
649 default :
650 throw css::beans::UnknownPropertyException(OUString::number(nHandle));
654 // XFastPropertySet
655 css::uno::Any SAL_CALL ShutdownIcon::getFastPropertyValue( ::sal_Int32 nHandle )
657 css::uno::Any aValue;
658 switch(nHandle)
660 case PROPHANDLE_TERMINATEVETOSTATE :
662 bool bState = (m_bListenForTermination && m_bVeto);
663 aValue <<= bState;
665 break;
667 default :
668 throw css::beans::UnknownPropertyException(OUString::number(nHandle));
671 return aValue;
674 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
675 com_sun_star_comp_desktop_QuickstartWrapper_get_implementation(
676 css::uno::XComponentContext *context,
677 css::uno::Sequence<css::uno::Any> const &)
679 return cppu::acquire(new ShutdownIcon(context));
682 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */