/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: */ |