1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
30 
31 //_________________________________________________________________________________________________________________
32 //	my own includes
33 //_________________________________________________________________________________________________________________
34 
35 #include <stdio.h>
36 #include <dispatch/dispatchprovider.hxx>
37 #include <loadenv/loadenv.hxx>
38 #include <dispatch/loaddispatcher.hxx>
39 #include <dispatch/closedispatcher.hxx>
40 #include <dispatch/menudispatcher.hxx>
41 #include <dispatch/helpagentdispatcher.hxx>
42 #include <dispatch/startmoduledispatcher.hxx>
43 
44 #include <pattern/window.hxx>
45 #include <threadhelp/transactionguard.hxx>
46 #include <threadhelp/readguard.hxx>
47 #include <threadhelp/writeguard.hxx>
48 #include <dispatchcommands.h>
49 #include <protocols.h>
50 #include <services.h>
51 #include <targets.h>
52 #include <general.h>
53 
54 //_________________________________________________________________________________________________________________
55 //	interface includes
56 //_________________________________________________________________________________________________________________
57 #include <com/sun/star/frame/FrameSearchFlag.hpp>
58 #include <com/sun/star/uno/Exception.hpp>
59 #include <com/sun/star/ucb/XContentProviderManager.hpp>
60 #include <com/sun/star/document/XTypeDetection.hpp>
61 #include <com/sun/star/lang/XInitialization.hpp>
62 
63 //_________________________________________________________________________________________________________________
64 //	includes of other projects
65 //_________________________________________________________________________________________________________________
66 #include <osl/diagnose.h>
67 #include <rtl/string.h>
68 #include <rtl/ustring.hxx>
69 #include <vcl/svapp.hxx>
70 #include <rtl/ustrbuf.hxx>
71 //_________________________________________________________________________________________________________________
72 //	namespace
73 //_________________________________________________________________________________________________________________
74 
75 namespace framework{
76 
77 //_________________________________________________________________________________________________________________
78 //	non exported const
79 //_________________________________________________________________________________________________________________
80 
81 //_________________________________________________________________________________________________________________
82 //	non exported definitions
83 //_________________________________________________________________________________________________________________
84 
85 //_________________________________________________________________________________________________________________
86 //	declarations
87 //_________________________________________________________________________________________________________________
88 
89 //*****************************************************************************************************************
90 //	XInterface, XTypeProvider
91 //*****************************************************************************************************************
92 DEFINE_XINTERFACE_2( DispatchProvider                               ,
93                      OWeakObject                                    ,
94                      DIRECT_INTERFACE(css::lang::XTypeProvider     ),
95                      DIRECT_INTERFACE(css::frame::XDispatchProvider)
96                    )
97 
98 DEFINE_XTYPEPROVIDER_2( DispatchProvider             ,
99                         css::lang::XTypeProvider     ,
100                         css::frame::XDispatchProvider
101                       )
102 
103 //_________________________________________________________________________________________________________________
104 
105 /**
106     @short      standard ctor/dtor
107     @descr      These initialize a new instance of tihs class with needed informations for work.
108                 We hold a weakreference to our owner frame which start dispatches at us.
109                 We can't use a normal reference because he hold a reference of us too ...
110                 nobody can die so ...!
111 
112     @seealso    using at owner
113 
114     @param      xFactory
115                     reference to servicemanager to create new services.
116     @param      xFrame
117                     reference to our owner frame.
118 
119     @modified   17.05.2002 10:07, as96863
120 */
121 DispatchProvider::DispatchProvider( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory  ,
122                                     const css::uno::Reference< css::frame::XFrame >&              xFrame    )
123 		//	Init baseclasses first
124         : ThreadHelpBase( &Application::GetSolarMutex() )
125         , OWeakObject   (                               )
126         // Init member
127         , m_xFactory    ( xFactory                      )
128         , m_xFrame      ( xFrame                        )
129 {
130 }
131 
132 //_________________________________________________________________________________________________________________
133 
134 /**
135     @short      protected(!) dtor for deinitializing
136     @descr      We made it protected to prevent using of us as base class instead as a member.
137 
138     @modified   17.05.2002 10:05, as96863
139  */
140 DispatchProvider::~DispatchProvider()
141 {
142 }
143 
144 //_________________________________________________________________________________________________________________
145 
146 /**
147     @interface  XDispatchProvider
148     @short      search a dispatcher for given URL
149     @descr      If no interceptor is set on owner, we search for right frame and dispatch URL to it.
150                 If no frame was found, we do nothing.
151                 But we doesn't do it directly here. We detect the type of our owner frame and calls
152                 specialized queryDispatch() helper dependen from that. Because a Desktop handle some
153                 requests in another way then a normal frame.
154 
155     @param      aURL
156                     URL to dispatch.
157     @param      sTargetFrameName
158                     name of searched frame.
159     @param      nSearchFlags
160                     flags for searching.
161     @return     A reference to a dispatch object for this URL (if someone was found!).
162 
163     @threadsafe yes
164     @modified   17.05.2002 10:59, as96863
165 */
166 css::uno::Reference< css::frame::XDispatch > SAL_CALL DispatchProvider::queryDispatch( const css::util::URL&  aURL             ,
167                                                                                        const ::rtl::OUString& sTargetFrameName ,
168                                                                                              sal_Int32        nSearchFlags     ) throw( css::uno::RuntimeException )
169 {
170     css::uno::Reference< css::frame::XDispatch > xDispatcher;
171 
172     /* SAFE { */
173     ReadGuard aReadLock( m_aLock );
174     css::uno::Reference< css::frame::XFrame > xOwner( m_xFrame.get(), css::uno::UNO_QUERY );
175     aReadLock.unlock();
176     /* } SAFE */
177 
178     css::uno::Reference< css::frame::XDesktop > xDesktopCheck( xOwner, css::uno::UNO_QUERY );
179 
180     if (xDesktopCheck.is())
181         xDispatcher = implts_queryDesktopDispatch(xOwner, aURL, sTargetFrameName, nSearchFlags);
182     else
183         xDispatcher = implts_queryFrameDispatch(xOwner, aURL, sTargetFrameName, nSearchFlags);
184 
185     return xDispatcher;
186 }
187 
188 //_________________________________________________________________________________________________________________
189 
190 /**
191     @interface  XDispatchProvider
192     @short      do the same like queryDispatch() ... but handle multiple dispatches at the same time
193     @descr      It's an optimism. User give us a list of queries ... and we return a list of dispatcher.
194                 If one of given queries couldn't be solved to a real existing dispatcher ...
195                 we return a list with empty references in it! Order of both lists will be retained!
196 
197     @seealso    method queryDispatch()
198 
199     @param      lDescriptions
200                     a list of all dispatch parameters for multiple requests
201     @return     A reference a list of dispatch objects for these URLs - may with some <NULL/> values inside.
202 
203     @threadsafe yes
204     @modified   17.05.2002 09:55, as96863
205 */
206 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL DispatchProvider::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptions ) throw( css::uno::RuntimeException )
207 {
208     // Create return list - which must have same size then the given descriptor
209     // It's not allowed to pack it!
210     sal_Int32                                                          nCount     = lDescriptions.getLength();
211     css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount );
212 
213     // Step over all descriptors and try to get any dispatcher for it.
214     for( sal_Int32 i=0; i<nCount; ++i )
215     {
216         lDispatcher[i] = queryDispatch( lDescriptions[i].FeatureURL  ,
217                                         lDescriptions[i].FrameName   ,
218                                         lDescriptions[i].SearchFlags );
219     }
220 
221     return lDispatcher;
222 }
223 
224 //_________________________________________________________________________________________________________________
225 
226 ::sal_Bool lcl_isStartModuleDispatch (const css::util::URL& aURL)
227 {
228     return (aURL.Complete.equals(CMD_UNO_SHOWSTARTMODULE));
229 }
230 
231 //_________________________________________________________________________________________________________________
232 
233 /**
234     @short      helper for queryDispatch()
235     @descr      Every member of the frame tree (frame, desktop) must handle such request
236                 in another way. So we implement different specialized metods for every one.
237 
238     @threadsafe yes
239     @modified   20.08.2003 08:32, as96863
240  */
241 css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_queryDesktopDispatch( const css::uno::Reference< css::frame::XFrame > xDesktop         ,
242                                                                                             const css::util::URL&                           aURL             ,
243                                                                                             const ::rtl::OUString&                          sTargetFrameName ,
244                                                                                                   sal_Int32                                 nSearchFlags     )
245 {
246     css::uno::Reference< css::frame::XDispatch > xDispatcher;
247 
248     // ignore wrong requests which are not supported
249     if (
250         (sTargetFrameName==SPECIALTARGET_MENUBAR  )   ||    // valid for frame dispatches - not for desktop
251         (sTargetFrameName==SPECIALTARGET_HELPAGENT)   ||    // valid for frame dispatches - not for desktop
252         (sTargetFrameName==SPECIALTARGET_PARENT   )   ||    // we have no parent by definition
253         (sTargetFrameName==SPECIALTARGET_BEAMER   )         // beamer frames are allowed as child of tasks only -
254                                                             // and they exist more then ones. We have no idea which our sub tasks is the right one
255        )
256     {
257         return NULL;
258     }
259 
260     //-----------------------------------------------------------------------------------------------------
261     // I) handle special cases which not right for using findFrame() first
262     //-----------------------------------------------------------------------------------------------------
263 
264     //-----------------------------------------------------------------------------------------------------
265     // I.I) "_blank"
266     //  It's not the right place to create a new task here - because we are queried for a dispatch object
267     //  only, which can handle such request. Such dispatcher should create the required task on demand.
268     //  Normaly the functionality for "_blank" is provided by findFrame() - but that would create it directly
269     //  here. Thats why we must "intercept" here.
270     //-----------------------------------------------------------------------------------------------------
271     if (sTargetFrameName==SPECIALTARGET_BLANK)
272     {
273         if (implts_isLoadableContent(aURL))
274             xDispatcher = implts_getOrCreateDispatchHelper( E_BLANKDISPATCHER, xDesktop );
275     }
276 
277     //-----------------------------------------------------------------------------------------------------
278     // I.II) "_default"
279     //  This is a combination of search an empty task for recycling - or create a new one.
280     //-----------------------------------------------------------------------------------------------------
281     else
282     if (sTargetFrameName==SPECIALTARGET_DEFAULT)
283     {
284         if (implts_isLoadableContent(aURL))
285             xDispatcher = implts_getOrCreateDispatchHelper( E_DEFAULTDISPATCHER, xDesktop );
286 
287         if (lcl_isStartModuleDispatch(aURL))
288             xDispatcher = implts_getOrCreateDispatchHelper( E_STARTMODULEDISPATCHER, xDesktop );
289     }
290 
291     //-----------------------------------------------------------------------------------------------------
292     // I.III) "_self", "", "_top"
293     //  The desktop can't load any document - but he can handle some special protocols like "uno", "slot" ...
294     //  Why is "top" here handled too? Because the desktop is the topest frame. Normaly it's superflous
295     //  to use this target - but we can handle it in the same manner then "_self".
296     //-----------------------------------------------------------------------------------------------------
297     else
298     if (
299         (sTargetFrameName==SPECIALTARGET_SELF)  ||
300         (sTargetFrameName==SPECIALTARGET_TOP )  ||
301         (sTargetFrameName.getLength()<1      )
302        )
303     {
304         xDispatcher = implts_searchProtocolHandler(aURL);
305     }
306 
307     //-----------------------------------------------------------------------------------------------------
308     // I.IV) no further special targets exist
309     //  Now we have to search for the right target frame by calling findFrame() - but should provide our code
310     //  against creation of a new task if no frame could be found.
311     //  I said it b efore - it's allowed for dispatch() only.
312     //-----------------------------------------------------------------------------------------------------
313     else
314     {
315         sal_Int32 nRightFlags  = nSearchFlags;
316                   nRightFlags &= ~css::frame::FrameSearchFlag::CREATE;
317 
318         // try to find any existing target and ask him for his dispatcher
319         css::uno::Reference< css::frame::XFrame > xFoundFrame = xDesktop->findFrame(sTargetFrameName, nRightFlags);
320         if (xFoundFrame.is())
321         {
322             css::uno::Reference< css::frame::XDispatchProvider > xProvider( xFoundFrame, css::uno::UNO_QUERY );
323             xDispatcher = xProvider->queryDispatch(aURL,SPECIALTARGET_SELF,0);
324         }
325         else
326         // if it couldn't be found - but creation was allowed
327         // use special dispatcher for creatio or froward it to the browser
328         if (nSearchFlags & css::frame::FrameSearchFlag::CREATE)
329             xDispatcher = implts_getOrCreateDispatchHelper( E_CREATEDISPATCHER, xDesktop, sTargetFrameName, nSearchFlags );
330     }
331 
332     return xDispatcher;
333 }
334 
335 //_________________________________________________________________________________________________________________
336 
337 css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_queryFrameDispatch( const css::uno::Reference< css::frame::XFrame > xFrame           ,
338                                                                                           const css::util::URL&                           aURL             ,
339                                                                                           const ::rtl::OUString&                          sTargetFrameName ,
340                                                                                                 sal_Int32                                 nSearchFlags     )
341 {
342     css::uno::Reference< css::frame::XDispatch > xDispatcher;
343 
344     //-----------------------------------------------------------------------------------------------------
345     // 0) Some URLs are dispatched in a generic way (e.g. by the menu) using the default target "".
346     //    But they are specified to use her own fix target. Detect such URLs here and use the correct target.
347     //-----------------------------------------------------------------------------------------------------
348 
349     ::rtl::OUString sTargetName = sTargetFrameName;
350 
351     //-----------------------------------------------------------------------------------------------------
352     // I) handle special cases which not right for using findFrame() first
353     //-----------------------------------------------------------------------------------------------------
354 
355     //-----------------------------------------------------------------------------------------------------
356     // I.I) "_blank", "_default"
357     //  It's not the right place to create a new task here. Only the desktop can do that.
358     //  Normaly the functionality for "_blank" is provided by findFrame() - but that would create it directly
359     //  here. Thats why we must "intercept" here.
360     //-----------------------------------------------------------------------------------------------------
361     if (
362         (sTargetName==SPECIALTARGET_BLANK  ) ||
363         (sTargetName==SPECIALTARGET_DEFAULT)
364        )
365     {
366         css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY );
367         if (xParent.is())
368             xDispatcher = xParent->queryDispatch(aURL, sTargetName, 0); // its a special target - ignore search flags
369     }
370 
371     //-----------------------------------------------------------------------------------------------------
372     // I.II) "_menubar"
373     //  Special mode on frame or task to receive the local menu. Not supported by findFrame()
374     //-----------------------------------------------------------------------------------------------------
375     else
376     if (sTargetName==SPECIALTARGET_MENUBAR)
377     {
378         xDispatcher = implts_getOrCreateDispatchHelper( E_MENUDISPATCHER, xFrame );
379     }
380 
381     //-----------------------------------------------------------------------------------------------------
382     // I.III) "_helpagent"
383     //  Special mode on frame or task to start the help agent.
384     //  It's defined for top level frames only.
385     //-----------------------------------------------------------------------------------------------------
386     else
387     if (sTargetName==SPECIALTARGET_HELPAGENT)
388     {
389 		if (WindowHelper::isTopWindow(xFrame->getContainerWindow()))
390             xDispatcher = implts_getOrCreateDispatchHelper( E_HELPAGENTDISPATCHER, xFrame );
391         else
392         {
393             // Don''t use findFrame() here - because it's not possible to find
394             // a top lebel frame without knowing his name. And a frame with name
395             // "" can't be realy searched! That's why forward query to any parent
396             // explicitly.
397             css::uno::Reference< css::frame::XDispatchProvider > xProvider( xFrame->getCreator(), css::uno::UNO_QUERY );
398             if (xProvider.is())
399                 xDispatcher = xProvider->queryDispatch(aURL,SPECIALTARGET_HELPAGENT,0);
400         }
401     }
402 
403     //-----------------------------------------------------------------------------------------------------
404     // I.IV) "_helpagent"
405     //  Special sub frame of a top frame only. Search or create it. ... OK it's currently a little bit HACKI.
406     //  Only the sfx (means the controller) can create it it.
407     //-----------------------------------------------------------------------------------------------------
408     else
409     if (sTargetName==SPECIALTARGET_BEAMER)
410     {
411         css::uno::Reference< css::frame::XDispatchProvider > xBeamer( xFrame->findFrame( SPECIALTARGET_BEAMER, css::frame::FrameSearchFlag::CHILDREN | css::frame::FrameSearchFlag::SELF ), css::uno::UNO_QUERY );
412         if (xBeamer.is())
413         {
414             xDispatcher = xBeamer->queryDispatch(aURL, SPECIALTARGET_SELF, 0);
415         }
416         else
417         {
418             css::uno::Reference< css::frame::XDispatchProvider > xController( xFrame->getController(), css::uno::UNO_QUERY );
419             if (xController.is())
420 				// force using of special target - but use original search flags
421 				// May the caller used the CREATE flag or not!
422                 xDispatcher = xController->queryDispatch(aURL, SPECIALTARGET_BEAMER, nSearchFlags);
423         }
424     }
425 
426     //-----------------------------------------------------------------------------------------------------
427     // I.V) "_parent"
428     //  Our parent frame (if it exist) should handle this URL.
429     //-----------------------------------------------------------------------------------------------------
430     else
431     if (sTargetName==SPECIALTARGET_PARENT)
432     {
433         css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY );
434         if (xParent.is())
435             // SELF => we must adress the parent directly... and not his parent or any other parent!
436             xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_SELF, 0);
437     }
438 
439     //-----------------------------------------------------------------------------------------------------
440     // I.VI) "_top"
441     //  This request must be forwarded to any parent frame, till we reach a top frame.
442     //  If no parent exist, we can handle itself.
443     //-----------------------------------------------------------------------------------------------------
444     else
445     if (sTargetName==SPECIALTARGET_TOP)
446     {
447         if (xFrame->isTop())
448         {
449             // If we are this top frame itself (means our owner frame)
450             // we should call ourself recursiv with a better target "_self".
451             // So we can share the same code! (see reaction for "_self" inside this method too.)
452             xDispatcher = this->queryDispatch(aURL,SPECIALTARGET_SELF,0);
453         }
454         else
455         {
456             css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY );
457             // Normaly if isTop() returned sal_False ... the parent frame MUST(!) exist ...
458             // But it seams to be better to check that here to prevent us against an access violation.
459             if (xParent.is())
460                 xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_TOP, 0);
461         }
462     }
463 
464     //-----------------------------------------------------------------------------------------------------
465     // I.VII) "_self", ""
466     //  Our owner frame should handle this URL. But we can't do it for all of them.
467     //  So we ask the internal setted controller first. If he disagree we try to find a registered
468     //  protocol handler. If this failed too - we check for a loadable content and in case of true
469     //  we load it into the frame by returning specilized dispatch object.
470     //-----------------------------------------------------------------------------------------------------
471     else
472     if (
473         (sTargetName==SPECIALTARGET_SELF)  ||
474         (sTargetName.getLength()<1      )
475        )
476     {
477         // There exist a hard coded interception for special URLs.
478         if (
479             (aURL.Complete.equalsAscii(".uno:CloseDoc"  )) ||
480             (aURL.Complete.equalsAscii(".uno:CloseWin"  ))
481            )
482         {
483             css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY );
484             // In case the frame is not a top one, is not based on system window and has a parent,
485             // the parent frame should to be queried for the correct dispatcher.
486             // See i93473
487             if (
488                 !WindowHelper::isTopWindow(xFrame->getContainerWindow()) &&
489                 !VCLUnoHelper::GetWindow(xFrame->getContainerWindow())->IsSystemWindow() &&
490                 xParent.is()
491                )
492                 xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_SELF, 0);
493             else
494                 xDispatcher = implts_getOrCreateDispatchHelper( E_CLOSEDISPATCHER, xFrame );
495         }
496         else if (aURL.Complete.equalsAscii(".uno:CloseFrame"))
497             xDispatcher = implts_getOrCreateDispatchHelper( E_CLOSEDISPATCHER, xFrame );
498 
499 		if ( ! xDispatcher.is())
500 		{
501 			// Ask our controller for his agreement for these dispatched URL ...
502 			// because some URLs are internal and can be handled faster by SFX - which most is the current controller!
503 			// But in case of e.g. the bibliography not all queries will be handled successfully here.
504 			css::uno::Reference< css::frame::XDispatchProvider > xController( xFrame->getController(), css::uno::UNO_QUERY );
505 			if (xController.is())
506 				xDispatcher = xController->queryDispatch(aURL, SPECIALTARGET_SELF, 0);
507 		}
508 
509 		// If controller has no fun to dispatch these URL - we must search another right dispatcher.
510 		// Search for any registered protocol handler first.
511 		if (!xDispatcher.is())
512 			xDispatcher = implts_searchProtocolHandler(aURL);
513 
514 		// Not for controller - not for protocol handler
515 		// It should be a loadable content - may be a file. Check it ...
516 		// This check is neccessary to found out, that
517 		// support for some protocols isn't installed by user. May be
518 		// "ftp" isn't available. So we suppress creation of our self dispatcher.
519 		// The result will be clear. He can't handle it - but he would try it.
520 		if (
521 			( ! xDispatcher.is()             )  &&
522 			( implts_isLoadableContent(aURL) )
523 		   )
524 		{
525 			xDispatcher = implts_getOrCreateDispatchHelper( E_SELFDISPATCHER, xFrame );
526 		}
527     }
528 
529     //-----------------------------------------------------------------------------------------------------
530     // I.VI) no further special handlings exist
531     //  Now we have to search for the right target frame by calling findFrame() - but should provide our code
532     //  against creation of a new task if no frame could be found.
533     //  I said it before - it's allowed for dispatch() only.
534     //-----------------------------------------------------------------------------------------------------
535     else
536     {
537         sal_Int32 nRightFlags  = nSearchFlags;
538                   nRightFlags &= ~css::frame::FrameSearchFlag::CREATE;
539 
540         // try to find any existing target and ask him for his dispatcher
541         css::uno::Reference< css::frame::XFrame > xFoundFrame = xFrame->findFrame(sTargetName, nRightFlags);
542         if (xFoundFrame.is())
543         {
544 			// Attention: Found target is our own owner frame!
545 			// Don't ask him for his dispatcher. We know it already - it's our self dispatch helper.
546 			// Otherwhise we can start a never ending recursiv call. Why?
547 			// Somewere called our owner frame - he called some interceptor objects - and may by this dispatch provider
548 			// is called. If wa use queryDispatch() on our owner frame again - we start this call stack again ... and again.
549 			if (xFoundFrame==xFrame)
550 		        xDispatcher = implts_getOrCreateDispatchHelper( E_SELFDISPATCHER, xFrame );
551 			else
552 			{
553 				css::uno::Reference< css::frame::XDispatchProvider > xProvider( xFoundFrame, css::uno::UNO_QUERY );
554 				xDispatcher = xProvider->queryDispatch(aURL,SPECIALTARGET_SELF,0);
555 			}
556         }
557         else
558         // if it couldn't be found - but creation was allowed
559         // forward request to the desktop.
560         // Note: The given target name must be used to set the name on new created task!
561         //       Don't forward request by changing it to a special one e.g _blank.
562         //       Use the CREATE flag only to prevent call against further searches.
563         //       We already know it - the target must be created new.
564         if (nSearchFlags & css::frame::FrameSearchFlag::CREATE)
565         {
566             css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY );
567             if (xParent.is())
568                 xDispatcher = xParent->queryDispatch(aURL, sTargetName, css::frame::FrameSearchFlag::CREATE);
569         }
570     }
571 
572     return xDispatcher;
573 }
574 
575 //_________________________________________________________________________________________________________________
576 
577 /**
578     @short      search for a registered protocol handler and ask him for a dispatch object
579     @descr      Wes earch a suitable handler inside our cfg package org.openoffice.Office.ProtocolHandler.
580                 If we found anyone, we create and initialize it. Initialize means: we set our owner frame on it
581                 as context information. He can use it or leave it. Of course - we are aware of handler implementations,
582                 which doesn't support initialization. It's an optional feature.
583 
584     @param      aURL
585                     the dispatch URL for which may a handler is registered
586 
587     @return     A dispatch object if a handler was found and agree with the given URL or <NULL/> otherwhise.
588 
589     @threadsafe yes
590     @modified   05.09.2002 13:43, as96863
591 */
592 css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_searchProtocolHandler( const css::util::URL& aURL )
593 {
594     css::uno::Reference< css::frame::XDispatch > xDispatcher;
595     ProtocolHandler                              aHandler   ;
596 
597     // This member is threadsafe by himself and lives if we live - we doesn't need any mutex here.
598     if (m_aProtocolHandlerCache.search(aURL,&aHandler))
599     {
600         /* SAFE { */
601         ReadGuard aReadLock( m_aLock );
602 
603         // create it
604         css::uno::Reference< css::frame::XDispatchProvider > xHandler;
605         try
606         {
607             xHandler = css::uno::Reference< css::frame::XDispatchProvider >(
608                             m_xFactory->createInstance(aHandler.m_sUNOName),
609                             css::uno::UNO_QUERY);
610         }
611         catch(css::uno::Exception&) {}
612 
613         // look if initialization is neccessary
614         css::uno::Reference< css::lang::XInitialization > xInit( xHandler, css::uno::UNO_QUERY );
615         if (xInit.is())
616         {
617             css::uno::Reference< css::frame::XFrame > xOwner( m_xFrame.get(), css::uno::UNO_QUERY );
618             LOG_ASSERT(xOwner.is(), "DispatchProvider::implts_searchProtocolHandler()\nCouldn't get reference to my owner frame. So I can't set may needed context information for this protocol handler.")
619             if (xOwner.is())
620             {
621                 try
622                 {
623                     // but do it only, if all context informations are OK
624                     css::uno::Sequence< css::uno::Any > lContext(1);
625                     lContext[0] <<= xOwner;
626                     xInit->initialize(lContext);
627                 }
628                 catch(css::uno::Exception&) {}
629             }
630         }
631 
632         aReadLock.unlock();
633         /* } SAFE */
634 
635         // ask for his (sub)dispatcher for the given URL
636         if (xHandler.is())
637             xDispatcher = xHandler->queryDispatch(aURL,SPECIALTARGET_SELF,0);
638     }
639 
640     return xDispatcher;
641 }
642 
643 //_________________________________________________________________________________________________________________
644 
645 /**
646     @short      get or create new dispatch helper
647     @descr      Sometimes we need some helper implementations to support dispatching of special URLs or commands.
648                 But it's not a good idea to hold these services for the whole life time of this provider instance.
649                 We should create it on demand ...
650                 Thats why we implement this method. It return an already existing helper or create a new one otherwise.
651 
652     @attention  The parameter sTarget and nSearchFlags are defaulted to "" and 0!
653                 Please use it only, if you can be shure, that the realy given by the outside calli!
654                 Mostly it depends from the parameter eHelper is they are required or not.
655 
656     @param      eHelper
657                     specify the requested dispatch helper
658     @param      xOwner
659                     the target of possible dispatch() call on created dispatch helper
660     @param      sTarget
661                     the target parameter of the original queryDispatch() request
662     @param      nSearchFlags
663                     the flags parameter of the original queryDispatch() request
664     @return     A reference to a dispatch helper.
665 
666     @threadsafe yes
667     @modified   20.08.2003 10:22, as96863
668 */
669 css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_getOrCreateDispatchHelper( EDispatchHelper                                  eHelper     ,
670                                                                                                  const css::uno::Reference< css::frame::XFrame >& xOwner      ,
671                                                                                                  const ::rtl::OUString&                           sTarget     ,
672                                                                                                        sal_Int32                                  nSearchFlags)
673 {
674     css::uno::Reference< css::frame::XDispatch > xDispatchHelper;
675 
676     /* SAFE { */
677     ReadGuard aReadLock( m_aLock );
678     css::uno::Reference< css::lang::XMultiServiceFactory > xFactory = m_xFactory;
679     aReadLock.unlock();
680     /* } SAFE */
681 
682     switch (eHelper)
683     {
684         case E_MENUDISPATCHER :
685                 {
686                     // Attention: Such menue dispatcher must be a singleton for this frame - means our owner frame.
687                     // Otherwhise he can make some trouble.
688                     /* SAFE { */
689                     WriteGuard aWriteLock( m_aLock );
690                     if ( ! m_xMenuDispatcher.is() )
691                     {
692                         MenuDispatcher* pDispatcher = new MenuDispatcher( xFactory, xOwner );
693                         m_xMenuDispatcher = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY );
694                     }
695                     xDispatchHelper = m_xMenuDispatcher;
696                     aWriteLock.unlock();
697                     /* } SAFE */
698                 }
699                 break;
700 
701         case E_HELPAGENTDISPATCHER :
702                 {
703                     // Attention: It's not a good idea to create this help agent twice for the same frame (window)
704                     // May it will be shown twice too - and user activate the first one. Then he get the corresponding
705                     // help window ... but there exist another help agent window on bottom side of the frame window.
706                     // It's superflous. Create it on demand - but hold it alive till this provider dies.
707                     /* SAFE { */
708                     WriteGuard aWriteLock( m_aLock );
709                     if ( ! m_xHelpAgentDispatcher.is() )
710                     {
711                         HelpAgentDispatcher* pDispatcher = new HelpAgentDispatcher( xOwner );
712                         m_xHelpAgentDispatcher = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY );
713                     }
714                     xDispatchHelper = m_xHelpAgentDispatcher;
715                     aWriteLock.unlock();
716                     /* } SAFE */
717                 }
718                 break;
719 
720         case E_CREATEDISPATCHER :
721                 {
722                     LoadDispatcher* pDispatcher = new LoadDispatcher(xFactory, xOwner, sTarget, nSearchFlags);
723                     xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY );
724                 }
725                 break;
726 
727         case E_BLANKDISPATCHER :
728                 {
729                     css::uno::Reference< css::frame::XFrame > xDesktop( xOwner, css::uno::UNO_QUERY );
730                     if (xDesktop.is())
731                     {
732                         LoadDispatcher* pDispatcher = new LoadDispatcher(xFactory, xOwner, SPECIALTARGET_BLANK, 0);
733                         xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY );
734                     }
735                 }
736                 break;
737 
738         case E_DEFAULTDISPATCHER :
739                 {
740                     css::uno::Reference< css::frame::XFrame > xDesktop( xOwner, css::uno::UNO_QUERY );
741                     if (xDesktop.is())
742                     {
743                         LoadDispatcher* pDispatcher = new LoadDispatcher(xFactory, xOwner, SPECIALTARGET_DEFAULT, 0);
744                         xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY );
745                     }
746                 }
747                 break;
748 
749         case E_SELFDISPATCHER :
750                 {
751                     LoadDispatcher* pDispatcher = new LoadDispatcher(xFactory, xOwner, SPECIALTARGET_SELF, 0);
752                     xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY );
753                 }
754                 break;
755 
756         case E_CLOSEDISPATCHER :
757                 {
758                     CloseDispatcher* pDispatcher = new CloseDispatcher( xFactory, xOwner, sTarget );
759                     xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY );
760                 }
761                 break;
762 
763         case E_STARTMODULEDISPATCHER :
764                 {
765                     StartModuleDispatcher* pDispatcher = new StartModuleDispatcher( xFactory, xOwner, sTarget );
766                     xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY );
767                 }
768                 break;
769     }
770 
771     return xDispatchHelper;
772 }
773 
774 //_________________________________________________________________________________________________________________
775 
776 /**
777     @short      check URL for support by our used loader or handler
778     @descr      If we must return our own dispatch helper implementations (self, blank, create dispatcher!)
779                 we should be shure, that URL describe any loadable content. Otherwise slot/uno URLs
780                 will be detected ... but there exist nothing for ral loading into a target frame!
781 
782     @param      aURL
783                     URL which should be "detected"
784     @return     <TRUE/> if somewhere could handle that - <FALSE/> otherwise.
785 
786     @threadsafe yes
787     @modified   17.05.2002 09:47, as96863
788 */
789 sal_Bool DispatchProvider::implts_isLoadableContent( const css::util::URL& aURL )
790 {
791     LoadEnv::EContentType eType = LoadEnv::classifyContent(aURL.Complete, css::uno::Sequence< css::beans::PropertyValue >());
792     return ( eType == LoadEnv::E_CAN_BE_LOADED );
793 }
794 
795 } // namespace framework
796