Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <loadenv/loadenv.hxx>
21 :
22 : #include <loadenv/targethelper.hxx>
23 : #include <framework/framelistanalyzer.hxx>
24 :
25 : #include <interaction/quietinteraction.hxx>
26 : #include <properties.h>
27 : #include <protocols.h>
28 : #include <services.h>
29 : #include <comphelper/interaction.hxx>
30 : #include <framework/interaction.hxx>
31 : #include <comphelper/processfactory.hxx>
32 : #include <comphelper/configuration.hxx>
33 : #include "officecfg/Office/Common.hxx"
34 :
35 : #include <com/sun/star/awt/XWindow.hpp>
36 : #include <com/sun/star/awt/XWindow2.hpp>
37 : #include <com/sun/star/awt/XTopWindow.hpp>
38 : #include <com/sun/star/container/XNameAccess.hpp>
39 : #include <com/sun/star/container/XContainerQuery.hpp>
40 : #include <com/sun/star/container/XEnumeration.hpp>
41 : #include <com/sun/star/document/MacroExecMode.hpp>
42 : #include <com/sun/star/document/XTypeDetection.hpp>
43 : #include <com/sun/star/document/XActionLockable.hpp>
44 : #include <com/sun/star/document/UpdateDocMode.hpp>
45 : #include <com/sun/star/frame/Desktop.hpp>
46 : #include <com/sun/star/frame/OfficeFrameLoader.hpp>
47 : #include <com/sun/star/frame/XModel.hpp>
48 : #include <com/sun/star/frame/XFrameLoader.hpp>
49 : #include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
50 : #include <com/sun/star/frame/XNotifyingDispatch.hpp>
51 : #include <com/sun/star/frame/FrameLoaderFactory.hpp>
52 : #include <com/sun/star/frame/ContentHandlerFactory.hpp>
53 : #include <com/sun/star/frame/DispatchResultState.hpp>
54 : #include <com/sun/star/frame/FrameSearchFlag.hpp>
55 : #include <com/sun/star/frame/XDispatchProvider.hpp>
56 : #include <com/sun/star/lang/XComponent.hpp>
57 : #include <com/sun/star/lang/XServiceInfo.hpp>
58 : #include <com/sun/star/lang/DisposedException.hpp>
59 : #include <com/sun/star/io/XInputStream.hpp>
60 : #include <com/sun/star/task/XInteractionHandler.hpp>
61 : #include <com/sun/star/task/ErrorCodeRequest.hpp>
62 : #include <com/sun/star/task/InteractionHandler.hpp>
63 : #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
64 : #include <com/sun/star/task/XStatusIndicator.hpp>
65 : #include <com/sun/star/uno/RuntimeException.hpp>
66 : #include <com/sun/star/ucb/UniversalContentBroker.hpp>
67 : #include <com/sun/star/util/URLTransformer.hpp>
68 : #include <com/sun/star/util/XURLTransformer.hpp>
69 : #include <com/sun/star/util/XCloseable.hpp>
70 : #include <com/sun/star/util/XModifiable.hpp>
71 :
72 : #include <vcl/window.hxx>
73 : #include <vcl/wrkwin.hxx>
74 : #include <vcl/syswin.hxx>
75 :
76 : #include <toolkit/helper/vclunohelper.hxx>
77 : #include <unotools/moduleoptions.hxx>
78 : #include <svtools/sfxecode.hxx>
79 : #include <unotools/ucbhelper.hxx>
80 : #include <comphelper/configurationhelper.hxx>
81 : #include <rtl/ustrbuf.hxx>
82 : #include <rtl/bootstrap.hxx>
83 : #include <vcl/svapp.hxx>
84 :
85 : #include <config_orcus.h>
86 :
87 : const char PROP_TYPES[] = "Types";
88 : const char PROP_NAME[] = "Name";
89 :
90 : namespace framework {
91 :
92 : using namespace com::sun::star;
93 :
94 16 : class LoadEnvListener : public ::cppu::WeakImplHelper2< css::frame::XLoadEventListener ,
95 : css::frame::XDispatchResultListener >
96 : {
97 : private:
98 : osl::Mutex m_mutex;
99 : bool m_bWaitingResult;
100 : LoadEnv* m_pLoadEnv;
101 :
102 : public:
103 :
104 8 : LoadEnvListener(LoadEnv* pLoadEnv)
105 : : m_bWaitingResult(true)
106 8 : , m_pLoadEnv(pLoadEnv)
107 : {
108 8 : }
109 :
110 : // frame.XLoadEventListener
111 : virtual void SAL_CALL loadFinished(const css::uno::Reference< css::frame::XFrameLoader >& xLoader)
112 : throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
113 :
114 : virtual void SAL_CALL loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >& xLoader)
115 : throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
116 :
117 : // frame.XDispatchResultListener
118 : virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent& aEvent)
119 : throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
120 :
121 : // lang.XEventListener
122 : virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent)
123 : throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
124 : };
125 :
126 3300 : LoadEnv::LoadEnv(const css::uno::Reference< css::uno::XComponentContext >& xContext)
127 : throw(LoadEnvException, css::uno::RuntimeException)
128 : : m_xContext(xContext)
129 : , m_nSearchFlags(0)
130 : , m_eFeature(E_NO_FEATURE)
131 : , m_eContentType(E_UNSUPPORTED_CONTENT)
132 : , m_bCloseFrameOnError(false)
133 : , m_bReactivateControllerOnError(false)
134 3300 : , m_bLoaded( false )
135 : {
136 3300 : }
137 :
138 3300 : LoadEnv::~LoadEnv()
139 : {
140 3300 : }
141 :
142 3298 : css::uno::Reference< css::lang::XComponent > LoadEnv::loadComponentFromURL(const css::uno::Reference< css::frame::XComponentLoader >& xLoader,
143 : const css::uno::Reference< css::uno::XComponentContext >& xContext ,
144 : const OUString& sURL ,
145 : const OUString& sTarget,
146 : sal_Int32 nFlags ,
147 : const css::uno::Sequence< css::beans::PropertyValue >& lArgs )
148 : throw(css::lang::IllegalArgumentException,
149 : css::io::IOException ,
150 : css::uno::RuntimeException )
151 : {
152 3298 : css::uno::Reference< css::lang::XComponent > xComponent;
153 :
154 : try
155 : {
156 3298 : LoadEnv aEnv(xContext);
157 :
158 : aEnv.initializeLoading(sURL,
159 : lArgs,
160 : css::uno::Reference< css::frame::XFrame >(xLoader, css::uno::UNO_QUERY),
161 : sTarget,
162 : nFlags,
163 3298 : LoadEnv::E_NO_FEATURE);
164 3298 : aEnv.startLoading();
165 3296 : aEnv.waitWhileLoading(); // wait for ever!
166 :
167 3296 : xComponent = aEnv.getTargetComponent();
168 : }
169 2 : catch(const LoadEnvException& ex)
170 : {
171 2 : switch(ex.m_nID)
172 : {
173 : case LoadEnvException::ID_INVALID_MEDIADESCRIPTOR:
174 : throw css::lang::IllegalArgumentException(
175 0 : "Optional list of arguments seem to be corrupted.", xLoader, 4);
176 :
177 : case LoadEnvException::ID_UNSUPPORTED_CONTENT:
178 : throw css::lang::IllegalArgumentException(
179 2 : "Unsupported URL <" + sURL + ">: \"" + ex.m_sMessage + "\"",
180 3 : xLoader, 1);
181 :
182 : default:
183 : SAL_WARN(
184 : "fwk.loadenv",
185 : "caught LoadEnvException " << +ex.m_nID << " \""
186 : << ex.m_sMessage << "\""
187 : << (ex.m_exOriginal.has<css::uno::Exception>()
188 : ? (", " + ex.m_exOriginal.getValueTypeName() + " \""
189 : + (ex.m_exOriginal.get<css::uno::Exception>().
190 : Message)
191 : + "\"")
192 : : OUString())
193 : << " while loading <" << sURL << ">");
194 1 : xComponent.clear();
195 1 : break;
196 : }
197 : }
198 :
199 3297 : return xComponent;
200 : }
201 :
202 3300 : utl::MediaDescriptor impl_mergeMediaDescriptorWithMightExistingModelArgs(const css::uno::Sequence< css::beans::PropertyValue >& lOutsideDescriptor)
203 : {
204 3300 : utl::MediaDescriptor lDescriptor(lOutsideDescriptor);
205 : css::uno::Reference< css::frame::XModel > xModel = lDescriptor.getUnpackedValueOrDefault(
206 3300 : utl::MediaDescriptor::PROP_MODEL (),
207 9900 : css::uno::Reference< css::frame::XModel > ());
208 3300 : if (xModel.is ())
209 : {
210 83 : utl::MediaDescriptor lModelDescriptor(xModel->getArgs());
211 83 : utl::MediaDescriptor::iterator pIt = lModelDescriptor.find( utl::MediaDescriptor::PROP_MACROEXECUTIONMODE() );
212 83 : if ( pIt != lModelDescriptor.end() )
213 81 : lDescriptor[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()] = pIt->second;
214 : }
215 :
216 6600 : return lDescriptor;
217 : }
218 :
219 3300 : void LoadEnv::initializeLoading(const OUString& sURL ,
220 : const css::uno::Sequence< css::beans::PropertyValue >& lMediaDescriptor,
221 : const css::uno::Reference< css::frame::XFrame >& xBaseFrame ,
222 : const OUString& sTarget ,
223 : sal_Int32 nSearchFlags ,
224 : EFeature eFeature , // => use default ...
225 : EContentType eContentType ) // => use default ...
226 : {
227 3300 : osl::MutexGuard g(m_mutex);
228 :
229 : // Handle still running processes!
230 3300 : if (m_xAsynchronousJob.is())
231 0 : throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
232 :
233 : // take over all new parameters.
234 3300 : m_xTargetFrame.clear();
235 3300 : m_xBaseFrame = xBaseFrame;
236 3300 : m_lMediaDescriptor = impl_mergeMediaDescriptorWithMightExistingModelArgs(lMediaDescriptor);
237 3300 : m_sTarget = sTarget;
238 3300 : m_nSearchFlags = nSearchFlags;
239 3300 : m_eFeature = eFeature;
240 3300 : m_eContentType = eContentType;
241 3300 : m_bCloseFrameOnError = false;
242 3300 : m_bReactivateControllerOnError = false;
243 3300 : m_bLoaded = false;
244 :
245 : // try to find out, if its really a content, which can be loaded or must be "handled"
246 : // We use a default value for this in-parameter. Then we have to start a complex check method
247 : // internally. But if this check was already done outside it can be suppressed to perform
248 : // the load request. We take over the result then!
249 3300 : if (m_eContentType == E_UNSUPPORTED_CONTENT)
250 : {
251 3300 : m_eContentType = LoadEnv::classifyContent(sURL, lMediaDescriptor);
252 3300 : if (m_eContentType == E_UNSUPPORTED_CONTENT)
253 0 : throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT, "from LoadEnv::initializeLoading");
254 : }
255 :
256 : // make URL part of the MediaDescriptor
257 : // It doesn't mater, if it is already an item of it.
258 : // It must be the same value ... so we can overwrite it :-)
259 3300 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_URL()] <<= sURL;
260 :
261 : // parse it - because some following code require that
262 3300 : m_aURL.Complete = sURL;
263 6600 : css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
264 3300 : xParser->parseStrict(m_aURL);
265 :
266 : // BTW: Split URL and JumpMark ...
267 : // Because such mark is an explicit value of the media descriptor!
268 3300 : if (!m_aURL.Mark.isEmpty())
269 0 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_JUMPMARK()] <<= m_aURL.Mark;
270 :
271 : // By the way: remove the old and deprecated value "FileName" from the descriptor!
272 3300 : utl::MediaDescriptor::iterator pIt = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FILENAME());
273 3300 : if (pIt != m_lMediaDescriptor.end())
274 0 : m_lMediaDescriptor.erase(pIt);
275 :
276 : // patch the MediaDescriptor, so it fulfil the outside requirements
277 : // Means especially items like e.g. UI InteractionHandler, Status Indicator,
278 : // MacroExecutionMode, etc.
279 :
280 : /*TODO progress is bound to a frame ... How can we set it here? */
281 :
282 : // UI mode
283 : const bool bUIMode =
284 3304 : ( ( m_eFeature & E_WORK_WITH_UI ) == E_WORK_WITH_UI ) &&
285 9908 : !m_lMediaDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_HIDDEN(), false ) &&
286 6602 : !m_lMediaDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_PREVIEW(), false );
287 :
288 : initializeUIDefaults(
289 : m_xContext,
290 : m_lMediaDescriptor,
291 : bUIMode,
292 : &m_pQuietInteraction
293 6600 : );
294 3300 : }
295 :
296 3300 : void LoadEnv::initializeUIDefaults( const css::uno::Reference< css::uno::XComponentContext >& i_rxContext,
297 : utl::MediaDescriptor& io_lMediaDescriptor, const bool i_bUIMode,
298 : rtl::Reference<QuietInteraction>* o_ppQuietInteraction )
299 : {
300 3300 : css::uno::Reference< css::task::XInteractionHandler > xInteractionHandler;
301 : sal_Int16 nMacroMode;
302 : sal_Int16 nUpdateMode;
303 :
304 3300 : if ( i_bUIMode )
305 : {
306 2 : nMacroMode = css::document::MacroExecMode::USE_CONFIG;
307 2 : nUpdateMode = css::document::UpdateDocMode::ACCORDING_TO_CONFIG;
308 : try
309 : {
310 2 : xInteractionHandler.set( css::task::InteractionHandler::createWithParent( i_rxContext, 0 ), css::uno::UNO_QUERY_THROW );
311 : }
312 0 : catch(const css::uno::RuntimeException&) {throw;}
313 0 : catch(const css::uno::Exception& ) { }
314 : }
315 : // hidden mode
316 : else
317 : {
318 3298 : nMacroMode = css::document::MacroExecMode::NEVER_EXECUTE;
319 3298 : nUpdateMode = css::document::UpdateDocMode::NO_UPDATE;
320 3298 : rtl::Reference<QuietInteraction> pQuietInteraction = new QuietInteraction();
321 3298 : xInteractionHandler = pQuietInteraction.get();
322 3298 : if ( o_ppQuietInteraction != NULL )
323 : {
324 3298 : *o_ppQuietInteraction = pQuietInteraction;
325 3298 : }
326 : }
327 :
328 6600 : if (
329 13200 : (xInteractionHandler.is() ) &&
330 16500 : (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_INTERACTIONHANDLER()) == io_lMediaDescriptor.end())
331 : )
332 : {
333 3283 : io_lMediaDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteractionHandler;
334 : }
335 :
336 3300 : if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()) == io_lMediaDescriptor.end())
337 749 : io_lMediaDescriptor[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()] <<= nMacroMode;
338 :
339 3300 : if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_UPDATEDOCMODE()) == io_lMediaDescriptor.end())
340 3283 : io_lMediaDescriptor[utl::MediaDescriptor::PROP_UPDATEDOCMODE()] <<= nUpdateMode;
341 3300 : }
342 :
343 3300 : void LoadEnv::startLoading()
344 : {
345 : // SAFE ->
346 3300 : osl::ClearableMutexGuard aReadLock(m_mutex);
347 :
348 : // Handle still running processes!
349 3300 : if (m_xAsynchronousJob.is())
350 0 : throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
351 :
352 : // content can not be loaded or handled
353 : // check "classifyContent()" failed before ...
354 3300 : if (m_eContentType == E_UNSUPPORTED_CONTENT)
355 0 : throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT, "from LoadEnv::startLoading");
356 :
357 : // <- SAFE
358 3300 : aReadLock.clear();
359 :
360 : // detect its type/filter etc.
361 : // These information will be available by the
362 : // used descriptor member afterwards and is needed
363 : // for all following operations!
364 : // Note: An exception will be thrown, in case operation was not successfully ...
365 3300 : if (m_eContentType != E_CAN_BE_SET)/* Attention: special feature to set existing component on a frame must ignore type detection! */
366 3218 : impl_detectTypeAndFilter();
367 :
368 : // start loading the content ...
369 : // Attention: Don't check m_eContentType deeper then UNSUPPORTED/SUPPORTED!
370 : // Because it was made in the easiest way ... may a flat detection was made only.
371 : // And such simple detection can fail some times .-)
372 : // Use another strategy here. Try it and let it run into the case "loading not possible".
373 3299 : bool bStarted = false;
374 3299 : if (
375 3301 : ((m_eFeature & E_ALLOW_CONTENTHANDLER) == E_ALLOW_CONTENTHANDLER) &&
376 2 : (m_eContentType != E_CAN_BE_SET ) /* Attention: special feature to set existing component on a frame must ignore type detection! */
377 : )
378 : {
379 2 : bStarted = impl_handleContent();
380 : }
381 :
382 3299 : if (!bStarted)
383 3299 : bStarted = impl_loadContent();
384 :
385 : // not started => general error
386 : // We can't say - what was the reason for.
387 3298 : if (!bStarted)
388 : throw LoadEnvException(
389 2 : LoadEnvException::ID_GENERAL_ERROR, "not started");
390 3298 : }
391 :
392 : /*-----------------------------------------------
393 : TODO
394 : First draft does not implement timeout using [ms].
395 : Current implementation counts yield calls only ...
396 : -----------------------------------------------*/
397 3300 : bool LoadEnv::waitWhileLoading(sal_uInt32 nTimeout)
398 : {
399 : // Because its not a good idea to block the main thread
400 : // (and we can't be sure that we are currently not used inside the
401 : // main thread!), we can't use conditions here really. We must yield
402 : // in an intelligent manner :-)
403 :
404 3300 : sal_Int32 nTime = nTimeout;
405 : while(true)
406 : {
407 : // SAFE -> ------------------------------
408 3300 : osl::ClearableMutexGuard aReadLock1(m_mutex);
409 3300 : if (!m_xAsynchronousJob.is())
410 3300 : break;
411 0 : aReadLock1.clear();
412 : // <- SAFE ------------------------------
413 :
414 0 : Application::Yield();
415 :
416 : // forever!
417 0 : if (nTimeout==0)
418 0 : continue;
419 :
420 : // timed out?
421 0 : --nTime;
422 0 : if (nTime<1)
423 0 : break;
424 0 : }
425 :
426 3300 : osl::MutexGuard g(m_mutex);
427 0 : return !m_xAsynchronousJob.is();
428 : }
429 :
430 3298 : css::uno::Reference< css::lang::XComponent > LoadEnv::getTargetComponent() const
431 : {
432 3298 : osl::MutexGuard g(m_mutex);
433 :
434 3298 : if (!m_xTargetFrame.is())
435 0 : return css::uno::Reference< css::lang::XComponent >();
436 :
437 6596 : css::uno::Reference< css::frame::XController > xController = m_xTargetFrame->getController();
438 3298 : if (!xController.is())
439 0 : return css::uno::Reference< css::lang::XComponent >(m_xTargetFrame->getComponentWindow(), css::uno::UNO_QUERY);
440 :
441 6596 : css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
442 3298 : if (!xModel.is())
443 1 : return css::uno::Reference< css::lang::XComponent >(xController, css::uno::UNO_QUERY);
444 :
445 6595 : return css::uno::Reference< css::lang::XComponent >(xModel, css::uno::UNO_QUERY);
446 : }
447 :
448 8 : void SAL_CALL LoadEnvListener::loadFinished(const css::uno::Reference< css::frame::XFrameLoader >&)
449 : throw(css::uno::RuntimeException, std::exception)
450 : {
451 8 : osl::MutexGuard g(m_mutex);
452 8 : if (m_bWaitingResult)
453 8 : m_pLoadEnv->impl_setResult(true);
454 8 : m_bWaitingResult = false;
455 8 : }
456 :
457 0 : void SAL_CALL LoadEnvListener::loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >&)
458 : throw(css::uno::RuntimeException, std::exception)
459 : {
460 0 : osl::MutexGuard g(m_mutex);
461 0 : if (m_bWaitingResult)
462 0 : m_pLoadEnv->impl_setResult(false);
463 0 : m_bWaitingResult = false;
464 0 : }
465 :
466 0 : void SAL_CALL LoadEnvListener::dispatchFinished(const css::frame::DispatchResultEvent& aEvent)
467 : throw(css::uno::RuntimeException, std::exception)
468 : {
469 0 : osl::MutexGuard g(m_mutex);
470 :
471 0 : if (!m_bWaitingResult)
472 0 : return;
473 :
474 0 : switch(aEvent.State)
475 : {
476 : case css::frame::DispatchResultState::FAILURE :
477 0 : m_pLoadEnv->impl_setResult(false);
478 0 : break;
479 :
480 : case css::frame::DispatchResultState::SUCCESS :
481 0 : m_pLoadEnv->impl_setResult(false);
482 0 : break;
483 :
484 : case css::frame::DispatchResultState::DONTKNOW :
485 0 : m_pLoadEnv->impl_setResult(false);
486 0 : break;
487 : }
488 0 : m_bWaitingResult = false;
489 : }
490 :
491 0 : void SAL_CALL LoadEnvListener::disposing(const css::lang::EventObject&)
492 : throw(css::uno::RuntimeException, std::exception)
493 : {
494 0 : osl::MutexGuard g(m_mutex);
495 0 : if (m_bWaitingResult)
496 0 : m_pLoadEnv->impl_setResult(false);
497 0 : m_bWaitingResult = false;
498 0 : }
499 :
500 3299 : void LoadEnv::impl_setResult(bool bResult)
501 : {
502 3299 : osl::MutexGuard g(m_mutex);
503 :
504 3299 : m_bLoaded = bResult;
505 :
506 3299 : impl_reactForLoadingState();
507 :
508 : // clearing of this reference will unblock waitWhileLoading()!
509 : // So we must be sure, that loading process was really finished.
510 : // => do it as last operation of this method ...
511 3299 : m_xAsynchronousJob.clear();
512 3298 : }
513 :
514 : /*-----------------------------------------------
515 : TODO: Is it a good idea to change Sequence<>
516 : parameter to stl-adapter?
517 : -----------------------------------------------*/
518 28071 : LoadEnv::EContentType LoadEnv::classifyContent(const OUString& sURL ,
519 : const css::uno::Sequence< css::beans::PropertyValue >& lMediaDescriptor)
520 : {
521 :
522 : // (i) Filter some special well known URL protocols,
523 : // which can not be handled or loaded in general.
524 : // Of course an empty URL must be ignored here too.
525 : // Note: These URL schemata are fix and well known ...
526 : // But there can be some additional ones, which was not
527 : // defined at implementation time of this class :-(
528 : // So we have to make sure, that the following code
529 : // can detect such protocol schemata too :-)
530 :
531 28071 : if(
532 56142 : (sURL.isEmpty() ) ||
533 52026 : (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_UNO )) ||
534 47910 : (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_SLOT )) ||
535 47910 : (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_MACRO )) ||
536 47910 : (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_SERVICE)) ||
537 75981 : (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_MAILTO )) ||
538 23955 : (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_NEWS ))
539 : )
540 : {
541 4116 : return E_UNSUPPORTED_CONTENT;
542 : }
543 :
544 : // (ii) Some special URLs indicates a given input stream,
545 : // a full featured document model directly or
546 : // specify a request for opening an empty document.
547 : // Such contents are loadable in general.
548 : // But we have to check, if the media descriptor contains
549 : // all needed resources. If they are missing - the following
550 : // load request will fail.
551 :
552 : /* Attention: The following code can't work on such special URLs!
553 : It should not break the office .. but it make no sense
554 : to start expensive object creations and complex search
555 : algorithm if its clear, that such URLs must be handled
556 : in a special way .-)
557 : */
558 :
559 : // creation of new documents
560 23955 : if (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_PRIVATE_FACTORY))
561 718 : return E_CAN_BE_LOADED;
562 :
563 : // using of an existing input stream
564 23237 : utl::MediaDescriptor stlMediaDescriptor(lMediaDescriptor);
565 23237 : utl::MediaDescriptor::const_iterator pIt;
566 23237 : if (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_PRIVATE_STREAM))
567 : {
568 0 : pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_INPUTSTREAM());
569 0 : css::uno::Reference< css::io::XInputStream > xStream;
570 0 : if (pIt != stlMediaDescriptor.end())
571 0 : pIt->second >>= xStream;
572 0 : if (xStream.is())
573 0 : return E_CAN_BE_LOADED;
574 : SAL_INFO("fwk", "LoadEnv::classifyContent(): loading from stream with right URL but invalid stream detected");
575 0 : return E_UNSUPPORTED_CONTENT;
576 : }
577 :
578 : // using of a full featured document
579 23237 : if (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_PRIVATE_OBJECT))
580 : {
581 82 : pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_MODEL());
582 82 : css::uno::Reference< css::frame::XModel > xModel;
583 82 : if (pIt != stlMediaDescriptor.end())
584 82 : pIt->second >>= xModel;
585 82 : if (xModel.is())
586 82 : return E_CAN_BE_SET;
587 : SAL_INFO("fwk", "LoadEnv::classifyContent(): loading with object with right URL but invalid object detected");
588 0 : return E_UNSUPPORTED_CONTENT;
589 : }
590 :
591 : // following operations can work on an internal type name only :-(
592 46310 : css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
593 : css::uno::Reference< css::document::XTypeDetection > xDetect(
594 46310 : xContext->getServiceManager()->createInstanceWithContext(
595 23155 : "com.sun.star.document.TypeDetection", xContext),
596 46310 : css::uno::UNO_QUERY_THROW);
597 :
598 46310 : OUString sType = xDetect->queryTypeByURL(sURL);
599 :
600 46310 : css::uno::Sequence< css::beans::NamedValue > lQuery(1);
601 46310 : css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory;
602 46310 : css::uno::Reference< css::container::XEnumeration > xSet;
603 46310 : css::uno::Sequence< OUString > lTypesReg(1);
604 :
605 : // (iii) If a FrameLoader service (or at least
606 : // a Filter) can be found, which supports
607 : // this URL - it must be a loadable content.
608 : // Because both items are registered for types
609 : // its enough to check for frame loaders only.
610 : // Mos of our filters are handled by our global
611 : // default loader. But there exist some specialized
612 : // loader, which does not work on top of filters!
613 : // So its not enough to search on the filter configuration.
614 : // Further its not enough to search for types!
615 : // Because there exist some types, which are referenced by
616 : // other objects ... but not by filters nor frame loaders!
617 :
618 46310 : OUString sPROP_TYPES(PROP_TYPES);
619 :
620 23155 : lTypesReg[0] = sType;
621 23155 : lQuery[0].Name = sPROP_TYPES;
622 23155 : lQuery[0].Value <<= lTypesReg;
623 :
624 23155 : xLoaderFactory = css::frame::FrameLoaderFactory::create(xContext);
625 23155 : xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
626 : // at least one registered frame loader is enough!
627 23155 : if (xSet->hasMoreElements())
628 1845 : return E_CAN_BE_LOADED;
629 :
630 : // (iv) Some URL protocols are supported by special services.
631 : // E.g. ContentHandler.
632 : // Such contents can be handled ... but not loaded.
633 :
634 21310 : lTypesReg[0] = sType;
635 21310 : lQuery[0].Name = sPROP_TYPES;
636 21310 : lQuery[0].Value <<= lTypesReg;
637 :
638 21310 : xLoaderFactory = css::frame::ContentHandlerFactory::create(xContext);
639 21310 : xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
640 : // at least one registered content handler is enough!
641 21310 : if (xSet->hasMoreElements())
642 0 : return E_CAN_BE_HANDLED;
643 :
644 : // (v) Last but not least the UCB is used inside office to
645 : // load contents. He has a special configuration to know
646 : // which URL schemata can be used inside office.
647 42620 : css::uno::Reference< css::ucb::XUniversalContentBroker > xUCB(css::ucb::UniversalContentBroker::create(xContext));
648 21310 : if (xUCB->queryContentProvider(sURL).is())
649 657 : return E_CAN_BE_LOADED;
650 :
651 : // (TODO) At this point, we have no idea .-)
652 : // But it seems to be better, to break all
653 : // further requests for this URL. Otherwise
654 : // we can run into some trouble.
655 43890 : return E_UNSUPPORTED_CONTENT;
656 : }
657 :
658 : namespace {
659 :
660 : #if ENABLE_ORCUS
661 :
662 3218 : bool queryOrcusTypeAndFilter(const uno::Sequence<beans::PropertyValue>& rDescriptor, OUString& rType, OUString& rFilter)
663 : {
664 : // depending on the experimental mode
665 3218 : uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
666 3218 : if (!xContext.is() || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext))
667 : {
668 3218 : return false;
669 : }
670 :
671 0 : OUString aURL;
672 0 : sal_Int32 nSize = rDescriptor.getLength();
673 0 : for (sal_Int32 i = 0; i < nSize; ++i)
674 : {
675 0 : const beans::PropertyValue& rProp = rDescriptor[i];
676 0 : if (rProp.Name == "URL")
677 : {
678 0 : rProp.Value >>= aURL;
679 0 : break;
680 : }
681 : }
682 :
683 0 : if (aURL.isEmpty() || aURL.copy(0,8).equalsIgnoreAsciiCase("private:"))
684 0 : return false;
685 :
686 0 : OUString aUseOrcus;
687 0 : rtl::Bootstrap::get("LIBO_USE_ORCUS", aUseOrcus);
688 0 : bool bUseOrcus = (aUseOrcus == "YES");
689 :
690 : // TODO : Type must be set to be generic_Text (or any other type that
691 : // exists) in order to find a usable loader. Exploit it as a temporary
692 : // hack.
693 :
694 0 : if (aURL.endsWith(".gnumeric"))
695 : {
696 0 : rType = "generic_Text";
697 0 : rFilter = "gnumeric";
698 0 : return true;
699 : }
700 :
701 0 : if (!bUseOrcus)
702 0 : return false;
703 :
704 0 : if (aURL.endsWith(".xlsx"))
705 : {
706 0 : rType = "generic_Text";
707 0 : rFilter = "xlsx";
708 0 : return true;
709 : }
710 0 : else if (aURL.endsWith(".ods"))
711 : {
712 0 : rType = "generic_Text";
713 0 : rFilter = "ods";
714 0 : return true;
715 : }
716 0 : else if (aURL.endsWith(".csv"))
717 : {
718 0 : rType = "generic_Text";
719 0 : rFilter = "csv";
720 0 : return true;
721 : }
722 :
723 3218 : return false;
724 : }
725 :
726 : #else
727 :
728 : bool queryOrcusTypeAndFilter(const uno::Sequence<beans::PropertyValue>&, OUString&, OUString&)
729 : {
730 : return false;
731 : }
732 :
733 : #endif
734 :
735 : }
736 :
737 3218 : void LoadEnv::impl_detectTypeAndFilter()
738 : throw(LoadEnvException, css::uno::RuntimeException, std::exception)
739 : {
740 : static const char TYPEPROP_PREFERREDFILTER[] = "PreferredFilter";
741 : static const char FILTERPROP_FLAGS [] = "Flags";
742 : static sal_Int32 FILTERFLAG_TEMPLATEPATH = 16;
743 :
744 : // SAFE ->
745 3218 : osl::ClearableMutexGuard aReadLock(m_mutex);
746 :
747 : // Attention: Because our stl media descriptor is a copy of an uno sequence
748 : // we can't use as an in/out parameter here. Copy it before and don't forget to
749 : // update structure afterwards again!
750 6436 : css::uno::Sequence< css::beans::PropertyValue > lDescriptor = m_lMediaDescriptor.getAsConstPropertyValueList();
751 6436 : css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
752 :
753 3218 : aReadLock.clear();
754 : // <- SAFE
755 :
756 6436 : OUString sType, sFilter;
757 :
758 3218 : if (queryOrcusTypeAndFilter(lDescriptor, sType, sFilter) && !sType.isEmpty() && !sFilter.isEmpty())
759 : {
760 : // Orcus type detected. Skip the normal type detection process.
761 0 : m_lMediaDescriptor << lDescriptor;
762 0 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType;
763 0 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
764 0 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERPROVIDER()] <<= OUString("orcus");
765 3217 : return;
766 : }
767 :
768 : css::uno::Reference< css::document::XTypeDetection > xDetect(
769 6436 : xContext->getServiceManager()->createInstanceWithContext(
770 3218 : "com.sun.star.document.TypeDetection", xContext),
771 6436 : css::uno::UNO_QUERY_THROW);
772 3218 : sType = xDetect->queryTypeByDescriptor(lDescriptor, sal_True); /*TODO should deep detection be able for enable/disable it from outside? */
773 :
774 : // no valid content -> loading not possible
775 3218 : if (sType.isEmpty())
776 : throw LoadEnvException(
777 1 : LoadEnvException::ID_UNSUPPORTED_CONTENT, "type detection failed");
778 :
779 : // SAFE ->
780 6434 : osl::ResettableMutexGuard aWriteLock(m_mutex);
781 :
782 : // detection was successfully => update the descriptor member of this class
783 3217 : m_lMediaDescriptor << lDescriptor;
784 3217 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType;
785 : // Is there an already detected (may be preselected) filter?
786 : // see below ...
787 3217 : sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
788 :
789 3217 : aWriteLock.clear();
790 : // <- SAFE
791 :
792 : // But the type isn't enough. For loading sometimes we need more information.
793 : // E.g. for our "_default" feature, where we recycle any frame which contains
794 : // and "Untitled" document, we must know if the new document is based on a template!
795 : // But this information is available as a filter property only.
796 : // => We must try(!) to detect the right filter for this load request.
797 : // On the other side ... if no filter is available .. ignore it.
798 : // Then the type information must be enough.
799 3217 : if (sFilter.isEmpty())
800 : {
801 : // no -> try to find a preferred filter for the detected type.
802 : // Don't forget to update the media descriptor.
803 1 : css::uno::Reference< css::container::XNameAccess > xTypeCont(xDetect, css::uno::UNO_QUERY_THROW);
804 : try
805 : {
806 1 : ::comphelper::SequenceAsHashMap lTypeProps(xTypeCont->getByName(sType));
807 1 : sFilter = lTypeProps.getUnpackedValueOrDefault(TYPEPROP_PREFERREDFILTER, OUString());
808 1 : if (!sFilter.isEmpty())
809 : {
810 : // SAFE ->
811 0 : aWriteLock.reset();
812 0 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
813 0 : aWriteLock.clear();
814 : // <- SAFE
815 1 : }
816 : }
817 0 : catch(const css::container::NoSuchElementException&)
818 1 : {}
819 : }
820 :
821 : // check if the filter (if one exists) points to a template format filter.
822 : // Then we have to add the property "AsTemplate".
823 : // We need this information to decide afterwards if we can use a "recycle frame"
824 : // for target "_default" or has to create a new one every time.
825 : // On the other side we have to suppress that, if this property already exists
826 : // and should trigger a special handling. Then the outside call of this method here,
827 : // has to know, what he is doing .-)
828 :
829 3217 : bool bIsOwnTemplate = false;
830 3217 : if (!sFilter.isEmpty())
831 : {
832 3216 : css::uno::Reference< css::container::XNameAccess > xFilterCont(xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext), css::uno::UNO_QUERY_THROW);
833 : try
834 : {
835 3216 : ::comphelper::SequenceAsHashMap lFilterProps(xFilterCont->getByName(sFilter));
836 3216 : sal_Int32 nFlags = lFilterProps.getUnpackedValueOrDefault(FILTERPROP_FLAGS, (sal_Int32)0);
837 3216 : bIsOwnTemplate = ((nFlags & FILTERFLAG_TEMPLATEPATH) == FILTERFLAG_TEMPLATEPATH);
838 : }
839 0 : catch(const css::container::NoSuchElementException&)
840 3216 : {}
841 : }
842 3217 : if (bIsOwnTemplate)
843 : {
844 : // SAFE ->
845 38 : aWriteLock.reset();
846 : // Don't overwrite external decisions! See comments before ...
847 38 : utl::MediaDescriptor::const_iterator pAsTemplateItem = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_ASTEMPLATE());
848 38 : if (pAsTemplateItem == m_lMediaDescriptor.end())
849 37 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE()] <<= sal_True;
850 38 : aWriteLock.clear();
851 : // <- SAFE
852 3218 : }
853 : }
854 :
855 2 : bool LoadEnv::impl_handleContent()
856 : throw(LoadEnvException, css::uno::RuntimeException, std::exception)
857 : {
858 : // SAFE -> -----------------------------------
859 2 : osl::ClearableMutexGuard aReadLock(m_mutex);
860 :
861 : // the type must exist inside the descriptor ... otherwise this class is implemented wrong :-)
862 4 : OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
863 2 : if (sType.isEmpty())
864 0 : throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
865 :
866 : // convert media descriptor and URL to right format for later interface call!
867 4 : css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
868 2 : m_lMediaDescriptor >> lDescriptor;
869 4 : css::util::URL aURL = m_aURL;
870 :
871 : // get necessary container to query for a handler object
872 4 : css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::ContentHandlerFactory::create(m_xContext);
873 :
874 2 : aReadLock.clear();
875 : // <- SAFE -----------------------------------
876 :
877 : // query
878 4 : css::uno::Sequence< OUString > lTypeReg(1);
879 2 : lTypeReg[0] = sType;
880 :
881 4 : css::uno::Sequence< css::beans::NamedValue > lQuery(1);
882 2 : lQuery[0].Name = PROP_TYPES;
883 2 : lQuery[0].Value <<= lTypeReg;
884 :
885 4 : OUString sPROP_NAME(PROP_NAME);
886 :
887 4 : css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
888 4 : while(xSet->hasMoreElements())
889 : {
890 0 : ::comphelper::SequenceAsHashMap lProps (xSet->nextElement());
891 0 : OUString sHandler = lProps.getUnpackedValueOrDefault(sPROP_NAME, OUString());
892 :
893 0 : css::uno::Reference< css::frame::XNotifyingDispatch > xHandler;
894 : try
895 : {
896 0 : xHandler = css::uno::Reference< css::frame::XNotifyingDispatch >(xLoaderFactory->createInstance(sHandler), css::uno::UNO_QUERY);
897 0 : if (!xHandler.is())
898 0 : continue;
899 : }
900 0 : catch(const css::uno::RuntimeException&)
901 0 : { throw; }
902 0 : catch(const css::uno::Exception&)
903 0 : { continue; }
904 :
905 : // SAFE -> -----------------------------------
906 0 : osl::ClearableMutexGuard aWriteLock(m_mutex);
907 0 : m_xAsynchronousJob = xHandler;
908 0 : LoadEnvListener* pListener = new LoadEnvListener(this);
909 0 : aWriteLock.clear();
910 : // <- SAFE -----------------------------------
911 :
912 0 : css::uno::Reference< css::frame::XDispatchResultListener > xListener(static_cast< css::frame::XDispatchResultListener* >(pListener), css::uno::UNO_QUERY);
913 0 : xHandler->dispatchWithNotification(aURL, lDescriptor, xListener);
914 :
915 0 : return true;
916 0 : }
917 :
918 4 : return false;
919 : }
920 :
921 3206 : bool LoadEnv::impl_furtherDocsAllowed()
922 : {
923 : // SAFE ->
924 3206 : osl::ResettableMutexGuard aReadLock(m_mutex);
925 6412 : css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
926 3206 : aReadLock.clear();
927 : // <- SAFE
928 :
929 3206 : bool bAllowed = true;
930 :
931 : try
932 : {
933 : css::uno::Any aVal = ::comphelper::ConfigurationHelper::readDirectKey(
934 : xContext,
935 : OUString("org.openoffice.Office.Common/"),
936 : OUString("Misc"),
937 : OUString("MaxOpenDocuments"),
938 3206 : ::comphelper::ConfigurationHelper::E_READONLY);
939 :
940 : // NIL means: count of allowed documents = infinite !
941 : // => return sal_True
942 3206 : if ( ! aVal.hasValue())
943 3206 : bAllowed = true;
944 : else
945 : {
946 0 : sal_Int32 nMaxOpenDocuments = 0;
947 0 : aVal >>= nMaxOpenDocuments;
948 :
949 : css::uno::Reference< css::frame::XFramesSupplier > xDesktop(
950 : css::frame::Desktop::create(xContext),
951 0 : css::uno::UNO_QUERY_THROW);
952 :
953 : FrameListAnalyzer aAnalyzer(xDesktop,
954 : css::uno::Reference< css::frame::XFrame >(),
955 : FrameListAnalyzer::E_HELP |
956 : FrameListAnalyzer::E_BACKINGCOMPONENT |
957 0 : FrameListAnalyzer::E_HIDDEN);
958 :
959 0 : sal_Int32 nOpenDocuments = aAnalyzer.m_lOtherVisibleFrames.getLength();
960 0 : bAllowed = (nOpenDocuments < nMaxOpenDocuments);
961 3206 : }
962 : }
963 0 : catch(const css::uno::Exception&)
964 0 : { bAllowed = true; } // !! internal errors are no reason to disturb the office from opening documents .-)
965 :
966 3206 : if ( ! bAllowed )
967 : {
968 : // SAFE ->
969 0 : aReadLock.reset();
970 : css::uno::Reference< css::task::XInteractionHandler > xInteraction = m_lMediaDescriptor.getUnpackedValueOrDefault(
971 0 : utl::MediaDescriptor::PROP_INTERACTIONHANDLER(),
972 0 : css::uno::Reference< css::task::XInteractionHandler >());
973 0 : aReadLock.clear();
974 : // <- SAFE
975 :
976 0 : if (xInteraction.is())
977 : {
978 0 : css::uno::Any aInteraction;
979 0 : css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations(2);
980 :
981 0 : comphelper::OInteractionAbort* pAbort = new comphelper::OInteractionAbort();
982 0 : comphelper::OInteractionApprove* pApprove = new comphelper::OInteractionApprove();
983 :
984 0 : lContinuations[0] = css::uno::Reference< css::task::XInteractionContinuation >(
985 0 : static_cast< css::task::XInteractionContinuation* >(pAbort),
986 0 : css::uno::UNO_QUERY_THROW);
987 0 : lContinuations[1] = css::uno::Reference< css::task::XInteractionContinuation >(
988 0 : static_cast< css::task::XInteractionContinuation* >(pApprove),
989 0 : css::uno::UNO_QUERY_THROW);
990 :
991 0 : css::task::ErrorCodeRequest aErrorCode;
992 0 : aErrorCode.ErrCode = ERRCODE_SFX_NOMOREDOCUMENTSALLOWED;
993 0 : aInteraction <<= aErrorCode;
994 0 : xInteraction->handle( InteractionRequest::CreateRequest(aInteraction, lContinuations) );
995 0 : }
996 : }
997 :
998 6412 : return bAllowed;
999 : }
1000 :
1001 3299 : bool LoadEnv::impl_loadContent()
1002 : throw(LoadEnvException, css::uno::RuntimeException, std::exception)
1003 : {
1004 : // SAFE -> -----------------------------------
1005 3299 : osl::ClearableMutexGuard aWriteLock(m_mutex);
1006 :
1007 : // search or create right target frame
1008 6598 : OUString sTarget = m_sTarget;
1009 3299 : if (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::E_DEFAULT))
1010 : {
1011 2463 : m_xTargetFrame = impl_searchAlreadyLoaded();
1012 2463 : if (m_xTargetFrame.is())
1013 : {
1014 9 : impl_setResult(true);
1015 9 : return true;
1016 : }
1017 2454 : m_xTargetFrame = impl_searchRecycleTarget();
1018 : }
1019 :
1020 3290 : if (! m_xTargetFrame.is())
1021 : {
1022 3290 : if (
1023 5828 : (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::E_BLANK )) ||
1024 2538 : (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::E_DEFAULT))
1025 : )
1026 : {
1027 3206 : if (! impl_furtherDocsAllowed())
1028 0 : return false;
1029 3206 : m_xTargetFrame = m_xBaseFrame->findFrame(SPECIALTARGET_BLANK, 0);
1030 3206 : m_bCloseFrameOnError = m_xTargetFrame.is();
1031 : }
1032 : else
1033 : {
1034 84 : sal_Int32 nFlags = m_nSearchFlags & ~css::frame::FrameSearchFlag::CREATE;
1035 84 : m_xTargetFrame = m_xBaseFrame->findFrame(sTarget, nFlags);
1036 84 : if (! m_xTargetFrame.is())
1037 : {
1038 0 : if (! impl_furtherDocsAllowed())
1039 0 : return false;
1040 0 : m_xTargetFrame = m_xBaseFrame->findFrame(SPECIALTARGET_BLANK, 0);
1041 0 : m_bCloseFrameOnError = m_xTargetFrame.is();
1042 : }
1043 : }
1044 : }
1045 :
1046 : // If we couldn't find a valid frame or the frame has no container window
1047 : // we have to throw an exception.
1048 6580 : if (
1049 9870 : ( ! m_xTargetFrame.is() ) ||
1050 13160 : ( ! m_xTargetFrame->getContainerWindow().is() )
1051 : )
1052 0 : throw LoadEnvException(LoadEnvException::ID_NO_TARGET_FOUND);
1053 :
1054 6580 : css::uno::Reference< css::frame::XFrame > xTargetFrame = m_xTargetFrame;
1055 :
1056 : // Now we have a valid frame ... and type detection was already done.
1057 : // We should apply the module dependent window position and size to the
1058 : // frame window.
1059 3290 : impl_applyPersistentWindowState(xTargetFrame->getContainerWindow());
1060 :
1061 : // Don't forget to lock task for following load process. Otherwise it could die
1062 : // during this operation runs by terminating the office or closing this task via api.
1063 : // If we set this lock "close()" will return false and closing will be broken.
1064 : // Attention: Don't forget to reset this lock again after finishing operation.
1065 : // Otherwise task AND office couldn't die!!!
1066 : // This includes gracefully handling of Exceptions (Runtime!) too ...
1067 : // That's why we use a specialized guard, which will reset the lock
1068 : // if it will be run out of scope.
1069 :
1070 : // Note further: ignore if this internal guard already contains a resource.
1071 : // Might impl_searchRecylcTarget() set it before. But in case this impl-method wasn't used
1072 : // and the target frame was new created ... this lock here must be set!
1073 6580 : css::uno::Reference< css::document::XActionLockable > xTargetLock(xTargetFrame, css::uno::UNO_QUERY);
1074 3290 : m_aTargetLock.setResource(xTargetLock);
1075 :
1076 : // Add status indicator to descriptor. Loader can show an progresses then.
1077 : // But don't do it, if loading should be hidden or preview is used ...!
1078 : // So we prevent our code against wrong using. Why?
1079 : // It could be, that using of this progress could make trouble. e.g. He make window visible ...
1080 : // but shouldn't do that. But if no indicator is available ... nobody has a chance to do that!
1081 3290 : bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN() , false );
1082 3290 : bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED() , false );
1083 3290 : bool bPreview = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW() , false );
1084 6580 : css::uno::Reference< css::task::XStatusIndicator > xProgress = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR(), css::uno::Reference< css::task::XStatusIndicator >());
1085 :
1086 3290 : if (!bHidden && !bMinimized && !bPreview && !xProgress.is())
1087 : {
1088 : // Note: its an optional interface!
1089 3187 : css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xTargetFrame, css::uno::UNO_QUERY);
1090 3187 : if (xProgressFactory.is())
1091 : {
1092 3187 : xProgress = xProgressFactory->createStatusIndicator();
1093 3187 : if (xProgress.is())
1094 3187 : m_lMediaDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xProgress;
1095 3187 : }
1096 : }
1097 :
1098 : // convert media descriptor and URL to right format for later interface call!
1099 6580 : css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
1100 3290 : m_lMediaDescriptor >> lDescriptor;
1101 6580 : OUString sURL = m_aURL.Complete;
1102 :
1103 : // try to locate any interested frame loader
1104 6580 : css::uno::Reference< css::uno::XInterface > xLoader = impl_searchLoader();
1105 6580 : css::uno::Reference< css::frame::XFrameLoader > xAsyncLoader(xLoader, css::uno::UNO_QUERY);
1106 6580 : css::uno::Reference< css::frame::XSynchronousFrameLoader > xSyncLoader (xLoader, css::uno::UNO_QUERY);
1107 :
1108 3290 : if (xAsyncLoader.is())
1109 : {
1110 8 : m_xAsynchronousJob = xAsyncLoader;
1111 8 : LoadEnvListener* pListener = new LoadEnvListener(this);
1112 8 : aWriteLock.clear();
1113 : // <- SAFE -----------------------------------
1114 :
1115 8 : css::uno::Reference< css::frame::XLoadEventListener > xListener(static_cast< css::frame::XLoadEventListener* >(pListener), css::uno::UNO_QUERY);
1116 8 : xAsyncLoader->load(xTargetFrame, sURL, lDescriptor, xListener);
1117 :
1118 8 : return true;
1119 : }
1120 3282 : else if (xSyncLoader.is())
1121 : {
1122 3282 : bool bResult = xSyncLoader->load(lDescriptor, xTargetFrame);
1123 : // react for the result here, so the outside waiting
1124 : // code can ask for it later.
1125 3282 : impl_setResult(bResult);
1126 : // But the return value indicates a valid started(!) operation.
1127 : // And that's true every time we reach this line :-)
1128 3281 : return true;
1129 : }
1130 :
1131 0 : aWriteLock.clear();
1132 : // <- SAFE
1133 :
1134 3299 : return false;
1135 : }
1136 :
1137 3290 : css::uno::Reference< css::uno::XInterface > LoadEnv::impl_searchLoader()
1138 : {
1139 : // SAFE -> -----------------------------------
1140 3290 : osl::ClearableMutexGuard aReadLock(m_mutex);
1141 :
1142 : // special mode to set an existing component on this frame
1143 : // In such case the loader is fix. It must be the SFX based implementation,
1144 : // which can create a view on top of such xModel components :-)
1145 3290 : if (m_eContentType == E_CAN_BE_SET)
1146 : {
1147 : try
1148 : {
1149 82 : return css::frame::OfficeFrameLoader::create(m_xContext);
1150 : }
1151 0 : catch(const css::uno::RuntimeException&)
1152 0 : { throw; }
1153 0 : catch(const css::uno::Exception&)
1154 : {}
1155 0 : throw LoadEnvException(LoadEnvException::ID_INVALID_ENVIRONMENT);
1156 : }
1157 :
1158 : // Otherwise ...
1159 : // We need this type information to locate an registered frame loader
1160 : // Without such information we can't work!
1161 6416 : OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
1162 3208 : if (sType.isEmpty())
1163 0 : throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
1164 :
1165 : // try to locate any interested frame loader
1166 6416 : css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::FrameLoaderFactory::create(m_xContext);
1167 :
1168 3208 : aReadLock.clear();
1169 : // <- SAFE -----------------------------------
1170 :
1171 6416 : css::uno::Sequence< OUString > lTypesReg(1);
1172 3208 : lTypesReg[0] = sType;
1173 :
1174 6416 : css::uno::Sequence< css::beans::NamedValue > lQuery(1);
1175 3208 : lQuery[0].Name = PROP_TYPES;
1176 3208 : lQuery[0].Value <<= lTypesReg;
1177 :
1178 6416 : OUString sPROP_NAME(PROP_NAME);
1179 :
1180 6416 : css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
1181 6416 : while(xSet->hasMoreElements())
1182 : {
1183 : try
1184 : {
1185 : // try everyone ...
1186 : // Ignore any loader, which makes trouble :-)
1187 3208 : ::comphelper::SequenceAsHashMap lLoaderProps(xSet->nextElement());
1188 3208 : OUString sLoader = lLoaderProps.getUnpackedValueOrDefault(sPROP_NAME, OUString());
1189 3208 : css::uno::Reference< css::uno::XInterface > xLoader;
1190 :
1191 3208 : xLoader = xLoaderFactory->createInstance(sLoader);
1192 3208 : if (xLoader.is())
1193 3208 : return xLoader;
1194 : }
1195 0 : catch(const css::uno::RuntimeException&)
1196 0 : { throw; }
1197 0 : catch(const css::uno::Exception&)
1198 0 : { continue; }
1199 : }
1200 :
1201 3290 : return css::uno::Reference< css::uno::XInterface >();
1202 : }
1203 :
1204 0 : void LoadEnv::impl_jumpToMark(const css::uno::Reference< css::frame::XFrame >& xFrame,
1205 : const css::util::URL& aURL )
1206 : {
1207 0 : if (aURL.Mark.isEmpty())
1208 0 : return;
1209 :
1210 0 : css::uno::Reference< css::frame::XDispatchProvider > xProvider(xFrame, css::uno::UNO_QUERY);
1211 0 : if (! xProvider.is())
1212 0 : return;
1213 :
1214 : // SAFE ->
1215 0 : osl::ClearableMutexGuard aReadLock(m_mutex);
1216 0 : css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1217 0 : aReadLock.clear();
1218 : // <- SAFE
1219 :
1220 0 : css::util::URL aCmd;
1221 0 : aCmd.Complete = ".uno:JumpToMark";
1222 :
1223 0 : css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(xContext));
1224 0 : xParser->parseStrict(aCmd);
1225 :
1226 0 : css::uno::Reference< css::frame::XDispatch > xDispatcher = xProvider->queryDispatch(aCmd, SPECIALTARGET_SELF, 0);
1227 0 : if (! xDispatcher.is())
1228 0 : return;
1229 :
1230 0 : ::comphelper::SequenceAsHashMap lArgs;
1231 0 : lArgs[OUString("Bookmark")] <<= aURL.Mark;
1232 0 : xDispatcher->dispatch(aCmd, lArgs.getAsConstPropertyValueList());
1233 : }
1234 :
1235 2463 : css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchAlreadyLoaded()
1236 : throw(LoadEnvException, css::uno::RuntimeException)
1237 : {
1238 2463 : osl::MutexGuard g(m_mutex);
1239 :
1240 : // such search is allowed for special requests only ...
1241 : // or better its not allowed for some requests in general :-)
1242 4926 : if (
1243 7389 : ( ! TargetHelper::matchSpecialTarget(m_sTarget, TargetHelper::E_DEFAULT) ) ||
1244 17169 : m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false) ||
1245 : // (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN() , false) == sal_True) ||
1246 7317 : m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW(), false)
1247 : )
1248 : {
1249 36 : return css::uno::Reference< css::frame::XFrame >();
1250 : }
1251 :
1252 : // check URL
1253 : // May its not useful to start expensive document search, if it
1254 : // can fail only .. because we load from a stream or model directly!
1255 2427 : if (
1256 4854 : (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_STREAM )) ||
1257 2427 : (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_OBJECT ))
1258 : /*TODO should be private:factory here tested too? */
1259 : )
1260 : {
1261 0 : return css::uno::Reference< css::frame::XFrame >();
1262 : }
1263 :
1264 : // otherwise - iterate through the tasks of the desktop container
1265 : // to find out, which of them might contains the requested document
1266 4854 : css::uno::Reference< css::frame::XDesktop2 > xSupplier = css::frame::Desktop::create( m_xContext );
1267 4854 : css::uno::Reference< css::container::XIndexAccess > xTaskList(xSupplier->getFrames() , css::uno::UNO_QUERY);
1268 :
1269 2427 : if (!xTaskList.is())
1270 0 : return css::uno::Reference< css::frame::XFrame >(); // task list can be empty!
1271 :
1272 : // Note: To detect if a document was already loaded before
1273 : // we check URLs here only. But might the existing and the required
1274 : // document has different versions! Then its URLs are the same ...
1275 2427 : sal_Int16 nNewVersion = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION(), (sal_Int16)(-1));
1276 :
1277 : // will be used to save the first hidden frame referring the searched model
1278 : // Normally we are interested on visible frames ... but if there is no such visible
1279 : // frame we refer to any hidden frame also (but as fallback only).
1280 4854 : css::uno::Reference< css::frame::XFrame > xHiddenTask;
1281 4854 : css::uno::Reference< css::frame::XFrame > xTask;
1282 :
1283 2427 : sal_Int32 count = xTaskList->getCount();
1284 2565 : for (sal_Int32 i=0; i<count; ++i)
1285 : {
1286 : try
1287 : {
1288 : // locate model of task
1289 : // Note: Without a model there is no chance to decide if
1290 : // this task contains the searched document or not!
1291 147 : xTaskList->getByIndex(i) >>= xTask;
1292 147 : if (!xTask.is())
1293 138 : continue;
1294 :
1295 147 : css::uno::Reference< css::frame::XController > xController = xTask->getController();
1296 147 : if (!xController.is())
1297 : {
1298 0 : xTask.clear ();
1299 0 : continue;
1300 : }
1301 :
1302 147 : css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1303 147 : if (!xModel.is())
1304 : {
1305 0 : xTask.clear ();
1306 0 : continue;
1307 : }
1308 :
1309 : // don't check the complete URL here.
1310 : // use its main part - ignore optional jumpmarks!
1311 147 : const OUString sURL = xModel->getURL();
1312 147 : if (!::utl::UCBContentHelper::EqualURLs( m_aURL.Main, sURL ))
1313 : {
1314 138 : xTask.clear ();
1315 138 : continue;
1316 : }
1317 :
1318 : // get the original load arguments from the current document
1319 : // and decide if its really the same then the one will be.
1320 : // It must be visible and must use the same file revision ...
1321 : // or must not have any file revision set (-1 == -1!)
1322 9 : utl::MediaDescriptor lOldDocDescriptor(xModel->getArgs());
1323 :
1324 9 : if (lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION(), (sal_Int32)(-1)) != nNewVersion)
1325 : {
1326 0 : xTask.clear ();
1327 0 : continue;
1328 : }
1329 :
1330 : // Hidden frames are special.
1331 : // They will be used as "last chance" if there is no visible frame pointing to the same model.
1332 : // Safe the result but continue with current loop might be looking for other visible frames.
1333 9 : bool bIsHidden = lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1334 9 : if (
1335 9 : ( bIsHidden ) &&
1336 0 : ( ! xHiddenTask.is())
1337 : )
1338 : {
1339 0 : xHiddenTask = xTask;
1340 0 : xTask.clear ();
1341 0 : continue;
1342 : }
1343 :
1344 : // We found a visible task pointing to the right model ...
1345 : // Break search.
1346 9 : break;
1347 : }
1348 0 : catch(const css::uno::RuntimeException&)
1349 0 : { throw; }
1350 0 : catch(const css::uno::Exception&)
1351 0 : { continue; }
1352 : }
1353 :
1354 4854 : css::uno::Reference< css::frame::XFrame > xResult;
1355 2427 : if (xTask.is())
1356 9 : xResult = xTask;
1357 2418 : else if (xHiddenTask.is())
1358 0 : xResult = xHiddenTask;
1359 :
1360 2427 : if (xResult.is())
1361 : {
1362 : // Now we are sure, that this task includes the searched document.
1363 : // It's time to activate it. As special feature we try to jump internally
1364 : // if an optional jumpmark is given too.
1365 9 : if (!m_aURL.Mark.isEmpty())
1366 0 : impl_jumpToMark(xResult, m_aURL);
1367 :
1368 : // bring it to front and make sure it's visible...
1369 9 : impl_makeFrameWindowVisible(xResult->getContainerWindow(), true);
1370 : }
1371 :
1372 4890 : return xResult;
1373 : }
1374 :
1375 0 : bool LoadEnv::impl_isFrameAlreadyUsedForLoading(const css::uno::Reference< css::frame::XFrame >& xFrame) const
1376 : {
1377 0 : css::uno::Reference< css::document::XActionLockable > xLock(xFrame, css::uno::UNO_QUERY);
1378 :
1379 : // ? no lock interface ?
1380 : // Might its an external written frame implementation :-(
1381 : // Allowing using of it ... but it can fail if its not synchronized with our processes !
1382 0 : if (!xLock.is())
1383 0 : return false;
1384 :
1385 : // Otherwise we have to look for any other existing lock.
1386 0 : return xLock->isActionLocked();
1387 : }
1388 :
1389 2454 : css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchRecycleTarget()
1390 : throw(LoadEnvException, css::uno::RuntimeException, std::exception)
1391 : {
1392 : // SAFE -> ..................................
1393 2454 : osl::ClearableMutexGuard aReadLock(m_mutex);
1394 :
1395 : // The special backing mode frame will be recycled by definition!
1396 : // It doesn't matter if somewhere wants to create a new view
1397 : // or open a new untitled document ...
1398 : // The only exception form that - hidden frames!
1399 2454 : if (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false))
1400 0 : return css::uno::Reference< css::frame::XFrame >();
1401 :
1402 4908 : css::uno::Reference< css::frame::XFramesSupplier > xSupplier( css::frame::Desktop::create( m_xContext ), css::uno::UNO_QUERY);
1403 4908 : FrameListAnalyzer aTasksAnalyzer(xSupplier, css::uno::Reference< css::frame::XFrame >(), FrameListAnalyzer::E_BACKINGCOMPONENT);
1404 2454 : if (aTasksAnalyzer.m_xBackingComponent.is())
1405 : {
1406 0 : if (!impl_isFrameAlreadyUsedForLoading(aTasksAnalyzer.m_xBackingComponent))
1407 : {
1408 : // bring it to front ...
1409 0 : impl_makeFrameWindowVisible(aTasksAnalyzer.m_xBackingComponent->getContainerWindow(), true);
1410 0 : return aTasksAnalyzer.m_xBackingComponent;
1411 : }
1412 : }
1413 :
1414 : // These states indicates a wish for creation of a new view in general.
1415 4908 : if (
1416 12198 : m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false) ||
1417 7290 : m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW(), false)
1418 : )
1419 : {
1420 36 : return css::uno::Reference< css::frame::XFrame >();
1421 : }
1422 :
1423 : // On the other side some special URLs will open a new frame every time (expecting
1424 : // they can use the backing-mode frame!)
1425 2418 : if (
1426 4829 : (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_FACTORY )) ||
1427 4829 : (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_STREAM )) ||
1428 2411 : (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_OBJECT ))
1429 : )
1430 : {
1431 7 : return css::uno::Reference< css::frame::XFrame >();
1432 : }
1433 :
1434 : // No backing frame! No special URL => recycle active task - if possible.
1435 : // Means - if it does not already contains a modified document, or
1436 : // use another office module.
1437 4822 : css::uno::Reference< css::frame::XFrame > xTask = xSupplier->getActiveFrame();
1438 :
1439 : // not a real error - but might a focus problem!
1440 2411 : if (!xTask.is())
1441 2408 : return css::uno::Reference< css::frame::XFrame >();
1442 :
1443 : // not a real error - may it's a view only
1444 6 : css::uno::Reference< css::frame::XController > xController = xTask->getController();
1445 3 : if (!xController.is())
1446 0 : return css::uno::Reference< css::frame::XFrame >();
1447 :
1448 : // not a real error - may it's a db component instead of a full featured office document
1449 6 : css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1450 3 : if (!xModel.is())
1451 0 : return css::uno::Reference< css::frame::XFrame >();
1452 :
1453 : // get some more information ...
1454 :
1455 : // A valid set URL means: there is already a location for this document.
1456 : // => it was saved there or opened from there. Such Documents can not be used here.
1457 : // We search for empty document ... created by a private:factory/ URL!
1458 3 : if (xModel->getURL().getLength()>0)
1459 3 : return css::uno::Reference< css::frame::XFrame >();
1460 :
1461 : // The old document must be unmodified ...
1462 0 : css::uno::Reference< css::util::XModifiable > xModified(xModel, css::uno::UNO_QUERY);
1463 0 : if (xModified->isModified())
1464 0 : return css::uno::Reference< css::frame::XFrame >();
1465 :
1466 0 : vcl::Window* pWindow = VCLUnoHelper::GetWindow(xTask->getContainerWindow());
1467 0 : if (pWindow && pWindow->IsInModalMode())
1468 0 : return css::uno::Reference< css::frame::XFrame >();
1469 :
1470 : // find out the application type of this document
1471 : // We can recycle only documents, which uses the same application
1472 : // then the new one.
1473 0 : SvtModuleOptions::EFactory eOldApp = SvtModuleOptions::ClassifyFactoryByModel(xModel);
1474 0 : SvtModuleOptions::EFactory eNewApp = SvtModuleOptions::ClassifyFactoryByURL (m_aURL.Complete, m_lMediaDescriptor.getAsConstPropertyValueList());
1475 :
1476 0 : aReadLock.clear();
1477 : // <- SAFE ..................................
1478 :
1479 0 : if (eOldApp != eNewApp)
1480 0 : return css::uno::Reference< css::frame::XFrame >();
1481 :
1482 : // OK this task seems to be usable for recycling
1483 : // But we should mark it as such - means set an action lock.
1484 : // Otherwise it would be used more than ones or will be destroyed
1485 : // by a close() or terminate() request.
1486 : // But if such lock already exist ... it means this task is used for
1487 : // any other operation already. Don't use it then.
1488 0 : if (impl_isFrameAlreadyUsedForLoading(xTask))
1489 0 : return css::uno::Reference< css::frame::XFrame >();
1490 :
1491 : // OK - there is a valid target frame.
1492 : // But may be it contains already a document.
1493 : // Then we have to ask it, if it allows recycling of this frame .-)
1494 0 : bool bReactivateOldControllerOnError = false;
1495 0 : css::uno::Reference< css::frame::XController > xOldDoc = xTask->getController();
1496 0 : if (xOldDoc.is())
1497 : {
1498 0 : bReactivateOldControllerOnError = xOldDoc->suspend(sal_True);
1499 0 : if (! bReactivateOldControllerOnError)
1500 0 : return css::uno::Reference< css::frame::XFrame >();
1501 : }
1502 :
1503 : // SAFE -> ..................................
1504 0 : osl::ClearableMutexGuard aWriteLock(m_mutex);
1505 :
1506 0 : css::uno::Reference< css::document::XActionLockable > xLock(xTask, css::uno::UNO_QUERY);
1507 0 : if (!m_aTargetLock.setResource(xLock))
1508 0 : return css::uno::Reference< css::frame::XFrame >();
1509 :
1510 0 : m_bReactivateControllerOnError = bReactivateOldControllerOnError;
1511 0 : aWriteLock.clear();
1512 : // <- SAFE ..................................
1513 :
1514 : // bring it to front ...
1515 0 : impl_makeFrameWindowVisible(xTask->getContainerWindow(), true);
1516 :
1517 2454 : return xTask;
1518 : }
1519 :
1520 3299 : void LoadEnv::impl_reactForLoadingState()
1521 : throw(LoadEnvException, css::uno::RuntimeException)
1522 : {
1523 : /*TODO reset action locks */
1524 :
1525 : // SAFE -> ----------------------------------
1526 3299 : osl::ClearableMutexGuard aReadLock(m_mutex);
1527 :
1528 3299 : if (m_bLoaded)
1529 : {
1530 : // Bring the new loaded document to front (if allowed!).
1531 : // Note: We show new created frames here only.
1532 : // We dont hide already visible frames here ...
1533 3298 : css::uno::Reference< css::awt::XWindow > xWindow = m_xTargetFrame->getContainerWindow();
1534 3298 : bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1535 3298 : bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED(), false);
1536 :
1537 3298 : if (bMinimized)
1538 : {
1539 0 : SolarMutexGuard aSolarGuard;
1540 0 : vcl::Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
1541 : // check for system window is necessary to guarantee correct pointer cast!
1542 0 : if (pWindow && pWindow->IsSystemWindow())
1543 0 : static_cast<WorkWindow*>(pWindow)->Minimize();
1544 : }
1545 3298 : else if (!bHidden)
1546 : {
1547 : // show frame ... if it's not still visible ...
1548 : // But do nothing if it's already visible!
1549 3195 : impl_makeFrameWindowVisible(xWindow, false);
1550 : }
1551 :
1552 : // Note: Only if an existing property "FrameName" is given by this media descriptor,
1553 : // it should be used. Otherwise we should do nothing. May be the outside code has already
1554 : // set a frame name on the target!
1555 3298 : utl::MediaDescriptor::const_iterator pFrameName = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FRAMENAME());
1556 3298 : if (pFrameName != m_lMediaDescriptor.end())
1557 : {
1558 0 : OUString sFrameName;
1559 0 : pFrameName->second >>= sFrameName;
1560 : // Check the name again. e.g. "_default" isn't allowed.
1561 : // On the other side "_beamer" is a valid name :-)
1562 0 : if (TargetHelper::isValidNameForFrame(sFrameName))
1563 0 : m_xTargetFrame->setName(sFrameName);
1564 3298 : }
1565 : }
1566 1 : else if (m_bReactivateControllerOnError)
1567 : {
1568 : // Try to reactivate the old document (if any exists!)
1569 0 : css::uno::Reference< css::frame::XController > xOldDoc = m_xTargetFrame->getController();
1570 : // clear does not depend from reactivation state of a might existing old document!
1571 : // We must make sure, that a might following getTargetComponent() call does not return
1572 : // the old document!
1573 0 : m_xTargetFrame.clear();
1574 0 : if (xOldDoc.is())
1575 : {
1576 0 : bool bReactivated = xOldDoc->suspend(sal_False);
1577 0 : if (!bReactivated)
1578 0 : throw LoadEnvException(LoadEnvException::ID_COULD_NOT_REACTIVATE_CONTROLLER);
1579 0 : m_bReactivateControllerOnError = false;
1580 0 : }
1581 : }
1582 1 : else if (m_bCloseFrameOnError)
1583 : {
1584 : // close empty frames
1585 1 : css::uno::Reference< css::util::XCloseable > xCloseable (m_xTargetFrame, css::uno::UNO_QUERY);
1586 2 : css::uno::Reference< css::lang::XComponent > xDisposable(m_xTargetFrame, css::uno::UNO_QUERY);
1587 :
1588 : try
1589 : {
1590 1 : if (xCloseable.is())
1591 1 : xCloseable->close(sal_True);
1592 : else
1593 0 : if (xDisposable.is())
1594 0 : xDisposable->dispose();
1595 : }
1596 1 : catch(const css::util::CloseVetoException&)
1597 : {}
1598 0 : catch(const css::lang::DisposedException&)
1599 : {}
1600 2 : m_xTargetFrame.clear();
1601 : }
1602 :
1603 : // This max force an implicit closing of our target frame ...
1604 : // e.g. in case close(sal_True) was called before and the frame
1605 : // kill itself if our external use-lock is released here!
1606 : // That's why we release this lock AFTER ALL OPERATIONS on this frame
1607 : // are finished. The frame itself must handle then
1608 : // this situation gracefully.
1609 3299 : m_aTargetLock.freeResource();
1610 :
1611 : // Last but not least :-)
1612 : // We have to clear the current media descriptor.
1613 : // Otherwise it hold a might existing stream open!
1614 3299 : m_lMediaDescriptor.clear();
1615 :
1616 6598 : css::uno::Any aRequest;
1617 3299 : bool bThrow = false;
1618 3299 : if ( !m_bLoaded && m_pQuietInteraction.is() && m_pQuietInteraction->wasUsed() )
1619 : {
1620 1 : aRequest = m_pQuietInteraction->getRequest();
1621 1 : m_pQuietInteraction.clear();
1622 1 : bThrow = true;
1623 : }
1624 :
1625 3299 : aReadLock.clear();
1626 :
1627 3299 : if (bThrow)
1628 : {
1629 1 : if ( aRequest.isExtractableTo( ::cppu::UnoType< css::uno::Exception >::get() ) )
1630 : throw LoadEnvException(
1631 : LoadEnvException::ID_GENERAL_ERROR, "interaction request",
1632 1 : aRequest);
1633 3299 : }
1634 :
1635 : // <- SAFE ----------------------------------
1636 3298 : }
1637 :
1638 3204 : void LoadEnv::impl_makeFrameWindowVisible(const css::uno::Reference< css::awt::XWindow >& xWindow ,
1639 : bool bForceToFront)
1640 : {
1641 : // SAFE -> ----------------------------------
1642 3204 : osl::ClearableMutexGuard aReadLock(m_mutex);
1643 6408 : css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1644 3204 : aReadLock.clear();
1645 : // <- SAFE ----------------------------------
1646 :
1647 6408 : SolarMutexGuard aSolarGuard;
1648 3204 : vcl::Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
1649 3204 : if ( pWindow )
1650 : {
1651 : bool const preview( m_lMediaDescriptor.getUnpackedValueOrDefault(
1652 3204 : utl::MediaDescriptor::PROP_PREVIEW(), false) );
1653 :
1654 3204 : bool bForceFrontAndFocus(false);
1655 3204 : if ( !preview )
1656 : {
1657 : css::uno::Any const a =
1658 : ::comphelper::ConfigurationHelper::readDirectKey(
1659 : xContext,
1660 : OUString("org.openoffice.Office.Common/View"),
1661 : OUString("NewDocumentHandling"),
1662 : OUString("ForceFocusAndToFront"),
1663 3204 : ::comphelper::ConfigurationHelper::E_READONLY);
1664 3204 : a >>= bForceFrontAndFocus;
1665 : }
1666 :
1667 3204 : if( pWindow->IsVisible() && (bForceFrontAndFocus || bForceToFront) )
1668 9 : pWindow->ToTop();
1669 : else
1670 3195 : pWindow->Show(true, (bForceFrontAndFocus || bForceToFront) ? ShowFlags::ForegroundTask : ShowFlags::NONE );
1671 3204 : }
1672 3204 : }
1673 :
1674 3290 : void LoadEnv::impl_applyPersistentWindowState(const css::uno::Reference< css::awt::XWindow >& xWindow)
1675 : {
1676 : static const char PACKAGE_SETUP_MODULES[] = "/org.openoffice.Setup/Office/Factories";
1677 :
1678 : // no window -> action not possible
1679 3290 : if (!xWindow.is())
1680 83 : return;
1681 :
1682 : // window already visible -> do nothing! If we use a "recycle frame" for loading ...
1683 : // the current position and size must be used.
1684 3290 : css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(xWindow, css::uno::UNO_QUERY);
1685 3290 : if (
1686 6580 : (xVisibleCheck.is() ) &&
1687 3290 : (xVisibleCheck->isVisible())
1688 : )
1689 17 : return;
1690 :
1691 : // SOLAR SAFE ->
1692 6480 : SolarMutexClearableGuard aSolarGuard1;
1693 :
1694 3273 : vcl::Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
1695 3273 : if (!pWindow)
1696 0 : return;
1697 :
1698 3273 : bool bSystemWindow = pWindow->IsSystemWindow();
1699 3273 : bool bWorkWindow = (pWindow->GetType() == WINDOW_WORKWINDOW);
1700 :
1701 3273 : if (!bSystemWindow && !bWorkWindow)
1702 0 : return;
1703 :
1704 : // dont overwrite this special state!
1705 3273 : WorkWindow* pWorkWindow = static_cast<WorkWindow*>(pWindow);
1706 3273 : if (pWorkWindow->IsMinimized())
1707 0 : return;
1708 :
1709 3273 : aSolarGuard1.clear();
1710 : // <- SOLAR SAFE
1711 :
1712 : // SAFE ->
1713 6480 : osl::ClearableMutexGuard aReadLock(m_mutex);
1714 :
1715 : // no filter -> no module -> no persistent window state
1716 : OUString sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(
1717 3273 : utl::MediaDescriptor::PROP_FILTERNAME(),
1718 9753 : OUString());
1719 3273 : if (sFilter.isEmpty())
1720 66 : return;
1721 :
1722 6414 : css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1723 :
1724 3207 : aReadLock.clear();
1725 : // <- SAFE
1726 :
1727 : try
1728 : {
1729 : // retrieve the module name from the filter configuration
1730 : css::uno::Reference< css::container::XNameAccess > xFilterCfg(
1731 6414 : xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext),
1732 3207 : css::uno::UNO_QUERY_THROW);
1733 6414 : ::comphelper::SequenceAsHashMap lProps (xFilterCfg->getByName(sFilter));
1734 6414 : OUString sModule = lProps.getUnpackedValueOrDefault(FILTER_PROPNAME_DOCUMENTSERVICE, OUString());
1735 :
1736 : // get access to the configuration of this office module
1737 : css::uno::Reference< css::container::XNameAccess > xModuleCfg(::comphelper::ConfigurationHelper::openConfig(
1738 : xContext,
1739 : PACKAGE_SETUP_MODULES,
1740 : ::comphelper::ConfigurationHelper::E_READONLY),
1741 6414 : css::uno::UNO_QUERY_THROW);
1742 :
1743 : // read window state from the configuration
1744 : // and apply it on the window.
1745 : // Do nothing, if no configuration entry exists!
1746 6414 : OUString sWindowState;
1747 3207 : ::comphelper::ConfigurationHelper::readRelativeKey(xModuleCfg, sModule, OFFICEFACTORY_PROPNAME_WINDOWATTRIBUTES) >>= sWindowState;
1748 3207 : if (!sWindowState.isEmpty())
1749 : {
1750 : // SOLAR SAFE ->
1751 3129 : SolarMutexGuard aSolarGuard;
1752 :
1753 : // We have to retrieve the window pointer again. Because nobody can guarantee
1754 : // that the XWindow was not disposed in between .-)
1755 : // But if we get a valid pointer we can be sure, that it's the system window pointer
1756 : // we already checked and used before. Because nobody recycle the same uno reference for
1757 : // a new internal c++ implementation ... hopefully .-))
1758 3129 : vcl::Window* pWindowCheck = VCLUnoHelper::GetWindow(xWindow);
1759 3129 : if (! pWindowCheck)
1760 0 : return;
1761 :
1762 3129 : SystemWindow* pSystemWindow = static_cast<SystemWindow*>(pWindowCheck);
1763 3129 : pSystemWindow->SetWindowState(OUStringToOString(sWindowState,RTL_TEXTENCODING_UTF8));
1764 : // <- SOLAR SAFE
1765 3207 : }
1766 : }
1767 0 : catch(const css::uno::RuntimeException&)
1768 0 : { throw; }
1769 0 : catch(const css::uno::Exception&)
1770 3207 : {}
1771 : }
1772 :
1773 : } // namespace framework
1774 :
1775 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|