From 6bacfc065bea8a717e5d8f0ebe3a26a857d73f02 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sat, 27 Nov 2021 09:42:25 +0100 Subject: [PATCH] sort menu items --- raven/mainwindow.py | 4 +- raven/plugins/domain/menucontribution.py | 44 ++++++++++++++++++- raven/plugins/domain/testmenucontribution.py | 45 ++++++++++++++++++++ raven/plugins/openfileplugin.py | 5 ++- raven/plugins/ravenlogplugin.py | 4 +- 5 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 raven/plugins/domain/testmenucontribution.py diff --git a/raven/mainwindow.py b/raven/mainwindow.py index 49e4652..dc06584 100644 --- a/raven/mainwindow.py +++ b/raven/mainwindow.py @@ -11,7 +11,7 @@ import urlutils from aboutdialog import AboutDialog from cutesettings import CuteSettings from raven.pluginregistry import PluginRegistry -from raven.plugins.domain.menucontribution import MenuContribution +from raven.plugins.domain.menucontribution import MenuContribution, sort_menu_contributions from raven.plugins.domain.raction import RAction from raven.plugins.domain.rmenu import RMenu from settingsstore import SettingsStore @@ -62,6 +62,8 @@ class MainWindow(QMainWindow): menu_contributions.append(MenuContribution("settings", action=self._action_highlight_search_terms())) menu_contributions.append(MenuContribution("settings", action=self._action_new_tab())) + menu_contributions = sort_menu_contributions(menu_contributions) + known_menus = [ ("file", self.tr("&File")), ("settings", self.tr("&Settings")), diff --git a/raven/plugins/domain/menucontribution.py b/raven/plugins/domain/menucontribution.py index 5954db9..424803e 100644 --- a/raven/plugins/domain/menucontribution.py +++ b/raven/plugins/domain/menucontribution.py @@ -1,11 +1,51 @@ from raven.plugins.domain.raction import RAction from raven.plugins.domain.rmenu import RMenu +id_counter = 0 + + +def next_id() -> str: + global id_counter + id_counter = id_counter + 1 + return "action_%d" % id_counter + class MenuContribution(): - def __init__(self, menu_id: str, action: RAction = None, menu: RMenu = None, action_id=None): + def __init__(self, + menu_id: str, + action: RAction = None, + menu: RMenu = None, + action_id=None, + after=None): super(MenuContribution, self).__init__() self.menu_id = menu_id self.action = action self.menu = menu - self.action_id = action_id + self.action_id = action_id if action_id else next_id() + self.after = after + + +def _sort_by_action_id(menu_contributions: [MenuContribution]) -> [MenuContribution]: + return sorted(menu_contributions, key=lambda mc: mc.action_id) + + +def sort_menu_contributions(menu_contributions: [MenuContribution]) -> [MenuContribution]: + result = [] + items = _sort_by_action_id(menu_contributions[:]) + + _recursive_half_order_adder(result, items, None) + + # add remaining items to the end (ordered by their action_id) + # This resolves cycles. + for item in items: + result.append(item) + return result + + +def _recursive_half_order_adder(result: [MenuContribution], items: [MenuContribution], parent): + for item in items: + mc: MenuContribution = item + if not mc.after: + result.append(mc) + items.remove(mc) + _recursive_half_order_adder(result, items, mc.action_id) diff --git a/raven/plugins/domain/testmenucontribution.py b/raven/plugins/domain/testmenucontribution.py new file mode 100644 index 0000000..f9e4b3d --- /dev/null +++ b/raven/plugins/domain/testmenucontribution.py @@ -0,0 +1,45 @@ +import unittest +from random import shuffle + +from raven.plugins.domain.menucontribution import MenuContribution, sort_menu_contributions + + +class MyTestCase(unittest.TestCase): + def test_sort(self): + items = [ + MenuContribution("menuId", action_id="a", after=None), + MenuContribution("menuId", action_id="b", after="a"), + MenuContribution("menuId", action_id="c", after="a"), + MenuContribution("menuId", action_id="d", after="b"), + MenuContribution("menuId", action_id="e", after="d"), + ] + shuffle(items) + + actual = sort_menu_contributions(items) + ordered_ids = "" + for a in actual: + ordered_ids = ordered_ids + a.action_id + self.assertEqual("abcde", ordered_ids) + + def test_sort_with_cycle(self): + """ + There is a cycle between a and b. This is resolved, because neither is set in the recursive + part of the method. After the recursive part the remaining items are added in order of + their action_id. + :return: + """ + items = [ + MenuContribution("menuId", action_id="a", after="b"), + MenuContribution("menuId", action_id="b", after="a"), + ] + shuffle(items) + + actual = sort_menu_contributions(items) + ordered_ids = "" + for a in actual: + ordered_ids = ordered_ids + a.action_id + self.assertEqual("ab", ordered_ids) + + +if __name__ == '__main__': + unittest.main() diff --git a/raven/plugins/openfileplugin.py b/raven/plugins/openfileplugin.py index 752e113..902a295 100644 --- a/raven/plugins/openfileplugin.py +++ b/raven/plugins/openfileplugin.py @@ -15,7 +15,8 @@ from settings import Settings class OpenFilePlugin(PluginBase): def __init__(self): super(OpenFilePlugin, self).__init__() - print("init OpenFilePlugin") + self.settings = None + self.tr = None def set_settings(self, settings: Settings): self.settings = settings @@ -24,7 +25,7 @@ class OpenFilePlugin(PluginBase): self.tr = tr def _action_open_file(self) -> RAction: - open_file = RAction(self.tr("&Open..."), self._open_file_dialog, shortcut='Ctrl+O', + open_file = RAction("&Open...", self._open_file_dialog, shortcut='Ctrl+O', icon_from_theme="document-open") return open_file diff --git a/raven/plugins/ravenlogplugin.py b/raven/plugins/ravenlogplugin.py index 62132fb..d4ebee7 100644 --- a/raven/plugins/ravenlogplugin.py +++ b/raven/plugins/ravenlogplugin.py @@ -22,8 +22,8 @@ class RavenLogPlugin(PluginBase): def get_menu_contributions(self) -> [MenuContribution]: return [ - MenuContribution("file", action=self._action_close(), action_id="close application"), - MenuContribution("help", action=self._action_about(), action_id="open about dialog"), + MenuContribution("file", action=self._action_close(), action_id="close application", after=""), + MenuContribution("help", action=self._action_about(), action_id="open about dialog", after=""), ] def current_file(self) -> Optional[str]: