Avoid potential negative array index access to cached text.
[LibreOffice.git] / framework / source / services / sessionlistener.cxx
bloba77e7f961ebb708ebaedb016f45f1d7fc3e6eb8b
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/types.h>
21 #include <sal/log.hxx>
23 #include <framework/desktop.hxx>
25 #include <comphelper/diagnose_ex.hxx>
26 #include <com/sun/star/beans/NamedValue.hpp>
27 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <com/sun/star/frame/theAutoRecovery.hpp>
29 #include <com/sun/star/frame/Desktop.hpp>
30 #include <com/sun/star/frame/FeatureStateEvent.hpp>
31 #include <com/sun/star/frame/XDispatch.hpp>
32 #include <com/sun/star/frame/XSessionManagerListener2.hpp>
33 #include <com/sun/star/frame/XSessionManagerClient.hpp>
34 #include <com/sun/star/frame/XStatusListener.hpp>
35 #include <com/sun/star/lang/EventObject.hpp>
36 #include <com/sun/star/lang/XInitialization.hpp>
37 #include <com/sun/star/util/URLTransformer.hpp>
38 #include <com/sun/star/util/XURLTransformer.hpp>
39 #include <com/sun/star/util/URL.hpp>
40 #include <cppuhelper/implbase.hxx>
41 #include <cppuhelper/supportsservice.hxx>
43 #include <com/sun/star/uno/Any.hxx>
44 #include <com/sun/star/uno/Sequence.hxx>
45 #include <utility>
47 using namespace css;
48 using namespace com::sun::star::uno;
49 using namespace com::sun::star::util;
50 using namespace com::sun::star::beans;
51 using namespace framework;
53 namespace {
55 /// @HTML
56 /** @short implements flat/deep detection of file/stream formats and provides
57 further read/write access to the global office type configuration.
59 @descr Using of this class makes it possible to get information about the
60 format type of a given URL or stream. The returned internal type name
61 can be used to get more information about this format. Further this
62 class provides full access to the configuration data and following
63 implementations will support some special query modes.
65 @docdate 10.03.2003 by as96863
67 @todo <ul>
68 <li>implementation of query mode</li>
69 <li>simple restore mechanism of last consistent cache state,
70 if flush failed</li>
71 </ul>
73 typedef cppu::WeakImplHelper<
74 css::lang::XInitialization,
75 css::frame::XSessionManagerListener2,
76 css::frame::XStatusListener,
77 css::lang::XServiceInfo> SessionListener_BASE;
79 class SessionListener : public SessionListener_BASE
81 private:
82 osl::Mutex m_aMutex;
84 /** reference to the uno service manager, which created this service.
85 It can be used to create own needed helper services. */
86 css::uno::Reference< css::uno::XComponentContext > m_xContext;
88 css::uno::Reference< css::frame::XSessionManagerClient > m_rSessionManager;
90 // restore handling
91 bool m_bRestored;
93 bool m_bSessionStoreRequested;
95 bool m_bAllowUserInteractionOnQuit;
96 bool m_bTerminated;
98 // in case of synchronous call the caller should do saveDone() call himself!
99 void StoreSession( bool bAsync );
101 // let session quietly close the documents, remove lock files, store configuration and etc.
102 void QuitSessionQuietly();
104 public:
105 explicit SessionListener(css::uno::Reference< css::uno::XComponentContext > xContext);
107 virtual ~SessionListener() override;
109 virtual OUString SAL_CALL getImplementationName() override
111 return "com.sun.star.comp.frame.SessionListener";
114 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
116 return cppu::supportsService(this, ServiceName);
119 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
121 return {"com.sun.star.frame.SessionListener"};
124 virtual void SAL_CALL disposing(const css::lang::EventObject&) override;
126 // XInitialization
127 virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any >& args) override;
129 // XSessionManagerListener
130 virtual void SAL_CALL doSave( sal_Bool bShutdown, sal_Bool bCancelable ) override;
131 virtual void SAL_CALL approveInteraction( sal_Bool bInteractionGranted ) override;
132 virtual void SAL_CALL shutdownCanceled() override;
133 virtual sal_Bool SAL_CALL doRestore() override;
135 // XSessionManagerListener2
136 virtual void SAL_CALL doQuit() override;
138 // XStatusListener
139 virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& event) override;
142 SessionListener::SessionListener(css::uno::Reference< css::uno::XComponentContext > rxContext )
143 : m_xContext(std::move( rxContext ))
144 , m_bRestored( false )
145 , m_bSessionStoreRequested( false )
146 , m_bAllowUserInteractionOnQuit( false )
147 , m_bTerminated( false )
149 SAL_INFO("fwk.session", "SessionListener::SessionListener");
152 SessionListener::~SessionListener()
154 SAL_INFO("fwk.session", "SessionListener::~SessionListener");
155 if (m_rSessionManager.is())
157 css::uno::Reference< XSessionManagerListener> me(this);
158 m_rSessionManager->removeSessionManagerListener(me);
162 void SessionListener::StoreSession( bool bAsync )
164 SAL_INFO("fwk.session", "SessionListener::StoreSession");
165 osl::MutexGuard g(m_aMutex);
168 // xd create SERVICENAME_AUTORECOVERY -> frame::XDispatch
169 // xd->dispatch("vnd.sun.star.autorecovery:/doSessionSave, async=bAsync
170 // on stop event m_rSessionManager->saveDone(this); in case of asynchronous call
171 // in case of synchronous call the caller should do saveDone() call himself!
173 css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext );
174 css::uno::Reference< XURLTransformer > xURLTransformer = URLTransformer::create( m_xContext );
175 URL aURL;
176 aURL.Complete = "vnd.sun.star.autorecovery:/doSessionSave";
177 xURLTransformer->parseStrict(aURL);
179 // in case of asynchronous call the notification will trigger saveDone()
180 if ( bAsync )
181 xDispatch->addStatusListener(this, aURL);
183 Sequence< PropertyValue > args{ PropertyValue("DispatchAsynchron",-1,Any(bAsync),
184 PropertyState_DIRECT_VALUE) };
185 xDispatch->dispatch(aURL, args);
186 } catch (const css::uno::Exception&) {
187 TOOLS_WARN_EXCEPTION("fwk.session", "");
188 // save failed, but tell manager to go on if we haven't yet dispatched the request
189 // in case of synchronous saving the notification is done by the caller
190 if ( bAsync && m_rSessionManager.is() )
191 m_rSessionManager->saveDone(this);
195 void SessionListener::QuitSessionQuietly()
197 SAL_INFO("fwk.session", "SessionListener::QuitSessionQuietly");
198 osl::MutexGuard g(m_aMutex);
201 // xd create SERVICENAME_AUTORECOVERY -> frame::XDispatch
202 // xd->dispatch("vnd.sun.star.autorecovery:/doSessionQuietQuit, async=false
203 // it is done synchronously to avoid conflict with normal quit process
205 css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext );
206 css::uno::Reference< XURLTransformer > xURLTransformer = URLTransformer::create( m_xContext );
207 URL aURL;
208 aURL.Complete = "vnd.sun.star.autorecovery:/doSessionQuietQuit";
209 xURLTransformer->parseStrict(aURL);
211 Sequence< PropertyValue > args{ PropertyValue("DispatchAsynchron",-1,Any(false),
212 PropertyState_DIRECT_VALUE) };
213 xDispatch->dispatch(aURL, args);
214 } catch (const css::uno::Exception&) {
215 TOOLS_WARN_EXCEPTION("fwk.session", "");
219 void SAL_CALL SessionListener::disposing(const css::lang::EventObject& Source)
221 SAL_INFO("fwk.session", "SessionListener::disposing");
222 if (Source.Source == m_rSessionManager) {
223 m_rSessionManager.clear();
227 void SAL_CALL SessionListener::initialize(const Sequence< Any >& args)
229 SAL_INFO("fwk.session", "SessionListener::initialize");
231 OUString aSMgr("com.sun.star.frame.SessionManagerClient");
232 if ( (args.getLength() == 1) && (args[0] >>= m_bAllowUserInteractionOnQuit) )
233 ;// do nothing
234 else if (args.hasElements())
236 NamedValue v;
237 for (const Any& rArg : args)
239 if (rArg >>= v)
241 if ( v.Name == "SessionManagerName" )
242 v.Value >>= aSMgr;
243 else if ( v.Name == "SessionManager" )
244 v.Value >>= m_rSessionManager;
245 else if ( v.Name == "AllowUserInteractionOnQuit" )
246 v.Value >>= m_bAllowUserInteractionOnQuit;
251 SAL_INFO("fwk.session.debug", " m_bAllowUserInteractionOnQuit = " << (m_bAllowUserInteractionOnQuit ? "true" : "false"));
252 if (!m_rSessionManager.is())
253 m_rSessionManager = css::uno::Reference< frame::XSessionManagerClient >
254 (m_xContext->getServiceManager()->createInstanceWithContext(aSMgr, m_xContext), UNO_QUERY);
256 if (m_rSessionManager.is())
258 m_rSessionManager->addSessionManagerListener(this);
262 void SAL_CALL SessionListener::statusChanged(const frame::FeatureStateEvent& event)
264 SAL_INFO("fwk.session", "SessionListener::statusChanged");
266 SAL_INFO("fwk.session.debug", " ev.Feature = " << event.FeatureURL.Complete <<
267 ", ev.Descript = " << event.FeatureDescriptor);
268 if ( event.FeatureURL.Complete == "vnd.sun.star.autorecovery:/doSessionRestore" )
270 if (event.FeatureDescriptor == "update")
271 m_bRestored = true; // a document was restored
274 else if ( event.FeatureURL.Complete == "vnd.sun.star.autorecovery:/doAutoSave" )
275 { // the "doSessionSave" was never set, look to framework/source/services/autorecovery.cxx
276 // it always testing but never setting (enum AutoRecovery::E_SESSION_SAVE)
277 if (event.FeatureDescriptor == "update")
279 if (m_rSessionManager.is())
280 m_rSessionManager->saveDone(this); // done with save
285 sal_Bool SAL_CALL SessionListener::doRestore()
287 SAL_INFO("fwk.session", "SessionListener::doRestore");
288 osl::MutexGuard g(m_aMutex);
289 m_bRestored = false;
290 try {
291 css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext );
293 URL aURL;
294 aURL.Complete = "vnd.sun.star.autorecovery:/doSessionRestore";
295 css::uno::Reference< XURLTransformer > xURLTransformer(URLTransformer::create(m_xContext));
296 xURLTransformer->parseStrict(aURL);
297 Sequence< PropertyValue > args;
298 xDispatch->addStatusListener(this, aURL);
299 xDispatch->dispatch(aURL, args);
300 m_bRestored = true;
302 } catch (const css::uno::Exception&) {
303 TOOLS_WARN_EXCEPTION("fwk.session", "");
306 return m_bRestored;
309 void SAL_CALL SessionListener::doSave( sal_Bool bShutdown, sal_Bool /*bCancelable*/ )
311 SAL_INFO("fwk.session", "SessionListener::doSave");
313 SAL_INFO("fwk.session.debug", " m_bAllowUserInteractionOnQuit = " << (m_bAllowUserInteractionOnQuit ? "true" : "false") <<
314 ", bShutdown = " << (bShutdown ? "true" : "false"));
315 if (bShutdown)
317 m_bSessionStoreRequested = true; // there is no need to protect it with mutex
318 if ( m_bAllowUserInteractionOnQuit && m_rSessionManager.is() )
319 m_rSessionManager->queryInteraction( static_cast< css::frame::XSessionManagerListener* >( this ) );
320 else
321 StoreSession( true );
323 // we don't have anything to do so tell the session manager we're done
324 else if( m_rSessionManager.is() )
325 m_rSessionManager->saveDone( this );
328 void SAL_CALL SessionListener::approveInteraction( sal_Bool bInteractionGranted )
330 SAL_INFO("fwk.session", "SessionListener::approveInteraction");
331 // do AutoSave as the first step
332 osl::MutexGuard g(m_aMutex);
334 if ( bInteractionGranted )
336 // close the office documents in normal way
339 // first of all let the session be stored to be sure that we lose no information
340 StoreSession( false );
342 css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext );
343 // honestly: how many implementations of XDesktop will we ever have?
344 // so casting this directly to the implementation
345 Desktop* pDesktop(dynamic_cast<Desktop*>(xDesktop.get()));
346 if(pDesktop)
348 SAL_INFO("fwk.session", " XDesktop is a framework::Desktop -- good.");
349 m_bTerminated = pDesktop->terminateQuickstarterToo();
351 else
353 SAL_WARN("fwk.session", " XDesktop is not a framework::Desktop -- this should never happen.");
354 m_bTerminated = xDesktop->terminate();
357 if ( m_rSessionManager.is() )
359 // false means that the application closing has been cancelled
360 if ( !m_bTerminated )
361 m_rSessionManager->cancelShutdown();
362 else
363 m_rSessionManager->interactionDone( this );
366 catch( const css::uno::Exception& )
368 StoreSession( true );
369 if (m_rSessionManager.is())
370 m_rSessionManager->interactionDone(this);
373 if ( m_rSessionManager.is() && m_bTerminated )
374 m_rSessionManager->saveDone(this);
376 else
378 StoreSession( true );
382 void SessionListener::shutdownCanceled()
384 SAL_INFO("fwk.session", "SessionListener::shutdownCanceled");
385 // set the state back
386 m_bSessionStoreRequested = false; // there is no need to protect it with mutex
388 if ( m_rSessionManager.is() )
389 m_rSessionManager->saveDone(this);
392 void SessionListener::doQuit()
394 SAL_INFO("fwk.session", "SessionListener::doQuit");
395 if ( m_bSessionStoreRequested && !m_bTerminated )
397 // let the session be closed quietly in this case
398 QuitSessionQuietly();
404 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
405 com_sun_star_comp_frame_SessionListener_get_implementation(
406 css::uno::XComponentContext *context,
407 css::uno::Sequence<css::uno::Any> const &)
409 SAL_INFO("fwk.session", "com_sun_star_comp_frame_SessionListener_get_implementation");
411 return cppu::acquire(new SessionListener(context));
414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */