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