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