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