summaryrefslogtreecommitdiffstats
path: root/sd/source/ui/framework
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sd/source/ui/framework
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source/ui/framework')
-rw-r--r--sd/source/ui/framework/configuration/ChangeRequestQueue.cxx28
-rw-r--r--sd/source/ui/framework/configuration/ChangeRequestQueue.hxx48
-rw-r--r--sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx180
-rw-r--r--sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx126
-rw-r--r--sd/source/ui/framework/configuration/Configuration.cxx311
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationClassifier.cxx167
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationClassifier.hxx165
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationController.cxx541
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx192
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx138
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx303
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx141
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationTracer.cxx73
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationTracer.hxx58
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationUpdater.cxx376
-rw-r--r--sd/source/ui/framework/configuration/ConfigurationUpdater.hxx209
-rw-r--r--sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx81
-rw-r--r--sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx98
-rw-r--r--sd/source/ui/framework/configuration/ResourceFactoryManager.cxx197
-rw-r--r--sd/source/ui/framework/configuration/ResourceFactoryManager.hxx120
-rw-r--r--sd/source/ui/framework/configuration/ResourceId.cxx503
-rw-r--r--sd/source/ui/framework/configuration/UpdateRequest.cxx47
-rw-r--r--sd/source/ui/framework/configuration/UpdateRequest.hxx70
-rw-r--r--sd/source/ui/framework/configuration/debugtrace.hxx15
-rw-r--r--sd/source/ui/framework/factories/BasicPaneFactory.cxx432
-rw-r--r--sd/source/ui/framework/factories/BasicPaneFactory.hxx131
-rw-r--r--sd/source/ui/framework/factories/BasicToolBarFactory.cxx161
-rw-r--r--sd/source/ui/framework/factories/BasicToolBarFactory.hxx84
-rw-r--r--sd/source/ui/framework/factories/BasicViewFactory.cxx518
-rw-r--r--sd/source/ui/framework/factories/BasicViewFactory.hxx129
-rw-r--r--sd/source/ui/framework/factories/ChildWindowPane.cxx219
-rw-r--r--sd/source/ui/framework/factories/ChildWindowPane.hxx101
-rw-r--r--sd/source/ui/framework/factories/FrameWindowPane.cxx39
-rw-r--r--sd/source/ui/framework/factories/FrameWindowPane.hxx50
-rw-r--r--sd/source/ui/framework/factories/FullScreenPane.cxx226
-rw-r--r--sd/source/ui/framework/factories/FullScreenPane.hxx85
-rw-r--r--sd/source/ui/framework/factories/Pane.cxx178
-rw-r--r--sd/source/ui/framework/factories/PresentationFactory.cxx192
-rw-r--r--sd/source/ui/framework/factories/ViewShellWrapper.cxx252
-rw-r--r--sd/source/ui/framework/module/CenterViewFocusModule.cxx151
-rw-r--r--sd/source/ui/framework/module/CenterViewFocusModule.hxx90
-rw-r--r--sd/source/ui/framework/module/DrawModule.cxx41
-rw-r--r--sd/source/ui/framework/module/ImpressModule.cxx51
-rw-r--r--sd/source/ui/framework/module/ModuleController.cxx244
-rw-r--r--sd/source/ui/framework/module/PresentationModule.cxx36
-rw-r--r--sd/source/ui/framework/module/ShellStackGuard.cxx150
-rw-r--r--sd/source/ui/framework/module/ShellStackGuard.hxx94
-rw-r--r--sd/source/ui/framework/module/SlideSorterModule.cxx313
-rw-r--r--sd/source/ui/framework/module/SlideSorterModule.hxx97
-rw-r--r--sd/source/ui/framework/module/ToolBarModule.cxx191
-rw-r--r--sd/source/ui/framework/module/ToolBarModule.hxx81
-rw-r--r--sd/source/ui/framework/module/ViewTabBarModule.cxx180
-rw-r--r--sd/source/ui/framework/module/ViewTabBarModule.hxx83
-rw-r--r--sd/source/ui/framework/tools/FrameworkHelper.cxx952
54 files changed, 9738 insertions, 0 deletions
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx b/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx
new file mode 100644
index 000000000..0168c162b
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ChangeRequestQueue.cxx
@@ -0,0 +1,28 @@
+/* -*- 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 "ChangeRequestQueue.hxx"
+
+namespace sd::framework
+{
+ChangeRequestQueue::ChangeRequestQueue() {}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx b/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx
new file mode 100644
index 000000000..e60b5b527
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ChangeRequestQueue.hxx
@@ -0,0 +1,48 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <queue>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationChangeRequest;
+}
+
+namespace sd::framework
+{
+/** The ChangeRequestQueue stores the pending requests for changes to the
+ requested configuration. It is the task of the
+ ChangeRequestQueueProcessor to process these requests.
+*/
+class ChangeRequestQueue
+ : public ::std::queue<css::uno::Reference<css::drawing::framework::XConfigurationChangeRequest>>
+{
+public:
+ /** Create an empty queue.
+ */
+ ChangeRequestQueue();
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx
new file mode 100644
index 000000000..da633a540
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx
@@ -0,0 +1,180 @@
+/* -*- 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 "debugtrace.hxx"
+#include "ChangeRequestQueueProcessor.hxx"
+#include "ConfigurationTracer.hxx"
+
+#include "ConfigurationUpdater.hxx"
+
+#include <vcl/svapp.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace {
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+
+void TraceRequest (const Reference<XConfigurationChangeRequest>& rxRequest)
+{
+ Reference<container::XNamed> xNamed (rxRequest, UNO_QUERY);
+ if (xNamed.is())
+ SAL_INFO("sd.fwk", __func__ << ": " << xNamed->getName());
+}
+
+#endif
+
+} // end of anonymous namespace
+
+namespace sd::framework {
+
+ChangeRequestQueueProcessor::ChangeRequestQueueProcessor (
+ const std::shared_ptr<ConfigurationUpdater>& rpConfigurationUpdater)
+ : mnUserEventId(nullptr),
+ mpConfigurationUpdater(rpConfigurationUpdater)
+{
+}
+
+ChangeRequestQueueProcessor::~ChangeRequestQueueProcessor()
+{
+ if (mnUserEventId != nullptr)
+ Application::RemoveUserEvent(mnUserEventId);
+}
+
+void ChangeRequestQueueProcessor::SetConfiguration (
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ mxConfiguration = rxConfiguration;
+ StartProcessing();
+}
+
+void ChangeRequestQueueProcessor::AddRequest (
+ const Reference<XConfigurationChangeRequest>& rxRequest)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+ if (maQueue.empty())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": Adding requests to empty queue");
+ ConfigurationTracer::TraceConfiguration(
+ mxConfiguration, "current configuration of queue processor");
+ }
+ SAL_INFO("sd.fwk", __func__ << ": Adding request");
+ TraceRequest(rxRequest);
+#endif
+
+ maQueue.push(rxRequest);
+ StartProcessing();
+}
+
+void ChangeRequestQueueProcessor::StartProcessing()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ if (mnUserEventId == nullptr
+ && mxConfiguration.is()
+ && ! maQueue.empty())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": ChangeRequestQueueProcessor scheduling processing");
+ mnUserEventId = Application::PostUserEvent(
+ LINK(this,ChangeRequestQueueProcessor,ProcessEvent));
+ }
+}
+
+IMPL_LINK_NOARG(ChangeRequestQueueProcessor, ProcessEvent, void*, void)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ mnUserEventId = nullptr;
+
+ ProcessOneEvent();
+
+ if ( ! maQueue.empty())
+ {
+ // Schedule the processing of the next event.
+ StartProcessing();
+ }
+}
+
+void ChangeRequestQueueProcessor::ProcessOneEvent()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+
+ SAL_INFO("sd.fwk", __func__ << ": ProcessOneEvent");
+
+ if (!mxConfiguration.is() || maQueue.empty())
+ return;
+
+ // Get and remove the first entry from the queue.
+ Reference<XConfigurationChangeRequest> xRequest (maQueue.front());
+ maQueue.pop();
+
+ // Execute the change request.
+ if (xRequest.is())
+ {
+#if DEBUG_SD_CONFIGURATION_TRACE
+ TraceRequest(xRequest);
+#endif
+ xRequest->execute(mxConfiguration);
+ }
+
+ if (!maQueue.empty())
+ return;
+
+ SAL_INFO("sd.fwk", __func__ << ": All requests are processed");
+ // The queue is empty so tell the ConfigurationManager to update
+ // its state.
+ if (mpConfigurationUpdater != nullptr)
+ {
+#if DEBUG_SD_CONFIGURATION_TRACE
+ ConfigurationTracer::TraceConfiguration (
+ mxConfiguration, "updating to configuration");
+#endif
+ mpConfigurationUpdater->RequestUpdate(mxConfiguration);
+ }
+}
+
+bool ChangeRequestQueueProcessor::IsEmpty() const
+{
+ return maQueue.empty();
+}
+
+void ChangeRequestQueueProcessor::ProcessUntilEmpty()
+{
+ while ( ! IsEmpty())
+ ProcessOneEvent();
+}
+
+void ChangeRequestQueueProcessor::Clear()
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ ChangeRequestQueue().swap(maQueue);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx
new file mode 100644
index 000000000..4afd5af76
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx
@@ -0,0 +1,126 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "ChangeRequestQueue.hxx"
+#include <osl/mutex.hxx>
+
+#include <tools/link.hxx>
+
+#include <memory>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationChangeRequest;
+}
+
+struct ImplSVEvent;
+
+namespace sd::framework
+{
+class ConfigurationUpdater;
+
+/** The ChangeRequestQueueProcessor owns the ChangeRequestQueue and
+ processes the configuration change requests.
+
+ When after processing one entry the queue is empty then the
+ XConfigurationController::update() method is called so that the changes
+ made to the local XConfiguration reference are reflected by the UI.
+
+ Queue entries are processed asynchronously by calling PostUserEvent().
+*/
+class ChangeRequestQueueProcessor
+{
+public:
+ /** The queue processor is created with a reference to an
+ ConfigurationController so that its UpdateConfiguration() method can
+ be called when the queue becomes empty.
+ */
+ explicit ChangeRequestQueueProcessor(const std::shared_ptr<ConfigurationUpdater>& rpUpdater);
+ ~ChangeRequestQueueProcessor();
+
+ /** Sets the configuration who will be changed by subsequent change
+ requests. This method should be called only by the configuration
+ controller who owns the configuration.
+ */
+ void SetConfiguration(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ /** The given request is appended to the end of the queue and will
+ eventually be processed when all other entries in front of it have
+ been processed.
+ */
+ void AddRequest(
+ const css::uno::Reference<css::drawing::framework::XConfigurationChangeRequest>& rxRequest);
+
+ /** Returns </sal_True> when the queue is empty.
+ */
+ bool IsEmpty() const;
+
+ /** Process all events in the queue synchronously.
+
+ <p>This method is typically called when the framework is shut down
+ to establish an empty configuration.</p>
+ */
+ void ProcessUntilEmpty();
+
+ /** Process the first event in queue.
+ */
+ void ProcessOneEvent();
+
+ /** Remove all events from the queue.
+
+ <p>This method is typically called when the framework is shut down
+ to avoid the processing of still pending activation requests.</p>
+ */
+ void Clear();
+
+private:
+ mutable ::osl::Mutex maMutex;
+
+ ChangeRequestQueue maQueue;
+
+ /** The id returned by the last PostUserEvent() call. This id is stored
+ so that a pending user event can be removed when the queue processor
+ is destroyed.
+ */
+ ImplSVEvent* mnUserEventId;
+
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxConfiguration;
+
+ std::shared_ptr<ConfigurationUpdater> mpConfigurationUpdater;
+
+ /** Initiate the processing of the entries in the queue. The actual
+ processing starts asynchronously.
+ */
+ void StartProcessing();
+
+ /** Callback function for the PostUserEvent() call.
+ */
+ DECL_LINK(ProcessEvent, void*, void);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/Configuration.cxx b/sd/source/ui/framework/configuration/Configuration.cxx
new file mode 100644
index 000000000..7b813a42b
--- /dev/null
+++ b/sd/source/ui/framework/configuration/Configuration.cxx
@@ -0,0 +1,311 @@
+/* -*- 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/Configuration.hxx>
+
+#include <framework/FrameworkHelper.hxx>
+
+#include <com/sun/star/drawing/framework/ConfigurationChangeEvent.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationControllerBroadcaster.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+/** Use the XResourceId::compareTo() method to implement a compare operator
+ for STL containers.
+*/
+class XResourceIdLess
+{
+public:
+ bool operator () (const Reference<XResourceId>& rId1, const Reference<XResourceId>& rId2) const
+ {
+ return rId1->compareTo(rId2) == -1;
+ }
+};
+
+} // end of anonymous namespace
+
+namespace sd::framework {
+
+class Configuration::ResourceContainer
+ : public ::std::set<Reference<XResourceId>, XResourceIdLess>
+{
+public:
+ ResourceContainer() {}
+};
+
+//===== Configuration =========================================================
+
+Configuration::Configuration (
+ const Reference<XConfigurationControllerBroadcaster>& rxBroadcaster,
+ bool bBroadcastRequestEvents)
+ : mpResourceContainer(new ResourceContainer()),
+ mxBroadcaster(rxBroadcaster),
+ mbBroadcastRequestEvents(bBroadcastRequestEvents)
+{
+}
+
+Configuration::Configuration (
+ const Reference<XConfigurationControllerBroadcaster>& rxBroadcaster,
+ bool bBroadcastRequestEvents,
+ const ResourceContainer& rResourceContainer)
+ : mpResourceContainer(new ResourceContainer(rResourceContainer)),
+ mxBroadcaster(rxBroadcaster),
+ mbBroadcastRequestEvents(bBroadcastRequestEvents)
+{
+}
+
+Configuration::~Configuration()
+{
+}
+
+void Configuration::disposing(std::unique_lock<std::mutex>&)
+{
+ mpResourceContainer->clear();
+ mxBroadcaster = nullptr;
+}
+
+//----- XConfiguration --------------------------------------------------------
+
+void SAL_CALL Configuration::addResource (const Reference<XResourceId>& rxResourceId)
+{
+ ThrowIfDisposed();
+
+ if ( ! rxResourceId.is() || rxResourceId->getResourceURL().isEmpty())
+ throw css::lang::IllegalArgumentException();
+
+ if (mpResourceContainer->insert(rxResourceId).second)
+ {
+ SAL_INFO("sd.fwk", __func__ << ": Configuration::addResource() " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+ PostEvent(rxResourceId, true);
+ }
+}
+
+void SAL_CALL Configuration::removeResource (const Reference<XResourceId>& rxResourceId)
+{
+ ThrowIfDisposed();
+
+ if ( ! rxResourceId.is() || rxResourceId->getResourceURL().isEmpty())
+ throw css::lang::IllegalArgumentException();
+
+ ResourceContainer::iterator iResource (mpResourceContainer->find(rxResourceId));
+ if (iResource != mpResourceContainer->end())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": Configuration::removeResource() " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+ PostEvent(rxResourceId,false);
+ mpResourceContainer->erase(iResource);
+ }
+}
+
+Sequence<Reference<XResourceId> > SAL_CALL Configuration::getResources (
+ const Reference<XResourceId>& rxAnchorId,
+ const OUString& rsResourceURLPrefix,
+ AnchorBindingMode eMode)
+{
+ std::unique_lock aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ const bool bFilterResources (!rsResourceURLPrefix.isEmpty());
+
+ // Collect the matching resources in a vector.
+ ::std::vector<Reference<XResourceId> > aResources;
+ for (const auto& rxResource : *mpResourceContainer)
+ {
+ if ( ! rxResource->isBoundTo(rxAnchorId,eMode))
+ continue;
+
+ if (bFilterResources)
+ {
+ // Apply the given resource prefix as filter.
+
+ // Make sure that the resource is bound directly to the anchor.
+ if (eMode != AnchorBindingMode_DIRECT
+ && ! rxResource->isBoundTo(rxAnchorId, AnchorBindingMode_DIRECT))
+ {
+ continue;
+ }
+
+ // Make sure that the resource URL matches the given prefix.
+ if ( ! rxResource->getResourceURL().match(rsResourceURLPrefix))
+ {
+ continue;
+ }
+ }
+
+ aResources.push_back(rxResource);
+ }
+
+ return comphelper::containerToSequence(aResources);
+}
+
+sal_Bool SAL_CALL Configuration::hasResource (const Reference<XResourceId>& rxResourceId)
+{
+ std::unique_lock aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ return rxResourceId.is()
+ && mpResourceContainer->find(rxResourceId) != mpResourceContainer->end();
+}
+
+//----- XCloneable ------------------------------------------------------------
+
+Reference<util::XCloneable> SAL_CALL Configuration::createClone()
+{
+ std::unique_lock aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ return new Configuration(
+ mxBroadcaster,
+ mbBroadcastRequestEvents,
+ *mpResourceContainer);
+}
+
+//----- XNamed ----------------------------------------------------------------
+
+OUString SAL_CALL Configuration::getName()
+{
+ std::unique_lock aGuard (m_aMutex);
+ OUStringBuffer aString;
+
+ if (m_bDisposed)
+ aString.append("DISPOSED ");
+ aString.append("Configuration[");
+
+ ResourceContainer::const_iterator iResource;
+ for (iResource=mpResourceContainer->begin();
+ iResource!=mpResourceContainer->end();
+ ++iResource)
+ {
+ if (iResource != mpResourceContainer->begin())
+ aString.append(", ");
+ aString.append(FrameworkHelper::ResourceIdToString(*iResource));
+ }
+ aString.append("]");
+
+ return aString.makeStringAndClear();
+}
+
+void SAL_CALL Configuration::setName (const OUString&)
+{
+ // ignored.
+}
+
+OUString Configuration::getImplementationName()
+{
+ return
+ "com.sun.star.comp.Draw.framework.configuration.Configuration";
+}
+
+sal_Bool Configuration::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> Configuration::getSupportedServiceNames()
+{
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.drawing.framework.Configuration"};
+}
+
+void Configuration::PostEvent (
+ const Reference<XResourceId>& rxResourceId,
+ const bool bActivation)
+{
+ OSL_ASSERT(rxResourceId.is());
+
+ if (!mxBroadcaster.is())
+ return;
+
+ ConfigurationChangeEvent aEvent;
+ aEvent.ResourceId = rxResourceId;
+ if (bActivation)
+ if (mbBroadcastRequestEvents)
+ aEvent.Type = FrameworkHelper::msResourceActivationRequestEvent;
+ else
+ aEvent.Type = FrameworkHelper::msResourceActivationEvent;
+ else
+ if (mbBroadcastRequestEvents)
+ aEvent.Type = FrameworkHelper::msResourceDeactivationRequestEvent;
+ else
+ aEvent.Type = FrameworkHelper::msResourceDeactivationEvent;
+ aEvent.Configuration = this;
+
+ mxBroadcaster->notifyEvent(aEvent);
+}
+
+void Configuration::ThrowIfDisposed() const
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("Configuration object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+bool AreConfigurationsEquivalent (
+ const Reference<XConfiguration>& rxConfiguration1,
+ const Reference<XConfiguration>& rxConfiguration2)
+{
+ if (rxConfiguration1.is() != rxConfiguration2.is())
+ return false;
+ if ( ! rxConfiguration1.is() && ! rxConfiguration2.is())
+ return true;
+
+ // Get the lists of resources from the two given configurations.
+ const Sequence<Reference<XResourceId> > aResources1(
+ rxConfiguration1->getResources(
+ nullptr, OUString(), AnchorBindingMode_INDIRECT));
+ const Sequence<Reference<XResourceId> > aResources2(
+ rxConfiguration2->getResources(
+ nullptr, OUString(), AnchorBindingMode_INDIRECT));
+
+ // When the number of resources differ then the configurations can not
+ // be equivalent.
+ // Comparison of the two lists of resource ids relies on their
+ // ordering.
+ return std::equal(aResources1.begin(), aResources1.end(), aResources2.begin(), aResources2.end(),
+ [](const Reference<XResourceId>& a, const Reference<XResourceId>& b) {
+ if (a.is() && b.is())
+ return a->compareTo(b) == 0;
+ return a.is() == b.is();
+ });
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_configuration_Configuration_get_implementation(
+ css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::Configuration(nullptr, false));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx b/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx
new file mode 100644
index 000000000..99fc1297d
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationClassifier.cxx
@@ -0,0 +1,167 @@
+/* -*- 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 "ConfigurationClassifier.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+ConfigurationClassifier::ConfigurationClassifier (
+ const Reference<XConfiguration>& rxConfiguration1,
+ const Reference<XConfiguration>& rxConfiguration2)
+ : mxConfiguration1(rxConfiguration1),
+ mxConfiguration2(rxConfiguration2)
+{
+}
+
+bool ConfigurationClassifier::Partition()
+{
+ maC1minusC2.clear();
+ maC2minusC1.clear();
+
+ PartitionResources(
+ mxConfiguration1->getResources(nullptr, OUString(), AnchorBindingMode_DIRECT),
+ mxConfiguration2->getResources(nullptr, OUString(), AnchorBindingMode_DIRECT));
+
+ return !maC1minusC2.empty() || !maC2minusC1.empty();
+}
+
+void ConfigurationClassifier::PartitionResources (
+ const css::uno::Sequence<Reference<XResourceId> >& rS1,
+ const css::uno::Sequence<Reference<XResourceId> >& rS2)
+{
+ ResourceIdVector aC1minusC2;
+ ResourceIdVector aC2minusC1;
+ ResourceIdVector aC1andC2;
+
+ // Classify the resources in the configurations that are not bound to
+ // other resources.
+ ClassifyResources(
+ rS1,
+ rS2,
+ aC1minusC2,
+ aC2minusC1,
+ aC1andC2);
+
+ SAL_INFO("sd.fwk", __func__ << ": copying resource ids to C1-C2");
+ CopyResources(aC1minusC2, mxConfiguration1, maC1minusC2);
+ SAL_INFO("sd.fwk", __func__ << ": copying resource ids to C2-C1");
+ CopyResources(aC2minusC1, mxConfiguration2, maC2minusC1);
+
+ // Process the unique resources that belong to both configurations.
+ for (const auto& rxResource : aC1andC2)
+ {
+ PartitionResources(
+ mxConfiguration1->getResources(rxResource, OUString(), AnchorBindingMode_DIRECT),
+ mxConfiguration2->getResources(rxResource, OUString(), AnchorBindingMode_DIRECT));
+ }
+}
+
+void ConfigurationClassifier::ClassifyResources (
+ const css::uno::Sequence<Reference<XResourceId> >& rS1,
+ const css::uno::Sequence<Reference<XResourceId> >& rS2,
+ ResourceIdVector& rS1minusS2,
+ ResourceIdVector& rS2minusS1,
+ ResourceIdVector& rS1andS2)
+{
+ // Find all elements in rS1 and place them in rS1minusS2 or rS1andS2
+ // depending on whether they are in rS2 or not.
+ for (const Reference<XResourceId>& rA1 : rS1)
+ {
+ bool bFound = std::any_of(rS2.begin(), rS2.end(),
+ [&rA1](const Reference<XResourceId>& rA2) {
+ return rA1->getResourceURL() == rA2->getResourceURL(); });
+
+ if (bFound)
+ rS1andS2.push_back(rA1);
+ else
+ rS1minusS2.push_back(rA1);
+ }
+
+ // Find all elements in rS2 that are not in rS1. The elements that are
+ // in both rS1 and rS2 have been handled above and are therefore ignored
+ // here.
+ for (const Reference<XResourceId>& rA2 : rS2)
+ {
+ bool bFound = std::any_of(rS1.begin(), rS1.end(),
+ [&rA2](const Reference<XResourceId>& rA1) {
+ return rA2->getResourceURL() == rA1->getResourceURL(); });
+
+ if ( ! bFound)
+ rS2minusS1.push_back(rA2);
+ }
+}
+
+void ConfigurationClassifier::CopyResources (
+ const ResourceIdVector& rSource,
+ const Reference<XConfiguration>& rxConfiguration,
+ ResourceIdVector& rTarget)
+{
+ // Copy all resources bound to the ones in aC1minusC2Unique to rC1minusC2.
+ for (const auto& rxResource : rSource)
+ {
+ const Sequence<Reference<XResourceId> > aBoundResources (
+ rxConfiguration->getResources(
+ rxResource,
+ OUString(),
+ AnchorBindingMode_INDIRECT));
+ const sal_Int32 nL (aBoundResources.getLength());
+
+ rTarget.reserve(rTarget.size() + 1 + nL);
+ rTarget.push_back(rxResource);
+
+ SAL_INFO("sd.fwk", __func__ << ": copying " <<
+ FrameworkHelper::ResourceIdToString(rxResource));
+
+ for (const Reference<XResourceId>& rBoundResource : aBoundResources)
+ {
+ rTarget.push_back(rBoundResource);
+ SAL_INFO("sd.fwk", __func__ << ": copying " <<
+ FrameworkHelper::ResourceIdToString(rBoundResource));
+ }
+ }
+}
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+
+void ConfigurationClassifier::TraceResourceIdVector (
+ const char* pMessage,
+ const ResourceIdVector& rResources)
+{
+
+ SAL_INFO("sd.fwk", __func__ << ": " << pMessage);
+ for (const auto& rxResource : rResources)
+ {
+ OUString sResource (FrameworkHelper::ResourceIdToString(rxResource));
+ SAL_INFO("sd.fwk", __func__ << ": " << sResource);
+ }
+}
+
+#endif
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx b/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx
new file mode 100644
index 000000000..e9384713b
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationClassifier.hxx
@@ -0,0 +1,165 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "debugtrace.hxx"
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <vector>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XResourceId;
+}
+
+namespace sd::framework
+{
+/** A ConfigurationClassifier object compares two configurations of
+ resources and gives access to the differences. It is used mainly when
+ changes to the current configuration have been requested and the various
+ resource controllers have to be supplied with the set of resources that
+ are to be activated or deactivated.
+*/
+class ConfigurationClassifier
+{
+public:
+ /** Create a new ConfigurationClassifier object that will compare the
+ two given configurations.
+ */
+ ConfigurationClassifier(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration1,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration2);
+
+ /** Calculate three lists of resource ids. These contain the resources
+ that belong to one configuration but not the other, or that belong
+ to both configurations.
+ @return
+ When the two configurations differ then return <TRUE/>. When
+ they are equivalent then return <FALSE/>.
+ */
+ bool Partition();
+
+ typedef ::std::vector<css::uno::Reference<css::drawing::framework::XResourceId>>
+ ResourceIdVector;
+
+ /** Return the resources that belong to the configuration given as
+ rxConfiguration1 to the constructor but that do not belong to
+ rxConfiguration2.
+ @return
+ A reference to the, possibly empty, list of resources is
+ returned. This reference remains valid as long as the called
+ ConfigurationClassifier object stays alive.
+ */
+ const ResourceIdVector& GetC1minusC2() const { return maC1minusC2; }
+
+ /** Return the resources that belong to the configuration given as
+ rxConfiguration2 to the constructor but that do not belong to
+ rxConfiguration1.
+ @return
+ A reference to the, possibly empty, list of resources is
+ returned. This reference remains valid as long as the called
+ ConfigurationClassifier object stays alive.
+ */
+ const ResourceIdVector& GetC2minusC1() const { return maC2minusC1; }
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+
+ /** Return the resources that belong to both the configurations that
+ where given to the constructor.
+ @return
+ A reference to the, possibly empty, list of resources is
+ returned. This reference remains valid as long as the called
+ ConfigurationClassifier object stays alive.
+ */
+ const ResourceIdVector& GetC1andC2() const { return maC1andC2; }
+
+ static void TraceResourceIdVector(const char* pMessage, const ResourceIdVector& rResources);
+
+#endif
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxConfiguration1;
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxConfiguration2;
+
+ /** After the call to Classify() this vector holds all elements from
+ mxConfiguration1 that are not in mxConfiguration2.
+ */
+ ResourceIdVector maC1minusC2;
+
+ /** After the call to Classify() this vector holds all elements from
+ mxConfiguration2 that are not in mxConfiguration1.
+ */
+ ResourceIdVector maC2minusC1;
+
+ /** Put all the elements in the two given sequences of resource ids and
+ copy them into one of the resource id result vectors maC1minusC2,
+ maC2minusC1, and maC1andC2. This is done by using only the resource
+ URLs for classification. Therefore this method calls itself
+ recursively.
+ @param rS1
+ One sequence of XResourceId objects.
+ @param rS2
+ Another sequence of XResourceId objects.
+ */
+ void PartitionResources(
+ const css::uno::Sequence<css::uno::Reference<css::drawing::framework::XResourceId>>& rS1,
+ const css::uno::Sequence<css::uno::Reference<css::drawing::framework::XResourceId>>& rS2);
+
+ /** Compare the given sequences of resource ids and put their elements
+ in one of three vectors depending on whether an element belongs to
+ both sequences or to one but not the other. Note that only the
+ resource URLs of the XResourceId objects are used for the
+ classification.
+ @param rS1
+ One sequence of XResourceId objects.
+ @param rS2
+ Another sequence of XResourceId objects.
+ */
+ static void ClassifyResources(
+ const css::uno::Sequence<css::uno::Reference<css::drawing::framework::XResourceId>>& rS1,
+ const css::uno::Sequence<css::uno::Reference<css::drawing::framework::XResourceId>>& rS2,
+ ResourceIdVector& rS1minusS2, ResourceIdVector& rS2minusS1, ResourceIdVector& rS1andS2);
+
+ /** Copy the resources given in rSource to the list of resources
+ specified by rTarget. Resources bound to the ones in rSource,
+ either directly or indirectly, are copied as well.
+ @param rSource
+ All resources and the ones bound to them, either directly or
+ indirectly, are copied.
+ @param rxConfiguration
+ This configuration is used to determine the resources bound to
+ the ones in rSource.
+ @param rTarget
+ This list is filled with resources from rSource and the ones
+ bound to them.
+ */
+ static void CopyResources(
+ const ResourceIdVector& rSource,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration,
+ ResourceIdVector& rTarget);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationController.cxx b/sd/source/ui/framework/configuration/ConfigurationController.cxx
new file mode 100644
index 000000000..3fc95adb9
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationController.cxx
@@ -0,0 +1,541 @@
+/* -*- 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 "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 Reference<frame::XController>& rxController);
+
+ Reference<XControllerManager> 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() noexcept
+ : ConfigurationControllerInterfaceBase(m_aMutex)
+ , mbIsDisposed(false)
+{
+}
+
+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);
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL ConfigurationController::initialize (const Sequence<Any>& aArguments)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ if (aArguments.getLength() == 1)
+ {
+ const SolarMutexGuard aSolarGuard;
+
+ mpImplementation.reset(new Implementation(
+ *this,
+ Reference<frame::XController>(aArguments[0], UNO_QUERY_THROW)));
+ }
+}
+
+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 Reference<frame::XController>& 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
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_configuration_ConfigurationController_get_implementation(
+ css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::ConfigurationController());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx
new file mode 100644
index 000000000..5d9f22255
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx
@@ -0,0 +1,192 @@
+/* -*- 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 "ConfigurationControllerBroadcaster.hxx"
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/drawing/framework/XResource.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+ConfigurationControllerBroadcaster::ConfigurationControllerBroadcaster (
+ const Reference<XConfigurationController>& rxController)
+ : mxConfigurationController(rxController)
+{
+}
+
+void ConfigurationControllerBroadcaster::AddListener(
+ const Reference<XConfigurationChangeListener>& rxListener,
+ const OUString& rsEventType,
+ const Any& rUserData)
+{
+ if ( ! rxListener.is())
+ throw lang::IllegalArgumentException("invalid listener",
+ mxConfigurationController,
+ 0);
+
+ maListenerMap.try_emplace(rsEventType);
+
+ ListenerDescriptor aDescriptor;
+ aDescriptor.mxListener = rxListener;
+ aDescriptor.maUserData = rUserData;
+ maListenerMap[rsEventType].push_back(aDescriptor);
+}
+
+void ConfigurationControllerBroadcaster::RemoveListener(
+ const Reference<XConfigurationChangeListener>& rxListener)
+{
+ if ( ! rxListener.is())
+ throw lang::IllegalArgumentException("invalid listener",
+ mxConfigurationController,
+ 0);
+
+ ListenerList::iterator iList;
+ for (auto& rMap : maListenerMap)
+ {
+ iList = std::find_if(rMap.second.begin(), rMap.second.end(),
+ [&rxListener](const ListenerDescriptor& rList) { return rList.mxListener == rxListener; });
+ if (iList != rMap.second.end())
+ rMap.second.erase(iList);
+ }
+}
+
+void ConfigurationControllerBroadcaster::NotifyListeners (
+ const ListenerList& rList,
+ const ConfigurationChangeEvent& rEvent)
+{
+ // Create a local copy of the event in which the user data is modified
+ // for every listener.
+ ConfigurationChangeEvent aEvent (rEvent);
+
+ for (const auto& rListener : rList)
+ {
+ try
+ {
+ aEvent.UserData = rListener.maUserData;
+ rListener.mxListener->notifyConfigurationChange(aEvent);
+ }
+ catch (const lang::DisposedException& rException)
+ {
+ // When the exception comes from the listener itself then
+ // unregister it.
+ if (rException.Context == rListener.mxListener)
+ RemoveListener(rListener.mxListener);
+ }
+ catch (const RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ }
+}
+
+void ConfigurationControllerBroadcaster::NotifyListeners (const ConfigurationChangeEvent& rEvent)
+{
+ // Notify the specialized listeners.
+ ListenerMap::const_iterator iMap (maListenerMap.find(rEvent.Type));
+ if (iMap != maListenerMap.end())
+ {
+ // Create a local list of the listeners to avoid problems with
+ // concurrent changes and to be able to remove disposed listeners.
+ ListenerList aList (iMap->second.begin(), iMap->second.end());
+ NotifyListeners(aList,rEvent);
+ }
+
+ // Notify the universal listeners.
+ iMap = maListenerMap.find(OUString());
+ if (iMap != maListenerMap.end())
+ {
+ // Create a local list of the listeners to avoid problems with
+ // concurrent changes and to be able to remove disposed listeners.
+ ListenerList aList (iMap->second.begin(), iMap->second.end());
+ NotifyListeners(aList,rEvent);
+ }
+}
+
+void ConfigurationControllerBroadcaster::NotifyListeners (
+ const OUString& rsEventType,
+ const Reference<XResourceId>& rxResourceId,
+ const Reference<XResource>& rxResourceObject)
+{
+ ConfigurationChangeEvent aEvent;
+ aEvent.Type = rsEventType;
+ aEvent.ResourceId = rxResourceId;
+ aEvent.ResourceObject = rxResourceObject;
+ try
+ {
+ NotifyListeners(aEvent);
+ }
+ catch (const lang::DisposedException&)
+ {
+ }
+}
+
+void ConfigurationControllerBroadcaster::DisposeAndClear()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = mxConfigurationController;
+ while (!maListenerMap.empty())
+ {
+ ListenerMap::iterator iMap (maListenerMap.begin());
+ if (iMap == maListenerMap.end())
+ break;
+
+ // When the first vector is empty then remove it from the map.
+ if (iMap->second.empty())
+ {
+ maListenerMap.erase(iMap);
+ continue;
+ }
+ else
+ {
+ Reference<XConfigurationChangeListener> xListener (
+ iMap->second.front().mxListener );
+ if (xListener.is())
+ {
+ // Tell the listener that the configuration controller is
+ // being disposed and remove the listener (for all event
+ // types).
+ try
+ {
+ RemoveListener(xListener);
+ xListener->disposing(aEvent);
+ }
+ catch (const RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ }
+ else
+ {
+ // Remove just this reference to the listener.
+ iMap->second.erase(iMap->second.begin());
+ }
+ }
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx
new file mode 100644
index 000000000..5dfd6843d
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx
@@ -0,0 +1,138 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <unordered_map>
+#include <vector>
+
+namespace com::sun::star::drawing::framework { class XConfigurationChangeListener; }
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XResource; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+namespace com::sun::star::drawing::framework { struct ConfigurationChangeEvent; }
+
+namespace sd::framework {
+
+/** This class manages the set of XConfigurationChangeListeners and
+ calls them when the ConfigurationController wants to broadcast an
+ event.
+
+ For every registered combination of listener and event type a user data
+ object is stored. This user data object is then given to the listener
+ whenever it is called for an event. With this the listener can use
+ a switch statement to handle different event types.
+*/
+class ConfigurationControllerBroadcaster
+{
+public:
+ /** The given controller is used as origin of thrown exceptions.
+ */
+ explicit ConfigurationControllerBroadcaster (
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationController>& rxController);
+
+ /** Add a listener for one type of event. When one listener is
+ interested in more than one event type this method has to be called
+ once for every event type. Alternatively it can register as
+ universal listener that will be called for all event types.
+ @param rxListener
+ A valid reference to a listener.
+ @param rsEventType
+ The type of event that the listener will be called for. The
+ empty string is a special value in that the listener will be
+ called for all event types.
+ @param rUserData
+ This object is passed to the listener whenever it is called for
+ the specified event type. For different event types different
+ user data objects can be provided.
+ @throws IllegalArgumentException
+ when an empty listener reference is given.
+ */
+ void AddListener(
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationChangeListener>& rxListener,
+ const OUString& rsEventType,
+ const css::uno::Any& rUserData);
+
+ /** Remove all references to the given listener. When one listener has
+ been registered for more than one type of event then it is removed
+ for all of them.
+ @param rxListener
+ A valid reference to a listener.
+ @throws IllegalArgumentException
+ when an empty listener reference is given.
+ */
+ void RemoveListener(
+ const css::uno::Reference<
+ css::drawing::framework::XConfigurationChangeListener>& rxListener);
+
+ /** Broadcast the given event to all listeners that have been registered
+ for its type of event as well as all universal listeners.
+
+ When calling a listener results in a DisposedException being thrown
+ the listener is unregistered automatically.
+ */
+ void NotifyListeners (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent);
+
+ /** This convenience variant of NotifyListeners create the event from
+ the given arguments.
+ */
+ void NotifyListeners (
+ const OUString& rsEventType,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const css::uno::Reference<css::drawing::framework::XResource>& rxResourceObject);
+
+ /** Call all listeners and inform them that the
+ ConfigurationController is being disposed. When this method returns
+ the list of registered listeners is empty. Further calls to
+ RemoveListener() are not necessary but do not result in an error.
+ */
+ void DisposeAndClear();
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController> mxConfigurationController;
+ class ListenerDescriptor
+ {
+ public:
+ css::uno::Reference<css::drawing::framework::XConfigurationChangeListener> mxListener;
+ css::uno::Any maUserData;
+ };
+ typedef std::vector<ListenerDescriptor> ListenerList;
+ typedef std::unordered_map
+ <OUString,
+ ListenerList> ListenerMap;
+ ListenerMap maListenerMap;
+
+ /** Broadcast the given event to all listeners in the given list.
+
+ When calling a listener results in a DisposedException being thrown
+ the listener is unregistered automatically.
+ */
+ void NotifyListeners (
+ const ListenerList& rList,
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx
new file mode 100644
index 000000000..904011d7d
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx
@@ -0,0 +1,303 @@
+/* -*- 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 "ConfigurationControllerResourceManager.hxx"
+#include "ConfigurationControllerBroadcaster.hxx"
+#include "ResourceFactoryManager.hxx"
+#include <framework/FrameworkHelper.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <algorithm>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+//===== ConfigurationControllerResourceManager ================================
+
+ConfigurationControllerResourceManager::ConfigurationControllerResourceManager (
+ const std::shared_ptr<ResourceFactoryManager>& rpResourceFactoryContainer,
+ const std::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster)
+ : maResourceMap(ResourceComparator()),
+ mpResourceFactoryContainer(rpResourceFactoryContainer),
+ mpBroadcaster(rpBroadcaster)
+{
+}
+
+ConfigurationControllerResourceManager::~ConfigurationControllerResourceManager()
+{
+}
+
+ConfigurationControllerResourceManager::ResourceDescriptor
+ ConfigurationControllerResourceManager::GetResource (
+ const Reference<XResourceId>& rxResourceId)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ ResourceMap::const_iterator iResource (maResourceMap.find(rxResourceId));
+ if (iResource != maResourceMap.end())
+ return iResource->second;
+ else
+ return ResourceDescriptor();
+}
+
+void ConfigurationControllerResourceManager::ActivateResources (
+ const ::std::vector<Reference<XResourceId> >& rResources,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ // Iterate in normal order over the resources that are to be
+ // activated so that resources on which others depend are activated
+ // before the depending resources are activated.
+ for (const Reference<XResourceId>& xResource : rResources)
+ ActivateResource(xResource, rxConfiguration);
+}
+
+void ConfigurationControllerResourceManager::DeactivateResources (
+ const ::std::vector<Reference<XResourceId> >& rResources,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ ::osl::MutexGuard aGuard (maMutex);
+ // Iterate in reverse order over the resources that are to be
+ // deactivated so that resources on which others depend are deactivated
+ // only when the depending resources have already been deactivated.
+ ::std::for_each(
+ rResources.rbegin(),
+ rResources.rend(),
+ [&] (Reference<XResourceId> const& xResource) {
+ return DeactivateResource(xResource, rxConfiguration);
+ } );
+}
+
+/* In this method we do following steps.
+ 1. Get the factory with which the resource will be created.
+ 2. Create the resource.
+ 3. Add the resource to the URL->Object map of the configuration
+ controller.
+ 4. Add the resource id to the current configuration.
+ 5. Notify listeners.
+*/
+void ConfigurationControllerResourceManager::ActivateResource (
+ const Reference<XResourceId>& rxResourceId,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ if ( ! rxResourceId.is())
+ {
+ OSL_ASSERT(rxResourceId.is());
+ return;
+ }
+
+ SAL_INFO("sd.fwk", __func__ << ": activating resource " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+
+ // 1. Get the factory.
+ const OUString sResourceURL (rxResourceId->getResourceURL());
+ Reference<XResourceFactory> xFactory (mpResourceFactoryContainer->GetFactory(sResourceURL));
+ if ( ! xFactory.is())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": no factory found for " << sResourceURL);
+ return;
+ }
+
+ try
+ {
+ // 2. Create the resource.
+ Reference<XResource> xResource;
+ try
+ {
+ xResource = xFactory->createResource(rxResourceId);
+ }
+ catch (lang::DisposedException&)
+ {
+ // The factory is disposed and can be removed from the list
+ // of registered factories.
+ mpResourceFactoryContainer->RemoveFactoryForReference(xFactory);
+ }
+ catch (Exception&) {}
+
+ if (xResource.is())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": successfully created");
+ // 3. Add resource to URL->Object map.
+ AddResource(xResource, xFactory);
+
+ // 4. Add resource id to current configuration.
+ rxConfiguration->addResource(rxResourceId);
+
+ // 5. Notify the new resource to listeners of the ConfigurationController.
+ mpBroadcaster->NotifyListeners(
+ FrameworkHelper::msResourceActivationEvent,
+ rxResourceId,
+ xResource);
+ }
+ else
+ {
+ SAL_INFO("sd.fwk", __func__ << ": resource creation failed");
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+/* In this method we do following steps.
+ 1. Remove the resource from the URL->Object map of the configuration
+ controller.
+ 2. Notify listeners that deactivation has started.
+ 3. Remove the resource id from the current configuration.
+ 4. Release the resource.
+ 5. Notify listeners about that deactivation is completed.
+*/
+void ConfigurationControllerResourceManager::DeactivateResource (
+ const Reference<XResourceId>& rxResourceId,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ if ( ! rxResourceId.is())
+ return;
+
+#if OSL_DEBUG_LEVEL >= 1
+ bool bSuccess (false);
+#endif
+ try
+ {
+ // 1. Remove resource from URL->Object map.
+ ResourceDescriptor aDescriptor (RemoveResource(rxResourceId));
+
+ if (aDescriptor.mxResource.is() && aDescriptor.mxResourceFactory.is())
+ {
+ // 2. Notify listeners that the resource is being deactivated.
+ mpBroadcaster->NotifyListeners(
+ FrameworkHelper::msResourceDeactivationEvent,
+ rxResourceId,
+ aDescriptor.mxResource);
+
+ // 3. Remove resource id from current configuration.
+ rxConfiguration->removeResource(rxResourceId);
+
+ // 4. Release the resource.
+ try
+ {
+ aDescriptor.mxResourceFactory->releaseResource(aDescriptor.mxResource);
+ }
+ catch (const lang::DisposedException& rException)
+ {
+ if ( ! rException.Context.is()
+ || rException.Context == aDescriptor.mxResourceFactory)
+ {
+ // The factory is disposed and can be removed from the
+ // list of registered factories.
+ mpResourceFactoryContainer->RemoveFactoryForReference(
+ aDescriptor.mxResourceFactory);
+ }
+ }
+
+#if OSL_DEBUG_LEVEL >= 1
+ bSuccess = true;
+#endif
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+
+ // 5. Notify listeners that the resource is being deactivated.
+ mpBroadcaster->NotifyListeners(
+ FrameworkHelper::msResourceDeactivationEndEvent,
+ rxResourceId,
+ nullptr);
+
+#if OSL_DEBUG_LEVEL >= 1
+ if (bSuccess)
+ SAL_INFO("sd.fwk", __func__ << ": successfully deactivated " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId));
+ else
+ SAL_INFO("sd.fwk", __func__ << ": activating resource " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId)
+ << " failed");
+#endif
+}
+
+void ConfigurationControllerResourceManager::AddResource (
+ const Reference<XResource>& rxResource,
+ const Reference<XResourceFactory>& rxFactory)
+{
+ if ( ! rxResource.is())
+ {
+ OSL_ASSERT(rxResource.is());
+ return;
+ }
+
+ // Add the resource to the resource container.
+ ResourceDescriptor aDescriptor;
+ aDescriptor.mxResource = rxResource;
+ aDescriptor.mxResourceFactory = rxFactory;
+ maResourceMap[rxResource->getResourceId()] = aDescriptor;
+
+#if OSL_DEBUG_LEVEL >= 2
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationControllerResourceManager::AddResource(): added " <<
+ FrameworkHelper::ResourceIdToString(rxResource->getResourceId()) <<
+ " -> " << rxResource.get());
+#endif
+}
+
+ConfigurationControllerResourceManager::ResourceDescriptor
+ ConfigurationControllerResourceManager::RemoveResource (
+ const Reference<XResourceId>& rxResourceId)
+{
+ ResourceDescriptor aDescriptor;
+
+ ResourceMap::iterator iResource (maResourceMap.find(rxResourceId));
+ if (iResource != maResourceMap.end())
+ {
+#if OSL_DEBUG_LEVEL >= 2
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationControllerResourceManager::RemoveResource(): removing " <<
+ FrameworkHelper::ResourceIdToString(rxResourceId) <<
+ " -> " << &iResource);
+#endif
+
+ aDescriptor = iResource->second;
+ maResourceMap.erase(rxResourceId);
+ }
+
+ return aDescriptor;
+}
+
+//===== ConfigurationControllerResourceManager::ResourceComparator ============
+
+bool ConfigurationControllerResourceManager::ResourceComparator::operator() (
+ const Reference<XResourceId>& rxId1,
+ const Reference<XResourceId>& rxId2) const
+{
+ if (rxId1.is() && rxId2.is())
+ return rxId1->compareTo(rxId2)<0;
+ else if (rxId1.is())
+ return true;
+ else
+ return false;
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx
new file mode 100644
index 000000000..f3a3d6d76
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx
@@ -0,0 +1,141 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::drawing::framework { class XConfiguration; }
+namespace com::sun::star::drawing::framework { class XResourceFactory; }
+namespace com::sun::star::drawing::framework { class XResource; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+
+namespace sd::framework {
+
+class ConfigurationControllerBroadcaster;
+class ResourceFactoryManager;
+
+/** Manage the set of active resources. Activate and deactivate resources.
+*/
+class ConfigurationControllerResourceManager
+{
+public:
+ /** For every active resource both the resource itself as well as its
+ creating factory are remembered, so that on deactivation, the
+ resource can be deactivated by this factory.
+ */
+ class ResourceDescriptor
+ {
+ public:
+ css::uno::Reference<css::drawing::framework::XResource> mxResource;
+ css::uno::Reference<css::drawing::framework::XResourceFactory> mxResourceFactory;
+ };
+
+ /** A new ResourceManager object is created with the resource factory
+ container for creating resources and the event broadcaster for
+ notifying ConfigurationChangeListeners of activated or deactivated
+ resources.
+ */
+ ConfigurationControllerResourceManager (
+ const std::shared_ptr<ResourceFactoryManager>& rpResourceFactoryContainer,
+ const std::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster);
+
+ ~ConfigurationControllerResourceManager();
+
+ /// Forbid copy construction and copy assignment
+ ConfigurationControllerResourceManager(const ConfigurationControllerResourceManager&) = delete;
+ ConfigurationControllerResourceManager& operator=(const ConfigurationControllerResourceManager&) = delete;
+
+ /** Activate all the resources that are specified by resource ids in
+ rResources. The resource ids of activated resources are added to
+ the given configuration. Activated resources are notified to all
+ interested ConfigurationChangeListeners.
+ */
+ void ActivateResources (
+ const ::std::vector<
+ css::uno::Reference<css::drawing::framework::XResourceId> >& rResources,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ /** Deactivate all the resources that are specified by resource ids in
+ rResources. The resource ids of deactivated resources are removed
+ from the given configuration. Activated resources are notified to all
+ interested ConfigurationChangeListeners.
+ */
+ void DeactivateResources (
+ const ::std::vector<
+ css::uno::Reference<css::drawing::framework::XResourceId> >& rResources,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ /** Return the descriptor for the specified resource.
+ @return
+ When there is no active resource for the given resource id then
+ an empty descriptor is returned.
+ */
+ ResourceDescriptor GetResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId);
+
+private:
+ osl::Mutex maMutex;
+
+ class ResourceComparator
+ {
+ public:
+ bool operator() (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxId1,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxId2) const;
+ };
+
+ typedef ::std::map<
+ css::uno::Reference<css::drawing::framework::XResourceId>,
+ ResourceDescriptor,
+ ResourceComparator> ResourceMap;
+ ResourceMap maResourceMap;
+
+ std::shared_ptr<ResourceFactoryManager> mpResourceFactoryContainer;
+
+ /** This broadcaster is used to notify the activation and deactivation
+ of resources.
+ */
+ std::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster;
+
+ void ActivateResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ void DeactivateResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+
+ void AddResource (
+ const css::uno::Reference<css::drawing::framework::XResource>& rxResource,
+ const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory);
+
+ ResourceDescriptor RemoveResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationTracer.cxx b/sd/source/ui/framework/configuration/ConfigurationTracer.cxx
new file mode 100644
index 000000000..00ddd5ff1
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationTracer.cxx
@@ -0,0 +1,73 @@
+/* -*- 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 "ConfigurationTracer.hxx"
+
+#include <com/sun/star/drawing/framework/XConfiguration.hpp>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+void ConfigurationTracer::TraceConfiguration (
+ const Reference<XConfiguration>& rxConfiguration,
+ const char* pMessage)
+{
+#if OSL_DEBUG_LEVEL >=1
+ SAL_INFO("sd.ui","" << pMessage << " at " << rxConfiguration.get() << " {");
+ if (rxConfiguration.is())
+ {
+ TraceBoundResources(rxConfiguration, nullptr, 0);
+ }
+ else
+ {
+ SAL_INFO("sd.ui"," empty");
+ }
+ SAL_INFO("sd.ui","}");
+#else
+ (void)rxConfiguration;
+ (void)pMessage;
+#endif
+}
+
+#if OSL_DEBUG_LEVEL >=1
+void ConfigurationTracer::TraceBoundResources (
+ const Reference<XConfiguration>& rxConfiguration,
+ const Reference<XResourceId>& rxResourceId,
+ const int nIndentation)
+{
+ const Sequence<Reference<XResourceId> > aResourceList (
+ rxConfiguration->getResources(rxResourceId, OUString(), AnchorBindingMode_DIRECT));
+ static const OUStringLiteral sIndentation (u" ");
+ for (Reference<XResourceId> const & resourceId : aResourceList)
+ {
+ OUString sLine (resourceId->getResourceURL());
+ for (int i=0; i<nIndentation; ++i)
+ sLine = sIndentation + sLine;
+ SAL_INFO("sd.ui", "" << sLine);
+ TraceBoundResources(rxConfiguration, resourceId, nIndentation+1);
+ }
+}
+#endif
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationTracer.hxx b/sd/source/ui/framework/configuration/ConfigurationTracer.hxx
new file mode 100644
index 000000000..337fae569
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationTracer.hxx
@@ -0,0 +1,58 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XResourceId;
+}
+namespace com::sun::star::uno
+{
+template <typename> class Reference;
+}
+
+namespace sd::framework
+{
+/** Print debug information about configurations to the standard error
+ output channel.
+*/
+class ConfigurationTracer
+{
+public:
+ static void TraceConfiguration(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration,
+ const char* pMessage);
+#if OSL_DEBUG_LEVEL >= 1
+ static void TraceBoundResources(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const int nIndentation);
+#endif
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx b/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx
new file mode 100644
index 000000000..96ac74186
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationUpdater.cxx
@@ -0,0 +1,376 @@
+/* -*- 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 "ConfigurationUpdater.hxx"
+#include "ConfigurationTracer.hxx"
+#include "ConfigurationClassifier.hxx"
+#include "ConfigurationControllerBroadcaster.hxx"
+#include "ConfigurationControllerResourceManager.hxx"
+#include <framework/Configuration.hxx>
+#include <framework/FrameworkHelper.hxx>
+
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <comphelper/scopeguard.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::framework::FrameworkHelper;
+using ::std::vector;
+
+namespace {
+const sal_Int32 snShortTimeout (100);
+const sal_Int32 snNormalTimeout (1000);
+const sal_Int32 snLongTimeout (10000);
+const sal_Int32 snShortTimeoutCountThreshold (1);
+const sal_Int32 snNormalTimeoutCountThreshold (5);
+}
+
+namespace sd::framework {
+
+//===== ConfigurationUpdaterLock ==============================================
+
+class ConfigurationUpdaterLock
+{
+public:
+ explicit ConfigurationUpdaterLock (ConfigurationUpdater& rUpdater)
+ : mrUpdater(rUpdater) { mrUpdater.LockUpdates(); }
+ ~ConfigurationUpdaterLock() { mrUpdater.UnlockUpdates(); }
+private:
+ ConfigurationUpdater& mrUpdater;
+};
+
+//===== ConfigurationUpdater ==================================================
+
+ConfigurationUpdater::ConfigurationUpdater (
+ const std::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster,
+ const std::shared_ptr<ConfigurationControllerResourceManager>& rpResourceManager,
+ const Reference<XControllerManager>& rxControllerManager)
+ : mpBroadcaster(rpBroadcaster),
+ mxCurrentConfiguration(Reference<XConfiguration>(new Configuration(nullptr, false))),
+ mbUpdatePending(false),
+ mbUpdateBeingProcessed(false),
+ mnLockCount(0),
+ maUpdateTimer("sd::ConfigurationUpdater maUpdateTimer"),
+ mnFailedUpdateCount(0),
+ mpResourceManager(rpResourceManager)
+{
+ // Prepare the timer that is started when after an update the current
+ // and the requested configuration differ. With the timer we try
+ // updates until the two configurations are the same.
+ maUpdateTimer.SetTimeout(snNormalTimeout);
+ maUpdateTimer.SetInvokeHandler(LINK(this,ConfigurationUpdater,TimeoutHandler));
+ mxControllerManager = rxControllerManager;
+}
+
+ConfigurationUpdater::~ConfigurationUpdater()
+{
+ maUpdateTimer.Stop();
+}
+
+void ConfigurationUpdater::RequestUpdate (
+ const Reference<XConfiguration>& rxRequestedConfiguration)
+{
+ mxRequestedConfiguration = rxRequestedConfiguration;
+
+ // Find out whether we really can update the configuration.
+ if (IsUpdatePossible())
+ {
+ SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration start");
+
+ // Call UpdateConfiguration while that is possible and while someone
+ // set mbUpdatePending to true in the middle of it.
+ do
+ {
+ UpdateConfiguration();
+ }
+ while (mbUpdatePending && IsUpdatePossible());
+ }
+ else
+ {
+ mbUpdatePending = true;
+ SAL_INFO("sd.fwk", __func__ << ": scheduling update for later");
+ }
+}
+
+bool ConfigurationUpdater::IsUpdatePossible() const
+{
+ return ! mbUpdateBeingProcessed
+ && mxControllerManager.is()
+ && mnLockCount==0
+ && mxRequestedConfiguration.is()
+ && mxCurrentConfiguration.is();
+}
+
+void ConfigurationUpdater::UpdateConfiguration()
+{
+ SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration update");
+ SetUpdateBeingProcessed(true);
+ comphelper::ScopeGuard aScopeGuard (
+ [this] () { return this->SetUpdateBeingProcessed(false); });
+
+ try
+ {
+ mbUpdatePending = false;
+
+ CleanRequestedConfiguration();
+ ConfigurationClassifier aClassifier(mxRequestedConfiguration, mxCurrentConfiguration);
+ if (aClassifier.Partition())
+ {
+#if DEBUG_SD_CONFIGURATION_TRACE
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationUpdater::UpdateConfiguration(");
+ ConfigurationTracer::TraceConfiguration(
+ mxRequestedConfiguration, "requested configuration");
+ ConfigurationTracer::TraceConfiguration(
+ mxCurrentConfiguration, "current configuration");
+#endif
+ // Notify the beginning of the update.
+ ConfigurationChangeEvent aEvent;
+ aEvent.Type = FrameworkHelper::msConfigurationUpdateStartEvent;
+ aEvent.Configuration = mxRequestedConfiguration;
+ mpBroadcaster->NotifyListeners(aEvent);
+
+ // Do the actual update. All exceptions are caught and ignored,
+ // so that the end of the update is notified always.
+ try
+ {
+ if (mnLockCount == 0)
+ UpdateCore(aClassifier);
+ }
+ catch(const RuntimeException&)
+ {
+ }
+
+ // Notify the end of the update.
+ aEvent.Type = FrameworkHelper::msConfigurationUpdateEndEvent;
+ mpBroadcaster->NotifyListeners(aEvent);
+
+ CheckUpdateSuccess();
+ }
+ else
+ {
+ SAL_INFO("sd.fwk", __func__ << ": nothing to do");
+#if DEBUG_SD_CONFIGURATION_TRACE
+ ConfigurationTracer::TraceConfiguration(
+ mxRequestedConfiguration, "requested configuration");
+ ConfigurationTracer::TraceConfiguration(
+ mxCurrentConfiguration, "current configuration");
+#endif
+ }
+ }
+ catch(const RuntimeException &)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationUpdater::UpdateConfiguration)");
+ SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration end");
+}
+
+void ConfigurationUpdater::CleanRequestedConfiguration()
+{
+ if (!mxControllerManager.is())
+ return;
+
+ // Request the deactivation of pure anchors that have no child.
+ vector<Reference<XResourceId> > aResourcesToDeactivate;
+ CheckPureAnchors(mxRequestedConfiguration, aResourcesToDeactivate);
+ if (!aResourcesToDeactivate.empty())
+ {
+ Reference<XConfigurationController> xCC (
+ mxControllerManager->getConfigurationController());
+ for (const auto& rxId : aResourcesToDeactivate)
+ if (rxId.is())
+ xCC->requestResourceDeactivation(rxId);
+ }
+}
+
+void ConfigurationUpdater::CheckUpdateSuccess()
+{
+ // When the two configurations differ then start the timer to call
+ // another update later.
+ if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
+ {
+ if (mnFailedUpdateCount <= snShortTimeoutCountThreshold)
+ maUpdateTimer.SetTimeout(snShortTimeout);
+ else if (mnFailedUpdateCount < snNormalTimeoutCountThreshold)
+ maUpdateTimer.SetTimeout(snNormalTimeout);
+ else
+ maUpdateTimer.SetTimeout(snLongTimeout);
+ ++mnFailedUpdateCount;
+ maUpdateTimer.Start();
+ }
+ else
+ {
+ // Update was successful. Reset the failed update count.
+ mnFailedUpdateCount = 0;
+ }
+}
+
+void ConfigurationUpdater::UpdateCore (const ConfigurationClassifier& rClassifier)
+{
+ try
+ {
+#if DEBUG_SD_CONFIGURATION_TRACE
+ rClassifier.TraceResourceIdVector(
+ "requested but not current resources:", rClassifier.GetC1minusC2());
+ rClassifier.TraceResourceIdVector(
+ "current but not requested resources:", rClassifier.GetC2minusC1());
+ rClassifier.TraceResourceIdVector(
+ "requested and current resources:", rClassifier.GetC1andC2());
+#endif
+
+ // Updating of the sub controllers is done in two steps. In the
+ // first the sub controllers typically shut down resources that are
+ // not requested anymore. In the second the sub controllers
+ // typically set up resources that have been newly requested.
+ mpResourceManager->DeactivateResources(rClassifier.GetC2minusC1(), mxCurrentConfiguration);
+ mpResourceManager->ActivateResources(rClassifier.GetC1minusC2(), mxCurrentConfiguration);
+
+#if DEBUG_SD_CONFIGURATION_TRACE
+ SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::UpdateConfiguration)");
+ ConfigurationTracer::TraceConfiguration(
+ mxRequestedConfiguration, "requested configuration");
+ ConfigurationTracer::TraceConfiguration(
+ mxCurrentConfiguration, "current configuration");
+#endif
+
+ // Deactivate pure anchors that have no child.
+ vector<Reference<XResourceId> > aResourcesToDeactivate;
+ CheckPureAnchors(mxCurrentConfiguration, aResourcesToDeactivate);
+ if (!aResourcesToDeactivate.empty())
+ mpResourceManager->DeactivateResources(aResourcesToDeactivate, mxCurrentConfiguration);
+ }
+ catch(const RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+void ConfigurationUpdater::CheckPureAnchors (
+ const Reference<XConfiguration>& rxConfiguration,
+ vector<Reference<XResourceId> >& rResourcesToDeactivate)
+{
+ if ( ! rxConfiguration.is())
+ return;
+
+ // Get a list of all resources in the configuration.
+ Sequence<Reference<XResourceId> > aResources(
+ rxConfiguration->getResources(
+ nullptr, OUString(), AnchorBindingMode_INDIRECT));
+ auto aResourcesRange = asNonConstRange(aResources);
+ sal_Int32 nCount (aResources.getLength());
+
+ // Prepare the list of pure anchors that have to be deactivated.
+ rResourcesToDeactivate.clear();
+
+ // Iterate over the list in reverse order because when there is a chain
+ // of pure anchors with only the last one having no child then the whole
+ // list has to be deactivated.
+ sal_Int32 nIndex (nCount-1);
+ while (nIndex >= 0)
+ {
+ const Reference<XResourceId> xResourceId (aResources[nIndex]);
+ const Reference<XResource> xResource (
+ mpResourceManager->GetResource(xResourceId).mxResource);
+ bool bDeactiveCurrentResource (false);
+
+ // Skip all resources that are no pure anchors.
+ if (xResource.is() && xResource->isAnchorOnly())
+ {
+ // When xResource is not an anchor of the next resource in
+ // the list then it is the anchor of no resource at all.
+ if (nIndex == nCount-1)
+ {
+ // No following anchors, deactivate this one, then remove it
+ // from the list.
+ bDeactiveCurrentResource = true;
+ }
+ else
+ {
+ const Reference<XResourceId> xPrevResourceId (aResources[nIndex+1]);
+ if ( ! xPrevResourceId.is()
+ || ! xPrevResourceId->isBoundTo(xResourceId, AnchorBindingMode_DIRECT))
+ {
+ // The previous resource (id) does not exist or is not bound to
+ // the current anchor.
+ bDeactiveCurrentResource = true;
+ }
+ }
+ }
+
+ if (bDeactiveCurrentResource)
+ {
+ SAL_INFO("sd.fwk", __func__ << ": deactivating pure anchor " <<
+ FrameworkHelper::ResourceIdToString(xResourceId) <<
+ "because it has no children");
+ // Erase element from current configuration.
+ for (sal_Int32 nI=nIndex; nI<nCount-2; ++nI)
+ aResourcesRange[nI] = aResources[nI+1];
+ nCount -= 1;
+
+ rResourcesToDeactivate.push_back(xResourceId);
+ }
+ nIndex -= 1;
+ }
+}
+
+void ConfigurationUpdater::LockUpdates()
+{
+ ++mnLockCount;
+}
+
+void ConfigurationUpdater::UnlockUpdates()
+{
+ --mnLockCount;
+ if (mnLockCount == 0 && mbUpdatePending)
+ {
+ RequestUpdate(mxRequestedConfiguration);
+ }
+}
+
+std::shared_ptr<ConfigurationUpdaterLock> ConfigurationUpdater::GetLock()
+{
+ return std::make_shared<ConfigurationUpdaterLock>(*this);
+}
+
+void ConfigurationUpdater::SetUpdateBeingProcessed (bool bValue)
+{
+ mbUpdateBeingProcessed = bValue;
+}
+
+IMPL_LINK_NOARG(ConfigurationUpdater, TimeoutHandler, Timer *, void)
+{
+ if ( ! mbUpdateBeingProcessed
+ && mxCurrentConfiguration.is()
+ && mxRequestedConfiguration.is())
+ {
+ if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
+ {
+ RequestUpdate(mxRequestedConfiguration);
+ }
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx b/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx
new file mode 100644
index 000000000..9fba364b1
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ConfigurationUpdater.hxx
@@ -0,0 +1,209 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <vcl/timer.hxx>
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfiguration;
+}
+namespace com::sun::star::drawing::framework
+{
+class XControllerManager;
+}
+namespace com::sun::star::drawing::framework
+{
+class XResourceId;
+}
+
+namespace sd::framework
+{
+class ConfigurationClassifier;
+class ConfigurationUpdaterLock;
+class ConfigurationControllerResourceManager;
+class ConfigurationControllerBroadcaster;
+
+/** This is a helper class for the ConfigurationController. It handles the
+ update of the current configuration so that it looks like a requested
+ configuration. An update is made by activating or deactivating drawing
+ framework resources.
+
+ When an update is not successful, i.e. after the update the current
+ configuration is not equivalent to the requested configuration, then a
+ timer is started to repeat the update after a short time.
+*/
+class ConfigurationUpdater
+{
+public:
+ /** Create a new ConfigurationUpdater object that notifies configuration
+ changes and the start and end of updates via the given broadcaster.
+ */
+ ConfigurationUpdater(
+ const std::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster,
+ const std::shared_ptr<ConfigurationControllerResourceManager>& rpResourceManager,
+ const css::uno::Reference<css::drawing::framework::XControllerManager>&
+ rxControllerManager);
+ ~ConfigurationUpdater();
+
+ /** Request an update of the current configuration so that it looks like
+ the given requested configuration. It checks whether an update of
+ the current configuration can be done. Calls UpdateConfiguration()
+ if that is the case. Otherwise it schedules a later call to
+ UpdateConfiguration().
+ */
+ void RequestUpdate(const css::uno::Reference<css::drawing::framework::XConfiguration>&
+ rxRequestedConfiguration);
+
+ const css::uno::Reference<css::drawing::framework::XConfiguration>&
+ GetCurrentConfiguration() const
+ {
+ return mxCurrentConfiguration;
+ }
+
+ friend class ConfigurationUpdaterLock;
+ /** Return a lock of the called ConfigurationUpdater. While the
+ returned object exists no update of the current configuration is
+ made.
+ */
+ std::shared_ptr<ConfigurationUpdaterLock> GetLock();
+
+private:
+ /** A reference to the XControllerManager is kept so that
+ UpdateConfiguration() has access to the other sub controllers.
+ */
+ css::uno::Reference<css::drawing::framework::XControllerManager> mxControllerManager;
+
+ std::shared_ptr<ConfigurationControllerBroadcaster> mpBroadcaster;
+
+ /** The current configuration holds the resources that are currently
+ active. It is modified during an update.
+ */
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxCurrentConfiguration;
+
+ /** The requested configuration holds the resources that have been
+ requested to activate or to deactivate since the last update. It is
+ (usually) not modified during an update. This configuration is
+ maintained by the ConfigurationController and given to the
+ ConfigurationUpdater in the RequestUpdate() method.
+ */
+ css::uno::Reference<css::drawing::framework::XConfiguration> mxRequestedConfiguration;
+
+ /** This flag is set to </sal_True> when an update of the current
+ configuration was requested (because the last request in the queue
+ was processed) but could not be executed because the
+ ConfigurationController was locked. A call to UpdateConfiguration()
+ resets the flag to </sal_False>.
+ */
+ bool mbUpdatePending;
+
+ /** This flag is set to </sal_True> while the UpdateConfiguration() method
+ is running. It is used to prevent reentrance problems with this
+ method.
+ */
+ bool mbUpdateBeingProcessed;
+
+ /** The ConfigurationController is locked when this count has a value
+ larger then zero. If the controller is locked then updates of the
+ current configuration are not made.
+ */
+ sal_Int32 mnLockCount;
+
+ /** This timer is used to check from time to time whether the requested
+ configuration and the current configuration are identical and request
+ an update when they are not.
+ This is used to overcome problems with resources that become
+ available asynchronously.
+ */
+ Timer maUpdateTimer;
+
+ /** The number of failed updates (those after which the current
+ configuration is not equivalent to the requested configuration) is
+ used to determine how long to wait before another update is made.
+ */
+ sal_Int32 mnFailedUpdateCount;
+
+ std::shared_ptr<ConfigurationControllerResourceManager> mpResourceManager;
+
+ /** This method does the main work of an update. It calls the sub
+ controllers that are responsible for the various types of resources
+ and tells them to update their active resources. It notifies
+ listeners about the start and end of the configuration update.
+ */
+ void UpdateConfiguration();
+
+ /** Basically calls UpdaterStart() andUpdateEnd() and makes some debug
+ output.
+ */
+ void UpdateCore(const ConfigurationClassifier& rClassifier);
+
+ /** Check for all pure anchors if they have at least one child.
+ Childless pure anchors are deactivated.
+ This affects only the current configuration.
+ */
+ void CheckPureAnchors(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration,
+ ::std::vector<css::uno::Reference<css::drawing::framework::XResourceId>>&
+ rResourcesToDeactivate);
+
+ /** Remove from the requested configuration all pure anchors that have no
+ child. Requested but not yet activated anchors can not be removed
+ because without the actual resource the 'pureness' of an anchor can
+ not be determined.
+ */
+ void CleanRequestedConfiguration();
+
+ /** Check the success of a recently executed configuration update.
+ When the update failed then start the timer.
+ */
+ void CheckUpdateSuccess();
+
+ /** This method sets the mbUpdateBeingProcessed member that is used to
+ prevent reentrance problems. This method allows function objects
+ easily and safely to modify the variable.
+ */
+ void SetUpdateBeingProcessed(bool bValue);
+
+ /** Return whether it is possible to do an update of the configuration.
+ This takes into account whether another update is currently being
+ executed, the lock count, and whether the configuration controller
+ is still valid.
+ */
+ bool IsUpdatePossible() const;
+
+ /** Lock updates of the current configuration. For intermediate requests
+ for updates mbUpdatePending is set to <TRUE/>.
+ */
+ void LockUpdates();
+
+ /** When an update was requested since the last LockUpdates() call then
+ RequestUpdate() is called.
+ */
+ void UnlockUpdates();
+
+ DECL_LINK(TimeoutHandler, Timer*, void);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx
new file mode 100644
index 000000000..fa6d41503
--- /dev/null
+++ b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx
@@ -0,0 +1,81 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include "GenericConfigurationChangeRequest.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+GenericConfigurationChangeRequest::GenericConfigurationChangeRequest (
+ const Reference<XResourceId>& rxResourceId,
+ const Mode eMode)
+ : mxResourceId(rxResourceId),
+ meMode(eMode)
+{
+ if ( ! rxResourceId.is() || rxResourceId->getResourceURL().isEmpty())
+ throw css::lang::IllegalArgumentException();
+}
+
+GenericConfigurationChangeRequest::~GenericConfigurationChangeRequest() noexcept
+{
+}
+
+void SAL_CALL GenericConfigurationChangeRequest::execute (
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ if (!rxConfiguration.is())
+ return;
+
+ switch (meMode)
+ {
+ case Activation:
+ rxConfiguration->addResource(mxResourceId);
+ break;
+
+ case Deactivation:
+ rxConfiguration->removeResource(mxResourceId);
+ break;
+ }
+}
+
+OUString SAL_CALL GenericConfigurationChangeRequest::getName()
+{
+ return OUString::Concat("GenericConfigurationChangeRequest ")
+ + (meMode==Activation
+ ? std::u16string_view(u"activate ") : std::u16string_view(u"deactivate "))
+ + FrameworkHelper::ResourceIdToString(mxResourceId);
+}
+
+void SAL_CALL GenericConfigurationChangeRequest::setName (const OUString&)
+{
+ // Ignored.
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx
new file mode 100644
index 000000000..3caa7a8ca
--- /dev/null
+++ b/sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx
@@ -0,0 +1,98 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing::framework { class XConfiguration; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeRequest,
+ css::container::XNamed
+ > GenericConfigurationChangeRequestInterfaceBase;
+
+/** This implementation of the XConfigurationChangeRequest interface
+ represents a single explicit request for a configuration change. On its
+ execution it may result in other, implicit, configuration changes. For
+ example this is the case when the deactivation of a unique resource is
+ requested: the resources linked to it have to be deactivated as well.
+*/
+class GenericConfigurationChangeRequest final
+ : public GenericConfigurationChangeRequestInterfaceBase
+{
+public:
+ /** This enum specified whether the activation or deactivation of a
+ resource is requested.
+ */
+ enum Mode { Activation, Deactivation };
+
+ /** Create a new object that represents the request for activation or
+ deactivation of the specified resource.
+ @param rxsResourceId
+ Id of the resource that is to be activated or deactivated.
+ @param eMode
+ The mode specifies whether to activate or to deactivate the
+ resource.
+ @throws css::css::lang::IllegalArgumentException
+ */
+ GenericConfigurationChangeRequest (
+ const css::uno::Reference<css::drawing::framework::XResourceId>&
+ rxResourceId,
+ const Mode eMode);
+
+ virtual ~GenericConfigurationChangeRequest() noexcept override;
+
+ // XConfigurationChangeOperation
+
+ /** The requested configuration change is executed on the given
+ configuration. Additionally to the explicitly requested change
+ other changes have to be made as well. See class description for an
+ example.
+ @param rxConfiguration
+ The configuration to which the requested change is made.
+ */
+ virtual void SAL_CALL execute (
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration) override;
+
+ // XNamed
+
+ /** Return a human readable string representation. This is used for
+ debugging purposes.
+ */
+ virtual OUString SAL_CALL getName() override;
+
+ /** This call is ignored because the XNamed interface is (mis)used to
+ give access to a human readable name for debugging purposes.
+ */
+ virtual void SAL_CALL setName (const OUString& rName) override;
+
+private:
+ const css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId;
+ const Mode meMode;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx b/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx
new file mode 100644
index 000000000..4817c1360
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ResourceFactoryManager.cxx
@@ -0,0 +1,197 @@
+/* -*- 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 "ResourceFactoryManager.hxx"
+#include <tools/wldcrd.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <comphelper/processfactory.hxx>
+#include <sal/log.hxx>
+
+#include <algorithm>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+#undef VERBOSE
+//#define VERBOSE 1
+
+namespace sd::framework {
+
+ResourceFactoryManager::ResourceFactoryManager (const Reference<XControllerManager>& rxManager)
+ : mxControllerManager(rxManager)
+{
+ // Create the URL transformer.
+ Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ mxURLTransformer = util::URLTransformer::create(xContext);
+}
+
+ResourceFactoryManager::~ResourceFactoryManager()
+{
+ for (auto& rXInterfaceResource : maFactoryMap)
+ {
+ Reference<lang::XComponent> xComponent (rXInterfaceResource.second, UNO_QUERY);
+ rXInterfaceResource.second = nullptr;
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+
+ Reference<lang::XComponent> xComponent (mxURLTransformer, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+void ResourceFactoryManager::AddFactory (
+ const OUString& rsURL,
+ const Reference<XResourceFactory>& rxFactory)
+{
+ if ( ! rxFactory.is())
+ throw lang::IllegalArgumentException();
+ if (rsURL.isEmpty())
+ throw lang::IllegalArgumentException();
+
+ std::scoped_lock aGuard (maMutex);
+
+ if (rsURL.indexOf('*') >= 0 || rsURL.indexOf('?') >= 0)
+ {
+ // The URL is a URL pattern not a single URL.
+ maFactoryPatternList.emplace_back(rsURL, rxFactory);
+
+#if defined VERBOSE && VERBOSE>=1
+ SAL_INFO("sd","ResourceFactoryManager::AddFactory pattern " << rsURL << std::hex << rxFactory.get());
+#endif
+ }
+ else
+ {
+ maFactoryMap[rsURL] = rxFactory;
+
+#if defined VERBOSE && VERBOSE>=1
+ SAL_INFO("sd", "ResourceFactoryManager::AddFactory fixed " << rsURL << " 0x" << std::hex << rxFactory.get());
+#endif
+ }
+}
+
+void ResourceFactoryManager::RemoveFactoryForURL (
+ const OUString& rsURL)
+{
+ if (rsURL.isEmpty())
+ throw lang::IllegalArgumentException();
+
+ std::scoped_lock aGuard (maMutex);
+
+ FactoryMap::iterator iFactory (maFactoryMap.find(rsURL));
+ if (iFactory != maFactoryMap.end())
+ {
+ maFactoryMap.erase(iFactory);
+ }
+ else
+ {
+ // The URL may be a pattern. Look that up.
+ auto iPattern = std::find_if(maFactoryPatternList.begin(), maFactoryPatternList.end(),
+ [&rsURL](const FactoryPatternList::value_type& rPattern) { return rPattern.first == rsURL; });
+ if (iPattern != maFactoryPatternList.end())
+ {
+ // Found the pattern. Remove it.
+ maFactoryPatternList.erase(iPattern);
+ }
+ }
+}
+
+void ResourceFactoryManager::RemoveFactoryForReference(
+ const Reference<XResourceFactory>& rxFactory)
+{
+ std::scoped_lock aGuard (maMutex);
+
+ // Collect a list with all keys that map to the given factory.
+ ::std::vector<OUString> aKeys;
+ for (const auto& rFactory : maFactoryMap)
+ if (rFactory.second == rxFactory)
+ aKeys.push_back(rFactory.first);
+
+ // Remove the entries whose keys we just have collected.
+ for (const auto& rKey : aKeys)
+ maFactoryMap.erase(rKey);
+
+ // Remove the pattern entries whose factories are identical to the given
+ // factory.
+ maFactoryPatternList.erase(
+ std::remove_if(
+ maFactoryPatternList.begin(),
+ maFactoryPatternList.end(),
+ [&] (FactoryPatternList::value_type const& it) { return it.second == rxFactory; }),
+ maFactoryPatternList.end());
+}
+
+Reference<XResourceFactory> ResourceFactoryManager::GetFactory (
+ const OUString& rsCompleteURL)
+{
+ OUString sURLBase (rsCompleteURL);
+ if (mxURLTransformer.is())
+ {
+ util::URL aURL;
+ aURL.Complete = rsCompleteURL;
+ if (mxURLTransformer->parseStrict(aURL))
+ sURLBase = aURL.Main;
+ }
+
+ Reference<XResourceFactory> xFactory = FindFactory(sURLBase);
+
+ if ( ! xFactory.is() && mxControllerManager.is())
+ {
+ Reference<XModuleController> xModuleController(mxControllerManager->getModuleController());
+ if (xModuleController.is())
+ {
+ // Ask the module controller to provide a factory of the
+ // requested view type. Note that this can (and should) cause
+ // intermediate calls to AddFactory().
+ xModuleController->requestResource(sURLBase);
+
+ xFactory = FindFactory(sURLBase);
+ }
+ }
+
+ return xFactory;
+}
+
+Reference<XResourceFactory> ResourceFactoryManager::FindFactory (const OUString& rsURLBase)
+{
+ std::scoped_lock aGuard (maMutex);
+ FactoryMap::const_iterator iFactory (maFactoryMap.find(rsURLBase));
+ if (iFactory != maFactoryMap.end())
+ return iFactory->second;
+ else
+ {
+ // Check the URL patterns.
+ auto iPattern = std::find_if(maFactoryPatternList.begin(), maFactoryPatternList.end(),
+ [&rsURLBase](const FactoryPatternList::value_type& rPattern) {
+ WildCard aWildCard (rPattern.first);
+ return aWildCard.Matches(rsURLBase);
+ });
+ if (iPattern != maFactoryPatternList.end())
+ return iPattern->second;
+ }
+ return nullptr;
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx b/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx
new file mode 100644
index 000000000..61daf383b
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ResourceFactoryManager.hxx
@@ -0,0 +1,120 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <mutex>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <rtl/ustring.hxx>
+
+namespace com::sun::star::drawing::framework { class XControllerManager; }
+namespace com::sun::star::drawing::framework { class XResourceFactory; }
+namespace com::sun::star::util { class XURLTransformer; }
+
+namespace sd::framework {
+
+/** Container of resource factories of the drawing framework.
+*/
+class ResourceFactoryManager
+{
+public:
+ explicit ResourceFactoryManager (
+ const css::uno::Reference<css::drawing::framework::XControllerManager>& rxManager);
+
+ ~ResourceFactoryManager();
+
+ /** Register a resource factory for one type of resource.
+ @param rsURL
+ The type of the resource that will be created by the factory.
+ @param rxFactory
+ The factory that will create resource objects of the specified type.
+ @throws css::uno::RuntimeException
+ */
+ void AddFactory (
+ const OUString& rsURL,
+ const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory);
+
+ /** Unregister the specified factory.
+ @param rsURL
+ Unregister only the factory for this URL. When the same factory
+ is registered for other URLs then these remain registered.
+ @throws css::uno::RuntimeException
+ */
+ void RemoveFactoryForURL(
+ const OUString& rsURL);
+
+ /** Unregister the specified factory.
+ @param rxFactory
+ Unregister the this factory for all URLs that it has been
+ registered for.
+ @throws css::uno::RuntimeException
+ */
+ void RemoveFactoryForReference(
+ const css::uno::Reference<css::drawing::framework::XResourceFactory>& rxFactory);
+
+ /** Return a factory that can create resources specified by the given URL.
+ @param rsCompleteURL
+ This URL specifies the type of the resource. It may contain arguments.
+ @return
+ When a factory for the specified URL has been registered by a
+ previous call to AddFactory() then a reference to that factory
+ is returned. Otherwise an empty reference is returned.
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Reference<css::drawing::framework::XResourceFactory> GetFactory (
+ const OUString& rsURL);
+
+private:
+ std::mutex maMutex;
+ typedef std::unordered_map<
+ OUString,
+ css::uno::Reference<css::drawing::framework::XResourceFactory> > FactoryMap;
+ FactoryMap maFactoryMap;
+
+ typedef ::std::vector<
+ ::std::pair<
+ OUString,
+ css::uno::Reference<css::drawing::framework::XResourceFactory> > >
+ FactoryPatternList;
+ FactoryPatternList maFactoryPatternList;
+
+ css::uno::Reference<css::drawing::framework::XControllerManager> mxControllerManager;
+ css::uno::Reference<css::util::XURLTransformer> mxURLTransformer;
+
+ /** Look up the factory for the given URL.
+ @param rsURLBase
+ The css::tools::URL.Main part of a URL. Arguments have to be
+ stripped off by the caller.
+ @return
+ When the factory has not yet been added then return NULL.
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Reference<css::drawing::framework::XResourceFactory> FindFactory (
+ const OUString& rsURLBase);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/ResourceId.cxx b/sd/source/ui/framework/configuration/ResourceId.cxx
new file mode 100644
index 000000000..1845b353f
--- /dev/null
+++ b/sd/source/ui/framework/configuration/ResourceId.cxx
@@ -0,0 +1,503 @@
+/* -*- 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/ResourceId.hxx>
+#include <tools/SdGlobalResourceContainer.hxx>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <rtl/ref.hxx>
+
+#include <algorithm>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+/** When the USE_OPTIMIZATIONS symbol is defined then at some optimizations
+ are activated that work only together with XResourceId objects that are
+ implemented by the ResourceId class. For other implementations of when
+ the USE_OPTIMIZATIONS symbol is not defined then alternative code is
+ used instead.
+*/
+#define USE_OPTIMIZATIONS
+
+namespace sd::framework {
+
+//===== ResourceId ============================================================
+
+WeakReference<util::XURLTransformer> ResourceId::mxURLTransformerWeak;
+
+ResourceId::ResourceId()
+ : maResourceURLs(0)
+{
+}
+
+ResourceId::ResourceId (
+ std::vector<OUString>&& rResourceURLs)
+ : maResourceURLs(std::move(rResourceURLs))
+{
+ ParseResourceURL();
+}
+
+ResourceId::ResourceId (
+ const OUString& rsResourceURL)
+ : maResourceURLs(1, rsResourceURL)
+{
+ // Handle the special case of an empty resource URL.
+ if (rsResourceURL.isEmpty())
+ maResourceURLs.clear();
+ ParseResourceURL();
+}
+
+ResourceId::ResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL)
+ : maResourceURLs(2)
+{
+ maResourceURLs[0] = rsResourceURL;
+ maResourceURLs[1] = rsAnchorURL;
+ ParseResourceURL();
+}
+
+ResourceId::ResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsFirstAnchorURL,
+ const Sequence<OUString>& rAnchorURLs)
+ : maResourceURLs(2+rAnchorURLs.getLength())
+{
+ maResourceURLs[0] = rsResourceURL;
+ maResourceURLs[1] = rsFirstAnchorURL;
+ std::copy(rAnchorURLs.begin(), rAnchorURLs.end(), std::next(maResourceURLs.begin(), 2));
+ ParseResourceURL();
+}
+
+ResourceId::~ResourceId()
+{
+ mpURL.reset();
+}
+
+OUString SAL_CALL
+ ResourceId::getResourceURL()
+{
+ if (!maResourceURLs.empty())
+ return maResourceURLs[0];
+ else
+ return OUString();
+}
+
+util::URL SAL_CALL
+ ResourceId::getFullResourceURL()
+{
+ if (mpURL != nullptr)
+ return *mpURL;
+
+ Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
+ if (xURLTransformer.is() && !maResourceURLs.empty() )
+ {
+ mpURL.reset(new util::URL);
+ mpURL->Complete = maResourceURLs[0];
+ xURLTransformer->parseStrict(*mpURL);
+ return *mpURL;
+ }
+
+ util::URL aURL;
+ if (!maResourceURLs.empty())
+ aURL.Complete = maResourceURLs[0];
+ return aURL;
+}
+
+sal_Bool SAL_CALL
+ ResourceId::hasAnchor()
+{
+ return maResourceURLs.size()>1;
+}
+
+Reference<XResourceId> SAL_CALL
+ ResourceId::getAnchor()
+{
+ ::rtl::Reference<ResourceId> rResourceId (new ResourceId());
+ const sal_Int32 nAnchorCount (maResourceURLs.size()-1);
+ if (nAnchorCount > 0)
+ {
+ rResourceId->maResourceURLs.resize(nAnchorCount);
+ for (sal_Int32 nIndex=0; nIndex<nAnchorCount; ++nIndex)
+ rResourceId->maResourceURLs[nIndex] = maResourceURLs[nIndex+1];
+ }
+ return rResourceId;
+}
+
+Sequence<OUString> SAL_CALL
+ ResourceId::getAnchorURLs()
+{
+ const sal_Int32 nAnchorCount (maResourceURLs.size() - 1);
+ if (nAnchorCount > 0)
+ {
+ Sequence<OUString> aAnchorURLs (nAnchorCount);
+ std::copy_n(maResourceURLs.begin() + 1, nAnchorCount, aAnchorURLs.getArray());
+ return aAnchorURLs;
+ }
+ else
+ return Sequence<OUString>();
+}
+
+OUString SAL_CALL
+ ResourceId::getResourceTypePrefix()
+{
+ if (!maResourceURLs.empty() )
+ {
+ // Return the "private:resource/<type>/" prefix.
+
+ // Get the prefix that ends with the second "/".
+ const OUString& rsResourceURL (maResourceURLs[0]);
+ sal_Int32 nPrefixEnd (rsResourceURL.indexOf('/'));
+ if (nPrefixEnd >= 0)
+ nPrefixEnd = rsResourceURL.indexOf('/', nPrefixEnd+1) + 1;
+ else
+ nPrefixEnd = 0;
+
+ return rsResourceURL.copy(0,nPrefixEnd);
+ }
+ else
+ return OUString();
+}
+
+sal_Int16 SAL_CALL
+ ResourceId::compareTo (const Reference<XResourceId>& rxResourceId)
+{
+ sal_Int16 nResult (0);
+
+ if ( ! rxResourceId.is())
+ {
+ // The empty reference is interpreted as empty resource id object.
+ if (!maResourceURLs.empty())
+ nResult = +1;
+ else
+ nResult = 0;
+ }
+ else
+ {
+ ResourceId* pId = nullptr;
+#ifdef USE_OPTIMIZATIONS
+ pId = dynamic_cast<ResourceId*>(rxResourceId.get());
+#endif
+ if (pId != nullptr)
+ {
+ // We have direct access to the implementation of the given
+ // resource id object.
+ nResult = CompareToLocalImplementation(*pId);
+ }
+ else
+ {
+ // We have to do the comparison via the UNO interface of the
+ // given resource id object.
+ nResult = CompareToExternalImplementation(rxResourceId);
+ }
+ }
+
+ return nResult;
+}
+
+sal_Int16 ResourceId::CompareToLocalImplementation (const ResourceId& rId) const
+{
+ sal_Int16 nResult (0);
+
+ const sal_uInt32 nLocalURLCount (maResourceURLs.size());
+ const sal_uInt32 nURLCount(rId.maResourceURLs.size());
+
+ // Start comparison with the top most anchors.
+ for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
+ nIndex>=0 && nLocalIndex>=0;
+ --nIndex,--nLocalIndex)
+ {
+ const OUString sLocalURL (maResourceURLs[nLocalIndex]);
+ const OUString sURL (rId.maResourceURLs[nIndex]);
+ const sal_Int32 nLocalResult (sURL.compareTo(sLocalURL));
+ if (nLocalResult != 0)
+ {
+ if (nLocalResult < 0)
+ nResult = -1;
+ else
+ nResult = +1;
+ break;
+ }
+ }
+
+ if (nResult == 0)
+ {
+ // No difference found yet. When the lengths are the same then the
+ // two resource ids are equivalent. Otherwise the shorter comes
+ // first.
+ if (nLocalURLCount != nURLCount)
+ {
+ if (nLocalURLCount < nURLCount)
+ nResult = -1;
+ else
+ nResult = +1;
+ }
+ }
+
+ return nResult;
+}
+
+sal_Int16 ResourceId::CompareToExternalImplementation (const Reference<XResourceId>& rxId) const
+{
+ sal_Int16 nResult (0);
+
+ const Sequence<OUString> aAnchorURLs (rxId->getAnchorURLs());
+ const sal_uInt32 nLocalURLCount (maResourceURLs.size());
+ const sal_uInt32 nURLCount(1+aAnchorURLs.getLength());
+
+ // Start comparison with the top most anchors.
+ sal_Int32 nLocalResult (0);
+ for (sal_Int32 nIndex=nURLCount-1,nLocalIndex=nLocalURLCount-1;
+ nIndex>=0&&nLocalIndex>=0;
+ --nIndex,--nLocalIndex)
+ {
+ if (nIndex == 0 )
+ nLocalResult = maResourceURLs[nIndex].compareTo(rxId->getResourceURL());
+ else
+ nLocalResult = maResourceURLs[nIndex].compareTo(aAnchorURLs[nIndex-1]);
+ if (nLocalResult != 0)
+ {
+ if (nLocalResult < 0)
+ nResult = -1;
+ else
+ nResult = +1;
+ break;
+ }
+ }
+
+ if (nResult == 0)
+ {
+ // No difference found yet. When the lengths are the same then the
+ // two resource ids are equivalent. Otherwise the shorter comes
+ // first.
+ if (nLocalURLCount != nURLCount)
+ {
+ if (nLocalURLCount < nURLCount)
+ nResult = -1;
+ else
+ nResult = +1;
+ }
+ }
+
+ return nResult;
+}
+
+sal_Bool SAL_CALL
+ ResourceId::isBoundTo (
+ const Reference<XResourceId>& rxResourceId,
+ AnchorBindingMode eMode)
+{
+ if ( ! rxResourceId.is())
+ {
+ // An empty reference is interpreted as empty resource id.
+ return IsBoundToAnchor(nullptr, nullptr, eMode);
+ }
+
+ ResourceId* pId = nullptr;
+#ifdef USE_OPTIMIZATIONS
+ pId = dynamic_cast<ResourceId*>(rxResourceId.get());
+#endif
+ if (pId != nullptr)
+ {
+ return IsBoundToAnchor(pId->maResourceURLs, eMode);
+ }
+ else
+ {
+ const OUString sResourceURL (rxResourceId->getResourceURL());
+ const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs());
+ return IsBoundToAnchor(&sResourceURL, &aAnchorURLs, eMode);
+ }
+}
+
+sal_Bool SAL_CALL
+ ResourceId::isBoundToURL (
+ const OUString& rsAnchorURL,
+ AnchorBindingMode eMode)
+{
+ return IsBoundToAnchor(&rsAnchorURL, nullptr, eMode);
+}
+
+Reference<XResourceId> SAL_CALL
+ ResourceId::clone()
+{
+ return new ResourceId(std::vector(maResourceURLs));
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL ResourceId::initialize (const Sequence<Any>& aArguments)
+{
+ for (const auto& rArgument : aArguments)
+ {
+ OUString sResourceURL;
+ if (rArgument >>= sResourceURL)
+ maResourceURLs.push_back(sResourceURL);
+ else
+ {
+ Reference<XResourceId> xAnchor;
+ if (rArgument >>= xAnchor)
+ {
+ if (xAnchor.is())
+ {
+ maResourceURLs.push_back(xAnchor->getResourceURL());
+ const Sequence<OUString> aAnchorURLs (xAnchor->getAnchorURLs());
+ maResourceURLs.insert( maResourceURLs.end(), aAnchorURLs.begin(), aAnchorURLs.end() );
+ }
+ }
+ }
+ }
+ ParseResourceURL();
+}
+
+OUString ResourceId::getImplementationName()
+{
+ return "com.sun.star.comp.Draw.framework.ResourceId";
+}
+
+sal_Bool ResourceId::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> ResourceId::getSupportedServiceNames()
+{
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.drawing.framework.ResourceId"};
+}
+
+/** When eMode is DIRECTLY then the anchor of the called object and the
+ anchor represented by the given sequence of anchor URLs have to be
+ identical. When eMode is RECURSIVE then the anchor of the called
+ object has to start with the given anchor URLs.
+*/
+bool ResourceId::IsBoundToAnchor (
+ const OUString* psFirstAnchorURL,
+ const Sequence<OUString>* paAnchorURLs,
+ AnchorBindingMode eMode) const
+{
+ const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
+ const bool bHasFirstAnchorURL (psFirstAnchorURL!=nullptr);
+ const sal_uInt32 nAnchorURLCount ((bHasFirstAnchorURL?1:0)
+ + (paAnchorURLs!=nullptr ? paAnchorURLs->getLength() : 0));
+
+ // Check the lengths.
+ if (nLocalAnchorURLCount<nAnchorURLCount ||
+ (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
+ {
+ return false;
+ }
+
+ // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
+ // id and the given anchor.
+ sal_uInt32 nOffset = 0;
+ if (paAnchorURLs != nullptr)
+ {
+ sal_uInt32 nCount = paAnchorURLs->getLength();
+ while (nOffset < nCount)
+ {
+ if ( maResourceURLs[nLocalAnchorURLCount - nOffset] !=
+ (*paAnchorURLs)[nCount - 1 - nOffset] )
+ {
+ return false;
+ }
+ ++nOffset;
+ }
+ }
+ if (bHasFirstAnchorURL)
+ {
+ if ( *psFirstAnchorURL != maResourceURLs[nLocalAnchorURLCount - nOffset] )
+ return false;
+ }
+
+ return true;
+}
+
+bool ResourceId::IsBoundToAnchor (
+ const ::std::vector<OUString>& rAnchorURLs,
+ AnchorBindingMode eMode) const
+{
+ const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1);
+ const sal_uInt32 nAnchorURLCount (rAnchorURLs.size());
+
+ // Check the lengths.
+ if (nLocalAnchorURLCount<nAnchorURLCount ||
+ (eMode==AnchorBindingMode_DIRECT && nLocalAnchorURLCount!=nAnchorURLCount))
+ {
+ return false;
+ }
+
+ // Compare the nAnchorURLCount bottom-most anchor URLs of this resource
+ // id and the given anchor.
+ for (sal_uInt32 nOffset=0; nOffset<nAnchorURLCount; ++nOffset)
+ {
+ if ( maResourceURLs[nLocalAnchorURLCount - nOffset] !=
+ rAnchorURLs[nAnchorURLCount - 1 - nOffset] )
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ResourceId::ParseResourceURL()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex());
+ Reference<util::XURLTransformer> xURLTransformer (mxURLTransformerWeak);
+ if ( ! xURLTransformer.is())
+ {
+ // Create the URL transformer.
+ Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ xURLTransformer.set(util::URLTransformer::create(xContext));
+ mxURLTransformerWeak = xURLTransformer;
+ SdGlobalResourceContainer::Instance().AddResource(
+ Reference<XInterface>(xURLTransformer,UNO_QUERY));
+ }
+
+ if (xURLTransformer.is() && !maResourceURLs.empty() )
+ {
+ mpURL.reset(new util::URL);
+ mpURL->Complete = maResourceURLs[0];
+ xURLTransformer->parseStrict(*mpURL);
+ if (mpURL->Main == maResourceURLs[0])
+ mpURL.reset();
+ else
+ maResourceURLs[0] = mpURL->Main;
+ }
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_ResourceID_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::ResourceId());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/UpdateRequest.cxx b/sd/source/ui/framework/configuration/UpdateRequest.cxx
new file mode 100644
index 000000000..b6c5e8c42
--- /dev/null
+++ b/sd/source/ui/framework/configuration/UpdateRequest.cxx
@@ -0,0 +1,47 @@
+/* -*- 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 "UpdateRequest.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework
+{
+UpdateRequest::UpdateRequest() noexcept {}
+
+UpdateRequest::~UpdateRequest() noexcept {}
+
+void SAL_CALL UpdateRequest::execute(const Reference<XConfiguration>&)
+{
+ // Do nothing here. The configuration is updated when the request queue
+ // becomes empty.
+}
+
+OUString SAL_CALL UpdateRequest::getName() { return "UpdateRequest"; }
+
+void SAL_CALL UpdateRequest::setName(const OUString&)
+{
+ // Ignored.
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/UpdateRequest.hxx b/sd/source/ui/framework/configuration/UpdateRequest.hxx
new file mode 100644
index 000000000..712167154
--- /dev/null
+++ b/sd/source/ui/framework/configuration/UpdateRequest.hxx
@@ -0,0 +1,70 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeRequest.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing::framework { class XConfiguration; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeRequest,
+ css::container::XNamed
+ > UpdateRequestInterfaceBase;
+
+/** This update request is used to request configuration updates
+ asynchronous when no other requests are being processed. When there are
+ other requests then we can simply wait until the last one is executed:
+ the configuration is updated when the request queue becomes empty. This
+ is use by this implementation as well. The execute() method does not
+ really do anything. This request just triggers the update of the
+ configuration when it is removed as last request from the queue.
+*/
+class UpdateRequest final
+ : public UpdateRequestInterfaceBase
+{
+public:
+ UpdateRequest() noexcept;
+ virtual ~UpdateRequest() noexcept override;
+
+ // XConfigurationChangeOperation
+
+ virtual void SAL_CALL execute (
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration) override;
+
+ // XNamed
+
+ /** Return a human readable string representation. This is used for
+ debugging purposes.
+ */
+ virtual OUString SAL_CALL getName() override;
+
+ /** This call is ignored because the XNamed interface is (mis)used to
+ give access to a human readable name for debugging purposes.
+ */
+ virtual void SAL_CALL setName (const OUString& rName) override;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/configuration/debugtrace.hxx b/sd/source/ui/framework/configuration/debugtrace.hxx
new file mode 100644
index 000000000..b520d0ff3
--- /dev/null
+++ b/sd/source/ui/framework/configuration/debugtrace.hxx
@@ -0,0 +1,15 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+/// Centrally define activation of configuration debug traces.
+#define DEBUG_SD_CONFIGURATION_TRACE 0
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicPaneFactory.cxx b/sd/source/ui/framework/factories/BasicPaneFactory.cxx
new file mode 100644
index 000000000..c01d315a3
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicPaneFactory.cxx
@@ -0,0 +1,432 @@
+/* -*- 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 <memory>
+#include <sal/config.h>
+
+#include "BasicPaneFactory.hxx"
+
+#include "ChildWindowPane.hxx"
+#include "FrameWindowPane.hxx"
+#include "FullScreenPane.hxx"
+
+#include <comphelper/servicehelper.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <PaneShells.hxx>
+#include <ViewShellBase.hxx>
+#include <PaneChildWindows.hxx>
+#include <DrawController.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+ enum PaneId {
+ CenterPaneId,
+ FullScreenPaneId,
+ LeftImpressPaneId,
+ LeftDrawPaneId
+ };
+
+ const sal_Int32 gnConfigurationUpdateStartEvent(0);
+ const sal_Int32 gnConfigurationUpdateEndEvent(1);
+}
+
+namespace sd::framework {
+
+/** Store URL, XPane reference and (local) PaneId for every pane factory
+ that is registered at the PaneController.
+*/
+class BasicPaneFactory::PaneDescriptor
+{
+public:
+ OUString msPaneURL;
+ Reference<XResource> mxPane;
+ PaneId mePaneId;
+ /** The mbReleased flag is set when the pane has been released. Some
+ panes are just hidden and destroyed. When the pane is reused this
+ flag is reset.
+ */
+ bool mbIsReleased;
+
+ bool CompareURL(std::u16string_view rsPaneURL) const { return msPaneURL == rsPaneURL; }
+ bool ComparePane(const Reference<XResource>& rxPane) const { return mxPane == rxPane; }
+};
+
+class BasicPaneFactory::PaneContainer
+ : public ::std::vector<PaneDescriptor>
+{
+public:
+ PaneContainer() {}
+};
+
+//===== PaneFactory ===========================================================
+
+BasicPaneFactory::BasicPaneFactory (
+ const Reference<XComponentContext>& rxContext)
+ : mxComponentContext(rxContext),
+ mpViewShellBase(nullptr),
+ mpPaneContainer(new PaneContainer)
+{
+}
+
+BasicPaneFactory::~BasicPaneFactory()
+{
+}
+
+void BasicPaneFactory::disposing(std::unique_lock<std::mutex>&)
+{
+ Reference<XConfigurationController> xCC (mxConfigurationControllerWeak);
+ if (xCC.is())
+ {
+ xCC->removeResourceFactoryForReference(this);
+ xCC->removeConfigurationChangeListener(this);
+ mxConfigurationControllerWeak.clear();
+ }
+
+ for (const auto& rDescriptor : *mpPaneContainer)
+ {
+ if (rDescriptor.mbIsReleased)
+ {
+ Reference<XComponent> xComponent (rDescriptor.mxPane, UNO_QUERY);
+ if (xComponent.is())
+ {
+ xComponent->removeEventListener(this);
+ xComponent->dispose();
+ }
+ }
+ }
+}
+
+void SAL_CALL BasicPaneFactory::initialize (const Sequence<Any>& aArguments)
+{
+ if (!aArguments.hasElements())
+ return;
+
+ try
+ {
+ // Get the XController from the first argument.
+ Reference<frame::XController> xController (aArguments[0], UNO_QUERY_THROW);
+
+ // Tunnel through the controller to obtain access to the ViewShellBase.
+ try
+ {
+ Reference<lang::XUnoTunnel> xTunnel (xController, UNO_QUERY_THROW);
+ if (auto pController = comphelper::getFromUnoTunnel<DrawController>(xTunnel))
+ mpViewShellBase = pController->GetViewShellBase();
+ }
+ catch(RuntimeException&)
+ {}
+
+ Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
+ Reference<XConfigurationController> xCC (xCM->getConfigurationController());
+ mxConfigurationControllerWeak = xCC;
+
+ // Add pane factories for the two left panes (one for Impress and one for
+ // Draw) and the center pane.
+ if (xController.is() && xCC.is())
+ {
+ PaneDescriptor aDescriptor;
+ aDescriptor.msPaneURL = FrameworkHelper::msCenterPaneURL;
+ aDescriptor.mePaneId = CenterPaneId;
+ aDescriptor.mbIsReleased = false;
+ mpPaneContainer->push_back(aDescriptor);
+ xCC->addResourceFactory(aDescriptor.msPaneURL, this);
+
+ aDescriptor.msPaneURL = FrameworkHelper::msFullScreenPaneURL;
+ aDescriptor.mePaneId = FullScreenPaneId;
+ mpPaneContainer->push_back(aDescriptor);
+ xCC->addResourceFactory(aDescriptor.msPaneURL, this);
+
+ aDescriptor.msPaneURL = FrameworkHelper::msLeftImpressPaneURL;
+ aDescriptor.mePaneId = LeftImpressPaneId;
+ mpPaneContainer->push_back(aDescriptor);
+ xCC->addResourceFactory(aDescriptor.msPaneURL, this);
+
+ aDescriptor.msPaneURL = FrameworkHelper::msLeftDrawPaneURL;
+ aDescriptor.mePaneId = LeftDrawPaneId;
+ mpPaneContainer->push_back(aDescriptor);
+ xCC->addResourceFactory(aDescriptor.msPaneURL, this);
+ }
+
+ // Register as configuration change listener.
+ if (xCC.is())
+ {
+ xCC->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateStartEvent,
+ Any(gnConfigurationUpdateStartEvent));
+ xCC->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ Any(gnConfigurationUpdateEndEvent));
+ }
+ }
+ catch (RuntimeException&)
+ {
+ Reference<XConfigurationController> xCC (mxConfigurationControllerWeak);
+ if (xCC.is())
+ xCC->removeResourceFactoryForReference(this);
+ }
+}
+
+//===== XPaneFactory ==========================================================
+
+Reference<XResource> SAL_CALL BasicPaneFactory::createResource (
+ const Reference<XResourceId>& rxPaneId)
+{
+ ThrowIfDisposed();
+
+ Reference<XResource> xPane;
+
+ // Based on the ResourceURL of the given ResourceId look up the
+ // corresponding factory descriptor.
+ PaneContainer::iterator iDescriptor (
+ ::std::find_if (
+ mpPaneContainer->begin(),
+ mpPaneContainer->end(),
+ [&] (PaneDescriptor const& rPane) {
+ return rPane.CompareURL(rxPaneId->getResourceURL());
+ } ));
+
+ if (iDescriptor == mpPaneContainer->end())
+ {
+ // The requested pane can not be created by any of the factories
+ // managed by the called BasicPaneFactory object.
+ throw lang::IllegalArgumentException("BasicPaneFactory::createPane() called for unknown resource id",
+ nullptr,
+ 0);
+ }
+
+ if (iDescriptor->mxPane.is())
+ {
+ // The pane has already been created and is still active (has
+ // not yet been released). This should not happen.
+ xPane = iDescriptor->mxPane;
+ }
+ else
+ {
+ // Create a new pane.
+ switch (iDescriptor->mePaneId)
+ {
+ case CenterPaneId:
+ xPane = CreateFrameWindowPane(rxPaneId);
+ break;
+
+ case FullScreenPaneId:
+ xPane = CreateFullScreenPane(mxComponentContext, rxPaneId);
+ break;
+
+ case LeftImpressPaneId:
+ case LeftDrawPaneId:
+ xPane = CreateChildWindowPane(
+ rxPaneId,
+ *iDescriptor);
+ break;
+ }
+ iDescriptor->mxPane = xPane;
+
+ // Listen for the pane being disposed.
+ Reference<lang::XComponent> xComponent (xPane, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+ }
+ iDescriptor->mbIsReleased = false;
+
+
+ return xPane;
+}
+
+void SAL_CALL BasicPaneFactory::releaseResource (
+ const Reference<XResource>& rxPane)
+{
+ ThrowIfDisposed();
+
+ // Based on the given XPane reference look up the corresponding factory
+ // descriptor.
+ PaneContainer::iterator iDescriptor (
+ ::std::find_if(
+ mpPaneContainer->begin(),
+ mpPaneContainer->end(),
+ [&] (PaneDescriptor const& rPane) { return rPane.ComparePane(rxPane); } ));
+
+ if (iDescriptor == mpPaneContainer->end())
+ {
+ // The given XPane reference is either empty or the pane was not
+ // created by any of the factories managed by the called
+ // BasicPaneFactory object.
+ throw lang::IllegalArgumentException("BasicPaneFactory::releasePane() called for pane that was not created by same factory.",
+ nullptr,
+ 0);
+ }
+
+ // The given pane was created by one of the factories. Child
+ // windows are just hidden and will be reused when requested later.
+ // Other windows are disposed and their reference is reset so that
+ // on the next createPane() call for the same pane type the pane is
+ // created anew.
+ ChildWindowPane* pChildWindowPane = dynamic_cast<ChildWindowPane*>(rxPane.get());
+ if (pChildWindowPane != nullptr)
+ {
+ iDescriptor->mbIsReleased = true;
+ pChildWindowPane->Hide();
+ }
+ else
+ {
+ iDescriptor->mxPane = nullptr;
+ Reference<XComponent> xComponent (rxPane, UNO_QUERY);
+ if (xComponent.is())
+ {
+ // We are disposing the pane and do not have to be informed of
+ // that.
+ xComponent->removeEventListener(this);
+ xComponent->dispose();
+ }
+ }
+
+}
+
+//===== XConfigurationChangeListener ==========================================
+
+void SAL_CALL BasicPaneFactory::notifyConfigurationChange (
+ const ConfigurationChangeEvent& /* rEvent */ )
+{
+ // FIXME: nothing to do
+}
+
+//===== lang::XEventListener ==================================================
+
+void SAL_CALL BasicPaneFactory::disposing (
+ const lang::EventObject& rEventObject)
+{
+ if (mxConfigurationControllerWeak.get() == rEventObject.Source)
+ {
+ mxConfigurationControllerWeak.clear();
+ }
+ else
+ {
+ // Has one of the panes been disposed? If so, then release the
+ // reference to that pane, but not the pane descriptor.
+ Reference<XResource> xPane (rEventObject.Source, UNO_QUERY);
+ PaneContainer::iterator iDescriptor (
+ ::std::find_if (
+ mpPaneContainer->begin(),
+ mpPaneContainer->end(),
+ [&] (PaneDescriptor const& rPane) { return rPane.ComparePane(xPane); } ));
+ if (iDescriptor != mpPaneContainer->end())
+ {
+ iDescriptor->mxPane = nullptr;
+ }
+ }
+}
+
+Reference<XResource> BasicPaneFactory::CreateFrameWindowPane (
+ const Reference<XResourceId>& rxPaneId)
+{
+ Reference<XResource> xPane;
+
+ if (mpViewShellBase != nullptr)
+ {
+ xPane = new FrameWindowPane(rxPaneId, mpViewShellBase->GetViewWindow());
+ }
+
+ return xPane;
+}
+
+Reference<XResource> BasicPaneFactory::CreateFullScreenPane (
+ const Reference<XComponentContext>& rxComponentContext,
+ const Reference<XResourceId>& rxPaneId)
+{
+ Reference<XResource> xPane (
+ new FullScreenPane(
+ rxComponentContext,
+ rxPaneId,
+ mpViewShellBase->GetViewWindow()));
+
+ return xPane;
+}
+
+Reference<XResource> BasicPaneFactory::CreateChildWindowPane (
+ const Reference<XResourceId>& rxPaneId,
+ const PaneDescriptor& rDescriptor)
+{
+ Reference<XResource> xPane;
+
+ if (mpViewShellBase != nullptr)
+ {
+ // Create the corresponding shell and determine the id of the child window.
+ sal_uInt16 nChildWindowId = 0;
+ ::std::unique_ptr<SfxShell> pShell;
+ switch (rDescriptor.mePaneId)
+ {
+ case LeftImpressPaneId:
+ pShell.reset(new LeftImpressPaneShell());
+ nChildWindowId = ::sd::LeftPaneImpressChildWindow::GetChildWindowId();
+ break;
+
+ case LeftDrawPaneId:
+ pShell.reset(new LeftDrawPaneShell());
+ nChildWindowId = ::sd::LeftPaneDrawChildWindow::GetChildWindowId();
+ break;
+
+ default:
+ break;
+ }
+
+ // With shell and child window id create the ChildWindowPane
+ // wrapper.
+ if (pShell != nullptr)
+ {
+ xPane = new ChildWindowPane(
+ rxPaneId,
+ nChildWindowId,
+ *mpViewShellBase,
+ std::move(pShell));
+ }
+ }
+
+ return xPane;
+}
+
+void BasicPaneFactory::ThrowIfDisposed() const
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("BasicPaneFactory object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_BasicPaneFactory_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::BasicPaneFactory(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicPaneFactory.hxx b/sd/source/ui/framework/factories/BasicPaneFactory.hxx
new file mode 100644
index 000000000..317776e48
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicPaneFactory.hxx
@@ -0,0 +1,131 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <memory>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd {
+
+class ViewShellBase;
+}
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::lang::XInitialization,
+ css::drawing::framework::XResourceFactory,
+ css::drawing::framework::XConfigurationChangeListener
+ > BasicPaneFactoryInterfaceBase;
+
+/** This factory provides the frequently used standard panes
+ private:resource/pane/CenterPane
+ private:resource/pane/FullScreenPane
+ private:resource/pane/LeftImpressPane
+ private:resource/pane/LeftDrawPane
+ There are two left panes because this is (seems to be) the only way to
+ show different titles for the left pane in Draw and Impress.
+*/
+class BasicPaneFactory
+ : public BasicPaneFactoryInterfaceBase
+{
+public:
+ explicit BasicPaneFactory (
+ const css::uno::Reference<css::uno::XComponentContext>& rxContext);
+ virtual ~BasicPaneFactory() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+ // XResourceFactory
+
+ virtual css::uno::Reference<css::drawing::framework::XResource>
+ SAL_CALL createResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId) override;
+
+ virtual void SAL_CALL
+ releaseResource (
+ const css::uno::Reference<css::drawing::framework::XResource>& rxPane) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // lang::XEventListener
+
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEventObject) override;
+
+private:
+ css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
+ css::uno::WeakReference<css::drawing::framework::XConfigurationController>
+ mxConfigurationControllerWeak;
+ ViewShellBase* mpViewShellBase;
+ class PaneDescriptor;
+ class PaneContainer;
+ std::unique_ptr<PaneContainer> mpPaneContainer;
+
+ /** Create a new instance of FrameWindowPane.
+ @param rPaneId
+ There is only one frame window so this id is just checked to
+ have the correct value.
+ */
+ css::uno::Reference<css::drawing::framework::XResource>
+ CreateFrameWindowPane (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId);
+
+ /** Create a new pane that represents the center pane in full screen
+ mode.
+ */
+ css::uno::Reference<css::drawing::framework::XResource>
+ CreateFullScreenPane (
+ const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId);
+
+ /** Create a new instance of ChildWindowPane.
+ @param rPaneId
+ The ResourceURL member defines which side pane to create.
+ */
+ css::uno::Reference<css::drawing::framework::XResource>
+ CreateChildWindowPane (
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxPaneId,
+ const PaneDescriptor& rDescriptor);
+
+ /// @throws css::lang::DisposedException
+ void ThrowIfDisposed() const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicToolBarFactory.cxx b/sd/source/ui/framework/factories/BasicToolBarFactory.cxx
new file mode 100644
index 000000000..af79a88ea
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicToolBarFactory.cxx
@@ -0,0 +1,161 @@
+/* -*- 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 "BasicToolBarFactory.hxx"
+
+#include <ViewTabBar.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+//===== BasicToolBarFactory ===================================================
+
+BasicToolBarFactory::BasicToolBarFactory ()
+{
+}
+
+BasicToolBarFactory::~BasicToolBarFactory()
+{
+}
+
+void BasicToolBarFactory::disposing(std::unique_lock<std::mutex>&)
+{
+ Shutdown();
+}
+
+void BasicToolBarFactory::Shutdown()
+{
+ Reference<lang::XComponent> xComponent (mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(static_cast<lang::XEventListener*>(this));
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->removeResourceFactoryForReference(this);
+ mxConfigurationController = nullptr;
+ }
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL BasicToolBarFactory::initialize (const Sequence<Any>& aArguments)
+{
+ if (!aArguments.hasElements())
+ return;
+
+ try
+ {
+ // Get the XController from the first argument.
+ mxController.set(aArguments[0], UNO_QUERY_THROW);
+
+ utl::MediaDescriptor aDescriptor (mxController->getModel()->getArgs());
+ if ( ! aDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_PREVIEW,
+ false))
+ {
+ // Register the factory for its supported tool bars.
+ Reference<XControllerManager> xControllerManager(mxController, UNO_QUERY_THROW);
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->addResourceFactory(
+ FrameworkHelper::msViewTabBarURL, this);
+ }
+
+ Reference<lang::XComponent> xComponent (mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast<lang::XEventListener*>(this));
+ }
+ else
+ {
+ // The view shell is in preview mode and thus does not need
+ // the view tab bar.
+ mxConfigurationController = nullptr;
+ }
+ }
+ catch (RuntimeException&)
+ {
+ Shutdown();
+ throw;
+ }
+}
+
+//----- lang::XEventListener --------------------------------------------------
+
+void SAL_CALL BasicToolBarFactory::disposing (
+ const lang::EventObject& rEventObject)
+{
+ if (rEventObject.Source == mxConfigurationController)
+ mxConfigurationController = nullptr;
+}
+
+//===== XPaneFactory ==========================================================
+
+Reference<XResource> SAL_CALL BasicToolBarFactory::createResource (
+ const Reference<XResourceId>& rxToolBarId)
+{
+ ThrowIfDisposed();
+
+ if (rxToolBarId->getResourceURL() != FrameworkHelper::msViewTabBarURL)
+ throw lang::IllegalArgumentException();
+
+ Reference<XResource> xToolBar = new ViewTabBar(rxToolBarId, mxController);
+ return xToolBar;
+}
+
+void SAL_CALL BasicToolBarFactory::releaseResource (
+ const Reference<XResource>& rxToolBar)
+{
+ ThrowIfDisposed();
+
+ Reference<XComponent> xComponent (rxToolBar, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+void BasicToolBarFactory::ThrowIfDisposed() const
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("BasicToolBarFactory object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+} // end of namespace sd::framework
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_BasicToolBarFactory_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::BasicToolBarFactory);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicToolBarFactory.hxx b/sd/source/ui/framework/factories/BasicToolBarFactory.hxx
new file mode 100644
index 000000000..fdaf92788
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicToolBarFactory.hxx
@@ -0,0 +1,84 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::frame { class XController; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XResourceFactory,
+ css::lang::XInitialization,
+ css::lang::XEventListener
+ > BasicToolBarFactoryInterfaceBase;
+
+/** This factory provides some of the frequently used tool bars:
+ private:resource/toolbar/ViewTabBar
+*/
+class BasicToolBarFactory
+ : public BasicToolBarFactoryInterfaceBase
+{
+public:
+ BasicToolBarFactory ();
+ virtual ~BasicToolBarFactory() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // ToolBarFactory
+
+ virtual css::uno::Reference<css::drawing::framework::XResource> SAL_CALL
+ createResource (
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxToolBarId) override;
+
+ virtual void SAL_CALL
+ releaseResource (
+ const css::uno::Reference<css::drawing::framework::XResource>&
+ rxToolBar) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+ // lang::XEventListener
+
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEventObject) override;
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController> mxConfigurationController;
+ css::uno::Reference<css::frame::XController> mxController;
+
+ void Shutdown();
+
+ /// @throws css::lang::DisposedException
+ void ThrowIfDisposed() const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicViewFactory.cxx b/sd/source/ui/framework/factories/BasicViewFactory.cxx
new file mode 100644
index 000000000..425cb4446
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicViewFactory.cxx
@@ -0,0 +1,518 @@
+/* -*- 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 "BasicViewFactory.hxx"
+
+#include <framework/ViewShellWrapper.hxx>
+#include <framework/FrameworkHelper.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <framework/Pane.hxx>
+#include <DrawController.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <DrawDocShell.hxx>
+#include <DrawViewShell.hxx>
+#include <GraphicViewShell.hxx>
+#include <OutlineViewShell.hxx>
+#include <PresentationViewShell.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <FrameView.hxx>
+#include <Window.hxx>
+
+#include <comphelper/servicehelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/wrkwin.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace sd::framework {
+
+//===== ViewDescriptor ========================================================
+
+class BasicViewFactory::ViewDescriptor
+{
+public:
+ Reference<XResource> mxView;
+ std::shared_ptr<sd::ViewShell> mpViewShell;
+ Reference<XResourceId> mxViewId;
+ static bool CompareView (const std::shared_ptr<ViewDescriptor>& rpDescriptor,
+ const Reference<XResource>& rxView)
+ { return rpDescriptor->mxView.get() == rxView.get(); }
+};
+
+//===== BasicViewFactory::ViewShellContainer ==================================
+
+class BasicViewFactory::ViewShellContainer
+ : public ::std::vector<std::shared_ptr<ViewDescriptor> >
+{
+public:
+ ViewShellContainer() {};
+};
+
+class BasicViewFactory::ViewCache
+ : public ::std::vector<std::shared_ptr<ViewDescriptor> >
+{
+public:
+ ViewCache() {};
+};
+
+//===== ViewFactory ===========================================================
+
+BasicViewFactory::BasicViewFactory ()
+ : mpViewShellContainer(new ViewShellContainer()),
+ mpBase(nullptr),
+ mpFrameView(nullptr),
+ mpWindow(VclPtr<WorkWindow>::Create(nullptr,WB_STDWORK)),
+ mpViewCache(std::make_shared<ViewCache>()),
+ mxLocalPane(new Pane(Reference<XResourceId>(), mpWindow.get()))
+{
+}
+
+BasicViewFactory::~BasicViewFactory()
+{
+}
+
+void BasicViewFactory::disposing(std::unique_lock<std::mutex>&)
+{
+ // Disconnect from the frame view.
+ if (mpFrameView != nullptr)
+ {
+ mpFrameView->Disconnect();
+ mpFrameView = nullptr;
+ }
+
+ // Release the view cache.
+ for (const auto& rxView : *mpViewCache)
+ {
+ ReleaseView(rxView, true);
+ }
+
+ // Release the view shell container. At this point no one other than us
+ // should hold references to the view shells (at the moment this is a
+ // trivial requirement, because no one other than us holds a shared
+ // pointer).
+ // ViewShellContainer::const_iterator iView;
+ for (const auto& rxView : *mpViewShellContainer)
+ {
+ OSL_ASSERT(rxView->mpViewShell.use_count() == 1);
+ }
+ mpViewShellContainer.reset();
+}
+
+Reference<XResource> SAL_CALL BasicViewFactory::createResource (
+ const Reference<XResourceId>& rxViewId)
+{
+ Reference<XResource> xView;
+ const bool bIsCenterPane (
+ rxViewId->isBoundToURL(FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT));
+
+ // Get the pane for the anchor URL.
+ Reference<XPane> xPane;
+ if (mxConfigurationController.is())
+ xPane.set(mxConfigurationController->getResource(rxViewId->getAnchor()), UNO_QUERY);
+
+ // For main views use the frame view of the last main view.
+ ::sd::FrameView* pFrameView = nullptr;
+ if (xPane.is() && bIsCenterPane)
+ {
+ pFrameView = mpFrameView;
+ }
+
+ // Get Window pointer for XWindow of the pane.
+ vcl::Window* pWindow = nullptr;
+ if (xPane.is())
+ pWindow = VCLUnoHelper::GetWindow(xPane->getWindow());
+
+ // Get the view frame.
+ SfxViewFrame* pFrame = nullptr;
+ if (mpBase != nullptr)
+ pFrame = mpBase->GetViewFrame();
+
+ if (pFrame != nullptr && mpBase!=nullptr && pWindow!=nullptr)
+ {
+ // Try to get the view from the cache.
+ std::shared_ptr<ViewDescriptor> pDescriptor (GetViewFromCache(rxViewId, xPane));
+
+ // When the requested view is not in the cache then create a new view.
+ if (pDescriptor == nullptr)
+ {
+ pDescriptor = CreateView(rxViewId, *pFrame, *pWindow, xPane, pFrameView, bIsCenterPane);
+ }
+
+ if (pDescriptor != nullptr)
+ xView = pDescriptor->mxView;
+
+ mpViewShellContainer->push_back(pDescriptor);
+
+ if (bIsCenterPane)
+ ActivateCenterView(pDescriptor);
+ else
+ pWindow->Resize();
+ }
+
+ return xView;
+}
+
+void SAL_CALL BasicViewFactory::releaseResource (const Reference<XResource>& rxView)
+{
+ if ( ! rxView.is())
+ throw lang::IllegalArgumentException();
+
+ if (!rxView.is() || !mpBase)
+ return;
+
+ ViewShellContainer::iterator iViewShell (
+ ::std::find_if(
+ mpViewShellContainer->begin(),
+ mpViewShellContainer->end(),
+ [&] (std::shared_ptr<ViewDescriptor> const& pVD) {
+ return ViewDescriptor::CompareView(pVD, rxView);
+ } ));
+ if (iViewShell == mpViewShellContainer->end())
+ {
+ throw lang::IllegalArgumentException();
+ }
+
+ std::shared_ptr<ViewShell> pViewShell ((*iViewShell)->mpViewShell);
+
+ if ((*iViewShell)->mxViewId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ // Obtain a pointer to and connect to the frame view of the
+ // view. The next view, that is created, will be
+ // initialized with this frame view.
+ if (mpFrameView == nullptr)
+ {
+ mpFrameView = pViewShell->GetFrameView();
+ if (mpFrameView)
+ mpFrameView->Connect();
+ }
+
+ // With the view in the center pane the sub controller is
+ // released, too.
+ mpBase->GetDrawController().SetSubController(
+ Reference<drawing::XDrawSubController>());
+
+ SfxViewShell* pSfxViewShell = pViewShell->GetViewShell();
+ if (pSfxViewShell != nullptr)
+ pSfxViewShell->DisconnectAllClients();
+ }
+
+ ReleaseView(*iViewShell, false);
+
+ mpViewShellContainer->erase(iViewShell);
+}
+
+void SAL_CALL BasicViewFactory::initialize (const Sequence<Any>& aArguments)
+{
+ if (!aArguments.hasElements())
+ return;
+
+ try
+ {
+ // Get the XController from the first argument.
+ Reference<frame::XController> xController (aArguments[0], UNO_QUERY_THROW);
+
+ // Tunnel through the controller to obtain a ViewShellBase.
+ Reference<lang::XUnoTunnel> xTunnel (xController, UNO_QUERY_THROW);
+ ::sd::DrawController* pController = comphelper::getFromUnoTunnel<sd::DrawController>(xTunnel);
+ if (pController != nullptr)
+ mpBase = pController->GetViewShellBase();
+
+ // Register the factory for its supported views.
+ Reference<XControllerManager> xCM (xController,UNO_QUERY_THROW);
+ mxConfigurationController = xCM->getConfigurationController();
+ if ( ! mxConfigurationController.is())
+ throw RuntimeException();
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msImpressViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msDrawViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msOutlineViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msNotesViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msHandoutViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msPresentationViewURL, this);
+ mxConfigurationController->addResourceFactory(FrameworkHelper::msSlideSorterURL, this);
+ }
+ catch (RuntimeException&)
+ {
+ mpBase = nullptr;
+ if (mxConfigurationController.is())
+ mxConfigurationController->removeResourceFactoryForReference(this);
+ throw;
+ }
+}
+
+std::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::CreateView (
+ const Reference<XResourceId>& rxViewId,
+ SfxViewFrame& rFrame,
+ vcl::Window& rWindow,
+ const Reference<XPane>& rxPane,
+ FrameView* pFrameView,
+ const bool bIsCenterPane)
+{
+ auto pDescriptor = std::make_shared<ViewDescriptor>();
+
+ pDescriptor->mpViewShell = CreateViewShell(
+ rxViewId,
+ rFrame,
+ rWindow,
+ pFrameView);
+ pDescriptor->mxViewId = rxViewId;
+
+ if (pDescriptor->mpViewShell != nullptr)
+ {
+ pDescriptor->mpViewShell->Init(bIsCenterPane);
+ mpBase->GetViewShellManager()->ActivateViewShell(pDescriptor->mpViewShell.get());
+
+ Reference<awt::XWindow> xWindow(rxPane->getWindow());
+ rtl::Reference<ViewShellWrapper> wrapper(new ViewShellWrapper(
+ pDescriptor->mpViewShell,
+ rxViewId,
+ xWindow));
+
+ // register ViewShellWrapper on pane window
+ if (xWindow.is())
+ {
+ xWindow->addWindowListener(wrapper);
+ if (pDescriptor->mpViewShell != nullptr)
+ {
+ pDescriptor->mpViewShell->Resize();
+ }
+ }
+
+ pDescriptor->mxView = wrapper.get();
+ }
+
+ return pDescriptor;
+}
+
+std::shared_ptr<ViewShell> BasicViewFactory::CreateViewShell (
+ const Reference<XResourceId>& rxViewId,
+ SfxViewFrame& rFrame,
+ vcl::Window& rWindow,
+ FrameView* pFrameView)
+{
+ std::shared_ptr<ViewShell> pViewShell;
+ const OUString& rsViewURL (rxViewId->getResourceURL());
+ if (rsViewURL == FrameworkHelper::msImpressViewURL)
+ {
+ pViewShell =
+ std::make_shared<DrawViewShell>(
+ *mpBase,
+ &rWindow,
+ PageKind::Standard,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("impress_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msDrawViewURL)
+ {
+ pViewShell = std::shared_ptr<GraphicViewShell>(
+ new GraphicViewShell(*mpBase, &rWindow, pFrameView),
+ o3tl::default_delete<GraphicViewShell>());
+ pViewShell->GetContentWindow()->set_id("draw_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msOutlineViewURL)
+ {
+ pViewShell =
+ std::make_shared<OutlineViewShell>(
+ &rFrame,
+ *mpBase,
+ &rWindow,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("outline_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msNotesViewURL)
+ {
+ pViewShell =
+ std::make_shared<DrawViewShell>(
+ *mpBase,
+ &rWindow,
+ PageKind::Notes,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("notes_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msHandoutViewURL)
+ {
+ pViewShell =
+ std::make_shared<DrawViewShell>(
+ *mpBase,
+ &rWindow,
+ PageKind::Handout,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("handout_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msPresentationViewURL)
+ {
+ pViewShell =
+ std::make_shared<PresentationViewShell>(
+ *mpBase,
+ &rWindow,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("presentation_win");
+ }
+ else if (rsViewURL == FrameworkHelper::msSlideSorterURL)
+ {
+ pViewShell = ::sd::slidesorter::SlideSorterViewShell::Create (
+ &rFrame,
+ *mpBase,
+ &rWindow,
+ pFrameView);
+ pViewShell->GetContentWindow()->set_id("slidesorter");
+ }
+
+ return pViewShell;
+}
+
+void BasicViewFactory::ReleaseView (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor,
+ bool bDoNotCache)
+{
+ bool bIsCacheable (!bDoNotCache && IsCacheable(rpDescriptor));
+
+ if (bIsCacheable)
+ {
+ Reference<XRelocatableResource> xResource (rpDescriptor->mxView, UNO_QUERY);
+ if (xResource.is())
+ {
+ if (mxLocalPane.is())
+ if (xResource->relocateToAnchor(mxLocalPane))
+ mpViewCache->push_back(rpDescriptor);
+ else
+ bIsCacheable = false;
+ else
+ bIsCacheable = false;
+ }
+ else
+ {
+ bIsCacheable = false;
+ }
+ }
+
+ if ( ! bIsCacheable)
+ {
+ // Shut down the current view shell.
+ rpDescriptor->mpViewShell->Shutdown ();
+ mpBase->GetDocShell()->Disconnect(rpDescriptor->mpViewShell.get());
+ mpBase->GetViewShellManager()->DeactivateViewShell(rpDescriptor->mpViewShell.get());
+
+ Reference<XComponent> xComponent (rpDescriptor->mxView, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+}
+
+bool BasicViewFactory::IsCacheable (const std::shared_ptr<ViewDescriptor>& rpDescriptor)
+{
+ bool bIsCacheable (false);
+
+ Reference<XRelocatableResource> xResource (rpDescriptor->mxView, UNO_QUERY);
+ if (xResource.is())
+ {
+ static ::std::vector<Reference<XResourceId> > s_aCacheableResources = [&]()
+ {
+ ::std::vector<Reference<XResourceId> > tmp;
+ FrameworkHelper::Instance(*mpBase);
+
+ // The slide sorter and the task panel are cacheable and relocatable.
+ tmp.push_back(FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftDrawPaneURL));
+ tmp.push_back(FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftImpressPaneURL));
+ return tmp;
+ }();
+
+ bIsCacheable = std::any_of(s_aCacheableResources.begin(), s_aCacheableResources.end(),
+ [&rpDescriptor](const Reference<XResourceId>& rxId) { return rxId->compareTo(rpDescriptor->mxViewId) == 0; });
+ }
+
+ return bIsCacheable;
+}
+
+std::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::GetViewFromCache (
+ const Reference<XResourceId>& rxViewId,
+ const Reference<XPane>& rxPane)
+{
+ std::shared_ptr<ViewDescriptor> pDescriptor;
+
+ // Search for the requested view in the cache.
+ ViewCache::iterator iEntry = std::find_if(mpViewCache->begin(), mpViewCache->end(),
+ [&rxViewId](const ViewCache::value_type& rxEntry) { return rxEntry->mxViewId->compareTo(rxViewId) == 0; });
+ if (iEntry != mpViewCache->end())
+ {
+ pDescriptor = *iEntry;
+ mpViewCache->erase(iEntry);
+ }
+
+ // When the view has been found then relocate it to the given pane and
+ // remove it from the cache.
+ if (pDescriptor != nullptr)
+ {
+ bool bRelocationSuccessful (false);
+ Reference<XRelocatableResource> xResource (pDescriptor->mxView, UNO_QUERY);
+ if (xResource.is() && rxPane.is())
+ {
+ if (xResource->relocateToAnchor(rxPane))
+ bRelocationSuccessful = true;
+ }
+
+ if ( ! bRelocationSuccessful)
+ {
+ ReleaseView(pDescriptor, true);
+ pDescriptor.reset();
+ }
+ }
+
+ return pDescriptor;
+}
+
+void BasicViewFactory::ActivateCenterView (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor)
+{
+ mpBase->GetDocShell()->Connect(rpDescriptor->mpViewShell.get());
+
+ // During the creation of the new sub-shell, resize requests were not
+ // forwarded to it because it was not yet registered. Therefore, we
+ // have to request a resize now.
+ rpDescriptor->mpViewShell->UIFeatureChanged();
+ if (mpBase->GetDocShell()->IsInPlaceActive())
+ mpBase->GetViewFrame()->Resize(true);
+
+ mpBase->GetDrawController().SetSubController(
+ rpDescriptor->mpViewShell->CreateSubController());
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_BasicViewFactory_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::BasicViewFactory);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/BasicViewFactory.hxx b/sd/source/ui/framework/factories/BasicViewFactory.hxx
new file mode 100644
index 000000000..ccd5cbbda
--- /dev/null
+++ b/sd/source/ui/framework/factories/BasicViewFactory.hxx
@@ -0,0 +1,129 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XResourceFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+#include <comphelper/compbase.hxx>
+
+#include <vcl/vclptr.hxx>
+#include <memory>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XPane; }
+
+namespace sd {
+class ViewShell;
+class ViewShellBase;
+class FrameView;
+}
+class SfxViewFrame;
+namespace vcl { class Window; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XResourceFactory,
+ css::lang::XInitialization
+ > BasicViewFactoryInterfaceBase;
+
+/** Factory for the frequently used standard views of the drawing framework:
+ private:resource/view/
+ private:resource/view/ImpressView
+ private:resource/view/GraphicView
+ private:resource/view/OutlineView
+ private:resource/view/NotesView
+ private:resource/view/HandoutView
+ private:resource/view/SlideSorter
+ private:resource/view/PresentationView
+ private:resource/view/TaskPane
+ For some views in some panes this class also acts as a cache.
+*/
+class BasicViewFactory
+ : public BasicViewFactoryInterfaceBase
+{
+public:
+ BasicViewFactory ();
+ virtual ~BasicViewFactory() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XViewFactory
+
+ virtual css::uno::Reference<css::drawing::framework::XResource>
+ SAL_CALL createResource (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId) override;
+
+ virtual void SAL_CALL releaseResource (
+ const css::uno::Reference<css::drawing::framework::XResource>& xView) override;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ class ViewDescriptor;
+ class ViewShellContainer;
+ std::unique_ptr<ViewShellContainer> mpViewShellContainer;
+ ViewShellBase* mpBase;
+ FrameView* mpFrameView;
+
+ class ViewCache;
+ ScopedVclPtr<vcl::Window> mpWindow;
+ std::shared_ptr<ViewCache> mpViewCache;
+
+ css::uno::Reference<css::drawing::framework::XPane> mxLocalPane;
+
+ std::shared_ptr<ViewDescriptor> CreateView (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
+ SfxViewFrame& rFrame,
+ vcl::Window& rWindow,
+ const css::uno::Reference<css::drawing::framework::XPane>& rxPane,
+ FrameView* pFrameView,
+ const bool bIsCenterView);
+
+ std::shared_ptr<ViewShell> CreateViewShell (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
+ SfxViewFrame& rFrame,
+ vcl::Window& rWindow,
+ FrameView* pFrameView);
+
+ void ActivateCenterView (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor);
+
+ void ReleaseView (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor,
+ bool bDoNotCache);
+
+ bool IsCacheable (
+ const std::shared_ptr<ViewDescriptor>& rpDescriptor);
+
+ std::shared_ptr<ViewDescriptor> GetViewFromCache (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
+ const css::uno::Reference<css::drawing::framework::XPane>& rxPane);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/ChildWindowPane.cxx b/sd/source/ui/framework/factories/ChildWindowPane.cxx
new file mode 100644
index 000000000..136f6fcb7
--- /dev/null
+++ b/sd/source/ui/framework/factories/ChildWindowPane.cxx
@@ -0,0 +1,219 @@
+/* -*- 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 <memory>
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <utility>
+
+#include "ChildWindowPane.hxx"
+
+#include <PaneDockingWindow.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <sfx2/viewfrm.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+ChildWindowPane::ChildWindowPane (
+ const Reference<XResourceId>& rxPaneId,
+ sal_uInt16 nChildWindowId,
+ ViewShellBase& rViewShellBase,
+ ::std::unique_ptr<SfxShell> && pShell)
+ : ChildWindowPaneInterfaceBase(rxPaneId,nullptr),
+ mnChildWindowId(nChildWindowId),
+ mrViewShellBase(rViewShellBase),
+ mpShell(std::move(pShell)),
+ mbHasBeenActivated(false)
+{
+ mrViewShellBase.GetViewShellManager()->ActivateShell(mpShell.get());
+
+ SfxViewFrame* pViewFrame = mrViewShellBase.GetViewFrame();
+ if (pViewFrame == nullptr)
+ return;
+
+ if (mrViewShellBase.IsActive())
+ {
+ if (pViewFrame->KnowsChildWindow(mnChildWindowId))
+ {
+ if (pViewFrame->HasChildWindow(mnChildWindowId))
+ {
+ // The ViewShellBase has already been activated. Make
+ // the child window visible as soon as possible.
+ pViewFrame->SetChildWindow(mnChildWindowId, true);
+ }
+ else
+ {
+ // The window is created asynchronously. Rely on the
+ // ConfigurationUpdater to try another update, and with
+ // that another request for this window, in a short
+ // time.
+ }
+ }
+ else
+ {
+ SAL_WARN("sd", "ChildWindowPane:not known");
+ }
+ }
+ else
+ {
+ // The ViewShellBase has not yet been activated. Hide the
+ // window and wait a little before it is made visible. See
+ // comments in the GetWindow() method for an explanation.
+ pViewFrame->SetChildWindow(mnChildWindowId, false);
+ }
+}
+
+ChildWindowPane::~ChildWindowPane()
+{
+}
+
+void ChildWindowPane::Hide()
+{
+ SfxViewFrame* pViewFrame = mrViewShellBase.GetViewFrame();
+ if (pViewFrame != nullptr)
+ if (pViewFrame->KnowsChildWindow(mnChildWindowId))
+ if (pViewFrame->HasChildWindow(mnChildWindowId))
+ pViewFrame->SetChildWindow(mnChildWindowId, false);
+
+ // Release the window because when the child window is shown again it
+ // may use a different window.
+ mxWindow = nullptr;
+}
+
+void SAL_CALL ChildWindowPane::disposing()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ mrViewShellBase.GetViewShellManager()->DeactivateShell(mpShell.get());
+ mpShell.reset();
+
+ if (mxWindow.is())
+ {
+ mxWindow->removeEventListener(this);
+ }
+
+ Pane::disposing();
+}
+
+vcl::Window* ChildWindowPane::GetWindow()
+{
+ do
+ {
+ if (mxWindow.is())
+ // Window already exists => nothing to do.
+ break;
+
+ // When the window is not yet present then obtain it only when the
+ // shell has already been activated. The activation is not
+ // necessary for the code to work properly but is used to optimize
+ // the layouting and displaying of the window. When it is made
+ // visible too early then some layouting seems to be made twice or at
+ // an inconvenient time and the overall process of initializing the
+ // Impress takes longer.
+ if (!mbHasBeenActivated && mpShell != nullptr && !mpShell->IsActive())
+ break;
+
+ mbHasBeenActivated = true;
+ SfxViewFrame* pViewFrame = mrViewShellBase.GetViewFrame();
+ if (pViewFrame == nullptr)
+ break;
+ // The view frame has to know the child window. This can be the
+ // case, when for example the document is in read-only mode: the
+ // task pane is then not available.
+ if ( ! pViewFrame->KnowsChildWindow(mnChildWindowId))
+ break;
+
+ pViewFrame->SetChildWindow(mnChildWindowId, true);
+ SfxChildWindow* pChildWindow = pViewFrame->GetChildWindow(mnChildWindowId);
+ if (pChildWindow == nullptr)
+ if (pViewFrame->HasChildWindow(mnChildWindowId))
+ {
+ // The child window is not yet visible. Ask the view frame
+ // to show it and try again to get access to the child
+ // window.
+ pViewFrame->ShowChildWindow(mnChildWindowId);
+ pChildWindow = pViewFrame->GetChildWindow(mnChildWindowId);
+ }
+
+ // When the child window is still not visible then we have to try later.
+ if (pChildWindow == nullptr)
+ break;
+
+ // From the child window get the docking window and from that the
+ // content window that is the container for the actual content.
+ PaneDockingWindow* pDockingWindow = dynamic_cast<PaneDockingWindow*>(
+ pChildWindow->GetWindow());
+ if (pDockingWindow == nullptr)
+ break;
+
+ // At last, we have access to the window and its UNO wrapper.
+ mpWindow = &pDockingWindow->GetContentWindow();
+ mxWindow = VCLUnoHelper::GetInterface(mpWindow);
+
+ // Register as window listener to be informed when the child window
+ // is hidden.
+ if (mxWindow.is())
+ mxWindow->addEventListener(this);
+ }
+ while (false);
+
+ return mpWindow;
+}
+
+Reference<awt::XWindow> SAL_CALL ChildWindowPane::getWindow()
+{
+ if (mpWindow == nullptr || ! mxWindow.is())
+ GetWindow();
+ return Pane::getWindow();
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2(
+ ChildWindowPane,
+ ChildWindowPaneInterfaceBase,
+ Pane);
+IMPLEMENT_FORWARD_XTYPEPROVIDER2(
+ ChildWindowPane,
+ ChildWindowPaneInterfaceBase,
+ Pane);
+
+//----- XEventListener --------------------------------------------------------
+
+void SAL_CALL ChildWindowPane::disposing (const lang::EventObject& rEvent)
+{
+ ThrowIfDisposed();
+
+ if (rEvent.Source == mxWindow)
+ {
+ // The window is gone but the pane remains alive. The next call to
+ // GetWindow() may create the window anew.
+ mxWindow = nullptr;
+ mpWindow = nullptr;
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/ChildWindowPane.hxx b/sd/source/ui/framework/factories/ChildWindowPane.hxx
new file mode 100644
index 000000000..082177757
--- /dev/null
+++ b/sd/source/ui/framework/factories/ChildWindowPane.hxx
@@ -0,0 +1,101 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <framework/Pane.hxx>
+
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/uno3.hxx>
+#include <memory>
+
+class SfxShell;
+
+namespace sd { class ViewShellBase; }
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::drawing::framework { class XResourceId; }
+
+namespace sd::framework {
+
+typedef ::cppu::ImplInheritanceHelper <
+ ::sd::framework::Pane,
+ css::lang::XEventListener
+ > ChildWindowPaneInterfaceBase;
+
+/** The ChildWindowPane listens to the child window and disposes itself when
+ the child window becomes inaccessible. This happens for instance when a
+ document is made read-only and the task pane is turned off.
+*/
+class ChildWindowPane
+ : public ChildWindowPaneInterfaceBase
+{
+public:
+ ChildWindowPane (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ sal_uInt16 nChildWindowId,
+ ViewShellBase& rViewShellBase,
+ ::std::unique_ptr<SfxShell> && pShell);
+ virtual ~ChildWindowPane() override;
+
+ /** Hide the pane. To make the pane visible again, call GetWindow().
+ */
+ void Hide();
+
+ virtual void SAL_CALL disposing() override;
+
+ /** This returns the content window when the child window is already
+ visible. Otherwise <NULL/> is returned. In that case a later call
+ may return the requested window (making a child window visible is an
+ asynchronous process.)
+ Note that GetWindow() may return different Window pointers when
+ Hide() is called in between.
+ */
+ virtual vcl::Window* GetWindow() override;
+
+ /** The local getWindow() first calls GetWindow() to provide a valid
+ window pointer before forwarding the call to the base class.
+ */
+ virtual css::uno::Reference<css::awt::XWindow>
+ SAL_CALL getWindow() override;
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ sal_uInt16 mnChildWindowId;
+ ViewShellBase& mrViewShellBase;
+ ::std::unique_ptr<SfxShell> mpShell;
+
+ /** This flag is set when the pane shell has been activated at least
+ once. It is used to optimize the start-up performance (by not
+ showing the window too early) and by not delaying its creation at
+ later times.
+ */
+ bool mbHasBeenActivated;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/FrameWindowPane.cxx b/sd/source/ui/framework/factories/FrameWindowPane.cxx
new file mode 100644
index 000000000..1f4b387d8
--- /dev/null
+++ b/sd/source/ui/framework/factories/FrameWindowPane.cxx
@@ -0,0 +1,39 @@
+/* -*- 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 "FrameWindowPane.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework
+{
+FrameWindowPane::FrameWindowPane(const Reference<XResourceId>& rxPaneId, vcl::Window* pWindow)
+ : Pane(rxPaneId, pWindow)
+{
+}
+
+FrameWindowPane::~FrameWindowPane() noexcept {}
+
+sal_Bool SAL_CALL FrameWindowPane::isAnchorOnly() { return false; }
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/FrameWindowPane.hxx b/sd/source/ui/framework/factories/FrameWindowPane.hxx
new file mode 100644
index 000000000..67da37fdf
--- /dev/null
+++ b/sd/source/ui/framework/factories/FrameWindowPane.hxx
@@ -0,0 +1,50 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <framework/Pane.hxx>
+
+namespace com::sun::star::drawing::framework
+{
+class XResourceId;
+}
+
+namespace sd::framework
+{
+/** This subclass is not necessary anymore. We can remove it if that
+ remains so.
+*/
+class FrameWindowPane : public Pane
+{
+public:
+ FrameWindowPane(const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ vcl::Window* pWindow);
+ virtual ~FrameWindowPane() noexcept override;
+
+ /** A frame window typically can (and should) exists on its own without
+ children, if only to visualize that something (a view) is missing.
+ Therefore this method always returns <FALSE/>.
+ */
+ virtual sal_Bool SAL_CALL isAnchorOnly() override;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/FullScreenPane.cxx b/sd/source/ui/framework/factories/FullScreenPane.cxx
new file mode 100644
index 000000000..dbf34213f
--- /dev/null
+++ b/sd/source/ui/framework/factories/FullScreenPane.cxx
@@ -0,0 +1,226 @@
+/* -*- 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 "FullScreenPane.hxx"
+#include <vcl/vclevent.hxx>
+#include <vcl/wrkwin.hxx>
+#include <o3tl/string_view.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+FullScreenPane::FullScreenPane (
+ const Reference<XComponentContext>& rxComponentContext,
+ const Reference<XResourceId>& rxPaneId,
+ const vcl::Window* pViewShellWindow)
+ : FrameWindowPane(rxPaneId,nullptr),
+ mxComponentContext(rxComponentContext)
+{
+ vcl::Window* pParent = nullptr;
+ mpWorkWindow.reset(VclPtr<WorkWindow>::Create(
+
+ pParent,
+ 0)); // For debugging (non-fullscreen) use WB_BORDER | WB_MOVEABLE | WB_SIZEABLE));
+
+ if ( ! rxPaneId.is())
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nScreenNumber = 1;
+ ExtractArguments(rxPaneId, nScreenNumber);
+
+ if (!mpWorkWindow)
+ return;
+
+ // Create a new top-level window that is displayed full screen.
+ mpWorkWindow->ShowFullScreenMode(true, nScreenNumber);
+ // For debugging (non-fullscreen) use mpWorkWindow->SetScreenNumber(nScreenNumber);
+ mpWorkWindow->SetMenuBarMode(MenuBarMode::Hide);
+ mpWorkWindow->SetBorderStyle(WindowBorderStyle::REMOVEBORDER);
+ mpWorkWindow->SetBackground(Wallpaper());
+ // Don't show the window right now in order to allow the setting of an
+ // accessibility object: accessibility objects are typically
+ // requested by AT-tools when the window is shown. Chaining it
+ // afterwards may or may not work.
+
+ // Add resize listener at the work window.
+ Link<VclWindowEvent&,void> aWindowEventHandler (LINK(this, FullScreenPane, WindowEventHandler));
+ mpWorkWindow->AddEventListener(aWindowEventHandler);
+
+ // Set title and icon of the new window to those of the current window
+ // of the view shell.
+ if (pViewShellWindow != nullptr)
+ {
+ const SystemWindow* pSystemWindow = pViewShellWindow->GetSystemWindow();
+ mpWorkWindow->SetText(pSystemWindow->GetText());
+ mpWorkWindow->SetIcon(pSystemWindow->GetIcon());
+ }
+
+ // For some reason the VCL canvas can not paint into a WorkWindow.
+ // Therefore a child window is created that covers the WorkWindow
+ // completely.
+ mpWindow = VclPtr<vcl::Window>::Create(mpWorkWindow.get());
+ mpWindow->SetPosSizePixel(Point(0,0), mpWorkWindow->GetSizePixel());
+ mpWindow->SetBackground(Wallpaper());
+ mxWindow = VCLUnoHelper::GetInterface(mpWindow);
+
+ // Create the canvas.
+ mxCanvas = CreateCanvas();
+
+ mpWindow->GrabFocus();
+}
+
+FullScreenPane::~FullScreenPane() noexcept
+{
+}
+
+void SAL_CALL FullScreenPane::disposing()
+{
+ mpWindow.disposeAndClear();
+
+ if (mpWorkWindow)
+ {
+ Link<VclWindowEvent&,void> aWindowEventHandler (LINK(this, FullScreenPane, WindowEventHandler));
+ mpWorkWindow->RemoveEventListener(aWindowEventHandler);
+ mpWorkWindow.disposeAndClear();
+ }
+
+ FrameWindowPane::disposing();
+}
+
+//----- XPane -----------------------------------------------------------------
+
+sal_Bool SAL_CALL FullScreenPane::isVisible()
+{
+ ThrowIfDisposed();
+
+ if (mpWindow != nullptr)
+ return mpWindow->IsReallyVisible();
+ else
+ return false;
+}
+
+void SAL_CALL FullScreenPane::setVisible (const sal_Bool bIsVisible)
+{
+ ThrowIfDisposed();
+
+ if (mpWindow != nullptr)
+ mpWindow->Show(bIsVisible);
+ if (mpWorkWindow != nullptr)
+ mpWorkWindow->Show(bIsVisible);
+}
+
+Reference<css::accessibility::XAccessible> SAL_CALL FullScreenPane::getAccessible()
+{
+ ThrowIfDisposed();
+
+ if (mpWorkWindow != nullptr)
+ return mpWorkWindow->GetAccessible(false);
+ else
+ return nullptr;
+}
+
+void SAL_CALL FullScreenPane::setAccessible (
+ const Reference<css::accessibility::XAccessible>& rxAccessible)
+{
+ ThrowIfDisposed();
+
+ if (mpWindow == nullptr)
+ return;
+
+ Reference<lang::XInitialization> xInitializable (rxAccessible, UNO_QUERY);
+ if (xInitializable.is())
+ {
+ vcl::Window* pParentWindow = mpWindow->GetParent();
+ Reference<css::accessibility::XAccessible> xAccessibleParent;
+ if (pParentWindow != nullptr)
+ xAccessibleParent = pParentWindow->GetAccessible();
+ Sequence<Any> aArguments{ Any(xAccessibleParent) };
+ xInitializable->initialize(aArguments);
+ }
+ GetWindow()->SetAccessible(rxAccessible);
+}
+
+IMPL_LINK(FullScreenPane, WindowEventHandler, VclWindowEvent&, rEvent, void)
+{
+ switch (rEvent.GetId())
+ {
+ case VclEventId::WindowResize:
+ GetWindow()->SetPosPixel(Point(0,0));
+ GetWindow()->SetSizePixel(Size(
+ mpWorkWindow->GetSizePixel().Width(),
+ mpWorkWindow->GetSizePixel().Height()));
+ break;
+
+ case VclEventId::ObjectDying:
+ mpWorkWindow.disposeAndClear();
+ break;
+
+ default: break;
+ }
+}
+
+Reference<rendering::XCanvas> FullScreenPane::CreateCanvas()
+{
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(mxWindow);
+ if (!pWindow)
+ throw RuntimeException();
+
+ Sequence<Any> aArg{ // common: first any is VCL pointer to window (for VCL canvas)
+ Any(reinterpret_cast<sal_Int64>(pWindow.get())),
+ Any(css::awt::Rectangle()),
+ Any(false),
+ Any(mxWindow)
+ };
+
+ Reference<lang::XMultiServiceFactory> xFactory (
+ mxComponentContext->getServiceManager(), UNO_QUERY_THROW);
+ return Reference<rendering::XCanvas>(
+ xFactory->createInstanceWithArguments("com.sun.star.rendering.SpriteCanvas.VCL",
+ aArg),
+ UNO_QUERY);
+}
+
+void FullScreenPane::ExtractArguments (
+ const Reference<XResourceId>& rxPaneId,
+ sal_Int32& rnScreenNumberReturnValue)
+{
+ // Extract arguments from the resource URL.
+ const util::URL aURL = rxPaneId->getFullResourceURL();
+ for (sal_Int32 nIndex{ 0 }; nIndex >= 0; )
+ {
+ const std::u16string_view aToken = o3tl::getToken(aURL.Arguments, 0, '&', nIndex);
+ std::u16string_view sValue;
+ if (o3tl::starts_with(aToken, u"ScreenNumber=", &sValue))
+ {
+ rnScreenNumberReturnValue = o3tl::toInt32(sValue);
+ }
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/FullScreenPane.hxx b/sd/source/ui/framework/factories/FullScreenPane.hxx
new file mode 100644
index 000000000..b33804ee5
--- /dev/null
+++ b/sd/source/ui/framework/factories/FullScreenPane.hxx
@@ -0,0 +1,85 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "FrameWindowPane.hxx"
+#include <tools/link.hxx>
+#include <vcl/wrkwin.hxx>
+
+class VclWindowEvent;
+
+namespace vcl { class Window; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd::framework {
+
+/** The full screen pane creates a pane that covers the complete application
+ window, i.e. that hides menu bar, tool bars, status bars.
+*/
+class FullScreenPane
+ : public FrameWindowPane
+{
+public:
+ /** Create a new full screen pane.
+ @param rxComponentContext
+ Used for creating a new canvas.
+ @param rxPaneId
+ The resource id of the new pane.
+ @param pViewShellWindow
+ The top-level parent of this window is used to obtain title and
+ icon for the new top-level window.
+ */
+ FullScreenPane (
+ const css::uno::Reference<css::uno::XComponentContext>& rxComponentContext,
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ const vcl::Window* pViewShellWindow);
+ virtual ~FullScreenPane() noexcept override;
+
+ virtual void SAL_CALL disposing() override;
+
+ //----- XPane -------------------------------------------------------------
+
+ virtual sal_Bool SAL_CALL isVisible() override;
+
+ virtual void SAL_CALL setVisible (sal_Bool bIsVisible) override;
+
+ virtual css::uno::Reference<css::accessibility::XAccessible> SAL_CALL getAccessible() override;
+
+ virtual void SAL_CALL setAccessible (
+ const css::uno::Reference<css::accessibility::XAccessible>& rxAccessible) override;
+
+ DECL_LINK(WindowEventHandler, VclWindowEvent&, void);
+
+protected:
+ virtual css::uno::Reference<css::rendering::XCanvas>
+ CreateCanvas() override;
+
+private:
+ css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
+ VclPtr<WorkWindow> mpWorkWindow;
+
+ static void ExtractArguments (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxPaneId,
+ sal_Int32& rnScreenNumberReturnValue);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/Pane.cxx b/sd/source/ui/framework/factories/Pane.cxx
new file mode 100644
index 000000000..a188f0e11
--- /dev/null
+++ b/sd/source/ui/framework/factories/Pane.cxx
@@ -0,0 +1,178 @@
+/* -*- 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/Pane.hxx>
+
+#include <osl/mutex.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <comphelper/servicehelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace sd::framework {
+
+Pane::Pane (
+ const Reference<XResourceId>& rxPaneId,
+ vcl::Window* pWindow)
+ noexcept
+ : PaneInterfaceBase(m_aMutex),
+ mxPaneId(rxPaneId),
+ mpWindow(pWindow),
+ mxWindow(VCLUnoHelper::GetInterface(pWindow))
+{
+}
+
+Pane::~Pane()
+{
+}
+
+void Pane::disposing()
+{
+ mxWindow = nullptr;
+ mpWindow = nullptr;
+}
+
+vcl::Window* Pane::GetWindow()
+{
+ if (mxWindow.is())
+ return mpWindow;
+ else
+ return nullptr;
+}
+
+//----- XPane -----------------------------------------------------------------
+
+Reference<awt::XWindow> SAL_CALL Pane::getWindow()
+{
+ ThrowIfDisposed();
+
+ return mxWindow;
+}
+
+Reference<rendering::XCanvas> SAL_CALL Pane::getCanvas()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ ThrowIfDisposed();
+
+ if ( ! mxCanvas.is())
+ mxCanvas = CreateCanvas();
+
+ return mxCanvas;
+}
+
+//----- XPane2 ----------------------------------------------------------------
+
+sal_Bool SAL_CALL Pane::isVisible()
+{
+ ThrowIfDisposed();
+
+ const vcl::Window* pWindow = GetWindow();
+ if (pWindow != nullptr)
+ return pWindow->IsVisible();
+ else
+ return false;
+}
+
+void SAL_CALL Pane::setVisible (sal_Bool bIsVisible)
+{
+ ThrowIfDisposed();
+
+ vcl::Window* pWindow = GetWindow();
+ if (pWindow != nullptr)
+ pWindow->Show(bIsVisible);
+}
+
+Reference<css::accessibility::XAccessible> SAL_CALL Pane::getAccessible()
+{
+ ThrowIfDisposed();
+ vcl::Window* pWindow = GetWindow();
+ if (pWindow != nullptr)
+ return pWindow->GetAccessible(false);
+ else
+ return nullptr;
+}
+
+void SAL_CALL Pane::setAccessible (
+ const Reference<css::accessibility::XAccessible>& rxAccessible)
+{
+ ThrowIfDisposed();
+ vcl::Window* pWindow = GetWindow();
+ if (pWindow != nullptr)
+ pWindow->SetAccessible(rxAccessible);
+}
+
+//----- XResource -------------------------------------------------------------
+
+Reference<XResourceId> SAL_CALL Pane::getResourceId()
+{
+ ThrowIfDisposed();
+
+ return mxPaneId;
+}
+
+sal_Bool SAL_CALL Pane::isAnchorOnly()
+{
+ return true;
+}
+
+//----- XUnoTunnel ------------------------------------------------------------
+
+const Sequence<sal_Int8>& Pane::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit thePaneUnoTunnelId;
+ return thePaneUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL Pane::getSomething (const Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+Reference<rendering::XCanvas> Pane::CreateCanvas()
+{
+ Reference<rendering::XCanvas> xCanvas;
+
+ if (mpWindow != nullptr)
+ {
+ ::cppcanvas::SpriteCanvasSharedPtr pCanvas (
+ cppcanvas::VCLFactory::createSpriteCanvas(*mpWindow));
+ if (pCanvas)
+ xCanvas.set(pCanvas->getUNOSpriteCanvas());
+ }
+
+ return xCanvas;
+}
+
+void Pane::ThrowIfDisposed() const
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ throw lang::DisposedException ("Pane object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/PresentationFactory.cxx b/sd/source/ui/framework/factories/PresentationFactory.cxx
new file mode 100644
index 000000000..8cf603809
--- /dev/null
+++ b/sd/source/ui/framework/factories/PresentationFactory.cxx
@@ -0,0 +1,192 @@
+/* -*- 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/PresentationFactory.hxx>
+
+#include <DrawController.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XView.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/compbase.hxx>
+#include <tools/diagnose_ex.h>
+#include <slideshow.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing::framework;
+
+
+namespace sd::framework {
+
+namespace {
+
+typedef comphelper::WeakComponentImplHelper<lang::XInitialization> PresentationFactoryProviderInterfaceBase;
+
+class PresentationFactoryProvider
+ : public PresentationFactoryProviderInterfaceBase
+{
+public:
+ PresentationFactoryProvider ();
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence<css::uno::Any>& aArguments) override;
+};
+
+typedef comphelper::WeakComponentImplHelper<XView> PresentationViewInterfaceBase;
+
+/** The PresentationView is not an actual view, it is a marker whose
+ existence in a configuration indicates that a slideshow is running
+ (in another application window).
+*/
+class PresentationView
+ : public PresentationViewInterfaceBase
+{
+public:
+ explicit PresentationView (const Reference<XResourceId>& rxViewId)
+ : mxResourceId(rxViewId) {};
+
+ // XView
+
+ virtual Reference<XResourceId> SAL_CALL getResourceId() override
+ { return mxResourceId; };
+
+ virtual sal_Bool SAL_CALL isAnchorOnly() override
+ { return false; }
+
+private:
+ Reference<XResourceId> mxResourceId;
+};
+
+} // end of anonymous namespace.
+
+//===== PresentationFactory ===================================================
+
+constexpr OUStringLiteral gsPresentationViewURL = u"private:resource/view/Presentation";
+
+PresentationFactory::PresentationFactory (
+ const Reference<frame::XController>& rxController)
+ : mxController(rxController)
+{
+}
+
+PresentationFactory::~PresentationFactory()
+{
+}
+
+//----- XViewFactory ----------------------------------------------------------
+
+Reference<XResource> SAL_CALL PresentationFactory::createResource (
+ const Reference<XResourceId>& rxViewId)
+{
+ ThrowIfDisposed();
+
+ if (rxViewId.is())
+ if ( ! rxViewId->hasAnchor() && rxViewId->getResourceURL() == gsPresentationViewURL)
+ return new PresentationView(rxViewId);
+
+ return Reference<XResource>();
+}
+
+void SAL_CALL PresentationFactory::releaseResource (
+ const Reference<XResource>&)
+{
+ ThrowIfDisposed();
+
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(mxController);
+ if (pController != nullptr)
+ {
+ ViewShellBase* pBase = pController->GetViewShellBase();
+ if (pBase != nullptr)
+ SlideShow::Stop( *pBase );
+ }
+}
+
+//===== XConfigurationChangeListener ==========================================
+
+void SAL_CALL PresentationFactory::notifyConfigurationChange (
+ const ConfigurationChangeEvent&)
+{}
+
+//===== lang::XEventListener ==================================================
+
+void SAL_CALL PresentationFactory::disposing (
+ const lang::EventObject&)
+{}
+
+void PresentationFactory::ThrowIfDisposed() const
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("PresentationFactory object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+namespace {
+
+//===== PresentationFactoryProvider ===========================================
+
+PresentationFactoryProvider::PresentationFactoryProvider ()
+{
+}
+
+// XInitialization
+
+void SAL_CALL PresentationFactoryProvider::initialize(
+ const Sequence<Any>& aArguments)
+{
+ if (!aArguments.hasElements())
+ return;
+
+ try
+ {
+ // Get the XController from the first argument.
+ Reference<frame::XController> xController (aArguments[0], UNO_QUERY_THROW);
+ Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
+ Reference<XConfigurationController> xCC (xCM->getConfigurationController());
+ if (xCC.is())
+ xCC->addResourceFactory(
+ gsPresentationViewURL,
+ new PresentationFactory(xController));
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+} // end of anonymous namespace.
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_PresentationFactoryProvider_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::framework::PresentationFactoryProvider);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/factories/ViewShellWrapper.cxx b/sd/source/ui/framework/factories/ViewShellWrapper.cxx
new file mode 100644
index 000000000..8f0fcd976
--- /dev/null
+++ b/sd/source/ui/framework/factories/ViewShellWrapper.cxx
@@ -0,0 +1,252 @@
+/* -*- 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/ViewShellWrapper.hxx>
+#include <sdpage.hxx>
+#include <ViewShell.hxx>
+
+#include <SlideSorter.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <controller/SlsPageSelector.hxx>
+#include <controller/SlideSorterController.hxx>
+#include <model/SlsPageEnumerationProvider.hxx>
+#include <model/SlsPageDescriptor.hxx>
+
+#include <com/sun/star/drawing/framework/XPane.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::com::sun::star::awt::XWindow;
+
+namespace sd::framework {
+
+ViewShellWrapper::ViewShellWrapper (
+ const std::shared_ptr<ViewShell>& pViewShell,
+ const Reference<XResourceId>& rxViewId,
+ const Reference<awt::XWindow>& rxWindow)
+ : mpViewShell(pViewShell),
+ mpSlideSorterViewShell(
+ std::dynamic_pointer_cast< ::sd::slidesorter::SlideSorterViewShell >( pViewShell )),
+ mxViewId(rxViewId),
+ mxWindow(rxWindow)
+{
+}
+
+ViewShellWrapper::~ViewShellWrapper()
+{
+}
+
+void ViewShellWrapper::disposing(std::unique_lock<std::mutex>&)
+{
+ SAL_INFO("sd.ui", "disposing ViewShellWrapper " << this);
+ Reference<awt::XWindow> xWindow (mxWindow);
+ if (xWindow.is())
+ {
+ SAL_INFO(
+ "sd.ui",
+ "removing ViewShellWrapper " << this << " from window listener at "
+ << mxWindow.get());
+ xWindow->removeWindowListener(this);
+ }
+
+ mpSlideSorterViewShell.reset();
+ mpViewShell.reset();
+}
+
+uno::Any SAL_CALL ViewShellWrapper::queryInterface( const uno::Type & rType )
+{
+ if( mpSlideSorterViewShell &&
+ rType == cppu::UnoType<view::XSelectionSupplier>::get() )
+ {
+ uno::Reference<view::XSelectionSupplier> xSupplier( this );
+ return Any(xSupplier);
+ }
+ else
+ return ViewShellWrapperInterfaceBase::queryInterface( rType );
+}
+
+//----- XResource -------------------------------------------------------------
+
+Reference<XResourceId> SAL_CALL ViewShellWrapper::getResourceId()
+{
+ return mxViewId;
+}
+
+sal_Bool SAL_CALL ViewShellWrapper::isAnchorOnly()
+{
+ return false;
+}
+
+//----- XSelectionSupplier --------------------------------------------------
+
+sal_Bool SAL_CALL ViewShellWrapper::select( const css::uno::Any& aSelection )
+{
+ if (!mpSlideSorterViewShell)
+ return false;
+
+ ::sd::slidesorter::controller::SlideSorterController& rSlideSorterController
+ = mpSlideSorterViewShell->GetSlideSorter().GetController();
+ ::sd::slidesorter::controller::PageSelector& rSelector (rSlideSorterController.GetPageSelector());
+ rSelector.DeselectAllPages();
+ Sequence<Reference<drawing::XDrawPage> > xPages;
+ aSelection >>= xPages;
+ for (const auto& rPage : std::as_const(xPages))
+ {
+ Reference<beans::XPropertySet> xSet (rPage, UNO_QUERY);
+ if (xSet.is())
+ {
+ try
+ {
+ Any aNumber = xSet->getPropertyValue("Number");
+ sal_Int32 nPageNumber = 0;
+ aNumber >>= nPageNumber;
+ nPageNumber -=1; // Transform 1-based page numbers to 0-based ones.
+ rSelector.SelectPage(nPageNumber);
+ }
+ catch (const RuntimeException&)
+ {
+ }
+ }
+ }
+
+ return true;
+}
+
+uno::Any SAL_CALL ViewShellWrapper::getSelection()
+{
+ Any aResult;
+
+ if (!mpSlideSorterViewShell)
+ return aResult;
+
+ slidesorter::model::PageEnumeration aSelectedPages (
+ slidesorter::model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mpSlideSorterViewShell->GetSlideSorter().GetModel()));
+ int nSelectedPageCount (
+ mpSlideSorterViewShell->GetSlideSorter().GetController().GetPageSelector().GetSelectedPageCount());
+
+ Sequence<Reference<XInterface> > aPages(nSelectedPageCount);
+ auto aPagesRange = asNonConstRange(aPages);
+ int nIndex = 0;
+ while (aSelectedPages.HasMoreElements() && nIndex<nSelectedPageCount)
+ {
+ slidesorter::model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ aPagesRange[nIndex++] = pDescriptor->GetPage()->getUnoPage();
+ }
+ aResult <<= aPages;
+
+ return aResult;
+}
+
+void SAL_CALL ViewShellWrapper::addSelectionChangeListener( const uno::Reference< view::XSelectionChangeListener >& )
+{
+}
+
+void SAL_CALL ViewShellWrapper::removeSelectionChangeListener( const uno::Reference< view::XSelectionChangeListener >& )
+{
+}
+
+//----- XRelocatableResource --------------------------------------------------
+
+sal_Bool SAL_CALL ViewShellWrapper::relocateToAnchor (
+ const Reference<XResource>& xResource)
+{
+ bool bResult (false);
+
+ Reference<XPane> xPane (xResource, UNO_QUERY);
+ if (xPane.is())
+ {
+ // Detach from the window of the old pane.
+ Reference<awt::XWindow> xWindow (mxWindow);
+ if (xWindow.is())
+ xWindow->removeWindowListener(this);
+ mxWindow = nullptr;
+
+ if (mpViewShell != nullptr)
+ {
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xPane->getWindow());
+ if (pWindow && mpViewShell->RelocateToParentWindow(pWindow))
+ {
+ bResult = true;
+
+ // Attach to the window of the new pane.
+ xWindow = xPane->getWindow();
+ if (xWindow.is())
+ {
+ xWindow->addWindowListener(this);
+ mpViewShell->Resize();
+ }
+ }
+ }
+ }
+
+ return bResult;
+}
+
+//----- XUnoTunnel ------------------------------------------------------------
+
+const Sequence<sal_Int8>& ViewShellWrapper::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theViewShellWrapperUnoTunnelId;
+ return theViewShellWrapperUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL ViewShellWrapper::getSomething (const Sequence<sal_Int8>& rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+//===== awt::XWindowListener ==================================================
+
+void SAL_CALL ViewShellWrapper::windowResized (const awt::WindowEvent&)
+{
+ ViewShell* pViewShell (mpViewShell.get());
+ if (pViewShell != nullptr)
+ pViewShell->Resize();
+}
+
+void SAL_CALL ViewShellWrapper::windowMoved (const awt::WindowEvent&) {}
+
+void SAL_CALL ViewShellWrapper::windowShown (const lang::EventObject&)
+{
+ ViewShell* pViewShell (mpViewShell.get());
+ if (pViewShell != nullptr)
+ pViewShell->Resize();
+}
+
+void SAL_CALL ViewShellWrapper::windowHidden (const lang::EventObject&) {}
+
+//===== XEventListener ========================================================
+
+void SAL_CALL ViewShellWrapper::disposing (const lang::EventObject& rEvent)
+{
+ if (rEvent.Source == mxWindow)
+ mxWindow = nullptr;
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/CenterViewFocusModule.cxx b/sd/source/ui/framework/module/CenterViewFocusModule.cxx
new file mode 100644
index 000000000..e36f95e33
--- /dev/null
+++ b/sd/source/ui/framework/module/CenterViewFocusModule.cxx
@@ -0,0 +1,151 @@
+/* -*- 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 "CenterViewFocusModule.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+#include <framework/ViewShellWrapper.hxx>
+
+#include <DrawController.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShellManager.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <comphelper/servicehelper.hxx>
+
+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 {
+
+//===== CenterViewFocusModule ====================================================
+
+CenterViewFocusModule::CenterViewFocusModule (Reference<frame::XController> const & rxController)
+ : mbValid(false),
+ mpBase(nullptr),
+ mbNewViewCreated(false)
+{
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+
+ // Tunnel through the controller to obtain a ViewShellBase.
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(rxController);
+ if (pController != nullptr)
+ mpBase = pController->GetViewShellBase();
+
+ // Check, if all required objects do exist.
+ if (mxConfigurationController.is() && mpBase!=nullptr)
+ {
+ mbValid = true;
+ }
+ }
+
+ if (mbValid)
+ {
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ Any());
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationEvent,
+ Any());
+ }
+}
+
+CenterViewFocusModule::~CenterViewFocusModule()
+{
+}
+
+void CenterViewFocusModule::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController.is())
+ mxConfigurationController->removeConfigurationChangeListener(this);
+
+ mbValid = false;
+ mxConfigurationController = nullptr;
+ mpBase = nullptr;
+}
+
+void SAL_CALL CenterViewFocusModule::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (mbValid)
+ {
+ if (rEvent.Type == FrameworkHelper::msConfigurationUpdateEndEvent)
+ {
+ HandleNewView(rEvent.Configuration);
+ }
+ else if (rEvent.Type == FrameworkHelper::msResourceActivationEvent)
+ {
+ if (rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix))
+ mbNewViewCreated = true;
+ }
+ }
+}
+
+void CenterViewFocusModule::HandleNewView (
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ if (!mbNewViewCreated)
+ return;
+
+ mbNewViewCreated = false;
+ // Make the center pane the active one. Tunnel through the
+ // controller to obtain a ViewShell pointer.
+
+ Sequence<Reference<XResourceId> > xViewIds (rxConfiguration->getResources(
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL),
+ FrameworkHelper::msViewURLPrefix,
+ AnchorBindingMode_DIRECT));
+ Reference<XView> xView;
+ if (xViewIds.hasElements())
+ xView.set( mxConfigurationController->getResource(xViewIds[0]),UNO_QUERY);
+ if (mpBase!=nullptr)
+ {
+ auto pViewShellWrapper = comphelper::getFromUnoTunnel<ViewShellWrapper>(xView);
+ if (pViewShellWrapper != nullptr)
+ {
+ std::shared_ptr<ViewShell> pViewShell = pViewShellWrapper->GetViewShell();
+ if (pViewShell != nullptr)
+ mpBase->GetViewShellManager()->MoveToTop(*pViewShell);
+ }
+ }
+}
+
+void SAL_CALL CenterViewFocusModule::disposing (
+ const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is())
+ if (rEvent.Source == mxConfigurationController)
+ {
+ mbValid = false;
+ mxConfigurationController = nullptr;
+ mpBase = nullptr;
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/CenterViewFocusModule.hxx b/sd/source/ui/framework/module/CenterViewFocusModule.hxx
new file mode 100644
index 000000000..c6d5d348e
--- /dev/null
+++ b/sd/source/ui/framework/module/CenterViewFocusModule.hxx
@@ -0,0 +1,90 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationController;
+}
+namespace com::sun::star::frame
+{
+class XController;
+}
+
+namespace sd
+{
+class ViewShellBase;
+}
+
+namespace sd::framework
+{
+typedef comphelper::WeakComponentImplHelper<css::drawing::framework::XConfigurationChangeListener>
+ CenterViewFocusModuleInterfaceBase;
+
+/** This module waits for new views to be created for the center pane and
+ then moves the center view to the top most place on the shell stack. As
+ we are moving away from the shell stack this module may become obsolete
+ or has to be modified.
+*/
+class CenterViewFocusModule final : public CenterViewFocusModuleInterfaceBase
+{
+public:
+ explicit CenterViewFocusModule(
+ css::uno::Reference<css::frame::XController> const& rxController);
+ virtual ~CenterViewFocusModule() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange(
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override;
+
+private:
+ class ViewShellContainer;
+
+ bool mbValid;
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ ViewShellBase* mpBase;
+ /** This flag indicates whether in the last configuration change cycle a
+ new view has been created and thus the center view has to be moved
+ to the top of the shell stack.
+ */
+ bool mbNewViewCreated;
+
+ /** At the end of an update of the current configuration this method
+ handles a new view in the center pane by moving the associated view
+ shell to the top of the shell stack.
+ */
+ void HandleNewView(
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/DrawModule.cxx b/sd/source/ui/framework/module/DrawModule.cxx
new file mode 100644
index 000000000..17f4671fc
--- /dev/null
+++ b/sd/source/ui/framework/module/DrawModule.cxx
@@ -0,0 +1,41 @@
+/* -*- 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/DrawModule.hxx>
+
+#include <framework/FrameworkHelper.hxx>
+#include "CenterViewFocusModule.hxx"
+#include "SlideSorterModule.hxx"
+#include "ToolBarModule.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::framework
+{
+void DrawModule::Initialize(Reference<frame::XController> const& rxController)
+{
+ new sd::framework::CenterViewFocusModule(rxController);
+ new sd::framework::SlideSorterModule(rxController, FrameworkHelper::msLeftDrawPaneURL);
+ new ToolBarModule(rxController);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ImpressModule.cxx b/sd/source/ui/framework/module/ImpressModule.cxx
new file mode 100644
index 000000000..139b250fd
--- /dev/null
+++ b/sd/source/ui/framework/module/ImpressModule.cxx
@@ -0,0 +1,51 @@
+/* -*- 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/ImpressModule.hxx>
+
+#include <framework/FrameworkHelper.hxx>
+#include "ViewTabBarModule.hxx"
+#include "CenterViewFocusModule.hxx"
+#include "SlideSorterModule.hxx"
+#include "ToolBarModule.hxx"
+#include "ShellStackGuard.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::framework {
+
+void ImpressModule::Initialize (Reference<frame::XController> const & rxController)
+{
+ new CenterViewFocusModule(rxController);
+ new ViewTabBarModule(
+ rxController,
+ FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msViewTabBarURL,
+ FrameworkHelper::msCenterPaneURL));
+ new SlideSorterModule(
+ rxController,
+ FrameworkHelper::msLeftImpressPaneURL);
+ new ToolBarModule(rxController);
+ new ShellStackGuard(rxController);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ModuleController.cxx b/sd/source/ui/framework/module/ModuleController.cxx
new file mode 100644
index 000000000..acd12ec8a
--- /dev/null
+++ b/sd/source/ui/framework/module/ModuleController.cxx
@@ -0,0 +1,244 @@
+/* -*- 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/ModuleController.hxx>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+#include <tools/ConfigurationAccess.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::sd::tools::ConfigurationAccess;
+
+namespace sd::framework {
+
+const sal_uInt32 snFactoryPropertyCount (2);
+const sal_uInt32 snStartupPropertyCount (1);
+
+//===== ModuleController ======================================================
+Reference<XModuleController> ModuleController::CreateInstance (
+ const Reference<XComponentContext>& rxContext)
+{
+ return new ModuleController(rxContext);
+}
+
+ModuleController::ModuleController (const Reference<XComponentContext>& rxContext)
+{
+ /** Load a list of URL to service mappings from the
+ /org.openoffice.Office.Impress/MultiPaneGUI/Framework/ResourceFactories
+ configuration entry. The mappings are stored in the
+ mpResourceToFactoryMap member.
+ */
+ try
+ {
+ ConfigurationAccess aConfiguration (
+ rxContext,
+ "/org.openoffice.Office.Impress/",
+ ConfigurationAccess::READ_ONLY);
+ Reference<container::XNameAccess> xFactories (
+ aConfiguration.GetConfigurationNode("MultiPaneGUI/Framework/ResourceFactories"),
+ UNO_QUERY);
+ ::std::vector<OUString> aProperties (snFactoryPropertyCount);
+ aProperties[0] = "ServiceName";
+ aProperties[1] = "ResourceList";
+ ConfigurationAccess::ForAll(
+ xFactories,
+ aProperties,
+ [this] (OUString const&, ::std::vector<Any> const& xs) {
+ return this->ProcessFactory(xs);
+ } );
+ }
+ catch (Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+ModuleController::~ModuleController() noexcept
+{
+}
+
+void ModuleController::disposing(std::unique_lock<std::mutex>&)
+{
+ // Break the cyclic reference back to DrawController object
+ maLoadedFactories.clear();
+ maResourceToFactoryMap.clear();
+ mxController.clear();
+}
+
+void ModuleController::ProcessFactory (const ::std::vector<Any>& rValues)
+{
+ OSL_ASSERT(rValues.size() == snFactoryPropertyCount);
+
+ // Get the service name of the factory.
+ OUString sServiceName;
+ rValues[0] >>= sServiceName;
+
+ // Get all resource URLs that are created by the factory.
+ Reference<container::XNameAccess> xResources (rValues[1], UNO_QUERY);
+ ::std::vector<OUString> aURLs;
+ tools::ConfigurationAccess::FillList(
+ xResources,
+ "URL",
+ aURLs);
+
+ SAL_INFO("sd.fwk", __func__ << ": ModuleController::adding factory " << sServiceName);
+
+ // Add the resource URLs to the map.
+ for (const auto& rResource : aURLs)
+ {
+ maResourceToFactoryMap[rResource] = sServiceName;
+ SAL_INFO("sd.fwk", __func__ << ": " << rResource);
+ }
+}
+
+void ModuleController::InstantiateStartupServices()
+{
+ try
+ {
+ tools::ConfigurationAccess aConfiguration (
+ "/org.openoffice.Office.Impress/",
+ tools::ConfigurationAccess::READ_ONLY);
+ Reference<container::XNameAccess> xFactories (
+ aConfiguration.GetConfigurationNode("MultiPaneGUI/Framework/StartupServices"),
+ UNO_QUERY);
+ ::std::vector<OUString> aProperties (snStartupPropertyCount);
+ aProperties[0] = "ServiceName";
+ tools::ConfigurationAccess::ForAll(
+ xFactories,
+ aProperties,
+ [this] (OUString const&, ::std::vector<Any> const& xs) {
+ return this->ProcessStartupService(xs);
+ } );
+ }
+ catch (Exception&)
+ {
+ SAL_WARN("sd.fwk", "ERROR in ModuleController::InstantiateStartupServices");
+ }
+}
+
+void ModuleController::ProcessStartupService (const ::std::vector<Any>& rValues)
+{
+ OSL_ASSERT(rValues.size() == snStartupPropertyCount);
+
+ try
+ {
+ // Get the service name of the startup service.
+ OUString sServiceName;
+ rValues[0] >>= sServiceName;
+
+ // Instantiate service.
+ Reference<uno::XComponentContext> xContext =
+ ::comphelper::getProcessComponentContext();
+
+ // Create the startup service.
+ Sequence<Any> aArguments{ Any(mxController) };
+ // Note that when the new object will be destroyed at the end of
+ // this scope when it does not register itself anywhere.
+ // Typically it will add itself as ConfigurationChangeListener
+ // at the configuration controller.
+ xContext->getServiceManager()->createInstanceWithArgumentsAndContext(sServiceName, aArguments, xContext);
+
+ SAL_INFO("sd.fwk", __func__ << ": ModuleController::created startup service " << sServiceName);
+ }
+ catch (Exception&)
+ {
+ SAL_WARN("sd.fwk", "ERROR in ModuleController::ProcessStartupServices");
+ }
+}
+
+//----- XModuleController -----------------------------------------------------
+
+void SAL_CALL ModuleController::requestResource (const OUString& rsResourceURL)
+{
+ auto iFactory = maResourceToFactoryMap.find(rsResourceURL);
+ if (iFactory == maResourceToFactoryMap.end())
+ return;
+
+ // Check that the factory has already been loaded and not been
+ // destroyed in the meantime.
+ Reference<XInterface> xFactory;
+ auto iLoadedFactory = maLoadedFactories.find(iFactory->second);
+ if (iLoadedFactory != maLoadedFactories.end())
+ xFactory.set(iLoadedFactory->second, UNO_QUERY);
+ if ( xFactory.is())
+ return;
+
+ // Create a new instance of the factory.
+ Reference<uno::XComponentContext> xContext =
+ ::comphelper::getProcessComponentContext();
+
+ // Create the factory service.
+ Sequence<Any> aArguments{ Any(mxController) };
+ try
+ {
+ xFactory = xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ iFactory->second,
+ aArguments,
+ xContext);
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sd.fwk", "caught exception while creating factory");
+ }
+
+ // Remember that this factory has been instanced.
+ maLoadedFactories[iFactory->second] = xFactory;
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL ModuleController::initialize (const Sequence<Any>& aArguments)
+{
+ if (aArguments.hasElements())
+ {
+ try
+ {
+ // Get the XController from the first argument.
+ mxController.set(aArguments[0], UNO_QUERY_THROW);
+
+ InstantiateStartupServices();
+ }
+ catch (RuntimeException&)
+ {}
+ }
+}
+
+} // end of namespace sd::framework
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_framework_module_ModuleController_get_implementation(
+ css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ css::uno::Reference< css::uno::XInterface > xModCont ( sd::framework::ModuleController::CreateInstance(context) );
+ xModCont->acquire();
+ return xModCont.get();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/PresentationModule.cxx b/sd/source/ui/framework/module/PresentationModule.cxx
new file mode 100644
index 000000000..fb0ac0558
--- /dev/null
+++ b/sd/source/ui/framework/module/PresentationModule.cxx
@@ -0,0 +1,36 @@
+/* -*- 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/PresentationModule.hxx>
+
+#include "CenterViewFocusModule.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::framework
+{
+void PresentationModule::Initialize(Reference<frame::XController> const& rxController)
+{
+ new sd::framework::CenterViewFocusModule(rxController);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ShellStackGuard.cxx b/sd/source/ui/framework/module/ShellStackGuard.cxx
new file mode 100644
index 000000000..83d73b055
--- /dev/null
+++ b/sd/source/ui/framework/module/ShellStackGuard.cxx
@@ -0,0 +1,150 @@
+/* -*- 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 "ShellStackGuard.hxx"
+
+#include <framework/ConfigurationController.hxx>
+#include <framework/FrameworkHelper.hxx>
+
+#include <DrawController.hxx>
+#include <ViewShellBase.hxx>
+#include <sfx2/printer.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <comphelper/servicehelper.hxx>
+
+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 {
+
+//===== CenterViewFocusModule ====================================================
+
+ShellStackGuard::ShellStackGuard (Reference<frame::XController> const & rxController)
+ : mpBase(nullptr),
+ maPrinterPollingIdle("sd ShellStackGuard PrinterPollingIdle")
+{
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+
+ // Tunnel through the controller to obtain a ViewShellBase.
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(rxController);
+ if (pController != nullptr)
+ mpBase = pController->GetViewShellBase();
+ }
+
+ if (mxConfigurationController.is())
+ {
+ // Listen for update starts so that the following update can be
+ // prevented in case of a printing printer.
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateStartEvent,
+ Any());
+
+ // Prepare the printer polling.
+ maPrinterPollingIdle.SetInvokeHandler(LINK(this,ShellStackGuard,TimeoutHandler));
+ }
+}
+
+ShellStackGuard::~ShellStackGuard()
+{
+}
+
+void ShellStackGuard::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController)
+ {
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ mxConfigurationController = nullptr;
+ }
+ mpBase = nullptr;
+}
+
+void SAL_CALL ShellStackGuard::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (rEvent.Type == FrameworkHelper::msConfigurationUpdateStartEvent)
+ {
+ if (mpUpdateLock == nullptr && IsPrinting())
+ {
+ // Prevent configuration updates while the printer is printing.
+ mpUpdateLock.reset(new ConfigurationController::Lock(mxConfigurationController));
+
+ // Start polling for the printer having finished printing.
+ maPrinterPollingIdle.Start();
+ }
+ }
+}
+
+void SAL_CALL ShellStackGuard::disposing (
+ const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is())
+ if (rEvent.Source == mxConfigurationController)
+ {
+ mxConfigurationController = nullptr;
+ mpBase = nullptr;
+ }
+}
+
+IMPL_LINK(ShellStackGuard, TimeoutHandler, Timer*, pIdle, void)
+{
+#ifdef DEBUG
+ OSL_ASSERT(pIdle==&maPrinterPollingIdle);
+#else
+ (void)pIdle;
+#endif
+ if (mpUpdateLock == nullptr)
+ return;
+
+ if ( ! IsPrinting())
+ {
+ // Printing finished. Release the update lock.
+ mpUpdateLock.reset();
+ }
+ else
+ {
+ // Wait long for the printing to finish.
+ maPrinterPollingIdle.Start();
+ }
+}
+
+bool ShellStackGuard::IsPrinting() const
+{
+ if (mpBase != nullptr)
+ {
+ SfxPrinter* pPrinter = mpBase->GetPrinter();
+ if (pPrinter != nullptr
+ && pPrinter->IsPrinting())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ShellStackGuard.hxx b/sd/source/ui/framework/module/ShellStackGuard.hxx
new file mode 100644
index 000000000..72b7ed2c6
--- /dev/null
+++ b/sd/source/ui/framework/module/ShellStackGuard.hxx
@@ -0,0 +1,94 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <framework/ConfigurationController.hxx>
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+
+#include <vcl/idle.hxx>
+#include <comphelper/compbase.hxx>
+#include <memory>
+
+namespace com::sun::star::drawing::framework
+{
+class XConfigurationController;
+}
+namespace com::sun::star::frame
+{
+class XController;
+}
+
+namespace sd
+{
+class ViewShellBase;
+}
+
+namespace sd::framework
+{
+typedef comphelper::WeakComponentImplHelper<css::drawing::framework::XConfigurationChangeListener>
+ ShellStackGuardInterfaceBase;
+
+/** This module locks updates of the current configuration in situations
+ when the shell stack must not be modified.
+
+ On every start of a configuration update the ShellStackGuard checks the
+ printer. If it is printing the configuration update is locked. It then
+ polls the printer and unlocks updates when printing finishes.
+
+ When in the future there are no resources left that use shells then this
+ module can be removed.
+*/
+class ShellStackGuard : public ShellStackGuardInterfaceBase
+{
+public:
+ explicit ShellStackGuard(css::uno::Reference<css::frame::XController> const& rxController);
+ virtual ~ShellStackGuard() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange(
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override;
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ ViewShellBase* mpBase;
+ std::unique_ptr<ConfigurationController::Lock> mpUpdateLock;
+ Idle maPrinterPollingIdle;
+
+ DECL_LINK(TimeoutHandler, Timer*, void);
+
+ /** Return <TRUE/> when the printer is printing. Return <FALSE/> when
+ the printer is not printing, or there is no printer, or something
+ else went wrong.
+ */
+ bool IsPrinting() const;
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/SlideSorterModule.cxx b/sd/source/ui/framework/module/SlideSorterModule.cxx
new file mode 100644
index 000000000..dbe30f0d3
--- /dev/null
+++ b/sd/source/ui/framework/module/SlideSorterModule.cxx
@@ -0,0 +1,313 @@
+/* -*- 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 "SlideSorterModule.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+#include <framework/ConfigurationController.hxx>
+#include <com/sun/star/drawing/framework/XTabBar.hpp>
+#include <com/sun/star/drawing/framework/TabBarButton.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/frame/XController.hpp>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+#include <svtools/slidesorterbaropt.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+ const sal_Int32 ResourceActivationRequestEvent = 0;
+ const sal_Int32 ResourceDeactivationRequestEvent = 1;
+}
+
+namespace sd::framework {
+
+//===== SlideSorterModule ==================================================
+
+SlideSorterModule::SlideSorterModule (
+ const Reference<frame::XController>& rxController,
+ const OUString& rsLeftPaneURL)
+ : mxResourceId(FrameworkHelper::CreateResourceId(FrameworkHelper::msSlideSorterURL, rsLeftPaneURL)),
+ mxMainViewAnchorId(FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL)),
+ mxViewTabBarId(FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msViewTabBarURL,
+ FrameworkHelper::msCenterPaneURL)),
+ mxControllerManager(rxController,UNO_QUERY)
+{
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+
+ if (mxConfigurationController.is())
+ {
+ uno::Reference<lang::XComponent> const xComppnent(
+ mxConfigurationController, UNO_QUERY_THROW);
+ xComppnent->addEventListener(this);
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationRequestEvent,
+ Any(ResourceActivationRequestEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceDeactivationRequestEvent,
+ Any(ResourceDeactivationRequestEvent));
+ }
+ }
+ if (!mxConfigurationController.is())
+ return;
+
+ UpdateViewTabBar(nullptr);
+
+ if (SvtSlideSorterBarOptions().GetVisibleImpressView())
+ AddActiveMainView(FrameworkHelper::msImpressViewURL);
+ if (SvtSlideSorterBarOptions().GetVisibleOutlineView())
+ AddActiveMainView(FrameworkHelper::msOutlineViewURL);
+ if (SvtSlideSorterBarOptions().GetVisibleNotesView())
+ AddActiveMainView(FrameworkHelper::msNotesViewURL);
+ if (SvtSlideSorterBarOptions().GetVisibleHandoutView())
+ AddActiveMainView(FrameworkHelper::msHandoutViewURL);
+ if (SvtSlideSorterBarOptions().GetVisibleSlideSorterView())
+ AddActiveMainView(FrameworkHelper::msSlideSorterURL);
+ if (SvtSlideSorterBarOptions().GetVisibleDrawView())
+ AddActiveMainView(FrameworkHelper::msDrawViewURL);
+
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationEvent,
+ Any());
+}
+
+SlideSorterModule::~SlideSorterModule()
+{
+}
+
+void SlideSorterModule::SaveResourceState()
+{
+ SvtSlideSorterBarOptions().SetVisibleImpressView(IsResourceActive(FrameworkHelper::msImpressViewURL));
+ SvtSlideSorterBarOptions().SetVisibleOutlineView(IsResourceActive(FrameworkHelper::msOutlineViewURL));
+ SvtSlideSorterBarOptions().SetVisibleNotesView(IsResourceActive(FrameworkHelper::msNotesViewURL));
+ SvtSlideSorterBarOptions().SetVisibleHandoutView(IsResourceActive(FrameworkHelper::msHandoutViewURL));
+ SvtSlideSorterBarOptions().SetVisibleSlideSorterView(IsResourceActive(FrameworkHelper::msSlideSorterURL));
+ SvtSlideSorterBarOptions().SetVisibleDrawView(IsResourceActive(FrameworkHelper::msDrawViewURL));
+}
+
+void SAL_CALL SlideSorterModule::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (rEvent.Type == FrameworkHelper::msResourceActivationEvent)
+ {
+ if (rEvent.ResourceId->compareTo(mxViewTabBarId) == 0)
+ {
+ // Update the view tab bar because the view tab bar has just
+ // become active.
+ UpdateViewTabBar(Reference<XTabBar>(rEvent.ResourceObject,UNO_QUERY));
+ }
+ else if (rEvent.ResourceId->getResourceTypePrefix() ==
+ FrameworkHelper::msViewURLPrefix
+ && rEvent.ResourceId->isBoundTo(
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL),
+ AnchorBindingMode_DIRECT))
+ {
+ // Update the view tab bar because the view in the center pane
+ // has changed.
+ UpdateViewTabBar(nullptr);
+ }
+ return;
+ }
+
+ OSL_ASSERT(rEvent.ResourceId.is());
+ sal_Int32 nEventType = 0;
+ rEvent.UserData >>= nEventType;
+ switch (nEventType)
+ {
+ case ResourceActivationRequestEvent:
+ if (rEvent.ResourceId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL,
+ AnchorBindingMode_DIRECT))
+ {
+ // A resource directly bound to the center pane has been
+ // requested.
+ if (rEvent.ResourceId->getResourceTypePrefix() ==
+ FrameworkHelper::msViewURLPrefix)
+ {
+ // The requested resource is a view. Show or hide the
+ // resource managed by this ResourceManager accordingly.
+ HandleMainViewSwitch(
+ rEvent.ResourceId->getResourceURL(),
+ true);
+ }
+ }
+ else if (rEvent.ResourceId->compareTo(mxResourceId) == 0)
+ {
+ // The resource managed by this ResourceManager has been
+ // explicitly been requested (maybe by us). Remember this
+ // setting.
+ HandleResourceRequest(true, rEvent.Configuration);
+ }
+ break;
+
+ case ResourceDeactivationRequestEvent:
+ if (rEvent.ResourceId->compareTo(mxMainViewAnchorId) == 0)
+ {
+ HandleMainViewSwitch(
+ OUString(),
+ false);
+ }
+ else if (rEvent.ResourceId->compareTo(mxResourceId) == 0)
+ {
+ // The resource managed by this ResourceManager has been
+ // explicitly been requested to be hidden (maybe by us).
+ // Remember this setting.
+ HandleResourceRequest(false, rEvent.Configuration);
+ }
+ break;
+ }
+}
+
+void SlideSorterModule::UpdateViewTabBar (const Reference<XTabBar>& rxTabBar)
+{
+ if ( ! mxControllerManager.is())
+ return;
+
+ Reference<XTabBar> xBar (rxTabBar);
+ if ( ! xBar.is())
+ {
+ Reference<XConfigurationController> xCC (
+ mxControllerManager->getConfigurationController());
+ if (xCC.is())
+ xBar.set(xCC->getResource(mxViewTabBarId), UNO_QUERY);
+ }
+
+ if (!xBar.is())
+ return;
+
+ TabBarButton aButtonA;
+ aButtonA.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msSlideSorterURL,
+ FrameworkHelper::msCenterPaneURL);
+ aButtonA.ButtonLabel = SdResId(STR_SLIDE_SORTER_MODE);
+
+ TabBarButton aButtonB;
+ aButtonB.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msHandoutViewURL,
+ FrameworkHelper::msCenterPaneURL);
+
+ if ( ! xBar->hasTabBarButton(aButtonA))
+ xBar->addTabBarButtonAfter(aButtonA, aButtonB);
+}
+
+void SlideSorterModule::AddActiveMainView (
+ const OUString& rsMainViewURL)
+{
+ maActiveMainViewContainer.insert(rsMainViewURL);
+}
+
+bool SlideSorterModule::IsResourceActive (
+ const OUString& rsMainViewURL)
+{
+ return (maActiveMainViewContainer.find(rsMainViewURL) != maActiveMainViewContainer.end());
+}
+
+void SlideSorterModule::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController.is())
+ {
+ uno::Reference<lang::XComponent> const xComponent(mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(this);
+
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ mxConfigurationController = nullptr;
+ }
+}
+
+void SlideSorterModule::HandleMainViewSwitch (
+ const OUString& rsViewURL,
+ const bool bIsActivated)
+{
+ if (bIsActivated)
+ msCurrentMainViewURL = rsViewURL;
+ else
+ msCurrentMainViewURL.clear();
+
+ if (!mxConfigurationController.is())
+ return;
+
+ ConfigurationController::Lock aLock (mxConfigurationController);
+
+ if (maActiveMainViewContainer.find(msCurrentMainViewURL)
+ != maActiveMainViewContainer.end())
+ {
+ // Activate resource.
+ mxConfigurationController->requestResourceActivation(
+ mxResourceId->getAnchor(),
+ ResourceActivationMode_ADD);
+ mxConfigurationController->requestResourceActivation(
+ mxResourceId,
+ ResourceActivationMode_REPLACE);
+ }
+ else
+ {
+ mxConfigurationController->requestResourceDeactivation(mxResourceId);
+ }
+}
+
+void SlideSorterModule::HandleResourceRequest(
+ bool bActivation,
+ const Reference<XConfiguration>& rxConfiguration)
+{
+ Sequence<Reference<XResourceId> > aCenterViews = rxConfiguration->getResources(
+ FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL),
+ FrameworkHelper::msViewURLPrefix,
+ AnchorBindingMode_DIRECT);
+ if (aCenterViews.getLength() == 1)
+ {
+ if (bActivation)
+ {
+ maActiveMainViewContainer.insert(aCenterViews[0]->getResourceURL());
+ }
+ else
+ {
+ maActiveMainViewContainer.erase(aCenterViews[0]->getResourceURL());
+ }
+ }
+}
+
+void SAL_CALL SlideSorterModule::disposing (
+ const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is()
+ && rEvent.Source == mxConfigurationController)
+ {
+ SaveResourceState();
+ // Without the configuration controller this class can do nothing.
+ mxConfigurationController = nullptr;
+ dispose();
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/SlideSorterModule.hxx b/sd/source/ui/framework/module/SlideSorterModule.hxx
new file mode 100644
index 000000000..bec9f5c3c
--- /dev/null
+++ b/sd/source/ui/framework/module/SlideSorterModule.hxx
@@ -0,0 +1,97 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+#include <memory>
+#include <set>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XControllerManager; }
+namespace com::sun::star::drawing::framework { class XTabBar; }
+namespace com::sun::star::frame { class XController; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeListener
+ > SlideSorterModuleBase;
+
+/** This module is responsible for showing the slide sorter bar and the
+ slide sorter view in the center pane.
+
+ Manage the activation state of one resource depending on the view in the
+ center pane. The ResourceManager remembers in which configuration to
+ activate and in which to deactivate the resource. When the resource is
+ deactivated or activated manually by the user then the ResourceManager
+ detects this and remembers it for the future.
+*/
+class SlideSorterModule final
+ : public SlideSorterModuleBase
+{
+public:
+ SlideSorterModule (
+ const css::uno::Reference<css::frame::XController>& rxController,
+ const OUString& rsLeftPaneURL);
+ virtual ~SlideSorterModule() override;
+
+ /** Remember the given URL as one of a center pane view for which to
+ activate the resource managed by the called object.
+ */
+ void AddActiveMainView (const OUString& rsMainViewURL);
+ bool IsResourceActive (const OUString& rsMainViewURL);
+ void SaveResourceState();
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ css::uno::Reference<css::drawing::framework::XConfigurationController>
+ mxConfigurationController;
+ ::std::set<OUString> maActiveMainViewContainer;
+ /// The resource managed by this class.
+ css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId;
+ /// The anchor of the main view.
+ css::uno::Reference<css::drawing::framework::XResourceId> mxMainViewAnchorId;
+ OUString msCurrentMainViewURL;
+ css::uno::Reference<css::drawing::framework::XResourceId> mxViewTabBarId;
+ css::uno::Reference<css::drawing::framework::XControllerManager> mxControllerManager;
+
+ void HandleMainViewSwitch (
+ const OUString& rsViewURL,
+ const bool bIsActivated);
+ void HandleResourceRequest(
+ bool bActivation,
+ const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration);
+ void UpdateViewTabBar (
+ const css::uno::Reference<css::drawing::framework::XTabBar>& rxViewTabBar);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ToolBarModule.cxx b/sd/source/ui/framework/module/ToolBarModule.cxx
new file mode 100644
index 000000000..3cecf7b03
--- /dev/null
+++ b/sd/source/ui/framework/module/ToolBarModule.cxx
@@ -0,0 +1,191 @@
+/* -*- 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 "ToolBarModule.hxx"
+#include <ViewShellBase.hxx>
+#include <DrawController.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <framework/FrameworkHelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+ const sal_Int32 gnConfigurationUpdateStartEvent(0);
+ const sal_Int32 gnConfigurationUpdateEndEvent(1);
+ const sal_Int32 gnResourceActivationRequestEvent(2);
+ const sal_Int32 gnResourceDeactivationRequestEvent(3);
+}
+
+namespace sd::framework {
+
+//===== ToolBarModule =========================================================
+
+ToolBarModule::ToolBarModule (
+ const Reference<frame::XController>& rxController)
+ : mpBase(nullptr),
+ mbMainViewSwitchUpdatePending(false)
+{
+ // Tunnel through the controller to obtain a ViewShellBase.
+ auto pController = comphelper::getFromUnoTunnel<sd::DrawController>(rxController);
+ if (pController != nullptr)
+ mpBase = pController->GetViewShellBase();
+
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+ if (!xControllerManager.is())
+ return;
+
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (!mxConfigurationController.is())
+ return;
+
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateStartEvent,
+ Any(gnConfigurationUpdateStartEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msConfigurationUpdateEndEvent,
+ Any(gnConfigurationUpdateEndEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationRequestEvent,
+ Any(gnResourceActivationRequestEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceDeactivationRequestEvent,
+ Any(gnResourceDeactivationRequestEvent));
+}
+
+ToolBarModule::~ToolBarModule()
+{
+}
+
+void ToolBarModule::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ mxConfigurationController = nullptr;
+ }
+}
+
+void SAL_CALL ToolBarModule::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (!mxConfigurationController.is())
+ return;
+
+ sal_Int32 nEventType = 0;
+ rEvent.UserData >>= nEventType;
+ switch (nEventType)
+ {
+ case gnConfigurationUpdateStartEvent:
+ HandleUpdateStart();
+ break;
+
+ case gnConfigurationUpdateEndEvent:
+ HandleUpdateEnd();
+ break;
+
+ case gnResourceActivationRequestEvent:
+ case gnResourceDeactivationRequestEvent:
+ // Remember the request for the activation or deactivation
+ // of the center pane view. When that happens then on end
+ // of the next configuration update the set of visible tool
+ // bars will be updated.
+ if ( ! mbMainViewSwitchUpdatePending)
+ if (rEvent.ResourceId->getResourceURL().match(
+ FrameworkHelper::msViewURLPrefix)
+ && rEvent.ResourceId->isBoundToURL(
+ FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
+ {
+ mbMainViewSwitchUpdatePending = true;
+ }
+ break;
+ }
+}
+
+void ToolBarModule::HandleUpdateStart()
+{
+ // Lock the ToolBarManager and tell it to lock the ViewShellManager as
+ // well. This way the ToolBarManager can optimize the releasing of
+ // locks and arranging of updates of both tool bars and the view shell
+ // stack.
+ if (mpBase != nullptr)
+ {
+ std::shared_ptr<ToolBarManager> pToolBarManager (mpBase->GetToolBarManager());
+ mpToolBarManagerLock.reset(new ToolBarManager::UpdateLock(pToolBarManager));
+ pToolBarManager->LockViewShellManager();
+ }
+}
+
+void ToolBarModule::HandleUpdateEnd()
+{
+ if (mbMainViewSwitchUpdatePending)
+ {
+ mbMainViewSwitchUpdatePending = false;
+ // Update the set of visible tool bars and deactivate those that are
+ // no longer visible. This is done before the old view shell is
+ // destroyed in order to avoid unnecessary updates of those tool
+ // bars.
+ std::shared_ptr<ToolBarManager> pToolBarManager (mpBase->GetToolBarManager());
+ std::shared_ptr<FrameworkHelper> pFrameworkHelper (
+ FrameworkHelper::Instance(*mpBase));
+ ViewShell* pViewShell
+ = pFrameworkHelper->GetViewShell(FrameworkHelper::msCenterPaneURL).get();
+ if (pViewShell != nullptr)
+ {
+ pToolBarManager->MainViewShellChanged(*pViewShell);
+ pToolBarManager->SelectionHasChanged(
+ *pViewShell,
+ *pViewShell->GetView());
+ pToolBarManager->PreUpdate();
+ }
+ else
+ {
+ pToolBarManager->MainViewShellChanged();
+ pToolBarManager->PreUpdate();
+ }
+ }
+
+ // Releasing the update lock of the ToolBarManager will let the
+ // ToolBarManager with the help of the ViewShellManager take care of
+ // updating tool bars and view shell with the minimal amount of
+ // shell stack modifications and tool bar updates.
+ mpToolBarManagerLock.reset();
+}
+
+void SAL_CALL ToolBarModule::disposing (const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is()
+ && rEvent.Source == mxConfigurationController)
+ {
+ // Without the configuration controller this class can do nothing.
+ mxConfigurationController = nullptr;
+ dispose();
+ }
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ToolBarModule.hxx b/sd/source/ui/framework/module/ToolBarModule.hxx
new file mode 100644
index 000000000..f9189657d
--- /dev/null
+++ b/sd/source/ui/framework/module/ToolBarModule.hxx
@@ -0,0 +1,81 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <ToolBarManager.hxx>
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+#include <o3tl/deleter.hxx>
+#include <memory>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::frame { class XController; }
+
+namespace sd {
+class ViewShellBase;
+}
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeListener
+ > ToolBarModuleInterfaceBase;
+
+/** This module is responsible for locking the ToolBarManager during
+ configuration updates and for triggering ToolBarManager updates.
+*/
+class ToolBarModule final
+ : public ToolBarModuleInterfaceBase
+{
+public:
+ /** Create a new module.
+ @param rxController
+ This is the access point to the drawing framework.
+ */
+ explicit ToolBarModule (
+ const css::uno::Reference<css::frame::XController>& rxController);
+ virtual ~ToolBarModule() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ css::uno::Reference<
+ css::drawing::framework::XConfigurationController> mxConfigurationController;
+ ViewShellBase* mpBase;
+ std::unique_ptr<ToolBarManager::UpdateLock, o3tl::default_delete<ToolBarManager::UpdateLock>> mpToolBarManagerLock;
+ bool mbMainViewSwitchUpdatePending;
+
+ void HandleUpdateStart();
+ void HandleUpdateEnd();
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ViewTabBarModule.cxx b/sd/source/ui/framework/module/ViewTabBarModule.cxx
new file mode 100644
index 000000000..4f5dd4828
--- /dev/null
+++ b/sd/source/ui/framework/module/ViewTabBarModule.cxx
@@ -0,0 +1,180 @@
+/* -*- 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 "ViewTabBarModule.hxx"
+
+#include <framework/FrameworkHelper.hxx>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/drawing/framework/XTabBar.hpp>
+#include <com/sun/star/frame/XController.hpp>
+
+#include <strings.hrc>
+#include <sdresid.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+using ::sd::framework::FrameworkHelper;
+
+namespace {
+
+const sal_Int32 ResourceActivationRequestEvent = 0;
+const sal_Int32 ResourceDeactivationRequestEvent = 1;
+const sal_Int32 ResourceActivationEvent = 2;
+
+}
+
+namespace sd::framework {
+
+//===== ViewTabBarModule ==================================================
+
+ViewTabBarModule::ViewTabBarModule (
+ const Reference<frame::XController>& rxController,
+ const Reference<XResourceId>& rxViewTabBarId)
+ : mxViewTabBarId(rxViewTabBarId)
+{
+ Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY);
+
+ if (!xControllerManager.is())
+ return;
+
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (!mxConfigurationController.is())
+ return;
+
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationRequestEvent,
+ Any(ResourceActivationRequestEvent));
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceDeactivationRequestEvent,
+ Any(ResourceDeactivationRequestEvent));
+
+ UpdateViewTabBar(nullptr);
+ mxConfigurationController->addConfigurationChangeListener(
+ this,
+ FrameworkHelper::msResourceActivationEvent,
+ Any(ResourceActivationEvent));
+}
+
+ViewTabBarModule::~ViewTabBarModule()
+{
+}
+
+void ViewTabBarModule::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->removeConfigurationChangeListener(this);
+ mxConfigurationController = nullptr;
+ }
+}
+
+void SAL_CALL ViewTabBarModule::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (!mxConfigurationController.is())
+ return;
+
+ sal_Int32 nEventType = 0;
+ rEvent.UserData >>= nEventType;
+ switch (nEventType)
+ {
+ case ResourceActivationRequestEvent:
+ if (mxViewTabBarId->isBoundTo(rEvent.ResourceId, AnchorBindingMode_DIRECT))
+ {
+ mxConfigurationController->requestResourceActivation(
+ mxViewTabBarId,
+ ResourceActivationMode_ADD);
+ }
+ break;
+
+ case ResourceDeactivationRequestEvent:
+ if (mxViewTabBarId->isBoundTo(rEvent.ResourceId, AnchorBindingMode_DIRECT))
+ {
+ mxConfigurationController->requestResourceDeactivation(mxViewTabBarId);
+ }
+ break;
+
+ case ResourceActivationEvent:
+ if (rEvent.ResourceId->compareTo(mxViewTabBarId) == 0)
+ {
+ UpdateViewTabBar(Reference<XTabBar>(rEvent.ResourceObject,UNO_QUERY));
+ }
+ }
+}
+
+void SAL_CALL ViewTabBarModule::disposing (
+ const lang::EventObject& rEvent)
+{
+ if (mxConfigurationController.is()
+ && rEvent.Source == mxConfigurationController)
+ {
+ // Without the configuration controller this class can do nothing.
+ mxConfigurationController = nullptr;
+ dispose();
+ }
+}
+
+void ViewTabBarModule::UpdateViewTabBar (const Reference<XTabBar>& rxTabBar)
+{
+ if (!mxConfigurationController.is())
+ return;
+
+ Reference<XTabBar> xBar (rxTabBar);
+ if ( ! xBar.is())
+ xBar.set( mxConfigurationController->getResource(mxViewTabBarId), UNO_QUERY);
+
+ if (!xBar.is())
+ return;
+
+ TabBarButton aEmptyButton;
+
+ Reference<XResourceId> xAnchor (mxViewTabBarId->getAnchor());
+
+ TabBarButton aImpressViewButton;
+ aImpressViewButton.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msImpressViewURL,
+ xAnchor);
+ aImpressViewButton.ButtonLabel = SdResId(STR_NORMAL_MODE);
+ if ( ! xBar->hasTabBarButton(aImpressViewButton))
+ xBar->addTabBarButtonAfter(aImpressViewButton, aEmptyButton);
+
+ TabBarButton aOutlineViewButton;
+ aOutlineViewButton.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msOutlineViewURL,
+ xAnchor);
+ aOutlineViewButton.ButtonLabel = SdResId(STR_OUTLINE_MODE);
+ if ( ! xBar->hasTabBarButton(aOutlineViewButton))
+ xBar->addTabBarButtonAfter(aOutlineViewButton, aImpressViewButton);
+
+ TabBarButton aNotesViewButton;
+ aNotesViewButton.ResourceId = FrameworkHelper::CreateResourceId(
+ FrameworkHelper::msNotesViewURL,
+ xAnchor);
+ aNotesViewButton.ButtonLabel = SdResId(STR_NOTES_MODE);
+ if ( ! xBar->hasTabBarButton(aNotesViewButton))
+ xBar->addTabBarButtonAfter(aNotesViewButton, aOutlineViewButton);
+}
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/module/ViewTabBarModule.hxx b/sd/source/ui/framework/module/ViewTabBarModule.hxx
new file mode 100644
index 000000000..bfb252b8d
--- /dev/null
+++ b/sd/source/ui/framework/module/ViewTabBarModule.hxx
@@ -0,0 +1,83 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing::framework { class XConfigurationController; }
+namespace com::sun::star::drawing::framework { class XTabBar; }
+namespace com::sun::star::frame { class XController; }
+
+namespace sd::framework {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeListener
+ > ViewTabBarModuleInterfaceBase;
+
+/** This module is responsible for showing the ViewTabBar above the view in
+ the center pane.
+*/
+class ViewTabBarModule
+ : public ViewTabBarModuleInterfaceBase
+{
+public:
+ /** Create a new module that controls the view tab bar above the view
+ in the specified pane.
+ @param rxController
+ This is the access point to the drawing framework.
+ @param rxViewTabBarId
+ This ResourceId specifies which tab bar is to be managed by the
+ new module.
+ */
+ ViewTabBarModule (
+ const css::uno::Reference<css::frame::XController>& rxController,
+ const css::uno::Reference<
+ css::drawing::framework::XResourceId>& rxViewTabBarId);
+ virtual ~ViewTabBarModule() override;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XConfigurationChangeListener
+
+ virtual void SAL_CALL notifyConfigurationChange (
+ const css::drawing::framework::ConfigurationChangeEvent& rEvent) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing (
+ const css::lang::EventObject& rEvent) override;
+
+private:
+ css::uno::Reference<
+ css::drawing::framework::XConfigurationController> mxConfigurationController;
+ css::uno::Reference<css::drawing::framework::XResourceId> mxViewTabBarId;
+
+ /** This is the place where the view tab bar is filled. Only missing
+ buttons are added, so it is safe to call this method multiple
+ times.
+ */
+ void UpdateViewTabBar (
+ const css::uno::Reference<css::drawing::framework::XTabBar>& rxTabBar);
+};
+
+} // end of namespace sd::framework
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/framework/tools/FrameworkHelper.cxx b/sd/source/ui/framework/tools/FrameworkHelper.cxx
new file mode 100644
index 000000000..dceecd510
--- /dev/null
+++ b/sd/source/ui/framework/tools/FrameworkHelper.cxx
@@ -0,0 +1,952 @@
+/* -*- 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 <osl/time.h>
+
+#include <framework/FrameworkHelper.hxx>
+
+#include <framework/ConfigurationController.hxx>
+#include <framework/ResourceId.hxx>
+#include <framework/ViewShellWrapper.hxx>
+#include <ViewShellBase.hxx>
+#include <DrawViewShell.hxx>
+#include <ViewShellHint.hxx>
+#include <app.hrc>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/compbase.hxx>
+#include <svl/lstner.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <sfx2/request.hxx>
+
+#include <vcl/svapp.hxx>
+#include <osl/doublecheckedlocking.h>
+#include <osl/getglobalmutex.hxx>
+#include <tools/diagnose_ex.h>
+#include <memory>
+#include <unordered_map>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+
+namespace {
+
+//----- CallbackCaller --------------------------------------------------------
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::framework::XConfigurationChangeListener
+ > CallbackCallerInterfaceBase;
+
+/** A CallbackCaller registers as listener at an XConfigurationController
+ object and waits for the notification of one type of event. When that
+ event is received, or when the CallbackCaller detects at its
+ construction that the event will not be sent in the near future, the
+ actual callback object is called and the CallbackCaller destroys itself.
+*/
+class CallbackCaller
+ : public CallbackCallerInterfaceBase
+{
+public:
+ /** Create a new CallbackCaller object. This object controls its own
+ lifetime by acquiring a reference to itself in the constructor.
+ When it detects that the event will not be notified in the near
+ future (because the queue of pending configuration change operations
+ is empty and therefore no event will be sent int the near future, it
+ does not acquires a reference and thus initiates its destruction in
+ the constructor.)
+ @param rBase
+ This ViewShellBase object is used to determine the
+ XConfigurationController at which to register.
+ @param rsEventType
+ The event type which the callback is waiting for.
+ @param pCallback
+ The callback object which is to be notified. The caller will
+ typically release his reference to the caller so that when the
+ CallbackCaller dies (after having called the callback) the
+ callback is destroyed.
+ */
+ CallbackCaller (
+ const ::sd::ViewShellBase& rBase,
+ const OUString& rsEventType,
+ const ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter& rFilter,
+ const ::sd::framework::FrameworkHelper::Callback& rCallback);
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+ // XEventListener
+ virtual void SAL_CALL disposing (const lang::EventObject& rEvent) override;
+ // XConfigurationChangeListener
+ virtual void SAL_CALL notifyConfigurationChange (const ConfigurationChangeEvent& rEvent) override;
+
+private:
+ OUString msEventType;
+ Reference<XConfigurationController> mxConfigurationController;
+ ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter maFilter;
+ ::sd::framework::FrameworkHelper::Callback maCallback;
+};
+
+//----- LifetimeController ----------------------------------------------------
+
+typedef comphelper::WeakComponentImplHelper <
+ css::lang::XEventListener
+ > LifetimeControllerInterfaceBase;
+
+/** This class helps controlling the lifetime of the
+ FrameworkHelper. Register at a ViewShellBase object and an XController
+ object and call Dispose() at the associated FrameworkHelper object when
+ one of them and Release() when both of them are destroyed.
+*/
+class LifetimeController
+ : public LifetimeControllerInterfaceBase,
+ public SfxListener
+{
+public:
+ explicit LifetimeController (::sd::ViewShellBase& rBase);
+ virtual ~LifetimeController() override;
+
+ /** XEventListener. This method is called when the frame::XController
+ is being destroyed.
+ */
+ using WeakComponentImplHelperBase::disposing;
+ virtual void SAL_CALL disposing (const lang::EventObject& rEvent) override;
+
+ /** This method is called when the ViewShellBase is being destroyed.
+ */
+ virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override;
+
+private:
+ ::sd::ViewShellBase& mrBase;
+ bool mbListeningToViewShellBase;
+ bool mbListeningToController;
+
+ /** When one or both of the mbListeningToViewShellBase and
+ mbListeningToController members were modified then call this method
+ to either dispose or release the associated FrameworkHelper.
+ */
+ void Update();
+};
+
+} // end of anonymous namespace
+
+namespace sd::framework {
+
+namespace {
+
+ class FrameworkHelperAllPassFilter
+ {
+ public:
+ bool operator() (const css::drawing::framework::ConfigurationChangeEvent&) { return true; }
+ };
+
+ class FrameworkHelperResourceIdFilter
+ {
+ public:
+ explicit FrameworkHelperResourceIdFilter (
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId);
+ bool operator() (const css::drawing::framework::ConfigurationChangeEvent& rEvent)
+ { return mxResourceId.is() && rEvent.ResourceId.is()
+ && mxResourceId->compareTo(rEvent.ResourceId) == 0; }
+ private:
+ css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId;
+ };
+
+} // end of anonymous namespace
+
+// Pane URLS.
+
+const OUString FrameworkHelper::msCenterPaneURL( msPaneURLPrefix + "CenterPane");
+const OUString FrameworkHelper::msFullScreenPaneURL( msPaneURLPrefix + "FullScreenPane");
+const OUString FrameworkHelper::msLeftImpressPaneURL( msPaneURLPrefix + "LeftImpressPane");
+const OUString FrameworkHelper::msLeftDrawPaneURL( msPaneURLPrefix + "LeftDrawPane");
+
+// View URLs.
+
+const OUString FrameworkHelper::msImpressViewURL( msViewURLPrefix + "ImpressView");
+const OUString FrameworkHelper::msDrawViewURL( msViewURLPrefix + "GraphicView");
+const OUString FrameworkHelper::msOutlineViewURL( msViewURLPrefix + "OutlineView");
+const OUString FrameworkHelper::msNotesViewURL( msViewURLPrefix + "NotesView");
+const OUString FrameworkHelper::msHandoutViewURL( msViewURLPrefix + "HandoutView");
+const OUString FrameworkHelper::msSlideSorterURL( msViewURLPrefix + "SlideSorter");
+const OUString FrameworkHelper::msPresentationViewURL( msViewURLPrefix + "PresentationView");
+const OUString FrameworkHelper::msSidebarViewURL( msViewURLPrefix + "SidebarView");
+
+// Tool bar URLs.
+
+const OUString FrameworkHelper::msViewTabBarURL( msToolBarURLPrefix + "ViewTabBar");
+
+//----- helper ----------------------------------------------------------------
+namespace
+{
+ ::std::shared_ptr< ViewShell > lcl_getViewShell( const Reference< XResource >& i_rViewShellWrapper )
+ {
+ ::std::shared_ptr< ViewShell > pViewShell;
+ try
+ {
+ Reference<lang::XUnoTunnel> xViewTunnel( i_rViewShellWrapper, UNO_QUERY_THROW );
+ if (auto pWrapper = comphelper::getFromUnoTunnel<ViewShellWrapper>(xViewTunnel))
+ pViewShell = pWrapper->GetViewShell();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ return pViewShell;
+ }
+ Reference< XResource > lcl_getFirstViewInPane( const Reference< XConfigurationController >& i_rConfigController,
+ const Reference< XResourceId >& i_rPaneId )
+ {
+ try
+ {
+ Reference< XConfiguration > xConfiguration( i_rConfigController->getRequestedConfiguration(), UNO_SET_THROW );
+ Sequence< Reference< XResourceId > > aViewIds( xConfiguration->getResources(
+ i_rPaneId, FrameworkHelper::msViewURLPrefix, AnchorBindingMode_DIRECT ) );
+ if ( aViewIds.hasElements() )
+ return i_rConfigController->getResource( aViewIds[0] );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+ return nullptr;
+ }
+}
+
+//----- FrameworkHelper::ViewURLMap -------------------------------------------
+
+/** The ViewURLMap is used to translate between the view URLs used by the
+ drawing framework and the enums defined in the ViewShell class.
+*/
+class FrameworkHelper::ViewURLMap
+ : public std::unordered_map<
+ OUString,
+ ViewShell::ShellType>
+{
+public:
+ ViewURLMap() {}
+};
+
+//----- Framework::DisposeListener ---------------------------------------------
+
+namespace {
+ typedef comphelper::WeakComponentImplHelper <
+ css::lang::XEventListener
+ > FrameworkHelperDisposeListenerInterfaceBase;
+}
+
+class FrameworkHelper::DisposeListener
+ : public FrameworkHelperDisposeListenerInterfaceBase
+{
+public:
+ explicit DisposeListener (const ::std::shared_ptr<FrameworkHelper>& rpHelper);
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ virtual void SAL_CALL disposing (const lang::EventObject& rEventObject) override;
+
+private:
+ ::std::shared_ptr<FrameworkHelper> mpHelper;
+};
+
+//----- FrameworkHelper::Deleter ----------------------------------------------
+
+class FrameworkHelper::Deleter
+{
+public:
+ void operator()(FrameworkHelper* pObject)
+ {
+ delete pObject;
+ }
+};
+
+//----- FrameworkHelper -------------------------------------------------------
+
+FrameworkHelper::ViewURLMap FrameworkHelper::maViewURLMap;
+
+FrameworkHelper::InstanceMap FrameworkHelper::maInstanceMap;
+
+::std::shared_ptr<FrameworkHelper> FrameworkHelper::Instance (ViewShellBase& rBase)
+{
+
+ ::std::shared_ptr<FrameworkHelper> pHelper;
+
+ InstanceMap::const_iterator iHelper (maInstanceMap.find(&rBase));
+ if (iHelper == maInstanceMap.end())
+ {
+ ::osl::GetGlobalMutex aMutexFunctor;
+ ::osl::MutexGuard aGuard (aMutexFunctor());
+ if (iHelper == maInstanceMap.end())
+ {
+ pHelper = ::std::shared_ptr<FrameworkHelper>(
+ new FrameworkHelper(rBase),
+ FrameworkHelper::Deleter());
+ pHelper->Initialize();
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ maInstanceMap[&rBase] = pHelper;
+ }
+ }
+ else
+ {
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ pHelper = iHelper->second;
+ }
+
+ return pHelper;
+}
+
+void FrameworkHelper::DisposeInstance (const ViewShellBase& rBase)
+{
+ InstanceMap::iterator iHelper (maInstanceMap.find(&rBase));
+ if (iHelper != maInstanceMap.end())
+ {
+ iHelper->second->Dispose();
+ }
+}
+
+void FrameworkHelper::ReleaseInstance (const ViewShellBase& rBase)
+{
+ InstanceMap::iterator iHelper (maInstanceMap.find(&rBase));
+ if (iHelper != maInstanceMap.end())
+ maInstanceMap.erase(iHelper);
+}
+
+FrameworkHelper::FrameworkHelper (ViewShellBase& rBase)
+ : mrBase(rBase)
+{
+ Reference<XControllerManager> xControllerManager (rBase.GetController(), UNO_QUERY);
+ if (xControllerManager.is())
+ {
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ }
+
+ new LifetimeController(mrBase);
+}
+
+void FrameworkHelper::Initialize()
+{
+ mxDisposeListener = new DisposeListener(shared_from_this());
+}
+
+FrameworkHelper::~FrameworkHelper()
+{
+}
+
+void FrameworkHelper::Dispose()
+{
+ if (mxDisposeListener.is())
+ mxDisposeListener->dispose();
+ mxConfigurationController = nullptr;
+}
+
+bool FrameworkHelper::IsValid() const
+{
+ return mxConfigurationController.is();
+}
+
+::std::shared_ptr<ViewShell> FrameworkHelper::GetViewShell (const OUString& rsPaneURL)
+{
+ if ( !mxConfigurationController.is() )
+ return ::std::shared_ptr<ViewShell>();
+
+ Reference<XResourceId> xPaneId( CreateResourceId( rsPaneURL ) );
+ return lcl_getViewShell( lcl_getFirstViewInPane( mxConfigurationController, xPaneId ) );
+}
+
+::std::shared_ptr<ViewShell> FrameworkHelper::GetViewShell (const Reference<XView>& rxView)
+{
+ return lcl_getViewShell( rxView );
+}
+
+Reference<XView> FrameworkHelper::GetView (const Reference<XResourceId>& rxPaneOrViewId)
+{
+ Reference<XView> xView;
+
+ if ( ! rxPaneOrViewId.is() || ! mxConfigurationController.is())
+ return nullptr;
+
+ try
+ {
+ if (rxPaneOrViewId->getResourceURL().match(msViewURLPrefix))
+ {
+ xView.set( mxConfigurationController->getResource( rxPaneOrViewId ), UNO_QUERY );
+ }
+ else
+ {
+ xView.set( lcl_getFirstViewInPane( mxConfigurationController, rxPaneOrViewId ), UNO_QUERY );
+ }
+ }
+ catch (lang::DisposedException&)
+ {
+ Dispose();
+ }
+ catch (RuntimeException&)
+ {
+ }
+
+ return xView;
+}
+
+Reference<XResourceId> FrameworkHelper::RequestView (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL)
+{
+ Reference<XResourceId> xViewId;
+
+ try
+ {
+ if (mxConfigurationController.is())
+ {
+ mxConfigurationController->requestResourceActivation(
+ CreateResourceId(rsAnchorURL),
+ ResourceActivationMode_ADD);
+ xViewId = CreateResourceId(rsResourceURL, rsAnchorURL);
+ mxConfigurationController->requestResourceActivation(
+ xViewId,
+ ResourceActivationMode_REPLACE);
+ }
+ }
+ catch (lang::DisposedException&)
+ {
+ Dispose();
+ xViewId = nullptr;
+ }
+ catch (RuntimeException&)
+ {
+ xViewId = nullptr;
+ }
+
+ return xViewId;
+}
+
+ViewShell::ShellType FrameworkHelper::GetViewId (const OUString& rsViewURL)
+{
+ if (maViewURLMap.empty())
+ {
+ maViewURLMap[msImpressViewURL] = ViewShell::ST_IMPRESS;
+ maViewURLMap[msDrawViewURL] = ViewShell::ST_DRAW;
+ maViewURLMap[msOutlineViewURL] = ViewShell::ST_OUTLINE;
+ maViewURLMap[msNotesViewURL] = ViewShell::ST_NOTES;
+ maViewURLMap[msHandoutViewURL] = ViewShell::ST_HANDOUT;
+ maViewURLMap[msSlideSorterURL] = ViewShell::ST_SLIDE_SORTER;
+ maViewURLMap[msPresentationViewURL] = ViewShell::ST_PRESENTATION;
+ maViewURLMap[msSidebarViewURL] = ViewShell::ST_SIDEBAR;
+ }
+ ViewURLMap::const_iterator iView (maViewURLMap.find(rsViewURL));
+ if (iView != maViewURLMap.end())
+ return iView->second;
+ else
+ return ViewShell::ST_NONE;
+}
+
+OUString FrameworkHelper::GetViewURL (ViewShell::ShellType eType)
+{
+ switch (eType)
+ {
+ case ViewShell::ST_IMPRESS : return msImpressViewURL;
+ case ViewShell::ST_DRAW : return msDrawViewURL;
+ case ViewShell::ST_OUTLINE : return msOutlineViewURL;
+ case ViewShell::ST_NOTES : return msNotesViewURL;
+ case ViewShell::ST_HANDOUT : return msHandoutViewURL;
+ case ViewShell::ST_SLIDE_SORTER : return msSlideSorterURL;
+ case ViewShell::ST_PRESENTATION : return msPresentationViewURL;
+ case ViewShell::ST_SIDEBAR : return msSidebarViewURL;
+ default:
+ return OUString();
+ }
+}
+
+namespace
+{
+
+void updateEditMode(const Reference<XView> &xView, const EditMode eEMode, bool updateFrameView)
+{
+ // Ensure we have the expected edit mode
+ // The check is only for DrawViewShell as OutlineViewShell
+ // and SlideSorterViewShell have no master mode
+ const ::std::shared_ptr<ViewShell> pCenterViewShell (FrameworkHelper::GetViewShell(xView));
+ DrawViewShell* pDrawViewShell
+ = dynamic_cast<DrawViewShell*>(pCenterViewShell.get());
+ if (pDrawViewShell != nullptr)
+ {
+ pCenterViewShell->Broadcast (
+ ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START));
+
+ pDrawViewShell->ChangeEditMode(eEMode, pDrawViewShell->IsLayerModeActive());
+ if (updateFrameView)
+ pDrawViewShell->WriteFrameViewData();
+
+ pCenterViewShell->Broadcast (
+ ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END));
+ }
+}
+
+void asyncUpdateEditMode(FrameworkHelper* const pHelper, const EditMode eEMode)
+{
+ Reference<XResourceId> xPaneId (
+ FrameworkHelper::CreateResourceId(framework::FrameworkHelper::msCenterPaneURL));
+ Reference<XView> xView (pHelper->GetView(xPaneId));
+ updateEditMode(xView, eEMode, true);
+}
+
+}
+
+void FrameworkHelper::HandleModeChangeSlot (
+ sal_uInt16 nSlotId,
+ SfxRequest const & rRequest)
+{
+ if ( ! mxConfigurationController.is())
+ return;
+
+ // Parameters are allowed for NotesMasterPage and SlideMasterPage
+ // for these command, transfor xxxxMasterPage with param = false
+ // to ActivatexxxxxMode
+ if (nSlotId == SID_NOTES_MASTER_MODE || nSlotId == SID_SLIDE_MASTER_MODE)
+ {
+ const SfxItemSet* pRequestArguments = rRequest.GetArgs();
+ if (pRequestArguments)
+ {
+ const SfxBoolItem* pIsActive = rRequest.GetArg<SfxBoolItem>(nSlotId);
+ if (!pIsActive->GetValue ())
+ {
+ if (nSlotId == SID_NOTES_MASTER_MODE)
+ nSlotId = SID_NOTES_MODE;
+ else
+ nSlotId = SID_NORMAL_MULTI_PANE_GUI;
+ }
+ }
+ }
+
+ try
+ {
+ if ( ! mxConfigurationController.is())
+ throw RuntimeException();
+
+ Reference<XResourceId> xPaneId (
+ CreateResourceId(framework::FrameworkHelper::msCenterPaneURL));
+ Reference<XView> xView (GetView(xPaneId));
+
+ // Compute requested view
+ OUString sRequestedView;
+ switch (nSlotId)
+ {
+ // draw
+ case SID_DRAWINGMODE:
+ // impress
+ case SID_NORMAL_MULTI_PANE_GUI:
+ case SID_SLIDE_MASTER_MODE:
+ sRequestedView = FrameworkHelper::msImpressViewURL;
+ break;
+
+ case SID_NOTES_MODE:
+ case SID_NOTES_MASTER_MODE:
+ sRequestedView = FrameworkHelper::msNotesViewURL;
+ break;
+
+ case SID_HANDOUT_MASTER_MODE:
+ sRequestedView = FrameworkHelper::msHandoutViewURL;
+ break;
+
+ case SID_SLIDE_SORTER_MULTI_PANE_GUI:
+ case SID_SLIDE_SORTER_MODE:
+ sRequestedView = FrameworkHelper::msSlideSorterURL;
+ break;
+
+ case SID_OUTLINE_MODE:
+ sRequestedView = FrameworkHelper::msOutlineViewURL;
+ break;
+ }
+
+ // Compute requested mode
+ EditMode eEMode = EditMode::Page;
+ if (nSlotId == SID_SLIDE_MASTER_MODE
+ || nSlotId == SID_NOTES_MASTER_MODE
+ || nSlotId == SID_HANDOUT_MASTER_MODE)
+ eEMode = EditMode::MasterPage;
+ // Ensure we have the expected view shell
+ if (!(xView.is() && xView->getResourceId()->getResourceURL() == sRequestedView))
+
+ {
+ const auto xId = CreateResourceId(sRequestedView, msCenterPaneURL);
+ mxConfigurationController->requestResourceActivation(
+ xId,
+ ResourceActivationMode_REPLACE);
+ RunOnResourceActivation(xId, std::bind(&asyncUpdateEditMode, this, eEMode));
+ }
+ else
+ {
+ updateEditMode(xView, eEMode, false);
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+void FrameworkHelper::RunOnConfigurationEvent(
+ const OUString& rsEventType,
+ const Callback& rCallback)
+{
+ RunOnEvent(
+ rsEventType,
+ FrameworkHelperAllPassFilter(),
+ rCallback);
+}
+
+void FrameworkHelper::RunOnResourceActivation(
+ const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
+ const Callback& rCallback)
+{
+ if (mxConfigurationController.is()
+ && mxConfigurationController->getResource(rxResourceId).is())
+ {
+ rCallback(false);
+ }
+ else
+ {
+ RunOnEvent(
+ msResourceActivationEvent,
+ FrameworkHelperResourceIdFilter(rxResourceId),
+ rCallback);
+ }
+}
+
+namespace {
+
+/** A callback that sets a flag to a specified value when the callback is
+ called.
+*/
+class FlagUpdater
+{
+public:
+ explicit FlagUpdater (bool& rFlag) : mrFlag(rFlag) {}
+ void operator() (bool) const {mrFlag = true;}
+private:
+ bool& mrFlag;
+};
+
+}
+
+void FrameworkHelper::RequestSynchronousUpdate()
+{
+ rtl::Reference<ConfigurationController> pCC (
+ dynamic_cast<ConfigurationController*>(mxConfigurationController.get()));
+ if (pCC.is())
+ pCC->RequestSynchronousUpdate();
+}
+
+void FrameworkHelper::WaitForEvent (const OUString& rsEventType) const
+{
+ bool bConfigurationUpdateSeen (false);
+
+ RunOnEvent(
+ rsEventType,
+ FrameworkHelperAllPassFilter(),
+ FlagUpdater(bConfigurationUpdateSeen));
+
+ sal_uInt32 nStartTime = osl_getGlobalTimer();
+ while ( ! bConfigurationUpdateSeen)
+ {
+ Application::Reschedule();
+
+ if( (osl_getGlobalTimer() - nStartTime) > 60000 )
+ {
+ OSL_FAIL("FrameworkHelper::WaitForEvent(), no event for a minute? giving up!");
+ break;
+ }
+ }
+}
+
+void FrameworkHelper::WaitForUpdate() const
+{
+ WaitForEvent(msConfigurationUpdateEndEvent);
+}
+
+void FrameworkHelper::RunOnEvent(
+ const OUString& rsEventType,
+ const ConfigurationChangeEventFilter& rFilter,
+ const Callback& rCallback) const
+{
+ new CallbackCaller(mrBase,rsEventType,rFilter,rCallback);
+}
+
+void FrameworkHelper::disposing (const lang::EventObject& rEventObject)
+{
+ if (rEventObject.Source == mxConfigurationController)
+ mxConfigurationController = nullptr;
+}
+
+void FrameworkHelper::UpdateConfiguration()
+{
+ if (!mxConfigurationController.is())
+ return;
+
+ try
+ {
+ if (mxConfigurationController.is())
+ mxConfigurationController->update();
+ }
+ catch (lang::DisposedException&)
+ {
+ Dispose();
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+OUString FrameworkHelper::ResourceIdToString (const Reference<XResourceId>& rxResourceId)
+{
+ OUStringBuffer sString;
+ if (rxResourceId.is())
+ {
+ sString.append(rxResourceId->getResourceURL());
+ if (rxResourceId->hasAnchor())
+ {
+ const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs());
+ for (const auto& rAnchorURL : aAnchorURLs)
+ {
+ sString.append(" | ");
+ sString.append(rAnchorURL);
+ }
+ }
+ }
+ return sString.makeStringAndClear();
+}
+
+Reference<XResourceId> FrameworkHelper::CreateResourceId (const OUString& rsResourceURL)
+{
+ return new ::sd::framework::ResourceId(rsResourceURL);
+}
+
+Reference<XResourceId> FrameworkHelper::CreateResourceId (
+ const OUString& rsResourceURL,
+ const OUString& rsAnchorURL)
+{
+ return new ::sd::framework::ResourceId(rsResourceURL, rsAnchorURL);
+}
+
+Reference<XResourceId> FrameworkHelper::CreateResourceId (
+ const OUString& rsResourceURL,
+ const Reference<XResourceId>& rxAnchorId)
+{
+ if (rxAnchorId.is())
+ return new ::sd::framework::ResourceId(
+ rsResourceURL,
+ rxAnchorId->getResourceURL(),
+ rxAnchorId->getAnchorURLs());
+ else
+ return new ::sd::framework::ResourceId(rsResourceURL);
+}
+
+//----- FrameworkHelper::DisposeListener --------------------------------------
+
+FrameworkHelper::DisposeListener::DisposeListener (
+ const ::std::shared_ptr<FrameworkHelper>& rpHelper)
+ : mpHelper(rpHelper)
+{
+ Reference<XComponent> xComponent (mpHelper->mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+}
+
+void FrameworkHelper::DisposeListener::disposing(std::unique_lock<std::mutex>&)
+{
+ Reference<XComponent> xComponent (mpHelper->mxConfigurationController, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(this);
+
+ mpHelper.reset();
+}
+
+void SAL_CALL FrameworkHelper::DisposeListener::disposing (const lang::EventObject& rEventObject)
+{
+ if (mpHelper != nullptr)
+ mpHelper->disposing(rEventObject);
+}
+
+//===== FrameworkHelperResourceIdFilter =======================================
+
+FrameworkHelperResourceIdFilter::FrameworkHelperResourceIdFilter (
+ const Reference<XResourceId>& rxResourceId)
+ : mxResourceId(rxResourceId)
+{
+}
+
+} // end of namespace sd::framework
+
+namespace {
+
+//===== CallbackCaller ========================================================
+
+CallbackCaller::CallbackCaller (
+ const ::sd::ViewShellBase& rBase,
+ const OUString& rsEventType,
+ const ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter& rFilter,
+ const ::sd::framework::FrameworkHelper::Callback& rCallback)
+ : msEventType(rsEventType),
+ maFilter(rFilter),
+ maCallback(rCallback)
+{
+ try
+ {
+ Reference<XControllerManager> xControllerManager (rBase.GetController(), UNO_QUERY_THROW);
+ mxConfigurationController = xControllerManager->getConfigurationController();
+ if (mxConfigurationController.is())
+ {
+ if (mxConfigurationController->hasPendingRequests())
+ mxConfigurationController->addConfigurationChangeListener(this,msEventType,Any());
+ else
+ {
+ // There are no requests waiting to be processed. Therefore
+ // no event, especially not the one we are waiting for, will
+ // be sent in the near future and the callback would never be
+ // called.
+ // Call the callback now and tell him that the event it is
+ // waiting for was not sent.
+ mxConfigurationController = nullptr;
+ maCallback(false);
+ }
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+void CallbackCaller::disposing(std::unique_lock<std::mutex>&)
+{
+ try
+ {
+ if (mxConfigurationController.is())
+ {
+ Reference<XConfigurationController> xCC (mxConfigurationController);
+ mxConfigurationController = nullptr;
+ xCC->removeConfigurationChangeListener(this);
+ }
+ }
+ catch (RuntimeException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sd");
+ }
+}
+
+void SAL_CALL CallbackCaller::disposing (const lang::EventObject& rEvent)
+{
+ if (rEvent.Source == mxConfigurationController)
+ {
+ mxConfigurationController = nullptr;
+ maCallback(false);
+ }
+}
+
+void SAL_CALL CallbackCaller::notifyConfigurationChange (
+ const ConfigurationChangeEvent& rEvent)
+{
+ if (!(rEvent.Type == msEventType && maFilter(rEvent)))
+ return;
+
+ maCallback(true);
+ if (mxConfigurationController.is())
+ {
+ // Reset the reference to the configuration controller so that
+ // dispose() will not try to remove the listener a second time.
+ Reference<XConfigurationController> xCC (mxConfigurationController);
+ mxConfigurationController = nullptr;
+
+ // Removing this object from the controller may very likely lead
+ // to its destruction, so no calls after that.
+ xCC->removeConfigurationChangeListener(this);
+ }
+}
+
+//----- LifetimeController -------------------------------------------------
+
+LifetimeController::LifetimeController (::sd::ViewShellBase& rBase)
+ : mrBase(rBase),
+ mbListeningToViewShellBase(false),
+ mbListeningToController(false)
+{
+ // Register as listener at the ViewShellBase. Because that is not done
+ // via a reference we have to increase the reference count manually.
+ // This is necessary even though listening to the XController did
+ // increase the reference count because the controller may release its
+ // reference to us before the ViewShellBase is destroyed.
+ StartListening(mrBase);
+ acquire();
+ mbListeningToViewShellBase = true;
+
+ Reference<XComponent> xComponent = rBase.GetController();
+ if (xComponent.is())
+ {
+ xComponent->addEventListener(this);
+ mbListeningToController = true;
+ }
+}
+
+LifetimeController::~LifetimeController()
+{
+ OSL_ASSERT(!mbListeningToController && !mbListeningToViewShellBase);
+}
+
+void SAL_CALL LifetimeController::disposing (const lang::EventObject&)
+{
+ mbListeningToController = false;
+ Update();
+}
+
+void LifetimeController::Notify (SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ mbListeningToViewShellBase = false;
+ Update();
+ release();
+ }
+}
+
+void LifetimeController::Update()
+{
+ if (mbListeningToViewShellBase && mbListeningToController)
+ {
+ // Both the controller and the ViewShellBase are alive. Keep
+ // waiting for their destruction.
+ }
+ else if (mbListeningToViewShellBase)
+ {
+ // The controller has been destroyed but the ViewShellBase is still
+ // alive. Dispose the associated FrameworkHelper but keep it around
+ // so that no new instance is created for the dying framework.
+ ::sd::framework::FrameworkHelper::DisposeInstance(mrBase);
+ }
+ else
+ {
+ // Both the controller and the ViewShellBase have been destroyed.
+ // Remove the FrameworkHelper so that the next call its Instance()
+ // method can create a new instance.
+ ::sd::framework::FrameworkHelper::ReleaseInstance(mrBase);
+ }
+}
+
+} // end of anonymous namespace.
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */