Files
krowlog/raven/mainwindow.py
2021-11-26 18:47:00 +01:00

271 lines
9.7 KiB
Python

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]
if len(mcs) == 0:
continue
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())