summaryrefslogtreecommitdiffstats
path: root/framework/source/loadenv
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/loadenv')
-rw-r--r--framework/source/loadenv/loadenv.cxx1808
-rw-r--r--framework/source/loadenv/targethelper.cxx64
2 files changed, 1872 insertions, 0 deletions
diff --git a/framework/source/loadenv/loadenv.cxx b/framework/source/loadenv/loadenv.cxx
new file mode 100644
index 000000000..76116ad98
--- /dev/null
+++ b/framework/source/loadenv/loadenv.cxx
@@ -0,0 +1,1808 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <loadenv/loadenv.hxx>
+
+#include <loadenv/loadenvexception.hxx>
+#include <loadenv/targethelper.hxx>
+#include <framework/framelistanalyzer.hxx>
+
+#include <interaction/quietinteraction.hxx>
+#include <properties.h>
+#include <protocols.h>
+#include <services.h>
+#include <targets.h>
+#include <comphelper/interaction.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <framework/interaction.hxx>
+#include <comphelper/processfactory.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <officecfg/Setup.hxx>
+
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/document/XTypeDetection.hpp>
+#include <com/sun/star/document/XActionLockable.hpp>
+#include <com/sun/star/document/UpdateDocMode.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/OfficeFrameLoader.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XFrameLoader.hpp>
+#include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
+#include <com/sun/star/frame/XNotifyingDispatch.hpp>
+#include <com/sun/star/frame/FrameLoaderFactory.hpp>
+#include <com/sun/star/frame/ContentHandlerFactory.hpp>
+#include <com/sun/star/frame/DispatchResultState.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/task/ErrorCodeRequest.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/task/XStatusIndicatorFactory.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/ucb/UniversalContentBroker.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+
+#include <utility>
+#include <vcl/window.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/syswin.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <svtools/sfxecode.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <comphelper/configurationhelper.hxx>
+#include <rtl/bootstrap.hxx>
+#include <sal/log.hxx>
+#include <vcl/errcode.hxx>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/profilezone.hxx>
+#include <classes/taskcreator.hxx>
+#include <tools/fileutil.hxx>
+
+constexpr OUStringLiteral PROP_TYPES = u"Types";
+constexpr OUStringLiteral PROP_NAME = u"Name";
+
+namespace framework {
+
+using namespace com::sun::star;
+
+namespace {
+
+class LoadEnvListener : public ::cppu::WeakImplHelper< css::frame::XLoadEventListener ,
+ css::frame::XDispatchResultListener >
+{
+ private:
+ osl::Mutex m_mutex;
+ bool m_bWaitingResult;
+ LoadEnv* m_pLoadEnv;
+
+ public:
+
+ explicit LoadEnvListener(LoadEnv* pLoadEnv)
+ : m_bWaitingResult(true)
+ , m_pLoadEnv(pLoadEnv)
+ {
+ }
+
+ // frame.XLoadEventListener
+ virtual void SAL_CALL loadFinished(const css::uno::Reference< css::frame::XFrameLoader >& xLoader) override;
+
+ virtual void SAL_CALL loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >& xLoader) override;
+
+ // frame.XDispatchResultListener
+ virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent& aEvent) override;
+
+ // lang.XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
+};
+
+}
+
+LoadEnv::LoadEnv(css::uno::Reference< css::uno::XComponentContext > xContext)
+ : m_xContext(std::move(xContext))
+ , m_nSearchFlags(0)
+ , m_eFeature(LoadEnvFeatures::NONE)
+ , m_eContentType(E_UNSUPPORTED_CONTENT)
+ , m_bCloseFrameOnError(false)
+ , m_bReactivateControllerOnError(false)
+ , m_bLoaded( false )
+{
+}
+
+LoadEnv::~LoadEnv()
+{
+}
+
+css::uno::Reference< css::lang::XComponent > LoadEnv::loadComponentFromURL(const css::uno::Reference< css::frame::XComponentLoader >& xLoader,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext ,
+ const OUString& sURL ,
+ const OUString& sTarget,
+ sal_Int32 nSearchFlags ,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArgs )
+{
+ css::uno::Reference< css::lang::XComponent > xComponent;
+ comphelper::ProfileZone aZone("loadComponentFromURL");
+
+ try
+ {
+ LoadEnv aEnv(xContext);
+
+ LoadEnvFeatures loadEnvFeatures = LoadEnvFeatures::WorkWithUI;
+ // tdf#118238 Only disable UI interaction when loading as hidden
+ if (comphelper::NamedValueCollection::get(lArgs, u"Hidden") == uno::Any(true) || Application::IsHeadlessModeEnabled())
+ loadEnvFeatures = LoadEnvFeatures::NONE;
+
+ aEnv.startLoading(sURL,
+ lArgs,
+ css::uno::Reference< css::frame::XFrame >(xLoader, css::uno::UNO_QUERY),
+ sTarget,
+ nSearchFlags,
+ loadEnvFeatures);
+ aEnv.waitWhileLoading(); // wait for ever!
+
+ xComponent = aEnv.getTargetComponent();
+ }
+ catch(const LoadEnvException& ex)
+ {
+ switch(ex.m_nID)
+ {
+ case LoadEnvException::ID_INVALID_MEDIADESCRIPTOR:
+ throw css::lang::IllegalArgumentException(
+ "Optional list of arguments seem to be corrupted.", xLoader, 4);
+
+ case LoadEnvException::ID_UNSUPPORTED_CONTENT:
+ throw css::lang::IllegalArgumentException(
+ "Unsupported URL <" + sURL + ">: \"" + ex.m_sMessage + "\"",
+ xLoader, 1);
+
+ default:
+ SAL_WARN(
+ "fwk.loadenv",
+ "caught LoadEnvException " << +ex.m_nID << " \""
+ << ex.m_sMessage << "\""
+ << (ex.m_exOriginal.has<css::uno::Exception>()
+ ? (", " + ex.m_exOriginal.getValueTypeName() + " \""
+ + (ex.m_exOriginal.get<css::uno::Exception>().
+ Message)
+ + "\"")
+ : OUString())
+ << " while loading <" << sURL << ">");
+ xComponent.clear();
+ break;
+ }
+ }
+
+ return xComponent;
+}
+
+namespace {
+
+utl::MediaDescriptor addModelArgs(const uno::Sequence<beans::PropertyValue>& rDescriptor)
+{
+ utl::MediaDescriptor rResult(rDescriptor);
+ uno::Reference<frame::XModel> xModel(rResult.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MODEL, uno::Reference<frame::XModel>()));
+
+ if (xModel.is())
+ {
+ utl::MediaDescriptor aModelArgs(xModel->getArgs());
+ utl::MediaDescriptor::iterator pIt = aModelArgs.find( utl::MediaDescriptor::PROP_MACROEXECUTIONMODE);
+ if (pIt != aModelArgs.end())
+ rResult[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE] = pIt->second;
+ }
+
+ return rResult;
+}
+
+}
+
+void LoadEnv::startLoading(const OUString& sURL, const uno::Sequence<beans::PropertyValue>& lMediaDescriptor,
+ const uno::Reference<frame::XFrame>& xBaseFrame, const OUString& sTarget,
+ sal_Int32 nSearchFlags, LoadEnvFeatures eFeature)
+{
+ osl::MutexGuard g(m_mutex);
+
+ // Handle still running processes!
+ if (m_xAsynchronousJob.is())
+ throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
+
+ // take over all new parameters.
+ m_xTargetFrame.clear();
+ m_xBaseFrame = xBaseFrame;
+ m_lMediaDescriptor = addModelArgs(lMediaDescriptor);
+ m_sTarget = sTarget;
+ m_nSearchFlags = nSearchFlags;
+ m_eFeature = eFeature;
+ m_eContentType = E_UNSUPPORTED_CONTENT;
+ m_bCloseFrameOnError = false;
+ m_bReactivateControllerOnError = false;
+ m_bLoaded = false;
+
+ OUString aRealURL;
+ if (!officecfg::Office::Common::Load::DetectWebDAVRedirection::get()
+ || !tools::IsMappedWebDAVPath(sURL, &aRealURL))
+ aRealURL = sURL;
+
+ // try to find out, if it's really a content, which can be loaded or must be "handled"
+ // We use a default value for this in-parameter. Then we have to start a complex check method
+ // internally. But if this check was already done outside it can be suppressed to perform
+ // the load request. We take over the result then!
+ m_eContentType = LoadEnv::classifyContent(aRealURL, lMediaDescriptor);
+ if (m_eContentType == E_UNSUPPORTED_CONTENT)
+ throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT, "from LoadEnv::startLoading");
+
+ // make URL part of the MediaDescriptor
+ // It doesn't matter if it is already an item of it.
+ // It must be the same value... so we can overwrite it :-)
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_URL] <<= aRealURL;
+
+ // parse it - because some following code require that
+ m_aURL.Complete = aRealURL;
+ uno::Reference<util::XURLTransformer> xParser(util::URLTransformer::create(m_xContext));
+ xParser->parseStrict(m_aURL);
+
+ // BTW: Split URL and JumpMark ...
+ // Because such mark is an explicit value of the media descriptor!
+ if (!m_aURL.Mark.isEmpty())
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_JUMPMARK] <<= m_aURL.Mark;
+
+ // By the way: remove the old and deprecated value "FileName" from the descriptor!
+ utl::MediaDescriptor::iterator pIt = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FILENAME);
+ if (pIt != m_lMediaDescriptor.end())
+ m_lMediaDescriptor.erase(pIt);
+
+ // patch the MediaDescriptor, so it fulfil the outside requirements
+ // Means especially items like e.g. UI InteractionHandler, Status Indicator,
+ // MacroExecutionMode, etc.
+
+ /*TODO progress is bound to a frame ... How can we set it here? */
+
+ // UI mode
+ const bool bUIMode =
+ (m_eFeature & LoadEnvFeatures::WorkWithUI) &&
+ !m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false) &&
+ !m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW, false);
+
+ initializeUIDefaults(m_xContext, m_lMediaDescriptor, bUIMode, &m_pQuietInteraction);
+
+ start();
+}
+
+void LoadEnv::initializeUIDefaults( const css::uno::Reference< css::uno::XComponentContext >& i_rxContext,
+ utl::MediaDescriptor& io_lMediaDescriptor, const bool i_bUIMode,
+ rtl::Reference<QuietInteraction>* o_ppQuietInteraction )
+{
+ css::uno::Reference< css::task::XInteractionHandler > xInteractionHandler;
+ sal_Int16 nMacroMode;
+ sal_Int16 nUpdateMode;
+
+ if ( i_bUIMode )
+ {
+ nMacroMode = css::document::MacroExecMode::USE_CONFIG;
+ nUpdateMode = css::document::UpdateDocMode::ACCORDING_TO_CONFIG;
+ try
+ {
+ xInteractionHandler.set( css::task::InteractionHandler::createWithParent( i_rxContext, nullptr ), css::uno::UNO_QUERY_THROW );
+ }
+ catch(const css::uno::RuntimeException&) {throw;}
+ catch(const css::uno::Exception& ) { }
+ }
+ // hidden mode
+ else
+ {
+ nMacroMode = css::document::MacroExecMode::NEVER_EXECUTE;
+ nUpdateMode = css::document::UpdateDocMode::NO_UPDATE;
+ rtl::Reference<QuietInteraction> pQuietInteraction = new QuietInteraction();
+ xInteractionHandler = pQuietInteraction.get();
+ if ( o_ppQuietInteraction != nullptr )
+ {
+ *o_ppQuietInteraction = pQuietInteraction;
+ }
+ }
+
+ if ( xInteractionHandler.is() )
+ {
+ if( io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_INTERACTIONHANDLER) == io_lMediaDescriptor.end() )
+ {
+ io_lMediaDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER] <<= xInteractionHandler;
+ }
+ if( io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER) == io_lMediaDescriptor.end() )
+ {
+ io_lMediaDescriptor[utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER] <<= xInteractionHandler;
+ }
+ }
+
+ if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_MACROEXECUTIONMODE) == io_lMediaDescriptor.end())
+ io_lMediaDescriptor[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE] <<= nMacroMode;
+
+ if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_UPDATEDOCMODE) == io_lMediaDescriptor.end())
+ io_lMediaDescriptor[utl::MediaDescriptor::PROP_UPDATEDOCMODE] <<= nUpdateMode;
+}
+
+void LoadEnv::start()
+{
+ // SAFE ->
+ {
+ osl::MutexGuard aReadLock(m_mutex);
+
+ // Handle still running processes!
+ if (m_xAsynchronousJob.is())
+ throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
+
+ // content can not be loaded or handled
+ // check "classifyContent()" failed before ...
+ if (m_eContentType == E_UNSUPPORTED_CONTENT)
+ throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT,
+ "from LoadEnv::start");
+ }
+ // <- SAFE
+
+ // detect its type/filter etc.
+ // This information will be available by the
+ // used descriptor member afterwards and is needed
+ // for all following operations!
+ // Note: An exception will be thrown, in case operation was not successfully ...
+ if (m_eContentType != E_CAN_BE_SET)/* Attention: special feature to set existing component on a frame must ignore type detection! */
+ impl_detectTypeAndFilter();
+
+ // start loading the content...
+ // Attention: Don't check m_eContentType deeper then UNSUPPORTED/SUPPORTED!
+ // Because it was made in the easiest way... may a flat detection was made only.
+ // And such simple detection can fail sometimes .-)
+ // Use another strategy here. Try it and let it run into the case "loading not possible".
+ bool bStarted = false;
+ if (
+ (m_eFeature & LoadEnvFeatures::AllowContentHandler) &&
+ (m_eContentType != E_CAN_BE_SET ) /* Attention: special feature to set existing component on a frame must ignore type detection! */
+ )
+ {
+ bStarted = impl_handleContent();
+ }
+
+ if (!bStarted)
+ bStarted = impl_loadContent();
+
+ // not started => general error
+ // We can't say - what was the reason for.
+ if (!bStarted)
+ throw LoadEnvException(
+ LoadEnvException::ID_GENERAL_ERROR, "not started");
+}
+
+/*-----------------------------------------------
+ TODO
+ First draft does not implement timeout using [ms].
+ Current implementation counts yield calls only ...
+-----------------------------------------------*/
+bool LoadEnv::waitWhileLoading(sal_uInt32 nTimeout)
+{
+ // Because it's not a good idea to block the main thread
+ // (and we can't be sure that we are currently not used inside the
+ // main thread!), we can't use conditions here really. We must yield
+ // in an intelligent manner :-)
+
+ sal_Int32 nTime = nTimeout;
+ while(!Application::IsQuit())
+ {
+ // SAFE -> ------------------------------
+ {
+ osl::MutexGuard aReadLock1(m_mutex);
+ if (!m_xAsynchronousJob.is())
+ break;
+ }
+ // <- SAFE ------------------------------
+
+ Application::Yield();
+
+ // forever!
+ if (nTimeout==0)
+ continue;
+
+ // timed out?
+ --nTime;
+ if (nTime<1)
+ break;
+ }
+
+ osl::MutexGuard g(m_mutex);
+ return !m_xAsynchronousJob.is();
+}
+
+css::uno::Reference< css::lang::XComponent > LoadEnv::getTargetComponent() const
+{
+ osl::MutexGuard g(m_mutex);
+
+ if (!m_xTargetFrame.is())
+ return css::uno::Reference< css::lang::XComponent >();
+
+ css::uno::Reference< css::frame::XController > xController = m_xTargetFrame->getController();
+ if (!xController.is())
+ return m_xTargetFrame->getComponentWindow();
+
+ css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
+ if (!xModel.is())
+ return xController;
+
+ return xModel;
+}
+
+void SAL_CALL LoadEnvListener::loadFinished(const css::uno::Reference< css::frame::XFrameLoader >&)
+{
+ osl::MutexGuard g(m_mutex);
+ if (m_bWaitingResult)
+ m_pLoadEnv->impl_setResult(true);
+ m_bWaitingResult = false;
+}
+
+void SAL_CALL LoadEnvListener::loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >&)
+{
+ osl::MutexGuard g(m_mutex);
+ if (m_bWaitingResult)
+ m_pLoadEnv->impl_setResult(false);
+ m_bWaitingResult = false;
+}
+
+void SAL_CALL LoadEnvListener::dispatchFinished(const css::frame::DispatchResultEvent& aEvent)
+{
+ osl::MutexGuard g(m_mutex);
+
+ if (!m_bWaitingResult)
+ return;
+
+ switch(aEvent.State)
+ {
+ case css::frame::DispatchResultState::FAILURE :
+ m_pLoadEnv->impl_setResult(false);
+ break;
+
+ case css::frame::DispatchResultState::SUCCESS :
+ m_pLoadEnv->impl_setResult(false);
+ break;
+
+ case css::frame::DispatchResultState::DONTKNOW :
+ m_pLoadEnv->impl_setResult(false);
+ break;
+ }
+ m_bWaitingResult = false;
+}
+
+void SAL_CALL LoadEnvListener::disposing(const css::lang::EventObject&)
+{
+ osl::MutexGuard g(m_mutex);
+ if (m_bWaitingResult)
+ m_pLoadEnv->impl_setResult(false);
+ m_bWaitingResult = false;
+}
+
+void LoadEnv::impl_setResult(bool bResult)
+{
+ osl::MutexGuard g(m_mutex);
+
+ m_bLoaded = bResult;
+
+ impl_reactForLoadingState();
+
+ // clearing of this reference will unblock waitWhileLoading()!
+ // So we must be sure, that loading process was really finished.
+ // => do it as last operation of this method ...
+ m_xAsynchronousJob.clear();
+}
+
+/*-----------------------------------------------
+ TODO: Is it a good idea to change Sequence<>
+ parameter to stl-adapter?
+-----------------------------------------------*/
+LoadEnv::EContentType LoadEnv::classifyContent(const OUString& sURL ,
+ const css::uno::Sequence< css::beans::PropertyValue >& lMediaDescriptor)
+{
+
+ // (i) Filter some special well known URL protocols,
+ // which can not be handled or loaded in general.
+ // Of course an empty URL must be ignored here too.
+ // Note: These URL schemata are fix and well known ...
+ // But there can be some additional ones, which was not
+ // defined at implementation time of this class :-(
+ // So we have to make sure, that the following code
+ // can detect such protocol schemata too :-)
+
+ if(
+ (sURL.isEmpty() ) ||
+ (ProtocolCheck::isProtocol(sURL,EProtocol::Uno )) ||
+ (ProtocolCheck::isProtocol(sURL,EProtocol::Slot )) ||
+ (ProtocolCheck::isProtocol(sURL,EProtocol::Macro )) ||
+ (ProtocolCheck::isProtocol(sURL,EProtocol::Service)) ||
+ (ProtocolCheck::isProtocol(sURL,EProtocol::MailTo )) ||
+ (ProtocolCheck::isProtocol(sURL,EProtocol::News ))
+ )
+ {
+ return E_UNSUPPORTED_CONTENT;
+ }
+
+ // (ii) Some special URLs indicates a given input stream,
+ // a full featured document model directly or
+ // specify a request for opening an empty document.
+ // Such contents are loadable in general.
+ // But we have to check, if the media descriptor contains
+ // all needed resources. If they are missing - the following
+ // load request will fail.
+
+ /* Attention: The following code can't work on such special URLs!
+ It should not break the office... but it makes no sense
+ to start expensive object creations and complex search
+ algorithm if it's clear, that such URLs must be handled
+ in a special way .-)
+ */
+
+ // creation of new documents
+ if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateFactory))
+ return E_CAN_BE_LOADED;
+
+ // using of an existing input stream
+ utl::MediaDescriptor stlMediaDescriptor(lMediaDescriptor);
+ utl::MediaDescriptor::const_iterator pIt;
+ if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateStream))
+ {
+ pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_INPUTSTREAM);
+ css::uno::Reference< css::io::XInputStream > xStream;
+ if (pIt != stlMediaDescriptor.end())
+ pIt->second >>= xStream;
+ if (xStream.is())
+ return E_CAN_BE_LOADED;
+ SAL_INFO("fwk.loadenv", "LoadEnv::classifyContent(): loading from stream with right URL but invalid stream detected");
+ return E_UNSUPPORTED_CONTENT;
+ }
+
+ // using of a full featured document
+ if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateObject))
+ {
+ pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_MODEL);
+ css::uno::Reference< css::frame::XModel > xModel;
+ if (pIt != stlMediaDescriptor.end())
+ pIt->second >>= xModel;
+ if (xModel.is())
+ return E_CAN_BE_SET;
+ SAL_INFO("fwk.loadenv", "LoadEnv::classifyContent(): loading with object with right URL but invalid object detected");
+ return E_UNSUPPORTED_CONTENT;
+ }
+
+ // following operations can work on an internal type name only :-(
+ css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ css::uno::Reference< css::document::XTypeDetection > xDetect(
+ xContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.document.TypeDetection", xContext),
+ css::uno::UNO_QUERY_THROW);
+
+ OUString sType = xDetect->queryTypeByURL(sURL);
+
+ css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory;
+ css::uno::Reference< css::container::XEnumeration > xSet;
+
+ // (iii) If a FrameLoader service (or at least
+ // a Filter) can be found, which supports
+ // this URL - it must be a loadable content.
+ // Because both items are registered for types
+ // it's enough to check for frame loaders only.
+ // Most of our filters are handled by our global
+ // default loader. But there exist some specialized
+ // loader, which does not work on top of filters!
+ // So it's not enough to search on the filter configuration.
+ // Further it's not enough to search for types!
+ // Because there exist some types, which are referenced by
+ // other objects... but neither by filters nor frame loaders!
+ css::uno::Sequence< OUString > lTypesReg { sType };
+ css::uno::Sequence< css::beans::NamedValue > lQuery
+ {
+ css::beans::NamedValue(PROP_TYPES, css::uno::Any(lTypesReg))
+ };
+
+ xLoaderFactory = css::frame::FrameLoaderFactory::create(xContext);
+ xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
+ // at least one registered frame loader is enough!
+ if (xSet->hasMoreElements())
+ return E_CAN_BE_LOADED;
+
+ // (iv) Some URL protocols are supported by special services.
+ // E.g. ContentHandler.
+ // Such contents can be handled ... but not loaded.
+
+ xLoaderFactory = css::frame::ContentHandlerFactory::create(xContext);
+ xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
+ // at least one registered content handler is enough!
+ if (xSet->hasMoreElements())
+ return E_CAN_BE_HANDLED;
+
+ // (v) Last but not least the UCB is used inside office to
+ // load contents. He has a special configuration to know
+ // which URL schemata can be used inside office.
+ css::uno::Reference< css::ucb::XUniversalContentBroker > xUCB(css::ucb::UniversalContentBroker::create(xContext));
+ if (xUCB->queryContentProvider(sURL).is())
+ return E_CAN_BE_LOADED;
+
+ // (TODO) At this point, we have no idea .-)
+ // But it seems to be better, to break all
+ // further requests for this URL. Otherwise
+ // we can run into some trouble.
+ return E_UNSUPPORTED_CONTENT;
+}
+
+namespace {
+
+bool queryOrcusTypeAndFilter(const uno::Sequence<beans::PropertyValue>& rDescriptor, OUString& rType, OUString& rFilter)
+{
+ OUString aURL;
+ sal_Int32 nSize = rDescriptor.getLength();
+ for (sal_Int32 i = 0; i < nSize; ++i)
+ {
+ const beans::PropertyValue& rProp = rDescriptor[i];
+ if (rProp.Name == "URL")
+ {
+ rProp.Value >>= aURL;
+ break;
+ }
+ }
+
+ if (aURL.isEmpty() || o3tl::equalsIgnoreAsciiCase(aURL.subView(0,8), u"private:"))
+ return false;
+
+ // TODO : Type must be set to be generic_Text (or any other type that
+ // exists) in order to find a usable loader. Exploit it as a temporary
+ // hack.
+
+ // depending on the experimental mode
+ if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
+ {
+ return false;
+ }
+
+ OUString aUseOrcus;
+ rtl::Bootstrap::get("LIBO_USE_ORCUS", aUseOrcus);
+ bool bUseOrcus = (aUseOrcus == "YES");
+
+ if (!bUseOrcus)
+ return false;
+
+ if (aURL.endsWith(".xlsx"))
+ {
+ rType = "generic_Text";
+ rFilter = "xlsx";
+ return true;
+ }
+ else if (aURL.endsWith(".ods"))
+ {
+ rType = "generic_Text";
+ rFilter = "ods";
+ return true;
+ }
+ else if (aURL.endsWith(".csv"))
+ {
+ rType = "generic_Text";
+ rFilter = "csv";
+ return true;
+ }
+
+ return false;
+}
+
+}
+
+void LoadEnv::impl_detectTypeAndFilter()
+{
+ static const sal_Int32 FILTERFLAG_TEMPLATEPATH = 16;
+
+ // SAFE ->
+ osl::ClearableMutexGuard aReadLock(m_mutex);
+
+ // Attention: Because our stl media descriptor is a copy of a uno sequence
+ // we can't use as an in/out parameter here. Copy it before and don't forget to
+ // update structure afterwards again!
+ css::uno::Sequence< css::beans::PropertyValue > lDescriptor = m_lMediaDescriptor.getAsConstPropertyValueList();
+ css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
+
+ aReadLock.clear();
+ // <- SAFE
+
+ OUString sType, sFilter;
+
+ if (queryOrcusTypeAndFilter(lDescriptor, sType, sFilter) && !sType.isEmpty() && !sFilter.isEmpty())
+ {
+ // SAFE ->
+ osl::MutexGuard aWriteLock(m_mutex);
+
+ // Orcus type detected. Skip the normal type detection process.
+ m_lMediaDescriptor << lDescriptor;
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME] <<= sType;
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= sFilter;
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERPROVIDER] <<= OUString("orcus");
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTSERVICE] <<= OUString("com.sun.star.sheet.SpreadsheetDocument");
+ return;
+ // <- SAFE
+ }
+
+ css::uno::Reference< css::document::XTypeDetection > xDetect(
+ xContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.document.TypeDetection", xContext),
+ css::uno::UNO_QUERY_THROW);
+ sType = xDetect->queryTypeByDescriptor(lDescriptor, true); /*TODO should deep detection be able for enable/disable it from outside? */
+
+ // no valid content -> loading not possible
+ if (sType.isEmpty())
+ throw LoadEnvException(
+ LoadEnvException::ID_UNSUPPORTED_CONTENT, "type detection failed");
+
+ // SAFE ->
+ osl::ResettableMutexGuard aWriteLock(m_mutex);
+
+ // detection was successful => update the descriptor member of this class
+ m_lMediaDescriptor << lDescriptor;
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME] <<= sType;
+ // Is there an already detected (may be preselected) filter?
+ // see below ...
+ sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME, OUString());
+
+ aWriteLock.clear();
+ // <- SAFE
+
+ // We do have potentially correct type, but the detection process was aborted.
+ if (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ABORTED, false))
+ throw LoadEnvException(
+ LoadEnvException::ID_UNSUPPORTED_CONTENT, "type detection aborted");
+
+ // But the type isn't enough. For loading sometimes we need more information.
+ // E.g. for our "_default" feature, where we recycle any frame which contains
+ // and "Untitled" document, we must know if the new document is based on a template!
+ // But this information is available as a filter property only.
+ // => We must try(!) to detect the right filter for this load request.
+ // On the other side ... if no filter is available .. ignore it.
+ // Then the type information must be enough.
+ if (sFilter.isEmpty())
+ {
+ // no -> try to find a preferred filter for the detected type.
+ // Don't forget to update the media descriptor.
+ css::uno::Reference< css::container::XNameAccess > xTypeCont(xDetect, css::uno::UNO_QUERY_THROW);
+ try
+ {
+ ::comphelper::SequenceAsHashMap lTypeProps(xTypeCont->getByName(sType));
+ sFilter = lTypeProps.getUnpackedValueOrDefault("PreferredFilter", OUString());
+ if (!sFilter.isEmpty())
+ {
+ // SAFE ->
+ aWriteLock.reset();
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= sFilter;
+ aWriteLock.clear();
+ // <- SAFE
+ }
+ }
+ catch(const css::container::NoSuchElementException&)
+ {}
+ }
+
+ // check if the filter (if one exists) points to a template format filter.
+ // Then we have to add the property "AsTemplate".
+ // We need this information to decide afterwards if we can use a "recycle frame"
+ // for target "_default" or has to create a new one every time.
+ // On the other side we have to suppress that, if this property already exists
+ // and should trigger a special handling. Then the outside call of this method here,
+ // has to know, what he is doing .-)
+
+ bool bIsOwnTemplate = false;
+ if (!sFilter.isEmpty())
+ {
+ css::uno::Reference< css::container::XNameAccess > xFilterCont(xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext), css::uno::UNO_QUERY_THROW);
+ try
+ {
+ ::comphelper::SequenceAsHashMap lFilterProps(xFilterCont->getByName(sFilter));
+ sal_Int32 nFlags = lFilterProps.getUnpackedValueOrDefault("Flags", sal_Int32(0));
+ bIsOwnTemplate = ((nFlags & FILTERFLAG_TEMPLATEPATH) == FILTERFLAG_TEMPLATEPATH);
+ }
+ catch(const css::container::NoSuchElementException&)
+ {}
+ }
+ if (bIsOwnTemplate)
+ {
+ // SAFE ->
+ aWriteLock.reset();
+ // Don't overwrite external decisions! See comments before ...
+ utl::MediaDescriptor::const_iterator pAsTemplateItem = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_ASTEMPLATE);
+ if (pAsTemplateItem == m_lMediaDescriptor.end())
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE] <<= true;
+ aWriteLock.clear();
+ // <- SAFE
+ }
+}
+
+bool LoadEnv::impl_handleContent()
+{
+ // SAFE -> -----------------------------------
+ osl::ClearableMutexGuard aReadLock(m_mutex);
+
+ // the type must exist inside the descriptor ... otherwise this class is implemented wrong :-)
+ OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME, OUString());
+ if (sType.isEmpty())
+ throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
+
+ // convert media descriptor and URL to right format for later interface call!
+ css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
+ m_lMediaDescriptor >> lDescriptor;
+ css::util::URL aURL = m_aURL;
+
+ // get necessary container to query for a handler object
+ css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::ContentHandlerFactory::create(m_xContext);
+
+ aReadLock.clear();
+ // <- SAFE -----------------------------------
+
+ // query
+ css::uno::Sequence< OUString > lTypeReg { sType };
+
+ css::uno::Sequence< css::beans::NamedValue > lQuery { { PROP_TYPES, css::uno::Any(lTypeReg) } };
+
+ css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
+ while(xSet->hasMoreElements())
+ {
+ ::comphelper::SequenceAsHashMap lProps (xSet->nextElement());
+ OUString sHandler = lProps.getUnpackedValueOrDefault(PROP_NAME, OUString());
+
+ css::uno::Reference< css::frame::XNotifyingDispatch > xHandler;
+ try
+ {
+ xHandler.set(xLoaderFactory->createInstance(sHandler), css::uno::UNO_QUERY);
+ if (!xHandler.is())
+ continue;
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ { continue; }
+
+ // SAFE -> -----------------------------------
+ osl::ClearableMutexGuard aWriteLock(m_mutex);
+ m_xAsynchronousJob = xHandler;
+ rtl::Reference<LoadEnvListener> xListener = new LoadEnvListener(this);
+ aWriteLock.clear();
+ // <- SAFE -----------------------------------
+
+ xHandler->dispatchWithNotification(aURL, lDescriptor, xListener);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool LoadEnv::impl_furtherDocsAllowed()
+{
+ // SAFE ->
+ osl::ResettableMutexGuard aReadLock(m_mutex);
+ css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
+ aReadLock.clear();
+ // <- SAFE
+
+ bool bAllowed = true;
+
+ try
+ {
+ std::optional<sal_Int32> x(officecfg::Office::Common::Misc::MaxOpenDocuments::get());
+
+ // NIL means: count of allowed documents = infinite !
+ // => return true
+ if ( !x)
+ bAllowed = true;
+ else
+ {
+ sal_Int32 nMaxOpenDocuments(*x);
+
+ css::uno::Reference< css::frame::XFramesSupplier > xDesktop(
+ css::frame::Desktop::create(xContext),
+ css::uno::UNO_QUERY_THROW);
+
+ FrameListAnalyzer aAnalyzer(xDesktop,
+ css::uno::Reference< css::frame::XFrame >(),
+ FrameAnalyzerFlags::Help |
+ FrameAnalyzerFlags::BackingComponent |
+ FrameAnalyzerFlags::Hidden);
+
+ sal_Int32 nOpenDocuments = aAnalyzer.m_lOtherVisibleFrames.size();
+ bAllowed = (nOpenDocuments < nMaxOpenDocuments);
+ }
+ }
+ catch(const css::uno::Exception&)
+ { bAllowed = true; } // !! internal errors are no reason to disturb the office from opening documents .-)
+
+ if ( ! bAllowed )
+ {
+ // SAFE ->
+ aReadLock.reset();
+ css::uno::Reference< css::task::XInteractionHandler > xInteraction = m_lMediaDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_INTERACTIONHANDLER,
+ css::uno::Reference< css::task::XInteractionHandler >());
+ aReadLock.clear();
+ // <- SAFE
+
+ if (xInteraction.is())
+ {
+ css::uno::Any aInteraction;
+
+ rtl::Reference<comphelper::OInteractionAbort> pAbort = new comphelper::OInteractionAbort();
+ rtl::Reference<comphelper::OInteractionApprove> pApprove = new comphelper::OInteractionApprove();
+
+ css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations{
+ pAbort, pApprove
+ };
+
+ css::task::ErrorCodeRequest aErrorCode;
+ aErrorCode.ErrCode = sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED);
+ aInteraction <<= aErrorCode;
+ xInteraction->handle( InteractionRequest::CreateRequest(aInteraction, lContinuations) );
+ }
+ }
+
+ return bAllowed;
+}
+
+bool LoadEnv::impl_filterHasInteractiveDialog() const
+{
+ //show the frame now so it can be the parent for any message dialogs shown during import
+
+ //unless (tdf#114648) an Interactive case such as the new database wizard
+ if (m_aURL.Arguments == "Interactive")
+ return true;
+
+ // unless (tdf#116277) it's the labels/business cards slave frame
+ if (m_aURL.Arguments.indexOf("slot=") != -1)
+ return true;
+
+ OUString sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME, OUString());
+ if (sFilter.isEmpty())
+ return false;
+
+ // unless (tdf#115683) the filter has a UIComponent
+ OUString sUIComponent;
+ css::uno::Reference<css::container::XNameAccess> xFilterCont(m_xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, m_xContext),
+ css::uno::UNO_QUERY_THROW);
+ try
+ {
+ ::comphelper::SequenceAsHashMap lFilterProps(xFilterCont->getByName(sFilter));
+ sUIComponent = lFilterProps.getUnpackedValueOrDefault("UIComponent", OUString());
+ }
+ catch(const css::container::NoSuchElementException&)
+ {
+ }
+
+ return !sUIComponent.isEmpty();
+}
+
+bool LoadEnv::impl_loadContent()
+{
+ // SAFE -> -----------------------------------
+ osl::ClearableMutexGuard aWriteLock(m_mutex);
+
+ // search or create right target frame
+ OUString sTarget = m_sTarget;
+ if (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Default))
+ {
+ m_xTargetFrame = impl_searchAlreadyLoaded();
+ if (m_xTargetFrame.is())
+ {
+ impl_setResult(true);
+ return true;
+ }
+ m_xTargetFrame = impl_searchRecycleTarget();
+ }
+
+ if (! m_xTargetFrame.is())
+ {
+ if (
+ (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Blank )) ||
+ (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Default))
+ )
+ {
+ if (! impl_furtherDocsAllowed())
+ return false;
+ TaskCreator aCreator(m_xContext);
+ m_xTargetFrame = aCreator.createTask(SPECIALTARGET_BLANK, m_lMediaDescriptor);
+ m_bCloseFrameOnError = m_xTargetFrame.is();
+ }
+ else
+ {
+ sal_Int32 nSearchFlags = m_nSearchFlags & ~css::frame::FrameSearchFlag::CREATE;
+ m_xTargetFrame = m_xBaseFrame->findFrame(sTarget, nSearchFlags);
+ if (! m_xTargetFrame.is())
+ {
+ if (! impl_furtherDocsAllowed())
+ return false;
+ m_xTargetFrame = m_xBaseFrame->findFrame(SPECIALTARGET_BLANK, 0);
+ m_bCloseFrameOnError = m_xTargetFrame.is();
+ }
+ }
+ }
+
+ // If we couldn't find a valid frame or the frame has no container window
+ // we have to throw an exception.
+ if (
+ ( ! m_xTargetFrame.is() ) ||
+ ( ! m_xTargetFrame->getContainerWindow().is() )
+ )
+ throw LoadEnvException(LoadEnvException::ID_NO_TARGET_FOUND);
+
+ css::uno::Reference< css::frame::XFrame > xTargetFrame = m_xTargetFrame;
+
+ // Now we have a valid frame ... and type detection was already done.
+ // We should apply the module dependent window position and size to the
+ // frame window.
+ impl_applyPersistentWindowState(xTargetFrame->getContainerWindow());
+
+ // Don't forget to lock task for following load process. Otherwise it could die
+ // during this operation runs by terminating the office or closing this task via api.
+ // If we set this lock "close()" will return false and closing will be broken.
+ // Attention: Don't forget to reset this lock again after finishing operation.
+ // Otherwise task AND office couldn't die!!!
+ // This includes gracefully handling of Exceptions (Runtime!) too ...
+ // That's why we use a specialized guard, which will reset the lock
+ // if it will be run out of scope.
+
+ // Note further: ignore if this internal guard already contains a resource.
+ // Might impl_searchRecycleTarget() set it before. But in case this impl-method wasn't used
+ // and the target frame was new created ... this lock here must be set!
+ css::uno::Reference< css::document::XActionLockable > xTargetLock(xTargetFrame, css::uno::UNO_QUERY);
+ m_aTargetLock.setResource(xTargetLock);
+
+ // Add status indicator to descriptor. Loader can show a progress then.
+ // But don't do it, if loading should be hidden or preview is used...!
+ // So we prevent our code against wrong using. Why?
+ // It could be, that using of this progress could make trouble. e.g. He makes window visible...
+ // but shouldn't do that. But if no indicator is available... nobody has a chance to do that!
+ bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false);
+ bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED, false);
+ bool bPreview = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW, false);
+
+ if (!bHidden && !bMinimized && !bPreview)
+ {
+ css::uno::Reference<css::task::XStatusIndicator> xProgress = m_lMediaDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_STATUSINDICATOR, css::uno::Reference<css::task::XStatusIndicator>());
+ if (!xProgress.is())
+ {
+ // Note: it's an optional interface!
+ css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xTargetFrame, css::uno::UNO_QUERY);
+ if (xProgressFactory.is())
+ {
+ xProgress = xProgressFactory->createStatusIndicator();
+ if (xProgress.is())
+ m_lMediaDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR] <<= xProgress;
+ }
+ }
+
+ // Now that we have a target window into which we can load, reinit the interaction handler to have this
+ // window as its parent for modal dialogs and ensure the window is visible
+ css::uno::Reference< css::task::XInteractionHandler > xInteraction = m_lMediaDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_INTERACTIONHANDLER,
+ css::uno::Reference< css::task::XInteractionHandler >());
+ css::uno::Reference<css::lang::XInitialization> xHandler(xInteraction, css::uno::UNO_QUERY);
+ if (xHandler.is())
+ {
+ css::uno::Reference<css::awt::XWindow> xWindow = xTargetFrame->getContainerWindow();
+ uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"Parent", uno::Any(xWindow)}
+ }));
+ xHandler->initialize(aArguments);
+ //show the frame as early as possible to make it the parent of any message dialogs
+ if (!impl_filterHasInteractiveDialog())
+ impl_makeFrameWindowVisible(xWindow, false);
+ }
+ }
+
+ // convert media descriptor and URL to right format for later interface call!
+ css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
+ m_lMediaDescriptor >> lDescriptor;
+ OUString sURL = m_aURL.Complete;
+
+ // try to locate any interested frame loader
+ css::uno::Reference< css::uno::XInterface > xLoader = impl_searchLoader();
+ css::uno::Reference< css::frame::XFrameLoader > xAsyncLoader(xLoader, css::uno::UNO_QUERY);
+ css::uno::Reference< css::frame::XSynchronousFrameLoader > xSyncLoader (xLoader, css::uno::UNO_QUERY);
+
+ if (xAsyncLoader.is())
+ {
+ m_xAsynchronousJob = xAsyncLoader;
+ rtl::Reference<LoadEnvListener> xListener = new LoadEnvListener(this);
+ aWriteLock.clear();
+ // <- SAFE -----------------------------------
+
+ xAsyncLoader->load(xTargetFrame, sURL, lDescriptor, xListener);
+
+ return true;
+ }
+ else if (xSyncLoader.is())
+ {
+ uno::Reference<beans::XPropertySet> xTargetFrameProps(xTargetFrame, uno::UNO_QUERY);
+ if (xTargetFrameProps.is())
+ {
+ // Set the URL on the frame itself, for the duration of the load, when it has no
+ // controller.
+ xTargetFrameProps->setPropertyValue("URL", uno::Any(sURL));
+ }
+ bool bResult = xSyncLoader->load(lDescriptor, xTargetFrame);
+ // react for the result here, so the outside waiting
+ // code can ask for it later.
+ impl_setResult(bResult);
+ // But the return value indicates a valid started(!) operation.
+ // And that's true every time we reach this line :-)
+ return true;
+ }
+
+ aWriteLock.clear();
+ // <- SAFE
+
+ return false;
+}
+
+css::uno::Reference< css::uno::XInterface > LoadEnv::impl_searchLoader()
+{
+ // SAFE -> -----------------------------------
+ osl::ClearableMutexGuard aReadLock(m_mutex);
+
+ // special mode to set an existing component on this frame
+ // In such case the loader is fix. It must be the SFX based implementation,
+ // which can create a view on top of such xModel components :-)
+ if (m_eContentType == E_CAN_BE_SET)
+ {
+ try
+ {
+ return css::frame::OfficeFrameLoader::create(m_xContext);
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ {}
+ throw LoadEnvException(LoadEnvException::ID_INVALID_ENVIRONMENT);
+ }
+
+ // Otherwise...
+ // We need this type information to locate a registered frame loader
+ // Without such information we can't work!
+ OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME, OUString());
+ if (sType.isEmpty())
+ throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
+
+ // try to locate any interested frame loader
+ css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::FrameLoaderFactory::create(m_xContext);
+
+ aReadLock.clear();
+ // <- SAFE -----------------------------------
+
+ css::uno::Sequence< OUString > lTypesReg { sType };
+
+ css::uno::Sequence< css::beans::NamedValue > lQuery { { PROP_TYPES, css::uno::Any(lTypesReg) } };
+
+ css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
+ while(xSet->hasMoreElements())
+ {
+ try
+ {
+ // try everyone ...
+ // Ignore any loader, which makes trouble :-)
+ ::comphelper::SequenceAsHashMap lLoaderProps(xSet->nextElement());
+ OUString sLoader = lLoaderProps.getUnpackedValueOrDefault(PROP_NAME, OUString());
+ css::uno::Reference< css::uno::XInterface > xLoader = xLoaderFactory->createInstance(sLoader);
+ if (xLoader.is())
+ return xLoader;
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ { continue; }
+ }
+
+ return css::uno::Reference< css::uno::XInterface >();
+}
+
+void LoadEnv::impl_jumpToMark(const css::uno::Reference< css::frame::XFrame >& xFrame,
+ const css::util::URL& aURL )
+{
+ if (aURL.Mark.isEmpty())
+ return;
+
+ css::uno::Reference< css::frame::XDispatchProvider > xProvider(xFrame, css::uno::UNO_QUERY);
+ if (! xProvider.is())
+ return;
+
+ // SAFE ->
+ osl::ClearableMutexGuard aReadLock(m_mutex);
+ css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
+ aReadLock.clear();
+ // <- SAFE
+
+ css::util::URL aCmd;
+ aCmd.Complete = ".uno:JumpToMark";
+
+ css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(xContext));
+ xParser->parseStrict(aCmd);
+
+ css::uno::Reference< css::frame::XDispatch > xDispatcher = xProvider->queryDispatch(aCmd, SPECIALTARGET_SELF, 0);
+ if (! xDispatcher.is())
+ return;
+
+ ::comphelper::SequenceAsHashMap lArgs;
+ lArgs[OUString("Bookmark")] <<= aURL.Mark;
+ xDispatcher->dispatch(aCmd, lArgs.getAsConstPropertyValueList());
+}
+
+css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchAlreadyLoaded()
+{
+ osl::MutexGuard g(m_mutex);
+
+ // such search is allowed for special requests only ...
+ // or better it's not allowed for some requests in general :-)
+ if (
+ ( ! TargetHelper::matchSpecialTarget(m_sTarget, TargetHelper::ESpecialTarget::Default) ) ||
+ m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE , false) ||
+// (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN() , false) == sal_True) ||
+ m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW, false)
+ )
+ {
+ return css::uno::Reference< css::frame::XFrame >();
+ }
+
+ // check URL
+ // May it's not useful to start expensive document search, if it
+ // can fail only .. because we load from a stream or model directly!
+ if (
+ (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateStream )) ||
+ (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateObject ))
+ /*TODO should be private:factory here tested too? */
+ )
+ {
+ return css::uno::Reference< css::frame::XFrame >();
+ }
+
+ // otherwise - iterate through the tasks of the desktop container
+ // to find out, which of them might contains the requested document
+ css::uno::Reference< css::frame::XDesktop2 > xSupplier = css::frame::Desktop::create( m_xContext );
+ css::uno::Reference< css::container::XIndexAccess > xTaskList = xSupplier->getFrames();
+
+ if (!xTaskList.is())
+ return css::uno::Reference< css::frame::XFrame >(); // task list can be empty!
+
+ // Note: To detect if a document was already loaded before
+ // we check URLs here only. But might the existing and the required
+ // document has different versions! Then its URLs are the same...
+ sal_Int16 nNewVersion = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION, sal_Int16(-1));
+
+ // will be used to save the first hidden frame referring the searched model
+ // Normally we are interested on visible frames... but if there is no such visible
+ // frame we refer to any hidden frame also (but as fallback only).
+ css::uno::Reference< css::frame::XFrame > xHiddenTask;
+ css::uno::Reference< css::frame::XFrame > xTask;
+
+ sal_Int32 count = xTaskList->getCount();
+ for (sal_Int32 i=0; i<count; ++i)
+ {
+ try
+ {
+ // locate model of task
+ // Note: Without a model there is no chance to decide if
+ // this task contains the searched document or not!
+ xTaskList->getByIndex(i) >>= xTask;
+ if (!xTask.is())
+ continue;
+
+ OUString sURL;
+ css::uno::Reference< css::frame::XController > xController = xTask->getController();
+ if (!xController.is())
+ {
+ // If we have no controller, then perhaps there is a load in progress. The frame
+ // itself has the URL in this case.
+ uno::Reference<beans::XPropertySet> xTaskProps(xTask, uno::UNO_QUERY);
+ if (xTaskProps.is())
+ {
+ xTaskProps->getPropertyValue("URL") >>= sURL;
+ }
+ if (sURL.isEmpty())
+ {
+ xTask.clear();
+ continue;
+ }
+ }
+
+ uno::Reference<frame::XModel> xModel;
+ if (sURL.isEmpty())
+ {
+ xModel = xController->getModel();
+ if (!xModel.is())
+ {
+ xTask.clear();
+ continue;
+ }
+
+ // don't check the complete URL here.
+ // use its main part - ignore optional jumpmarks!
+ sURL = xModel->getURL();
+ }
+ if (!::utl::UCBContentHelper::EqualURLs( m_aURL.Main, sURL ))
+ {
+ xTask.clear ();
+ continue;
+ }
+
+ // get the original load arguments from the current document
+ // and decide if it's really the same then the one will be.
+ // It must be visible and must use the same file revision ...
+ // or must not have any file revision set (-1 == -1!)
+ utl::MediaDescriptor lOldDocDescriptor;
+ if (xModel.is())
+ {
+ lOldDocDescriptor = xModel->getArgs();
+
+ if (lOldDocDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_VERSION, sal_Int32(-1))
+ != nNewVersion)
+ {
+ xTask.clear();
+ continue;
+ }
+ }
+
+ // Hidden frames are special.
+ // They will be used as "last chance" if there is no visible frame pointing to the same model.
+ // Safe the result but continue with current loop might be looking for other visible frames.
+ bool bIsHidden = lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false);
+ if ( bIsHidden && ! xHiddenTask.is() )
+ {
+ xHiddenTask = xTask;
+ xTask.clear ();
+ continue;
+ }
+
+ // We found a visible task pointing to the right model ...
+ // Break search.
+ break;
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ { continue; }
+ }
+
+ css::uno::Reference< css::frame::XFrame > xResult;
+ if (xTask.is())
+ xResult = xTask;
+ else if (xHiddenTask.is())
+ xResult = xHiddenTask;
+
+ if (xResult.is())
+ {
+ // Now we are sure, that this task includes the searched document.
+ // It's time to activate it. As special feature we try to jump internally
+ // if an optional jumpmark is given too.
+ if (!m_aURL.Mark.isEmpty())
+ impl_jumpToMark(xResult, m_aURL);
+
+ // bring it to front and make sure it's visible...
+ impl_makeFrameWindowVisible(xResult->getContainerWindow(), true);
+ }
+
+ return xResult;
+}
+
+bool LoadEnv::impl_isFrameAlreadyUsedForLoading(const css::uno::Reference< css::frame::XFrame >& xFrame) const
+{
+ css::uno::Reference< css::document::XActionLockable > xLock(xFrame, css::uno::UNO_QUERY);
+
+ // ? no lock interface ?
+ // Maybe it's an external written frame implementation :-(
+ // Allowing using of it... but it can fail if it's not synchronized with our processes!
+ if (!xLock.is())
+ return false;
+
+ // Otherwise we have to look for any other existing lock.
+ return xLock->isActionLocked();
+}
+
+css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchRecycleTarget()
+{
+ // SAFE -> ..................................
+ osl::ClearableMutexGuard aReadLock(m_mutex);
+
+ // The special backing mode frame will be recycled by definition!
+ // It doesn't matter if somewhere wants to create a new view
+ // or open a new untitled document...
+ // The only exception from that - hidden frames!
+ if (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false))
+ return css::uno::Reference< css::frame::XFrame >();
+
+ css::uno::Reference< css::frame::XFramesSupplier > xSupplier = css::frame::Desktop::create( m_xContext );
+ FrameListAnalyzer aTasksAnalyzer(xSupplier, css::uno::Reference< css::frame::XFrame >(), FrameAnalyzerFlags::BackingComponent);
+ if (aTasksAnalyzer.m_xBackingComponent.is())
+ {
+ if (!impl_isFrameAlreadyUsedForLoading(aTasksAnalyzer.m_xBackingComponent))
+ {
+ // bring it to front...
+ impl_makeFrameWindowVisible(aTasksAnalyzer.m_xBackingComponent->getContainerWindow(), true);
+ m_bReactivateControllerOnError = true;
+ return aTasksAnalyzer.m_xBackingComponent;
+ }
+ }
+
+ // These states indicates a wish for creation of a new view in general.
+ if (
+ m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE , false) ||
+ m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW, false)
+ )
+ {
+ return css::uno::Reference< css::frame::XFrame >();
+ }
+
+ // On the other side some special URLs will open a new frame every time (expecting
+ // they can use the backing-mode frame!)
+ if (
+ (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateFactory )) ||
+ (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateStream )) ||
+ (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateObject ))
+ )
+ {
+ return css::uno::Reference< css::frame::XFrame >();
+ }
+
+ // No backing frame! No special URL => recycle active task - if possible.
+ // Means - if it does not already contains a modified document, or
+ // use another office module.
+ css::uno::Reference< css::frame::XFrame > xTask = xSupplier->getActiveFrame();
+
+ // not a real error - but might a focus problem!
+ if (!xTask.is())
+ return css::uno::Reference< css::frame::XFrame >();
+
+ // not a real error - may it's a view only
+ css::uno::Reference< css::frame::XController > xController = xTask->getController();
+ if (!xController.is())
+ return css::uno::Reference< css::frame::XFrame >();
+
+ // not a real error - may it's a db component instead of a full featured office document
+ css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
+ if (!xModel.is())
+ return css::uno::Reference< css::frame::XFrame >();
+
+ // get some more information ...
+
+ // A valid set URL means: there is already a location for this document.
+ // => it was saved there or opened from there. Such Documents can not be used here.
+ // We search for empty document ... created by a private:factory/ URL!
+ if (xModel->getURL().getLength()>0)
+ return css::uno::Reference< css::frame::XFrame >();
+
+ // The old document must be unmodified ...
+ css::uno::Reference< css::util::XModifiable > xModified(xModel, css::uno::UNO_QUERY);
+ if (xModified->isModified())
+ return css::uno::Reference< css::frame::XFrame >();
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xTask->getContainerWindow());
+ if (pWindow && pWindow->IsInModalMode())
+ return css::uno::Reference< css::frame::XFrame >();
+
+ // find out the application type of this document
+ // We can recycle only documents, which uses the same application
+ // then the new one.
+ SvtModuleOptions::EFactory eOldApp = SvtModuleOptions::ClassifyFactoryByModel(xModel);
+ SvtModuleOptions::EFactory eNewApp = SvtModuleOptions::ClassifyFactoryByURL (m_aURL.Complete, m_lMediaDescriptor.getAsConstPropertyValueList());
+
+ aReadLock.clear();
+ // <- SAFE ..................................
+
+ if (eOldApp != eNewApp)
+ return css::uno::Reference< css::frame::XFrame >();
+
+ // OK this task seems to be usable for recycling
+ // But we should mark it as such - means set an action lock.
+ // Otherwise it would be used more than ones or will be destroyed
+ // by a close() or terminate() request.
+ // But if such lock already exist ... it means this task is used for
+ // any other operation already. Don't use it then.
+ if (impl_isFrameAlreadyUsedForLoading(xTask))
+ return css::uno::Reference< css::frame::XFrame >();
+
+ // OK - there is a valid target frame.
+ // But may be it contains already a document.
+ // Then we have to ask it, if it allows recycling of this frame .-)
+ bool bReactivateOldControllerOnError = false;
+ css::uno::Reference< css::frame::XController > xOldDoc = xTask->getController();
+ if (xOldDoc.is())
+ {
+ utl::MediaDescriptor lOldDocDescriptor(xModel->getArgs());
+
+ // replaceable document
+ if (!lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REPLACEABLE, false))
+ return css::uno::Reference< css::frame::XFrame >();
+
+ bReactivateOldControllerOnError = xOldDoc->suspend(true);
+ if (! bReactivateOldControllerOnError)
+ return css::uno::Reference< css::frame::XFrame >();
+ }
+
+ // SAFE -> ..................................
+ {
+ osl::MutexGuard aWriteLock(m_mutex);
+
+ css::uno::Reference< css::document::XActionLockable > xLock(xTask, css::uno::UNO_QUERY);
+ if (!m_aTargetLock.setResource(xLock))
+ return css::uno::Reference< css::frame::XFrame >();
+
+ m_bReactivateControllerOnError = bReactivateOldControllerOnError;
+ }
+ // <- SAFE ..................................
+
+ // bring it to front ...
+ impl_makeFrameWindowVisible(xTask->getContainerWindow(), true);
+
+ return xTask;
+}
+
+void LoadEnv::impl_reactForLoadingState()
+{
+ /*TODO reset action locks */
+
+ // SAFE -> ----------------------------------
+ osl::ClearableMutexGuard aReadLock(m_mutex);
+
+ if (m_bLoaded)
+ {
+ // Bring the new loaded document to front (if allowed!).
+ // Note: We show new created frames here only.
+ // We don't hide already visible frames here ...
+ css::uno::Reference< css::awt::XWindow > xWindow = m_xTargetFrame->getContainerWindow();
+ bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN, false);
+ bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED, false);
+
+ if (bMinimized)
+ {
+ SolarMutexGuard aSolarGuard;
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
+ // check for system window is necessary to guarantee correct pointer cast!
+ if (pWindow && pWindow->IsSystemWindow())
+ static_cast<WorkWindow*>(pWindow.get())->Minimize();
+ }
+ else if (!bHidden)
+ {
+ // show frame ... if it's not still visible ...
+ // But do nothing if it's already visible!
+ impl_makeFrameWindowVisible(xWindow, false);
+ }
+
+ // Note: Only if an existing property "FrameName" is given by this media descriptor,
+ // it should be used. Otherwise we should do nothing. May be the outside code has already
+ // set a frame name on the target!
+ utl::MediaDescriptor::const_iterator pFrameName = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FRAMENAME);
+ if (pFrameName != m_lMediaDescriptor.end())
+ {
+ OUString sFrameName;
+ pFrameName->second >>= sFrameName;
+ // Check the name again. e.g. "_default" isn't allowed.
+ // On the other side "_beamer" is a valid name :-)
+ if (TargetHelper::isValidNameForFrame(sFrameName))
+ m_xTargetFrame->setName(sFrameName);
+ }
+ }
+ else if (m_bReactivateControllerOnError)
+ {
+ // Try to reactivate the old document (if any exists!)
+ css::uno::Reference< css::frame::XController > xOldDoc = m_xTargetFrame->getController();
+ // clear does not depend from reactivation state of a might existing old document!
+ // We must make sure, that a might following getTargetComponent() call does not return
+ // the old document!
+ m_xTargetFrame.clear();
+ if (xOldDoc.is())
+ {
+ bool bReactivated = xOldDoc->suspend(false);
+ if (!bReactivated)
+ throw LoadEnvException(LoadEnvException::ID_COULD_NOT_REACTIVATE_CONTROLLER);
+ m_bReactivateControllerOnError = false;
+ }
+ }
+ else if (m_bCloseFrameOnError)
+ {
+ // close empty frames
+ css::uno::Reference< css::util::XCloseable > xCloseable (m_xTargetFrame, css::uno::UNO_QUERY);
+
+ try
+ {
+ if (xCloseable.is())
+ xCloseable->close(true);
+ else if (m_xTargetFrame.is())
+ m_xTargetFrame->dispose();
+ }
+ catch(const css::util::CloseVetoException&)
+ {}
+ catch(const css::lang::DisposedException&)
+ {}
+ m_xTargetFrame.clear();
+ }
+
+ // This max force an implicit closing of our target frame ...
+ // e.g. in case close(sal_True) was called before and the frame
+ // kill itself if our external use-lock is released here!
+ // That's why we release this lock AFTER ALL OPERATIONS on this frame
+ // are finished. The frame itself must handle then
+ // this situation gracefully.
+ m_aTargetLock.freeResource();
+
+ // Last but not least :-)
+ // We have to clear the current media descriptor.
+ // Otherwise it hold a might existing stream open!
+ m_lMediaDescriptor.clear();
+
+ css::uno::Any aRequest;
+ bool bThrow = false;
+ if ( !m_bLoaded && m_pQuietInteraction.is() && m_pQuietInteraction->wasUsed() )
+ {
+ aRequest = m_pQuietInteraction->getRequest();
+ m_pQuietInteraction.clear();
+ bThrow = true;
+ }
+
+ aReadLock.clear();
+
+ if (bThrow)
+ {
+ if ( aRequest.isExtractableTo( ::cppu::UnoType< css::uno::Exception >::get() ) )
+ throw LoadEnvException(
+ LoadEnvException::ID_GENERAL_ERROR, "interaction request",
+ aRequest);
+ }
+
+ // <- SAFE ----------------------------------
+}
+
+void LoadEnv::impl_makeFrameWindowVisible(const css::uno::Reference< css::awt::XWindow >& xWindow ,
+ bool bForceToFront)
+{
+ SolarMutexGuard aSolarGuard;
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
+ if ( !pWindow )
+ return;
+
+ bool const preview( m_lMediaDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_PREVIEW, false) );
+
+ bool bForceFrontAndFocus(false);
+ if ( !preview )
+ {
+ bForceFrontAndFocus = officecfg::Office::Common::View::NewDocumentHandling::ForceFocusAndToFront::get();
+ }
+
+ if( pWindow->IsVisible() && (bForceFrontAndFocus || bForceToFront) )
+ pWindow->ToTop( ToTopFlags::RestoreWhenMin | ToTopFlags::ForegroundTask );
+ else
+ pWindow->Show(true, (bForceFrontAndFocus || bForceToFront) ? ShowFlags::ForegroundTask : ShowFlags::NONE );
+}
+
+void LoadEnv::impl_applyPersistentWindowState(const css::uno::Reference< css::awt::XWindow >& xWindow)
+{
+ // no window -> action not possible
+ if (!xWindow.is())
+ return;
+
+ // window already visible -> do nothing! If we use a "recycle frame" for loading ...
+ // the current position and size must be used.
+ css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(xWindow, css::uno::UNO_QUERY);
+ if (
+ (xVisibleCheck.is() ) &&
+ (xVisibleCheck->isVisible())
+ )
+ return;
+
+ // SOLAR SAFE ->
+ {
+ SolarMutexGuard aSolarGuard1;
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
+ if (!pWindow)
+ return;
+
+ bool bSystemWindow = pWindow->IsSystemWindow();
+ bool bWorkWindow = (pWindow->GetType() == WindowType::WORKWINDOW);
+
+ if (!bSystemWindow && !bWorkWindow)
+ return;
+
+ // don't overwrite this special state!
+ WorkWindow* pWorkWindow = static_cast<WorkWindow*>(pWindow.get());
+ if (pWorkWindow->IsMinimized())
+ return;
+ }
+ // <- SOLAR SAFE
+
+ // SAFE ->
+ osl::ClearableMutexGuard aReadLock(m_mutex);
+
+ // no filter -> no module -> no persistent window state
+ OUString sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_FILTERNAME,
+ OUString());
+ if (sFilter.isEmpty())
+ return;
+
+ css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
+
+ aReadLock.clear();
+ // <- SAFE
+
+ try
+ {
+ // retrieve the module name from the filter configuration
+ css::uno::Reference< css::container::XNameAccess > xFilterCfg(
+ xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext),
+ css::uno::UNO_QUERY_THROW);
+ ::comphelper::SequenceAsHashMap lProps (xFilterCfg->getByName(sFilter));
+ OUString sModule = lProps.getUnpackedValueOrDefault(FILTER_PROPNAME_ASCII_DOCUMENTSERVICE, OUString());
+
+ // get access to the configuration of this office module
+ css::uno::Reference< css::container::XNameAccess > xModuleCfg(officecfg::Setup::Office::Factories::get());
+
+ // read window state from the configuration
+ // and apply it on the window.
+ // Do nothing, if no configuration entry exists!
+ OUString sWindowState;
+
+ // Don't look for persistent window attributes when used through LibreOfficeKit
+ if( !comphelper::LibreOfficeKit::isActive() )
+ comphelper::ConfigurationHelper::readRelativeKey(xModuleCfg, sModule, "ooSetupFactoryWindowAttributes") >>= sWindowState;
+
+ if (!sWindowState.isEmpty())
+ {
+ // SOLAR SAFE ->
+ SolarMutexGuard aSolarGuard;
+
+ // We have to retrieve the window pointer again. Because nobody can guarantee
+ // that the XWindow was not disposed in between .-)
+ // But if we get a valid pointer we can be sure, that it's the system window pointer
+ // we already checked and used before. Because nobody recycle the same uno reference for
+ // a new internal c++ implementation ... hopefully .-))
+ VclPtr<vcl::Window> pWindowCheck = VCLUnoHelper::GetWindow(xWindow);
+ if (! pWindowCheck)
+ return;
+
+ SystemWindow* pSystemWindow = static_cast<SystemWindow*>(pWindowCheck.get());
+ pSystemWindow->SetWindowState(OUStringToOString(sWindowState,RTL_TEXTENCODING_UTF8));
+ // <- SOLAR SAFE
+ }
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ {}
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/source/loadenv/targethelper.cxx b/framework/source/loadenv/targethelper.cxx
new file mode 100644
index 000000000..7c06521da
--- /dev/null
+++ b/framework/source/loadenv/targethelper.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <loadenv/targethelper.hxx>
+#include <targets.h>
+
+namespace framework{
+
+bool TargetHelper::matchSpecialTarget(std::u16string_view sCheckTarget ,
+ ESpecialTarget eSpecialTarget)
+{
+ switch(eSpecialTarget)
+ {
+ case ESpecialTarget::Blank :
+ return sCheckTarget == SPECIALTARGET_BLANK;
+
+ case ESpecialTarget::Default :
+ return sCheckTarget == SPECIALTARGET_DEFAULT;
+
+ case ESpecialTarget::Beamer :
+ return sCheckTarget == SPECIALTARGET_BEAMER;
+
+ case ESpecialTarget::HelpTask :
+ return sCheckTarget == SPECIALTARGET_HELPTASK;
+ default:
+ return false;
+ }
+}
+
+bool TargetHelper::isValidNameForFrame(std::u16string_view sName)
+{
+ // some special targets are really special ones :-)
+ // E.g. the are really used to locate one frame inside the frame tree.
+ if (
+ (sName.empty() ) ||
+ (TargetHelper::matchSpecialTarget(sName, ESpecialTarget::HelpTask)) ||
+ (TargetHelper::matchSpecialTarget(sName, ESpecialTarget::Beamer) )
+ )
+ return true;
+
+ // all other names must be checked more general
+ // special targets starts with a "_".
+ return (sName.find('_') != 0);
+}
+
+} // namespace framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */