1
0
Fork 0
mirror of synced 2024-05-18 19:42:54 +12:00

Merge pull request #366 from loathingKernel/next

Refactor UninstallDialog, and implement MoveDialog
This commit is contained in:
Stelios Tsampas 2024-01-06 14:12:10 +02:00 committed by GitHub
commit 828a232ba2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 889 additions and 754 deletions

View file

@ -4,12 +4,14 @@ from enum import auto
from logging import getLogger
from typing import Tuple, Optional
from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFileDialog
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QFileDialog, QLayout
from rare.models.install import MoveGameModel
from rare.models.game import RareGame
from rare.shared import RareCore
from rare.utils.misc import path_size, format_size
from rare.utils.misc import path_size, format_size, icon
from rare.widgets.dialogs import ActionDialog, dialog_title_game
from rare.widgets.elide_label import ElideLabel
from rare.widgets.indicator_edit import PathEdit, IndicatorReasons, IndicatorReasonsCommon
@ -25,12 +27,16 @@ class MovePathEditReasons(IndicatorReasons):
NO_SPACE = auto()
class MoveGamePopUp(QWidget):
move_clicked = pyqtSignal(str)
browse_done = pyqtSignal()
class MoveDialog(ActionDialog):
result_ready = pyqtSignal(RareGame, MoveGameModel)
def __init__(self, rgame: RareGame, parent=None):
super(MoveDialog, self).__init__(parent=parent)
header = self.tr("Move")
self.setWindowTitle(dialog_title_game(header, rgame.app_title))
title_label = QLabel(f"<h4>{dialog_title_game(header, rgame.app_title)}</h4>", self)
def __init__(self, parent=None):
super(MoveGamePopUp, self).__init__(parent=parent)
self.rcore = RareCore.instance()
self.core = RareCore.instance().core()
self.rgame: Optional[RareGame] = None
@ -44,19 +50,9 @@ class MoveGamePopUp(QWidget):
MovePathEditReasons.NESTED_DIR: self.tr("Game install directories cannot be nested."),
MovePathEditReasons.NO_SPACE: self.tr("Not enough space available on drive."),
})
self.path_edit.path_select.clicked.connect(self.browse_done)
self.button = QPushButton(self.tr("Move"))
self.button.setFixedSize(self.path_edit.path_select.sizeHint())
self.button.clicked.connect(lambda p: self.move_clicked.emit(self.path_edit.text()))
self.warn_label = ElideLabel("", parent=self)
middle_layout = QHBoxLayout()
middle_layout.setAlignment(Qt.AlignRight)
middle_layout.addWidget(self.warn_label, stretch=1)
middle_layout.addWidget(self.button)
font = self.font()
font.setBold(True)
self.req_space_label = QLabel(self.tr("Required:"), self)
@ -72,11 +68,38 @@ class MoveGamePopUp(QWidget):
bottom_layout.addWidget(self.avail_space_label)
bottom_layout.addWidget(self.avail_space, stretch=1)
layout: QVBoxLayout = QVBoxLayout(self)
layout = QVBoxLayout()
layout.setSizeConstraint(QLayout.SetFixedSize)
layout.addWidget(title_label)
layout.addWidget(self.path_edit)
layout.addLayout(middle_layout)
layout.addWidget(self.warn_label)
layout.addLayout(bottom_layout)
self.setCentralLayout(layout)
self.accept_button.setText(self.tr("Move"))
self.accept_button.setIcon(icon("mdi.folder-move-outline"))
self.action_button.setHidden(True)
self.update_game(rgame)
self.options: MoveGameModel = MoveGameModel(rgame.app_name)
def action_handler(self):
pass
def done_handler(self):
self.result_ready.emit(self.rgame, self.options)
def accept_handler(self):
self.options.accepted = True
self.options.target_path = self.path_edit.text()
def reject_handler(self):
self.options.accepted = False
self.options.target_path = ""
def refresh_indicator(self):
# needed so the edit_func gets run again
text = self.path_edit.text()
@ -84,13 +107,13 @@ class MoveGamePopUp(QWidget):
self.path_edit.setText(text)
def path_edit_callback(self, path: str) -> Tuple[bool, str, int]:
self.button.setEnabled(True)
self.accept_button.setEnabled(True)
self.warn_label.setHidden(False)
self.req_space.setText("...")
self.avail_space.setText("...")
def helper_func(reason: int) -> Tuple[bool, str, int]:
self.button.setEnabled(False)
self.accept_button.setEnabled(False)
return False, path, reason
if not self.rgame.install_path or not path:
@ -141,7 +164,7 @@ class MoveGamePopUp(QWidget):
return helper_func(MovePathEditReasons.NO_SPACE)
# Fallback
self.button.setEnabled(True)
self.accept_button.setEnabled(True)
return True, path, IndicatorReasonsCommon.VALID
@pyqtSlot()
@ -151,20 +174,18 @@ class MoveGamePopUp(QWidget):
self.setDisabled(True)
return
# FIXME: Make edit_func lighter instead of blocking signals
self.path_edit.line_edit.blockSignals(True)
# self.path_edit.line_edit.blockSignals(True)
self.setActive(True)
self.path_edit.setText(self.rgame.install_path)
# FIXME: Make edit_func lighter instead of blocking signals
self.path_edit.line_edit.blockSignals(False)
# self.path_edit.line_edit.blockSignals(False)
self.setActive(False)
self.warn_label.setText(
self.tr("Moving here will overwrite <b>{}</b>").format(os.path.basename(self.rgame.install_path))
)
self.refresh_indicator()
def update_game(self, rgame: RareGame):
if self.rgame is not None:
self.rgame.signals.widget.update.disconnect(self.__update_widget)
self.rgame = None
rgame.signals.widget.update.connect(self.__update_widget)
self.rgame = rgame
self.__update_widget()

View file

@ -1,81 +1,57 @@
from PyQt5.QtCore import Qt, pyqtSignal, QCoreApplication
from PyQt5.QtGui import QCloseEvent, QKeyEvent
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import (
QDialog,
QLabel,
QVBoxLayout,
QCheckBox,
QHBoxLayout,
QPushButton, QLayout,
)
from legendary.utils.selective_dl import get_sdl_appname
from rare.models.game import RareGame
from rare.models.install import UninstallOptionsModel
from rare.utils.misc import icon
from rare.widgets.dialogs import ButtonDialog, dialog_title_game
class UninstallDialog(QDialog):
class UninstallDialog(ButtonDialog):
result_ready = pyqtSignal(UninstallOptionsModel)
def __init__(self, rgame: RareGame, options: UninstallOptionsModel, parent=None):
super(UninstallDialog, self).__init__(parent=parent)
self.setAttribute(Qt.WA_DeleteOnClose, True)
self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint)
header = self.tr("Uninstall")
self.setWindowTitle(f'{header} "{rgame.app_title}" - {QCoreApplication.instance().applicationName()}')
self.title_label = QLabel(
self.tr("<h4>Do you really want to uninstall <b>{}</b>?</h4>").format(rgame.app_title)
)
self.setWindowTitle(dialog_title_game(header, rgame.app_title))
self.keep_files = QCheckBox(self.tr("Keep game files."))
title_label = QLabel(f"<h4>{dialog_title_game(header, rgame.app_title)}</h4>", self)
self.keep_files = QCheckBox(self.tr("Keep files"))
self.keep_files.setChecked(bool(options.keep_files))
self.keep_config = QCheckBox(self.tr("Keep game configuation."))
self.keep_config = QCheckBox(self.tr("Keep configuation"))
self.keep_config.setChecked(bool(options.keep_config))
self.uninstall_button = QPushButton(
icon("ei.remove-circle", color="red"), self.tr("Uninstall")
)
self.uninstall_button.setObjectName("UninstallButton")
self.uninstall_button.clicked.connect(self.__on_uninstall)
layout = QVBoxLayout()
layout.addWidget(title_label)
layout.addWidget(self.keep_files)
layout.addWidget(self.keep_config)
self.cancel_button = QPushButton(self.tr("Cancel"))
self.cancel_button.clicked.connect(self.__on_cancel)
self.setCentralLayout(layout)
form_layout = QVBoxLayout()
form_layout.setContentsMargins(-1, -1, 0, -1)
form_layout.addWidget(self.keep_files)
form_layout.addWidget(self.keep_config)
button_layout = QHBoxLayout()
button_layout.addWidget(self.cancel_button)
button_layout.addStretch(1)
button_layout.addWidget(self.uninstall_button)
layout = QVBoxLayout(self)
layout.setSizeConstraint(QLayout.SetFixedSize)
layout.addWidget(self.title_label)
layout.addLayout(form_layout)
layout.addLayout(button_layout)
self.accept_button.setText(self.tr("Uninstall"))
self.accept_button.setIcon(icon("ri.uninstall-line"))
self.accept_button.setObjectName("UninstallButton")
if rgame.sdl_name is not None:
self.keep_config.setChecked(True)
self.options: UninstallOptionsModel = options
def closeEvent(self, a0: QCloseEvent) -> None:
def done_handler(self) -> None:
self.result_ready.emit(self.options)
super(UninstallDialog, self).closeEvent(a0)
def __on_uninstall(self):
self.options.values = (True, self.keep_files.isChecked(), self.keep_config.isChecked())
self.close()
def accept_handler(self):
self.options.values = (
True,
self.keep_files.isChecked(),
self.keep_config.isChecked(),
)
def __on_cancel(self):
def reject_handler(self):
self.options.values = (None, None, None)
self.close()
def keyPressEvent(self, e: QKeyEvent) -> None:
if e.key() == Qt.Key_Escape:
e.accept()
self.__on_cancel()

View file

@ -330,7 +330,7 @@ class DownloadsTab(QWidget):
parent=self,
)
uninstall_dialog.result_ready.connect(self.__on_uninstall_dialog_closed)
uninstall_dialog.exec()
uninstall_dialog.open()
@pyqtSlot(UninstallOptionsModel)
def __on_uninstall_dialog_closed(self, options: UninstallOptionsModel):

View file

@ -10,13 +10,11 @@ from PyQt5.QtCore import (
pyqtSignal,
)
from PyQt5.QtWidgets import (
QMenu,
QWidget,
QMessageBox,
QWidgetAction,
)
from rare.models.install import SelectiveDownloadsModel
from rare.models.install import SelectiveDownloadsModel, MoveGameModel
from rare.components.dialogs.selective_dialog import SelectiveDialog
from rare.models.game import RareGame
from rare.shared import RareCore
@ -25,7 +23,7 @@ from rare.ui.components.tabs.games.game_info.game_info import Ui_GameInfo
from rare.utils.misc import format_size, icon
from rare.widgets.image_widget import ImageWidget, ImageSize
from rare.widgets.side_tab import SideTabContents
from .move_game import MoveGamePopUp, is_game_dir
from rare.components.dialogs.move_dialog import MoveDialog, is_game_dir
logger = getLogger("GameInfo")
@ -68,18 +66,9 @@ class GameInfo(QWidget, SideTabContents):
self.ui.modify_button.clicked.connect(self.__on_modify)
self.ui.verify_button.clicked.connect(self.__on_verify)
self.ui.repair_button.clicked.connect(self.__on_repair)
self.ui.move_button.clicked.connect(self.__on_move)
self.ui.uninstall_button.clicked.connect(self.__on_uninstall)
self.move_game_pop_up = MoveGamePopUp(self)
move_action = QWidgetAction(self)
move_action.setDefaultWidget(self.move_game_pop_up)
self.ui.move_button.setMenu(QMenu(self.ui.move_button))
self.ui.move_button.menu().addAction(move_action)
self.move_game_pop_up.browse_done.connect(self.ui.move_button.showMenu)
self.move_game_pop_up.move_clicked.connect(self.ui.move_button.menu().close)
self.move_game_pop_up.move_clicked.connect(self.__on_move)
self.steam_grade_ratings = {
"platinum": self.tr("Platinum"),
"gold": self.tr("Gold"),
@ -217,17 +206,24 @@ class GameInfo(QWidget, SideTabContents):
if ans == QMessageBox.Yes:
self.repair_game(rgame)
@pyqtSlot(str)
def __on_move(self, dst_path: str):
@pyqtSlot()
def __on_move(self):
""" This method is to be called from the button only """
new_install_path = os.path.join(dst_path, os.path.basename(self.rgame.install_path))
move_dialog = MoveDialog(self.rgame, parent=self)
move_dialog.result_ready.connect(self.move_game)
move_dialog.open()
def move_game(self, rgame: RareGame, model: MoveGameModel):
if not model.accepted:
return
new_install_path = os.path.join(model.target_path, os.path.basename(self.rgame.install_path))
dir_exists = False
if os.path.isdir(new_install_path):
dir_exists = is_game_dir(self.rgame.install_path, new_install_path)
if not dir_exists:
for item in os.listdir(dst_path):
for item in os.listdir(model.target_path):
if os.path.basename(self.rgame.install_path) in os.path.basename(item):
ans = QMessageBox.question(
self,
@ -248,11 +244,8 @@ class GameInfo(QWidget, SideTabContents):
else:
return
self.move_game(self.rgame, new_install_path, dir_exists)
def move_game(self, rgame: RareGame, dst_path, dst_exists):
worker = MoveWorker(
self.core, rgame=rgame, dst_path=dst_path, dst_exists=dst_exists
self.core, rgame=rgame, dst_path=model.target_path, dst_exists=dir_exists
)
worker.signals.progress.connect(self.__on_move_progress)
worker.signals.result.connect(self.__on_move_result)
@ -395,7 +388,5 @@ class GameInfo(QWidget, SideTabContents):
else:
self.ui.install_button.setText(self.tr("Install"))
self.move_game_pop_up.update_game(rgame)
self.rgame = rgame
self.__update_widget()

View file

@ -101,7 +101,7 @@ class UninstallOptionsModel:
This model's options
:return:
Tuple of `accepted` `keep_files` `keep_config`
Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys`
"""
return self.accepted, self.keep_config, self.keep_files
@ -111,7 +111,7 @@ class UninstallOptionsModel:
Set this model's options
:param values:
Tuple of `accepted` `keep_files` `keep_config`
Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys`
:return:
"""
self.accepted = values[0]
@ -132,3 +132,16 @@ class SelectiveDownloadsModel:
and (self.install_tag is not None)
)
@dataclass
class MoveGameModel:
app_name: str
accepted: bool = None
target_path: Optional[str] = None
def __bool__(self):
return (
bool(self.app_name)
and (self.accepted is not None)
and (self.target_path is not None)
)

File diff suppressed because it is too large Load diff

View file

@ -255,15 +255,12 @@ class Ui_GameInfo(object):
self.move_button_layout.setContentsMargins(0, 0, 0, 0)
self.move_button_layout.setSpacing(0)
self.move_button_layout.setObjectName("move_button_layout")
self.move_button = QtWidgets.QToolButton(self.move_button_page)
self.move_button = QtWidgets.QPushButton(self.move_button_page)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.move_button.sizePolicy().hasHeightForWidth())
self.move_button.setSizePolicy(sizePolicy)
self.move_button.setPopupMode(QtWidgets.QToolButton.InstantPopup)
self.move_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
self.move_button.setArrowType(QtCore.Qt.DownArrow)
self.move_button.setObjectName("move_button")
self.move_button_layout.addWidget(self.move_button)
self.move_stack.addWidget(self.move_button_page)

View file

@ -488,7 +488,7 @@
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="move_button">
<widget class="QPushButton" name="move_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -498,15 +498,6 @@
<property name="text">
<string>Move</string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextOnly</enum>
</property>
<property name="arrowType">
<enum>Qt::DownArrow</enum>
</property>
</widget>
</item>
</layout>

View file

@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ImportGroup(object):
def setupUi(self, ImportGroup):
ImportGroup.setObjectName("ImportGroup")
ImportGroup.resize(651, 218)
ImportGroup.resize(651, 232)
ImportGroup.setWindowTitle("ImportGroup")
ImportGroup.setWindowFilePath("")
self.import_layout = QtWidgets.QFormLayout(ImportGroup)
@ -54,7 +54,7 @@ class Ui_ImportGroup(object):
self.import_force_check.setObjectName("import_force_check")
self.import_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.import_force_check)
self.import_button_label = QtWidgets.QLabel(ImportGroup)
self.import_button_label.setText("Error")
self.import_button_label.setText("error")
self.import_button_label.setObjectName("import_button_label")
self.import_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.import_button_label)
self.button_info_layout = QtWidgets.QHBoxLayout()
@ -96,13 +96,13 @@ class Ui_ImportGroup(object):
ImportGroup.setTitle(_translate("ImportGroup", "Import EGL game from a directory"))
self.path_edit_label.setText(_translate("ImportGroup", "Installation path"))
self.app_name_label.setText(_translate("ImportGroup", "Override app name"))
self.import_folder_label.setText(_translate("ImportGroup", "Import all folders"))
self.import_folder_label.setText(_translate("ImportGroup", "Import all games"))
self.import_folder_check.setText(_translate("ImportGroup", "Scan the installation path for game folders and import them"))
self.import_dlcs_label.setText(_translate("ImportGroup", "Import DLCs"))
self.import_dlcs_check.setText(_translate("ImportGroup", "If a game has DLCs, try to import them too"))
self.import_force_label.setText(_translate("ImportGroup", "Force import"))
self.import_force_check.setText(_translate("ImportGroup", "Import game despite missing files"))
self.import_button.setText(_translate("ImportGroup", "Import Game"))
self.import_button.setText(_translate("ImportGroup", "Import game(s)"))
self.platform_label.setText(_translate("ImportGroup", "Platform"))
self.platform_tooltip.setText(_translate("ImportGroup", "Select the native platform of the game"))

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>651</width>
<height>218</height>
<height>232</height>
</rect>
</property>
<property name="windowTitle">
@ -40,7 +40,7 @@
<item row="3" column="0">
<widget class="QLabel" name="import_folder_label">
<property name="text">
<string>Import all folders</string>
<string>Import all games</string>
</property>
</widget>
</item>
@ -97,7 +97,7 @@
<item row="6" column="0">
<widget class="QLabel" name="import_button_label">
<property name="text">
<string notr="true">Error</string>
<string notr="true">error</string>
</property>
</widget>
</item>
@ -112,7 +112,7 @@
</sizepolicy>
</property>
<property name="text">
<string>Import Game</string>
<string>Import game(s)</string>
</property>
</widget>
</item>