officecfg/registry/schema/org/openoffice/Office/Impress.xcs | 40 + sd/Library_sd.mk | 1 sd/source/ui/framework/module/ImpressModule.cxx | 2 sd/source/ui/framework/module/ModuleController.cxx | 2 sd/source/ui/framework/module/NotesPaneModule.cxx | 268 ++++++++++++ sd/source/ui/framework/module/NotesPaneModule.hxx | 91 ++++ sd/source/ui/inc/framework/factories/BasicPaneFactory.hxx | 1 sd/source/ui/view/NotesPanelView.cxx | 1 8 files changed, 406 insertions(+)
New commits: commit 51436ecfd3d3f31d50dc1f617cb6793398b5dad6 Author: Sarper Akdemir <sarper.akde...@allotropia.de> AuthorDate: Fri May 10 18:38:02 2024 +0200 Commit: Sarper Akdemir <sarper.akde...@allotropia.de> CommitDate: Thu May 16 15:02:03 2024 +0200 tdf#33603: sd: notes pane: force proper flush on page change After clearing the notes pane outliner and filling with then new content, if the new content didn't overfill the previous' area there was a residue from the last content visible. Make sure it is flushed by triggering onResize() on page change. Which also fixes the notespane sometimes keeping the scrollbar & scrollarea from the previous content. Change-Id: Ibbcb0f4f316bd283e5e65bb2ebd9cf17a3b38c0e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167489 Tested-by: Jenkins Reviewed-by: Sarper Akdemir <sarper.akde...@allotropia.de> diff --git a/sd/source/ui/view/NotesPanelView.cxx b/sd/source/ui/view/NotesPanelView.cxx index 02c750db52e3..f95284c25ade 100644 --- a/sd/source/ui/view/NotesPanelView.cxx +++ b/sd/source/ui/view/NotesPanelView.cxx @@ -284,6 +284,7 @@ IMPL_LINK(NotesPanelView, EventMultiplexerListener, tools::EventMultiplexerEvent case EventMultiplexerEventId::MainViewRemoved: case EventMultiplexerEventId::MainViewAdded: FillOutliner(); + onResize(); break; default: break; commit 9d075157ccf3e9468b5208291e398a9d7e4728b8 Author: Sarper Akdemir <sarper.akde...@allotropia.de> AuthorDate: Wed May 8 14:14:58 2024 +0200 Commit: Sarper Akdemir <sarper.akde...@allotropia.de> CommitDate: Thu May 16 15:01:55 2024 +0200 tdf#33603: sd: make state of notes pane persist across runs Introduces new NotesPaneModule which manages the visibility of NotesPane across modes and different runs. Also introduces new three config values under Office/Impress/MuliPaneGUI/NotesPane/Visible ImpressView, OutlineView and NotesView. Similar to what was there for SlideSorterBar. Change-Id: Id540c508e81878e5a8e1aebd6544839e70b813c8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167348 Tested-by: Jenkins Reviewed-by: Sarper Akdemir <sarper.akde...@allotropia.de> diff --git a/officecfg/registry/schema/org/openoffice/Office/Impress.xcs b/officecfg/registry/schema/org/openoffice/Office/Impress.xcs index 699cdc752a2f..77319ab50499 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Impress.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Impress.xcs @@ -1319,6 +1319,46 @@ </info> </set> </group> + <group oor:name="NotesPane"> + <info> + <desc>Values related to the slide sorter.</desc> + <label>Notes Pane Options</label> + </info> + <group oor:name="Visible"> + <info> + <desc>Options that control the visibility of the slide sorter.</desc> + <label>Notes Pane Visibility</label> + </info> + <prop oor:name="ImpressView" oor:type="xs:boolean"> + <info> + <desc>Visibility of the Notes Pane in the Impress view.</desc> + <label>Notes Pane Visibility ImpressView</label> + </info> + <value>false</value> + </prop> + <prop oor:name="OutlineView" oor:type="xs:boolean"> + <info> + <desc>Visibility of the Notes Pane in the Outline view.</desc> + <label>Notes Pane Visibility OutlineView</label> + </info> + <value>false</value> + </prop> + <prop oor:name="NotesView" oor:type="xs:boolean"> + <info> + <desc>Visibility of the Notes Pane in the Notes view.</desc> + <label>Notes Pane Visibility NotesView</label> + </info> + <value>false</value> + </prop> + <prop oor:name="HandoutView" oor:type="xs:boolean"> + <info> + <desc>Visibility of the Notes Pane in the Handout view.</desc> + <label>Notes Pane Visibility HandoutView</label> + </info> + <value>false</value> + </prop> + </group> + </group> <group oor:name="SlideSorterBar"> <info> <desc>Values related to the slide sorter.</desc> diff --git a/sd/Library_sd.mk b/sd/Library_sd.mk index de39df79b25b..01f3a1d59610 100644 --- a/sd/Library_sd.mk +++ b/sd/Library_sd.mk @@ -277,6 +277,7 @@ $(eval $(call gb_Library_add_exception_objects,sd,\ sd/source/ui/framework/module/DrawModule \ sd/source/ui/framework/module/ImpressModule \ sd/source/ui/framework/module/ModuleController \ + sd/source/ui/framework/module/NotesPaneModule \ sd/source/ui/framework/module/PresentationModule \ sd/source/ui/framework/module/ShellStackGuard \ sd/source/ui/framework/module/SlideSorterModule \ diff --git a/sd/source/ui/framework/module/ImpressModule.cxx b/sd/source/ui/framework/module/ImpressModule.cxx index 03c393e29ec4..6879513950a9 100644 --- a/sd/source/ui/framework/module/ImpressModule.cxx +++ b/sd/source/ui/framework/module/ImpressModule.cxx @@ -22,6 +22,7 @@ #include <framework/FrameworkHelper.hxx> #include "ViewTabBarModule.hxx" #include "CenterViewFocusModule.hxx" +#include "NotesPaneModule.hxx" #include "SlideSorterModule.hxx" #include "ToolBarModule.hxx" #include "ShellStackGuard.hxx" @@ -42,6 +43,7 @@ void ImpressModule::Initialize (rtl::Reference<sd::DrawController> const & rxCon new SlideSorterModule( rxController, FrameworkHelper::msLeftImpressPaneURL); + new NotesPaneModule(rxController); new ToolBarModule(rxController); new ShellStackGuard(rxController); } diff --git a/sd/source/ui/framework/module/ModuleController.cxx b/sd/source/ui/framework/module/ModuleController.cxx index b064eefcdad7..501eb0d81af9 100644 --- a/sd/source/ui/framework/module/ModuleController.cxx +++ b/sd/source/ui/framework/module/ModuleController.cxx @@ -52,6 +52,7 @@ ModuleController::ModuleController(const rtl::Reference<::sd::DrawController>& r "com.sun.star.drawing.framework.BasicPaneFactory", { "private:resource/pane/CenterPane", "private:resource/pane/LeftImpressPane", + "private:resource/pane/BottomImpressPane", "private:resource/pane/LeftDrawPane" }); ProcessFactory( "com.sun.star.drawing.framework.BasicViewFactory", @@ -59,6 +60,7 @@ ModuleController::ModuleController(const rtl::Reference<::sd::DrawController>& r "private:resource/view/GraphicView", "private:resource/view/OutlineView", "private:resource/view/NotesView", + "private:resource/view/NotesPanelView", "private:resource/view/HandoutView", "private:resource/view/SlideSorter", "private:resource/view/PresentationView" }); diff --git a/sd/source/ui/framework/module/NotesPaneModule.cxx b/sd/source/ui/framework/module/NotesPaneModule.cxx new file mode 100644 index 000000000000..e489d8a8ff7c --- /dev/null +++ b/sd/source/ui/framework/module/NotesPaneModule.cxx @@ -0,0 +1,268 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 "NotesPaneModule.hxx" + +#include <DrawController.hxx> +#include <DrawViewShell.hxx> +#include <EventMultiplexer.hxx> +#include <ViewShellBase.hxx> +#include <ViewShellManager.hxx> + +#include <framework/ConfigurationController.hxx> +#include <framework/FrameworkHelper.hxx> +#include <framework/ViewShellWrapper.hxx> + +#include <officecfg/Office/Impress.hxx> + +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/frame/XController.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +namespace +{ +const sal_Int32 ResourceActivationRequestEvent = 0; +const sal_Int32 ResourceDeactivationRequestEvent = 1; +} + +namespace sd::framework +{ +NotesPaneModule::NotesPaneModule(const rtl::Reference<::sd::DrawController>& rxController) + : mxBottomImpressPaneId(FrameworkHelper::CreateResourceId( + FrameworkHelper::msNotesPanelViewURL, FrameworkHelper::msBottomImpressPaneURL)) + , mxMainViewAnchorId(FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL)) +{ + if (!rxController.is()) + return; + + mpViewShellBase = rxController->GetViewShellBase(); + + mxConfigurationController = rxController->getConfigurationController(); + if (!mxConfigurationController.is()) + return; + + mxConfigurationController->addConfigurationChangeListener( + this, FrameworkHelper::msResourceActivationRequestEvent, + Any(ResourceActivationRequestEvent)); + mxConfigurationController->addConfigurationChangeListener( + this, FrameworkHelper::msResourceDeactivationRequestEvent, + Any(ResourceDeactivationRequestEvent)); + + if (officecfg::Office::Impress::MultiPaneGUI::NotesPane::Visible::ImpressView::get().value_or( + false)) + AddActiveMainView(FrameworkHelper::msImpressViewURL); + if (officecfg::Office::Impress::MultiPaneGUI::NotesPane::Visible::OutlineView::get().value_or( + false)) + AddActiveMainView(FrameworkHelper::msOutlineViewURL); + if (officecfg::Office::Impress::MultiPaneGUI::NotesPane::Visible::NotesView::get().value_or( + false)) + AddActiveMainView(FrameworkHelper::msNotesViewURL); +} + +NotesPaneModule::~NotesPaneModule() +{ + if (mpViewShellBase && mbListeningEventMultiplexer) + mpViewShellBase->GetEventMultiplexer()->RemoveEventListener( + LINK(this, NotesPaneModule, EventMultiplexerListener)); +} + +void NotesPaneModule::AddActiveMainView(const OUString& rsMainViewURL) +{ + maActiveMainViewContainer.insert(rsMainViewURL); +} + +bool NotesPaneModule::IsResourceActive(const OUString& rsMainViewURL) +{ + return maActiveMainViewContainer.contains(rsMainViewURL); +} + +void NotesPaneModule::SaveResourceState() +{ + auto xChanges = comphelper::ConfigurationChanges::create(); + officecfg::Office::Impress::MultiPaneGUI::NotesPane::Visible::ImpressView::set( + IsResourceActive(FrameworkHelper::msImpressViewURL), xChanges); + officecfg::Office::Impress::MultiPaneGUI::NotesPane::Visible::OutlineView::set( + IsResourceActive(FrameworkHelper::msOutlineViewURL), xChanges); + officecfg::Office::Impress::MultiPaneGUI::NotesPane::Visible::NotesView::set( + IsResourceActive(FrameworkHelper::msNotesViewURL), xChanges); + xChanges->commit(); +} + +void NotesPaneModule::disposing(std::unique_lock<std::mutex>&) +{ + if (mxConfigurationController.is()) + { + mxConfigurationController->removeConfigurationChangeListener(this); + mxConfigurationController = nullptr; + } +} + +IMPL_LINK(NotesPaneModule, EventMultiplexerListener, sd::tools::EventMultiplexerEvent&, rEvent, + void) +{ + if (!mxConfigurationController.is()) + return; + + switch (rEvent.meEventId) + { + case EventMultiplexerEventId::EditModeNormal: + mbInMasterEditMode = false; + if (IsResourceActive(msCurrentMainViewURL)) + { + mxConfigurationController->requestResourceActivation( + mxBottomImpressPaneId->getAnchor(), ResourceActivationMode_ADD); + mxConfigurationController->requestResourceActivation( + mxBottomImpressPaneId, ResourceActivationMode_REPLACE); + } + else + { + mxConfigurationController->requestResourceDeactivation(mxBottomImpressPaneId); + } + break; + case EventMultiplexerEventId::EditModeMaster: + mbInMasterEditMode = true; + mxConfigurationController->requestResourceDeactivation(mxBottomImpressPaneId); + break; + default: + break; + } +} + +void SAL_CALL NotesPaneModule::notifyConfigurationChange(const ConfigurationChangeEvent& rEvent) +{ + if (!mxConfigurationController.is()) + return; + + // the late init is hacked here since there's EventMultiplexer isn't available when the + // NotesPaneModule is constructed + if (!mbListeningEventMultiplexer) + { + mpViewShellBase->GetEventMultiplexer()->AddEventListener( + LINK(this, NotesPaneModule, EventMultiplexerListener)); + mbListeningEventMultiplexer = true; + } + + sal_Int32 nEventType = 0; + rEvent.UserData >>= nEventType; + switch (nEventType) + { + case ResourceActivationRequestEvent: + if (rEvent.ResourceId->isBoundToURL(FrameworkHelper::msCenterPaneURL, + AnchorBindingMode_DIRECT)) + { + if (rEvent.ResourceId->getResourceTypePrefix() == FrameworkHelper::msViewURLPrefix) + { + onMainViewSwitch(rEvent.ResourceId->getResourceURL(), true); + } + } + else if (rEvent.ResourceId->compareTo(mxBottomImpressPaneId) == 0) + { + onResourceRequest(true, rEvent.Configuration); + } + break; + + case ResourceDeactivationRequestEvent: + if (rEvent.ResourceId->compareTo(mxMainViewAnchorId) == 0) + { + onMainViewSwitch(OUString(), false); + } + else if (rEvent.ResourceId->compareTo(mxBottomImpressPaneId) == 0) + { + onResourceRequest(false, rEvent.Configuration); + } + break; + default: + break; + } +} + +void SAL_CALL NotesPaneModule::disposing(const lang::EventObject& rEvent) +{ + if (mxConfigurationController.is() && rEvent.Source == mxConfigurationController) + { + SaveResourceState(); + // Without the configuration controller this class can do nothing. + mxConfigurationController = nullptr; + dispose(); + } +} + +void NotesPaneModule::onMainViewSwitch(const OUString& rsViewURL, const bool bIsActivated) +{ + if (bIsActivated) + msCurrentMainViewURL = rsViewURL; + else + msCurrentMainViewURL.clear(); + + if (!mxConfigurationController.is()) + return; + + sd::framework::ConfigurationController::Lock aLock(mxConfigurationController); + + if (IsResourceActive(msCurrentMainViewURL) && !mbInMasterEditMode) + { + mxConfigurationController->requestResourceActivation(mxBottomImpressPaneId->getAnchor(), + ResourceActivationMode_ADD); + mxConfigurationController->requestResourceActivation(mxBottomImpressPaneId, + ResourceActivationMode_REPLACE); + } + else + { + mxConfigurationController->requestResourceDeactivation(mxBottomImpressPaneId); + } +} + +bool NotesPaneModule::IsMasterView(const Reference<XView>& xView) +{ + if (mpViewShellBase != nullptr) + { + auto pViewShellWrapper = dynamic_cast<ViewShellWrapper*>(xView.get()); + if (pViewShellWrapper) + { + std::shared_ptr<ViewShell> pViewShell = pViewShellWrapper->GetViewShell(); + auto pDrawViewShell = std::dynamic_pointer_cast<DrawViewShell>(pViewShell); + + if (pDrawViewShell && pDrawViewShell->GetEditMode() == EditMode::MasterPage) + return true; + } + } + return false; +} + +void NotesPaneModule::onResourceRequest( + bool bActivation, + const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration) +{ + Sequence<Reference<XResourceId>> aCenterViews = rxConfiguration->getResources( + FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL), + FrameworkHelper::msViewURLPrefix, AnchorBindingMode_DIRECT); + + if (aCenterViews.getLength() != 1) + return; + + // do not record the state of bottom pane when in master edit modes + if (!IsMasterView({ mxConfigurationController->getResource(aCenterViews[0]), UNO_QUERY })) + { + if (bActivation) + { + maActiveMainViewContainer.insert(aCenterViews[0]->getResourceURL()); + } + else + { + maActiveMainViewContainer.erase(aCenterViews[0]->getResourceURL()); + } + } +} + +} // end of namespace sd::framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sd/source/ui/framework/module/NotesPaneModule.hxx b/sd/source/ui/framework/module/NotesPaneModule.hxx new file mode 100644 index 000000000000..69a74acbdf0c --- /dev/null +++ b/sd/source/ui/framework/module/NotesPaneModule.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 + +#include <com/sun/star/drawing/framework/XConfigurationChangeListener.hpp> +#include <comphelper/compbase.hxx> +#include <rtl/ref.hxx> +#include <tools/link.hxx> +#include <set> + +namespace com::sun::star::drawing::framework +{ +class XConfigurationController; +class XView; +} +namespace com::sun::star::frame +{ +class XController; +} +namespace sd +{ +class DrawController; +class ViewShellBase; +} +namespace sd::tools +{ +class EventMultiplexerEvent; +} + +namespace sd::framework +{ +/** This module is responsible for handling visibility of NotesPane across modes +*/ +class NotesPaneModule : public comphelper::WeakComponentImplHelper< + css::drawing::framework::XConfigurationChangeListener> +{ +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. + */ + NotesPaneModule(const rtl::Reference<::sd::DrawController>& rxController); + virtual ~NotesPaneModule() override; + + void AddActiveMainView(const OUString& rsMainViewURL); + bool IsResourceActive(const OUString& rsMainViewURL); + void SaveResourceState(); + + virtual void disposing(std::unique_lock<std::mutex>&) override; + + // XConfigurationChangeListener + + virtual void SAL_CALL notifyConfigurationChange( + const css::drawing::framework::ConfigurationChangeEvent& rEvent) override; + + // XEventListener + + virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; + +private: + css::uno::Reference<css::drawing::framework::XConfigurationController> + mxConfigurationController; + + css::uno::Reference<css::drawing::framework::XResourceId> mxBottomImpressPaneId; + css::uno::Reference<css::drawing::framework::XResourceId> mxMainViewAnchorId; + + std::set<OUString> maActiveMainViewContainer; + OUString msCurrentMainViewURL; + ViewShellBase* mpViewShellBase; + bool mbListeningEventMultiplexer = false; + bool mbInMasterEditMode = false; + + void onMainViewSwitch(const OUString& rsViewURL, const bool bIsActivated); + void onResourceRequest( + bool bActivation, + const css::uno::Reference<css::drawing::framework::XConfiguration>& rxConfiguration); + bool IsMasterView(const css::uno::Reference<css::drawing::framework::XView>& xView); + + DECL_LINK(EventMultiplexerListener, ::sd::tools::EventMultiplexerEvent&, void); +}; + +} // end of namespace sd::framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sd/source/ui/inc/framework/factories/BasicPaneFactory.hxx b/sd/source/ui/inc/framework/factories/BasicPaneFactory.hxx index fb1ac2cf8236..57395f196bf4 100644 --- a/sd/source/ui/inc/framework/factories/BasicPaneFactory.hxx +++ b/sd/source/ui/inc/framework/factories/BasicPaneFactory.hxx @@ -47,6 +47,7 @@ typedef comphelper::WeakComponentImplHelper < private:resource/pane/CenterPane private:resource/pane/FullScreenPane private:resource/pane/LeftImpressPane + private:resource/pane/BottomImpressPane 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.