xref: /core/framework/source/loadenv/loadenv.cxx (revision 602c6097)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <loadenv/loadenv.hxx>
21 
22 #include <loadenv/targethelper.hxx>
23 #include <framework/framelistanalyzer.hxx>
24 
25 #include <interaction/quietinteraction.hxx>
26 #include <properties.h>
27 #include <protocols.h>
28 #include <services.h>
29 #include <comphelper/interaction.hxx>
30 #include <comphelper/lok.hxx>
31 #include <comphelper/namedvaluecollection.hxx>
32 #include <comphelper/propertysequence.hxx>
33 #include <framework/interaction.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <officecfg/Office/Common.hxx>
36 
37 #include <com/sun/star/awt/XWindow.hpp>
38 #include <com/sun/star/awt/XWindow2.hpp>
39 #include <com/sun/star/awt/XTopWindow.hpp>
40 #include <com/sun/star/container/XNameAccess.hpp>
41 #include <com/sun/star/container/XContainerQuery.hpp>
42 #include <com/sun/star/container/XEnumeration.hpp>
43 #include <com/sun/star/document/MacroExecMode.hpp>
44 #include <com/sun/star/document/XTypeDetection.hpp>
45 #include <com/sun/star/document/XActionLockable.hpp>
46 #include <com/sun/star/document/UpdateDocMode.hpp>
47 #include <com/sun/star/frame/Desktop.hpp>
48 #include <com/sun/star/frame/OfficeFrameLoader.hpp>
49 #include <com/sun/star/frame/XModel.hpp>
50 #include <com/sun/star/frame/XFrameLoader.hpp>
51 #include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
52 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
53 #include <com/sun/star/frame/FrameLoaderFactory.hpp>
54 #include <com/sun/star/frame/ContentHandlerFactory.hpp>
55 #include <com/sun/star/frame/DispatchResultState.hpp>
56 #include <com/sun/star/frame/FrameSearchFlag.hpp>
57 #include <com/sun/star/frame/XDispatchProvider.hpp>
58 #include <com/sun/star/lang/XComponent.hpp>
59 #include <com/sun/star/lang/XInitialization.hpp>
60 #include <com/sun/star/lang/XServiceInfo.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>
75 
76 #include <vcl/window.hxx>
77 #include <vcl/wrkwin.hxx>
78 #include <vcl/syswin.hxx>
79 
80 #include <toolkit/helper/vclunohelper.hxx>
81 #include <unotools/moduleoptions.hxx>
82 #include <svtools/sfxecode.hxx>
83 #include <unotools/ucbhelper.hxx>
84 #include <comphelper/configurationhelper.hxx>
85 #include <rtl/ustrbuf.hxx>
86 #include <rtl/bootstrap.hxx>
87 #include <sal/log.hxx>
88 #include <vcl/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>
94 
95 const char PROP_TYPES[] = "Types";
96 const char PROP_NAME[] = "Name";
97 
98 namespace framework {
99 
100 using namespace com::sun::star;
101 
102 class LoadEnvListener : public ::cppu::WeakImplHelper< css::frame::XLoadEventListener      ,
103                                                         css::frame::XDispatchResultListener >
104 {
105     private:
106         osl::Mutex m_mutex;
107         bool m_bWaitingResult;
108         LoadEnv* m_pLoadEnv;
109 
110     public:
111 
112         explicit LoadEnvListener(LoadEnv* pLoadEnv)
113             : m_bWaitingResult(true)
114             , m_pLoadEnv(pLoadEnv)
115         {
116         }
117 
118         // frame.XLoadEventListener
119         virtual void SAL_CALL loadFinished(const css::uno::Reference< css::frame::XFrameLoader >& xLoader) override;
120 
121         virtual void SAL_CALL loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >& xLoader) override;
122 
123         // frame.XDispatchResultListener
124         virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent& aEvent) override;
125 
126         // lang.XEventListener
127         virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
128 };
129 
130 LoadEnv::LoadEnv(const css::uno::Reference< css::uno::XComponentContext >& xContext)
131     : m_xContext(xContext)
132     , m_nSearchFlags(0)
133     , m_eFeature(LoadEnvFeatures::NONE)
134     , m_eContentType(E_UNSUPPORTED_CONTENT)
135     , m_bCloseFrameOnError(false)
136     , m_bReactivateControllerOnError(false)
137     , m_bLoaded( false )
138 {
139 }
140 
141 LoadEnv::~LoadEnv()
142 {
143 }
144 
145 css::uno::Reference< css::lang::XComponent > LoadEnv::loadComponentFromURL(const css::uno::Reference< css::frame::XComponentLoader >&    xLoader,
146                                                                            const css::uno::Reference< css::uno::XComponentContext >&     xContext  ,
147                                                                            const OUString&                                        sURL   ,
148                                                                            const OUString&                                        sTarget,
149                                                                                  sal_Int32                                               nSearchFlags ,
150                                                                            const css::uno::Sequence< css::beans::PropertyValue >&        lArgs  )
151 {
152     css::uno::Reference< css::lang::XComponent > xComponent;
153     comphelper::ProfileZone aZone("loadComponentFromURL");
154 
155     try
156     {
157         LoadEnv aEnv(xContext);
158 
159         LoadEnvFeatures loadEnvFeatures = LoadEnvFeatures::WorkWithUI;
160         comphelper::NamedValueCollection aDescriptor( lArgs );
161         // tdf#118238 Only disable UI interaction when loading as hidden
162         if (aDescriptor.get("Hidden") == uno::Any(true) || Application::IsHeadlessModeEnabled())
163             loadEnvFeatures = LoadEnvFeatures::NONE;
164 
165         aEnv.initializeLoading(sURL,
166                                lArgs,
167                                css::uno::Reference< css::frame::XFrame >(xLoader, css::uno::UNO_QUERY),
168                                sTarget,
169                                nSearchFlags,
170                                loadEnvFeatures);
171         aEnv.startLoading();
172         aEnv.waitWhileLoading(); // wait for ever!
173 
174         xComponent = aEnv.getTargetComponent();
175     }
176     catch(const LoadEnvException& ex)
177     {
178         switch(ex.m_nID)
179         {
180             case LoadEnvException::ID_INVALID_MEDIADESCRIPTOR:
181                 throw css::lang::IllegalArgumentException(
182                     "Optional list of arguments seem to be corrupted.", xLoader, 4);
183 
184             case LoadEnvException::ID_UNSUPPORTED_CONTENT:
185                 throw css::lang::IllegalArgumentException(
186                     "Unsupported URL <" + sURL + ">: \"" + ex.m_sMessage + "\"",
187                     xLoader, 1);
188 
189             default:
190                 SAL_WARN(
191                     "fwk.loadenv",
192                     "caught LoadEnvException " << +ex.m_nID << " \""
193                         << ex.m_sMessage << "\""
194                         << (ex.m_exOriginal.has<css::uno::Exception>()
195                             ? (", " + ex.m_exOriginal.getValueTypeName() + " \""
196                                + (ex.m_exOriginal.get<css::uno::Exception>().
197                                   Message)
198                                + "\"")
199                             : OUString())
200                         << " while loading <" << sURL << ">");
201                 xComponent.clear();
202                 break;
203         }
204     }
205 
206     return xComponent;
207 }
208 
209 namespace {
210 
211 utl::MediaDescriptor addModelArgs(const uno::Sequence<beans::PropertyValue>& rDescriptor)
212 {
213     utl::MediaDescriptor rResult(rDescriptor);
214     uno::Reference<frame::XModel> xModel(rResult.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MODEL(), uno::Reference<frame::XModel>()));
215 
216     if (xModel.is())
217     {
218         utl::MediaDescriptor aModelArgs(xModel->getArgs());
219         utl::MediaDescriptor::iterator pIt = aModelArgs.find( utl::MediaDescriptor::PROP_MACROEXECUTIONMODE());
220         if (pIt != aModelArgs.end())
221             rResult[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()] = pIt->second;
222     }
223 
224     return rResult;
225 }
226 
227 }
228 
229 void LoadEnv::initializeLoading(const OUString& sURL, const uno::Sequence<beans::PropertyValue>& lMediaDescriptor,
230         const uno::Reference<frame::XFrame>& xBaseFrame, const OUString& sTarget,
231         sal_Int32 nSearchFlags, LoadEnvFeatures eFeature)
232 {
233     osl::MutexGuard g(m_mutex);
234 
235     // Handle still running processes!
236     if (m_xAsynchronousJob.is())
237         throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
238 
239     // take over all new parameters.
240     m_xTargetFrame.clear();
241     m_xBaseFrame = xBaseFrame;
242     m_lMediaDescriptor = addModelArgs(lMediaDescriptor);
243     m_sTarget = sTarget;
244     m_nSearchFlags = nSearchFlags;
245     m_eFeature = eFeature;
246     m_eContentType = E_UNSUPPORTED_CONTENT;
247     m_bCloseFrameOnError = false;
248     m_bReactivateControllerOnError = false;
249     m_bLoaded = false;
250 
251     OUString aRealURL;
252     if (!tools::IsMappedWebDAVPath(sURL, &aRealURL))
253         aRealURL = sURL;
254 
255     // try to find out, if it's really a content, which can be loaded or must be "handled"
256     // We use a default value for this in-parameter. Then we have to start a complex check method
257     // internally. But if this check was already done outside it can be suppressed to perform
258     // the load request. We take over the result then!
259     m_eContentType = LoadEnv::classifyContent(aRealURL, lMediaDescriptor);
260     if (m_eContentType == E_UNSUPPORTED_CONTENT)
261         throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT, "from LoadEnv::initializeLoading");
262 
263     // make URL part of the MediaDescriptor
264     // It doesn't matter if it is already an item of it.
265     // It must be the same value... so we can overwrite it :-)
266     m_lMediaDescriptor[utl::MediaDescriptor::PROP_URL()] <<= aRealURL;
267 
268     // parse it - because some following code require that
269     m_aURL.Complete = aRealURL;
270     uno::Reference<util::XURLTransformer> xParser(util::URLTransformer::create(m_xContext));
271     xParser->parseStrict(m_aURL);
272 
273     // BTW: Split URL and JumpMark ...
274     // Because such mark is an explicit value of the media descriptor!
275     if (!m_aURL.Mark.isEmpty())
276         m_lMediaDescriptor[utl::MediaDescriptor::PROP_JUMPMARK()] <<= m_aURL.Mark;
277 
278     // By the way: remove the old and deprecated value "FileName" from the descriptor!
279     utl::MediaDescriptor::iterator pIt = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FILENAME());
280     if (pIt != m_lMediaDescriptor.end())
281         m_lMediaDescriptor.erase(pIt);
282 
283     // patch the MediaDescriptor, so it fulfil the outside requirements
284     // Means especially items like e.g. UI InteractionHandler, Status Indicator,
285     // MacroExecutionMode, etc.
286 
287     /*TODO progress is bound to a frame ... How can we set it here? */
288 
289     // UI mode
290     const bool bUIMode =
291         (m_eFeature & LoadEnvFeatures::WorkWithUI) &&
292         !m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false) &&
293         !m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW(), false);
294 
295     initializeUIDefaults(m_xContext, m_lMediaDescriptor, bUIMode, &m_pQuietInteraction);
296 }
297 
298 void LoadEnv::initializeUIDefaults( const css::uno::Reference< css::uno::XComponentContext >& i_rxContext,
299                                     utl::MediaDescriptor& io_lMediaDescriptor, const bool i_bUIMode,
300                                     rtl::Reference<QuietInteraction>* o_ppQuietInteraction )
301 {
302     css::uno::Reference< css::task::XInteractionHandler > xInteractionHandler;
303     sal_Int16                                             nMacroMode;
304     sal_Int16                                             nUpdateMode;
305 
306     if ( i_bUIMode )
307     {
308         nMacroMode  = css::document::MacroExecMode::USE_CONFIG;
309         nUpdateMode = css::document::UpdateDocMode::ACCORDING_TO_CONFIG;
310         try
311         {
312             xInteractionHandler.set( css::task::InteractionHandler::createWithParent( i_rxContext, nullptr ), css::uno::UNO_QUERY_THROW );
313         }
314         catch(const css::uno::RuntimeException&) {throw;}
315         catch(const css::uno::Exception&       ) {      }
316     }
317     // hidden mode
318     else
319     {
320         nMacroMode  = css::document::MacroExecMode::NEVER_EXECUTE;
321         nUpdateMode = css::document::UpdateDocMode::NO_UPDATE;
322         rtl::Reference<QuietInteraction> pQuietInteraction = new QuietInteraction();
323         xInteractionHandler = pQuietInteraction.get();
324         if ( o_ppQuietInteraction != nullptr )
325         {
326             *o_ppQuietInteraction = pQuietInteraction;
327         }
328     }
329 
330     if ( xInteractionHandler.is() )
331     {
332         if( io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_INTERACTIONHANDLER()) == io_lMediaDescriptor.end() )
333         {
334             io_lMediaDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteractionHandler;
335         }
336         if( io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER()) == io_lMediaDescriptor.end() )
337         {
338             io_lMediaDescriptor[utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER()] <<= xInteractionHandler;
339         }
340     }
341 
342     if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()) == io_lMediaDescriptor.end())
343         io_lMediaDescriptor[utl::MediaDescriptor::PROP_MACROEXECUTIONMODE()] <<= nMacroMode;
344 
345     if (io_lMediaDescriptor.find(utl::MediaDescriptor::PROP_UPDATEDOCMODE()) == io_lMediaDescriptor.end())
346         io_lMediaDescriptor[utl::MediaDescriptor::PROP_UPDATEDOCMODE()] <<= nUpdateMode;
347 }
348 
349 void LoadEnv::startLoading()
350 {
351     // SAFE ->
352     {
353         osl::MutexGuard aReadLock(m_mutex);
354 
355         // Handle still running processes!
356         if (m_xAsynchronousJob.is())
357             throw LoadEnvException(LoadEnvException::ID_STILL_RUNNING);
358 
359         // content can not be loaded or handled
360         // check "classifyContent()" failed before ...
361         if (m_eContentType == E_UNSUPPORTED_CONTENT)
362             throw LoadEnvException(LoadEnvException::ID_UNSUPPORTED_CONTENT,
363                                    "from LoadEnv::startLoading");
364     }
365     // <- SAFE
366 
367     // detect its type/filter etc.
368     // This information will be available by the
369     // used descriptor member afterwards and is needed
370     // for all following operations!
371     // Note: An exception will be thrown, in case operation was not successfully ...
372     if (m_eContentType != E_CAN_BE_SET)/* Attention: special feature to set existing component on a frame must ignore type detection! */
373         impl_detectTypeAndFilter();
374 
375     // start loading the content...
376     // Attention: Don't check m_eContentType deeper then UNSUPPORTED/SUPPORTED!
377     // Because it was made in the easiest way... may a flat detection was made only.
378     // And such simple detection can fail sometimes .-)
379     // Use another strategy here. Try it and let it run into the case "loading not possible".
380     bool bStarted = false;
381     if (
382         (m_eFeature & LoadEnvFeatures::AllowContentHandler) &&
383         (m_eContentType                        != E_CAN_BE_SET          )   /* Attention: special feature to set existing component on a frame must ignore type detection! */
384        )
385     {
386         bStarted = impl_handleContent();
387     }
388 
389     if (!bStarted)
390         bStarted = impl_loadContent();
391 
392     // not started => general error
393     // We can't say - what was the reason for.
394     if (!bStarted)
395         throw LoadEnvException(
396             LoadEnvException::ID_GENERAL_ERROR, "not started");
397 }
398 
399 /*-----------------------------------------------
400     TODO
401         First draft does not implement timeout using [ms].
402         Current implementation counts yield calls only ...
403 -----------------------------------------------*/
404 bool LoadEnv::waitWhileLoading(sal_uInt32 nTimeout)
405 {
406     // Because it's not a good idea to block the main thread
407     // (and we can't be sure that we are currently not used inside the
408     // main thread!), we can't use conditions here really. We must yield
409     // in an intelligent manner :-)
410 
411     sal_Int32 nTime = nTimeout;
412     while(true)
413     {
414         // SAFE -> ------------------------------
415         {
416             osl::MutexGuard aReadLock1(m_mutex);
417             if (!m_xAsynchronousJob.is())
418                 break;
419         }
420         // <- SAFE ------------------------------
421 
422         Application::Yield();
423 
424         // forever!
425         if (nTimeout==0)
426             continue;
427 
428         // timed out?
429         --nTime;
430         if (nTime<1)
431             break;
432     }
433 
434     osl::MutexGuard g(m_mutex);
435     return !m_xAsynchronousJob.is();
436 }
437 
438 css::uno::Reference< css::lang::XComponent > LoadEnv::getTargetComponent() const
439 {
440     osl::MutexGuard g(m_mutex);
441 
442     if (!m_xTargetFrame.is())
443         return css::uno::Reference< css::lang::XComponent >();
444 
445     css::uno::Reference< css::frame::XController > xController = m_xTargetFrame->getController();
446     if (!xController.is())
447         return m_xTargetFrame->getComponentWindow();
448 
449     css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
450     if (!xModel.is())
451         return xController;
452 
453     return xModel;
454 }
455 
456 void SAL_CALL LoadEnvListener::loadFinished(const css::uno::Reference< css::frame::XFrameLoader >&)
457 {
458     osl::MutexGuard g(m_mutex);
459     if (m_bWaitingResult)
460         m_pLoadEnv->impl_setResult(true);
461     m_bWaitingResult = false;
462 }
463 
464 void SAL_CALL LoadEnvListener::loadCancelled(const css::uno::Reference< css::frame::XFrameLoader >&)
465 {
466     osl::MutexGuard g(m_mutex);
467     if (m_bWaitingResult)
468         m_pLoadEnv->impl_setResult(false);
469     m_bWaitingResult = false;
470 }
471 
472 void SAL_CALL LoadEnvListener::dispatchFinished(const css::frame::DispatchResultEvent& aEvent)
473 {
474     osl::MutexGuard g(m_mutex);
475 
476     if (!m_bWaitingResult)
477         return;
478 
479     switch(aEvent.State)
480     {
481         case css::frame::DispatchResultState::FAILURE :
482             m_pLoadEnv->impl_setResult(false);
483             break;
484 
485         case css::frame::DispatchResultState::SUCCESS :
486             m_pLoadEnv->impl_setResult(false);
487             break;
488 
489         case css::frame::DispatchResultState::DONTKNOW :
490             m_pLoadEnv->impl_setResult(false);
491             break;
492     }
493     m_bWaitingResult = false;
494 }
495 
496 void SAL_CALL LoadEnvListener::disposing(const css::lang::EventObject&)
497 {
498     osl::MutexGuard g(m_mutex);
499     if (m_bWaitingResult)
500         m_pLoadEnv->impl_setResult(false);
501     m_bWaitingResult = false;
502 }
503 
504 void LoadEnv::impl_setResult(bool bResult)
505 {
506     osl::MutexGuard g(m_mutex);
507 
508     m_bLoaded = bResult;
509 
510     impl_reactForLoadingState();
511 
512     // clearing of this reference will unblock waitWhileLoading()!
513     // So we must be sure, that loading process was really finished.
514     // => do it as last operation of this method ...
515     m_xAsynchronousJob.clear();
516 }
517 
518 /*-----------------------------------------------
519     TODO: Is it a good idea to change Sequence<>
520           parameter to stl-adapter?
521 -----------------------------------------------*/
522 LoadEnv::EContentType LoadEnv::classifyContent(const OUString&                                 sURL            ,
523                                                const css::uno::Sequence< css::beans::PropertyValue >& lMediaDescriptor)
524 {
525 
526     // (i) Filter some special well known URL protocols,
527     //     which can not be handled or loaded in general.
528     //     Of course an empty URL must be ignored here too.
529     //     Note: These URL schemata are fix and well known ...
530     //     But there can be some additional ones, which was not
531     //     defined at implementation time of this class :-(
532     //     So we have to make sure, that the following code
533     //     can detect such protocol schemata too :-)
534 
535     if(
536         (sURL.isEmpty()                                          ) ||
537         (ProtocolCheck::isProtocol(sURL,EProtocol::Uno    )) ||
538         (ProtocolCheck::isProtocol(sURL,EProtocol::Slot   )) ||
539         (ProtocolCheck::isProtocol(sURL,EProtocol::Macro  )) ||
540         (ProtocolCheck::isProtocol(sURL,EProtocol::Service)) ||
541         (ProtocolCheck::isProtocol(sURL,EProtocol::MailTo )) ||
542         (ProtocolCheck::isProtocol(sURL,EProtocol::News   ))
543       )
544     {
545         return E_UNSUPPORTED_CONTENT;
546     }
547 
548     // (ii) Some special URLs indicates a given input stream,
549     //      a full featured document model directly or
550     //      specify a request for opening an empty document.
551     //      Such contents are loadable in general.
552     //      But we have to check, if the media descriptor contains
553     //      all needed resources. If they are missing - the following
554     //      load request will fail.
555 
556     /* Attention: The following code can't work on such special URLs!
557                   It should not break the office .. but it makes no sense
558                   to start expensive object creations and complex search
559                   algorithm if its clear, that such URLs must be handled
560                   in a special way .-)
561     */
562 
563     // creation of new documents
564     if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateFactory))
565         return E_CAN_BE_LOADED;
566 
567     // using of an existing input stream
568     utl::MediaDescriptor                 stlMediaDescriptor(lMediaDescriptor);
569     utl::MediaDescriptor::const_iterator pIt;
570     if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateStream))
571     {
572         pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_INPUTSTREAM());
573         css::uno::Reference< css::io::XInputStream > xStream;
574         if (pIt != stlMediaDescriptor.end())
575             pIt->second >>= xStream;
576         if (xStream.is())
577             return E_CAN_BE_LOADED;
578         SAL_INFO("fwk.loadenv", "LoadEnv::classifyContent(): loading from stream with right URL but invalid stream detected");
579         return E_UNSUPPORTED_CONTENT;
580     }
581 
582     // using of a full featured document
583     if (ProtocolCheck::isProtocol(sURL,EProtocol::PrivateObject))
584     {
585         pIt = stlMediaDescriptor.find(utl::MediaDescriptor::PROP_MODEL());
586         css::uno::Reference< css::frame::XModel > xModel;
587         if (pIt != stlMediaDescriptor.end())
588             pIt->second >>= xModel;
589         if (xModel.is())
590             return E_CAN_BE_SET;
591         SAL_INFO("fwk.loadenv", "LoadEnv::classifyContent(): loading with object with right URL but invalid object detected");
592         return E_UNSUPPORTED_CONTENT;
593     }
594 
595     // following operations can work on an internal type name only :-(
596     css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
597     css::uno::Reference< css::document::XTypeDetection > xDetect(
598          xContext->getServiceManager()->createInstanceWithContext(
599              "com.sun.star.document.TypeDetection", xContext),
600          css::uno::UNO_QUERY_THROW);
601 
602     OUString sType = xDetect->queryTypeByURL(sURL);
603 
604     css::uno::Sequence< css::beans::NamedValue >           lQuery(1);
605     css::uno::Reference< css::frame::XLoaderFactory >      xLoaderFactory;
606     css::uno::Reference< css::container::XEnumeration >    xSet;
607     css::uno::Sequence< OUString >                  lTypesReg(1);
608 
609     // (iii) If a FrameLoader service (or at least
610     //      a Filter) can be found, which supports
611     //      this URL - it must be a loadable content.
612     //      Because both items are registered for types
613     //      it's enough to check for frame loaders only.
614     //      Mos of our filters are handled by our global
615     //      default loader. But there exist some specialized
616     //      loader, which does not work on top of filters!
617     //      So it's not enough to search on the filter configuration.
618     //      Further it's not enough to search for types!
619     //      Because there exist some types, which are referenced by
620     //      other objects... but not by filters nor frame loaders!
621 
622     OUString sPROP_TYPES(PROP_TYPES);
623 
624     lTypesReg[0]      = sType;
625     lQuery[0].Name    = sPROP_TYPES;
626     lQuery[0].Value <<= lTypesReg;
627 
628     xLoaderFactory = css::frame::FrameLoaderFactory::create(xContext);
629     xSet       = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
630     // at least one registered frame loader is enough!
631     if (xSet->hasMoreElements())
632         return E_CAN_BE_LOADED;
633 
634     // (iv) Some URL protocols are supported by special services.
635     //      E.g. ContentHandler.
636     //      Such contents can be handled ... but not loaded.
637 
638     lTypesReg[0]      = sType;
639     lQuery[0].Name    = sPROP_TYPES;
640     lQuery[0].Value <<= lTypesReg;
641 
642     xLoaderFactory = css::frame::ContentHandlerFactory::create(xContext);
643     xSet       = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
644     // at least one registered content handler is enough!
645     if (xSet->hasMoreElements())
646         return E_CAN_BE_HANDLED;
647 
648     // (v) Last but not least the UCB is used inside office to
649     //     load contents. He has a special configuration to know
650     //     which URL schemata can be used inside office.
651     css::uno::Reference< css::ucb::XUniversalContentBroker > xUCB(css::ucb::UniversalContentBroker::create(xContext));
652     if (xUCB->queryContentProvider(sURL).is())
653         return E_CAN_BE_LOADED;
654 
655     // (TODO) At this point, we have no idea .-)
656     //        But it seems to be better, to break all
657     //        further requests for this URL. Otherwise
658     //        we can run into some trouble.
659     return E_UNSUPPORTED_CONTENT;
660 }
661 
662 namespace {
663 
664 bool queryOrcusTypeAndFilter(const uno::Sequence<beans::PropertyValue>& rDescriptor, OUString& rType, OUString& rFilter)
665 {
666     OUString aURL;
667     sal_Int32 nSize = rDescriptor.getLength();
668     for (sal_Int32 i = 0; i < nSize; ++i)
669     {
670         const beans::PropertyValue& rProp = rDescriptor[i];
671         if (rProp.Name == "URL")
672         {
673             rProp.Value >>= aURL;
674             break;
675         }
676     }
677 
678     if (aURL.isEmpty() || aURL.copy(0,8).equalsIgnoreAsciiCase("private:"))
679         return false;
680 
681     // TODO : Type must be set to be generic_Text (or any other type that
682     // exists) in order to find a usable loader. Exploit it as a temporary
683     // hack.
684 
685     // depending on the experimental mode
686     uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
687     if (!xContext.is() || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext))
688     {
689         return false;
690     }
691 
692     OUString aUseOrcus;
693     rtl::Bootstrap::get("LIBO_USE_ORCUS", aUseOrcus);
694     bool bUseOrcus = (aUseOrcus == "YES");
695 
696     if (!bUseOrcus)
697         return false;
698 
699     if (aURL.endsWith(".xlsx"))
700     {
701         rType = "generic_Text";
702         rFilter = "xlsx";
703         return true;
704     }
705     else if (aURL.endsWith(".ods"))
706     {
707         rType = "generic_Text";
708         rFilter = "ods";
709         return true;
710     }
711     else if (aURL.endsWith(".csv"))
712     {
713         rType = "generic_Text";
714         rFilter = "csv";
715         return true;
716     }
717 
718     return false;
719 }
720 
721 }
722 
723 void LoadEnv::impl_detectTypeAndFilter()
724 {
725     static const sal_Int32 FILTERFLAG_TEMPLATEPATH  = 16;
726 
727     // SAFE ->
728     osl::ClearableMutexGuard aReadLock(m_mutex);
729 
730     // Attention: Because our stl media descriptor is a copy of a uno sequence
731     // we can't use as an in/out parameter here. Copy it before and don't forget to
732     // update structure afterwards again!
733     css::uno::Sequence< css::beans::PropertyValue >        lDescriptor = m_lMediaDescriptor.getAsConstPropertyValueList();
734     css::uno::Reference< css::uno::XComponentContext >     xContext = m_xContext;
735 
736     aReadLock.clear();
737     // <- SAFE
738 
739     OUString sType, sFilter;
740 
741     if (queryOrcusTypeAndFilter(lDescriptor, sType, sFilter) && !sType.isEmpty() && !sFilter.isEmpty())
742     {
743         // Orcus type detected.  Skip the normal type detection process.
744         m_lMediaDescriptor << lDescriptor;
745         m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType;
746         m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
747         m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERPROVIDER()] <<= OUString("orcus");
748         m_lMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTSERVICE()] <<= OUString("com.sun.star.sheet.SpreadsheetDocument");
749         return;
750     }
751 
752     css::uno::Reference< css::document::XTypeDetection > xDetect(
753         xContext->getServiceManager()->createInstanceWithContext(
754             "com.sun.star.document.TypeDetection", xContext),
755         css::uno::UNO_QUERY_THROW);
756     sType = xDetect->queryTypeByDescriptor(lDescriptor, true); /*TODO should deep detection be able for enable/disable it from outside? */
757 
758     // no valid content -> loading not possible
759     if (sType.isEmpty())
760         throw LoadEnvException(
761             LoadEnvException::ID_UNSUPPORTED_CONTENT, "type detection failed");
762 
763     // SAFE ->
764     osl::ResettableMutexGuard aWriteLock(m_mutex);
765 
766     // detection was successful => update the descriptor member of this class
767     m_lMediaDescriptor << lDescriptor;
768     m_lMediaDescriptor[utl::MediaDescriptor::PROP_TYPENAME()] <<= sType;
769     // Is there an already detected (may be preselected) filter?
770     // see below ...
771     sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
772 
773     aWriteLock.clear();
774     // <- SAFE
775 
776     // We do have potentially correct type, but the detection process was aborted.
777     if (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ABORTED(), false))
778         throw LoadEnvException(
779             LoadEnvException::ID_UNSUPPORTED_CONTENT, "type detection aborted");
780 
781     // But the type isn't enough. For loading sometimes we need more information.
782     // E.g. for our "_default" feature, where we recycle any frame which contains
783     // and "Untitled" document, we must know if the new document is based on a template!
784     // But this information is available as a filter property only.
785     // => We must try(!) to detect the right filter for this load request.
786     // On the other side ... if no filter is available .. ignore it.
787     // Then the type information must be enough.
788     if (sFilter.isEmpty())
789     {
790         // no -> try to find a preferred filter for the detected type.
791         // Don't forget to update the media descriptor.
792         css::uno::Reference< css::container::XNameAccess > xTypeCont(xDetect, css::uno::UNO_QUERY_THROW);
793         try
794         {
795             ::comphelper::SequenceAsHashMap lTypeProps(xTypeCont->getByName(sType));
796             sFilter = lTypeProps.getUnpackedValueOrDefault("PreferredFilter", OUString());
797             if (!sFilter.isEmpty())
798             {
799                 // SAFE ->
800                 aWriteLock.reset();
801                 m_lMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= sFilter;
802                 aWriteLock.clear();
803                 // <- SAFE
804             }
805         }
806         catch(const css::container::NoSuchElementException&)
807             {}
808     }
809 
810     // check if the filter (if one exists) points to a template format filter.
811     // Then we have to add the property "AsTemplate".
812     // We need this information to decide afterwards if we can use a "recycle frame"
813     // for target "_default" or has to create a new one every time.
814     // On the other side we have to suppress that, if this property already exists
815     // and should trigger a special handling. Then the outside call of this method here,
816     // has to know, what he is doing .-)
817 
818     bool bIsOwnTemplate = false;
819     if (!sFilter.isEmpty())
820     {
821         css::uno::Reference< css::container::XNameAccess > xFilterCont(xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext), css::uno::UNO_QUERY_THROW);
822         try
823         {
824             ::comphelper::SequenceAsHashMap lFilterProps(xFilterCont->getByName(sFilter));
825             sal_Int32 nFlags         = lFilterProps.getUnpackedValueOrDefault("Flags", sal_Int32(0));
826             bIsOwnTemplate = ((nFlags & FILTERFLAG_TEMPLATEPATH) == FILTERFLAG_TEMPLATEPATH);
827         }
828         catch(const css::container::NoSuchElementException&)
829             {}
830     }
831     if (bIsOwnTemplate)
832     {
833         // SAFE ->
834         aWriteLock.reset();
835         // Don't overwrite external decisions! See comments before ...
836         utl::MediaDescriptor::const_iterator pAsTemplateItem = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_ASTEMPLATE());
837         if (pAsTemplateItem == m_lMediaDescriptor.end())
838             m_lMediaDescriptor[utl::MediaDescriptor::PROP_ASTEMPLATE()] <<= true;
839         aWriteLock.clear();
840         // <- SAFE
841     }
842 }
843 
844 bool LoadEnv::impl_handleContent()
845 {
846     // SAFE -> -----------------------------------
847     osl::ClearableMutexGuard aReadLock(m_mutex);
848 
849     // the type must exist inside the descriptor ... otherwise this class is implemented wrong :-)
850     OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
851     if (sType.isEmpty())
852         throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
853 
854     // convert media descriptor and URL to right format for later interface call!
855     css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
856     m_lMediaDescriptor >> lDescriptor;
857     css::util::URL aURL = m_aURL;
858 
859     // get necessary container to query for a handler object
860     css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::ContentHandlerFactory::create(m_xContext);
861 
862     aReadLock.clear();
863     // <- SAFE -----------------------------------
864 
865     // query
866     css::uno::Sequence< OUString > lTypeReg { sType };
867 
868     css::uno::Sequence< css::beans::NamedValue > lQuery { { PROP_TYPES, css::uno::makeAny(lTypeReg) } };
869 
870     css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
871     while(xSet->hasMoreElements())
872     {
873         ::comphelper::SequenceAsHashMap lProps   (xSet->nextElement());
874         OUString                 sHandler = lProps.getUnpackedValueOrDefault(PROP_NAME, OUString());
875 
876         css::uno::Reference< css::frame::XNotifyingDispatch > xHandler;
877         try
878         {
879             xHandler.set(xLoaderFactory->createInstance(sHandler), css::uno::UNO_QUERY);
880             if (!xHandler.is())
881                 continue;
882         }
883         catch(const css::uno::RuntimeException&)
884             { throw; }
885         catch(const css::uno::Exception&)
886             { continue; }
887 
888         // SAFE -> -----------------------------------
889         osl::ClearableMutexGuard aWriteLock(m_mutex);
890         m_xAsynchronousJob = xHandler;
891         LoadEnvListener* pListener = new LoadEnvListener(this);
892         aWriteLock.clear();
893         // <- SAFE -----------------------------------
894 
895         css::uno::Reference< css::frame::XDispatchResultListener > xListener(static_cast< css::frame::XDispatchResultListener* >(pListener), css::uno::UNO_QUERY);
896         xHandler->dispatchWithNotification(aURL, lDescriptor, xListener);
897 
898         return true;
899     }
900 
901     return false;
902 }
903 
904 bool LoadEnv::impl_furtherDocsAllowed()
905 {
906     // SAFE ->
907     osl::ResettableMutexGuard aReadLock(m_mutex);
908     css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
909     aReadLock.clear();
910     // <- SAFE
911 
912     bool bAllowed = true;
913 
914     try
915     {
916         css::uno::Any aVal = ::comphelper::ConfigurationHelper::readDirectKey(
917                                 xContext,
918                                 "org.openoffice.Office.Common/",
919                                 "Misc",
920                                 "MaxOpenDocuments",
921                                 ::comphelper::EConfigurationModes::ReadOnly);
922 
923         // NIL means: count of allowed documents = infinite !
924         //     => return sal_True
925         if ( ! aVal.hasValue())
926             bAllowed = true;
927         else
928         {
929             sal_Int32 nMaxOpenDocuments = 0;
930             aVal >>= nMaxOpenDocuments;
931 
932             css::uno::Reference< css::frame::XFramesSupplier > xDesktop(
933                 css::frame::Desktop::create(xContext),
934                 css::uno::UNO_QUERY_THROW);
935 
936             FrameListAnalyzer aAnalyzer(xDesktop,
937                                         css::uno::Reference< css::frame::XFrame >(),
938                                         FrameAnalyzerFlags::Help |
939                                         FrameAnalyzerFlags::BackingComponent |
940                                         FrameAnalyzerFlags::Hidden);
941 
942             sal_Int32 nOpenDocuments = aAnalyzer.m_lOtherVisibleFrames.size();
943             bAllowed       = (nOpenDocuments < nMaxOpenDocuments);
944         }
945     }
946     catch(const css::uno::Exception&)
947         { bAllowed = true; } // !! internal errors are no reason to disturb the office from opening documents .-)
948 
949     if ( ! bAllowed )
950     {
951         // SAFE ->
952         aReadLock.reset();
953         css::uno::Reference< css::task::XInteractionHandler > xInteraction = m_lMediaDescriptor.getUnpackedValueOrDefault(
954                                                                                 utl::MediaDescriptor::PROP_INTERACTIONHANDLER(),
955                                                                                 css::uno::Reference< css::task::XInteractionHandler >());
956         aReadLock.clear();
957         // <- SAFE
958 
959         if (xInteraction.is())
960         {
961             css::uno::Any                                                                    aInteraction;
962             css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations(2);
963 
964             comphelper::OInteractionAbort*   pAbort   = new comphelper::OInteractionAbort();
965             comphelper::OInteractionApprove* pApprove = new comphelper::OInteractionApprove();
966 
967             lContinuations[0].set( static_cast< css::task::XInteractionContinuation* >(pAbort),
968                                    css::uno::UNO_QUERY_THROW);
969             lContinuations[1].set( static_cast< css::task::XInteractionContinuation* >(pApprove),
970                                    css::uno::UNO_QUERY_THROW);
971 
972             css::task::ErrorCodeRequest aErrorCode;
973             aErrorCode.ErrCode = sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED);
974             aInteraction <<= aErrorCode;
975             xInteraction->handle( InteractionRequest::CreateRequest(aInteraction, lContinuations) );
976         }
977     }
978 
979     return bAllowed;
980 }
981 
982 bool LoadEnv::impl_filterHasInteractiveDialog() const
983 {
984     //show the frame now so it can be the parent for any message dialogs shown during import
985 
986     //unless (tdf#114648) an Interactive case such as the new database wizard
987     if (m_aURL.Arguments == "Interactive")
988        return true;
989 
990     // unless (tdf#116277) its the labels/business cards slave frame
991     if (m_aURL.Arguments.indexOf("slot=") != -1)
992         return true;
993 
994     OUString sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_FILTERNAME(), OUString());
995     if (sFilter.isEmpty())
996         return false;
997 
998     // unless (tdf#115683) the filter has a UIComponent
999     OUString sUIComponent;
1000     css::uno::Reference<css::container::XNameAccess> xFilterCont(m_xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, m_xContext),
1001                                                                  css::uno::UNO_QUERY_THROW);
1002     try
1003     {
1004         ::comphelper::SequenceAsHashMap lFilterProps(xFilterCont->getByName(sFilter));
1005         sUIComponent = lFilterProps.getUnpackedValueOrDefault("UIComponent", OUString());
1006     }
1007     catch(const css::container::NoSuchElementException&)
1008     {
1009     }
1010 
1011     return !sUIComponent.isEmpty();
1012 }
1013 
1014 bool LoadEnv::impl_loadContent()
1015 {
1016     // SAFE -> -----------------------------------
1017     osl::ClearableMutexGuard aWriteLock(m_mutex);
1018 
1019     // search or create right target frame
1020     OUString sTarget = m_sTarget;
1021     if (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Default))
1022     {
1023         m_xTargetFrame = impl_searchAlreadyLoaded();
1024         if (m_xTargetFrame.is())
1025         {
1026             impl_setResult(true);
1027             return true;
1028         }
1029         m_xTargetFrame = impl_searchRecycleTarget();
1030     }
1031 
1032     if (! m_xTargetFrame.is())
1033     {
1034         if (
1035             (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Blank  )) ||
1036             (TargetHelper::matchSpecialTarget(sTarget, TargetHelper::ESpecialTarget::Default))
1037            )
1038         {
1039             if (! impl_furtherDocsAllowed())
1040                 return false;
1041             TaskCreator aCreator(m_xContext);
1042             m_xTargetFrame = aCreator.createTask(SPECIALTARGET_BLANK, m_lMediaDescriptor);
1043             m_bCloseFrameOnError = m_xTargetFrame.is();
1044         }
1045         else
1046         {
1047             sal_Int32 nSearchFlags = m_nSearchFlags & ~css::frame::FrameSearchFlag::CREATE;
1048             m_xTargetFrame   = m_xBaseFrame->findFrame(sTarget, nSearchFlags);
1049             if (! m_xTargetFrame.is())
1050             {
1051                 if (! impl_furtherDocsAllowed())
1052                     return false;
1053                 m_xTargetFrame       = m_xBaseFrame->findFrame(SPECIALTARGET_BLANK, 0);
1054                 m_bCloseFrameOnError = m_xTargetFrame.is();
1055             }
1056         }
1057     }
1058 
1059     // If we couldn't find a valid frame or the frame has no container window
1060     // we have to throw an exception.
1061     if (
1062         ( ! m_xTargetFrame.is()                       ) ||
1063         ( ! m_xTargetFrame->getContainerWindow().is() )
1064        )
1065         throw LoadEnvException(LoadEnvException::ID_NO_TARGET_FOUND);
1066 
1067     css::uno::Reference< css::frame::XFrame > xTargetFrame = m_xTargetFrame;
1068 
1069     // Now we have a valid frame ... and type detection was already done.
1070     // We should apply the module dependent window position and size to the
1071     // frame window.
1072     impl_applyPersistentWindowState(xTargetFrame->getContainerWindow());
1073 
1074     // Don't forget to lock task for following load process. Otherwise it could die
1075     // during this operation runs by terminating the office or closing this task via api.
1076     // If we set this lock "close()" will return false and closing will be broken.
1077     // Attention: Don't forget to reset this lock again after finishing operation.
1078     // Otherwise task AND office couldn't die!!!
1079     // This includes gracefully handling of Exceptions (Runtime!) too ...
1080     // That's why we use a specialized guard, which will reset the lock
1081     // if it will be run out of scope.
1082 
1083     // Note further: ignore if this internal guard already contains a resource.
1084     // Might impl_searchRecycleTarget() set it before. But in case this impl-method wasn't used
1085     // and the target frame was new created ... this lock here must be set!
1086     css::uno::Reference< css::document::XActionLockable > xTargetLock(xTargetFrame, css::uno::UNO_QUERY);
1087     m_aTargetLock.setResource(xTargetLock);
1088 
1089     // Add status indicator to descriptor. Loader can show a progress then.
1090     // But don't do it, if loading should be hidden or preview is used ...!
1091     // So we prevent our code against wrong using. Why?
1092     // It could be, that using of this progress could make trouble. e.g. He make window visible ...
1093     // but shouldn't do that. But if no indicator is available ... nobody has a chance to do that!
1094     bool bHidden    = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1095     bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED(), false);
1096     bool bPreview   = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW(), false);
1097     css::uno::Reference< css::task::XStatusIndicator > xProgress  = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR(), css::uno::Reference< css::task::XStatusIndicator >());
1098 
1099     if (!bHidden && !bMinimized && !bPreview)
1100     {
1101         if (!xProgress.is())
1102         {
1103             // Note: it's an optional interface!
1104             css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xTargetFrame, css::uno::UNO_QUERY);
1105             if (xProgressFactory.is())
1106             {
1107                 xProgress = xProgressFactory->createStatusIndicator();
1108                 if (xProgress.is())
1109                     m_lMediaDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xProgress;
1110             }
1111         }
1112 
1113         // Now that we have a target window into which we can load, reinit the interaction handler to have this
1114         // window as its parent for modal dialogs and ensure the window is visible
1115         css::uno::Reference< css::task::XInteractionHandler > xInteraction = m_lMediaDescriptor.getUnpackedValueOrDefault(
1116                                                                                 utl::MediaDescriptor::PROP_INTERACTIONHANDLER(),
1117                                                                                 css::uno::Reference< css::task::XInteractionHandler >());
1118         css::uno::Reference<css::lang::XInitialization> xHandler(xInteraction, css::uno::UNO_QUERY);
1119         if (xHandler.is())
1120         {
1121             css::uno::Reference<css::awt::XWindow> xWindow = xTargetFrame->getContainerWindow();
1122             uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
1123             {
1124                 {"Parent", uno::Any(xWindow)}
1125             }));
1126             xHandler->initialize(aArguments);
1127             //show the frame as early as possible to make it the parent of any message dialogs
1128             if (!impl_filterHasInteractiveDialog())
1129                 impl_makeFrameWindowVisible(xWindow, false);
1130         }
1131     }
1132 
1133     // convert media descriptor and URL to right format for later interface call!
1134     css::uno::Sequence< css::beans::PropertyValue > lDescriptor;
1135     m_lMediaDescriptor >> lDescriptor;
1136     OUString sURL = m_aURL.Complete;
1137 
1138     // try to locate any interested frame loader
1139     css::uno::Reference< css::uno::XInterface >                xLoader     = impl_searchLoader();
1140     css::uno::Reference< css::frame::XFrameLoader >            xAsyncLoader(xLoader, css::uno::UNO_QUERY);
1141     css::uno::Reference< css::frame::XSynchronousFrameLoader > xSyncLoader (xLoader, css::uno::UNO_QUERY);
1142 
1143     if (xAsyncLoader.is())
1144     {
1145         m_xAsynchronousJob = xAsyncLoader;
1146         LoadEnvListener* pListener = new LoadEnvListener(this);
1147         aWriteLock.clear();
1148         // <- SAFE -----------------------------------
1149 
1150         css::uno::Reference< css::frame::XLoadEventListener > xListener(static_cast< css::frame::XLoadEventListener* >(pListener), css::uno::UNO_QUERY);
1151         xAsyncLoader->load(xTargetFrame, sURL, lDescriptor, xListener);
1152 
1153         return true;
1154     }
1155     else if (xSyncLoader.is())
1156     {
1157         bool bResult = xSyncLoader->load(lDescriptor, xTargetFrame);
1158         // react for the result here, so the outside waiting
1159         // code can ask for it later.
1160         impl_setResult(bResult);
1161         // But the return value indicates a valid started(!) operation.
1162         // And that's true every time we reach this line :-)
1163         return true;
1164     }
1165 
1166     aWriteLock.clear();
1167     // <- SAFE
1168 
1169     return false;
1170 }
1171 
1172 css::uno::Reference< css::uno::XInterface > LoadEnv::impl_searchLoader()
1173 {
1174     // SAFE -> -----------------------------------
1175     osl::ClearableMutexGuard aReadLock(m_mutex);
1176 
1177     // special mode to set an existing component on this frame
1178     // In such case the loader is fix. It must be the SFX based implementation,
1179     // which can create a view on top of such xModel components :-)
1180     if (m_eContentType == E_CAN_BE_SET)
1181     {
1182         try
1183         {
1184             return css::frame::OfficeFrameLoader::create(m_xContext);
1185         }
1186         catch(const css::uno::RuntimeException&)
1187             { throw; }
1188         catch(const css::uno::Exception&)
1189             {}
1190         throw LoadEnvException(LoadEnvException::ID_INVALID_ENVIRONMENT);
1191     }
1192 
1193     // Otherwise...
1194     // We need this type information to locate a registered frame loader
1195     // Without such information we can't work!
1196     OUString sType = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_TYPENAME(), OUString());
1197     if (sType.isEmpty())
1198         throw LoadEnvException(LoadEnvException::ID_INVALID_MEDIADESCRIPTOR);
1199 
1200     // try to locate any interested frame loader
1201     css::uno::Reference< css::frame::XLoaderFactory > xLoaderFactory = css::frame::FrameLoaderFactory::create(m_xContext);
1202 
1203     aReadLock.clear();
1204     // <- SAFE -----------------------------------
1205 
1206     css::uno::Sequence< OUString > lTypesReg { sType };
1207 
1208     css::uno::Sequence< css::beans::NamedValue > lQuery { { PROP_TYPES, css::uno::makeAny(lTypesReg) } };
1209 
1210     css::uno::Reference< css::container::XEnumeration > xSet = xLoaderFactory->createSubSetEnumerationByProperties(lQuery);
1211     while(xSet->hasMoreElements())
1212     {
1213         try
1214         {
1215             // try everyone ...
1216             // Ignore any loader, which makes trouble :-)
1217             ::comphelper::SequenceAsHashMap             lLoaderProps(xSet->nextElement());
1218             OUString                             sLoader     = lLoaderProps.getUnpackedValueOrDefault(PROP_NAME, OUString());
1219             css::uno::Reference< css::uno::XInterface > xLoader = xLoaderFactory->createInstance(sLoader);
1220             if (xLoader.is())
1221                 return xLoader;
1222         }
1223         catch(const css::uno::RuntimeException&)
1224             { throw; }
1225         catch(const css::uno::Exception&)
1226             { continue; }
1227     }
1228 
1229     return css::uno::Reference< css::uno::XInterface >();
1230 }
1231 
1232 void LoadEnv::impl_jumpToMark(const css::uno::Reference< css::frame::XFrame >& xFrame,
1233                               const css::util::URL&                            aURL  )
1234 {
1235     if (aURL.Mark.isEmpty())
1236         return;
1237 
1238     css::uno::Reference< css::frame::XDispatchProvider > xProvider(xFrame, css::uno::UNO_QUERY);
1239     if (! xProvider.is())
1240         return;
1241 
1242     // SAFE ->
1243     osl::ClearableMutexGuard aReadLock(m_mutex);
1244     css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1245     aReadLock.clear();
1246     // <- SAFE
1247 
1248     css::util::URL aCmd;
1249     aCmd.Complete = ".uno:JumpToMark";
1250 
1251     css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(xContext));
1252     xParser->parseStrict(aCmd);
1253 
1254     css::uno::Reference< css::frame::XDispatch > xDispatcher = xProvider->queryDispatch(aCmd, SPECIALTARGET_SELF, 0);
1255     if (! xDispatcher.is())
1256         return;
1257 
1258     ::comphelper::SequenceAsHashMap lArgs;
1259     lArgs[OUString("Bookmark")] <<= aURL.Mark;
1260     xDispatcher->dispatch(aCmd, lArgs.getAsConstPropertyValueList());
1261 }
1262 
1263 css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchAlreadyLoaded()
1264 {
1265     osl::MutexGuard g(m_mutex);
1266 
1267     // such search is allowed for special requests only ...
1268     // or better it's not allowed for some requests in general :-)
1269     if (
1270         ( ! TargetHelper::matchSpecialTarget(m_sTarget, TargetHelper::ESpecialTarget::Default)                                               ) ||
1271         m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false) ||
1272 //      (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN()     , false) == sal_True) ||
1273         m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW(), false)
1274        )
1275     {
1276         return css::uno::Reference< css::frame::XFrame >();
1277     }
1278 
1279     // check URL
1280     // May it's not useful to start expensive document search, if it
1281     // can fail only .. because we load from a stream or model directly!
1282     if (
1283         (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateStream )) ||
1284         (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateObject ))
1285         /*TODO should be private:factory here tested too? */
1286        )
1287     {
1288         return css::uno::Reference< css::frame::XFrame >();
1289     }
1290 
1291     // otherwise - iterate through the tasks of the desktop container
1292     // to find out, which of them might contains the requested document
1293     css::uno::Reference< css::frame::XDesktop2 >  xSupplier = css::frame::Desktop::create( m_xContext );
1294     css::uno::Reference< css::container::XIndexAccess > xTaskList = xSupplier->getFrames();
1295 
1296     if (!xTaskList.is())
1297         return css::uno::Reference< css::frame::XFrame >(); // task list can be empty!
1298 
1299     // Note: To detect if a document was already loaded before
1300     // we check URLs here only. But might the existing and the required
1301     // document has different versions! Then its URLs are the same...
1302     sal_Int16 nNewVersion = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION(), sal_Int16(-1));
1303 
1304     // will be used to save the first hidden frame referring the searched model
1305     // Normally we are interested on visible frames... but if there is no such visible
1306     // frame we refer to any hidden frame also (but as fallback only).
1307     css::uno::Reference< css::frame::XFrame > xHiddenTask;
1308     css::uno::Reference< css::frame::XFrame > xTask;
1309 
1310     sal_Int32 count = xTaskList->getCount();
1311     for (sal_Int32 i=0; i<count; ++i)
1312     {
1313         try
1314         {
1315             // locate model of task
1316             // Note: Without a model there is no chance to decide if
1317             // this task contains the searched document or not!
1318             xTaskList->getByIndex(i) >>= xTask;
1319             if (!xTask.is())
1320                 continue;
1321 
1322             css::uno::Reference< css::frame::XController > xController = xTask->getController();
1323             if (!xController.is())
1324             {
1325                 xTask.clear ();
1326                 continue;
1327             }
1328 
1329             css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1330             if (!xModel.is())
1331             {
1332                 xTask.clear ();
1333                 continue;
1334             }
1335 
1336             // don't check the complete URL here.
1337             // use its main part - ignore optional jumpmarks!
1338             const OUString sURL = xModel->getURL();
1339             if (!::utl::UCBContentHelper::EqualURLs( m_aURL.Main, sURL ))
1340             {
1341                 xTask.clear ();
1342                 continue;
1343             }
1344 
1345             // get the original load arguments from the current document
1346             // and decide if it's really the same then the one will be.
1347             // It must be visible and must use the same file revision ...
1348             // or must not have any file revision set (-1 == -1!)
1349             utl::MediaDescriptor lOldDocDescriptor(xModel->getArgs());
1350 
1351             if (lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_VERSION(), sal_Int32(-1)) != nNewVersion)
1352             {
1353                 xTask.clear ();
1354                 continue;
1355             }
1356 
1357             // Hidden frames are special.
1358             // They will be used as "last chance" if there is no visible frame pointing to the same model.
1359             // Safe the result but continue with current loop might be looking for other visible frames.
1360             bool bIsHidden = lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1361             if ( bIsHidden && ! xHiddenTask.is() )
1362             {
1363                 xHiddenTask = xTask;
1364                 xTask.clear ();
1365                 continue;
1366             }
1367 
1368             // We found a visible task pointing to the right model ...
1369             // Break search.
1370             break;
1371         }
1372         catch(const css::uno::RuntimeException&)
1373             { throw; }
1374         catch(const css::uno::Exception&)
1375             { continue; }
1376     }
1377 
1378     css::uno::Reference< css::frame::XFrame > xResult;
1379     if (xTask.is())
1380         xResult = xTask;
1381     else if (xHiddenTask.is())
1382         xResult = xHiddenTask;
1383 
1384     if (xResult.is())
1385     {
1386         // Now we are sure, that this task includes the searched document.
1387         // It's time to activate it. As special feature we try to jump internally
1388         // if an optional jumpmark is given too.
1389         if (!m_aURL.Mark.isEmpty())
1390             impl_jumpToMark(xResult, m_aURL);
1391 
1392         // bring it to front and make sure it's visible...
1393         impl_makeFrameWindowVisible(xResult->getContainerWindow(), true);
1394     }
1395 
1396     return xResult;
1397 }
1398 
1399 bool LoadEnv::impl_isFrameAlreadyUsedForLoading(const css::uno::Reference< css::frame::XFrame >& xFrame) const
1400 {
1401     css::uno::Reference< css::document::XActionLockable > xLock(xFrame, css::uno::UNO_QUERY);
1402 
1403     // ? no lock interface ?
1404     // Maybe it's an external written frame implementation :-(
1405     // Allowing using of it... but it can fail if it's not synchronized with our processes!
1406     if (!xLock.is())
1407         return false;
1408 
1409     // Otherwise we have to look for any other existing lock.
1410     return xLock->isActionLocked();
1411 }
1412 
1413 css::uno::Reference< css::frame::XFrame > LoadEnv::impl_searchRecycleTarget()
1414 {
1415     // SAFE -> ..................................
1416     osl::ClearableMutexGuard aReadLock(m_mutex);
1417 
1418     // The special backing mode frame will be recycled by definition!
1419     // It doesn't matter if somewhere wants to create a new view
1420     // or open a new untitled document...
1421     // The only exception from that - hidden frames!
1422     if (m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false))
1423         return css::uno::Reference< css::frame::XFrame >();
1424 
1425     css::uno::Reference< css::frame::XFramesSupplier > xSupplier = css::frame::Desktop::create( m_xContext );
1426     FrameListAnalyzer aTasksAnalyzer(xSupplier, css::uno::Reference< css::frame::XFrame >(), FrameAnalyzerFlags::BackingComponent);
1427     if (aTasksAnalyzer.m_xBackingComponent.is())
1428     {
1429         if (!impl_isFrameAlreadyUsedForLoading(aTasksAnalyzer.m_xBackingComponent))
1430         {
1431             // bring it to front...
1432             impl_makeFrameWindowVisible(aTasksAnalyzer.m_xBackingComponent->getContainerWindow(), true);
1433             m_bReactivateControllerOnError = true;
1434             return aTasksAnalyzer.m_xBackingComponent;
1435         }
1436     }
1437 
1438     // These states indicates a wish for creation of a new view in general.
1439     if (
1440         m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false) ||
1441         m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_OPENNEWVIEW(), false)
1442        )
1443     {
1444         return css::uno::Reference< css::frame::XFrame >();
1445     }
1446 
1447     // On the other side some special URLs will open a new frame every time (expecting
1448     // they can use the backing-mode frame!)
1449     if (
1450         (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateFactory )) ||
1451         (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateStream  )) ||
1452         (ProtocolCheck::isProtocol(m_aURL.Complete, EProtocol::PrivateObject  ))
1453        )
1454     {
1455         return css::uno::Reference< css::frame::XFrame >();
1456     }
1457 
1458     // No backing frame! No special URL => recycle active task - if possible.
1459     // Means - if it does not already contains a modified document, or
1460     // use another office module.
1461     css::uno::Reference< css::frame::XFrame > xTask = xSupplier->getActiveFrame();
1462 
1463     // not a real error - but might a focus problem!
1464     if (!xTask.is())
1465         return css::uno::Reference< css::frame::XFrame >();
1466 
1467     // not a real error - may it's a view only
1468     css::uno::Reference< css::frame::XController > xController = xTask->getController();
1469     if (!xController.is())
1470         return css::uno::Reference< css::frame::XFrame >();
1471 
1472     // not a real error - may it's a db component instead of a full featured office document
1473     css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
1474     if (!xModel.is())
1475         return css::uno::Reference< css::frame::XFrame >();
1476 
1477     // get some more information ...
1478 
1479     // A valid set URL means: there is already a location for this document.
1480     // => it was saved there or opened from there. Such Documents can not be used here.
1481     // We search for empty document ... created by a private:factory/ URL!
1482     if (xModel->getURL().getLength()>0)
1483         return css::uno::Reference< css::frame::XFrame >();
1484 
1485     // The old document must be unmodified ...
1486     css::uno::Reference< css::util::XModifiable > xModified(xModel, css::uno::UNO_QUERY);
1487     if (xModified->isModified())
1488         return css::uno::Reference< css::frame::XFrame >();
1489 
1490     VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xTask->getContainerWindow());
1491     if (pWindow && pWindow->IsInModalMode())
1492         return css::uno::Reference< css::frame::XFrame >();
1493 
1494     // find out the application type of this document
1495     // We can recycle only documents, which uses the same application
1496     // then the new one.
1497     SvtModuleOptions::EFactory eOldApp = SvtModuleOptions::ClassifyFactoryByModel(xModel);
1498     SvtModuleOptions::EFactory eNewApp = SvtModuleOptions::ClassifyFactoryByURL  (m_aURL.Complete, m_lMediaDescriptor.getAsConstPropertyValueList());
1499 
1500     aReadLock.clear();
1501     // <- SAFE ..................................
1502 
1503     if (eOldApp != eNewApp)
1504         return css::uno::Reference< css::frame::XFrame >();
1505 
1506     // OK this task seems to be usable for recycling
1507     // But we should mark it as such - means set an action lock.
1508     // Otherwise it would be used more than ones or will be destroyed
1509     // by a close() or terminate() request.
1510     // But if such lock already exist ... it means this task is used for
1511     // any other operation already. Don't use it then.
1512     if (impl_isFrameAlreadyUsedForLoading(xTask))
1513         return css::uno::Reference< css::frame::XFrame >();
1514 
1515     // OK - there is a valid target frame.
1516     // But may be it contains already a document.
1517     // Then we have to ask it, if it allows recycling of this frame .-)
1518     bool bReactivateOldControllerOnError = false;
1519     css::uno::Reference< css::frame::XController > xOldDoc = xTask->getController();
1520     if (xOldDoc.is())
1521     {
1522         utl::MediaDescriptor lOldDocDescriptor(xModel->getArgs());
1523         bool bFromTemplate = lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_ASTEMPLATE() , false);
1524         OUString sReferrer = lOldDocDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REFERRER(), OUString());
1525 
1526         // tdf#83722: valid but unmodified document, either from template
1527         // or opened by the user (via File > New, referrer is set to private:user)
1528         if (bFromTemplate || (sReferrer == "private:user"))
1529             return css::uno::Reference< css::frame::XFrame >();
1530 
1531         bReactivateOldControllerOnError = xOldDoc->suspend(true);
1532         if (! bReactivateOldControllerOnError)
1533             return css::uno::Reference< css::frame::XFrame >();
1534     }
1535 
1536     // SAFE -> ..................................
1537     {
1538         osl::MutexGuard aWriteLock(m_mutex);
1539 
1540         css::uno::Reference< css::document::XActionLockable > xLock(xTask, css::uno::UNO_QUERY);
1541         if (!m_aTargetLock.setResource(xLock))
1542             return css::uno::Reference< css::frame::XFrame >();
1543 
1544         m_bReactivateControllerOnError = bReactivateOldControllerOnError;
1545     }
1546     // <- SAFE ..................................
1547 
1548     // bring it to front ...
1549     impl_makeFrameWindowVisible(xTask->getContainerWindow(), true);
1550 
1551     return xTask;
1552 }
1553 
1554 void LoadEnv::impl_reactForLoadingState()
1555 {
1556     /*TODO reset action locks */
1557 
1558     // SAFE -> ----------------------------------
1559     osl::ClearableMutexGuard aReadLock(m_mutex);
1560 
1561     if (m_bLoaded)
1562     {
1563         // Bring the new loaded document to front (if allowed!).
1564         // Note: We show new created frames here only.
1565         // We don't hide already visible frames here ...
1566         css::uno::Reference< css::awt::XWindow > xWindow      = m_xTargetFrame->getContainerWindow();
1567         bool                                 bHidden      = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
1568         bool                                 bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED(), false);
1569 
1570         if (bMinimized)
1571         {
1572             SolarMutexGuard aSolarGuard;
1573             VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
1574             // check for system window is necessary to guarantee correct pointer cast!
1575             if (pWindow && pWindow->IsSystemWindow())
1576                 static_cast<WorkWindow*>(pWindow.get())->Minimize();
1577         }
1578         else if (!bHidden)
1579         {
1580             // show frame ... if it's not still visible ...
1581             // But do nothing if it's already visible!
1582             impl_makeFrameWindowVisible(xWindow, false);
1583         }
1584 
1585         // Note: Only if an existing property "FrameName" is given by this media descriptor,
1586         // it should be used. Otherwise we should do nothing. May be the outside code has already
1587         // set a frame name on the target!
1588         utl::MediaDescriptor::const_iterator pFrameName = m_lMediaDescriptor.find(utl::MediaDescriptor::PROP_FRAMENAME());
1589         if (pFrameName != m_lMediaDescriptor.end())
1590         {
1591             OUString sFrameName;
1592             pFrameName->second >>= sFrameName;
1593             // Check the name again. e.g. "_default" isn't allowed.
1594             // On the other side "_beamer" is a valid name :-)
1595             if (TargetHelper::isValidNameForFrame(sFrameName))
1596                 m_xTargetFrame->setName(sFrameName);
1597         }
1598     }
1599     else if (m_bReactivateControllerOnError)
1600     {
1601         // Try to reactivate the old document (if any exists!)
1602         css::uno::Reference< css::frame::XController > xOldDoc = m_xTargetFrame->getController();
1603         // clear does not depend from reactivation state of a might existing old document!
1604         // We must make sure, that a might following getTargetComponent() call does not return
1605         // the old document!
1606         m_xTargetFrame.clear();
1607         if (xOldDoc.is())
1608         {
1609             bool bReactivated = xOldDoc->suspend(false);
1610             if (!bReactivated)
1611                 throw LoadEnvException(LoadEnvException::ID_COULD_NOT_REACTIVATE_CONTROLLER);
1612             m_bReactivateControllerOnError = false;
1613         }
1614     }
1615     else if (m_bCloseFrameOnError)
1616     {
1617         // close empty frames
1618         css::uno::Reference< css::util::XCloseable > xCloseable (m_xTargetFrame, css::uno::UNO_QUERY);
1619 
1620         try
1621         {
1622             if (xCloseable.is())
1623                 xCloseable->close(true);
1624             else if (m_xTargetFrame.is())
1625                 m_xTargetFrame->dispose();
1626         }
1627         catch(const css::util::CloseVetoException&)
1628         {}
1629         catch(const css::lang::DisposedException&)
1630         {}
1631         m_xTargetFrame.clear();
1632     }
1633 
1634     // This max force an implicit closing of our target frame ...
1635     // e.g. in case close(sal_True) was called before and the frame
1636     // kill itself if our external use-lock is released here!
1637     // That's why we release this lock AFTER ALL OPERATIONS on this frame
1638     // are finished. The frame itself must handle then
1639     // this situation gracefully.
1640     m_aTargetLock.freeResource();
1641 
1642     // Last but not least :-)
1643     // We have to clear the current media descriptor.
1644     // Otherwise it hold a might existing stream open!
1645     m_lMediaDescriptor.clear();
1646 
1647     css::uno::Any aRequest;
1648     bool bThrow = false;
1649     if ( !m_bLoaded && m_pQuietInteraction.is() && m_pQuietInteraction->wasUsed() )
1650     {
1651         aRequest = m_pQuietInteraction->getRequest();
1652         m_pQuietInteraction.clear();
1653         bThrow = true;
1654     }
1655 
1656     aReadLock.clear();
1657 
1658     if (bThrow)
1659     {
1660         if  ( aRequest.isExtractableTo( ::cppu::UnoType< css::uno::Exception >::get() ) )
1661             throw LoadEnvException(
1662                 LoadEnvException::ID_GENERAL_ERROR, "interaction request",
1663                 aRequest);
1664     }
1665 
1666     // <- SAFE ----------------------------------
1667 }
1668 
1669 void LoadEnv::impl_makeFrameWindowVisible(const css::uno::Reference< css::awt::XWindow >& xWindow      ,
1670                                                 bool bForceToFront)
1671 {
1672     // SAFE -> ----------------------------------
1673     osl::ClearableMutexGuard aReadLock(m_mutex);
1674     css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1675     aReadLock.clear();
1676     // <- SAFE ----------------------------------
1677 
1678     SolarMutexGuard aSolarGuard;
1679     VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
1680     if ( pWindow )
1681     {
1682         bool const preview( m_lMediaDescriptor.getUnpackedValueOrDefault(
1683                 utl::MediaDescriptor::PROP_PREVIEW(), false) );
1684 
1685         bool bForceFrontAndFocus(false);
1686         if ( !preview )
1687         {
1688             css::uno::Any const a =
1689                 ::comphelper::ConfigurationHelper::readDirectKey(
1690                   xContext,
1691                   "org.openoffice.Office.Common/View",
1692                   "NewDocumentHandling",
1693                   "ForceFocusAndToFront",
1694                   ::comphelper::EConfigurationModes::ReadOnly);
1695             a >>= bForceFrontAndFocus;
1696         }
1697 
1698         if( pWindow->IsVisible() && (bForceFrontAndFocus || bForceToFront) )
1699             pWindow->ToTop( ToTopFlags::RestoreWhenMin | ToTopFlags::ForegroundTask );
1700         else
1701             pWindow->Show(true, (bForceFrontAndFocus || bForceToFront) ? ShowFlags::ForegroundTask : ShowFlags::NONE );
1702     }
1703 }
1704 
1705 void LoadEnv::impl_applyPersistentWindowState(const css::uno::Reference< css::awt::XWindow >& xWindow)
1706 {
1707     // no window -> action not possible
1708     if (!xWindow.is())
1709         return;
1710 
1711     // window already visible -> do nothing! If we use a "recycle frame" for loading ...
1712     // the current position and size must be used.
1713     css::uno::Reference< css::awt::XWindow2 > xVisibleCheck(xWindow, css::uno::UNO_QUERY);
1714     if (
1715         (xVisibleCheck.is()        ) &&
1716         (xVisibleCheck->isVisible())
1717        )
1718        return;
1719 
1720     // SOLAR SAFE ->
1721     {
1722         SolarMutexGuard aSolarGuard1;
1723 
1724         VclPtr<vcl::Window>  pWindow = VCLUnoHelper::GetWindow(xWindow);
1725         if (!pWindow)
1726             return;
1727 
1728         bool bSystemWindow = pWindow->IsSystemWindow();
1729         bool bWorkWindow = (pWindow->GetType() == WindowType::WORKWINDOW);
1730 
1731         if (!bSystemWindow && !bWorkWindow)
1732             return;
1733 
1734         // don't overwrite this special state!
1735         WorkWindow* pWorkWindow = static_cast<WorkWindow*>(pWindow.get());
1736         if (pWorkWindow->IsMinimized())
1737             return;
1738     }
1739     // <- SOLAR SAFE
1740 
1741     // SAFE ->
1742     osl::ClearableMutexGuard aReadLock(m_mutex);
1743 
1744     // no filter -> no module -> no persistent window state
1745     OUString sFilter = m_lMediaDescriptor.getUnpackedValueOrDefault(
1746                                     utl::MediaDescriptor::PROP_FILTERNAME(),
1747                                     OUString());
1748     if (sFilter.isEmpty())
1749         return;
1750 
1751     css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
1752 
1753     aReadLock.clear();
1754     // <- SAFE
1755 
1756     try
1757     {
1758         // retrieve the module name from the filter configuration
1759         css::uno::Reference< css::container::XNameAccess > xFilterCfg(
1760             xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_FILTERFACTORY, xContext),
1761             css::uno::UNO_QUERY_THROW);
1762         ::comphelper::SequenceAsHashMap lProps (xFilterCfg->getByName(sFilter));
1763         OUString                 sModule = lProps.getUnpackedValueOrDefault(FILTER_PROPNAME_ASCII_DOCUMENTSERVICE, OUString());
1764 
1765         // get access to the configuration of this office module
1766         css::uno::Reference< css::container::XNameAccess > xModuleCfg(::comphelper::ConfigurationHelper::openConfig(
1767                                                                         xContext,
1768                                                                         "/org.openoffice.Setup/Office/Factories",
1769                                                                         ::comphelper::EConfigurationModes::ReadOnly),
1770                                                                       css::uno::UNO_QUERY_THROW);
1771 
1772         // read window state from the configuration
1773         // and apply it on the window.
1774         // Do nothing, if no configuration entry exists!
1775         OUString sWindowState;
1776 
1777         // Don't look for persistent window attributes when used through LibreOfficeKit
1778         if( !comphelper::LibreOfficeKit::isActive() )
1779             comphelper::ConfigurationHelper::readRelativeKey(xModuleCfg, sModule, OFFICEFACTORY_PROPNAME_ASCII_WINDOWATTRIBUTES) >>= sWindowState;
1780 
1781         if (!sWindowState.isEmpty())
1782         {
1783             // SOLAR SAFE ->
1784             SolarMutexGuard aSolarGuard;
1785 
1786             // We have to retrieve the window pointer again. Because nobody can guarantee
1787             // that the XWindow was not disposed in between .-)
1788             // But if we get a valid pointer we can be sure, that it's the system window pointer
1789             // we already checked and used before. Because nobody recycle the same uno reference for
1790             // a new internal c++ implementation ... hopefully .-))
1791             VclPtr<vcl::Window> pWindowCheck = VCLUnoHelper::GetWindow(xWindow);
1792             if (! pWindowCheck)
1793                 return;
1794 
1795             SystemWindow* pSystemWindow = static_cast<SystemWindow*>(pWindowCheck.get());
1796             pSystemWindow->SetWindowState(OUStringToOString(sWindowState,RTL_TEXTENCODING_UTF8));
1797             // <- SOLAR SAFE
1798         }
1799     }
1800     catch(const css::uno::RuntimeException&)
1801         { throw; }
1802     catch(const css::uno::Exception&)
1803         {}
1804 }
1805 
1806 } // namespace framework
1807 
1808 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1809