diff options
author | Sarper Akdemir <sarper.akdemir.extern@allotropia.de> | 2023-11-09 20:18:44 +0300 |
---|---|---|
committer | Thorsten Behrens <thorsten.behrens@allotropia.de> | 2024-02-22 13:51:47 +0100 |
commit | 71a7fdfae4d350c950fec5a8b59ad45168945a28 (patch) | |
tree | 0386d39292895f5a0eab07e560e4cfe8b28d4c86 | |
parent | 75275cf453975f9b391e024b0431869496db0189 (diff) |
tdf#33603: sd: add notes panel for normal viewcib_contract49-7.6.5.2.M1
Change-Id: Ibc6e8a3f126c443453c5ecab52ba988a4f4f56e6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159288
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
-rw-r--r-- | officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu | 8 | ||||
-rw-r--r-- | sd/Library_sd.mk | 1 | ||||
-rw-r--r-- | sd/UIConfig_simpress.mk | 2 | ||||
-rw-r--r-- | sd/inc/strings.hrc | 1 | ||||
-rw-r--r-- | sd/source/ui/app/sddll.cxx | 2 | ||||
-rw-r--r-- | sd/source/ui/dlg/NotesChildWindow.cxx | 632 | ||||
-rw-r--r-- | sd/source/ui/inc/NotesChildWindow.hxx | 108 | ||||
-rw-r--r-- | sd/source/ui/view/ViewShellBase.cxx | 24 | ||||
-rw-r--r-- | sd/source/ui/view/drvwshrg.cxx | 3 | ||||
-rw-r--r-- | sd/uiconfig/simpress/menubar/menubar.xml | 1 | ||||
-rw-r--r-- | sd/uiconfig/simpress/ui/noteschildwindow.ui | 41 | ||||
-rw-r--r-- | sd/uiconfig/simpress/ui/notespanelcontextmenu.ui | 9 |
12 files changed, 832 insertions, 0 deletions
diff --git a/officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu index cca1b2ec38ae..618dbfa0d837 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu @@ -24,6 +24,14 @@ <value xml:lang="en-US">S~lide</value> </prop> </node> + <node oor:name=".uno:NotesChildWindow" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Notes Panel</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:PageMenu" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">~Page</value> diff --git a/sd/Library_sd.mk b/sd/Library_sd.mk index 926dd86ee755..d7483cb77c25 100644 --- a/sd/Library_sd.mk +++ b/sd/Library_sd.mk @@ -232,6 +232,7 @@ $(eval $(call gb_Library_add_exception_objects,sd,\ sd/source/ui/dlg/AnimationChildWindow \ sd/source/ui/dlg/LayerTabBar \ sd/source/ui/dlg/NavigatorChildWindow \ + sd/source/ui/dlg/NotesChildWindow \ sd/source/ui/dlg/PaneChildWindows \ sd/source/ui/dlg/PaneShells \ sd/source/ui/dlg/SpellDialogChildWindow \ diff --git a/sd/UIConfig_simpress.mk b/sd/UIConfig_simpress.mk index ab6b2875e7bc..f0395c7646f2 100644 --- a/sd/UIConfig_simpress.mk +++ b/sd/UIConfig_simpress.mk @@ -147,6 +147,8 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/simpress,\ sd/uiconfig/simpress/ui/notebookbar_groupedbar_full \ sd/uiconfig/simpress/ui/notebookbar_groupedbar_compact \ sd/uiconfig/simpress/ui/notebookbar_online \ + sd/uiconfig/simpress/ui/noteschildwindow \ + sd/uiconfig/simpress/ui/notespanelcontextmenu \ sd/uiconfig/simpress/ui/optimpressgeneralpage \ sd/uiconfig/simpress/ui/pagesfieldbox \ sd/uiconfig/simpress/ui/photoalbum \ diff --git a/sd/inc/strings.hrc b/sd/inc/strings.hrc index 3e1ddd1542e7..adf9f6538129 100644 --- a/sd/inc/strings.hrc +++ b/sd/inc/strings.hrc @@ -315,6 +315,7 @@ #define STR_PRESOBJ_OUTLINE NC_("STR_PRESOBJ_OUTLINE", "Click to add Text" ) #define STR_PRESOBJ_TEXT NC_("STR_PRESOBJ_TEXT", "Click to add Text" ) #define STR_PRESOBJ_NOTESTEXT NC_("STR_PRESOBJ_NOTESTEXT", "Click to add Notes" ) +#define STR_PRESOBJ_NOTESTEXT_MISSING NC_("STR_PRESOBJ_NOTESTEXT_MISSING", "Notes placeholder object is missing for the current slide." ) #define STR_PRESOBJ_TITLE_MOBILE NC_("STR_PRESOBJ_TITLE_MOBILE", "Double-tap to add Title" ) #define STR_PRESOBJ_OUTLINE_MOBILE NC_("STR_PRESOBJ_OUTLINE_MOBILE", "Double-tap to add Text" ) #define STR_PRESOBJ_TEXT_MOBILE NC_("STR_PRESOBJ_TEXT_MOBILE", "Double-tap to add Text" ) diff --git a/sd/source/ui/app/sddll.cxx b/sd/source/ui/app/sddll.cxx index b4734310a39b..331c32afe5a7 100644 --- a/sd/source/ui/app/sddll.cxx +++ b/sd/source/ui/app/sddll.cxx @@ -48,6 +48,7 @@ #include <OutlineViewShell.hxx> #include <OutlineViewShellBase.hxx> #include <PaneChildWindows.hxx> +#include <NotesChildWindow.hxx> #include <SpellDialogChildWindow.hxx> #include <SlideSorterViewShell.hxx> #include <SlideSorterViewShellBase.hxx> @@ -178,6 +179,7 @@ void SdDLL::RegisterControllers(SdModule* pMod) ::sd::LeftPaneImpressChildWindow::RegisterChildWindow(false, pMod); ::sd::LeftPaneDrawChildWindow::RegisterChildWindow(false, pMod); ::sfx2::sidebar::SidebarChildWindow::RegisterChildWindow(false, pMod); + ::sd::NotesChildWindow::RegisterChildWindow(false, pMod); DevelopmentToolChildWindow::RegisterChildWindow(false, pMod); ::sd::SdNavigatorWrapper::RegisterChildWindow(false, pMod, SfxChildWindowFlags::NEVERHIDE); diff --git a/sd/source/ui/dlg/NotesChildWindow.cxx b/sd/source/ui/dlg/NotesChildWindow.cxx new file mode 100644 index 000000000000..0ab856da55ef --- /dev/null +++ b/sd/source/ui/dlg/NotesChildWindow.cxx @@ -0,0 +1,632 @@ +/* -*- 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 <DrawDocShell.hxx> +#include <DrawViewShell.hxx> +#include <EventMultiplexer.hxx> +#include <NotesChildWindow.hxx> +#include <Outliner.hxx> +#include <ViewShellBase.hxx> +#include <app.hrc> +#include <config_wasm_strip.h> +#include <drawdoc.hxx> +#include <drawview.hxx> +#include <sdpage.hxx> +#include <sdresid.hxx> + +#include <editeng/crossedoutitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editstat.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/ptrstyle.hxx> +#include <strings.hrc> + +namespace sd +{ +SFX_IMPL_DOCKINGWINDOW_WITHID(NotesChildWindow, SID_NOTES_WINDOW); + +NotesChildWindow::NotesChildWindow(vcl::Window* pParentWindow, sal_uInt16 nId, + SfxBindings* pBindings, SfxChildWinInfo* pInfo) + : SfxChildWindow(pParentWindow, nId) +{ + VclPtr<NotesChildDockingWindow> pWin + = VclPtr<NotesChildDockingWindow>::Create(pBindings, this, pParentWindow); + SetWindow(pWin); + SetAlignment(SfxChildAlignment::BOTTOM); + pWin->setDeferredProperties(); + pWin->SetSizePixel({ 200, 200 }); + pWin->set_border_width(3); + pWin->set_margin_top(11); + pWin->Initialize(pInfo); +} + +NotesChildDockingWindow::NotesChildDockingWindow(SfxBindings* _pBindings, + SfxChildWindow* pChildWindow, Window* pParent) + : SfxDockingWindow(_pBindings, pChildWindow, pParent, "NotesChildEditWindow", + "modules/simpress/ui/noteschildwindow.ui") + , mpViewShellBase(ViewShellBase::GetViewShellBase(_pBindings->GetDispatcher()->GetFrame())) + , m_xEditWindow( + new NotesEditWindow(*this, m_xBuilder->weld_scrolled_window("scrolledwin", true))) +{ + mpOutliner = std::make_unique<Outliner>(&mpViewShellBase->GetDocShell()->GetPool(), + OutlinerMode::TextObject); + + mpOutlinerView = std::make_unique<OutlinerView>(mpOutliner.get(), nullptr); + mpOutliner->InsertView(mpOutlinerView.get()); + + m_xEditWindowWeld + = std::make_unique<weld::CustomWeld>(*m_xBuilder, "noteschildeditview", *m_xEditWindow); +} + +DrawViewShell* NotesChildDockingWindow::GetDrawViewShell() +{ + auto pDocShell = GetViewShellBase()->GetDocShell(); + if (!pDocShell) + return nullptr; + + return dynamic_cast<DrawViewShell*>(pDocShell->GetViewShell()); +} + +NotesChildDockingWindow::~NotesChildDockingWindow() { disposeOnce(); } + +void NotesChildDockingWindow::dispose() +{ + m_xEditWindow.reset(); + m_xEditWindowWeld.reset(); + SfxDockingWindow::dispose(); +} + +NotesEditWindow::NotesEditWindow(NotesChildDockingWindow& rParentWindow, + std::unique_ptr<weld::ScrolledWindow> pScrolledWindow) + : mrParentWindow(rParentWindow) + , m_xScrolledWindow(std::move(pScrolledWindow)) + , aModifyIdle("NotesEditWindow ModifyIdle") +{ + aModifyIdle.SetInvokeHandler(LINK(this, NotesEditWindow, ModifyTimerHdl)); + aModifyIdle.SetPriority(TaskPriority::LOWEST); + + SetAcceptsTab(true); + m_xScrolledWindow->connect_vadjustment_changed(LINK(this, NotesEditWindow, ScrollHdl)); +} + +NotesEditWindow::~NotesEditWindow() +{ + aModifyIdle.Stop(); + m_xScrolledWindow.reset(); + if (!mrParentWindow.GetViewShellBase()) + return; + + mrParentWindow.GetViewShellBase()->GetEventMultiplexer()->RemoveEventListener( + LINK(this, NotesEditWindow, EventMultiplexerListener)); +} + +IMPL_LINK(NotesEditWindow, EventMultiplexerListener, tools::EventMultiplexerEvent&, rEvent, void) +{ + switch (rEvent.meEventId) + { + case EventMultiplexerEventId::CurrentPageChanged: + case EventMultiplexerEventId::MainViewRemoved: + case EventMultiplexerEventId::MainViewAdded: + provideNoteText(); + break; + default: + break; + } +} + +void NotesEditWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + Size aSize(pDrawingArea->get_size_request()); + if (aSize.Width() == -1) + aSize.setWidth(500); + if (aSize.Height() == -1) + aSize.setHeight(100); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + + SetOutputSizePixel(aSize); + + weld::CustomWidgetController::SetDrawingArea(pDrawingArea); + + EnableRTL(false); + + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + Color aBgColor = rStyleSettings.GetWindowColor(); + + OutputDevice& rDevice = pDrawingArea->get_ref_device(); + + rDevice.SetMapMode(MapMode(MapUnit::MapTwip)); + rDevice.SetBackground(aBgColor); + + Size aOutputSize(rDevice.PixelToLogic(aSize)); + + EditView* pEditView = GetEditView(); + pEditView->setEditViewCallbacks(this); + + EditEngine* pEditEngine = GetEditEngine(); + pEditEngine->SetPaperSize(aOutputSize); + pEditEngine->SetRefDevice(&rDevice); + + pEditEngine->SetControlWord(pEditEngine->GetControlWord() | EEControlBits::MARKFIELDS); + pEditView->SetOutputArea(::tools::Rectangle(Point(0, 0), aOutputSize)); + + pEditView->SetBackgroundColor(aBgColor); + + pDrawingArea->set_cursor(PointerStyle::Text); + +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + InitAccessible(); +#endif + + mrParentWindow.GetViewShellBase()->GetEventMultiplexer()->AddEventListener( + LINK(this, NotesEditWindow, EventMultiplexerListener)); + + // For setGlobalScale to work correctly EEControlBits::STRETCHING must be set. + mrParentWindow.GetOutliner()->SetControlWord(mrParentWindow.GetOutliner()->GetControlWord() + | EEControlBits::STRETCHING); + mrParentWindow.GetOutliner()->setGlobalScale(30.0, 30.0); + + provideNoteText(); + + GetEditEngine()->SetStatusEventHdl(LINK(this, NotesEditWindow, EditStatusHdl)); +} + +void NotesEditWindow::doScroll() +{ + if (m_xEditView) + { + auto currentDocPos = m_xEditView->GetVisArea().Top(); + auto nDiff = currentDocPos - m_xScrolledWindow->vadjustment_get_value(); + // we expect SetScrollBarRange callback to be triggered by Scroll + // to set where we ended up + m_xEditView->Scroll(0, nDiff); + } +} + +void NotesEditWindow::setScrollBarRange() +{ + EditEngine* pEditEngine = GetEditEngine(); + if (!pEditEngine) + return; + if (!m_xScrolledWindow) + return; + EditView* pEditView = GetEditView(); + if (!pEditView) + return; + + int nVUpper = pEditEngine->GetTextHeight(); + int nVCurrentDocPos = pEditView->GetVisArea().Top(); + const Size aOut(pEditView->GetOutputArea().GetSize()); + int nVStepIncrement = aOut.Height() * 2 / 10; + int nVPageIncrement = aOut.Height() * 8 / 10; + int nVPageSize = aOut.Height(); + + /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has + effectively... + + lower = gtk_adjustment_get_lower + upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size + + and requires that upper > lower or the deceleration animation never ends + */ + nVPageSize = std::min(nVPageSize, nVUpper); + + m_xScrolledWindow->vadjustment_configure(nVCurrentDocPos, 0, nVUpper, nVStepIncrement, + nVPageIncrement, nVPageSize); +} + +void NotesEditWindow::showContextMenu(const Point& rPos) +{ + ::tools::Rectangle aRect(rPos, Size(1, 1)); + weld::Widget* pPopupParent = GetDrawingArea(); + std::unique_ptr<weld::Builder> xBuilder( + Application::CreateBuilder(pPopupParent, "modules/simpress/ui/notespanelcontextmenu.ui")); + std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu")); + + auto xFrame = mrParentWindow.GetDrawViewShell()->GetViewFrame()->GetFrame().GetFrameInterface(); + OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame)); + + SfxItemSet aSet(mrParentWindow.GetOutlinerView()->GetAttribs()); + int nInsertPos = 0; + xMenu->insert(nInsertPos++, ".uno:Bold", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:Bold", aModuleName)), + nullptr, nullptr, + vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Bold", xFrame), + TRISTATE_TRUE); + + if (aSet.GetItemState(EE_CHAR_WEIGHT) == SfxItemState::SET) + { + if (aSet.Get(EE_CHAR_WEIGHT).GetWeight() == WEIGHT_BOLD) + xMenu->set_active(".uno:Bold", true); + } + + xMenu->insert(nInsertPos++, ".uno:Italic", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:Italic", aModuleName)), + nullptr, nullptr, + vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Italic", xFrame), + TRISTATE_TRUE); + + if (aSet.GetItemState(EE_CHAR_ITALIC) == SfxItemState::SET) + { + if (aSet.Get(EE_CHAR_ITALIC).GetPosture() != ITALIC_NONE) + xMenu->set_active(".uno:Italic", true); + } + + xMenu->insert( + nInsertPos++, ".uno:Underline", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:Underline", aModuleName)), + nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Underline", xFrame), + TRISTATE_TRUE); + + if (aSet.GetItemState(EE_CHAR_UNDERLINE) == SfxItemState::SET) + { + if (aSet.Get(EE_CHAR_UNDERLINE).GetLineStyle() != LINESTYLE_NONE) + xMenu->set_active(".uno:Underline", true); + } + + xMenu->insert( + nInsertPos++, ".uno:Strikeout", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:Strikeout", aModuleName)), + nullptr, nullptr, vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Strikeout", xFrame), + TRISTATE_TRUE); + + if (aSet.GetItemState(EE_CHAR_STRIKEOUT) == SfxItemState::SET) + { + if (aSet.Get(EE_CHAR_STRIKEOUT).GetStrikeout() != STRIKEOUT_NONE) + xMenu->set_active(".uno:Strikeout", true); + } + + xMenu->insert_separator(nInsertPos++, "separator2"); + + xMenu->insert(nInsertPos++, ".uno:Copy", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:Copy", aModuleName)), + nullptr, nullptr, + vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Copy", xFrame), + TRISTATE_INDET); + + xMenu->insert(nInsertPos++, ".uno:Paste", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:Paste", aModuleName)), + nullptr, nullptr, + vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:Paste", xFrame), + TRISTATE_INDET); + + bool bCanPaste = false; + { + TransferableDataHelper aDataHelper( + TransferableDataHelper::CreateFromClipboard(GetClipboard())); + bCanPaste = aDataHelper.GetFormatCount() != 0; + } + + xMenu->insert_separator(nInsertPos++, "separator3"); + + xMenu->insert( + nInsertPos++, ".uno:DefaultBullet", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:DefaultBullet", aModuleName)), + nullptr, nullptr, + vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:DefaultBullet", xFrame), + TRISTATE_TRUE); + + ESelection aSel(GetEditView()->GetSelection()); + aSel.Adjust(); + bool bBulletsEnabled = true; + for (sal_Int32 nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++) + { + if (mrParentWindow.GetOutliner()->GetDepth(nPara) == -1) + { + bBulletsEnabled = false; + break; + } + } + + if (bBulletsEnabled) + xMenu->set_active(".uno:DefaultBullet", true); + + xMenu->insert( + nInsertPos++, ".uno:OutlineLeft", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:OutlineLeft", aModuleName)), + nullptr, nullptr, + vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:OutlineLeft", xFrame), + TRISTATE_INDET); + + xMenu->insert( + nInsertPos++, ".uno:OutlineRight", + vcl::CommandInfoProvider::GetMenuLabelForCommand( + vcl::CommandInfoProvider::GetCommandProperties(".uno:OutlineRight", aModuleName)), + nullptr, nullptr, + vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:OutlineRight", xFrame), + TRISTATE_INDET); + + xMenu->set_sensitive(".uno:Copy", mrParentWindow.GetOutlinerView()->HasSelection()); + xMenu->set_sensitive(".uno:Paste", bCanPaste); + + auto sId = xMenu->popup_at_rect(pPopupParent, aRect); + + if (sId == ".uno:Copy") + { + mrParentWindow.GetOutlinerView()->Copy(); + } + else if (sId == ".uno:Paste") + { + mrParentWindow.GetOutlinerView()->PasteSpecial(); + } + else if (sId == ".uno:DefaultBullet") + { + mrParentWindow.GetOutlinerView()->ToggleBullets(); + } + else if (sId == ".uno:OutlineLeft" || sId == ".uno:OutlineRight") + { + bool isOutlineLeft = sId == ".uno:OutlineLeft"; + for (sal_Int32 nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++) + { + auto nCurrentDepth = mrParentWindow.GetOutliner()->GetDepth(nPara); + if (nCurrentDepth == -1) + continue; + + mrParentWindow.GetOutlinerView()->SetDepth(nPara, isOutlineLeft ? --nCurrentDepth + : ++nCurrentDepth); + } + } + else if (!sId.isEmpty()) + { + SfxItemSet aEditAttr(mrParentWindow.GetOutlinerView()->GetAttribs()); + SfxItemSet aNewAttr(mrParentWindow.GetOutliner()->GetEmptyItemSet()); + + if (sId == ".uno:Bold") + { + FontWeight eFW = aEditAttr.Get(EE_CHAR_WEIGHT).GetWeight(); + aNewAttr.Put( + SvxWeightItem(eFW == WEIGHT_NORMAL ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT)); + } + else if (sId == ".uno:Italic") + { + FontItalic eFI = aEditAttr.Get(EE_CHAR_ITALIC).GetPosture(); + aNewAttr.Put( + SvxPostureItem(eFI == ITALIC_NORMAL ? ITALIC_NONE : ITALIC_NORMAL, EE_CHAR_ITALIC)); + } + else if (sId == ".uno:Underline") + { + FontLineStyle eFU = aEditAttr.Get(EE_CHAR_UNDERLINE).GetLineStyle(); + aNewAttr.Put(SvxUnderlineItem( + eFU == LINESTYLE_SINGLE ? LINESTYLE_NONE : LINESTYLE_SINGLE, EE_CHAR_UNDERLINE)); + } + else if (sId == ".uno:Strikeout") + { + FontStrikeout eFSO = aEditAttr.Get(EE_CHAR_STRIKEOUT).GetStrikeout(); + aNewAttr.Put(SvxCrossedOutItem( + eFSO == STRIKEOUT_SINGLE ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, EE_CHAR_STRIKEOUT)); + } + + mrParentWindow.GetOutlinerView()->SetAttribs(aNewAttr); + } +} + +void NotesEditWindow::EditViewScrollStateChange() { setScrollBarRange(); } + +EditView* NotesEditWindow::GetEditView() const +{ + if (!mrParentWindow.GetOutlinerView()) + return nullptr; + return &mrParentWindow.GetOutlinerView()->GetEditView(); +} + +EditEngine* NotesEditWindow::GetEditEngine() const +{ + if (!mrParentWindow.GetOutlinerView()) + return nullptr; + return mrParentWindow.GetOutlinerView()->GetEditView().GetEditEngine(); +} + +void NotesEditWindow::GetFocus() +{ + if (auto pDrawViewShell = mrParentWindow.GetDrawViewShell()) + { + if (auto pDrawView = pDrawViewShell->GetDrawView()) + { + pDrawView->EndTextEditCurrentView(); + pDrawView->UnmarkAll(); + } + } + + if (mpTextObj && mpTextObj->IsEmptyPresObj()) + { + // clear the "Click to add Notes" text on enter of the window. + mrParentWindow.GetOutliner()->SetToEmptyText(); + } + WeldEditView::GetFocus(); +} + +bool NotesEditWindow::CanFocus() const +{ + auto pDocShell = mrParentWindow.GetViewShellBase()->GetDocShell(); + if (pDocShell && pDocShell->IsReadOnly()) + return false; + + return mpTextObj; +} + +void NotesEditWindow::LoseFocus() +{ + aModifyIdle.Stop(); + if (mpTextObj) + { + if (GetText().getLength() == 0) + { + // if the notes are empty restore the placeholder text and state. + SdPage* pPage = dynamic_cast<SdPage*>(mpTextObj->getSdrPageFromSdrObject()); + if (pPage) + pPage->RestoreDefaultText(mpTextObj); + } + else + setNotesToDoc(); + } + + WeldEditView::LoseFocus(); +} + +bool NotesEditWindow::Command(const CommandEvent& rCEvt) +{ + if (rCEvt.GetCommand() == CommandEventId::ContextMenu) + { + showContextMenu(rCEvt.GetMousePosPixel()); + return true; + } + + return WeldEditView::Command(rCEvt); +} + +void NotesEditWindow::provideNoteText() +{ + removeListener(); + mpTextObj = nullptr; + SetText(SdResId(STR_PRESOBJ_NOTESTEXT_MISSING)); + + const auto pDrawViewShell = mrParentWindow.GetDrawViewShell(); + if (!pDrawViewShell) + return; + + SdPage* pCurrentPage = pDrawViewShell->getCurrentPage(); + if (!pCurrentPage) + return; + + SdDrawDocument* pDoc = pDrawViewShell->GetDoc(); + if (!pDoc) + return; + + SdPage* pNotesPage = pDoc->GetSdPage((pCurrentPage->GetPageNum() - 1) >> 1, PageKind::Notes); + if (!pNotesPage) + return; + + SdrObject* pNotesObj = pNotesPage->GetPresObj(PresObjKind::Notes); + if (!pNotesObj) + return; + + mpTextObj = dynamic_cast<SdrTextObj*>(pNotesObj); + addListener(); + getNotesFromDoc(); +} + +void NotesEditWindow::removeListener() +{ + if (mpTextObj) + mpTextObj->RemoveListener(*this); +} +void NotesEditWindow::addListener() +{ + if (mpTextObj) + mpTextObj->AddListener(*this); +} + +void NotesEditWindow::setListenerIgnored(bool bIgnore) { mbIgnoreNotifications = bIgnore; } +bool NotesEditWindow::isListenerIgnored() { return mbIgnoreNotifications; } + +void NotesEditWindow::getNotesFromDoc() +{ + if (!mpTextObj) + return; + + // Ignore notifications that will rebound from updating the text + SetModifyHdl(Link<LinkParamNone*, void>()); + setListenerIgnored(true); + + if (OutlinerParaObject* pPara = mpTextObj->GetOutlinerParaObject()) + mrParentWindow.GetOutliner()->SetText(*pPara); + + setListenerIgnored(false); + SetModifyHdl(LINK(this, NotesEditWindow, EditModifiedHdl)); +} + +void NotesEditWindow::setNotesToDoc() +{ + if (!mpTextObj) + return; + + setListenerIgnored(true); + + std::optional<OutlinerParaObject> pNewText = mrParentWindow.GetOutliner()->CreateParaObject(); + mpTextObj->SetOutlinerParaObject(std::move(pNewText)); + if (mpTextObj->IsEmptyPresObj()) + mpTextObj->SetEmptyPresObj(false); + + setListenerIgnored(false); +} + +void NotesEditWindow::Notify(SfxBroadcaster&, const SfxHint& rHint) +{ + if (isListenerIgnored()) + return; + + if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint) + { + const SdrHint& rSdrHint = reinterpret_cast<const SdrHint&>(rHint); + switch (rSdrHint.GetKind()) + { + case SdrHintKind::ObjectRemoved: + case SdrHintKind::ModelCleared: + provideNoteText(); + break; + case SdrHintKind::ObjectChange: + case SdrHintKind::EndEdit: + getNotesFromDoc(); + break; + default: + break; + } + } +} + +IMPL_LINK_NOARG(NotesEditWindow, EditStatusHdl, EditStatus&, void) { Resize(); } + +IMPL_LINK_NOARG(NotesEditWindow, EditModifiedHdl, LinkParamNone*, void) +{ + // EditEngine calls ModifyHdl many times in succession for some edits. + // (e.g. when deleting multiple lines) + // Debounce the rapid ModifyHdl calls using a timer. + aModifyIdle.Start(); + return; +} + +IMPL_LINK_NOARG(NotesEditWindow, ModifyTimerHdl, Timer*, void) +{ + setNotesToDoc(); + aModifyIdle.Stop(); +} + +IMPL_LINK(NotesEditWindow, ScrollHdl, weld::ScrolledWindow&, rScrolledWindow, void) +{ + if (EditView* pEditView = GetEditView()) + { + pEditView->SetVisArea(::tools::Rectangle(Point(0, rScrolledWindow.vadjustment_get_value()), + pEditView->GetVisArea().GetSize())); + pEditView->Invalidate(); + } + doScroll(); +} + +} // end of namespace ::sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sd/source/ui/inc/NotesChildWindow.hxx b/sd/source/ui/inc/NotesChildWindow.hxx new file mode 100644 index 000000000000..5242595bcb24 --- /dev/null +++ b/sd/source/ui/inc/NotesChildWindow.hxx @@ -0,0 +1,108 @@ +/* -*- 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 <svx/weldeditview.hxx> +#include <sfx2/dockwin.hxx> + +class Outliner; +class OutlinerView; +class SdrTextObj; + +namespace sd::tools +{ +class EventMultiplexerEvent; +} + +namespace sd +{ +class ViewShellBase; +class DrawViewShell; +class NotesChildWindow; +class NotesEditWindow; +class NotesChildDockingWindow; + +class NotesEditWindow : public WeldEditView, public SfxListener +{ + NotesChildDockingWindow& mrParentWindow; + std::unique_ptr<weld::ScrolledWindow> m_xScrolledWindow; + Idle aModifyIdle; + + SdrTextObj* mpTextObj = nullptr; + bool mbIgnoreNotifications = false; + + void doScroll(); + void setScrollBarRange(); + void showContextMenu(const Point& rPos); + + DECL_LINK(ScrollHdl, weld::ScrolledWindow&, void); + DECL_LINK(EditStatusHdl, EditStatus&, void); + DECL_LINK(EditModifiedHdl, LinkParamNone*, void); + DECL_LINK(ModifyTimerHdl, Timer*, void); + DECL_LINK(EventMultiplexerListener, tools::EventMultiplexerEvent&, void); + + void removeListener(); + void addListener(); + + void setListenerIgnored(bool bIgnore); + bool isListenerIgnored(); + + void getNotesFromDoc(); + void setNotesToDoc(); + +public: + NotesEditWindow(NotesChildDockingWindow& rParentWindow, + std::unique_ptr<weld::ScrolledWindow> pScrolledWindow); + virtual ~NotesEditWindow() override; + + void provideNoteText(); + bool HasNotesPlaceholder() { return mpTextObj; } + + virtual void EditViewScrollStateChange() override; + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + virtual EditView* GetEditView() const override; + virtual EditEngine* GetEditEngine() const override; + virtual void GetFocus() override; + virtual bool CanFocus() const override; + virtual void LoseFocus() override; + virtual bool Command(const CommandEvent& rCEvt) override; + virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override; +}; + +class NotesChildDockingWindow final : public SfxDockingWindow +{ + ViewShellBase* mpViewShellBase; + std::unique_ptr<NotesEditWindow> m_xEditWindow; + std::unique_ptr<weld::CustomWeld> m_xEditWindowWeld; + + std::unique_ptr<OutlinerView> mpOutlinerView; + std::unique_ptr<Outliner> mpOutliner; + +public: + NotesChildDockingWindow(SfxBindings* pBindings, SfxChildWindow* pChildWindow, Window* pParent); + virtual ~NotesChildDockingWindow() override; + void dispose() override; + + OutlinerView* GetOutlinerView() { return mpOutlinerView.get(); } + ::Outliner* GetOutliner() { return mpOutliner.get(); } + ViewShellBase* GetViewShellBase() { return mpViewShellBase; } + DrawViewShell* GetDrawViewShell(); +}; + +class NotesChildWindow final : public SfxChildWindow +{ +public: + SFX_DECL_CHILDWINDOW_WITHID(NotesChildWindow); + NotesChildWindow(vcl::Window* pParentWindow, sal_uInt16 nId, SfxBindings* pBindings, + SfxChildWinInfo* pInfo); +}; + +} // end of namespace ::sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sd/source/ui/view/ViewShellBase.cxx b/sd/source/ui/view/ViewShellBase.cxx index 9099988969d8..671a56f99389 100644 --- a/sd/source/ui/view/ViewShellBase.cxx +++ b/sd/source/ui/view/ViewShellBase.cxx @@ -628,6 +628,15 @@ void ViewShellBase::Execute (SfxRequest& rRequest) framework::FrameworkHelper::msSlideSorterURL); break; + case SID_NOTES_WINDOW: + { + SfxViewShell* pViewShell = SfxViewShell::Current(); + SfxViewFrame& rViewFrame = pViewShell->GetViewFrame(); + auto nID = rRequest.GetSlot(); + rViewFrame.ToggleChildWindow(nID); + break; + } + case SID_TOGGLE_TABBAR_VISIBILITY: { SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDocument()->GetDocumentType()); @@ -1277,6 +1286,21 @@ void ViewShellBase::Implementation::GetSlotState (SfxItemSet& rSet) bState = xConfiguration->hasResource(xResourceId); break; + case SID_NOTES_WINDOW: + { + bState = false; + auto* pViewShell = SfxViewShell::Current(); + if (pViewShell) + { + auto& rViewFrame = pViewShell->GetViewFrame(); + if (rViewFrame.KnowsChildWindow(nItemId)) + { + bState = rViewFrame.HasChildWindow(nItemId); + } + } + break; + } + case SID_DRAWINGMODE: case SID_NORMAL_MULTI_PANE_GUI: case SID_SLIDE_MASTER_MODE: diff --git a/sd/source/ui/view/drvwshrg.cxx b/sd/source/ui/view/drvwshrg.cxx index 792d5b833a54..9871db2e2de7 100644 --- a/sd/source/ui/view/drvwshrg.cxx +++ b/sd/source/ui/view/drvwshrg.cxx @@ -40,6 +40,7 @@ #include <SpellDialogChildWindow.hxx> #include <GraphicViewShell.hxx> #include <AnimationChildWindow.hxx> +#include <NotesChildWindow.hxx> using namespace sd; #define ShellClass_DrawViewShell @@ -77,6 +78,7 @@ void DrawViewShell::InitInterface_Impl() GetStaticInterface()->RegisterChildWindow( sfx2::sidebar::SidebarChildWindow::GetChildWindowId()); GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(::sd::NotesChildWindow::GetChildWindowId()); } // SdGraphicViewShell @@ -103,6 +105,7 @@ void GraphicViewShell::InitInterface_Impl() GetStaticInterface()->RegisterChildWindow( sfx2::sidebar::SidebarChildWindow::GetChildWindowId()); GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(::sd::NotesChildWindow::GetChildWindowId()); } } // end of namespace sd diff --git a/sd/uiconfig/simpress/menubar/menubar.xml b/sd/uiconfig/simpress/menubar/menubar.xml index 78489c56383e..ba1cc4868cc0 100644 --- a/sd/uiconfig/simpress/menubar/menubar.xml +++ b/sd/uiconfig/simpress/menubar/menubar.xml @@ -125,6 +125,7 @@ <menu:menuitem menu:id=".uno:StatusBarVisible" menu:style="text"/> <menu:menuitem menu:id=".uno:LeftPaneImpress" menu:style="text"/> <menu:menuitem menu:id=".uno:ToggleTabBarVisibility" menu:style="text"/> + <menu:menuitem menu:id=".uno:NotesChildWindow" menu:style="text"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:ShowRuler"/> <menu:menu menu:id=".uno:GridMenu"> diff --git a/sd/uiconfig/simpress/ui/noteschildwindow.ui b/sd/uiconfig/simpress/ui/noteschildwindow.ui new file mode 100644 index 000000000000..de09708702f1 --- /dev/null +++ b/sd/uiconfig/simpress/ui/noteschildwindow.ui @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 --> +<interface domain="sd"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkBox" id="NotesChildEditWindow"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwin"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="hexpand">True</property> + <property name="border-width">0</property> + <property name="hscrollbar-policy">never</property> + <property name="vscrollbar-policy">always</property> + <property name="shadow-type">etched-out</property> + <child> + <object class="GtkViewport"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkDrawingArea" id="noteschildeditview"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> +</interface> diff --git a/sd/uiconfig/simpress/ui/notespanelcontextmenu.ui b/sd/uiconfig/simpress/ui/notespanelcontextmenu.ui new file mode 100644 index 000000000000..e6ca46e8a7cf --- /dev/null +++ b/sd/uiconfig/simpress/ui/notespanelcontextmenu.ui @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.20.0 --> +<interface domain="sd"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkMenu" id="menu"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> +</interface> |