diff options
Diffstat (limited to '')
-rw-r--r-- | framework/source/services/sessionlistener.cxx | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/framework/source/services/sessionlistener.cxx b/framework/source/services/sessionlistener.cxx new file mode 100644 index 000000000..b0c7e70eb --- /dev/null +++ b/framework/source/services/sessionlistener.cxx @@ -0,0 +1,412 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> +#include <sal/log.hxx> + +#include <services/desktop.hxx> + +#include <tools/diagnose_ex.h> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/frame/theAutoRecovery.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/FeatureStateEvent.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XSessionManagerListener2.hpp> +#include <com/sun/star/frame/XSessionManagerClient.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/util/URL.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +using namespace css; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace com::sun::star::beans; +using namespace framework; + +namespace { + +/// @HTML +/** @short implements flat/deep detection of file/stream formats and provides + further read/write access to the global office type configuration. + + @descr Using of this class makes it possible to get information about the + format type of a given URL or stream. The returned internal type name + can be used to get more information about this format. Further this + class provides full access to the configuration data and following + implementations will support some special query modes. + + @docdate 10.03.2003 by as96863 + + @todo <ul> + <li>implementation of query mode</li> + <li>simple restore mechanism of last consistent cache state, + if flush failed</li> + </ul> + */ +typedef cppu::WeakImplHelper< + css::lang::XInitialization, + css::frame::XSessionManagerListener2, + css::frame::XStatusListener, + css::lang::XServiceInfo> SessionListener_BASE; + +class SessionListener : public SessionListener_BASE +{ +private: + osl::Mutex m_aMutex; + + /** reference to the uno service manager, which created this service. + It can be used to create own needed helper services. */ + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + css::uno::Reference< css::frame::XSessionManagerClient > m_rSessionManager; + + // restore handling + bool m_bRestored; + + bool m_bSessionStoreRequested; + + bool m_bAllowUserInteractionOnQuit; + bool m_bTerminated; + + // in case of synchronous call the caller should do saveDone() call himself! + void StoreSession( bool bAsync ); + + // let session quietly close the documents, remove lock files, store configuration and etc. + void QuitSessionQuietly(); + +public: + explicit SessionListener(const css::uno::Reference< css::uno::XComponentContext >& xContext); + + virtual ~SessionListener() override; + + virtual OUString SAL_CALL getImplementationName() override + { + return "com.sun.star.comp.frame.SessionListener"; + } + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override + { + return cppu::supportsService(this, ServiceName); + } + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override + { + return {"com.sun.star.frame.SessionListener"}; + } + + virtual void SAL_CALL disposing(const css::lang::EventObject&) override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any >& args) override; + + // XSessionManagerListener + virtual void SAL_CALL doSave( sal_Bool bShutdown, sal_Bool bCancelable ) override; + virtual void SAL_CALL approveInteraction( sal_Bool bInteractionGranted ) override; + virtual void SAL_CALL shutdownCanceled() override; + virtual sal_Bool SAL_CALL doRestore() override; + + // XSessionManagerListener2 + virtual void SAL_CALL doQuit() override; + + // XStatusListener + virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& event) override; +}; + +SessionListener::SessionListener(const css::uno::Reference< css::uno::XComponentContext >& rxContext ) + : m_xContext( rxContext ) + , m_bRestored( false ) + , m_bSessionStoreRequested( false ) + , m_bAllowUserInteractionOnQuit( false ) + , m_bTerminated( false ) +{ + SAL_INFO("fwk.session", "SessionListener::SessionListener"); +} + +SessionListener::~SessionListener() +{ + SAL_INFO("fwk.session", "SessionListener::~SessionListener"); + if (m_rSessionManager.is()) + { + css::uno::Reference< XSessionManagerListener> me(this); + m_rSessionManager->removeSessionManagerListener(me); + } +} + +void SessionListener::StoreSession( bool bAsync ) +{ + SAL_INFO("fwk.session", "SessionListener::StoreSession"); + osl::MutexGuard g(m_aMutex); + try + { + // xd create SERVICENAME_AUTORECOVERY -> frame::XDispatch + // xd->dispatch("vnd.sun.star.autorecovery:/doSessionSave, async=bAsync + // on stop event m_rSessionManager->saveDone(this); in case of asynchronous call + // in case of synchronous call the caller should do saveDone() call himself! + + css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext ); + css::uno::Reference< XURLTransformer > xURLTransformer = URLTransformer::create( m_xContext ); + URL aURL; + aURL.Complete = "vnd.sun.star.autorecovery:/doSessionSave"; + xURLTransformer->parseStrict(aURL); + + // in case of asynchronous call the notification will trigger saveDone() + if ( bAsync ) + xDispatch->addStatusListener(this, aURL); + + Sequence< PropertyValue > args(1); + args[0] = PropertyValue("DispatchAsynchron",-1,makeAny(bAsync),PropertyState_DIRECT_VALUE); + xDispatch->dispatch(aURL, args); + } catch (const css::uno::Exception&) { + TOOLS_WARN_EXCEPTION("fwk.session", ""); + // save failed, but tell manager to go on if we haven't yet dispatched the request + // in case of synchronous saving the notification is done by the caller + if ( bAsync && m_rSessionManager.is() ) + m_rSessionManager->saveDone(this); + } +} + +void SessionListener::QuitSessionQuietly() +{ + SAL_INFO("fwk.session", "SessionListener::QuitSessionQuietly"); + osl::MutexGuard g(m_aMutex); + try + { + // xd create SERVICENAME_AUTORECOVERY -> frame::XDispatch + // xd->dispatch("vnd.sun.star.autorecovery:/doSessionQuietQuit, async=false + // it is done synchronously to avoid conflict with normal quit process + + css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext ); + css::uno::Reference< XURLTransformer > xURLTransformer = URLTransformer::create( m_xContext ); + URL aURL; + aURL.Complete = "vnd.sun.star.autorecovery:/doSessionQuietQuit"; + xURLTransformer->parseStrict(aURL); + + Sequence< PropertyValue > args(1); + args[0] = PropertyValue("DispatchAsynchron",-1,makeAny(false),PropertyState_DIRECT_VALUE); + xDispatch->dispatch(aURL, args); + } catch (const css::uno::Exception&) { + TOOLS_WARN_EXCEPTION("fwk.session", ""); + } +} + +void SAL_CALL SessionListener::disposing(const css::lang::EventObject& Source) +{ + SAL_INFO("fwk.session", "SessionListener::disposing"); + if (Source.Source == m_rSessionManager) { + m_rSessionManager.clear(); + } +} + +void SAL_CALL SessionListener::initialize(const Sequence< Any >& args) +{ + SAL_INFO("fwk.session", "SessionListener::initialize"); + + OUString aSMgr("com.sun.star.frame.SessionManagerClient"); + if ( (args.getLength() == 1) && (args[0] >>= m_bAllowUserInteractionOnQuit) ) + ;// do nothing + else if (args.hasElements()) + { + NamedValue v; + for (const Any& rArg : args) + { + if (rArg >>= v) + { + if ( v.Name == "SessionManagerName" ) + v.Value >>= aSMgr; + else if ( v.Name == "SessionManager" ) + v.Value >>= m_rSessionManager; + else if ( v.Name == "AllowUserInteractionOnQuit" ) + v.Value >>= m_bAllowUserInteractionOnQuit; + } + } + } + + SAL_INFO("fwk.session.debug", " m_bAllowUserInteractionOnQuit = " << (m_bAllowUserInteractionOnQuit ? "true" : "false")); + if (!m_rSessionManager.is()) + m_rSessionManager = css::uno::Reference< frame::XSessionManagerClient > + (m_xContext->getServiceManager()->createInstanceWithContext(aSMgr, m_xContext), UNO_QUERY); + + if (m_rSessionManager.is()) + { + m_rSessionManager->addSessionManagerListener(this); + } +} + +void SAL_CALL SessionListener::statusChanged(const frame::FeatureStateEvent& event) +{ + SAL_INFO("fwk.session", "SessionListener::statusChanged"); + + SAL_INFO("fwk.session.debug", " ev.Feature = " << event.FeatureURL.Complete << + ", ev.Descript = " << event.FeatureDescriptor); + if ( event.FeatureURL.Complete == "vnd.sun.star.autorecovery:/doSessionRestore" ) + { + if (event.FeatureDescriptor == "update") + m_bRestored = true; // a document was restored + + } + else if ( event.FeatureURL.Complete == "vnd.sun.star.autorecovery:/doAutoSave" ) + { // the "doSessionSave" was never set, look to framework/source/services/autorecovery.cxx + // it always testing but never setting (enum AutoRecovery::E_SESSION_SAVE) + if (event.FeatureDescriptor == "update") + { + if (m_rSessionManager.is()) + m_rSessionManager->saveDone(this); // done with save + } + } +} + +sal_Bool SAL_CALL SessionListener::doRestore() +{ + SAL_INFO("fwk.session", "SessionListener::doRestore"); + osl::MutexGuard g(m_aMutex); + m_bRestored = false; + try { + css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext ); + + URL aURL; + aURL.Complete = "vnd.sun.star.autorecovery:/doSessionRestore"; + css::uno::Reference< XURLTransformer > xURLTransformer(URLTransformer::create(m_xContext)); + xURLTransformer->parseStrict(aURL); + Sequence< PropertyValue > args; + xDispatch->addStatusListener(this, aURL); + xDispatch->dispatch(aURL, args); + m_bRestored = true; + + } catch (const css::uno::Exception&) { + TOOLS_WARN_EXCEPTION("fwk.session", ""); + } + + return m_bRestored; +} + +void SAL_CALL SessionListener::doSave( sal_Bool bShutdown, sal_Bool /*bCancelable*/ ) +{ + SAL_INFO("fwk.session", "SessionListener::doSave"); + + SAL_INFO("fwk.session.debug", " m_bAllowUserInteractionOnQuit = " << (m_bAllowUserInteractionOnQuit ? "true" : "false") << + ", bShutdown = " << (bShutdown ? "true" : "false")); + if (bShutdown) + { + m_bSessionStoreRequested = true; // there is no need to protect it with mutex + if ( m_bAllowUserInteractionOnQuit && m_rSessionManager.is() ) + m_rSessionManager->queryInteraction( static_cast< css::frame::XSessionManagerListener* >( this ) ); + else + StoreSession( true ); + } + // we don't have anything to do so tell the session manager we're done + else if( m_rSessionManager.is() ) + m_rSessionManager->saveDone( this ); +} + +void SAL_CALL SessionListener::approveInteraction( sal_Bool bInteractionGranted ) +{ + SAL_INFO("fwk.session", "SessionListener::approveInteraction"); + // do AutoSave as the first step + osl::MutexGuard g(m_aMutex); + + if ( bInteractionGranted ) + { + // close the office documents in normal way + try + { + // first of all let the session be stored to be sure that we lose no information + StoreSession( false ); + + css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext ); + // honestly: how many implementations of XDesktop will we ever have? + // so casting this directly to the implementation + Desktop* pDesktop(dynamic_cast<Desktop*>(xDesktop.get())); + if(pDesktop) + { + SAL_INFO("fwk.session", " XDesktop is a framework::Desktop -- good."); + m_bTerminated = pDesktop->terminateQuickstarterToo(); + } + else + { + SAL_WARN("fwk.session", " XDesktop is not a framework::Desktop -- this should never happen."); + m_bTerminated = xDesktop->terminate(); + } + + if ( m_rSessionManager.is() ) + { + // false means that the application closing has been cancelled + if ( !m_bTerminated ) + m_rSessionManager->cancelShutdown(); + else + m_rSessionManager->interactionDone( this ); + } + } + catch( const css::uno::Exception& ) + { + StoreSession( true ); + m_rSessionManager->interactionDone( this ); + } + + if ( m_rSessionManager.is() && m_bTerminated ) + m_rSessionManager->saveDone(this); + } + else + { + StoreSession( true ); + } +} + +void SessionListener::shutdownCanceled() +{ + SAL_INFO("fwk.session", "SessionListener::shutdownCanceled"); + // set the state back + m_bSessionStoreRequested = false; // there is no need to protect it with mutex + + if ( m_rSessionManager.is() ) + m_rSessionManager->saveDone(this); +} + +void SessionListener::doQuit() +{ + SAL_INFO("fwk.session", "SessionListener::doQuit"); + if ( m_bSessionStoreRequested && !m_bTerminated ) + { + // let the session be closed quietly in this case + QuitSessionQuietly(); + } +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_frame_SessionListener_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + SAL_INFO("fwk.session", "com_sun_star_comp_frame_SessionListener_get_implementation"); + + return cppu::acquire(new SessionListener(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |