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