Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / framework / source / loadenv / loadenv.cxx
blob328152765c93ddb816f3d60175e305ee22ad3903
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <loadenv/loadenv.hxx>
22 #include <loadenv/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>
29 #include <services.h>
30 #include <targets.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>
38 #include <officecfg/Setup.hxx>
40 #include <com/sun/star/awt/XWindow2.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <com/sun/star/container/XEnumeration.hpp>
44 #include <com/sun/star/document/MacroExecMode.hpp>
45 #include <com/sun/star/document/XTypeDetection.hpp>
46 #include <com/sun/star/document/XActionLockable.hpp>
47 #include <com/sun/star/document/UpdateDocMode.hpp>
48 #include <com/sun/star/frame/Desktop.hpp>
49 #include <com/sun/star/frame/OfficeFrameLoader.hpp>
50 #include <com/sun/star/frame/XModel.hpp>
51 #include <com/sun/star/frame/XFrameLoader.hpp>
52 #include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
53 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
54 #include <com/sun/star/frame/FrameLoaderFactory.hpp>
55 #include <com/sun/star/frame/ContentHandlerFactory.hpp>
56 #include <com/sun/star/frame/DispatchResultState.hpp>
57 #include <com/sun/star/frame/FrameSearchFlag.hpp>
58 #include <com/sun/star/frame/XDispatchProvider.hpp>
59 #include <com/sun/star/lang/IllegalArgumentException.hpp>
60 #include <com/sun/star/lang/XInitialization.hpp>
61 #include <com/sun/star/lang/DisposedException.hpp>
62 #include <com/sun/star/io/XInputStream.hpp>
63 #include <com/sun/star/task/XInteractionHandler.hpp>
64 #include <com/sun/star/task/ErrorCodeRequest.hpp>
65 #include <com/sun/star/task/InteractionHandler.hpp>
66 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
67 #include <com/sun/star/task/XStatusIndicator.hpp>
68 #include <com/sun/star/uno/RuntimeException.hpp>
69 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
70 #include <com/sun/star/util/CloseVetoException.hpp>
71 #include <com/sun/star/util/URLTransformer.hpp>
72 #include <com/sun/star/util/XURLTransformer.hpp>
73 #include <com/sun/star/util/XCloseable.hpp>
74 #include <com/sun/star/util/XModifiable.hpp>
76 #include <utility>
77 #include <vcl/window.hxx>
78 #include <vcl/wrkwin.hxx>
79 #include <vcl/syswin.hxx>
81 #include <toolkit/helper/vclunohelper.hxx>
82 #include <unotools/moduleoptions.hxx>
83 #include <svtools/sfxecode.hxx>
84 #include <unotools/ucbhelper.hxx>
85 #include <comphelper/configurationhelper.hxx>
86 #include <rtl/bootstrap.hxx>
87 #include <sal/log.hxx>
88 #include <comphelper/errcode.hxx>
89 #include <vcl/svapp.hxx>
90 #include <cppuhelper/implbase.hxx>
91 #include <comphelper/profilezone.hxx>
92 #include <classes/taskcreator.hxx>
93 #include <tools/fileutil.hxx>
95 constexpr OUString PROP_TYPES = u"Types"_ustr;
96 constexpr OUString PROP_NAME = u"Name"_ustr;
98 namespace framework {
100 using namespace com::sun::star;
102 namespace {
104 class LoadEnvListener : public ::cppu::WeakImplHelper< css::frame::XLoadEventListener ,
105 css::frame::XDispatchResultListener >
107 private:
108 std::mutex m_mutex;
109 bool m_bWaitingResult;
110 LoadEnv* m_pLoadEnv;
112 public:
114 explicit LoadEnvListener(LoadEnv* pLoadEnv)
115 : m_bWaitingResult(true)
116 , m_pLoadEnv(pLoadEnv)
120 // frame.XLoadEventListener
121 virtual void SAL_CALL loadFinished(const css::uno::Reference< css::frame::XFrameLoader >& xLoader) override;
123 virtual void SAL_CALL loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >& xLoader) override;
125 // frame.XDispatchResultListener
126 virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent& aEvent) override;
128 // lang.XEventListener
129 virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
134 LoadEnv::LoadEnv(css::uno::Reference< css::uno::XComponentContext > xContext)
135 : m_xContext(std::move(xContext))
136 , m_nSearchFlags(0)
137 , m_eFeature(LoadEnvFeatures::NONE)
138 , m_eContentType(E_UNSUPPORTED_CONTENT)
139 , m_bCloseFrameOnError(false)
140 , m_bReactivateControllerOnError(false)
141 , m_bLoaded( false )
145 LoadEnv::~LoadEnv()
149 css::uno::Reference< css::lang::XComponent > LoadEnv::loadComponentFromURL(const css::uno::Reference< css::frame::XComponentLoader >& xLoader,
150 const css::uno::Reference< css::uno::XComponentContext >& xContext ,
151 const OUString& sURL ,
152 const OUString& sTarget,
153 sal_Int32 nSearchFlags ,
154 const css::uno::Sequence< css::beans::PropertyValue >& lArgs )
156 css::uno::Reference< css::lang::XComponent > xComponent;
157 comphelper::ProfileZone aZone("loadComponentFromURL");
161 LoadEnv aEnv(xContext);
162 LoadEnvFeatures loadEnvFeatures = LoadEnvFeatures::WorkWithUI;
163 // tdf#118238 Only disable UI interaction when loading as hidden
164 if (comphelper::NamedValueCollection::get(lArgs, u"Hidden") == uno::Any(true) || Application::IsHeadlessModeEnabled())
165 loadEnvFeatures = LoadEnvFeatures::NONE;
167 aEnv.startLoading(sURL,
168 lArgs,
169 css::uno::Reference< css::frame::XFrame >(xLoader, css::uno::UNO_QUERY),
170 sTarget,
171 nSearchFlags,
172 loadEnvFeatures);
173 aEnv.waitWhileLoading(); // wait for ever!
175 xComponent = aEnv.getTargetComponent();
177 catch(const LoadEnvException& ex)
179 switch(ex.m_nID)
181 case LoadEnvException::ID_INVALID_MEDIADESCRIPTOR:
182 throw css::lang::IllegalArgumentException(
183 u"Optional list of arguments seem to be corrupted."_ustr, xLoader, 4);
185 case LoadEnvException::ID_UNSUPPORTED_CONTENT:
186 throw css::lang::IllegalArgumentException(
187 "Unsupported URL <" + sURL + ">: \"" + ex.m_sMessage + "\"",
188 xLoader, 1);
190 default:
191 SAL_WARN(
192 "fwk.loadenv",
193 "caught LoadEnvException " << +ex.m_nID << " \""
194 << ex.m_sMessage << "\""
195 << (ex.m_exOriginal.has<css::uno::Exception>()
196 ? (", " + ex.m_exOriginal.getValueTypeName() + " \""
197 + (ex.m_exOriginal.get<css::uno::Exception>().
198 Message)
199 + "\"")
200 : OUString())
201 << " while loading <" << sURL << ">");
202 xComponent.clear();
203 break;
207 // if AbortOnLoadFailure is set and we couldn't load the document, assert, intended for use with crashtesting to
208 // detect when we export something we can't import
209 assert(xComponent.is() || comphelper::NamedValueCollection::get(lArgs, u"AbortOnLoadFailure") != uno::Any(true));
211 return xComponent;
214 namespace {
216 utl::MediaDescriptor addModelArgs(const uno::Sequence<beans::PropertyValue>& rDescriptor)
218 utl::MediaDescriptor rResult(rDescriptor);
219 uno::Reference<frame::XModel> xModel(rResult.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MODEL, uno::Reference<frame::XModel>()));
221 if (xModel.is())
223 utl::MediaDescriptor aModelArgs(xModel->getArgs());
224 utl::MediaDescriptor::iterator pIt = aModelArgs.find( utl::MediaDescriptor::PROP_MACROEXECUTIONMODE);
225 if (pIt != aModelArgs.end())
226 rResult[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE] = pIt->second;
229 return rResult;
234 void LoadEnv::startLoading(const OUString& sURL, const uno::Sequence<beans::PropertyValue>& lMediaDescriptor,
235 const uno::Reference<frame::XFrame>& xBaseFrame, const OUString& sTarget,
236 sal_Int32 nSearchFlags, LoadEnvFeatures eFeature)
238 osl::MutexGuard g(m_mutex);
240 // Handle still running processes!
241 if (m_xAsynchronousJob.is())
242 throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
244 // take over all new parameters.
245 m_xTargetFrame.clear();
246 m_xBaseFrame = xBaseFrame;
247 m_lMediaDescriptor = addModelArgs(lMediaDescriptor);
248 m_sTarget = sTarget;
249 m_nSearchFlags = nSearchFlags;
250 m_eFeature = eFeature;
251 m_eContentType = E_UNSUPPORTED_CONTENT;
252 m_bCloseFrameOnError = false;
253 m_bReactivateControllerOnError = false;
254 m_bLoaded = false;
256 OUString aRealURL;
257 if (!officecfg::Office::Common::Load::DetectWebDAVRedirection::get()
258 || !tools::IsMappedWebDAVPath(sURL, &aRealURL))
259 aRealURL = sURL;
261 // try to find out, if it's really a content, which can be loaded or must be "handled"
262 // We use a default value for this in-parameter. Then we have to start a complex check method
263 // internally. But if this check was already done outside it can be suppressed to perform
264 // the load request. We take over the result then!
265 m_eContentType = LoadEnv::classifyContent(aRealURL, lMediaDescriptor);
266 if (m_eContentType == E_UNSUPPORTED_CONTENT)
267 throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT, u"from LoadEnv::startLoading"_ustr);
269 // make URL part of the MediaDescriptor
270 // It doesn't matter if it is already an item of it.
271 // It must be the same value... so we can overwrite it :-)
272 m_lMediaDescriptor[utl::MediaDescriptor::PROP_URL] <<= aRealURL;
274 // parse it - because some following code require that
275 m_aURL.Complete = aRealURL;
276 uno::Reference<util::XURLTransformer> xParser(util::URLTransformer::create(m_xContext));
277 xParser->parseStrict(m_aURL);
279 // BTW: Split URL and JumpMark ...
280 // Because such mark is an explicit value of the media descriptor!
281 if (!m_aURL.Mark.isEmpty())
282 m_lMediaDescriptor[utl::MediaDescriptor::PROP_JUMPMARK] <<= m_aURL.Mark;
284 // By the way: remove the old and deprecated value "FileName" from the descriptor!
285 utl::MediaDescriptor::iterator pIt = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FILENAME);
286 if (pIt != m_lMediaDescriptor.end())
287 m_lMediaDescriptor.erase(pIt);
289 // patch the MediaDescriptor, so it fulfil the outside requirements
290 // Means especially items like e.g. UI InteractionHandler, Status Indicator,
291 // MacroExecutionMode, etc.
293 /*TODO progress is bound to a frame ... How can we set it here? */
295 // UI mode
296 const bool bUIMode =
297 (m_eFeature & LoadEnvFeatures::WorkWithUI) &&
298 !m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false) &&
299 !m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW, false);
301 if( comphelper::LibreOfficeKit::isActive() &&
302 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_SILENT, false))
304 rtl::Reference<QuietInteraction> pQuietInteraction = new QuietInteraction();
305 uno::Reference<task::XInteractionHandler> xInteractionHandler(pQuietInteraction);
306 m_lMediaDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER] <<= xInteractionHandler;
309 initializeUIDefaults(m_xContext, m_lMediaDescriptor, bUIMode, &m_pQuietInteraction);
311 start();
314 void LoadEnv::initializeUIDefaults( const css::uno::Reference< css::uno::XComponentContext >& i_rxContext,
315 utl::MediaDescriptor& io_lMediaDescriptor, const bool i_bUIMode,
316 rtl::Reference<QuietInteraction>* o_ppQuietInteraction )
318 css::uno::Reference< css::task::XInteractionHandler > xInteractionHandler;
319 sal_Int16 nMacroMode;
320 sal_Int16 nUpdateMode;
322 if ( i_bUIMode )
324 nMacroMode = css::document::MacroExecMode::USE_CONFIG;
325 nUpdateMode = css::document::UpdateDocMode::ACCORDING_TO_CONFIG;
328 // tdf#154308 At least for the case the document is launched from the StartCenter, put that StartCenter as the
329 // parent for any dialogs that may appear during typedetection (once load starts a permanent frame will be set
330 // anyway and used as dialog parent, which will be this one if the startcenter was running)
331 css::uno::Reference<css::frame::XFramesSupplier> xSupplier = css::frame::Desktop::create(i_rxContext);
332 FrameListAnalyzer aTasksAnalyzer(xSupplier, css::uno::Reference<css::frame::XFrame>(), FrameAnalyzerFlags::BackingComponent);
333 css::uno::Reference<css::awt::XWindow> xDialogParent(aTasksAnalyzer.m_xBackingComponent ?
334 aTasksAnalyzer.m_xBackingComponent->getContainerWindow() :
335 nullptr);
337 xInteractionHandler.set( css::task::InteractionHandler::createWithParent(i_rxContext, xDialogParent), css::uno::UNO_QUERY_THROW );
339 catch(const css::uno::RuntimeException&) {throw;}
340 catch(const css::uno::Exception& ) { }
342 // hidden mode
343 else
345 nMacroMode = css::document::MacroExecMode::NEVER_EXECUTE;
346 nUpdateMode = css::document::UpdateDocMode::NO_UPDATE;
347 rtl::Reference<QuietInteraction> pQuietInteraction = new QuietInteraction();
348 xInteractionHandler = pQuietInteraction.get();
349 if ( o_ppQuietInteraction != nullptr )
351 *o_ppQuietInteraction = std::move(pQuietInteraction);
355 if ( xInteractionHandler.is() )
357 if( io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_INTERACTIONHANDLER) == io_lMediaDescriptor.end() )
359 io_lMediaDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER] <<= xInteractionHandler;
361 if( io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER) == io_lMediaDescriptor.end() )
363 io_lMediaDescriptor[utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER] <<= xInteractionHandler;
367 if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_MACROEXECUTIONMODE) == io_lMediaDescriptor.end())
368 io_lMediaDescriptor[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE] <<= nMacroMode;
370 if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_UPDATEDOCMODE) == io_lMediaDescriptor.end())
371 io_lMediaDescriptor[utl::MediaDescriptor::PROP_UPDATEDOCMODE] <<= nUpdateMode;
374 void LoadEnv::start()
376 // SAFE ->
378 osl::MutexGuard aReadLock(m_mutex);
380 // Handle still running processes!
381 if (m_xAsynchronousJob.is())
382 throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
384 // content can not be loaded or handled
385 // check "classifyContent()" failed before ...
386 if (m_eContentType == E_UNSUPPORTED_CONTENT)
387 throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT,
388 u"from LoadEnv::start"_ustr);
390 // <- SAFE
392 // detect its type/filter etc.
393 // This information will be available by the
394 // used descriptor member afterwards and is needed
395 // for all following operations!
396 // Note: An exception will be thrown, in case operation was not successfully ...
397 if (m_eContentType != E_CAN_BE_SET)/* Attention: special feature to set existing component on a frame must ignore type detection! */
398 impl_detectTypeAndFilter();
400 // start loading the content...
401 // Attention: Don't check m_eContentType deeper then UNSUPPORTED/SUPPORTED!
402 // Because it was made in the easiest way... may a flat detection was made only.
403 // And such simple detection can fail sometimes .-)
404 // Use another strategy here. Try it and let it run into the case "loading not possible".
405 bool bStarted = false;
406 if (
407 (m_eFeature & LoadEnvFeatures::AllowContentHandler) &&
408 (m_eContentType != E_CAN_BE_SET ) /* Attention: special feature to set existing component on a frame must ignore type detection! */
411 bStarted = impl_handleContent();
414 if (!bStarted)
415 bStarted = impl_loadContent();
417 // not started => general error
418 // We can't say - what was the reason for.
419 if (!bStarted)
420 throw LoadEnvException(
421 LoadEnvException::ID_GENERAL_ERROR, u"not started"_ustr);
424 /*-----------------------------------------------
425 TODO
426 First draft does not implement timeout using [ms].
427 Current implementation counts yield calls only ...
428 -----------------------------------------------*/
429 bool LoadEnv::waitWhileLoading(sal_uInt32 nTimeout)
431 // Because it's not a good idea to block the main thread
432 // (and we can't be sure that we are currently not used inside the
433 // main thread!), we can't use conditions here really. We must yield
434 // in an intelligent manner :-)
436 sal_Int32 nTime = nTimeout;
437 while(!Application::IsQuit())
439 // SAFE -> ------------------------------
441 osl::MutexGuard aReadLock1(m_mutex);
442 if (!m_xAsynchronousJob.is())
443 break;
445 // <- SAFE ------------------------------
447 Application::Yield();
449 // forever!
450 if (nTimeout==0)
451 continue;
453 // timed out?
454 --nTime;
455 if (nTime<1)
456 break;
459 osl::MutexGuard g(m_mutex);
460 return !m_xAsynchronousJob.is();
463 css::uno::Reference< css::lang::XComponent > LoadEnv::getTargetComponent() const
465 osl::MutexGuard g(m_mutex);
467 if (!m_xTargetFrame.is())
468 return css::uno::Reference< css::lang::XComponent >();
470 css::uno::Reference< css::frame::XController > xController = m_xTargetFrame->getController();
471 if (!xController.is())
472 return m_xTargetFrame->getComponentWindow();
474 css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
475 if (!xModel.is())
476 return xController;
478 return xModel;
481 void SAL_CALL LoadEnvListener::loadFinished(const css::uno::Reference< css::frame::XFrameLoader >&)
483 std::unique_lock g(m_mutex);
484 if (m_bWaitingResult)
485 m_pLoadEnv->impl_setResult(true);
486 m_bWaitingResult = false;
489 void SAL_CALL LoadEnvListener::loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >&)
491 std::unique_lock g(m_mutex);
492 if (m_bWaitingResult)
493 m_pLoadEnv->impl_setResult(false);
494 m_bWaitingResult = false;
497 void SAL_CALL LoadEnvListener::dispatchFinished(const css::frame::DispatchResultEvent& aEvent)
499 std::unique_lock g(m_mutex);
501 if (!m_bWaitingResult)
502 return;
504 switch(aEvent.State)
506 case css::frame::DispatchResultState::FAILURE :
507 m_pLoadEnv->impl_setResult(false);
508 break;
510 case css::frame::DispatchResultState::SUCCESS :
511 m_pLoadEnv->impl_setResult(false);
512 break;
514 case css::frame::DispatchResultState::DONTKNOW :
515 m_pLoadEnv->impl_setResult(false);
516 break;
518 m_bWaitingResult = false;
521 void SAL_CALL LoadEnvListener::disposing(const css::lang::EventObject&)
523 std::unique_lock g(m_mutex);
524 if (m_bWaitingResult)
525 m_pLoadEnv->impl_setResult(false);
526 m_bWaitingResult = false;
529 void LoadEnv::impl_setResult(bool bResult)
531 osl::MutexGuard g(m_mutex);
533 m_bLoaded = bResult;
535 impl_reactForLoadingState();
537 // clearing of this reference will unblock waitWhileLoading()!
538 // So we must be sure, that loading process was really finished.
539 // => do it as last operation of this method ...
540 m_xAsynchronousJob.clear();
543 /*-----------------------------------------------
544 TODO: Is it a good idea to change Sequence<>
545 parameter to stl-adapter?
546 -----------------------------------------------*/
547 LoadEnv::EContentType LoadEnv::classifyContent(const OUString& sURL ,
548 const css::uno::Sequence< css::beans::PropertyValue >& lMediaDescriptor)
551 // (i) Filter some special well known URL protocols,
552 // which can not be handled or loaded in general.
553 // Of course an empty URL must be ignored here too.
554 // Note: These URL schemata are fix and well known ...
555 // But there can be some additional ones, which was not
556 // defined at implementation time of this class :-(
557 // So we have to make sure, that the following code
558 // can detect such protocol schemata too :-)
561 (sURL.isEmpty() ) ||
562 (ProtocolCheck::isProtocol(sURL,EProtocol::Uno )) ||
563 (ProtocolCheck::isProtocol(sURL,EProtocol::Slot )) ||
564 (ProtocolCheck::isProtocol(sURL,EProtocol::Macro )) ||
565 (ProtocolCheck::isProtocol(sURL,EProtocol::Service)) ||
566 (ProtocolCheck::isProtocol(sURL,EProtocol::MailTo )) ||
567 (ProtocolCheck::isProtocol(sURL,EProtocol::News ))
570 return E_UNSUPPORTED_CONTENT;
573 // (ii) Some special URLs indicates a given input stream,
574 // a full featured document model directly or
575 // specify a request for opening an empty document.
576 // Such contents are loadable in general.
577 // But we have to check, if the media descriptor contains
578 // all needed resources. If they are missing - the following
579 // load request will fail.
581 /* Attention: The following code can't work on such special URLs!
582 It should not break the office... but it makes no sense
583 to start expensive object creations and complex search
584 algorithm if it's clear, that such URLs must be handled
585 in a special way .-)
588 // creation of new documents
589 if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateFactory))
590 return E_CAN_BE_LOADED;
592 // using of an existing input stream
593 utl::MediaDescriptor stlMediaDescriptor(lMediaDescriptor);
594 utl::MediaDescriptor::const_iterator pIt;
595 if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateStream))
597 pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_INPUTSTREAM);
598 css::uno::Reference< css::io::XInputStream > xStream;
599 if (pIt != stlMediaDescriptor.end())
600 pIt->second >>= xStream;
601 if (xStream.is())
602 return E_CAN_BE_LOADED;
603 SAL_INFO("fwk.loadenv", "LoadEnv::classifyContent(): loading from stream with right URL but invalid stream detected");
604 return E_UNSUPPORTED_CONTENT;
607 // using of a full featured document
608 if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateObject))
610 pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_MODEL);
611 css::uno::Reference< css::frame::XModel > xModel;
612 if (pIt != stlMediaDescriptor.end())
613 pIt->second >>= xModel;
614 if (xModel.is())
615 return E_CAN_BE_SET;
616 SAL_INFO("fwk.loadenv", "LoadEnv::classifyContent(): loading with object with right URL but invalid object detected");
617 return E_UNSUPPORTED_CONTENT;
620 // following operations can work on an internal type name only :-(
621 const css::uno::Reference< css::uno::XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
622 css::uno::Reference< css::document::XTypeDetection > xDetect(
623 xContext->getServiceManager()->createInstanceWithContext(
624 u"com.sun.star.document.TypeDetection"_ustr, xContext),
625 css::uno::UNO_QUERY_THROW);
627 OUString sType = xDetect->queryTypeByURL(sURL);
629 css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory;
630 css::uno::Reference< css::container::XEnumeration > xSet;
632 // (iii) If a FrameLoader service (or at least
633 // a Filter) can be found, which supports
634 // this URL - it must be a loadable content.
635 // Because both items are registered for types
636 // it's enough to check for frame loaders only.
637 // Most of our filters are handled by our global
638 // default loader. But there exist some specialized
639 // loader, which does not work on top of filters!
640 // So it's not enough to search on the filter configuration.
641 // Further it's not enough to search for types!
642 // Because there exist some types, which are referenced by
643 // other objects... but neither by filters nor frame loaders!
644 css::uno::Sequence< OUString > lTypesReg { sType };
645 css::uno::Sequence< css::beans::NamedValue > lQuery
647 css::beans::NamedValue(PROP_TYPES, css::uno::Any(lTypesReg))
650 xLoaderFactory = css::frame::FrameLoaderFactory::create(xContext);
651 xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
652 // at least one registered frame loader is enough!
653 if (xSet->hasMoreElements())
654 return E_CAN_BE_LOADED;
656 // (iv) Some URL protocols are supported by special services.
657 // E.g. ContentHandler.
658 // Such contents can be handled ... but not loaded.
660 xLoaderFactory = css::frame::ContentHandlerFactory::create(xContext);
661 xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
662 // at least one registered content handler is enough!
663 if (xSet->hasMoreElements())
664 return E_CAN_BE_HANDLED;
666 // (v) Last but not least the UCB is used inside office to
667 // load contents. He has a special configuration to know
668 // which URL schemata can be used inside office.
669 css::uno::Reference< css::ucb::XUniversalContentBroker > xUCB(css::ucb::UniversalContentBroker::create(xContext));
670 if (xUCB->queryContentProvider(sURL).is())
671 return E_CAN_BE_LOADED;
673 // (TODO) At this point, we have no idea .-)
674 // But it seems to be better, to break all
675 // further requests for this URL. Otherwise
676 // we can run into some trouble.
677 return E_UNSUPPORTED_CONTENT;
680 namespace {
682 bool queryOrcusTypeAndFilter(const uno::Sequence<beans::PropertyValue>& rDescriptor, OUString& rType, OUString& rFilter)
684 OUString aURL;
685 sal_Int32 nSize = rDescriptor.getLength();
686 for (sal_Int32 i = 0; i < nSize; ++i)
688 const beans::PropertyValue& rProp = rDescriptor[i];
689 if (rProp.Name == "URL")
691 rProp.Value >>= aURL;
692 break;
696 if (aURL.isEmpty() || o3tl::equalsIgnoreAsciiCase(aURL.subView(0,8), u"private:"))
697 return false;
699 // TODO : Type must be set to be generic_Text (or any other type that
700 // exists) in order to find a usable loader. Exploit it as a temporary
701 // hack.
703 // depending on the experimental mode
704 if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
706 return false;
709 OUString aUseOrcus;
710 rtl::Bootstrap::get(u"LIBO_USE_ORCUS"_ustr, aUseOrcus);
711 bool bUseOrcus = (aUseOrcus == "YES");
713 if (!bUseOrcus)
714 return false;
716 if (aURL.endsWith(".xlsx"))
718 rType = "generic_Text";
719 rFilter = "xlsx";
720 return true;
722 else if (aURL.endsWith(".ods"))
724 rType = "generic_Text";
725 rFilter = "ods";
726 return true;
728 else if (aURL.endsWith(".csv"))
730 rType = "generic_Text";
731 rFilter = "csv";
732 return true;
735 return false;
740 void LoadEnv::impl_detectTypeAndFilter()
742 static const sal_Int32 FILTERFLAG_TEMPLATEPATH = 16;
744 // SAFE ->
745 osl::ClearableMutexGuard aReadLock(m_mutex);
747 // Attention: Because our stl media descriptor is a copy of a uno sequence
748 // we can't use as an in/out parameter here. Copy it before and don't forget to
749 // update structure afterwards again!
750 css::uno::Sequence< css::beans::PropertyValue > lDescriptor = m_lMediaDescriptor.getAsConstPropertyValueList();
751 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
753 aReadLock.clear();
754 // <- SAFE
756 OUString sType, sFilter;
758 if (queryOrcusTypeAndFilter(lDescriptor, sType, sFilter) && !sType.isEmpty() && !sFilter.isEmpty())
760 // SAFE ->
761 osl::MutexGuard aWriteLock(m_mutex);
763 // Orcus type detected. Skip the normal type detection process.
764 m_lMediaDescriptor << lDescriptor;
765 m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME] <<= sType;
766 m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= sFilter;
767 m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERPROVIDER] <<= u"orcus"_ustr;
768 m_lMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTSERVICE] <<= u"com.sun.star.sheet.SpreadsheetDocument"_ustr;
769 return;
770 // <- SAFE
773 css::uno::Reference< css::document::XTypeDetection > xDetect(
774 xContext->getServiceManager()->createInstanceWithContext(
775 u"com.sun.star.document.TypeDetection"_ustr, xContext),
776 css::uno::UNO_QUERY_THROW);
777 sType = xDetect->queryTypeByDescriptor(lDescriptor, true); /*TODO should deep detection be able for enable/disable it from outside? */
779 // no valid content -> loading not possible
780 if (sType.isEmpty())
781 throw LoadEnvException(
782 LoadEnvException::ID_UNSUPPORTED_CONTENT, u"type detection failed"_ustr);
784 // SAFE ->
785 osl::ResettableMutexGuard aWriteLock(m_mutex);
787 // detection was successful => update the descriptor member of this class
788 m_lMediaDescriptor << lDescriptor;
789 m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME] <<= sType;
790 // Is there an already detected (may be preselected) filter?
791 // see below ...
792 sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME, OUString());
794 aWriteLock.clear();
795 // <- SAFE
797 // We do have potentially correct type, but the detection process was aborted.
798 if (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ABORTED, false))
799 throw LoadEnvException(
800 LoadEnvException::ID_UNSUPPORTED_CONTENT, u"type detection aborted"_ustr);
802 // But the type isn't enough. For loading sometimes we need more information.
803 // E.g. for our "_default" feature, where we recycle any frame which contains
804 // and "Untitled" document, we must know if the new document is based on a template!
805 // But this information is available as a filter property only.
806 // => We must try(!) to detect the right filter for this load request.
807 // On the other side ... if no filter is available .. ignore it.
808 // Then the type information must be enough.
809 if (sFilter.isEmpty())
811 // no -> try to find a preferred filter for the detected type.
812 // Don't forget to update the media descriptor.
813 css::uno::Reference< css::container::XNameAccess > xTypeCont(xDetect, css::uno::UNO_QUERY_THROW);
816 ::comphelper::SequenceAsHashMap lTypeProps(xTypeCont->getByName(sType));
817 sFilter = lTypeProps.getUnpackedValueOrDefault(u"PreferredFilter"_ustr, OUString());
818 if (!sFilter.isEmpty())
820 // SAFE ->
821 aWriteLock.reset();
822 m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= sFilter;
823 aWriteLock.clear();
824 // <- SAFE
827 catch(const css::container::NoSuchElementException&)
831 // check if the filter (if one exists) points to a template format filter.
832 // Then we have to add the property "AsTemplate".
833 // We need this information to decide afterwards if we can use a "recycle frame"
834 // for target "_default" or has to create a new one every time.
835 // On the other side we have to suppress that, if this property already exists
836 // and should trigger a special handling. Then the outside call of this method here,
837 // has to know, what he is doing .-)
839 bool bIsOwnTemplate = false;
840 if (!sFilter.isEmpty())
842 css::uno::Reference< css::container::XNameAccess > xFilterCont(xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext), css::uno::UNO_QUERY_THROW);
845 ::comphelper::SequenceAsHashMap lFilterProps(xFilterCont->getByName(sFilter));
846 sal_Int32 nFlags = lFilterProps.getUnpackedValueOrDefault(u"Flags"_ustr, sal_Int32(0));
847 bIsOwnTemplate = ((nFlags & FILTERFLAG_TEMPLATEPATH) == FILTERFLAG_TEMPLATEPATH);
849 catch(const css::container::NoSuchElementException&)
852 if (bIsOwnTemplate)
854 // SAFE ->
855 aWriteLock.reset();
856 // Don't overwrite external decisions! See comments before ...
857 utl::MediaDescriptor::const_iterator pAsTemplateItem = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_ASTEMPLATE);
858 if (pAsTemplateItem == m_lMediaDescriptor.end())
859 m_lMediaDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE] <<= true;
860 aWriteLock.clear();
861 // <- SAFE
865 bool LoadEnv::impl_handleContent()
867 // SAFE -> -----------------------------------
868 osl::ClearableMutexGuard aReadLock(m_mutex);
870 // the type must exist inside the descriptor ... otherwise this class is implemented wrong :-)
871 OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME, OUString());
872 if (sType.isEmpty())
873 throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
875 // convert media descriptor and URL to right format for later interface call!
876 css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
877 m_lMediaDescriptor >> lDescriptor;
878 css::util::URL aURL = m_aURL;
880 // get necessary container to query for a handler object
881 css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::ContentHandlerFactory::create(m_xContext);
883 aReadLock.clear();
884 // <- SAFE -----------------------------------
886 // query
887 css::uno::Sequence< OUString > lTypeReg { sType };
889 css::uno::Sequence< css::beans::NamedValue > lQuery { { PROP_TYPES, css::uno::Any(lTypeReg) } };
891 css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
892 while(xSet->hasMoreElements())
894 ::comphelper::SequenceAsHashMap lProps (xSet->nextElement());
895 OUString sHandler = lProps.getUnpackedValueOrDefault(PROP_NAME, OUString());
897 css::uno::Reference< css::frame::XNotifyingDispatch > xHandler;
900 xHandler.set(xLoaderFactory->createInstance(sHandler), css::uno::UNO_QUERY);
901 if (!xHandler.is())
902 continue;
904 catch(const css::uno::RuntimeException&)
905 { throw; }
906 catch(const css::uno::Exception&)
907 { continue; }
909 // SAFE -> -----------------------------------
910 osl::ClearableMutexGuard aWriteLock(m_mutex);
911 m_xAsynchronousJob = xHandler;
912 rtl::Reference<LoadEnvListener> xListener = new LoadEnvListener(this);
913 aWriteLock.clear();
914 // <- SAFE -----------------------------------
916 xHandler->dispatchWithNotification(aURL, lDescriptor, xListener);
918 return true;
921 return false;
924 bool LoadEnv::impl_furtherDocsAllowed()
926 // SAFE ->
927 osl::ResettableMutexGuard aReadLock(m_mutex);
928 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
929 aReadLock.clear();
930 // <- SAFE
932 bool bAllowed = true;
936 std::optional<sal_Int32> x(officecfg::Office::Common::Misc::MaxOpenDocuments::get());
938 // NIL means: count of allowed documents = infinite !
939 // => return true
940 if ( !x)
941 bAllowed = true;
942 else
944 sal_Int32 nMaxOpenDocuments(*x);
946 css::uno::Reference< css::frame::XFramesSupplier > xDesktop(
947 css::frame::Desktop::create(xContext),
948 css::uno::UNO_QUERY_THROW);
950 FrameListAnalyzer aAnalyzer(xDesktop,
951 css::uno::Reference< css::frame::XFrame >(),
952 FrameAnalyzerFlags::Help |
953 FrameAnalyzerFlags::BackingComponent |
954 FrameAnalyzerFlags::Hidden);
956 sal_Int32 nOpenDocuments = aAnalyzer.m_lOtherVisibleFrames.size();
957 bAllowed = (nOpenDocuments < nMaxOpenDocuments);
960 catch(const css::uno::Exception&)
961 { bAllowed = true; } // !! internal errors are no reason to disturb the office from opening documents .-)
963 if ( ! bAllowed )
965 // SAFE ->
966 aReadLock.reset();
967 css::uno::Reference< css::task::XInteractionHandler > xInteraction = m_lMediaDescriptor.getUnpackedValueOrDefault(
968 utl::MediaDescriptor::PROP_INTERACTIONHANDLER,
969 css::uno::Reference< css::task::XInteractionHandler >());
970 aReadLock.clear();
971 // <- SAFE
973 if (xInteraction.is())
975 css::uno::Any aInteraction;
977 rtl::Reference<comphelper::OInteractionAbort> pAbort = new comphelper::OInteractionAbort();
978 rtl::Reference<comphelper::OInteractionApprove> pApprove = new comphelper::OInteractionApprove();
980 css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations{
981 pAbort, pApprove
984 css::task::ErrorCodeRequest aErrorCode;
985 aErrorCode.ErrCode = sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED);
986 aInteraction <<= aErrorCode;
987 xInteraction->handle( InteractionRequest::CreateRequest(aInteraction, lContinuations) );
991 return bAllowed;
994 bool LoadEnv::impl_filterHasInteractiveDialog() const
996 //show the frame now so it can be the parent for any message dialogs shown during import
998 //unless (tdf#114648) an Interactive case such as the new database wizard
999 if (m_aURL.Arguments == "Interactive")
1000 return true;
1002 // unless (tdf#116277) it's the labels/business cards slave frame
1003 if (m_aURL.Arguments.indexOf("slot=") != -1)
1004 return true;
1006 OUString sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME, OUString());
1007 if (sFilter.isEmpty())
1008 return false;
1010 // unless (tdf#115683) the filter has a UIComponent
1011 OUString sUIComponent;
1012 css::uno::Reference<css::container::XNameAccess> xFilterCont(m_xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, m_xContext),
1013 css::uno::UNO_QUERY_THROW);
1016 ::comphelper::SequenceAsHashMap lFilterProps(xFilterCont->getByName(sFilter));
1017 sUIComponent = lFilterProps.getUnpackedValueOrDefault(u"UIComponent"_ustr, OUString());
1019 catch(const css::container::NoSuchElementException&)
1023 return !sUIComponent.isEmpty();
1026 bool LoadEnv::impl_loadContent()
1028 // SAFE -> -----------------------------------
1029 osl::ClearableMutexGuard aWriteLock(m_mutex);
1031 // search or create right target frame
1032 OUString sTarget = m_sTarget;
1033 if (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Default))
1035 m_xTargetFrame = impl_searchAlreadyLoaded();
1036 if (m_xTargetFrame.is())
1038 impl_setResult(true);
1039 return true;
1041 m_xTargetFrame = impl_searchRecycleTarget();
1044 if (! m_xTargetFrame.is())
1046 if (
1047 (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Blank )) ||
1048 (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Default))
1051 if (! impl_furtherDocsAllowed())
1052 return false;
1053 TaskCreator aCreator(m_xContext);
1054 m_xTargetFrame = aCreator.createTask(SPECIALTARGET_BLANK, m_lMediaDescriptor);
1055 m_bCloseFrameOnError = m_xTargetFrame.is();
1057 else
1059 sal_Int32 nSearchFlags = m_nSearchFlags & ~css::frame::FrameSearchFlag::CREATE;
1060 m_xTargetFrame = m_xBaseFrame->findFrame(sTarget, nSearchFlags);
1061 if (! m_xTargetFrame.is())
1063 if (! impl_furtherDocsAllowed())
1064 return false;
1065 m_xTargetFrame = m_xBaseFrame->findFrame(SPECIALTARGET_BLANK, 0);
1066 m_bCloseFrameOnError = m_xTargetFrame.is();
1071 // If we couldn't find a valid frame or the frame has no container window
1072 // we have to throw an exception.
1073 if (
1074 ( ! m_xTargetFrame.is() ) ||
1075 ( ! m_xTargetFrame->getContainerWindow().is() )
1077 throw LoadEnvException(LoadEnvException::ID_NO_TARGET_FOUND);
1079 css::uno::Reference< css::frame::XFrame > xTargetFrame = m_xTargetFrame;
1081 // Now we have a valid frame ... and type detection was already done.
1082 // We should apply the module dependent window position and size to the
1083 // frame window.
1084 impl_applyPersistentWindowState(xTargetFrame->getContainerWindow());
1086 // Don't forget to lock task for following load process. Otherwise it could die
1087 // during this operation runs by terminating the office or closing this task via api.
1088 // If we set this lock "close()" will return false and closing will be broken.
1089 // Attention: Don't forget to reset this lock again after finishing operation.
1090 // Otherwise task AND office couldn't die!!!
1091 // This includes gracefully handling of Exceptions (Runtime!) too ...
1092 // That's why we use a specialized guard, which will reset the lock
1093 // if it will be run out of scope.
1095 // Note further: ignore if this internal guard already contains a resource.
1096 // Might impl_searchRecycleTarget() set it before. But in case this impl-method wasn't used
1097 // and the target frame was new created ... this lock here must be set!
1098 css::uno::Reference< css::document::XActionLockable > xTargetLock(xTargetFrame, css::uno::UNO_QUERY);
1099 m_aTargetLock.setResource(xTargetLock);
1101 // Add status indicator to descriptor. Loader can show a progress then.
1102 // But don't do it, if loading should be hidden or preview is used...!
1103 // So we prevent our code against wrong using. Why?
1104 // It could be, that using of this progress could make trouble. e.g. He makes window visible...
1105 // but shouldn't do that. But if no indicator is available... nobody has a chance to do that!
1106 bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false);
1107 bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED, false);
1108 bool bPreview = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW, false);
1109 bool bStartPres = m_lMediaDescriptor.contains("StartPresentation");
1111 if (!bHidden && !bMinimized && !bPreview && !bStartPres)
1113 css::uno::Reference<css::task::XStatusIndicator> xProgress = m_lMediaDescriptor.getUnpackedValueOrDefault(
1114 utl::MediaDescriptor::PROP_STATUSINDICATOR, css::uno::Reference<css::task::XStatusIndicator>());
1115 if (!xProgress.is())
1117 // Note: it's an optional interface!
1118 css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xTargetFrame, css::uno::UNO_QUERY);
1119 if (xProgressFactory.is())
1121 xProgress = xProgressFactory->createStatusIndicator();
1122 if (xProgress.is())
1123 m_lMediaDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR] <<= xProgress;
1127 // Now that we have a target window into which we can load, reinit the interaction handler to have this
1128 // window as its parent for modal dialogs and ensure the window is visible
1129 css::uno::Reference< css::task::XInteractionHandler > xInteraction = m_lMediaDescriptor.getUnpackedValueOrDefault(
1130 utl::MediaDescriptor::PROP_INTERACTIONHANDLER,
1131 css::uno::Reference< css::task::XInteractionHandler >());
1132 css::uno::Reference<css::lang::XInitialization> xHandler(xInteraction, css::uno::UNO_QUERY);
1133 if (xHandler.is())
1135 css::uno::Reference<css::awt::XWindow> xWindow = xTargetFrame->getContainerWindow();
1136 uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
1138 {"Parent", uno::Any(xWindow)}
1139 }));
1140 xHandler->initialize(aArguments);
1141 //show the frame as early as possible to make it the parent of any message dialogs
1142 if (!impl_filterHasInteractiveDialog())
1144 impl_makeFrameWindowVisible(xWindow, shouldFocusAndToFront());
1145 m_bFocusedAndToFront = true; // no need to ask shouldFocusAndToFront second time
1150 // convert media descriptor and URL to right format for later interface call!
1151 css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
1152 m_lMediaDescriptor >> lDescriptor;
1153 OUString sURL = m_aURL.Complete;
1155 // try to locate any interested frame loader
1156 css::uno::Reference< css::uno::XInterface > xLoader = impl_searchLoader();
1157 css::uno::Reference< css::frame::XFrameLoader > xAsyncLoader(xLoader, css::uno::UNO_QUERY);
1158 css::uno::Reference< css::frame::XSynchronousFrameLoader > xSyncLoader (xLoader, css::uno::UNO_QUERY);
1160 if (xAsyncLoader.is())
1162 m_xAsynchronousJob = xAsyncLoader;
1163 rtl::Reference<LoadEnvListener> xListener = new LoadEnvListener(this);
1164 aWriteLock.clear();
1165 // <- SAFE -----------------------------------
1167 xAsyncLoader->load(xTargetFrame, sURL, lDescriptor, xListener);
1169 return true;
1171 else if (xSyncLoader.is())
1173 uno::Reference<beans::XPropertySet> xTargetFrameProps(xTargetFrame, uno::UNO_QUERY);
1174 if (xTargetFrameProps.is())
1176 // Set the URL on the frame itself, for the duration of the load, when it has no
1177 // controller.
1178 xTargetFrameProps->setPropertyValue(u"URL"_ustr, uno::Any(sURL));
1180 bool bResult = xSyncLoader->load(lDescriptor, xTargetFrame);
1181 // react for the result here, so the outside waiting
1182 // code can ask for it later.
1183 impl_setResult(bResult);
1184 // But the return value indicates a valid started(!) operation.
1185 // And that's true every time we reach this line :-)
1186 return true;
1189 aWriteLock.clear();
1190 // <- SAFE
1192 return false;
1195 css::uno::Reference< css::uno::XInterface > LoadEnv::impl_searchLoader()
1197 // SAFE -> -----------------------------------
1198 osl::ClearableMutexGuard aReadLock(m_mutex);
1200 // special mode to set an existing component on this frame
1201 // In such case the loader is fix. It must be the SFX based implementation,
1202 // which can create a view on top of such xModel components :-)
1203 if (m_eContentType == E_CAN_BE_SET)
1207 return css::frame::OfficeFrameLoader::create(m_xContext);
1209 catch(const css::uno::RuntimeException&)
1210 { throw; }
1211 catch(const css::uno::Exception&)
1213 throw LoadEnvException(LoadEnvException::ID_INVALID_ENVIRONMENT);
1216 // Otherwise...
1217 // We need this type information to locate a registered frame loader
1218 // Without such information we can't work!
1219 OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME, OUString());
1220 if (sType.isEmpty())
1221 throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
1223 // try to locate any interested frame loader
1224 css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::FrameLoaderFactory::create(m_xContext);
1226 aReadLock.clear();
1227 // <- SAFE -----------------------------------
1229 css::uno::Sequence< OUString > lTypesReg { sType };
1231 css::uno::Sequence< css::beans::NamedValue > lQuery { { PROP_TYPES, css::uno::Any(lTypesReg) } };
1233 css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
1234 while(xSet->hasMoreElements())
1238 // try everyone ...
1239 // Ignore any loader, which makes trouble :-)
1240 ::comphelper::SequenceAsHashMap lLoaderProps(xSet->nextElement());
1241 OUString sLoader = lLoaderProps.getUnpackedValueOrDefault(PROP_NAME, OUString());
1242 css::uno::Reference< css::uno::XInterface > xLoader = xLoaderFactory->createInstance(sLoader);
1243 if (xLoader.is())
1244 return xLoader;
1246 catch(const css::uno::RuntimeException&)
1247 { throw; }
1248 catch(const css::uno::Exception&)
1249 { continue; }
1252 return css::uno::Reference< css::uno::XInterface >();
1255 void LoadEnv::impl_jumpToMark(const css::uno::Reference< css::frame::XFrame >& xFrame,
1256 const css::util::URL& aURL )
1258 if (aURL.Mark.isEmpty())
1259 return;
1261 css::uno::Reference< css::frame::XDispatchProvider > xProvider(xFrame, css::uno::UNO_QUERY);
1262 if (! xProvider.is())
1263 return;
1265 // SAFE ->
1266 osl::ClearableMutexGuard aReadLock(m_mutex);
1267 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1268 aReadLock.clear();
1269 // <- SAFE
1271 css::util::URL aCmd;
1272 aCmd.Complete = ".uno:JumpToMark";
1274 css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(xContext));
1275 xParser->parseStrict(aCmd);
1277 css::uno::Reference< css::frame::XDispatch > xDispatcher = xProvider->queryDispatch(aCmd, SPECIALTARGET_SELF, 0);
1278 if (! xDispatcher.is())
1279 return;
1281 ::comphelper::SequenceAsHashMap lArgs;
1282 lArgs[u"Bookmark"_ustr] <<= aURL.Mark;
1283 xDispatcher->dispatch(aCmd, lArgs.getAsConstPropertyValueList());
1286 css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchAlreadyLoaded()
1288 osl::MutexGuard g(m_mutex);
1290 // such search is allowed for special requests only ...
1291 // or better it's not allowed for some requests in general :-)
1292 if (
1293 ( ! TargetHelper::matchSpecialTarget(m_sTarget, TargetHelper::ESpecialTarget::Default) ) ||
1294 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE , false) ||
1295 // (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN() , false) == sal_True) ||
1296 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW, false)
1299 return css::uno::Reference< css::frame::XFrame >();
1302 // check URL
1303 // May it's not useful to start expensive document search, if it
1304 // can fail only .. because we load from a stream or model directly!
1305 if (
1306 (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateStream )) ||
1307 (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateObject ))
1308 /*TODO should be private:factory here tested too? */
1311 return css::uno::Reference< css::frame::XFrame >();
1314 // otherwise - iterate through the tasks of the desktop container
1315 // to find out, which of them might contains the requested document
1316 css::uno::Reference< css::frame::XDesktop2 > xSupplier = css::frame::Desktop::create( m_xContext );
1317 css::uno::Reference< css::container::XIndexAccess > xTaskList = xSupplier->getFrames();
1319 if (!xTaskList.is())
1320 return css::uno::Reference< css::frame::XFrame >(); // task list can be empty!
1322 // Note: To detect if a document was already loaded before
1323 // we check URLs here only. But might the existing and the required
1324 // document has different versions! Then its URLs are the same...
1325 sal_Int16 nNewVersion = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION, sal_Int16(-1));
1327 // will be used to save the first hidden frame referring the searched model
1328 // Normally we are interested on visible frames... but if there is no such visible
1329 // frame we refer to any hidden frame also (but as fallback only).
1330 css::uno::Reference< css::frame::XFrame > xHiddenTask;
1331 css::uno::Reference< css::frame::XFrame > xTask;
1333 sal_Int32 count = xTaskList->getCount();
1334 for (sal_Int32 i=0; i<count; ++i)
1338 // locate model of task
1339 // Note: Without a model there is no chance to decide if
1340 // this task contains the searched document or not!
1341 xTaskList->getByIndex(i) >>= xTask;
1342 if (!xTask.is())
1343 continue;
1345 OUString sURL;
1346 css::uno::Reference< css::frame::XController > xController = xTask->getController();
1347 if (!xController.is())
1349 // If we have no controller, then perhaps there is a load in progress. The frame
1350 // itself has the URL in this case.
1351 uno::Reference<beans::XPropertySet> xTaskProps(xTask, uno::UNO_QUERY);
1352 if (xTaskProps.is())
1354 xTaskProps->getPropertyValue(u"URL"_ustr) >>= sURL;
1356 if (sURL.isEmpty())
1358 xTask.clear();
1359 continue;
1363 uno::Reference<frame::XModel> xModel;
1364 if (sURL.isEmpty())
1366 xModel = xController->getModel();
1367 if (!xModel.is())
1369 xTask.clear();
1370 continue;
1373 // don't check the complete URL here.
1374 // use its main part - ignore optional jumpmarks!
1375 sURL = xModel->getURL();
1377 if (!::utl::UCBContentHelper::EqualURLs( m_aURL.Main, sURL ))
1379 xTask.clear ();
1380 continue;
1383 // get the original load arguments from the current document
1384 // and decide if it's really the same then the one will be.
1385 // It must be visible and must use the same file revision ...
1386 // or must not have any file revision set (-1 == -1!)
1387 utl::MediaDescriptor lOldDocDescriptor;
1388 if (xModel.is())
1390 lOldDocDescriptor = xModel->getArgs();
1392 if (lOldDocDescriptor.getUnpackedValueOrDefault(
1393 utl::MediaDescriptor::PROP_VERSION, sal_Int32(-1))
1394 != nNewVersion)
1396 xTask.clear();
1397 continue;
1401 // Hidden frames are special.
1402 // They will be used as "last chance" if there is no visible frame pointing to the same model.
1403 // Safe the result but continue with current loop might be looking for other visible frames.
1404 bool bIsHidden = lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false);
1405 if ( bIsHidden && ! xHiddenTask.is() )
1407 xHiddenTask = xTask;
1408 xTask.clear ();
1409 continue;
1412 // We found a visible task pointing to the right model ...
1413 // Break search.
1414 break;
1416 catch(const css::uno::RuntimeException&)
1417 { throw; }
1418 catch(const css::uno::Exception&)
1419 { continue; }
1422 css::uno::Reference< css::frame::XFrame > xResult;
1423 if (xTask.is())
1424 xResult = std::move(xTask);
1425 else if (xHiddenTask.is())
1426 xResult = std::move(xHiddenTask);
1428 if (xResult.is())
1430 // Now we are sure, that this task includes the searched document.
1431 // It's time to activate it. As special feature we try to jump internally
1432 // if an optional jumpmark is given too.
1433 if (!m_aURL.Mark.isEmpty())
1434 impl_jumpToMark(xResult, m_aURL);
1437 return xResult;
1440 // static
1441 bool LoadEnv::impl_isFrameAlreadyUsedForLoading(const css::uno::Reference< css::frame::XFrame >& xFrame)
1443 css::uno::Reference< css::document::XActionLockable > xLock(xFrame, css::uno::UNO_QUERY);
1445 // ? no lock interface ?
1446 // Maybe it's an external written frame implementation :-(
1447 // Allowing using of it... but it can fail if it's not synchronized with our processes!
1448 if (!xLock.is())
1449 return false;
1451 // Otherwise we have to look for any other existing lock.
1452 return xLock->isActionLocked();
1455 css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchRecycleTarget()
1457 // SAFE -> ..................................
1458 osl::ClearableMutexGuard aReadLock(m_mutex);
1460 // The special backing mode frame will be recycled by definition!
1461 // It doesn't matter if somewhere wants to create a new view
1462 // or open a new untitled document...
1463 // The only exception from that - hidden frames!
1464 if (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false))
1465 return css::uno::Reference< css::frame::XFrame >();
1467 css::uno::Reference< css::frame::XFramesSupplier > xSupplier = css::frame::Desktop::create( m_xContext );
1468 FrameListAnalyzer aTasksAnalyzer(xSupplier, css::uno::Reference< css::frame::XFrame >(), FrameAnalyzerFlags::BackingComponent);
1469 if (aTasksAnalyzer.m_xBackingComponent.is())
1471 if (!impl_isFrameAlreadyUsedForLoading(aTasksAnalyzer.m_xBackingComponent))
1473 m_bReactivateControllerOnError = true;
1474 return aTasksAnalyzer.m_xBackingComponent;
1478 // These states indicates a wish for creation of a new view in general.
1479 if (
1480 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE , false) ||
1481 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW, false)
1484 return css::uno::Reference< css::frame::XFrame >();
1487 // On the other side some special URLs will open a new frame every time (expecting
1488 // they can use the backing-mode frame!)
1489 if (
1490 (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateFactory )) ||
1491 (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateStream )) ||
1492 (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateObject ))
1495 return css::uno::Reference< css::frame::XFrame >();
1498 // No backing frame! No special URL => recycle active task - if possible.
1499 // Means - if it does not already contains a modified document, or
1500 // use another office module.
1501 css::uno::Reference< css::frame::XFrame > xTask = xSupplier->getActiveFrame();
1503 // not a real error - but might a focus problem!
1504 if (!xTask.is())
1505 return css::uno::Reference< css::frame::XFrame >();
1507 // not a real error - may it's a view only
1508 css::uno::Reference< css::frame::XController > xController = xTask->getController();
1509 if (!xController.is())
1510 return css::uno::Reference< css::frame::XFrame >();
1512 // not a real error - may it's a db component instead of a full featured office document
1513 css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1514 if (!xModel.is())
1515 return css::uno::Reference< css::frame::XFrame >();
1517 // get some more information ...
1519 // A valid set URL means: there is already a location for this document.
1520 // => it was saved there or opened from there. Such Documents can not be used here.
1521 // We search for empty document ... created by a private:factory/ URL!
1522 if (xModel->getURL().getLength()>0)
1523 return css::uno::Reference< css::frame::XFrame >();
1525 // The old document must be unmodified ...
1526 css::uno::Reference< css::util::XModifiable > xModified(xModel, css::uno::UNO_QUERY);
1527 if (xModified->isModified())
1528 return css::uno::Reference< css::frame::XFrame >();
1530 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xTask->getContainerWindow());
1531 if (pWindow && pWindow->IsInModalMode())
1532 return css::uno::Reference< css::frame::XFrame >();
1534 // find out the application type of this document
1535 // We can recycle only documents, which uses the same application
1536 // then the new one.
1537 SvtModuleOptions::EFactory eOldApp = SvtModuleOptions::ClassifyFactoryByModel(xModel);
1538 SvtModuleOptions::EFactory eNewApp = SvtModuleOptions::ClassifyFactoryByURL (m_aURL.Complete, m_lMediaDescriptor.getAsConstPropertyValueList());
1540 aReadLock.clear();
1541 // <- SAFE ..................................
1543 if (eOldApp != eNewApp)
1544 return css::uno::Reference< css::frame::XFrame >();
1546 // OK this task seems to be usable for recycling
1547 // But we should mark it as such - means set an action lock.
1548 // Otherwise it would be used more than ones or will be destroyed
1549 // by a close() or terminate() request.
1550 // But if such lock already exist ... it means this task is used for
1551 // any other operation already. Don't use it then.
1552 if (impl_isFrameAlreadyUsedForLoading(xTask))
1553 return css::uno::Reference< css::frame::XFrame >();
1555 // OK - there is a valid target frame.
1556 // But may be it contains already a document.
1557 // Then we have to ask it, if it allows recycling of this frame .-)
1558 bool bReactivateOldControllerOnError = false;
1559 css::uno::Reference< css::frame::XController > xOldDoc = xTask->getController();
1560 if (xOldDoc.is())
1562 utl::MediaDescriptor lOldDocDescriptor(xModel->getArgs());
1564 // replaceable document
1565 if (!lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REPLACEABLE, false))
1566 return css::uno::Reference< css::frame::XFrame >();
1568 bReactivateOldControllerOnError = xOldDoc->suspend(true);
1569 if (! bReactivateOldControllerOnError)
1570 return css::uno::Reference< css::frame::XFrame >();
1573 // SAFE -> ..................................
1575 osl::MutexGuard aWriteLock(m_mutex);
1577 css::uno::Reference< css::document::XActionLockable > xLock(xTask, css::uno::UNO_QUERY);
1578 if (!m_aTargetLock.setResource(xLock))
1579 return css::uno::Reference< css::frame::XFrame >();
1581 m_bReactivateControllerOnError = bReactivateOldControllerOnError;
1583 // <- SAFE ..................................
1585 return xTask;
1588 void LoadEnv::impl_reactForLoadingState()
1590 /*TODO reset action locks */
1592 // SAFE -> ----------------------------------
1593 osl::ClearableMutexGuard aReadLock(m_mutex);
1595 if (m_bLoaded)
1597 // Bring the new loaded document to front (if allowed!).
1598 // Note: We show new created frames here only.
1599 // We don't hide already visible frames here ...
1600 css::uno::Reference< css::awt::XWindow > xWindow = m_xTargetFrame->getContainerWindow();
1601 bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false);
1602 bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED, false);
1603 bool bStartPres = m_lMediaDescriptor.contains("StartPresentation");
1605 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
1607 if (bMinimized)
1609 SolarMutexGuard aSolarGuard;
1610 // check for system window is necessary to guarantee correct pointer cast!
1611 if (pWindow && pWindow->IsSystemWindow())
1612 static_cast<WorkWindow*>(pWindow.get())->Minimize();
1614 else if (!bHidden && !bStartPres)
1616 // show frame ... if it's not still visible ...
1617 // But do nothing if it's already visible!
1618 impl_makeFrameWindowVisible(xWindow, !m_bFocusedAndToFront && shouldFocusAndToFront());
1621 if (pWindow)
1622 pWindow->FlashWindow();
1624 // Note: Only if an existing property "FrameName" is given by this media descriptor,
1625 // it should be used. Otherwise we should do nothing. May be the outside code has already
1626 // set a frame name on the target!
1627 utl::MediaDescriptor::const_iterator pFrameName = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FRAMENAME);
1628 if (pFrameName != m_lMediaDescriptor.end())
1630 OUString sFrameName;
1631 pFrameName->second >>= sFrameName;
1632 // Check the name again. e.g. "_default" isn't allowed.
1633 // On the other side "_beamer" is a valid name :-)
1634 if (TargetHelper::isValidNameForFrame(sFrameName))
1635 m_xTargetFrame->setName(sFrameName);
1638 else if (m_bReactivateControllerOnError)
1640 // Try to reactivate the old document (if any exists!)
1641 css::uno::Reference< css::frame::XController > xOldDoc = m_xTargetFrame->getController();
1642 // clear does not depend from reactivation state of a might existing old document!
1643 // We must make sure, that a might following getTargetComponent() call does not return
1644 // the old document!
1645 m_xTargetFrame.clear();
1646 if (xOldDoc.is())
1648 bool bReactivated = xOldDoc->suspend(false);
1649 if (!bReactivated)
1650 throw LoadEnvException(LoadEnvException::ID_COULD_NOT_REACTIVATE_CONTROLLER);
1651 m_bReactivateControllerOnError = false;
1654 else if (m_bCloseFrameOnError)
1656 // close empty frames
1657 css::uno::Reference< css::util::XCloseable > xCloseable (m_xTargetFrame, css::uno::UNO_QUERY);
1661 if (xCloseable.is())
1662 xCloseable->close(true);
1663 else if (m_xTargetFrame.is())
1664 m_xTargetFrame->dispose();
1666 catch(const css::util::CloseVetoException&)
1668 catch(const css::lang::DisposedException&)
1670 m_xTargetFrame.clear();
1673 // This max force an implicit closing of our target frame ...
1674 // e.g. in case close(sal_True) was called before and the frame
1675 // kill itself if our external use-lock is released here!
1676 // That's why we release this lock AFTER ALL OPERATIONS on this frame
1677 // are finished. The frame itself must handle then
1678 // this situation gracefully.
1679 m_aTargetLock.freeResource();
1681 // Last but not least :-)
1682 // We have to clear the current media descriptor.
1683 // Otherwise it hold a might existing stream open!
1684 m_lMediaDescriptor.clear();
1686 css::uno::Any aRequest;
1687 bool bThrow = false;
1688 if ( !m_bLoaded && m_pQuietInteraction.is() && m_pQuietInteraction->wasUsed() )
1690 aRequest = m_pQuietInteraction->getRequest();
1691 m_pQuietInteraction.clear();
1692 bThrow = true;
1695 aReadLock.clear();
1697 if (bThrow)
1699 if ( aRequest.isExtractableTo( ::cppu::UnoType< css::uno::Exception >::get() ) )
1700 throw LoadEnvException(
1701 LoadEnvException::ID_GENERAL_ERROR, u"interaction request"_ustr,
1702 aRequest);
1705 // <- SAFE ----------------------------------
1708 bool LoadEnv::shouldFocusAndToFront() const
1710 bool const preview(
1711 m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW, false));
1712 return !preview;
1715 // static
1716 void LoadEnv::impl_makeFrameWindowVisible(const css::uno::Reference< css::awt::XWindow >& xWindow ,
1717 bool bForceToFront)
1719 SolarMutexGuard aSolarGuard;
1720 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
1721 if ( !pWindow )
1722 return;
1724 if (pWindow->IsVisible() && bForceToFront)
1725 pWindow->ToTop( ToTopFlags::RestoreWhenMin | ToTopFlags::ForegroundTask );
1726 else
1727 pWindow->Show(true, bForceToFront ? ShowFlags::ForegroundTask : ShowFlags::NONE);
1730 void LoadEnv::impl_applyPersistentWindowState(const css::uno::Reference< css::awt::XWindow >& xWindow)
1732 // no window -> action not possible
1733 if (!xWindow.is())
1734 return;
1736 // window already visible -> do nothing! If we use a "recycle frame" for loading ...
1737 // the current position and size must be used.
1738 css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(xWindow, css::uno::UNO_QUERY);
1739 if (
1740 (xVisibleCheck.is() ) &&
1741 (xVisibleCheck->isVisible())
1743 return;
1745 // SOLAR SAFE ->
1747 SolarMutexGuard aSolarGuard1;
1749 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
1750 if (!pWindow)
1751 return;
1753 bool bSystemWindow = pWindow->IsSystemWindow();
1754 bool bWorkWindow = (pWindow->GetType() == WindowType::WORKWINDOW);
1756 if (!bSystemWindow && !bWorkWindow)
1757 return;
1759 // don't overwrite this special state!
1760 WorkWindow* pWorkWindow = static_cast<WorkWindow*>(pWindow.get());
1761 if (pWorkWindow->IsMinimized())
1762 return;
1764 // <- SOLAR SAFE
1766 // SAFE ->
1767 osl::ClearableMutexGuard aReadLock(m_mutex);
1769 // no filter -> no module -> no persistent window state
1770 OUString sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(
1771 utl::MediaDescriptor::PROP_FILTERNAME,
1772 OUString());
1773 if (sFilter.isEmpty())
1774 return;
1776 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1778 aReadLock.clear();
1779 // <- SAFE
1783 // retrieve the module name from the filter configuration
1784 css::uno::Reference< css::container::XNameAccess > xFilterCfg(
1785 xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext),
1786 css::uno::UNO_QUERY_THROW);
1787 ::comphelper::SequenceAsHashMap lProps (xFilterCfg->getByName(sFilter));
1788 OUString sModule = lProps.getUnpackedValueOrDefault(FILTER_PROPNAME_ASCII_DOCUMENTSERVICE, OUString());
1790 // get access to the configuration of this office module
1791 css::uno::Reference< css::container::XNameAccess > xModuleCfg(officecfg::Setup::Office::Factories::get());
1793 // read window state from the configuration
1794 // and apply it on the window.
1795 // Do nothing, if no configuration entry exists!
1796 OUString sWindowState;
1798 // Don't look for persistent window attributes when used through LibreOfficeKit
1799 if( !comphelper::LibreOfficeKit::isActive() )
1800 comphelper::ConfigurationHelper::readRelativeKey(xModuleCfg, sModule, u"ooSetupFactoryWindowAttributes"_ustr) >>= sWindowState;
1802 if (!sWindowState.isEmpty())
1804 // SOLAR SAFE ->
1805 SolarMutexGuard aSolarGuard;
1807 // We have to retrieve the window pointer again. Because nobody can guarantee
1808 // that the XWindow was not disposed in between .-)
1809 // But if we get a valid pointer we can be sure, that it's the system window pointer
1810 // we already checked and used before. Because nobody recycle the same uno reference for
1811 // a new internal c++ implementation ... hopefully .-))
1812 VclPtr<vcl::Window> pWindowCheck = VCLUnoHelper::GetWindow(xWindow);
1813 if (! pWindowCheck)
1814 return;
1816 SystemWindow* pSystemWindow = static_cast<SystemWindow*>(pWindowCheck.get());
1817 pSystemWindow->SetWindowState(sWindowState);
1818 // <- SOLAR SAFE
1821 catch(const css::uno::RuntimeException&)
1822 { throw; }
1823 catch(const css::uno::Exception&)
1827 } // namespace framework
1829 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */