sd/UIConfig_sdraw.mk                         |    1 
 sd/source/ui/dlg/navigatr.cxx                |   30 ++++++-
 sd/source/ui/dlg/sdtreelb.cxx                |  114 ++++++++++++++++++++++++++-
 sd/source/ui/inc/navigatr.hxx                |    3 
 sd/source/ui/inc/sdtreelb.hxx                |   31 +++++++
 sd/uiconfig/sdraw/ui/navigatorcontextmenu.ui |   17 ++++
 6 files changed, 194 insertions(+), 2 deletions(-)

New commits:
commit ace75043781b5fe36546ec75574a14617f4feb30
Author:     Jim Raykowski <rayk...@gmail.com>
AuthorDate: Mon Oct 24 23:32:30 2022 -0800
Commit:     Jim Raykowski <rayk...@gmail.com>
CommitDate: Wed Nov 9 08:23:42 2022 +0100

    tdf#139633 SdNavigator: Enhancement to rename pages and objects
    
    This enhancement adds a context popup menu to the Navigator tree that
    has menu entry 'Rename...'. Renaming is done by direct editing in the
    tree.
    
    Change-Id: I392ea839110b942e1a336748c896d33ee5ece9b3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141801
    Tested-by: Jenkins
    Reviewed-by: Jim Raykowski <rayk...@gmail.com>

diff --git a/sd/UIConfig_sdraw.mk b/sd/UIConfig_sdraw.mk
index 136f84fcd315..abc068cff737 100644
--- a/sd/UIConfig_sdraw.mk
+++ b/sd/UIConfig_sdraw.mk
@@ -113,6 +113,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/sdraw,\
        sd/uiconfig/sdraw/ui/insertlayer \
        sd/uiconfig/sdraw/ui/insertslidesdialog \
        sd/uiconfig/sdraw/ui/namedesign \
+       sd/uiconfig/sdraw/ui/navigatorcontextmenu \
        sd/uiconfig/sdraw/ui/notebookbar \
        sd/uiconfig/sdraw/ui/notebookbar_compact \
        sd/uiconfig/sdraw/ui/notebookbar_single \
diff --git a/sd/source/ui/dlg/navigatr.cxx b/sd/source/ui/dlg/navigatr.cxx
index 162b3011a23d..98883e79999b 100644
--- a/sd/source/ui/dlg/navigatr.cxx
+++ b/sd/source/ui/dlg/navigatr.cxx
@@ -47,6 +47,8 @@
 #include <DrawViewShell.hxx>
 #include <utility>
 
+#include <vcl/commandevent.hxx>
+
 /**
  * SdNavigatorWin - FloatingWindow
  */
@@ -68,6 +70,7 @@ SdNavigatorWin::SdNavigatorWin(weld::Widget* pParent, 
SfxBindings* pInBindings,
     mxTlbObjects->connect_row_activated(LINK(this, SdNavigatorWin, 
ClickObjectHdl));
     mxTlbObjects->set_selection_mode(SelectionMode::Multiple);
     mxTlbObjects->connect_mouse_release(LINK(this, SdNavigatorWin, 
MouseReleaseHdl));
+    mxTlbObjects->connect_popup_menu(LINK(this, SdNavigatorWin, CommandHdl));
 
     mxToolbox->connect_clicked(LINK(this, SdNavigatorWin, SelectToolboxHdl));
     mxToolbox->connect_menu_toggled(LINK(this, SdNavigatorWin, 
DropdownClickToolBoxHdl));
@@ -238,6 +241,27 @@ IMPL_STATIC_LINK_NOARG(SdNavigatorWin, MouseReleaseHdl, 
const MouseEvent&, bool)
     return true;
 }
 
+IMPL_LINK(SdNavigatorWin, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+        return false;
+    weld::TreeView& rTreeView = GetObjects().get_treeview();
+    std::unique_ptr<weld::Builder> 
xBuilder(Application::CreateBuilder(&rTreeView,
+                                            
"modules/sdraw/ui/navigatorcontextmenu.ui"));
+    std::unique_ptr<weld::Menu> xPop = xBuilder->weld_menu("navmenu");
+    OString sCommand = xPop->popup_at_rect(&rTreeView,
+                                           
tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
+    if (!sCommand.isEmpty())
+        ExecuteContextMenuAction(sCommand);
+    return true;
+}
+
+void SdNavigatorWin::ExecuteContextMenuAction(std::string_view 
rSelectedPopupEntry)
+{
+    if (rSelectedPopupEntry == "rename")
+        GetObjects().start_editing();
+}
+
 IMPL_LINK(SdNavigatorWin, SelectToolboxHdl, const OString&, rCommand, void)
 {
     PageJump ePage = PAGE_NONE;
@@ -393,9 +417,13 @@ IMPL_LINK_NOARG(SdNavigatorWin, ClickObjectHdl, 
weld::TreeView&, bool)
                     pWindow->GrabFocus();
 
                 if (!mxTlbObjects->IsNavigationGrabsFocus())
+                {
                     // This is the case when keyboard navigation inside the
                     // navigator should continue to work.
+                    if (mxNavigatorDlg)
+                        mxNavigatorDlg->GrabFocus();
                     mxTlbObjects->grab_focus();
+                }
             }
         }
     }
@@ -687,7 +715,7 @@ IMPL_LINK(SdNavigatorWin, KeyInputHdl, const KeyEvent&, 
rKEvt, bool)
     if (KEY_ESCAPE == rKEvt.GetKeyCode().GetCode())
     {
         // during drag'n'drop we just stop the drag but do not close the 
navigator
-        if (!SdPageObjsTLV::IsInDrag())
+        if (!SdPageObjsTLV::IsInDrag() && !GetObjects().IsEditingActive())
         {
             ::sd::ViewShellBase* pBase = 
::sd::ViewShellBase::GetViewShellBase( mpBindings->GetDispatcher()->GetFrame());
             if (pBase)
diff --git a/sd/source/ui/dlg/sdtreelb.cxx b/sd/source/ui/dlg/sdtreelb.cxx
index 226f8fe11eac..0c0e5df03245 100644
--- a/sd/source/ui/dlg/sdtreelb.cxx
+++ b/sd/source/ui/dlg/sdtreelb.cxx
@@ -53,6 +53,8 @@
 #include <comphelper/servicehelper.hxx>
 #include <comphelper/processfactory.hxx>
 
+#include <svx/svditer.hxx>
+#include <vcl/commandevent.hxx>
 
 using namespace com::sun::star;
 
@@ -286,16 +288,44 @@ bool SdPageObjsTLV::IsEqualToDoc( const SdDrawDocument* 
pInDoc )
     return !xEntry;
 }
 
+IMPL_LINK(SdPageObjsTLV, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+    if (IsEditingActive())
+        return false;
+
+    if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
+    {
+        m_xTreeView->grab_focus();
+
+        // select clicked entry
+        if (std::unique_ptr<weld::TreeIter> 
xEntry(m_xTreeView->make_iterator());
+                rCEvt.IsMouseEvent() &&  m_xTreeView->get_dest_row_at_pos(
+                    rCEvt.GetMousePosPixel(), xEntry.get(), false))
+        {
+            m_bSelectionHandlerNavigates = true;
+            m_bNavigationGrabsFocus = false;
+            m_xTreeView->set_cursor(*xEntry);
+            Select();
+        }
+
+        return m_aPopupMenuHdl.Call(rCEvt);
+    }
+
+    return false;
+}
+
 IMPL_LINK(SdPageObjsTLV, KeyInputHdl, const KeyEvent&, rKEvt, bool)
 {
     const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
     if (m_xAccel->execute(rKeyCode))
     {
+        m_bEditing = false;
         // the accelerator consumed the event
         return true;
     }
     if (rKeyCode.GetCode() == KEY_RETURN)
     {
+        m_bEditing = false;
         std::unique_ptr<weld::TreeIter> xCursor(m_xTreeView->make_iterator());
         if (m_xTreeView->get_cursor(xCursor.get()) && 
m_xTreeView->iter_has_child(*xCursor))
         {
@@ -309,11 +339,16 @@ IMPL_LINK(SdPageObjsTLV, KeyInputHdl, const KeyEvent&, 
rKEvt, bool)
         m_bNavigationGrabsFocus = false;
         return true;
     }
-    return m_aKeyPressHdl.Call(rKEvt);
+    bool bRet = m_aKeyPressHdl.Call(rKEvt);
+    // m_bEditing needs to be set after key press handler call back or x11 
won't end editing on
+    // Esc key press. See SdNavigatorWin::KeyInputHdl.
+    m_bEditing = false;
+    return bRet;
 }
 
 IMPL_LINK(SdPageObjsTLV, MousePressHdl, const MouseEvent&, rMEvt, bool)
 {
+    m_bEditing = false;
     m_bSelectionHandlerNavigates = rMEvt.GetClicks() == 1;
     m_bNavigationGrabsFocus = rMEvt.GetClicks() != 1;
     return false;
@@ -652,11 +687,85 @@ 
SdPageObjsTLV::SdPageObjsTLV(std::unique_ptr<weld::TreeView> xTreeView)
     m_xTreeView->connect_key_press(LINK(this, SdPageObjsTLV, KeyInputHdl));
     m_xTreeView->connect_mouse_press(LINK(this, SdPageObjsTLV, MousePressHdl));
     m_xTreeView->connect_mouse_release(LINK(this, SdPageObjsTLV, 
MouseReleaseHdl));
+    m_xTreeView->connect_editing(LINK(this, SdPageObjsTLV, EditingEntryHdl),
+                                 LINK(this, SdPageObjsTLV, EditedEntryHdl));
+    m_xTreeView->connect_popup_menu(LINK(this, SdPageObjsTLV, CommandHdl));
 
     m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 
28,
                                   m_xTreeView->get_text_height() * 8);
 }
 
+IMPL_LINK(SdPageObjsTLV, EditEntryAgain, void*, p, void)
+{
+    m_xTreeView->grab_focus();
+    std::unique_ptr<weld::TreeIter> xEntry(static_cast<weld::TreeIter*>(p));
+    m_xTreeView->start_editing(*xEntry);
+    m_bEditing = true;
+}
+
+IMPL_LINK_NOARG(SdPageObjsTLV, EditingEntryHdl, const weld::TreeIter&, bool)
+{
+    m_bEditing = true;
+    return true;
+}
+
+IMPL_LINK(SdPageObjsTLV, EditedEntryHdl, const IterString&, rIterString, bool)
+{
+    m_bEditing = false;
+
+    // Did the name change?
+    if (m_xTreeView->get_text(rIterString.first) == rIterString.second)
+        return true;
+
+    // If the new name is empty or not unique, start editing again.
+    bool bUniqueName = true;
+    std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+    if (!rIterString.second.isEmpty())
+    {
+        if (m_xTreeView->get_iter_first(*xEntry))
+        {
+            do
+            {
+                // skip self!
+                if (m_xTreeView->iter_compare(*xEntry, rIterString.first) != 0 
&&
+                        m_xTreeView->get_text(*xEntry) == rIterString.second)
+                {
+                    bUniqueName = false;
+                    break;
+                }
+            } while(m_xTreeView->iter_next(*xEntry));
+        }
+    }
+    if (rIterString.second.isEmpty() || !bUniqueName)
+    {
+        m_xTreeView->copy_iterator(rIterString.first, *xEntry);
+        Application::PostUserEvent(LINK(this, SdPageObjsTLV, EditEntryAgain), 
xEntry.release());
+        return false;
+    }
+
+    // set the new name
+    const auto& rEntryId = m_xTreeView->get_id(rIterString.first);
+    if (rEntryId.toInt64() == 1)
+    {
+        // page name
+        if (::sd::DrawDocShell* pDocShell = m_pDoc->GetDocSh())
+        {
+            if (::sd::ViewShell* pViewShell = 
GetViewShellForDocShell(*pDocShell))
+            {
+                SdPage* pPage = pViewShell->GetActualPage();
+                pPage->SetName(rIterString.second);
+            }
+        }
+    }
+    else if (SdrObject* pCursorEntryObject = 
weld::fromId<SdrObject*>(rEntryId))
+    {
+        // object name
+        pCursorEntryObject->SetName(rIterString.second);
+    }
+
+    return true;
+}
+
 IMPL_LINK_NOARG(SdPageObjsTLV, SelectHdl, weld::TreeView&, void)
 {
     if (m_nSelectEventId)
@@ -683,6 +792,9 @@ void SdPageObjsTLV::Select()
 {
     m_nSelectEventId = nullptr;
 
+    if (IsEditingActive())
+        return;
+
     m_bLinkableSelected = true;
 
     m_xTreeView->selected_foreach([this](weld::TreeIter& rEntry){
diff --git a/sd/source/ui/inc/navigatr.hxx b/sd/source/ui/inc/navigatr.hxx
index f0b7d1fca5e8..fdcc1f2cf3ab 100644
--- a/sd/source/ui/inc/navigatr.hxx
+++ b/sd/source/ui/inc/navigatr.hxx
@@ -159,9 +159,12 @@ private:
                                 DECL_DLLPRIVATE_LINK( ShapeFilterCallback, 
const OString&, void );
                                 DECL_DLLPRIVATE_LINK( KeyInputHdl, const 
KeyEvent&, bool );
     DECL_DLLPRIVATE_STATIC_LINK(SdNavigatorWin, MouseReleaseHdl, const 
MouseEvent&, bool);
+    DECL_LINK(CommandHdl, const CommandEvent&, bool);
 
     void                        SetDragImage();
 
+    void ExecuteContextMenuAction(std::string_view rSelectedPopupEntry);
+
 public:
     //when object is marked , fresh the corresponding entry tree .
     void                        FreshTree ( const  SdDrawDocument* pDoc );
diff --git a/sd/source/ui/inc/sdtreelb.hxx b/sd/source/ui/inc/sdtreelb.hxx
index 38a797519654..d937f9e310c0 100644
--- a/sd/source/ui/inc/sdtreelb.hxx
+++ b/sd/source/ui/inc/sdtreelb.hxx
@@ -95,6 +95,8 @@ private:
      */
     bool m_bNavigationGrabsFocus;
 
+    bool m_bEditing = false;
+
     SelectionMode m_eSelectionMode;
 
     ImplSVEvent* m_nSelectEventId;
@@ -106,6 +108,7 @@ private:
     Link<weld::TreeView&, bool> m_aRowActivatedHdl;
     Link<const KeyEvent&, bool> m_aKeyPressHdl;
     Link<const MouseEvent&, bool> m_aMouseReleaseHdl;
+    Link<const CommandEvent&, bool> m_aPopupMenuHdl;
 
     /** Return the name of the object.  When the object has no user supplied
         name and the bCreate flag is <TRUE/> then a name is created
@@ -134,6 +137,13 @@ private:
     DECL_DLLPRIVATE_LINK(DragBeginHdl, bool&, bool);
     DECL_DLLPRIVATE_LINK(KeyInputHdl, const KeyEvent&, bool);
 
+    DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool);
+    typedef std::pair<const weld::TreeIter&, OUString> IterString;
+    DECL_LINK(EditedEntryHdl, const IterString&, bool);
+    DECL_LINK(EditEntryAgain, void*, void);
+
+    DECL_LINK(CommandHdl, const CommandEvent&, bool);
+
     /** Determine whether the specified page belongs to the current show
         which is either the standard show or a custom show.
         @param pPage
@@ -156,6 +166,17 @@ public:
     SdPageObjsTLV(std::unique_ptr<weld::TreeView> xTreeview);
     ~SdPageObjsTLV();
 
+    bool IsEditingActive() const {return m_bEditing;}
+
+    void start_editing()
+    {
+        std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
+        if (m_xTreeView->get_cursor(xIter.get()))
+        {
+            m_xTreeView->start_editing(*xIter);
+        }
+    }
+
     void set_sensitive(bool bSensitive)
     {
         m_xTreeView->set_sensitive(bSensitive);
@@ -222,6 +243,11 @@ public:
         m_aMouseReleaseHdl = rLink;
     }
 
+    void connect_popup_menu(const Link<const CommandEvent&, bool>& rLink)
+    {
+        m_aPopupMenuHdl = rLink;
+    }
+
     bool HasSelectedChildren(std::u16string_view rName);
     bool SelectEntry(std::u16string_view rName);
     void SelectEntry(const SdrObject* pObj);
@@ -256,6 +282,11 @@ public:
         return m_xTreeView->get_iter_first(rIter);
     }
 
+    weld::TreeView& get_treeview()
+    {
+        return *m_xTreeView;
+    }
+
     std::unique_ptr<weld::TreeIter> make_iterator()
     {
         return m_xTreeView->make_iterator();
diff --git a/sd/uiconfig/sdraw/ui/navigatorcontextmenu.ui 
b/sd/uiconfig/sdraw/ui/navigatorcontextmenu.ui
new file mode 100644
index 000000000000..746734e4e86f
--- /dev/null
+++ b/sd/uiconfig/sdraw/ui/navigatorcontextmenu.ui
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="sd">
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkMenu" id="navmenu">
+    <property name="visible">True</property>
+    <property name="can-focus">False</property>
+    <child>
+      <object class="GtkMenuItem" id="rename">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="label" translatable="yes" 
context="navigatorcontextmenu|STR_RENAME">Rename...</property>
+        <property name="use-underline">True</property>
+      </object>
+    </child>
+  </object>
+</interface>

Reply via email to