/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star::uno; using namespace com::sun::star::util; using namespace com::sun::star::frame; using namespace com::sun::star::lang; using namespace com::sun::star::beans; using namespace com::sun::star::container; using ::rtl::OUString; using ::rtl::OString; namespace framework{ //*********************************************** // XInterface, XTypeProvider, XServiceInfo DEFINE_XINTERFACE_6( SessionListener, OWeakObject, DIRECT_INTERFACE(css::lang::XTypeProvider), DIRECT_INTERFACE(css::lang::XInitialization), DIRECT_INTERFACE(css::frame::XSessionManagerListener), DIRECT_INTERFACE(css::frame::XSessionManagerListener2), DIRECT_INTERFACE(css::frame::XStatusListener), DIRECT_INTERFACE(css::lang::XServiceInfo)) DEFINE_XTYPEPROVIDER_5( SessionListener, css::lang::XTypeProvider, css::lang::XInitialization, css::frame::XSessionManagerListener2, css::frame::XStatusListener, css::lang::XServiceInfo) DEFINE_XSERVICEINFO_ONEINSTANCESERVICE( SessionListener, cppu::OWeakObject, "com.sun.star.frame.SessionListener", IMPLEMENTATIONNAME_SESSIONLISTENER) DEFINE_INIT_SERVICE(SessionListener, { /* Add special code for initialization here, if you have to use your own instance during your ctor is still in progress! */ } ) SessionListener::SessionListener(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ) : ThreadHelpBase (&Application::GetSolarMutex()) , OWeakObject ( ) , m_xSMGR (xSMGR ) , m_bRestored( sal_False ) , m_bSessionStoreRequested( sal_False ) , m_bAllowUserInteractionOnQuit( sal_False ) , m_bTerminated( sal_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( sal_Bool bAsync ) { SAL_INFO("fwk.session", "SessionListener::StoreSession"); ResetableGuard aGuard(m_aLock); try { // xd create SERVICENAME_AUTORECOVERY -> 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< XDispatch > xDispatch = css::frame::AutoRecovery::create( ::comphelper::getComponentContext(m_xSMGR) ); css::uno::Reference< XURLTransformer > xURLTransformer = URLTransformer::create( ::comphelper::getComponentContext(m_xSMGR) ); URL aURL; aURL.Complete = OUString("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(OUString("DispatchAsynchron"),-1,makeAny(bAsync),PropertyState_DIRECT_VALUE); xDispatch->dispatch(aURL, args); } catch (const com::sun::star::uno::Exception& e) { OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8); OSL_FAIL(aMsg.getStr()); // save failed, but tell manager to go on if we havent 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"); ResetableGuard aGuard(m_aLock); try { // xd create SERVICENAME_AUTORECOVERY -> XDispatch // xd->dispatch("vnd.sun.star.autorecovery:/doSessionQuietQuit, async=false // it is done synchronously to avoid conflict with normal quit process css::uno::Reference< XDispatch > xDispatch = css::frame::AutoRecovery::create( ::comphelper::getComponentContext(m_xSMGR) ); css::uno::Reference< XURLTransformer > xURLTransformer = URLTransformer::create( ::comphelper::getComponentContext(m_xSMGR) ); URL aURL; aURL.Complete = OUString("vnd.sun.star.autorecovery:/doSessionQuietQuit"); xURLTransformer->parseStrict(aURL); Sequence< PropertyValue > args(1); args[0] = PropertyValue(OUString("DispatchAsynchron"),-1,makeAny(sal_False),PropertyState_DIRECT_VALUE); xDispatch->dispatch(aURL, args); } catch (const com::sun::star::uno::Exception& e) { OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8); OSL_FAIL(aMsg.getStr()); } } void SAL_CALL SessionListener::disposing(const com::sun::star::lang::EventObject&) throw (RuntimeException) { SAL_INFO("fwk.session", "SessionListener::disposing"); } void SAL_CALL SessionListener::initialize(const Sequence< Any >& args) throw (RuntimeException) { 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.getLength() > 0) { NamedValue v; for (int i = 0; i < args.getLength(); i++) { if (args[i] >>= 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; } } } if (!m_rSessionManager.is()) m_rSessionManager = css::uno::Reference< XSessionManagerClient > (m_xSMGR->createInstance(aSMgr), UNO_QUERY); if (m_rSessionManager.is()) { m_rSessionManager->addSessionManagerListener(this); } } void SAL_CALL SessionListener::statusChanged(const FeatureStateEvent& event) throw (css::uno::RuntimeException) { SAL_INFO("fwk.session", "SessionListener::statusChanged"); if ( event.FeatureURL.Complete == "vnd.sun.star.autorecovery:/doSessionRestore" ) { if (event.FeatureDescriptor.compareToAscii("update")==0) m_bRestored = sal_True; // a document was restored } else if ( event.FeatureURL.Complete == "vnd.sun.star.autorecovery:/doSessionSave" ) { if (event.FeatureDescriptor.compareToAscii("stop")==0) { if (m_rSessionManager.is()) m_rSessionManager->saveDone(this); // done with save } } } sal_Bool SAL_CALL SessionListener::doRestore() throw (RuntimeException) { SAL_INFO("fwk.session", "SessionListener::doRestore"); ResetableGuard aGuard(m_aLock); m_bRestored = sal_False; try { css::uno::Reference< XDispatch > xDispatch = css::frame::AutoRecovery::create( ::comphelper::getComponentContext(m_xSMGR) ); URL aURL; aURL.Complete = OUString("vnd.sun.star.autorecovery:/doSessionRestore"); css::uno::Reference< XURLTransformer > xURLTransformer(URLTransformer::create(::comphelper::getComponentContext(m_xSMGR))); xURLTransformer->parseStrict(aURL); Sequence< PropertyValue > args; xDispatch->addStatusListener(this, aURL); xDispatch->dispatch(aURL, args); m_bRestored = sal_True; } catch (const com::sun::star::uno::Exception& e) { OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8); OSL_FAIL(aMsg.getStr()); } return m_bRestored; } void SAL_CALL SessionListener::doSave( sal_Bool bShutdown, sal_Bool /*bCancelable*/ ) throw (RuntimeException) { SAL_INFO("fwk.session", "SessionListener::doSave"); if (bShutdown) { m_bSessionStoreRequested = sal_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( sal_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 ) throw (RuntimeException) { SAL_INFO("fwk.session", "SessionListener::approveInteraction"); // do AutoSave as the first step ResetableGuard aGuard(m_aLock); 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( sal_False ); css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( comphelper::getComponentContext(m_xSMGR) ); // honestly: how many implementations of XDesktop will we ever have? // so casting this directly to the implementation Desktop* pDesktop(dynamic_cast(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( sal_True ); m_rSessionManager->interactionDone( this ); } if ( m_rSessionManager.is() ) m_rSessionManager->saveDone(this); } else { StoreSession( sal_True ); } } void SessionListener::shutdownCanceled() throw (RuntimeException) { SAL_INFO("fwk.session", "SessionListener::shutdownCanceled"); // set the state back m_bSessionStoreRequested = sal_False; // there is no need to protect it with mutex } void SessionListener::doQuit() throw (RuntimeException) { SAL_INFO("fwk.session", "SessionListener::doQuit"); if ( m_bSessionStoreRequested && !m_bTerminated ) { // let the session be closed quietly in this case QuitSessionQuietly(); } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */