1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "precompiled_sd.hxx" 29 30 #include "framework/ConfigurationController.hxx" 31 32 #include "framework/Configuration.hxx" 33 #include "framework/FrameworkHelper.hxx" 34 #include "ConfigurationUpdater.hxx" 35 #include "ConfigurationControllerBroadcaster.hxx" 36 #include "ConfigurationTracer.hxx" 37 #include "GenericConfigurationChangeRequest.hxx" 38 #include "ResourceFactoryManager.hxx" 39 #include "UpdateRequest.hxx" 40 #include "ChangeRequestQueueProcessor.hxx" 41 #include "ConfigurationClassifier.hxx" 42 #include "ViewShellBase.hxx" 43 #include "UpdateLockManager.hxx" 44 #include "DrawController.hxx" 45 #include <com/sun/star/drawing/framework/XControllerManager.hpp> 46 #include <com/sun/star/util/XURLTransformer.hpp> 47 48 #include <comphelper/stl_types.hxx> 49 #include <vos/mutex.hxx> 50 #include <vcl/svapp.hxx> 51 52 using namespace ::com::sun::star; 53 using namespace ::com::sun::star::uno; 54 using namespace ::com::sun::star::drawing::framework; 55 using rtl::OUString; 56 using ::sd::framework::FrameworkHelper; 57 58 #undef VERBOSE 59 //#define VERBOSE 3 60 61 62 namespace sd { namespace framework { 63 64 Reference<XInterface> SAL_CALL ConfigurationController_createInstance ( 65 const Reference<XComponentContext>& rxContext) 66 { 67 (void)rxContext; 68 return static_cast<XWeak*>(new ConfigurationController()); 69 } 70 71 72 73 74 OUString ConfigurationController_getImplementationName (void) throw(RuntimeException) 75 { 76 return OUString(RTL_CONSTASCII_USTRINGPARAM( 77 "com.sun.star.comp.Draw.framework.configuration.ConfigurationController")); 78 } 79 80 81 82 83 Sequence<rtl::OUString> SAL_CALL ConfigurationController_getSupportedServiceNames (void) 84 throw (RuntimeException) 85 { 86 static const OUString sServiceName(OUString::createFromAscii( 87 "com.sun.star.drawing.framework.ConfigurationController")); 88 return Sequence<rtl::OUString>(&sServiceName, 1); 89 } 90 91 92 93 94 //----- ConfigurationController::Implementation ------------------------------- 95 96 class ConfigurationController::Implementation 97 { 98 public: 99 Implementation ( 100 ConfigurationController& rController, 101 const Reference<frame::XController>& rxController); 102 ~Implementation (void); 103 104 Reference<XControllerManager> mxControllerManager; 105 106 /** The Broadcaster class implements storing and calling of listeners. 107 */ 108 ::boost::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster; 109 110 /** The requested configuration which is modifed (asynchronously) by 111 calls to requestResourceActivation() and 112 requestResourceDeactivation(). The mpConfigurationUpdater makes the 113 current configuration reflect the content of this one. 114 */ 115 ::com::sun::star::uno::Reference< 116 ::com::sun::star::drawing::framework::XConfiguration> mxRequestedConfiguration; 117 118 ViewShellBase* mpBase; 119 120 ::boost::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer; 121 122 ::boost::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager; 123 124 ::boost::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater; 125 126 /** The queue processor ownes the queue of configuration change request 127 objects and processes the objects. 128 */ 129 ::boost::scoped_ptr<ChangeRequestQueueProcessor> mpQueueProcessor; 130 131 ::boost::shared_ptr<ConfigurationUpdaterLock> mpConfigurationUpdaterLock; 132 133 sal_Int32 mnLockCount; 134 }; 135 136 137 138 139 //===== ConfigurationController::Lock ========================================= 140 141 ConfigurationController::Lock::Lock (const Reference<XConfigurationController>& rxController) 142 : mxController(rxController) 143 { 144 OSL_ASSERT(mxController.is()); 145 146 if (mxController.is()) 147 mxController->lock(); 148 } 149 150 151 152 153 ConfigurationController::Lock::~Lock (void) 154 { 155 if (mxController.is()) 156 mxController->unlock(); 157 } 158 159 160 161 162 //===== ConfigurationController =============================================== 163 164 ConfigurationController::ConfigurationController (void) throw() 165 : ConfigurationControllerInterfaceBase(MutexOwner::maMutex), 166 mpImplementation(), 167 mbIsDisposed(false) 168 { 169 } 170 171 172 173 174 ConfigurationController::~ConfigurationController (void) throw() 175 { 176 } 177 178 179 180 181 void SAL_CALL ConfigurationController::disposing (void) 182 { 183 if (mpImplementation.get() == NULL) 184 return; 185 186 #if defined VERBOSE && VERBOSE>=1 187 OSL_TRACE("ConfigurationController::disposing\n"); 188 OSL_TRACE(" requesting empty configuration\n"); 189 #endif 190 // To destroy all resources an empty configuration is requested and then, 191 // synchronously, all resulting requests are processed. 192 mpImplementation->mpQueueProcessor->Clear(); 193 restoreConfiguration(new Configuration(this,false)); 194 mpImplementation->mpQueueProcessor->ProcessUntilEmpty(); 195 #if defined VERBOSE && VERBOSE>=1 196 OSL_TRACE(" all requests processed\n"); 197 #endif 198 199 // Now that all resources have been deactivated, mark the controller as 200 // disposed. 201 mbIsDisposed = true; 202 203 // Release the listeners. 204 lang::EventObject aEvent; 205 aEvent.Source = uno::Reference<uno::XInterface>((cppu::OWeakObject*)this); 206 207 { 208 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 209 mpImplementation->mpBroadcaster->DisposeAndClear(); 210 } 211 212 mpImplementation->mpQueueProcessor.reset(); 213 mpImplementation->mxRequestedConfiguration = NULL; 214 mpImplementation.reset(); 215 } 216 217 218 219 220 void ConfigurationController::ProcessEvent (void) 221 { 222 if (mpImplementation.get() != NULL) 223 { 224 OSL_ASSERT(mpImplementation->mpQueueProcessor.get()!=NULL); 225 226 mpImplementation->mpQueueProcessor->ProcessOneEvent(); 227 } 228 } 229 230 231 232 233 void ConfigurationController::RequestSynchronousUpdate (void) 234 { 235 if (mpImplementation.get() == NULL) 236 return; 237 if (mpImplementation->mpQueueProcessor.get() == 0) 238 return; 239 mpImplementation->mpQueueProcessor->ProcessUntilEmpty(); 240 } 241 242 243 244 245 //----- XConfigurationControllerBroadcaster ----------------------------------- 246 247 void SAL_CALL ConfigurationController::addConfigurationChangeListener ( 248 const Reference<XConfigurationChangeListener>& rxListener, 249 const ::rtl::OUString& rsEventType, 250 const Any& rUserData) 251 throw (RuntimeException) 252 { 253 ::osl::MutexGuard aGuard (maMutex); 254 255 ThrowIfDisposed(); 256 OSL_ASSERT(mpImplementation.get()!=NULL); 257 mpImplementation->mpBroadcaster->AddListener(rxListener, rsEventType, rUserData); 258 } 259 260 261 262 263 void SAL_CALL ConfigurationController::removeConfigurationChangeListener ( 264 const Reference<XConfigurationChangeListener>& rxListener) 265 throw (RuntimeException) 266 { 267 ::osl::MutexGuard aGuard (maMutex); 268 269 ThrowIfDisposed(); 270 mpImplementation->mpBroadcaster->RemoveListener(rxListener); 271 } 272 273 274 275 276 void SAL_CALL ConfigurationController::notifyEvent ( 277 const ConfigurationChangeEvent& rEvent) 278 throw (RuntimeException) 279 { 280 ThrowIfDisposed(); 281 mpImplementation->mpBroadcaster->NotifyListeners(rEvent); 282 } 283 284 285 286 287 288 //----- XConfigurationController ---------------------------------------------- 289 290 void SAL_CALL ConfigurationController::lock (void) 291 throw (RuntimeException) 292 { 293 OSL_ASSERT(mpImplementation.get()!=NULL); 294 OSL_ASSERT(mpImplementation->mpConfigurationUpdater.get()!=NULL); 295 296 ::osl::MutexGuard aGuard (maMutex); 297 ThrowIfDisposed(); 298 299 300 ++mpImplementation->mnLockCount; 301 if (mpImplementation->mpConfigurationUpdaterLock.get()==NULL) 302 mpImplementation->mpConfigurationUpdaterLock 303 = mpImplementation->mpConfigurationUpdater->GetLock(); 304 } 305 306 307 308 309 void SAL_CALL ConfigurationController::unlock (void) 310 throw (RuntimeException) 311 { 312 ::osl::MutexGuard aGuard (maMutex); 313 314 // Allow unlocking while the ConfigurationController is being disposed 315 // (but not when that is done and the controller is disposed.) 316 if (rBHelper.bDisposed) 317 ThrowIfDisposed(); 318 319 OSL_ASSERT(mpImplementation->mnLockCount>0); 320 --mpImplementation->mnLockCount; 321 if (mpImplementation->mnLockCount == 0) 322 mpImplementation->mpConfigurationUpdaterLock.reset(); 323 } 324 325 326 327 328 void SAL_CALL ConfigurationController::requestResourceActivation ( 329 const Reference<XResourceId>& rxResourceId, 330 ResourceActivationMode eMode) 331 throw (RuntimeException) 332 { 333 ::osl::MutexGuard aGuard (maMutex); 334 ThrowIfDisposed(); 335 336 // Check whether we are being disposed. This is handled differently 337 // then being completely disposed because the first thing disposing() 338 // does is to deactivate all remaining resources. This is done via 339 // regular methods which must not throw DisposedExceptions. Therefore 340 // we just return silently during that stage. 341 if (rBHelper.bInDispose) 342 { 343 #if defined VERBOSE && VERBOSE>=1 344 OSL_TRACE("ConfigurationController::requestResourceActivation(): ignoring %s\n", 345 OUStringToOString( 346 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); 347 #endif 348 return; 349 } 350 351 #if defined VERBOSE && VERBOSE>=2 352 OSL_TRACE("ConfigurationController::requestResourceActivation() %s\n", 353 OUStringToOString( 354 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); 355 #endif 356 357 if (rxResourceId.is()) 358 { 359 if (eMode == ResourceActivationMode_REPLACE) 360 { 361 // Get a list of the matching resources and create deactivation 362 // requests for them. 363 Sequence<Reference<XResourceId> > aResourceList ( 364 mpImplementation->mxRequestedConfiguration->getResources( 365 rxResourceId->getAnchor(), 366 rxResourceId->getResourceTypePrefix(), 367 AnchorBindingMode_DIRECT)); 368 369 for (sal_Int32 nIndex=0; nIndex<aResourceList.getLength(); ++nIndex) 370 { 371 // Do not request the deactivation of the resource for which 372 // this method was called. Doing it would not change the 373 // outcome but would result in unnecessary work. 374 if (rxResourceId->compareTo(aResourceList[nIndex]) == 0) 375 continue; 376 377 // Request the deactivation of a resource and all resources 378 // linked to it. 379 requestResourceDeactivation(aResourceList[nIndex]); 380 } 381 } 382 383 Reference<XConfigurationChangeRequest> xRequest( 384 new GenericConfigurationChangeRequest( 385 rxResourceId, 386 GenericConfigurationChangeRequest::Activation)); 387 postChangeRequest(xRequest); 388 } 389 } 390 391 392 393 394 void SAL_CALL ConfigurationController::requestResourceDeactivation ( 395 const Reference<XResourceId>& rxResourceId) 396 throw (RuntimeException) 397 { 398 ::osl::MutexGuard aGuard (maMutex); 399 ThrowIfDisposed(); 400 401 #if defined VERBOSE && VERBOSE>=2 402 OSL_TRACE("ConfigurationController::requestResourceDeactivation() %s\n", 403 OUStringToOString( 404 FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); 405 #endif 406 407 if (rxResourceId.is()) 408 { 409 // Request deactivation of all resources linked to the specified one 410 // as well. 411 const Sequence<Reference<XResourceId> > aLinkedResources ( 412 mpImplementation->mxRequestedConfiguration->getResources( 413 rxResourceId, 414 OUString(), 415 AnchorBindingMode_DIRECT)); 416 const sal_Int32 nCount (aLinkedResources.getLength()); 417 for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) 418 { 419 // We do not add deactivation requests directly but call this 420 // method recursively, so that when one time there are resources 421 // linked to linked resources, these are handled correctly, too. 422 requestResourceDeactivation(aLinkedResources[nIndex]); 423 } 424 425 // Add a deactivation request for the specified resource. 426 Reference<XConfigurationChangeRequest> xRequest( 427 new GenericConfigurationChangeRequest( 428 rxResourceId, 429 GenericConfigurationChangeRequest::Deactivation)); 430 postChangeRequest(xRequest); 431 } 432 } 433 434 435 436 437 Reference<XResource> SAL_CALL ConfigurationController::getResource ( 438 const Reference<XResourceId>& rxResourceId) 439 throw (RuntimeException) 440 { 441 ::osl::MutexGuard aGuard (maMutex); 442 ThrowIfDisposed(); 443 444 ConfigurationControllerResourceManager::ResourceDescriptor aDescriptor ( 445 mpImplementation->mpResourceManager->GetResource(rxResourceId)); 446 return aDescriptor.mxResource; 447 } 448 449 450 451 452 void SAL_CALL ConfigurationController::update (void) 453 throw (RuntimeException) 454 { 455 ::osl::MutexGuard aGuard (maMutex); 456 ThrowIfDisposed(); 457 458 if (mpImplementation->mpQueueProcessor->IsEmpty()) 459 { 460 // The queue is empty. Add another request that does nothing but 461 // asynchronously trigger a request for an update. 462 mpImplementation->mpQueueProcessor->AddRequest(new UpdateRequest()); 463 } 464 else 465 { 466 // The queue is not empty, so we rely on the queue processor to 467 // request an update automatically when the queue becomes empty. 468 } 469 } 470 471 472 473 474 sal_Bool SAL_CALL ConfigurationController::hasPendingRequests (void) 475 throw (RuntimeException) 476 { 477 ::osl::MutexGuard aGuard (maMutex); 478 ThrowIfDisposed(); 479 480 return ! mpImplementation->mpQueueProcessor->IsEmpty(); 481 } 482 483 484 485 486 487 void SAL_CALL ConfigurationController::postChangeRequest ( 488 const Reference<XConfigurationChangeRequest>& rxRequest) 489 throw (RuntimeException) 490 { 491 ::osl::MutexGuard aGuard (maMutex); 492 ThrowIfDisposed(); 493 494 mpImplementation->mpQueueProcessor->AddRequest(rxRequest); 495 } 496 497 498 499 500 Reference<XConfiguration> SAL_CALL ConfigurationController::getRequestedConfiguration (void) 501 throw (RuntimeException) 502 { 503 ::osl::MutexGuard aGuard (maMutex); 504 ThrowIfDisposed(); 505 506 if (mpImplementation->mxRequestedConfiguration.is()) 507 return Reference<XConfiguration>( 508 mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY); 509 else 510 return Reference<XConfiguration>(); 511 } 512 513 514 515 516 Reference<XConfiguration> SAL_CALL ConfigurationController::getCurrentConfiguration (void) 517 throw (RuntimeException) 518 { 519 ::osl::MutexGuard aGuard (maMutex); 520 ThrowIfDisposed(); 521 522 Reference<XConfiguration> xCurrentConfiguration( 523 mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration()); 524 if (xCurrentConfiguration.is()) 525 return Reference<XConfiguration>(xCurrentConfiguration->createClone(), UNO_QUERY); 526 else 527 return Reference<XConfiguration>(); 528 } 529 530 531 532 533 /** The given configuration is restored by generating the appropriate set of 534 activation and deactivation requests. 535 */ 536 void SAL_CALL ConfigurationController::restoreConfiguration ( 537 const Reference<XConfiguration>& rxNewConfiguration) 538 throw (RuntimeException) 539 { 540 ::osl::MutexGuard aGuard (maMutex); 541 ThrowIfDisposed(); 542 543 // We will probably be making a couple of activation and deactivation 544 // requests so lock the configuration controller and let it later update 545 // all changes at once. 546 ::boost::shared_ptr<ConfigurationUpdaterLock> pLock ( 547 mpImplementation->mpConfigurationUpdater->GetLock()); 548 549 // Get lists of resources that are to be activated or deactivated. 550 Reference<XConfiguration> xCurrentConfiguration (mpImplementation->mxRequestedConfiguration); 551 #if defined VERBOSE && VERBOSE>=1 552 OSL_TRACE("ConfigurationController::restoreConfiguration(\n"); 553 ConfigurationTracer::TraceConfiguration(rxNewConfiguration, "requested configuration"); 554 ConfigurationTracer::TraceConfiguration(xCurrentConfiguration, "current configuration"); 555 #endif 556 ConfigurationClassifier aClassifier (rxNewConfiguration, xCurrentConfiguration); 557 aClassifier.Partition(); 558 #if defined VERBOSE && VERBOSE>=3 559 aClassifier.TraceResourceIdVector( 560 "requested but not current resources:\n", aClassifier.GetC1minusC2()); 561 aClassifier.TraceResourceIdVector( 562 "current but not requested resources:\n", aClassifier.GetC2minusC1()); 563 aClassifier.TraceResourceIdVector( 564 "requested and current resources:\n", aClassifier.GetC1andC2()); 565 #endif 566 567 ConfigurationClassifier::ResourceIdVector::const_iterator iResource; 568 569 // Request the deactivation of resources that are not requested in the 570 // new configuration. 571 const ConfigurationClassifier::ResourceIdVector& rResourcesToDeactivate ( 572 aClassifier.GetC2minusC1()); 573 for (iResource=rResourcesToDeactivate.begin(); 574 iResource!=rResourcesToDeactivate.end(); 575 ++iResource) 576 { 577 requestResourceDeactivation(*iResource); 578 } 579 580 // Request the activation of resources that are requested in the 581 // new configuration but are not part of the current configuration. 582 const ConfigurationClassifier::ResourceIdVector& rResourcesToActivate ( 583 aClassifier.GetC1minusC2()); 584 for (iResource=rResourcesToActivate.begin(); 585 iResource!=rResourcesToActivate.end(); 586 ++iResource) 587 { 588 requestResourceActivation(*iResource, ResourceActivationMode_ADD); 589 } 590 591 pLock.reset(); 592 } 593 594 595 596 597 //----- XResourceFactoryManager ----------------------------------------------- 598 599 void SAL_CALL ConfigurationController::addResourceFactory( 600 const OUString& sResourceURL, 601 const Reference<XResourceFactory>& rxResourceFactory) 602 throw (RuntimeException) 603 { 604 ::osl::MutexGuard aGuard (maMutex); 605 ThrowIfDisposed(); 606 mpImplementation->mpResourceFactoryContainer->AddFactory(sResourceURL, rxResourceFactory); 607 } 608 609 610 611 612 void SAL_CALL ConfigurationController::removeResourceFactoryForURL( 613 const OUString& sResourceURL) 614 throw (RuntimeException) 615 { 616 ::osl::MutexGuard aGuard (maMutex); 617 ThrowIfDisposed(); 618 mpImplementation->mpResourceFactoryContainer->RemoveFactoryForURL(sResourceURL); 619 } 620 621 622 623 624 void SAL_CALL ConfigurationController::removeResourceFactoryForReference( 625 const Reference<XResourceFactory>& rxResourceFactory) 626 throw (RuntimeException) 627 { 628 ::osl::MutexGuard aGuard (maMutex); 629 ThrowIfDisposed(); 630 mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory); 631 } 632 633 634 635 636 Reference<XResourceFactory> SAL_CALL ConfigurationController::getResourceFactory ( 637 const OUString& sResourceURL) 638 throw (RuntimeException) 639 { 640 ::osl::MutexGuard aGuard (maMutex); 641 ThrowIfDisposed(); 642 643 return mpImplementation->mpResourceFactoryContainer->GetFactory(sResourceURL); 644 } 645 646 647 648 649 //----- XInitialization ------------------------------------------------------- 650 651 void SAL_CALL ConfigurationController::initialize (const Sequence<Any>& aArguments) 652 throw (Exception, RuntimeException) 653 { 654 ::osl::MutexGuard aGuard (maMutex); 655 656 if (aArguments.getLength() == 1) 657 { 658 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 659 660 mpImplementation.reset(new Implementation( 661 *this, 662 Reference<frame::XController>(aArguments[0], UNO_QUERY_THROW))); 663 } 664 } 665 666 667 668 669 //----------------------------------------------------------------------------- 670 671 void ConfigurationController::ThrowIfDisposed (void) const 672 throw (::com::sun::star::lang::DisposedException) 673 { 674 if (mbIsDisposed) 675 { 676 throw lang::DisposedException ( 677 OUString(RTL_CONSTASCII_USTRINGPARAM( 678 "ConfigurationController object has already been disposed")), 679 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this))); 680 } 681 682 if (mpImplementation.get() == NULL) 683 { 684 OSL_ASSERT(mpImplementation.get() != NULL); 685 throw RuntimeException( 686 OUString(RTL_CONSTASCII_USTRINGPARAM( 687 "ConfigurationController not initialized")), 688 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this))); 689 } 690 } 691 692 693 694 695 //===== ConfigurationController::Implementation =============================== 696 697 ConfigurationController::Implementation::Implementation ( 698 ConfigurationController& rController, 699 const Reference<frame::XController>& rxController) 700 : mxControllerManager(rxController, UNO_QUERY_THROW), 701 mpBroadcaster(new ConfigurationControllerBroadcaster(&rController)), 702 mxRequestedConfiguration(new Configuration(&rController, true)), 703 mpBase(NULL), 704 mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager)), 705 mpResourceManager( 706 new ConfigurationControllerResourceManager(mpResourceFactoryContainer,mpBroadcaster)), 707 mpConfigurationUpdater( 708 new ConfigurationUpdater(mpBroadcaster, mpResourceManager,mxControllerManager)), 709 mpQueueProcessor(new ChangeRequestQueueProcessor(&rController,mpConfigurationUpdater)), 710 mpConfigurationUpdaterLock(), 711 mnLockCount(0) 712 { 713 mpQueueProcessor->SetConfiguration(mxRequestedConfiguration); 714 } 715 716 717 718 719 ConfigurationController::Implementation::~Implementation (void) 720 { 721 } 722 723 724 725 726 } } // end of namespace sd::framework 727