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.akdemir@allotropia.de>
diff --git a/officecfg/registry/schema/org/openoffice/Office/Impress.xcs b/officecfg/registry/schema/org/openoffice/Office/Impress.xcs
index 699cdc7..77319ab 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 de39df7..01f3a1d 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 03c393e..6879513 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 b064eef..501eb0d 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 0000000..e489d8a8
--- /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 0000000..69a74ac
--- /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 fb1ac2c..57395f1 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.