INTEGRATION: CWS swqbf91 (1.61.120); FILE MERGED
2007/06/21 12:53:26 as 1.61.120.2: #i73788# handle sfx terminate listener exlicit 2007/06/20 05:11:39 as 1.61.120.1: #i73788# desktop.terminate() supports new optional interface which notifies listener about canceled termination
This commit is contained in:
parent
ef96cf4ed4
commit
d184137f62
1 changed files with 394 additions and 413 deletions
|
@ -4,9 +4,9 @@
|
|||
*
|
||||
* $RCSfile: desktop.cxx,v $
|
||||
*
|
||||
* $Revision: 1.61 $
|
||||
* $Revision: 1.62 $
|
||||
*
|
||||
* last change: $Author: obo $ $Date: 2006-09-16 14:08:27 $
|
||||
* last change: $Author: obo $ $Date: 2007-07-18 13:25:55 $
|
||||
*
|
||||
* The Contents of this file are made available subject to
|
||||
* the terms of GNU Lesser General Public License Version 2.1.
|
||||
|
@ -188,6 +188,10 @@
|
|||
#include <com/sun/star/document/UpdateDocMode.hpp>
|
||||
#endif
|
||||
|
||||
#ifndef _COM_SUN_STAR_FRAME_XTERMINATELISTENER2_HPP_
|
||||
#include <com/sun/star/frame/XTerminateListener2.hpp>
|
||||
#endif
|
||||
|
||||
//_________________________________________________________________________________________________________________
|
||||
// includes of other projects
|
||||
//_________________________________________________________________________________________________________________
|
||||
|
@ -321,14 +325,6 @@ DEFINE_INIT_SERVICE ( Desktop,
|
|||
InterceptionHelper* pInterceptionHelper = new InterceptionHelper( this, xDispatchProvider );
|
||||
m_xDispatchHelper = css::uno::Reference< css::frame::XDispatchProvider >( static_cast< ::cppu::OWeakObject* >(pInterceptionHelper), css::uno::UNO_QUERY );
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// I'am the desktop - and use my frame container in a special mode.
|
||||
// If last child task is removed, I must die!
|
||||
// My container should terminate me asynchronous by using a timer.
|
||||
// Enable timer at container.
|
||||
// (The timer will be initialized with right timeout value automaticly by himself. see class AsyncQuit for further informations!)
|
||||
m_aChildTaskContainer.enableQuitTimer( this );
|
||||
|
||||
// Safe impossible cases
|
||||
// We can't work without this helper!
|
||||
LOG_ASSERT2( m_xFramesHelper.is ()==sal_False, "Desktop::Desktop()", "Frames helper is not valid. XFrames, XIndexAccess and XElementAcces are not supported!\n")
|
||||
|
@ -378,9 +374,20 @@ Desktop::Desktop( const css::uno::Reference< css::lang::XMultiServiceFactory >&
|
|||
, m_xFactory ( xFactory )
|
||||
, m_aChildTaskContainer ( )
|
||||
, m_aListenerContainer ( m_aLock.getShareableOslMutex() )
|
||||
, m_xFramesHelper ( )
|
||||
, m_xDispatchHelper ( )
|
||||
, m_eLoadState ( E_NOTSET )
|
||||
, m_xLastFrame ( )
|
||||
, m_aInteractionRequest ( )
|
||||
, m_bSuspendQuickstartVeto( sal_False )
|
||||
, m_bSuspendQuickstartVeto( sal_False )
|
||||
, m_aCommandOptions ( )
|
||||
, m_sName ( )
|
||||
, m_sTitle ( )
|
||||
, m_xDispatchRecorderSupplier( )
|
||||
, m_xPipeTerminator ( )
|
||||
, m_xQuickLauncher ( )
|
||||
, m_xSWThreadManager ( )
|
||||
, m_xSfxTerminator ( )
|
||||
{
|
||||
// Safe impossible cases
|
||||
// We don't accept all incoming parameter.
|
||||
|
@ -404,337 +411,229 @@ Desktop::~Desktop()
|
|||
LOG_ASSERT2( m_aTransactionManager.getWorkingMode()!=E_CLOSE , "Desktop::~Desktop()", "Who forgot to dispose this service?" )
|
||||
}
|
||||
|
||||
/*-************************************************************************************************************//**
|
||||
@interface XDesktop
|
||||
@short ask desktop before terminate it
|
||||
@descr The desktop ask his components and if all say "yes" it will destroy this components
|
||||
and return "yes" to caller of this method. Otherwhise, desktop will not be destroied!
|
||||
But a TerminateListener with a veto - will be the new owner of this service and MUST
|
||||
call terminate again, if he stop using of it!
|
||||
|
||||
@seealso interface XTerminateListener
|
||||
|
||||
@param -
|
||||
@return sal_True ,if all components say "yes" for terminate
|
||||
sal_False ,otherwise
|
||||
|
||||
@onerror We return sal_False.
|
||||
@threadsafe yes
|
||||
*//*-*************************************************************************************************************/
|
||||
sal_Bool SAL_CALL Desktop::terminate() throw( css::uno::RuntimeException )
|
||||
//=============================================================================
|
||||
sal_Bool SAL_CALL Desktop::terminate()
|
||||
throw( css::uno::RuntimeException )
|
||||
{
|
||||
/* UNSAFE AREA --------------------------------------------------------------------------------------------- */
|
||||
// Register transaction and reject wrong calls.
|
||||
TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
|
||||
|
||||
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
|
||||
ReadGuard aReadLock( m_aLock );
|
||||
// Attention, Our timer hold a reference to use ... and sometimes (e.g. for headless office mode)
|
||||
// he forget this one insteandly during his own instantiation! So we can die during next call.
|
||||
// That's why it's agood idea to hold use self alive.
|
||||
css::uno::Reference< css::frame::XDesktop > xThis( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
|
||||
// Get other neccessary references.
|
||||
css::uno::Reference< css::frame::XTerminateListener > xPipeTerminator = m_xPipeTerminator ;
|
||||
css::uno::Reference< css::frame::XTerminateListener > xQuickLauncher = m_xQuickLauncher ;
|
||||
css::lang::EventObject aEvent ( static_cast< ::cppu::OWeakObject* >(this) );
|
||||
sal_Bool bAskQuickStart = !m_bSuspendQuickstartVeto ;
|
||||
aReadLock.unlock();
|
||||
/* UNSAFE AREA --------------------------------------------------------------------------------------------- */
|
||||
SYNCHRONIZED_START
|
||||
ReadGuard aReadLock( m_aLock );
|
||||
|
||||
// Set default. If a veto occure - break operation and
|
||||
// return "not terminated". Otherwise termination was successfully.
|
||||
sal_Bool bNormalListenerVeto = sal_False;
|
||||
sal_Bool bQuickLaunchVeto = sal_False;
|
||||
sal_Bool bPipeVeto = sal_False;
|
||||
sal_Bool bTaskVeto = sal_False;
|
||||
css::uno::Reference< css::frame::XTerminateListener > xPipeTerminator = m_xPipeTerminator;
|
||||
css::uno::Reference< css::frame::XTerminateListener > xQuickLauncher = m_xQuickLauncher;
|
||||
css::uno::Reference< css::frame::XTerminateListener > xSWThreadManager = m_xSWThreadManager;
|
||||
css::uno::Reference< css::frame::XTerminateListener > xSfxTerminator = m_xSfxTerminator;
|
||||
|
||||
css::lang::EventObject aEvent ( static_cast< ::cppu::OWeakObject* >(this) );
|
||||
::sal_Bool bAskQuickStart = !m_bSuspendQuickstartVeto ;
|
||||
|
||||
aReadLock.unlock();
|
||||
SYNCHRONIZED_END
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// Disable our async quit timer ... we terminate ourself!
|
||||
// But if termination fail ... don't forget to enable it again!
|
||||
// Member is threadsafe himself!
|
||||
m_aChildTaskContainer.disableQuitTimer();
|
||||
// Ask normal terminate listener. They could stop terminate without closing any open document.
|
||||
Desktop::TTerminateListenerList lCalledTerminationListener;
|
||||
::sal_Bool bVeto = sal_False;
|
||||
impl_sendQueryTerminationEvent(lCalledTerminationListener, bVeto);
|
||||
if ( bVeto )
|
||||
{
|
||||
impl_sendCancelTerminationEvent(lCalledTerminationListener);
|
||||
return sal_False;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// Ask normal terminate listener. They could stop complete terminate AND closing of currently open documents!
|
||||
// try to close all open frames.
|
||||
// Allow using of any UI ... because Desktop.terminate() was designed as UI functionality in the past.
|
||||
::sal_Bool bAllowUI = sal_True;
|
||||
::sal_Bool bFramesClosed = impl_closeFrames(bAllowUI);
|
||||
if ( ! bFramesClosed )
|
||||
{
|
||||
impl_sendCancelTerminationEvent(lCalledTerminationListener);
|
||||
return sal_False;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// Normal listener had no problem ...
|
||||
// all frames was closed ...
|
||||
// now it's time to ask our specialized listener.
|
||||
// They are handled these way because they wish to hinder the office on termination
|
||||
// but they wish also closing of all frames.
|
||||
|
||||
// Note further:
|
||||
// We shouldn't ask quicklauncher in case it was allowed from outside only.
|
||||
// This is special trick to "ignore existing quick starter" for debug purposes.
|
||||
|
||||
// Attention:
|
||||
// Order of alled listener is important !
|
||||
// some of them are harmless .-)
|
||||
// But some of them can be dangerous. E.g. it would be dangerous if we close our pipe
|
||||
// and dont terminate in real because another listener throws a veto exception .-)
|
||||
|
||||
::sal_Bool bTerminate = sal_False;
|
||||
try
|
||||
{
|
||||
impl_sendQueryTerminationEvent();
|
||||
}
|
||||
catch( css::frame::TerminationVetoException& )
|
||||
{
|
||||
bNormalListenerVeto = sal_True;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// If no veto comes we should ask our quicklauncher.
|
||||
// He stop termination of whole office .. but not closing of open tasks!!!
|
||||
// We shouldn't ask quicklauncher if property "SuspendQuickstartVeto" is set to FALSE!!
|
||||
if(
|
||||
( bNormalListenerVeto == sal_False ) &&
|
||||
( bAskQuickStart == sal_True ) &&
|
||||
( xQuickLauncher.is() == sal_True )
|
||||
)
|
||||
{
|
||||
try
|
||||
if(
|
||||
( bAskQuickStart ) &&
|
||||
( xQuickLauncher.is() )
|
||||
)
|
||||
{
|
||||
xQuickLauncher->queryTermination( aEvent );
|
||||
lCalledTerminationListener.push_back( xQuickLauncher );
|
||||
}
|
||||
catch( css::frame::TerminationVetoException& )
|
||||
{
|
||||
bQuickLaunchVeto = sal_True;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// If no veto comes from quick launcher ... we should ask our pipe terminator too.
|
||||
// He close pipe if no external requests are pending.
|
||||
// Otherwise he throw the veto exception and we don't terminate AND don't close open tasks!
|
||||
// Attention: If quick launcher exist - ask him before pipe terminator. Otherwise pipe will be closed
|
||||
// quick launcher stop real termination ... but pipe will not reopened! So no further external requests
|
||||
// could come in!!!
|
||||
if(
|
||||
( bNormalListenerVeto == sal_False ) &&
|
||||
( bQuickLaunchVeto == sal_False ) &&
|
||||
( xPipeTerminator.is() == sal_True )
|
||||
)
|
||||
{
|
||||
try
|
||||
if ( xSWThreadManager.is() )
|
||||
{
|
||||
xSWThreadManager->queryTermination( aEvent );
|
||||
lCalledTerminationListener.push_back( xSWThreadManager );
|
||||
}
|
||||
|
||||
if ( xPipeTerminator.is() )
|
||||
{
|
||||
xPipeTerminator->queryTermination( aEvent );
|
||||
lCalledTerminationListener.push_back( xPipeTerminator );
|
||||
}
|
||||
catch( css::frame::TerminationVetoException& )
|
||||
|
||||
if ( xSfxTerminator.is() )
|
||||
{
|
||||
bPipeVeto = sal_True;
|
||||
xSfxTerminator->queryTermination( aEvent );
|
||||
lCalledTerminationListener.push_back( xSfxTerminator );
|
||||
}
|
||||
|
||||
bTerminate = sal_True;
|
||||
}
|
||||
catch(const css::frame::TerminationVetoException&)
|
||||
{
|
||||
bTerminate = sal_False;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// Close tasks only, if no veto exist ... but if veto comes from our quick launcher ...
|
||||
// DO IT! He stop termination - not closing tasks. => It doesn't matter, if bQuickLaunchVeto is true or false.
|
||||
// We close tasks for both cases!
|
||||
if(
|
||||
( bNormalListenerVeto == sal_False ) &&
|
||||
( bPipeVeto == sal_False )
|
||||
)
|
||||
if ( ! bTerminate )
|
||||
impl_sendCancelTerminationEvent(lCalledTerminationListener);
|
||||
else
|
||||
{
|
||||
// Step over all child tasks and ask they "WOULD YOU DIE?"
|
||||
css::uno::Sequence< css::uno::Reference< css::frame::XFrame > > lTasks = m_aChildTaskContainer.getAllElements();
|
||||
sal_Int32 c = lTasks.getLength();
|
||||
sal_Int32 i = 0;
|
||||
for(i=0; !bTaskVeto && i<c; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get an element from container and cast it to task.
|
||||
// Ignore already gone references.
|
||||
// So it can happen that a frame was still closed by another client.
|
||||
css::uno::Reference< css::frame::XFrame > xTask = lTasks[i];
|
||||
if (! xTask.is())
|
||||
continue;
|
||||
#ifdef ENABLE_ASSERTIONS
|
||||
// "Protect" us against dispose before terminate calls!
|
||||
// see dispose() for further informations.
|
||||
/* SAFE AREA --------------------------------------------------------------------------------------- */
|
||||
WriteGuard aWriteLock( m_aLock );
|
||||
m_bIsTerminated = sal_True;
|
||||
aWriteLock.unlock();
|
||||
/* UNSAFE AREA ------------------------------------------------------------------------------------- */
|
||||
#endif
|
||||
|
||||
// Terminate allow showing of UI ... so it can ask a controller
|
||||
// if it agree with a close. If it disagree .. stop terminate!
|
||||
css::uno::Reference< css::frame::XController > xController( xTask->getController(), css::uno::UNO_QUERY );
|
||||
sal_Bool bReactivateController = sal_False;
|
||||
if (xController.is())
|
||||
{
|
||||
sal_Bool bSuspended = xController->suspend(sal_True);
|
||||
if (!bSuspended)
|
||||
{
|
||||
bTaskVeto = sal_True;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
bReactivateController = sal_True;
|
||||
}
|
||||
|
||||
css::uno::Reference< css::util::XCloseable > xClose(xTask, css::uno::UNO_QUERY);
|
||||
if (xClose.is())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Don't deliver ownership of this task to any other one! => means call close(sal_False).
|
||||
// Desktop::terminate() can be called by the user ... using "File->Exit()" again!
|
||||
xClose->close(sal_False);
|
||||
// Don't remove the task from our child container!
|
||||
// A task do it by itself inside close
|
||||
}
|
||||
catch( css::util::CloseVetoException& )
|
||||
{
|
||||
// Any internal process of this task disagree with our request.
|
||||
// Safe this state and break this loop. Following task willn't be asked!
|
||||
bTaskVeto = sal_True;
|
||||
|
||||
if (
|
||||
(bReactivateController) &&
|
||||
(xController.is() )
|
||||
)
|
||||
xController->suspend(sal_False);
|
||||
}
|
||||
|
||||
// It doesnt matter if this task was closed sucesfully or not.
|
||||
// It's not allowed to try other possible interfaces to kill this task.
|
||||
// Try the next one !
|
||||
continue;
|
||||
}
|
||||
|
||||
css::uno::Reference< css::lang::XComponent > xDispose(xTask, css::uno::UNO_QUERY);
|
||||
if (xDispose.is())
|
||||
xDispose->dispose();
|
||||
}
|
||||
catch(const css::lang::DisposedException&)
|
||||
{
|
||||
// Task already closed / disposed by another thread or user ...
|
||||
// It doesn't matter! Because dead is dead is dead ...!
|
||||
// Do nothing and try to close next one.
|
||||
// But may it's agood idea to release this task from our container
|
||||
m_aChildTaskContainer.remove( lTasks[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// All listener has no problem with our termination!
|
||||
// Send NotifyTermination event to all and return with true.
|
||||
sal_Bool bTerminated = (
|
||||
( bNormalListenerVeto == sal_False ) &&
|
||||
( bQuickLaunchVeto == sal_False ) &&
|
||||
( bPipeVeto == sal_False ) &&
|
||||
( bTaskVeto == sal_False )
|
||||
);
|
||||
#ifdef ENABLE_ASSERTIONS
|
||||
// "Protect" us against dispose before terminate calls!
|
||||
// see dispose() for further informations.
|
||||
// Follow notify will start shutdown of office and somewhere call dispose() at us ...
|
||||
// Set debug variable BEFORE notify!
|
||||
/* SAFE AREA --------------------------------------------------------------------------------------- */
|
||||
WriteGuard aWriteLock( m_aLock );
|
||||
m_bIsTerminated = bTerminated;
|
||||
aWriteLock.unlock();
|
||||
/* UNSAFE AREA ------------------------------------------------------------------------------------- */
|
||||
#endif
|
||||
if( bTerminated == sal_True )
|
||||
{
|
||||
// Send event to normal listener ...
|
||||
impl_sendNotifyTerminationEvent();
|
||||
// ... but don't forget to send it to our special terminat listener too!
|
||||
if( xPipeTerminator.is() == sal_True )
|
||||
{
|
||||
xPipeTerminator->notifyTermination( aEvent );
|
||||
}
|
||||
if( xQuickLauncher.is() == sal_True )
|
||||
|
||||
if(
|
||||
( bAskQuickStart ) &&
|
||||
( xQuickLauncher.is() )
|
||||
)
|
||||
{
|
||||
xQuickLauncher->notifyTermination( aEvent );
|
||||
}
|
||||
}
|
||||
// If somewhere break this terminate operation and we must return FALSE ...
|
||||
// we must reactivate our quit timer!
|
||||
// Otherwise we live for ever.
|
||||
else
|
||||
{
|
||||
m_aChildTaskContainer.enableQuitTimer( xThis );
|
||||
|
||||
if ( xSWThreadManager.is() )
|
||||
xSWThreadManager->notifyTermination( aEvent );
|
||||
|
||||
if ( xPipeTerminator.is() )
|
||||
xPipeTerminator->notifyTermination( aEvent );
|
||||
|
||||
// Must be realy the last listener to be called.
|
||||
// Because it shutdown the whole process asynchronous !
|
||||
if ( xSfxTerminator.is() )
|
||||
xSfxTerminator->notifyTermination( aEvent );
|
||||
}
|
||||
|
||||
// Return result of this question.
|
||||
return bTerminated;
|
||||
return bTerminate;
|
||||
}
|
||||
|
||||
/*-************************************************************************************************************//**
|
||||
@interface XDesktop
|
||||
@short add/remove a listener for terminate events
|
||||
@descr You can add a listener, if you wish to get an event, if desktop will be terminate.
|
||||
Then it's possible to say "NO" by using a TerminateVetoException!
|
||||
|
||||
@attention a) We know a special terminate listener - the pipe terminator. He is called as last of all terminate
|
||||
listeners. If no request stands in our office pipe - he has no veto. Otherwise
|
||||
he close the pipe and external requests are rejected.
|
||||
b) Another special listener is our quick launcher. He throw a veto exception, if tray-icon
|
||||
is still active. But he doesn't block closing of tasks! So we must call him after closing of these ones!
|
||||
c) May be we dispose our listener during our own dispose methode ... after closing object for
|
||||
real working. They call us back to remove her interfaces from our listener container.
|
||||
So we should allow that by using E_SOFTEXCEPTIONS and suppress rejection of this calls!
|
||||
|
||||
@seealso method terminate()
|
||||
|
||||
@param "xListener" is a reference to the listener. His value must be valid!
|
||||
@return -
|
||||
|
||||
@onerror We do nothing.
|
||||
@threadsafe yes
|
||||
*//*-*************************************************************************************************************/
|
||||
void SAL_CALL Desktop::addTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener ) throw( css::uno::RuntimeException )
|
||||
//=============================================================================
|
||||
void SAL_CALL Desktop::addTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener )
|
||||
throw( css::uno::RuntimeException )
|
||||
{
|
||||
/* UNSAFE AREA --------------------------------------------------------------------------------------------- */
|
||||
// Safe impossible cases
|
||||
// Method not defined for all incoming parameter.
|
||||
LOG_ASSERT2( implcp_addTerminateListener( xListener ), "Desktop::addTerminateListener()", "Invalid parameter detected!" )
|
||||
// Register transaction and reject wrong calls.
|
||||
TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
|
||||
|
||||
sal_Bool bSpecialListener = sal_False ;
|
||||
css::uno::Reference< css::lang::XServiceInfo > xInfo ( xListener, css::uno::UNO_QUERY );
|
||||
if( xInfo.is() == sal_True )
|
||||
css::uno::Reference< css::lang::XServiceInfo > xInfo( xListener, css::uno::UNO_QUERY );
|
||||
if ( xInfo.is() )
|
||||
{
|
||||
::rtl::OUString sImplementationName = xInfo->getImplementationName();
|
||||
/* SAFE AREA ------------------------------------------------------------------------------------------- */
|
||||
|
||||
// SYCNHRONIZED ->
|
||||
WriteGuard aWriteLock( m_aLock );
|
||||
if( sImplementationName == IMPLEMENTATIONNAME_PIPETERMINATOR )
|
||||
|
||||
if( sImplementationName.equals(IMPLEMENTATIONNAME_SFXTERMINATOR) )
|
||||
{
|
||||
m_xSfxTerminator = xListener;
|
||||
return;
|
||||
}
|
||||
if( sImplementationName.equals(IMPLEMENTATIONNAME_PIPETERMINATOR) )
|
||||
{
|
||||
m_xPipeTerminator = xListener;
|
||||
bSpecialListener = sal_True ;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if( sImplementationName == IMPLEMENTATIONNAME_QUICKLAUNCHER )
|
||||
if( sImplementationName.equals(IMPLEMENTATIONNAME_QUICKLAUNCHER) )
|
||||
{
|
||||
m_xQuickLauncher = xListener;
|
||||
bSpecialListener = sal_True ;
|
||||
return;
|
||||
}
|
||||
if( sImplementationName.equals(IMPLEMENTATIONNAME_SWTHREADMANAGER) )
|
||||
{
|
||||
m_xSWThreadManager = xListener;
|
||||
return;
|
||||
}
|
||||
|
||||
aWriteLock.unlock();
|
||||
/* UNSAFE AREA ----------------------------------------------------------------------------------------- */
|
||||
// <- SYCNHRONIZED
|
||||
}
|
||||
|
||||
if( bSpecialListener == sal_False )
|
||||
{
|
||||
m_aListenerContainer.addInterface( ::getCppuType( ( const css::uno::Reference< css::frame::XTerminateListener >*) NULL ), xListener );
|
||||
}
|
||||
// No lock required ... container is threadsafe by itself.
|
||||
m_aListenerContainer.addInterface( ::getCppuType( ( const css::uno::Reference< css::frame::XTerminateListener >*) NULL ), xListener );
|
||||
}
|
||||
|
||||
//*****************************************************************************************************************
|
||||
void SAL_CALL Desktop::removeTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener ) throw( css::uno::RuntimeException )
|
||||
//=============================================================================
|
||||
void SAL_CALL Desktop::removeTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener )
|
||||
throw( css::uno::RuntimeException )
|
||||
{
|
||||
/* UNSAFE AREA --------------------------------------------------------------------------------------------- */
|
||||
// Safe impossible cases
|
||||
// Method not defined for all incoming parameter.
|
||||
LOG_ASSERT2( implcp_removeTerminateListener( xListener ), "Desktop::removeTerminateListener()", "Invalid parameter detected!" )
|
||||
// Register transaction and reject wrong calls.
|
||||
TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
|
||||
|
||||
sal_Bool bSpecialListener = sal_False ;
|
||||
css::uno::Reference< css::lang::XServiceInfo > xInfo ( xListener, css::uno::UNO_QUERY );
|
||||
if( xInfo.is() == sal_True )
|
||||
css::uno::Reference< css::lang::XServiceInfo > xInfo( xListener, css::uno::UNO_QUERY );
|
||||
if ( xInfo.is() )
|
||||
{
|
||||
::rtl::OUString sImplementationName = xInfo->getImplementationName();
|
||||
/* SAFE AREA ------------------------------------------------------------------------------------------- */
|
||||
|
||||
// SYCNHRONIZED ->
|
||||
WriteGuard aWriteLock( m_aLock );
|
||||
if( sImplementationName == IMPLEMENTATIONNAME_PIPETERMINATOR )
|
||||
|
||||
if( sImplementationName.equals(IMPLEMENTATIONNAME_SFXTERMINATOR) )
|
||||
{
|
||||
m_xPipeTerminator = css::uno::Reference< css::frame::XTerminateListener >();
|
||||
bSpecialListener = sal_True;
|
||||
m_xSfxTerminator.clear();
|
||||
return;
|
||||
}
|
||||
else
|
||||
if( sImplementationName == IMPLEMENTATIONNAME_QUICKLAUNCHER )
|
||||
|
||||
if( sImplementationName.equals(IMPLEMENTATIONNAME_PIPETERMINATOR) )
|
||||
{
|
||||
m_xQuickLauncher = css::uno::Reference< css::frame::XTerminateListener >();
|
||||
bSpecialListener = sal_True;
|
||||
m_xPipeTerminator.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if( sImplementationName.equals(IMPLEMENTATIONNAME_QUICKLAUNCHER) )
|
||||
{
|
||||
m_xQuickLauncher.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if( sImplementationName.equals(IMPLEMENTATIONNAME_SWTHREADMANAGER) )
|
||||
{
|
||||
m_xSWThreadManager.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
aWriteLock.unlock();
|
||||
/* UNSAFE AREA ----------------------------------------------------------------------------------------- */
|
||||
// <- SYCNHRONIZED
|
||||
}
|
||||
|
||||
if( bSpecialListener == sal_False )
|
||||
{
|
||||
m_aListenerContainer.removeInterface( ::getCppuType( ( const css::uno::Reference< css::frame::XTerminateListener >*) NULL ), xListener );
|
||||
}
|
||||
// No lock required ... container is threadsafe by itself.
|
||||
m_aListenerContainer.removeInterface( ::getCppuType( ( const css::uno::Reference< css::frame::XTerminateListener >*) NULL ), xListener );
|
||||
}
|
||||
|
||||
/*-************************************************************************************************************//**
|
||||
|
@ -1397,96 +1296,73 @@ css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::findFrame( const ::r
|
|||
return xTarget;
|
||||
}
|
||||
|
||||
/*-************************************************************************************************************//**
|
||||
@interface XComponent
|
||||
@short release all reference
|
||||
@descr The owner of this object calles the dispose method if the object
|
||||
should be destroyed. All other objects and components, that are registered
|
||||
as an EventListener are forced to release their references to this object.
|
||||
The reference attributes are disposed and released also.
|
||||
|
||||
@seealso -
|
||||
|
||||
@param -
|
||||
@return -
|
||||
|
||||
@onerror -
|
||||
@threadsafe yes
|
||||
*//*-*************************************************************************************************************/
|
||||
void SAL_CALL Desktop::dispose() throw( css::uno::RuntimeException )
|
||||
//=============================================================================
|
||||
void SAL_CALL Desktop::dispose()
|
||||
throw( css::uno::RuntimeException )
|
||||
{
|
||||
// Safe impossible cases
|
||||
// It's an programming error if dispose is called before terminate!
|
||||
LOG_ASSERT2( m_bIsTerminated==sal_False, "Desktop::dispose()", "It's not allowed to dispose the desktop before terminate() is called!" )
|
||||
|
||||
/*ATTENTION
|
||||
Make it threadsafe ... but this method is a special one!
|
||||
We must close objet for working BEFORE we dispose it realy ...
|
||||
After successful closing all interface calls are rejected by our
|
||||
transaction manager automaticly.
|
||||
*/
|
||||
SYNCHRONIZED_START
|
||||
WriteGuard aWriteLock( m_aLock );
|
||||
|
||||
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
|
||||
// Create an exclusiv access!
|
||||
// It's neccessary for follow transaction check ...
|
||||
// Another reason: We can recylce these write lock at later time ..
|
||||
// and it's superflous to create read- and write- locks in combination.
|
||||
WriteGuard aWriteLock( m_aLock );
|
||||
// Look for multiple calls of this method!
|
||||
// If somewhere call dispose() twice - he will be stopped here realy!!!
|
||||
TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
|
||||
|
||||
// Look for multiple calls of this method!
|
||||
// If somewhere call dispose() twice - he will be stopped here realy!!!
|
||||
TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
|
||||
// Now - we are alone and its the first call of this method ...
|
||||
// otherwise call before had thrown a DisposedException / hopefully .-)
|
||||
// But we dont use the transaction object created before ... we reset it immediatly ...
|
||||
// two lines of code ... for what ?
|
||||
// The answer: We wished to synchronize concurrent dispose() calls -> OK
|
||||
// But next line will wait for all currently running transaction (even if they
|
||||
// are running within the same thread!) So we would block ourself there if aTransaction
|
||||
// will stay registered .-)
|
||||
aTransaction.stop();
|
||||
|
||||
// Now - we are alone and its the first call of this method ...
|
||||
// otherwise call before must throw a DisposedException!
|
||||
// Don't forget to release this registered transaction here ...
|
||||
// because next "setWorkingMode()" call blocks till all current existing one
|
||||
// are finished!
|
||||
aTransaction.stop();
|
||||
// Disable this instance for further work.
|
||||
// This will wait for all current running transactions ...
|
||||
// and reject all new incoming requests!
|
||||
m_aTransactionManager.setWorkingMode( E_BEFORECLOSE );
|
||||
|
||||
// Disable this instance for further work.
|
||||
// This will wait for all current running ones ...
|
||||
// and reject all further requests!
|
||||
m_aTransactionManager.setWorkingMode( E_BEFORECLOSE );
|
||||
aWriteLock.unlock();
|
||||
SYNCHRONIZED_END
|
||||
|
||||
// We should hold a reference to ourself ...
|
||||
// because our owner dispose us and release our reference ...
|
||||
// May be we will die before we could finish this method ...
|
||||
// Make snapshot of other neecessary member too.
|
||||
css::uno::Reference< css::uno::XInterface > xThis( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
|
||||
// Following lines of code can be called outside a synchronized block ...
|
||||
// Because our transaction manager will block all new requests to this object.
|
||||
// So nobody can use us any longer.
|
||||
// Exception: Only removing of listener will work ... and this code cant be dangerous.
|
||||
|
||||
// We don't need this lock any longer ... this method couldn't be called twice ... it was disabled for working!
|
||||
aWriteLock.unlock();
|
||||
/* UNSAFE AREA --------------------------------------------------------------------------------------------- */
|
||||
// First we has to kill all listener connections.
|
||||
// They might rely on our member and can hinder us on releasing them.
|
||||
css::uno::Reference< css::uno::XInterface > xThis ( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
|
||||
css::lang::EventObject aEvent( xThis );
|
||||
m_aListenerContainer.disposeAndClear( aEvent );
|
||||
|
||||
// We must disable the special quit timer of our frame container.
|
||||
// Because it will call terminate at THESE instance if last task will be removed!.
|
||||
m_aChildTaskContainer.disableQuitTimer();
|
||||
|
||||
// We must send the dispose message to all listener.
|
||||
// Otherwise our child tasks are disposed and try to remove it by himself at our container ...
|
||||
css::lang::EventObject aDisposeEvent( xThis );
|
||||
m_aListenerContainer.disposeAndClear( aDisposeEvent );
|
||||
|
||||
// Clear our child task container and forget all task references.
|
||||
// Clear our child task container and forget all task references hardly.
|
||||
// Normaly all open document was already closed by our terminate() function before ...
|
||||
// New opened frames will have a problem now .-)
|
||||
m_aChildTaskContainer.clear();
|
||||
|
||||
// Dispose our helper too.
|
||||
css::uno::Reference< css::lang::XEventListener > xFramesHelper ( m_xFramesHelper , css::uno::UNO_QUERY );
|
||||
if( xFramesHelper.is() == sal_True )
|
||||
{
|
||||
xFramesHelper->disposing( aDisposeEvent );
|
||||
}
|
||||
css::uno::Reference< css::lang::XEventListener > xFramesHelper( m_xFramesHelper, css::uno::UNO_QUERY );
|
||||
if( xFramesHelper.is() )
|
||||
xFramesHelper->disposing( aEvent );
|
||||
|
||||
// Release all member references.
|
||||
m_xDispatchHelper = css::uno::Reference< css::frame::XDispatchProvider >();
|
||||
m_xFramesHelper = css::uno::Reference< css::frame::XFrames >();
|
||||
m_xLastFrame = css::uno::Reference< css::frame::XFrame >();
|
||||
m_xFactory = css::uno::Reference< css::lang::XMultiServiceFactory >();
|
||||
m_xPipeTerminator = css::uno::Reference< css::frame::XTerminateListener >();
|
||||
m_xQuickLauncher = css::uno::Reference< css::frame::XTerminateListener >();
|
||||
// At least clean up other member references.
|
||||
m_xDispatchHelper.clear();
|
||||
m_xFramesHelper.clear();
|
||||
m_xLastFrame.clear();
|
||||
m_xFactory.clear();
|
||||
|
||||
// Disable object for further working.
|
||||
m_xPipeTerminator.clear();
|
||||
m_xQuickLauncher.clear();
|
||||
m_xSWThreadManager.clear();
|
||||
m_xSfxTerminator.clear();
|
||||
|
||||
// From this point nothing will work further on this object ...
|
||||
// excepting our dtor() .-)
|
||||
m_aTransactionManager.setWorkingMode( E_CLOSE );
|
||||
}
|
||||
|
||||
|
@ -2014,85 +1890,190 @@ const css::uno::Sequence< css::beans::Property > Desktop::impl_getStaticProperty
|
|||
return lPropertyDescriptor;
|
||||
}
|
||||
|
||||
/*-************************************************************************************************************//**
|
||||
@short work with our terminate listener
|
||||
@descr If somewhere call terminate on this object, we must notify our listener. They could throw a veto exception
|
||||
to break it or accept it by doing nothing. These two helper methods send right events to all registered
|
||||
listener.
|
||||
|
||||
@attention We don't need any lock here - our container is threadsafe himself!
|
||||
|
||||
@seealso method terminate()
|
||||
|
||||
@param -
|
||||
@return -
|
||||
|
||||
@onerror -
|
||||
@threadsafe yes
|
||||
*//*-*************************************************************************************************************/
|
||||
void Desktop::impl_sendQueryTerminationEvent() throw( css::frame::TerminationVetoException )
|
||||
//=============================================================================
|
||||
void Desktop::impl_sendQueryTerminationEvent(Desktop::TTerminateListenerList& lCalledListener,
|
||||
::sal_Bool& bVeto )
|
||||
{
|
||||
/* UNSAFE AREA --------------------------------------------------------------------------------------------- */
|
||||
// Register transaction and reject wrong calls.
|
||||
bVeto = sal_False;
|
||||
|
||||
TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
|
||||
|
||||
// Send QueryTermination event to all listener.
|
||||
// Get container for right listener.
|
||||
::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( ::getCppuType( ( const css::uno::Reference< css::frame::XTerminateListener >*) NULL ) );
|
||||
if( pContainer != NULL )
|
||||
if ( ! pContainer )
|
||||
return;
|
||||
|
||||
css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
|
||||
|
||||
::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
|
||||
while ( aIterator.hasMoreElements() )
|
||||
{
|
||||
// Build QueryTermination event.
|
||||
css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
|
||||
// Get iterator for access to listener.
|
||||
::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
|
||||
// Send message to all listener.
|
||||
// Somewhere can throw a TerminationVetoException.
|
||||
// We don't look for that(!) ... caller of this method will catch these.
|
||||
while( aIterator.hasMoreElements() == sal_True )
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
((css::frame::XTerminateListener*)aIterator.next())->queryTermination( aEvent );
|
||||
}
|
||||
catch( css::uno::RuntimeException& )
|
||||
{
|
||||
aIterator.remove();
|
||||
}
|
||||
css::uno::Reference< css::frame::XTerminateListener > xListener(aIterator.next(), css::uno::UNO_QUERY);
|
||||
if ( ! xListener.is() )
|
||||
continue;
|
||||
xListener->queryTermination( aEvent );
|
||||
lCalledListener.push_back(xListener);
|
||||
}
|
||||
catch( const css::frame::TerminationVetoException& )
|
||||
{
|
||||
// first veto will stop notification loop.
|
||||
bVeto = sal_True;
|
||||
return;
|
||||
}
|
||||
catch( const css::uno::Exception& )
|
||||
{
|
||||
// clean up container.
|
||||
// E.g. dead remote listener objects can make trouble otherwise.
|
||||
// Iterator implementation allows removing objects during it's used !
|
||||
aIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************************************************
|
||||
void Desktop::impl_sendNotifyTerminationEvent()
|
||||
//=============================================================================
|
||||
void Desktop::impl_sendCancelTerminationEvent(const Desktop::TTerminateListenerList& lCalledListener)
|
||||
{
|
||||
/* UNSAFE AREA --------------------------------------------------------------------------------------------- */
|
||||
// Register transaction and reject wrong calls.
|
||||
TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
|
||||
|
||||
// Send NotifyTermination event to all listener.
|
||||
// Get container for right listener.
|
||||
::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( ::getCppuType( ( const css::uno::Reference< css::frame::XTerminateListener >*) NULL ) );
|
||||
if( pContainer != NULL )
|
||||
css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
|
||||
Desktop::TTerminateListenerList::const_iterator pIt;
|
||||
for ( pIt = lCalledListener.begin();
|
||||
pIt != lCalledListener.end ();
|
||||
++pIt )
|
||||
{
|
||||
// Build QueryTermination event.
|
||||
css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
|
||||
// Get iterator for access to listener.
|
||||
::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
|
||||
// Send message to all listener.
|
||||
while( aIterator.hasMoreElements() == sal_True )
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
((css::frame::XTerminateListener*)aIterator.next())->notifyTermination( aEvent );
|
||||
}
|
||||
catch( css::uno::RuntimeException& )
|
||||
{
|
||||
aIterator.remove();
|
||||
}
|
||||
// Note: cancelTermination() is a new and optional interface method !
|
||||
css::uno::Reference< css::frame::XTerminateListener > xListener = *pIt;
|
||||
css::uno::Reference< css::frame::XTerminateListener2 > xListenerGeneration2(xListener, css::uno::UNO_QUERY);
|
||||
if ( ! xListenerGeneration2.is() )
|
||||
continue;
|
||||
xListenerGeneration2->cancelTermination( aEvent );
|
||||
}
|
||||
catch( const css::uno::Exception& )
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
void Desktop::impl_sendNotifyTerminationEvent()
|
||||
{
|
||||
TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
|
||||
|
||||
::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( ::getCppuType( ( const css::uno::Reference< css::frame::XTerminateListener >*) NULL ) );
|
||||
if ( ! pContainer )
|
||||
return;
|
||||
|
||||
css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
|
||||
|
||||
::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
|
||||
while ( aIterator.hasMoreElements() )
|
||||
{
|
||||
try
|
||||
{
|
||||
css::uno::Reference< css::frame::XTerminateListener > xListener(aIterator.next(), css::uno::UNO_QUERY);
|
||||
if ( ! xListener.is() )
|
||||
continue;
|
||||
xListener->notifyTermination( aEvent );
|
||||
}
|
||||
catch( const css::uno::Exception& )
|
||||
{
|
||||
// clean up container.
|
||||
// E.g. dead remote listener objects can make trouble otherwise.
|
||||
// Iterator implementation allows removing objects during it's used !
|
||||
aIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
::sal_Bool Desktop::impl_closeFrames(::sal_Bool bAllowUI)
|
||||
{
|
||||
SYNCHRONIZED_START
|
||||
ReadGuard aReadLock( m_aLock );
|
||||
css::uno::Sequence< css::uno::Reference< css::frame::XFrame > > lFrames = m_aChildTaskContainer.getAllElements();
|
||||
aReadLock.unlock();
|
||||
SYNCHRONIZED_END
|
||||
|
||||
::sal_Int32 c = lFrames.getLength();
|
||||
::sal_Int32 i = 0;
|
||||
::sal_Int32 nNonClosedFrames = 0;
|
||||
|
||||
for( i=0; i<c; ++i )
|
||||
{
|
||||
try
|
||||
{
|
||||
css::uno::Reference< css::frame::XFrame > xFrame = lFrames[i];
|
||||
|
||||
// XController.suspend() will show an UI ...
|
||||
// Use it in case it was allowed from outside only.
|
||||
sal_Bool bSuspended = sal_False;
|
||||
css::uno::Reference< css::frame::XController > xController( xFrame->getController(), css::uno::UNO_QUERY );
|
||||
if (
|
||||
( bAllowUI ) &&
|
||||
( xController.is() )
|
||||
)
|
||||
{
|
||||
bSuspended = xController->suspend( sal_True );
|
||||
if ( ! bSuspended )
|
||||
{
|
||||
++nNonClosedFrames;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to close frame (in case no UI was allowed without calling XController->suspend() before!)
|
||||
// But don't deliver ownership to any other one!
|
||||
// This method can be called again.
|
||||
css::uno::Reference< css::util::XCloseable > xClose( xFrame, css::uno::UNO_QUERY );
|
||||
if ( xClose.is() )
|
||||
{
|
||||
try
|
||||
{
|
||||
xClose->close(sal_False);
|
||||
}
|
||||
catch(const css::util::CloseVetoException&)
|
||||
{
|
||||
// Any internal process of this frame disagree with our request.
|
||||
// Safe this state but dont break these loop. Other frames has to be closed!
|
||||
++nNonClosedFrames;
|
||||
|
||||
// Reactivate controller.
|
||||
// It can happen that XController.suspend() returned true ... but a registered close listener
|
||||
// throwed these veto exception. Then the controller has to be reactivated. Otherwise
|
||||
// these document doesnt work any more.
|
||||
if (
|
||||
(bSuspended ) &&
|
||||
(xController.is())
|
||||
)
|
||||
xController->suspend(sal_False);
|
||||
}
|
||||
|
||||
// If interface XClosable interface exists and was used ...
|
||||
// it's not allowed to use XComponent->dispose() also !
|
||||
continue;
|
||||
}
|
||||
|
||||
// XClosable not supported ?
|
||||
// Then we have to dispose these frame hardly.
|
||||
css::uno::Reference< css::lang::XComponent > xDispose( xFrame, css::uno::UNO_QUERY );
|
||||
if ( xDispose.is() )
|
||||
xDispose->dispose();
|
||||
|
||||
// Don't remove these frame from our child container!
|
||||
// A frame do it by itself inside close()/dispose() method.
|
||||
}
|
||||
catch(const css::lang::DisposedException&)
|
||||
{
|
||||
// Dispose frames are closed frames.
|
||||
// So we can count it here .-)
|
||||
}
|
||||
}
|
||||
|
||||
return (nNonClosedFrames < 1);
|
||||
}
|
||||
|
||||
//_________________________________________________________________________________________________________________
|
||||
// debug methods
|
||||
//_________________________________________________________________________________________________________________
|
||||
|
|
Loading…
Reference in a new issue