add the first plugins
This commit is contained in:
@@ -85,7 +85,9 @@ class LogFileModel:
|
|||||||
return "", -1, -1
|
return "", -1, -1
|
||||||
|
|
||||||
offset_in_line = byte_offset - line.byte_offset()
|
offset_in_line = byte_offset - line.byte_offset()
|
||||||
current_char = line.line()[line.byte_index_to_char_index(offset_in_line)]
|
char_index = line.byte_index_to_char_index(offset_in_line)
|
||||||
|
# todo char_index may be out of range
|
||||||
|
current_char = line.line()[char_index]
|
||||||
if not self._is_word_char(current_char):
|
if not self._is_word_char(current_char):
|
||||||
return current_char, byte_offset, byte_offset + 1
|
return current_char, byte_offset, byte_offset + 1
|
||||||
start_in_line = line.byte_index_to_char_index(byte_offset - line.byte_offset())
|
start_in_line = line.byte_index_to_char_index(byte_offset - line.byte_offset())
|
||||||
|
|||||||
182
main.py
182
main.py
@@ -1,5 +1,4 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
import signal
|
import signal
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
||||||
@@ -10,174 +9,13 @@ from PyQt6.QtGui import *
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import constants
|
import constants
|
||||||
import urlutils
|
from raven.pluginregistry import PluginRegistry
|
||||||
from aboutdialog import AboutDialog
|
|
||||||
from cutesettings import CuteSettings
|
|
||||||
from ravenui import RavenUI
|
from ravenui import RavenUI
|
||||||
from settingsstore import SettingsStore
|
|
||||||
from highlightingdialog import HighlightingDialog
|
|
||||||
from tabs import Tabs
|
|
||||||
from urlutils import url_is_file
|
|
||||||
|
|
||||||
MAX_LINE_LENGTH = 4096
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
log = logging.getLogger("main")
|
log = logging.getLogger("main")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(MainWindow, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
self.settings = SettingsStore.load()
|
|
||||||
self.setWindowTitle(self.tr("RavenLog"))
|
|
||||||
self._restore_window()
|
|
||||||
|
|
||||||
self.setDockNestingEnabled(True)
|
|
||||||
self.setAcceptDrops(True)
|
|
||||||
|
|
||||||
self.tabs = Tabs(self.settings)
|
|
||||||
|
|
||||||
self._menu_recent_files = QMenu(self.tr("Open &Recent"), self)
|
|
||||||
|
|
||||||
self.setCentralWidget(self.tabs)
|
|
||||||
self.status_bar = QStatusBar(self)
|
|
||||||
self.setStatusBar(self.status_bar)
|
|
||||||
self.setMenuBar(self.create_menu_bar())
|
|
||||||
|
|
||||||
def create_menu_bar(self) -> QMenuBar:
|
|
||||||
menu_bar = QMenuBar()
|
|
||||||
|
|
||||||
menu_bar.addMenu(self.file_menu())
|
|
||||||
menu_bar.addMenu(self.settings_menu())
|
|
||||||
menu_bar.addMenu(self.help_menu())
|
|
||||||
|
|
||||||
return menu_bar
|
|
||||||
|
|
||||||
def file_menu(self) -> QMenu:
|
|
||||||
file_menu = QMenu(self.tr("&File", "name of the file menu"), self)
|
|
||||||
|
|
||||||
open_file = QAction(QIcon.fromTheme("document-open"), self.tr("&Open..."), self)
|
|
||||||
open_file.setShortcut('Ctrl+O')
|
|
||||||
open_file.triggered.connect(self._open_file_dialog)
|
|
||||||
|
|
||||||
# Linux: QIcon.fromTheme("exit")
|
|
||||||
close_action = QAction(QIcon.fromTheme("close"), self.tr("E&xit", "menu item to close the application"), self)
|
|
||||||
close_action.setShortcut('Ctrl+X')
|
|
||||||
close_action.triggered.connect(self.destruct)
|
|
||||||
|
|
||||||
self._update_recent_files_menu()
|
|
||||||
|
|
||||||
file_menu.addAction(open_file)
|
|
||||||
file_menu.addMenu(self._menu_recent_files)
|
|
||||||
file_menu.addAction(close_action)
|
|
||||||
return file_menu
|
|
||||||
|
|
||||||
def settings_menu(self) -> QMenu:
|
|
||||||
result = QMenu(self.tr("&Settings"), self)
|
|
||||||
manage = QAction(self.tr("&Highlighter"), self)
|
|
||||||
manage.setShortcut('Ctrl+H')
|
|
||||||
manage.triggered.connect(lambda: HighlightingDialog(self.settings).exec())
|
|
||||||
result.addAction(manage)
|
|
||||||
|
|
||||||
highlight_search_terms = QAction(self.tr("Highlight &Searches"), self)
|
|
||||||
highlight_search_terms.setCheckable(True)
|
|
||||||
highlight_search_terms.setChecked(self.settings.session.getboolean("general", "highlight_search_term"))
|
|
||||||
highlight_search_terms.triggered.connect(
|
|
||||||
lambda checked: self.settings.set_session("general", "highlight_search_term", str(checked)) or self.update()
|
|
||||||
)
|
|
||||||
result.addAction(highlight_search_terms)
|
|
||||||
|
|
||||||
new_tab = QAction(self.tr("Open Tab on Save As File"), self)
|
|
||||||
new_tab.setCheckable(True)
|
|
||||||
new_tab.setChecked(self.settings.session.getboolean("general", "open_tab_on_save_as_file"))
|
|
||||||
new_tab.triggered.connect(
|
|
||||||
lambda checked: self.settings.set_session("general", "open_tab_on_save_as_file", str(checked)))
|
|
||||||
result.addAction(new_tab)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def help_menu(self) -> QMenu:
|
|
||||||
help_menu = QMenu(self.tr("&Help", "name of the help menu"), self)
|
|
||||||
|
|
||||||
about_action = QAction(QIcon(constants.raven_icon), self.tr("&About"), self)
|
|
||||||
about_action.triggered.connect(lambda: AboutDialog().exec())
|
|
||||||
help_menu.addAction(about_action)
|
|
||||||
|
|
||||||
return help_menu
|
|
||||||
|
|
||||||
def _update_recent_files_menu(self):
|
|
||||||
self._menu_recent_files.clear()
|
|
||||||
files = self._get_recent_files()
|
|
||||||
for file in files:
|
|
||||||
action = QAction(os.path.basename(file), self)
|
|
||||||
action.triggered.connect(lambda x, f=file: self.open_file(f))
|
|
||||||
self._menu_recent_files.addAction(action)
|
|
||||||
|
|
||||||
def _open_file_dialog(self) -> None:
|
|
||||||
current_file = self.tabs.current_file()
|
|
||||||
directory = os.path.dirname(current_file) if current_file else ''
|
|
||||||
|
|
||||||
dialog = QFileDialog(self)
|
|
||||||
(selected_file, _filter) = dialog.getOpenFileName(
|
|
||||||
caption=self.tr("Open File"),
|
|
||||||
directory=directory
|
|
||||||
)
|
|
||||||
if selected_file:
|
|
||||||
self.tabs.create_tab(selected_file)
|
|
||||||
self._remember_recent_file(selected_file)
|
|
||||||
|
|
||||||
def open_file(self, file: str) -> None:
|
|
||||||
self.tabs.create_tab(file)
|
|
||||||
self._remember_recent_file(file)
|
|
||||||
|
|
||||||
def _get_recent_files(self) -> [str]:
|
|
||||||
recent_files = self.settings.session.get('general', 'recent_files', fallback='')
|
|
||||||
files = recent_files.split(os.pathsep)
|
|
||||||
if "" in files:
|
|
||||||
files.remove("")
|
|
||||||
return files
|
|
||||||
|
|
||||||
def _remember_recent_file(self, file: str):
|
|
||||||
files = self._get_recent_files()
|
|
||||||
if file in files:
|
|
||||||
files.remove(file)
|
|
||||||
files.insert(0, file)
|
|
||||||
recent_files = os.pathsep.join(files[:10])
|
|
||||||
self.settings.set_session('general', 'recent_files', recent_files)
|
|
||||||
self._update_recent_files_menu()
|
|
||||||
|
|
||||||
def dragEnterEvent(self, e: QDragEnterEvent):
|
|
||||||
if url_is_file(e.mimeData().text()):
|
|
||||||
e.accept()
|
|
||||||
else:
|
|
||||||
e.ignore()
|
|
||||||
|
|
||||||
def dropEvent(self, e):
|
|
||||||
file = urlutils.url_to_path(e.mimeData().text())
|
|
||||||
self.open_file(file)
|
|
||||||
|
|
||||||
def _restore_window(self):
|
|
||||||
qsettings = CuteSettings()
|
|
||||||
geometry_restored = False
|
|
||||||
geometry = qsettings.value("mainWindow/geometry")
|
|
||||||
if geometry:
|
|
||||||
geometry_restored = self.restoreGeometry(geometry)
|
|
||||||
if not geometry_restored:
|
|
||||||
self.setGeometry(0, 0, 800, 600)
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
|
||||||
self.destruct()
|
|
||||||
|
|
||||||
def destruct(self):
|
|
||||||
self.tabs.destruct()
|
|
||||||
self.close()
|
|
||||||
SettingsStore.save(self.settings)
|
|
||||||
CuteSettings().set_value("mainWindow/geometry", self.saveGeometry())
|
|
||||||
|
|
||||||
|
|
||||||
def stop_signal(signum, _stackframe):
|
def stop_signal(signum, _stackframe):
|
||||||
""" Handle terminate signal """
|
""" Handle terminate signal """
|
||||||
try:
|
try:
|
||||||
@@ -212,14 +50,20 @@ if __name__ == "__main__":
|
|||||||
timer.timeout.connect(lambda: None)
|
timer.timeout.connect(lambda: None)
|
||||||
timer.start(100)
|
timer.start(100)
|
||||||
|
|
||||||
window = MainWindow()
|
# init plugins
|
||||||
|
PluginRegistry.load_plugin("RavenLogPlugin")
|
||||||
|
PluginRegistry.load_plugin("FilterPlugin")
|
||||||
|
PluginRegistry.load_plugin("LogFileViewerPlugin")
|
||||||
|
PluginRegistry.load_plugin("OpenFilePlugin")
|
||||||
|
|
||||||
|
window = PluginRegistry.executeSingle("create_main_window")
|
||||||
RavenUI.window = window
|
RavenUI.window = window
|
||||||
window.show()
|
window.show()
|
||||||
#window.open_file("/home/andi/ws/performanceDb/data/production/logs_2018-09-06_2018-09-06.csv")
|
# window.open_file("/home/andi/ws/performanceDb/data/production/logs_2018-09-06_2018-09-06.csv")
|
||||||
#window.open_file("/home/andi/ws/performanceDb/data/production/vapbdcom.csv")
|
# window.open_file("/home/andi/ws/performanceDb/data/production/vapbdcom.csv")
|
||||||
#window.open_file("/var/log/syslog")
|
# window.open_file("/var/log/syslog")
|
||||||
#window.open_file("/home/andi/ws/ravenlog/example.log")
|
# window.open_file("/home/andi/ws/ravenlog/example.log")
|
||||||
#window.open_file("C:\\Users\\andi\\ws\\some.log")
|
# window.open_file("C:\\Users\\andi\\ws\\some.log")
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, stop_signal)
|
signal.signal(signal.SIGINT, stop_signal)
|
||||||
signal.signal(signal.SIGTERM, stop_signal)
|
signal.signal(signal.SIGTERM, stop_signal)
|
||||||
|
|||||||
268
raven/mainwindow.py
Normal file
268
raven/mainwindow.py
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import *
|
||||||
|
from PyQt6.QtGui import *
|
||||||
|
|
||||||
|
import constants
|
||||||
|
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.raction import RAction
|
||||||
|
from raven.plugins.domain.rmenu import RMenu
|
||||||
|
from settingsstore import SettingsStore
|
||||||
|
from highlightingdialog import HighlightingDialog
|
||||||
|
from tabs import Tabs
|
||||||
|
from urlutils import url_is_file
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
MAX_LINE_LENGTH = 4096
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
log = logging.getLogger("main")
|
||||||
|
|
||||||
|
|
||||||
|
def flat_map(array: List[List]) -> List:
|
||||||
|
return reduce(list.__add__, array)
|
||||||
|
|
||||||
|
|
||||||
|
def _action_about():
|
||||||
|
about_action = RAction(
|
||||||
|
"&About",
|
||||||
|
action=lambda: AboutDialog().exec(),
|
||||||
|
icon_file=constants.raven_icon
|
||||||
|
)
|
||||||
|
return about_action
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(MainWindow, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.settings = SettingsStore.load()
|
||||||
|
PluginRegistry.execute("set_settings", self.settings)
|
||||||
|
|
||||||
|
PluginRegistry.execute("set_translator", lambda string: self.tr(string))
|
||||||
|
|
||||||
|
self.setWindowTitle(self.tr("RavenLog"))
|
||||||
|
self._restore_window()
|
||||||
|
|
||||||
|
self.setDockNestingEnabled(True)
|
||||||
|
self.setAcceptDrops(True)
|
||||||
|
|
||||||
|
self.tabs = Tabs(self.settings)
|
||||||
|
|
||||||
|
self._menu_recent_files = QMenu(self.tr("Open &Recent"), self)
|
||||||
|
|
||||||
|
self.setCentralWidget(self.tabs)
|
||||||
|
self.status_bar = QStatusBar(self)
|
||||||
|
self.setStatusBar(self.status_bar)
|
||||||
|
self.setMenuBar(self.create_dynamic_menu_bar())
|
||||||
|
|
||||||
|
def create_dynamic_menu_bar(self) -> QMenuBar:
|
||||||
|
menu_bar = QMenuBar()
|
||||||
|
|
||||||
|
menu_contributions: [MenuContribution] = flat_map(PluginRegistry.execute("get_menu_contributions"))
|
||||||
|
menu_contributions.append(MenuContribution("file", action=self._action_close(), action_id="close app"))
|
||||||
|
menu_contributions.append(MenuContribution("settings", action=self._action_highlighter()))
|
||||||
|
menu_contributions.append(MenuContribution("settings", action=self._action_highlight_search_terms()))
|
||||||
|
menu_contributions.append(MenuContribution("settings", action=self._action_new_tab()))
|
||||||
|
menu_contributions.append(MenuContribution("help", action=_action_about()))
|
||||||
|
|
||||||
|
known_menus = [
|
||||||
|
("file", self.tr("&File")),
|
||||||
|
("settings", self.tr("&Settings")),
|
||||||
|
("help", self.tr("&Help"))
|
||||||
|
]
|
||||||
|
|
||||||
|
for (menu_id, menu_label) in known_menus:
|
||||||
|
menu = QMenu(menu_label, self)
|
||||||
|
mcs: [MenuContribution] = [mc for mc in menu_contributions if mc.menu_id == menu_id]
|
||||||
|
for menu_contribution in mcs:
|
||||||
|
print("%s %s" % (menu_id, menu_contribution.action_id))
|
||||||
|
if menu_contribution.action:
|
||||||
|
action = self._raction_to_qaction(menu_contribution.action, menu)
|
||||||
|
menu.addAction(action)
|
||||||
|
if menu_contribution.menu:
|
||||||
|
submenu = QMenu(self.tr(menu_contribution.menu.label), menu_bar)
|
||||||
|
menu_contribution.menu.add_change_listener(
|
||||||
|
lambda qmenu=submenu, rmenu=menu_contribution.menu: self._rmenu_update(qmenu, rmenu))
|
||||||
|
self._rmenu_update(submenu, menu_contribution.menu)
|
||||||
|
menu.addMenu(submenu)
|
||||||
|
|
||||||
|
menu_bar.addMenu(menu)
|
||||||
|
|
||||||
|
return menu_bar
|
||||||
|
|
||||||
|
def _rmenu_update(self, qmenu: QMenu, rmenu: RMenu):
|
||||||
|
qmenu.clear()
|
||||||
|
for action in rmenu.actions:
|
||||||
|
action = self._raction_to_qaction(action, qmenu)
|
||||||
|
qmenu.addAction(action)
|
||||||
|
|
||||||
|
def _raction_to_qaction(self, raction: RAction, qmenu: QMenu) -> QAction:
|
||||||
|
action = QAction(self.tr(raction.label), qmenu)
|
||||||
|
if raction.icon_from_theme:
|
||||||
|
action.setIcon(QIcon.fromTheme(raction.icon_from_theme))
|
||||||
|
if raction.icon_file:
|
||||||
|
action.setIcon(QIcon(raction.icon_file))
|
||||||
|
if raction.shortcut:
|
||||||
|
action.setShortcut(raction.shortcut)
|
||||||
|
if raction.action:
|
||||||
|
action.triggered.connect(raction.action)
|
||||||
|
if raction.checkable:
|
||||||
|
action.setCheckable(raction.checkable)
|
||||||
|
action.setChecked(raction.checked)
|
||||||
|
return action
|
||||||
|
|
||||||
|
def _action_open_file(self) -> RAction:
|
||||||
|
open_file = RAction("&Open...", action=self._open_file_dialog, shortcut='Ctrl+O',
|
||||||
|
icon_from_theme="document-open")
|
||||||
|
return open_file
|
||||||
|
|
||||||
|
def _action_close(self) -> RAction:
|
||||||
|
# Linux: QIcon.fromTheme("exit")
|
||||||
|
icon = "close" if sys.platform == 'win32' or sys.platform == 'cygwin' else "exit"
|
||||||
|
close_action = RAction("E&xit", action=self.destruct, shortcut='Ctrl+X', icon_from_theme=icon)
|
||||||
|
return close_action
|
||||||
|
|
||||||
|
def create_menu_bar(self) -> QMenuBar:
|
||||||
|
menu_bar = QMenuBar()
|
||||||
|
|
||||||
|
menu_bar.addMenu(self.file_menu())
|
||||||
|
menu_bar.addMenu(self.settings_menu())
|
||||||
|
menu_bar.addMenu(self.help_menu())
|
||||||
|
|
||||||
|
return menu_bar
|
||||||
|
|
||||||
|
def file_menu(self) -> QMenu:
|
||||||
|
file_menu = QMenu(self.tr("&File", "name of the file menu"), self)
|
||||||
|
|
||||||
|
open_file = self._action_open_file()
|
||||||
|
close_action = self._action_close()
|
||||||
|
|
||||||
|
self._update_recent_files_menu()
|
||||||
|
|
||||||
|
file_menu.addAction(open_file)
|
||||||
|
file_menu.addMenu(self._menu_recent_files)
|
||||||
|
file_menu.addAction(close_action)
|
||||||
|
return file_menu
|
||||||
|
|
||||||
|
def _action_highlighter(self):
|
||||||
|
manage = RAction(
|
||||||
|
"&Highlighter",
|
||||||
|
action=lambda: HighlightingDialog(self.settings).exec(),
|
||||||
|
shortcut='Ctrl+H'
|
||||||
|
)
|
||||||
|
return manage
|
||||||
|
|
||||||
|
def _action_highlight_search_terms(self):
|
||||||
|
highlight_search_terms = RAction(
|
||||||
|
"Highlight &Searches",
|
||||||
|
action=lambda checked: self.settings.set_session("general", "highlight_search_term",
|
||||||
|
str(checked)) or self.update()
|
||||||
|
)
|
||||||
|
highlight_search_terms.set_checkable(True)
|
||||||
|
highlight_search_terms.set_checked(self.settings.session.getboolean("general", "highlight_search_term"))
|
||||||
|
return highlight_search_terms
|
||||||
|
|
||||||
|
def _action_new_tab(self):
|
||||||
|
new_tab = RAction("Open Tab on Save As File")
|
||||||
|
new_tab.set_checkable(True)
|
||||||
|
new_tab.set_checked(self.settings.session.getboolean("general", "open_tab_on_save_as_file"))
|
||||||
|
new_tab.set_action(
|
||||||
|
lambda checked: self.settings.set_session("general", "open_tab_on_save_as_file", str(checked)))
|
||||||
|
return new_tab
|
||||||
|
|
||||||
|
def settings_menu(self) -> QMenu:
|
||||||
|
result = QMenu(self.tr("&Settings"), self)
|
||||||
|
result.addAction(self._action_highlighter())
|
||||||
|
result.addAction(self._action_highlight_search_terms())
|
||||||
|
result.addAction(self._action_new_tab())
|
||||||
|
return result
|
||||||
|
|
||||||
|
def help_menu(self) -> QMenu:
|
||||||
|
help_menu = QMenu(self.tr("&Help", "name of the help menu"), self)
|
||||||
|
help_menu.addAction(_action_about())
|
||||||
|
return help_menu
|
||||||
|
|
||||||
|
def _update_recent_files_menu(self):
|
||||||
|
self._menu_recent_files.clear()
|
||||||
|
files = self._get_recent_files()
|
||||||
|
for file in files:
|
||||||
|
action = QAction(os.path.basename(file), self)
|
||||||
|
action.triggered.connect(lambda x, f=file: self.open_file(f))
|
||||||
|
self._menu_recent_files.addAction(action)
|
||||||
|
|
||||||
|
def _open_file_dialog(self) -> None:
|
||||||
|
current_file = self.tabs.current_file()
|
||||||
|
directory = os.path.dirname(current_file) if current_file else ''
|
||||||
|
|
||||||
|
dialog = QFileDialog(self)
|
||||||
|
(selected_file, _filter) = dialog.getOpenFileName(
|
||||||
|
caption=self.tr("Open File"),
|
||||||
|
directory=directory
|
||||||
|
)
|
||||||
|
if selected_file:
|
||||||
|
self.tabs.create_tab(selected_file)
|
||||||
|
self._remember_recent_file(selected_file)
|
||||||
|
|
||||||
|
def current_file(self) -> Optional[str]:
|
||||||
|
return self.tabs.current_file()
|
||||||
|
|
||||||
|
def open_file(self, file: str) -> None:
|
||||||
|
|
||||||
|
self.tabs.create_tab(file)
|
||||||
|
PluginRegistry.execute("after_open_file", file)
|
||||||
|
# self._remember_recent_file(file)
|
||||||
|
# can_open_plugins = PluginRegistry.execute("can_open_file", file)
|
||||||
|
# if len(can_open_plugins) == 1:
|
||||||
|
# else:
|
||||||
|
|
||||||
|
def _get_recent_files(self) -> [str]:
|
||||||
|
recent_files = self.settings.session.get('general', 'recent_files', fallback='')
|
||||||
|
files = recent_files.split(os.pathsep)
|
||||||
|
if "" in files:
|
||||||
|
files.remove("")
|
||||||
|
return files
|
||||||
|
|
||||||
|
# def _remember_recent_file(self, file: str):
|
||||||
|
# files = self._get_recent_files()
|
||||||
|
# if file in files:
|
||||||
|
# files.remove(file)
|
||||||
|
# files.insert(0, file)
|
||||||
|
# recent_files = os.pathsep.join(files[:10])
|
||||||
|
# self.settings.set_session('general', 'recent_files', recent_files)
|
||||||
|
# self._update_recent_files_menu()
|
||||||
|
|
||||||
|
def dragEnterEvent(self, e: QDragEnterEvent):
|
||||||
|
if url_is_file(e.mimeData().text()):
|
||||||
|
e.accept()
|
||||||
|
else:
|
||||||
|
e.ignore()
|
||||||
|
|
||||||
|
def dropEvent(self, e):
|
||||||
|
file = urlutils.url_to_path(e.mimeData().text())
|
||||||
|
self.open_file(file)
|
||||||
|
|
||||||
|
def _restore_window(self):
|
||||||
|
qsettings = CuteSettings()
|
||||||
|
geometry_restored = False
|
||||||
|
geometry = qsettings.value("mainWindow/geometry")
|
||||||
|
if geometry:
|
||||||
|
geometry_restored = self.restoreGeometry(geometry)
|
||||||
|
if not geometry_restored:
|
||||||
|
self.setGeometry(0, 0, 800, 600)
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
self.destruct()
|
||||||
|
|
||||||
|
def destruct(self):
|
||||||
|
self.tabs.destruct()
|
||||||
|
self.close()
|
||||||
|
SettingsStore.save(self.settings)
|
||||||
|
CuteSettings().set_value("mainWindow/geometry", self.saveGeometry())
|
||||||
@@ -15,53 +15,74 @@ class PluginRegistry():
|
|||||||
modules: [ModuleType] = []
|
modules: [ModuleType] = []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def register_plugin(name: str, plugin: PluginBase):
|
def _register_plugin(name: str, plugin: PluginBase):
|
||||||
PluginRegistry.plugins[name] = plugin
|
PluginRegistry.plugins[name] = plugin
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def get_plugins_by_function(function_name: str) -> [PluginBase]:
|
# def load_module(module_name: str) -> ModuleType:
|
||||||
result = []
|
# module_name = f"raven.plugins.{module_name}"
|
||||||
for plugin in PluginRegistry.plugins.values():
|
# module = import_module(module_name)
|
||||||
fun = getattr(plugin, function_name, None)
|
# PluginRegistry.modules.append(module)
|
||||||
if callable(fun):
|
# return module
|
||||||
result.append(plugin)
|
|
||||||
return result
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def load_module(module_name: str) -> ModuleType:
|
|
||||||
module_name = f"plugins.{module_name}"
|
|
||||||
module = import_module(module_name)
|
|
||||||
PluginRegistry.modules.append(module)
|
|
||||||
return module
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_plugin(plugin_name: str) -> PluginBase:
|
def load_plugin(plugin_name: str) -> PluginBase:
|
||||||
module_name = f"plugins.{plugin_name.lower()}"
|
module_name = f"raven.plugins.{plugin_name.lower()}"
|
||||||
module = import_module(module_name)
|
module = import_module(module_name)
|
||||||
if plugin_name in dir(module):
|
if plugin_name in dir(module):
|
||||||
plugin_class = getattr(module, plugin_name)
|
plugin_class = getattr(module, plugin_name)
|
||||||
|
|
||||||
if isclass(plugin_class) and issubclass(plugin_class, PluginBase):
|
if isclass(plugin_class) and issubclass(plugin_class, PluginBase):
|
||||||
PluginRegistry.register_plugin(plugin_name, plugin_class())
|
PluginRegistry._register_plugin(plugin_name, plugin_class())
|
||||||
return plugin_class
|
return plugin_class
|
||||||
raise RuntimeError("plugin %s not found" % plugin_name)
|
raise RuntimeError("plugin %s not found" % plugin_name)
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def get_modules() -> [ModuleType]:
|
# def get_modules() -> [ModuleType]:
|
||||||
return PluginRegistry.modules.copy()
|
# return PluginRegistry.modules.copy()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_plugins() -> [PluginBase]:
|
def get_plugins() -> [PluginBase]:
|
||||||
return PluginRegistry.modules.copy()
|
return PluginRegistry.modules.copy()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def execute(function_name: str, *args):
|
def executeSingle(function_name: str, *args):
|
||||||
|
return PluginRegistry._execute(function_name, True, *args)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def execute(function_name: str, *args) -> []:
|
||||||
|
return PluginRegistry._execute(function_name, False, *args)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _execute(function_name: str, return_first: bool, *args) -> []:
|
||||||
|
result = []
|
||||||
for plugin in PluginRegistry.plugins.values():
|
for plugin in PluginRegistry.plugins.values():
|
||||||
fun = getattr(plugin, function_name, None)
|
fun = getattr(plugin, function_name, None)
|
||||||
|
|
||||||
sig = signature(fun)
|
|
||||||
if callable(fun):
|
if callable(fun):
|
||||||
|
sig = signature(fun)
|
||||||
if len(sig.parameters) != len(args):
|
if len(sig.parameters) != len(args):
|
||||||
raise RuntimeError("method %s.%s has wrong number of arguments. expected %s but was %s " % (
|
raise RuntimeError("method %s.%s has wrong number of arguments. expected %s but was %s " % (
|
||||||
plugin, function_name, len(args), len(sig.parameters)))
|
plugin, function_name, len(args), len(sig.parameters)))
|
||||||
fun(args)
|
print("calling %s with args %s" % (fun, args))
|
||||||
|
if len(args) == 0:
|
||||||
|
return_value = fun()
|
||||||
|
elif len(args) == 1:
|
||||||
|
return_value = fun(args[0])
|
||||||
|
elif len(args) == 2:
|
||||||
|
return_value = fun(args[0], args[1])
|
||||||
|
elif len(args) == 3:
|
||||||
|
return_value = fun(args[0], args[1], args[2])
|
||||||
|
elif len(args) == 4:
|
||||||
|
return_value = fun(args[0], args[1], args[2], args[3])
|
||||||
|
elif len(args) == 5:
|
||||||
|
return_value = fun(args[0], args[1], args[2], args[3], args[4])
|
||||||
|
else:
|
||||||
|
raise Exception("too many arguments")
|
||||||
|
|
||||||
|
if return_first:
|
||||||
|
return return_value
|
||||||
|
result.append(return_value)
|
||||||
|
if return_first:
|
||||||
|
return None
|
||||||
|
return result
|
||||||
|
|||||||
0
raven/plugins/domain/__init__.py
Normal file
0
raven/plugins/domain/__init__.py
Normal file
11
raven/plugins/domain/menucontribution.py
Normal file
11
raven/plugins/domain/menucontribution.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from raven.plugins.domain.raction import RAction
|
||||||
|
from raven.plugins.domain.rmenu import RMenu
|
||||||
|
|
||||||
|
|
||||||
|
class MenuContribution():
|
||||||
|
def __init__(self, menu_id: str, action: RAction = None, menu: RMenu = None, action_id=None):
|
||||||
|
super(MenuContribution, self).__init__()
|
||||||
|
self.menu_id = menu_id
|
||||||
|
self.action = action
|
||||||
|
self.menu = menu
|
||||||
|
self.action_id = action_id
|
||||||
37
raven/plugins/domain/raction.py
Normal file
37
raven/plugins/domain/raction.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
class RAction():
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
label: str,
|
||||||
|
action=None,
|
||||||
|
shortcut: str = None,
|
||||||
|
icon_from_theme: str = None,
|
||||||
|
icon_file: str = None,
|
||||||
|
checkable: bool = False,
|
||||||
|
checked: bool = False
|
||||||
|
):
|
||||||
|
super(RAction, self).__init__()
|
||||||
|
self.label = label
|
||||||
|
self.action = action
|
||||||
|
self.shortcut = shortcut
|
||||||
|
self.icon_from_theme = icon_from_theme
|
||||||
|
self.icon_file = icon_file
|
||||||
|
self.checkable = checkable
|
||||||
|
self.checked = checked
|
||||||
|
|
||||||
|
def set_action(self, action):
|
||||||
|
self.action = action
|
||||||
|
|
||||||
|
def set_icon_from_theme(self, icon_from_theme: str):
|
||||||
|
self.icon_from_theme = icon_from_theme
|
||||||
|
|
||||||
|
def set_icon_file(self, icon_file: str):
|
||||||
|
self.icon_file = icon_file
|
||||||
|
|
||||||
|
def set_shortcut(self, shortcut: str):
|
||||||
|
self.shortcut = shortcut
|
||||||
|
|
||||||
|
def set_checkable(self, checkable: bool):
|
||||||
|
self.checkable = checkable
|
||||||
|
|
||||||
|
def set_checked(self, checked: bool):
|
||||||
|
self.checked = checked
|
||||||
26
raven/plugins/domain/rmenu.py
Normal file
26
raven/plugins/domain/rmenu.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from raven.plugins.domain.raction import RAction
|
||||||
|
|
||||||
|
|
||||||
|
class RMenu():
|
||||||
|
def __init__(self, label: str):
|
||||||
|
super(RMenu, self).__init__()
|
||||||
|
self.label = label
|
||||||
|
self.actions = []
|
||||||
|
self.listeners = []
|
||||||
|
|
||||||
|
def add_action(self, action: RAction):
|
||||||
|
self.actions.append(action)
|
||||||
|
self._notify()
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.actions.clear()
|
||||||
|
self._notify()
|
||||||
|
|
||||||
|
def _notify(self):
|
||||||
|
for listener in self.listeners:
|
||||||
|
listener()
|
||||||
|
|
||||||
|
def add_change_listener(self, listener: Callable[[], None]):
|
||||||
|
self.listeners.append(listener)
|
||||||
84
raven/plugins/openfileplugin.py
Normal file
84
raven/plugins/openfileplugin.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import os
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from PyQt6.QtGui import QAction, QIcon
|
||||||
|
from PyQt6.QtWidgets import QMenu, QFileDialog
|
||||||
|
|
||||||
|
from raven.pluginbase import PluginBase
|
||||||
|
from raven.pluginregistry import PluginRegistry
|
||||||
|
from raven.plugins.domain.menucontribution import MenuContribution
|
||||||
|
from raven.plugins.domain.raction import RAction
|
||||||
|
from raven.plugins.domain.rmenu import RMenu
|
||||||
|
from settings import Settings
|
||||||
|
|
||||||
|
|
||||||
|
class OpenFilePlugin(PluginBase):
|
||||||
|
def __init__(self):
|
||||||
|
super(OpenFilePlugin, self).__init__()
|
||||||
|
print("init OpenFilePlugin")
|
||||||
|
|
||||||
|
def set_settings(self, settings: Settings):
|
||||||
|
self.settings = settings
|
||||||
|
|
||||||
|
def set_translator(self, tr: Callable[[str], str]):
|
||||||
|
self.tr = tr
|
||||||
|
|
||||||
|
def _action_open_file(self) -> RAction:
|
||||||
|
open_file = RAction(self.tr("&Open..."), self._open_file_dialog, shortcut='Ctrl+O',
|
||||||
|
icon_from_theme="document-open")
|
||||||
|
return open_file
|
||||||
|
|
||||||
|
def _sub_menu_recent_files(self) -> RMenu:
|
||||||
|
self._menu_recent_files = RMenu("Open &Recent")
|
||||||
|
self._update_recent_files_menu()
|
||||||
|
return self._menu_recent_files
|
||||||
|
|
||||||
|
def get_menu_contributions(self) -> [MenuContribution]:
|
||||||
|
return [
|
||||||
|
MenuContribution("file", action=self._action_open_file(), action_id="open file"),
|
||||||
|
MenuContribution("file", menu=self._sub_menu_recent_files(), action_id="recent files menu"),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _open_file_dialog(self) -> None:
|
||||||
|
current_file = PluginRegistry.executeSingle("current_file")
|
||||||
|
directory = os.path.dirname(current_file) if current_file else ''
|
||||||
|
|
||||||
|
dialog = QFileDialog()
|
||||||
|
(selected_file, _filter) = dialog.getOpenFileName(
|
||||||
|
caption=self.tr("Open File"),
|
||||||
|
directory=directory
|
||||||
|
)
|
||||||
|
if selected_file:
|
||||||
|
self._open_file(selected_file)
|
||||||
|
|
||||||
|
def _open_file(self, selected_file: str):
|
||||||
|
PluginRegistry.executeSingle("create_tab", selected_file)
|
||||||
|
self._remember_recent_file(selected_file)
|
||||||
|
|
||||||
|
def _get_recent_files(self) -> [str]:
|
||||||
|
recent_files = self.settings.session.get('general', 'recent_files', fallback='')
|
||||||
|
print(recent_files)
|
||||||
|
files = recent_files.split(os.pathsep)
|
||||||
|
if "" in files:
|
||||||
|
files.remove("")
|
||||||
|
return files
|
||||||
|
|
||||||
|
def _update_recent_files_menu(self):
|
||||||
|
self._menu_recent_files.clear()
|
||||||
|
files = self._get_recent_files()
|
||||||
|
for file in files:
|
||||||
|
action = RAction(os.path.basename(file))
|
||||||
|
action.set_action(lambda x, f=file: self._open_file(f))
|
||||||
|
self._menu_recent_files.add_action(action)
|
||||||
|
|
||||||
|
def _remember_recent_file(self, file: str):
|
||||||
|
files = self._get_recent_files()
|
||||||
|
if file in files:
|
||||||
|
files.remove(file)
|
||||||
|
files.insert(0, file)
|
||||||
|
recent_files = os.pathsep.join(files[:10])
|
||||||
|
self.settings.set_session('general', 'recent_files', recent_files)
|
||||||
|
self._update_recent_files_menu()
|
||||||
|
|
||||||
|
def after_open_file(self, file: str):
|
||||||
|
self._remember_recent_file(file)
|
||||||
21
raven/plugins/ravenlogplugin.py
Normal file
21
raven/plugins/ravenlogplugin.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from raven.mainwindow import MainWindow
|
||||||
|
from raven.pluginbase import PluginBase
|
||||||
|
|
||||||
|
|
||||||
|
class RavenLogPlugin(PluginBase):
|
||||||
|
def __init__(self):
|
||||||
|
super(RavenLogPlugin, self).__init__()
|
||||||
|
self.main_window = None
|
||||||
|
|
||||||
|
def create_main_window(self):
|
||||||
|
if not self.main_window:
|
||||||
|
self.main_window = MainWindow()
|
||||||
|
return self.main_window
|
||||||
|
|
||||||
|
def current_file(self) -> Optional[str]:
|
||||||
|
return self.main_window.current_file()
|
||||||
|
|
||||||
|
def create_tab(self, file: str):
|
||||||
|
self.main_window.tabs.create_tab(file)
|
||||||
@@ -62,8 +62,8 @@ def set_window_icon(app: QApplication):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
filterplugin = PluginRegistry.load_plugin("FilterPlugin")
|
PluginRegistry.load_plugin("FilterPlugin")
|
||||||
logfileviewerplugin = PluginRegistry.load_plugin("LogFileViewerPlugin")
|
PluginRegistry.load_plugin("LogFileViewerPlugin")
|
||||||
|
|
||||||
PluginRegistry.execute("say_hello", "World")
|
PluginRegistry.execute("say_hello", "World")
|
||||||
|
|
||||||
|
|||||||
0
testbed/__init__.py
Normal file
0
testbed/__init__.py
Normal file
32
testbed/docks.py
Normal file
32
testbed/docks.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import QApplication, QMainWindow, QDockWidget, QLabel, QTextEdit
|
||||||
|
from PyQt6.QtCore import Qt
|
||||||
|
|
||||||
|
|
||||||
|
class DockWindow(QMainWindow):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(DockWindow, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.dock_1 = QDockWidget("Dock1", self)
|
||||||
|
self.dock_1.layout().addWidget(QLabel("dock1"))
|
||||||
|
|
||||||
|
self.dock_2 = QDockWidget("Dock2", self)
|
||||||
|
self.dock_2.layout().addWidget(QLabel("dock2"))
|
||||||
|
|
||||||
|
self.dock_3 = QDockWidget("Dock3", self)
|
||||||
|
self.dock_3.layout().addWidget(QLabel("dock3"))
|
||||||
|
|
||||||
|
self.setCentralWidget(QTextEdit())
|
||||||
|
self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.dock_1)
|
||||||
|
self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock_2)
|
||||||
|
self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock_3)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
window = DockWindow()
|
||||||
|
window.show()
|
||||||
|
|
||||||
|
app.exec()
|
||||||
Reference in New Issue
Block a user