Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <sal/types.h>
21 :
22 : #include <services/desktop.hxx>
23 : #include <classes/filtercache.hxx>
24 : #include <protocols.h>
25 : #include <general.h>
26 :
27 : #include <vcl/svapp.hxx>
28 : #include <unotools/tempfile.hxx>
29 : #include <com/sun/star/beans/NamedValue.hpp>
30 : #include <com/sun/star/beans/PropertyValue.hpp>
31 : #include <com/sun/star/frame/theAutoRecovery.hpp>
32 : #include <com/sun/star/frame/Desktop.hpp>
33 : #include <com/sun/star/frame/FeatureStateEvent.hpp>
34 : #include <com/sun/star/frame/XDispatch.hpp>
35 : #include <com/sun/star/frame/XSessionManagerListener2.hpp>
36 : #include <com/sun/star/frame/XSessionManagerClient.hpp>
37 : #include <com/sun/star/frame/XStatusListener.hpp>
38 : #include <com/sun/star/lang/EventObject.hpp>
39 : #include <com/sun/star/lang/XInitialization.hpp>
40 : #include <com/sun/star/util/URLTransformer.hpp>
41 : #include <com/sun/star/util/XURLTransformer.hpp>
42 : #include <com/sun/star/util/URL.hpp>
43 : #include <cppuhelper/implbase4.hxx>
44 : #include <cppuhelper/supportsservice.hxx>
45 : #include <unotools/pathoptions.hxx>
46 :
47 : #include <com/sun/star/uno/Any.hxx>
48 : #include <com/sun/star/uno/Sequence.hxx>
49 :
50 : using namespace css;
51 : using namespace com::sun::star::uno;
52 : using namespace com::sun::star::util;
53 : using namespace com::sun::star::beans;
54 : using namespace framework;
55 :
56 : namespace {
57 :
58 : /// @HTML
59 : /** @short implements flat/deep detection of file/stream formats and provides
60 : further read/write access to the global office type configuration.
61 :
62 : @descr Using of this class makes it possible to get information about the
63 : format type of a given URL or stream. The returned internal type name
64 : can be used to get more information about this format. Further this
65 : class provides full access to the configuration data and following
66 : implementations will support some special query modes.
67 :
68 : @author as96863
69 :
70 : @docdate 10.03.2003 by as96863
71 :
72 : @todo <ul>
73 : <li>implementation of query mode</li>
74 : <li>simple restore mechanism of last consistent cache state,
75 : if flush failed</li>
76 : </ul>
77 : */
78 : typedef cppu::WeakImplHelper4<
79 : css::lang::XInitialization,
80 : css::frame::XSessionManagerListener2,
81 : css::frame::XStatusListener,
82 : css::lang::XServiceInfo> SessionListener_BASE;
83 :
84 : class SessionListener : public SessionListener_BASE
85 : {
86 : private:
87 : osl::Mutex m_aMutex;
88 :
89 : /** reference to the uno service manager, which created this service.
90 : It can be used to create own needed helper services. */
91 : css::uno::Reference< css::uno::XComponentContext > m_xContext;
92 :
93 : css::uno::Reference< css::frame::XSessionManagerClient > m_rSessionManager;
94 :
95 : // restore handling
96 : bool m_bRestored;
97 :
98 : bool m_bSessionStoreRequested;
99 :
100 : bool m_bAllowUserInteractionOnQuit;
101 : bool m_bTerminated;
102 :
103 : // in case of synchronous call the caller should do saveDone() call himself!
104 : void StoreSession( bool bAsync );
105 :
106 : // let session quietly close the documents, remove lock files, store configuration and etc.
107 : void QuitSessionQuietly();
108 :
109 : public:
110 : SessionListener( const css::uno::Reference< css::uno::XComponentContext >& xContext );
111 :
112 : virtual ~SessionListener();
113 :
114 0 : virtual OUString SAL_CALL getImplementationName()
115 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
116 : {
117 0 : return OUString("com.sun.star.comp.frame.SessionListener");
118 : }
119 :
120 0 : virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
121 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
122 : {
123 0 : return cppu::supportsService(this, ServiceName);
124 : }
125 :
126 0 : virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
127 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
128 : {
129 0 : css::uno::Sequence< OUString > aSeq(1);
130 0 : aSeq[0] = "com.sun.star.frame.SessionListener";
131 0 : return aSeq;
132 : }
133 :
134 : virtual void SAL_CALL disposing(const com::sun::star::lang::EventObject&) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
135 :
136 : // XInitialization
137 : virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any >& args) throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
138 :
139 : // XSessionManagerListener
140 : virtual void SAL_CALL doSave( sal_Bool bShutdown, sal_Bool bCancelable )
141 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
142 : virtual void SAL_CALL approveInteraction( sal_Bool bInteractionGranted )
143 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
144 : virtual void SAL_CALL shutdownCanceled()
145 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
146 : virtual sal_Bool SAL_CALL doRestore()
147 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
148 :
149 : // XSessionManagerListener2
150 : virtual void SAL_CALL doQuit()
151 : throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
152 :
153 : // XStatusListener
154 : virtual void SAL_CALL statusChanged(const com::sun::star::frame::FeatureStateEvent& event)
155 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
156 : };
157 :
158 0 : SessionListener::SessionListener(const css::uno::Reference< css::uno::XComponentContext >& rxContext )
159 : : m_xContext( rxContext )
160 : , m_bRestored( false )
161 : , m_bSessionStoreRequested( false )
162 : , m_bAllowUserInteractionOnQuit( false )
163 0 : , m_bTerminated( false )
164 : {
165 : SAL_INFO("fwk.session", "SessionListener::SessionListener");
166 0 : }
167 :
168 0 : SessionListener::~SessionListener()
169 : {
170 : SAL_INFO("fwk.session", "SessionListener::~SessionListener");
171 0 : if (m_rSessionManager.is())
172 : {
173 0 : css::uno::Reference< XSessionManagerListener> me(this);
174 0 : m_rSessionManager->removeSessionManagerListener(me);
175 : }
176 0 : }
177 :
178 0 : void SessionListener::StoreSession( bool bAsync )
179 : {
180 : SAL_INFO("fwk.session", "SessionListener::StoreSession");
181 0 : osl::MutexGuard g(m_aMutex);
182 : try
183 : {
184 : // xd create SERVICENAME_AUTORECOVERY -> frame::XDispatch
185 : // xd->dispatch("vnd.sun.star.autorecovery:/doSessionSave, async=bAsync
186 : // on stop event m_rSessionManager->saveDone(this); in case of asynchronous call
187 : // in case of synchronous call the caller should do saveDone() call himself!
188 :
189 0 : css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext );
190 0 : css::uno::Reference< XURLTransformer > xURLTransformer = URLTransformer::create( m_xContext );
191 0 : URL aURL;
192 0 : aURL.Complete = "vnd.sun.star.autorecovery:/doSessionSave";
193 0 : xURLTransformer->parseStrict(aURL);
194 :
195 : // in case of asynchronous call the notification will trigger saveDone()
196 0 : if ( bAsync )
197 0 : xDispatch->addStatusListener(this, aURL);
198 :
199 0 : Sequence< PropertyValue > args(1);
200 0 : args[0] = PropertyValue(OUString("DispatchAsynchron"),-1,makeAny(bAsync),PropertyState_DIRECT_VALUE);
201 0 : xDispatch->dispatch(aURL, args);
202 0 : } catch (const com::sun::star::uno::Exception& e) {
203 : SAL_WARN("fwk.session",e.Message);
204 : // save failed, but tell manager to go on if we havent yet dispatched the request
205 : // in case of synchronous saving the notification is done by the caller
206 0 : if ( bAsync && m_rSessionManager.is() )
207 0 : m_rSessionManager->saveDone(this);
208 0 : }
209 0 : }
210 :
211 0 : void SessionListener::QuitSessionQuietly()
212 : {
213 : SAL_INFO("fwk.session", "SessionListener::QuitSessionQuietly");
214 0 : osl::MutexGuard g(m_aMutex);
215 : try
216 : {
217 : // xd create SERVICENAME_AUTORECOVERY -> frame::XDispatch
218 : // xd->dispatch("vnd.sun.star.autorecovery:/doSessionQuietQuit, async=false
219 : // it is done synchronously to avoid conflict with normal quit process
220 :
221 0 : css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext );
222 0 : css::uno::Reference< XURLTransformer > xURLTransformer = URLTransformer::create( m_xContext );
223 0 : URL aURL;
224 0 : aURL.Complete = "vnd.sun.star.autorecovery:/doSessionQuietQuit";
225 0 : xURLTransformer->parseStrict(aURL);
226 :
227 0 : Sequence< PropertyValue > args(1);
228 0 : args[0] = PropertyValue(OUString("DispatchAsynchron"),-1,makeAny(sal_False),PropertyState_DIRECT_VALUE);
229 0 : xDispatch->dispatch(aURL, args);
230 0 : } catch (const com::sun::star::uno::Exception& e) {
231 : SAL_WARN("fwk.session",e.Message);
232 0 : }
233 0 : }
234 :
235 0 : void SAL_CALL SessionListener::disposing(const com::sun::star::lang::EventObject&) throw (RuntimeException, std::exception)
236 : {
237 : SAL_INFO("fwk.session", "SessionListener::disposing");
238 0 : }
239 :
240 0 : void SAL_CALL SessionListener::initialize(const Sequence< Any >& args)
241 : throw (RuntimeException, std::exception)
242 : {
243 : SAL_INFO("fwk.session", "SessionListener::initialize");
244 :
245 0 : OUString aSMgr("com.sun.star.frame.SessionManagerClient");
246 0 : if ( (args.getLength() == 1) && (args[0] >>= m_bAllowUserInteractionOnQuit) )
247 : ;// do nothing
248 0 : else if (args.getLength() > 0)
249 : {
250 0 : NamedValue v;
251 0 : for (int i = 0; i < args.getLength(); i++)
252 : {
253 0 : if (args[i] >>= v)
254 : {
255 0 : if ( v.Name == "SessionManagerName" )
256 0 : v.Value >>= aSMgr;
257 0 : else if ( v.Name == "SessionManager" )
258 0 : v.Value >>= m_rSessionManager;
259 0 : else if ( v.Name == "AllowUserInteractionOnQuit" )
260 0 : v.Value >>= m_bAllowUserInteractionOnQuit;
261 : }
262 0 : }
263 : }
264 0 : if (!m_rSessionManager.is())
265 0 : m_rSessionManager = css::uno::Reference< frame::XSessionManagerClient >
266 0 : (m_xContext->getServiceManager()->createInstanceWithContext(aSMgr, m_xContext), UNO_QUERY);
267 :
268 0 : if (m_rSessionManager.is())
269 : {
270 0 : m_rSessionManager->addSessionManagerListener(this);
271 0 : }
272 0 : }
273 :
274 0 : void SAL_CALL SessionListener::statusChanged(const frame::FeatureStateEvent& event)
275 : throw (css::uno::RuntimeException, std::exception)
276 : {
277 : SAL_INFO("fwk.session", "SessionListener::statusChanged");
278 0 : if ( event.FeatureURL.Complete == "vnd.sun.star.autorecovery:/doSessionRestore" )
279 : {
280 0 : if (event.FeatureDescriptor == "update")
281 0 : m_bRestored = true; // a document was restored
282 :
283 : }
284 0 : else if ( event.FeatureURL.Complete == "vnd.sun.star.autorecovery:/doSessionSave" )
285 : {
286 0 : if (event.FeatureDescriptor == "stop")
287 : {
288 0 : if (m_rSessionManager.is())
289 0 : m_rSessionManager->saveDone(this); // done with save
290 : }
291 : }
292 0 : }
293 :
294 0 : sal_Bool SAL_CALL SessionListener::doRestore()
295 : throw (RuntimeException, std::exception)
296 : {
297 : SAL_INFO("fwk.session", "SessionListener::doRestore");
298 0 : osl::MutexGuard g(m_aMutex);
299 0 : m_bRestored = false;
300 : try {
301 0 : css::uno::Reference< frame::XDispatch > xDispatch = css::frame::theAutoRecovery::get( m_xContext );
302 :
303 0 : URL aURL;
304 0 : aURL.Complete = "vnd.sun.star.autorecovery:/doSessionRestore";
305 0 : css::uno::Reference< XURLTransformer > xURLTransformer(URLTransformer::create(m_xContext));
306 0 : xURLTransformer->parseStrict(aURL);
307 0 : Sequence< PropertyValue > args;
308 0 : xDispatch->addStatusListener(this, aURL);
309 0 : xDispatch->dispatch(aURL, args);
310 0 : m_bRestored = true;
311 :
312 0 : } catch (const com::sun::star::uno::Exception& e) {
313 : SAL_WARN("fwk.session",e.Message);
314 : }
315 :
316 0 : return m_bRestored;
317 : }
318 :
319 0 : void SAL_CALL SessionListener::doSave( sal_Bool bShutdown, sal_Bool /*bCancelable*/ )
320 : throw (RuntimeException, std::exception)
321 : {
322 : SAL_INFO("fwk.session", "SessionListener::doSave");
323 0 : if (bShutdown)
324 : {
325 0 : m_bSessionStoreRequested = true; // there is no need to protect it with mutex
326 0 : if ( m_bAllowUserInteractionOnQuit && m_rSessionManager.is() )
327 0 : m_rSessionManager->queryInteraction( static_cast< css::frame::XSessionManagerListener* >( this ) );
328 : else
329 0 : StoreSession( true );
330 : }
331 : // we don't have anything to do so tell the session manager we're done
332 0 : else if( m_rSessionManager.is() )
333 0 : m_rSessionManager->saveDone( this );
334 0 : }
335 :
336 0 : void SAL_CALL SessionListener::approveInteraction( sal_Bool bInteractionGranted )
337 : throw (RuntimeException, std::exception)
338 : {
339 : SAL_INFO("fwk.session", "SessionListener::approveInteraction");
340 : // do AutoSave as the first step
341 0 : osl::MutexGuard g(m_aMutex);
342 :
343 0 : if ( bInteractionGranted )
344 : {
345 : // close the office documents in normal way
346 : try
347 : {
348 : // first of all let the session be stored to be sure that we lose no information
349 0 : StoreSession( false );
350 :
351 0 : css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext );
352 : // honestly: how many implementations of XDesktop will we ever have?
353 : // so casting this directly to the implementation
354 0 : Desktop* pDesktop(dynamic_cast<Desktop*>(xDesktop.get()));
355 0 : if(pDesktop)
356 : {
357 : SAL_INFO("fwk.session", "XDesktop is a framework::Desktop -- good.");
358 0 : m_bTerminated = pDesktop->terminateQuickstarterToo();
359 : }
360 : else
361 : {
362 : SAL_WARN("fwk.session", "XDesktop is not a framework::Desktop -- this should never happen.");
363 0 : m_bTerminated = xDesktop->terminate();
364 : }
365 :
366 0 : if ( m_rSessionManager.is() )
367 : {
368 : // false means that the application closing has been cancelled
369 0 : if ( !m_bTerminated )
370 0 : m_rSessionManager->cancelShutdown();
371 : else
372 0 : m_rSessionManager->interactionDone( this );
373 0 : }
374 : }
375 0 : catch( const css::uno::Exception& )
376 : {
377 0 : StoreSession( true );
378 0 : m_rSessionManager->interactionDone( this );
379 : }
380 :
381 0 : if ( m_rSessionManager.is() )
382 0 : m_rSessionManager->saveDone(this);
383 : }
384 : else
385 : {
386 0 : StoreSession( true );
387 0 : }
388 0 : }
389 :
390 0 : void SessionListener::shutdownCanceled()
391 : throw (RuntimeException, std::exception)
392 : {
393 : SAL_INFO("fwk.session", "SessionListener::shutdownCanceled");
394 : // set the state back
395 0 : m_bSessionStoreRequested = false; // there is no need to protect it with mutex
396 0 : }
397 :
398 0 : void SessionListener::doQuit()
399 : throw (RuntimeException, std::exception)
400 : {
401 : SAL_INFO("fwk.session", "SessionListener::doQuit");
402 0 : if ( m_bSessionStoreRequested && !m_bTerminated )
403 : {
404 : // let the session be closed quietly in this case
405 0 : QuitSessionQuietly();
406 : }
407 0 : }
408 :
409 : }
410 :
411 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
412 0 : com_sun_star_comp_frame_SessionListener_get_implementation(
413 : css::uno::XComponentContext *context,
414 : css::uno::Sequence<css::uno::Any> const &)
415 : {
416 0 : return cppu::acquire(new SessionListener(context));
417 : }
418 :
419 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|