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