/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "precompiled_sd.hxx" #include "framework/ConfigurationController.hxx" #include "framework/Configuration.hxx" #include "framework/FrameworkHelper.hxx" #include "ConfigurationUpdater.hxx" #include "ConfigurationControllerBroadcaster.hxx" #include "ConfigurationTracer.hxx" #include "GenericConfigurationChangeRequest.hxx" #include "ResourceFactoryManager.hxx" #include "UpdateRequest.hxx" #include "ChangeRequestQueueProcessor.hxx" #include "ConfigurationClassifier.hxx" #include "ViewShellBase.hxx" #include "UpdateLockManager.hxx" #include "DrawController.hxx" #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::drawing::framework; using rtl::OUString; using ::sd::framework::FrameworkHelper; #undef VERBOSE //#define VERBOSE 3 namespace sd { namespace framework { Reference SAL_CALL ConfigurationController_createInstance ( const Reference& rxContext) { (void)rxContext; return static_cast(new ConfigurationController()); } OUString ConfigurationController_getImplementationName (void) throw(RuntimeException) { return OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Draw.framework.configuration.ConfigurationController")); } Sequence SAL_CALL ConfigurationController_getSupportedServiceNames (void) throw (RuntimeException) { static const OUString sServiceName(OUString::createFromAscii( "com.sun.star.drawing.framework.ConfigurationController")); return Sequence(&sServiceName, 1); } //----- ConfigurationController::Implementation ------------------------------- class ConfigurationController::Implementation { public: Implementation ( ConfigurationController& rController, const Reference& rxController); ~Implementation (void); Reference mxControllerManager; /** The Broadcaster class implements storing and calling of listeners. */ ::boost::shared_ptr mpBroadcaster; /** The requested configuration which is modifed (asynchronously) by calls to requestResourceActivation() and requestResourceDeactivation(). The mpConfigurationUpdater makes the current configuration reflect the content of this one. */ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::framework::XConfiguration> mxRequestedConfiguration; ViewShellBase* mpBase; ::boost::shared_ptr mpResourceFactoryContainer; ::boost::shared_ptr mpResourceManager; ::boost::shared_ptr mpConfigurationUpdater; /** The queue processor ownes the queue of configuration change request objects and processes the objects. */ ::boost::scoped_ptr mpQueueProcessor; ::boost::shared_ptr mpConfigurationUpdaterLock; sal_Int32 mnLockCount; }; //===== ConfigurationController::Lock ========================================= ConfigurationController::Lock::Lock (const Reference& rxController) : mxController(rxController) { OSL_ASSERT(mxController.is()); if (mxController.is()) mxController->lock(); } ConfigurationController::Lock::~Lock (void) { if (mxController.is()) mxController->unlock(); } //===== ConfigurationController =============================================== ConfigurationController::ConfigurationController (void) throw() : ConfigurationControllerInterfaceBase(MutexOwner::maMutex), mpImplementation(), mbIsDisposed(false) { } ConfigurationController::~ConfigurationController (void) throw() { } void SAL_CALL ConfigurationController::disposing (void) { if (mpImplementation.get() == NULL) return; #if defined VERBOSE && VERBOSE>=1 OSL_TRACE("ConfigurationController::disposing\n"); OSL_TRACE(" requesting empty configuration\n"); #endif // To destroy all resources an empty configuration is requested and then, // synchronously, all resulting requests are processed. mpImplementation->mpQueueProcessor->Clear(); restoreConfiguration(new Configuration(this,false)); mpImplementation->mpQueueProcessor->ProcessUntilEmpty(); #if defined VERBOSE && VERBOSE>=1 OSL_TRACE(" all requests processed\n"); #endif // Now that all resources have been deactivated, mark the controller as // disposed. mbIsDisposed = true; // Release the listeners. lang::EventObject aEvent; aEvent.Source = uno::Reference((cppu::OWeakObject*)this); { const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); mpImplementation->mpBroadcaster->DisposeAndClear(); } mpImplementation->mpQueueProcessor.reset(); mpImplementation->mxRequestedConfiguration = NULL; mpImplementation.reset(); } void ConfigurationController::ProcessEvent (void) { if (mpImplementation.get() != NULL) { OSL_ASSERT(mpImplementation->mpQueueProcessor.get()!=NULL); mpImplementation->mpQueueProcessor->ProcessOneEvent(); } } void ConfigurationController::RequestSynchronousUpdate (void) { if (mpImplementation.get() == NULL) return; if (mpImplementation->mpQueueProcessor.get() == 0) return; mpImplementation->mpQueueProcessor->ProcessUntilEmpty(); } //----- XConfigurationControllerBroadcaster ----------------------------------- void SAL_CALL ConfigurationController::addConfigurationChangeListener ( const Reference& rxListener, const ::rtl::OUString& rsEventType, const Any& rUserData) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); OSL_ASSERT(mpImplementation.get()!=NULL); mpImplementation->mpBroadcaster->AddListener(rxListener, rsEventType, rUserData); } void SAL_CALL ConfigurationController::removeConfigurationChangeListener ( const Reference& rxListener) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); mpImplementation->mpBroadcaster->RemoveListener(rxListener); } void SAL_CALL ConfigurationController::notifyEvent ( const ConfigurationChangeEvent& rEvent) throw (RuntimeException) { ThrowIfDisposed(); mpImplementation->mpBroadcaster->NotifyListeners(rEvent); } //----- XConfigurationController ---------------------------------------------- void SAL_CALL ConfigurationController::lock (void) throw (RuntimeException) { OSL_ASSERT(mpImplementation.get()!=NULL); OSL_ASSERT(mpImplementation->mpConfigurationUpdater.get()!=NULL); ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); ++mpImplementation->mnLockCount; if (mpImplementation->mpConfigurationUpdaterLock.get()==NULL) mpImplementation->mpConfigurationUpdaterLock = mpImplementation->mpConfigurationUpdater->GetLock(); } void SAL_CALL ConfigurationController::unlock (void) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); // Allow unlocking while the ConfigurationController is being disposed // (but not when that is done and the controller is disposed.) if (rBHelper.bDisposed) ThrowIfDisposed(); OSL_ASSERT(mpImplementation->mnLockCount>0); --mpImplementation->mnLockCount; if (mpImplementation->mnLockCount == 0) mpImplementation->mpConfigurationUpdaterLock.reset(); } void SAL_CALL ConfigurationController::requestResourceActivation ( const Reference& rxResourceId, ResourceActivationMode eMode) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); // Check whether we are being disposed. This is handled differently // then being completely disposed because the first thing disposing() // does is to deactivate all remaining resources. This is done via // regular methods which must not throw DisposedExceptions. Therefore // we just return silently during that stage. if (rBHelper.bInDispose) { #if defined VERBOSE && VERBOSE>=1 OSL_TRACE("ConfigurationController::requestResourceActivation(): ignoring %s\n", OUStringToOString( FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); #endif return; } #if defined VERBOSE && VERBOSE>=2 OSL_TRACE("ConfigurationController::requestResourceActivation() %s\n", OUStringToOString( FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); #endif if (rxResourceId.is()) { if (eMode == ResourceActivationMode_REPLACE) { // Get a list of the matching resources and create deactivation // requests for them. Sequence > aResourceList ( mpImplementation->mxRequestedConfiguration->getResources( rxResourceId->getAnchor(), rxResourceId->getResourceTypePrefix(), AnchorBindingMode_DIRECT)); for (sal_Int32 nIndex=0; nIndexcompareTo(aResourceList[nIndex]) == 0) continue; // Request the deactivation of a resource and all resources // linked to it. requestResourceDeactivation(aResourceList[nIndex]); } } Reference xRequest( new GenericConfigurationChangeRequest( rxResourceId, GenericConfigurationChangeRequest::Activation)); postChangeRequest(xRequest); } } void SAL_CALL ConfigurationController::requestResourceDeactivation ( const Reference& rxResourceId) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); #if defined VERBOSE && VERBOSE>=2 OSL_TRACE("ConfigurationController::requestResourceDeactivation() %s\n", OUStringToOString( FrameworkHelper::ResourceIdToString(rxResourceId), RTL_TEXTENCODING_UTF8).getStr()); #endif if (rxResourceId.is()) { // Request deactivation of all resources linked to the specified one // as well. const Sequence > aLinkedResources ( mpImplementation->mxRequestedConfiguration->getResources( rxResourceId, OUString(), AnchorBindingMode_DIRECT)); const sal_Int32 nCount (aLinkedResources.getLength()); for (sal_Int32 nIndex=0; nIndex xRequest( new GenericConfigurationChangeRequest( rxResourceId, GenericConfigurationChangeRequest::Deactivation)); postChangeRequest(xRequest); } } Reference SAL_CALL ConfigurationController::getResource ( const Reference& rxResourceId) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); ConfigurationControllerResourceManager::ResourceDescriptor aDescriptor ( mpImplementation->mpResourceManager->GetResource(rxResourceId)); return aDescriptor.mxResource; } void SAL_CALL ConfigurationController::update (void) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); if (mpImplementation->mpQueueProcessor->IsEmpty()) { // The queue is empty. Add another request that does nothing but // asynchronously trigger a request for an update. mpImplementation->mpQueueProcessor->AddRequest(new UpdateRequest()); } else { // The queue is not empty, so we rely on the queue processor to // request an update automatically when the queue becomes empty. } } sal_Bool SAL_CALL ConfigurationController::hasPendingRequests (void) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); return ! mpImplementation->mpQueueProcessor->IsEmpty(); } void SAL_CALL ConfigurationController::postChangeRequest ( const Reference& rxRequest) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); mpImplementation->mpQueueProcessor->AddRequest(rxRequest); } Reference SAL_CALL ConfigurationController::getRequestedConfiguration (void) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); if (mpImplementation->mxRequestedConfiguration.is()) return Reference( mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY); else return Reference(); } Reference SAL_CALL ConfigurationController::getCurrentConfiguration (void) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); Reference xCurrentConfiguration( mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration()); if (xCurrentConfiguration.is()) return Reference(xCurrentConfiguration->createClone(), UNO_QUERY); else return Reference(); } /** The given configuration is restored by generating the appropriate set of activation and deactivation requests. */ void SAL_CALL ConfigurationController::restoreConfiguration ( const Reference& rxNewConfiguration) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); // We will probably be making a couple of activation and deactivation // requests so lock the configuration controller and let it later update // all changes at once. ::boost::shared_ptr pLock ( mpImplementation->mpConfigurationUpdater->GetLock()); // Get lists of resources that are to be activated or deactivated. Reference xCurrentConfiguration (mpImplementation->mxRequestedConfiguration); #if defined VERBOSE && VERBOSE>=1 OSL_TRACE("ConfigurationController::restoreConfiguration(\n"); ConfigurationTracer::TraceConfiguration(rxNewConfiguration, "requested configuration"); ConfigurationTracer::TraceConfiguration(xCurrentConfiguration, "current configuration"); #endif ConfigurationClassifier aClassifier (rxNewConfiguration, xCurrentConfiguration); aClassifier.Partition(); #if defined VERBOSE && VERBOSE>=3 aClassifier.TraceResourceIdVector( "requested but not current resources:\n", aClassifier.GetC1minusC2()); aClassifier.TraceResourceIdVector( "current but not requested resources:\n", aClassifier.GetC2minusC1()); aClassifier.TraceResourceIdVector( "requested and current resources:\n", aClassifier.GetC1andC2()); #endif ConfigurationClassifier::ResourceIdVector::const_iterator iResource; // Request the deactivation of resources that are not requested in the // new configuration. const ConfigurationClassifier::ResourceIdVector& rResourcesToDeactivate ( aClassifier.GetC2minusC1()); for (iResource=rResourcesToDeactivate.begin(); iResource!=rResourcesToDeactivate.end(); ++iResource) { requestResourceDeactivation(*iResource); } // Request the activation of resources that are requested in the // new configuration but are not part of the current configuration. const ConfigurationClassifier::ResourceIdVector& rResourcesToActivate ( aClassifier.GetC1minusC2()); for (iResource=rResourcesToActivate.begin(); iResource!=rResourcesToActivate.end(); ++iResource) { requestResourceActivation(*iResource, ResourceActivationMode_ADD); } pLock.reset(); } //----- XResourceFactoryManager ----------------------------------------------- void SAL_CALL ConfigurationController::addResourceFactory( const OUString& sResourceURL, const Reference& rxResourceFactory) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); mpImplementation->mpResourceFactoryContainer->AddFactory(sResourceURL, rxResourceFactory); } void SAL_CALL ConfigurationController::removeResourceFactoryForURL( const OUString& sResourceURL) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); mpImplementation->mpResourceFactoryContainer->RemoveFactoryForURL(sResourceURL); } void SAL_CALL ConfigurationController::removeResourceFactoryForReference( const Reference& rxResourceFactory) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory); } Reference SAL_CALL ConfigurationController::getResourceFactory ( const OUString& sResourceURL) throw (RuntimeException) { ::osl::MutexGuard aGuard (maMutex); ThrowIfDisposed(); return mpImplementation->mpResourceFactoryContainer->GetFactory(sResourceURL); } //----- XInitialization ------------------------------------------------------- void SAL_CALL ConfigurationController::initialize (const Sequence& aArguments) throw (Exception, RuntimeException) { ::osl::MutexGuard aGuard (maMutex); if (aArguments.getLength() == 1) { const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); mpImplementation.reset(new Implementation( *this, Reference(aArguments[0], UNO_QUERY_THROW))); } } //----------------------------------------------------------------------------- void ConfigurationController::ThrowIfDisposed (void) const throw (::com::sun::star::lang::DisposedException) { if (mbIsDisposed) { throw lang::DisposedException ( OUString(RTL_CONSTASCII_USTRINGPARAM( "ConfigurationController object has already been disposed")), const_cast(static_cast(this))); } if (mpImplementation.get() == NULL) { OSL_ASSERT(mpImplementation.get() != NULL); throw RuntimeException( OUString(RTL_CONSTASCII_USTRINGPARAM( "ConfigurationController not initialized")), const_cast(static_cast(this))); } } //===== ConfigurationController::Implementation =============================== ConfigurationController::Implementation::Implementation ( ConfigurationController& rController, const Reference& rxController) : mxControllerManager(rxController, UNO_QUERY_THROW), mpBroadcaster(new ConfigurationControllerBroadcaster(&rController)), mxRequestedConfiguration(new Configuration(&rController, true)), mpBase(NULL), mpResourceFactoryContainer(new ResourceFactoryManager(mxControllerManager)), mpResourceManager( new ConfigurationControllerResourceManager(mpResourceFactoryContainer,mpBroadcaster)), mpConfigurationUpdater( new ConfigurationUpdater(mpBroadcaster, mpResourceManager,mxControllerManager)), mpQueueProcessor(new ChangeRequestQueueProcessor(&rController,mpConfigurationUpdater)), mpConfigurationUpdaterLock(), mnLockCount(0) { mpQueueProcessor->SetConfiguration(mxRequestedConfiguration); } ConfigurationController::Implementation::~Implementation (void) { } } } // end of namespace sd::framework