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