// This enum can be used to set different active states of frames enum EActiveState
{
E_INACTIVE, // I am not a member of active path in tree and I don't have the focus.
E_ACTIVE, // I am in the middle of an active path in tree and I don't have the focus.
E_FOCUS // I have the focus now. I must be a member of an active path!
};
/** set a new owner for this helper. * *Thisownerisusedassourceforallbroadcastedevents. *Furtherweholditweak,becausewedon'twishtobedisposed().-)
*/ void impl_setPropertyChangeBroadcaster(XFrameImpl& rBroadcaster);
/** add a new property info to the set of supported ones. * *@paramaProperty *describesthenewproperty. * *@throw[css::beans::PropertyExistException] *ifapropertywiththesamenamealreadyexists. * *Note:Theconsistenceofthewholesetofpropertiesisnotcheckedhere. *Meaninge.g.ahandlewhichexistsmorethanonceisnotdetected. *Theownerofthisclasshastobesure,thatnonewproperty *clasheswithanexistingone.
*/ void impl_addPropertyInfo(const css::beans::Property& aProperty);
/** mark the object as "dead".
*/ void impl_disablePropertySet();
/// reference to factory, which has created this instance
css::uno::Reference< css::uno::XComponentContext > m_xContext; /// reference to factory helper to create status indicator objects
css::uno::Reference< css::task::XStatusIndicatorFactory > m_xIndicatorFactoryHelper; /// points to an external set progress, which should be used instead of the internal one.
css::uno::WeakReference< css::task::XStatusIndicator > m_xIndicatorInterception; /// helper for XDispatch/Provider and interception interfaces
rtl::Reference< InterceptionHelper > m_xDispatchHelper; /// helper for XFrames, XIndexAccess and XElementAccess interfaces
rtl::Reference< OFrames > m_xFramesHelper; /// container for ALL Listeners
comphelper::OMultiTypeInterfaceContainerHelper2 m_aListenerContainer; /// parent of this frame
css::uno::Reference< css::frame::XFramesSupplier > m_xParent; /// containerwindow of this frame for embedded components
css::uno::Reference< css::awt::XWindow > m_xContainerWindow; /// window of the actual component
css::uno::Reference< css::awt::XWindow > m_xComponentWindow; /// controller of the actual frame
css::uno::Reference< css::frame::XController > m_xController; /// listen to drag & drop
rtl::Reference< OpenFileDropTargetListener > m_xDropTargetListener; /// state, if I am a member of an active path in the tree or I have the focus or...
EActiveState m_eActiveState; /// name of this frame
OUString m_sName; /// frame has no parent or the parent is a task or the desktop bool m_bIsFrameTop; /// due to FrameActionEvent bool m_bConnected;
sal_Int16 m_nExternalLockCount; /// is used for dispatch recording and will be set/get from outside. Only the frame provides it!
css::uno::Reference< css::frame::XDispatchRecorderSupplier > m_xDispatchRecorderSupplier; /// ref counted class to support disabling commands defined by configuration file
SvtCommandOptions m_aCommandOptions; /// in case of CloseVetoException on method close() was thrown by ourselves, we must close ourselves later if no internal processes are running bool m_bSelfClose; /// indicates, if this frame is used in hidden mode or not bool m_bIsHidden; /// The container window has WindowExtendedStyle::DocHidden set. bool m_bDocHidden = false; /// Is used to layout the child windows of the frame.
css::uno::Reference< css::frame::XLayoutManager2 > m_xLayoutManager;
rtl::Reference< DispatchInformationProvider > m_xDispatchInfoHelper;
rtl::Reference< TitleHelper > m_xTitleHelper;
// 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 );
m_xDispatchInfoHelper = new DispatchInformationProvider(m_xContext, this);
// Initialize a new interception helper object to handle dispatches and implement an interceptor mechanism. // Set created dispatch provider as slowest slave of it. // Hold interception helper by reference only - not by pointer! // So it's easier to destroy it.
m_xDispatchHelper = new InterceptionHelper( this, xDispatchProvider );
// 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. Container itself is threadsafe ... So I think we can do that. // But look at dispose() for the right order of deinitialization.
m_xFramesHelper = new OFrames( this, &m_aChildFrameContainer );
// Initialize the drop target listener. // We only hold the member as reference and not as pointer!
m_xDropTargetListener = new OpenFileDropTargetListener( m_xContext, this );
// Safe impossible cases // We can't work without these helpers!
SAL_WARN_IF( !xDispatchProvider.is(), "fwk.frame", "XFrameImpl::XFrameImpl(): Slowest slave for dispatch- and interception helper " "is not valid. XDispatchProvider, XDispatch, XDispatchProviderInterception are not full supported!" );
SAL_WARN_IF( !m_xDispatchHelper.is(), "fwk.frame", "XFrameImpl::XFrameImpl(): Interception helper is not valid. XDispatchProvider, " "XDispatch, XDispatchProviderInterception are not full supported!" );
SAL_WARN_IF( !m_xFramesHelper.is(), "fwk.frame", "XFrameImpl::XFrameImpl(): Frames helper is not valid. XFrames, " "XIndexAccess and XElementAccess are not supported!" );
SAL_WARN_IF( !m_xDropTargetListener.is(), "fwk.frame", "XFrameImpl::XFrameImpl(): DropTarget helper is not valid. " "Drag and drop without functionality!" );
// establish notifications for changing of "disabled commands" configuration during runtime
m_aCommandOptions.EstablishFrameCallback(this);
// Create an initial layout manager // Create layout manager and connect it to the newly created frame
m_xLayoutManager = css::frame::LayoutManager::create(m_xContext);
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;
SolarMutexGuard g; // Return access to all child frames to caller. // Our childframe container is implemented in helper class OFrames and used as a reference m_xFramesHelper! return m_xFramesHelper;
}
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
SolarMutexResettableGuard aWriteLock;
// Copy necessary member for threadsafe access! // m_aChildFrameContainer itself is threadsafe and it lives if we live!!!
css::uno::Reference< css::frame::XFrame > xActiveChild = m_aChildFrameContainer.getActive();
EActiveState eActiveState = m_eActiveState;
aWriteLock.clear(); /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
// Don't work, if "new" active frame isn't different from current one! // (xFrame==NULL is allowed to UNSET it!) if( xActiveChild != xFrame )
{ // ... otherwise set new and deactivate old one.
m_aChildFrameContainer.setActive( xFrame ); if (
( eActiveState != E_INACTIVE ) &&
xActiveChild.is()
)
{
xActiveChild->deactivate();
}
}
if( xFrame.is() )
{ // If last active frame had focus ... // ... reset state to ACTIVE and send right FrameActionEvent for focus lost. if( eActiveState == E_FOCUS )
{
aWriteLock.reset();
eActiveState = E_ACTIVE;
m_eActiveState = eActiveState;
aWriteLock.clear();
implts_sendFrameActionEvent( css::frame::FrameAction_FRAME_UI_DEACTIVATING );
}
// If last active frame was active ... // but new one is not it ... // ... set it as the active one. if ( eActiveState == E_ACTIVE && !xFrame->isActive() )
{
xFrame->activate();
}
} else // If this frame is active and has no active subframe anymore it is UI active too if( eActiveState == E_ACTIVE )
{
aWriteLock.reset();
eActiveState = E_FOCUS;
m_eActiveState = eActiveState;
aWriteLock.clear();
implts_sendFrameActionEvent( css::frame::FrameAction_FRAME_UI_ACTIVATED );
}
}
@param"xWindow",referencetoanewcontainerwindow-mustbevalid! @onerrorWedonothing.
*//*-*****************************************************************************************************/ void SAL_CALL XFrameImpl::initialize( const css::uno::Reference< css::awt::XWindow >& xWindow )
{ /* UNSAFE AREA --------------------------------------------------------------------------------------------- */ if (!xWindow.is()) throw css::uno::RuntimeException(
u"XFrameImpl::initialize() called without a valid container window reference."_ustr, static_cast< css::frame::XFrame* >(this));
checkDisposed();
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
SolarMutexResettableGuard aWriteLock;
// This must be the first call of this method! // We should initialize our object and open it for working. if ( m_xContainerWindow.is() ) throw css::uno::RuntimeException(
u"XFrameImpl::initialized() is called more than once, which is not useful nor allowed."_ustr, static_cast< css::frame::XFrame* >(this));
// Set the new window.
m_xContainerWindow = xWindow;
// if window is initially visible, we will never get a windowShowing event
VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow); if (pWindow)
{ if (pWindow->IsVisible())
m_bIsHidden = false;
m_bDocHidden
= static_cast<bool>(pWindow->GetExtendedStyle() & WindowExtendedStyle::DocHidden);
}
// Release lock, because we call some impl methods, which are threadsafe by themselves. // If we hold this lock - we will produce our own deadlock!
aWriteLock.clear(); /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
// Avoid enabling the layout manager for hidden frames: it's expensive and // provides little value. if (xLayoutManager.is() && !m_bDocHidden)
lcl_enableLayoutManager(xLayoutManager, this);
@param"sName",newframename. @onerrorWedonothing.
*//*-*****************************************************************************************************/ void SAL_CALL XFrameImpl::setName( const OUString& sName )
{
SolarMutexGuard g; // Set new name... but look for invalid special target names! // They are not allowed to set. if (TargetHelper::isValidNameForFrame(sName))
m_sName = sName;
}
// 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()!
{ return nullptr;
}
// I) Check for special defined targets first which must be handled exclusive. // Force using of "if() else if() ..."
// get threadsafe some members which are necessary for the functionality that follows /* SAFE { */
SolarMutexResettableGuard aReadLock;
css::uno::Reference< css::frame::XFrame > xParent = m_xParent; bool bIsTopFrame = m_bIsFrameTop; bool bIsTopWindow = WindowHelper::isTopWindow(m_xContainerWindow);
aReadLock.clear(); /* } SAFE */
// I.I) "_blank" // Not allowed for a normal frame, but for the desktop. // Use helper class to do so. It uses the desktop automatically.
// I.III) "_top" // If we are not the top frame in this hierarchy, we must forward the request to our parent. // Otherwise we must return ourselves.
elseif ( sTargetFrameName==SPECIALTARGET_TOP )
{ if (bIsTopFrame)
xTarget = this; elseif (xParent.is()) // If we are not top - the parent MUST exist. But may it's better to check it again .-)
xTarget = xParent->findFrame(SPECIALTARGET_TOP,0);
}
// I.IV) "_self", "" // This means this frame in every case.
// I.V) "_beamer" // This is a special sub frame of any task. We must return it if we found it among our direct children // or create it there if it does not already exist. // Note: such a beamer exists for task(top) frames only!
elseif ( sTargetFrameName==SPECIALTARGET_BEAMER )
{ // We are a task => search or create the beamer if (bIsTopWindow)
{
xTarget = m_aChildFrameContainer.searchOnDirectChildrens(SPECIALTARGET_BEAMER); if ( ! xTarget.is() )
{ /* TODO Creationnotsupportedyet! Waitfornewlayoutmanagerservicebecausewecan'tplugit insidealreadyopeneddocumentofthisframe.
*/
}
} // We aren't a task => forward the request to our parent or ignore it. elseif (xParent.is())
xTarget = xParent->findFrame(SPECIALTARGET_BEAMER,0);
}
else
{
// 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. // Order of using flags is fixed: SELF - CHILDREN - SIBLINGS - PARENT // TASK and CREATE are handled as special cases.
// get threadsafe some members which are necessary for the functionality that follows /* SAFE { */
aReadLock.reset();
OUString sOwnName = m_sName;
aReadLock.clear(); /* } SAFE */
// II.I) SELF // Check for the right name. If it's the searched one return ourselves, otherwise // ignore this flag.
// II.II) CHILDREN // Search among 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 only makes a deep search.
// II.III) TASKS // This is a special flag. It regulates search only on this task tree or allows searching among // all the other ones (which are sibling trees of us) as well. // Upper search must stop at this frame if we are the topmost one and the TASK flag is not set // or we can ignore it if we have no valid parent.
// II.III.I) SIBLINGS // Search among all our direct siblings, meaning all the children of our parent. // Use this flag in combination with TASK. We must suppress such an upper search if // the user has not set it and if we are a top frame. // Attention: don't forward this request to our parent as a findFrame() call. // In such cases we must protect ourselves from recursive calls. // Use a snapshot of our parent. But don't use queryFrames() of XFrames interface. // Because it returns all siblings and all their children including our children, // if we call it with the CHILDREN flag. We don't need that - we only need the direct container // items of our parent to start searches there. So we must use the container interface // XIndexAccess instead of XFrames.
if (
( ! xTarget.is() ) &&
(nSearchFlags & css::frame::FrameSearchFlag::SIBLINGS) &&
( xParent.is() ) // search among siblings is impossible without a parent
)
{
css::uno::Reference< css::frame::XFramesSupplier > xSupplier( xParent, css::uno::UNO_QUERY ); if (xSupplier.is())
{
css::uno::Reference< css::container::XIndexAccess > xContainer = xSupplier->getFrames(); if (xContainer.is())
{
sal_Int32 nCount = xContainer->getCount(); for( sal_Int32 i=0; i<nCount; ++i )
{
css::uno::Reference< css::frame::XFrame > xSibling; if ( // control unpacking
( !(xContainer->getByIndex(i)>>=xSibling) ) || // check for valid items
( ! xSibling.is() ) || // ignore ourselves! (We are a part of this container too, but search among our children was already done.)
( xSibling==static_cast< ::cppu::OWeakObject* >(this) )
)
{ continue;
}
// Don't allow upper search here! Use the appropriate flags to regulate it. // And only allow deep search among children, if it was allowed for us as well.
sal_Int32 nRightFlags = css::frame::FrameSearchFlag::SELF; if (nSearchFlags & css::frame::FrameSearchFlag::CHILDREN)
nRightFlags |= css::frame::FrameSearchFlag::CHILDREN;
xTarget = xSibling->findFrame(sTargetFrameName, nRightFlags ); // perform search and break further searching if a result exists if (xTarget.is()) break;
}
}
}
}
// II.III.II) PARENT // Forward search to our parent (if it exists). // To avoid recursive and superfluous calls (which can occur if we allow it // to search among its children too) we must change the used search flags.
// 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 Desktop instance automatically as parent!
@onerrorNoerrorshouldoccur!
*//*-*****************************************************************************************************/
sal_Bool SAL_CALL XFrameImpl::isTop()
{
checkDisposed();
SolarMutexGuard g; // This information is set in setCreator(). // We are top, if our parent is a task or the desktop or if no parent exists! return m_bIsFrameTop;
}
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
SolarMutexResettableGuard aWriteLock;
// Copy necessary member and free the lock. // It's not necessary for m_aChildFrameContainer, because // it is threadsafe by itself and lives if we live.
css::uno::Reference< css::frame::XFrame > xActiveChild = m_aChildFrameContainer.getActive();
css::uno::Reference< css::frame::XFramesSupplier > xParent = m_xParent;
css::uno::Reference< css::frame::XFrame > xThis(this);
EActiveState eState = m_eActiveState;
aWriteLock.clear(); /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
// 1) If I am not active before... if( eState == E_INACTIVE )
{ // ... do it then.
aWriteLock.reset();
eState = E_ACTIVE;
m_eActiveState = eState;
aWriteLock.clear(); // Deactivate sibling path and forward activation to parent, if any parent exists! if( xParent.is() )
{ // Set THIS frame as active child of parent every time and activate it. // We MUST have a valid path from bottom to top as active path! // But we must deactivate the old active sibling path first.
// Attention: deactivation of an active path, deactivates the whole path from bottom to top! // But we only wish to deactivate the found sibling-tree. // [ see deactivate() / step 4) for further information! ]
xParent->setActiveFrame( xThis );
// Then we can activate from here to top. // Attention: we are ACTIVE now. And the parent will call activate() at us! // But we do nothing then! We are already activated.
xParent->activate();
} // It's necessary to send event NOW, not before. // Activation goes from bottom to top! // That's the reason to activate parent first and send event now.
implts_sendFrameActionEvent( css::frame::FrameAction_FRAME_ACTIVATED );
}
// 2) I was active before or currently activated and there is a path from here to bottom, who CAN be active. // But our direct child of path is not active yet. // (It can be, if activation occurs in the middle of a current path!) // In this case we activate path to bottom to set focus on the correct frame! if ( eState == E_ACTIVE && xActiveChild.is() && !xActiveChild->isActive() )
{
xActiveChild->activate();
}
// 3) I was active before or currently activated. But if I have no active child => I will get the focus! if ( eState == E_ACTIVE && !xActiveChild.is() )
{
aWriteLock.reset();
eState = E_FOCUS;
m_eActiveState = eState;
aWriteLock.clear();
implts_sendFrameActionEvent( css::frame::FrameAction_FRAME_UI_ACTIVATED );
}
}
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
SolarMutexResettableGuard aWriteLock;
// Copy necessary member and free the lock.
css::uno::Reference< css::frame::XFrame > xActiveChild = m_aChildFrameContainer.getActive();
css::uno::Reference< css::frame::XFramesSupplier > xParent = m_xParent;
css::uno::Reference< css::frame::XFrame > xThis(this);
EActiveState eState = m_eActiveState;
aWriteLock.clear(); /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
// Work only, if there is something to do! if( eState == E_INACTIVE ) return;
// 1) Deactivate all active children. if ( xActiveChild.is() && xActiveChild->isActive() )
{
xActiveChild->deactivate();
}
// 2) If I have the focus, I will lose it now. if( eState == E_FOCUS )
{ // Set new state INACTIVE(!) and send message to all listeners. // Don't set ACTIVE as new state. This frame is deactivated the next time due to activate().
aWriteLock.reset();
eState = E_ACTIVE;
m_eActiveState = eState;
aWriteLock.clear();
implts_sendFrameActionEvent( css::frame::FrameAction_FRAME_UI_DEACTIVATING );
}
// 3) If I am active, I will be deactivated now. if( eState == E_ACTIVE )
{ // Set new state and send message to all listeners.
aWriteLock.reset();
eState = E_INACTIVE;
m_eActiveState = eState;
aWriteLock.clear();
implts_sendFrameActionEvent( css::frame::FrameAction_FRAME_DEACTIVATING );
}
// 4) If there is a path from here to my parent, // I am at the top or in the middle of a deactivated subtree and the action was started here. // I must deactivate all frames from here to top, which are members of the current path. // Stop, if THIS frame is not the active frame of our parent! if ( xParent.is() && xParent->getActiveFrame() == xThis )
{ // We MUST break the path - otherwise we will get the focus instead of our parent! // Attention: our parent will not call us again - WE ARE NOT ACTIVE YET! // [ see step 3 and condition "if ( m_eActiveState!=INACTIVE ) ..." in this method! ]
xParent->deactivate();
}
}
/*-**************************************************************************************************** @short???
*//*-*****************************************************************************************************/ void SAL_CALL XFrameImpl::contextChanged()
{ // Sometimes called during closing object... // Impl-method itself is threadsafe! // Send event to all listeners for frame actions.
implts_sendFrameActionEvent( css::frame::FrameAction_CONTEXT_CHANGED );
}
// Ignore this HACK of sfx2! // It calls us with a valid controller without a valid window - that's not allowed! if ( xController.is() && ! xComponentWindow.is() ) returntrue;
// Stop listening on old window. // It may cause some trouble. // But don't forget to listen on new window again or reactivate listening, // if we reject this setComponent() request and leave this method without changing the old window.
implts_stopWindowListening();
// Notify all listeners, that this component (if current one exists) will be unloaded. if (bWasConnected)
implts_sendFrameActionEvent( css::frame::FrameAction_COMPONENT_DETACHING );
// Otherwise release old component first. // Always release controller before releasing window, // because controller may want to access its window! // But check for real changes - the new controller might be the old one. if (
(xOldController.is() ) &&
(xOldController != xController)
)
{ /* ATTENTION Don'tsuspendtheoldcontrollerhere.Becausetheoutsidecallermustdothat bydefinition.Weonlyhavetodisposeithere.
*/
// Before we dispose this controller we should hide it inside this frame instance. // We hold it alive for the subsequent calls by using xOldController! /* SAFE {*/
{
SolarMutexGuard aWriteLock;
m_xController = nullptr;
if (m_xDispatchHelper)
{
rtl::Reference<DispatchProvider> pDispatchProvider = m_xDispatchHelper->GetSlave(); if (pDispatchProvider)
{
pDispatchProvider->ClearProtocolHandlers();
}
}
} /* } SAFE */
// Now it's time to release the component window. // If the controller wasn't released successfully, this code block shouldn't be reached. // Because in case of "suspend()==false" we return immediately with false, see before. // Check for real changes, too. if (
(xOldComponentWindow.is() ) &&
(xOldComponentWindow != xComponentWindow)
)
{ /* SAFE { */
{
SolarMutexGuard aWriteLock;
m_xComponentWindow = nullptr;
} /* } SAFE */
// Now it's time to set the new component. // By the way, find out our new "load state", meaning if we have a valid component inside. /* SAFE { */
SolarMutexResettableGuard aWriteLock;
m_xComponentWindow = xComponentWindow;
m_xController = xController;
// Clear the URL on the frame itself, now that the controller has it.
m_aURL.clear();
// notifies all interested listeners, that current component was changed or a new one was loaded if (bIsConnected && bWasConnected)
implts_sendFrameActionEvent( css::frame::FrameAction_COMPONENT_REATTACHED ); elseif (bIsConnected && !bWasConnected)
implts_sendFrameActionEvent( css::frame::FrameAction_COMPONENT_ATTACHED );
// A new component window doesn't know anything about current active/focus states. // Set this information on it! if ( bHadFocus && xComponentWindow.is() )
{
xComponentWindow->setFocus();
}
// If it was a new component window, we must resize it to fill out // our container window.
implts_resizeComponentWindow(); // New component should change our current icon.
implts_setIconOnWindow(); // OK - start listening on new window again or do nothing if it is an empty one.
implts_startWindowListening();
// At the end of this method we might have to dispose ourselves // without anybody from outside holding a reference to us. // Thus, it's a good idea to do that ourselves.
css::uno::Reference< css::uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
// Try to close any listeners before we look for currently running internal processes. // Because if a listener disagrees with this close() request, we have time to finish these // internal operations too. // Note: container itself is threadsafe.
css::lang::EventObject aSource (static_cast< ::cppu::OWeakObject*>(this));
comphelper::OInterfaceContainerHelper2* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::util::XCloseListener>::get()); if (pContainer!=nullptr)
{
comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer); while (pIterator.hasMoreElements())
{ try
{ static_cast<css::util::XCloseListener*>(pIterator.next())->queryClosing( aSource, bDeliverOwnership );
} catch( const css::uno::RuntimeException& )
{
pIterator.remove();
}
}
}
// Ok - no listener disagreed with this close() request. // Check if this frame is used for any load process currently. if (isActionLocked())
{ if (bDeliverOwnership)
{
SolarMutexGuard g;
m_bSelfClose = true;
}
throw css::util::CloseVetoException(u"Frame in use for loading document..."_ustr,static_cast< ::cppu::OWeakObject*>(this));
}
if ( ! setComponent(nullptr,nullptr) ) throw css::util::CloseVetoException(u"Component couldn't be detached..."_ustr,static_cast< ::cppu::OWeakObject*>(this));
// If closing is allowed, inform all listeners and dispose this frame!
pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::util::XCloseListener>::get()); if (pContainer!=nullptr)
{
comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer); while (pIterator.hasMoreElements())
{ try
{ static_cast<css::util::XCloseListener*>(pIterator.next())->notifyClosing( aSource );
} catch( const css::uno::RuntimeException& )
{
pIterator.remove();
}
}
}
void SAL_CALL XFrameImpl::setPropertyValue(const OUString& sProperty, const css::uno::Any& rValue)
{ // TODO look for e.g. readonly props and reject setProp() call!
checkDisposed();
// SAFE ->
SolarMutexGuard g;
TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty); if (pIt == m_lProps.end()) throw css::beans::UnknownPropertyException(sProperty);
@seealsomethodinitialize() @seealsobaseclassFairRWLockBase!
*//*-*****************************************************************************************************/ void SAL_CALL XFrameImpl::disposing()
{ // We should hold a reference to ourselves, // because our owner disposes us and releases our reference. // We might die before finishing this method.
css::uno::Reference< css::frame::XFrame > xThis(this);
// First operation should be "stop all listening for window events on our container window". // These events are superfluous but can cause trouble! // We will die, die and die...
implts_stopWindowListening();
// Send message to all listeners and forget their references.
css::lang::EventObject aEvent( xThis );
m_aListenerContainer.disposeAndClear( aEvent );
// set "end of life" for our property set helper
impl_disablePropertySet();
// Interception/dispatch chain must be destroyed explicitly. // Otherwise some dispatches and/or interception objects won't die.
rtl::Reference< InterceptionHelper > xDispatchHelper;
{
SolarMutexGuard g;
xDispatchHelper = m_xDispatchHelper;
}
xDispatchHelper->disposing(aEvent);
xDispatchHelper.clear();
// Don't show any dialogs, errors or anything else anymore! // If dispose() without a preceding close() was called somewhere, normally no dialogs // should exist. Otherwise it's the problem of the outside caller. // Note: // (a) Do it after implts_stopWindowListening(). If the order is not followed, // some activate/deactivate notifications may appear, which can be fatal. // (b) Don't forget to save the old value of IsDialogCancelEnabled() to // restore it afterwards (to not kill headless mode).
DialogCancelMode old = Application::GetDialogCancelMode();
Application::SetDialogCancelMode( DialogCancelMode::Silent );
// We should be alone forever and any further dispose calls are rejected by the preceding lines, // I hope :-)
// Free references of our frame tree. // Force parent container to forget this frame, too // ( It's contained in m_xParent and so no css::lang::XEventListener for m_xParent! ) // It's important to do that before we free some other internal structures. // Because if our parent gets an activate and found us as last possible active frame // it tries to deactivate us and we run into some trouble (DisposedExceptions!).
css::uno::Reference<css::frame::XFramesSupplier> parent;
{
SolarMutexGuard g;
std::swap(parent, m_xParent);
} if( parent.is() )
{
parent->getFrames()->remove( xThis );
}
/* } SAFE */ // Forget our internal component and its window first. // So we can release our container window later without problems. // Because this container window is the parent of the component window. // Note: dispose it forcefully, because suspending must be done inside close() call! // But try to dispose the controller first before you destroy the window. // Because the window is used by the controller too.
css::uno::Reference< css::lang::XComponent > xDisposableCtrl;
css::uno::Reference< css::lang::XComponent > xDisposableComp;
{
SolarMutexGuard g;
xDisposableCtrl = m_xController;
xDisposableComp = m_xComponentWindow;
} if (xDisposableCtrl.is())
xDisposableCtrl->dispose(); if (xDisposableComp.is())
xDisposableComp->dispose();
impl_checkMenuCloser();
css::uno::Reference<css::awt::XWindow> contWin;
{
SolarMutexGuard g;
std::swap(contWin, m_xContainerWindow);
} if( contWin.is() )
{
contWin->setVisible( false ); // All VclComponents are XComponents; so call dispose before discarding // a css::uno::Reference< XVclComponent >, because this frame is the owner of the window
contWin->dispose();
}
// Release some other references. // These calls should be easy, I hope :-)
m_xDispatchHelper.clear();
m_xDropTargetListener.clear();
m_xDispatchRecorderSupplier.clear();
m_xLayoutManager.clear();
m_xIndicatorFactoryHelper.clear();
// It's important to set default values here! // If maybe later the disposed-behaviour of this implementation is changed somewhere // and doesn't throw any DisposedExceptions, we must guarantee best matching default values.
m_eActiveState = E_INACTIVE;
m_sName.clear();
m_bIsFrameTop = false;
m_bConnected = false;
m_nExternalLockCount = 0;
m_bSelfClose = false;
m_bIsHidden = true;
}
// Don't forget to restore old value. // Otherwise no dialogs can be shown anymore in other frames.
Application::SetDialogCancelMode( old );
}
@onerrorAnullreferenceisreturned.
*//*-*****************************************************************************************************/
css::uno::Reference< css::frame::XDispatch > SAL_CALL XFrameImpl::queryDispatch( const css::util::URL& aURL, const OUString& sTargetFrameName,
sal_Int32 nSearchFlags)
{ // Don't check incoming parameters here! Our helper does it for us and it is not a good idea to do it more than once!
checkDisposed();
// 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;
// Make std::unordered_map lookup if the current URL is in the disabled list if ( m_aCommandOptions.LookupDisabled( aCommand ) ) return css::uno::Reference< css::frame::XDispatch >(); else
{ // We use a helper to support this interface and an interceptor mechanism.
rtl::Reference<InterceptionHelper> disp;
{
SolarMutexGuard g;
disp = m_xDispatchHelper;
} if (!disp.is()) { throw css::lang::DisposedException(u"Frame disposed"_ustr);
} return disp->queryDispatch( aURL, sTargetFrameName, nSearchFlags );
}
}
@onerrorAnemptylistisreturned.
*//*-*****************************************************************************************************/
css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL XFrameImpl::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor )
{ // Don't check incoming parameters here! Our helper does it for us and it is not a good idea to do it more than once!
checkDisposed();
// We use a helper to support this interface and an interceptor mechanism.
rtl::Reference<InterceptionHelper> disp;
{
SolarMutexGuard g;
disp = m_xDispatchHelper;
} if (!disp.is()) { throw css::lang::DisposedException(u"Frame disposed"_ustr);
} return disp->queryDispatches( lDescriptor );
}
@param"xInterceptor",referencetoyourinterceptorimplementation. @onerrorInterceptorisignored.
*//*-*****************************************************************************************************/ void SAL_CALL XFrameImpl::registerDispatchProviderInterceptor( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor )
{ // We use a helper to support this interface and an interceptor mechanism. // This helper itself is threadsafe and checks incoming parameters, too. // I think we don't need any lock here!
void SAL_CALL XFrameImpl::releaseDispatchProviderInterceptor( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor )
{ // We use a helper to support this interface and an interceptor mechanism. // This helper itself is threadsafe and checks incoming parameters, too. // I think we don't need any lock here!
// Sometimes we are called during our dispose() method
@param"aEvent"describesourceofdetectedevent
*//*-*****************************************************************************************************/ void SAL_CALL XFrameImpl::windowResized( const css::awt::WindowEvent& )
{ // Part of dispose-mechanism
/* SAFE AREA ----------------------------------------------------------------------------------------------- */ // Impl-method is threadsafe! // If we have a current component window, we must resize it!
implts_resizeComponentWindow();
}
void SAL_CALL XFrameImpl::focusGained( const css::awt::FocusEvent& )
{ // Part of dispose() mechanism
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
SolarMutexClearableGuard aReadLock; // Make snapshot of member!
css::uno::Reference< css::awt::XWindow > xComponentWindow = m_xComponentWindow;
aReadLock.clear(); /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
SolarMutexClearableGuard aReadLock; // Make snapshot of member!
EActiveState eState = m_eActiveState;
aReadLock.clear(); /* UNSAFE AREA --------------------------------------------------------------------------------------------- */ // Activate the new active path from here to top. if( eState == E_INACTIVE )
{
setActiveFrame( css::uno::Reference< css::frame::XFrame >() );
activate();
}
}
void SAL_CALL XFrameImpl::windowDeactivated( const css::lang::EventObject& )
{ // Sometimes called during dispose()
/* SAFE AREA ----------------------------------------------------------------------------------------------- */
SolarMutexClearableGuard aReadLock;
// Deactivation is always done implicitly by activation of another frame. // Only if no activation is done, deactivations have to be processed if the activated window // is a parent window of the last active Window!
SolarMutexClearableGuard aSolarGuard;
vcl::Window* pFocusWindow = Application::GetFocusWindow(); if ( !xContainerWindow.is() || !xParent.is() ||
css::uno::Reference< css::frame::XDesktop >( xParent, css::uno::UNO_QUERY ).is()
) return;
css::uno::Reference< css::awt::XWindow > xParentWindow = xParent->getContainerWindow();
VclPtr<vcl::Window> pParentWindow = VCLUnoHelper::GetWindow( xParentWindow ); //#i70261#: dialogs opened from an OLE object will cause a deactivate on the frame of the OLE object // On Solaris/Linux at that time pFocusWindow is still NULL because the focus handling is different; right after // the deactivation the focus will be set into the dialog! // Currently I see no case where a sub frame could get a deactivate with pFocusWindow being NULL permanently // so for now this case is omitted from handled deactivations if( pFocusWindow && pParentWindow->IsChild( pFocusWindow ) )
{
css::uno::Reference< css::frame::XFramesSupplier > xSupplier( xParent, css::uno::UNO_QUERY ); if( xSupplier.is() )
{
aSolarGuard.clear();
xSupplier->setActiveFrame( css::uno::Reference< css::frame::XFrame >() );
}
}
}
// and try to close it // But do it asynchronously inside the main thread. // VCL doesn't like to do such things outside its main thread :-( // Note: the used dispatch makes it asynchronous for us .-)
// Attention: if this dispatch works synchronously and fulfills its job, // this line of code will never be reached. // Or if it will be reached it will be for sure that all your member are gone .-)
}
void SAL_CALL XFrameImpl::removeActionLock()
{
{
SolarMutexGuard g;
SAL_WARN_IF( m_nExternalLockCount<=0, "fwk.frame", "XFrameImpl::removeActionLock(): Frame is not locked! " "Possible multithreading problem detected." );
--m_nExternalLockCount;
}
implts_checkSuicide();
}
void SAL_CALL XFrameImpl::setActionLocks( sal_Int16 nLock )
{
SolarMutexGuard g; // Attention: if resetActionLocks() is called somewhere before and gets e.g. 5 locks // and tried to set these 5 here after its operations, // we can't ignore set requests during these two calls! // So we must add(!) these 5 locks here.
m_nExternalLockCount = m_nExternalLockCount + nLock;
}
// Attention: // external lock count is 0 here every time, but if // member m_bSelfClose is set to true as well, we call our own close()/dispose(). // See close() for further information
implts_checkSuicide();
{ /* There is no need to lock any mutex here. Because we share the solarmutexwithourbaseclass.Andwesaidtoourbaseclass:"don'treleaseitoncallingus".-)
*/
/* Attention: you can use nHandle only, if you are sure that all supported propertieshaveauniquehandle.Thatmustbeguaranteed insidemethodinitListeners()!
*/ switch (nHandle)
{ case FRAME_PROPHANDLE_TITLE :
{
OUString sExternalTitle;
aValue >>= sExternalTitle;
setTitle (sExternalTitle);
} break;
case FRAME_PROPHANDLE_DISPATCHRECORDERSUPPLIER :
aValue >>= m_xDispatchRecorderSupplier; break;
css::uno::Any XFrameImpl::impl_getPropertyValue(sal_Int32 nHandle)
{ /* There is no need to lock any mutex here. Because we share the solarmutexwithourbaseclass.Andwesaidtoourbaseclass:"don'treleaseitoncallingus".-)
*/
/* Attention: you can use nHandle only, if you are sure that all supported propertieshaveauniquehandle.Thatmustbeguaranteed insidemethodinitListeners()!
*/
css::uno::Any aValue; switch (nHandle)
{ case FRAME_PROPHANDLE_TITLE :
aValue <<= getTitle (); break;
case FRAME_PROPHANDLE_DISPATCHRECORDERSUPPLIER :
aValue <<= m_xDispatchRecorderSupplier; break;
case FRAME_PROPHANDLE_ISHIDDEN :
aValue <<= m_bIsHidden; break;
case FRAME_PROPHANDLE_LAYOUTMANAGER :
aValue <<= m_xLayoutManager; break;
/* SAFE AREA ----------------------------------------------------------------------------------------------- */ // Send css::frame::FrameAction event to all listeners. // Get container for right listener. // THE FOLLOWING LINES ARE THREADSAFE!!! // ( OInterfaceContainerHelper2 is synchronized with m_aListenerContainer! )
comphelper::OInterfaceContainerHelper2* pContainer = m_aListenerContainer.getContainer(
cppu::UnoType<css::frame::XFrameActionListener>::get());
// Get iterator for access to listener.
comphelper::OInterfaceIteratorHelper2 aIterator( *pContainer ); // Send message to all listeners. while( aIterator.hasMoreElements() )
{ try
{ static_cast<css::frame::XFrameActionListener*>(aIterator.next())->frameAction( aFrameActionEvent );
} catch( const css::uno::RuntimeException& )
{
aIterator.remove();
}
}
}
/*-**************************************************************************************************** @shorthelpertoresizeourcomponentwindow @descrAframecontains2windows:acontainerandacomponentwindow. Thismethodresizestheinnercomponentwindowtothefullsizeoftheoutercontainerwindow. ThismethodisthreadsafeANDcanbecalledbyourdisposemethodtoo!
*//*-*****************************************************************************************************/ void XFrameImpl::implts_resizeComponentWindow()
{ // usually the LayoutManager does the resizing // in case there is no LayoutManager resizing has to be done here if ( m_xLayoutManager.is() ) return;
// a) set default value to an invalid one. So we can start further searches for right icon id, if // first steps failed! // We must reset it to any fallback value - if no search step returns a valid result.
sal_Int32 nIcon = -1;
// b) try to find information on controller propertyset directly // Don't forget to catch possible exceptions, because this property is an optional one!
css::uno::Reference< css::beans::XPropertySet > xSet( xController, css::uno::UNO_QUERY ); if( xSet.is() )
{ try
{
css::uno::Reference< css::beans::XPropertySetInfo > const xPSI( xSet->getPropertySetInfo(),
css::uno::UNO_SET_THROW ); if ( xPSI->hasPropertyByName( u"IconId"_ustr ) )
xSet->getPropertyValue( u"IconId"_ustr ) >>= nIcon;
} catch( css::uno::Exception& )
{
DBG_UNHANDLED_EXCEPTION("fwk");
}
}
// c) if b) failed, analyze argument list of currently loaded document inside the frame to find the filter. // It can be used to detect the right factory and these can be used to match factory to icon. if( nIcon == -1 )
{
css::uno::Reference< css::frame::XModel > xModel = xController->getModel(); if( xModel.is() )
{
SvtModuleOptions::EFactory eFactory = SvtModuleOptions::ClassifyFactoryByModel(xModel); if (eFactory != SvtModuleOptions::EFactory::UNKNOWN_FACTORY)
nIcon = SvtModuleOptions().GetFactoryIcon( eFactory );
}
}
// d) if all steps failed, use fallback! if( nIcon == -1 )
{
nIcon = 0;
}
// e) set icon on container window now // Don't forget SolarMutex! We use vcl directly :-( // Check window pointer for right WorkWindow class too!!! /* SAFE AREA ----------------------------------------------------------------------------------------------- */
{
SolarMutexGuard aSolarGuard;
VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xContainerWindow ); if(
( pWindow != nullptr ) &&
( pWindow->GetType() == WindowType::WORKWINDOW )
)
{
WorkWindow* pWorkWindow = static_cast<WorkWindow*>(pWindow.get());
pWorkWindow->SetIcon( static_cast<sal_uInt16>(nIcon) );
}
} /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
}
@threadsafeyes
*//*-*****************************************************************************************************/ void XFrameImpl::implts_checkSuicide()
{ /* SAFE */
SolarMutexClearableGuard aReadLock; // in case of lock==0 and saved state of previous close() request m_bSelfClose // we must force close() again. Because we had disagreed with that before. bool bSuicide = (m_nExternalLockCount==0 && m_bSelfClose);
m_bSelfClose = false;
aReadLock.clear(); /* } SAFE */ // Force close and deliver ownership to source of possible thrown veto exception. // Attention: because this method is not designed to throw such an exception we must suppress // it for outside code! try
{ if (bSuicide)
close(true);
} catch(const css::util::CloseVetoException&)
{} catch(const css::lang::DisposedException&)
{}
}
/** a small helper to enable/disable the menu closer at the menubar of the given frame.
@parambState <TRUE/>enable;<FALSE/>disablethisstate
*/ // static void XFrameImpl::impl_setCloser( /*IN*/ const css::uno::Reference< css::frame::XFrame2 >& xFrame , /*IN*/ bool bState )
{ // Note: if start module is not installed, no closer has to be shown! if (!SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE)) return;
// Only top frames, which are part of our desktop hierarchy, can // do so! By the way, we need the desktop instance to have access // to all other top level frames too.
css::uno::Reference< css::frame::XDesktop > xDesktop (m_xParent, css::uno::UNO_QUERY);
css::uno::Reference< css::frame::XFramesSupplier > xTaskSupplier(xDesktop , css::uno::UNO_QUERY); if ( !xDesktop.is() || !xTaskSupplier.is() ) return;
aReadLock.clear(); /* } SAFE */
// Analyze the list of current open tasks. // Suppress search for other views to the same model. // It's not needed here and can be very expensive.
FrameListAnalyzer aAnalyzer(
xTaskSupplier, this,
FrameAnalyzerFlags::Hidden | FrameAnalyzerFlags::Help | FrameAnalyzerFlags::BackingComponent);
// specify the new frame, which must have this special state...
css::uno::Reference< css::frame::XFrame2 > xNewCloserFrame;
// a) // If there exists at least one other frame, there are two frames currently open. // But we can only enable this closer, if one of these two tasks includes the help module. // The "other frame" couldn't be the help. Because then it wouldn't be part of this "other list". // In such a case it will be separated to the reference aAnalyzer.m_xHelp! // But we must check, if we ourselves include the help. // Check aAnalyzer.m_bReferenceIsHelp! if (
(aAnalyzer.m_lOtherVisibleFrames.size()==1) &&
(
(aAnalyzer.m_bReferenceIsHelp ) ||
(aAnalyzer.m_bReferenceIsHidden)
)
)
{ // others[0] can't be the backing component! // Because it's set at the special member aAnalyzer.m_xBackingComponent ... :-)
xNewCloserFrame.set( aAnalyzer.m_lOtherVisibleFrames[0], css::uno::UNO_QUERY_THROW );
}
// b) // There is no other frame, meaning no other document frame. The help module // will be handled separately and must(!) be ignored here, except if we ourselves include the help. elseif (
(aAnalyzer.m_lOtherVisibleFrames.empty()) &&
(!aAnalyzer.m_bReferenceIsHelp) &&
(!aAnalyzer.m_bReferenceIsHidden) &&
(!aAnalyzer.m_bReferenceIsBacking)
)
{
xNewCloserFrame = this;
}
// Look for necessary actions. // Only if the closer state must be moved from one frame to another one // or must be enabled/disabled at all.
SolarMutexGuard aGuard; // Holds the only frame, which must show the special closer menu item (can be NULL!) static css::uno::WeakReference< css::frame::XFrame2 > s_xCloserFrame;
css::uno::Reference< css::frame::XFrame2 > xCloserFrame (s_xCloserFrame.get(), css::uno::UNO_QUERY); if (xCloserFrame!=xNewCloserFrame)
{ if (xCloserFrame.is())
impl_setCloser(xCloserFrame, false); if (xNewCloserFrame.is())
impl_setCloser(xNewCloserFrame, true);
s_xCloserFrame = xNewCloserFrame;
}
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.125Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-01)
¤
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.