summaryrefslogtreecommitdiffstats
path: root/sd/source/ui/framework/configuration/ConfigurationController.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sd/source/ui/framework/configuration/ConfigurationController.cxx')
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationController.cxx522
1 files changed, 522 insertions, 0 deletions
diff --git a/sd/source/ui/framework/configuration/ConfigurationController.cxx b/sd/source/ui/framework/configuration/ConfigurationController.cxx
new file mode 100644
index 0000000000..15daf362f9
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationController.cxx
@@ -0,0 +1,522 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <framework/ConfigurationController.hxx>
+#include <framework/Configuration.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <DrawController.hxx>
+#include "ConfigurationUpdater.hxx"
+#include "ConfigurationControllerBroadcaster.hxx"
+#include "ConfigurationTracer.hxx"
+#include "GenericConfigurationChangeRequest.hxx"
+#include "ConfigurationControllerResourceManager.hxx"
+#include "ResourceFactoryManager.hxx"
+#include "UpdateRequest.hxx"
+#include "ChangeRequestQueueProcessor.hxx"
+#include "ConfigurationClassifier.hxx"
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/frame/XController.hpp>
+
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+
+namespace sd::framework {
+
+//----- ConfigurationController::Implementation -------------------------------
+
+class ConfigurationController::Implementation
+{
+public:
+ Implementation (
+ ConfigurationController& rController,
+ const rtl::Reference<::sd::DrawController>& rxController);
+
+ rtl::Reference<::sd::DrawController> mxControllerManager;
+
+ /** The Broadcaster class implements storing and calling of listeners.
+ */
+ std::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster;
+
+ /** The requested configuration which is modified (asynchronously) by
+ calls to requestResourceActivation() and
+ requestResourceDeactivation(). The mpConfigurationUpdater makes the
+ current configuration reflect the content of this one.
+ */
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxRequestedConfiguration;
+
+ std::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer;
+
+ std::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager;
+
+ std::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater;
+
+ /** The queue processor owns the queue of configuration change request
+ objects and processes the objects.
+ */
+ std::unique_ptr<ChangeRequestQueueProcessor> mpQueueProcessor;
+
+ std::shared_ptr<ConfigurationUpdaterLock> mpConfigurationUpdaterLock;
+
+ sal_Int32 mnLockCount;
+};
+
+//===== ConfigurationController::Lock =========================================
+
+ConfigurationController::Lock::Lock (const Reference<XConfigurationController>& rxController)
+ : mxController(rxController)
+{
+ OSL_ASSERT(mxController.is());
+
+ if (mxController.is())
+ mxController->lock();
+}
+
+ConfigurationController::Lock::~Lock()
+{
+ if (mxController.is())
+ mxController->unlock();
+}
+
+//===== ConfigurationController ===============================================
+
+ConfigurationController::ConfigurationController(const rtl::Reference<::sd::DrawController>& rxController)
+ : ConfigurationControllerInterfaceBase(m_aMutex)
+ , mbIsDisposed(false)
+{
+ const SolarMutexGuard aSolarGuard;
+
+ mpImplementation.reset(new Implementation(
+ *this,
+ rxController));
+}
+
+ConfigurationController::~ConfigurationController() noexcept
+{
+}
+
+void SAL_CALL ConfigurationController::disposing()
+{
+ if (mpImplementation == nullptr)
+ return;
+
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::disposing");
+ SAL_INFO("sd.fwk", __func__ << ": requesting empty configuration");
+ // 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();
+ SAL_INFO("sd.fwk", __func__ << ": all requests processed");
+
+ // Now that all resources have been deactivated, mark the controller as
+ // disposed.
+ mbIsDisposed = true;
+
+ // Release the listeners.
+ lang::EventObject aEvent;
+ aEvent.Source = uno::Reference<uno::XInterface>(static_cast<cppu::OWeakObject*>(this));
+
+ {
+ const SolarMutexGuard aSolarGuard;
+ mpImplementation->mpBroadcaster->DisposeAndClear();
+ }
+
+ mpImplementation->mpQueueProcessor.reset();
+ mpImplementation->mxRequestedConfiguration = nullptr;
+ mpImplementation.reset();
+}
+
+void ConfigurationController::ProcessEvent()
+{
+ if (mpImplementation != nullptr)
+ {
+ OSL_ASSERT(mpImplementation->mpQueueProcessor != nullptr);
+
+ mpImplementation->mpQueueProcessor->ProcessOneEvent();
+ }
+}
+
+void ConfigurationController::RequestSynchronousUpdate()
+{
+ if (mpImplementation == nullptr)
+ return;
+ if (mpImplementation->mpQueueProcessor == nullptr)
+ return;
+ mpImplementation->mpQueueProcessor->ProcessUntilEmpty();
+}
+
+//----- XConfigurationControllerBroadcaster -----------------------------------
+
+void SAL_CALL ConfigurationController::addConfigurationChangeListener (
+ const Reference<XConfigurationChangeListener>& rxListener,
+ const OUString& rsEventType,
+ const Any& rUserData)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ ThrowIfDisposed();
+ OSL_ASSERT(mpImplementation != nullptr);
+ mpImplementation->mpBroadcaster->AddListener(rxListener, rsEventType, rUserData);
+}
+
+void SAL_CALL ConfigurationController::removeConfigurationChangeListener (
+ const Reference<XConfigurationChangeListener>& rxListener)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ ThrowIfDisposed();
+ mpImplementation->mpBroadcaster->RemoveListener(rxListener);
+}
+
+void SAL_CALL ConfigurationController::notifyEvent (
+ const ConfigurationChangeEvent& rEvent)
+{
+ ThrowIfDisposed();
+ mpImplementation->mpBroadcaster->NotifyListeners(rEvent);
+}
+
+//----- XConfigurationController ----------------------------------------------
+
+void SAL_CALL ConfigurationController::lock()
+{
+ OSL_ASSERT(mpImplementation != nullptr);
+ OSL_ASSERT(mpImplementation->mpConfigurationUpdater != nullptr);
+
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ ++mpImplementation->mnLockCount;
+ if (mpImplementation->mpConfigurationUpdaterLock == nullptr)
+ mpImplementation->mpConfigurationUpdaterLock
+ = mpImplementation->mpConfigurationUpdater->GetLock();
+}
+
+void SAL_CALL ConfigurationController::unlock()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ // 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<XResourceId>& rxResourceId,
+ ResourceActivationMode eMode)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ 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)
+ {
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceActivation(): ignoring " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+ return;
+ }
+
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceActivation() " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+
+ if (!rxResourceId.is())
+ return;
+
+ if (eMode == ResourceActivationMode_REPLACE)
+ {
+ // Get a list of the matching resources and create deactivation
+ // requests for them.
+ const Sequence<Reference<XResourceId> > aResourceList (
+ mpImplementation->mxRequestedConfiguration->getResources(
+ rxResourceId->getAnchor(),
+ rxResourceId->getResourceTypePrefix(),
+ AnchorBindingMode_DIRECT));
+
+ for (const auto& rResource : aResourceList)
+ {
+ // Do not request the deactivation of the resource for which
+ // this method was called. Doing it would not change the
+ // outcome but would result in unnecessary work.
+ if (rxResourceId->compareTo(rResource) == 0)
+ continue;
+
+ // Request the deactivation of a resource and all resources
+ // linked to it.
+ requestResourceDeactivation(rResource);
+ }
+ }
+
+ Reference<XConfigurationChangeRequest> xRequest(
+ new GenericConfigurationChangeRequest(
+ rxResourceId,
+ GenericConfigurationChangeRequest::Activation));
+ postChangeRequest(xRequest);
+}
+
+void SAL_CALL ConfigurationController::requestResourceDeactivation (
+ const Reference<XResourceId>& rxResourceId)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::requestResourceDeactivation() " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+
+ if (!rxResourceId.is())
+ return;
+
+ // Request deactivation of all resources linked to the specified one
+ // as well.
+ const Sequence<Reference<XResourceId> > aLinkedResources (
+ mpImplementation->mxRequestedConfiguration->getResources(
+ rxResourceId,
+ OUString(),
+ AnchorBindingMode_DIRECT));
+ for (const auto& rLinkedResource : aLinkedResources)
+ {
+ // We do not add deactivation requests directly but call this
+ // method recursively, so that when one time there are resources
+ // linked to linked resources, these are handled correctly, too.
+ requestResourceDeactivation(rLinkedResource);
+ }
+
+ // Add a deactivation request for the specified resource.
+ Reference<XConfigurationChangeRequest> xRequest(
+ new GenericConfigurationChangeRequest(
+ rxResourceId,
+ GenericConfigurationChangeRequest::Deactivation));
+ postChangeRequest(xRequest);
+}
+
+Reference<XResource> SAL_CALL ConfigurationController::getResource (
+ const Reference<XResourceId>& rxResourceId)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ ConfigurationControllerResourceManager::ResourceDescriptor aDescriptor (
+ mpImplementation->mpResourceManager->GetResource(rxResourceId));
+ return aDescriptor.mxResource;
+}
+
+void SAL_CALL ConfigurationController::update()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ 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()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ return ! mpImplementation->mpQueueProcessor->IsEmpty();
+}
+
+void SAL_CALL ConfigurationController::postChangeRequest (
+ const Reference<XConfigurationChangeRequest>& rxRequest)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ mpImplementation->mpQueueProcessor->AddRequest(rxRequest);
+}
+
+Reference<XConfiguration> SAL_CALL ConfigurationController::getRequestedConfiguration()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ if (mpImplementation->mxRequestedConfiguration.is())
+ return Reference<XConfiguration>(
+ mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY);
+ else
+ return Reference<XConfiguration>();
+}
+
+Reference<XConfiguration> SAL_CALL ConfigurationController::getCurrentConfiguration()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ Reference<XConfiguration> xCurrentConfiguration(
+ mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration());
+ if (xCurrentConfiguration.is())
+ return Reference<XConfiguration>(xCurrentConfiguration->createClone(), UNO_QUERY);
+ else
+ return Reference<XConfiguration>();
+}
+
+/** The given configuration is restored by generating the appropriate set of
+ activation and deactivation requests.
+*/
+void SAL_CALL ConfigurationController::restoreConfiguration (
+ const Reference<XConfiguration>& rxNewConfiguration)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ 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.
+ std::shared_ptr<ConfigurationUpdaterLock> pLock (
+ mpImplementation->mpConfigurationUpdater->GetLock());
+
+ // Get lists of resources that are to be activated or deactivated.
+ Reference<XConfiguration> xCurrentConfiguration (mpImplementation->mxRequestedConfiguration);
+#if OSL_DEBUG_LEVEL >=1
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::restoreConfiguration(");
+ ConfigurationTracer::TraceConfiguration(rxNewConfiguration, "requested configuration");
+ ConfigurationTracer::TraceConfiguration(xCurrentConfiguration, "current configuration");
+#endif
+ ConfigurationClassifier aClassifier (rxNewConfiguration, xCurrentConfiguration);
+ aClassifier.Partition();
+#if DEBUG_SD_CONFIGURATION_TRACE
+ 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
+
+ // Request the deactivation of resources that are not requested in the
+ // new configuration.
+ const ConfigurationClassifier::ResourceIdVector& rResourcesToDeactivate (
+ aClassifier.GetC2minusC1());
+ for (const auto& rxResource : rResourcesToDeactivate)
+ {
+ requestResourceDeactivation(rxResource);
+ }
+
+ // 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 (const auto& rxResource : rResourcesToActivate)
+ {
+ requestResourceActivation(rxResource, ResourceActivationMode_ADD);
+ }
+
+ pLock.reset();
+}
+
+//----- XResourceFactoryManager -----------------------------------------------
+
+void SAL_CALL ConfigurationController::addResourceFactory(
+ const OUString& sResourceURL,
+ const Reference<XResourceFactory>& rxResourceFactory)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+ mpImplementation->mpResourceFactoryContainer->AddFactory(sResourceURL, rxResourceFactory);
+}
+
+void SAL_CALL ConfigurationController::removeResourceFactoryForURL(
+ const OUString& sResourceURL)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+ mpImplementation->mpResourceFactoryContainer->RemoveFactoryForURL(sResourceURL);
+}
+
+void SAL_CALL ConfigurationController::removeResourceFactoryForReference(
+ const Reference<XResourceFactory>& rxResourceFactory)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+ mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory);
+}
+
+Reference<XResourceFactory> SAL_CALL ConfigurationController::getResourceFactory (
+ const OUString& sResourceURL)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ return mpImplementation->mpResourceFactoryContainer->GetFactory(sResourceURL);
+}
+
+void ConfigurationController::ThrowIfDisposed () const
+{
+ if (mbIsDisposed)
+ {
+ throw lang::DisposedException ("ConfigurationController object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+
+ if (mpImplementation == nullptr)
+ {
+ OSL_ASSERT(mpImplementation != nullptr);
+ throw RuntimeException("ConfigurationController not initialized",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+//===== ConfigurationController::Implementation ===============================
+
+ConfigurationController::Implementation::Implementation (
+ ConfigurationController& rController,
+ const rtl::Reference<::sd::DrawController>& rxController)
+ : mxControllerManager(rxController, UNO_QUERY_THROW),
+ mpBroadcaster(std::make_shared<ConfigurationControllerBroadcaster>(&rController)),
+ mxRequestedConfiguration(new Configuration(&rController, true)),
+ mpResourceFactoryContainer(std::make_shared<ResourceFactoryManager>(mxControllerManager)),
+ mpResourceManager(
+ std::make_shared<ConfigurationControllerResourceManager>(mpResourceFactoryContainer,mpBroadcaster)),
+ mpConfigurationUpdater(
+ std::make_shared<ConfigurationUpdater>(mpBroadcaster, mpResourceManager,mxControllerManager)),
+ mpQueueProcessor(new ChangeRequestQueueProcessor(mpConfigurationUpdater)),
+ mnLockCount(0)
+{
+ mpQueueProcessor->SetConfiguration(mxRequestedConfiguration);
+}
+
+} // end of namespace sd::framework
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */