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