fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / framework / source / loadenv / loadenv.cxx
blob42619711ad5a02f625b411dde521f2f6a1450234
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <loadenv/loadenv.hxx>
22 #include <loadenv/targethelper.hxx>
23 #include <framework/framelistanalyzer.hxx>
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"
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>
72 #include <vcl/window.hxx>
73 #include <vcl/wrkwin.hxx>
74 #include <vcl/syswin.hxx>
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>
85 #include <config_orcus.h>
87 const char PROP_TYPES[] = "Types";
88 const char PROP_NAME[] = "Name";
90 namespace framework {
92 using namespace com::sun::star;
94 class LoadEnvListener : public ::cppu::WeakImplHelper2< css::frame::XLoadEventListener ,
95 css::frame::XDispatchResultListener >
97 private:
98 osl::Mutex m_mutex;
99 bool m_bWaitingResult;
100 LoadEnv* m_pLoadEnv;
102 public:
104 LoadEnvListener(LoadEnv* pLoadEnv)
105 : m_bWaitingResult(true)
106 , m_pLoadEnv(pLoadEnv)
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;
114 virtual void SAL_CALL loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >& xLoader)
115 throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
117 // frame.XDispatchResultListener
118 virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent& aEvent)
119 throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
121 // lang.XEventListener
122 virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent)
123 throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
126 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 , m_bLoaded( false )
138 LoadEnv::~LoadEnv()
142 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 )
152 css::uno::Reference< css::lang::XComponent > xComponent;
156 LoadEnv aEnv(xContext);
158 aEnv.initializeLoading(sURL,
159 lArgs,
160 css::uno::Reference< css::frame::XFrame >(xLoader, css::uno::UNO_QUERY),
161 sTarget,
162 nFlags,
163 LoadEnv::E_NO_FEATURE);
164 aEnv.startLoading();
165 aEnv.waitWhileLoading(); // wait for ever!
167 xComponent = aEnv.getTargetComponent();
169 catch(const LoadEnvException& ex)
171 switch(ex.m_nID)
173 case LoadEnvException::ID_INVALID_MEDIADESCRIPTOR:
174 throw css::lang::IllegalArgumentException(
175 "Optional list of arguments seem to be corrupted.", xLoader, 4);
177 case LoadEnvException::ID_UNSUPPORTED_CONTENT:
178 throw css::lang::IllegalArgumentException(
179 "Unsupported URL <" + sURL + ">: \"" + ex.m_sMessage + "\"",
180 xLoader, 1);
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 xComponent.clear();
195 break;
199 return xComponent;
202 utl::MediaDescriptor impl_mergeMediaDescriptorWithMightExistingModelArgs(const css::uno::Sequence< css::beans::PropertyValue >& lOutsideDescriptor)
204 utl::MediaDescriptor lDescriptor(lOutsideDescriptor);
205 css::uno::Reference< css::frame::XModel > xModel = lDescriptor.getUnpackedValueOrDefault(
206 utl::MediaDescriptor::PROP_MODEL (),
207 css::uno::Reference< css::frame::XModel > ());
208 if (xModel.is ())
210 utl::MediaDescriptor lModelDescriptor(xModel->getArgs());
211 utl::MediaDescriptor::iterator pIt = lModelDescriptor.find( utl::MediaDescriptor::PROP_MACROEXECUTIONMODE() );
212 if ( pIt != lModelDescriptor.end() )
213 lDescriptor[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()] = pIt->second;
216 return lDescriptor;
219 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 ...
227 osl::MutexGuard g(m_mutex);
229 // Handle still running processes!
230 if (m_xAsynchronousJob.is())
231 throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
233 // take over all new parameters.
234 m_xTargetFrame.clear();
235 m_xBaseFrame = xBaseFrame;
236 m_lMediaDescriptor = impl_mergeMediaDescriptorWithMightExistingModelArgs(lMediaDescriptor);
237 m_sTarget = sTarget;
238 m_nSearchFlags = nSearchFlags;
239 m_eFeature = eFeature;
240 m_eContentType = eContentType;
241 m_bCloseFrameOnError = false;
242 m_bReactivateControllerOnError = false;
243 m_bLoaded = false;
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 if (m_eContentType == E_UNSUPPORTED_CONTENT)
251 m_eContentType = LoadEnv::classifyContent(sURL, lMediaDescriptor);
252 if (m_eContentType == E_UNSUPPORTED_CONTENT)
253 throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT, "from LoadEnv::initializeLoading");
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 m_lMediaDescriptor[utl::MediaDescriptor::PROP_URL()] <<= sURL;
261 // parse it - because some following code require that
262 m_aURL.Complete = sURL;
263 css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
264 xParser->parseStrict(m_aURL);
266 // BTW: Split URL and JumpMark ...
267 // Because such mark is an explicit value of the media descriptor!
268 if (!m_aURL.Mark.isEmpty())
269 m_lMediaDescriptor[utl::MediaDescriptor::PROP_JUMPMARK()] <<= m_aURL.Mark;
271 // By the way: remove the old and deprecated value "FileName" from the descriptor!
272 utl::MediaDescriptor::iterator pIt = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FILENAME());
273 if (pIt != m_lMediaDescriptor.end())
274 m_lMediaDescriptor.erase(pIt);
276 // patch the MediaDescriptor, so it fulfil the outside requirements
277 // Means especially items like e.g. UI InteractionHandler, Status Indicator,
278 // MacroExecutionMode, etc.
280 /*TODO progress is bound to a frame ... How can we set it here? */
282 // UI mode
283 const bool bUIMode =
284 ( ( m_eFeature & E_WORK_WITH_UI ) == E_WORK_WITH_UI ) &&
285 !m_lMediaDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_HIDDEN(), false ) &&
286 !m_lMediaDescriptor.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_PREVIEW(), false );
288 initializeUIDefaults(
289 m_xContext,
290 m_lMediaDescriptor,
291 bUIMode,
292 &m_pQuietInteraction
296 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 )
300 css::uno::Reference< css::task::XInteractionHandler > xInteractionHandler;
301 sal_Int16 nMacroMode;
302 sal_Int16 nUpdateMode;
304 if ( i_bUIMode )
306 nMacroMode = css::document::MacroExecMode::USE_CONFIG;
307 nUpdateMode = css::document::UpdateDocMode::ACCORDING_TO_CONFIG;
310 xInteractionHandler.set( css::task::InteractionHandler::createWithParent( i_rxContext, 0 ), css::uno::UNO_QUERY_THROW );
312 catch(const css::uno::RuntimeException&) {throw;}
313 catch(const css::uno::Exception& ) { }
315 // hidden mode
316 else
318 nMacroMode = css::document::MacroExecMode::NEVER_EXECUTE;
319 nUpdateMode = css::document::UpdateDocMode::NO_UPDATE;
320 rtl::Reference<QuietInteraction> pQuietInteraction = new QuietInteraction();
321 xInteractionHandler = pQuietInteraction.get();
322 if ( o_ppQuietInteraction != NULL )
324 *o_ppQuietInteraction = pQuietInteraction;
328 if (
329 (xInteractionHandler.is() ) &&
330 (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_INTERACTIONHANDLER()) == io_lMediaDescriptor.end())
333 io_lMediaDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteractionHandler;
336 if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()) == io_lMediaDescriptor.end())
337 io_lMediaDescriptor[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()] <<= nMacroMode;
339 if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_UPDATEDOCMODE()) == io_lMediaDescriptor.end())
340 io_lMediaDescriptor[utl::MediaDescriptor::PROP_UPDATEDOCMODE()] <<= nUpdateMode;
343 void LoadEnv::startLoading()
345 // SAFE ->
346 osl::ClearableMutexGuard aReadLock(m_mutex);
348 // Handle still running processes!
349 if (m_xAsynchronousJob.is())
350 throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
352 // content can not be loaded or handled
353 // check "classifyContent()" failed before ...
354 if (m_eContentType == E_UNSUPPORTED_CONTENT)
355 throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT, "from LoadEnv::startLoading");
357 // <- SAFE
358 aReadLock.clear();
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 if (m_eContentType != E_CAN_BE_SET)/* Attention: special feature to set existing component on a frame must ignore type detection! */
366 impl_detectTypeAndFilter();
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 bool bStarted = false;
374 if (
375 ((m_eFeature & E_ALLOW_CONTENTHANDLER) == E_ALLOW_CONTENTHANDLER) &&
376 (m_eContentType != E_CAN_BE_SET ) /* Attention: special feature to set existing component on a frame must ignore type detection! */
379 bStarted = impl_handleContent();
382 if (!bStarted)
383 bStarted = impl_loadContent();
385 // not started => general error
386 // We can't say - what was the reason for.
387 if (!bStarted)
388 throw LoadEnvException(
389 LoadEnvException::ID_GENERAL_ERROR, "not started");
392 /*-----------------------------------------------
393 TODO
394 First draft does not implement timeout using [ms].
395 Current implementation counts yield calls only ...
396 -----------------------------------------------*/
397 bool LoadEnv::waitWhileLoading(sal_uInt32 nTimeout)
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 :-)
404 sal_Int32 nTime = nTimeout;
405 while(true)
407 // SAFE -> ------------------------------
408 osl::ClearableMutexGuard aReadLock1(m_mutex);
409 if (!m_xAsynchronousJob.is())
410 break;
411 aReadLock1.clear();
412 // <- SAFE ------------------------------
414 Application::Yield();
416 // forever!
417 if (nTimeout==0)
418 continue;
420 // timed out?
421 --nTime;
422 if (nTime<1)
423 break;
426 osl::MutexGuard g(m_mutex);
427 return !m_xAsynchronousJob.is();
430 css::uno::Reference< css::lang::XComponent > LoadEnv::getTargetComponent() const
432 osl::MutexGuard g(m_mutex);
434 if (!m_xTargetFrame.is())
435 return css::uno::Reference< css::lang::XComponent >();
437 css::uno::Reference< css::frame::XController > xController = m_xTargetFrame->getController();
438 if (!xController.is())
439 return css::uno::Reference< css::lang::XComponent >(m_xTargetFrame->getComponentWindow(), css::uno::UNO_QUERY);
441 css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
442 if (!xModel.is())
443 return css::uno::Reference< css::lang::XComponent >(xController, css::uno::UNO_QUERY);
445 return css::uno::Reference< css::lang::XComponent >(xModel, css::uno::UNO_QUERY);
448 void SAL_CALL LoadEnvListener::loadFinished(const css::uno::Reference< css::frame::XFrameLoader >&)
449 throw(css::uno::RuntimeException, std::exception)
451 osl::MutexGuard g(m_mutex);
452 if (m_bWaitingResult)
453 m_pLoadEnv->impl_setResult(true);
454 m_bWaitingResult = false;
457 void SAL_CALL LoadEnvListener::loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >&)
458 throw(css::uno::RuntimeException, std::exception)
460 osl::MutexGuard g(m_mutex);
461 if (m_bWaitingResult)
462 m_pLoadEnv->impl_setResult(false);
463 m_bWaitingResult = false;
466 void SAL_CALL LoadEnvListener::dispatchFinished(const css::frame::DispatchResultEvent& aEvent)
467 throw(css::uno::RuntimeException, std::exception)
469 osl::MutexGuard g(m_mutex);
471 if (!m_bWaitingResult)
472 return;
474 switch(aEvent.State)
476 case css::frame::DispatchResultState::FAILURE :
477 m_pLoadEnv->impl_setResult(false);
478 break;
480 case css::frame::DispatchResultState::SUCCESS :
481 m_pLoadEnv->impl_setResult(false);
482 break;
484 case css::frame::DispatchResultState::DONTKNOW :
485 m_pLoadEnv->impl_setResult(false);
486 break;
488 m_bWaitingResult = false;
491 void SAL_CALL LoadEnvListener::disposing(const css::lang::EventObject&)
492 throw(css::uno::RuntimeException, std::exception)
494 osl::MutexGuard g(m_mutex);
495 if (m_bWaitingResult)
496 m_pLoadEnv->impl_setResult(false);
497 m_bWaitingResult = false;
500 void LoadEnv::impl_setResult(bool bResult)
502 osl::MutexGuard g(m_mutex);
504 m_bLoaded = bResult;
506 impl_reactForLoadingState();
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 m_xAsynchronousJob.clear();
514 /*-----------------------------------------------
515 TODO: Is it a good idea to change Sequence<>
516 parameter to stl-adapter?
517 -----------------------------------------------*/
518 LoadEnv::EContentType LoadEnv::classifyContent(const OUString& sURL ,
519 const css::uno::Sequence< css::beans::PropertyValue >& lMediaDescriptor)
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 :-)
532 (sURL.isEmpty() ) ||
533 (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_UNO )) ||
534 (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_SLOT )) ||
535 (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_MACRO )) ||
536 (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_SERVICE)) ||
537 (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_MAILTO )) ||
538 (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_NEWS ))
541 return E_UNSUPPORTED_CONTENT;
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.
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 .-)
559 // creation of new documents
560 if (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_PRIVATE_FACTORY))
561 return E_CAN_BE_LOADED;
563 // using of an existing input stream
564 utl::MediaDescriptor stlMediaDescriptor(lMediaDescriptor);
565 utl::MediaDescriptor::const_iterator pIt;
566 if (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_PRIVATE_STREAM))
568 pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_INPUTSTREAM());
569 css::uno::Reference< css::io::XInputStream > xStream;
570 if (pIt != stlMediaDescriptor.end())
571 pIt->second >>= xStream;
572 if (xStream.is())
573 return E_CAN_BE_LOADED;
574 SAL_INFO("fwk", "LoadEnv::classifyContent(): loading from stream with right URL but invalid stream detected");
575 return E_UNSUPPORTED_CONTENT;
578 // using of a full featured document
579 if (ProtocolCheck::isProtocol(sURL,ProtocolCheck::E_PRIVATE_OBJECT))
581 pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_MODEL());
582 css::uno::Reference< css::frame::XModel > xModel;
583 if (pIt != stlMediaDescriptor.end())
584 pIt->second >>= xModel;
585 if (xModel.is())
586 return E_CAN_BE_SET;
587 SAL_INFO("fwk", "LoadEnv::classifyContent(): loading with object with right URL but invalid object detected");
588 return E_UNSUPPORTED_CONTENT;
591 // following operations can work on an internal type name only :-(
592 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
593 css::uno::Reference< css::document::XTypeDetection > xDetect(
594 xContext->getServiceManager()->createInstanceWithContext(
595 "com.sun.star.document.TypeDetection", xContext),
596 css::uno::UNO_QUERY_THROW);
598 OUString sType = xDetect->queryTypeByURL(sURL);
600 css::uno::Sequence< css::beans::NamedValue > lQuery(1);
601 css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory;
602 css::uno::Reference< css::container::XEnumeration > xSet;
603 css::uno::Sequence< OUString > lTypesReg(1);
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!
618 OUString sPROP_TYPES(PROP_TYPES);
620 lTypesReg[0] = sType;
621 lQuery[0].Name = sPROP_TYPES;
622 lQuery[0].Value <<= lTypesReg;
624 xLoaderFactory = css::frame::FrameLoaderFactory::create(xContext);
625 xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
626 // at least one registered frame loader is enough!
627 if (xSet->hasMoreElements())
628 return E_CAN_BE_LOADED;
630 // (iv) Some URL protocols are supported by special services.
631 // E.g. ContentHandler.
632 // Such contents can be handled ... but not loaded.
634 lTypesReg[0] = sType;
635 lQuery[0].Name = sPROP_TYPES;
636 lQuery[0].Value <<= lTypesReg;
638 xLoaderFactory = css::frame::ContentHandlerFactory::create(xContext);
639 xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
640 // at least one registered content handler is enough!
641 if (xSet->hasMoreElements())
642 return E_CAN_BE_HANDLED;
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 css::uno::Reference< css::ucb::XUniversalContentBroker > xUCB(css::ucb::UniversalContentBroker::create(xContext));
648 if (xUCB->queryContentProvider(sURL).is())
649 return E_CAN_BE_LOADED;
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 return E_UNSUPPORTED_CONTENT;
658 namespace {
660 #if ENABLE_ORCUS
662 bool queryOrcusTypeAndFilter(const uno::Sequence<beans::PropertyValue>& rDescriptor, OUString& rType, OUString& rFilter)
664 // depending on the experimental mode
665 uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
666 if (!xContext.is() || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext))
668 return false;
671 OUString aURL;
672 sal_Int32 nSize = rDescriptor.getLength();
673 for (sal_Int32 i = 0; i < nSize; ++i)
675 const beans::PropertyValue& rProp = rDescriptor[i];
676 if (rProp.Name == "URL")
678 rProp.Value >>= aURL;
679 break;
683 if (aURL.isEmpty() || aURL.copy(0,8).equalsIgnoreAsciiCase("private:"))
684 return false;
686 OUString aUseOrcus;
687 rtl::Bootstrap::get("LIBO_USE_ORCUS", aUseOrcus);
688 bool bUseOrcus = (aUseOrcus == "YES");
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.
694 if (aURL.endsWith(".gnumeric"))
696 rType = "generic_Text";
697 rFilter = "gnumeric";
698 return true;
701 if (!bUseOrcus)
702 return false;
704 if (aURL.endsWith(".xlsx"))
706 rType = "generic_Text";
707 rFilter = "xlsx";
708 return true;
710 else if (aURL.endsWith(".ods"))
712 rType = "generic_Text";
713 rFilter = "ods";
714 return true;
716 else if (aURL.endsWith(".csv"))
718 rType = "generic_Text";
719 rFilter = "csv";
720 return true;
723 return false;
726 #else
728 bool queryOrcusTypeAndFilter(const uno::Sequence<beans::PropertyValue>&, OUString&, OUString&)
730 return false;
733 #endif
737 void LoadEnv::impl_detectTypeAndFilter()
738 throw(LoadEnvException, css::uno::RuntimeException, std::exception)
740 static const char TYPEPROP_PREFERREDFILTER[] = "PreferredFilter";
741 static const char FILTERPROP_FLAGS [] = "Flags";
742 static sal_Int32 FILTERFLAG_TEMPLATEPATH = 16;
744 // SAFE ->
745 osl::ClearableMutexGuard aReadLock(m_mutex);
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 css::uno::Sequence< css::beans::PropertyValue > lDescriptor = m_lMediaDescriptor.getAsConstPropertyValueList();
751 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
753 aReadLock.clear();
754 // <- SAFE
756 OUString sType, sFilter;
758 if (queryOrcusTypeAndFilter(lDescriptor, sType, sFilter) && !sType.isEmpty() && !sFilter.isEmpty())
760 // Orcus type detected. Skip the normal type detection process.
761 m_lMediaDescriptor << lDescriptor;
762 m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType;
763 m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
764 m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERPROVIDER()] <<= OUString("orcus");
765 return;
768 css::uno::Reference< css::document::XTypeDetection > xDetect(
769 xContext->getServiceManager()->createInstanceWithContext(
770 "com.sun.star.document.TypeDetection", xContext),
771 css::uno::UNO_QUERY_THROW);
772 sType = xDetect->queryTypeByDescriptor(lDescriptor, sal_True); /*TODO should deep detection be able for enable/disable it from outside? */
774 // no valid content -> loading not possible
775 if (sType.isEmpty())
776 throw LoadEnvException(
777 LoadEnvException::ID_UNSUPPORTED_CONTENT, "type detection failed");
779 // SAFE ->
780 osl::ResettableMutexGuard aWriteLock(m_mutex);
782 // detection was successfully => update the descriptor member of this class
783 m_lMediaDescriptor << lDescriptor;
784 m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType;
785 // Is there an already detected (may be preselected) filter?
786 // see below ...
787 sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
789 aWriteLock.clear();
790 // <- SAFE
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 if (sFilter.isEmpty())
801 // no -> try to find a preferred filter for the detected type.
802 // Don't forget to update the media descriptor.
803 css::uno::Reference< css::container::XNameAccess > xTypeCont(xDetect, css::uno::UNO_QUERY_THROW);
806 ::comphelper::SequenceAsHashMap lTypeProps(xTypeCont->getByName(sType));
807 sFilter = lTypeProps.getUnpackedValueOrDefault(TYPEPROP_PREFERREDFILTER, OUString());
808 if (!sFilter.isEmpty())
810 // SAFE ->
811 aWriteLock.reset();
812 m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
813 aWriteLock.clear();
814 // <- SAFE
817 catch(const css::container::NoSuchElementException&)
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 .-)
829 bool bIsOwnTemplate = false;
830 if (!sFilter.isEmpty())
832 css::uno::Reference< css::container::XNameAccess > xFilterCont(xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext), css::uno::UNO_QUERY_THROW);
835 ::comphelper::SequenceAsHashMap lFilterProps(xFilterCont->getByName(sFilter));
836 sal_Int32 nFlags = lFilterProps.getUnpackedValueOrDefault(FILTERPROP_FLAGS, (sal_Int32)0);
837 bIsOwnTemplate = ((nFlags & FILTERFLAG_TEMPLATEPATH) == FILTERFLAG_TEMPLATEPATH);
839 catch(const css::container::NoSuchElementException&)
842 if (bIsOwnTemplate)
844 // SAFE ->
845 aWriteLock.reset();
846 // Don't overwrite external decisions! See comments before ...
847 utl::MediaDescriptor::const_iterator pAsTemplateItem = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_ASTEMPLATE());
848 if (pAsTemplateItem == m_lMediaDescriptor.end())
849 m_lMediaDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE()] <<= sal_True;
850 aWriteLock.clear();
851 // <- SAFE
855 bool LoadEnv::impl_handleContent()
856 throw(LoadEnvException, css::uno::RuntimeException, std::exception)
858 // SAFE -> -----------------------------------
859 osl::ClearableMutexGuard aReadLock(m_mutex);
861 // the type must exist inside the descriptor ... otherwise this class is implemented wrong :-)
862 OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
863 if (sType.isEmpty())
864 throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
866 // convert media descriptor and URL to right format for later interface call!
867 css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
868 m_lMediaDescriptor >> lDescriptor;
869 css::util::URL aURL = m_aURL;
871 // get necessary container to query for a handler object
872 css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::ContentHandlerFactory::create(m_xContext);
874 aReadLock.clear();
875 // <- SAFE -----------------------------------
877 // query
878 css::uno::Sequence< OUString > lTypeReg(1);
879 lTypeReg[0] = sType;
881 css::uno::Sequence< css::beans::NamedValue > lQuery(1);
882 lQuery[0].Name = PROP_TYPES;
883 lQuery[0].Value <<= lTypeReg;
885 OUString sPROP_NAME(PROP_NAME);
887 css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
888 while(xSet->hasMoreElements())
890 ::comphelper::SequenceAsHashMap lProps (xSet->nextElement());
891 OUString sHandler = lProps.getUnpackedValueOrDefault(sPROP_NAME, OUString());
893 css::uno::Reference< css::frame::XNotifyingDispatch > xHandler;
896 xHandler = css::uno::Reference< css::frame::XNotifyingDispatch >(xLoaderFactory->createInstance(sHandler), css::uno::UNO_QUERY);
897 if (!xHandler.is())
898 continue;
900 catch(const css::uno::RuntimeException&)
901 { throw; }
902 catch(const css::uno::Exception&)
903 { continue; }
905 // SAFE -> -----------------------------------
906 osl::ClearableMutexGuard aWriteLock(m_mutex);
907 m_xAsynchronousJob = xHandler;
908 LoadEnvListener* pListener = new LoadEnvListener(this);
909 aWriteLock.clear();
910 // <- SAFE -----------------------------------
912 css::uno::Reference< css::frame::XDispatchResultListener > xListener(static_cast< css::frame::XDispatchResultListener* >(pListener), css::uno::UNO_QUERY);
913 xHandler->dispatchWithNotification(aURL, lDescriptor, xListener);
915 return true;
918 return false;
921 bool LoadEnv::impl_furtherDocsAllowed()
923 // SAFE ->
924 osl::ResettableMutexGuard aReadLock(m_mutex);
925 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
926 aReadLock.clear();
927 // <- SAFE
929 bool bAllowed = true;
933 css::uno::Any aVal = ::comphelper::ConfigurationHelper::readDirectKey(
934 xContext,
935 OUString("org.openoffice.Office.Common/"),
936 OUString("Misc"),
937 OUString("MaxOpenDocuments"),
938 ::comphelper::ConfigurationHelper::E_READONLY);
940 // NIL means: count of allowed documents = infinite !
941 // => return sal_True
942 if ( ! aVal.hasValue())
943 bAllowed = true;
944 else
946 sal_Int32 nMaxOpenDocuments = 0;
947 aVal >>= nMaxOpenDocuments;
949 css::uno::Reference< css::frame::XFramesSupplier > xDesktop(
950 css::frame::Desktop::create(xContext),
951 css::uno::UNO_QUERY_THROW);
953 FrameListAnalyzer aAnalyzer(xDesktop,
954 css::uno::Reference< css::frame::XFrame >(),
955 FrameListAnalyzer::E_HELP |
956 FrameListAnalyzer::E_BACKINGCOMPONENT |
957 FrameListAnalyzer::E_HIDDEN);
959 sal_Int32 nOpenDocuments = aAnalyzer.m_lOtherVisibleFrames.getLength();
960 bAllowed = (nOpenDocuments < nMaxOpenDocuments);
963 catch(const css::uno::Exception&)
964 { bAllowed = true; } // !! internal errors are no reason to disturb the office from opening documents .-)
966 if ( ! bAllowed )
968 // SAFE ->
969 aReadLock.reset();
970 css::uno::Reference< css::task::XInteractionHandler > xInteraction = m_lMediaDescriptor.getUnpackedValueOrDefault(
971 utl::MediaDescriptor::PROP_INTERACTIONHANDLER(),
972 css::uno::Reference< css::task::XInteractionHandler >());
973 aReadLock.clear();
974 // <- SAFE
976 if (xInteraction.is())
978 css::uno::Any aInteraction;
979 css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations(2);
981 comphelper::OInteractionAbort* pAbort = new comphelper::OInteractionAbort();
982 comphelper::OInteractionApprove* pApprove = new comphelper::OInteractionApprove();
984 lContinuations[0] = css::uno::Reference< css::task::XInteractionContinuation >(
985 static_cast< css::task::XInteractionContinuation* >(pAbort),
986 css::uno::UNO_QUERY_THROW);
987 lContinuations[1] = css::uno::Reference< css::task::XInteractionContinuation >(
988 static_cast< css::task::XInteractionContinuation* >(pApprove),
989 css::uno::UNO_QUERY_THROW);
991 css::task::ErrorCodeRequest aErrorCode;
992 aErrorCode.ErrCode = ERRCODE_SFX_NOMOREDOCUMENTSALLOWED;
993 aInteraction <<= aErrorCode;
994 xInteraction->handle( InteractionRequest::CreateRequest(aInteraction, lContinuations) );
998 return bAllowed;
1001 bool LoadEnv::impl_loadContent()
1002 throw(LoadEnvException, css::uno::RuntimeException, std::exception)
1004 // SAFE -> -----------------------------------
1005 osl::ClearableMutexGuard aWriteLock(m_mutex);
1007 // search or create right target frame
1008 OUString sTarget = m_sTarget;
1009 if (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::E_DEFAULT))
1011 m_xTargetFrame = impl_searchAlreadyLoaded();
1012 if (m_xTargetFrame.is())
1014 impl_setResult(true);
1015 return true;
1017 m_xTargetFrame = impl_searchRecycleTarget();
1020 if (! m_xTargetFrame.is())
1022 if (
1023 (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::E_BLANK )) ||
1024 (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::E_DEFAULT))
1027 if (! impl_furtherDocsAllowed())
1028 return false;
1029 m_xTargetFrame = m_xBaseFrame->findFrame(SPECIALTARGET_BLANK, 0);
1030 m_bCloseFrameOnError = m_xTargetFrame.is();
1032 else
1034 sal_Int32 nFlags = m_nSearchFlags & ~css::frame::FrameSearchFlag::CREATE;
1035 m_xTargetFrame = m_xBaseFrame->findFrame(sTarget, nFlags);
1036 if (! m_xTargetFrame.is())
1038 if (! impl_furtherDocsAllowed())
1039 return false;
1040 m_xTargetFrame = m_xBaseFrame->findFrame(SPECIALTARGET_BLANK, 0);
1041 m_bCloseFrameOnError = m_xTargetFrame.is();
1046 // If we couldn't find a valid frame or the frame has no container window
1047 // we have to throw an exception.
1048 if (
1049 ( ! m_xTargetFrame.is() ) ||
1050 ( ! m_xTargetFrame->getContainerWindow().is() )
1052 throw LoadEnvException(LoadEnvException::ID_NO_TARGET_FOUND);
1054 css::uno::Reference< css::frame::XFrame > xTargetFrame = m_xTargetFrame;
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 impl_applyPersistentWindowState(xTargetFrame->getContainerWindow());
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.
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 css::uno::Reference< css::document::XActionLockable > xTargetLock(xTargetFrame, css::uno::UNO_QUERY);
1074 m_aTargetLock.setResource(xTargetLock);
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 bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN() , false );
1082 bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED() , false );
1083 bool bPreview = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW() , false );
1084 css::uno::Reference< css::task::XStatusIndicator > xProgress = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR(), css::uno::Reference< css::task::XStatusIndicator >());
1086 if (!bHidden && !bMinimized && !bPreview && !xProgress.is())
1088 // Note: its an optional interface!
1089 css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xTargetFrame, css::uno::UNO_QUERY);
1090 if (xProgressFactory.is())
1092 xProgress = xProgressFactory->createStatusIndicator();
1093 if (xProgress.is())
1094 m_lMediaDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xProgress;
1098 // convert media descriptor and URL to right format for later interface call!
1099 css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
1100 m_lMediaDescriptor >> lDescriptor;
1101 OUString sURL = m_aURL.Complete;
1103 // try to locate any interested frame loader
1104 css::uno::Reference< css::uno::XInterface > xLoader = impl_searchLoader();
1105 css::uno::Reference< css::frame::XFrameLoader > xAsyncLoader(xLoader, css::uno::UNO_QUERY);
1106 css::uno::Reference< css::frame::XSynchronousFrameLoader > xSyncLoader (xLoader, css::uno::UNO_QUERY);
1108 if (xAsyncLoader.is())
1110 m_xAsynchronousJob = xAsyncLoader;
1111 LoadEnvListener* pListener = new LoadEnvListener(this);
1112 aWriteLock.clear();
1113 // <- SAFE -----------------------------------
1115 css::uno::Reference< css::frame::XLoadEventListener > xListener(static_cast< css::frame::XLoadEventListener* >(pListener), css::uno::UNO_QUERY);
1116 xAsyncLoader->load(xTargetFrame, sURL, lDescriptor, xListener);
1118 return true;
1120 else if (xSyncLoader.is())
1122 bool bResult = xSyncLoader->load(lDescriptor, xTargetFrame);
1123 // react for the result here, so the outside waiting
1124 // code can ask for it later.
1125 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 return true;
1131 aWriteLock.clear();
1132 // <- SAFE
1134 return false;
1137 css::uno::Reference< css::uno::XInterface > LoadEnv::impl_searchLoader()
1139 // SAFE -> -----------------------------------
1140 osl::ClearableMutexGuard aReadLock(m_mutex);
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 if (m_eContentType == E_CAN_BE_SET)
1149 return css::frame::OfficeFrameLoader::create(m_xContext);
1151 catch(const css::uno::RuntimeException&)
1152 { throw; }
1153 catch(const css::uno::Exception&)
1155 throw LoadEnvException(LoadEnvException::ID_INVALID_ENVIRONMENT);
1158 // Otherwise ...
1159 // We need this type information to locate an registered frame loader
1160 // Without such information we can't work!
1161 OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
1162 if (sType.isEmpty())
1163 throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
1165 // try to locate any interested frame loader
1166 css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::FrameLoaderFactory::create(m_xContext);
1168 aReadLock.clear();
1169 // <- SAFE -----------------------------------
1171 css::uno::Sequence< OUString > lTypesReg(1);
1172 lTypesReg[0] = sType;
1174 css::uno::Sequence< css::beans::NamedValue > lQuery(1);
1175 lQuery[0].Name = PROP_TYPES;
1176 lQuery[0].Value <<= lTypesReg;
1178 OUString sPROP_NAME(PROP_NAME);
1180 css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
1181 while(xSet->hasMoreElements())
1185 // try everyone ...
1186 // Ignore any loader, which makes trouble :-)
1187 ::comphelper::SequenceAsHashMap lLoaderProps(xSet->nextElement());
1188 OUString sLoader = lLoaderProps.getUnpackedValueOrDefault(sPROP_NAME, OUString());
1189 css::uno::Reference< css::uno::XInterface > xLoader;
1191 xLoader = xLoaderFactory->createInstance(sLoader);
1192 if (xLoader.is())
1193 return xLoader;
1195 catch(const css::uno::RuntimeException&)
1196 { throw; }
1197 catch(const css::uno::Exception&)
1198 { continue; }
1201 return css::uno::Reference< css::uno::XInterface >();
1204 void LoadEnv::impl_jumpToMark(const css::uno::Reference< css::frame::XFrame >& xFrame,
1205 const css::util::URL& aURL )
1207 if (aURL.Mark.isEmpty())
1208 return;
1210 css::uno::Reference< css::frame::XDispatchProvider > xProvider(xFrame, css::uno::UNO_QUERY);
1211 if (! xProvider.is())
1212 return;
1214 // SAFE ->
1215 osl::ClearableMutexGuard aReadLock(m_mutex);
1216 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1217 aReadLock.clear();
1218 // <- SAFE
1220 css::util::URL aCmd;
1221 aCmd.Complete = ".uno:JumpToMark";
1223 css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(xContext));
1224 xParser->parseStrict(aCmd);
1226 css::uno::Reference< css::frame::XDispatch > xDispatcher = xProvider->queryDispatch(aCmd, SPECIALTARGET_SELF, 0);
1227 if (! xDispatcher.is())
1228 return;
1230 ::comphelper::SequenceAsHashMap lArgs;
1231 lArgs[OUString("Bookmark")] <<= aURL.Mark;
1232 xDispatcher->dispatch(aCmd, lArgs.getAsConstPropertyValueList());
1235 css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchAlreadyLoaded()
1236 throw(LoadEnvException, css::uno::RuntimeException)
1238 osl::MutexGuard g(m_mutex);
1240 // such search is allowed for special requests only ...
1241 // or better its not allowed for some requests in general :-)
1242 if (
1243 ( ! TargetHelper::matchSpecialTarget(m_sTarget, TargetHelper::E_DEFAULT) ) ||
1244 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false) ||
1245 // (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN() , false) == sal_True) ||
1246 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW(), false)
1249 return css::uno::Reference< css::frame::XFrame >();
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 if (
1256 (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_STREAM )) ||
1257 (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_OBJECT ))
1258 /*TODO should be private:factory here tested too? */
1261 return css::uno::Reference< css::frame::XFrame >();
1264 // otherwise - iterate through the tasks of the desktop container
1265 // to find out, which of them might contains the requested document
1266 css::uno::Reference< css::frame::XDesktop2 > xSupplier = css::frame::Desktop::create( m_xContext );
1267 css::uno::Reference< css::container::XIndexAccess > xTaskList(xSupplier->getFrames() , css::uno::UNO_QUERY);
1269 if (!xTaskList.is())
1270 return css::uno::Reference< css::frame::XFrame >(); // task list can be empty!
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 sal_Int16 nNewVersion = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION(), (sal_Int16)(-1));
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 css::uno::Reference< css::frame::XFrame > xHiddenTask;
1281 css::uno::Reference< css::frame::XFrame > xTask;
1283 sal_Int32 count = xTaskList->getCount();
1284 for (sal_Int32 i=0; i<count; ++i)
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 xTaskList->getByIndex(i) >>= xTask;
1292 if (!xTask.is())
1293 continue;
1295 css::uno::Reference< css::frame::XController > xController = xTask->getController();
1296 if (!xController.is())
1298 xTask.clear ();
1299 continue;
1302 css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1303 if (!xModel.is())
1305 xTask.clear ();
1306 continue;
1309 // don't check the complete URL here.
1310 // use its main part - ignore optional jumpmarks!
1311 const OUString sURL = xModel->getURL();
1312 if (!::utl::UCBContentHelper::EqualURLs( m_aURL.Main, sURL ))
1314 xTask.clear ();
1315 continue;
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 utl::MediaDescriptor lOldDocDescriptor(xModel->getArgs());
1324 if (lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION(), (sal_Int32)(-1)) != nNewVersion)
1326 xTask.clear ();
1327 continue;
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 bool bIsHidden = lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1334 if (
1335 ( bIsHidden ) &&
1336 ( ! xHiddenTask.is())
1339 xHiddenTask = xTask;
1340 xTask.clear ();
1341 continue;
1344 // We found a visible task pointing to the right model ...
1345 // Break search.
1346 break;
1348 catch(const css::uno::RuntimeException&)
1349 { throw; }
1350 catch(const css::uno::Exception&)
1351 { continue; }
1354 css::uno::Reference< css::frame::XFrame > xResult;
1355 if (xTask.is())
1356 xResult = xTask;
1357 else if (xHiddenTask.is())
1358 xResult = xHiddenTask;
1360 if (xResult.is())
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 if (!m_aURL.Mark.isEmpty())
1366 impl_jumpToMark(xResult, m_aURL);
1368 // bring it to front and make sure it's visible...
1369 impl_makeFrameWindowVisible(xResult->getContainerWindow(), true);
1372 return xResult;
1375 bool LoadEnv::impl_isFrameAlreadyUsedForLoading(const css::uno::Reference< css::frame::XFrame >& xFrame) const
1377 css::uno::Reference< css::document::XActionLockable > xLock(xFrame, css::uno::UNO_QUERY);
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 if (!xLock.is())
1383 return false;
1385 // Otherwise we have to look for any other existing lock.
1386 return xLock->isActionLocked();
1389 css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchRecycleTarget()
1390 throw(LoadEnvException, css::uno::RuntimeException, std::exception)
1392 // SAFE -> ..................................
1393 osl::ClearableMutexGuard aReadLock(m_mutex);
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 if (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false))
1400 return css::uno::Reference< css::frame::XFrame >();
1402 css::uno::Reference< css::frame::XFramesSupplier > xSupplier( css::frame::Desktop::create( m_xContext ), css::uno::UNO_QUERY);
1403 FrameListAnalyzer aTasksAnalyzer(xSupplier, css::uno::Reference< css::frame::XFrame >(), FrameListAnalyzer::E_BACKINGCOMPONENT);
1404 if (aTasksAnalyzer.m_xBackingComponent.is())
1406 if (!impl_isFrameAlreadyUsedForLoading(aTasksAnalyzer.m_xBackingComponent))
1408 // bring it to front ...
1409 impl_makeFrameWindowVisible(aTasksAnalyzer.m_xBackingComponent->getContainerWindow(), true);
1410 return aTasksAnalyzer.m_xBackingComponent;
1414 // These states indicates a wish for creation of a new view in general.
1415 if (
1416 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false) ||
1417 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW(), false)
1420 return css::uno::Reference< css::frame::XFrame >();
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 if (
1426 (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_FACTORY )) ||
1427 (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_STREAM )) ||
1428 (ProtocolCheck::isProtocol(m_aURL.Complete, ProtocolCheck::E_PRIVATE_OBJECT ))
1431 return css::uno::Reference< css::frame::XFrame >();
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 css::uno::Reference< css::frame::XFrame > xTask = xSupplier->getActiveFrame();
1439 // not a real error - but might a focus problem!
1440 if (!xTask.is())
1441 return css::uno::Reference< css::frame::XFrame >();
1443 // not a real error - may it's a view only
1444 css::uno::Reference< css::frame::XController > xController = xTask->getController();
1445 if (!xController.is())
1446 return css::uno::Reference< css::frame::XFrame >();
1448 // not a real error - may it's a db component instead of a full featured office document
1449 css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1450 if (!xModel.is())
1451 return css::uno::Reference< css::frame::XFrame >();
1453 // get some more information ...
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 if (xModel->getURL().getLength()>0)
1459 return css::uno::Reference< css::frame::XFrame >();
1461 // The old document must be unmodified ...
1462 css::uno::Reference< css::util::XModifiable > xModified(xModel, css::uno::UNO_QUERY);
1463 if (xModified->isModified())
1464 return css::uno::Reference< css::frame::XFrame >();
1466 vcl::Window* pWindow = VCLUnoHelper::GetWindow(xTask->getContainerWindow());
1467 if (pWindow && pWindow->IsInModalMode())
1468 return css::uno::Reference< css::frame::XFrame >();
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 SvtModuleOptions::EFactory eOldApp = SvtModuleOptions::ClassifyFactoryByModel(xModel);
1474 SvtModuleOptions::EFactory eNewApp = SvtModuleOptions::ClassifyFactoryByURL (m_aURL.Complete, m_lMediaDescriptor.getAsConstPropertyValueList());
1476 aReadLock.clear();
1477 // <- SAFE ..................................
1479 if (eOldApp != eNewApp)
1480 return css::uno::Reference< css::frame::XFrame >();
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 if (impl_isFrameAlreadyUsedForLoading(xTask))
1489 return css::uno::Reference< css::frame::XFrame >();
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 bool bReactivateOldControllerOnError = false;
1495 css::uno::Reference< css::frame::XController > xOldDoc = xTask->getController();
1496 if (xOldDoc.is())
1498 bReactivateOldControllerOnError = xOldDoc->suspend(sal_True);
1499 if (! bReactivateOldControllerOnError)
1500 return css::uno::Reference< css::frame::XFrame >();
1503 // SAFE -> ..................................
1504 osl::ClearableMutexGuard aWriteLock(m_mutex);
1506 css::uno::Reference< css::document::XActionLockable > xLock(xTask, css::uno::UNO_QUERY);
1507 if (!m_aTargetLock.setResource(xLock))
1508 return css::uno::Reference< css::frame::XFrame >();
1510 m_bReactivateControllerOnError = bReactivateOldControllerOnError;
1511 aWriteLock.clear();
1512 // <- SAFE ..................................
1514 // bring it to front ...
1515 impl_makeFrameWindowVisible(xTask->getContainerWindow(), true);
1517 return xTask;
1520 void LoadEnv::impl_reactForLoadingState()
1521 throw(LoadEnvException, css::uno::RuntimeException)
1523 /*TODO reset action locks */
1525 // SAFE -> ----------------------------------
1526 osl::ClearableMutexGuard aReadLock(m_mutex);
1528 if (m_bLoaded)
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 css::uno::Reference< css::awt::XWindow > xWindow = m_xTargetFrame->getContainerWindow();
1534 bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1535 bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED(), false);
1537 if (bMinimized)
1539 SolarMutexGuard aSolarGuard;
1540 vcl::Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
1541 // check for system window is necessary to guarantee correct pointer cast!
1542 if (pWindow && pWindow->IsSystemWindow())
1543 static_cast<WorkWindow*>(pWindow)->Minimize();
1545 else if (!bHidden)
1547 // show frame ... if it's not still visible ...
1548 // But do nothing if it's already visible!
1549 impl_makeFrameWindowVisible(xWindow, false);
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 utl::MediaDescriptor::const_iterator pFrameName = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FRAMENAME());
1556 if (pFrameName != m_lMediaDescriptor.end())
1558 OUString sFrameName;
1559 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 if (TargetHelper::isValidNameForFrame(sFrameName))
1563 m_xTargetFrame->setName(sFrameName);
1566 else if (m_bReactivateControllerOnError)
1568 // Try to reactivate the old document (if any exists!)
1569 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 m_xTargetFrame.clear();
1574 if (xOldDoc.is())
1576 bool bReactivated = xOldDoc->suspend(sal_False);
1577 if (!bReactivated)
1578 throw LoadEnvException(LoadEnvException::ID_COULD_NOT_REACTIVATE_CONTROLLER);
1579 m_bReactivateControllerOnError = false;
1582 else if (m_bCloseFrameOnError)
1584 // close empty frames
1585 css::uno::Reference< css::util::XCloseable > xCloseable (m_xTargetFrame, css::uno::UNO_QUERY);
1586 css::uno::Reference< css::lang::XComponent > xDisposable(m_xTargetFrame, css::uno::UNO_QUERY);
1590 if (xCloseable.is())
1591 xCloseable->close(sal_True);
1592 else
1593 if (xDisposable.is())
1594 xDisposable->dispose();
1596 catch(const css::util::CloseVetoException&)
1598 catch(const css::lang::DisposedException&)
1600 m_xTargetFrame.clear();
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 m_aTargetLock.freeResource();
1611 // Last but not least :-)
1612 // We have to clear the current media descriptor.
1613 // Otherwise it hold a might existing stream open!
1614 m_lMediaDescriptor.clear();
1616 css::uno::Any aRequest;
1617 bool bThrow = false;
1618 if ( !m_bLoaded && m_pQuietInteraction.is() && m_pQuietInteraction->wasUsed() )
1620 aRequest = m_pQuietInteraction->getRequest();
1621 m_pQuietInteraction.clear();
1622 bThrow = true;
1625 aReadLock.clear();
1627 if (bThrow)
1629 if ( aRequest.isExtractableTo( ::cppu::UnoType< css::uno::Exception >::get() ) )
1630 throw LoadEnvException(
1631 LoadEnvException::ID_GENERAL_ERROR, "interaction request",
1632 aRequest);
1635 // <- SAFE ----------------------------------
1638 void LoadEnv::impl_makeFrameWindowVisible(const css::uno::Reference< css::awt::XWindow >& xWindow ,
1639 bool bForceToFront)
1641 // SAFE -> ----------------------------------
1642 osl::ClearableMutexGuard aReadLock(m_mutex);
1643 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1644 aReadLock.clear();
1645 // <- SAFE ----------------------------------
1647 SolarMutexGuard aSolarGuard;
1648 vcl::Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
1649 if ( pWindow )
1651 bool const preview( m_lMediaDescriptor.getUnpackedValueOrDefault(
1652 utl::MediaDescriptor::PROP_PREVIEW(), false) );
1654 bool bForceFrontAndFocus(false);
1655 if ( !preview )
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 ::comphelper::ConfigurationHelper::E_READONLY);
1664 a >>= bForceFrontAndFocus;
1667 if( pWindow->IsVisible() && (bForceFrontAndFocus || bForceToFront) )
1668 pWindow->ToTop();
1669 else
1670 pWindow->Show(true, (bForceFrontAndFocus || bForceToFront) ? SHOW_FOREGROUNDTASK : 0 );
1674 void LoadEnv::impl_applyPersistentWindowState(const css::uno::Reference< css::awt::XWindow >& xWindow)
1676 static const char PACKAGE_SETUP_MODULES[] = "/org.openoffice.Setup/Office/Factories";
1678 // no window -> action not possible
1679 if (!xWindow.is())
1680 return;
1682 // window already visible -> do nothing! If we use a "recycle frame" for loading ...
1683 // the current position and size must be used.
1684 css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(xWindow, css::uno::UNO_QUERY);
1685 if (
1686 (xVisibleCheck.is() ) &&
1687 (xVisibleCheck->isVisible())
1689 return;
1691 // SOLAR SAFE ->
1692 SolarMutexClearableGuard aSolarGuard1;
1694 vcl::Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
1695 if (!pWindow)
1696 return;
1698 bool bSystemWindow = pWindow->IsSystemWindow();
1699 bool bWorkWindow = (pWindow->GetType() == WINDOW_WORKWINDOW);
1701 if (!bSystemWindow && !bWorkWindow)
1702 return;
1704 // dont overwrite this special state!
1705 WorkWindow* pWorkWindow = static_cast<WorkWindow*>(pWindow);
1706 if (pWorkWindow->IsMinimized())
1707 return;
1709 aSolarGuard1.clear();
1710 // <- SOLAR SAFE
1712 // SAFE ->
1713 osl::ClearableMutexGuard aReadLock(m_mutex);
1715 // no filter -> no module -> no persistent window state
1716 OUString sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(
1717 utl::MediaDescriptor::PROP_FILTERNAME(),
1718 OUString());
1719 if (sFilter.isEmpty())
1720 return;
1722 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1724 aReadLock.clear();
1725 // <- SAFE
1729 // retrieve the module name from the filter configuration
1730 css::uno::Reference< css::container::XNameAccess > xFilterCfg(
1731 xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext),
1732 css::uno::UNO_QUERY_THROW);
1733 ::comphelper::SequenceAsHashMap lProps (xFilterCfg->getByName(sFilter));
1734 OUString sModule = lProps.getUnpackedValueOrDefault(FILTER_PROPNAME_DOCUMENTSERVICE, OUString());
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 css::uno::UNO_QUERY_THROW);
1743 // read window state from the configuration
1744 // and apply it on the window.
1745 // Do nothing, if no configuration entry exists!
1746 OUString sWindowState;
1747 ::comphelper::ConfigurationHelper::readRelativeKey(xModuleCfg, sModule, OFFICEFACTORY_PROPNAME_WINDOWATTRIBUTES) >>= sWindowState;
1748 if (!sWindowState.isEmpty())
1750 // SOLAR SAFE ->
1751 SolarMutexGuard aSolarGuard;
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 vcl::Window* pWindowCheck = VCLUnoHelper::GetWindow(xWindow);
1759 if (! pWindowCheck)
1760 return;
1762 SystemWindow* pSystemWindow = static_cast<SystemWindow*>(pWindowCheck);
1763 pSystemWindow->SetWindowState(OUStringToOString(sWindowState,RTL_TEXTENCODING_UTF8));
1764 // <- SOLAR SAFE
1767 catch(const css::uno::RuntimeException&)
1768 { throw; }
1769 catch(const css::uno::Exception&)
1773 } // namespace framework
1775 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */