1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26
27 //_______________________________________________
28 // my own includes
29 #include <dispatch/closedispatcher.hxx>
30 #include <pattern/frame.hxx>
31 #include <threadhelp/readguard.hxx>
32 #include <threadhelp/writeguard.hxx>
33 #include <framework/framelistanalyzer.hxx>
34 #include <services.h>
35 #include <general.h>
36
37 //_______________________________________________
38 // interface includes
39 #include <com/sun/star/frame/XDesktop.hpp>
40 #include <com/sun/star/frame/XController.hpp>
41 #include <com/sun/star/frame/CommandGroup.hpp>
42 #include <com/sun/star/lang/DisposedException.hpp>
43 #include <com/sun/star/awt/XTopWindow.hpp>
44 #include <com/sun/star/document/XActionLockable.hpp>
45 #include "com/sun/star/beans/XFastPropertySet.hpp"
46 #include <toolkit/helper/vclunohelper.hxx>
47
48 //_______________________________________________
49 // includes of other projects
50
51 #include <vcl/window.hxx>
52 #include <vcl/svapp.hxx>
53 #include <vos/mutex.hxx>
54 #include <unotools/moduleoptions.hxx>
55
56 //_______________________________________________
57 // namespace
58
59 namespace framework{
60
61 #ifdef fpf
62 #error "Who uses \"fpf\" as define. It will overwrite my namespace alias ..."
63 #endif
64 namespace fpf = ::framework::pattern::frame;
65
66 //_______________________________________________
67 // non exported const
68
69 static ::rtl::OUString URL_CLOSEDOC = DECLARE_ASCII(".uno:CloseDoc" );
70 static ::rtl::OUString URL_CLOSEWIN = DECLARE_ASCII(".uno:CloseWin" );
71 static ::rtl::OUString URL_CLOSEFRAME = DECLARE_ASCII(".uno:CloseFrame");
72
73 //_______________________________________________
74 // declarations
75
DEFINE_XINTERFACE_4(CloseDispatcher,OWeakObject,DIRECT_INTERFACE (css::lang::XTypeProvider),DIRECT_INTERFACE (css::frame::XNotifyingDispatch),DIRECT_INTERFACE (css::frame::XDispatch),DIRECT_INTERFACE (css::frame::XDispatchInformationProvider))76 DEFINE_XINTERFACE_4(CloseDispatcher ,
77 OWeakObject ,
78 DIRECT_INTERFACE(css::lang::XTypeProvider ),
79 DIRECT_INTERFACE(css::frame::XNotifyingDispatch ),
80 DIRECT_INTERFACE(css::frame::XDispatch ),
81 DIRECT_INTERFACE(css::frame::XDispatchInformationProvider))
82
83 // Note: XStatusListener is an implementation detail. Hide it for scripting!
84 DEFINE_XTYPEPROVIDER_4(CloseDispatcher ,
85 css::lang::XTypeProvider ,
86 css::frame::XDispatchInformationProvider,
87 css::frame::XNotifyingDispatch ,
88 css::frame::XDispatch )
89
90 //-----------------------------------------------
91 CloseDispatcher::CloseDispatcher(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
92 const css::uno::Reference< css::frame::XFrame >& xFrame ,
93 const ::rtl::OUString& sTarget)
94 : ThreadHelpBase (&Application::GetSolarMutex() )
95 , ::cppu::OWeakObject( )
96 , m_xSMGR (xSMGR )
97 , m_aAsyncCallback (LINK( this, CloseDispatcher, impl_asyncCallback))
98 , m_lStatusListener (m_aLock.getShareableOslMutex() )
99 {
100 m_xCloseFrame = CloseDispatcher::static_impl_searchRightTargetFrame(xFrame, sTarget);
101 }
102
103 //-----------------------------------------------
~CloseDispatcher()104 CloseDispatcher::~CloseDispatcher()
105 {
106 }
107
108 //-----------------------------------------------
dispatch(const css::util::URL & aURL,const css::uno::Sequence<css::beans::PropertyValue> & lArguments)109 void SAL_CALL CloseDispatcher::dispatch(const css::util::URL& aURL ,
110 const css::uno::Sequence< css::beans::PropertyValue >& lArguments)
111 throw(css::uno::RuntimeException)
112 {
113 dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >());
114 }
115
116 //-----------------------------------------------
getSupportedCommandGroups()117 css::uno::Sequence< sal_Int16 > SAL_CALL CloseDispatcher::getSupportedCommandGroups()
118 throw(css::uno::RuntimeException)
119 {
120 css::uno::Sequence< sal_Int16 > lGroups(2);
121 lGroups[0] = css::frame::CommandGroup::VIEW;
122 lGroups[1] = css::frame::CommandGroup::DOCUMENT;
123 return lGroups;
124 }
125
126 //-----------------------------------------------
getConfigurableDispatchInformation(sal_Int16 nCommandGroup)127 css::uno::Sequence< css::frame::DispatchInformation > SAL_CALL CloseDispatcher::getConfigurableDispatchInformation(sal_Int16 nCommandGroup)
128 throw(css::uno::RuntimeException)
129 {
130 if (nCommandGroup == css::frame::CommandGroup::VIEW)
131 {
132 /* Attention: Dont add .uno:CloseFrame here. Because its not realy
133 a configurable feature ... and further it does not have
134 a valid UIName entry inside the GenericCommands.xcu ... */
135 css::uno::Sequence< css::frame::DispatchInformation > lViewInfos(1);
136 lViewInfos[0].Command = URL_CLOSEWIN;
137 lViewInfos[0].GroupId = css::frame::CommandGroup::VIEW;
138 return lViewInfos;
139 }
140 else
141 if (nCommandGroup == css::frame::CommandGroup::DOCUMENT)
142 {
143 css::uno::Sequence< css::frame::DispatchInformation > lDocInfos(1);
144 lDocInfos[0].Command = URL_CLOSEDOC;
145 lDocInfos[0].GroupId = css::frame::CommandGroup::DOCUMENT;
146 return lDocInfos;
147 }
148
149 return css::uno::Sequence< css::frame::DispatchInformation >();
150 }
151
152 //-----------------------------------------------
addStatusListener(const css::uno::Reference<css::frame::XStatusListener> &,const css::util::URL &)153 void SAL_CALL CloseDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/,
154 const css::util::URL& /*aURL*/ )
155 throw(css::uno::RuntimeException)
156 {
157 }
158
159 //-----------------------------------------------
removeStatusListener(const css::uno::Reference<css::frame::XStatusListener> &,const css::util::URL &)160 void SAL_CALL CloseDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/,
161 const css::util::URL& /*aURL*/ )
162 throw(css::uno::RuntimeException)
163 {
164 }
165
166 //-----------------------------------------------
dispatchWithNotification(const css::util::URL & aURL,const css::uno::Sequence<css::beans::PropertyValue> & lArguments,const css::uno::Reference<css::frame::XDispatchResultListener> & xListener)167 void SAL_CALL CloseDispatcher::dispatchWithNotification(const css::util::URL& aURL ,
168 const css::uno::Sequence< css::beans::PropertyValue >& lArguments,
169 const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
170 throw(css::uno::RuntimeException)
171 {
172 // SAFE -> ----------------------------------
173 WriteGuard aWriteLock(m_aLock);
174
175 // This reference indicates, that we was already called before and
176 // our asynchronous process was not finished yet.
177 // We have to reject double calls. Otherwhise we risk,
178 // that we try to close an already closed resource ...
179 // And its no problem to do nothing then. The UI user will try it again, if
180 // non of these jobs was successfully.
181 if (m_xSelfHold.is())
182 {
183 aWriteLock.unlock();
184 // <- SAFE ------------------------------
185
186 implts_notifyResultListener(
187 xListener,
188 css::frame::DispatchResultState::DONTKNOW,
189 css::uno::Any());
190 return;
191 }
192
193 // First we have to check, if this dispatcher is used right. Means if valid URLs are used.
194 // If not - we have to break this operation. But an optional listener must be informed.
195 // BTW: We save the information about the requested operation. Because
196 // we need it later.
197 if (aURL.Complete.equals(URL_CLOSEDOC))
198 m_eOperation = E_CLOSE_DOC;
199 else
200 if (aURL.Complete.equals(URL_CLOSEWIN))
201 m_eOperation = E_CLOSE_WIN;
202 else
203 if (aURL.Complete.equals(URL_CLOSEFRAME))
204 m_eOperation = E_CLOSE_FRAME;
205 else
206 {
207 aWriteLock.unlock();
208 // <- SAFE ------------------------------
209
210 implts_notifyResultListener(
211 xListener,
212 css::frame::DispatchResultState::FAILURE,
213 css::uno::Any());
214 return;
215 }
216
217 // OK - URLs are the right ones.
218 // But we cant execute synchronously :-)
219 // May we are called from a generic key-input handler,
220 // which isnt aware that this call kill its own environment ...
221 // Do it asynchronous everytimes!
222
223 // But dont forget to hold usself alive.
224 // We are called back from an environment, which doesnt know an uno reference.
225 // They call us back by using our c++ interface.
226
227 m_xResultListener = xListener;
228 m_xSelfHold = css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
229
230 aWriteLock.unlock();
231 // <- SAFE ----------------------------------
232
233 sal_Bool bIsSynchron = sal_False;
234 for (sal_Int32 nArgs=0; nArgs<lArguments.getLength(); nArgs++ )
235 {
236 if ( lArguments[nArgs].Name.equalsAscii("SynchronMode") )
237 {
238 lArguments[nArgs].Value >>= bIsSynchron;
239 break;
240 }
241 }
242
243 if ( bIsSynchron )
244 impl_asyncCallback(0);
245 else
246 m_aAsyncCallback.Post(0);
247 }
248
249 //-----------------------------------------------
250 /**
251 @short asynchronous callback
252 @descr We start all actions inside this object asnychronoue.
253 (see comments there).
254 Now we do the following:
255 - close all views to the same document, if needed and possible
256 - make the current frame empty
257 ! This step is neccessary to handle errors during closing the
258 document inside the frame. May the document shows a dialog and
259 the user ignore it. Then the state of the office can be changed
260 during we try to close frame and document.
261 - check the environment (menas count open frames - exlcuding our
262 current one)
263 - decide then, if we must close this frame only, establish the backing mode
264 or shutdown the whole application.
265 */
IMPL_LINK(CloseDispatcher,impl_asyncCallback,void *,EMPTYARG)266 IMPL_LINK( CloseDispatcher, impl_asyncCallback, void*, EMPTYARG )
267 {
268 try
269 {
270
271 // Allow calling of XController->suspend() everytimes.
272 // Dispatch is an UI functionality. We implement such dispatch object here.
273 // And further XController->suspend() was designed to bring an UI ...
274 sal_Bool bAllowSuspend = sal_True;
275 sal_Bool bControllerSuspended = sal_False;
276
277 // SAFE -> ----------------------------------
278 ReadGuard aReadLock(m_aLock);
279
280 // Closing of all views, related to the same document, is allowed
281 // only if the dispatched URL was ".uno:CloseDoc"!
282 sal_Bool bCloseAllViewsToo = (m_eOperation == E_CLOSE_DOC);
283
284 // BTW: Make some copies, which are needed later ...
285 EOperation eOperation = m_eOperation;
286 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
287 css::uno::Reference< css::frame::XFrame > xCloseFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY);
288 css::uno::Reference< css::frame::XDispatchResultListener > xListener = m_xResultListener;
289
290 aReadLock.unlock();
291 // <- SAFE ----------------------------------
292
293 // frame already dead ?!
294 // Nothing to do !
295 if (! xCloseFrame.is())
296 return 0;
297
298 sal_Bool bCloseFrame = sal_False;
299 sal_Bool bEstablishBackingMode = sal_False;
300 sal_Bool bTerminateApp = sal_False;
301
302 // Analyze the environment a first time.
303 // If we found some special cases, we can
304 // make some decisions erliar!
305 css::uno::Reference< css::frame::XFramesSupplier > xDesktop(xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW);
306 FrameListAnalyzer aCheck1(xDesktop, xCloseFrame, FrameListAnalyzer::E_HELP | FrameListAnalyzer::E_BACKINGCOMPONENT);
307
308 // a) If the curent frame (where the close dispatch was requested for) does not have
309 // any parent frame ... it will close this frame only. Such frame isnt part of the
310 // global desktop tree ... and such frames are used as "implementation details" only.
311 // E.g. the live previews of our wizards doing such things. And then the owner of the frame
312 // is responsible for closing the application or accepting closing of the application
313 // by others.
314 if ( ! xCloseFrame->getCreator().is())
315 bCloseFrame = sal_True;
316 else
317
318 // b) The help window cant disagree with any request.
319 // Because it doesnt implement a controller - it uses a window only.
320 // Further t cant be the last open frame - if we do all other things
321 // right inside this CloseDispatcher implementation.
322 // => close it!
323 if (aCheck1.m_bReferenceIsHelp)
324 bCloseFrame = sal_True;
325 else
326
327 // c) If we are already in "backing mode", we have to terminate
328 // the application, if this special frame is closed.
329 // It doesnt matter, how many other frames (can be the help or hidden frames only)
330 // are open then.
331 // => terminate the application!
332 if (aCheck1.m_bReferenceIsBacking)
333 bTerminateApp = sal_True;
334 else
335
336 // d) Otherwhise we have to: close all views to the same document, close the
337 // document inside our own frame and decide then again, what has to be done!
338 {
339 if (implts_prepareFrameForClosing(m_xCloseFrame, bAllowSuspend, bCloseAllViewsToo, bControllerSuspended))
340 {
341 // OK; this frame is empty now.
342 // Check the environment again to decide, what is the next step.
343 FrameListAnalyzer aCheck2(xDesktop, xCloseFrame, FrameListAnalyzer::E_ALL);
344
345 // c1) there is as minimum 1 frame open, which is visible and contains a document
346 // different from our one. And its not the help!
347 // => close our frame only - nothing else.
348 if (aCheck2.m_lOtherVisibleFrames.getLength()>0)
349 bCloseFrame = sal_True;
350 else
351
352 // c2) if we close the current view ... but not all other views
353 // to the same document, we must close the current frame only!
354 // Because implts_closeView() suspended this view only - does not
355 // close the frame.
356 if (
357 (!bCloseAllViewsToo ) &&
358 (aCheck2.m_lModelFrames.getLength() > 0)
359 )
360 bCloseFrame = sal_True;
361
362 else
363 // c3) there is no other (visible) frame open ...
364 // The help module will be ignored everytimes!
365 // But we have to decide if we must terminate the
366 // application or establish the backing mode now.
367 // And that depends from the dispatched URL ...
368 {
369 if (eOperation == E_CLOSE_FRAME)
370 bTerminateApp = sal_True;
371 else if( SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SSTARTMODULE) )
372 bEstablishBackingMode = sal_True;
373 else
374 bTerminateApp = sal_True;
375 }
376 }
377 }
378
379 // Do it now ...
380 sal_Bool bSuccess = sal_False;
381 if (bCloseFrame)
382 bSuccess = implts_closeFrame();
383 else
384 if (bEstablishBackingMode)
385 #if defined QUARTZ
386 {
387 // on mac close down, quickstarter keeps the process alive
388 // however if someone has shut down the quickstarter
389 // behave as any other platform
390
391 bool bQuickstarterRunning = false;
392 // get quickstart service
393 try
394 {
395 css::uno::Reference< css::beans::XFastPropertySet > xSet( xSMGR->createInstance(IMPLEMENTATIONNAME_QUICKLAUNCHER), css::uno::UNO_QUERY_THROW );
396 if( xSet.is() )
397 {
398 css::uno::Any aVal( xSet->getFastPropertyValue( 0 ) );
399 sal_Bool bState = sal_False;
400 if( aVal >>= bState )
401 bQuickstarterRunning = bState;
402 }
403 }
404 catch( css::uno::Exception& )
405 {
406 }
407 bSuccess = bQuickstarterRunning ? implts_terminateApplication() : implts_establishBackingMode();
408 }
409 #else
410 bSuccess = implts_establishBackingMode();
411 #endif
412 else
413 if (bTerminateApp)
414 bSuccess = implts_terminateApplication();
415
416 if (
417 ( ! bSuccess ) &&
418 ( bControllerSuspended )
419 )
420 {
421 css::uno::Reference< css::frame::XController > xController = xCloseFrame->getController();
422 if (xController.is())
423 xController->suspend(sal_False);
424 }
425
426 // inform listener
427 sal_Int16 nState = css::frame::DispatchResultState::FAILURE;
428 if (bSuccess)
429 nState = css::frame::DispatchResultState::SUCCESS;
430 implts_notifyResultListener(xListener, nState, css::uno::Any());
431
432 // SAFE -> ----------------------------------
433 WriteGuard aWriteLock(m_aLock);
434
435 // This method was called asynchronous from our main thread by using a pointer.
436 // We reached this method only, by using a reference to ourself :-)
437 // Further this member is used to detect still running and not yet finished
438 // ansynchronous operations. So its time now to release this reference.
439 // But hold it temp alive. Otherwhise we die before we can finish this method realy :-))
440 css::uno::Reference< css::uno::XInterface > xTempHold = m_xSelfHold;
441 m_xSelfHold.clear();
442 m_xResultListener.clear();
443
444 aWriteLock.unlock();
445 // <- SAFE ----------------------------------
446
447 }
448 catch(const css::lang::DisposedException&)
449 {
450 LOG_ERROR("CloseDispatcher::impl_asyncCallback", "Congratulation! You found the reason for bug #120310#. Please contact the right developer and show him a scenario, which trigger this bug. THX.")
451 }
452
453 return 0;
454 }
455
456 //-----------------------------------------------
implts_prepareFrameForClosing(const css::uno::Reference<css::frame::XFrame> & xFrame,sal_Bool bAllowSuspend,sal_Bool bCloseAllOtherViewsToo,sal_Bool & bControllerSuspended)457 sal_Bool CloseDispatcher::implts_prepareFrameForClosing(const css::uno::Reference< css::frame::XFrame >& xFrame ,
458 sal_Bool bAllowSuspend ,
459 sal_Bool bCloseAllOtherViewsToo,
460 sal_Bool& bControllerSuspended )
461 {
462 // Frame already dead ... so this view is closed ... is closed ... is ... .-)
463 if (! xFrame.is())
464 return sal_True;
465
466 // Close all views to the same document ... if forced to do so.
467 // But dont touch our own frame here!
468 // We must do so ... because the may be following controller->suspend()
469 // will show the "save/discard/cancel" dialog for the last view only!
470 if (bCloseAllOtherViewsToo)
471 {
472 // SAFE -> ----------------------------------
473 ReadGuard aReadLock(m_aLock);
474 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
475 aReadLock.unlock();
476 // <- SAFE ----------------------------------
477
478 css::uno::Reference< css::frame::XFramesSupplier > xDesktop(xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW);
479 FrameListAnalyzer aCheck(xDesktop, xFrame, FrameListAnalyzer::E_ALL);
480
481 sal_Int32 c = aCheck.m_lModelFrames.getLength();
482 sal_Int32 i = 0;
483 for (i=0; i<c; ++i)
484 {
485 if (!fpf::closeIt(aCheck.m_lModelFrames[i], sal_False))
486 return sal_False;
487 }
488 }
489
490 // If allowed - inform user about modified documents or
491 // still running jobs (e.g. printing).
492 if (bAllowSuspend)
493 {
494 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
495 if (xController.is()) // some views dont uses a controller .-( (e.g. the help window)
496 {
497 bControllerSuspended = xController->suspend(sal_True);
498 if (! bControllerSuspended)
499 return sal_False;
500 }
501 }
502
503 // dont remove the component realy by e.g. calling setComponent(null, null).
504 // It's enough to suspend the controller.
505 // If we close the frame later this controller doesnt show the same dialog again.
506 return sal_True;
507 }
508
509 //-----------------------------------------------
implts_closeFrame()510 sal_Bool CloseDispatcher::implts_closeFrame()
511 {
512 // SAFE -> ----------------------------------
513 ReadGuard aReadLock(m_aLock);
514 css::uno::Reference< css::frame::XFrame > xFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY);
515 aReadLock.unlock();
516 // <- SAFE ----------------------------------
517
518 // frame already dead ? => so it's closed ... it's closed ...
519 if ( ! xFrame.is() )
520 return sal_True;
521
522 // dont deliver owner ship; our "UI user" will try it again if it failed.
523 // OK - he will get an empty frame then. But normaly an empty frame
524 // should be closeable always :-)
525 if (!fpf::closeIt(xFrame, sal_False))
526 return sal_False;
527
528 // SAFE -> ----------------------------------
529 WriteGuard aWriteLock(m_aLock);
530 m_xCloseFrame = css::uno::WeakReference< css::frame::XFrame >();
531 aWriteLock.unlock();
532 // <- SAFE ----------------------------------
533
534 return sal_True;
535 }
536
537 //-----------------------------------------------
implts_establishBackingMode()538 sal_Bool CloseDispatcher::implts_establishBackingMode()
539 {
540 // SAFE -> ----------------------------------
541 ReadGuard aReadLock(m_aLock);
542 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
543 css::uno::Reference< css::frame::XFrame > xFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY);
544 aReadLock.unlock();
545 // <- SAFE ----------------------------------
546
547 if (!xFrame.is())
548 return sal_False;
549
550 css::uno::Reference < css::document::XActionLockable > xLock( xFrame, css::uno::UNO_QUERY );
551 if ( xLock.is() && xLock->isActionLocked() )
552 return sal_False;
553
554 css::uno::Reference< css::awt::XWindow > xContainerWindow = xFrame->getContainerWindow();
555 css::uno::Sequence< css::uno::Any > lArgs(1);
556 lArgs[0] <<= xContainerWindow;
557
558 css::uno::Reference< css::frame::XController > xBackingComp(
559 xSMGR->createInstanceWithArguments(SERVICENAME_STARTMODULE, lArgs),
560 css::uno::UNO_QUERY_THROW);
561
562 // Attention: You MUST(!) call setComponent() before you call attachFrame().
563 css::uno::Reference< css::awt::XWindow > xBackingWin(xBackingComp, css::uno::UNO_QUERY);
564 xFrame->setComponent(xBackingWin, xBackingComp);
565 xBackingComp->attachFrame(xFrame);
566 xContainerWindow->setVisible(sal_True);
567
568 return sal_True;
569 }
570
571 //-----------------------------------------------
implts_terminateApplication()572 sal_Bool CloseDispatcher::implts_terminateApplication()
573 {
574 // SAFE -> ----------------------------------
575 ReadGuard aReadLock(m_aLock);
576 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
577 aReadLock.unlock();
578 // <- SAFE ----------------------------------
579
580 css::uno::Reference< css::frame::XDesktop > xDesktop(
581 xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW);
582
583 return xDesktop->terminate();
584 }
585
586 //-----------------------------------------------
implts_notifyResultListener(const css::uno::Reference<css::frame::XDispatchResultListener> & xListener,sal_Int16 nState,const css::uno::Any & aResult)587 void CloseDispatcher::implts_notifyResultListener(const css::uno::Reference< css::frame::XDispatchResultListener >& xListener,
588 sal_Int16 nState ,
589 const css::uno::Any& aResult )
590 {
591 if (!xListener.is())
592 return;
593
594 css::frame::DispatchResultEvent aEvent(
595 css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY),
596 nState,
597 aResult);
598
599 xListener->dispatchFinished(aEvent);
600 }
601
602 //-----------------------------------------------
static_impl_searchRightTargetFrame(const css::uno::Reference<css::frame::XFrame> & xFrame,const::rtl::OUString & sTarget)603 css::uno::Reference< css::frame::XFrame > CloseDispatcher::static_impl_searchRightTargetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame ,
604 const ::rtl::OUString& sTarget)
605 {
606 if (sTarget.equalsIgnoreAsciiCaseAscii("_self"))
607 return xFrame;
608
609 OSL_ENSURE((sTarget.getLength() < 1), "CloseDispatch used for unexpected target. Magic things will happen now .-)");
610
611 css::uno::Reference< css::frame::XFrame > xTarget = xFrame;
612 while(sal_True)
613 {
614 // a) top frames wil be closed
615 if (xTarget->isTop())
616 return xTarget;
617
618 // b) even child frame containing top level windows (e.g. query designer of database) will be closed
619 css::uno::Reference< css::awt::XWindow > xWindow = xTarget->getContainerWindow();
620 css::uno::Reference< css::awt::XTopWindow > xTopWindowCheck(xWindow, css::uno::UNO_QUERY);
621 if (xTopWindowCheck.is())
622 {
623 // b1) Note: Toolkit interface XTopWindow sometimes is used by real VCL-child-windows also .-)
624 // Be sure that these window is realy a "top system window".
625 // Attention ! Checking Window->GetParent() isnt the right approach here.
626 // Because sometimes VCL create "implicit border windows" as parents even we created
627 // a simple XWindow using the toolkit only .-(
628 ::vos::OGuard aSolarLock(&Application::GetSolarMutex());
629 Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
630 if (
631 (pWindow ) &&
632 (pWindow->IsSystemWindow())
633 )
634 return xTarget;
635 }
636
637 // c) try to find better results on parent frame
638 // If no parent frame exists (because this frame is used outside the desktop tree)
639 // the given frame must be used directly.
640 css::uno::Reference< css::frame::XFrame > xParent(xTarget->getCreator(), css::uno::UNO_QUERY);
641 if ( ! xParent.is())
642 return xTarget;
643
644 // c1) check parent frame inside next loop ...
645 xTarget = xParent;
646 }
647 }
648
649 } // namespace framework
650