diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sd/source/ui/tools | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source/ui/tools')
-rw-r--r-- | sd/source/ui/tools/AsynchronousCall.cxx | 56 | ||||
-rw-r--r-- | sd/source/ui/tools/ConfigurationAccess.cxx | 173 | ||||
-rw-r--r-- | sd/source/ui/tools/EventMultiplexer.cxx | 661 | ||||
-rw-r--r-- | sd/source/ui/tools/GraphicSizeCheck.cxx | 221 | ||||
-rw-r--r-- | sd/source/ui/tools/IconCache.cxx | 106 | ||||
-rw-r--r-- | sd/source/ui/tools/IdleDetection.cxx | 103 | ||||
-rw-r--r-- | sd/source/ui/tools/PreviewRenderer.cxx | 532 | ||||
-rw-r--r-- | sd/source/ui/tools/PropertySet.cxx | 158 | ||||
-rw-r--r-- | sd/source/ui/tools/SdGlobalResourceContainer.cxx | 197 | ||||
-rw-r--r-- | sd/source/ui/tools/SlotStateListener.cxx | 153 | ||||
-rw-r--r-- | sd/source/ui/tools/TimerBasedTaskExecution.cxx | 130 |
11 files changed, 2490 insertions, 0 deletions
diff --git a/sd/source/ui/tools/AsynchronousCall.cxx b/sd/source/ui/tools/AsynchronousCall.cxx new file mode 100644 index 000000000..b7b70f63a --- /dev/null +++ b/sd/source/ui/tools/AsynchronousCall.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <tools/AsynchronousCall.hxx> + +namespace sd::tools +{ +AsynchronousCall::AsynchronousCall() + : maTimer("sd AsynchronousCall") +{ + maTimer.SetInvokeHandler(LINK(this, AsynchronousCall, TimerCallback)); +} + +AsynchronousCall::~AsynchronousCall() +{ + mpFunction.reset(); + maTimer.Stop(); +} + +void AsynchronousCall::Post(const AsynchronousFunction& rFunction) +{ + mpFunction.reset(new AsynchronousFunction(rFunction)); + maTimer.SetTimeout(10); + maTimer.Start(); +} + +IMPL_LINK(AsynchronousCall, TimerCallback, Timer*, pTimer, void) +{ + if (pTimer == &maTimer) + { + ::std::unique_ptr<AsynchronousFunction> pFunction; + pFunction.swap(mpFunction); + (*pFunction)(); + } +} + +} // end of namespace ::sd::tools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/ConfigurationAccess.cxx b/sd/source/ui/tools/ConfigurationAccess.cxx new file mode 100644 index 000000000..d359aeb18 --- /dev/null +++ b/sd/source/ui/tools/ConfigurationAccess.cxx @@ -0,0 +1,173 @@ +/* -*- 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 <tools/ConfigurationAccess.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd::tools { + +ConfigurationAccess::ConfigurationAccess ( + const Reference<XComponentContext>& rxContext, + const OUString& rsRootName, + const WriteMode eMode) +{ + Reference<lang::XMultiServiceFactory> xProvider = + configuration::theDefaultProvider::get( rxContext ); + Initialize(xProvider, rsRootName, eMode); +} + +ConfigurationAccess::ConfigurationAccess ( + const OUString& rsRootName, + const WriteMode eMode) +{ + Reference<lang::XMultiServiceFactory> xProvider = + configuration::theDefaultProvider::get( ::comphelper::getProcessComponentContext() ); + Initialize(xProvider, rsRootName, eMode); +} + +void ConfigurationAccess::Initialize ( + const Reference<lang::XMultiServiceFactory>& rxProvider, + const OUString& rsRootName, + const WriteMode eMode) +{ + try + { + Sequence<Any> aCreationArguments(comphelper::InitAnyPropertySequence( + { + {"nodepath", Any(rsRootName)}, + {"depth", Any(sal_Int32(-1))} + })); + + OUString sAccessService; + if (eMode == READ_ONLY) + sAccessService = "com.sun.star.configuration.ConfigurationAccess"; + else + sAccessService = "com.sun.star.configuration.ConfigurationUpdateAccess"; + + mxRoot = rxProvider->createInstanceWithArguments( + sAccessService, + aCreationArguments); + } + catch (Exception&) + { + DBG_UNHANDLED_EXCEPTION("sd.tools"); + } +} + +Any ConfigurationAccess::GetConfigurationNode ( + const OUString& sPathToNode) +{ + return GetConfigurationNode( + Reference<container::XHierarchicalNameAccess>(mxRoot, UNO_QUERY), + sPathToNode); +} + +Any ConfigurationAccess::GetConfigurationNode ( + const css::uno::Reference<css::container::XHierarchicalNameAccess>& rxNode, + const OUString& sPathToNode) +{ + if (sPathToNode.isEmpty()) + return Any(rxNode); + + try + { + if (rxNode.is()) + { + return rxNode->getByHierarchicalName(sPathToNode); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("sd", "caught exception while getting configuration node" << sPathToNode); + } + + return Any(); +} + +void ConfigurationAccess::CommitChanges() +{ + Reference<util::XChangesBatch> xConfiguration (mxRoot, UNO_QUERY); + if (xConfiguration.is()) + xConfiguration->commitChanges(); +} + +void ConfigurationAccess::ForAll ( + const Reference<container::XNameAccess>& rxContainer, + const ::std::vector<OUString>& rArguments, + const Functor& rFunctor) +{ + if (!rxContainer.is()) + return; + + ::std::vector<Any> aValues(rArguments.size()); + const Sequence<OUString> aKeys (rxContainer->getElementNames()); + for (const OUString& rsKey : aKeys) + { + Reference<container::XNameAccess> xSetItem (rxContainer->getByName(rsKey), UNO_QUERY); + if (xSetItem.is()) + { + // Get from the current item of the container the children + // that match the names in the rArguments list. + for (size_t nValueIndex=0; nValueIndex<aValues.size(); ++nValueIndex) + aValues[nValueIndex] = xSetItem->getByName(rArguments[nValueIndex]); + } + rFunctor(rsKey, aValues); + } +} + +void ConfigurationAccess::FillList( + const Reference<container::XNameAccess>& rxContainer, + const OUString& rsArgument, + ::std::vector<OUString>& rList) +{ + try + { + if (rxContainer.is()) + { + Sequence<OUString> aKeys (rxContainer->getElementNames()); + rList.resize(aKeys.getLength()); + for (sal_Int32 nItemIndex=0; nItemIndex<aKeys.getLength(); ++nItemIndex) + { + Reference<container::XNameAccess> xSetItem ( + rxContainer->getByName(aKeys[nItemIndex]), UNO_QUERY); + if (xSetItem.is()) + { + xSetItem->getByName(rsArgument) >>= rList[nItemIndex]; + } + } + } + } + catch (RuntimeException&) + {} +} + +} // end of namespace sd::tools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/EventMultiplexer.cxx b/sd/source/ui/tools/EventMultiplexer.cxx new file mode 100644 index 000000000..a61413ac6 --- /dev/null +++ b/sd/source/ui/tools/EventMultiplexer.cxx @@ -0,0 +1,661 @@ +/* -*- 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 <EventMultiplexer.hxx> + +#include <ViewShellBase.hxx> +#include <drawdoc.hxx> +#include <DrawController.hxx> +#include <SlideSorterViewShell.hxx> +#include <framework/FrameworkHelper.hxx> +#include <sal/log.hxx> +#include <tools/debug.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp> +#include <com/sun/star/drawing/framework/XView.hpp> +#include <comphelper/compbase.hxx> +#include <sfx2/viewfrm.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +using ::sd::framework::FrameworkHelper; + +class SdDrawDocument; + +namespace { +const sal_Int32 ResourceActivationEvent = 0; +const sal_Int32 ResourceDeactivationEvent = 1; +const sal_Int32 ConfigurationUpdateEvent = 2; +} + +namespace sd::tools { + +typedef comphelper::WeakComponentImplHelper< + css::beans::XPropertyChangeListener, + css::frame::XFrameActionListener, + css::view::XSelectionChangeListener, + css::drawing::framework::XConfigurationChangeListener + > EventMultiplexerImplementationInterfaceBase; + +class EventMultiplexer::Implementation + : public EventMultiplexerImplementationInterfaceBase, + public SfxListener +{ +public: + explicit Implementation (ViewShellBase& rBase); + virtual ~Implementation() override; + + void AddEventListener ( + const Link<EventMultiplexerEvent&,void>& rCallback); + + void RemoveEventListener ( + const Link<EventMultiplexerEvent&,void>& rCallback); + + void CallListeners (EventMultiplexerEvent& rEvent); + + //===== lang::XEventListener ============================================== + virtual void SAL_CALL + disposing (const css::lang::EventObject& rEventObject) override; + + //===== beans::XPropertySetListener ======================================= + virtual void SAL_CALL + propertyChange ( + const css::beans::PropertyChangeEvent& rEvent) override; + + //===== view::XSelectionChangeListener ==================================== + virtual void SAL_CALL + selectionChanged ( + const css::lang::EventObject& rEvent) override; + + //===== frame::XFrameActionListener ====================================== + /** For certain actions the listener connects to a new controller of the + frame it is listening to. This usually happens when the view shell + in the center pane is replaced by another view shell. + */ + virtual void SAL_CALL + frameAction (const css::frame::FrameActionEvent& rEvent) override; + + //===== drawing::framework::XConfigurationChangeListener ================== + virtual void SAL_CALL + notifyConfigurationChange ( + const css::drawing::framework::ConfigurationChangeEvent& rEvent) override; + + virtual void disposing(std::unique_lock<std::mutex>&) override; + +protected: + virtual void Notify ( + SfxBroadcaster& rBroadcaster, + const SfxHint& rHint) override; + +private: + ViewShellBase& mrBase; + typedef ::std::vector<Link<EventMultiplexerEvent&,void>> ListenerList; + ListenerList maListeners; + + /// Remember whether we are listening to the UNO controller. + bool mbListeningToController; + /// Remember whether we are listening to the frame. + bool mbListeningToFrame; + + css::uno::WeakReference<css::frame::XController> mxControllerWeak; + css::uno::WeakReference<css::frame::XFrame> mxFrameWeak; + SdDrawDocument* mpDocument; + css::uno::WeakReference<css::drawing::framework::XConfigurationController> + mxConfigurationControllerWeak; + + void ReleaseListeners(); + + void ConnectToController(); + void DisconnectFromController(); + + void CallListeners ( + EventMultiplexerEventId eId, + void const * pUserData = nullptr); + + DECL_LINK(SlideSorterSelectionChangeListener, LinkParamNone*, void); +}; + +constexpr OUStringLiteral aCurrentPagePropertyName = u"CurrentPage"; +constexpr OUStringLiteral aEditModePropertyName = u"IsMasterPageMode"; + +//===== EventMultiplexer ====================================================== + +EventMultiplexer::EventMultiplexer (ViewShellBase& rBase) + : mpImpl (new EventMultiplexer::Implementation(rBase)) +{ +} + +EventMultiplexer::~EventMultiplexer() +{ + try + { + mpImpl->dispose(); + } + catch (const RuntimeException&) + { + } + catch (const Exception&) + { + } +} + +void EventMultiplexer::AddEventListener ( + const Link<EventMultiplexerEvent&,void>& rCallback) +{ + mpImpl->AddEventListener(rCallback); +} + +void EventMultiplexer::RemoveEventListener ( + const Link<EventMultiplexerEvent&,void>& rCallback) +{ + mpImpl->RemoveEventListener(rCallback); +} + +void EventMultiplexer::MultiplexEvent( + EventMultiplexerEventId eEventId, + void const * pUserData ) +{ + EventMultiplexerEvent aEvent(eEventId, pUserData); + mpImpl->CallListeners(aEvent); +} + +//===== EventMultiplexer::Implementation ====================================== + +EventMultiplexer::Implementation::Implementation (ViewShellBase& rBase) + : mrBase (rBase), + mbListeningToController (false), + mbListeningToFrame (false), + mxControllerWeak(nullptr), + mxFrameWeak(nullptr), + mpDocument(nullptr) +{ + // Connect to the frame to listen for controllers being exchanged. + // Listen to changes of certain properties. + Reference<frame::XFrame> xFrame = + mrBase.GetFrame()->GetFrame().GetFrameInterface(); + mxFrameWeak = xFrame; + if (xFrame.is()) + { + xFrame->addFrameActionListener ( Reference<frame::XFrameActionListener>(this) ); + mbListeningToFrame = true; + } + + // Connect to the current controller. + ConnectToController (); + + // Listen for document changes. + mpDocument = mrBase.GetDocument(); + if (mpDocument != nullptr) + StartListening (*mpDocument); + + // Listen for configuration changes. + Reference<XControllerManager> xControllerManager ( + Reference<XWeak>(&mrBase.GetDrawController()), UNO_QUERY); + if (!xControllerManager.is()) + return; + + Reference<XConfigurationController> xConfigurationController ( + xControllerManager->getConfigurationController()); + mxConfigurationControllerWeak = xConfigurationController; + if (!xConfigurationController.is()) + return; + + Reference<XComponent> xComponent (xConfigurationController, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(static_cast<beans::XPropertyChangeListener*>(this)); + + xConfigurationController->addConfigurationChangeListener( + this, + FrameworkHelper::msResourceActivationEvent, + Any(ResourceActivationEvent)); + xConfigurationController->addConfigurationChangeListener( + this, + FrameworkHelper::msResourceDeactivationEvent, + Any(ResourceDeactivationEvent)); + xConfigurationController->addConfigurationChangeListener( + this, + FrameworkHelper::msConfigurationUpdateEndEvent, + Any(ConfigurationUpdateEvent)); +} + +EventMultiplexer::Implementation::~Implementation() +{ + DBG_ASSERT( !mbListeningToFrame, + "sd::EventMultiplexer::Implementation::~Implementation(), disposing was not called!" ); +} + +void EventMultiplexer::Implementation::ReleaseListeners() +{ + if (mbListeningToFrame) + { + mbListeningToFrame = false; + + // Stop listening for changes of certain properties. + Reference<frame::XFrame> xFrame (mxFrameWeak); + if (xFrame.is()) + { + xFrame->removeFrameActionListener ( + Reference<frame::XFrameActionListener>(this) ); + } + } + + DisconnectFromController (); + + if (mpDocument != nullptr) + { + EndListening (*mpDocument); + mpDocument = nullptr; + } + + // Stop listening for configuration changes. + Reference<XConfigurationController> xConfigurationController (mxConfigurationControllerWeak); + if (xConfigurationController.is()) + { + Reference<XComponent> xComponent (xConfigurationController, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(static_cast<beans::XPropertyChangeListener*>(this)); + + xConfigurationController->removeConfigurationChangeListener(this); + } +} + +void EventMultiplexer::Implementation::AddEventListener ( + const Link<EventMultiplexerEvent&,void>& rCallback) +{ + for (auto const & i : maListeners) + if (i == rCallback) + return; + maListeners.push_back(rCallback); +} + +void EventMultiplexer::Implementation::RemoveEventListener ( + const Link<EventMultiplexerEvent&,void>& rCallback) +{ + auto iListener = std::find(maListeners.begin(), maListeners.end(), rCallback); + if (iListener != maListeners.end()) + maListeners.erase(iListener); +} + +void EventMultiplexer::Implementation::ConnectToController() +{ + // Just in case that we missed some event we now disconnect from the old + // controller. + DisconnectFromController (); + + // Register at the controller of the main view shell. + + // We have to store a (weak) reference to the controller so that we can + // unregister without having to ask the mrBase member (which at that + // time may be destroyed.) + Reference<frame::XController> xController = mrBase.GetController(); + mxControllerWeak = mrBase.GetController(); + + try + { + // Listen for disposing events. + if (xController.is()) + { + xController->addEventListener ( + Reference<lang::XEventListener>( + static_cast<XWeak*>(this), UNO_QUERY)); + mbListeningToController = true; + } + + // Listen to changes of certain properties. + Reference<beans::XPropertySet> xSet (xController, UNO_QUERY); + if (xSet.is()) + { + try + { + xSet->addPropertyChangeListener(aCurrentPagePropertyName, this); + } + catch (const beans::UnknownPropertyException&) + { + SAL_WARN("sd", "EventMultiplexer::ConnectToController: CurrentPage unknown"); + } + + try + { + xSet->addPropertyChangeListener(aEditModePropertyName, this); + } + catch (const beans::UnknownPropertyException&) + { + SAL_WARN("sd", "EventMultiplexer::ConnectToController: IsMasterPageMode unknown"); + } + } + + // Listen for selection change events. + Reference<view::XSelectionSupplier> xSelection (xController, UNO_QUERY); + if (xSelection.is()) + { + xSelection->addSelectionChangeListener(this); + } + } + catch (const lang::DisposedException&) + { + mbListeningToController = false; + } +} + +void EventMultiplexer::Implementation::DisconnectFromController() +{ + if (!mbListeningToController) + return; + + mbListeningToController = false; + + Reference<frame::XController> xController = mxControllerWeak; + + Reference<beans::XPropertySet> xSet (xController, UNO_QUERY); + // Remove the property listener. + if (xSet.is()) + { + try + { + xSet->removePropertyChangeListener(aCurrentPagePropertyName, this); + } + catch (const beans::UnknownPropertyException&) + { + SAL_WARN("sd", "DisconnectFromController: CurrentPage unknown"); + } + + try + { + xSet->removePropertyChangeListener(aEditModePropertyName, this); + } + catch (const beans::UnknownPropertyException&) + { + SAL_WARN("sd", "DisconnectFromController: IsMasterPageMode unknown"); + } + } + + // Remove selection change listener. + Reference<view::XSelectionSupplier> xSelection (xController, UNO_QUERY); + if (xSelection.is()) + { + xSelection->removeSelectionChangeListener(this); + } + + // Remove listener for disposing events. + if (xController.is()) + { + xController->removeEventListener ( + Reference<lang::XEventListener>(static_cast<XWeak*>(this), UNO_QUERY)); + } +} + +//===== lang::XEventListener ================================================ + +void SAL_CALL EventMultiplexer::Implementation::disposing ( + const lang::EventObject& rEventObject) +{ + if (mbListeningToController) + { + Reference<frame::XController> xController (mxControllerWeak); + if (rEventObject.Source == xController) + { + mbListeningToController = false; + } + } + + Reference<XConfigurationController> xConfigurationController ( + mxConfigurationControllerWeak); + if (xConfigurationController.is() + && rEventObject.Source == xConfigurationController) + { + mxConfigurationControllerWeak.clear(); + } +} + +//===== beans::XPropertySetListener ========================================= + +void SAL_CALL EventMultiplexer::Implementation::propertyChange ( + const beans::PropertyChangeEvent& rEvent) +{ + if (m_bDisposed) + { + throw lang::DisposedException ( + "SlideSorterController object has already been disposed", + static_cast<uno::XWeak*>(this)); + } + + if ( rEvent.PropertyName == aCurrentPagePropertyName ) + { + CallListeners(EventMultiplexerEventId::CurrentPageChanged); + } + else if ( rEvent.PropertyName == aEditModePropertyName ) + { + bool bIsMasterPageMode (false); + rEvent.NewValue >>= bIsMasterPageMode; + if (bIsMasterPageMode) + CallListeners(EventMultiplexerEventId::EditModeMaster); + else + CallListeners(EventMultiplexerEventId::EditModeNormal); + } +} + +//===== frame::XFrameActionListener ========================================== + +void SAL_CALL EventMultiplexer::Implementation::frameAction ( + const frame::FrameActionEvent& rEvent) +{ + Reference<frame::XFrame> xFrame (mxFrameWeak); + if (rEvent.Frame != xFrame) + return; + + switch (rEvent.Action) + { + case frame::FrameAction_COMPONENT_DETACHING: + DisconnectFromController(); + CallListeners (EventMultiplexerEventId::ControllerDetached); + break; + + case frame::FrameAction_COMPONENT_REATTACHED: + CallListeners (EventMultiplexerEventId::ControllerDetached); + DisconnectFromController(); + ConnectToController(); + CallListeners (EventMultiplexerEventId::ControllerAttached); + break; + + case frame::FrameAction_COMPONENT_ATTACHED: + ConnectToController(); + CallListeners (EventMultiplexerEventId::ControllerAttached); + break; + + default: + break; + } +} + +//===== view::XSelectionChangeListener ======================================== + +void SAL_CALL EventMultiplexer::Implementation::selectionChanged ( + const lang::EventObject& ) +{ + CallListeners (EventMultiplexerEventId::EditViewSelection); +} + +//===== drawing::framework::XConfigurationChangeListener ================== + +void SAL_CALL EventMultiplexer::Implementation::notifyConfigurationChange ( + const ConfigurationChangeEvent& rEvent) +{ + sal_Int32 nEventType = 0; + rEvent.UserData >>= nEventType; + switch (nEventType) + { + case ResourceActivationEvent: + if (rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix)) + { + CallListeners (EventMultiplexerEventId::ViewAdded); + + if (rEvent.ResourceId->isBoundToURL( + FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) + { + CallListeners (EventMultiplexerEventId::MainViewAdded); + } + + // Add selection change listener at slide sorter. + if (rEvent.ResourceId->getResourceURL() == FrameworkHelper::msSlideSorterURL) + { + slidesorter::SlideSorterViewShell* pViewShell + = dynamic_cast<slidesorter::SlideSorterViewShell*>( + FrameworkHelper::GetViewShell( + Reference<XView>(rEvent.ResourceObject,UNO_QUERY)).get()); + if (pViewShell != nullptr) + pViewShell->AddSelectionChangeListener ( + LINK(this, + EventMultiplexer::Implementation, + SlideSorterSelectionChangeListener)); + } + } + break; + + case ResourceDeactivationEvent: + if (rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix)) + { + if (rEvent.ResourceId->isBoundToURL( + FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) + { + CallListeners (EventMultiplexerEventId::MainViewRemoved); + } + + // Remove selection change listener from slide sorter. Add + // selection change listener at slide sorter. + if (rEvent.ResourceId->getResourceURL() == FrameworkHelper::msSlideSorterURL) + { + slidesorter::SlideSorterViewShell* pViewShell + = dynamic_cast<slidesorter::SlideSorterViewShell*>( + FrameworkHelper::GetViewShell( + Reference<XView>(rEvent.ResourceObject, UNO_QUERY)).get()); + if (pViewShell != nullptr) + pViewShell->RemoveSelectionChangeListener ( + LINK(this, + EventMultiplexer::Implementation, + SlideSorterSelectionChangeListener)); + } + } + break; + + case ConfigurationUpdateEvent: + CallListeners (EventMultiplexerEventId::ConfigurationUpdated); + break; + } + +} + +void EventMultiplexer::Implementation::disposing(std::unique_lock<std::mutex>& rGuard) +{ + ListenerList aCopyListeners( maListeners ); + + rGuard.unlock(); + + EventMultiplexerEvent rEvent(EventMultiplexerEventId::Disposing, nullptr); + for (const auto& rListener : aCopyListeners) + rListener.Call(rEvent); + + rGuard.lock(); + + ReleaseListeners(); +} + +void EventMultiplexer::Implementation::Notify ( + SfxBroadcaster&, + const SfxHint& rHint) +{ + if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint) + { + const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint); + switch (pSdrHint->GetKind()) + { + case SdrHintKind::ModelCleared: + case SdrHintKind::PageOrderChange: + CallListeners (EventMultiplexerEventId::PageOrder); + break; + + case SdrHintKind::SwitchToPage: + CallListeners (EventMultiplexerEventId::CurrentPageChanged); + break; + + case SdrHintKind::ObjectChange: + CallListeners(EventMultiplexerEventId::ShapeChanged, + static_cast<const void*>(pSdrHint->GetPage())); + break; + + case SdrHintKind::ObjectInserted: + CallListeners(EventMultiplexerEventId::ShapeInserted, + static_cast<const void*>(pSdrHint->GetPage())); + break; + + case SdrHintKind::ObjectRemoved: + CallListeners(EventMultiplexerEventId::ShapeRemoved, + static_cast<const void*>(pSdrHint->GetPage())); + break; + default: + break; + } + } + else + { + if (rHint.GetId() == SfxHintId::Dying) + mpDocument = nullptr; + } +} + +void EventMultiplexer::Implementation::CallListeners ( + EventMultiplexerEventId eId, + void const * pUserData) +{ + EventMultiplexerEvent aEvent(eId, pUserData); + CallListeners(aEvent); +} + +void EventMultiplexer::Implementation::CallListeners (EventMultiplexerEvent& rEvent) +{ + ListenerList aCopyListeners( maListeners ); + for (const auto& rListener : aCopyListeners) + { + rListener.Call(rEvent); + } +} + +IMPL_LINK_NOARG(EventMultiplexer::Implementation, SlideSorterSelectionChangeListener, LinkParamNone*, void) +{ + CallListeners(EventMultiplexerEventId::SlideSortedSelection); +} + +//===== EventMultiplexerEvent ================================================= + +EventMultiplexerEvent::EventMultiplexerEvent ( + EventMultiplexerEventId eEventId, + const void* pUserData) + : meEventId(eEventId), + mpUserData(pUserData) +{ +} + +} // end of namespace ::sd::tools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/GraphicSizeCheck.cxx b/sd/source/ui/tools/GraphicSizeCheck.cxx new file mode 100644 index 000000000..492a2d70b --- /dev/null +++ b/sd/source/ui/tools/GraphicSizeCheck.cxx @@ -0,0 +1,221 @@ +/* -*- 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/. + * + */ + +#include <memory> +#include <tools/GraphicSizeCheck.hxx> +#include <svx/strings.hrc> +#include <svx/svdobj.hxx> +#include <svx/svdpage.hxx> +#include <svx/svxids.hrc> +#include <sfx2/dispatch.hxx> + +#include <sdresid.hxx> +#include <DrawDocShell.hxx> +#include <ViewShell.hxx> + +namespace sd +{ +namespace +{ +/** + * Interface for the visitor class, which handles each visited SdrObject + * in the DOM. + */ +class ModelTraverseHandler +{ +public: + virtual ~ModelTraverseHandler() {} + + virtual void handleSdrObject(SdrObject* pObject) = 0; +}; + +/** + * Traverses the DOM and calls a handler for each object (SdrObject) it + * encounters. + */ +class ModelTraverser +{ +private: + std::vector<std::shared_ptr<ModelTraverseHandler>> m_pNodeHandler; + SdDrawDocument* m_pDocument; + +public: + ModelTraverser(SdDrawDocument* pDocument) + : m_pDocument(pDocument) + { + } + + void traverse() + { + if (!m_pDocument) + return; + + for (sal_uInt16 nPage = 0; nPage < m_pDocument->GetPageCount(); ++nPage) + { + SdrPage* pPage = m_pDocument->GetPage(nPage); + if (pPage) + { + for (size_t nObject = 0; nObject < pPage->GetObjCount(); ++nObject) + { + SdrObject* pObject = pPage->GetObj(nObject); + if (pObject) + { + for (auto& pNodeHandler : m_pNodeHandler) + { + pNodeHandler->handleSdrObject(pObject); + } + } + } + } + } + } + + void addNodeHandler(std::shared_ptr<ModelTraverseHandler> pHandler) + { + m_pNodeHandler.push_back(pHandler); + } +}; +} + +GraphicSizeViolation::GraphicSizeViolation(sal_Int32 nDPI, SdrGrafObj* pGraphicObject) + : m_pGraphicObject(pGraphicObject) +{ + constexpr double fLowPercentage = 110; + constexpr double fHighPercentage = 50; + + m_nLowDPILimit = sal_Int32(100.0 / fLowPercentage * nDPI); + m_nHighDPILimit = sal_Int32(100.0 / fHighPercentage * nDPI); +} + +bool GraphicSizeViolation::check() +{ + Graphic aGraphic = m_pGraphicObject->GetGraphic(); + Size aSizePixel = aGraphic.GetSizePixel(); + Size aGraphicSize = m_pGraphicObject->GetLogicRect().GetSize(); + + double nSizeXInch + = o3tl::convert(double(aGraphicSize.Width()), o3tl::Length::mm100, o3tl::Length::in); + double nSizeYInch + = o3tl::convert(double(aGraphicSize.Height()), o3tl::Length::mm100, o3tl::Length::in); + + m_nDPIX = sal_Int32(aSizePixel.Width() / nSizeXInch); + m_nDPIY = sal_Int32(aSizePixel.Height() / nSizeYInch); + + return isDPITooLow() || isDPITooHigh(); +} + +const OUString& GraphicSizeViolation::getGraphicName() { return m_pGraphicObject->GetName(); } + +namespace +{ +class GraphicSizeCheckHandler : public ModelTraverseHandler +{ + sal_Int32 m_nDPI; + std::vector<std::unique_ptr<GraphicSizeViolation>>& m_rGraphicSizeViolationList; + +public: + GraphicSizeCheckHandler( + sal_Int32 nDPI, + std::vector<std::unique_ptr<GraphicSizeViolation>>& rGraphicSizeViolationList) + : m_nDPI(nDPI) + , m_rGraphicSizeViolationList(rGraphicSizeViolationList) + { + } + + void handleSdrObject(SdrObject* pObject) override + { + auto* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + if (!pGraphicObject) + return; + + auto pEntry = std::make_unique<GraphicSizeViolation>(m_nDPI, pGraphicObject); + if (pEntry->check()) + { + m_rGraphicSizeViolationList.push_back(std::move(pEntry)); + } + } +}; + +} // end anonymous namespace + +void GraphicSizeCheck::check() +{ + if (!m_pDocument) + return; + + sal_Int32 nDPI = m_pDocument->getImagePreferredDPI(); + if (nDPI == 0) + return; + + auto pHandler = std::make_shared<GraphicSizeCheckHandler>(nDPI, m_aGraphicSizeViolationList); + + ModelTraverser aModelTraverser(m_pDocument); + aModelTraverser.addNodeHandler(pHandler); + aModelTraverser.traverse(); +} + +OUString GraphicSizeCheckGUIEntry::getText() +{ + OUString sText; + + if (m_pViolation->isDPITooLow()) + { + sText = SdResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_LOW); + } + else if (m_pViolation->isDPITooHigh()) + { + sText = SdResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_HIGH); + } + + sText = sText.replaceAll("%NAME%", m_pViolation->getGraphicName()); + sText = sText.replaceAll("%DPIX%", OUString::number(m_pViolation->getDPIX())); + sText = sText.replaceAll("%DPIY%", OUString::number(m_pViolation->getDPIY())); + + return sText; +} + +void GraphicSizeCheckGUIEntry::markObject() +{ + sd::ViewShell* pViewShell = m_pDocument->GetDocSh()->GetViewShell(); + SdrView* pView = pViewShell->GetView(); + pView->ShowSdrPage(m_pViolation->getObject()->getSdrPageFromSdrObject()); + pView->UnmarkAll(); + pView->MarkObj(m_pViolation->getObject(), pView->GetSdrPageView()); +} + +void GraphicSizeCheckGUIEntry::runProperties() +{ + markObject(); + sd::ViewShell* pViewShell = m_pDocument->GetDocSh()->GetViewShell(); + pViewShell->GetDispatcher()->Execute(SID_ATTR_GRAF_CROP, SfxCallMode::SYNCHRON); +} + +GraphicSizeCheckGUIResult::GraphicSizeCheckGUIResult(SdDrawDocument* pDocument) +{ + GraphicSizeCheck aCheck(pDocument); + aCheck.check(); + + auto& rCollection = getCollection(); + for (auto& rpViolation : aCheck.getViolationList()) + { + auto rGUIEntry + = std::make_unique<GraphicSizeCheckGUIEntry>(pDocument, std::move(rpViolation)); + rCollection.push_back(std::move(rGUIEntry)); + } +} + +OUString GraphicSizeCheckGUIResult::getTitle() +{ + return SdResId(STR_GRAPHIC_SIZE_CHECK_DIALOG_TITLE); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/IconCache.cxx b/sd/source/ui/tools/IconCache.cxx new file mode 100644 index 000000000..0ce80922b --- /dev/null +++ b/sd/source/ui/tools/IconCache.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <tools/IconCache.hxx> + +#include <tools/debug.hxx> +#include <osl/doublecheckedlocking.h> +#include <osl/getglobalmutex.hxx> +#include <unordered_map> + +namespace sd +{ +//===== IconCache::Implementation ============================================= + +class IconCache::Implementation +{ +private: + friend class IconCache; + + /** This pointer holds a valid reference from first time that + IconCache::Instance() is called to the end of the sd module when the + cache is destroyed from SdGlobalResourceContainer. + */ + static IconCache* s_pIconCache; + + typedef std::unordered_map<OUString, Image> ImageContainer; + ImageContainer maContainer; + + Image GetIcon(const OUString& rResourceId); +}; + +IconCache* IconCache::Implementation::s_pIconCache = nullptr; + +Image IconCache::Implementation::GetIcon(const OUString& rResourceId) +{ + Image aResult; + ImageContainer::iterator iImage = maContainer.find(rResourceId); + if (iImage == maContainer.end()) + { + aResult = Image(StockImage::Yes, rResourceId); + maContainer[rResourceId] = aResult; + } + else + aResult = iImage->second; + return aResult; +} + +//===== IconCache ============================================================= + +//static +IconCache& IconCache::Instance() +{ + if (Implementation::s_pIconCache == nullptr) + { + ::osl::GetGlobalMutex aMutexFunctor; + ::osl::MutexGuard aGuard(aMutexFunctor()); + if (Implementation::s_pIconCache == nullptr) + { + IconCache* pCache = new IconCache(); + SdGlobalResourceContainer::Instance().AddResource( + ::std::unique_ptr<SdGlobalResource>(pCache)); + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + Implementation::s_pIconCache = pCache; + } + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + + DBG_ASSERT(Implementation::s_pIconCache != nullptr, "IconCache::Instance(): instance is NULL"); + return *Implementation::s_pIconCache; +} + +Image IconCache::GetIcon(const OUString& rResourceId) { return mpImpl->GetIcon(rResourceId); } + +IconCache::IconCache() + : mpImpl(new Implementation) +{ +} + +IconCache::~IconCache() +{ + // empty +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/IdleDetection.cxx b/sd/source/ui/tools/IdleDetection.cxx new file mode 100644 index 000000000..988bd849b --- /dev/null +++ b/sd/source/ui/tools/IdleDetection.cxx @@ -0,0 +1,103 @@ +/* -*- 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 <tools/IdleDetection.hxx> + +#include <slideshow.hxx> +#include <ViewShellBase.hxx> + +#include <vcl/window.hxx> +#include <sfx2/viewfrm.hxx> + +#include <com/sun/star/frame/XFrame.hpp> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; + +namespace sd::tools { + +IdleState IdleDetection::GetIdleState (const vcl::Window* pWindow) +{ + IdleState nResult (CheckInputPending() | CheckSlideShowRunning()); + if (pWindow != nullptr) + nResult |= CheckWindowPainting(*pWindow); + return nResult; +} + +IdleState IdleDetection::CheckInputPending() +{ + if (Application::AnyInput(VclInputFlags::MOUSE | VclInputFlags::KEYBOARD | VclInputFlags::PAINT)) + return IdleState::SystemEventPending; + else + return IdleState::Idle; +} + +IdleState IdleDetection::CheckSlideShowRunning() +{ + IdleState eResult (IdleState::Idle); + + // Iterate over all view frames. + for (SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(); + pViewFrame!=nullptr; + pViewFrame = SfxViewFrame::GetNext(*pViewFrame)) + { + // Ignore the current frame when it does not exist, is not valid, or + // is not active. + bool bIgnoreFrame (true); + uno::Reference<frame::XFrame> xFrame (pViewFrame->GetFrame().GetFrameInterface()); + try + { + if (xFrame.is() && xFrame->isActive()) + bIgnoreFrame = false; + } + catch (const uno::RuntimeException&) + { + } + if (bIgnoreFrame) + continue; + + // Get sd::ViewShell from active frame. + ViewShellBase* pBase = ViewShellBase::GetViewShellBase(pViewFrame); + if (pBase != nullptr) + { + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( *pBase ) ); + if( xSlideShow.is() && xSlideShow->isRunning() ) + { + if (xSlideShow->isFullScreen()) + eResult |= IdleState::FullScreenShowActive; + else + eResult |= IdleState::WindowShowActive; + } + } + } + + return eResult; +} + +IdleState IdleDetection::CheckWindowPainting (const vcl::Window& rWindow) +{ + if (rWindow.IsInPaint()) + return IdleState::WindowPainting; + else + return IdleState::Idle; +} + +} // end of namespace ::sd::tools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/PreviewRenderer.cxx b/sd/source/ui/tools/PreviewRenderer.cxx new file mode 100644 index 000000000..be8d8ca20 --- /dev/null +++ b/sd/source/ui/tools/PreviewRenderer.cxx @@ -0,0 +1,532 @@ +/* -*- 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 <PreviewRenderer.hxx> + +#include <DrawDocShell.hxx> +#include <drawdoc.hxx> +#include <drawview.hxx> +#include <sdpage.hxx> +#include <ViewShell.hxx> +#include <vcl/virdev.hxx> +#include <vcl/settings.hxx> + +#include <svx/svdpagv.hxx> +#include <svx/svdoutl.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/editstat.hxx> +#include <vcl/svapp.hxx> +#include <tools/diagnose_ex.h> +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/sdr/contact/viewcontact.hxx> + +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd { + +const int PreviewRenderer::snSubstitutionTextSize = 11; +const int PreviewRenderer::snFrameWidth = 1; + +namespace { + /** This incarnation of the ViewObjectContactRedirector filters away all + PageObj objects, unconditionally. + */ + class ViewRedirector : public sdr::contact::ViewObjectContactRedirector + { + public: + ViewRedirector(); + + virtual void createRedirectedPrimitive2DSequence( + const sdr::contact::ViewObjectContact& rOriginal, + const sdr::contact::DisplayInfo& rDisplayInfo, + drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override; + }; +} + +//===== PreviewRenderer ======================================================= + +PreviewRenderer::PreviewRenderer ( + const bool bHasFrame) + : mpPreviewDevice (VclPtr<VirtualDevice>::Create()), + mpDocShellOfView(nullptr), + maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES).nColor), + mbHasFrame(bHasFrame) +{ + mpPreviewDevice->SetBackground(Wallpaper( + Application::GetSettings().GetStyleSettings().GetWindowColor())); +} + +PreviewRenderer::~PreviewRenderer() +{ + if (mpDocShellOfView != nullptr) + EndListening (*mpDocShellOfView); +} + +Image PreviewRenderer::RenderPage ( + const SdPage* pPage, + const sal_Int32 nWidth) +{ + if (pPage != nullptr) + { + const Size aPageModelSize (pPage->GetSize()); + const double nAspectRatio ( + double(aPageModelSize.Width()) / double(aPageModelSize.Height())); + const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); + const sal_Int32 nHeight (sal::static_int_cast<sal_Int32>( + (nWidth - 2*nFrameWidth) / nAspectRatio + 2*nFrameWidth + 0.5)); + return RenderPage ( + pPage, + Size(nWidth,nHeight), + false/*bObeyHighContrastMode*/); + } + else + return Image(); +} + +Image PreviewRenderer::RenderPage ( + const SdPage* pPage, + Size aPixelSize, + const bool bObeyHighContrastMode, + const bool bDisplayPresentationObjects) +{ + Image aPreview; + + if (pPage != nullptr) + { + try + { + if (Initialize(pPage, aPixelSize, bObeyHighContrastMode)) + { + PaintPage(pPage, bDisplayPresentationObjects); + PaintSubstitutionText(""); + PaintFrame(); + + Size aSize (mpPreviewDevice->GetOutputSizePixel()); + aPreview = Image(mpPreviewDevice->GetBitmapEx( + mpPreviewDevice->PixelToLogic(Point(0,0)), + mpPreviewDevice->PixelToLogic(aSize))); + + mpView->HideSdrPage(); + } + } + catch (const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("sd.tools"); + } + } + + return aPreview; +} + +Image PreviewRenderer::RenderSubstitution ( + const Size& rPreviewPixelSize, + const OUString& rSubstitutionText) +{ + Image aPreview; + + try + { + // Set size. + mpPreviewDevice->SetOutputSizePixel(rPreviewPixelSize); + + // Adjust contrast mode. + const bool bUseContrast ( + Application::GetSettings().GetStyleSettings().GetHighContrastMode()); + mpPreviewDevice->SetDrawMode (bUseContrast + ? sd::OUTPUT_DRAWMODE_CONTRAST + : sd::OUTPUT_DRAWMODE_COLOR); + + // Set a map mode that makes a typical substitution text completely + // visible. + MapMode aMapMode (mpPreviewDevice->GetMapMode()); + aMapMode.SetMapUnit(MapUnit::Map100thMM); + Fraction aFinalScale(25 * rPreviewPixelSize.Width(), 28000); + aMapMode.SetScaleX(aFinalScale); + aMapMode.SetScaleY(aFinalScale); + const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); + aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic( + Point(nFrameWidth,nFrameWidth),aMapMode)); + mpPreviewDevice->SetMapMode (aMapMode); + + // Clear the background. + const ::tools::Rectangle aPaintRectangle ( + Point(0,0), + mpPreviewDevice->GetOutputSizePixel()); + mpPreviewDevice->EnableMapMode(false); + mpPreviewDevice->SetLineColor(); + svtools::ColorConfig aColorConfig; + mpPreviewDevice->SetFillColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor); + mpPreviewDevice->DrawRect (aPaintRectangle); + mpPreviewDevice->EnableMapMode(); + + // Paint substitution text and a frame around it. + PaintSubstitutionText (rSubstitutionText); + PaintFrame(); + + const Size aSize (mpPreviewDevice->GetOutputSizePixel()); + aPreview = Image(mpPreviewDevice->GetBitmapEx( + mpPreviewDevice->PixelToLogic(Point(0,0)), + mpPreviewDevice->PixelToLogic(aSize))); + } + catch (const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("sd.tools"); + } + + return aPreview; +} + +bool PreviewRenderer::Initialize ( + const SdPage* pPage, + const Size& rPixelSize, + const bool bObeyHighContrastMode) +{ + if (!pPage) + return false; + + SetupOutputSize(*pPage, rPixelSize); + SdDrawDocument& rDocument(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage())); + DrawDocShell* pDocShell = rDocument.GetDocSh(); + + if (!pDocShell) + return false; + + // Create view + ProvideView (pDocShell); + if (mpView == nullptr) + return false; + + // Adjust contrast mode. + bool bUseContrast (bObeyHighContrastMode + && Application::GetSettings().GetStyleSettings().GetHighContrastMode()); + mpPreviewDevice->SetDrawMode (bUseContrast + ? sd::OUTPUT_DRAWMODE_CONTRAST + : sd::OUTPUT_DRAWMODE_COLOR); + mpPreviewDevice->SetSettings(Application::GetSettings()); + + // Tell the view to show the given page. + SdPage* pNonConstPage = const_cast<SdPage*>(pPage); + if (pPage->IsMasterPage()) + { + mpView->ShowSdrPage(mpView->GetModel()->GetMasterPage(pPage->GetPageNum())); + } + else + { + mpView->ShowSdrPage(pNonConstPage); + } + + // Make sure that a page view exists. + SdrPageView* pPageView = mpView->GetSdrPageView(); + + if (pPageView == nullptr) + return false; + + // #i121224# No need to set SetApplicationBackgroundColor (which is the color + // of the area 'behind' the page (formerly called 'Wiese') since the page previews + // produced exactly cover the page's area, so it would never be visible. What + // needs to be set is the ApplicationDocumentColor which is derived from + // svtools::DOCCOLOR normally + Color aApplicationDocumentColor; + + if (pPageView->GetApplicationDocumentColor() == COL_AUTO) + { + svtools::ColorConfig aColorConfig; + aApplicationDocumentColor = aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor; + } + else + { + aApplicationDocumentColor = pPageView->GetApplicationDocumentColor(); + } + + pPageView->SetApplicationDocumentColor(aApplicationDocumentColor); + SdrOutliner& rOutliner(rDocument.GetDrawOutliner()); + rOutliner.SetBackgroundColor(aApplicationDocumentColor); + rOutliner.SetDefaultLanguage(rDocument.GetLanguage(EE_CHAR_LANGUAGE)); + mpPreviewDevice->SetBackground(Wallpaper(aApplicationDocumentColor)); + mpPreviewDevice->Erase(); + + return true; +} + +void PreviewRenderer::PaintPage ( + const SdPage* pPage, + const bool bDisplayPresentationObjects) +{ + // Paint the page. + ::tools::Rectangle aPaintRectangle (Point(0,0), pPage->GetSize()); + vcl::Region aRegion (aPaintRectangle); + + // Turn off online spelling and redlining. + SdrOutliner* pOutliner = nullptr; + EEControlBits nSavedControlWord = EEControlBits::NONE; + if (mpDocShellOfView!=nullptr && mpDocShellOfView->GetDoc()!=nullptr) + { + pOutliner = &mpDocShellOfView->GetDoc()->GetDrawOutliner(); + nSavedControlWord = pOutliner->GetControlWord(); + pOutliner->SetControlWord(nSavedControlWord & ~EEControlBits::ONLINESPELLING); + } + + // Use a special redirector to prevent PresObj shapes from being painted. + std::unique_ptr<ViewRedirector> pRedirector; + if ( ! bDisplayPresentationObjects) + pRedirector.reset(new ViewRedirector()); + + try + { + mpView->CompleteRedraw(mpPreviewDevice.get(), aRegion, pRedirector.get()); + } + catch (const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("sd.tools"); + } + + // Restore the previous online spelling and redlining states. + if (pOutliner != nullptr) + pOutliner->SetControlWord(nSavedControlWord); +} + +void PreviewRenderer::PaintSubstitutionText (const OUString& rSubstitutionText) +{ + if (rSubstitutionText.isEmpty()) + return; + + // Set the font size. + const vcl::Font& rOriginalFont (mpPreviewDevice->GetFont()); + vcl::Font aFont (mpPreviewDevice->GetSettings().GetStyleSettings().GetAppFont()); + sal_Int32 nHeight (mpPreviewDevice->PixelToLogic(Size(0,snSubstitutionTextSize)).Height()); + aFont.SetFontHeight(nHeight); + mpPreviewDevice->SetFont (aFont); + + // Paint the substitution text. + ::tools::Rectangle aTextBox ( + Point(0,0), + mpPreviewDevice->PixelToLogic( + mpPreviewDevice->GetOutputSizePixel())); + DrawTextFlags const nTextStyle = + DrawTextFlags::Center + | DrawTextFlags::VCenter + | DrawTextFlags::MultiLine + | DrawTextFlags::WordBreak; + mpPreviewDevice->DrawText (aTextBox, rSubstitutionText, nTextStyle); + + // Restore the font. + mpPreviewDevice->SetFont (rOriginalFont); +} + +void PreviewRenderer::PaintFrame() +{ + if (mbHasFrame) + { + // Paint a frame around the preview. + ::tools::Rectangle aPaintRectangle ( + Point(0,0), + mpPreviewDevice->GetOutputSizePixel()); + mpPreviewDevice->EnableMapMode(false); + mpPreviewDevice->SetLineColor(maFrameColor); + mpPreviewDevice->SetFillColor(); + mpPreviewDevice->DrawRect(aPaintRectangle); + mpPreviewDevice->EnableMapMode(); + } +} + +void PreviewRenderer::SetupOutputSize ( + const SdPage& rPage, + const Size& rFramePixelSize) +{ + // First set the map mode to some arbitrary scale that is numerically + // stable. + MapMode aMapMode (mpPreviewDevice->GetMapMode()); + aMapMode.SetMapUnit(MapUnit::MapPixel); + + // Adapt it to the desired width. + const Size aPageModelSize (rPage.GetSize()); + if (!aPageModelSize.IsEmpty()) + { + const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); + aMapMode.SetScaleX( + Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width())); + aMapMode.SetScaleY( + Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height())); + aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode)); + } + else + { + // We should never get here. + OSL_ASSERT(false); + aMapMode.SetScaleX(Fraction(1.0)); + aMapMode.SetScaleY(Fraction(1.0)); + } + mpPreviewDevice->SetMapMode (aMapMode); + mpPreviewDevice->SetOutputSizePixel(rFramePixelSize); +} + +void PreviewRenderer::ProvideView (DrawDocShell* pDocShell) +{ + if (pDocShell != mpDocShellOfView) + { + // Destroy the view that is connected to the current doc shell. + mpView.reset(); + + // Switch our attention, i.e. listening for DYING events, to + // the new doc shell. + if (mpDocShellOfView != nullptr) + EndListening (*mpDocShellOfView); + mpDocShellOfView = pDocShell; + if (mpDocShellOfView != nullptr) + StartListening (*mpDocShellOfView); + } + if (mpView == nullptr) + { + mpView.reset (new DrawView (pDocShell, mpPreviewDevice.get(), nullptr)); + } + mpView->SetPreviewRenderer(true); +#if 1 + mpView->SetPageVisible(false); + mpView->SetPageBorderVisible(); + mpView->SetBordVisible(false); + mpView->SetGridVisible(false); + mpView->SetHlplVisible(false); + mpView->SetGlueVisible(false); + +#else + // This works in the slide sorter but prevents the master page + // background being painted in the list of current master pages in the + // task manager. + mpView->SetPagePaintingAllowed(false); +#endif +} + +Image PreviewRenderer::ScaleBitmap ( + const BitmapEx& rBitmapEx, + int nWidth) +{ + Image aPreview; + + do + { + // Adjust contrast mode. + bool bUseContrast = Application::GetSettings().GetStyleSettings(). + GetHighContrastMode(); + mpPreviewDevice->SetDrawMode (bUseContrast + ? sd::OUTPUT_DRAWMODE_CONTRAST + : sd::OUTPUT_DRAWMODE_COLOR); + + // Set output size. + Size aSize (rBitmapEx.GetSizePixel()); + if (aSize.Width() <= 0) + break; + Size aFrameSize ( + nWidth, + static_cast<::tools::Long>((nWidth*1.0 * aSize.Height()) / aSize.Width() + 0.5)); + Size aPreviewSize (aFrameSize.Width()-2,aFrameSize.Height()-2); + MapMode aMapMode (mpPreviewDevice->GetMapMode()); + aMapMode.SetMapUnit(MapUnit::MapPixel); + aMapMode.SetOrigin (Point()); + aMapMode.SetScaleX (Fraction(1.0)); + aMapMode.SetScaleY (Fraction(1.0)); + mpPreviewDevice->SetMapMode (aMapMode); + mpPreviewDevice->SetOutputSize (aFrameSize); + + // Paint a frame around the preview. + mpPreviewDevice->SetLineColor (maFrameColor); + mpPreviewDevice->SetFillColor (); + mpPreviewDevice->DrawRect (::tools::Rectangle(Point(0,0), aFrameSize)); + + // Paint the bitmap scaled to the desired width. + BitmapEx aScaledBitmap(rBitmapEx); + aScaledBitmap.Scale (aPreviewSize, BmpScaleFlag::BestQuality); + mpPreviewDevice->DrawBitmapEx ( + Point(1,1), + aPreviewSize, + aScaledBitmap); + + // Get the resulting bitmap. + aPreview = Image(mpPreviewDevice->GetBitmapEx(Point(0,0), aFrameSize)); + } + while (false); + + return aPreview; +} + +void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint) +{ + if (!mpDocShellOfView) + return; + + if (rHint.GetId() == SfxHintId::Dying) + { + // The doc shell is dying. Our view uses its item pool and + // has to be destroyed as well. The next call to + // ProvideView will create a new one (for another + // doc shell, of course.) + mpView.reset(); + mpDocShellOfView = nullptr; + } +} + +//===== ViewRedirector ======================================================== + +namespace { + +ViewRedirector::ViewRedirector() +{ +} + +void ViewRedirector::createRedirectedPrimitive2DSequence( + const sdr::contact::ViewObjectContact& rOriginal, + const sdr::contact::DisplayInfo& rDisplayInfo, + drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) +{ + SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject(); + + if (pObject==nullptr || pObject->getSdrPageFromSdrObject() == nullptr) + { + // not a SdrObject visualisation (maybe e.g. page) or no page + sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( + rOriginal, + rDisplayInfo, + rVisitor); + return; + } + + const bool bDoCreateGeometry (pObject->getSdrPageFromSdrObject()->checkVisibility( rOriginal, rDisplayInfo, true)); + + if ( ! bDoCreateGeometry + && (pObject->GetObjInventor() != SdrInventor::Default || pObject->GetObjIdentifier() != SdrObjKind::Page)) + { + return; + } + + if (pObject->IsEmptyPresObj()) + return; + + sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( + rOriginal, + rDisplayInfo, + rVisitor); +} + +} // end of anonymous namespace + +} // end of namespace ::sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/PropertySet.cxx b/sd/source/ui/tools/PropertySet.cxx new file mode 100644 index 000000000..057b7dd96 --- /dev/null +++ b/sd/source/ui/tools/PropertySet.cxx @@ -0,0 +1,158 @@ +/* -*- 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 <tools/PropertySet.hxx> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd::tools { + +PropertySet::PropertySet() + : PropertySetInterfaceBase(m_aMutex), + mpChangeListeners(new ChangeListenerContainer) +{ +} + +PropertySet::~PropertySet() +{ +} + +void SAL_CALL PropertySet::disposing() +{ +} + +//----- XPropertySet ---------------------------------------------------------- + +Reference<beans::XPropertySetInfo> SAL_CALL PropertySet::getPropertySetInfo() +{ + return nullptr; +} + +void SAL_CALL PropertySet::setPropertyValue ( + const OUString& rsPropertyName, + const css::uno::Any& rsPropertyValue) +{ + ThrowIfDisposed(); + + Any aOldValue (SetPropertyValue(rsPropertyName,rsPropertyValue)); + if (aOldValue == rsPropertyValue) + return; + + // Inform listeners that are registered specifically for the + // property and those registered for any property. + beans::PropertyChangeEvent aEvent( + static_cast<XWeak*>(this), + rsPropertyName, + false, + -1, + aOldValue, + rsPropertyValue); + CallListeners(rsPropertyName, aEvent); + CallListeners(OUString(), aEvent); +} + +Any SAL_CALL PropertySet::getPropertyValue (const OUString& rsPropertyName) +{ + ThrowIfDisposed(); + + return GetPropertyValue(rsPropertyName); +} + +void SAL_CALL PropertySet::addPropertyChangeListener ( + const OUString& rsPropertyName, + const css::uno::Reference<css::beans::XPropertyChangeListener>& rxListener) +{ + if ( ! rxListener.is()) + throw lang::IllegalArgumentException(); + + if (rBHelper.bDisposed || rBHelper.bInDispose) + return; + + mpChangeListeners->emplace(rsPropertyName, rxListener); +} + +void SAL_CALL PropertySet::removePropertyChangeListener ( + const OUString& rsPropertyName, + const css::uno::Reference<css::beans::XPropertyChangeListener>& rxListener) +{ + ::std::pair<ChangeListenerContainer::iterator,ChangeListenerContainer::iterator> + aRange (mpChangeListeners->equal_range(rsPropertyName)); + + ChangeListenerContainer::iterator iListener ( + ::std::find_if( + aRange.first, + aRange.second, + [&rxListener] (const ChangeListenerContainer::value_type& listener) { + return listener.second == rxListener; + })); + + if (iListener == mpChangeListeners->end()) + { + throw lang::IllegalArgumentException(); + } + + mpChangeListeners->erase(iListener); + +} + +void SAL_CALL PropertySet::addVetoableChangeListener ( + const OUString&, + const css::uno::Reference<css::beans::XVetoableChangeListener>&) +{ + // Constraint properties are not supported and thus no vetoable + // listeners. +} + +void SAL_CALL PropertySet::removeVetoableChangeListener ( + const OUString&, + const css::uno::Reference<css::beans::XVetoableChangeListener>&) +{ + // Constraint properties are not supported and thus no vetoable + // listeners. +} + +void PropertySet::CallListeners ( + const OUString& rsPropertyName, + const beans::PropertyChangeEvent& rEvent) +{ + ::std::pair<ChangeListenerContainer::iterator,ChangeListenerContainer::iterator> + aRange (mpChangeListeners->equal_range(rsPropertyName)); + ChangeListenerContainer::const_iterator iListener; + for (iListener=aRange.first; iListener!=aRange.second; ++iListener) + { + if (iListener->second.is()) + iListener->second->propertyChange(rEvent); + } +} + +void PropertySet::ThrowIfDisposed() +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + throw lang::DisposedException ( + "PropertySet object has already been disposed", + static_cast<uno::XWeak*>(this)); + } +} + +} // end of namespace ::sd::tools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/SdGlobalResourceContainer.cxx b/sd/source/ui/tools/SdGlobalResourceContainer.cxx new file mode 100644 index 000000000..a7dbc5f25 --- /dev/null +++ b/sd/source/ui/tools/SdGlobalResourceContainer.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 <tools/SdGlobalResourceContainer.hxx> + +#include <../cache/SlsCacheConfiguration.hxx> + +#include <comphelper/processfactory.hxx> +#include <comphelper/unique_disposing_ptr.hxx> + +#include <com/sun/star/frame/Desktop.hpp> + +#include <sal/log.hxx> +#include <tools/debug.hxx> + +#include <algorithm> +#include <memory> +#include <vector> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd { + +class SdGlobalResourceContainerInstance + : public comphelper::unique_disposing_solar_mutex_reset_ptr<SdGlobalResourceContainer> +{ +public: + SdGlobalResourceContainerInstance() + : comphelper::unique_disposing_solar_mutex_reset_ptr<SdGlobalResourceContainer>( + uno::Reference<lang::XComponent>(frame::Desktop::create(comphelper::getProcessComponentContext()), uno::UNO_QUERY_THROW), + new SdGlobalResourceContainer, true) + { + } +}; + +namespace { + +SdGlobalResourceContainerInstance& theSdGlobalResourceContainerInstance() +{ + static SdGlobalResourceContainerInstance SINGLETON; + return SINGLETON; +} + +} // namespace + +//===== SdGlobalResourceContainer::Implementation ============================= + +class SdGlobalResourceContainer::Implementation +{ +private: + friend class SdGlobalResourceContainer; + + ::osl::Mutex maMutex; + + /** All instances of SdGlobalResource in this vector are owned by the + container and will be destroyed when the container is destroyed. + */ + std::vector<std::unique_ptr<SdGlobalResource>> maResources; + + typedef ::std::vector<std::shared_ptr<SdGlobalResource> > SharedResourceList; + SharedResourceList maSharedResources; + + typedef ::std::vector<Reference<XInterface> > XInterfaceResourceList; + XInterfaceResourceList maXInterfaceResources; +}; + +// static +SdGlobalResourceContainer& SdGlobalResourceContainer::Instance() +{ + SdGlobalResourceContainer *const pRet(theSdGlobalResourceContainerInstance().get()); + assert(pRet); // error if it has been deleted and is null + return *pRet; +} + +//===== SdGlobalResourceContainer ============================================= + +void SdGlobalResourceContainer::AddResource ( + ::std::unique_ptr<SdGlobalResource> pResource) +{ + ::osl::MutexGuard aGuard (mpImpl->maMutex); + + assert( std::none_of( + mpImpl->maResources.begin(), + mpImpl->maResources.end(), + [&](const std::unique_ptr<SdGlobalResource>& p) { return p == pResource; }) + && "duplicate resource?"); + + mpImpl->maResources.push_back(std::move(pResource)); +} + +void SdGlobalResourceContainer::AddResource ( + const std::shared_ptr<SdGlobalResource>& pResource) +{ + ::osl::MutexGuard aGuard (mpImpl->maMutex); + + Implementation::SharedResourceList::iterator iResource = ::std::find ( + mpImpl->maSharedResources.begin(), + mpImpl->maSharedResources.end(), + pResource); + if (iResource == mpImpl->maSharedResources.end()) + mpImpl->maSharedResources.push_back(pResource); + else + { + SAL_WARN ("sd.tools", + "SdGlobalResourceContainer:AddResource(): Resource added twice."); + } +} + +void SdGlobalResourceContainer::AddResource (const Reference<XInterface>& rxResource) +{ + ::osl::MutexGuard aGuard (mpImpl->maMutex); + + Implementation::XInterfaceResourceList::iterator iResource = ::std::find ( + mpImpl->maXInterfaceResources.begin(), + mpImpl->maXInterfaceResources.end(), + rxResource); + if (iResource == mpImpl->maXInterfaceResources.end()) + mpImpl->maXInterfaceResources.push_back(rxResource); + else + { + SAL_WARN ("sd.tools", + "SdGlobalResourceContainer:AddResource(): Resource added twice."); + } +} + +SdGlobalResourceContainer::SdGlobalResourceContainer() + : mpImpl (new SdGlobalResourceContainer::Implementation) +{ +} + +SdGlobalResourceContainer::~SdGlobalResourceContainer() +{ + ::osl::MutexGuard aGuard (mpImpl->maMutex); + + // Release the resources in reversed order of their addition to the + // container. This is because a resource A added before resource B + // may have been created due to a request of B. Thus B depends on A and + // should be destroyed first. + for (auto iResource = mpImpl->maResources.rbegin(); + iResource != mpImpl->maResources.rend(); + ++iResource) + { + iResource->reset(); + } + + + // The SharedResourceList has not to be released manually. We just + // assert resources that are still held by someone other than us. + Implementation::SharedResourceList::reverse_iterator iSharedResource; + for (iSharedResource = mpImpl->maSharedResources.rbegin(); + iSharedResource != mpImpl->maSharedResources.rend(); + ++iSharedResource) + { + if (iSharedResource->use_count() > 1) + { + SdGlobalResource* pResource = iSharedResource->get(); + SAL_INFO( + "sd.tools", pResource << " " << iSharedResource->use_count()); + DBG_ASSERT(iSharedResource->use_count() == 1, + "SdGlobalResource still held in ~SdGlobalResourceContainer"); + } + } + + Implementation::XInterfaceResourceList::reverse_iterator iXInterfaceResource; + for (iXInterfaceResource = mpImpl->maXInterfaceResources.rbegin(); + iXInterfaceResource != mpImpl->maXInterfaceResources.rend(); + ++iXInterfaceResource) + { + Reference<lang::XComponent> xComponent (*iXInterfaceResource, UNO_QUERY); + *iXInterfaceResource = nullptr; + if (xComponent.is()) + xComponent->dispose(); + } + + sd::slidesorter::cache::CacheConfiguration::Shutdown(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/SlotStateListener.cxx b/sd/source/ui/tools/SlotStateListener.cxx new file mode 100644 index 000000000..9b75b322e --- /dev/null +++ b/sd/source/ui/tools/SlotStateListener.cxx @@ -0,0 +1,153 @@ +/* -*- 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 <tools/SlotStateListener.hxx> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <comphelper/processfactory.hxx> + +using namespace ::com::sun::star; + +namespace sd::tools { + +SlotStateListener::SlotStateListener ( + Link<const OUString&,void> const & rCallback, + const uno::Reference<frame::XDispatchProvider>& rxDispatchProvider, + const OUString& rSlotName) + : mxDispatchProviderWeak(nullptr) +{ + SetCallback(rCallback); + ConnectToDispatchProvider(rxDispatchProvider); + ObserveSlot(rSlotName); +} + +SlotStateListener::~SlotStateListener() +{ + ReleaseListeners(); +} + +void SlotStateListener::SetCallback (const Link<const OUString&,void>& rCallback) +{ + ThrowIfDisposed(); + + maCallback = rCallback; +} + +void SlotStateListener::ConnectToDispatchProvider ( + const uno::Reference<frame::XDispatchProvider>& rxDispatchProvider) +{ + ThrowIfDisposed(); + + // When we are listening to state changes of slots of another frame then + // release these listeners first. + if ( ! maRegisteredURLList.empty()) + ReleaseListeners(); + + mxDispatchProviderWeak = rxDispatchProvider; +} + +void SlotStateListener::ObserveSlot (const OUString& rSlotName) +{ + ThrowIfDisposed(); + + if (maCallback.IsSet()) + { + // Connect the state change listener. + util::URL aURL (MakeURL(rSlotName)); + uno::Reference<frame::XDispatch> xDispatch (GetDispatch(aURL)); + if (xDispatch.is()) + { + maRegisteredURLList.push_back(aURL); + xDispatch->addStatusListener(this,aURL); + } + } +} + +void SlotStateListener::disposing(std::unique_lock<std::mutex>&) +{ + ReleaseListeners(); + mxDispatchProviderWeak.clear(); + maCallback = Link<const OUString&,void>(); +} + +util::URL SlotStateListener::MakeURL (const OUString& rSlotName) +{ + util::URL aURL; + aURL.Complete = rSlotName; + + uno::Reference<util::XURLTransformer> xTransformer(util::URLTransformer::create(::comphelper::getProcessComponentContext())); + xTransformer->parseStrict(aURL); + + return aURL; +} + +uno::Reference<frame::XDispatch> + SlotStateListener::GetDispatch (const util::URL& rURL) const +{ + uno::Reference<frame::XDispatch> xDispatch; + + uno::Reference<frame::XDispatchProvider> xDispatchProvider (mxDispatchProviderWeak); + if (xDispatchProvider.is()) + xDispatch = xDispatchProvider->queryDispatch(rURL, OUString(), 0); + + return xDispatch; +} + +void SlotStateListener::statusChanged ( + const frame::FeatureStateEvent& rState) +{ + ThrowIfDisposed(); + OUString sSlotName (rState.FeatureURL.Complete); + maCallback.Call(sSlotName); +} + +void SlotStateListener::ReleaseListeners() +{ + for (const auto& rURL : maRegisteredURLList) + { + uno::Reference<frame::XDispatch> xDispatch (GetDispatch(rURL)); + if (xDispatch.is()) + { + xDispatch->removeStatusListener(this,rURL); + } + } +} + +//===== lang::XEventListener ================================================ + +void SAL_CALL SlotStateListener::disposing ( + const lang::EventObject& ) +{ +} + +void SlotStateListener::ThrowIfDisposed() +{ + if (m_bDisposed) + { + throw lang::DisposedException ("SlideSorterController object has already been disposed", + static_cast<uno::XWeak*>(this)); + } +} + +} // end of namespace ::sd::tools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/TimerBasedTaskExecution.cxx b/sd/source/ui/tools/TimerBasedTaskExecution.cxx new file mode 100644 index 000000000..ae1f2233f --- /dev/null +++ b/sd/source/ui/tools/TimerBasedTaskExecution.cxx @@ -0,0 +1,130 @@ +/* -*- 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 <tools/TimerBasedTaskExecution.hxx> +#include <tools/AsynchronousTask.hxx> +#include <tools/time.hxx> +#include <sal/log.hxx> +#include <memory> + +namespace sd::tools { + +/** Used by the shared_ptr instead of the private destructor. +*/ +class TimerBasedTaskExecution::Deleter +{ +public: + void operator() (TimerBasedTaskExecution* pObject) + { + delete pObject; + } +}; + +std::shared_ptr<TimerBasedTaskExecution> TimerBasedTaskExecution::Create ( + const std::shared_ptr<AsynchronousTask>& rpTask, + sal_uInt32 nMillisecondsBetweenSteps, + sal_uInt32 nMaxTimePerStep) +{ + std::shared_ptr<TimerBasedTaskExecution> pExecution( + new TimerBasedTaskExecution(rpTask,nMillisecondsBetweenSteps,nMaxTimePerStep), + Deleter()); + // Let the new object have a shared_ptr to itself, so that it can + // release itself when the AsynchronousTask has been executed + // completely. + if (pExecution->mpTask != nullptr) + pExecution->mpSelf = pExecution; + return pExecution; +} + +void TimerBasedTaskExecution::Release() +{ + maTimer.Stop(); + mpSelf.reset(); +} + +//static +void TimerBasedTaskExecution::ReleaseTask ( + const std::weak_ptr<TimerBasedTaskExecution>& rpExecution) +{ + if ( rpExecution.expired()) + return; + + try + { + std::shared_ptr<tools::TimerBasedTaskExecution> pExecution (rpExecution); + pExecution->Release(); + } + catch (const std::bad_weak_ptr&) + { + // When a bad_weak_ptr has been thrown then the object pointed + // to by rpTask has been released right after we checked that it + // still existed. Too bad, but that means, that we have nothing + // more do. + } +} + +TimerBasedTaskExecution::TimerBasedTaskExecution ( + const std::shared_ptr<AsynchronousTask>& rpTask, + sal_uInt32 nMillisecondsBetweenSteps, + sal_uInt32 nMaxTimePerStep) + : mpTask(rpTask), + maTimer("sd TimerBasedTaskExecution maTimer"), + mnMaxTimePerStep(nMaxTimePerStep) +{ + maTimer.SetInvokeHandler( LINK(this,TimerBasedTaskExecution,TimerCallback) ); + maTimer.SetTimeout(nMillisecondsBetweenSteps); + maTimer.Start(); +} + +TimerBasedTaskExecution::~TimerBasedTaskExecution() +{ + maTimer.Stop(); +} + +IMPL_LINK_NOARG(TimerBasedTaskExecution, TimerCallback, Timer *, void) +{ + if (mpTask == nullptr) + return; + + if (mpTask->HasNextStep()) + { + // Execute as many steps as fit into the time span of length + // mnMaxTimePerStep. Note that the last step may take longer + // than allowed. + sal_uInt32 nStartTime (::tools::Time( ::tools::Time::SYSTEM ).GetMSFromTime()); + SAL_INFO("sd.tools", __func__ << ": starting TimerBasedTaskExecution at " << nStartTime); + do + { + mpTask->RunNextStep(); + sal_uInt32 nDuration (::tools::Time( ::tools::Time::SYSTEM ).GetMSFromTime()-nStartTime); + SAL_INFO("sd.tools", __func__ << ": executed step in " << nDuration); + if (nDuration > mnMaxTimePerStep) + break; + } + while (mpTask->HasNextStep()); + SAL_INFO("sd.tools", __func__ << ": TimerBasedTaskExecution sleeping"); + maTimer.Start(); + } + else + mpSelf.reset(); +} + +} // end of namespace ::sd::tools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |