1
0
Fork 0
mirror of synced 2024-06-17 18:14:44 +12:00

EosGroup: Remake the UI and integrate with Rare's facilities

* Uninstalling the Overlay now goes through the same procedure as
uninstalling any other game.

* The available prefixes are now listed instead of hiding them inside
a combo box.

* Each listing works indepedently to enable/disable the Overlay for the prefix
This commit is contained in:
loathingKernel 2023-09-08 19:38:39 +03:00
parent 2a0f80a9f0
commit a246f4ee16
10 changed files with 375 additions and 455 deletions

View file

@ -23,14 +23,21 @@ class UninstallDialog(ButtonDialog):
self.keep_files = QCheckBox(self.tr("Keep files")) self.keep_files = QCheckBox(self.tr("Keep files"))
self.keep_files.setChecked(bool(options.keep_files)) self.keep_files.setChecked(bool(options.keep_files))
self.keep_files.setEnabled(not rgame.is_overlay)
self.keep_config = QCheckBox(self.tr("Keep configuation")) self.keep_config = QCheckBox(self.tr("Keep configuation"))
self.keep_config.setChecked(bool(options.keep_config)) self.keep_config.setChecked(bool(options.keep_config))
self.keep_config.setEnabled(not rgame.is_overlay)
self.keep_overlay_keys = QCheckBox(self.tr("Keep EOS Overlay registry keys"))
self.keep_overlay_keys.setChecked(bool(options.keep_overlay_keys))
self.keep_overlay_keys.setEnabled(rgame.is_overlay)
layout = QVBoxLayout() layout = QVBoxLayout()
layout.addWidget(title_label) layout.addWidget(title_label)
layout.addWidget(self.keep_files) layout.addWidget(self.keep_files)
layout.addWidget(self.keep_config) layout.addWidget(self.keep_config)
layout.addWidget(self.keep_overlay_keys)
self.setCentralLayout(layout) self.setCentralLayout(layout)
@ -51,7 +58,8 @@ class UninstallDialog(ButtonDialog):
True, True,
self.keep_files.isChecked(), self.keep_files.isChecked(),
self.keep_config.isChecked(), self.keep_config.isChecked(),
self.keep_overlay_keys.isChecked(),
) )
def reject_handler(self): def reject_handler(self):
self.options.values = (None, None, None) self.options.values = (None, None, None, None)

View file

@ -238,10 +238,7 @@ class DownloadsTab(QWidget):
else: else:
logger.info(f"Created desktop link {result.shortcut_name} for {result.options.app_name}") logger.info(f"Created desktop link {result.shortcut_name} for {result.options.app_name}")
if result.options.overlay: self.signals.application.notify.emit(result.options.app_name)
self.signals.application.overlay_installed.emit()
else:
self.signals.application.notify.emit(result.options.app_name)
if self.updates_group.contains(result.options.app_name): if self.updates_group.contains(result.options.app_name):
self.updates_group.set_widget_enabled(result.options.app_name, True) self.updates_group.set_widget_enabled(result.options.app_name, True)

View file

@ -5,7 +5,7 @@ from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLabel, QSpacerItem, QSizePoli
from rare.widgets.side_tab import SideTabWidget from rare.widgets.side_tab import SideTabWidget
from .egl_sync_group import EGLSyncGroup from .egl_sync_group import EGLSyncGroup
from .eos_group import EOSGroup from .eos_group import EosGroup
from .import_group import ImportGroup from .import_group import ImportGroup
from .ubisoft_group import UbisoftGroup from .ubisoft_group import UbisoftGroup
@ -35,7 +35,7 @@ class IntegrationsTabs(SideTabWidget):
self, self,
) )
self.ubisoft_group = UbisoftGroup(self.eos_ubisoft) self.ubisoft_group = UbisoftGroup(self.eos_ubisoft)
self.eos_group = EOSGroup(self.eos_ubisoft) self.eos_group = EosGroup(self.eos_ubisoft)
self.eos_ubisoft.addWidget(self.eos_group) self.eos_ubisoft.addWidget(self.eos_group)
self.eos_ubisoft.addWidget(self.ubisoft_group) self.eos_ubisoft.addWidget(self.ubisoft_group)
self.eos_ubisoft_index = self.addTab(self.eos_ubisoft, self.tr("Epic Overlay and Ubisoft")) self.eos_ubisoft_index = self.addTab(self.eos_ubisoft, self.tr("Epic Overlay and Ubisoft"))

View file

@ -1,161 +1,189 @@
import os import os
import platform import platform
from logging import getLogger from logging import getLogger
from typing import List from typing import Optional
from PyQt5.QtCore import QRunnable, QObject, pyqtSignal, QThreadPool from PyQt5.QtCore import QRunnable, QObject, pyqtSignal, QThreadPool, Qt, pyqtSlot, QSize
from PyQt5.QtWidgets import QGroupBox, QMessageBox from PyQt5.QtWidgets import QGroupBox, QMessageBox, QFrame, QHBoxLayout, QSizePolicy, QLabel, QPushButton, QFormLayout
from legendary.lfs import eos from legendary.lfs import eos
from rare.models.install import InstallOptionsModel from rare.lgndr.core import LegendaryCore
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton from rare.models.game import RareEosOverlay
from rare.shared import RareCore
from rare.ui.components.tabs.games.integrations.eos_widget import Ui_EosWidget from rare.ui.components.tabs.games.integrations.eos_widget import Ui_EosWidget
from rare.utils import config_helper
from rare.utils.misc import icon from rare.utils.misc import icon
from rare.widgets.elide_label import ElideLabel
logger = getLogger("EpicOverlay") logger = getLogger("EpicOverlay")
def get_wine_prefixes() -> List[str]:
prefixes = list()
if os.path.exists(p := os.path.expanduser("~/.wine")):
prefixes.append(p)
for name, section in LegendaryCoreSingleton().lgd.config.items():
pfx = section.get("WINEPREFIX") or section.get("wine_prefix")
if pfx and pfx not in prefixes:
prefixes.append(pfx)
return prefixes
class CheckForUpdateWorker(QRunnable): class CheckForUpdateWorker(QRunnable):
class CheckForUpdateSignals(QObject): class CheckForUpdateSignals(QObject):
update_available = pyqtSignal(bool) update_available = pyqtSignal(bool)
def __init__(self): def __init__(self, core: LegendaryCore):
super(CheckForUpdateWorker, self).__init__() super(CheckForUpdateWorker, self).__init__()
self.signals = self.CheckForUpdateSignals() self.signals = self.CheckForUpdateSignals()
self.setAutoDelete(True) self.setAutoDelete(True)
self.core = LegendaryCoreSingleton() self.core = core
def run(self) -> None: def run(self) -> None:
self.core.check_for_overlay_updates() self.core.check_for_overlay_updates()
self.signals.update_available.emit(self.core.overlay_update_available) self.signals.update_available.emit(self.core.overlay_update_available)
class EOSGroup(QGroupBox): class EosPrefixWidget(QFrame):
def __init__(self, overlay: RareEosOverlay, prefix: Optional[str], parent=None):
super(EosPrefixWidget, self).__init__(parent=parent)
self.setFrameShape(QFrame.StyledPanel)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.indicator = QLabel(parent=self)
self.indicator.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)
self.label = ElideLabel(
prefix if prefix is not None else "Epic Online Services Overlay",
parent=self
)
self.button = QPushButton(parent=self)
self.button.setMinimumWidth(150)
self.button.clicked.connect(self.action)
layout = QHBoxLayout(self)
layout.setContentsMargins(-1, 0, 0, 0)
layout.addWidget(self.indicator)
layout.addWidget(self.label, stretch=1)
layout.addWidget(self.button)
self.overlay = overlay
self.prefix = prefix
self.overlay.signals.game.installed.connect(self.update_state)
self.overlay.signals.game.uninstalled.connect(self.update_state)
self.update_state()
@pyqtSlot()
def update_state(self):
if not self.overlay.is_installed:
self.setDisabled(True)
self.button.setText(self.tr("Unavailable"))
self.indicator.setPixmap(icon("fa.circle-o", color="grey").pixmap(20, 20))
return
self.setDisabled(False)
if self.overlay.is_enabled(self.prefix):
self.button.setText(self.tr("Disable overlay"))
self.indicator.setPixmap(
icon("fa.check-circle-o", color="green").pixmap(QSize(20, 20))
)
else:
self.button.setText(self.tr("Enable overlay"))
self.indicator.setPixmap(
icon("fa.times-circle-o", color="red").pixmap(QSize(20, 20))
)
@pyqtSlot()
def action(self):
if self.overlay.is_enabled(self.prefix):
self.overlay.disable(prefix=self.prefix)
else:
self.overlay.enable(prefix=self.prefix)
self.update_state()
class EosGroup(QGroupBox):
def __init__(self, parent=None): def __init__(self, parent=None):
super(EOSGroup, self).__init__(parent=parent) super(EosGroup, self).__init__(parent=parent)
self.ui = Ui_EosWidget() self.ui = Ui_EosWidget()
self.ui.setupUi(self) self.ui.setupUi(self)
# lk: set object names for CSS properties # lk: set object names for CSS properties
self.ui.install_button.setObjectName("InstallButton") self.ui.install_button.setObjectName("InstallButton")
self.ui.install_button.setIcon(icon("ri.install-line"))
self.ui.uninstall_button.setObjectName("UninstallButton") self.ui.uninstall_button.setObjectName("UninstallButton")
self.ui.install_page_layout.setAlignment(Qt.AlignTop)
self.ui.info_page_layout.setAlignment(Qt.AlignTop)
self.ui.install_button.setIcon(icon("ri.install-line"))
self.ui.uninstall_button.setIcon(icon("ri.uninstall-line")) self.ui.uninstall_button.setIcon(icon("ri.uninstall-line"))
self.core = LegendaryCoreSingleton() self.installed_path_label = ElideLabel(parent=self)
self.signals = GlobalSignalsSingleton() self.installed_version_label = ElideLabel(parent=self)
self.prefix_enabled = False self.ui.info_label_layout.setWidget(0, QFormLayout.FieldRole, self.installed_version_label)
self.ui.info_label_layout.setWidget(1, QFormLayout.FieldRole, self.installed_path_label)
self.ui.enabled_cb.stateChanged.connect(self.change_enable) self.rcore = RareCore.instance()
self.core = self.rcore.core()
self.signals = self.rcore.signals()
self.overlay = self.rcore.get_overlay()
self.overlay.signals.game.installed.connect(self.install_finished)
self.overlay.signals.game.uninstalled.connect(self.uninstall_finished)
self.ui.install_button.clicked.connect(self.install_overlay)
self.ui.update_button.clicked.connect(self.install_overlay)
self.ui.uninstall_button.clicked.connect(self.uninstall_overlay) self.ui.uninstall_button.clicked.connect(self.uninstall_overlay)
self.ui.update_button.setVisible(False) if self.overlay.is_installed: # installed
self.overlay = self.core.lgd.get_overlay_install_info() self.installed_version_label.setText(f"<b>{self.overlay.version}</b>")
self.installed_path_label.setText(self.overlay.install_path)
self.signals.application.overlay_installed.connect(self.overlay_installation_finished) self.ui.overlay_stack.setCurrentWidget(self.ui.info_page)
self.signals.application.prefix_updated.connect(self.update_prefixes)
self.ui.update_check_button.clicked.connect(self.check_for_update)
self.ui.install_button.clicked.connect(self.install_overlay)
self.ui.update_button.clicked.connect(lambda: self.install_overlay(True))
if self.overlay: # installed
self.ui.installed_version_lbl.setText(f"<b>{self.overlay.version}</b>")
self.ui.installed_path_lbl.setText(f"<b>{self.overlay.install_path}</b>")
self.ui.overlay_stack.setCurrentIndex(0)
else: else:
self.ui.overlay_stack.setCurrentIndex(1) self.ui.overlay_stack.setCurrentWidget(self.ui.install_page)
self.ui.enable_frame.setDisabled(True) self.ui.update_button.setEnabled(False)
if platform.system() == "Windows":
self.current_prefix = None
self.ui.select_pfx_combo.setVisible(False)
else:
self.current_prefix = os.path.expanduser("~/.wine") \
if os.path.exists(os.path.expanduser("~/.wine")) \
else None
pfxs = get_wine_prefixes()
for pfx in pfxs:
self.ui.select_pfx_combo.addItem(pfx.replace(os.path.expanduser("~/"), "~/"))
if not pfxs:
self.ui.enable_frame.setDisabled(True)
else:
self.ui.select_pfx_combo.setCurrentIndex(0)
self.ui.select_pfx_combo.currentIndexChanged.connect(self.update_select_combo)
if pfxs:
self.update_select_combo(None)
self.ui.enabled_info_label.setText("")
self.threadpool = QThreadPool.globalInstance() self.threadpool = QThreadPool.globalInstance()
def showEvent(self, a0) -> None:
self.check_for_update()
self.update_prefixes()
super().showEvent(a0)
def update_prefixes(self): def update_prefixes(self):
logger.debug("Updated prefixes") for widget in self.findChildren(EosPrefixWidget, options=Qt.FindDirectChildrenOnly):
pfxs = get_wine_prefixes() # returns /home/whatever widget.deleteLater()
self.ui.select_pfx_combo.clear()
for pfx in pfxs: if platform.system() != "Windows":
self.ui.select_pfx_combo.addItem(pfx.replace(os.path.expanduser("~/"), "~/")) prefixes = config_helper.get_wine_prefixes()
if platform.system() == "Darwin":
if self.current_prefix in pfxs: # TODO: add crossover support
self.ui.select_pfx_combo.setCurrentIndex( pass
self.ui.select_pfx_combo.findText(self.current_prefix.replace(os.path.expanduser("~/"), "~/"))) for prefix in prefixes:
widget = EosPrefixWidget(self.overlay, prefix)
self.ui.eos_layout.addWidget(widget)
logger.debug("Updated prefixes")
else:
widget = EosPrefixWidget(self.overlay, None)
self.ui.eos_layout.addWidget(widget)
def check_for_update(self): def check_for_update(self):
def worker_finished(update_available): if not self.overlay.is_installed:
self.ui.update_button.setVisible(update_available) return
self.ui.update_check_button.setDisabled(False)
if not update_available:
self.ui.update_check_button.setText(self.tr("No update available"))
self.ui.update_check_button.setDisabled(True) def worker_finished(update_available):
worker = CheckForUpdateWorker() self.ui.update_button.setEnabled(update_available)
worker = CheckForUpdateWorker(self.core)
worker.signals.update_available.connect(worker_finished) worker.signals.update_available.connect(worker_finished)
QThreadPool.globalInstance().start(worker) QThreadPool.globalInstance().start(worker)
def overlay_installation_finished(self): @pyqtSlot()
self.overlay = self.core.lgd.get_overlay_install_info() def install_finished(self):
if not self.overlay.is_installed:
if not self.overlay: logger.error("Something went wrong while installing overlay")
logger.error("Something went wrong, when installing overlay") QMessageBox.warning(self, "Error", self.tr("Something went wrong while installing Overlay"))
QMessageBox.warning(self, "Error", self.tr("Something went wrong, when installing overlay"))
return return
self.ui.overlay_stack.setCurrentWidget(self.ui.info_page)
self.installed_version_label.setText(f"<b>{self.overlay.version}</b>")
self.installed_path_label.setText(self.overlay.install_path)
self.ui.update_button.setEnabled(False)
self.ui.overlay_stack.setCurrentIndex(0) @pyqtSlot()
self.ui.installed_version_lbl.setText(f"<b>{self.overlay.version}</b>") def uninstall_finished(self):
self.ui.installed_path_lbl.setText(f"<b>{self.overlay.install_path}</b>") self.ui.overlay_stack.setCurrentWidget(self.ui.install_page)
self.ui.update_button.setVisible(False)
self.ui.enable_frame.setEnabled(True)
def update_select_combo(self, i: None):
if i is None:
i = self.ui.select_pfx_combo.currentIndex()
prefix = os.path.expanduser(self.ui.select_pfx_combo.itemText(i))
if platform.system() != "Windows" and not os.path.isfile(os.path.join(prefix, "user.reg")):
return
self.current_prefix = prefix
reg_paths = eos.query_registry_entries(self.current_prefix)
overlay_enabled = False
if reg_paths['overlay_path'] and self.core.is_overlay_install(reg_paths['overlay_path']):
overlay_enabled = True
self.ui.enabled_cb.setChecked(overlay_enabled)
def change_enable(self): def change_enable(self):
enabled = self.ui.enabled_cb.isChecked() enabled = self.ui.enabled_cb.isChecked()
@ -170,7 +198,7 @@ class EOSGroup(QGroupBox):
logger.info("Disabled Epic Overlay") logger.info("Disabled Epic Overlay")
self.ui.enabled_info_label.setText(self.tr("Disabled")) self.ui.enabled_info_label.setText(self.tr("Disabled"))
else: else:
if not self.overlay: if not self.overlay.is_installed:
available_installs = self.core.search_overlay_installs(self.current_prefix) available_installs = self.core.search_overlay_installs(self.current_prefix)
if not available_installs: if not available_installs:
logger.error('No EOS overlay installs found!') logger.error('No EOS overlay installs found!')
@ -209,51 +237,13 @@ class EOSGroup(QGroupBox):
self.ui.enabled_info_label.setText(self.tr("Enabled")) self.ui.enabled_info_label.setText(self.tr("Enabled"))
logger.info(f'Enabled overlay at: {path}') logger.info(f'Enabled overlay at: {path}')
def update_checkbox(self): @pyqtSlot()
reg_paths = eos.query_registry_entries(self.current_prefix) def install_overlay(self):
enabled = False self.overlay.install()
if reg_paths['overlay_path'] and self.core.is_overlay_install(reg_paths['overlay_path']):
enabled = True
self.ui.enabled_cb.setChecked(enabled)
def install_overlay(self, update=False):
base_path = os.path.join(self.core.get_default_install_dir(), ".overlay")
if update:
if not self.overlay:
self.ui.overlay_stack.setCurrentIndex(1)
self.ui.enable_frame.setDisabled(True)
QMessageBox.warning(self, "Warning", self.tr("Overlay is not installed. Could not update"))
return
base_path = self.overlay.install_path
options = InstallOptionsModel(
app_name=eos.EOSOverlayApp.app_name, base_path=base_path, platform="Windows", overlay=True
)
self.signals.game.install.emit(options)
def uninstall_overlay(self): def uninstall_overlay(self):
if not self.core.is_overlay_installed(): if not self.overlay.is_installed:
logger.error('No legendary-managed overlay installation found.') logger.error('No Rare-managed overlay installation found.')
self.ui.overlay_stack.setCurrentIndex(1) self.ui.overlay_stack.setCurrentWidget(self.ui.install_page)
return return
self.overlay.uninstall()
if QMessageBox.No == QMessageBox.question(
self, "Uninstall Overlay", self.tr("Do you want to uninstall overlay?"),
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
):
return
if platform.system() == "Windows":
eos.remove_registry_entries(None)
else:
for prefix in [self.ui.select_pfx_combo.itemText(i) for i in range(self.ui.select_pfx_combo.count())]:
logger.info(f"Removing registry entries from {prefix}")
try:
eos.remove_registry_entries(os.path.expanduser(prefix))
except Exception as e:
logger.warning(f"{prefix}: {e}")
self.core.remove_overlay_install()
self.ui.overlay_stack.setCurrentIndex(1)
self.ui.enable_frame.setDisabled(True)

View file

@ -86,6 +86,7 @@ class UninstallOptionsModel:
accepted: bool = None accepted: bool = None
keep_files: bool = None keep_files: bool = None
keep_config: bool = None keep_config: bool = None
keep_overlay_keys: bool = None
def __bool__(self): def __bool__(self):
return ( return (
@ -93,20 +94,21 @@ class UninstallOptionsModel:
and (self.accepted is not None) and (self.accepted is not None)
and (self.keep_files is not None) and (self.keep_files is not None)
and (self.keep_config is not None) and (self.keep_config is not None)
and (self.keep_overlay_keys is not None)
) )
@property @property
def values(self) -> Tuple[bool, bool, bool]: def values(self) -> Tuple[bool, bool, bool, bool]:
""" """
This model's options This model's options
:return: :return:
Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys` Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys`
""" """
return self.accepted, self.keep_config, self.keep_files return self.accepted, self.keep_config, self.keep_files, self.keep_overlay_keys
@values.setter @values.setter
def values(self, values: Tuple[bool, bool, bool]): def values(self, values: Tuple[bool, bool, bool, bool]):
""" """
Set this model's options Set this model's options
@ -117,6 +119,7 @@ class UninstallOptionsModel:
self.accepted = values[0] self.accepted = values[0]
self.keep_files = values[1] self.keep_files = values[1]
self.keep_config = values[2] self.keep_config = values[2]
self.keep_overlay_keys = values[3]
@dataclass @dataclass

View file

@ -10,14 +10,12 @@ class GlobalSignals:
class ApplicationSignals(QObject): class ApplicationSignals(QObject):
# int: exit code # int: exit code
quit = pyqtSignal(int) quit = pyqtSignal(int)
# str: app_title # str: app_title
notify = pyqtSignal(str) notify = pyqtSignal(str)
# none # none
prefix_updated = pyqtSignal() prefix_updated = pyqtSignal()
# none # none
overlay_installed = pyqtSignal()
# none
update_tray = pyqtSignal() update_tray = pyqtSignal()
# none # none
update_statusbar = pyqtSignal() update_statusbar = pyqtSignal()
@ -58,4 +56,4 @@ class GlobalSignals:
self.download.deleteLater() self.download.deleteLater()
del self.download del self.download
self.discord_rpc.deleteLater() self.discord_rpc.deleteLater()
del self.discord_rpc del self.discord_rpc

View file

@ -66,6 +66,8 @@ class RareCore(QObject):
self.__library: Dict[str, RareGame] = {} self.__library: Dict[str, RareGame] = {}
self.__eos_overlay = RareEosOverlay(self.__core, EOSOverlayApp) self.__eos_overlay = RareEosOverlay(self.__core, EOSOverlayApp)
self.__eos_overlay.signals.game.install.connect(self.__signals.game.install)
self.__eos_overlay.signals.game.uninstall.connect(self.__signals.game.uninstall)
RareCore.__instance = self RareCore.__instance = self
@ -224,12 +226,12 @@ class RareCore(QObject):
for dlc in rgame.owned_dlcs: for dlc in rgame.owned_dlcs:
if dlc.is_installed: if dlc.is_installed:
logger.info(f'Uninstalling DLC "{dlc.app_name}" ({dlc.app_title})...') logger.info(f'Uninstalling DLC "{dlc.app_name}" ({dlc.app_title})...')
uninstall_game(self.__core, dlc.app_name, keep_files=True, keep_config=True) uninstall_game(self.__core, dlc, keep_files=True, keep_config=True)
dlc.igame = None dlc.igame = None
logger.info( logger.info(
f'Removing "{rgame.app_title}" because "{rgame.igame.install_path}" does not exist...' f'Removing "{rgame.app_title}" because "{rgame.igame.install_path}" does not exist...'
) )
uninstall_game(self.__core, rgame.app_name, keep_files=True, keep_config=True) uninstall_game(self.__core, rgame, keep_files=True, keep_config=True)
logger.info(f"Uninstalled {rgame.app_title}, because no game files exist") logger.info(f"Uninstalled {rgame.app_title}, because no game files exist")
rgame.igame = None rgame.igame = None
return return
@ -254,6 +256,9 @@ class RareCore(QObject):
return self.__eos_overlay return self.__eos_overlay
return self.__library[app_name] return self.__library[app_name]
def get_overlay(self):
return self.get_game(EOSOverlayApp.app_name)
def __add_game(self, rgame: RareGame) -> None: def __add_game(self, rgame: RareGame) -> None:
rgame.signals.download.enqueue.connect(self.__signals.download.enqueue) rgame.signals.download.enqueue.connect(self.__signals.download.enqueue)
rgame.signals.download.dequeue.connect(self.__signals.download.dequeue) rgame.signals.download.dequeue.connect(self.__signals.download.dequeue)
@ -345,7 +350,6 @@ class RareCore(QObject):
start_time = time.time() start_time = time.time()
try: try:
entitlements = self.__core.egs.get_user_entitlements() entitlements = self.__core.egs.get_user_entitlements()
self.__core.lgd.entitlements = entitlements
for game in self.__library.values(): for game in self.__library.values():
game.grant_date() game.grant_date()
except (HTTPError, ConnectionError) as e: except (HTTPError, ConnectionError) as e:

View file

@ -1,7 +1,10 @@
import platform
from logging import getLogger from logging import getLogger
from typing import Tuple
from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtCore import QObject, pyqtSignal
from legendary.core import LegendaryCore from legendary.core import LegendaryCore
from legendary.lfs.eos import remove_registry_entries
from rare.lgndr.cli import LegendaryCLI from rare.lgndr.cli import LegendaryCLI
from rare.lgndr.glue.arguments import LgndrUninstallGameArgs from rare.lgndr.glue.arguments import LgndrUninstallGameArgs
@ -16,14 +19,36 @@ logger = getLogger("UninstallWorker")
# TODO: You can use RareGame directly here once this is called inside RareCore and skip metadata fetch # TODO: You can use RareGame directly here once this is called inside RareCore and skip metadata fetch
def uninstall_game(core: LegendaryCore, app_name: str, keep_files=False, keep_config=False): def uninstall_game(
game = core.get_game(app_name) core: LegendaryCore, rgame: RareGame, keep_files=False, keep_config=False, keep_overlay_keys=False
) -> Tuple[bool, str]:
if rgame.is_overlay:
logger.info('Deleting overlay installation...')
core.remove_overlay_install()
if keep_overlay_keys:
return True, ""
logger.info('Removing registry entries...')
if platform.system() != "Window":
prefixes = config_helper.get_wine_prefixes()
if platform.system() == "Darwin":
# TODO: add crossover support
pass
if prefixes is not None:
for prefix in prefixes:
remove_registry_entries(prefix)
logger.debug("Removed registry entries for prefix %s", prefix)
else:
remove_registry_entries(None)
return True, ""
# remove shortcuts link # remove shortcuts link
if desktop_links_supported(): if desktop_links_supported():
for link_type in desktop_link_types(): for link_type in desktop_link_types():
link_path = desktop_link_path( link_path = desktop_link_path(
game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value"), link_type rgame.game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value"), link_type
) )
if link_path.exists(): if link_path.exists():
link_path.unlink(missing_ok=True) link_path.unlink(missing_ok=True)
@ -31,7 +56,7 @@ def uninstall_game(core: LegendaryCore, app_name: str, keep_files=False, keep_co
status = LgndrIndirectStatus() status = LgndrIndirectStatus()
LegendaryCLI(core).uninstall_game( LegendaryCLI(core).uninstall_game(
LgndrUninstallGameArgs( LgndrUninstallGameArgs(
app_name=app_name, app_name=rgame.app_name,
keep_files=keep_files, keep_files=keep_files,
skip_uninstaller=False, skip_uninstaller=False,
yes=True, yes=True,
@ -40,8 +65,8 @@ def uninstall_game(core: LegendaryCore, app_name: str, keep_files=False, keep_co
) )
if not keep_config: if not keep_config:
logger.info("Removing sections in config file") logger.info("Removing sections in config file")
config_helper.remove_section(app_name) config_helper.remove_section(rgame.app_name)
config_helper.remove_section(f"{app_name}.env") config_helper.remove_section(f"{rgame.app_name}.env")
config_helper.save_config() config_helper.save_config()
@ -62,7 +87,11 @@ class UninstallWorker(Worker):
def run_real(self) -> None: def run_real(self) -> None:
self.rgame.state = RareGame.State.UNINSTALLING self.rgame.state = RareGame.State.UNINSTALLING
success, message = uninstall_game( success, message = uninstall_game(
self.core, self.rgame.app_name, self.options.keep_files, self.options.keep_config self.core,
self.rgame,
self.options.keep_files,
self.options.keep_config,
self.options.keep_overlay_keys,
) )
self.rgame.state = RareGame.State.IDLE self.rgame.state = RareGame.State.IDLE
self.signals.result.emit(self.rgame, success, message) self.signals.result.emit(self.rgame, success, message)

View file

@ -14,102 +14,71 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_EosWidget(object): class Ui_EosWidget(object):
def setupUi(self, EosWidget): def setupUi(self, EosWidget):
EosWidget.setObjectName("EosWidget") EosWidget.setObjectName("EosWidget")
EosWidget.resize(586, 146) EosWidget.resize(464, 98)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(EosWidget.sizePolicy().hasHeightForWidth())
EosWidget.setSizePolicy(sizePolicy)
EosWidget.setWindowTitle("GroupBox") EosWidget.setWindowTitle("GroupBox")
self.eos_layout = QtWidgets.QHBoxLayout(EosWidget) self.eos_layout = QtWidgets.QVBoxLayout(EosWidget)
self.eos_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) self.eos_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.eos_layout.setObjectName("eos_layout") self.eos_layout.setObjectName("eos_layout")
self.overlay_stack = QtWidgets.QStackedWidget(EosWidget) self.overlay_stack = QtWidgets.QStackedWidget(EosWidget)
self.overlay_stack.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.overlay_stack.setFrameShadow(QtWidgets.QFrame.Raised)
self.overlay_stack.setObjectName("overlay_stack") self.overlay_stack.setObjectName("overlay_stack")
self.overlay_info_page = QtWidgets.QWidget() self.install_page = QtWidgets.QWidget()
self.overlay_info_page.setObjectName("overlay_info_page") self.install_page.setObjectName("install_page")
self.overlay_info_layout = QtWidgets.QFormLayout(self.overlay_info_page) self.install_page_layout = QtWidgets.QHBoxLayout(self.install_page)
self.overlay_info_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.install_page_layout.setContentsMargins(0, 0, 0, 0)
self.overlay_info_layout.setFormAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft) self.install_page_layout.setObjectName("install_page_layout")
self.overlay_info_layout.setObjectName("overlay_info_layout") self.install_label_layout = QtWidgets.QFormLayout()
self.installed_version_info_lbl = QtWidgets.QLabel(self.overlay_info_page) self.install_label_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.installed_version_info_lbl.setObjectName("installed_version_info_lbl") self.install_label_layout.setFormAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.overlay_info_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.installed_version_info_lbl) self.install_label_layout.setObjectName("install_label_layout")
self.installed_version_lbl = QtWidgets.QLabel(self.overlay_info_page) self.install_label = QtWidgets.QLabel(self.install_page)
self.installed_version_lbl.setText("error") self.install_label.setObjectName("install_label")
self.installed_version_lbl.setObjectName("installed_version_lbl") self.install_label_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.install_label)
self.overlay_info_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.installed_version_lbl) self.install_text = QtWidgets.QLabel(self.install_page)
self.installed_path_info_lbl = QtWidgets.QLabel(self.overlay_info_page) self.install_text.setObjectName("install_text")
self.installed_path_info_lbl.setObjectName("installed_path_info_lbl") self.install_label_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.install_text)
self.overlay_info_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.installed_path_info_lbl) self.install_page_layout.addLayout(self.install_label_layout)
self.installed_path_lbl = QtWidgets.QLabel(self.overlay_info_page) self.install_button_layout = QtWidgets.QVBoxLayout()
self.installed_path_lbl.setText("error") self.install_button_layout.setContentsMargins(-1, -1, 0, -1)
self.installed_path_lbl.setObjectName("installed_path_lbl") self.install_button_layout.setObjectName("install_button_layout")
self.overlay_info_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.installed_path_lbl) self.install_button = QtWidgets.QPushButton(self.install_page)
self.info_buttons_layout = QtWidgets.QHBoxLayout() self.install_button.setMinimumSize(QtCore.QSize(140, 0))
self.info_buttons_layout.setObjectName("info_buttons_layout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.info_buttons_layout.addItem(spacerItem)
self.uninstall_button = QtWidgets.QPushButton(self.overlay_info_page)
self.uninstall_button.setMinimumSize(QtCore.QSize(120, 0))
self.uninstall_button.setObjectName("uninstall_button")
self.info_buttons_layout.addWidget(self.uninstall_button)
self.update_check_button = QtWidgets.QPushButton(self.overlay_info_page)
self.update_check_button.setMinimumSize(QtCore.QSize(120, 0))
self.update_check_button.setObjectName("update_check_button")
self.info_buttons_layout.addWidget(self.update_check_button)
self.update_button = QtWidgets.QPushButton(self.overlay_info_page)
self.update_button.setMinimumSize(QtCore.QSize(120, 0))
self.update_button.setObjectName("update_button")
self.info_buttons_layout.addWidget(self.update_button)
self.overlay_info_layout.setLayout(3, QtWidgets.QFormLayout.SpanningRole, self.info_buttons_layout)
spacerItem1 = QtWidgets.QSpacerItem(6, 6, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.overlay_info_layout.setItem(2, QtWidgets.QFormLayout.SpanningRole, spacerItem1)
self.overlay_stack.addWidget(self.overlay_info_page)
self.overlay_install_page = QtWidgets.QWidget()
self.overlay_install_page.setObjectName("overlay_install_page")
self.overlay_install_layout = QtWidgets.QFormLayout(self.overlay_install_page)
self.overlay_install_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.overlay_install_layout.setFormAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft)
self.overlay_install_layout.setObjectName("overlay_install_layout")
self.label = QtWidgets.QLabel(self.overlay_install_page)
self.label.setObjectName("label")
self.overlay_install_layout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.label)
self.install_buttons_layout = QtWidgets.QHBoxLayout()
self.install_buttons_layout.setObjectName("install_buttons_layout")
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.install_buttons_layout.addItem(spacerItem2)
self.install_button = QtWidgets.QPushButton(self.overlay_install_page)
self.install_button.setMinimumSize(QtCore.QSize(120, 0))
self.install_button.setObjectName("install_button") self.install_button.setObjectName("install_button")
self.install_buttons_layout.addWidget(self.install_button) self.install_button_layout.addWidget(self.install_button)
self.overlay_install_layout.setLayout(2, QtWidgets.QFormLayout.SpanningRole, self.install_buttons_layout) self.install_page_layout.addLayout(self.install_button_layout)
spacerItem3 = QtWidgets.QSpacerItem(6, 6, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.install_page_layout.setStretch(0, 1)
self.overlay_install_layout.setItem(1, QtWidgets.QFormLayout.SpanningRole, spacerItem3) self.overlay_stack.addWidget(self.install_page)
self.overlay_stack.addWidget(self.overlay_install_page) self.info_page = QtWidgets.QWidget()
self.info_page.setObjectName("info_page")
self.info_page_layout = QtWidgets.QHBoxLayout(self.info_page)
self.info_page_layout.setContentsMargins(0, 0, 0, 0)
self.info_page_layout.setObjectName("info_page_layout")
self.info_label_layout = QtWidgets.QFormLayout()
self.info_label_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.info_label_layout.setFormAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.info_label_layout.setObjectName("info_label_layout")
self.version_label = QtWidgets.QLabel(self.info_page)
self.version_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.version_label.setObjectName("version_label")
self.info_label_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.version_label)
self.path_label = QtWidgets.QLabel(self.info_page)
self.path_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.path_label.setObjectName("path_label")
self.info_label_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.path_label)
self.info_page_layout.addLayout(self.info_label_layout)
self.info_button_layout = QtWidgets.QVBoxLayout()
self.info_button_layout.setObjectName("info_button_layout")
self.update_button = QtWidgets.QPushButton(self.info_page)
self.update_button.setMinimumSize(QtCore.QSize(140, 0))
self.update_button.setObjectName("update_button")
self.info_button_layout.addWidget(self.update_button)
self.uninstall_button = QtWidgets.QPushButton(self.info_page)
self.uninstall_button.setMinimumSize(QtCore.QSize(140, 0))
self.uninstall_button.setObjectName("uninstall_button")
self.info_button_layout.addWidget(self.uninstall_button)
self.info_page_layout.addLayout(self.info_button_layout)
self.info_page_layout.setStretch(0, 1)
self.overlay_stack.addWidget(self.info_page)
self.eos_layout.addWidget(self.overlay_stack) self.eos_layout.addWidget(self.overlay_stack)
self.enable_frame = QtWidgets.QFrame(EosWidget)
self.enable_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.enable_frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.enable_frame.setObjectName("enable_frame")
self.enable_layout = QtWidgets.QVBoxLayout(self.enable_frame)
self.enable_layout.setObjectName("enable_layout")
self.select_pfx_combo = QtWidgets.QComboBox(self.enable_frame)
self.select_pfx_combo.setObjectName("select_pfx_combo")
self.enable_layout.addWidget(self.select_pfx_combo)
self.enabled_cb = QtWidgets.QCheckBox(self.enable_frame)
self.enabled_cb.setObjectName("enabled_cb")
self.enable_layout.addWidget(self.enabled_cb)
self.enabled_info_label = QtWidgets.QLabel(self.enable_frame)
font = QtGui.QFont()
font.setItalic(True)
self.enabled_info_label.setFont(font)
self.enabled_info_label.setText("")
self.enabled_info_label.setObjectName("enabled_info_label")
self.enable_layout.addWidget(self.enabled_info_label)
self.eos_layout.addWidget(self.enable_frame)
self.retranslateUi(EosWidget) self.retranslateUi(EosWidget)
self.overlay_stack.setCurrentIndex(0) self.overlay_stack.setCurrentIndex(0)
@ -117,14 +86,13 @@ class Ui_EosWidget(object):
def retranslateUi(self, EosWidget): def retranslateUi(self, EosWidget):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
EosWidget.setTitle(_translate("EosWidget", "Epic Overlay")) EosWidget.setTitle(_translate("EosWidget", "Epic Overlay"))
self.installed_version_info_lbl.setText(_translate("EosWidget", "Version")) self.install_label.setText(_translate("EosWidget", "Status:"))
self.installed_path_info_lbl.setText(_translate("EosWidget", "Location")) self.install_text.setText(_translate("EosWidget", "Epic Online Services Overlay is not installed"))
self.uninstall_button.setText(_translate("EosWidget", "Uninstall"))
self.update_check_button.setText(_translate("EosWidget", "Check for update"))
self.update_button.setText(_translate("EosWidget", "Update"))
self.label.setText(_translate("EosWidget", "Epic Overlay Services is not installed"))
self.install_button.setText(_translate("EosWidget", "Install")) self.install_button.setText(_translate("EosWidget", "Install"))
self.enabled_cb.setText(_translate("EosWidget", "Activated")) self.version_label.setText(_translate("EosWidget", "Version:"))
self.path_label.setText(_translate("EosWidget", "Path:"))
self.update_button.setText(_translate("EosWidget", "Update"))
self.uninstall_button.setText(_translate("EosWidget", "Uninstall"))
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -6,179 +6,73 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>586</width> <width>464</width>
<height>146</height> <height>98</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string notr="true">GroupBox</string> <string notr="true">GroupBox</string>
</property> </property>
<property name="title"> <property name="title">
<string>Epic Overlay</string> <string>Epic Overlay</string>
</property> </property>
<layout class="QHBoxLayout" name="eos_layout" stretch="0,0"> <layout class="QVBoxLayout" name="eos_layout" stretch="0">
<property name="sizeConstraint"> <property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum> <enum>QLayout::SetDefaultConstraint</enum>
</property> </property>
<item> <item>
<widget class="QStackedWidget" name="overlay_stack"> <widget class="QStackedWidget" name="overlay_stack">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="overlay_info_page"> <widget class="QWidget" name="install_page">
<layout class="QFormLayout" name="overlay_info_layout"> <layout class="QHBoxLayout" name="install_page_layout" stretch="1,0">
<property name="labelAlignment"> <property name="leftMargin">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <number>0</number>
</property> </property>
<property name="formAlignment"> <property name="topMargin">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> <number>0</number>
</property> </property>
<item row="0" column="0"> <property name="rightMargin">
<widget class="QLabel" name="installed_version_info_lbl"> <number>0</number>
<property name="text"> </property>
<string>Version</string> <property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QFormLayout" name="install_label_layout">
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> <property name="formAlignment">
</item> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
<item row="0" column="1">
<widget class="QLabel" name="installed_version_lbl">
<property name="text">
<string notr="true">error</string>
</property> </property>
</widget> <item row="0" column="0">
</item> <widget class="QLabel" name="install_label">
<item row="1" column="0">
<widget class="QLabel" name="installed_path_info_lbl">
<property name="text">
<string>Location</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="installed_path_lbl">
<property name="text">
<string notr="true">error</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<layout class="QHBoxLayout" name="info_buttons_layout">
<item>
<spacer name="info_buttons_hspacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="uninstall_button">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="text"> <property name="text">
<string>Uninstall</string> <string>Status:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="0" column="1">
<widget class="QPushButton" name="update_check_button"> <widget class="QLabel" name="install_text">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="text"> <property name="text">
<string>Check for update</string> <string>Epic Online Services Overlay is not installed</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="update_button">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Update</string>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</item> </item>
<item row="2" column="0" colspan="2"> <item>
<spacer name="info_page_vspacer"> <layout class="QVBoxLayout" name="install_button_layout">
<property name="orientation"> <property name="rightMargin">
<enum>Qt::Vertical</enum> <number>0</number>
</property> </property>
<property name="sizeHint" stdset="0">
<size>
<width>6</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="overlay_install_page">
<layout class="QFormLayout" name="overlay_install_layout">
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Epic Overlay Services is not installed</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="install_buttons_layout">
<item>
<spacer name="install_buttons_hspacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item> <item>
<widget class="QPushButton" name="install_button"> <widget class="QPushButton" name="install_button">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>120</width> <width>140</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -189,57 +83,86 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="1" column="0" colspan="2"> </layout>
<spacer name="install_page_vspacer"> </widget>
<property name="orientation"> <widget class="QWidget" name="info_page">
<enum>Qt::Vertical</enum> <layout class="QHBoxLayout" name="info_page_layout" stretch="1,0">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QFormLayout" name="info_label_layout">
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="formAlignment">
<size> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
<width>6</width>
<height>6</height>
</size>
</property> </property>
</spacer> <item row="0" column="0">
<widget class="QLabel" name="version_label">
<property name="text">
<string>Version:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="path_label">
<property name="text">
<string>Path:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="info_button_layout">
<item>
<widget class="QPushButton" name="update_button">
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="uninstall_button">
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Uninstall</string>
</property>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
</item> </item>
<item>
<widget class="QFrame" name="enable_frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="enable_layout">
<item>
<widget class="QComboBox" name="select_pfx_combo"/>
</item>
<item>
<widget class="QCheckBox" name="enabled_cb">
<property name="text">
<string>Activated</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="enabled_info_label">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>