MoveDialog: Refactor MovePopup into a dialog using ActionDialog as base
This commit is contained in:
parent
17a5562b4c
commit
0fb1526d67
5 changed files with 82 additions and 69 deletions
|
@ -4,12 +4,14 @@ from enum import auto
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from typing import Tuple, Optional
|
from typing import Tuple, Optional
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
||||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFileDialog
|
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QFileDialog, QLayout
|
||||||
|
|
||||||
|
from rare.models.install import MoveGameModel
|
||||||
from rare.models.game import RareGame
|
from rare.models.game import RareGame
|
||||||
from rare.shared import RareCore
|
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.elide_label import ElideLabel
|
||||||
from rare.widgets.indicator_edit import PathEdit, IndicatorReasons, IndicatorReasonsCommon
|
from rare.widgets.indicator_edit import PathEdit, IndicatorReasons, IndicatorReasonsCommon
|
||||||
|
|
||||||
|
@ -25,12 +27,16 @@ class MovePathEditReasons(IndicatorReasons):
|
||||||
NO_SPACE = auto()
|
NO_SPACE = auto()
|
||||||
|
|
||||||
|
|
||||||
class MoveGamePopUp(QWidget):
|
class MoveDialog(ActionDialog):
|
||||||
move_clicked = pyqtSignal(str)
|
result_ready = pyqtSignal(RareGame, MoveGameModel)
|
||||||
browse_done = pyqtSignal()
|
|
||||||
|
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.rcore = RareCore.instance()
|
||||||
self.core = RareCore.instance().core()
|
self.core = RareCore.instance().core()
|
||||||
self.rgame: Optional[RareGame] = None
|
self.rgame: Optional[RareGame] = None
|
||||||
|
@ -44,19 +50,9 @@ class MoveGamePopUp(QWidget):
|
||||||
MovePathEditReasons.NESTED_DIR: self.tr("Game install directories cannot be nested."),
|
MovePathEditReasons.NESTED_DIR: self.tr("Game install directories cannot be nested."),
|
||||||
MovePathEditReasons.NO_SPACE: self.tr("Not enough space available on drive."),
|
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)
|
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 = self.font()
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
self.req_space_label = QLabel(self.tr("Required:"), self)
|
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_label)
|
||||||
bottom_layout.addWidget(self.avail_space, stretch=1)
|
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.addWidget(self.path_edit)
|
||||||
layout.addLayout(middle_layout)
|
layout.addWidget(self.warn_label)
|
||||||
layout.addLayout(bottom_layout)
|
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):
|
def refresh_indicator(self):
|
||||||
# needed so the edit_func gets run again
|
# needed so the edit_func gets run again
|
||||||
text = self.path_edit.text()
|
text = self.path_edit.text()
|
||||||
|
@ -84,13 +107,13 @@ class MoveGamePopUp(QWidget):
|
||||||
self.path_edit.setText(text)
|
self.path_edit.setText(text)
|
||||||
|
|
||||||
def path_edit_callback(self, path: str) -> Tuple[bool, str, int]:
|
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.warn_label.setHidden(False)
|
||||||
self.req_space.setText("...")
|
self.req_space.setText("...")
|
||||||
self.avail_space.setText("...")
|
self.avail_space.setText("...")
|
||||||
|
|
||||||
def helper_func(reason: int) -> Tuple[bool, str, int]:
|
def helper_func(reason: int) -> Tuple[bool, str, int]:
|
||||||
self.button.setEnabled(False)
|
self.accept_button.setEnabled(False)
|
||||||
return False, path, reason
|
return False, path, reason
|
||||||
|
|
||||||
if not self.rgame.install_path or not path:
|
if not self.rgame.install_path or not path:
|
||||||
|
@ -141,7 +164,7 @@ class MoveGamePopUp(QWidget):
|
||||||
return helper_func(MovePathEditReasons.NO_SPACE)
|
return helper_func(MovePathEditReasons.NO_SPACE)
|
||||||
|
|
||||||
# Fallback
|
# Fallback
|
||||||
self.button.setEnabled(True)
|
self.accept_button.setEnabled(True)
|
||||||
return True, path, IndicatorReasonsCommon.VALID
|
return True, path, IndicatorReasonsCommon.VALID
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
|
@ -151,20 +174,18 @@ class MoveGamePopUp(QWidget):
|
||||||
self.setDisabled(True)
|
self.setDisabled(True)
|
||||||
return
|
return
|
||||||
# FIXME: Make edit_func lighter instead of blocking signals
|
# 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)
|
self.path_edit.setText(self.rgame.install_path)
|
||||||
# FIXME: Make edit_func lighter instead of blocking signals
|
# 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.warn_label.setText(
|
||||||
self.tr("Moving here will overwrite <b>{}</b>").format(os.path.basename(self.rgame.install_path))
|
self.tr("Moving here will overwrite <b>{}</b>").format(os.path.basename(self.rgame.install_path))
|
||||||
)
|
)
|
||||||
self.refresh_indicator()
|
self.refresh_indicator()
|
||||||
|
|
||||||
def update_game(self, rgame: RareGame):
|
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.rgame = rgame
|
||||||
self.__update_widget()
|
self.__update_widget()
|
||||||
|
|
|
@ -10,13 +10,11 @@ from PyQt5.QtCore import (
|
||||||
pyqtSignal,
|
pyqtSignal,
|
||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QMenu,
|
|
||||||
QWidget,
|
QWidget,
|
||||||
QMessageBox,
|
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.components.dialogs.selective_dialog import SelectiveDialog
|
||||||
from rare.models.game import RareGame
|
from rare.models.game import RareGame
|
||||||
from rare.shared import RareCore
|
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.utils.misc import format_size, icon
|
||||||
from rare.widgets.image_widget import ImageWidget, ImageSize
|
from rare.widgets.image_widget import ImageWidget, ImageSize
|
||||||
from rare.widgets.side_tab import SideTabContents
|
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")
|
logger = getLogger("GameInfo")
|
||||||
|
|
||||||
|
@ -68,18 +66,9 @@ class GameInfo(QWidget, SideTabContents):
|
||||||
self.ui.modify_button.clicked.connect(self.__on_modify)
|
self.ui.modify_button.clicked.connect(self.__on_modify)
|
||||||
self.ui.verify_button.clicked.connect(self.__on_verify)
|
self.ui.verify_button.clicked.connect(self.__on_verify)
|
||||||
self.ui.repair_button.clicked.connect(self.__on_repair)
|
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.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 = {
|
self.steam_grade_ratings = {
|
||||||
"platinum": self.tr("Platinum"),
|
"platinum": self.tr("Platinum"),
|
||||||
"gold": self.tr("Gold"),
|
"gold": self.tr("Gold"),
|
||||||
|
@ -217,17 +206,24 @@ class GameInfo(QWidget, SideTabContents):
|
||||||
if ans == QMessageBox.Yes:
|
if ans == QMessageBox.Yes:
|
||||||
self.repair_game(rgame)
|
self.repair_game(rgame)
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot()
|
||||||
def __on_move(self, dst_path: str):
|
def __on_move(self):
|
||||||
""" This method is to be called from the button only """
|
""" 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
|
dir_exists = False
|
||||||
if os.path.isdir(new_install_path):
|
if os.path.isdir(new_install_path):
|
||||||
dir_exists = is_game_dir(self.rgame.install_path, new_install_path)
|
dir_exists = is_game_dir(self.rgame.install_path, new_install_path)
|
||||||
|
|
||||||
if not dir_exists:
|
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):
|
if os.path.basename(self.rgame.install_path) in os.path.basename(item):
|
||||||
ans = QMessageBox.question(
|
ans = QMessageBox.question(
|
||||||
self,
|
self,
|
||||||
|
@ -248,11 +244,8 @@ class GameInfo(QWidget, SideTabContents):
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.move_game(self.rgame, new_install_path, dir_exists)
|
|
||||||
|
|
||||||
def move_game(self, rgame: RareGame, dst_path, dst_exists):
|
|
||||||
worker = MoveWorker(
|
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.progress.connect(self.__on_move_progress)
|
||||||
worker.signals.result.connect(self.__on_move_result)
|
worker.signals.result.connect(self.__on_move_result)
|
||||||
|
@ -395,7 +388,5 @@ class GameInfo(QWidget, SideTabContents):
|
||||||
else:
|
else:
|
||||||
self.ui.install_button.setText(self.tr("Install"))
|
self.ui.install_button.setText(self.tr("Install"))
|
||||||
|
|
||||||
self.move_game_pop_up.update_game(rgame)
|
|
||||||
|
|
||||||
self.rgame = rgame
|
self.rgame = rgame
|
||||||
self.__update_widget()
|
self.__update_widget()
|
||||||
|
|
|
@ -101,7 +101,7 @@ class UninstallOptionsModel:
|
||||||
This model's options
|
This model's options
|
||||||
|
|
||||||
:return:
|
: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
|
return self.accepted, self.keep_config, self.keep_files
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ class UninstallOptionsModel:
|
||||||
Set this model's options
|
Set this model's options
|
||||||
|
|
||||||
:param values:
|
:param values:
|
||||||
Tuple of `accepted` `keep_files` `keep_config`
|
Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys`
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self.accepted = values[0]
|
self.accepted = values[0]
|
||||||
|
@ -132,3 +132,16 @@ class SelectiveDownloadsModel:
|
||||||
and (self.install_tag is not None)
|
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)
|
||||||
|
)
|
||||||
|
|
|
@ -255,15 +255,12 @@ class Ui_GameInfo(object):
|
||||||
self.move_button_layout.setContentsMargins(0, 0, 0, 0)
|
self.move_button_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
self.move_button_layout.setSpacing(0)
|
self.move_button_layout.setSpacing(0)
|
||||||
self.move_button_layout.setObjectName("move_button_layout")
|
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 = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.move_button.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.move_button.sizePolicy().hasHeightForWidth())
|
||||||
self.move_button.setSizePolicy(sizePolicy)
|
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.setObjectName("move_button")
|
||||||
self.move_button_layout.addWidget(self.move_button)
|
self.move_button_layout.addWidget(self.move_button)
|
||||||
self.move_stack.addWidget(self.move_button_page)
|
self.move_stack.addWidget(self.move_button_page)
|
||||||
|
|
|
@ -488,7 +488,7 @@
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QToolButton" name="move_button">
|
<widget class="QPushButton" name="move_button">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
|
@ -498,15 +498,6 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Move</string>
|
<string>Move</string>
|
||||||
</property>
|
</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>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
Loading…
Reference in a new issue