From 14c059e5aaba96a6e33a8c9525434f54bd5e3d82 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sat, 30 Jul 2022 09:17:08 +0200 Subject: [PATCH] add findInFiles plugin --- icons/ionicons/search-circle.svg | 5 ++ icons/ionicons/search-outline.svg | 7 ++ icons/ionicons/search-sharp.svg | 4 + icons/myicons/target.svg | 13 +++ main.py | 1 + src/plugins/domain/menucontribution.py | 52 +++++++++--- src/plugins/domain/testmenucontribution.py | 33 ++++++++ src/plugins/findInFiles/__init__.py | 0 src/plugins/findInFiles/findinfileswidget.py | 86 ++++++++++++++++++++ src/plugins/findinfilesplugin.py | 40 +++++++++ src/plugins/notesplugin.py | 2 +- src/ui/formgrid.py | 15 ++++ 12 files changed, 247 insertions(+), 11 deletions(-) create mode 100644 icons/ionicons/search-circle.svg create mode 100644 icons/ionicons/search-outline.svg create mode 100644 icons/ionicons/search-sharp.svg create mode 100644 icons/myicons/target.svg create mode 100644 src/plugins/findInFiles/__init__.py create mode 100644 src/plugins/findInFiles/findinfileswidget.py create mode 100644 src/plugins/findinfilesplugin.py create mode 100644 src/ui/formgrid.py diff --git a/icons/ionicons/search-circle.svg b/icons/ionicons/search-circle.svg new file mode 100644 index 0000000..e9e1a04 --- /dev/null +++ b/icons/ionicons/search-circle.svg @@ -0,0 +1,5 @@ + + ionicons-v5-f + + + \ No newline at end of file diff --git a/icons/ionicons/search-outline.svg b/icons/ionicons/search-outline.svg new file mode 100644 index 0000000..eb09c6c --- /dev/null +++ b/icons/ionicons/search-outline.svg @@ -0,0 +1,7 @@ + + ionicons-v5-f + + + \ No newline at end of file diff --git a/icons/ionicons/search-sharp.svg b/icons/ionicons/search-sharp.svg new file mode 100644 index 0000000..3be92cc --- /dev/null +++ b/icons/ionicons/search-sharp.svg @@ -0,0 +1,4 @@ + + ionicons-v5-f + + \ No newline at end of file diff --git a/icons/myicons/target.svg b/icons/myicons/target.svg new file mode 100644 index 0000000..9169f5b --- /dev/null +++ b/icons/myicons/target.svg @@ -0,0 +1,13 @@ + + ionicons-v5-m + + + + + + diff --git a/main.py b/main.py index b3319a5..98338dc 100644 --- a/main.py +++ b/main.py @@ -55,6 +55,7 @@ if __name__ == "__main__": PluginRegistry.load_plugin("LogFilePlugin") PluginRegistry.load_plugin("NotesPlugin") PluginRegistry.load_plugin("TimeDiffPlugin") + PluginRegistry.load_plugin("FindInFilesPlugin") window = PluginRegistry.execute_single("create_main_window") window.show() diff --git a/src/plugins/domain/menucontribution.py b/src/plugins/domain/menucontribution.py index 5496d12..7b4e8f2 100644 --- a/src/plugins/domain/menucontribution.py +++ b/src/plugins/domain/menucontribution.py @@ -33,18 +33,50 @@ def sort_menu_contributions(menu_contributions: [MenuContribution]) -> [MenuCont result = [] items = _sort_by_action_id(menu_contributions[:]) - _recursive_half_order_adder(result, items) - - # 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]): for item in items: mc: MenuContribution = item + if not mc.after: + result.append(mc) + items.remove(mc) + result = result + _new_recursive(mc.action_id, items) + + # _recursive_half_order_adder(result, items) + + # add remaining items to the end (ordered by their action_id) + # This resolves cycles. + for item in items: + if result.count(item) == 0: + result.append(item) + return result + + +def _new_recursive(current_action_id: str, items: [MenuContribution]) -> [MenuContribution]: + result = [] + for item in items: + + mc: MenuContribution = item + print("%s checking %s" % (current_action_id, mc.action_id)) + if mc.after == current_action_id: + print("%s adding %s" % (current_action_id, mc.action_id)) + result.append(mc) + result = result + _new_recursive(mc.action_id, items) + + return result + + +def _recursive_half_order_adder(result: [MenuContribution], items: [MenuContribution]): + print("%s -- %s" % ([mc.action_id for mc in result], [mc.action_id for mc in items])) + for item in items: + mc: MenuContribution = item + if mc.after: + index = 0 + for r in result: + index = index + 1 + mc_in_result: MenuContribution = r + if mc.after == mc_in_result.action_id: + result.insert(index, mc) + items.remove(mc) + _recursive_half_order_adder(result, items) if not mc.after: result.append(mc) items.remove(mc) diff --git a/src/plugins/domain/testmenucontribution.py b/src/plugins/domain/testmenucontribution.py index ae1b2be..23b6cd7 100644 --- a/src/plugins/domain/testmenucontribution.py +++ b/src/plugins/domain/testmenucontribution.py @@ -40,6 +40,39 @@ class MyTestCase(unittest.TestCase): ordered_ids = ordered_ids + a.action_id self.assertEqual("ab", ordered_ids) + def test_sort_with_non_consecutive_action_ids(self): + items = [ + MenuContribution("menuId", action_id="The", after=None), + MenuContribution("menuId", action_id="quick", after="The"), + MenuContribution("menuId", action_id="brown", after="quick"), + MenuContribution("menuId", action_id="fox", after="brown"), + MenuContribution("menuId", action_id="jumped", after="fox"), + ] + shuffle(items) + + actual = sort_menu_contributions(items) + ordered_ids = "" + for a in actual: + ordered_ids = ordered_ids + a.action_id + self.assertEqual("Thequickbrownfoxjumped", ordered_ids) + + def test_sort_with_multiple_equal_after_values(self): + items = [ + MenuContribution("menuId", action_id="Tanja", after=None), + MenuContribution("menuId", action_id="jumps", after="Tanja"), + MenuContribution("menuId", action_id="over", after="Tanja"), + MenuContribution("menuId", action_id="the", after="Tanja"), + MenuContribution("menuId", action_id="yellow", after="Tanja"), + MenuContribution("menuId", action_id="Zebra", after=None), + ] + shuffle(items) + + actual = sort_menu_contributions(items) + ordered_ids = "" + for a in actual: + ordered_ids = ordered_ids + a.action_id + self.assertEqual("TanjajumpsovertheyellowZebra", ordered_ids) + if __name__ == '__main__': unittest.main() diff --git a/src/plugins/findInFiles/__init__.py b/src/plugins/findInFiles/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/plugins/findInFiles/findinfileswidget.py b/src/plugins/findInFiles/findinfileswidget.py new file mode 100644 index 0000000..a5f501e --- /dev/null +++ b/src/plugins/findInFiles/findinfileswidget.py @@ -0,0 +1,86 @@ +import os +import sys +from pathlib import Path + +from PySide6.QtGui import QIcon + +from src.pluginregistry import PluginRegistry +from src.plugins.krowlog.Tab import Tab +from PySide6.QtWidgets import QTextEdit, QVBoxLayout, QLabel, QLineEdit, QPushButton, QFileDialog +from src.i18n import _ +from src.settings.settings import Settings +from src.ui.formgrid import FormGrid +from src.ui.hbox import HBox + + +class FindInFilesWidget(Tab): + + def __init__(self, unique_id: str, title: str, settings: Settings): + super(FindInFilesWidget, self).__init__(unique_id, title) + self._settings = settings + + self.layout = QVBoxLayout(self) + self.layout.setContentsMargins(0, 0, 0, 0) + form = FormGrid(); + self.layout.addWidget(form) + + self._base_dir = QLineEdit(self._initialFolder()) + self._base_dir.textChanged.connect(self._base_dir_changed) + + btn_select_base_dir = QPushButton(QIcon.fromTheme("document-open"), "") + btn_select_base_dir.pressed.connect(self._select_base_dir) + + btn_base_dir_for_current_file = QPushButton(QIcon("icons/myicons/target.svg"), "") + btn_base_dir_for_current_file.setToolTip(_("Focus on current file")) + btn_base_dir_for_current_file.pressed.connect(self._select_btn_base_dir_for_current_file) + + form.addRow(QLabel(_("Folder:")), + HBox(self._base_dir, btn_select_base_dir, btn_base_dir_for_current_file)) + + self._filter = QLineEdit("*.log") + form.addRow(QLabel(_("Filter:")), self._filter) + + self._btn_search = QPushButton(QIcon("icons/ionicons/search-outline.svg"), _("Search")) + self._btn_search.pressed.connect(self._search) + self.layout.addWidget(self._btn_search) + + self.layout.addWidget(QTextEdit()) + + def _search(self): + pass + + def _select_base_dir(self): + dialog = QFileDialog() + selected_dir = dialog.getExistingDirectory( + caption=_("Open Directory"), + dir=self._base_dir.text() + ) + if selected_dir: + self._base_dir.setText(selected_dir) + + def _select_btn_base_dir_for_current_file(self): + dir = self._get_base_dir_for_current_file() + self._base_dir.setText(dir) + + def _base_dir_changed(self, base_dir): + if os.path.isdir(base_dir): + self._settings.set_session("findInFiles", "folder", base_dir) + + def _initialFolder(self) -> str: + folder = self._settings.get_session("findInFiles", "folder", fallback=None) + if folder is None or not os.path.isdir(folder): + folder = self._get_base_dir_for_current_file() + + return folder + + def _get_base_dir_for_current_file(self): + current_file = PluginRegistry.execute_single("current_file") + folder = os.path.dirname(current_file) if current_file else None + + if not os.path.isdir(folder): + if sys.platform == 'win32' or sys.platform == 'cygwin': + folder = "C:\\" + else: + folder = os.path.join(Path.home()) + + return folder diff --git a/src/plugins/findinfilesplugin.py b/src/plugins/findinfilesplugin.py new file mode 100644 index 0000000..5642138 --- /dev/null +++ b/src/plugins/findinfilesplugin.py @@ -0,0 +1,40 @@ +from PySide6.QtCore import Qt + +from src.pluginbase import PluginBase +from src.pluginregistry import PluginRegistry +from src.plugins.domain.menucontribution import MenuContribution +from src.plugins.domain.raction import RAction +from src.plugins.findInFiles.findinfileswidget import FindInFilesWidget +from src.plugins.notes.noteswidget import NotesWidget +from src.i18n import _ +from src.settings.settings import Settings + + +class FindInFilesPlugin(PluginBase): + + def __init__(self): + super(FindInFilesPlugin, self).__init__() + self.settings = None + + def set_settings(self, settings: Settings): + self.settings = settings + if not self.settings.session.has_section("findInFiles"): + self.settings.session.add_section("findInFiles") + + def get_menu_contributions(self) -> [MenuContribution]: + return [ + MenuContribution("window", action=self._add_find_in_files_tab_action(), action_id="add find in files tab", + after="add notes tab"), + ] + + def _add_find_in_files_tab_action(self) -> RAction: + return RAction(_("&Find In Files"), self._add_notes_tab, shortcut='Ctrl+Shift+F', + icon_file="icons/ionicons/search-outline.svg") + + def _add_notes_tab(self): + findInFiles = FindInFilesWidget( + "find_in_files", + _("Find In Files"), + self.settings + ) + PluginRegistry.execute_single("add_dock", Qt.DockWidgetArea.LeftDockWidgetArea, findInFiles) diff --git a/src/plugins/notesplugin.py b/src/plugins/notesplugin.py index b0c8de3..111447a 100644 --- a/src/plugins/notesplugin.py +++ b/src/plugins/notesplugin.py @@ -21,7 +21,7 @@ class NotesPlugin(PluginBase): ] def _add_notes_tab_action(self) -> RAction: - open_file = RAction(_("Add &Notes"), self._add_notes_tab, shortcut='Ctrl+Shift+N', + open_file = RAction(_("&Notes"), self._add_notes_tab, shortcut='Ctrl+Shift+N', icon_from_theme="filenew") return open_file diff --git a/src/ui/formgrid.py b/src/ui/formgrid.py new file mode 100644 index 0000000..0289e2d --- /dev/null +++ b/src/ui/formgrid.py @@ -0,0 +1,15 @@ +from PySide6.QtWidgets import QWidget, QGridLayout, QLabel + + +class FormGrid(QWidget): + def __init__(self): + super(FormGrid, self).__init__() + self.layout = QGridLayout(self) + self.row = -1 + + def addRow(self, *widgets: QWidget): + self.row = self.row + 1 + col = -1 + for widget in widgets: + col = col + 1 + self.layout.addWidget(widget, self.row, col)