1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <services/desktop.hxx>
21
22 #include <loadenv/loadenv.hxx>
23 #include <loadenv/targethelper.hxx>
24
25 #include <helper/ocomponentaccess.hxx>
26 #include <helper/oframes.hxx>
27 #include <dispatch/dispatchprovider.hxx>
28
29 #include <dispatch/interceptionhelper.hxx>
30 #include <classes/taskcreator.hxx>
31 #include <threadhelp/transactionguard.hxx>
32 #include <general.h>
33 #include <properties.h>
34 #include <targets.h>
35
36 #include <strings.hrc>
37 #include <classes/fwkresid.hxx>
38
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/frame/FrameSearchFlag.hpp>
41 #include <com/sun/star/frame/TerminationVetoException.hpp>
42 #include <com/sun/star/awt/XWindow.hpp>
43 #include <com/sun/star/awt/XWindowPeer.hpp>
44 #include <com/sun/star/awt/WindowDescriptor.hpp>
45 #include <com/sun/star/awt/WindowAttribute.hpp>
46 #include <com/sun/star/awt/PosSize.hpp>
47 #include <com/sun/star/util/XURLTransformer.hpp>
48 #include <com/sun/star/task/XInteractionAbort.hpp>
49 #include <com/sun/star/task/XInteractionApprove.hpp>
50 #include <com/sun/star/document/XInteractionFilterSelect.hpp>
51 #include <com/sun/star/task/ErrorCodeRequest.hpp>
52 #include <com/sun/star/ucb/InteractiveIOException.hpp>
53 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
54 #include <com/sun/star/frame/DispatchResultState.hpp>
55 #include <com/sun/star/lang/IllegalArgumentException.hpp>
56 #include <com/sun/star/lang/DisposedException.hpp>
57 #include <com/sun/star/util/CloseVetoException.hpp>
58 #include <com/sun/star/util/XCloseable.hpp>
59 #include <com/sun/star/document/MacroExecMode.hpp>
60 #include <com/sun/star/document/UpdateDocMode.hpp>
61 #include <com/sun/star/frame/XTerminateListener2.hpp>
62
63 #include <comphelper/numberedcollection.hxx>
64 #include <comphelper/sequence.hxx>
65 #include <comphelper/lok.hxx>
66 #include <cppuhelper/supportsservice.hxx>
67 #include <rtl/instance.hxx>
68 #include <vcl/svapp.hxx>
69 #include <desktop/crashreport.hxx>
70 #include <vcl/scheduler.hxx>
71 #include <sal/log.hxx>
72 #include <rtl/ustrbuf.hxx>
73
74 #include <vcl/errinf.hxx>
75 #include <unotools/configmgr.hxx>
76
77 namespace framework{
78
79 enum PropHandle {
80 ActiveFrame, DispatchRecorderSupplier, IsPlugged, SuspendQuickstartVeto,
81 Title };
82
getImplementationName()83 OUString SAL_CALL Desktop::getImplementationName()
84 {
85 return "com.sun.star.comp.framework.Desktop";
86 }
87
supportsService(OUString const & ServiceName)88 sal_Bool SAL_CALL Desktop::supportsService(OUString const & ServiceName)
89 {
90 return cppu::supportsService(this, ServiceName);
91 }
92
getSupportedServiceNames()93 css::uno::Sequence<OUString> SAL_CALL Desktop::getSupportedServiceNames()
94 {
95 return { "com.sun.star.frame.Desktop" };
96 }
97
constructorInit()98 void Desktop::constructorInit()
99 {
100 // Initialize a new XFrames-helper-object to handle XIndexAccess and XElementAccess.
101 // We hold member as reference ... not as pointer too!
102 // Attention: We share our frame container with this helper. Container is threadsafe himself ... So I think we can do that.
103 // But look on dispose() for right order of deinitialization.
104 OFrames* pFramesHelper = new OFrames( this, &m_aChildTaskContainer );
105 m_xFramesHelper.set( static_cast< ::cppu::OWeakObject* >(pFramesHelper), css::uno::UNO_QUERY );
106
107 // Initialize a new dispatchhelper-object to handle dispatches.
108 // We use these helper as slave for our interceptor helper ... not directly!
109 // But he is event listener on THIS instance!
110 DispatchProvider* pDispatchHelper = new DispatchProvider( m_xContext, this );
111 css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( static_cast< ::cppu::OWeakObject* >(pDispatchHelper), css::uno::UNO_QUERY );
112
113 // Initialize a new interception helper object to handle dispatches and implement an interceptor mechanism.
114 // Set created dispatch provider as slowest slave of it.
115 // Hold interception helper by reference only - not by pointer!
116 // So it's easier to destroy it.
117 InterceptionHelper* pInterceptionHelper = new InterceptionHelper( this, xDispatchProvider );
118 m_xDispatchHelper.set( static_cast< ::cppu::OWeakObject* >(pInterceptionHelper), css::uno::UNO_QUERY );
119
120 OUString sUntitledPrefix = FwkResId(STR_UNTITLED_DOCUMENT) + " ";
121
122 ::comphelper::NumberedCollection* pNumbers = new ::comphelper::NumberedCollection ();
123 m_xTitleNumberGenerator.set(static_cast< ::cppu::OWeakObject* >(pNumbers), css::uno::UNO_QUERY_THROW);
124 pNumbers->setOwner ( static_cast< ::cppu::OWeakObject* >(this) );
125 pNumbers->setUntitledPrefix ( sUntitledPrefix );
126
127 // Safe impossible cases
128 // We can't work without this helper!
129 SAL_WARN_IF( !m_xFramesHelper.is(), "fwk.desktop", "Desktop::Desktop(): Frames helper is not valid. XFrames, XIndexAccess and XElementAccess are not supported!");
130 SAL_WARN_IF( !m_xDispatchHelper.is(), "fwk.desktop", "Desktop::Desktop(): Dispatch helper is not valid. XDispatch will not work correctly!" );
131
132 // Enable object for real working!
133 // Otherwise all calls will be rejected ...
134 m_aTransactionManager.setWorkingMode( E_WORK );
135 }
136
137 /*-************************************************************************************************************
138 @short standard constructor to create instance by factory
139 @descr This constructor initialize a new instance of this class by valid factory,
140 and will be set valid values on his member and baseclasses.
141
142 @attention a) Don't use your own reference during a UNO-Service-ctor! There is no guarantee, that you
143 will get over this. (e.g. using of your reference as parameter to initialize some member)
144 Do such things in DEFINE_INIT_SERVICE() method, which is called automatically after your ctor!!!
145 b) Baseclass OBroadcastHelper is a typedef in namespace cppu!
146 The microsoft compiler has some problems to handle it right BY using namespace explicitly ::cppu::OBroadcastHelper.
147 If we write it without a namespace or expand the typedef to OBroadcastHelperVar<...> -> it will be OK!?
148 I don't know why! (other compiler not tested .. but it works!)
149
150 @seealso method DEFINE_INIT_SERVICE()
151
152 @param "xFactory" is the multi service manager, which create this instance.
153 The value must be different from NULL!
154 @onerror We throw an ASSERT in debug version or do nothing in release version.
155 *//*-*************************************************************************************************************/
Desktop(const css::uno::Reference<css::uno::XComponentContext> & xContext)156 Desktop::Desktop( const css::uno::Reference< css::uno::XComponentContext >& xContext )
157 : TransactionBase ( )
158 , Desktop_BASE ( m_aMutex )
159 , cppu::OPropertySetHelper( cppu::WeakComponentImplHelperBase::rBHelper )
160 // Init member
161 , m_bIsTerminated ( false ) // see dispose() for further information!
162 , m_bSession ( false )
163 , m_xContext ( xContext )
164 , m_aChildTaskContainer ( )
165 , m_aListenerContainer ( m_aMutex )
166 , m_xFramesHelper ( )
167 , m_xDispatchHelper ( )
168 , m_eLoadState ( E_NOTSET )
169 , m_bSuspendQuickstartVeto( false )
170 , m_sName ( )
171 , m_sTitle ( )
172 , m_xDispatchRecorderSupplier( )
173 , m_xPipeTerminator ( )
174 , m_xQuickLauncher ( )
175 , m_xStarBasicQuitGuard ( )
176 , m_xSWThreadManager ( )
177 , m_xSfxTerminator ( )
178 , m_xTitleNumberGenerator ( )
179 {
180 }
181
182 /*-************************************************************************************************************
183 @short standard destructor
184 @descr This one do NOTHING! Use dispose() instead of this.
185
186 @seealso method dispose()
187 *//*-*************************************************************************************************************/
~Desktop()188 Desktop::~Desktop()
189 {
190 SAL_WARN_IF( !m_bIsTerminated, "fwk.desktop", "Desktop not terminated before being destructed" );
191 SAL_WARN_IF( m_aTransactionManager.getWorkingMode()!=E_CLOSE, "fwk.desktop", "Desktop::~Desktop(): Who forgot to dispose this service?" );
192 }
193
queryInterface(const css::uno::Type & _rType)194 css::uno::Any SAL_CALL Desktop::queryInterface( const css::uno::Type& _rType )
195 {
196 css::uno::Any aRet = Desktop_BASE::queryInterface( _rType );
197 if ( !aRet.hasValue() )
198 aRet = OPropertySetHelper::queryInterface( _rType );
199 return aRet;
200 }
201
getTypes()202 css::uno::Sequence< css::uno::Type > SAL_CALL Desktop::getTypes( )
203 {
204 return comphelper::concatSequences(
205 Desktop_BASE::getTypes(),
206 ::cppu::OPropertySetHelper::getTypes()
207 );
208 }
209
terminate()210 sal_Bool SAL_CALL Desktop::terminate()
211 {
212 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
213
214 SolarMutexClearableGuard aReadLock;
215
216 css::uno::Reference< css::frame::XTerminateListener > xPipeTerminator = m_xPipeTerminator;
217 css::uno::Reference< css::frame::XTerminateListener > xQuickLauncher = m_xQuickLauncher;
218 css::uno::Reference< css::frame::XTerminateListener > xStarBasicQuitGuard = m_xStarBasicQuitGuard;
219 css::uno::Reference< css::frame::XTerminateListener > xSWThreadManager = m_xSWThreadManager;
220 css::uno::Reference< css::frame::XTerminateListener > xSfxTerminator = m_xSfxTerminator;
221
222 css::lang::EventObject aEvent ( static_cast< ::cppu::OWeakObject* >(this) );
223 bool bAskQuickStart = !m_bSuspendQuickstartVeto;
224
225 aReadLock.clear();
226
227 // try to close all open frames.
228 // Allow using of any UI ... because Desktop.terminate() was designed as UI functionality in the past.
229 bool bRestartableMainLoop = Application::IsEventTestingModeEnabled() ||
230 comphelper::LibreOfficeKit::isActive();
231 bool bFramesClosed = impl_closeFrames(!bRestartableMainLoop);
232
233 // Ask normal terminate listener. They could stop terminating the process.
234 Desktop::TTerminateListenerList lCalledTerminationListener;
235 bool bVeto = false;
236 impl_sendQueryTerminationEvent(lCalledTerminationListener, bVeto);
237 if ( bVeto )
238 {
239 impl_sendCancelTerminationEvent(lCalledTerminationListener);
240 return false;
241 }
242
243 if (bRestartableMainLoop)
244 {
245 #ifndef IOS // or ANDROID?
246 // In the iOS app, posting the ImplQuitMsg user event will be too late, it will not be handled during the
247 // lifetime of the current document, but handled for the next document opened, which thus will break horribly.
248 Application::Quit();
249 #endif
250 return true;
251 }
252 if ( ! bFramesClosed )
253 {
254 impl_sendCancelTerminationEvent(lCalledTerminationListener);
255 return false;
256 }
257
258 // Normal listener had no problem ...
259 // all frames was closed ...
260 // now it's time to ask our specialized listener.
261 // They are handled these way because they wish to hinder the office on termination
262 // but they wish also closing of all frames.
263
264 // Note further:
265 // We shouldn't ask quicklauncher in case it was allowed from outside only.
266 // This is special trick to "ignore existing quick starter" for debug purposes.
267
268 // Attention:
269 // Order of called listener is important!
270 // Some of them are harmless,-)
271 // but some can be dangerous. E.g. it would be dangerous if we close our pipe
272 // and don't terminate in real because another listener throws a veto exception .-)
273
274 bool bTerminate = false;
275 try
276 {
277 if( bAskQuickStart && xQuickLauncher.is() )
278 {
279 xQuickLauncher->queryTermination( aEvent );
280 lCalledTerminationListener.push_back( xQuickLauncher );
281 }
282
283 if ( xStarBasicQuitGuard.is() )
284 {
285 xStarBasicQuitGuard->queryTermination( aEvent );
286 lCalledTerminationListener.push_back( xStarBasicQuitGuard );
287 }
288
289 if ( xSWThreadManager.is() )
290 {
291 xSWThreadManager->queryTermination( aEvent );
292 lCalledTerminationListener.push_back( xSWThreadManager );
293 }
294
295 if ( xPipeTerminator.is() )
296 {
297 xPipeTerminator->queryTermination( aEvent );
298 lCalledTerminationListener.push_back( xPipeTerminator );
299 }
300
301 if ( xSfxTerminator.is() )
302 {
303 xSfxTerminator->queryTermination( aEvent );
304 lCalledTerminationListener.push_back( xSfxTerminator );
305 }
306
307 bTerminate = true;
308 }
309 catch(const css::frame::TerminationVetoException&)
310 {
311 bTerminate = false;
312 }
313
314 if ( ! bTerminate )
315 impl_sendCancelTerminationEvent(lCalledTerminationListener);
316 else
317 {
318 // "Protect" us against dispose before terminate calls!
319 // see dispose() for further information.
320 /* SAFE AREA --------------------------------------------------------------------------------------- */
321 SolarMutexClearableGuard aWriteLock;
322 CrashReporter::addKeyValue("ShutDown", OUString::boolean(true), CrashReporter::Write);
323 m_bIsTerminated = true;
324 aWriteLock.clear();
325 /* UNSAFE AREA ------------------------------------------------------------------------------------- */
326
327 // The clipboard listener needs to be the first. It can create copies of the
328 // existing document which needs basically all the available infrastructure.
329 {
330 SolarMutexResettableGuard aGuard;
331 impl_sendTerminateToClipboard();
332 aGuard.clear();
333 impl_sendNotifyTerminationEvent();
334 aGuard.reset();
335 Scheduler::ProcessEventsToIdle();
336 }
337
338 if( bAskQuickStart && xQuickLauncher.is() )
339 {
340 xQuickLauncher->notifyTermination( aEvent );
341 }
342
343 if ( xStarBasicQuitGuard.is() )
344 xStarBasicQuitGuard->notifyTermination( aEvent );
345
346 if ( xSWThreadManager.is() )
347 xSWThreadManager->notifyTermination( aEvent );
348
349 if ( xPipeTerminator.is() )
350 xPipeTerminator->notifyTermination( aEvent );
351
352 // we need a copy here as the notifyTermination call might cause a removeTerminateListener call
353 std::vector< css::uno::Reference<css::frame::XTerminateListener> > xComponentDllListeners = m_xComponentDllListeners;
354 for (auto& xListener : xComponentDllListeners)
355 {
356 xListener->notifyTermination(aEvent);
357 }
358 m_xComponentDllListeners.clear();
359
360 // Must be really the last listener to be called.
361 // Because it shutdown the whole process asynchronous !
362 if ( xSfxTerminator.is() )
363 xSfxTerminator->notifyTermination( aEvent );
364 }
365
366 return bTerminate;
367 }
368
369 namespace
370 {
371 class QuickstartSuppressor
372 {
373 Desktop* const m_pDesktop;
374 css::uno::Reference< css::frame::XTerminateListener > m_xQuickLauncher;
375 public:
QuickstartSuppressor(Desktop * const pDesktop,css::uno::Reference<css::frame::XTerminateListener> const & xQuickLauncher)376 QuickstartSuppressor(Desktop* const pDesktop, css::uno::Reference< css::frame::XTerminateListener > const & xQuickLauncher)
377 : m_pDesktop(pDesktop)
378 , m_xQuickLauncher(xQuickLauncher)
379 {
380 SAL_INFO("fwk.desktop", "temporary removing Quickstarter");
381 if(m_xQuickLauncher.is())
382 m_pDesktop->removeTerminateListener(m_xQuickLauncher);
383 }
~QuickstartSuppressor()384 ~QuickstartSuppressor()
385 {
386 SAL_INFO("fwk.desktop", "readding Quickstarter");
387 if(m_xQuickLauncher.is())
388 m_pDesktop->addTerminateListener(m_xQuickLauncher);
389 }
390 };
391 }
392
terminateQuickstarterToo()393 bool Desktop::terminateQuickstarterToo()
394 {
395 QuickstartSuppressor aQuickstartSuppressor(this, m_xQuickLauncher);
396 m_bSession = true;
397 return terminate();
398 }
399
addTerminateListener(const css::uno::Reference<css::frame::XTerminateListener> & xListener)400 void SAL_CALL Desktop::addTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener )
401 {
402 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
403
404 css::uno::Reference< css::lang::XServiceInfo > xInfo( xListener, css::uno::UNO_QUERY );
405 if ( xInfo.is() )
406 {
407 OUString sImplementationName = xInfo->getImplementationName();
408
409 SolarMutexGuard g;
410
411 if( sImplementationName == "com.sun.star.comp.sfx2.SfxTerminateListener" )
412 {
413 m_xSfxTerminator = xListener;
414 return;
415 }
416 if( sImplementationName == "com.sun.star.comp.RequestHandlerController" )
417 {
418 m_xPipeTerminator = xListener;
419 return;
420 }
421 if( sImplementationName == "com.sun.star.comp.desktop.QuickstartWrapper" )
422 {
423 m_xQuickLauncher = xListener;
424 return;
425 }
426 if( sImplementationName == "com.sun.star.comp.svx.StarBasicQuitGuard" )
427 {
428 m_xStarBasicQuitGuard = xListener;
429 return;
430 }
431 if( sImplementationName == "com.sun.star.util.comp.FinalThreadManager" )
432 {
433 m_xSWThreadManager = xListener;
434 return;
435 }
436 else if ( sImplementationName == "com.sun.star.comp.ComponentDLLListener" )
437 {
438 m_xComponentDllListeners.push_back(xListener);
439 return;
440 }
441 }
442
443 // No lock required... container is threadsafe by itself.
444 m_aListenerContainer.addInterface( cppu::UnoType<css::frame::XTerminateListener>::get(), xListener );
445 }
446
removeTerminateListener(const css::uno::Reference<css::frame::XTerminateListener> & xListener)447 void SAL_CALL Desktop::removeTerminateListener( const css::uno::Reference< css::frame::XTerminateListener >& xListener )
448 {
449 TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
450
451 css::uno::Reference< css::lang::XServiceInfo > xInfo( xListener, css::uno::UNO_QUERY );
452 if ( xInfo.is() )
453 {
454 OUString sImplementationName = xInfo->getImplementationName();
455
456 SolarMutexGuard g;
457
458 if( sImplementationName == "com.sun.star.comp.sfx2.SfxTerminateListener" )
459 {
460 m_xSfxTerminator.clear();
461 return;
462 }
463
464 if( sImplementationName == "com.sun.star.comp.RequestHandlerController" )
465 {
466 m_xPipeTerminator.clear();
467 return;
468 }
469
470 if( sImplementationName == "com.sun.star.comp.desktop.QuickstartWrapper" )
471 {
472 m_xQuickLauncher.clear();
473 return;
474 }
475
476 if( sImplementationName == "com.sun.star.comp.svx.StarBasicQuitGuard" )
477 {
478 m_xStarBasicQuitGuard.clear();
479 return;
480 }
481
482 if( sImplementationName == "com.sun.star.util.comp.FinalThreadManager" )
483 {
484 m_xSWThreadManager.clear();
485 return;
486 }
487 else if (sImplementationName == "com.sun.star.comp.ComponentDLLListener")
488 {
489 m_xComponentDllListeners.erase(
490 std::remove(m_xComponentDllListeners.begin(), m_xComponentDllListeners.end(), xListener),
491 m_xComponentDllListeners.end());
492 return;
493 }
494 }
495
496 // No lock required ... container is threadsafe by itself.
497 m_aListenerContainer.removeInterface( cppu::UnoType<css::frame::XTerminateListener>::get(), xListener );
498 }
499
500 /*-************************************************************************************************************
501 @interface XDesktop
502 @short get access to create enumerations of all current components
503 @descr You will be the owner of the returned object and must delete it if you don't use it again.
504
505 @seealso class TasksAccess
506 @seealso class TasksEnumeration
507 @return A reference to an XEnumerationAccess-object.
508
509 @onerror We return a null-reference.
510 @threadsafe yes
511 *//*-*************************************************************************************************************/
getComponents()512 css::uno::Reference< css::container::XEnumerationAccess > SAL_CALL Desktop::getComponents()
513 {
514 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
515 // Register transaction and reject wrong calls.
516 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
517
518 // We use a helper class OComponentAccess to have access on all child components.
519 // Create it on demand and return it as a reference.
520 OComponentAccess* pAccess = new OComponentAccess( this );
521 css::uno::Reference< css::container::XEnumerationAccess > xAccess( static_cast< ::cppu::OWeakObject* >(pAccess), css::uno::UNO_QUERY );
522 return xAccess;
523 }
524
525 /*-************************************************************************************************************
526 @interface XDesktop
527 @short return the current active component
528 @descr The most current component is the window, model or the controller of the current active frame.
529
530 @seealso method getCurrentFrame()
531 @seealso method impl_getFrameComponent()
532 @return A reference to the component.
533
534 @onerror We return a null-reference.
535 @threadsafe yes
536 *//*-*************************************************************************************************************/
getCurrentComponent()537 css::uno::Reference< css::lang::XComponent > SAL_CALL Desktop::getCurrentComponent()
538 {
539 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
540 // Register transaction and reject wrong calls.
541 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
542
543 // Set return value if method failed.
544 css::uno::Reference< css::lang::XComponent > xComponent;
545
546 // Get reference to current frame ...
547 // ... get component of this frame ... (It can be the window, the model or the controller.)
548 // ... and return the result.
549 css::uno::Reference< css::frame::XFrame > xCurrentFrame = getCurrentFrame();
550 if( xCurrentFrame.is() )
551 {
552 xComponent = impl_getFrameComponent( xCurrentFrame );
553 }
554 return xComponent;
555 }
556
557 /*-************************************************************************************************************
558 @interface XDesktop
559 @short return the current active frame in hierarchy
560 @descr There can be more than one different active paths in our frame hierarchy. But only one of them
561 could be the most active frame (normal he has the focus).
562 Don't mix it with getActiveFrame()! That will return our current active frame, which must be
563 a direct child of us and should be a part(!) of an active path.
564
565 @seealso method getActiveFrame()
566 @return A valid reference, if there is an active frame.
567 A null reference , otherwise.
568
569 @onerror We return a null reference.
570 @threadsafe yes
571 *//*-*************************************************************************************************************/
getCurrentFrame()572 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::getCurrentFrame()
573 {
574 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
575 // Register transaction and reject wrong calls.
576 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
577
578 // Start search with our direct active frame (if it exist!).
579 // Search on his children for other active frames too.
580 // Stop if no one could be found and return last of found ones.
581 css::uno::Reference< css::frame::XFramesSupplier > xLast( getActiveFrame(), css::uno::UNO_QUERY );
582 if( xLast.is() )
583 {
584 css::uno::Reference< css::frame::XFramesSupplier > xNext( xLast->getActiveFrame(), css::uno::UNO_QUERY );
585 while( xNext.is() )
586 {
587 xLast = xNext;
588 xNext.set( xNext->getActiveFrame(), css::uno::UNO_QUERY );
589 }
590 }
591 return xLast;
592 }
593
594 /*-************************************************************************************************************
595 @interface XComponentLoader
596 @short try to load given URL into a task
597 @descr You can give us some information about the content, which you will load into a frame.
598 We search or create this target for you, make a type detection of given URL and try to load it.
599 As result of this operation we return the new created component or nothing, if loading failed.
600 @param "sURL" , URL, which represent the content
601 @param "sTargetFrameName" , name of target frame or special value like "_self", "_blank" ...
602 @param "nSearchFlags" , optional arguments for frame search, if target isn't a special one
603 @param "lArguments" , optional arguments for loading
604 @return A valid component reference, if loading was successful.
605 A null reference otherwise.
606
607 @onerror We return a null reference.
608 @threadsafe yes
609 *//*-*************************************************************************************************************/
loadComponentFromURL(const OUString & sURL,const OUString & sTargetFrameName,sal_Int32 nSearchFlags,const css::uno::Sequence<css::beans::PropertyValue> & lArguments)610 css::uno::Reference< css::lang::XComponent > SAL_CALL Desktop::loadComponentFromURL( const OUString& sURL ,
611 const OUString& sTargetFrameName,
612 sal_Int32 nSearchFlags ,
613 const css::uno::Sequence< css::beans::PropertyValue >& lArguments )
614 {
615 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
616 // Register transaction and reject wrong calls.
617 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
618 SAL_INFO( "fwk.desktop", "loadComponentFromURL" );
619
620 css::uno::Reference< css::frame::XComponentLoader > xThis(static_cast< css::frame::XComponentLoader* >(this), css::uno::UNO_QUERY);
621
622 return LoadEnv::loadComponentFromURL(xThis, m_xContext, sURL, sTargetFrameName, nSearchFlags, lArguments);
623 }
624
625 /*-************************************************************************************************************
626 @interface XTasksSupplier
627 @short get access to create enumerations of our taskchildren
628 @descr Direct children of desktop are tasks every time.
629 Call these method to could create enumerations of it.
630
631 But; Don't forget - you will be the owner of returned object and must release it!
632 We use a helper class to implement the access interface. They hold a weakreference to us.
633 It can be, that the desktop is dead - but not your tasksaccess-object! Then they will do nothing!
634 You can't create enumerations then.
635
636 @attention Normally we don't need any lock here. We don't work on internal member!
637
638 @seealso class TasksAccess
639 @return A reference to an accessobject, which can create enumerations of our childtasks.
640
641 @onerror A null reference is returned.
642 @threadsafe yes
643 *//*-*************************************************************************************************************/
getTasks()644 css::uno::Reference< css::container::XEnumerationAccess > SAL_CALL Desktop::getTasks()
645 {
646 SAL_INFO("fwk.desktop", "Desktop::getTasks(): Use of obsolete interface XTaskSupplier");
647 return nullptr;
648 }
649
650 /*-************************************************************************************************************
651 @interface XTasksSupplier
652 @short return current active task of our direct children
653 @descr Desktop children are tasks only ! If we have an active path from desktop
654 as top to any frame on bottom, we must have an active direct child. His reference is returned here.
655
656 @attention a) Do not confuse it with getCurrentFrame()! The current frame don't must one of our direct children.
657 It can be every frame in subtree and must have the focus (Is the last one of an active path!).
658 b) We don't need any lock here. Our container is threadsafe himself and live, if we live!
659
660 @seealso method getCurrentFrame()
661 @return A reference to our current active taskchild.
662
663 @onerror A null reference is returned.
664 @threadsafe yes
665 *//*-*************************************************************************************************************/
getActiveTask()666 css::uno::Reference< css::frame::XTask > SAL_CALL Desktop::getActiveTask()
667 {
668 SAL_INFO("fwk.desktop", "Desktop::getActiveTask(): Use of obsolete interface XTaskSupplier");
669 return nullptr;
670 }
671
672 /*-************************************************************************************************************
673 @interface XDispatchProvider
674 @short search a dispatcher for given URL
675 @descr We use a helper implementation (class DispatchProvider) to do so.
676 So we don't must implement this algorithm twice!
677
678 @attention We don't need any lock here. Our helper is threadsafe himself and live, if we live!
679
680 @seealso class DispatchProvider
681
682 @param "aURL" , URL to dispatch
683 @param "sTargetFrameName" , name of target frame, who should dispatch these URL
684 @param "nSearchFlags" , flags to regulate the search
685 @param "lQueries" , list of queryDispatch() calls!
686 @return A reference or list of founded dispatch objects for these URL.
687
688 @onerror A null reference is returned.
689 @threadsafe yes
690 *//*-*************************************************************************************************************/
queryDispatch(const css::util::URL & aURL,const OUString & sTargetFrameName,sal_Int32 nSearchFlags)691 css::uno::Reference< css::frame::XDispatch > SAL_CALL Desktop::queryDispatch( const css::util::URL& aURL ,
692 const OUString& sTargetFrameName ,
693 sal_Int32 nSearchFlags )
694 {
695 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
696 // Register transaction and reject wrong calls.
697 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
698
699 // Remove uno and cmd protocol part as we want to support both of them. We store only the command part
700 // in our hash map. All other protocols are stored with the protocol part.
701 OUString aCommand( aURL.Main );
702 if ( aURL.Protocol.equalsIgnoreAsciiCase(".uno:") )
703 aCommand = aURL.Path;
704
705 if (!m_xCommandOptions && !utl::ConfigManager::IsFuzzing())
706 m_xCommandOptions.reset(new SvtCommandOptions);
707
708 // Make std::unordered_map lookup if the current URL is in the disabled list
709 if (m_xCommandOptions && m_xCommandOptions->Lookup(SvtCommandOptions::CMDOPTION_DISABLED, aCommand))
710 return css::uno::Reference< css::frame::XDispatch >();
711 else
712 {
713 // We use a helper to support these interface and an interceptor mechanism.
714 // Our helper is threadsafe by himself!
715 return m_xDispatchHelper->queryDispatch( aURL, sTargetFrameName, nSearchFlags );
716 }
717 }
718
queryDispatches(const css::uno::Sequence<css::frame::DispatchDescriptor> & lQueries)719 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL Desktop::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lQueries )
720 {
721 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
722 // Register transaction and reject wrong calls.
723 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
724
725 return m_xDispatchHelper->queryDispatches( lQueries );
726 }
727
728 /*-************************************************************************************************************
729 @interface XDispatchProviderInterception
730 @short supports registration/deregistration of interception objects, which
731 are interested on special dispatches.
732
733 @descr It's really provided by an internal helper, which is used inside the dispatch API too.
734 @param xInterceptor
735 the interceptor object, which wishes to be (de)registered.
736
737 @threadsafe yes
738 *//*-*************************************************************************************************************/
registerDispatchProviderInterceptor(const css::uno::Reference<css::frame::XDispatchProviderInterceptor> & xInterceptor)739 void SAL_CALL Desktop::registerDispatchProviderInterceptor( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor)
740 {
741 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
742
743 css::uno::Reference< css::frame::XDispatchProviderInterception > xInterceptionHelper( m_xDispatchHelper, css::uno::UNO_QUERY );
744 xInterceptionHelper->registerDispatchProviderInterceptor( xInterceptor );
745 }
746
releaseDispatchProviderInterceptor(const css::uno::Reference<css::frame::XDispatchProviderInterceptor> & xInterceptor)747 void SAL_CALL Desktop::releaseDispatchProviderInterceptor ( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor)
748 {
749 TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
750
751 css::uno::Reference< css::frame::XDispatchProviderInterception > xInterceptionHelper( m_xDispatchHelper, css::uno::UNO_QUERY );
752 xInterceptionHelper->releaseDispatchProviderInterceptor( xInterceptor );
753 }
754
755 /*-************************************************************************************************************
756 @interface XFramesSupplier
757 @short return access to append or remove children on desktop
758 @descr We don't implement these interface directly. We use a helper class to do this.
759 If you wish to add or delete children to/from the container, call these method to get
760 a reference to the helper.
761
762 @attention Helper is threadsafe himself. So we don't need any lock here.
763
764 @seealso class OFrames
765 @return A reference to the helper.
766
767 @onerror A null reference is returned.
768 @threadsafe yes
769 *//*-*************************************************************************************************************/
getFrames()770 css::uno::Reference< css::frame::XFrames > SAL_CALL Desktop::getFrames()
771 {
772 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
773 // Register transaction and reject wrong calls.
774 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
775
776 return m_xFramesHelper;
777 }
778
779 /*-************************************************************************************************************
780 @interface XFramesSupplier
781 @short set/get the current active child frame
782 @descr It must be a task. Direct children of desktop are tasks only! No frames are accepted.
783 We don't save this information directly in this class. We use our container-helper
784 to do that.
785
786 @attention Helper is threadsafe himself. So we don't need any lock here.
787
788 @seealso class OFrameContainer
789
790 @param "xFrame", new active frame (must be valid!)
791 @return A reference to our current active childtask, if anyone exist.
792
793 @onerror A null reference is returned.
794 @threadsafe yes
795 *//*-*************************************************************************************************************/
setActiveFrame(const css::uno::Reference<css::frame::XFrame> & xFrame)796 void SAL_CALL Desktop::setActiveFrame( const css::uno::Reference< css::frame::XFrame >& xFrame )
797 {
798 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
799 // Register transaction and reject wrong calls.
800 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
801
802 // Get old active frame first.
803 // If nothing will change - do nothing!
804 // Otherwise set new active frame ...
805 // and deactivate last frame.
806 // It's necessary for our FrameActionEvent listener on a frame!
807 css::uno::Reference< css::frame::XFrame > xLastActiveChild = m_aChildTaskContainer.getActive();
808 if( xLastActiveChild != xFrame )
809 {
810 m_aChildTaskContainer.setActive( xFrame );
811 if( xLastActiveChild.is() )
812 {
813 xLastActiveChild->deactivate();
814 }
815 }
816 }
817
getActiveFrame()818 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::getActiveFrame()
819 {
820 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
821 // Register transaction and reject wrong calls.
822 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
823
824 return m_aChildTaskContainer.getActive();
825 }
826
827 /*
828 @interface XFrame
829 @short non implemented methods!
830 @descr Some method make no sense for our desktop! He has no window or parent or ...
831 So we should implement it empty and warn programmer, if he use it!
832 */
initialize(const css::uno::Reference<css::awt::XWindow> &)833 void SAL_CALL Desktop::initialize( const css::uno::Reference< css::awt::XWindow >& )
834 {
835 }
836
getContainerWindow()837 css::uno::Reference< css::awt::XWindow > SAL_CALL Desktop::getContainerWindow()
838 {
839 return css::uno::Reference< css::awt::XWindow >();
840 }
841
setCreator(const css::uno::Reference<css::frame::XFramesSupplier> &)842 void SAL_CALL Desktop::setCreator( const css::uno::Reference< css::frame::XFramesSupplier >& /*xCreator*/ )
843 {
844 }
845
getCreator()846 css::uno::Reference< css::frame::XFramesSupplier > SAL_CALL Desktop::getCreator()
847 {
848 return css::uno::Reference< css::frame::XFramesSupplier >();
849 }
850
getName()851 OUString SAL_CALL Desktop::getName()
852 {
853 SolarMutexGuard g;
854 return m_sName;
855 }
856
setName(const OUString & sName)857 void SAL_CALL Desktop::setName( const OUString& sName )
858 {
859 SolarMutexGuard g;
860 m_sName = sName;
861 }
862
isTop()863 sal_Bool SAL_CALL Desktop::isTop()
864 {
865 return true;
866 }
867
activate()868 void SAL_CALL Desktop::activate()
869 {
870 // Desktop is active always... but sometimes our frames try to activate
871 // the complete path from bottom to top... And our desktop is the topest frame :-(
872 // So - please don't show any assertions here. Do nothing!
873 }
874
deactivate()875 void SAL_CALL Desktop::deactivate()
876 {
877 // Desktop is active always... but sometimes our frames try to deactivate
878 // the complete path from bottom to top... And our desktop is the topest frame :-(
879 // So - please don't show any assertions here. Do nothing!
880 }
881
isActive()882 sal_Bool SAL_CALL Desktop::isActive()
883 {
884 return true;
885 }
886
setComponent(const css::uno::Reference<css::awt::XWindow> &,const css::uno::Reference<css::frame::XController> &)887 sal_Bool SAL_CALL Desktop::setComponent( const css::uno::Reference< css::awt::XWindow >& /*xComponentWindow*/ ,
888 const css::uno::Reference< css::frame::XController >& /*xController*/ )
889 {
890 return false;
891 }
892
getComponentWindow()893 css::uno::Reference< css::awt::XWindow > SAL_CALL Desktop::getComponentWindow()
894 {
895 return css::uno::Reference< css::awt::XWindow >();
896 }
897
getController()898 css::uno::Reference< css::frame::XController > SAL_CALL Desktop::getController()
899 {
900 return css::uno::Reference< css::frame::XController >();
901 }
902
contextChanged()903 void SAL_CALL Desktop::contextChanged()
904 {
905 }
906
addFrameActionListener(const css::uno::Reference<css::frame::XFrameActionListener> &)907 void SAL_CALL Desktop::addFrameActionListener( const css::uno::Reference< css::frame::XFrameActionListener >& )
908 {
909 }
910
911 // css::frame::XFrame
removeFrameActionListener(const css::uno::Reference<css::frame::XFrameActionListener> &)912 void SAL_CALL Desktop::removeFrameActionListener( const css::uno::Reference< css::frame::XFrameActionListener >& )
913 {
914 }
915
916 /*-************************************************************************************************************
917 @interface XFrame
918 @short try to find a frame with special parameters
919 @descr This method searches for a frame with the specified name.
920 Frames may contain other frames (e.g. a frameset) and may
921 be contained in other frames. This hierarchy is searched by
922 this method.
923 First some special names are taken into account, i.e. "",
924 "_self", "_top", "_parent" etc. The FrameSearchFlags are ignored
925 when comparing these names with aTargetFrameName, further steps are
926 controlled by the FrameSearchFlags. If allowed, the name of the frame
927 itself is compared with the desired one, then ( again if allowed )
928 the method findFrame is called for all children of the frame.
929 If no Frame with the given name is found until the top frames container,
930 a new top Frame is created, if this is allowed by a special
931 FrameSearchFlag. The new Frame also gets the desired name.
932 We use a helper to get right search direction and react in a right manner.
933
934 @seealso class TargetFinder
935
936 @param "sTargetFrameName" , name of searched frame
937 @param "nSearchFlags" , flags to regulate search
938 @return A reference to an existing frame in hierarchy, if it exist.
939
940 @onerror A null reference is returned.
941 @threadsafe yes
942 *//*-*************************************************************************************************************/
findFrame(const OUString & sTargetFrameName,sal_Int32 nSearchFlags)943 css::uno::Reference< css::frame::XFrame > SAL_CALL Desktop::findFrame( const OUString& sTargetFrameName ,
944 sal_Int32 nSearchFlags )
945 {
946 css::uno::Reference< css::frame::XFrame > xTarget;
947
948 // 0) Ignore wrong parameter!
949 // We don't support search for following special targets.
950 // If we reject these requests, we must not check for such names
951 // in following code again and again. If we do not, so wrong
952 // search results can occur!
953
954 if (
955 (sTargetFrameName==SPECIALTARGET_DEFAULT ) || // valid for dispatches - not for findFrame()!
956 (sTargetFrameName==SPECIALTARGET_PARENT ) || // we have no parent by definition
957 (sTargetFrameName==SPECIALTARGET_BEAMER ) // beamer frames are allowed as child of tasks only -
958 // and they exist more than ones. We have no idea which our sub tasks is the right one
959 )
960 {
961 return nullptr;
962 }
963
964 // I) check for special defined targets first which must be handled exclusive.
965 // force using of "if() else if() ..."
966
967 // I.I) "_blank"
968 // create a new task as child of this desktop instance
969 // Note: Used helper TaskCreator use us automatically ...
970
971 if ( sTargetFrameName==SPECIALTARGET_BLANK )
972 {
973 TaskCreator aCreator( m_xContext );
974 xTarget = aCreator.createTask(sTargetFrameName, utl::MediaDescriptor());
975 }
976
977 // I.II) "_top"
978 // We are top by definition
979
980 else if ( sTargetFrameName==SPECIALTARGET_TOP )
981 {
982 xTarget = this;
983 }
984
985 // I.III) "_self", ""
986 // This mean this "frame" in every case.
987
988 else if (
989 ( sTargetFrameName==SPECIALTARGET_SELF ) ||
990 ( sTargetFrameName.isEmpty() )
991 )
992 {
993 xTarget = this;
994 }
995
996 else
997 {
998
999 // II) otherwise use optional given search flags
1000 // force using of combinations of such flags. means no "else" part of use if() statements.
1001 // But we ust break further searches if target was already found.
1002 // Order of using flags is fix: SELF - CHILDREN - SIBLINGS - PARENT
1003 // TASK and CREATE are handled special.
1004 // But note: Such flags are not valid for the desktop - especially SIBLINGS or PARENT.
1005
1006 // II.I) SELF
1007 // Check for right name. If it's the searched one return ourself - otherwise
1008 // ignore this flag.
1009
1010 if (
1011 (nSearchFlags & css::frame::FrameSearchFlag::SELF) &&
1012 (m_sName == sTargetFrameName)
1013 )
1014 {
1015 xTarget = this;
1016 }
1017
1018 // II.II) TASKS
1019 // This is a special flag. Normally it regulate search inside tasks and forbid access to parent trees.
1020 // But the desktop exists outside such task trees. They are our sub trees. So the desktop implement
1021 // a special feature: We use it to start search on our direct children only. That means we suppress
1022 // search on ALL child frames. May that can be useful to get access on opened document tasks
1023 // only without filter out all non really required sub frames ...
1024 // Used helper method on our container doesn't create any frame - it's a search only.
1025
1026 if (
1027 ( ! xTarget.is() ) &&
1028 (nSearchFlags & css::frame::FrameSearchFlag::TASKS)
1029 )
1030 {
1031 xTarget = m_aChildTaskContainer.searchOnDirectChildrens(sTargetFrameName);
1032 }
1033
1034 // II.III) CHILDREN
1035 // Search on all children for the given target name.
1036 // An empty name value can't occur here - because it must be already handled as "_self"
1037 // before. Used helper function of container doesn't create any frame.
1038 // It makes a deep search only.
1039
1040 if (
1041 ( ! xTarget.is() ) &&
1042 (nSearchFlags & css::frame::FrameSearchFlag::CHILDREN)
1043 )
1044 {
1045 xTarget = m_aChildTaskContainer.searchOnAllChildrens(sTargetFrameName);
1046 }
1047
1048 // II.IV) CREATE
1049 // If we haven't found any valid target frame by using normal flags - but user allowed us to create
1050 // a new one ... we should do that. Used TaskCreator use us automatically as parent!
1051
1052 if (
1053 ( ! xTarget.is() ) &&
1054 (nSearchFlags & css::frame::FrameSearchFlag::CREATE)
1055 )
1056 {
1057 TaskCreator aCreator( m_xContext );
1058 xTarget = aCreator.createTask(sTargetFrameName, utl::MediaDescriptor());
1059 }
1060 }
1061
1062 return xTarget;
1063 }
1064
disposing()1065 void SAL_CALL Desktop::disposing()
1066 {
1067 // Safe impossible cases
1068 // It's a programming error if dispose is called before terminate!
1069
1070 // But if you just ignore the assertion (which happens in unit
1071 // tests for instance in sc/qa/unit) nothing bad happens.
1072 SAL_WARN_IF( !m_bIsTerminated, "fwk.desktop", "Desktop disposed before terminating it" );
1073
1074 {
1075 SolarMutexGuard aWriteLock;
1076
1077 {
1078 TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);
1079 }
1080
1081 // Disable this instance for further work.
1082 // This will wait for all current running transactions ...
1083 // and reject all new incoming requests!
1084 m_aTransactionManager.setWorkingMode(E_BEFORECLOSE);
1085 }
1086
1087 // Following lines of code can be called outside a synchronized block ...
1088 // Because our transaction manager will block all new requests to this object.
1089 // So nobody can use us any longer.
1090 // Exception: Only removing of listener will work ... and this code can't be dangerous.
1091
1092 // First we have to kill all listener connections.
1093 // They might rely on our member and can hinder us on releasing them.
1094 css::uno::Reference< css::uno::XInterface > xThis ( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
1095 css::lang::EventObject aEvent( xThis );
1096 m_aListenerContainer.disposeAndClear( aEvent );
1097
1098 // Clear our child task container and forget all task references hardly.
1099 // Normally all open document was already closed by our terminate() function before ...
1100 // New opened frames will have a problem now .-)
1101 m_aChildTaskContainer.clear();
1102
1103 // Dispose our helper too.
1104 css::uno::Reference< css::lang::XEventListener > xFramesHelper( m_xFramesHelper, css::uno::UNO_QUERY );
1105 if( xFramesHelper.is() )
1106 xFramesHelper->disposing( aEvent );
1107
1108 // At least clean up other member references.
1109 m_xDispatchHelper.clear();
1110 m_xFramesHelper.clear();
1111 m_xContext.clear();
1112
1113 m_xPipeTerminator.clear();
1114 m_xQuickLauncher.clear();
1115 m_xStarBasicQuitGuard.clear();
1116 m_xSWThreadManager.clear();
1117
1118 // we need a copy because the disposing might call the removeEventListener method
1119 std::vector< css::uno::Reference<css::frame::XTerminateListener> > xComponentDllListeners = m_xComponentDllListeners;
1120 for (auto& xListener: xComponentDllListeners)
1121 {
1122 xListener->disposing(aEvent);
1123 }
1124 xComponentDllListeners.clear();
1125 m_xComponentDllListeners.clear();
1126 m_xSfxTerminator.clear();
1127 m_xCommandOptions.reset();
1128
1129 // From this point nothing will work further on this object ...
1130 // excepting our dtor() .-)
1131 m_aTransactionManager.setWorkingMode( E_CLOSE );
1132 }
1133
1134 /*
1135 @interface XComponent
1136 @short add/remove listener for dispose events
1137 @descr Add an event listener to this object, if you wish to get information
1138 about our dying!
1139 You must release this listener reference during your own disposing() method.
1140
1141 @attention Our container is threadsafe himself. So we don't need any lock here.
1142 @param "xListener", reference to valid listener. We don't accept invalid values!
1143 @threadsafe yes
1144 */
addEventListener(const css::uno::Reference<css::lang::XEventListener> & xListener)1145 void SAL_CALL Desktop::addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener )
1146 {
1147 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1148 // Safe impossible cases
1149 // Method not defined for all incoming parameter.
1150 SAL_WARN_IF( !xListener.is(), "fwk.desktop", "Desktop::addEventListener(): Invalid parameter detected!" );
1151 // Register transaction and reject wrong calls.
1152 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1153
1154 m_aListenerContainer.addInterface( cppu::UnoType<css::lang::XEventListener>::get(), xListener );
1155 }
1156
removeEventListener(const css::uno::Reference<css::lang::XEventListener> & xListener)1157 void SAL_CALL Desktop::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener )
1158 {
1159 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1160 // Safe impossible cases
1161 // Method not defined for all incoming parameter.
1162 SAL_WARN_IF( !xListener.is(), "fwk.desktop", "Desktop::removeEventListener(): Invalid parameter detected!" );
1163 // Register transaction and reject wrong calls.
1164 TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
1165
1166 m_aListenerContainer.removeInterface( cppu::UnoType<css::lang::XEventListener>::get(), xListener );
1167 }
1168
1169 /*-************************************************************************************************************
1170 @interface XDispatchResultListener
1171 @short callback for dispatches
1172 @descr To support our method "loadComponentFromURL()" we are listener on temp. created dispatcher.
1173 They call us back in this method "statusChanged()". As source of given state event, they give us a
1174 reference to the target frame, in which dispatch was loaded! So we can use it to return his component
1175 to caller! If no target exist ... ??!!
1176
1177 @seealso method loadComponentFromURL()
1178
1179 @param "aEvent", state event which (hopefully) valid information
1180 @threadsafe yes
1181 *//*-*************************************************************************************************************/
dispatchFinished(const css::frame::DispatchResultEvent & aEvent)1182 void SAL_CALL Desktop::dispatchFinished( const css::frame::DispatchResultEvent& aEvent )
1183 {
1184 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1185 // Register transaction and reject wrong calls.
1186 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1187
1188 SolarMutexGuard g;
1189 if( m_eLoadState != E_INTERACTION )
1190 {
1191 m_eLoadState = E_FAILED;
1192 if( aEvent.State == css::frame::DispatchResultState::SUCCESS )
1193 {
1194 css::uno::Reference< css::frame::XFrame > xLastFrame; /// last target of "loadComponentFromURL()"!
1195 if ( aEvent.Result >>= xLastFrame )
1196 m_eLoadState = E_SUCCESSFUL;
1197 }
1198 }
1199 }
1200
1201 /*-************************************************************************************************************
1202 @interface XEventListener
1203 @short not implemented!
1204 @descr We are a status listener ... and so we must be an event listener too ... But we don't need it really!
1205 We are a temp. listener only and our lifetime isn't smaller then of our temp. used dispatcher.
1206
1207 @seealso method loadComponentFromURL()
1208 *//*-*************************************************************************************************************/
disposing(const css::lang::EventObject &)1209 void SAL_CALL Desktop::disposing( const css::lang::EventObject& )
1210 {
1211 SAL_WARN( "fwk.desktop", "Desktop::disposing(): Algorithm error! Normally desktop is temp. listener ... not all the time. So this method shouldn't be called." );
1212 }
1213
1214 /*-************************************************************************************************************
1215 @interface XInteractionHandler
1216 @short callback for loadComponentFromURL for detected exceptions during load process
1217 @descr In this case we must cancel loading and throw these detected exception again as result
1218 of our own called method.
1219
1220 @attention a)
1221 Normal loop in loadComponentFromURL() breaks on set member m_eLoadState during callback statusChanged().
1222 But these interaction feature implements second way to do so! So we must look on different callbacks
1223 for same operation ... and live with it.
1224 b)
1225 Search for given continuations too. If any XInteractionAbort exist ... use it to abort further operations
1226 for currently running operation!
1227
1228 @seealso method loadComponentFromURL()
1229 @seealso member m_eLoadState
1230
1231 @param "xRequest", request for interaction - normal a wrapped target exception from bottom services
1232 @threadsafe yes
1233 *//*-*************************************************************************************************************/
handle(const css::uno::Reference<css::task::XInteractionRequest> & xRequest)1234 void SAL_CALL Desktop::handle( const css::uno::Reference< css::task::XInteractionRequest >& xRequest )
1235 {
1236 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1237 // Register transaction and reject wrong calls.
1238 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1239
1240 // Don't check incoming request!
1241 // If somewhere starts interaction without right parameter - he made something wrong.
1242 // loadComponentFromURL() waits for these event - otherwise it yield for ever!
1243
1244 // get packed request and work on it first
1245 // Attention: Don't set it on internal member BEFORE interaction is finished - because
1246 // "loadComponentFromURL()" yield tills this member is changed. If we do it before
1247 // interaction finish we can't guarantee right functionality. May be we cancel load process to earlier...
1248 css::uno::Any aRequest = xRequest->getRequest();
1249
1250 // extract continuations from request
1251 css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations = xRequest->getContinuations();
1252 css::uno::Reference< css::task::XInteractionAbort > xAbort;
1253 css::uno::Reference< css::task::XInteractionApprove > xApprove;
1254 css::uno::Reference< css::document::XInteractionFilterSelect > xFilterSelect;
1255 bool bAbort = false;
1256
1257 sal_Int32 nCount=lContinuations.getLength();
1258 for( sal_Int32 nStep=0; nStep<nCount; ++nStep )
1259 {
1260 if( ! xAbort.is() )
1261 xAbort.set( lContinuations[nStep], css::uno::UNO_QUERY );
1262
1263 if( ! xApprove.is() )
1264 xApprove.set( lContinuations[nStep], css::uno::UNO_QUERY );
1265
1266 if( ! xFilterSelect.is() )
1267 xFilterSelect.set( lContinuations[nStep], css::uno::UNO_QUERY );
1268 }
1269
1270 // differ between abortable interactions (error, unknown filter...)
1271 // and other ones (ambiguous but not unknown filter...)
1272 css::task::ErrorCodeRequest aErrorCodeRequest;
1273 if( aRequest >>= aErrorCodeRequest )
1274 {
1275 bool bWarning = ErrCode(aErrorCodeRequest.ErrCode).IsWarning();
1276 if (xApprove.is() && bWarning)
1277 xApprove->select();
1278 else
1279 if (xAbort.is())
1280 {
1281 xAbort->select();
1282 bAbort = true;
1283 }
1284 }
1285 else if( xAbort.is() )
1286 {
1287 xAbort->select();
1288 bAbort = true;
1289 }
1290
1291 // Ok now it's time to break yield loop of loadComponentFromURL().
1292 // But only for really aborted requests!
1293 // For example warnings will be approved and we wait for any success story ...
1294 if (bAbort)
1295 {
1296 SolarMutexGuard g;
1297 m_eLoadState = E_INTERACTION;
1298 }
1299 }
1300
leaseNumber(const css::uno::Reference<css::uno::XInterface> & xComponent)1301 ::sal_Int32 SAL_CALL Desktop::leaseNumber( const css::uno::Reference< css::uno::XInterface >& xComponent )
1302 {
1303 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1304 return m_xTitleNumberGenerator->leaseNumber (xComponent);
1305 }
1306
releaseNumber(::sal_Int32 nNumber)1307 void SAL_CALL Desktop::releaseNumber( ::sal_Int32 nNumber )
1308 {
1309 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1310 m_xTitleNumberGenerator->releaseNumber (nNumber);
1311 }
1312
releaseNumberForComponent(const css::uno::Reference<css::uno::XInterface> & xComponent)1313 void SAL_CALL Desktop::releaseNumberForComponent( const css::uno::Reference< css::uno::XInterface >& xComponent )
1314 {
1315 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1316 m_xTitleNumberGenerator->releaseNumberForComponent (xComponent);
1317 }
1318
getUntitledPrefix()1319 OUString SAL_CALL Desktop::getUntitledPrefix()
1320 {
1321 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1322 return m_xTitleNumberGenerator->getUntitledPrefix ();
1323 }
1324
1325 /*-************************************************************************************************************
1326 @short try to convert a property value
1327 @descr This method is called from helperclass "OPropertySetHelper".
1328 Don't use this directly!
1329 You must try to convert the value of given PropHandle and
1330 return results of this operation. This will be used to ask vetoable
1331 listener. If no listener has a veto, we will change value really!
1332 ( in method setFastPropertyValue_NoBroadcast(...) )
1333
1334 @attention Methods of OPropertySethelper are safed by using our shared osl mutex! (see ctor!)
1335 So we must use different locks to make our implementation threadsafe.
1336
1337 @seealso class OPropertySetHelper
1338 @seealso method setFastPropertyValue_NoBroadcast()
1339
1340 @param "aConvertedValue" new converted value of property
1341 @param "aOldValue" old value of property
1342 @param "nHandle" handle of property
1343 @param "aValue" new value of property
1344 @return sal_True if value will be changed, sal_FALSE otherway
1345
1346 @onerror IllegalArgumentException, if you call this with an invalid argument
1347 @threadsafe yes
1348 *//*-*************************************************************************************************************/
convertFastPropertyValue(css::uno::Any & aConvertedValue,css::uno::Any & aOldValue,sal_Int32 nHandle,const css::uno::Any & aValue)1349 sal_Bool SAL_CALL Desktop::convertFastPropertyValue( css::uno::Any& aConvertedValue ,
1350 css::uno::Any& aOldValue ,
1351 sal_Int32 nHandle ,
1352 const css::uno::Any& aValue )
1353 {
1354 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1355 // Register transaction and reject wrong calls.
1356 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1357
1358 // Initialize state with sal_False !!!
1359 // (Handle can be invalid)
1360 bool bReturn = false;
1361
1362 switch( nHandle )
1363 {
1364 case PropHandle::SuspendQuickstartVeto:
1365 bReturn = PropHelper::willPropertyBeChanged(
1366 css::uno::makeAny(m_bSuspendQuickstartVeto),
1367 aValue,
1368 aOldValue,
1369 aConvertedValue);
1370 break;
1371 case PropHandle::DispatchRecorderSupplier :
1372 bReturn = PropHelper::willPropertyBeChanged(
1373 css::uno::makeAny(m_xDispatchRecorderSupplier),
1374 aValue,
1375 aOldValue,
1376 aConvertedValue);
1377 break;
1378 case PropHandle::Title :
1379 bReturn = PropHelper::willPropertyBeChanged(
1380 css::uno::makeAny(m_sTitle),
1381 aValue,
1382 aOldValue,
1383 aConvertedValue);
1384 break;
1385 }
1386
1387 // Return state of operation.
1388 return bReturn;
1389 }
1390
1391 /*-************************************************************************************************************
1392 @short set value of a transient property
1393 @descr This method is calling from helperclass "OPropertySetHelper".
1394 Don't use this directly!
1395 Handle and value are valid everyway! You must set the new value only.
1396 After this, baseclass send messages to all listener automatically.
1397
1398 @seealso class OPropertySetHelper
1399
1400 @param "nHandle" handle of property to change
1401 @param "aValue" new value of property
1402 @onerror An exception is thrown.
1403 @threadsafe yes
1404 *//*-*************************************************************************************************************/
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any & aValue)1405 void SAL_CALL Desktop::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle ,
1406 const css::uno::Any& aValue )
1407 {
1408 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1409 // Register transaction and reject wrong calls.
1410 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1411
1412 switch( nHandle )
1413 {
1414 case PropHandle::SuspendQuickstartVeto: aValue >>= m_bSuspendQuickstartVeto;
1415 break;
1416 case PropHandle::DispatchRecorderSupplier: aValue >>= m_xDispatchRecorderSupplier;
1417 break;
1418 case PropHandle::Title: aValue >>= m_sTitle;
1419 break;
1420 }
1421 }
1422
1423 /*-************************************************************************************************************
1424 @short get value of a transient property
1425 @descr This method is calling from helperclass "OPropertySetHelper".
1426 Don't use this directly!
1427
1428 @attention We don't need any mutex or lock here ... We use threadsafe container or methods here only!
1429
1430 @seealso class OPropertySetHelper
1431
1432 @param "nHandle" handle of property to change
1433 @param "aValue" current value of property
1434 @threadsafe yes
1435 *//*-*************************************************************************************************************/
getFastPropertyValue(css::uno::Any & aValue,sal_Int32 nHandle) const1436 void SAL_CALL Desktop::getFastPropertyValue( css::uno::Any& aValue ,
1437 sal_Int32 nHandle ) const
1438 {
1439 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1440 // Register transaction and reject wrong calls.
1441 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1442
1443 switch( nHandle )
1444 {
1445 case PropHandle::ActiveFrame : aValue <<= m_aChildTaskContainer.getActive();
1446 break;
1447 case PropHandle::IsPlugged : aValue <<= false;
1448 break;
1449 case PropHandle::SuspendQuickstartVeto: aValue <<= m_bSuspendQuickstartVeto;
1450 break;
1451 case PropHandle::DispatchRecorderSupplier: aValue <<= m_xDispatchRecorderSupplier;
1452 break;
1453 case PropHandle::Title: aValue <<= m_sTitle;
1454 break;
1455 }
1456 }
1457
getInfoHelper()1458 ::cppu::IPropertyArrayHelper& SAL_CALL Desktop::getInfoHelper()
1459 {
1460 struct Static:
1461 public rtl::StaticWithInit<cppu::OPropertyArrayHelper, Static>
1462 {
1463 cppu::OPropertyArrayHelper operator ()() {
1464 return {
1465 {{"ActiveFrame", PropHandle::ActiveFrame,
1466 cppu::UnoType<css::lang::XComponent>::get(),
1467 (css::beans::PropertyAttribute::TRANSIENT
1468 | css::beans::PropertyAttribute::READONLY)},
1469 {"DispatchRecorderSupplier",
1470 PropHandle::DispatchRecorderSupplier,
1471 cppu::UnoType<css::frame::XDispatchRecorderSupplier>::get(),
1472 css::beans::PropertyAttribute::TRANSIENT},
1473 {"IsPlugged",
1474 PropHandle::IsPlugged, cppu::UnoType<bool>::get(),
1475 (css::beans::PropertyAttribute::TRANSIENT
1476 | css::beans::PropertyAttribute::READONLY)},
1477 {"SuspendQuickstartVeto", PropHandle::SuspendQuickstartVeto,
1478 cppu::UnoType<bool>::get(),
1479 css::beans::PropertyAttribute::TRANSIENT},
1480 {"Title", PropHandle::Title, cppu::UnoType<OUString>::get(),
1481 css::beans::PropertyAttribute::TRANSIENT}},
1482 true};
1483 }
1484 };
1485 return Static::get();
1486 }
1487
1488 /*-************************************************************************************************************
1489 @short return propertysetinfo
1490 @descr You can call this method to get information about transient properties
1491 of this object.
1492
1493 @attention You must use global lock (method use static variable) ... and it must be the shareable osl mutex of it.
1494 Because; our baseclass use this mutex to make his code threadsafe. We use our lock!
1495 So we could have two different mutex/lock mechanism at the same object.
1496
1497 @seealso class OPropertySetHelper
1498 @seealso interface XPropertySet
1499 @seealso interface XMultiPropertySet
1500 @return reference to object with information [XPropertySetInfo]
1501 @threadsafe yes
1502 *//*-*************************************************************************************************************/
getPropertySetInfo()1503 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL Desktop::getPropertySetInfo()
1504 {
1505 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1506 // Register transaction and reject wrong calls.
1507 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1508
1509 // Create structure of propertysetinfo for baseclass "OPropertySetHelper".
1510 // (Use method "getInfoHelper()".)
1511 static css::uno::Reference< css::beans::XPropertySetInfo > xInfo(
1512 cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ) );
1513
1514 return xInfo;
1515 }
1516
1517 /*-************************************************************************************************************
1518 @short return current component of current frame
1519 @descr The desktop himself has no component. But every frame in subtree.
1520 If somewhere call getCurrentComponent() at this class, we try to find the right frame and
1521 then we try to become his component. It can be a VCL-component, the model or the controller
1522 of founded frame.
1523
1524 @attention We don't work on internal member ... so we don't need any lock here.
1525
1526 @seealso method getCurrentComponent();
1527
1528 @param "xFrame", reference to valid frame in hierarchy. Method is not defined for invalid values.
1529 But we don't check these. It's an IMPL-method and caller must use it right!
1530 @return A reference to found component.
1531
1532 @onerror A null reference is returned.
1533 @threadsafe yes
1534 *//*-*************************************************************************************************************/
impl_getFrameComponent(const css::uno::Reference<css::frame::XFrame> & xFrame) const1535 css::uno::Reference< css::lang::XComponent > Desktop::impl_getFrameComponent( const css::uno::Reference< css::frame::XFrame >& xFrame ) const
1536 {
1537 /* UNSAFE AREA --------------------------------------------------------------------------------------------- */
1538 // Register transaction and reject wrong calls.
1539 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1540
1541 // Set default return value, if method failed.
1542 css::uno::Reference< css::lang::XComponent > xComponent;
1543 // Does no controller exists?
1544 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
1545 if( !xController.is() )
1546 {
1547 // Controller not exist - use the VCL-component.
1548 xComponent = xFrame->getComponentWindow();
1549 }
1550 else
1551 {
1552 // Does no model exists?
1553 css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1554 if( xModel.is() )
1555 {
1556 // Model exist - use the model as component.
1557 xComponent = xModel;
1558 }
1559 else
1560 {
1561 // Model not exist - use the controller as component.
1562 xComponent = xController;
1563 }
1564 }
1565
1566 return xComponent;
1567 }
1568
impl_sendQueryTerminationEvent(Desktop::TTerminateListenerList & lCalledListener,bool & bVeto)1569 void Desktop::impl_sendQueryTerminationEvent(Desktop::TTerminateListenerList& lCalledListener,
1570 bool& bVeto )
1571 {
1572 bVeto = false;
1573
1574 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1575
1576 ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1577 if ( ! pContainer )
1578 return;
1579
1580 css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1581
1582 ::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
1583 while ( aIterator.hasMoreElements() )
1584 {
1585 try
1586 {
1587 css::uno::Reference< css::frame::XTerminateListener > xListener(aIterator.next(), css::uno::UNO_QUERY);
1588 if ( ! xListener.is() )
1589 continue;
1590 xListener->queryTermination( aEvent );
1591 lCalledListener.push_back(xListener);
1592 }
1593 catch( const css::frame::TerminationVetoException& )
1594 {
1595 // first veto will stop notification loop.
1596 bVeto = true;
1597 return;
1598 }
1599 catch( const css::uno::Exception& )
1600 {
1601 // clean up container.
1602 // E.g. dead remote listener objects can make trouble otherwise.
1603 // Iterator implementation allows removing objects during it's used !
1604 aIterator.remove();
1605 }
1606 }
1607 }
1608
impl_sendCancelTerminationEvent(const Desktop::TTerminateListenerList & lCalledListener)1609 void Desktop::impl_sendCancelTerminationEvent(const Desktop::TTerminateListenerList& lCalledListener)
1610 {
1611 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1612
1613 css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1614 for (const css::uno::Reference<css::frame::XTerminateListener>& xListener : lCalledListener)
1615 {
1616 try
1617 {
1618 // Note: cancelTermination() is a new and optional interface method !
1619 css::uno::Reference< css::frame::XTerminateListener2 > xListenerGeneration2(xListener, css::uno::UNO_QUERY);
1620 if ( ! xListenerGeneration2.is() )
1621 continue;
1622 xListenerGeneration2->cancelTermination( aEvent );
1623 }
1624 catch( const css::uno::Exception& )
1625 {}
1626 }
1627 }
1628
impl_sendTerminateToClipboard()1629 void Desktop::impl_sendTerminateToClipboard()
1630 {
1631 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1632
1633 ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1634 if ( ! pContainer )
1635 return;
1636
1637 ::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
1638 while ( aIterator.hasMoreElements() )
1639 {
1640 try
1641 {
1642 css::uno::Reference< css::lang::XServiceInfo > xInfo( aIterator.next(), css::uno::UNO_QUERY );
1643 if ( !xInfo.is() )
1644 continue;
1645
1646 if ( xInfo->getImplementationName() != "com.sun.star.comp.svt.TransferableHelperTerminateListener" )
1647 continue;
1648
1649 css::uno::Reference< css::frame::XTerminateListener > xListener(xInfo, css::uno::UNO_QUERY);
1650 if ( ! xListener.is() )
1651 continue;
1652
1653 css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1654 xListener->notifyTermination( aEvent );
1655
1656 // don't notify twice
1657 aIterator.remove();
1658 }
1659 catch( const css::uno::Exception& )
1660 {
1661 // clean up container.
1662 // E.g. dead remote listener objects can make trouble otherwise.
1663 // Iterator implementation allows removing objects during it's used !
1664 aIterator.remove();
1665 }
1666 }
1667 }
1668
impl_sendNotifyTerminationEvent()1669 void Desktop::impl_sendNotifyTerminationEvent()
1670 {
1671 TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
1672
1673 ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer( cppu::UnoType<css::frame::XTerminateListener>::get());
1674 if ( ! pContainer )
1675 return;
1676
1677 css::lang::EventObject aEvent( static_cast< ::cppu::OWeakObject* >(this) );
1678
1679 ::cppu::OInterfaceIteratorHelper aIterator( *pContainer );
1680 while ( aIterator.hasMoreElements() )
1681 {
1682 try
1683 {
1684 css::uno::Reference< css::frame::XTerminateListener > xListener(aIterator.next(), css::uno::UNO_QUERY);
1685 if ( ! xListener.is() )
1686 continue;
1687 xListener->notifyTermination( aEvent );
1688 }
1689 catch( const css::uno::Exception& )
1690 {
1691 // clean up container.
1692 // E.g. dead remote listener objects can make trouble otherwise.
1693 // Iterator implementation allows removing objects during it's used !
1694 aIterator.remove();
1695 }
1696 }
1697 }
1698
impl_closeFrames(bool bAllowUI)1699 bool Desktop::impl_closeFrames(bool bAllowUI)
1700 {
1701 SolarMutexClearableGuard aReadLock;
1702 css::uno::Sequence< css::uno::Reference< css::frame::XFrame > > lFrames = m_aChildTaskContainer.getAllElements();
1703 aReadLock.clear();
1704
1705 ::sal_Int32 c = lFrames.getLength();
1706 ::sal_Int32 i = 0;
1707 ::sal_Int32 nNonClosedFrames = 0;
1708
1709 for( i=0; i<c; ++i )
1710 {
1711 try
1712 {
1713 css::uno::Reference< css::frame::XFrame > xFrame = lFrames[i];
1714
1715 // XController.suspend() will show a UI ...
1716 // Use it in case it was allowed from outside only.
1717 bool bSuspended = false;
1718 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
1719 if ( bAllowUI && xController.is() )
1720 {
1721 bSuspended = xController->suspend( true );
1722 if ( ! bSuspended )
1723 {
1724 ++nNonClosedFrames;
1725 if(m_bSession)
1726 break;
1727 else
1728 continue;
1729 }
1730 }
1731
1732 // Try to close frame (in case no UI was allowed without calling XController->suspend() before!)
1733 // But don't deliver ownership to any other one!
1734 // This method can be called again.
1735 css::uno::Reference< css::util::XCloseable > xClose( xFrame, css::uno::UNO_QUERY );
1736 if ( xClose.is() )
1737 {
1738 try
1739 {
1740 xClose->close(false);
1741 }
1742 catch(const css::util::CloseVetoException&)
1743 {
1744 // Any internal process of this frame disagree with our request.
1745 // Safe this state but don't break these loop. Other frames has to be closed!
1746 ++nNonClosedFrames;
1747
1748 // Reactivate controller.
1749 // It can happen that XController.suspend() returned true... but a registered close listener
1750 // threw these veto exception. Then the controller has to be reactivated. Otherwise
1751 // these document doesn't work any more.
1752 if ( bSuspended && xController.is())
1753 xController->suspend(false);
1754 }
1755
1756 // If interface XClosable interface exists and was used...
1757 // it's not allowed to use XComponent->dispose() also!
1758 continue;
1759 }
1760
1761 // XClosable not supported ?
1762 // Then we have to dispose these frame hardly.
1763 if ( xFrame.is() )
1764 xFrame->dispose();
1765
1766 // Don't remove these frame from our child container!
1767 // A frame do it by itself inside close()/dispose() method.
1768 }
1769 catch(const css::lang::DisposedException&)
1770 {
1771 // Dispose frames are closed frames.
1772 // So we can count it here .-)
1773 }
1774 }
1775
1776 // reset the session
1777 m_bSession = false;
1778
1779 return (nNonClosedFrames < 1);
1780 }
1781
1782 } // namespace framework
1783
1784 namespace {
1785
1786 struct Instance {
Instance__anoned184b700211::Instance1787 explicit Instance(
1788 css::uno::Reference<css::uno::XComponentContext> const & context):
1789 instance(new framework::Desktop(context))
1790 {
1791 instance->constructorInit();
1792 }
1793
1794 rtl::Reference<framework::Desktop> instance;
1795 };
1796
1797 struct InstanceInit {
operator ()__anoned184b700211::InstanceInit1798 Instance * operator() (css::uno::Reference<css::uno::XComponentContext> const& xContext) {
1799 static Instance instance(xContext);
1800 return &instance;
1801 }
1802 };
1803
1804 struct GetSolarMutex {
operator ()__anoned184b700211::GetSolarMutex1805 comphelper::SolarMutex * operator() ()
1806 {
1807 return &Application::GetSolarMutex();
1808 }
1809 };
1810
getInstance(css::uno::Reference<css::uno::XComponentContext> const & xContext)1811 Instance & getInstance(css::uno::Reference<css::uno::XComponentContext> const& xContext)
1812 {
1813 // tdf#114025 init with SolarMutex to avoid deadlock
1814 return *rtl_Instance<Instance,
1815 InstanceInit,
1816 osl::Guard<comphelper::SolarMutex>,
1817 GetSolarMutex,
1818 css::uno::Reference<css::uno::XComponentContext> const>
1819 ::create(InstanceInit(), GetSolarMutex(), xContext);
1820 }
1821
1822 }
1823
1824 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_framework_Desktop_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)1825 com_sun_star_comp_framework_Desktop_get_implementation(
1826 css::uno::XComponentContext *context,
1827 css::uno::Sequence<css::uno::Any> const &)
1828 {
1829 return cppu::acquire(getInstance(context).instance.get());
1830 }
1831
1832 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1833