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: */