diff --git a/raven/__init__.py b/raven/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/raven/pluginbase.py b/raven/pluginbase.py new file mode 100644 index 0000000..1b79fbc --- /dev/null +++ b/raven/pluginbase.py @@ -0,0 +1,3 @@ +class PluginBase(): + def __init__(self): + pass diff --git a/raven/pluginregistry.py b/raven/pluginregistry.py new file mode 100644 index 0000000..28886f9 --- /dev/null +++ b/raven/pluginregistry.py @@ -0,0 +1,55 @@ +from types import ModuleType +from typing import Dict +from inspect import isclass +from pkgutil import iter_modules +from pathlib import Path +from os.path import dirname +from importlib import import_module +from raven.pluginbase import PluginBase + + +class PluginRegistry(): + plugins: Dict[str, PluginBase] = {} + + modules: [ModuleType] = [] + + @staticmethod + def register_plugin(name: str, plugin: PluginBase): + PluginRegistry.plugins[name] = plugin + + @staticmethod + def get_plugins_by_function(function_name: str) -> [PluginBase]: + result = [] + for plugin in PluginRegistry.plugins.values(): + fun = getattr(plugin, function_name, None) + if callable(fun): + result.append(plugin) + return result + + @staticmethod + def load_module(module_name: str) -> ModuleType: + module_name = f"plugins.{module_name}" + # import the module and iterate through its attributes + module = import_module(module_name) + PluginRegistry.modules.append(module) + return module + + @staticmethod + def load_plugin(plugin_name: str): + module_name = f"plugins.{plugin_name.lower()}" + module = import_module(module_name) + if plugin_name in dir(module): + plugin_class = getattr(module, plugin_name) + + if isclass(plugin_class) and issubclass(plugin_class, PluginBase): + PluginRegistry.register_plugin(plugin_name, plugin_class) + print("%s -> %s :: %s in %s" % (plugin_name, plugin_class, module_name, module)) + return plugin_class + + @staticmethod + def get_modules() -> [ModuleType]: + return PluginRegistry.modules.copy() + + @staticmethod + def get_plugins() -> [ModuleType]: + return PluginRegistry.modules.copy() diff --git a/raven/plugins/__init__.py b/raven/plugins/__init__.py new file mode 100644 index 0000000..570a12b --- /dev/null +++ b/raven/plugins/__init__.py @@ -0,0 +1,25 @@ +from inspect import isclass +from pkgutil import iter_modules +from pathlib import Path +from importlib import import_module +from raven.pluginbase import PluginBase + +# iterate through the modules in the current package +from raven.pluginregistry import PluginRegistry + +if False: + package_dir = Path(__file__).resolve().parent + for (_, module_name, _) in iter_modules([str(package_dir)]): + # import the module and iterate through its attributes + module = import_module(f"{__name__}.{module_name}") + print("module: %s" % module) + + for attribute_name in dir(module): + if attribute_name == "PluginBase": + continue + attribute = getattr(module, attribute_name) + + if isclass(attribute) and issubclass(attribute, PluginBase): + globals()[attribute_name] = attribute + PluginRegistry.register_plugin(attribute_name, attribute) + print("%s -> %s :: %s in %s" % (attribute_name, attribute, module_name, module)) diff --git a/raven/plugins/filterplugin.py b/raven/plugins/filterplugin.py new file mode 100644 index 0000000..caade22 --- /dev/null +++ b/raven/plugins/filterplugin.py @@ -0,0 +1,11 @@ +from raven.pluginbase import PluginBase + + +class FilterPlugin(PluginBase): + def __init__(self): + super(FilterPlugin, self).__init__() + print("init FilterPlugin") + + +def init(): + print("initializing filter plugin") diff --git a/raven/plugins/logfileviewerplugin.py b/raven/plugins/logfileviewerplugin.py new file mode 100644 index 0000000..fecbc12 --- /dev/null +++ b/raven/plugins/logfileviewerplugin.py @@ -0,0 +1,7 @@ +from raven.pluginbase import PluginBase + + +class LogFileViewerPlugin(PluginBase): + def __init__(self): + super(LogFileViewerPlugin, self).__init__() + print("init LogFileViewerPlugin") diff --git a/raven/ravenlog.py b/raven/ravenlog.py new file mode 100644 index 0000000..5ce3fab --- /dev/null +++ b/raven/ravenlog.py @@ -0,0 +1,80 @@ +import ctypes +import logging +import signal +import sys +from inspect import isclass +from importlib import import_module +from pathlib import Path +from pkgutil import iter_modules + +from plugins import * + +from PyQt6 import QtCore +from PyQt6.QtCore import QTimer +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import QApplication + +import constants +from raven.ravenwindow import RavenWindow +from ravenui import RavenUI + +logging.basicConfig(level=logging.INFO) +log = logging.getLogger("main") + + +def stop_signal(signum, _stackframe): + """ Handle terminate signal """ + try: + log.info("Terminate signal received. %s", signum) + QtCore.QCoreApplication.quit() + except Exception: + log.exception("Exception occurred while terminating") + sys.exit(1) + sys.exit(0) + + +def init_signal_handler(): + # workaround to make signals work in QT apps. + # They do not work out of the box, because the main thread + # is running in C++ code once app.exec() is executed + # Forcing an empty lambda to be executed periodically gives + # control back to python and allows python to react to signals + timer = QTimer() + timer.timeout.connect(lambda: None) + timer.start(100) + signal.signal(signal.SIGINT, stop_signal) + signal.signal(signal.SIGTERM, stop_signal) + + +def init_translator(app: QApplication): + # translator = QTranslator() + # if translator.load(QLocale("de"), "messages_de.ts"): + # app.installTranslator(translator) + pass + + +def set_window_icon(app: QApplication): + app.setWindowIcon(QIcon("../" + constants.raven_icon)) + + # see https://stackoverflow.com/questions/1551605/how-to-set-applications-taskbar-icon-in-windows-7/1552105#1552105 + if sys.platform == 'win32' or sys.platform == 'cygwin': + ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('opentext.ravenlog') + + +if __name__ == "__main__": + filterplugin = PluginRegistry.load_plugin("FilterPlugin") + filterplugin() + + logfileviewerplugin = PluginRegistry.load_plugin("LogFileViewerPlugin") + logfileviewerplugin() + + app = QApplication(sys.argv) + set_window_icon(app) + init_translator(app) + init_signal_handler() + + window = RavenWindow() + RavenUI.window = window + window.show() + + app.exec() diff --git a/raven/ravenwindow.py b/raven/ravenwindow.py new file mode 100644 index 0000000..d2b02c8 --- /dev/null +++ b/raven/ravenwindow.py @@ -0,0 +1,34 @@ +from PyQt6.QtWidgets import QMainWindow, QMenu, QStatusBar + +from cutesettings import CuteSettings +from settingsstore import SettingsStore + + +class RavenWindow(QMainWindow): + def __init__(self, *args, **kwargs): + super(RavenWindow, 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 _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)