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