Coverage Report

Created: 2025-11-16 09:57

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