1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
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
68 <li>implementation of query mode</li>
69 <li>simple restore mechanism of last consistent cache state,
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
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
;
93 bool m_bSessionStoreRequested
;
95 bool m_bAllowUserInteractionOnQuit
;
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();
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
;
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
;
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
);
176 aURL
.Complete
= "vnd.sun.star.autorecovery:/doSessionSave";
177 xURLTransformer
->parseStrict(aURL
);
179 // in case of asynchronous call the notification will trigger saveDone()
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
);
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
) )
234 else if (args
.hasElements())
237 for (const Any
& rArg
: args
)
241 if ( v
.Name
== "SessionManagerName" )
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
);
291 css::uno::Reference
< frame::XDispatch
> xDispatch
= css::frame::theAutoRecovery::get( m_xContext
);
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
);
302 } catch (const css::uno::Exception
&) {
303 TOOLS_WARN_EXCEPTION("fwk.session", "");
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"));
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 ) );
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()));
348 SAL_INFO("fwk.session", " XDesktop is a framework::Desktop -- good.");
349 m_bTerminated
= pDesktop
->terminateQuickstarterToo();
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();
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);
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: */