1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <framework/desktop.hxx>
22 #include <loadenv/loadenv.hxx>
24 #include <helper/ocomponentaccess.hxx>
25 #include <helper/oframes.hxx>
26 #include <dispatch/dispatchprovider.hxx>
28 #include <dispatch/interceptionhelper.hxx>
29 #include <classes/taskcreator.hxx>
30 #include <threadhelp/transactionguard.hxx>
31 #include <properties.h>
34 #include <strings.hrc>
35 #include <classes/fwkresid.hxx>
37 #include <com/sun/star/beans/PropertyAttribute.hpp>
38 #include <com/sun/star/frame/FrameSearchFlag.hpp>
39 #include <com/sun/star/frame/TerminationVetoException.hpp>
40 #include <com/sun/star/task/XInteractionAbort.hpp>
41 #include <com/sun/star/task/XInteractionApprove.hpp>
42 #include <com/sun/star/document/XInteractionFilterSelect.hpp>
43 #include <com/sun/star/task/ErrorCodeRequest.hpp>
44 #include <com/sun/star/frame/DispatchResultState.hpp>
45 #include <com/sun/star/lang/DisposedException.hpp>
46 #include <com/sun/star/util/CloseVetoException.hpp>
47 #include <com/sun/star/util/XCloseable.hpp>
48 #include <com/sun/star/frame/XTerminateListener2.hpp>
50 #include <comphelper/numberedcollection.hxx>
51 #include <comphelper/sequence.hxx>
52 #include <comphelper/lok.hxx>
53 #include <cppuhelper/supportsservice.hxx>
55 #include <vcl/svapp.hxx>
56 #include <desktop/crashreport.hxx>
57 #include <vcl/scheduler.hxx>
58 #include <sal/log.hxx>
59 #include <comphelper/errcode.hxx>
60 #include <vcl/threadex.hxx>
61 #include <unotools/configmgr.hxx>
68 ActiveFrame
, DispatchRecorderSupplier
, IsPlugged
, SuspendQuickstartVeto
,
73 OUString SAL_CALL
Desktop::getImplementationName()
75 return "com.sun.star.comp.framework.Desktop";
78 sal_Bool SAL_CALL
Desktop::supportsService(OUString
const & ServiceName
)
80 return cppu::supportsService(this, ServiceName
);
83 css::uno::Sequence
<OUString
> SAL_CALL
Desktop::getSupportedServiceNames()
85 return { "com.sun.star.frame.Desktop" };
88 void Desktop::constructorInit()
90 // Initialize a new XFrames-helper-object to handle XIndexAccess and XElementAccess.
91 // We hold member as reference ... not as pointer too!
92 // Attention: We share our frame container with this helper. Container is threadsafe himself ... So I think we can do that.
93 // But look on dispose() for right order of deinitialization.
94 m_xFramesHelper
= new OFrames( this, &m_aChildTaskContainer
);
96 // Initialize a new dispatchhelper-object to handle dispatches.
97 // We use these helper as slave for our interceptor helper ... not directly!
98 // But he is event listener on THIS instance!
99 rtl::Reference
<DispatchProvider
> xDispatchProvider
= new DispatchProvider( m_xContext
, this );
101 // Initialize a new interception helper object to handle dispatches and implement an interceptor mechanism.
102 // Set created dispatch provider as slowest slave of it.
103 // Hold interception helper by reference only - not by pointer!
104 // So it's easier to destroy it.
105 m_xDispatchHelper
= new InterceptionHelper( this, xDispatchProvider
);
107 OUString sUntitledPrefix
= FwkResId(STR_UNTITLED_DOCUMENT
) + " ";
109 rtl::Reference
<::comphelper::NumberedCollection
> pNumbers
= new ::comphelper::NumberedCollection ();
110 m_xTitleNumberGenerator
= pNumbers
;
111 pNumbers
->setOwner ( static_cast< ::cppu::OWeakObject
* >(this) );
112 pNumbers
->setUntitledPrefix ( sUntitledPrefix
);
114 // Safe impossible cases
115 // We can't work without this helper!
116 SAL_WARN_IF( !m_xFramesHelper
.is(), "fwk.desktop", "Desktop::Desktop(): Frames helper is not valid. XFrames, XIndexAccess and XElementAccess are not supported!");
117 SAL_WARN_IF( !m_xDispatchHelper
.is(), "fwk.desktop", "Desktop::Desktop(): Dispatch helper is not valid. XDispatch will not work correctly!" );
119 // Enable object for real working!
120 // Otherwise all calls will be rejected ...
121 m_aTransactionManager
.setWorkingMode( E_WORK
);
124 /*-************************************************************************************************************
125 @short standard constructor to create instance by factory
126 @descr This constructor initialize a new instance of this class by valid factory,
127 and will be set valid values on his member and baseclasses.
129 @attention a) Don't use your own reference during a UNO-Service-ctor! There is no guarantee, that you
130 will get over this. (e.g. using of your reference as parameter to initialize some member)
131 Do such things in DEFINE_INIT_SERVICE() method, which is called automatically after your ctor!!!
132 b) Baseclass OBroadcastHelper is a typedef in namespace cppu!
133 The microsoft compiler has some problems to handle it right BY using namespace explicitly ::cppu::OBroadcastHelper.
134 If we write it without a namespace or expand the typedef to OBroadcastHelperVar<...> -> it will be OK!?
135 I don't know why! (other compiler not tested .. but it works!)
137 @seealso method DEFINE_INIT_SERVICE()
139 @param "xFactory" is the multi service manager, which create this instance.
140 The value must be different from NULL!
141 @onerror We throw an ASSERT in debug version or do nothing in release version.
142 *//*-*************************************************************************************************************/
143 Desktop::Desktop( css::uno::Reference
< css::uno::XComponentContext
> xContext
)
144 : Desktop_BASE ( m_aMutex
)
145 , cppu::OPropertySetHelper( cppu::WeakComponentImplHelperBase::rBHelper
)
147 , m_bIsTerminated(false)
148 , m_bIsShutdown(false) // see dispose() for further information!
149 , m_bSession ( false )
150 , m_xContext (std::move( xContext
))
151 , m_aListenerContainer ( m_aMutex
)
152 , m_eLoadState ( E_NOTSET
)
153 , m_bSuspendQuickstartVeto( false )
157 /*-************************************************************************************************************
158 @short standard destructor
159 @descr This one do NOTHING! Use dispose() instead of this.
161 @seealso method dispose()
162 *//*-*************************************************************************************************************/
165 SAL_WARN_IF(!m_bIsShutdown
, "fwk.desktop", "Desktop not terminated before being destructed");
166 SAL_WARN_IF( m_aTransactionManager
.getWorkingMode()!=E_CLOSE
, "fwk.desktop", "Desktop::~Desktop(): Who forgot to dispose this service?" );
169 css::uno::Any SAL_CALL
Desktop::queryInterface( const css::uno::Type
& _rType
)
171 css::uno::Any aRet
= Desktop_BASE::queryInterface( _rType
);
172 if ( !aRet
.hasValue() )
173 aRet
= OPropertySetHelper::queryInterface( _rType
);
177 css::uno::Sequence
< css::uno::Type
> SAL_CALL
Desktop::getTypes( )
179 return comphelper::concatSequences(
180 Desktop_BASE::getTypes(),
181 ::cppu::OPropertySetHelper::getTypes()
185 sal_Bool SAL_CALL
Desktop::terminate()
187 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
188 SolarMutexResettableGuard aGuard
;
193 css::uno::Reference
< css::frame::XTerminateListener
> xPipeTerminator
= m_xPipeTerminator
;
194 css::uno::Reference
< css::frame::XTerminateListener
> xQuickLauncher
= m_xQuickLauncher
;
195 css::uno::Reference
< css::frame::XTerminateListener
> xSWThreadManager
= m_xSWThreadManager
;
196 css::uno::Reference
< css::frame::XTerminateListener
> xSfxTerminator
= m_xSfxTerminator
;
198 css::lang::EventObject
aEvent ( static_cast< ::cppu::OWeakObject
* >(this) );
199 bool bAskQuickStart
= !m_bSuspendQuickstartVeto
;
200 const bool bRestartableMainLoop
= Application::IsEventTestingModeEnabled() ||
201 comphelper::LibreOfficeKit::isActive();
204 // Allow using of any UI ... because Desktop.terminate() was designed as UI functionality in the past.
206 // Ask normal terminate listener. They could veto terminating the process.
207 Desktop::TTerminateListenerList lCalledTerminationListener
;
208 if (!impl_sendQueryTerminationEvent(lCalledTerminationListener
))
210 impl_sendCancelTerminationEvent(lCalledTerminationListener
);
214 // try to close all open frames
215 if (!impl_closeFrames(!bRestartableMainLoop
))
217 impl_sendCancelTerminationEvent(lCalledTerminationListener
);
221 // Normal listener had no problem ...
222 // all frames was closed ...
223 // now it's time to ask our specialized listener.
224 // They are handled these way because they wish to hinder the office on termination
225 // but they wish also closing of all frames.
228 // We shouldn't ask quicklauncher in case it was allowed from outside only.
229 // This is special trick to "ignore existing quick starter" for debug purposes.
232 // Order of called listener is important!
233 // Some of them are harmless,-)
234 // but some can be dangerous. E.g. it would be dangerous if we close our pipe
235 // and don't terminate in real because another listener throws a veto exception .-)
239 if( bAskQuickStart
&& xQuickLauncher
.is() )
241 xQuickLauncher
->queryTermination( aEvent
);
242 lCalledTerminationListener
.push_back( xQuickLauncher
);
245 if ( xSWThreadManager
.is() )
247 xSWThreadManager
->queryTermination( aEvent
);
248 lCalledTerminationListener
.push_back( xSWThreadManager
);
251 if ( xPipeTerminator
.is() )
253 xPipeTerminator
->queryTermination( aEvent
);
254 lCalledTerminationListener
.push_back( xPipeTerminator
);
257 if ( xSfxTerminator
.is() )
259 xSfxTerminator
->queryTermination( aEvent
);
260 lCalledTerminationListener
.push_back( xSfxTerminator
);
263 catch(const css::frame::TerminationVetoException
&)
265 impl_sendCancelTerminationEvent(lCalledTerminationListener
);
272 m_bIsTerminated
= true;
274 if (!bRestartableMainLoop
)
276 CrashReporter::addKeyValue("ShutDown", OUString::boolean(true), CrashReporter::Write
);
278 // The clipboard listener needs to be the first. It can create copies of the
279 // existing document which needs basically all the available infrastructure.
280 impl_sendTerminateToClipboard();
282 SolarMutexReleaser aReleaser
;
283 impl_sendNotifyTerminationEvent();
285 Scheduler::ProcessEventsToIdle();
287 if( bAskQuickStart
&& xQuickLauncher
.is() )
288 xQuickLauncher
->notifyTermination( aEvent
);
290 if ( xSWThreadManager
.is() )
291 xSWThreadManager
->notifyTermination( aEvent
);
293 if ( xPipeTerminator
.is() )
294 xPipeTerminator
->notifyTermination( aEvent
);
296 // further termination is postponed to shutdown, if LO already runs the main loop
297 if (!Application::IsInExecute())
301 m_bIsShutdown
= true;
303 #ifndef IOS // or ANDROID?
305 // In the iOS app, posting the ImplQuitMsg user event will be too late, it will not be handled during the
306 // lifetime of the current document, but handled for the next document opened, which thus will break horribly.
313 void Desktop::shutdown()
315 TransactionGuard
aTransaction(m_aTransactionManager
, E_HARDEXCEPTIONS
);
316 SolarMutexGuard aGuard
;
320 m_bIsShutdown
= true;
322 css::uno::Reference
<css::frame::XTerminateListener
> xSfxTerminator
= m_xSfxTerminator
;
323 css::lang::EventObject
aEvent(static_cast<::cppu::OWeakObject
* >(this));
325 // we need a copy here as the notifyTermination call might cause a removeTerminateListener call
326 std::vector
< css::uno::Reference
<css::frame::XTerminateListener
> > xComponentDllListeners
;
327 xComponentDllListeners
.swap(m_xComponentDllListeners
);
328 for (auto& xListener
: xComponentDllListeners
)
329 xListener
->notifyTermination(aEvent
);
330 xComponentDllListeners
.clear();
332 // Must be really the last listener to be called.
333 // Because it shuts down the whole process asynchronous!
334 if (xSfxTerminator
.is())
335 xSfxTerminator
->notifyTermination(aEvent
);
340 class QuickstartSuppressor
342 Desktop
* const m_pDesktop
;
343 css::uno::Reference
< css::frame::XTerminateListener
> m_xQuickLauncher
;
345 QuickstartSuppressor(Desktop
* const pDesktop
, css::uno::Reference
< css::frame::XTerminateListener
> xQuickLauncher
)
346 : m_pDesktop(pDesktop
)
347 , m_xQuickLauncher(std::move(xQuickLauncher
))
349 SAL_INFO("fwk.desktop", "temporary removing Quickstarter");
350 if(m_xQuickLauncher
.is())
351 m_pDesktop
->removeTerminateListener(m_xQuickLauncher
);
353 ~QuickstartSuppressor()
355 SAL_INFO("fwk.desktop", "readding Quickstarter");
356 if(m_xQuickLauncher
.is())
357 m_pDesktop
->addTerminateListener(m_xQuickLauncher
);
362 bool Desktop::terminateQuickstarterToo()
364 QuickstartSuppressor
aQuickstartSuppressor(this, m_xQuickLauncher
);
369 void SAL_CALL
Desktop::addTerminateListener( const css::uno::Reference
< css::frame::XTerminateListener
>& xListener
)
371 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
373 css::uno::Reference
< css::lang::XServiceInfo
> xInfo( xListener
, css::uno::UNO_QUERY
);
376 OUString sImplementationName
= xInfo
->getImplementationName();
380 if( sImplementationName
== "com.sun.star.comp.sfx2.SfxTerminateListener" )
382 m_xSfxTerminator
= xListener
;
385 if( sImplementationName
== "com.sun.star.comp.RequestHandlerController" )
387 m_xPipeTerminator
= xListener
;
390 if( sImplementationName
== "com.sun.star.comp.desktop.QuickstartWrapper" )
392 m_xQuickLauncher
= xListener
;
395 if( sImplementationName
== "com.sun.star.util.comp.FinalThreadManager" )
397 m_xSWThreadManager
= xListener
;
400 else if ( sImplementationName
== "com.sun.star.comp.ComponentDLLListener" )
402 m_xComponentDllListeners
.push_back(xListener
);
407 // No lock required... container is threadsafe by itself.
408 m_aListenerContainer
.addInterface( cppu::UnoType
<css::frame::XTerminateListener
>::get(), xListener
);
411 void SAL_CALL
Desktop::removeTerminateListener( const css::uno::Reference
< css::frame::XTerminateListener
>& xListener
)
413 TransactionGuard
aTransaction( m_aTransactionManager
, E_SOFTEXCEPTIONS
);
415 css::uno::Reference
< css::lang::XServiceInfo
> xInfo( xListener
, css::uno::UNO_QUERY
);
418 OUString sImplementationName
= xInfo
->getImplementationName();
422 if( sImplementationName
== "com.sun.star.comp.sfx2.SfxTerminateListener" )
424 m_xSfxTerminator
.clear();
428 if( sImplementationName
== "com.sun.star.comp.RequestHandlerController" )
430 m_xPipeTerminator
.clear();
434 if( sImplementationName
== "com.sun.star.comp.desktop.QuickstartWrapper" )
436 m_xQuickLauncher
.clear();
440 if( sImplementationName
== "com.sun.star.util.comp.FinalThreadManager" )
442 m_xSWThreadManager
.clear();
445 else if (sImplementationName
== "com.sun.star.comp.ComponentDLLListener")
447 m_xComponentDllListeners
.erase(
448 std::remove(m_xComponentDllListeners
.begin(), m_xComponentDllListeners
.end(), xListener
),
449 m_xComponentDllListeners
.end());
454 // No lock required ... container is threadsafe by itself.
455 m_aListenerContainer
.removeInterface( cppu::UnoType
<css::frame::XTerminateListener
>::get(), xListener
);
458 /*-************************************************************************************************************
460 @short get access to create enumerations of all current components
461 @descr You will be the owner of the returned object and must delete it if you don't use it again.
463 @seealso class TasksAccess
464 @seealso class TasksEnumeration
465 @return A reference to an XEnumerationAccess-object.
467 @onerror We return a null-reference.
469 *//*-*************************************************************************************************************/
470 css::uno::Reference
< css::container::XEnumerationAccess
> SAL_CALL
Desktop::getComponents()
472 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
473 // Register transaction and reject wrong calls.
474 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
476 // We use a helper class OComponentAccess to have access on all child components.
477 // Create it on demand and return it as a reference.
478 return new OComponentAccess( this );
481 /*-************************************************************************************************************
483 @short return the current active component
484 @descr The most current component is the window, model or the controller of the current active frame.
486 @seealso method getCurrentFrame()
487 @seealso method impl_getFrameComponent()
488 @return A reference to the component.
490 @onerror We return a null-reference.
492 *//*-*************************************************************************************************************/
493 css::uno::Reference
< css::lang::XComponent
> SAL_CALL
Desktop::getCurrentComponent()
495 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
496 // Register transaction and reject wrong calls.
497 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
499 // Set return value if method failed.
500 css::uno::Reference
< css::lang::XComponent
> xComponent
;
502 // Get reference to current frame ...
503 // ... get component of this frame ... (It can be the window, the model or the controller.)
504 // ... and return the result.
505 css::uno::Reference
< css::frame::XFrame
> xCurrentFrame
= getCurrentFrame();
506 if( xCurrentFrame
.is() )
508 xComponent
= impl_getFrameComponent( xCurrentFrame
);
513 /*-************************************************************************************************************
515 @short return the current active frame in hierarchy
516 @descr There can be more than one different active paths in our frame hierarchy. But only one of them
517 could be the most active frame (normal he has the focus).
518 Don't mix it with getActiveFrame()! That will return our current active frame, which must be
519 a direct child of us and should be a part(!) of an active path.
521 @seealso method getActiveFrame()
522 @return A valid reference, if there is an active frame.
523 A null reference , otherwise.
525 @onerror We return a null reference.
527 *//*-*************************************************************************************************************/
528 css::uno::Reference
< css::frame::XFrame
> SAL_CALL
Desktop::getCurrentFrame()
530 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
531 // Register transaction and reject wrong calls.
532 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
534 // Start search with our direct active frame (if it exist!).
535 // Search on his children for other active frames too.
536 // Stop if no one could be found and return last of found ones.
537 css::uno::Reference
< css::frame::XFramesSupplier
> xLast( getActiveFrame(), css::uno::UNO_QUERY
);
540 css::uno::Reference
< css::frame::XFramesSupplier
> xNext( xLast
->getActiveFrame(), css::uno::UNO_QUERY
);
544 xNext
.set( xNext
->getActiveFrame(), css::uno::UNO_QUERY
);
550 /*-************************************************************************************************************
551 @interface XComponentLoader
552 @short try to load given URL into a task
553 @descr You can give us some information about the content, which you will load into a frame.
554 We search or create this target for you, make a type detection of given URL and try to load it.
555 As result of this operation we return the new created component or nothing, if loading failed.
556 @param "sURL" , URL, which represent the content
557 @param "sTargetFrameName" , name of target frame or special value like "_self", "_blank" ...
558 @param "nSearchFlags" , optional arguments for frame search, if target isn't a special one
559 @param "lArguments" , optional arguments for loading
560 @return A valid component reference, if loading was successful.
561 A null reference otherwise.
563 @onerror We return a null reference.
565 *//*-*************************************************************************************************************/
566 css::uno::Reference
< css::lang::XComponent
> SAL_CALL
Desktop::loadComponentFromURL( const OUString
& sURL
,
567 const OUString
& sTargetFrameName
,
568 sal_Int32 nSearchFlags
,
569 const css::uno::Sequence
< css::beans::PropertyValue
>& lArguments
)
571 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
572 // Register transaction and reject wrong calls.
573 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
574 SAL_INFO( "fwk.desktop", "loadComponentFromURL" );
576 css::uno::Reference
< css::frame::XComponentLoader
> xThis(this);
578 utl::MediaDescriptor
aDescriptor(lArguments
);
579 bool bOnMainThread
= aDescriptor
.getUnpackedValueOrDefault("OnMainThread", false);
583 // Make sure that we own the solar mutex, otherwise later
584 // vcl::SolarThreadExecutor::execute() will release the solar mutex, even if it's owned by
585 // another thread, leading to an std::abort() at the end.
588 return vcl::solarthread::syncExecute(std::bind(&LoadEnv::loadComponentFromURL
, xThis
,
589 m_xContext
, sURL
, sTargetFrameName
,
590 nSearchFlags
, lArguments
));
594 return LoadEnv::loadComponentFromURL(xThis
, m_xContext
, sURL
, sTargetFrameName
,
595 nSearchFlags
, lArguments
);
599 /*-************************************************************************************************************
600 @interface XTasksSupplier
601 @short get access to create enumerations of our taskchildren
602 @descr Direct children of desktop are tasks every time.
603 Call these method to could create enumerations of it.
605 But; Don't forget - you will be the owner of returned object and must release it!
606 We use a helper class to implement the access interface. They hold a weakreference to us.
607 It can be, that the desktop is dead - but not your tasksaccess-object! Then they will do nothing!
608 You can't create enumerations then.
610 @attention Normally we don't need any lock here. We don't work on internal member!
612 @seealso class TasksAccess
613 @return A reference to an accessobject, which can create enumerations of our childtasks.
615 @onerror A null reference is returned.
617 *//*-*************************************************************************************************************/
618 css::uno::Reference
< css::container::XEnumerationAccess
> SAL_CALL
Desktop::getTasks()
620 SAL_INFO("fwk.desktop", "Desktop::getTasks(): Use of obsolete interface XTaskSupplier");
624 /*-************************************************************************************************************
625 @interface XTasksSupplier
626 @short return current active task of our direct children
627 @descr Desktop children are tasks only ! If we have an active path from desktop
628 as top to any frame on bottom, we must have an active direct child. His reference is returned here.
630 @attention a) Do not confuse it with getCurrentFrame()! The current frame don't must one of our direct children.
631 It can be every frame in subtree and must have the focus (Is the last one of an active path!).
632 b) We don't need any lock here. Our container is threadsafe himself and live, if we live!
634 @seealso method getCurrentFrame()
635 @return A reference to our current active taskchild.
637 @onerror A null reference is returned.
639 *//*-*************************************************************************************************************/
640 css::uno::Reference
< css::frame::XTask
> SAL_CALL
Desktop::getActiveTask()
642 SAL_INFO("fwk.desktop", "Desktop::getActiveTask(): Use of obsolete interface XTaskSupplier");
646 /*-************************************************************************************************************
647 @interface XDispatchProvider
648 @short search a dispatcher for given URL
649 @descr We use a helper implementation (class DispatchProvider) to do so.
650 So we don't must implement this algorithm twice!
652 @attention We don't need any lock here. Our helper is threadsafe himself and live, if we live!
654 @seealso class DispatchProvider
656 @param "aURL" , URL to dispatch
657 @param "sTargetFrameName" , name of target frame, who should dispatch these URL
658 @param "nSearchFlags" , flags to regulate the search
659 @param "lQueries" , list of queryDispatch() calls!
660 @return A reference or list of founded dispatch objects for these URL.
662 @onerror A null reference is returned.
664 *//*-*************************************************************************************************************/
665 css::uno::Reference
< css::frame::XDispatch
> SAL_CALL
Desktop::queryDispatch( const css::util::URL
& aURL
,
666 const OUString
& sTargetFrameName
,
667 sal_Int32 nSearchFlags
)
669 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
670 // Register transaction and reject wrong calls.
671 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
673 // Remove uno and cmd protocol part as we want to support both of them. We store only the command part
674 // in our hash map. All other protocols are stored with the protocol part.
675 OUString
aCommand( aURL
.Main
);
676 if ( aURL
.Protocol
.equalsIgnoreAsciiCase(".uno:") )
677 aCommand
= aURL
.Path
;
679 if (!m_xCommandOptions
&& !utl::ConfigManager::IsFuzzing())
680 m_xCommandOptions
.reset(new SvtCommandOptions
);
682 // Make std::unordered_map lookup if the current URL is in the disabled list
683 if (m_xCommandOptions
&& m_xCommandOptions
->Lookup(SvtCommandOptions::CMDOPTION_DISABLED
, aCommand
))
684 return css::uno::Reference
< css::frame::XDispatch
>();
687 // We use a helper to support these interface and an interceptor mechanism.
688 // Our helper is threadsafe by himself!
689 return m_xDispatchHelper
->queryDispatch( aURL
, sTargetFrameName
, nSearchFlags
);
693 css::uno::Sequence
< css::uno::Reference
< css::frame::XDispatch
> > SAL_CALL
Desktop::queryDispatches( const css::uno::Sequence
< css::frame::DispatchDescriptor
>& lQueries
)
695 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
696 // Register transaction and reject wrong calls.
697 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
699 return m_xDispatchHelper
->queryDispatches( lQueries
);
702 /*-************************************************************************************************************
703 @interface XDispatchProviderInterception
704 @short supports registration/deregistration of interception objects, which
705 are interested on special dispatches.
707 @descr It's really provided by an internal helper, which is used inside the dispatch API too.
709 the interceptor object, which wishes to be (de)registered.
712 *//*-*************************************************************************************************************/
713 void SAL_CALL
Desktop::registerDispatchProviderInterceptor( const css::uno::Reference
< css::frame::XDispatchProviderInterceptor
>& xInterceptor
)
715 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
717 css::uno::Reference
< css::frame::XDispatchProviderInterception
> xInterceptionHelper( m_xDispatchHelper
, css::uno::UNO_QUERY
);
718 xInterceptionHelper
->registerDispatchProviderInterceptor( xInterceptor
);
721 void SAL_CALL
Desktop::releaseDispatchProviderInterceptor ( const css::uno::Reference
< css::frame::XDispatchProviderInterceptor
>& xInterceptor
)
723 TransactionGuard
aTransaction( m_aTransactionManager
, E_SOFTEXCEPTIONS
);
725 css::uno::Reference
< css::frame::XDispatchProviderInterception
> xInterceptionHelper( m_xDispatchHelper
, css::uno::UNO_QUERY
);
726 xInterceptionHelper
->releaseDispatchProviderInterceptor( xInterceptor
);
729 /*-************************************************************************************************************
730 @interface XFramesSupplier
731 @short return access to append or remove children on desktop
732 @descr We don't implement these interface directly. We use a helper class to do this.
733 If you wish to add or delete children to/from the container, call these method to get
734 a reference to the helper.
736 @attention Helper is threadsafe himself. So we don't need any lock here.
738 @seealso class OFrames
739 @return A reference to the helper.
741 @onerror A null reference is returned.
743 *//*-*************************************************************************************************************/
744 css::uno::Reference
< css::frame::XFrames
> SAL_CALL
Desktop::getFrames()
746 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
747 // Register transaction and reject wrong calls.
748 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
750 return m_xFramesHelper
;
753 /*-************************************************************************************************************
754 @interface XFramesSupplier
755 @short set/get the current active child frame
756 @descr It must be a task. Direct children of desktop are tasks only! No frames are accepted.
757 We don't save this information directly in this class. We use our container-helper
760 @attention Helper is threadsafe himself. So we don't need any lock here.
762 @seealso class OFrameContainer
764 @param "xFrame", new active frame (must be valid!)
765 @return A reference to our current active childtask, if anyone exist.
767 @onerror A null reference is returned.
769 *//*-*************************************************************************************************************/
770 void SAL_CALL
Desktop::setActiveFrame( const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
772 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
773 // Register transaction and reject wrong calls.
774 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
776 // Get old active frame first.
777 // If nothing will change - do nothing!
778 // Otherwise set new active frame ...
779 // and deactivate last frame.
780 // It's necessary for our FrameActionEvent listener on a frame!
781 css::uno::Reference
< css::frame::XFrame
> xLastActiveChild
= m_aChildTaskContainer
.getActive();
782 if( xLastActiveChild
!= xFrame
)
784 m_aChildTaskContainer
.setActive( xFrame
);
785 if( xLastActiveChild
.is() )
787 xLastActiveChild
->deactivate();
792 css::uno::Reference
< css::frame::XFrame
> SAL_CALL
Desktop::getActiveFrame()
794 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
795 // Register transaction and reject wrong calls.
796 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
798 return m_aChildTaskContainer
.getActive();
803 @short non implemented methods!
804 @descr Some method make no sense for our desktop! He has no window or parent or ...
805 So we should implement it empty and warn programmer, if he use it!
807 void SAL_CALL
Desktop::initialize( const css::uno::Reference
< css::awt::XWindow
>& )
811 css::uno::Reference
< css::awt::XWindow
> SAL_CALL
Desktop::getContainerWindow()
813 return css::uno::Reference
< css::awt::XWindow
>();
816 void SAL_CALL
Desktop::setCreator( const css::uno::Reference
< css::frame::XFramesSupplier
>& /*xCreator*/ )
820 css::uno::Reference
< css::frame::XFramesSupplier
> SAL_CALL
Desktop::getCreator()
822 return css::uno::Reference
< css::frame::XFramesSupplier
>();
825 OUString SAL_CALL
Desktop::getName()
831 void SAL_CALL
Desktop::setName( const OUString
& sName
)
837 sal_Bool SAL_CALL
Desktop::isTop()
842 void SAL_CALL
Desktop::activate()
844 // Desktop is active always... but sometimes our frames try to activate
845 // the complete path from bottom to top... And our desktop is the topest frame :-(
846 // So - please don't show any assertions here. Do nothing!
849 void SAL_CALL
Desktop::deactivate()
851 // Desktop is active always... but sometimes our frames try to deactivate
852 // the complete path from bottom to top... And our desktop is the topest frame :-(
853 // So - please don't show any assertions here. Do nothing!
856 sal_Bool SAL_CALL
Desktop::isActive()
861 sal_Bool SAL_CALL
Desktop::setComponent( const css::uno::Reference
< css::awt::XWindow
>& /*xComponentWindow*/ ,
862 const css::uno::Reference
< css::frame::XController
>& /*xController*/ )
867 css::uno::Reference
< css::awt::XWindow
> SAL_CALL
Desktop::getComponentWindow()
869 return css::uno::Reference
< css::awt::XWindow
>();
872 css::uno::Reference
< css::frame::XController
> SAL_CALL
Desktop::getController()
874 return css::uno::Reference
< css::frame::XController
>();
877 void SAL_CALL
Desktop::contextChanged()
881 void SAL_CALL
Desktop::addFrameActionListener( const css::uno::Reference
< css::frame::XFrameActionListener
>& )
885 // css::frame::XFrame
886 void SAL_CALL
Desktop::removeFrameActionListener( const css::uno::Reference
< css::frame::XFrameActionListener
>& )
890 /*-************************************************************************************************************
892 @short try to find a frame with special parameters
893 @descr This method searches for a frame with the specified name.
894 Frames may contain other frames (e.g. a frameset) and may
895 be contained in other frames. This hierarchy is searched by
897 First some special names are taken into account, i.e. "",
898 "_self", "_top", "_parent" etc. The FrameSearchFlags are ignored
899 when comparing these names with aTargetFrameName, further steps are
900 controlled by the FrameSearchFlags. If allowed, the name of the frame
901 itself is compared with the desired one, then ( again if allowed )
902 the method findFrame is called for all children of the frame.
903 If no Frame with the given name is found until the top frames container,
904 a new top Frame is created, if this is allowed by a special
905 FrameSearchFlag. The new Frame also gets the desired name.
906 We use a helper to get right search direction and react in a right manner.
908 @seealso class TargetFinder
910 @param "sTargetFrameName" , name of searched frame
911 @param "nSearchFlags" , flags to regulate search
912 @return A reference to an existing frame in hierarchy, if it exist.
914 @onerror A null reference is returned.
916 *//*-*************************************************************************************************************/
917 css::uno::Reference
< css::frame::XFrame
> SAL_CALL
Desktop::findFrame( const OUString
& sTargetFrameName
,
918 sal_Int32 nSearchFlags
)
920 css::uno::Reference
< css::frame::XFrame
> xTarget
;
922 // 0) Ignore wrong parameter!
923 // We don't support search for following special targets.
924 // If we reject these requests, we must not check for such names
925 // in following code again and again. If we do not, so wrong
926 // search results can occur!
929 (sTargetFrameName
==SPECIALTARGET_DEFAULT
) || // valid for dispatches - not for findFrame()!
930 (sTargetFrameName
==SPECIALTARGET_PARENT
) || // we have no parent by definition
931 (sTargetFrameName
==SPECIALTARGET_BEAMER
) // beamer frames are allowed as child of tasks only -
932 // and they exist more than ones. We have no idea which our sub tasks is the right one
938 // I) check for special defined targets first which must be handled exclusive.
939 // force using of "if() else if() ..."
942 // create a new task as child of this desktop instance
943 // Note: Used helper TaskCreator use us automatically ...
945 if ( sTargetFrameName
==SPECIALTARGET_BLANK
)
947 TaskCreator
aCreator( m_xContext
);
948 xTarget
= aCreator
.createTask(sTargetFrameName
, utl::MediaDescriptor());
952 // We are top by definition
954 else if ( sTargetFrameName
==SPECIALTARGET_TOP
)
959 // I.III) "_self", ""
960 // This mean this "frame" in every case.
963 ( sTargetFrameName
==SPECIALTARGET_SELF
) ||
964 ( sTargetFrameName
.isEmpty() )
973 // II) otherwise use optional given search flags
974 // force using of combinations of such flags. means no "else" part of use if() statements.
975 // But we ust break further searches if target was already found.
976 // Order of using flags is fix: SELF - CHILDREN - SIBLINGS - PARENT
977 // TASK and CREATE are handled special.
978 // But note: Such flags are not valid for the desktop - especially SIBLINGS or PARENT.
981 // Check for right name. If it's the searched one return ourself - otherwise
985 (nSearchFlags
& css::frame::FrameSearchFlag::SELF
) &&
986 (m_sName
== sTargetFrameName
)
993 // This is a special flag. Normally it regulate search inside tasks and forbid access to parent trees.
994 // But the desktop exists outside such task trees. They are our sub trees. So the desktop implement
995 // a special feature: We use it to start search on our direct children only. That means we suppress
996 // search on ALL child frames. May that can be useful to get access on opened document tasks
997 // only without filter out all non really required sub frames ...
998 // Used helper method on our container doesn't create any frame - it's a search only.
1001 ( ! xTarget
.is() ) &&
1002 (nSearchFlags
& css::frame::FrameSearchFlag::TASKS
)
1005 xTarget
= m_aChildTaskContainer
.searchOnDirectChildrens(sTargetFrameName
);
1009 // Search on all children for the given target name.
1010 // An empty name value can't occur here - because it must be already handled as "_self"
1011 // before. Used helper function of container doesn't create any frame.
1012 // It makes a deep search only.
1015 ( ! xTarget
.is() ) &&
1016 (nSearchFlags
& css::frame::FrameSearchFlag::CHILDREN
)
1019 xTarget
= m_aChildTaskContainer
.searchOnAllChildrens(sTargetFrameName
);
1023 // If we haven't found any valid target frame by using normal flags - but user allowed us to create
1024 // a new one ... we should do that. Used TaskCreator use us automatically as parent!
1027 ( ! xTarget
.is() ) &&
1028 (nSearchFlags
& css::frame::FrameSearchFlag::CREATE
)
1031 TaskCreator
aCreator( m_xContext
);
1032 xTarget
= aCreator
.createTask(sTargetFrameName
, utl::MediaDescriptor());
1039 void SAL_CALL
Desktop::disposing()
1041 // Safe impossible cases
1042 // It's a programming error if dispose is called before terminate!
1044 // But if you just ignore the assertion (which happens in unit
1045 // tests for instance in sc/qa/unit) nothing bad happens.
1046 assert(m_bIsShutdown
&& "Desktop disposed before terminating it");
1049 SolarMutexGuard aWriteLock
;
1052 TransactionGuard
aTransaction(m_aTransactionManager
, E_HARDEXCEPTIONS
);
1055 // Disable this instance for further work.
1056 // This will wait for all current running transactions ...
1057 // and reject all new incoming requests!
1058 m_aTransactionManager
.setWorkingMode(E_BEFORECLOSE
);
1061 // Following lines of code can be called outside a synchronized block ...
1062 // Because our transaction manager will block all new requests to this object.
1063 // So nobody can use us any longer.
1064 // Exception: Only removing of listener will work ... and this code can't be dangerous.
1066 // First we have to kill all listener connections.
1067 // They might rely on our member and can hinder us on releasing them.
1068 css::uno::Reference
< css::uno::XInterface
> xThis ( static_cast< ::cppu::OWeakObject
* >(this), css::uno::UNO_QUERY
);
1069 css::lang::EventObject
aEvent( xThis
);
1070 m_aListenerContainer
.disposeAndClear( aEvent
);
1072 // Clear our child task container and forget all task references hardly.
1073 // Normally all open document was already closed by our terminate() function before ...
1074 // New opened frames will have a problem now .-)
1075 m_aChildTaskContainer
.clear();
1077 // Dispose our helper too.
1078 css::uno::Reference
< css::lang::XEventListener
> xFramesHelper( m_xFramesHelper
, css::uno::UNO_QUERY
);
1079 if( xFramesHelper
.is() )
1080 xFramesHelper
->disposing( aEvent
);
1082 // At least clean up other member references.
1083 m_xDispatchHelper
.clear();
1084 m_xFramesHelper
.clear();
1087 m_xPipeTerminator
.clear();
1088 m_xQuickLauncher
.clear();
1089 m_xSWThreadManager
.clear();
1091 // we need a copy because the disposing might call the removeEventListener method
1092 std::vector
< css::uno::Reference
<css::frame::XTerminateListener
> > xComponentDllListeners
;
1093 xComponentDllListeners
.swap(m_xComponentDllListeners
);
1094 for (auto& xListener
: xComponentDllListeners
)
1096 xListener
->disposing(aEvent
);
1098 xComponentDllListeners
.clear();
1099 m_xSfxTerminator
.clear();
1100 m_xCommandOptions
.reset();
1102 // From this point nothing will work further on this object ...
1103 // excepting our dtor() .-)
1104 m_aTransactionManager
.setWorkingMode( E_CLOSE
);
1108 @interface XComponent
1109 @short add/remove listener for dispose events
1110 @descr Add an event listener to this object, if you wish to get information
1112 You must release this listener reference during your own disposing() method.
1114 @attention Our container is threadsafe himself. So we don't need any lock here.
1115 @param "xListener", reference to valid listener. We don't accept invalid values!
1118 void SAL_CALL
Desktop::addEventListener( const css::uno::Reference
< css::lang::XEventListener
>& xListener
)
1120 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1121 // Safe impossible cases
1122 // Method not defined for all incoming parameter.
1123 SAL_WARN_IF( !xListener
.is(), "fwk.desktop", "Desktop::addEventListener(): Invalid parameter detected!" );
1124 // Register transaction and reject wrong calls.
1125 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1127 m_aListenerContainer
.addInterface( cppu::UnoType
<css::lang::XEventListener
>::get(), xListener
);
1130 void SAL_CALL
Desktop::removeEventListener( const css::uno::Reference
< css::lang::XEventListener
>& xListener
)
1132 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1133 // Safe impossible cases
1134 // Method not defined for all incoming parameter.
1135 SAL_WARN_IF( !xListener
.is(), "fwk.desktop", "Desktop::removeEventListener(): Invalid parameter detected!" );
1136 // Register transaction and reject wrong calls.
1137 TransactionGuard
aTransaction( m_aTransactionManager
, E_SOFTEXCEPTIONS
);
1139 m_aListenerContainer
.removeInterface( cppu::UnoType
<css::lang::XEventListener
>::get(), xListener
);
1142 /*-************************************************************************************************************
1143 @interface XDispatchResultListener
1144 @short callback for dispatches
1145 @descr To support our method "loadComponentFromURL()" we are listener on temp. created dispatcher.
1146 They call us back in this method "statusChanged()". As source of given state event, they give us a
1147 reference to the target frame, in which dispatch was loaded! So we can use it to return his component
1148 to caller! If no target exist ... ??!!
1150 @seealso method loadComponentFromURL()
1152 @param "aEvent", state event which (hopefully) valid information
1154 *//*-*************************************************************************************************************/
1155 void SAL_CALL
Desktop::dispatchFinished( const css::frame::DispatchResultEvent
& aEvent
)
1157 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1158 // Register transaction and reject wrong calls.
1159 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1162 if( m_eLoadState
!= E_INTERACTION
)
1164 m_eLoadState
= E_FAILED
;
1165 if( aEvent
.State
== css::frame::DispatchResultState::SUCCESS
)
1167 css::uno::Reference
< css::frame::XFrame
> xLastFrame
; /// last target of "loadComponentFromURL()"!
1168 if ( aEvent
.Result
>>= xLastFrame
)
1169 m_eLoadState
= E_SUCCESSFUL
;
1174 /*-************************************************************************************************************
1175 @interface XEventListener
1176 @short not implemented!
1177 @descr We are a status listener ... and so we must be an event listener too ... But we don't need it really!
1178 We are a temp. listener only and our lifetime isn't smaller then of our temp. used dispatcher.
1180 @seealso method loadComponentFromURL()
1181 *//*-*************************************************************************************************************/
1182 void SAL_CALL
Desktop::disposing( const css::lang::EventObject
& )
1184 SAL_WARN( "fwk.desktop", "Desktop::disposing(): Algorithm error! Normally desktop is temp. listener ... not all the time. So this method shouldn't be called." );
1187 /*-************************************************************************************************************
1188 @interface XInteractionHandler
1189 @short callback for loadComponentFromURL for detected exceptions during load process
1190 @descr In this case we must cancel loading and throw these detected exception again as result
1191 of our own called method.
1194 Normal loop in loadComponentFromURL() breaks on set member m_eLoadState during callback statusChanged().
1195 But these interaction feature implements second way to do so! So we must look on different callbacks
1196 for same operation ... and live with it.
1198 Search for given continuations too. If any XInteractionAbort exist ... use it to abort further operations
1199 for currently running operation!
1201 @seealso method loadComponentFromURL()
1202 @seealso member m_eLoadState
1204 @param "xRequest", request for interaction - normal a wrapped target exception from bottom services
1206 *//*-*************************************************************************************************************/
1207 void SAL_CALL
Desktop::handle( const css::uno::Reference
< css::task::XInteractionRequest
>& xRequest
)
1209 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1210 // Register transaction and reject wrong calls.
1211 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1213 // Don't check incoming request!
1214 // If somewhere starts interaction without right parameter - he made something wrong.
1215 // loadComponentFromURL() waits for these event - otherwise it yield for ever!
1217 // get packed request and work on it first
1218 // Attention: Don't set it on internal member BEFORE interaction is finished - because
1219 // "loadComponentFromURL()" yield tills this member is changed. If we do it before
1220 // interaction finish we can't guarantee right functionality. May be we cancel load process to earlier...
1221 css::uno::Any aRequest
= xRequest
->getRequest();
1223 // extract continuations from request
1224 css::uno::Sequence
< css::uno::Reference
< css::task::XInteractionContinuation
> > lContinuations
= xRequest
->getContinuations();
1225 css::uno::Reference
< css::task::XInteractionAbort
> xAbort
;
1226 css::uno::Reference
< css::task::XInteractionApprove
> xApprove
;
1227 css::uno::Reference
< css::document::XInteractionFilterSelect
> xFilterSelect
;
1228 bool bAbort
= false;
1230 sal_Int32 nCount
=lContinuations
.getLength();
1231 for( sal_Int32 nStep
=0; nStep
<nCount
; ++nStep
)
1234 xAbort
.set( lContinuations
[nStep
], css::uno::UNO_QUERY
);
1236 if( ! xApprove
.is() )
1237 xApprove
.set( lContinuations
[nStep
], css::uno::UNO_QUERY
);
1239 if( ! xFilterSelect
.is() )
1240 xFilterSelect
.set( lContinuations
[nStep
], css::uno::UNO_QUERY
);
1243 // differ between abortable interactions (error, unknown filter...)
1244 // and other ones (ambiguous but not unknown filter...)
1245 css::task::ErrorCodeRequest aErrorCodeRequest
;
1246 if( aRequest
>>= aErrorCodeRequest
)
1248 bool bWarning
= ErrCode(aErrorCodeRequest
.ErrCode
).IsWarning();
1249 if (xApprove
.is() && bWarning
)
1258 else if( xAbort
.is() )
1264 // Ok now it's time to break yield loop of loadComponentFromURL().
1265 // But only for really aborted requests!
1266 // For example warnings will be approved and we wait for any success story ...
1270 m_eLoadState
= E_INTERACTION
;
1274 ::sal_Int32 SAL_CALL
Desktop::leaseNumber( const css::uno::Reference
< css::uno::XInterface
>& xComponent
)
1276 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1277 return m_xTitleNumberGenerator
->leaseNumber (xComponent
);
1280 void SAL_CALL
Desktop::releaseNumber( ::sal_Int32 nNumber
)
1282 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1283 m_xTitleNumberGenerator
->releaseNumber (nNumber
);
1286 void SAL_CALL
Desktop::releaseNumberForComponent( const css::uno::Reference
< css::uno::XInterface
>& xComponent
)
1288 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1289 m_xTitleNumberGenerator
->releaseNumberForComponent (xComponent
);
1292 OUString SAL_CALL
Desktop::getUntitledPrefix()
1294 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1295 return m_xTitleNumberGenerator
->getUntitledPrefix ();
1298 /*-************************************************************************************************************
1299 @short try to convert a property value
1300 @descr This method is called from helperclass "OPropertySetHelper".
1301 Don't use this directly!
1302 You must try to convert the value of given PropHandle and
1303 return results of this operation. This will be used to ask vetoable
1304 listener. If no listener has a veto, we will change value really!
1305 ( in method setFastPropertyValue_NoBroadcast(...) )
1307 @attention Methods of OPropertySethelper are safed by using our shared osl mutex! (see ctor!)
1308 So we must use different locks to make our implementation threadsafe.
1310 @seealso class OPropertySetHelper
1311 @seealso method setFastPropertyValue_NoBroadcast()
1313 @param "aConvertedValue" new converted value of property
1314 @param "aOldValue" old value of property
1315 @param "nHandle" handle of property
1316 @param "aValue" new value of property
1317 @return sal_True if value will be changed, sal_FALSE otherway
1319 @onerror IllegalArgumentException, if you call this with an invalid argument
1321 *//*-*************************************************************************************************************/
1322 sal_Bool SAL_CALL
Desktop::convertFastPropertyValue( css::uno::Any
& aConvertedValue
,
1323 css::uno::Any
& aOldValue
,
1325 const css::uno::Any
& aValue
)
1327 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1328 // Register transaction and reject wrong calls.
1329 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1331 // Initialize state with sal_False !!!
1332 // (Handle can be invalid)
1333 bool bReturn
= false;
1337 case PropHandle::SuspendQuickstartVeto
:
1338 bReturn
= PropHelper::willPropertyBeChanged(
1339 css::uno::Any(m_bSuspendQuickstartVeto
),
1344 case PropHandle::DispatchRecorderSupplier
:
1345 bReturn
= PropHelper::willPropertyBeChanged(
1346 css::uno::Any(m_xDispatchRecorderSupplier
),
1351 case PropHandle::Title
:
1352 bReturn
= PropHelper::willPropertyBeChanged(
1353 css::uno::Any(m_sTitle
),
1360 // Return state of operation.
1364 /*-************************************************************************************************************
1365 @short set value of a transient property
1366 @descr This method is calling from helperclass "OPropertySetHelper".
1367 Don't use this directly!
1368 Handle and value are valid everyway! You must set the new value only.
1369 After this, baseclass send messages to all listener automatically.
1371 @seealso class OPropertySetHelper
1373 @param "nHandle" handle of property to change
1374 @param "aValue" new value of property
1375 @onerror An exception is thrown.
1377 *//*-*************************************************************************************************************/
1378 void SAL_CALL
Desktop::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
,
1379 const css::uno::Any
& aValue
)
1381 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1382 // Register transaction and reject wrong calls.
1383 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1387 case PropHandle::SuspendQuickstartVeto
: aValue
>>= m_bSuspendQuickstartVeto
;
1389 case PropHandle::DispatchRecorderSupplier
: aValue
>>= m_xDispatchRecorderSupplier
;
1391 case PropHandle::Title
: aValue
>>= m_sTitle
;
1396 /*-************************************************************************************************************
1397 @short get value of a transient property
1398 @descr This method is calling from helperclass "OPropertySetHelper".
1399 Don't use this directly!
1401 @attention We don't need any mutex or lock here ... We use threadsafe container or methods here only!
1403 @seealso class OPropertySetHelper
1405 @param "nHandle" handle of property to change
1406 @param "aValue" current value of property
1408 *//*-*************************************************************************************************************/
1409 void SAL_CALL
Desktop::getFastPropertyValue( css::uno::Any
& aValue
,
1410 sal_Int32 nHandle
) const
1412 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1413 // Register transaction and reject wrong calls.
1414 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1418 case PropHandle::ActiveFrame
: aValue
<<= m_aChildTaskContainer
.getActive();
1420 case PropHandle::IsPlugged
: aValue
<<= false;
1422 case PropHandle::SuspendQuickstartVeto
: aValue
<<= m_bSuspendQuickstartVeto
;
1424 case PropHandle::DispatchRecorderSupplier
: aValue
<<= m_xDispatchRecorderSupplier
;
1426 case PropHandle::Title
: aValue
<<= m_sTitle
;
1431 ::cppu::IPropertyArrayHelper
& SAL_CALL
Desktop::getInfoHelper()
1433 static cppu::OPropertyArrayHelper HELPER
=
1435 return cppu::OPropertyArrayHelper
{
1436 {{"ActiveFrame", PropHandle::ActiveFrame
,
1437 cppu::UnoType
<css::lang::XComponent
>::get(),
1438 (css::beans::PropertyAttribute::TRANSIENT
1439 | css::beans::PropertyAttribute::READONLY
)},
1440 {"DispatchRecorderSupplier",
1441 PropHandle::DispatchRecorderSupplier
,
1442 cppu::UnoType
<css::frame::XDispatchRecorderSupplier
>::get(),
1443 css::beans::PropertyAttribute::TRANSIENT
},
1445 PropHandle::IsPlugged
, cppu::UnoType
<bool>::get(),
1446 (css::beans::PropertyAttribute::TRANSIENT
1447 | css::beans::PropertyAttribute::READONLY
)},
1448 {"SuspendQuickstartVeto", PropHandle::SuspendQuickstartVeto
,
1449 cppu::UnoType
<bool>::get(),
1450 css::beans::PropertyAttribute::TRANSIENT
},
1451 {"Title", PropHandle::Title
, cppu::UnoType
<OUString
>::get(),
1452 css::beans::PropertyAttribute::TRANSIENT
}},
1458 /*-************************************************************************************************************
1459 @short return propertysetinfo
1460 @descr You can call this method to get information about transient properties
1463 @attention You must use global lock (method use static variable) ... and it must be the shareable osl mutex of it.
1464 Because; our baseclass use this mutex to make his code threadsafe. We use our lock!
1465 So we could have two different mutex/lock mechanism at the same object.
1467 @seealso class OPropertySetHelper
1468 @seealso interface XPropertySet
1469 @seealso interface XMultiPropertySet
1470 @return reference to object with information [XPropertySetInfo]
1472 *//*-*************************************************************************************************************/
1473 css::uno::Reference
< css::beans::XPropertySetInfo
> SAL_CALL
Desktop::getPropertySetInfo()
1475 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1476 // Register transaction and reject wrong calls.
1477 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1479 // Create structure of propertysetinfo for baseclass "OPropertySetHelper".
1480 // (Use method "getInfoHelper()".)
1481 static css::uno::Reference
< css::beans::XPropertySetInfo
> xInfo(
1482 cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ) );
1487 /*-************************************************************************************************************
1488 @short return current component of current frame
1489 @descr The desktop himself has no component. But every frame in subtree.
1490 If somewhere call getCurrentComponent() at this class, we try to find the right frame and
1491 then we try to become his component. It can be a VCL-component, the model or the controller
1494 @attention We don't work on internal member ... so we don't need any lock here.
1496 @seealso method getCurrentComponent();
1498 @param "xFrame", reference to valid frame in hierarchy. Method is not defined for invalid values.
1499 But we don't check these. It's an IMPL-method and caller must use it right!
1500 @return A reference to found component.
1502 @onerror A null reference is returned.
1504 *//*-*************************************************************************************************************/
1505 css::uno::Reference
< css::lang::XComponent
> Desktop::impl_getFrameComponent( const css::uno::Reference
< css::frame::XFrame
>& xFrame
) const
1507 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1508 // Register transaction and reject wrong calls.
1509 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1511 // Set default return value, if method failed.
1512 css::uno::Reference
< css::lang::XComponent
> xComponent
;
1513 // Does no controller exists?
1514 css::uno::Reference
< css::frame::XController
> xController
= xFrame
->getController();
1515 if( !xController
.is() )
1517 // Controller not exist - use the VCL-component.
1518 xComponent
= xFrame
->getComponentWindow();
1522 // Does no model exists?
1523 css::uno::Reference
< css::frame::XModel
> xModel
= xController
->getModel();
1526 // Model exist - use the model as component.
1527 xComponent
= xModel
;
1531 // Model not exist - use the controller as component.
1532 xComponent
= xController
;
1539 bool Desktop::impl_sendQueryTerminationEvent(Desktop::TTerminateListenerList
& lCalledListener
)
1541 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1543 comphelper::OInterfaceContainerHelper2
* pContainer
= m_aListenerContainer
.getContainer( cppu::UnoType
<css::frame::XTerminateListener
>::get());
1547 css::lang::EventObject
aEvent( static_cast< ::cppu::OWeakObject
* >(this) );
1549 comphelper::OInterfaceIteratorHelper2
aIterator( *pContainer
);
1550 while ( aIterator
.hasMoreElements() )
1554 css::uno::Reference
< css::frame::XTerminateListener
> xListener(aIterator
.next(), css::uno::UNO_QUERY
);
1555 if ( ! xListener
.is() )
1557 xListener
->queryTermination( aEvent
);
1558 lCalledListener
.push_back(xListener
);
1560 catch( const css::frame::TerminationVetoException
& )
1562 // first veto will stop the query loop.
1565 catch( const css::uno::Exception
& )
1567 // clean up container.
1568 // E.g. dead remote listener objects can make trouble otherwise.
1569 // Iterator implementation allows removing objects during it's used !
1577 void Desktop::impl_sendCancelTerminationEvent(const Desktop::TTerminateListenerList
& lCalledListener
)
1579 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1581 css::lang::EventObject
aEvent( static_cast< ::cppu::OWeakObject
* >(this) );
1582 for (const css::uno::Reference
<css::frame::XTerminateListener
>& xListener
: lCalledListener
)
1586 // Note: cancelTermination() is a new and optional interface method !
1587 css::uno::Reference
< css::frame::XTerminateListener2
> xListenerGeneration2(xListener
, css::uno::UNO_QUERY
);
1588 if ( ! xListenerGeneration2
.is() )
1590 xListenerGeneration2
->cancelTermination( aEvent
);
1592 catch( const css::uno::Exception
& )
1597 void Desktop::impl_sendTerminateToClipboard()
1599 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1601 comphelper::OInterfaceContainerHelper2
* pContainer
= m_aListenerContainer
.getContainer( cppu::UnoType
<css::frame::XTerminateListener
>::get());
1605 comphelper::OInterfaceIteratorHelper2
aIterator( *pContainer
);
1606 while ( aIterator
.hasMoreElements() )
1610 css::frame::XTerminateListener
* pTerminateListener
=
1611 static_cast< css::frame::XTerminateListener
* >(aIterator
.next());
1612 css::uno::Reference
< css::lang::XServiceInfo
> xInfo( pTerminateListener
, css::uno::UNO_QUERY
);
1616 if ( xInfo
->getImplementationName() != "com.sun.star.comp.svt.TransferableHelperTerminateListener" )
1619 css::lang::EventObject
aEvent( static_cast< ::cppu::OWeakObject
* >(this) );
1620 pTerminateListener
->notifyTermination( aEvent
);
1622 // don't notify twice
1625 catch( const css::uno::Exception
& )
1627 // clean up container.
1628 // E.g. dead remote listener objects can make trouble otherwise.
1629 // Iterator implementation allows removing objects during it's used !
1635 void Desktop::impl_sendNotifyTerminationEvent()
1637 TransactionGuard
aTransaction( m_aTransactionManager
, E_HARDEXCEPTIONS
);
1639 comphelper::OInterfaceContainerHelper2
* pContainer
= m_aListenerContainer
.getContainer( cppu::UnoType
<css::frame::XTerminateListener
>::get());
1643 css::lang::EventObject
aEvent( static_cast< ::cppu::OWeakObject
* >(this) );
1645 comphelper::OInterfaceIteratorHelper2
aIterator( *pContainer
);
1646 while ( aIterator
.hasMoreElements() )
1650 static_cast< css::frame::XTerminateListener
* >(aIterator
.next())->notifyTermination( aEvent
);
1652 catch( const css::uno::Exception
& )
1654 // clean up container.
1655 // E.g. dead remote listener objects can make trouble otherwise.
1656 // Iterator implementation allows removing objects during it's used !
1662 bool Desktop::impl_closeFrames(bool bAllowUI
)
1664 SolarMutexClearableGuard aReadLock
;
1665 css::uno::Sequence
< css::uno::Reference
< css::frame::XFrame
> > lFrames
= m_aChildTaskContainer
.getAllElements();
1668 ::sal_Int32 c
= lFrames
.getLength();
1670 ::sal_Int32 nNonClosedFrames
= 0;
1672 for( i
=0; i
<c
; ++i
)
1676 css::uno::Reference
< css::frame::XFrame
> xFrame
= lFrames
[i
];
1678 // XController.suspend() will show a UI ...
1679 // Use it in case it was allowed from outside only.
1680 bool bSuspended
= false;
1681 css::uno::Reference
< css::frame::XController
> xController
= xFrame
->getController();
1682 if ( bAllowUI
&& xController
.is() )
1684 bSuspended
= xController
->suspend( true );
1695 // Try to close frame (in case no UI was allowed without calling XController->suspend() before!)
1696 // But don't deliver ownership to any other one!
1697 // This method can be called again.
1698 css::uno::Reference
< css::util::XCloseable
> xClose( xFrame
, css::uno::UNO_QUERY
);
1703 xClose
->close(false);
1705 catch(const css::util::CloseVetoException
&)
1707 // Any internal process of this frame disagree with our request.
1708 // Safe this state but don't break these loop. Other frames has to be closed!
1711 // Reactivate controller.
1712 // It can happen that XController.suspend() returned true... but a registered close listener
1713 // threw these veto exception. Then the controller has to be reactivated. Otherwise
1714 // these document doesn't work any more.
1715 if ( bSuspended
&& xController
.is())
1716 xController
->suspend(false);
1719 // If interface XClosable interface exists and was used...
1720 // it's not allowed to use XComponent->dispose() also!
1724 // XClosable not supported ?
1725 // Then we have to dispose these frame hardly.
1729 // Don't remove these frame from our child container!
1730 // A frame do it by itself inside close()/dispose() method.
1732 catch(const css::lang::DisposedException
&)
1734 // Dispose frames are closed frames.
1735 // So we can count it here .-)
1739 // reset the session
1742 return (nNonClosedFrames
< 1);
1745 } // namespace framework
1749 rtl::Reference
<framework::Desktop
> createDesktop(
1750 css::uno::Reference
<css::uno::XComponentContext
> const & context
)
1752 SolarMutexGuard g
; // tdf#114025 init with SolarMutex to avoid deadlock
1753 rtl::Reference
<framework::Desktop
> desktop(new framework::Desktop(context
));
1754 desktop
->constructorInit();
1760 const rtl::Reference
<framework::Desktop
> & framework::getDesktop(
1761 css::uno::Reference
<css::uno::XComponentContext
> const & context
)
1763 static auto const instance
= createDesktop(context
);
1767 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
1768 com_sun_star_comp_framework_Desktop_get_implementation(
1769 css::uno::XComponentContext
*context
,
1770 css::uno::Sequence
<css::uno::Any
> const &)
1772 return cppu::acquire(framework::getDesktop(context
).get());
1775 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */