2019-03-26 20:52:43 +11:00
|
|
|
# Copyright 2019 miruka
|
|
|
|
# This file is part of harmonyqml, licensed under GPLv3.
|
|
|
|
|
2019-05-01 15:23:38 +10:00
|
|
|
import signal
|
2019-03-26 20:52:43 +11:00
|
|
|
import sys
|
|
|
|
from pathlib import Path
|
2019-05-01 15:23:38 +10:00
|
|
|
from typing import Any, Dict, Generator
|
2019-03-26 20:52:43 +11:00
|
|
|
|
2019-05-01 15:23:38 +10:00
|
|
|
from PyQt5.QtCore import QObject, QTimer
|
2019-03-26 20:52:43 +11:00
|
|
|
from PyQt5.QtQml import QQmlApplicationEngine
|
|
|
|
|
|
|
|
|
|
|
|
class Engine(QQmlApplicationEngine):
|
2019-05-01 15:23:38 +10:00
|
|
|
def __init__(self, debug: bool = False) -> None:
|
|
|
|
# Connect UNXI signals to properly exit program
|
|
|
|
self._original_signal_handlers: Dict[int, Any] = {}
|
2019-03-26 20:52:43 +11:00
|
|
|
|
2019-05-01 15:23:38 +10:00
|
|
|
for signame in ("INT" , "HUP", "QUIT", "TERM"):
|
|
|
|
sig = signal.Signals[f"SIG{signame}"] # pylint: disable=no-member
|
|
|
|
self._original_signal_handlers[sig] = signal.getsignal(sig)
|
|
|
|
signal.signal(sig, self.onExitSignal)
|
2019-03-26 20:52:43 +11:00
|
|
|
|
|
|
|
# Make SIGINT (ctrl-c) work
|
|
|
|
self._sigint_timer = QTimer()
|
|
|
|
self._sigint_timer.timeout.connect(lambda: None)
|
|
|
|
self._sigint_timer.start(100)
|
|
|
|
|
2019-05-01 15:23:38 +10:00
|
|
|
super().__init__()
|
2019-05-01 15:32:06 +10:00
|
|
|
self.app_dir = Path(__file__).resolve().parent
|
2019-05-01 15:23:38 +10:00
|
|
|
|
|
|
|
from .backend.backend import Backend
|
|
|
|
self.backend = Backend(self)
|
|
|
|
self.rootContext().setContextProperty("Backend", self.backend)
|
|
|
|
|
2019-03-26 20:52:43 +11:00
|
|
|
# Setup UI live-reloading when a file is edited
|
2019-03-28 07:21:31 +11:00
|
|
|
if debug:
|
2019-05-01 15:23:38 +10:00
|
|
|
from PyQt5.QtCore import QFileSystemWatcher
|
2019-03-28 07:21:31 +11:00
|
|
|
self._watcher = QFileSystemWatcher()
|
2019-05-01 15:23:38 +10:00
|
|
|
self._watcher.directoryChanged.connect(lambda _: self.reloadQml())
|
2019-03-28 07:21:31 +11:00
|
|
|
self._watcher.addPath(str(self.app_dir))
|
|
|
|
|
|
|
|
for _dir in list(self._recursive_dirs_in(self.app_dir)):
|
|
|
|
self._watcher.addPath(str(_dir))
|
2019-03-26 20:52:43 +11:00
|
|
|
|
|
|
|
|
2019-05-01 15:23:38 +10:00
|
|
|
def onExitSignal(self, *_) -> None:
|
|
|
|
for sig, handler in self._original_signal_handlers.items():
|
|
|
|
signal.signal(sig, handler)
|
2019-03-26 20:52:43 +11:00
|
|
|
|
2019-05-01 15:23:38 +10:00
|
|
|
self._original_signal_handlers.clear()
|
|
|
|
self.closeWindow()
|
2019-03-26 20:52:43 +11:00
|
|
|
|
|
|
|
|
2019-03-28 07:21:31 +11:00
|
|
|
def _recursive_dirs_in(self, path: Path) -> Generator[Path, None, None]:
|
|
|
|
for item in path.iterdir():
|
|
|
|
if item.is_dir() and item.name != "__pycache__":
|
|
|
|
yield item
|
|
|
|
yield from self._recursive_dirs_in(item)
|
|
|
|
|
|
|
|
|
2019-05-01 15:23:38 +10:00
|
|
|
def showWindow(self) -> None:
|
|
|
|
self.load(str(self.app_dir / "components" / "Window.qml"))
|
|
|
|
|
|
|
|
|
|
|
|
def closeWindow(self) -> None:
|
|
|
|
try:
|
|
|
|
self.rootObjects()[0].close()
|
|
|
|
except IndexError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def reloadQml(self) -> None:
|
2019-03-26 20:52:43 +11:00
|
|
|
loader = self.rootObjects()[0].findChild(QObject, "UILoader")
|
2019-05-01 15:23:38 +10:00
|
|
|
|
2019-03-26 20:52:43 +11:00
|
|
|
source = loader.property("source")
|
|
|
|
loader.setProperty("source", None)
|
2019-04-28 14:44:55 +10:00
|
|
|
self.clearComponentCache()
|
2019-05-01 15:23:38 +10:00
|
|
|
|
2019-03-26 20:52:43 +11:00
|
|
|
loader.setProperty("source", source)
|