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