lok: register view callback also for nested sm view
[LibreOffice.git] / comphelper / source / misc / instancelocker.cxx
blob84c8054ecbb8fae8dc1c783d5b68484433505099
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 .
21 #include <cppuhelper/supportsservice.hxx>
23 #include <com/sun/star/util/CloseVetoException.hpp>
24 #include <com/sun/star/util/XCloseBroadcaster.hpp>
25 #include <com/sun/star/util/XCloseable.hpp>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/lang/IllegalArgumentException.hpp>
28 #include <com/sun/star/frame/XDesktop.hpp>
29 #include <com/sun/star/frame/TerminationVetoException.hpp>
30 #include <com/sun/star/frame/DoubleInitializationException.hpp>
31 #include <com/sun/star/embed/Actions.hpp>
32 #include <com/sun/star/embed/XActionsApproval.hpp>
33 #include <utility>
35 #include "instancelocker.hxx"
37 namespace com::sun::star::uno { class XComponentContext; }
39 using namespace ::com::sun::star;
42 // OInstanceLocker
45 OInstanceLocker::OInstanceLocker()
46 : m_bDisposed( false )
47 , m_bInitialized( false )
52 OInstanceLocker::~OInstanceLocker()
54 if ( !m_bDisposed )
56 osl_atomic_increment(&m_refCount); // to call dispose
57 try {
58 dispose();
60 catch ( uno::RuntimeException& )
65 // XComponent
67 void SAL_CALL OInstanceLocker::dispose()
69 std::unique_lock aGuard( m_aMutex );
71 if ( m_bDisposed )
72 throw lang::DisposedException();
74 lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) );
75 m_aListenersContainer.disposeAndClear( aGuard, aSource );
76 if ( m_xLockListener.is() )
78 auto tmp = std::move(m_xLockListener);
79 aGuard.unlock();
80 tmp->Dispose();
81 aGuard.lock();
84 m_bDisposed = true;
88 void SAL_CALL OInstanceLocker::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
90 std::unique_lock aGuard( m_aMutex );
91 if ( m_bDisposed )
92 throw lang::DisposedException(); // TODO
94 m_aListenersContainer.addInterface( aGuard, xListener );
98 void SAL_CALL OInstanceLocker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
100 std::unique_lock aGuard( m_aMutex );
101 m_aListenersContainer.removeInterface( aGuard, xListener );
104 // XInitialization
106 void SAL_CALL OInstanceLocker::initialize( const uno::Sequence< uno::Any >& aArguments )
108 std::unique_lock aGuard( m_aMutex );
109 if ( m_bInitialized )
110 throw frame::DoubleInitializationException();
112 if ( m_bDisposed )
113 throw lang::DisposedException(); // TODO
115 if ( !m_refCount )
116 throw uno::RuntimeException(); // the object must be refcounted already!
118 uno::Reference< uno::XInterface > xInstance;
119 uno::Reference< embed::XActionsApproval > xApproval;
123 sal_Int32 nLen = aArguments.getLength();
124 if ( nLen < 2 || nLen > 3 )
125 throw lang::IllegalArgumentException(
126 "Wrong count of parameters!",
127 uno::Reference< uno::XInterface >(),
128 0 );
130 if ( !( aArguments[0] >>= xInstance ) || !xInstance.is() )
131 throw lang::IllegalArgumentException(
132 "Nonempty reference is expected as the first argument!",
133 uno::Reference< uno::XInterface >(),
134 0 );
136 sal_Int32 nModes = 0;
137 if (
138 !( aArguments[1] >>= nModes ) ||
140 !( nModes & embed::Actions::PREVENT_CLOSE ) &&
141 !( nModes & embed::Actions::PREVENT_TERMINATION )
145 throw lang::IllegalArgumentException(
146 "The correct modes set is expected as the second argument!",
147 uno::Reference< uno::XInterface >(),
148 0 );
151 if ( nLen == 3 && !( aArguments[2] >>= xApproval ) )
152 throw lang::IllegalArgumentException(
153 "If the third argument is provided, it must be XActionsApproval implementation!",
154 uno::Reference< uno::XInterface >(),
155 0 );
157 m_xLockListener = new OLockListener( uno::Reference< lang::XComponent > ( static_cast< lang::XComponent* >( this ) ),
158 xInstance,
159 nModes,
160 xApproval );
161 m_xLockListener->Init();
163 catch( uno::Exception& )
165 aGuard.unlock();
166 dispose();
167 throw;
170 m_bInitialized = true;
173 // XServiceInfo
174 OUString SAL_CALL OInstanceLocker::getImplementationName( )
176 return "com.sun.star.comp.embed.InstanceLocker";
179 sal_Bool SAL_CALL OInstanceLocker::supportsService( const OUString& ServiceName )
181 return cppu::supportsService(this, ServiceName);
184 uno::Sequence< OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames()
186 return { "com.sun.star.embed.InstanceLocker" };
189 // OLockListener
192 OLockListener::OLockListener( uno::WeakReference< lang::XComponent > xWrapper,
193 uno::Reference< uno::XInterface > xInstance,
194 sal_Int32 nMode,
195 uno::Reference< embed::XActionsApproval > xApproval )
196 : m_xInstance(std::move( xInstance ))
197 , m_xApproval(std::move( xApproval ))
198 , m_xWrapper(std::move( xWrapper ))
199 , m_bDisposed( false )
200 , m_bInitialized( false )
201 , m_nMode( nMode )
206 OLockListener::~OLockListener()
211 void OLockListener::Dispose()
213 std::unique_lock aGuard( m_aMutex );
215 if ( m_bDisposed )
216 return;
218 auto xInstance = std::move(m_xInstance);
219 auto nMode = m_nMode;
220 m_bDisposed = true;
221 aGuard.unlock();
223 if ( nMode & embed::Actions::PREVENT_CLOSE )
227 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( xInstance, uno::UNO_QUERY );
228 if ( xCloseBroadcaster.is() )
229 xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
231 uno::Reference< util::XCloseable > xCloseable( xInstance, uno::UNO_QUERY );
232 if ( xCloseable.is() )
233 xCloseable->close( true );
235 catch( uno::Exception& )
239 if ( nMode & embed::Actions::PREVENT_TERMINATION )
243 uno::Reference< frame::XDesktop > xDesktop( xInstance, uno::UNO_QUERY_THROW );
244 xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
246 catch( uno::Exception& )
251 // XEventListener
253 void SAL_CALL OLockListener::disposing( const lang::EventObject& aEvent )
255 std::unique_lock aGuard( m_aMutex );
257 // object is disposed
258 if ( aEvent.Source != m_xInstance )
259 return;
261 // the object does not listen for anything any more
262 m_nMode = 0;
264 // dispose the wrapper;
265 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
266 aGuard.unlock();
267 if ( xComponent.is() )
269 try { xComponent->dispose(); }
270 catch( uno::Exception& ){}
275 // XCloseListener
277 void SAL_CALL OLockListener::queryClosing( const lang::EventObject& aEvent, sal_Bool )
279 // GetsOwnership parameter is always ignored, the user of the service must close the object always
280 std::unique_lock aGuard( m_aMutex );
281 if ( !(!m_bDisposed && aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_CLOSE )) )
282 return;
286 uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
288 // unlock the mutex here
289 aGuard.unlock();
291 if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_CLOSE ) )
292 throw util::CloseVetoException();
294 catch( util::CloseVetoException& )
296 // rethrow this exception
297 throw;
299 catch( uno::Exception& )
301 // no action should be done
306 void SAL_CALL OLockListener::notifyClosing( const lang::EventObject& aEvent )
308 std::unique_lock aGuard( m_aMutex );
310 // object is closed, no reason to listen
311 if ( aEvent.Source != m_xInstance )
312 return;
314 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( aEvent.Source, uno::UNO_QUERY );
315 if ( !xCloseBroadcaster.is() )
316 return;
318 xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
319 m_nMode &= ~embed::Actions::PREVENT_CLOSE;
320 if ( !m_nMode )
322 // dispose the wrapper;
323 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
324 aGuard.unlock();
325 if ( xComponent.is() )
327 try { xComponent->dispose(); }
328 catch( uno::Exception& ){}
334 // XTerminateListener
336 void SAL_CALL OLockListener::queryTermination( const lang::EventObject& aEvent )
338 std::unique_lock aGuard( m_aMutex );
339 if ( !(aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_TERMINATION )) )
340 return;
344 uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
346 // unlock the mutex here
347 aGuard.unlock();
349 if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_TERMINATION ) )
350 throw frame::TerminationVetoException();
352 catch( frame::TerminationVetoException& )
354 // rethrow this exception
355 throw;
357 catch( uno::Exception& )
359 // no action should be done
364 void SAL_CALL OLockListener::notifyTermination( const lang::EventObject& aEvent )
366 std::unique_lock aGuard( m_aMutex );
368 // object is terminated, no reason to listen
369 if ( aEvent.Source != m_xInstance )
370 return;
372 uno::Reference< frame::XDesktop > xDesktop( aEvent.Source, uno::UNO_QUERY );
373 if ( !xDesktop.is() )
374 return;
378 xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
379 m_nMode &= ~embed::Actions::PREVENT_TERMINATION;
380 if ( !m_nMode )
382 // dispose the wrapper;
383 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
384 aGuard.unlock();
385 if ( xComponent.is() )
387 try { xComponent->dispose(); }
388 catch( uno::Exception& ){}
392 catch( uno::Exception& )
397 // XInitialization
399 void OLockListener::Init()
401 std::unique_lock aGuard( m_aMutex );
403 if ( m_bDisposed || m_bInitialized )
404 return;
408 if ( m_nMode & embed::Actions::PREVENT_CLOSE )
410 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY_THROW );
411 xCloseBroadcaster->addCloseListener( static_cast< util::XCloseListener* >( this ) );
414 if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
416 uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
417 xDesktop->addTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
420 catch( uno::Exception& )
422 // dispose the wrapper;
423 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
424 aGuard.unlock();
425 if ( xComponent.is() )
427 try { xComponent->dispose(); }
428 catch( uno::Exception& ){}
431 throw;
434 m_bInitialized = true;
437 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
438 com_sun_star_comp_embed_InstanceLocker(
439 css::uno::XComponentContext *,
440 css::uno::Sequence<css::uno::Any> const &)
442 return cppu::acquire(new OInstanceLocker());
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */