LCOV - code coverage report
Current view: top level - framework/source/loadenv - loadenv.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 486 741 65.6 %
Date: 2015-06-13 12:38:46 Functions: 26 31 83.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11