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