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