1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/loadenvexception.hxx>
23 #include <loadenv/targethelper.hxx>
24 #include <framework/framelistanalyzer.hxx>
26 #include <interaction/quietinteraction.hxx>
27 #include <properties.h>
28 #include <protocols.h>
31 #include <comphelper/interaction.hxx>
32 #include <comphelper/lok.hxx>
33 #include <comphelper/namedvaluecollection.hxx>
34 #include <comphelper/propertysequence.hxx>
35 #include <framework/interaction.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <officecfg/Office/Common.hxx>
39 #include <com/sun/star/awt/XWindow.hpp>
40 #include <com/sun/star/awt/XWindow2.hpp>
41 #include <com/sun/star/awt/XTopWindow.hpp>
42 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <com/sun/star/container/XContainerQuery.hpp>
44 #include <com/sun/star/container/XEnumeration.hpp>
45 #include <com/sun/star/document/MacroExecMode.hpp>
46 #include <com/sun/star/document/XTypeDetection.hpp>
47 #include <com/sun/star/document/XActionLockable.hpp>
48 #include <com/sun/star/document/UpdateDocMode.hpp>
49 #include <com/sun/star/frame/Desktop.hpp>
50 #include <com/sun/star/frame/OfficeFrameLoader.hpp>
51 #include <com/sun/star/frame/XModel.hpp>
52 #include <com/sun/star/frame/XFrameLoader.hpp>
53 #include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
54 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
55 #include <com/sun/star/frame/FrameLoaderFactory.hpp>
56 #include <com/sun/star/frame/ContentHandlerFactory.hpp>
57 #include <com/sun/star/frame/DispatchResultState.hpp>
58 #include <com/sun/star/frame/FrameSearchFlag.hpp>
59 #include <com/sun/star/frame/XDispatchProvider.hpp>
60 #include <com/sun/star/lang/IllegalArgumentException.hpp>
61 #include <com/sun/star/lang/XComponent.hpp>
62 #include <com/sun/star/lang/XInitialization.hpp>
63 #include <com/sun/star/lang/XServiceInfo.hpp>
64 #include <com/sun/star/lang/DisposedException.hpp>
65 #include <com/sun/star/io/XInputStream.hpp>
66 #include <com/sun/star/task/XInteractionHandler.hpp>
67 #include <com/sun/star/task/ErrorCodeRequest.hpp>
68 #include <com/sun/star/task/InteractionHandler.hpp>
69 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
70 #include <com/sun/star/task/XStatusIndicator.hpp>
71 #include <com/sun/star/uno/RuntimeException.hpp>
72 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
73 #include <com/sun/star/util/CloseVetoException.hpp>
74 #include <com/sun/star/util/URLTransformer.hpp>
75 #include <com/sun/star/util/XURLTransformer.hpp>
76 #include <com/sun/star/util/XCloseable.hpp>
77 #include <com/sun/star/util/XModifiable.hpp>
79 #include <vcl/window.hxx>
80 #include <vcl/wrkwin.hxx>
81 #include <vcl/syswin.hxx>
83 #include <toolkit/helper/vclunohelper.hxx>
84 #include <unotools/moduleoptions.hxx>
85 #include <svtools/sfxecode.hxx>
86 #include <unotools/ucbhelper.hxx>
87 #include <comphelper/configurationhelper.hxx>
88 #include <rtl/ustrbuf.hxx>
89 #include <rtl/bootstrap.hxx>
90 #include <sal/log.hxx>
91 #include <vcl/errcode.hxx>
92 #include <vcl/svapp.hxx>
93 #include <cppuhelper/implbase.hxx>
94 #include <comphelper/profilezone.hxx>
95 #include <classes/taskcreator.hxx>
96 #include <tools/fileutil.hxx>
98 const char PROP_TYPES
[] = "Types";
99 const char PROP_NAME
[] = "Name";
101 namespace framework
{
103 using namespace com::sun::star
;
105 class LoadEnvListener
: public ::cppu::WeakImplHelper
< css::frame::XLoadEventListener
,
106 css::frame::XDispatchResultListener
>
110 bool m_bWaitingResult
;
115 explicit LoadEnvListener(LoadEnv
* pLoadEnv
)
116 : m_bWaitingResult(true)
117 , m_pLoadEnv(pLoadEnv
)
121 // frame.XLoadEventListener
122 virtual void SAL_CALL
loadFinished(const css::uno::Reference
< css::frame::XFrameLoader
>& xLoader
) override
;
124 virtual void SAL_CALL
loadCancelled(const css::uno::Reference
< css::frame::XFrameLoader
>& xLoader
) override
;
126 // frame.XDispatchResultListener
127 virtual void SAL_CALL
dispatchFinished(const css::frame::DispatchResultEvent
& aEvent
) override
;
129 // lang.XEventListener
130 virtual void SAL_CALL
disposing(const css::lang::EventObject
& aEvent
) override
;
133 LoadEnv::LoadEnv(const css::uno::Reference
< css::uno::XComponentContext
>& xContext
)
134 : m_xContext(xContext
)
136 , m_eFeature(LoadEnvFeatures::NONE
)
137 , m_eContentType(E_UNSUPPORTED_CONTENT
)
138 , m_bCloseFrameOnError(false)
139 , m_bReactivateControllerOnError(false)
148 css::uno::Reference
< css::lang::XComponent
> LoadEnv::loadComponentFromURL(const css::uno::Reference
< css::frame::XComponentLoader
>& xLoader
,
149 const css::uno::Reference
< css::uno::XComponentContext
>& xContext
,
150 const OUString
& sURL
,
151 const OUString
& sTarget
,
152 sal_Int32 nSearchFlags
,
153 const css::uno::Sequence
< css::beans::PropertyValue
>& lArgs
)
155 css::uno::Reference
< css::lang::XComponent
> xComponent
;
156 comphelper::ProfileZone
aZone("loadComponentFromURL");
160 LoadEnv
aEnv(xContext
);
162 LoadEnvFeatures loadEnvFeatures
= LoadEnvFeatures::WorkWithUI
;
163 comphelper::NamedValueCollection
aDescriptor( lArgs
);
164 // tdf#118238 Only disable UI interaction when loading as hidden
165 if (aDescriptor
.get("Hidden") == uno::Any(true) || Application::IsHeadlessModeEnabled())
166 loadEnvFeatures
= LoadEnvFeatures::NONE
;
168 aEnv
.startLoading(sURL
,
170 css::uno::Reference
< css::frame::XFrame
>(xLoader
, css::uno::UNO_QUERY
),
174 aEnv
.waitWhileLoading(); // wait for ever!
176 xComponent
= aEnv
.getTargetComponent();
178 catch(const LoadEnvException
& ex
)
182 case LoadEnvException::ID_INVALID_MEDIADESCRIPTOR
:
183 throw css::lang::IllegalArgumentException(
184 "Optional list of arguments seem to be corrupted.", xLoader
, 4);
186 case LoadEnvException::ID_UNSUPPORTED_CONTENT
:
187 throw css::lang::IllegalArgumentException(
188 "Unsupported URL <" + sURL
+ ">: \"" + ex
.m_sMessage
+ "\"",
194 "caught LoadEnvException " << +ex
.m_nID
<< " \""
195 << ex
.m_sMessage
<< "\""
196 << (ex
.m_exOriginal
.has
<css::uno::Exception
>()
197 ? (", " + ex
.m_exOriginal
.getValueTypeName() + " \""
198 + (ex
.m_exOriginal
.get
<css::uno::Exception
>().
202 << " while loading <" << sURL
<< ">");
213 utl::MediaDescriptor
addModelArgs(const uno::Sequence
<beans::PropertyValue
>& rDescriptor
)
215 utl::MediaDescriptor
rResult(rDescriptor
);
216 uno::Reference
<frame::XModel
> xModel(rResult
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MODEL(), uno::Reference
<frame::XModel
>()));
220 utl::MediaDescriptor
aModelArgs(xModel
->getArgs());
221 utl::MediaDescriptor::iterator pIt
= aModelArgs
.find( utl::MediaDescriptor::PROP_MACROEXECUTIONMODE());
222 if (pIt
!= aModelArgs
.end())
223 rResult
[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()] = pIt
->second
;
231 void LoadEnv::startLoading(const OUString
& sURL
, const uno::Sequence
<beans::PropertyValue
>& lMediaDescriptor
,
232 const uno::Reference
<frame::XFrame
>& xBaseFrame
, const OUString
& sTarget
,
233 sal_Int32 nSearchFlags
, LoadEnvFeatures eFeature
)
235 osl::MutexGuard
g(m_mutex
);
237 // Handle still running processes!
238 if (m_xAsynchronousJob
.is())
239 throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING
);
241 // take over all new parameters.
242 m_xTargetFrame
.clear();
243 m_xBaseFrame
= xBaseFrame
;
244 m_lMediaDescriptor
= addModelArgs(lMediaDescriptor
);
246 m_nSearchFlags
= nSearchFlags
;
247 m_eFeature
= eFeature
;
248 m_eContentType
= E_UNSUPPORTED_CONTENT
;
249 m_bCloseFrameOnError
= false;
250 m_bReactivateControllerOnError
= false;
254 if (!tools::IsMappedWebDAVPath(sURL
, &aRealURL
))
257 // try to find out, if it's really a content, which can be loaded or must be "handled"
258 // We use a default value for this in-parameter. Then we have to start a complex check method
259 // internally. But if this check was already done outside it can be suppressed to perform
260 // the load request. We take over the result then!
261 m_eContentType
= LoadEnv::classifyContent(aRealURL
, lMediaDescriptor
);
262 if (m_eContentType
== E_UNSUPPORTED_CONTENT
)
263 throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT
, "from LoadEnv::startLoading");
265 // make URL part of the MediaDescriptor
266 // It doesn't matter if it is already an item of it.
267 // It must be the same value... so we can overwrite it :-)
268 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_URL()] <<= aRealURL
;
270 // parse it - because some following code require that
271 m_aURL
.Complete
= aRealURL
;
272 uno::Reference
<util::XURLTransformer
> xParser(util::URLTransformer::create(m_xContext
));
273 xParser
->parseStrict(m_aURL
);
275 // BTW: Split URL and JumpMark ...
276 // Because such mark is an explicit value of the media descriptor!
277 if (!m_aURL
.Mark
.isEmpty())
278 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_JUMPMARK()] <<= m_aURL
.Mark
;
280 // By the way: remove the old and deprecated value "FileName" from the descriptor!
281 utl::MediaDescriptor::iterator pIt
= m_lMediaDescriptor
.find(utl::MediaDescriptor::PROP_FILENAME());
282 if (pIt
!= m_lMediaDescriptor
.end())
283 m_lMediaDescriptor
.erase(pIt
);
285 // patch the MediaDescriptor, so it fulfil the outside requirements
286 // Means especially items like e.g. UI InteractionHandler, Status Indicator,
287 // MacroExecutionMode, etc.
289 /*TODO progress is bound to a frame ... How can we set it here? */
293 (m_eFeature
& LoadEnvFeatures::WorkWithUI
) &&
294 !m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false) &&
295 !m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW(), false);
297 initializeUIDefaults(m_xContext
, m_lMediaDescriptor
, bUIMode
, &m_pQuietInteraction
);
302 void LoadEnv::initializeUIDefaults( const css::uno::Reference
< css::uno::XComponentContext
>& i_rxContext
,
303 utl::MediaDescriptor
& io_lMediaDescriptor
, const bool i_bUIMode
,
304 rtl::Reference
<QuietInteraction
>* o_ppQuietInteraction
)
306 css::uno::Reference
< css::task::XInteractionHandler
> xInteractionHandler
;
307 sal_Int16 nMacroMode
;
308 sal_Int16 nUpdateMode
;
312 nMacroMode
= css::document::MacroExecMode::USE_CONFIG
;
313 nUpdateMode
= css::document::UpdateDocMode::ACCORDING_TO_CONFIG
;
316 xInteractionHandler
.set( css::task::InteractionHandler::createWithParent( i_rxContext
, nullptr ), css::uno::UNO_QUERY_THROW
);
318 catch(const css::uno::RuntimeException
&) {throw;}
319 catch(const css::uno::Exception
& ) { }
324 nMacroMode
= css::document::MacroExecMode::NEVER_EXECUTE
;
325 nUpdateMode
= css::document::UpdateDocMode::NO_UPDATE
;
326 rtl::Reference
<QuietInteraction
> pQuietInteraction
= new QuietInteraction();
327 xInteractionHandler
= pQuietInteraction
.get();
328 if ( o_ppQuietInteraction
!= nullptr )
330 *o_ppQuietInteraction
= pQuietInteraction
;
334 if ( xInteractionHandler
.is() )
336 if( io_lMediaDescriptor
.find(utl::MediaDescriptor::PROP_INTERACTIONHANDLER()) == io_lMediaDescriptor
.end() )
338 io_lMediaDescriptor
[utl::MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteractionHandler
;
340 if( io_lMediaDescriptor
.find(utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER()) == io_lMediaDescriptor
.end() )
342 io_lMediaDescriptor
[utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER()] <<= xInteractionHandler
;
346 if (io_lMediaDescriptor
.find(utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()) == io_lMediaDescriptor
.end())
347 io_lMediaDescriptor
[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()] <<= nMacroMode
;
349 if (io_lMediaDescriptor
.find(utl::MediaDescriptor::PROP_UPDATEDOCMODE()) == io_lMediaDescriptor
.end())
350 io_lMediaDescriptor
[utl::MediaDescriptor::PROP_UPDATEDOCMODE()] <<= nUpdateMode
;
353 void LoadEnv::start()
357 osl::MutexGuard
aReadLock(m_mutex
);
359 // Handle still running processes!
360 if (m_xAsynchronousJob
.is())
361 throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING
);
363 // content can not be loaded or handled
364 // check "classifyContent()" failed before ...
365 if (m_eContentType
== E_UNSUPPORTED_CONTENT
)
366 throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT
,
367 "from LoadEnv::start");
371 // detect its type/filter etc.
372 // This information will be available by the
373 // used descriptor member afterwards and is needed
374 // for all following operations!
375 // Note: An exception will be thrown, in case operation was not successfully ...
376 if (m_eContentType
!= E_CAN_BE_SET
)/* Attention: special feature to set existing component on a frame must ignore type detection! */
377 impl_detectTypeAndFilter();
379 // start loading the content...
380 // Attention: Don't check m_eContentType deeper then UNSUPPORTED/SUPPORTED!
381 // Because it was made in the easiest way... may a flat detection was made only.
382 // And such simple detection can fail sometimes .-)
383 // Use another strategy here. Try it and let it run into the case "loading not possible".
384 bool bStarted
= false;
386 (m_eFeature
& LoadEnvFeatures::AllowContentHandler
) &&
387 (m_eContentType
!= E_CAN_BE_SET
) /* Attention: special feature to set existing component on a frame must ignore type detection! */
390 bStarted
= impl_handleContent();
394 bStarted
= impl_loadContent();
396 // not started => general error
397 // We can't say - what was the reason for.
399 throw LoadEnvException(
400 LoadEnvException::ID_GENERAL_ERROR
, "not started");
403 /*-----------------------------------------------
405 First draft does not implement timeout using [ms].
406 Current implementation counts yield calls only ...
407 -----------------------------------------------*/
408 bool LoadEnv::waitWhileLoading(sal_uInt32 nTimeout
)
410 // Because it's not a good idea to block the main thread
411 // (and we can't be sure that we are currently not used inside the
412 // main thread!), we can't use conditions here really. We must yield
413 // in an intelligent manner :-)
415 sal_Int32 nTime
= nTimeout
;
418 // SAFE -> ------------------------------
420 osl::MutexGuard
aReadLock1(m_mutex
);
421 if (!m_xAsynchronousJob
.is())
424 // <- SAFE ------------------------------
426 Application::Yield();
438 osl::MutexGuard
g(m_mutex
);
439 return !m_xAsynchronousJob
.is();
442 css::uno::Reference
< css::lang::XComponent
> LoadEnv::getTargetComponent() const
444 osl::MutexGuard
g(m_mutex
);
446 if (!m_xTargetFrame
.is())
447 return css::uno::Reference
< css::lang::XComponent
>();
449 css::uno::Reference
< css::frame::XController
> xController
= m_xTargetFrame
->getController();
450 if (!xController
.is())
451 return m_xTargetFrame
->getComponentWindow();
453 css::uno::Reference
< css::frame::XModel
> xModel
= xController
->getModel();
460 void SAL_CALL
LoadEnvListener::loadFinished(const css::uno::Reference
< css::frame::XFrameLoader
>&)
462 osl::MutexGuard
g(m_mutex
);
463 if (m_bWaitingResult
)
464 m_pLoadEnv
->impl_setResult(true);
465 m_bWaitingResult
= false;
468 void SAL_CALL
LoadEnvListener::loadCancelled(const css::uno::Reference
< css::frame::XFrameLoader
>&)
470 osl::MutexGuard
g(m_mutex
);
471 if (m_bWaitingResult
)
472 m_pLoadEnv
->impl_setResult(false);
473 m_bWaitingResult
= false;
476 void SAL_CALL
LoadEnvListener::dispatchFinished(const css::frame::DispatchResultEvent
& aEvent
)
478 osl::MutexGuard
g(m_mutex
);
480 if (!m_bWaitingResult
)
485 case css::frame::DispatchResultState::FAILURE
:
486 m_pLoadEnv
->impl_setResult(false);
489 case css::frame::DispatchResultState::SUCCESS
:
490 m_pLoadEnv
->impl_setResult(false);
493 case css::frame::DispatchResultState::DONTKNOW
:
494 m_pLoadEnv
->impl_setResult(false);
497 m_bWaitingResult
= false;
500 void SAL_CALL
LoadEnvListener::disposing(const css::lang::EventObject
&)
502 osl::MutexGuard
g(m_mutex
);
503 if (m_bWaitingResult
)
504 m_pLoadEnv
->impl_setResult(false);
505 m_bWaitingResult
= false;
508 void LoadEnv::impl_setResult(bool bResult
)
510 osl::MutexGuard
g(m_mutex
);
514 impl_reactForLoadingState();
516 // clearing of this reference will unblock waitWhileLoading()!
517 // So we must be sure, that loading process was really finished.
518 // => do it as last operation of this method ...
519 m_xAsynchronousJob
.clear();
522 /*-----------------------------------------------
523 TODO: Is it a good idea to change Sequence<>
524 parameter to stl-adapter?
525 -----------------------------------------------*/
526 LoadEnv::EContentType
LoadEnv::classifyContent(const OUString
& sURL
,
527 const css::uno::Sequence
< css::beans::PropertyValue
>& lMediaDescriptor
)
530 // (i) Filter some special well known URL protocols,
531 // which can not be handled or loaded in general.
532 // Of course an empty URL must be ignored here too.
533 // Note: These URL schemata are fix and well known ...
534 // But there can be some additional ones, which was not
535 // defined at implementation time of this class :-(
536 // So we have to make sure, that the following code
537 // can detect such protocol schemata too :-)
541 (ProtocolCheck::isProtocol(sURL
,EProtocol::Uno
)) ||
542 (ProtocolCheck::isProtocol(sURL
,EProtocol::Slot
)) ||
543 (ProtocolCheck::isProtocol(sURL
,EProtocol::Macro
)) ||
544 (ProtocolCheck::isProtocol(sURL
,EProtocol::Service
)) ||
545 (ProtocolCheck::isProtocol(sURL
,EProtocol::MailTo
)) ||
546 (ProtocolCheck::isProtocol(sURL
,EProtocol::News
))
549 return E_UNSUPPORTED_CONTENT
;
552 // (ii) Some special URLs indicates a given input stream,
553 // a full featured document model directly or
554 // specify a request for opening an empty document.
555 // Such contents are loadable in general.
556 // But we have to check, if the media descriptor contains
557 // all needed resources. If they are missing - the following
558 // load request will fail.
560 /* Attention: The following code can't work on such special URLs!
561 It should not break the office .. but it makes no sense
562 to start expensive object creations and complex search
563 algorithm if its clear, that such URLs must be handled
567 // creation of new documents
568 if (ProtocolCheck::isProtocol(sURL
,EProtocol::PrivateFactory
))
569 return E_CAN_BE_LOADED
;
571 // using of an existing input stream
572 utl::MediaDescriptor
stlMediaDescriptor(lMediaDescriptor
);
573 utl::MediaDescriptor::const_iterator pIt
;
574 if (ProtocolCheck::isProtocol(sURL
,EProtocol::PrivateStream
))
576 pIt
= stlMediaDescriptor
.find(utl::MediaDescriptor::PROP_INPUTSTREAM());
577 css::uno::Reference
< css::io::XInputStream
> xStream
;
578 if (pIt
!= stlMediaDescriptor
.end())
579 pIt
->second
>>= xStream
;
581 return E_CAN_BE_LOADED
;
582 SAL_INFO("fwk.loadenv", "LoadEnv::classifyContent(): loading from stream with right URL but invalid stream detected");
583 return E_UNSUPPORTED_CONTENT
;
586 // using of a full featured document
587 if (ProtocolCheck::isProtocol(sURL
,EProtocol::PrivateObject
))
589 pIt
= stlMediaDescriptor
.find(utl::MediaDescriptor::PROP_MODEL());
590 css::uno::Reference
< css::frame::XModel
> xModel
;
591 if (pIt
!= stlMediaDescriptor
.end())
592 pIt
->second
>>= xModel
;
595 SAL_INFO("fwk.loadenv", "LoadEnv::classifyContent(): loading with object with right URL but invalid object detected");
596 return E_UNSUPPORTED_CONTENT
;
599 // following operations can work on an internal type name only :-(
600 css::uno::Reference
< css::uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
601 css::uno::Reference
< css::document::XTypeDetection
> xDetect(
602 xContext
->getServiceManager()->createInstanceWithContext(
603 "com.sun.star.document.TypeDetection", xContext
),
604 css::uno::UNO_QUERY_THROW
);
606 OUString sType
= xDetect
->queryTypeByURL(sURL
);
608 css::uno::Sequence
< css::beans::NamedValue
> lQuery(1);
609 css::uno::Reference
< css::frame::XLoaderFactory
> xLoaderFactory
;
610 css::uno::Reference
< css::container::XEnumeration
> xSet
;
611 css::uno::Sequence
< OUString
> lTypesReg(1);
613 // (iii) If a FrameLoader service (or at least
614 // a Filter) can be found, which supports
615 // this URL - it must be a loadable content.
616 // Because both items are registered for types
617 // it's enough to check for frame loaders only.
618 // Mos of our filters are handled by our global
619 // default loader. But there exist some specialized
620 // loader, which does not work on top of filters!
621 // So it's not enough to search on the filter configuration.
622 // Further it's not enough to search for types!
623 // Because there exist some types, which are referenced by
624 // other objects... but not by filters nor frame loaders!
626 OUString
sPROP_TYPES(PROP_TYPES
);
628 lTypesReg
[0] = sType
;
629 lQuery
[0].Name
= sPROP_TYPES
;
630 lQuery
[0].Value
<<= lTypesReg
;
632 xLoaderFactory
= css::frame::FrameLoaderFactory::create(xContext
);
633 xSet
= xLoaderFactory
->createSubSetEnumerationByProperties(lQuery
);
634 // at least one registered frame loader is enough!
635 if (xSet
->hasMoreElements())
636 return E_CAN_BE_LOADED
;
638 // (iv) Some URL protocols are supported by special services.
639 // E.g. ContentHandler.
640 // Such contents can be handled ... but not loaded.
642 lTypesReg
[0] = sType
;
643 lQuery
[0].Name
= sPROP_TYPES
;
644 lQuery
[0].Value
<<= lTypesReg
;
646 xLoaderFactory
= css::frame::ContentHandlerFactory::create(xContext
);
647 xSet
= xLoaderFactory
->createSubSetEnumerationByProperties(lQuery
);
648 // at least one registered content handler is enough!
649 if (xSet
->hasMoreElements())
650 return E_CAN_BE_HANDLED
;
652 // (v) Last but not least the UCB is used inside office to
653 // load contents. He has a special configuration to know
654 // which URL schemata can be used inside office.
655 css::uno::Reference
< css::ucb::XUniversalContentBroker
> xUCB(css::ucb::UniversalContentBroker::create(xContext
));
656 if (xUCB
->queryContentProvider(sURL
).is())
657 return E_CAN_BE_LOADED
;
659 // (TODO) At this point, we have no idea .-)
660 // But it seems to be better, to break all
661 // further requests for this URL. Otherwise
662 // we can run into some trouble.
663 return E_UNSUPPORTED_CONTENT
;
668 bool queryOrcusTypeAndFilter(const uno::Sequence
<beans::PropertyValue
>& rDescriptor
, OUString
& rType
, OUString
& rFilter
)
671 sal_Int32 nSize
= rDescriptor
.getLength();
672 for (sal_Int32 i
= 0; i
< nSize
; ++i
)
674 const beans::PropertyValue
& rProp
= rDescriptor
[i
];
675 if (rProp
.Name
== "URL")
677 rProp
.Value
>>= aURL
;
682 if (aURL
.isEmpty() || aURL
.copy(0,8).equalsIgnoreAsciiCase("private:"))
685 // TODO : Type must be set to be generic_Text (or any other type that
686 // exists) in order to find a usable loader. Exploit it as a temporary
689 // depending on the experimental mode
690 uno::Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
691 if (!xContext
.is() || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext
))
697 rtl::Bootstrap::get("LIBO_USE_ORCUS", aUseOrcus
);
698 bool bUseOrcus
= (aUseOrcus
== "YES");
703 if (aURL
.endsWith(".xlsx"))
705 rType
= "generic_Text";
709 else if (aURL
.endsWith(".ods"))
711 rType
= "generic_Text";
715 else if (aURL
.endsWith(".csv"))
717 rType
= "generic_Text";
727 void LoadEnv::impl_detectTypeAndFilter()
729 static const sal_Int32 FILTERFLAG_TEMPLATEPATH
= 16;
732 osl::ClearableMutexGuard
aReadLock(m_mutex
);
734 // Attention: Because our stl media descriptor is a copy of a uno sequence
735 // we can't use as an in/out parameter here. Copy it before and don't forget to
736 // update structure afterwards again!
737 css::uno::Sequence
< css::beans::PropertyValue
> lDescriptor
= m_lMediaDescriptor
.getAsConstPropertyValueList();
738 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
743 OUString sType
, sFilter
;
745 if (queryOrcusTypeAndFilter(lDescriptor
, sType
, sFilter
) && !sType
.isEmpty() && !sFilter
.isEmpty())
747 // Orcus type detected. Skip the normal type detection process.
748 m_lMediaDescriptor
<< lDescriptor
;
749 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType
;
750 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter
;
751 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_FILTERPROVIDER()] <<= OUString("orcus");
752 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_DOCUMENTSERVICE()] <<= OUString("com.sun.star.sheet.SpreadsheetDocument");
756 css::uno::Reference
< css::document::XTypeDetection
> xDetect(
757 xContext
->getServiceManager()->createInstanceWithContext(
758 "com.sun.star.document.TypeDetection", xContext
),
759 css::uno::UNO_QUERY_THROW
);
760 sType
= xDetect
->queryTypeByDescriptor(lDescriptor
, true); /*TODO should deep detection be able for enable/disable it from outside? */
762 // no valid content -> loading not possible
764 throw LoadEnvException(
765 LoadEnvException::ID_UNSUPPORTED_CONTENT
, "type detection failed");
768 osl::ResettableMutexGuard
aWriteLock(m_mutex
);
770 // detection was successful => update the descriptor member of this class
771 m_lMediaDescriptor
<< lDescriptor
;
772 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType
;
773 // Is there an already detected (may be preselected) filter?
775 sFilter
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
780 // We do have potentially correct type, but the detection process was aborted.
781 if (m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ABORTED(), false))
782 throw LoadEnvException(
783 LoadEnvException::ID_UNSUPPORTED_CONTENT
, "type detection aborted");
785 // But the type isn't enough. For loading sometimes we need more information.
786 // E.g. for our "_default" feature, where we recycle any frame which contains
787 // and "Untitled" document, we must know if the new document is based on a template!
788 // But this information is available as a filter property only.
789 // => We must try(!) to detect the right filter for this load request.
790 // On the other side ... if no filter is available .. ignore it.
791 // Then the type information must be enough.
792 if (sFilter
.isEmpty())
794 // no -> try to find a preferred filter for the detected type.
795 // Don't forget to update the media descriptor.
796 css::uno::Reference
< css::container::XNameAccess
> xTypeCont(xDetect
, css::uno::UNO_QUERY_THROW
);
799 ::comphelper::SequenceAsHashMap
lTypeProps(xTypeCont
->getByName(sType
));
800 sFilter
= lTypeProps
.getUnpackedValueOrDefault("PreferredFilter", OUString());
801 if (!sFilter
.isEmpty())
805 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter
;
810 catch(const css::container::NoSuchElementException
&)
814 // check if the filter (if one exists) points to a template format filter.
815 // Then we have to add the property "AsTemplate".
816 // We need this information to decide afterwards if we can use a "recycle frame"
817 // for target "_default" or has to create a new one every time.
818 // On the other side we have to suppress that, if this property already exists
819 // and should trigger a special handling. Then the outside call of this method here,
820 // has to know, what he is doing .-)
822 bool bIsOwnTemplate
= false;
823 if (!sFilter
.isEmpty())
825 css::uno::Reference
< css::container::XNameAccess
> xFilterCont(xContext
->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY
, xContext
), css::uno::UNO_QUERY_THROW
);
828 ::comphelper::SequenceAsHashMap
lFilterProps(xFilterCont
->getByName(sFilter
));
829 sal_Int32 nFlags
= lFilterProps
.getUnpackedValueOrDefault("Flags", sal_Int32(0));
830 bIsOwnTemplate
= ((nFlags
& FILTERFLAG_TEMPLATEPATH
) == FILTERFLAG_TEMPLATEPATH
);
832 catch(const css::container::NoSuchElementException
&)
839 // Don't overwrite external decisions! See comments before ...
840 utl::MediaDescriptor::const_iterator pAsTemplateItem
= m_lMediaDescriptor
.find(utl::MediaDescriptor::PROP_ASTEMPLATE());
841 if (pAsTemplateItem
== m_lMediaDescriptor
.end())
842 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_ASTEMPLATE()] <<= true;
848 bool LoadEnv::impl_handleContent()
850 // SAFE -> -----------------------------------
851 osl::ClearableMutexGuard
aReadLock(m_mutex
);
853 // the type must exist inside the descriptor ... otherwise this class is implemented wrong :-)
854 OUString sType
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
856 throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR
);
858 // convert media descriptor and URL to right format for later interface call!
859 css::uno::Sequence
< css::beans::PropertyValue
> lDescriptor
;
860 m_lMediaDescriptor
>> lDescriptor
;
861 css::util::URL aURL
= m_aURL
;
863 // get necessary container to query for a handler object
864 css::uno::Reference
< css::frame::XLoaderFactory
> xLoaderFactory
= css::frame::ContentHandlerFactory::create(m_xContext
);
867 // <- SAFE -----------------------------------
870 css::uno::Sequence
< OUString
> lTypeReg
{ sType
};
872 css::uno::Sequence
< css::beans::NamedValue
> lQuery
{ { PROP_TYPES
, css::uno::makeAny(lTypeReg
) } };
874 css::uno::Reference
< css::container::XEnumeration
> xSet
= xLoaderFactory
->createSubSetEnumerationByProperties(lQuery
);
875 while(xSet
->hasMoreElements())
877 ::comphelper::SequenceAsHashMap
lProps (xSet
->nextElement());
878 OUString sHandler
= lProps
.getUnpackedValueOrDefault(PROP_NAME
, OUString());
880 css::uno::Reference
< css::frame::XNotifyingDispatch
> xHandler
;
883 xHandler
.set(xLoaderFactory
->createInstance(sHandler
), css::uno::UNO_QUERY
);
887 catch(const css::uno::RuntimeException
&)
889 catch(const css::uno::Exception
&)
892 // SAFE -> -----------------------------------
893 osl::ClearableMutexGuard
aWriteLock(m_mutex
);
894 m_xAsynchronousJob
= xHandler
;
895 LoadEnvListener
* pListener
= new LoadEnvListener(this);
897 // <- SAFE -----------------------------------
899 css::uno::Reference
< css::frame::XDispatchResultListener
> xListener(static_cast< css::frame::XDispatchResultListener
* >(pListener
), css::uno::UNO_QUERY
);
900 xHandler
->dispatchWithNotification(aURL
, lDescriptor
, xListener
);
908 bool LoadEnv::impl_furtherDocsAllowed()
911 osl::ResettableMutexGuard
aReadLock(m_mutex
);
912 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
916 bool bAllowed
= true;
920 css::uno::Any aVal
= ::comphelper::ConfigurationHelper::readDirectKey(
922 "org.openoffice.Office.Common/",
925 ::comphelper::EConfigurationModes::ReadOnly
);
927 // NIL means: count of allowed documents = infinite !
928 // => return sal_True
929 if ( ! aVal
.hasValue())
933 sal_Int32 nMaxOpenDocuments
= 0;
934 aVal
>>= nMaxOpenDocuments
;
936 css::uno::Reference
< css::frame::XFramesSupplier
> xDesktop(
937 css::frame::Desktop::create(xContext
),
938 css::uno::UNO_QUERY_THROW
);
940 FrameListAnalyzer
aAnalyzer(xDesktop
,
941 css::uno::Reference
< css::frame::XFrame
>(),
942 FrameAnalyzerFlags::Help
|
943 FrameAnalyzerFlags::BackingComponent
|
944 FrameAnalyzerFlags::Hidden
);
946 sal_Int32 nOpenDocuments
= aAnalyzer
.m_lOtherVisibleFrames
.size();
947 bAllowed
= (nOpenDocuments
< nMaxOpenDocuments
);
950 catch(const css::uno::Exception
&)
951 { bAllowed
= true; } // !! internal errors are no reason to disturb the office from opening documents .-)
957 css::uno::Reference
< css::task::XInteractionHandler
> xInteraction
= m_lMediaDescriptor
.getUnpackedValueOrDefault(
958 utl::MediaDescriptor::PROP_INTERACTIONHANDLER(),
959 css::uno::Reference
< css::task::XInteractionHandler
>());
963 if (xInteraction
.is())
965 css::uno::Any aInteraction
;
966 css::uno::Sequence
< css::uno::Reference
< css::task::XInteractionContinuation
> > lContinuations(2);
968 comphelper::OInteractionAbort
* pAbort
= new comphelper::OInteractionAbort();
969 comphelper::OInteractionApprove
* pApprove
= new comphelper::OInteractionApprove();
971 lContinuations
[0].set( static_cast< css::task::XInteractionContinuation
* >(pAbort
),
972 css::uno::UNO_QUERY_THROW
);
973 lContinuations
[1].set( static_cast< css::task::XInteractionContinuation
* >(pApprove
),
974 css::uno::UNO_QUERY_THROW
);
976 css::task::ErrorCodeRequest aErrorCode
;
977 aErrorCode
.ErrCode
= sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED
);
978 aInteraction
<<= aErrorCode
;
979 xInteraction
->handle( InteractionRequest::CreateRequest(aInteraction
, lContinuations
) );
986 bool LoadEnv::impl_filterHasInteractiveDialog() const
988 //show the frame now so it can be the parent for any message dialogs shown during import
990 //unless (tdf#114648) an Interactive case such as the new database wizard
991 if (m_aURL
.Arguments
== "Interactive")
994 // unless (tdf#116277) its the labels/business cards slave frame
995 if (m_aURL
.Arguments
.indexOf("slot=") != -1)
998 OUString sFilter
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
999 if (sFilter
.isEmpty())
1002 // unless (tdf#115683) the filter has a UIComponent
1003 OUString sUIComponent
;
1004 css::uno::Reference
<css::container::XNameAccess
> xFilterCont(m_xContext
->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY
, m_xContext
),
1005 css::uno::UNO_QUERY_THROW
);
1008 ::comphelper::SequenceAsHashMap
lFilterProps(xFilterCont
->getByName(sFilter
));
1009 sUIComponent
= lFilterProps
.getUnpackedValueOrDefault("UIComponent", OUString());
1011 catch(const css::container::NoSuchElementException
&)
1015 return !sUIComponent
.isEmpty();
1018 bool LoadEnv::impl_loadContent()
1020 // SAFE -> -----------------------------------
1021 osl::ClearableMutexGuard
aWriteLock(m_mutex
);
1023 // search or create right target frame
1024 OUString sTarget
= m_sTarget
;
1025 if (TargetHelper::matchSpecialTarget(sTarget
, TargetHelper::ESpecialTarget::Default
))
1027 m_xTargetFrame
= impl_searchAlreadyLoaded();
1028 if (m_xTargetFrame
.is())
1030 impl_setResult(true);
1033 m_xTargetFrame
= impl_searchRecycleTarget();
1036 if (! m_xTargetFrame
.is())
1039 (TargetHelper::matchSpecialTarget(sTarget
, TargetHelper::ESpecialTarget::Blank
)) ||
1040 (TargetHelper::matchSpecialTarget(sTarget
, TargetHelper::ESpecialTarget::Default
))
1043 if (! impl_furtherDocsAllowed())
1045 TaskCreator
aCreator(m_xContext
);
1046 m_xTargetFrame
= aCreator
.createTask(SPECIALTARGET_BLANK
, m_lMediaDescriptor
);
1047 m_bCloseFrameOnError
= m_xTargetFrame
.is();
1051 sal_Int32 nSearchFlags
= m_nSearchFlags
& ~css::frame::FrameSearchFlag::CREATE
;
1052 m_xTargetFrame
= m_xBaseFrame
->findFrame(sTarget
, nSearchFlags
);
1053 if (! m_xTargetFrame
.is())
1055 if (! impl_furtherDocsAllowed())
1057 m_xTargetFrame
= m_xBaseFrame
->findFrame(SPECIALTARGET_BLANK
, 0);
1058 m_bCloseFrameOnError
= m_xTargetFrame
.is();
1063 // If we couldn't find a valid frame or the frame has no container window
1064 // we have to throw an exception.
1066 ( ! m_xTargetFrame
.is() ) ||
1067 ( ! m_xTargetFrame
->getContainerWindow().is() )
1069 throw LoadEnvException(LoadEnvException::ID_NO_TARGET_FOUND
);
1071 css::uno::Reference
< css::frame::XFrame
> xTargetFrame
= m_xTargetFrame
;
1073 // Now we have a valid frame ... and type detection was already done.
1074 // We should apply the module dependent window position and size to the
1076 impl_applyPersistentWindowState(xTargetFrame
->getContainerWindow());
1078 // Don't forget to lock task for following load process. Otherwise it could die
1079 // during this operation runs by terminating the office or closing this task via api.
1080 // If we set this lock "close()" will return false and closing will be broken.
1081 // Attention: Don't forget to reset this lock again after finishing operation.
1082 // Otherwise task AND office couldn't die!!!
1083 // This includes gracefully handling of Exceptions (Runtime!) too ...
1084 // That's why we use a specialized guard, which will reset the lock
1085 // if it will be run out of scope.
1087 // Note further: ignore if this internal guard already contains a resource.
1088 // Might impl_searchRecycleTarget() set it before. But in case this impl-method wasn't used
1089 // and the target frame was new created ... this lock here must be set!
1090 css::uno::Reference
< css::document::XActionLockable
> xTargetLock(xTargetFrame
, css::uno::UNO_QUERY
);
1091 m_aTargetLock
.setResource(xTargetLock
);
1093 // Add status indicator to descriptor. Loader can show a progress then.
1094 // But don't do it, if loading should be hidden or preview is used...!
1095 // So we prevent our code against wrong using. Why?
1096 // It could be, that using of this progress could make trouble. e.g. He makes window visible...
1097 // but shouldn't do that. But if no indicator is available... nobody has a chance to do that!
1098 bool bHidden
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1099 bool bMinimized
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED(), false);
1100 bool bPreview
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW(), false);
1101 css::uno::Reference
< css::task::XStatusIndicator
> xProgress
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR(), css::uno::Reference
< css::task::XStatusIndicator
>());
1103 if (!bHidden
&& !bMinimized
&& !bPreview
)
1105 if (!xProgress
.is())
1107 // Note: it's an optional interface!
1108 css::uno::Reference
< css::task::XStatusIndicatorFactory
> xProgressFactory(xTargetFrame
, css::uno::UNO_QUERY
);
1109 if (xProgressFactory
.is())
1111 xProgress
= xProgressFactory
->createStatusIndicator();
1113 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xProgress
;
1117 // Now that we have a target window into which we can load, reinit the interaction handler to have this
1118 // window as its parent for modal dialogs and ensure the window is visible
1119 css::uno::Reference
< css::task::XInteractionHandler
> xInteraction
= m_lMediaDescriptor
.getUnpackedValueOrDefault(
1120 utl::MediaDescriptor::PROP_INTERACTIONHANDLER(),
1121 css::uno::Reference
< css::task::XInteractionHandler
>());
1122 css::uno::Reference
<css::lang::XInitialization
> xHandler(xInteraction
, css::uno::UNO_QUERY
);
1125 css::uno::Reference
<css::awt::XWindow
> xWindow
= xTargetFrame
->getContainerWindow();
1126 uno::Sequence
<uno::Any
> aArguments(comphelper::InitAnyPropertySequence(
1128 {"Parent", uno::Any(xWindow
)}
1130 xHandler
->initialize(aArguments
);
1131 //show the frame as early as possible to make it the parent of any message dialogs
1132 if (!impl_filterHasInteractiveDialog())
1133 impl_makeFrameWindowVisible(xWindow
, false);
1137 // convert media descriptor and URL to right format for later interface call!
1138 css::uno::Sequence
< css::beans::PropertyValue
> lDescriptor
;
1139 m_lMediaDescriptor
>> lDescriptor
;
1140 OUString sURL
= m_aURL
.Complete
;
1142 // try to locate any interested frame loader
1143 css::uno::Reference
< css::uno::XInterface
> xLoader
= impl_searchLoader();
1144 css::uno::Reference
< css::frame::XFrameLoader
> xAsyncLoader(xLoader
, css::uno::UNO_QUERY
);
1145 css::uno::Reference
< css::frame::XSynchronousFrameLoader
> xSyncLoader (xLoader
, css::uno::UNO_QUERY
);
1147 if (xAsyncLoader
.is())
1149 m_xAsynchronousJob
= xAsyncLoader
;
1150 LoadEnvListener
* pListener
= new LoadEnvListener(this);
1152 // <- SAFE -----------------------------------
1154 css::uno::Reference
< css::frame::XLoadEventListener
> xListener(static_cast< css::frame::XLoadEventListener
* >(pListener
), css::uno::UNO_QUERY
);
1155 xAsyncLoader
->load(xTargetFrame
, sURL
, lDescriptor
, xListener
);
1159 else if (xSyncLoader
.is())
1161 bool bResult
= xSyncLoader
->load(lDescriptor
, xTargetFrame
);
1162 // react for the result here, so the outside waiting
1163 // code can ask for it later.
1164 impl_setResult(bResult
);
1165 // But the return value indicates a valid started(!) operation.
1166 // And that's true every time we reach this line :-)
1176 css::uno::Reference
< css::uno::XInterface
> LoadEnv::impl_searchLoader()
1178 // SAFE -> -----------------------------------
1179 osl::ClearableMutexGuard
aReadLock(m_mutex
);
1181 // special mode to set an existing component on this frame
1182 // In such case the loader is fix. It must be the SFX based implementation,
1183 // which can create a view on top of such xModel components :-)
1184 if (m_eContentType
== E_CAN_BE_SET
)
1188 return css::frame::OfficeFrameLoader::create(m_xContext
);
1190 catch(const css::uno::RuntimeException
&)
1192 catch(const css::uno::Exception
&)
1194 throw LoadEnvException(LoadEnvException::ID_INVALID_ENVIRONMENT
);
1198 // We need this type information to locate a registered frame loader
1199 // Without such information we can't work!
1200 OUString sType
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
1201 if (sType
.isEmpty())
1202 throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR
);
1204 // try to locate any interested frame loader
1205 css::uno::Reference
< css::frame::XLoaderFactory
> xLoaderFactory
= css::frame::FrameLoaderFactory::create(m_xContext
);
1208 // <- SAFE -----------------------------------
1210 css::uno::Sequence
< OUString
> lTypesReg
{ sType
};
1212 css::uno::Sequence
< css::beans::NamedValue
> lQuery
{ { PROP_TYPES
, css::uno::makeAny(lTypesReg
) } };
1214 css::uno::Reference
< css::container::XEnumeration
> xSet
= xLoaderFactory
->createSubSetEnumerationByProperties(lQuery
);
1215 while(xSet
->hasMoreElements())
1220 // Ignore any loader, which makes trouble :-)
1221 ::comphelper::SequenceAsHashMap
lLoaderProps(xSet
->nextElement());
1222 OUString sLoader
= lLoaderProps
.getUnpackedValueOrDefault(PROP_NAME
, OUString());
1223 css::uno::Reference
< css::uno::XInterface
> xLoader
= xLoaderFactory
->createInstance(sLoader
);
1227 catch(const css::uno::RuntimeException
&)
1229 catch(const css::uno::Exception
&)
1233 return css::uno::Reference
< css::uno::XInterface
>();
1236 void LoadEnv::impl_jumpToMark(const css::uno::Reference
< css::frame::XFrame
>& xFrame
,
1237 const css::util::URL
& aURL
)
1239 if (aURL
.Mark
.isEmpty())
1242 css::uno::Reference
< css::frame::XDispatchProvider
> xProvider(xFrame
, css::uno::UNO_QUERY
);
1243 if (! xProvider
.is())
1247 osl::ClearableMutexGuard
aReadLock(m_mutex
);
1248 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
1252 css::util::URL aCmd
;
1253 aCmd
.Complete
= ".uno:JumpToMark";
1255 css::uno::Reference
< css::util::XURLTransformer
> xParser(css::util::URLTransformer::create(xContext
));
1256 xParser
->parseStrict(aCmd
);
1258 css::uno::Reference
< css::frame::XDispatch
> xDispatcher
= xProvider
->queryDispatch(aCmd
, SPECIALTARGET_SELF
, 0);
1259 if (! xDispatcher
.is())
1262 ::comphelper::SequenceAsHashMap lArgs
;
1263 lArgs
[OUString("Bookmark")] <<= aURL
.Mark
;
1264 xDispatcher
->dispatch(aCmd
, lArgs
.getAsConstPropertyValueList());
1267 css::uno::Reference
< css::frame::XFrame
> LoadEnv::impl_searchAlreadyLoaded()
1269 osl::MutexGuard
g(m_mutex
);
1271 // such search is allowed for special requests only ...
1272 // or better it's not allowed for some requests in general :-)
1274 ( ! TargetHelper::matchSpecialTarget(m_sTarget
, TargetHelper::ESpecialTarget::Default
) ) ||
1275 m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false) ||
1276 // (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN() , false) == sal_True) ||
1277 m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW(), false)
1280 return css::uno::Reference
< css::frame::XFrame
>();
1284 // May it's not useful to start expensive document search, if it
1285 // can fail only .. because we load from a stream or model directly!
1287 (ProtocolCheck::isProtocol(m_aURL
.Complete
, EProtocol::PrivateStream
)) ||
1288 (ProtocolCheck::isProtocol(m_aURL
.Complete
, EProtocol::PrivateObject
))
1289 /*TODO should be private:factory here tested too? */
1292 return css::uno::Reference
< css::frame::XFrame
>();
1295 // otherwise - iterate through the tasks of the desktop container
1296 // to find out, which of them might contains the requested document
1297 css::uno::Reference
< css::frame::XDesktop2
> xSupplier
= css::frame::Desktop::create( m_xContext
);
1298 css::uno::Reference
< css::container::XIndexAccess
> xTaskList
= xSupplier
->getFrames();
1300 if (!xTaskList
.is())
1301 return css::uno::Reference
< css::frame::XFrame
>(); // task list can be empty!
1303 // Note: To detect if a document was already loaded before
1304 // we check URLs here only. But might the existing and the required
1305 // document has different versions! Then its URLs are the same...
1306 sal_Int16 nNewVersion
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION(), sal_Int16(-1));
1308 // will be used to save the first hidden frame referring the searched model
1309 // Normally we are interested on visible frames... but if there is no such visible
1310 // frame we refer to any hidden frame also (but as fallback only).
1311 css::uno::Reference
< css::frame::XFrame
> xHiddenTask
;
1312 css::uno::Reference
< css::frame::XFrame
> xTask
;
1314 sal_Int32 count
= xTaskList
->getCount();
1315 for (sal_Int32 i
=0; i
<count
; ++i
)
1319 // locate model of task
1320 // Note: Without a model there is no chance to decide if
1321 // this task contains the searched document or not!
1322 xTaskList
->getByIndex(i
) >>= xTask
;
1326 css::uno::Reference
< css::frame::XController
> xController
= xTask
->getController();
1327 if (!xController
.is())
1333 css::uno::Reference
< css::frame::XModel
> xModel
= xController
->getModel();
1340 // don't check the complete URL here.
1341 // use its main part - ignore optional jumpmarks!
1342 const OUString sURL
= xModel
->getURL();
1343 if (!::utl::UCBContentHelper::EqualURLs( m_aURL
.Main
, sURL
))
1349 // get the original load arguments from the current document
1350 // and decide if it's really the same then the one will be.
1351 // It must be visible and must use the same file revision ...
1352 // or must not have any file revision set (-1 == -1!)
1353 utl::MediaDescriptor
lOldDocDescriptor(xModel
->getArgs());
1355 if (lOldDocDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION(), sal_Int32(-1)) != nNewVersion
)
1361 // Hidden frames are special.
1362 // They will be used as "last chance" if there is no visible frame pointing to the same model.
1363 // Safe the result but continue with current loop might be looking for other visible frames.
1364 bool bIsHidden
= lOldDocDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1365 if ( bIsHidden
&& ! xHiddenTask
.is() )
1367 xHiddenTask
= xTask
;
1372 // We found a visible task pointing to the right model ...
1376 catch(const css::uno::RuntimeException
&)
1378 catch(const css::uno::Exception
&)
1382 css::uno::Reference
< css::frame::XFrame
> xResult
;
1385 else if (xHiddenTask
.is())
1386 xResult
= xHiddenTask
;
1390 // Now we are sure, that this task includes the searched document.
1391 // It's time to activate it. As special feature we try to jump internally
1392 // if an optional jumpmark is given too.
1393 if (!m_aURL
.Mark
.isEmpty())
1394 impl_jumpToMark(xResult
, m_aURL
);
1396 // bring it to front and make sure it's visible...
1397 impl_makeFrameWindowVisible(xResult
->getContainerWindow(), true);
1403 bool LoadEnv::impl_isFrameAlreadyUsedForLoading(const css::uno::Reference
< css::frame::XFrame
>& xFrame
) const
1405 css::uno::Reference
< css::document::XActionLockable
> xLock(xFrame
, css::uno::UNO_QUERY
);
1407 // ? no lock interface ?
1408 // Maybe it's an external written frame implementation :-(
1409 // Allowing using of it... but it can fail if it's not synchronized with our processes!
1413 // Otherwise we have to look for any other existing lock.
1414 return xLock
->isActionLocked();
1417 css::uno::Reference
< css::frame::XFrame
> LoadEnv::impl_searchRecycleTarget()
1419 // SAFE -> ..................................
1420 osl::ClearableMutexGuard
aReadLock(m_mutex
);
1422 // The special backing mode frame will be recycled by definition!
1423 // It doesn't matter if somewhere wants to create a new view
1424 // or open a new untitled document...
1425 // The only exception from that - hidden frames!
1426 if (m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false))
1427 return css::uno::Reference
< css::frame::XFrame
>();
1429 css::uno::Reference
< css::frame::XFramesSupplier
> xSupplier
= css::frame::Desktop::create( m_xContext
);
1430 FrameListAnalyzer
aTasksAnalyzer(xSupplier
, css::uno::Reference
< css::frame::XFrame
>(), FrameAnalyzerFlags::BackingComponent
);
1431 if (aTasksAnalyzer
.m_xBackingComponent
.is())
1433 if (!impl_isFrameAlreadyUsedForLoading(aTasksAnalyzer
.m_xBackingComponent
))
1435 // bring it to front...
1436 impl_makeFrameWindowVisible(aTasksAnalyzer
.m_xBackingComponent
->getContainerWindow(), true);
1437 m_bReactivateControllerOnError
= true;
1438 return aTasksAnalyzer
.m_xBackingComponent
;
1442 // These states indicates a wish for creation of a new view in general.
1444 m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false) ||
1445 m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW(), false)
1448 return css::uno::Reference
< css::frame::XFrame
>();
1451 // On the other side some special URLs will open a new frame every time (expecting
1452 // they can use the backing-mode frame!)
1454 (ProtocolCheck::isProtocol(m_aURL
.Complete
, EProtocol::PrivateFactory
)) ||
1455 (ProtocolCheck::isProtocol(m_aURL
.Complete
, EProtocol::PrivateStream
)) ||
1456 (ProtocolCheck::isProtocol(m_aURL
.Complete
, EProtocol::PrivateObject
))
1459 return css::uno::Reference
< css::frame::XFrame
>();
1462 // No backing frame! No special URL => recycle active task - if possible.
1463 // Means - if it does not already contains a modified document, or
1464 // use another office module.
1465 css::uno::Reference
< css::frame::XFrame
> xTask
= xSupplier
->getActiveFrame();
1467 // not a real error - but might a focus problem!
1469 return css::uno::Reference
< css::frame::XFrame
>();
1471 // not a real error - may it's a view only
1472 css::uno::Reference
< css::frame::XController
> xController
= xTask
->getController();
1473 if (!xController
.is())
1474 return css::uno::Reference
< css::frame::XFrame
>();
1476 // not a real error - may it's a db component instead of a full featured office document
1477 css::uno::Reference
< css::frame::XModel
> xModel
= xController
->getModel();
1479 return css::uno::Reference
< css::frame::XFrame
>();
1481 // get some more information ...
1483 // A valid set URL means: there is already a location for this document.
1484 // => it was saved there or opened from there. Such Documents can not be used here.
1485 // We search for empty document ... created by a private:factory/ URL!
1486 if (xModel
->getURL().getLength()>0)
1487 return css::uno::Reference
< css::frame::XFrame
>();
1489 // The old document must be unmodified ...
1490 css::uno::Reference
< css::util::XModifiable
> xModified(xModel
, css::uno::UNO_QUERY
);
1491 if (xModified
->isModified())
1492 return css::uno::Reference
< css::frame::XFrame
>();
1494 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow(xTask
->getContainerWindow());
1495 if (pWindow
&& pWindow
->IsInModalMode())
1496 return css::uno::Reference
< css::frame::XFrame
>();
1498 // find out the application type of this document
1499 // We can recycle only documents, which uses the same application
1500 // then the new one.
1501 SvtModuleOptions::EFactory eOldApp
= SvtModuleOptions::ClassifyFactoryByModel(xModel
);
1502 SvtModuleOptions::EFactory eNewApp
= SvtModuleOptions::ClassifyFactoryByURL (m_aURL
.Complete
, m_lMediaDescriptor
.getAsConstPropertyValueList());
1505 // <- SAFE ..................................
1507 if (eOldApp
!= eNewApp
)
1508 return css::uno::Reference
< css::frame::XFrame
>();
1510 // OK this task seems to be usable for recycling
1511 // But we should mark it as such - means set an action lock.
1512 // Otherwise it would be used more than ones or will be destroyed
1513 // by a close() or terminate() request.
1514 // But if such lock already exist ... it means this task is used for
1515 // any other operation already. Don't use it then.
1516 if (impl_isFrameAlreadyUsedForLoading(xTask
))
1517 return css::uno::Reference
< css::frame::XFrame
>();
1519 // OK - there is a valid target frame.
1520 // But may be it contains already a document.
1521 // Then we have to ask it, if it allows recycling of this frame .-)
1522 bool bReactivateOldControllerOnError
= false;
1523 css::uno::Reference
< css::frame::XController
> xOldDoc
= xTask
->getController();
1526 utl::MediaDescriptor
lOldDocDescriptor(xModel
->getArgs());
1527 bool bFromTemplate
= lOldDocDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false);
1528 OUString sReferrer
= lOldDocDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REFERRER(), OUString());
1530 // tdf#83722: valid but unmodified document, either from template
1531 // or opened by the user (via File > New, referrer is set to private:user)
1532 if (bFromTemplate
|| (sReferrer
== "private:user"))
1533 return css::uno::Reference
< css::frame::XFrame
>();
1535 bReactivateOldControllerOnError
= xOldDoc
->suspend(true);
1536 if (! bReactivateOldControllerOnError
)
1537 return css::uno::Reference
< css::frame::XFrame
>();
1540 // SAFE -> ..................................
1542 osl::MutexGuard
aWriteLock(m_mutex
);
1544 css::uno::Reference
< css::document::XActionLockable
> xLock(xTask
, css::uno::UNO_QUERY
);
1545 if (!m_aTargetLock
.setResource(xLock
))
1546 return css::uno::Reference
< css::frame::XFrame
>();
1548 m_bReactivateControllerOnError
= bReactivateOldControllerOnError
;
1550 // <- SAFE ..................................
1552 // bring it to front ...
1553 impl_makeFrameWindowVisible(xTask
->getContainerWindow(), true);
1558 void LoadEnv::impl_reactForLoadingState()
1560 /*TODO reset action locks */
1562 // SAFE -> ----------------------------------
1563 osl::ClearableMutexGuard
aReadLock(m_mutex
);
1567 // Bring the new loaded document to front (if allowed!).
1568 // Note: We show new created frames here only.
1569 // We don't hide already visible frames here ...
1570 css::uno::Reference
< css::awt::XWindow
> xWindow
= m_xTargetFrame
->getContainerWindow();
1571 bool bHidden
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1572 bool bMinimized
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED(), false);
1576 SolarMutexGuard aSolarGuard
;
1577 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow(xWindow
);
1578 // check for system window is necessary to guarantee correct pointer cast!
1579 if (pWindow
&& pWindow
->IsSystemWindow())
1580 static_cast<WorkWindow
*>(pWindow
.get())->Minimize();
1584 // show frame ... if it's not still visible ...
1585 // But do nothing if it's already visible!
1586 impl_makeFrameWindowVisible(xWindow
, false);
1589 // Note: Only if an existing property "FrameName" is given by this media descriptor,
1590 // it should be used. Otherwise we should do nothing. May be the outside code has already
1591 // set a frame name on the target!
1592 utl::MediaDescriptor::const_iterator pFrameName
= m_lMediaDescriptor
.find(utl::MediaDescriptor::PROP_FRAMENAME());
1593 if (pFrameName
!= m_lMediaDescriptor
.end())
1595 OUString sFrameName
;
1596 pFrameName
->second
>>= sFrameName
;
1597 // Check the name again. e.g. "_default" isn't allowed.
1598 // On the other side "_beamer" is a valid name :-)
1599 if (TargetHelper::isValidNameForFrame(sFrameName
))
1600 m_xTargetFrame
->setName(sFrameName
);
1603 else if (m_bReactivateControllerOnError
)
1605 // Try to reactivate the old document (if any exists!)
1606 css::uno::Reference
< css::frame::XController
> xOldDoc
= m_xTargetFrame
->getController();
1607 // clear does not depend from reactivation state of a might existing old document!
1608 // We must make sure, that a might following getTargetComponent() call does not return
1609 // the old document!
1610 m_xTargetFrame
.clear();
1613 bool bReactivated
= xOldDoc
->suspend(false);
1615 throw LoadEnvException(LoadEnvException::ID_COULD_NOT_REACTIVATE_CONTROLLER
);
1616 m_bReactivateControllerOnError
= false;
1619 else if (m_bCloseFrameOnError
)
1621 // close empty frames
1622 css::uno::Reference
< css::util::XCloseable
> xCloseable (m_xTargetFrame
, css::uno::UNO_QUERY
);
1626 if (xCloseable
.is())
1627 xCloseable
->close(true);
1628 else if (m_xTargetFrame
.is())
1629 m_xTargetFrame
->dispose();
1631 catch(const css::util::CloseVetoException
&)
1633 catch(const css::lang::DisposedException
&)
1635 m_xTargetFrame
.clear();
1638 // This max force an implicit closing of our target frame ...
1639 // e.g. in case close(sal_True) was called before and the frame
1640 // kill itself if our external use-lock is released here!
1641 // That's why we release this lock AFTER ALL OPERATIONS on this frame
1642 // are finished. The frame itself must handle then
1643 // this situation gracefully.
1644 m_aTargetLock
.freeResource();
1646 // Last but not least :-)
1647 // We have to clear the current media descriptor.
1648 // Otherwise it hold a might existing stream open!
1649 m_lMediaDescriptor
.clear();
1651 css::uno::Any aRequest
;
1652 bool bThrow
= false;
1653 if ( !m_bLoaded
&& m_pQuietInteraction
.is() && m_pQuietInteraction
->wasUsed() )
1655 aRequest
= m_pQuietInteraction
->getRequest();
1656 m_pQuietInteraction
.clear();
1664 if ( aRequest
.isExtractableTo( ::cppu::UnoType
< css::uno::Exception
>::get() ) )
1665 throw LoadEnvException(
1666 LoadEnvException::ID_GENERAL_ERROR
, "interaction request",
1670 // <- SAFE ----------------------------------
1673 void LoadEnv::impl_makeFrameWindowVisible(const css::uno::Reference
< css::awt::XWindow
>& xWindow
,
1676 // SAFE -> ----------------------------------
1677 osl::ClearableMutexGuard
aReadLock(m_mutex
);
1678 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
1680 // <- SAFE ----------------------------------
1682 SolarMutexGuard aSolarGuard
;
1683 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow(xWindow
);
1686 bool const preview( m_lMediaDescriptor
.getUnpackedValueOrDefault(
1687 utl::MediaDescriptor::PROP_PREVIEW(), false) );
1689 bool bForceFrontAndFocus(false);
1692 css::uno::Any
const a
=
1693 ::comphelper::ConfigurationHelper::readDirectKey(
1695 "org.openoffice.Office.Common/View",
1696 "NewDocumentHandling",
1697 "ForceFocusAndToFront",
1698 ::comphelper::EConfigurationModes::ReadOnly
);
1699 a
>>= bForceFrontAndFocus
;
1702 if( pWindow
->IsVisible() && (bForceFrontAndFocus
|| bForceToFront
) )
1703 pWindow
->ToTop( ToTopFlags::RestoreWhenMin
| ToTopFlags::ForegroundTask
);
1705 pWindow
->Show(true, (bForceFrontAndFocus
|| bForceToFront
) ? ShowFlags::ForegroundTask
: ShowFlags::NONE
);
1709 void LoadEnv::impl_applyPersistentWindowState(const css::uno::Reference
< css::awt::XWindow
>& xWindow
)
1711 // no window -> action not possible
1715 // window already visible -> do nothing! If we use a "recycle frame" for loading ...
1716 // the current position and size must be used.
1717 css::uno::Reference
< css::awt::XWindow2
> xVisibleCheck(xWindow
, css::uno::UNO_QUERY
);
1719 (xVisibleCheck
.is() ) &&
1720 (xVisibleCheck
->isVisible())
1726 SolarMutexGuard aSolarGuard1
;
1728 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow(xWindow
);
1732 bool bSystemWindow
= pWindow
->IsSystemWindow();
1733 bool bWorkWindow
= (pWindow
->GetType() == WindowType::WORKWINDOW
);
1735 if (!bSystemWindow
&& !bWorkWindow
)
1738 // don't overwrite this special state!
1739 WorkWindow
* pWorkWindow
= static_cast<WorkWindow
*>(pWindow
.get());
1740 if (pWorkWindow
->IsMinimized())
1746 osl::ClearableMutexGuard
aReadLock(m_mutex
);
1748 // no filter -> no module -> no persistent window state
1749 OUString sFilter
= m_lMediaDescriptor
.getUnpackedValueOrDefault(
1750 utl::MediaDescriptor::PROP_FILTERNAME(),
1752 if (sFilter
.isEmpty())
1755 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
1762 // retrieve the module name from the filter configuration
1763 css::uno::Reference
< css::container::XNameAccess
> xFilterCfg(
1764 xContext
->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY
, xContext
),
1765 css::uno::UNO_QUERY_THROW
);
1766 ::comphelper::SequenceAsHashMap
lProps (xFilterCfg
->getByName(sFilter
));
1767 OUString sModule
= lProps
.getUnpackedValueOrDefault(FILTER_PROPNAME_ASCII_DOCUMENTSERVICE
, OUString());
1769 // get access to the configuration of this office module
1770 css::uno::Reference
< css::container::XNameAccess
> xModuleCfg(::comphelper::ConfigurationHelper::openConfig(
1772 "/org.openoffice.Setup/Office/Factories",
1773 ::comphelper::EConfigurationModes::ReadOnly
),
1774 css::uno::UNO_QUERY_THROW
);
1776 // read window state from the configuration
1777 // and apply it on the window.
1778 // Do nothing, if no configuration entry exists!
1779 OUString sWindowState
;
1781 // Don't look for persistent window attributes when used through LibreOfficeKit
1782 if( !comphelper::LibreOfficeKit::isActive() )
1783 comphelper::ConfigurationHelper::readRelativeKey(xModuleCfg
, sModule
, OFFICEFACTORY_PROPNAME_ASCII_WINDOWATTRIBUTES
) >>= sWindowState
;
1785 if (!sWindowState
.isEmpty())
1788 SolarMutexGuard aSolarGuard
;
1790 // We have to retrieve the window pointer again. Because nobody can guarantee
1791 // that the XWindow was not disposed in between .-)
1792 // But if we get a valid pointer we can be sure, that it's the system window pointer
1793 // we already checked and used before. Because nobody recycle the same uno reference for
1794 // a new internal c++ implementation ... hopefully .-))
1795 VclPtr
<vcl::Window
> pWindowCheck
= VCLUnoHelper::GetWindow(xWindow
);
1799 SystemWindow
* pSystemWindow
= static_cast<SystemWindow
*>(pWindowCheck
.get());
1800 pSystemWindow
->SetWindowState(OUStringToOString(sWindowState
,RTL_TEXTENCODING_UTF8
));
1804 catch(const css::uno::RuntimeException
&)
1806 catch(const css::uno::Exception
&)
1810 } // namespace framework
1812 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */