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