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 10cdf0e10cSrcweir * 11*6d739b60SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 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. 19cdf0e10cSrcweir * 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 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 //----------------------------------------------- 104cdf0e10cSrcweir CloseDispatcher::~CloseDispatcher() 105cdf0e10cSrcweir { 106cdf0e10cSrcweir } 107cdf0e10cSrcweir 108cdf0e10cSrcweir //----------------------------------------------- 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 //----------------------------------------------- 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 //----------------------------------------------- 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 //----------------------------------------------- 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 //----------------------------------------------- 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 //----------------------------------------------- 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 */ 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 //----------------------------------------------- 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 //----------------------------------------------- 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 //----------------------------------------------- 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 //----------------------------------------------- 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 //----------------------------------------------- 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 //----------------------------------------------- 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