void Desktop::constructorInit()
{ // Initialize a new XFrames-helper-object to handle XIndexAccess and XElementAccess. // We only hold the member as reference and not as pointer! // Attention: we share our frame container with this helper. // The container itself is threadsafe, so we should be able to do that. // But look at dispose() for the right order of deinitialization.
m_xFramesHelper = new OFrames( this, &m_aChildTaskContainer );
// Initialize a new DispatchHelper-object to handle dispatches. // We use this helper as a slave for our interceptor helper - not directly! // But the helper is an event listener in THIS instance!
rtl::Reference<DispatchProvider> xDispatchProvider = new DispatchProvider( m_xContext, this );
// Initialize a new interception helper object to handle dispatches and implement an interceptor mechanism. // Set created dispatch provider as its slowest slave. // Hold interception helper by reference only - not by pointer! // So it's easier to destroy it.
m_xDispatchHelper = new InterceptionHelper( this, xDispatchProvider );
// Safe impossible cases. // We can't work without this helper!
SAL_WARN_IF( !m_xFramesHelper.is(), "fwk.desktop", "Desktop::Desktop(): Frames helper is not valid. XFrames, XIndexAccess and XElementAccess are not supported!");
SAL_WARN_IF( !m_xDispatchHelper.is(), "fwk.desktop", "Desktop::Desktop(): Dispatch helper is not valid. XDispatch will not work correctly!" );
// Enable object for real work! // Otherwise all calls will be rejected.
m_aTransactionManager.setWorkingMode( E_WORK );
}
@seealsomethoddispose()
*//*-*************************************************************************************************************/
Desktop::~Desktop()
{
SAL_WARN_IF(!m_bIsShutdown, "fwk.desktop", "Desktop not terminated before being destructed");
SAL_WARN_IF( m_aTransactionManager.getWorkingMode()!=E_CLOSE, "fwk.desktop", "Desktop::~Desktop(): Who forgot to dispose this service?" );
}
// Allow use of any UI, because Desktop.terminate() was designed as UI functionality in the past. // Try to close all open frames. bool bFramesClosed = impl_closeFrames(!bRestartableMainLoop);
// Ask normal terminate listener. They could veto terminating the process.
Desktop::TTerminateListenerList lCalledTerminationListener; if (!impl_sendQueryTerminationEvent(lCalledTerminationListener))
{
impl_sendCancelTerminationEvent(lCalledTerminationListener); returnfalse;
}
if (!bFramesClosed)
{
impl_sendCancelTerminationEvent(lCalledTerminationListener); returnfalse;
}
// Normal listener had no problem. // All frames were closed. // Now it's time to ask our specialized listener. // They are handled in this way because they wish to hinder the office on termination, // but they also wish to close all frames.
// Note: // We shouldn't ask quicklauncher in case it was allowed from outside only. // This is a special trick to "ignore existing quickstarter" for debug purposes.
// Attention: // Order of called listeners is important! // Some of them are harmless, // but some can be dangerous. E.g. it would be dangerous if we close our pipe // and don't terminate for real because another listener throws a veto exception .-)
aGuard.reset(); if (m_bIsTerminated) returntrue;
m_bIsTerminated = true;
if (!bRestartableMainLoop)
{
CrashReporter::addKeyValue(u"ShutDown"_ustr, OUString::boolean(true), CrashReporter::Write);
// The clipboard listener needs to be the first. It can create copies of the // existing document which needs basically all the available infrastructure.
impl_sendTerminateToClipboard();
{
SolarMutexReleaser aReleaser;
impl_sendNotifyTerminationEvent();
}
Scheduler::ProcessEventsToIdle();
if ( xSWThreadManager.is() )
xSWThreadManager->notifyTermination( aEvent );
if ( xPipeTerminator.is() )
xPipeTerminator->notifyTermination( aEvent );
// further termination is postponed to shutdown, if LO already runs the main loop if (!Application::IsInExecute())
shutdown();
} else
m_bIsShutdown = true;
#ifndef IOS // or ANDROID?
aGuard.clear(); // In the iOS app, posting the ImplQuitMsg user event will be too late, it will not be handled during the // lifetime of the current document, but handled for the next document opened, which thus will break horribly.
Application::Quit(); #endif
// we need a copy here as the notifyTermination call might cause a removeTerminateListener call
std::vector< css::uno::Reference<css::frame::XTerminateListener> > xComponentDllListeners;
xComponentDllListeners.swap(m_xComponentDllListeners); for (auto& xListener : xComponentDllListeners)
xListener->notifyTermination(aEvent);
xComponentDllListeners.clear();
// Must be really the last listener to be called. // Because it shuts down the whole process asynchronously! if (xSfxTerminator.is())
xSfxTerminator->notifyTermination(aEvent);
}
// No lock required, the container itself is threadsafe.
m_aListenerContainer.addInterface( cppu::UnoType<css::frame::XTerminateListener>::get(), xListener );
}
// No lock required, the container itself is threadsafe.
m_aListenerContainer.removeInterface( cppu::UnoType<css::frame::XTerminateListener>::get(), xListener );
}
// We use a helper class OComponentAccess to have access to all child components. // Create it on demand and return it as a reference. returnnew OComponentAccess( this );
}
// Set return value if method failed.
css::uno::Reference< css::lang::XComponent > xComponent;
// Get reference to current frame ... // ... get component of this frame ... (It can be the window, the model or the controller.) // ... and return the result.
css::uno::Reference< css::frame::XFrame > xCurrentFrame = getCurrentFrame(); if( xCurrentFrame.is() )
{
xComponent = impl_getFrameComponent( xCurrentFrame );
} return xComponent;
}
// Start search with our direct active frame (if it exists!). // Search its children for other active frames too. // Stop if none could be found and return the last of the found ones.
css::uno::Reference< css::frame::XFramesSupplier > xLast( getActiveFrame(), css::uno::UNO_QUERY ); if( xLast.is() )
{
css::uno::Reference< css::frame::XFramesSupplier > xNext( xLast->getActiveFrame(), css::uno::UNO_QUERY ); while( xNext.is() )
{
xLast = xNext;
xNext.set( xNext->getActiveFrame(), css::uno::UNO_QUERY );
}
} return xLast;
}
if (bOnMainThread)
{ // Make sure that we own the solar mutex, otherwise later // vcl::SolarThreadExecutor::execute() will release the solar mutex, even if it's owned by // another thread, leading to an std::abort() at the end.
SolarMutexGuard g;
// Remove uno and cmd protocol part as we want to support both of them. We store only the command part // in our hash map. All other protocols are stored with the protocol part.
OUString aCommand( aURL.Main ); if ( aURL.Protocol.equalsIgnoreAsciiCase(".uno:") )
aCommand = aURL.Path;
if (!m_xCommandOptions && !comphelper::IsFuzzing())
m_xCommandOptions.reset(new SvtCommandOptions);
// Make std::unordered_map lookup if the current URL is in the disabled list if (m_xCommandOptions && m_xCommandOptions->LookupDisabled(aCommand)) return css::uno::Reference< css::frame::XDispatch >(); else
{ // We use a helper to support this interface and an interceptor mechanism. // Our helper itself is threadsafe! return m_xDispatchHelper->queryDispatch( aURL, sTargetFrameName, nSearchFlags );
}
}
// Get old active frame first. // If nothing will change - do nothing! // Otherwise set new active frame ... // and deactivate last frame. // It's necessary for our FrameActionEvent listener on a frame!
css::uno::Reference< css::frame::XFrame > xLastActiveChild = m_aChildTaskContainer.getActive(); if( xLastActiveChild != xFrame )
{
m_aChildTaskContainer.setActive( xFrame ); if( xLastActiveChild.is() )
{
xLastActiveChild->deactivate();
}
}
}
void SAL_CALL Desktop::activate()
{ // Desktop is active always... but sometimes our frames try to activate // the complete path from bottom to top... And our desktop is the topmost frame :-( // So - please don't show any assertions here. Do nothing!
}
void SAL_CALL Desktop::deactivate()
{ // Desktop is active always... but sometimes our frames try to deactivate // the complete path from bottom to top... And our desktop is the topmost frame :-( // So - please don't show any assertions here. Do nothing!
}
// 0) Ignore wrong parameters! // We don't support searching for the following special targets. // If we reject these requests, we don't have to keep checking for such names // in the code that follows. If we do not reject them, very wrong // search results may occur!
if (
(sTargetFrameName==SPECIALTARGET_DEFAULT ) || // valid for dispatches - not for findFrame()!
(sTargetFrameName==SPECIALTARGET_PARENT ) || // we have no parent by definition
(sTargetFrameName==SPECIALTARGET_BEAMER ) // beamer frames are allowed as children of tasks only - // and they exist more than once. We have no idea which of our sub tasks is the right one
)
{ return nullptr;
}
// I) Check for special defined targets first which must be handled exclusively. // Force using of "if() else if() ..."
// I.I) "_blank" // Create a new task as child of this desktop instance. // Note: the used helper TaskCreator uses us automatically.
// II) Otherwise use optional given search flags. // Force using of combinations of such flags. It means there is no "else" part in the used if() statements. // But we must break further searches if target was already found. // The order of using flags is fixed: SELF - CHILDREN - SIBLINGS - PARENT // TASK and CREATE are handled as special cases. // But note: such flags are not valid for the desktop - especially SIBLINGS or PARENT.
// II.I) SELF // Check for the right name. If it's the searched one, return ourselves - otherwise // ignore this flag.
// II.II) TASKS // This is a special flag. Normally it regulates search inside tasks and forbids access to parent trees. // But the desktop exists outside such task trees. They are our sub trees. So the desktop implements // a special feature: we use it to start searching on our direct children only. That means we suppress // search on ALL child frames. It may be useful to get access to opened document tasks // only without filtering out all sub frames that are not really required. // The helper method used on our container doesn't create any frame - it's only for searching.
// II.III) CHILDREN // Search all children for the given target name. // An empty name value can't occur here - because it must be already handled as "_self" // before. The used helper function of the container doesn't create any frame. // It makes a deep search only.
// II.IV) CREATE // If we haven't found any valid target frame by using normal flags, but the user allowed us to create // a new one, we should do that. The used TaskCreator uses us automatically as parent!
// Disable this instance for further work. // This will wait for all current running transactions // and rejects all new incoming requests!
m_aTransactionManager.setWorkingMode(E_BEFORECLOSE);
}
// The 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 listeners will work and this code can't be dangerous.
// First we have 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 );
// Clear our child task container and forcefully forget all task references. // Normally all open documents were already closed by our terminate() function. // New opened frames will have a problem now .-)
m_aChildTaskContainer.clear();
// At least clean up other member references.
m_xDispatchHelper.clear();
m_xFramesHelper.clear();
m_xContext.clear();
// we need a copy because the disposing might call the removeEventListener method
std::vector< css::uno::Reference<css::frame::XTerminateListener> > xComponentDllListeners;
xComponentDllListeners.swap(m_xComponentDllListeners); for (auto& xListener: xComponentDllListeners)
{
xListener->disposing(aEvent);
}
xComponentDllListeners.clear();
m_xSfxTerminator.clear();
m_xCommandOptions.reset();
// From this point nothing will do further work on this object, // excepting our dtor() .-)
m_aTransactionManager.setWorkingMode( E_CLOSE );
}
@seealsomethodloadComponentFromURL()
*//*-*************************************************************************************************************/ void SAL_CALL Desktop::disposing( const css::lang::EventObject& )
{
SAL_WARN( "fwk.desktop", "Desktop::disposing(): Algorithm error! Normally desktop is temp. listener ... not all the time. So this method shouldn't be called." );
}
// Don't check incoming request! // If interaction starts somewhere without a correct parameter, a mistake was made. // loadComponentFromURL() waits for this event - otherwise it yields forever!
// Get packed request and work on it first. // Attention: don't set it on internal member BEFORE interaction is finished - because // "loadComponentFromURL()" yields until this member is changed. If we do it before // interaction finishes we can't guarantee correct functionality. Maybe we cancel load process to earlier...
css::uno::Any aRequest = xRequest->getRequest();
// Differ between abortable interactions (error, unknown filter...) // and other ones (ambiguous but not unknown filter...)
css::task::ErrorCodeRequest aErrorCodeRequest; if( aRequest >>= aErrorCodeRequest )
{ bool bWarning = ErrCode(aErrorCodeRequest.ErrCode).IsWarning(); if (xApprove.is() && bWarning)
xApprove->select(); else if (xAbort.is())
{
xAbort->select();
bAbort = true;
}
} elseif( xAbort.is() )
{
xAbort->select();
bAbort = true;
}
// Ok now it's time to break yield loop of loadComponentFromURL(). // But only for actually aborted requests! // For example, warnings will be approved and we wait for any success story. if (bAbort)
{
SolarMutexGuard g;
m_eLoadState = E_INTERACTION;
}
}
// Set default return value, if method failed.
css::uno::Reference< css::lang::XComponent > xComponent; // Does no controller exist?
css::uno::Reference< css::frame::XController > xController = xFrame->getController(); if( !xController.is() )
{ // Controller does not exist - use the VCL-component.
xComponent = xFrame->getComponentWindow();
} else
{ // Does no model exist?
css::uno::Reference< css::frame::XModel > xModel = xController->getModel(); if( xModel.is() )
{ // Model exists - use the model as component.
xComponent = xModel;
} else
{ // Model does not exist - use the controller as component.
xComponent = xController;
}
}
// XController.suspend() will show a UI. // Use it in case it was allowed from outside only. bool bSuspended = false;
css::uno::Reference< css::frame::XController > xController = xFrame->getController(); if ( bAllowUI && xController.is() )
{
bSuspended = xController->suspend( true ); if ( ! bSuspended )
{
++nNonClosedFrames; if(m_bSession) break; else 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(false);
} catch(const css::util::CloseVetoException&)
{ // Any internal process of this frame disagrees with our request. // Save this state but don't break this loop. Other frames have to be closed!
++nNonClosedFrames;
// Reactivate controller. // It can happen that XController.suspend() returned true, but a registered closed listener // threw this veto exception. Then the controller has to be reactivated. Otherwise // this document doesn't work any more. if ( bSuspended && xController.is())
xController->suspend(false);
}
// If interface XClosable interface exists and was used, // it's not allowed to also use XComponent->dispose() ! continue;
}
// XClosable not supported ? // Then we have to forcefully dispose this frame. if ( xFrame.is() )
xFrame->dispose();
// Don't remove this frame from our child container! // A frame does it by itself inside close()/dispose() method.
} catch(const css::lang::DisposedException&)
{ // Disposed frames are closed frames. // So we can count them here .-)
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.