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.

Reply via email to