/src/libreoffice/framework/source/dispatch/dispatchprovider.cxx
Line | Count | Source |
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/dispatchprovider.hxx> |
21 | | #include <loadenv/loadenv.hxx> |
22 | | #include <dispatch/loaddispatcher.hxx> |
23 | | #include <dispatch/closedispatcher.hxx> |
24 | | #include <dispatch/startmoduledispatcher.hxx> |
25 | | |
26 | | #include <pattern/window.hxx> |
27 | | #include <targets.h> |
28 | | #include "isstartmoduledispatch.hxx" |
29 | | |
30 | | #include <com/sun/star/frame/XDesktop.hpp> |
31 | | #include <com/sun/star/frame/FrameSearchFlag.hpp> |
32 | | #include <com/sun/star/uno/Exception.hpp> |
33 | | #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
34 | | #include <com/sun/star/lang/XInitialization.hpp> |
35 | | #include <com/sun/star/util/XCacheInfo.hpp> |
36 | | |
37 | | #include <rtl/ustring.hxx> |
38 | | #include <utility> |
39 | | #include <vcl/svapp.hxx> |
40 | | #include <sal/log.hxx> |
41 | | #include <framework/dispatchhelper.hxx> |
42 | | |
43 | | namespace framework{ |
44 | | |
45 | | /** |
46 | | @short standard ctor/dtor |
47 | | @descr These initialize a new instance of this class with needed information for work. |
48 | | We hold a weak reference to our owner frame which starts dispatches to us. |
49 | | We can't use a normal reference because it holds a reference of us, too - |
50 | | nobody can die so ...! |
51 | | |
52 | | @seealso using at owner |
53 | | |
54 | | @param rxContext |
55 | | reference to servicemanager to create new services. |
56 | | @param xFrame |
57 | | reference to our owner frame. |
58 | | */ |
59 | | DispatchProvider::DispatchProvider( css::uno::Reference< css::uno::XComponentContext > xContext , |
60 | | const css::uno::Reference< css::frame::XFrame >& xFrame ) |
61 | 7.17k | : m_xContext (std::move( xContext )) |
62 | 7.17k | , m_xFrame ( xFrame ) |
63 | 7.17k | { |
64 | 7.17k | } |
65 | | |
66 | | /** |
67 | | @short protected(!) dtor for deinitializing |
68 | | @descr We made it protected to prevent using us as a base class instead of as a member. |
69 | | */ |
70 | | DispatchProvider::~DispatchProvider() |
71 | 3.28k | { |
72 | 3.28k | } |
73 | | |
74 | | /** |
75 | | @interface XDispatchProvider |
76 | | @short search a dispatcher for given URL |
77 | | @descr If no interceptor is set on owner, we search for the correct frame and dispatch URL to it. |
78 | | If no frame was found, we do nothing. |
79 | | But we don't do it directly here. We detect the type of our owner frame and call |
80 | | a specialized queryDispatch() helper. Because a Desktop handles some |
81 | | requests in a different way than a normal frame. |
82 | | |
83 | | @param aURL |
84 | | URL to dispatch. |
85 | | @param sTargetFrameName |
86 | | name of searched frame. |
87 | | @param nSearchFlags |
88 | | flags for searching. |
89 | | @return A reference to a dispatch object for this URL (if one was found!). |
90 | | |
91 | | @threadsafe yes |
92 | | */ |
93 | | css::uno::Reference< css::frame::XDispatch > SAL_CALL DispatchProvider::queryDispatch( const css::util::URL& aURL , |
94 | | const OUString& sTargetFrameName , |
95 | | sal_Int32 nSearchFlags ) |
96 | 0 | { |
97 | 0 | css::uno::Reference< css::frame::XDispatch > xDispatcher; |
98 | |
|
99 | 0 | css::uno::Reference< css::frame::XFrame > xOwner(m_xFrame); |
100 | |
|
101 | 0 | css::uno::Reference< css::frame::XDesktop > xDesktopCheck( xOwner, css::uno::UNO_QUERY ); |
102 | |
|
103 | 0 | if (xDesktopCheck.is()) |
104 | 0 | xDispatcher = implts_queryDesktopDispatch(xOwner, aURL, sTargetFrameName, nSearchFlags); |
105 | 0 | else |
106 | 0 | xDispatcher = implts_queryFrameDispatch(xOwner, aURL, sTargetFrameName, nSearchFlags); |
107 | |
|
108 | 0 | return xDispatcher; |
109 | 0 | } |
110 | | |
111 | | /** |
112 | | @interface XDispatchProvider |
113 | | @short do the same as queryDispatch(), but handle multiple dispatches at the same time |
114 | | @descr It's optimistic. The user gives us a list of queries and we return a list of dispatchers. |
115 | | If one of the given queries couldn't be solved to an actually existing dispatcher, |
116 | | we return an empty reference for that entry. Order of both lists will be retained! |
117 | | |
118 | | @seealso method queryDispatch() |
119 | | |
120 | | @param lDescriptions |
121 | | a list of all dispatch parameters for multiple requests |
122 | | @return A reference to a list of dispatch objects for these URLs - may have some <NULL/> values inside. |
123 | | |
124 | | @threadsafe yes |
125 | | */ |
126 | | css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL DispatchProvider::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptions ) |
127 | 0 | { |
128 | | // Create return list - which must have the same size as the given descriptor. |
129 | | // It's not allowed to pack it! |
130 | 0 | sal_Int32 nCount = lDescriptions.getLength(); |
131 | 0 | css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount ); |
132 | 0 | auto lDispatcherRange = asNonConstRange(lDispatcher); |
133 | | // Step over all descriptors and try to get a dispatcher for it. |
134 | 0 | for( sal_Int32 i=0; i<nCount; ++i ) |
135 | 0 | { |
136 | 0 | lDispatcherRange[i] = queryDispatch( lDescriptions[i].FeatureURL , |
137 | 0 | lDescriptions[i].FrameName , |
138 | 0 | lDescriptions[i].SearchFlags ); |
139 | 0 | } |
140 | |
|
141 | 0 | return lDispatcher; |
142 | 0 | } |
143 | | |
144 | | /** |
145 | | @short helper for queryDispatch() |
146 | | @descr Every member of the frame tree (frame, desktop) may handle such a request |
147 | | in a different way. So we implement different specialized methods for everyone. |
148 | | |
149 | | @threadsafe yes |
150 | | */ |
151 | | css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_queryDesktopDispatch( const css::uno::Reference< css::frame::XFrame >& xDesktop , |
152 | | const css::util::URL& aURL , |
153 | | const OUString& sTargetFrameName , |
154 | | sal_Int32 nSearchFlags ) |
155 | 0 | { |
156 | 0 | css::uno::Reference< css::frame::XDispatch > xDispatcher; |
157 | | |
158 | | // ignore wrong requests which are not supported |
159 | 0 | if ( |
160 | 0 | (sTargetFrameName==SPECIALTARGET_PARENT ) || // We have no parent by definition |
161 | 0 | (sTargetFrameName==SPECIALTARGET_BEAMER ) // Beamer frames are allowed as children of tasks only - |
162 | | // and they exist more than once. We have no idea which of our sub tasks is the right one |
163 | 0 | ) |
164 | 0 | { |
165 | 0 | return nullptr; |
166 | 0 | } |
167 | | |
168 | | // I) First handle special cases which are not suited for using findFrame() |
169 | | |
170 | | // I.I) "_blank" |
171 | | // It's not the right place to create a new task here - because we are queried for a dispatch object |
172 | | // only, which can handle such request. Such a dispatcher should create the required task on demand. |
173 | | // Normally the functionality for "_blank" is provided by findFrame(), but that would create it directly |
174 | | // here. That's why we must "intercept" here. |
175 | | |
176 | 0 | if (sTargetFrameName==SPECIALTARGET_BLANK) |
177 | 0 | { |
178 | 0 | if (implts_isLoadableContent(aURL)) |
179 | 0 | xDispatcher = implts_getOrCreateDispatchHelper( E_BLANKDISPATCHER, xDesktop ); |
180 | 0 | } |
181 | | |
182 | | // I.II) "_default" |
183 | | // This is a combination of searching an empty task for recycling or creating a new one. |
184 | | |
185 | 0 | else if (sTargetFrameName==SPECIALTARGET_DEFAULT) |
186 | 0 | { |
187 | 0 | if (implts_isLoadableContent(aURL)) |
188 | 0 | xDispatcher = implts_getOrCreateDispatchHelper( E_DEFAULTDISPATCHER, xDesktop ); |
189 | |
|
190 | 0 | if (isStartModuleDispatch(aURL)) |
191 | 0 | xDispatcher = implts_getOrCreateDispatchHelper( E_STARTMODULEDISPATCHER, xDesktop ); |
192 | 0 | } |
193 | | |
194 | | // I.III) "_self", "", "_top" |
195 | | // The desktop can't load any document, but it can handle some special protocols like "uno", "slot" ... |
196 | | // Why is "top" handled here as well? Because the desktop is the topmost frame. Normally it's superfluous |
197 | | // to use this target, but we can handle it in the same manner as "_self". |
198 | | |
199 | 0 | else if ( |
200 | 0 | (sTargetFrameName==SPECIALTARGET_SELF) || |
201 | 0 | (sTargetFrameName==SPECIALTARGET_TOP ) || |
202 | 0 | (sTargetFrameName.isEmpty()) |
203 | 0 | ) |
204 | 0 | { |
205 | 0 | xDispatcher = implts_searchProtocolHandler(aURL); |
206 | 0 | } |
207 | | |
208 | | // I.IV) no further special targets exist |
209 | | // Now we have to search for the right target frame by calling findFrame(), but should provide our code |
210 | | // against the creation of a new task if no frame could be found. |
211 | | // As mentioned earlier, it's allowed for dispatch() only. |
212 | | |
213 | 0 | else |
214 | 0 | { |
215 | 0 | sal_Int32 nRightFlags = nSearchFlags & ~css::frame::FrameSearchFlag::CREATE; |
216 | | |
217 | | // try to find any existing target and ask it for its dispatcher |
218 | 0 | css::uno::Reference< css::frame::XFrame > xFoundFrame = xDesktop->findFrame(sTargetFrameName, nRightFlags); |
219 | 0 | if (xFoundFrame.is()) |
220 | 0 | { |
221 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xProvider( xFoundFrame, css::uno::UNO_QUERY ); |
222 | 0 | xDispatcher = xProvider->queryDispatch(aURL,SPECIALTARGET_SELF,0); |
223 | 0 | } |
224 | | // If it couldn't be found, but creation was allowed, |
225 | | // use a special dispatcher for creation or forwarding to the browser |
226 | 0 | else if (nSearchFlags & css::frame::FrameSearchFlag::CREATE) |
227 | 0 | xDispatcher = implts_getOrCreateDispatchHelper( E_CREATEDISPATCHER, xDesktop, sTargetFrameName, nSearchFlags ); |
228 | 0 | } |
229 | |
|
230 | 0 | return xDispatcher; |
231 | 0 | } |
232 | | |
233 | | css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_queryFrameDispatch( const css::uno::Reference< css::frame::XFrame >& xFrame , |
234 | | const css::util::URL& aURL , |
235 | | const OUString& sTargetFrameName , |
236 | | sal_Int32 nSearchFlags ) |
237 | 0 | { |
238 | 0 | css::uno::Reference< css::frame::XDispatch > xDispatcher; |
239 | | |
240 | | // 0) Some URLs are dispatched in a generic way (e.g. by the menu) using the default target "". |
241 | | // But they are specified to use their own fixed target. Detect such URLs here and use the correct target. |
242 | | |
243 | | // I) First handle special cases which are not suited for using findFrame() |
244 | | |
245 | | // I.I) "_blank", "_default" |
246 | | // It's not the right place to create a new task here. Only the desktop can do that. |
247 | | // Normally the functionality for "_blank" is provided by findFrame(), but that would create it directly |
248 | | // here. That's why we must "intercept" here. |
249 | |
|
250 | 0 | if ( |
251 | 0 | (sTargetFrameName==SPECIALTARGET_BLANK ) || |
252 | 0 | (sTargetFrameName==SPECIALTARGET_DEFAULT) |
253 | 0 | ) |
254 | 0 | { |
255 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); |
256 | 0 | if (xParent.is()) |
257 | 0 | xDispatcher = xParent->queryDispatch(aURL, sTargetFrameName, 0); // it's a special target - ignore search flags |
258 | 0 | } |
259 | | |
260 | | // I.II) "_beamer" |
261 | | // Special sub frame of a top frame only. Search or create it. It's currently a little bit hacky. |
262 | | // Only the sfx (meaning the controller) can create it. |
263 | | |
264 | 0 | else if (sTargetFrameName==SPECIALTARGET_BEAMER) |
265 | 0 | { |
266 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xBeamer( xFrame->findFrame( SPECIALTARGET_BEAMER, css::frame::FrameSearchFlag::CHILDREN | css::frame::FrameSearchFlag::SELF ), css::uno::UNO_QUERY ); |
267 | 0 | if (xBeamer.is()) |
268 | 0 | { |
269 | 0 | xDispatcher = xBeamer->queryDispatch(aURL, SPECIALTARGET_SELF, 0); |
270 | 0 | } |
271 | 0 | else |
272 | 0 | { |
273 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xController( xFrame->getController(), css::uno::UNO_QUERY ); |
274 | 0 | if (xController.is()) |
275 | | // Force using of a special target, but use original search flags. |
276 | | // The caller may or may not use the CREATE flag! |
277 | 0 | xDispatcher = xController->queryDispatch(aURL, SPECIALTARGET_BEAMER, nSearchFlags); |
278 | 0 | } |
279 | 0 | } |
280 | | |
281 | | // I.IV) "_parent" |
282 | | // Our parent frame (if it exists) should handle this URL. |
283 | | |
284 | 0 | else if (sTargetFrameName==SPECIALTARGET_PARENT) |
285 | 0 | { |
286 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); |
287 | 0 | if (xParent.is()) |
288 | | // SELF => we must address the parent directly, and not its parent or any other parent! |
289 | 0 | xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_SELF, 0); |
290 | 0 | } |
291 | | |
292 | | // I.V) "_top" |
293 | | // This request must be forwarded to any parent frame, until we reach a top frame. |
294 | | // If no parent exists, the frame itself can be handled. |
295 | | |
296 | 0 | else if (sTargetFrameName==SPECIALTARGET_TOP) |
297 | 0 | { |
298 | 0 | if (xFrame->isTop()) |
299 | 0 | { |
300 | | // If we are this top frame itself (meaning our owner frame), |
301 | | // we should call ourselves recursively with a better target "_self". |
302 | | // So we can share the same code! (see reaction for "_self" inside this method too.) |
303 | 0 | xDispatcher = queryDispatch(aURL,SPECIALTARGET_SELF,0); |
304 | 0 | } |
305 | 0 | else |
306 | 0 | { |
307 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); |
308 | | // Normally if isTop() returned sal_False, the parent frame MUST(!) exist, |
309 | | // but it seems to be better to check that here to avoid an access violation. |
310 | 0 | if (xParent.is()) |
311 | 0 | xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_TOP, 0); |
312 | 0 | } |
313 | 0 | } |
314 | | |
315 | | // I.VI) "_self", "" |
316 | | // Our owner frame should handle this URL. But we can't do it for all of them. |
317 | | // So we ask the internal set controller first. If it disagrees we try to find a registered |
318 | | // protocol handler. If this failed as well, we check for loadable content and in case of true |
319 | | // we load it into the frame by returning a specialized dispatch object. |
320 | | |
321 | 0 | else if ( |
322 | 0 | (sTargetFrameName==SPECIALTARGET_SELF) || |
323 | 0 | (sTargetFrameName.isEmpty()) |
324 | 0 | ) |
325 | 0 | { |
326 | | // There is a hardcoded interception for special URLs. |
327 | 0 | if ( aURL.Complete == ".uno:CloseDoc" || aURL.Complete == ".uno:CloseWin" ) |
328 | 0 | { |
329 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); |
330 | | // In case the frame is not a top one, is not based on system window and has a parent, |
331 | | // the parent frame should be queried for the correct dispatcher. |
332 | | // See i93473 |
333 | 0 | if ( |
334 | 0 | !WindowHelper::isTopWindow(xFrame->getContainerWindow()) && |
335 | 0 | !VCLUnoHelper::GetWindow(xFrame->getContainerWindow())->IsSystemWindow() && |
336 | 0 | xParent.is() |
337 | 0 | ) |
338 | 0 | xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_SELF, 0); |
339 | 0 | else |
340 | 0 | xDispatcher = implts_getOrCreateDispatchHelper( E_CLOSEDISPATCHER, xFrame ); |
341 | 0 | } |
342 | 0 | else if ( aURL.Complete == ".uno:CloseFrame" ) |
343 | 0 | xDispatcher = implts_getOrCreateDispatchHelper( E_CLOSEDISPATCHER, xFrame ); |
344 | |
|
345 | 0 | if ( ! xDispatcher.is()) |
346 | 0 | { |
347 | | // Ask our controller for its opinion on these dispatched URLs, |
348 | | // because some URLs are internal and can be handled faster by SFX - which usually is the current controller! |
349 | | // But in case of e.g. the bibliography not all queries will be handled successfully here. |
350 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xController( xFrame->getController(), css::uno::UNO_QUERY ); |
351 | 0 | if (xController.is()) |
352 | 0 | xDispatcher = xController->queryDispatch(aURL, SPECIALTARGET_SELF, 0); |
353 | 0 | } |
354 | | |
355 | | // If the controller doesn't feel like dispatching these URLs, we must find an appropriate dispatcher. |
356 | | // Search for any registered protocol handlers first. |
357 | 0 | if (!xDispatcher.is()) |
358 | 0 | xDispatcher = implts_searchProtocolHandler(aURL); |
359 | | |
360 | | // Not for controller - not for protocol handler. |
361 | | // It should be a loadable content, maybe a file. Check it. |
362 | | // This check is necessary for finding out, if |
363 | | // support for some protocols isn't installed by the user. |
364 | | // If a protocol is not available, we suppress the creation of our dispatcher. |
365 | | // The result will be clear. It can't handle it, but will try. |
366 | 0 | if ( |
367 | 0 | ( ! xDispatcher.is() ) && |
368 | 0 | ( implts_isLoadableContent(aURL) ) |
369 | 0 | ) |
370 | 0 | { |
371 | 0 | xDispatcher = implts_getOrCreateDispatchHelper( E_SELFDISPATCHER, xFrame ); |
372 | 0 | } |
373 | 0 | } |
374 | | |
375 | | // I.VII) No further special handlings exist. |
376 | | // Now we have to search for the right target frame by calling findFrame(), but should provide our code |
377 | | // against the creation of a new task if no frame could be found. |
378 | | // As mentioned earlier, it's allowed for dispatch() only. |
379 | | |
380 | 0 | else |
381 | 0 | { |
382 | 0 | sal_Int32 nRightFlags = nSearchFlags & ~css::frame::FrameSearchFlag::CREATE; |
383 | | |
384 | | // try to find any existing target and ask it for its dispatcher |
385 | 0 | css::uno::Reference< css::frame::XFrame > xFoundFrame = xFrame->findFrame(sTargetFrameName, nRightFlags); |
386 | 0 | if (xFoundFrame.is()) |
387 | 0 | { |
388 | | // Attention: Found target is our own owner frame! |
389 | | // Don't ask it for its dispatcher. We know it already - it's our dispatch helper. |
390 | | // Otherwise we can start a neverending recursive call. Why? |
391 | | // Our owner frame was called somewhere, it called some interceptor objects and maybe this dispatch provider |
392 | | // is called. If we use queryDispatch() on our owner frame again, we start this call stack again and again. |
393 | 0 | if (xFoundFrame==xFrame) |
394 | 0 | xDispatcher = implts_getOrCreateDispatchHelper( E_SELFDISPATCHER, xFrame ); |
395 | 0 | else |
396 | 0 | { |
397 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xProvider( xFoundFrame, css::uno::UNO_QUERY ); |
398 | 0 | xDispatcher = xProvider->queryDispatch(aURL,SPECIALTARGET_SELF,0); |
399 | 0 | } |
400 | 0 | } |
401 | 0 | else |
402 | | // If it couldn't be found, but creation was allowed |
403 | | // forward request to the desktop. |
404 | | // Note: The given target name must be used to set the name on a new created task! |
405 | | // Don't forward the request by changing it to a special one e.g _blank. |
406 | | // Use the CREATE flag only to prevent call against further searches. |
407 | | // We already know it: the target must be created new. |
408 | 0 | if (nSearchFlags & css::frame::FrameSearchFlag::CREATE) |
409 | 0 | { |
410 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); |
411 | 0 | if (xParent.is()) |
412 | 0 | xDispatcher = xParent->queryDispatch(aURL, sTargetFrameName, css::frame::FrameSearchFlag::CREATE); |
413 | 0 | } |
414 | 0 | } |
415 | |
|
416 | 0 | return xDispatcher; |
417 | 0 | } |
418 | | |
419 | | /** |
420 | | @short search for a registered protocol handler and ask it for a dispatch object |
421 | | @descr We search a suitable handler inside our cfg package org.openoffice.Office.ProtocolHandler. |
422 | | If we found any, we create and initialize it. Initializing means: we set our owner frame on it |
423 | | as context information. It can use it or leave it. Of course - we are aware of handler implementations, which don't support initialization. It's an optional feature. |
424 | | |
425 | | @param aURL |
426 | | the dispatch URL for which a handler may be registered |
427 | | |
428 | | @return A dispatch object if a handler was found and agrees with the given URL or <NULL/> otherwise. |
429 | | |
430 | | @threadsafe yes |
431 | | */ |
432 | | css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_searchProtocolHandler( const css::util::URL& aURL ) |
433 | 0 | { |
434 | 0 | css::uno::Reference< css::frame::XDispatch > xDispatcher; |
435 | 0 | ProtocolHandler aHandler; |
436 | | |
437 | | // This member itself is threadsafe and lives if we live - we don't need any mutex here. |
438 | 0 | if (framework::HandlerCache::search(aURL,&aHandler)) |
439 | 0 | { |
440 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xHandler; |
441 | 0 | { |
442 | 0 | SolarMutexGuard g; |
443 | | |
444 | | // create it |
445 | 0 | bool bInitialize = true; |
446 | 0 | try |
447 | 0 | { |
448 | | // Only create the protocol handler instance once, the creation is expensive. |
449 | 0 | auto it = m_aProtocolHandlers.find(aHandler.m_sUNOName); |
450 | 0 | if (it == m_aProtocolHandlers.end()) |
451 | 0 | { |
452 | 0 | xHandler.set( |
453 | 0 | css::uno::Reference<css::lang::XMultiServiceFactory>(m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW) |
454 | 0 | ->createInstance(aHandler.m_sUNOName), |
455 | 0 | css::uno::UNO_QUERY); |
456 | | |
457 | | // Check if the handler explicitly requested to avoid caching. |
458 | 0 | css::uno::Reference<css::util::XCacheInfo> xCacheInfo(xHandler, css::uno::UNO_QUERY); |
459 | 0 | if (!xCacheInfo.is() || xCacheInfo->isCachingAllowed()) |
460 | 0 | { |
461 | 0 | m_aProtocolHandlers.emplace(aHandler.m_sUNOName, xHandler); |
462 | 0 | } |
463 | 0 | } |
464 | 0 | else |
465 | 0 | { |
466 | 0 | xHandler = it->second; |
467 | 0 | bInitialize = false; |
468 | 0 | } |
469 | 0 | } |
470 | 0 | catch(const css::uno::Exception&) {} |
471 | | |
472 | | // check if initialization is necessary |
473 | 0 | css::uno::Reference< css::lang::XInitialization > xInit( xHandler, css::uno::UNO_QUERY ); |
474 | 0 | if (xInit.is() && bInitialize) |
475 | 0 | { |
476 | 0 | css::uno::Reference< css::frame::XFrame > xOwner( m_xFrame.get(), css::uno::UNO_QUERY ); |
477 | 0 | SAL_WARN_IF(!xOwner.is(), "fwk", "DispatchProvider::implts_searchProtocolHandler(): Couldn't get reference to my owner frame. So I can't set may needed context information for this protocol handler."); |
478 | 0 | if (xOwner.is()) |
479 | 0 | { |
480 | 0 | try |
481 | 0 | { |
482 | | // but do it only, if all context information is OK |
483 | 0 | css::uno::Sequence< css::uno::Any > lContext{ css::uno::Any(xOwner) }; |
484 | 0 | xInit->initialize(lContext); |
485 | 0 | } |
486 | 0 | catch(const css::uno::Exception&) {} |
487 | 0 | } |
488 | 0 | } |
489 | 0 | } |
490 | | |
491 | | // ask for its (sub)dispatcher for the given URL |
492 | 0 | if (xHandler.is()) |
493 | 0 | xDispatcher = xHandler->queryDispatch(aURL,SPECIALTARGET_SELF,0); |
494 | 0 | } |
495 | | |
496 | 0 | return xDispatcher; |
497 | 0 | } |
498 | | |
499 | | /** |
500 | | @short get or create a new dispatch helper |
501 | | @descr Sometimes we need some helper implementations to support dispatching of special URLs or commands. |
502 | | But it's not a good idea to hold these services for the whole life time of this provider instance. |
503 | | We should create it on demand. |
504 | | That's why we implement this method. It returns an already existing helper or creates a new one otherwise. |
505 | | |
506 | | @attention The parameters sTarget and nSearchFlags are defaulted to "" and 0! |
507 | | Mostly it depends on the parameter eHelper, if they are required or not. |
508 | | |
509 | | @param eHelper |
510 | | specify the requested dispatch helper |
511 | | @param xOwner |
512 | | the target of possible dispatch() call on created dispatch helper |
513 | | @param sTarget |
514 | | the target parameter of the original queryDispatch() request |
515 | | @param nSearchFlags |
516 | | the flags parameter of the original queryDispatch() request |
517 | | @return A reference to a dispatch helper. |
518 | | |
519 | | @threadsafe yes |
520 | | */ |
521 | | css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_getOrCreateDispatchHelper( EDispatchHelper eHelper , |
522 | | const css::uno::Reference< css::frame::XFrame >& xOwner , |
523 | | const OUString& sTarget , |
524 | | sal_Int32 nSearchFlags) |
525 | 0 | { |
526 | 0 | css::uno::Reference< css::frame::XDispatch > xDispatchHelper; |
527 | |
|
528 | 0 | switch (eHelper) |
529 | 0 | { |
530 | 0 | case E_CREATEDISPATCHER : |
531 | 0 | xDispatchHelper = new LoadDispatcher(m_xContext, xOwner, sTarget, nSearchFlags); |
532 | 0 | break; |
533 | | |
534 | 0 | case E_BLANKDISPATCHER : |
535 | 0 | { |
536 | 0 | if (xOwner.is()) |
537 | 0 | xDispatchHelper = new LoadDispatcher(m_xContext, xOwner, SPECIALTARGET_BLANK, 0); |
538 | 0 | } |
539 | 0 | break; |
540 | | |
541 | 0 | case E_DEFAULTDISPATCHER : |
542 | 0 | { |
543 | 0 | if (xOwner.is()) |
544 | 0 | xDispatchHelper = new LoadDispatcher(m_xContext, xOwner, SPECIALTARGET_DEFAULT, 0); |
545 | 0 | } |
546 | 0 | break; |
547 | | |
548 | 0 | case E_SELFDISPATCHER : |
549 | 0 | xDispatchHelper = new LoadDispatcher(m_xContext, xOwner, SPECIALTARGET_SELF, 0); |
550 | 0 | break; |
551 | | |
552 | 0 | case E_CLOSEDISPATCHER : |
553 | 0 | xDispatchHelper = new CloseDispatcher( m_xContext, xOwner, sTarget ); |
554 | 0 | break; |
555 | | |
556 | 0 | case E_STARTMODULEDISPATCHER : |
557 | 0 | xDispatchHelper = new StartModuleDispatcher( m_xContext ); |
558 | 0 | break; |
559 | 0 | } |
560 | | |
561 | 0 | return xDispatchHelper; |
562 | 0 | } |
563 | | |
564 | | /** |
565 | | @short check URL for support by our used loader or handler |
566 | | @descr If we must return our own dispatch helper implementations (self, blank, create dispatcher!) |
567 | | we should be sure, that the URL describes any loadable content. Otherwise slot/uno URLs |
568 | | will be detected, but there exists nothing for real loading into a target frame! |
569 | | |
570 | | @param aURL |
571 | | URL which should be "detected" |
572 | | @return <TRUE/> if it could be handled somewhere - <FALSE/> otherwise. |
573 | | |
574 | | @threadsafe yes |
575 | | */ |
576 | | // static |
577 | | bool DispatchProvider::implts_isLoadableContent( const css::util::URL& aURL ) |
578 | 0 | { |
579 | 0 | LoadEnv::EContentType eType = LoadEnv::classifyContent(aURL.Complete, css::uno::Sequence< css::beans::PropertyValue >()); |
580 | 0 | return ( eType == LoadEnv::E_CAN_BE_LOADED ); |
581 | 0 | } |
582 | | |
583 | | } // namespace framework |
584 | | |
585 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |