From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- .../framework/configuration/ChangeRequestQueue.cxx | 28 + .../framework/configuration/ChangeRequestQueue.hxx | 48 ++ .../configuration/ChangeRequestQueueProcessor.cxx | 180 ++++ .../configuration/ChangeRequestQueueProcessor.hxx | 126 +++ .../ui/framework/configuration/Configuration.cxx | 311 +++++++ .../configuration/ConfigurationClassifier.cxx | 167 ++++ .../configuration/ConfigurationClassifier.hxx | 165 ++++ .../configuration/ConfigurationController.cxx | 541 ++++++++++++ .../ConfigurationControllerBroadcaster.cxx | 192 +++++ .../ConfigurationControllerBroadcaster.hxx | 138 +++ .../ConfigurationControllerResourceManager.cxx | 303 +++++++ .../ConfigurationControllerResourceManager.hxx | 141 +++ .../configuration/ConfigurationTracer.cxx | 73 ++ .../configuration/ConfigurationTracer.hxx | 58 ++ .../configuration/ConfigurationUpdater.cxx | 376 ++++++++ .../configuration/ConfigurationUpdater.hxx | 209 +++++ .../GenericConfigurationChangeRequest.cxx | 81 ++ .../GenericConfigurationChangeRequest.hxx | 98 +++ .../configuration/ResourceFactoryManager.cxx | 197 +++++ .../configuration/ResourceFactoryManager.hxx | 120 +++ .../ui/framework/configuration/ResourceId.cxx | 503 +++++++++++ .../ui/framework/configuration/UpdateRequest.cxx | 47 + .../ui/framework/configuration/UpdateRequest.hxx | 70 ++ .../ui/framework/configuration/debugtrace.hxx | 15 + .../ui/framework/factories/BasicPaneFactory.cxx | 432 ++++++++++ .../ui/framework/factories/BasicPaneFactory.hxx | 131 +++ .../ui/framework/factories/BasicToolBarFactory.cxx | 161 ++++ .../ui/framework/factories/BasicToolBarFactory.hxx | 84 ++ .../ui/framework/factories/BasicViewFactory.cxx | 518 +++++++++++ .../ui/framework/factories/BasicViewFactory.hxx | 129 +++ .../ui/framework/factories/ChildWindowPane.cxx | 219 +++++ .../ui/framework/factories/ChildWindowPane.hxx | 101 +++ .../ui/framework/factories/FrameWindowPane.cxx | 39 + .../ui/framework/factories/FrameWindowPane.hxx | 50 ++ .../ui/framework/factories/FullScreenPane.cxx | 226 +++++ .../ui/framework/factories/FullScreenPane.hxx | 85 ++ sd/source/ui/framework/factories/Pane.cxx | 178 ++++ .../ui/framework/factories/PresentationFactory.cxx | 192 +++++ .../ui/framework/factories/ViewShellWrapper.cxx | 252 ++++++ .../ui/framework/module/CenterViewFocusModule.cxx | 151 ++++ .../ui/framework/module/CenterViewFocusModule.hxx | 90 ++ sd/source/ui/framework/module/DrawModule.cxx | 41 + sd/source/ui/framework/module/ImpressModule.cxx | 51 ++ sd/source/ui/framework/module/ModuleController.cxx | 244 ++++++ .../ui/framework/module/PresentationModule.cxx | 36 + sd/source/ui/framework/module/ShellStackGuard.cxx | 150 ++++ sd/source/ui/framework/module/ShellStackGuard.hxx | 94 ++ .../ui/framework/module/SlideSorterModule.cxx | 313 +++++++ .../ui/framework/module/SlideSorterModule.hxx | 97 +++ sd/source/ui/framework/module/ToolBarModule.cxx | 191 +++++ sd/source/ui/framework/module/ToolBarModule.hxx | 81 ++ sd/source/ui/framework/module/ViewTabBarModule.cxx | 180 ++++ sd/source/ui/framework/module/ViewTabBarModule.hxx | 83 ++ sd/source/ui/framework/tools/FrameworkHelper.cxx | 952 +++++++++++++++++++++ 54 files changed, 9738 insertions(+) create mode 100644 sd/source/ui/framework/configuration/ChangeRequestQueue.cxx create mode 100644 sd/source/ui/framework/configuration/ChangeRequestQueue.hxx create mode 100644 sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.cxx create mode 100644 sd/source/ui/framework/configuration/ChangeRequestQueueProcessor.hxx create mode 100644 sd/source/ui/framework/configuration/Configuration.cxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationClassifier.cxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationClassifier.hxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationController.cxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.cxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationControllerBroadcaster.hxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.cxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationControllerResourceManager.hxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationTracer.cxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationTracer.hxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationUpdater.cxx create mode 100644 sd/source/ui/framework/configuration/ConfigurationUpdater.hxx create mode 100644 sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.cxx create mode 100644 sd/source/ui/framework/configuration/GenericConfigurationChangeRequest.hxx create mode 100644 sd/source/ui/framework/configuration/ResourceFactoryManager.cxx create mode 100644 sd/source/ui/framework/configuration/ResourceFactoryManager.hxx create mode 100644 sd/source/ui/framework/configuration/ResourceId.cxx create mode 100644 sd/source/ui/framework/configuration/UpdateRequest.cxx create mode 100644 sd/source/ui/framework/configuration/UpdateRequest.hxx create mode 100644 sd/source/ui/framework/configuration/debugtrace.hxx create mode 100644 sd/source/ui/framework/factories/BasicPaneFactory.cxx create mode 100644 sd/source/ui/framework/factories/BasicPaneFactory.hxx create mode 100644 sd/source/ui/framework/factories/BasicToolBarFactory.cxx create mode 100644 sd/source/ui/framework/factories/BasicToolBarFactory.hxx create mode 100644 sd/source/ui/framework/factories/BasicViewFactory.cxx create mode 100644 sd/source/ui/framework/factories/BasicViewFactory.hxx create mode 100644 sd/source/ui/framework/factories/ChildWindowPane.cxx create mode 100644 sd/source/ui/framework/factories/ChildWindowPane.hxx create mode 100644 sd/source/ui/framework/factories/FrameWindowPane.cxx create mode 100644 sd/source/ui/framework/factories/FrameWindowPane.hxx create mode 100644 sd/source/ui/framework/factories/FullScreenPane.cxx create mode 100644 sd/source/ui/framework/factories/FullScreenPane.hxx create mode 100644 sd/source/ui/framework/factories/Pane.cxx create mode 100644 sd/source/ui/framework/factories/PresentationFactory.cxx create mode 100644 sd/source/ui/framework/factories/ViewShellWrapper.cxx create mode 100644 sd/source/ui/framework/module/CenterViewFocusModule.cxx create mode 100644 sd/source/ui/framework/module/CenterViewFocusModule.hxx create mode 100644 sd/source/ui/framework/module/DrawModule.cxx create mode 100644 sd/source/ui/framework/module/ImpressModule.cxx create mode 100644 sd/source/ui/framework/module/ModuleController.cxx create mode 100644 sd/source/ui/framework/module/PresentationModule.cxx create mode 100644 sd/source/ui/framework/module/ShellStackGuard.cxx create mode 100644 sd/source/ui/framework/module/ShellStackGuard.hxx create mode 100644 sd/source/ui/framework/module/SlideSorterModule.cxx create mode 100644 sd/source/ui/framework/module/SlideSorterModule.hxx create mode 100644 sd/source/ui/framework/module/ToolBarModule.cxx create mode 100644 sd/source/ui/framework/module/ToolBarModule.hxx create mode 100644 sd/source/ui/framework/module/ViewTabBarModule.cxx create mode 100644 sd/source/ui/framework/module/ViewTabBarModule.hxx create mode 100644 sd/source/ui/framework/tools/FrameworkHelper.cxx (limited to 'sd/source/ui/framework') 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 + +#include + +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> +{ +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 +#include +#include +#include + +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& rxRequest) +{ + Reference 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& rpConfigurationUpdater) + : mnUserEventId(nullptr), + mpConfigurationUpdater(rpConfigurationUpdater) +{ +} + +ChangeRequestQueueProcessor::~ChangeRequestQueueProcessor() +{ + if (mnUserEventId != nullptr) + Application::RemoveUserEvent(mnUserEventId); +} + +void ChangeRequestQueueProcessor::SetConfiguration ( + const Reference& rxConfiguration) +{ + ::osl::MutexGuard aGuard (maMutex); + + mxConfiguration = rxConfiguration; + StartProcessing(); +} + +void ChangeRequestQueueProcessor::AddRequest ( + const Reference& 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 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 + +#include + +#include + +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& 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& 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& rxRequest); + + /** Returns when the queue is empty. + */ + bool IsEmpty() const; + + /** Process all events in the queue synchronously. + +

This method is typically called when the framework is shut down + to establish an empty configuration.

+ */ + void ProcessUntilEmpty(); + + /** Process the first event in queue. + */ + void ProcessOneEvent(); + + /** Remove all events from the queue. + +

This method is typically called when the framework is shut down + to avoid the processing of still pending activation requests.

+ */ + 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 mxConfiguration; + + std::shared_ptr 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 + +#include + +#include +#include +#include +#include +#include +#include + +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& rId1, const Reference& rId2) const + { + return rId1->compareTo(rId2) == -1; + } +}; + +} // end of anonymous namespace + +namespace sd::framework { + +class Configuration::ResourceContainer + : public ::std::set, XResourceIdLess> +{ +public: + ResourceContainer() {} +}; + +//===== Configuration ========================================================= + +Configuration::Configuration ( + const Reference& rxBroadcaster, + bool bBroadcastRequestEvents) + : mpResourceContainer(new ResourceContainer()), + mxBroadcaster(rxBroadcaster), + mbBroadcastRequestEvents(bBroadcastRequestEvents) +{ +} + +Configuration::Configuration ( + const Reference& rxBroadcaster, + bool bBroadcastRequestEvents, + const ResourceContainer& rResourceContainer) + : mpResourceContainer(new ResourceContainer(rResourceContainer)), + mxBroadcaster(rxBroadcaster), + mbBroadcastRequestEvents(bBroadcastRequestEvents) +{ +} + +Configuration::~Configuration() +{ +} + +void Configuration::disposing(std::unique_lock&) +{ + mpResourceContainer->clear(); + mxBroadcaster = nullptr; +} + +//----- XConfiguration -------------------------------------------------------- + +void SAL_CALL Configuration::addResource (const Reference& 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& 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 > SAL_CALL Configuration::getResources ( + const Reference& 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 > 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& rxResourceId) +{ + std::unique_lock aGuard (m_aMutex); + ThrowIfDisposed(); + + return rxResourceId.is() + && mpResourceContainer->find(rxResourceId) != mpResourceContainer->end(); +} + +//----- XCloneable ------------------------------------------------------------ + +Reference 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 Configuration::getSupportedServiceNames() +{ + return css::uno::Sequence{ + "com.sun.star.drawing.framework.Configuration"}; +} + +void Configuration::PostEvent ( + const Reference& 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(static_cast(this))); + } +} + +bool AreConfigurationsEquivalent ( + const Reference& rxConfiguration1, + const Reference& 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 > aResources1( + rxConfiguration1->getResources( + nullptr, OUString(), AnchorBindingMode_INDIRECT)); + const Sequence > 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& a, const Reference& 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 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 +#include +#include + +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& rxConfiguration1, + const Reference& 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 >& rS1, + const css::uno::Sequence >& 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 >& rS1, + const css::uno::Sequence >& 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& rA1 : rS1) + { + bool bFound = std::any_of(rS2.begin(), rS2.end(), + [&rA1](const Reference& 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& rA2 : rS2) + { + bool bFound = std::any_of(rS1.begin(), rS1.end(), + [&rA2](const Reference& rA1) { + return rA2->getResourceURL() == rA1->getResourceURL(); }); + + if ( ! bFound) + rS2minusS1.push_back(rA2); + } +} + +void ConfigurationClassifier::CopyResources ( + const ResourceIdVector& rSource, + const Reference& rxConfiguration, + ResourceIdVector& rTarget) +{ + // Copy all resources bound to the ones in aC1minusC2Unique to rC1minusC2. + for (const auto& rxResource : rSource) + { + const Sequence > 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& 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 + +#include + +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& rxConfiguration1, + const css::uno::Reference& 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 . When + they are equivalent then return . + */ + bool Partition(); + + typedef ::std::vector> + 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 mxConfiguration1; + css::uno::Reference 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>& rS1, + const css::uno::Sequence>& 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>& rS1, + const css::uno::Sequence>& 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& 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 +#include +#include +#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 +#include + +#include +#include +#include +#include + +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& rxController); + + Reference mxControllerManager; + + /** The Broadcaster class implements storing and calling of listeners. + */ + std::shared_ptr 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 mxRequestedConfiguration; + + std::shared_ptr mpResourceFactoryContainer; + + std::shared_ptr mpResourceManager; + + std::shared_ptr mpConfigurationUpdater; + + /** The queue processor owns the queue of configuration change request + objects and processes the objects. + */ + std::unique_ptr mpQueueProcessor; + + std::shared_ptr mpConfigurationUpdaterLock; + + sal_Int32 mnLockCount; +}; + +//===== ConfigurationController::Lock ========================================= + +ConfigurationController::Lock::Lock (const Reference& rxController) + : mxController(rxController) +{ + OSL_ASSERT(mxController.is()); + + if (mxController.is()) + mxController->lock(); +} + +ConfigurationController::Lock::~Lock() +{ + 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(static_cast(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& 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& 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& 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 > 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 xRequest( + new GenericConfigurationChangeRequest( + rxResourceId, + GenericConfigurationChangeRequest::Activation)); + postChangeRequest(xRequest); +} + +void SAL_CALL ConfigurationController::requestResourceDeactivation ( + const Reference& 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 > 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 xRequest( + new GenericConfigurationChangeRequest( + rxResourceId, + GenericConfigurationChangeRequest::Deactivation)); + postChangeRequest(xRequest); +} + +Reference SAL_CALL ConfigurationController::getResource ( + const Reference& 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& rxRequest) +{ + ::osl::MutexGuard aGuard (m_aMutex); + ThrowIfDisposed(); + + mpImplementation->mpQueueProcessor->AddRequest(rxRequest); +} + +Reference SAL_CALL ConfigurationController::getRequestedConfiguration() +{ + ::osl::MutexGuard aGuard (m_aMutex); + ThrowIfDisposed(); + + if (mpImplementation->mxRequestedConfiguration.is()) + return Reference( + mpImplementation->mxRequestedConfiguration->createClone(), UNO_QUERY); + else + return Reference(); +} + +Reference SAL_CALL ConfigurationController::getCurrentConfiguration() +{ + ::osl::MutexGuard aGuard (m_aMutex); + ThrowIfDisposed(); + + Reference xCurrentConfiguration( + mpImplementation->mpConfigurationUpdater->GetCurrentConfiguration()); + if (xCurrentConfiguration.is()) + return Reference(xCurrentConfiguration->createClone(), UNO_QUERY); + else + return Reference(); +} + +/** The given configuration is restored by generating the appropriate set of + activation and deactivation requests. +*/ +void SAL_CALL ConfigurationController::restoreConfiguration ( + const Reference& rxNewConfiguration) +{ + ::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 pLock ( + mpImplementation->mpConfigurationUpdater->GetLock()); + + // Get lists of resources that are to be activated or deactivated. + Reference 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& 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& rxResourceFactory) +{ + ::osl::MutexGuard aGuard (m_aMutex); + ThrowIfDisposed(); + mpImplementation->mpResourceFactoryContainer->RemoveFactoryForReference(rxResourceFactory); +} + +Reference 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& aArguments) +{ + ::osl::MutexGuard aGuard (m_aMutex); + + if (aArguments.getLength() == 1) + { + const SolarMutexGuard aSolarGuard; + + mpImplementation.reset(new Implementation( + *this, + Reference(aArguments[0], UNO_QUERY_THROW))); + } +} + +void ConfigurationController::ThrowIfDisposed () const +{ + if (mbIsDisposed) + { + throw lang::DisposedException ("ConfigurationController object has already been disposed", + const_cast(static_cast(this))); + } + + if (mpImplementation == nullptr) + { + OSL_ASSERT(mpImplementation != nullptr); + throw RuntimeException("ConfigurationController not initialized", + const_cast(static_cast(this))); + } +} + +//===== ConfigurationController::Implementation =============================== + +ConfigurationController::Implementation::Implementation ( + ConfigurationController& rController, + const Reference& rxController) + : mxControllerManager(rxController, UNO_QUERY_THROW), + mpBroadcaster(std::make_shared(&rController)), + mxRequestedConfiguration(new Configuration(&rController, true)), + mpResourceFactoryContainer(std::make_shared(mxControllerManager)), + mpResourceManager( + std::make_shared(mpResourceFactoryContainer,mpBroadcaster)), + mpConfigurationUpdater( + std::make_shared(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 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 +#include +#include +#include +#include +#include + +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& rxController) + : mxConfigurationController(rxController) +{ +} + +void ConfigurationControllerBroadcaster::AddListener( + const Reference& 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& 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& rxResourceId, + const Reference& 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 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 + +#include +#include + +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& rxResourceId, + const css::uno::Reference& 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 mxConfigurationController; + class ListenerDescriptor + { + public: + css::uno::Reference mxListener; + css::uno::Any maUserData; + }; + typedef std::vector ListenerList; + typedef std::unordered_map + 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 +#include +#include +#include +#include +#include +#include + +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& rpResourceFactoryContainer, + const std::shared_ptr& rpBroadcaster) + : maResourceMap(ResourceComparator()), + mpResourceFactoryContainer(rpResourceFactoryContainer), + mpBroadcaster(rpBroadcaster) +{ +} + +ConfigurationControllerResourceManager::~ConfigurationControllerResourceManager() +{ +} + +ConfigurationControllerResourceManager::ResourceDescriptor + ConfigurationControllerResourceManager::GetResource ( + const Reference& 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 >& rResources, + const Reference& 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& xResource : rResources) + ActivateResource(xResource, rxConfiguration); +} + +void ConfigurationControllerResourceManager::DeactivateResources ( + const ::std::vector >& rResources, + const Reference& 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 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& rxResourceId, + const Reference& 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 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; + 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& rxResourceId, + const Reference& 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& rxResource, + const Reference& 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& 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& rxId1, + const Reference& 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 + +#include + +#include +#include +#include + +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 mxResource; + css::uno::Reference 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& rpResourceFactoryContainer, + const std::shared_ptr& 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 >& rResources, + const css::uno::Reference& 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 >& rResources, + const css::uno::Reference& 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& rxResourceId); + +private: + osl::Mutex maMutex; + + class ResourceComparator + { + public: + bool operator() ( + const css::uno::Reference& rxId1, + const css::uno::Reference& rxId2) const; + }; + + typedef ::std::map< + css::uno::Reference, + ResourceDescriptor, + ResourceComparator> ResourceMap; + ResourceMap maResourceMap; + + std::shared_ptr mpResourceFactoryContainer; + + /** This broadcaster is used to notify the activation and deactivation + of resources. + */ + std::shared_ptr mpBroadcaster; + + void ActivateResource ( + const css::uno::Reference& rxResourceId, + const css::uno::Reference& rxConfiguration); + + void DeactivateResource ( + const css::uno::Reference& rxResourceId, + const css::uno::Reference& rxConfiguration); + + void AddResource ( + const css::uno::Reference& rxResource, + const css::uno::Reference& rxFactory); + + ResourceDescriptor RemoveResource ( + const css::uno::Reference& 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 +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +namespace sd::framework { + +void ConfigurationTracer::TraceConfiguration ( + const Reference& 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& rxConfiguration, + const Reference& rxResourceId, + const int nIndentation) +{ + const Sequence > aResourceList ( + rxConfiguration->getResources(rxResourceId, OUString(), AnchorBindingMode_DIRECT)); + static const OUStringLiteral sIndentation (u" "); + for (Reference const & resourceId : aResourceList) + { + OUString sLine (resourceId->getResourceURL()); + for (int i=0; i + +namespace com::sun::star::drawing::framework +{ +class XConfiguration; +} +namespace com::sun::star::drawing::framework +{ +class XResourceId; +} +namespace com::sun::star::uno +{ +template 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& rxConfiguration, + const char* pMessage); +#if OSL_DEBUG_LEVEL >= 1 + static void TraceBoundResources( + const css::uno::Reference& rxConfiguration, + const css::uno::Reference& 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 +#include + +#include +#include +#include +#include + + +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& rpBroadcaster, + const std::shared_ptr& rpResourceManager, + const Reference& rxControllerManager) + : mpBroadcaster(rpBroadcaster), + mxCurrentConfiguration(Reference(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& 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 > aResourcesToDeactivate; + CheckPureAnchors(mxRequestedConfiguration, aResourcesToDeactivate); + if (!aResourcesToDeactivate.empty()) + { + Reference 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 > aResourcesToDeactivate; + CheckPureAnchors(mxCurrentConfiguration, aResourcesToDeactivate); + if (!aResourcesToDeactivate.empty()) + mpResourceManager->DeactivateResources(aResourcesToDeactivate, mxCurrentConfiguration); + } + catch(const RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("sd"); + } +} + +void ConfigurationUpdater::CheckPureAnchors ( + const Reference& rxConfiguration, + vector >& rResourcesToDeactivate) +{ + if ( ! rxConfiguration.is()) + return; + + // Get a list of all resources in the configuration. + Sequence > 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 (aResources[nIndex]); + const Reference 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 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 ConfigurationUpdater::GetLock() +{ + return std::make_shared(*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 +#include +#include +#include + +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& rpBroadcaster, + const std::shared_ptr& rpResourceManager, + const css::uno::Reference& + 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& + rxRequestedConfiguration); + + const css::uno::Reference& + 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 GetLock(); + +private: + /** A reference to the XControllerManager is kept so that + UpdateConfiguration() has access to the other sub controllers. + */ + css::uno::Reference mxControllerManager; + + std::shared_ptr mpBroadcaster; + + /** The current configuration holds the resources that are currently + active. It is modified during an update. + */ + css::uno::Reference 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 mxRequestedConfiguration; + + /** This flag is set to 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 . + */ + bool mbUpdatePending; + + /** This flag is set to 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 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& rxConfiguration, + ::std::vector>& + 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 . + */ + 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 + +#include + +#include "GenericConfigurationChangeRequest.hxx" + +#include + +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& 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& 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 +#include +#include + +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& + 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& 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 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 +#include +#include +#include +#include +#include +#include + +#include + +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& rxManager) + : mxControllerManager(rxManager) +{ + // Create the URL transformer. + Reference xContext(::comphelper::getProcessComponentContext()); + mxURLTransformer = util::URLTransformer::create(xContext); +} + +ResourceFactoryManager::~ResourceFactoryManager() +{ + for (auto& rXInterfaceResource : maFactoryMap) + { + Reference xComponent (rXInterfaceResource.second, UNO_QUERY); + rXInterfaceResource.second = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + + Reference xComponent (mxURLTransformer, UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); +} + +void ResourceFactoryManager::AddFactory ( + const OUString& rsURL, + const Reference& 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& rxFactory) +{ + std::scoped_lock aGuard (maMutex); + + // Collect a list with all keys that map to the given factory. + ::std::vector 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 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 xFactory = FindFactory(sURLBase); + + if ( ! xFactory.is() && mxControllerManager.is()) + { + Reference 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 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 + +#include +#include +#include +#include + +#include +#include + +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& 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& 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& 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 GetFactory ( + const OUString& rsURL); + +private: + std::mutex maMutex; + typedef std::unordered_map< + OUString, + css::uno::Reference > FactoryMap; + FactoryMap maFactoryMap; + + typedef ::std::vector< + ::std::pair< + OUString, + css::uno::Reference > > + FactoryPatternList; + FactoryPatternList maFactoryPatternList; + + css::uno::Reference mxControllerManager; + css::uno::Reference 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 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 +#include +#include +#include +#include +#include +#include + +#include + +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 ResourceId::mxURLTransformerWeak; + +ResourceId::ResourceId() + : maResourceURLs(0) +{ +} + +ResourceId::ResourceId ( + std::vector&& 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& 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 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 SAL_CALL + ResourceId::getAnchor() +{ + ::rtl::Reference rResourceId (new ResourceId()); + const sal_Int32 nAnchorCount (maResourceURLs.size()-1); + if (nAnchorCount > 0) + { + rResourceId->maResourceURLs.resize(nAnchorCount); + for (sal_Int32 nIndex=0; nIndexmaResourceURLs[nIndex] = maResourceURLs[nIndex+1]; + } + return rResourceId; +} + +Sequence SAL_CALL + ResourceId::getAnchorURLs() +{ + const sal_Int32 nAnchorCount (maResourceURLs.size() - 1); + if (nAnchorCount > 0) + { + Sequence aAnchorURLs (nAnchorCount); + std::copy_n(maResourceURLs.begin() + 1, nAnchorCount, aAnchorURLs.getArray()); + return aAnchorURLs; + } + else + return Sequence(); +} + +OUString SAL_CALL + ResourceId::getResourceTypePrefix() +{ + if (!maResourceURLs.empty() ) + { + // Return the "private:resource//" 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& 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(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& rxId) const +{ + sal_Int16 nResult (0); + + const Sequence 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& 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(rxResourceId.get()); +#endif + if (pId != nullptr) + { + return IsBoundToAnchor(pId->maResourceURLs, eMode); + } + else + { + const OUString sResourceURL (rxResourceId->getResourceURL()); + const Sequence 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 SAL_CALL + ResourceId::clone() +{ + return new ResourceId(std::vector(maResourceURLs)); +} + +//----- XInitialization ------------------------------------------------------- + +void SAL_CALL ResourceId::initialize (const Sequence& aArguments) +{ + for (const auto& rArgument : aArguments) + { + OUString sResourceURL; + if (rArgument >>= sResourceURL) + maResourceURLs.push_back(sResourceURL); + else + { + Reference xAnchor; + if (rArgument >>= xAnchor) + { + if (xAnchor.is()) + { + maResourceURLs.push_back(xAnchor->getResourceURL()); + const Sequence 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 ResourceId::getSupportedServiceNames() +{ + return css::uno::Sequence{ + "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* 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 (nLocalAnchorURLCountgetLength(); + 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& rAnchorURLs, + AnchorBindingMode eMode) const +{ + const sal_uInt32 nLocalAnchorURLCount (maResourceURLs.size() - 1); + const sal_uInt32 nAnchorURLCount (rAnchorURLs.size()); + + // Check the lengths. + if (nLocalAnchorURLCount aGuard (::osl::Mutex::getGlobalMutex()); + Reference xURLTransformer (mxURLTransformerWeak); + if ( ! xURLTransformer.is()) + { + // Create the URL transformer. + Reference xContext(::comphelper::getProcessComponentContext()); + xURLTransformer.set(util::URLTransformer::create(xContext)); + mxURLTransformerWeak = xURLTransformer; + SdGlobalResourceContainer::Instance().AddResource( + Reference(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 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&) +{ + // 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 +#include +#include + +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& 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 +#include + +#include "BasicPaneFactory.hxx" + +#include "ChildWindowPane.hxx" +#include "FrameWindowPane.hxx" +#include "FullScreenPane.hxx" + +#include +#include +#include +#include +#include +#include +#include + +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 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& rxPane) const { return mxPane == rxPane; } +}; + +class BasicPaneFactory::PaneContainer + : public ::std::vector +{ +public: + PaneContainer() {} +}; + +//===== PaneFactory =========================================================== + +BasicPaneFactory::BasicPaneFactory ( + const Reference& rxContext) + : mxComponentContext(rxContext), + mpViewShellBase(nullptr), + mpPaneContainer(new PaneContainer) +{ +} + +BasicPaneFactory::~BasicPaneFactory() +{ +} + +void BasicPaneFactory::disposing(std::unique_lock&) +{ + Reference xCC (mxConfigurationControllerWeak); + if (xCC.is()) + { + xCC->removeResourceFactoryForReference(this); + xCC->removeConfigurationChangeListener(this); + mxConfigurationControllerWeak.clear(); + } + + for (const auto& rDescriptor : *mpPaneContainer) + { + if (rDescriptor.mbIsReleased) + { + Reference xComponent (rDescriptor.mxPane, UNO_QUERY); + if (xComponent.is()) + { + xComponent->removeEventListener(this); + xComponent->dispose(); + } + } + } +} + +void SAL_CALL BasicPaneFactory::initialize (const Sequence& aArguments) +{ + if (!aArguments.hasElements()) + return; + + try + { + // Get the XController from the first argument. + Reference xController (aArguments[0], UNO_QUERY_THROW); + + // Tunnel through the controller to obtain access to the ViewShellBase. + try + { + Reference xTunnel (xController, UNO_QUERY_THROW); + if (auto pController = comphelper::getFromUnoTunnel(xTunnel)) + mpViewShellBase = pController->GetViewShellBase(); + } + catch(RuntimeException&) + {} + + Reference xCM (xController, UNO_QUERY_THROW); + Reference 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 xCC (mxConfigurationControllerWeak); + if (xCC.is()) + xCC->removeResourceFactoryForReference(this); + } +} + +//===== XPaneFactory ========================================================== + +Reference SAL_CALL BasicPaneFactory::createResource ( + const Reference& rxPaneId) +{ + ThrowIfDisposed(); + + Reference 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 xComponent (xPane, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); + } + iDescriptor->mbIsReleased = false; + + + return xPane; +} + +void SAL_CALL BasicPaneFactory::releaseResource ( + const Reference& 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(rxPane.get()); + if (pChildWindowPane != nullptr) + { + iDescriptor->mbIsReleased = true; + pChildWindowPane->Hide(); + } + else + { + iDescriptor->mxPane = nullptr; + Reference 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 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 BasicPaneFactory::CreateFrameWindowPane ( + const Reference& rxPaneId) +{ + Reference xPane; + + if (mpViewShellBase != nullptr) + { + xPane = new FrameWindowPane(rxPaneId, mpViewShellBase->GetViewWindow()); + } + + return xPane; +} + +Reference BasicPaneFactory::CreateFullScreenPane ( + const Reference& rxComponentContext, + const Reference& rxPaneId) +{ + Reference xPane ( + new FullScreenPane( + rxComponentContext, + rxPaneId, + mpViewShellBase->GetViewWindow())); + + return xPane; +} + +Reference BasicPaneFactory::CreateChildWindowPane ( + const Reference& rxPaneId, + const PaneDescriptor& rDescriptor) +{ + Reference xPane; + + if (mpViewShellBase != nullptr) + { + // Create the corresponding shell and determine the id of the child window. + sal_uInt16 nChildWindowId = 0; + ::std::unique_ptr 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(static_cast(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 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 +#include +#include +#include +#include + +#include + +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& rxContext); + virtual ~BasicPaneFactory() override; + + virtual void disposing(std::unique_lock&) override; + + // XInitialization + + virtual void SAL_CALL initialize( + const css::uno::Sequence& aArguments) override; + + // XResourceFactory + + virtual css::uno::Reference + SAL_CALL createResource ( + const css::uno::Reference& rxPaneId) override; + + virtual void SAL_CALL + releaseResource ( + const css::uno::Reference& 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 mxComponentContext; + css::uno::WeakReference + mxConfigurationControllerWeak; + ViewShellBase* mpViewShellBase; + class PaneDescriptor; + class PaneContainer; + std::unique_ptr 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 + CreateFrameWindowPane ( + const css::uno::Reference& rxPaneId); + + /** Create a new pane that represents the center pane in full screen + mode. + */ + css::uno::Reference + CreateFullScreenPane ( + const css::uno::Reference& rxComponentContext, + const css::uno::Reference& rxPaneId); + + /** Create a new instance of ChildWindowPane. + @param rPaneId + The ResourceURL member defines which side pane to create. + */ + css::uno::Reference + 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 +#include +#include + +#include +#include +#include +#include + +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&) +{ + Shutdown(); +} + +void BasicToolBarFactory::Shutdown() +{ + Reference xComponent (mxConfigurationController, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(static_cast(this)); + if (mxConfigurationController.is()) + { + mxConfigurationController->removeResourceFactoryForReference(this); + mxConfigurationController = nullptr; + } +} + +//----- XInitialization ------------------------------------------------------- + +void SAL_CALL BasicToolBarFactory::initialize (const Sequence& 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(mxController, UNO_QUERY_THROW); + mxConfigurationController = xControllerManager->getConfigurationController(); + if (mxConfigurationController.is()) + { + mxConfigurationController->addResourceFactory( + FrameworkHelper::msViewTabBarURL, this); + } + + Reference xComponent (mxConfigurationController, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(static_cast(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 SAL_CALL BasicToolBarFactory::createResource ( + const Reference& rxToolBarId) +{ + ThrowIfDisposed(); + + if (rxToolBarId->getResourceURL() != FrameworkHelper::msViewTabBarURL) + throw lang::IllegalArgumentException(); + + Reference xToolBar = new ViewTabBar(rxToolBarId, mxController); + return xToolBar; +} + +void SAL_CALL BasicToolBarFactory::releaseResource ( + const Reference& rxToolBar) +{ + ThrowIfDisposed(); + + Reference 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(static_cast(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 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 +#include +#include + +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&) override; + + // ToolBarFactory + + virtual css::uno::Reference SAL_CALL + createResource ( + const css::uno::Reference< + css::drawing::framework::XResourceId>& rxToolBarId) override; + + virtual void SAL_CALL + releaseResource ( + const css::uno::Reference& + rxToolBar) override; + + // XInitialization + + virtual void SAL_CALL initialize( + const css::uno::Sequence& aArguments) override; + + // lang::XEventListener + + virtual void SAL_CALL disposing ( + const css::lang::EventObject& rEventObject) override; + +private: + css::uno::Reference mxConfigurationController; + css::uno::Reference 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +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 mxView; + std::shared_ptr mpViewShell; + Reference mxViewId; + static bool CompareView (const std::shared_ptr& rpDescriptor, + const Reference& rxView) + { return rpDescriptor->mxView.get() == rxView.get(); } +}; + +//===== BasicViewFactory::ViewShellContainer ================================== + +class BasicViewFactory::ViewShellContainer + : public ::std::vector > +{ +public: + ViewShellContainer() {}; +}; + +class BasicViewFactory::ViewCache + : public ::std::vector > +{ +public: + ViewCache() {}; +}; + +//===== ViewFactory =========================================================== + +BasicViewFactory::BasicViewFactory () + : mpViewShellContainer(new ViewShellContainer()), + mpBase(nullptr), + mpFrameView(nullptr), + mpWindow(VclPtr::Create(nullptr,WB_STDWORK)), + mpViewCache(std::make_shared()), + mxLocalPane(new Pane(Reference(), mpWindow.get())) +{ +} + +BasicViewFactory::~BasicViewFactory() +{ +} + +void BasicViewFactory::disposing(std::unique_lock&) +{ + // 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 SAL_CALL BasicViewFactory::createResource ( + const Reference& rxViewId) +{ + Reference xView; + const bool bIsCenterPane ( + rxViewId->isBoundToURL(FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)); + + // Get the pane for the anchor URL. + Reference 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 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& 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 const& pVD) { + return ViewDescriptor::CompareView(pVD, rxView); + } )); + if (iViewShell == mpViewShellContainer->end()) + { + throw lang::IllegalArgumentException(); + } + + std::shared_ptr 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()); + + SfxViewShell* pSfxViewShell = pViewShell->GetViewShell(); + if (pSfxViewShell != nullptr) + pSfxViewShell->DisconnectAllClients(); + } + + ReleaseView(*iViewShell, false); + + mpViewShellContainer->erase(iViewShell); +} + +void SAL_CALL BasicViewFactory::initialize (const Sequence& aArguments) +{ + if (!aArguments.hasElements()) + return; + + try + { + // Get the XController from the first argument. + Reference xController (aArguments[0], UNO_QUERY_THROW); + + // Tunnel through the controller to obtain a ViewShellBase. + Reference xTunnel (xController, UNO_QUERY_THROW); + ::sd::DrawController* pController = comphelper::getFromUnoTunnel(xTunnel); + if (pController != nullptr) + mpBase = pController->GetViewShellBase(); + + // Register the factory for its supported views. + Reference 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::CreateView ( + const Reference& rxViewId, + SfxViewFrame& rFrame, + vcl::Window& rWindow, + const Reference& rxPane, + FrameView* pFrameView, + const bool bIsCenterPane) +{ + auto pDescriptor = std::make_shared(); + + 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 xWindow(rxPane->getWindow()); + rtl::Reference 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 BasicViewFactory::CreateViewShell ( + const Reference& rxViewId, + SfxViewFrame& rFrame, + vcl::Window& rWindow, + FrameView* pFrameView) +{ + std::shared_ptr pViewShell; + const OUString& rsViewURL (rxViewId->getResourceURL()); + if (rsViewURL == FrameworkHelper::msImpressViewURL) + { + pViewShell = + std::make_shared( + *mpBase, + &rWindow, + PageKind::Standard, + pFrameView); + pViewShell->GetContentWindow()->set_id("impress_win"); + } + else if (rsViewURL == FrameworkHelper::msDrawViewURL) + { + pViewShell = std::shared_ptr( + new GraphicViewShell(*mpBase, &rWindow, pFrameView), + o3tl::default_delete()); + pViewShell->GetContentWindow()->set_id("draw_win"); + } + else if (rsViewURL == FrameworkHelper::msOutlineViewURL) + { + pViewShell = + std::make_shared( + &rFrame, + *mpBase, + &rWindow, + pFrameView); + pViewShell->GetContentWindow()->set_id("outline_win"); + } + else if (rsViewURL == FrameworkHelper::msNotesViewURL) + { + pViewShell = + std::make_shared( + *mpBase, + &rWindow, + PageKind::Notes, + pFrameView); + pViewShell->GetContentWindow()->set_id("notes_win"); + } + else if (rsViewURL == FrameworkHelper::msHandoutViewURL) + { + pViewShell = + std::make_shared( + *mpBase, + &rWindow, + PageKind::Handout, + pFrameView); + pViewShell->GetContentWindow()->set_id("handout_win"); + } + else if (rsViewURL == FrameworkHelper::msPresentationViewURL) + { + pViewShell = + std::make_shared( + *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& rpDescriptor, + bool bDoNotCache) +{ + bool bIsCacheable (!bDoNotCache && IsCacheable(rpDescriptor)); + + if (bIsCacheable) + { + Reference 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 (rpDescriptor->mxView, UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + } +} + +bool BasicViewFactory::IsCacheable (const std::shared_ptr& rpDescriptor) +{ + bool bIsCacheable (false); + + Reference xResource (rpDescriptor->mxView, UNO_QUERY); + if (xResource.is()) + { + static ::std::vector > s_aCacheableResources = [&]() + { + ::std::vector > 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& rxId) { return rxId->compareTo(rpDescriptor->mxViewId) == 0; }); + } + + return bIsCacheable; +} + +std::shared_ptr BasicViewFactory::GetViewFromCache ( + const Reference& rxViewId, + const Reference& rxPane) +{ + std::shared_ptr 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 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& 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 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 +#include + +#include + +#include +#include + +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&) override; + + // XViewFactory + + virtual css::uno::Reference + SAL_CALL createResource ( + const css::uno::Reference& rxViewId) override; + + virtual void SAL_CALL releaseResource ( + const css::uno::Reference& xView) override; + + // XInitialization + + virtual void SAL_CALL initialize( + const css::uno::Sequence& aArguments) override; + +private: + css::uno::Reference + mxConfigurationController; + class ViewDescriptor; + class ViewShellContainer; + std::unique_ptr mpViewShellContainer; + ViewShellBase* mpBase; + FrameView* mpFrameView; + + class ViewCache; + ScopedVclPtr mpWindow; + std::shared_ptr mpViewCache; + + css::uno::Reference mxLocalPane; + + std::shared_ptr CreateView ( + const css::uno::Reference& rxViewId, + SfxViewFrame& rFrame, + vcl::Window& rWindow, + const css::uno::Reference& rxPane, + FrameView* pFrameView, + const bool bIsCenterView); + + std::shared_ptr CreateViewShell ( + const css::uno::Reference& rxViewId, + SfxViewFrame& rFrame, + vcl::Window& rWindow, + FrameView* pFrameView); + + void ActivateCenterView ( + const std::shared_ptr& rpDescriptor); + + void ReleaseView ( + const std::shared_ptr& rpDescriptor, + bool bDoNotCache); + + bool IsCacheable ( + const std::shared_ptr& rpDescriptor); + + std::shared_ptr GetViewFromCache ( + const css::uno::Reference& rxViewId, + const css::uno::Reference& 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 +#include +#include + +#include + +#include "ChildWindowPane.hxx" + +#include +#include +#include +#include +#include + +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& rxPaneId, + sal_uInt16 nChildWindowId, + ViewShellBase& rViewShellBase, + ::std::unique_ptr && 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( + 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 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 + +#include +#include +#include +#include + +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& rxPaneId, + sal_uInt16 nChildWindowId, + ViewShellBase& rViewShellBase, + ::std::unique_ptr && 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 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 + 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 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& 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 + +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& 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 . + */ + 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 +#include +#include +#include +#include +#include +#include +#include + +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& rxComponentContext, + const Reference& rxPaneId, + const vcl::Window* pViewShellWindow) + : FrameWindowPane(rxPaneId,nullptr), + mxComponentContext(rxComponentContext) +{ + vcl::Window* pParent = nullptr; + mpWorkWindow.reset(VclPtr::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 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::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 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 SAL_CALL FullScreenPane::getAccessible() +{ + ThrowIfDisposed(); + + if (mpWorkWindow != nullptr) + return mpWorkWindow->GetAccessible(false); + else + return nullptr; +} + +void SAL_CALL FullScreenPane::setAccessible ( + const Reference& rxAccessible) +{ + ThrowIfDisposed(); + + if (mpWindow == nullptr) + return; + + Reference xInitializable (rxAccessible, UNO_QUERY); + if (xInitializable.is()) + { + vcl::Window* pParentWindow = mpWindow->GetParent(); + Reference xAccessibleParent; + if (pParentWindow != nullptr) + xAccessibleParent = pParentWindow->GetAccessible(); + Sequence 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 FullScreenPane::CreateCanvas() +{ + VclPtr pWindow = VCLUnoHelper::GetWindow(mxWindow); + if (!pWindow) + throw RuntimeException(); + + Sequence aArg{ // common: first any is VCL pointer to window (for VCL canvas) + Any(reinterpret_cast(pWindow.get())), + Any(css::awt::Rectangle()), + Any(false), + Any(mxWindow) + }; + + Reference xFactory ( + mxComponentContext->getServiceManager(), UNO_QUERY_THROW); + return Reference( + xFactory->createInstanceWithArguments("com.sun.star.rendering.SpriteCanvas.VCL", + aArg), + UNO_QUERY); +} + +void FullScreenPane::ExtractArguments ( + const Reference& 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 +#include + +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& rxComponentContext, + const css::uno::Reference& 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 SAL_CALL getAccessible() override; + + virtual void SAL_CALL setAccessible ( + const css::uno::Reference& rxAccessible) override; + + DECL_LINK(WindowEventHandler, VclWindowEvent&, void); + +protected: + virtual css::uno::Reference + CreateCanvas() override; + +private: + css::uno::Reference mxComponentContext; + VclPtr mpWorkWindow; + + static void ExtractArguments ( + const css::uno::Reference& 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 + +#include +#include +#include +#include +#include +#include + +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& 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 SAL_CALL Pane::getWindow() +{ + ThrowIfDisposed(); + + return mxWindow; +} + +Reference 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 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& rxAccessible) +{ + ThrowIfDisposed(); + vcl::Window* pWindow = GetWindow(); + if (pWindow != nullptr) + pWindow->SetAccessible(rxAccessible); +} + +//----- XResource ------------------------------------------------------------- + +Reference SAL_CALL Pane::getResourceId() +{ + ThrowIfDisposed(); + + return mxPaneId; +} + +sal_Bool SAL_CALL Pane::isAnchorOnly() +{ + return true; +} + +//----- XUnoTunnel ------------------------------------------------------------ + +const Sequence& Pane::getUnoTunnelId() +{ + static const comphelper::UnoIdInit thePaneUnoTunnelId; + return thePaneUnoTunnelId.getSeq(); +} + +sal_Int64 SAL_CALL Pane::getSomething (const Sequence& rId) +{ + return comphelper::getSomethingImpl(rId, this); +} + +Reference Pane::CreateCanvas() +{ + Reference 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(static_cast(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 + +#include +#include +#include +#include +#include +#include +#include + +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 PresentationFactoryProviderInterfaceBase; + +class PresentationFactoryProvider + : public PresentationFactoryProviderInterfaceBase +{ +public: + PresentationFactoryProvider (); + + // XInitialization + + virtual void SAL_CALL initialize( + const css::uno::Sequence& aArguments) override; +}; + +typedef comphelper::WeakComponentImplHelper 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& rxViewId) + : mxResourceId(rxViewId) {}; + + // XView + + virtual Reference SAL_CALL getResourceId() override + { return mxResourceId; }; + + virtual sal_Bool SAL_CALL isAnchorOnly() override + { return false; } + +private: + Reference mxResourceId; +}; + +} // end of anonymous namespace. + +//===== PresentationFactory =================================================== + +constexpr OUStringLiteral gsPresentationViewURL = u"private:resource/view/Presentation"; + +PresentationFactory::PresentationFactory ( + const Reference& rxController) + : mxController(rxController) +{ +} + +PresentationFactory::~PresentationFactory() +{ +} + +//----- XViewFactory ---------------------------------------------------------- + +Reference SAL_CALL PresentationFactory::createResource ( + const Reference& rxViewId) +{ + ThrowIfDisposed(); + + if (rxViewId.is()) + if ( ! rxViewId->hasAnchor() && rxViewId->getResourceURL() == gsPresentationViewURL) + return new PresentationView(rxViewId); + + return Reference(); +} + +void SAL_CALL PresentationFactory::releaseResource ( + const Reference&) +{ + ThrowIfDisposed(); + + auto pController = comphelper::getFromUnoTunnel(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(static_cast(this))); + } +} + +namespace { + +//===== PresentationFactoryProvider =========================================== + +PresentationFactoryProvider::PresentationFactoryProvider () +{ +} + +// XInitialization + +void SAL_CALL PresentationFactoryProvider::initialize( + const Sequence& aArguments) +{ + if (!aArguments.hasElements()) + return; + + try + { + // Get the XController from the first argument. + Reference xController (aArguments[0], UNO_QUERY_THROW); + Reference xCM (xController, UNO_QUERY_THROW); + Reference 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 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +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& pViewShell, + const Reference& rxViewId, + const Reference& rxWindow) + : mpViewShell(pViewShell), + mpSlideSorterViewShell( + std::dynamic_pointer_cast< ::sd::slidesorter::SlideSorterViewShell >( pViewShell )), + mxViewId(rxViewId), + mxWindow(rxWindow) +{ +} + +ViewShellWrapper::~ViewShellWrapper() +{ +} + +void ViewShellWrapper::disposing(std::unique_lock&) +{ + SAL_INFO("sd.ui", "disposing ViewShellWrapper " << this); + Reference 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::get() ) + { + uno::Reference xSupplier( this ); + return Any(xSupplier); + } + else + return ViewShellWrapperInterfaceBase::queryInterface( rType ); +} + +//----- XResource ------------------------------------------------------------- + +Reference 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 > xPages; + aSelection >>= xPages; + for (const auto& rPage : std::as_const(xPages)) + { + Reference 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 > aPages(nSelectedPageCount); + auto aPagesRange = asNonConstRange(aPages); + int nIndex = 0; + while (aSelectedPages.HasMoreElements() && nIndexGetPage()->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) +{ + bool bResult (false); + + Reference xPane (xResource, UNO_QUERY); + if (xPane.is()) + { + // Detach from the window of the old pane. + Reference xWindow (mxWindow); + if (xWindow.is()) + xWindow->removeWindowListener(this); + mxWindow = nullptr; + + if (mpViewShell != nullptr) + { + VclPtr 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& ViewShellWrapper::getUnoTunnelId() +{ + static const comphelper::UnoIdInit theViewShellWrapperUnoTunnelId; + return theViewShellWrapperUnoTunnelId.getSeq(); +} + +sal_Int64 SAL_CALL ViewShellWrapper::getSomething (const Sequence& 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 +#include + +#include +#include +#include +#include +#include +#include + +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 const & rxController) + : mbValid(false), + mpBase(nullptr), + mbNewViewCreated(false) +{ + Reference xControllerManager (rxController, UNO_QUERY); + if (xControllerManager.is()) + { + mxConfigurationController = xControllerManager->getConfigurationController(); + + // Tunnel through the controller to obtain a ViewShellBase. + auto pController = comphelper::getFromUnoTunnel(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&) +{ + 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& rxConfiguration) +{ + if (!mbNewViewCreated) + return; + + mbNewViewCreated = false; + // Make the center pane the active one. Tunnel through the + // controller to obtain a ViewShell pointer. + + Sequence > xViewIds (rxConfiguration->getResources( + FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL), + FrameworkHelper::msViewURLPrefix, + AnchorBindingMode_DIRECT)); + Reference xView; + if (xViewIds.hasElements()) + xView.set( mxConfigurationController->getResource(xViewIds[0]),UNO_QUERY); + if (mpBase!=nullptr) + { + auto pViewShellWrapper = comphelper::getFromUnoTunnel(xView); + if (pViewShellWrapper != nullptr) + { + std::shared_ptr 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 +#include + +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 + 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 const& rxController); + virtual ~CenterViewFocusModule() override; + + virtual void disposing(std::unique_lock&) 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 + 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& 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 + +#include +#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 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 + +#include +#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 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 +#include +#include +#include + +#include +#include + +#include +#include + +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 ModuleController::CreateInstance ( + const Reference& rxContext) +{ + return new ModuleController(rxContext); +} + +ModuleController::ModuleController (const Reference& 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 xFactories ( + aConfiguration.GetConfigurationNode("MultiPaneGUI/Framework/ResourceFactories"), + UNO_QUERY); + ::std::vector aProperties (snFactoryPropertyCount); + aProperties[0] = "ServiceName"; + aProperties[1] = "ResourceList"; + ConfigurationAccess::ForAll( + xFactories, + aProperties, + [this] (OUString const&, ::std::vector const& xs) { + return this->ProcessFactory(xs); + } ); + } + catch (Exception&) + { + DBG_UNHANDLED_EXCEPTION("sd"); + } +} + +ModuleController::~ModuleController() noexcept +{ +} + +void ModuleController::disposing(std::unique_lock&) +{ + // Break the cyclic reference back to DrawController object + maLoadedFactories.clear(); + maResourceToFactoryMap.clear(); + mxController.clear(); +} + +void ModuleController::ProcessFactory (const ::std::vector& 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 xResources (rValues[1], UNO_QUERY); + ::std::vector 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 xFactories ( + aConfiguration.GetConfigurationNode("MultiPaneGUI/Framework/StartupServices"), + UNO_QUERY); + ::std::vector aProperties (snStartupPropertyCount); + aProperties[0] = "ServiceName"; + tools::ConfigurationAccess::ForAll( + xFactories, + aProperties, + [this] (OUString const&, ::std::vector const& xs) { + return this->ProcessStartupService(xs); + } ); + } + catch (Exception&) + { + SAL_WARN("sd.fwk", "ERROR in ModuleController::InstantiateStartupServices"); + } +} + +void ModuleController::ProcessStartupService (const ::std::vector& rValues) +{ + OSL_ASSERT(rValues.size() == snStartupPropertyCount); + + try + { + // Get the service name of the startup service. + OUString sServiceName; + rValues[0] >>= sServiceName; + + // Instantiate service. + Reference xContext = + ::comphelper::getProcessComponentContext(); + + // Create the startup service. + Sequence 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 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 xContext = + ::comphelper::getProcessComponentContext(); + + // Create the factory service. + Sequence 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& 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 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 + +#include "CenterViewFocusModule.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd::framework +{ +void PresentationModule::Initialize(Reference 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 +#include + +#include +#include +#include +#include +#include + +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 const & rxController) + : mpBase(nullptr), + maPrinterPollingIdle("sd ShellStackGuard PrinterPollingIdle") +{ + Reference xControllerManager (rxController, UNO_QUERY); + if (xControllerManager.is()) + { + mxConfigurationController = xControllerManager->getConfigurationController(); + + // Tunnel through the controller to obtain a ViewShellBase. + auto pController = comphelper::getFromUnoTunnel(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&) +{ + 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 + +#include + +#include +#include +#include + +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 + 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 const& rxController); + virtual ~ShellStackGuard() override; + + virtual void disposing(std::unique_lock&) 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 + mxConfigurationController; + ViewShellBase* mpBase; + std::unique_ptr mpUpdateLock; + Idle maPrinterPollingIdle; + + DECL_LINK(TimeoutHandler, Timer*, void); + + /** Return when the printer is printing. Return 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +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& 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 (rxController, UNO_QUERY); + if (xControllerManager.is()) + { + mxConfigurationController = xControllerManager->getConfigurationController(); + + if (mxConfigurationController.is()) + { + uno::Reference 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(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& rxTabBar) +{ + if ( ! mxControllerManager.is()) + return; + + Reference xBar (rxTabBar); + if ( ! xBar.is()) + { + Reference 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&) +{ + if (mxConfigurationController.is()) + { + uno::Reference 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& rxConfiguration) +{ + Sequence > 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 +#include +#include +#include + +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& 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&) 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 + mxConfigurationController; + ::std::set maActiveMainViewContainer; + /// The resource managed by this class. + css::uno::Reference mxResourceId; + /// The anchor of the main view. + css::uno::Reference mxMainViewAnchorId; + OUString msCurrentMainViewURL; + css::uno::Reference mxViewTabBarId; + css::uno::Reference mxControllerManager; + + void HandleMainViewSwitch ( + const OUString& rsViewURL, + const bool bIsActivated); + void HandleResourceRequest( + bool bActivation, + const css::uno::Reference& rxConfiguration); + void UpdateViewTabBar ( + const css::uno::Reference& 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 +#include +#include +#include + +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& rxController) + : mpBase(nullptr), + mbMainViewSwitchUpdatePending(false) +{ + // Tunnel through the controller to obtain a ViewShellBase. + auto pController = comphelper::getFromUnoTunnel(rxController); + if (pController != nullptr) + mpBase = pController->GetViewShellBase(); + + Reference 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&) +{ + 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 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 pToolBarManager (mpBase->GetToolBarManager()); + std::shared_ptr 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 +#include +#include +#include +#include + +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& rxController); + virtual ~ToolBarModule() override; + + virtual void disposing(std::unique_lock&) 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> 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 +#include +#include +#include + +#include +#include + +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& rxController, + const Reference& rxViewTabBarId) + : mxViewTabBarId(rxViewTabBarId) +{ + Reference 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&) +{ + 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(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& rxTabBar) +{ + if (!mxConfigurationController.is()) + return; + + Reference xBar (rxTabBar); + if ( ! xBar.is()) + xBar.set( mxConfigurationController->getResource(mxViewTabBarId), UNO_QUERY); + + if (!xBar.is()) + return; + + TabBarButton aEmptyButton; + + Reference 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 +#include + +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& rxController, + const css::uno::Reference< + css::drawing::framework::XResourceId>& rxViewTabBarId); + virtual ~ViewTabBarModule() override; + + virtual void disposing(std::unique_lock&) 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 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& 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +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&) 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 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& rxResourceId); + bool operator() (const css::drawing::framework::ConfigurationChangeEvent& rEvent) + { return mxResourceId.is() && rEvent.ResourceId.is() + && mxResourceId->compareTo(rEvent.ResourceId) == 0; } + private: + css::uno::Reference 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 xViewTunnel( i_rViewShellWrapper, UNO_QUERY_THROW ); + if (auto pWrapper = comphelper::getFromUnoTunnel(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& rpHelper); + + virtual void disposing(std::unique_lock&) override; + + virtual void SAL_CALL disposing (const lang::EventObject& rEventObject) override; + +private: + ::std::shared_ptr 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::Instance (ViewShellBase& rBase) +{ + + ::std::shared_ptr 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( + 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 (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 FrameworkHelper::GetViewShell (const OUString& rsPaneURL) +{ + if ( !mxConfigurationController.is() ) + return ::std::shared_ptr(); + + Reference xPaneId( CreateResourceId( rsPaneURL ) ); + return lcl_getViewShell( lcl_getFirstViewInPane( mxConfigurationController, xPaneId ) ); +} + +::std::shared_ptr FrameworkHelper::GetViewShell (const Reference& rxView) +{ + return lcl_getViewShell( rxView ); +} + +Reference FrameworkHelper::GetView (const Reference& rxPaneOrViewId) +{ + Reference 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 FrameworkHelper::RequestView ( + const OUString& rsResourceURL, + const OUString& rsAnchorURL) +{ + Reference 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, 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 pCenterViewShell (FrameworkHelper::GetViewShell(xView)); + DrawViewShell* pDrawViewShell + = dynamic_cast(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 xPaneId ( + FrameworkHelper::CreateResourceId(framework::FrameworkHelper::msCenterPaneURL)); + Reference 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(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 xPaneId ( + CreateResourceId(framework::FrameworkHelper::msCenterPaneURL)); + Reference 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& 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 pCC ( + dynamic_cast(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& rxResourceId) +{ + OUStringBuffer sString; + if (rxResourceId.is()) + { + sString.append(rxResourceId->getResourceURL()); + if (rxResourceId->hasAnchor()) + { + const Sequence aAnchorURLs (rxResourceId->getAnchorURLs()); + for (const auto& rAnchorURL : aAnchorURLs) + { + sString.append(" | "); + sString.append(rAnchorURL); + } + } + } + return sString.makeStringAndClear(); +} + +Reference FrameworkHelper::CreateResourceId (const OUString& rsResourceURL) +{ + return new ::sd::framework::ResourceId(rsResourceURL); +} + +Reference FrameworkHelper::CreateResourceId ( + const OUString& rsResourceURL, + const OUString& rsAnchorURL) +{ + return new ::sd::framework::ResourceId(rsResourceURL, rsAnchorURL); +} + +Reference FrameworkHelper::CreateResourceId ( + const OUString& rsResourceURL, + const Reference& 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& rpHelper) + : mpHelper(rpHelper) +{ + Reference xComponent (mpHelper->mxConfigurationController, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); +} + +void FrameworkHelper::DisposeListener::disposing(std::unique_lock&) +{ + Reference 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& 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 (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&) +{ + try + { + if (mxConfigurationController.is()) + { + Reference 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 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 = 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: */ -- cgit v1.2.3