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