basctl/source/basicide/bastype2.cxx |   94 ++++++++++++++++++++++++++++++++++++
 basctl/source/inc/bastype2.hxx      |   37 ++++++++++++++
 2 files changed, 131 insertions(+)

New commits:
commit c0c3d93e577d24085663bcb1a62596bc5ab7e678
Author:     Jim Chen <totally.not.jims.proj...@gmail.com>
AuthorDate: Thu Jan 2 08:35:39 2025 -0800
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Thu Jun 12 10:38:54 2025 +0200

    tdf#97169 Macro Sort Dialog for Basic IDE Panel
    
    Allows users of the BASIC macro editor the option to sort Basic scripts
    either alphabetically or in the order in which they appear.
    
    Change-Id: I346fc543ae9d6930ed707185c84c0fdf5d3bf727
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179627
    Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de>
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins

diff --git a/basctl/source/basicide/bastype2.cxx 
b/basctl/source/basicide/bastype2.cxx
index 75d21f3c41c1..f227a0dfcd43 100644
--- a/basctl/source/basicide/bastype2.cxx
+++ b/basctl/source/basicide/bastype2.cxx
@@ -168,6 +168,7 @@ 
SbTreeListBox::SbTreeListBox(std::unique_ptr<weld::TreeView> xControl, weld::Win
 {
     m_xControl->connect_row_activated(LINK(this, SbTreeListBox, 
OpenCurrentHdl));
     m_xControl->connect_expanding(LINK(this, SbTreeListBox, 
RequestingChildrenHdl));
+    m_xControl->connect_popup_menu(LINK(this, SbTreeListBox, ContextMenuHdl));
     nMode = BrowseMode::All;   // everything
 }
 
@@ -446,6 +447,99 @@ void 
SbTreeListBox::ImpCreateLibSubSubEntriesInVBAMode(const weld::TreeIter& rLi
     }
 }
 
+IMPL_LINK(SbTreeListBox, ContextMenuHdl, const CommandEvent&, rCEvt, bool)
+{
+    weld::TreeView& rTreeView = get_widget();
+
+    if (rCEvt.GetCommand() != CommandEventId::ContextMenu || 
!rTreeView.n_children())
+        return false;
+
+    // Build popup menu
+    std::unique_ptr<weld::Builder> xBuilder(
+        Application::CreateBuilder(&rTreeView, 
u"modules/BasicIDE/ui/sortmenu.ui"_ustr));
+    std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu(u"sortmenu"_ustr));
+    std::unique_ptr<weld::Menu> 
xDropMenu(xBuilder->weld_menu(u"sortsubmenu"_ustr));
+
+    // Check the currently selected sort mode
+    bool bAlphabetical = rTreeView.get_sort_order();
+    xDropMenu->set_active(u"alphabetically"_ustr, bAlphabetical);
+    xDropMenu->set_active(u"properorder"_ustr, !bAlphabetical);
+
+    // Display completed popup menu at user mouse location
+    OUString sCommand(
+        xPopup->popup_at_rect(&rTreeView, 
tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1))));
+
+    // Return early if user cancels action
+    if (sCommand.isEmpty())
+        return true;
+
+    assert((sCommand == u"alphabetically" || sCommand == u"properorder") && 
"Unknown context menu action!");
+
+    bool bValidIter = m_xControl->get_selected(m_xScratchIter.get());
+    EntryDescriptor aCurDesc(GetEntryDescriptor(bValidIter ? 
m_xScratchIter.get() : nullptr));
+
+    if (sCommand == u"alphabetically")
+    {
+        rTreeView.make_sorted();
+    }
+    else if (sCommand == u"properorder")
+    {
+        rTreeView.make_unsorted();
+
+        // make_unsorted() does not reorder; macros must be reloaded for 
changes to take effect
+        ReloadAllEntries();
+    }
+
+    // Set the entry so that selected module is in window after sort
+    SetCurrentEntry(aCurDesc);
+
+    return true;
+}
+
+void SbTreeListBox::ReloadAllEntries()
+{
+    // List of modules to expand; stored as an OUString signature
+    std::unordered_set<EntryDescriptor> aExpandedRows;
+
+    // Find all instances of expanded rows in tree so they can be re-expanded 
later
+    bool bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
+    while (bValidIter)
+    {
+        if (m_xControl->get_row_expanded(*m_xScratchIter)) {
+            EntryDescriptor aDesc = GetEntryDescriptor(m_xScratchIter.get());
+
+            aExpandedRows.insert(aDesc);
+        }
+
+        bValidIter = m_xControl->iter_next(*m_xScratchIter);
+    }
+
+    // Remove all entries in treelist
+    bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
+    while (bValidIter)
+    {
+        RemoveEntry(*m_xScratchIter);
+
+        bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
+    }
+
+    // Load in all macros in unsorted order
+    UpdateEntries();
+
+    // Re-expand previously expanded items
+    bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
+    while (bValidIter)
+    {
+        EntryDescriptor aDesc = GetEntryDescriptor(m_xScratchIter.get());
+
+        if (aExpandedRows.contains(aDesc)) {
+            m_xControl->expand_row(*m_xScratchIter);
+        }
+
+        bValidIter = m_xControl->iter_next(*m_xScratchIter);
+    }
+}
+
 bool SbTreeListBox::ImpFindEntry(weld::TreeIter& rIter, std::u16string_view 
rText)
 {
     bool bValidIter = m_xControl->iter_children(rIter);
diff --git a/basctl/source/inc/bastype2.hxx b/basctl/source/inc/bastype2.hxx
index 49731333680f..b2d3f4ba7eac 100644
--- a/basctl/source/inc/bastype2.hxx
+++ b/basctl/source/inc/bastype2.hxx
@@ -28,6 +28,9 @@
 #include <vcl/weld.hxx>
 #include <basctl/sbxitem.hxx>
 #include <o3tl/typed_flags_set.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+
 
 class SbModule;
 class SbxVariable;
@@ -156,6 +159,8 @@ public:
 
     EntryType               GetType() const { return m_eType; }
     void                    SetType( EntryType eType ) { m_eType = eType; }
+
+    friend bool operator==(const basctl::EntryDescriptor& aDesc1, const 
basctl::EntryDescriptor& aDesc2) = default;
 };
 
 
@@ -184,6 +189,8 @@ private:
 protected:
     DECL_LINK(RequestingChildrenHdl, const weld::TreeIter&, bool);
     DECL_LINK(OpenCurrentHdl, weld::TreeView&, bool);
+    // Creates popup menu to select between alphabetic or unsorted view in 
Macro List Tree
+    DECL_LINK(ContextMenuHdl, const CommandEvent&, bool);
     void                    ImpCreateLibEntries(const weld::TreeIter& 
rShellRootEntry, const ScriptDocument& rDocument, LibraryLocation eLocation);
     void                    ImpCreateLibSubEntries(const weld::TreeIter& 
rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName);
     void                    ImpCreateLibSubEntriesInVBAMode(const 
weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& 
rLibName );
@@ -208,6 +215,15 @@ public:
     void            ScanEntry( const ScriptDocument& rDocument, 
LibraryLocation eLocation );
     void            ScanAllEntries();
     void            UpdateEntries();
+    /**
+     * Removes then reloads all items in tree, restoring expansion state of 
entries
+     *
+     * @see SbTreeListBox::UpdateEntries()
+     * @see SbTreeListBox::FindRootEntry(const ScriptDocument&, 
LibraryLocation, weld::TreeIter&)
+     * @param None
+     * @return None
+     */
+    void            ReloadAllEntries();
 
     bool            IsEntryProtected(const weld::TreeIter* pEntry);
 
@@ -277,4 +293,25 @@ private:
 
 } // namespace basctl
 
+
+namespace std {
+template<> class hash<basctl::EntryDescriptor>
+{
+    public:
+    std::size_t operator()(const basctl::EntryDescriptor& rDesc) const noexcept
+    {
+        // Serialize EntryDescriptor as OUString
+        OUString sDescSerial =
+            OUString::number(rDesc.GetDocument().hashCode())    + "|" +
+            OUString::number(rDesc.GetLocation())               + "|" +
+            rDesc.GetLibName()                                  + "|" +
+            rDesc.GetLibSubName()                               + "|" +
+            rDesc.GetName()                                     + "|" +
+            rDesc.GetMethodName()                               + "|" +
+            OUString::number(rDesc.GetType());
+
+        return sDescSerial.hashCode();
+    }
+};
+}
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to