add findInFiles plugin
This commit is contained in:
5
icons/ionicons/search-circle.svg
Normal file
5
icons/ionicons/search-circle.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
|
||||
<title>ionicons-v5-f</title>
|
||||
<path d="M256,64C150.13,64,64,150.13,64,256s86.13,192,192,192,192-86.13,192-192S361.87,64,256,64Zm91.31,283.31a16,16,0,0,1-22.62,0l-42.84-42.83a88.08,88.08,0,1,1,22.63-22.63l42.83,42.84A16,16,0,0,1,347.31,347.31Z"/>
|
||||
<circle cx="232" cy="232" r="56"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 386 B |
7
icons/ionicons/search-outline.svg
Normal file
7
icons/ionicons/search-outline.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
|
||||
<title>ionicons-v5-f</title>
|
||||
<path d="M221.09,64A157.09,157.09,0,1,0,378.18,221.09,157.1,157.1,0,0,0,221.09,64Z"
|
||||
style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:32px"/>
|
||||
<line x1="338.29" y1="338.29" x2="448" y2="448"
|
||||
style="fill:none;stroke:#000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 450 B |
4
icons/ionicons/search-sharp.svg
Normal file
4
icons/ionicons/search-sharp.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
|
||||
<title>ionicons-v5-f</title>
|
||||
<path d="M464,428,339.92,303.9a160.48,160.48,0,0,0,30.72-94.58C370.64,120.37,298.27,48,209.32,48S48,120.37,48,209.32s72.37,161.32,161.32,161.32a160.48,160.48,0,0,0,94.58-30.72L428,464ZM209.32,319.69A110.38,110.38,0,1,1,319.69,209.32,110.5,110.5,0,0,1,209.32,319.69Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 400 B |
13
icons/myicons/target.svg
Normal file
13
icons/myicons/target.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
|
||||
<title>ionicons-v5-m</title>
|
||||
<path d="M448,256c0-106-86-192-192-192S64,150,64,256s86,192,192,192S448,362,448,256Z"
|
||||
style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:32px"/>
|
||||
<line x1="70" y1="256" x2="170" y2="256"
|
||||
style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:40px"/>
|
||||
<line x1="342" y1="256" x2="442" y2="256"
|
||||
style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:40px"/>
|
||||
<line x1="256" y1="70" x2="256" y2="170"
|
||||
style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:40px"/>
|
||||
<line x1="256" y1="342" x2="256" y2="442"
|
||||
style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:40px"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 893 B |
1
main.py
1
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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
0
src/plugins/findInFiles/__init__.py
Normal file
0
src/plugins/findInFiles/__init__.py
Normal file
86
src/plugins/findInFiles/findinfileswidget.py
Normal file
86
src/plugins/findInFiles/findinfileswidget.py
Normal file
@@ -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
|
||||
40
src/plugins/findinfilesplugin.py
Normal file
40
src/plugins/findinfilesplugin.py
Normal file
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
15
src/ui/formgrid.py
Normal file
15
src/ui/formgrid.py
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user