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