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/targethelper.hxx>
23 #include <framework/framelistanalyzer.hxx>
25 #include <interaction/quietinteraction.hxx>
26 #include <properties.h>
27 #include <protocols.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";
92 using namespace com::sun::star
;
94 class LoadEnvListener
: public ::cppu::WeakImplHelper2
< css::frame::XLoadEventListener
,
95 css::frame::XDispatchResultListener
>
99 bool m_bWaitingResult
;
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
)
130 , m_eFeature(E_NO_FEATURE
)
131 , m_eContentType(E_UNSUPPORTED_CONTENT
)
132 , m_bCloseFrameOnError(false)
133 , m_bReactivateControllerOnError(false)
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
,
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
,
160 css::uno::Reference
< css::frame::XFrame
>(xLoader
, css::uno::UNO_QUERY
),
163 LoadEnv::E_NO_FEATURE
);
165 aEnv
.waitWhileLoading(); // wait for ever!
167 xComponent
= aEnv
.getTargetComponent();
169 catch(const LoadEnvException
& ex
)
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
+ "\"",
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
>().
193 << " while loading <" << sURL
<< ">");
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
> ());
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
;
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
);
238 m_nSearchFlags
= nSearchFlags
;
239 m_eFeature
= eFeature
;
240 m_eContentType
= eContentType
;
241 m_bCloseFrameOnError
= false;
242 m_bReactivateControllerOnError
= 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? */
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(
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
;
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
& ) { }
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
;
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()
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");
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;
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();
383 bStarted
= impl_loadContent();
385 // not started => general error
386 // We can't say - what was the reason for.
388 throw LoadEnvException(
389 LoadEnvException::ID_GENERAL_ERROR
, "not started");
392 /*-----------------------------------------------
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
;
407 // SAFE -> ------------------------------
408 osl::ClearableMutexGuard
aReadLock1(m_mutex
);
409 if (!m_xAsynchronousJob
.is())
412 // <- SAFE ------------------------------
414 Application::Yield();
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();
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
)
476 case css::frame::DispatchResultState::FAILURE
:
477 m_pLoadEnv
->impl_setResult(false);
480 case css::frame::DispatchResultState::SUCCESS
:
481 m_pLoadEnv
->impl_setResult(false);
484 case css::frame::DispatchResultState::DONTKNOW
:
485 m_pLoadEnv
->impl_setResult(false);
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
);
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 :-)
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
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
;
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
;
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
;
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
))
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
;
683 if (aURL
.isEmpty() || aURL
.copy(0,8).equalsIgnoreAsciiCase("private:"))
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
694 if (aURL
.endsWith(".gnumeric"))
696 rType
= "generic_Text";
697 rFilter
= "gnumeric";
704 if (aURL
.endsWith(".xlsx"))
706 rType
= "generic_Text";
710 else if (aURL
.endsWith(".ods"))
712 rType
= "generic_Text";
716 else if (aURL
.endsWith(".csv"))
718 rType
= "generic_Text";
728 bool queryOrcusTypeAndFilter(const uno::Sequence
<beans::PropertyValue
>&, OUString
&, OUString
&)
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;
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
;
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");
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
776 throw LoadEnvException(
777 LoadEnvException::ID_UNSUPPORTED_CONTENT
, "type detection failed");
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?
787 sFilter
= m_lMediaDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
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())
812 m_lMediaDescriptor
[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter
;
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
&)
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
;
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());
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
);
875 // <- SAFE -----------------------------------
878 css::uno::Sequence
< OUString
> lTypeReg(1);
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
);
900 catch(const css::uno::RuntimeException
&)
902 catch(const css::uno::Exception
&)
905 // SAFE -> -----------------------------------
906 osl::ClearableMutexGuard
aWriteLock(m_mutex
);
907 m_xAsynchronousJob
= xHandler
;
908 LoadEnvListener
* pListener
= new LoadEnvListener(this);
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
);
921 bool LoadEnv::impl_furtherDocsAllowed()
924 osl::ResettableMutexGuard
aReadLock(m_mutex
);
925 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
929 bool bAllowed
= true;
933 css::uno::Any aVal
= ::comphelper::ConfigurationHelper::readDirectKey(
935 OUString("org.openoffice.Office.Common/"),
937 OUString("MaxOpenDocuments"),
938 ::comphelper::ConfigurationHelper::E_READONLY
);
940 // NIL means: count of allowed documents = infinite !
941 // => return sal_True
942 if ( ! aVal
.hasValue())
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 .-)
970 css::uno::Reference
< css::task::XInteractionHandler
> xInteraction
= m_lMediaDescriptor
.getUnpackedValueOrDefault(
971 utl::MediaDescriptor::PROP_INTERACTIONHANDLER(),
972 css::uno::Reference
< css::task::XInteractionHandler
>());
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
) );
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);
1017 m_xTargetFrame
= impl_searchRecycleTarget();
1020 if (! m_xTargetFrame
.is())
1023 (TargetHelper::matchSpecialTarget(sTarget
, TargetHelper::E_BLANK
)) ||
1024 (TargetHelper::matchSpecialTarget(sTarget
, TargetHelper::E_DEFAULT
))
1027 if (! impl_furtherDocsAllowed())
1029 m_xTargetFrame
= m_xBaseFrame
->findFrame(SPECIALTARGET_BLANK
, 0);
1030 m_bCloseFrameOnError
= m_xTargetFrame
.is();
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())
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.
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
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();
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);
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
);
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 :-)
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
&)
1153 catch(const css::uno::Exception
&)
1155 throw LoadEnvException(LoadEnvException::ID_INVALID_ENVIRONMENT
);
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
);
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())
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
);
1195 catch(const css::uno::RuntimeException
&)
1197 catch(const css::uno::Exception
&)
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())
1210 css::uno::Reference
< css::frame::XDispatchProvider
> xProvider(xFrame
, css::uno::UNO_QUERY
);
1211 if (! xProvider
.is())
1215 osl::ClearableMutexGuard
aReadLock(m_mutex
);
1216 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
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())
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 :-)
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
>();
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!
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
;
1295 css::uno::Reference
< css::frame::XController
> xController
= xTask
->getController();
1296 if (!xController
.is())
1302 css::uno::Reference
< css::frame::XModel
> xModel
= xController
->getModel();
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
))
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
)
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);
1336 ( ! xHiddenTask
.is())
1339 xHiddenTask
= xTask
;
1344 // We found a visible task pointing to the right model ...
1348 catch(const css::uno::RuntimeException
&)
1350 catch(const css::uno::Exception
&)
1354 css::uno::Reference
< css::frame::XFrame
> xResult
;
1357 else if (xHiddenTask
.is())
1358 xResult
= xHiddenTask
;
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);
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 !
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.
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!)
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!
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();
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());
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();
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
;
1512 // <- SAFE ..................................
1514 // bring it to front ...
1515 impl_makeFrameWindowVisible(xTask
->getContainerWindow(), true);
1520 void LoadEnv::impl_reactForLoadingState()
1521 throw(LoadEnvException
, css::uno::RuntimeException
)
1523 /*TODO reset action locks */
1525 // SAFE -> ----------------------------------
1526 osl::ClearableMutexGuard
aReadLock(m_mutex
);
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);
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();
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();
1576 bool bReactivated
= xOldDoc
->suspend(sal_False
);
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
);
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();
1629 if ( aRequest
.isExtractableTo( ::cppu::UnoType
< css::uno::Exception
>::get() ) )
1630 throw LoadEnvException(
1631 LoadEnvException::ID_GENERAL_ERROR
, "interaction request",
1635 // <- SAFE ----------------------------------
1638 void LoadEnv::impl_makeFrameWindowVisible(const css::uno::Reference
< css::awt::XWindow
>& xWindow
,
1641 // SAFE -> ----------------------------------
1642 osl::ClearableMutexGuard
aReadLock(m_mutex
);
1643 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
1645 // <- SAFE ----------------------------------
1647 SolarMutexGuard aSolarGuard
;
1648 vcl::Window
* pWindow
= VCLUnoHelper::GetWindow(xWindow
);
1651 bool const preview( m_lMediaDescriptor
.getUnpackedValueOrDefault(
1652 utl::MediaDescriptor::PROP_PREVIEW(), false) );
1654 bool bForceFrontAndFocus(false);
1657 css::uno::Any
const a
=
1658 ::comphelper::ConfigurationHelper::readDirectKey(
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
) )
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
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
);
1686 (xVisibleCheck
.is() ) &&
1687 (xVisibleCheck
->isVisible())
1692 SolarMutexClearableGuard aSolarGuard1
;
1694 vcl::Window
* pWindow
= VCLUnoHelper::GetWindow(xWindow
);
1698 bool bSystemWindow
= pWindow
->IsSystemWindow();
1699 bool bWorkWindow
= (pWindow
->GetType() == WINDOW_WORKWINDOW
);
1701 if (!bSystemWindow
&& !bWorkWindow
)
1704 // dont overwrite this special state!
1705 WorkWindow
* pWorkWindow
= static_cast<WorkWindow
*>(pWindow
);
1706 if (pWorkWindow
->IsMinimized())
1709 aSolarGuard1
.clear();
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(),
1719 if (sFilter
.isEmpty())
1722 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
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(
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())
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
);
1762 SystemWindow
* pSystemWindow
= static_cast<SystemWindow
*>(pWindowCheck
);
1763 pSystemWindow
->SetWindowState(OUStringToOString(sWindowState
,RTL_TEXTENCODING_UTF8
));
1767 catch(const css::uno::RuntimeException
&)
1769 catch(const css::uno::Exception
&)
1773 } // namespace framework
1775 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */