App: Move legendary initialization to the singleton
App: Move tray to MainWindow Shared: Add destructor for singleton instances
This commit is contained in:
parent
4951743bbf
commit
afcdc1dea1
146
rare/app.py
146
rare/app.py
|
@ -13,14 +13,19 @@ from typing import Optional
|
||||||
import legendary
|
import legendary
|
||||||
import requests.exceptions
|
import requests.exceptions
|
||||||
from PyQt5.QtCore import QThreadPool, QTimer, QT_VERSION_STR, PYQT_VERSION_STR
|
from PyQt5.QtCore import QThreadPool, QTimer, QT_VERSION_STR, PYQT_VERSION_STR
|
||||||
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QMessageBox
|
from PyQt5.QtWidgets import QApplication, QMessageBox
|
||||||
from requests import HTTPError
|
from requests import HTTPError
|
||||||
|
|
||||||
import rare
|
import rare
|
||||||
from rare.components.dialogs.launch_dialog import LaunchDialog
|
from rare.components.dialogs.launch_dialog import LaunchDialog
|
||||||
from rare.components.main_window import MainWindow
|
from rare.components.main_window import MainWindow
|
||||||
from rare.components.tray_icon import TrayIcon
|
from rare.shared import (
|
||||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
|
LegendaryCoreSingleton,
|
||||||
|
GlobalSignalsSingleton,
|
||||||
|
ArgumentsSingleton,
|
||||||
|
ApiResultsSingleton,
|
||||||
|
clear_singleton_instance
|
||||||
|
)
|
||||||
from rare.shared.image_manager import ImageManagerSingleton
|
from rare.shared.image_manager import ImageManagerSingleton
|
||||||
from rare.utils import legendary_utils, config_helper
|
from rare.utils import legendary_utils, config_helper
|
||||||
from rare.utils.paths import cache_dir, tmp_dir
|
from rare.utils.paths import cache_dir, tmp_dir
|
||||||
|
@ -54,64 +59,21 @@ def excepthook(exc_type, exc_value, exc_tb):
|
||||||
|
|
||||||
|
|
||||||
class App(RareApp):
|
class App(RareApp):
|
||||||
mainwindow: Optional[MainWindow] = None
|
|
||||||
tray_icon: Optional[QSystemTrayIcon] = None
|
|
||||||
|
|
||||||
def __init__(self, args: Namespace):
|
def __init__(self, args: Namespace):
|
||||||
super(App, self).__init__()
|
super(App, self).__init__()
|
||||||
|
self.core = LegendaryCoreSingleton()
|
||||||
self.args = ArgumentsSingleton(args) # add some options
|
self.args = ArgumentsSingleton(args) # add some options
|
||||||
self.window_launched = False
|
|
||||||
|
|
||||||
# init Legendary
|
|
||||||
try:
|
|
||||||
self.core = LegendaryCoreSingleton(init=True)
|
|
||||||
except configparser.MissingSectionHeaderError as e:
|
|
||||||
logger.warning(f"Config is corrupt: {e}")
|
|
||||||
if config_path := os.environ.get("XDG_CONFIG_HOME"):
|
|
||||||
path = os.path.join(config_path, "legendary")
|
|
||||||
else:
|
|
||||||
path = os.path.expanduser("~/.config/legendary")
|
|
||||||
with open(os.path.join(path, "config.ini"), "w") as config_file:
|
|
||||||
config_file.write("[Legendary]")
|
|
||||||
self.core = LegendaryCoreSingleton(init=True)
|
|
||||||
if "Legendary" not in self.core.lgd.config.sections():
|
|
||||||
self.core.lgd.config.add_section("Legendary")
|
|
||||||
self.core.lgd.save_config()
|
|
||||||
|
|
||||||
lang = self.settings.value("language", self.core.language_code, type=str)
|
lang = self.settings.value("language", self.core.language_code, type=str)
|
||||||
self.load_translator(lang)
|
self.load_translator(lang)
|
||||||
|
|
||||||
config_helper.init_config_handler(self.core)
|
|
||||||
|
|
||||||
# workaround if egl sync enabled, but no programdata_path
|
|
||||||
# programdata_path might be unset if logging in through the browser
|
|
||||||
if self.core.egl_sync_enabled:
|
|
||||||
if self.core.egl.programdata_path is None:
|
|
||||||
self.core.lgd.config.remove_option("Legendary", "egl_sync")
|
|
||||||
self.core.lgd.save_config()
|
|
||||||
else:
|
|
||||||
if not os.path.exists(self.core.egl.programdata_path):
|
|
||||||
self.core.lgd.config.remove_option("Legendary", "egl_sync")
|
|
||||||
self.core.lgd.save_config()
|
|
||||||
|
|
||||||
# set Application name for settings
|
# set Application name for settings
|
||||||
self.launch_dialog = None
|
self.mainwindow: Optional[MainWindow] = None
|
||||||
|
self.launch_dialog: Optional[LaunchDialog] = None
|
||||||
|
|
||||||
self.signals = GlobalSignalsSingleton(init=True)
|
self.signals = GlobalSignalsSingleton(init=True)
|
||||||
self.image_manager = ImageManagerSingleton(init=True)
|
self.image_manager = ImageManagerSingleton(init=True)
|
||||||
|
|
||||||
self.signals.exit_app.connect(self.exit_app)
|
|
||||||
self.signals.send_notification.connect(
|
|
||||||
lambda title: self.tray_icon.showMessage(
|
|
||||||
self.tr("Download finished"),
|
|
||||||
self.tr("Download finished. {} is playable now").format(title),
|
|
||||||
QSystemTrayIcon.Information,
|
|
||||||
4000,
|
|
||||||
)
|
|
||||||
if self.settings.value("notification", True, bool)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
# launch app
|
# launch app
|
||||||
self.launch_dialog = LaunchDialog(parent=None)
|
self.launch_dialog = LaunchDialog(parent=None)
|
||||||
self.launch_dialog.quit_app.connect(self.launch_dialog.close)
|
self.launch_dialog.quit_app.connect(self.launch_dialog.close)
|
||||||
|
@ -140,12 +102,6 @@ class App(RareApp):
|
||||||
td = abs(dt_exp - dt_now)
|
td = abs(dt_exp - dt_now)
|
||||||
self.timer.start(int(td.total_seconds() - 60) * 1000)
|
self.timer.start(int(td.total_seconds() - 60) * 1000)
|
||||||
|
|
||||||
def show_mainwindow(self):
|
|
||||||
if self.window_launched:
|
|
||||||
self.mainwindow.show()
|
|
||||||
else:
|
|
||||||
self.mainwindow.show_window_centered()
|
|
||||||
|
|
||||||
def start_app(self):
|
def start_app(self):
|
||||||
for igame in self.core.get_installed_list():
|
for igame in self.core.get_installed_list():
|
||||||
if not os.path.exists(igame.install_path):
|
if not os.path.exists(igame.install_path):
|
||||||
|
@ -167,85 +123,27 @@ class App(RareApp):
|
||||||
logger.info(f"{igame.title} needs verification")
|
logger.info(f"{igame.title} needs verification")
|
||||||
|
|
||||||
self.mainwindow = MainWindow()
|
self.mainwindow = MainWindow()
|
||||||
self.tray_icon: TrayIcon = TrayIcon(self)
|
self.mainwindow.exit_app.connect(self.exit_app)
|
||||||
self.tray_icon.exit_action.triggered.connect(self.exit_app)
|
|
||||||
self.tray_icon.start_rare.triggered.connect(self.show_mainwindow)
|
|
||||||
self.tray_icon.activated.connect(
|
|
||||||
lambda r: self.show_mainwindow()
|
|
||||||
if r == QSystemTrayIcon.DoubleClick
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
if not self.args.silent:
|
if not self.args.silent:
|
||||||
self.mainwindow.show_window_centered()
|
self.mainwindow.show()
|
||||||
self.window_launched = True
|
|
||||||
|
|
||||||
if self.args.subparser == "launch":
|
|
||||||
if self.args.app_name in [
|
|
||||||
i.app_name for i in self.core.get_installed_list()
|
|
||||||
]:
|
|
||||||
logger.info(
|
|
||||||
f"Launching {self.core.get_installed_game(self.args.app_name).title}"
|
|
||||||
)
|
|
||||||
self.mainwindow.tab_widget.games_tab.game_utils.prepare_launch(
|
|
||||||
self.args.app_name
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.error(
|
|
||||||
f"Could not find {self.args.app_name} in Games or it is not installed"
|
|
||||||
)
|
|
||||||
QMessageBox.warning(
|
|
||||||
self.mainwindow,
|
|
||||||
"Warning",
|
|
||||||
self.tr(
|
|
||||||
"Could not find {} in installed games. Did you modify the shortcut? "
|
|
||||||
).format(self.args.app_name),
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.args.test_start:
|
if self.args.test_start:
|
||||||
self.exit_app(0)
|
self.exit_app(0)
|
||||||
|
|
||||||
def tray(self, reason):
|
|
||||||
if reason == QSystemTrayIcon.DoubleClick:
|
|
||||||
self.mainwindow.show()
|
|
||||||
logger.info("Show App")
|
|
||||||
|
|
||||||
def exit_app(self, exit_code=0):
|
def exit_app(self, exit_code=0):
|
||||||
# FIXME: Fix this with the download tab redesign
|
|
||||||
if self.mainwindow is not None:
|
|
||||||
if not self.args.offline and self.mainwindow.tab_widget.downloadTab.is_download_active:
|
|
||||||
question = QMessageBox.question(
|
|
||||||
self.mainwindow,
|
|
||||||
self.tr("Close"),
|
|
||||||
self.tr(
|
|
||||||
"There is a download active. Do you really want to exit app?"
|
|
||||||
),
|
|
||||||
QMessageBox.Yes,
|
|
||||||
QMessageBox.No,
|
|
||||||
)
|
|
||||||
if question == QMessageBox.No:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
# clear queue
|
|
||||||
self.mainwindow.tab_widget.downloadTab.queue_widget.update_queue([])
|
|
||||||
self.mainwindow.tab_widget.downloadTab.stop_download()
|
|
||||||
# FIXME: End of FIXME
|
|
||||||
self.mainwindow.timer.stop()
|
|
||||||
self.mainwindow.hide()
|
|
||||||
threadpool = QThreadPool.globalInstance()
|
threadpool = QThreadPool.globalInstance()
|
||||||
threadpool.waitForDone()
|
threadpool.waitForDone()
|
||||||
self.core.exit()
|
|
||||||
if self.mainwindow is not None:
|
|
||||||
self.mainwindow.close()
|
|
||||||
self.mainwindow.deleteLater()
|
|
||||||
self.mainwindow = None
|
|
||||||
if self.tray_icon is not None:
|
|
||||||
self.tray_icon.deleteLater()
|
|
||||||
self.tray_icon = None
|
|
||||||
if self.timer is not None:
|
if self.timer is not None:
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
self.timer.deleteLater()
|
self.timer.deleteLater()
|
||||||
self.timer = None
|
self.timer = None
|
||||||
|
if self.mainwindow is not None:
|
||||||
|
self.mainwindow.close()
|
||||||
|
self.mainwindow = None
|
||||||
|
clear_singleton_instance(self.signals)
|
||||||
|
clear_singleton_instance(self.args)
|
||||||
|
clear_singleton_instance(ApiResultsSingleton())
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
shutil.rmtree(tmp_dir)
|
shutil.rmtree(tmp_dir)
|
||||||
os.makedirs(tmp_dir)
|
os.makedirs(tmp_dir)
|
||||||
|
@ -284,10 +182,16 @@ def start(args):
|
||||||
logger.info(f"Operating System: {platform.system()}")
|
logger.info(f"Operating System: {platform.system()}")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
core = LegendaryCoreSingleton(init=True)
|
||||||
|
config_helper.init_config_handler(core)
|
||||||
app = App(args)
|
app = App(args)
|
||||||
exit_code = app.exec_()
|
exit_code = app.exec_()
|
||||||
# if not restart
|
# if not restart
|
||||||
# restart app
|
# restart app
|
||||||
del app
|
del app
|
||||||
|
core.exit()
|
||||||
|
clear_singleton_instance(core)
|
||||||
if exit_code != -133742:
|
if exit_code != -133742:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
import os
|
import os
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, QSettings, QTimer, QSize
|
from PyQt5.QtCore import Qt, QSettings, QTimer, QSize, pyqtSignal, pyqtSlot
|
||||||
from PyQt5.QtGui import QCloseEvent, QCursor
|
from PyQt5.QtGui import QCloseEvent, QCursor
|
||||||
from PyQt5.QtWidgets import QMainWindow, QApplication, QStatusBar, QScrollArea, QScroller, QComboBox
|
from PyQt5.QtWidgets import QMainWindow, QApplication, QStatusBar, QScrollArea, QScroller, QComboBox, QMessageBox
|
||||||
|
|
||||||
from rare.components.tabs import TabWidget
|
from rare.components.tabs import TabWidget
|
||||||
|
from rare.components.tray_icon import TrayIcon
|
||||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
|
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
|
||||||
from rare.utils.paths import data_dir
|
from rare.utils.paths import data_dir
|
||||||
|
|
||||||
logger = getLogger("Window")
|
logger = getLogger("MainWindow")
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
|
# int: exit code
|
||||||
|
exit_app: pyqtSignal = pyqtSignal(int)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(MainWindow, self).__init__(parent=parent)
|
super(MainWindow, self).__init__(parent=parent)
|
||||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||||
|
@ -46,8 +50,42 @@ class MainWindow(QMainWindow):
|
||||||
self.timer.timeout.connect(self.timer_finished)
|
self.timer.timeout.connect(self.timer_finished)
|
||||||
self.timer.start(1000)
|
self.timer.start(1000)
|
||||||
|
|
||||||
def show_window_centered(self):
|
self.signals.exit_app.connect(self.on_exit_app)
|
||||||
self.show()
|
self.exit_code = 0
|
||||||
|
self.accept_close = False
|
||||||
|
|
||||||
|
self.tray_icon: TrayIcon = TrayIcon(self)
|
||||||
|
self.tray_icon.exit_action.triggered.connect(self.on_exit_app)
|
||||||
|
self.tray_icon.start_rare.triggered.connect(self.show)
|
||||||
|
self.tray_icon.activated.connect(
|
||||||
|
lambda r: self.toggle()
|
||||||
|
if r == self.tray_icon.DoubleClick
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
self.signals.send_notification.connect(
|
||||||
|
lambda title: self.tray_icon.showMessage(
|
||||||
|
self.tr("Download finished"),
|
||||||
|
self.tr("Download finished. {} is playable now").format(title),
|
||||||
|
self.tray_icon.Information,
|
||||||
|
4000,
|
||||||
|
)
|
||||||
|
if self.settings.value("notification", True, bool)
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
self.window_launched = False
|
||||||
|
|
||||||
|
# enable kinetic scrolling
|
||||||
|
for scroll_area in self.findChildren(QScrollArea):
|
||||||
|
if not scroll_area.property("no_kinetic_scroll"):
|
||||||
|
QScroller.grabGesture(scroll_area.viewport(), QScroller.LeftMouseButtonGesture)
|
||||||
|
|
||||||
|
# fix scrolling
|
||||||
|
for combo_box in scroll_area.findChildren(QComboBox):
|
||||||
|
combo_box.wheelEvent = lambda e: e.ignore()
|
||||||
|
|
||||||
|
def center_window(self):
|
||||||
# get the margins of the decorated window
|
# get the margins of the decorated window
|
||||||
margins = self.windowHandle().frameMargins()
|
margins = self.windowHandle().frameMargins()
|
||||||
# get the screen the cursor is on
|
# get the screen the cursor is on
|
||||||
|
@ -68,14 +106,23 @@ class MainWindow(QMainWindow):
|
||||||
- self.rect().adjusted(0, 0, decor_width, decor_height).center()
|
- self.rect().adjusted(0, 0, decor_width, decor_height).center()
|
||||||
)
|
)
|
||||||
|
|
||||||
# enable kinetic scrolling
|
def show(self) -> None:
|
||||||
for scroll_area in self.findChildren(QScrollArea):
|
super(MainWindow, self).show()
|
||||||
if not scroll_area.property("no_kinetic_scroll"):
|
if not self.window_launched:
|
||||||
QScroller.grabGesture(scroll_area.viewport(), QScroller.LeftMouseButtonGesture)
|
self.center_window()
|
||||||
|
self.window_launched = True
|
||||||
|
|
||||||
# fix scrolling
|
def hide(self) -> None:
|
||||||
for combo_box in scroll_area.findChildren(QComboBox):
|
if self.settings.value("save_size", False, bool):
|
||||||
combo_box.wheelEvent = lambda e: e.ignore()
|
size = self.size().width(), self.size().height()
|
||||||
|
self.settings.setValue("window_size", size)
|
||||||
|
super(MainWindow, self).hide()
|
||||||
|
|
||||||
|
def toggle(self):
|
||||||
|
if self.isHidden():
|
||||||
|
self.show()
|
||||||
|
else:
|
||||||
|
self.hide()
|
||||||
|
|
||||||
def timer_finished(self):
|
def timer_finished(self):
|
||||||
file_path = os.path.join(data_dir, "lockfile")
|
file_path = os.path.join(data_dir, "lockfile")
|
||||||
|
@ -88,15 +135,43 @@ class MainWindow(QMainWindow):
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
self.timer.start(1000)
|
self.timer.start(1000)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
@pyqtSlot(int)
|
||||||
|
def on_exit_app(self, exit_code=0) -> None:
|
||||||
|
# FIXME: Fix this with the download tab redesign
|
||||||
|
if not self.args.offline and self.tab_widget.downloadTab.is_download_active:
|
||||||
|
question = QMessageBox.question(
|
||||||
|
self,
|
||||||
|
self.tr("Close"),
|
||||||
|
self.tr(
|
||||||
|
"There is a download active. Do you really want to exit app?"
|
||||||
|
),
|
||||||
|
QMessageBox.Yes,
|
||||||
|
QMessageBox.No,
|
||||||
|
)
|
||||||
|
if question == QMessageBox.No:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# clear queue
|
||||||
|
self.tab_widget.downloadTab.queue_widget.update_queue([])
|
||||||
|
self.tab_widget.downloadTab.stop_download()
|
||||||
|
# FIXME: End of FIXME
|
||||||
|
self.exit_code = exit_code
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def close(self) -> bool:
|
||||||
|
self.accept_close = True
|
||||||
|
return super(MainWindow, self).close()
|
||||||
|
|
||||||
def closeEvent(self, e: QCloseEvent):
|
def closeEvent(self, e: QCloseEvent):
|
||||||
if self.settings.value("save_size", False, bool):
|
if not self.accept_close:
|
||||||
size = self.size().width(), self.size().height()
|
|
||||||
self.settings.setValue("window_size", size)
|
|
||||||
if self.settings.value("sys_tray", True, bool):
|
if self.settings.value("sys_tray", True, bool):
|
||||||
self.hide()
|
self.hide()
|
||||||
e.ignore()
|
e.ignore()
|
||||||
return
|
return
|
||||||
elif self.args.offline:
|
self.timer.stop()
|
||||||
pass
|
self.tray_icon.deleteLater()
|
||||||
self.signals.exit_app.emit(0)
|
self.hide()
|
||||||
e.ignore()
|
self.exit_app.emit(self.exit_code)
|
||||||
|
super(MainWindow, self).closeEvent(e)
|
||||||
|
e.accept()
|
||||||
|
|
|
@ -13,7 +13,7 @@ logger = getLogger("TrayIcon")
|
||||||
|
|
||||||
class TrayIcon(QSystemTrayIcon):
|
class TrayIcon(QSystemTrayIcon):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(TrayIcon, self).__init__(parent)
|
super(TrayIcon, self).__init__(parent=parent)
|
||||||
self.core = LegendaryCoreSingleton()
|
self.core = LegendaryCoreSingleton()
|
||||||
|
|
||||||
self.setIcon(QIcon(":/images/Rare.png"))
|
self.setIcon(QIcon(":/images/Rare.png"))
|
||||||
|
@ -33,7 +33,7 @@ class TrayIcon(QSystemTrayIcon):
|
||||||
if len(installed := self.core.get_installed_list()) < 5:
|
if len(installed := self.core.get_installed_list()) < 5:
|
||||||
last_played = [GameMeta(i.app_name) for i in sorted(installed, key=lambda x: x.title)]
|
last_played = [GameMeta(i.app_name) for i in sorted(installed, key=lambda x: x.title)]
|
||||||
elif games := sorted(
|
elif games := sorted(
|
||||||
parent.mainwindow.tab_widget.games_tab.game_utils.game_meta.get_games(),
|
parent.tab_widget.games_tab.game_utils.game_meta.get_games(),
|
||||||
key=lambda x: x.last_played, reverse=True):
|
key=lambda x: x.last_played, reverse=True):
|
||||||
last_played: List[GameMeta] = games[0:5]
|
last_played: List[GameMeta] = games[0:5]
|
||||||
else:
|
else:
|
||||||
|
@ -46,7 +46,7 @@ class TrayIcon(QSystemTrayIcon):
|
||||||
a.setProperty("app_name", game.app_name)
|
a.setProperty("app_name", game.app_name)
|
||||||
self.game_actions.append(a)
|
self.game_actions.append(a)
|
||||||
a.triggered.connect(
|
a.triggered.connect(
|
||||||
lambda: parent.mainwindow.tab_widget.games_tab.game_utils.prepare_launch(
|
lambda: parent.tab_widget.games_tab.game_utils.prepare_launch(
|
||||||
self.sender().property("app_name"))
|
self.sender().property("app_name"))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,18 @@ Each of the objects in this module should be instantiated ONCE
|
||||||
and only ONCE!
|
and only ONCE!
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import configparser
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
from typing import Optional
|
from typing import Optional, Union
|
||||||
|
|
||||||
from rare.lgndr.core import LegendaryCore
|
from rare.lgndr.core import LegendaryCore
|
||||||
|
|
||||||
from rare.models.apiresults import ApiResults
|
from rare.models.apiresults import ApiResults
|
||||||
from rare.models.signals import GlobalSignals
|
from rare.models.signals import GlobalSignals
|
||||||
|
|
||||||
|
logger = logging.getLogger("Singleton")
|
||||||
|
|
||||||
_legendary_core_singleton: Optional[LegendaryCore] = None
|
_legendary_core_singleton: Optional[LegendaryCore] = None
|
||||||
_global_signals_singleton: Optional[GlobalSignals] = None
|
_global_signals_singleton: Optional[GlobalSignals] = None
|
||||||
_arguments_singleton: Optional[Namespace] = None
|
_arguments_singleton: Optional[Namespace] = None
|
||||||
|
@ -23,8 +27,33 @@ def LegendaryCoreSingleton(init: bool = False) -> LegendaryCore:
|
||||||
global _legendary_core_singleton
|
global _legendary_core_singleton
|
||||||
if _legendary_core_singleton is None and not init:
|
if _legendary_core_singleton is None and not init:
|
||||||
raise RuntimeError("Uninitialized use of LegendaryCoreSingleton")
|
raise RuntimeError("Uninitialized use of LegendaryCoreSingleton")
|
||||||
if _legendary_core_singleton is None:
|
if _legendary_core_singleton is not None and init:
|
||||||
|
raise RuntimeError("LegendaryCore already initialized")
|
||||||
|
if init:
|
||||||
|
try:
|
||||||
_legendary_core_singleton = LegendaryCore()
|
_legendary_core_singleton = LegendaryCore()
|
||||||
|
except configparser.MissingSectionHeaderError as e:
|
||||||
|
logger.warning(f"Config is corrupt: {e}")
|
||||||
|
if config_path := os.environ.get("XDG_CONFIG_HOME"):
|
||||||
|
path = os.path.join(config_path, "legendary")
|
||||||
|
else:
|
||||||
|
path = os.path.expanduser("~/.config/legendary")
|
||||||
|
with open(os.path.join(path, "config.ini"), "w") as config_file:
|
||||||
|
config_file.write("[Legendary]")
|
||||||
|
_legendary_core_singleton = LegendaryCore()
|
||||||
|
if "Legendary" not in _legendary_core_singleton.lgd.config.sections():
|
||||||
|
_legendary_core_singleton.lgd.config.add_section("Legendary")
|
||||||
|
_legendary_core_singleton.lgd.save_config()
|
||||||
|
# workaround if egl sync enabled, but no programdata_path
|
||||||
|
# programdata_path might be unset if logging in through the browser
|
||||||
|
if _legendary_core_singleton.egl_sync_enabled:
|
||||||
|
if _legendary_core_singleton.egl.programdata_path is None:
|
||||||
|
_legendary_core_singleton.lgd.config.remove_option("Legendary", "egl_sync")
|
||||||
|
_legendary_core_singleton.lgd.save_config()
|
||||||
|
else:
|
||||||
|
if not os.path.exists(_legendary_core_singleton.egl.programdata_path):
|
||||||
|
_legendary_core_singleton.lgd.config.remove_option("Legendary", "egl_sync")
|
||||||
|
_legendary_core_singleton.lgd.save_config()
|
||||||
return _legendary_core_singleton
|
return _legendary_core_singleton
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +61,9 @@ def GlobalSignalsSingleton(init: bool = False) -> GlobalSignals:
|
||||||
global _global_signals_singleton
|
global _global_signals_singleton
|
||||||
if _global_signals_singleton is None and not init:
|
if _global_signals_singleton is None and not init:
|
||||||
raise RuntimeError("Uninitialized use of GlobalSignalsSingleton")
|
raise RuntimeError("Uninitialized use of GlobalSignalsSingleton")
|
||||||
if _global_signals_singleton is None:
|
if _global_signals_singleton is not None and init:
|
||||||
|
raise RuntimeError("GlobalSignals already initialized")
|
||||||
|
if init:
|
||||||
_global_signals_singleton = GlobalSignals()
|
_global_signals_singleton = GlobalSignals()
|
||||||
return _global_signals_singleton
|
return _global_signals_singleton
|
||||||
|
|
||||||
|
@ -41,7 +72,9 @@ def ArgumentsSingleton(args: Namespace = None) -> Optional[Namespace]:
|
||||||
global _arguments_singleton
|
global _arguments_singleton
|
||||||
if _arguments_singleton is None and args is None:
|
if _arguments_singleton is None and args is None:
|
||||||
raise RuntimeError("Uninitialized use of ArgumentsSingleton")
|
raise RuntimeError("Uninitialized use of ArgumentsSingleton")
|
||||||
if _arguments_singleton is None:
|
if _arguments_singleton is not None and args is not None:
|
||||||
|
raise RuntimeError("Arguments already initialized")
|
||||||
|
if args is not None:
|
||||||
_arguments_singleton = args
|
_arguments_singleton = args
|
||||||
return _arguments_singleton
|
return _arguments_singleton
|
||||||
|
|
||||||
|
@ -50,7 +83,27 @@ def ApiResultsSingleton(res: ApiResults = None) -> Optional[ApiResults]:
|
||||||
global _api_results_singleton
|
global _api_results_singleton
|
||||||
if _api_results_singleton is None and res is None:
|
if _api_results_singleton is None and res is None:
|
||||||
raise RuntimeError("Uninitialized use of ApiResultsSingleton")
|
raise RuntimeError("Uninitialized use of ApiResultsSingleton")
|
||||||
if _api_results_singleton is None:
|
if _api_results_singleton is not None and res is not None:
|
||||||
|
raise RuntimeError("ApiResults already initialized")
|
||||||
|
if res is not None:
|
||||||
_api_results_singleton = res
|
_api_results_singleton = res
|
||||||
return _api_results_singleton
|
return _api_results_singleton
|
||||||
|
|
||||||
|
|
||||||
|
def clear_singleton_instance(instance: Union[LegendaryCore, GlobalSignals, Namespace, ApiResults]):
|
||||||
|
global _legendary_core_singleton, _global_signals_singleton, _arguments_singleton, _api_results_singleton
|
||||||
|
if isinstance(instance, LegendaryCore):
|
||||||
|
del instance
|
||||||
|
_legendary_core_singleton = None
|
||||||
|
elif isinstance(instance, GlobalSignals):
|
||||||
|
instance.deleteLater()
|
||||||
|
del instance
|
||||||
|
_global_signals_singleton = None
|
||||||
|
elif isinstance(instance, Namespace):
|
||||||
|
del instance
|
||||||
|
_arguments_singleton = None
|
||||||
|
elif isinstance(instance, ApiResults):
|
||||||
|
del instance
|
||||||
|
_api_results_singleton = None
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Instance is of unknown type \"{type(instance)}\"")
|
||||||
|
|
|
@ -54,7 +54,6 @@ class IndicatorReasons:
|
||||||
|
|
||||||
class IndicatorLineEdit(QWidget):
|
class IndicatorLineEdit(QWidget):
|
||||||
textChanged = pyqtSignal(str)
|
textChanged = pyqtSignal(str)
|
||||||
is_valid = False
|
|
||||||
reasons = IndicatorReasons()
|
reasons = IndicatorReasons()
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -97,9 +96,10 @@ class IndicatorLineEdit(QWidget):
|
||||||
layout.addWidget(self.indicator_label)
|
layout.addWidget(self.indicator_label)
|
||||||
|
|
||||||
if not placeholder:
|
if not placeholder:
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.instance().translate
|
||||||
self.line_edit.setPlaceholderText(_translate(self.__class__.__name__, "Default"))
|
self.line_edit.setPlaceholderText(_translate(self.__class__.__name__, "Default"))
|
||||||
|
|
||||||
|
self.is_valid = False
|
||||||
self.edit_func = edit_func
|
self.edit_func = edit_func
|
||||||
self.save_func = save_func
|
self.save_func = save_func
|
||||||
self.line_edit.textChanged.connect(self.__edit)
|
self.line_edit.textChanged.connect(self.__edit)
|
||||||
|
@ -107,7 +107,7 @@ class IndicatorLineEdit(QWidget):
|
||||||
self.line_edit.textChanged.connect(self.__save)
|
self.line_edit.textChanged.connect(self.__save)
|
||||||
|
|
||||||
# lk: this can be placed here to trigger __edit
|
# lk: this can be placed here to trigger __edit
|
||||||
# lk: it going to save the input again if it is valid which
|
# lk: it is going to save the input again if it is valid which
|
||||||
# lk: is ok to do given the checks don't misbehave (they shouldn't)
|
# lk: is ok to do given the checks don't misbehave (they shouldn't)
|
||||||
# lk: however it is going to edit any "understood" bad input to good input
|
# lk: however it is going to edit any "understood" bad input to good input
|
||||||
# lk: and we might not want that (but the validity check reports on the edited string)
|
# lk: and we might not want that (but the validity check reports on the edited string)
|
||||||
|
@ -185,9 +185,6 @@ class PathEditIconProvider(QFileIconProvider):
|
||||||
|
|
||||||
|
|
||||||
class PathEdit(IndicatorLineEdit):
|
class PathEdit(IndicatorLineEdit):
|
||||||
completer = QCompleter()
|
|
||||||
compl_model = QFileSystemModel()
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
path: str = "",
|
path: str = "",
|
||||||
|
@ -200,6 +197,9 @@ class PathEdit(IndicatorLineEdit):
|
||||||
horiz_policy: QSizePolicy = QSizePolicy.Expanding,
|
horiz_policy: QSizePolicy = QSizePolicy.Expanding,
|
||||||
parent=None,
|
parent=None,
|
||||||
):
|
):
|
||||||
|
self.completer = QCompleter()
|
||||||
|
self.compl_model = QFileSystemModel()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.compl_model.setOptions(
|
self.compl_model.setOptions(
|
||||||
QFileSystemModel.DontWatchForChanges
|
QFileSystemModel.DontWatchForChanges
|
||||||
|
@ -230,7 +230,7 @@ class PathEdit(IndicatorLineEdit):
|
||||||
layout = self.layout()
|
layout = self.layout()
|
||||||
layout.addWidget(self.path_select)
|
layout.addWidget(self.path_select)
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.instance().translate
|
||||||
self.path_select.setText(_translate("PathEdit", "Browse..."))
|
self.path_select.setText(_translate("PathEdit", "Browse..."))
|
||||||
|
|
||||||
self.type_filter = type_filter
|
self.type_filter = type_filter
|
||||||
|
@ -414,7 +414,7 @@ class SelectViewWidget(QWidget):
|
||||||
class ImageLabel(QLabel):
|
class ImageLabel(QLabel):
|
||||||
image = None
|
image = None
|
||||||
img_size = None
|
img_size = None
|
||||||
name = str()
|
name = ""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ImageLabel, self).__init__()
|
super(ImageLabel, self).__init__()
|
||||||
|
|
Loading…
Reference in a new issue