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