import logging import os import signal from PyQt6 import QtCore from PyQt6.QtWidgets import * from PyQt6.QtCore import * from PyQt6.QtGui import * import sys import urlutils from aboutdialog import AboutDialog from cutesettings import CuteSettings 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) log = logging.getLogger("main") raven_icon = "icon7.png" 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) close_action = QAction(QIcon.fromTheme("exit"), 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(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 e.mimeData().hasFormat('text/plain') and 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): """ 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) if __name__ == "__main__": app = QApplication(sys.argv) app.setWindowIcon(QIcon(raven_icon)) # translator = QTranslator() # if translator.load(QLocale("de"), "messages_de.ts"): # app.installTranslator(translator) # 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) window = MainWindow() RavenUI.window = window 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/vapbdcom.csv") window.open_file("/var/log/syslog") window.open_file("/home/andi/ws/ravenlog/example.log") signal.signal(signal.SIGINT, stop_signal) signal.signal(signal.SIGTERM, stop_signal) app.exec()