commit
90aa28323c
|
@ -1,9 +1,9 @@
|
|||
import os
|
||||
import platform
|
||||
from logging import getLogger
|
||||
from typing import Tuple, Iterable
|
||||
from typing import Tuple, Iterable, List
|
||||
|
||||
from PyQt5.QtCore import Qt, QThreadPool, QRunnable, pyqtSlot
|
||||
from PyQt5.QtCore import Qt, QThreadPool, QRunnable, pyqtSlot, pyqtSignal
|
||||
from PyQt5.QtWidgets import QGroupBox, QListWidgetItem, QFileDialog, QMessageBox
|
||||
|
||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
|
||||
|
@ -200,12 +200,16 @@ class EGLSyncListItem(QListWidgetItem):
|
|||
|
||||
|
||||
class EGLSyncListGroup(QGroupBox, Ui_EGLSyncListGroup):
|
||||
action_errors = pyqtSignal(list)
|
||||
|
||||
def __init__(self, export: bool, parent=None):
|
||||
super(EGLSyncListGroup, self).__init__(parent=parent)
|
||||
self.setupUi(self)
|
||||
self.core = LegendaryCoreSingleton()
|
||||
self.signals = GlobalSignalsSingleton()
|
||||
self.list.setProperty("noBorder", 1)
|
||||
# TODO: Convert the CSS and the code to adhere to NoFrame
|
||||
# self.list.setFrameShape(self.list.NoFrame)
|
||||
|
||||
self.export = export
|
||||
|
||||
|
@ -232,6 +236,8 @@ class EGLSyncListGroup(QGroupBox, Ui_EGLSyncListGroup):
|
|||
|
||||
self.action_button.clicked.connect(self.action)
|
||||
|
||||
self.action_errors.connect(self.show_errors)
|
||||
|
||||
def has_selected(self):
|
||||
for item in self.items:
|
||||
if item.is_checked():
|
||||
|
@ -258,8 +264,8 @@ class EGLSyncListGroup(QGroupBox, Ui_EGLSyncListGroup):
|
|||
self.buttons_widget.setVisible(enabled and bool(self.list.count()))
|
||||
|
||||
def action(self):
|
||||
imported = list()
|
||||
errors = list()
|
||||
imported: List = []
|
||||
errors: List = []
|
||||
for item in self.items:
|
||||
if item.is_checked():
|
||||
if e := item.action():
|
||||
|
@ -271,13 +277,17 @@ class EGLSyncListGroup(QGroupBox, Ui_EGLSyncListGroup):
|
|||
self.signals.update_gamelist.emit(imported)
|
||||
self.populate(True)
|
||||
if errors:
|
||||
QMessageBox.warning(
|
||||
self.parent(),
|
||||
self.tr("The following errors occurred while {}.").format(
|
||||
self.tr("exporting") if self.export else self.tr("importing")
|
||||
),
|
||||
"\n".join(errors),
|
||||
)
|
||||
self.action_errors.emit(errors)
|
||||
|
||||
@pyqtSlot(list)
|
||||
def show_errors(self, errors: List):
|
||||
QMessageBox.warning(
|
||||
self.parent(),
|
||||
self.tr("The following errors occurred while {}.").format(
|
||||
self.tr("exporting") if self.export else self.tr("importing")
|
||||
),
|
||||
"\n".join(errors),
|
||||
)
|
||||
|
||||
@property
|
||||
def items(self) -> Iterable[EGLSyncListItem]:
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import json
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from enum import IntEnum
|
||||
from logging import getLogger
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
from PyQt5.QtCore import Qt, QModelIndex, pyqtSignal, QRunnable, QObject, QThreadPool
|
||||
from PyQt5.QtCore import Qt, QModelIndex, pyqtSignal, QRunnable, QObject, QThreadPool, pyqtSlot
|
||||
from PyQt5.QtGui import QStandardItemModel
|
||||
from PyQt5.QtWidgets import QFileDialog, QGroupBox, QCompleter, QTreeView, QHeaderView, QApplication, QMessageBox
|
||||
from PyQt5.QtWidgets import QFileDialog, QGroupBox, QCompleter, QTreeView, QHeaderView, qApp, QMessageBox
|
||||
|
||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ApiResultsSingleton
|
||||
from rare.ui.components.tabs.games.import_sync.import_group import Ui_ImportGroup
|
||||
|
@ -34,22 +35,22 @@ def find_app_name(path: str, core) -> Optional[str]:
|
|||
return None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ResultGame:
|
||||
app_name: str
|
||||
error: Optional[str] = None
|
||||
class ImportResult(IntEnum):
|
||||
ERROR = 0
|
||||
FAILED = 1
|
||||
SUCCESS = 2
|
||||
|
||||
|
||||
@dataclass
|
||||
class Result:
|
||||
successful_games: List[ResultGame] = None
|
||||
failed_games: List[ResultGame] = None
|
||||
error_messages: List[str] = None
|
||||
class ImportedGame:
|
||||
result: ImportResult
|
||||
app_name: Optional[str] = None
|
||||
message: Optional[str] = None
|
||||
|
||||
|
||||
class ImportWorker(QRunnable):
|
||||
class Signals(QObject):
|
||||
finished = pyqtSignal(Result)
|
||||
finished = pyqtSignal(list)
|
||||
progress = pyqtSignal(int)
|
||||
|
||||
def __init__(self, path: str, import_folder: bool = False, app_name: str = None):
|
||||
|
@ -59,39 +60,37 @@ class ImportWorker(QRunnable):
|
|||
self.path = Path(path)
|
||||
self.import_folder = import_folder
|
||||
self.app_name = app_name
|
||||
self.tr = lambda message: QApplication.translate("ImportThread", message)
|
||||
self.tr = lambda message: qApp.translate("ImportThread", message)
|
||||
|
||||
def run(self) -> None:
|
||||
result = Result([], [], [])
|
||||
result_list: List = []
|
||||
if self.import_folder:
|
||||
number_of_folders = len(list(self.path.iterdir()))
|
||||
for i, child in enumerate(self.path.iterdir()):
|
||||
folders = [i for i in self.path.iterdir() if i.is_dir()]
|
||||
number_of_folders = len(folders)
|
||||
for i, child in enumerate(folders):
|
||||
if not child.is_dir():
|
||||
continue
|
||||
if (app_name := find_app_name(str(child), self.core)) is not None:
|
||||
logger.debug(f"Found app_name {app_name} for {child}")
|
||||
err = self.__import_game(app_name, child)
|
||||
if err:
|
||||
result.failed_games.append(ResultGame(app_name, err))
|
||||
else:
|
||||
result.successful_games.append(ResultGame(app_name))
|
||||
else:
|
||||
result.error_messages.append(self.tr("Could not find AppName for {}").format(child))
|
||||
result = self.__try_import(child, None)
|
||||
result_list.append(result)
|
||||
self.signals.progress.emit(int(100 * i // number_of_folders))
|
||||
else:
|
||||
if not self.app_name:
|
||||
# try to find app name
|
||||
if a_n := find_app_name(str(self.path), self.core):
|
||||
self.app_name = a_n
|
||||
else:
|
||||
result.error_messages.append(self.tr("Could not find AppName for {}").format(str(self.path)))
|
||||
return
|
||||
err = self.__import_game(self.app_name, self.path)
|
||||
result = self.__try_import(self.path, self.app_name)
|
||||
result_list.append(result)
|
||||
self.signals.finished.emit(result_list)
|
||||
|
||||
def __try_import(self, path: Path, app_name: str = None) -> ImportedGame:
|
||||
result = ImportedGame(ImportResult.ERROR, None, None)
|
||||
if app_name or (app_name := find_app_name(str(path), self.core)):
|
||||
result.app_name = app_name
|
||||
err = self.__import_game(app_name, path)
|
||||
if err:
|
||||
result.failed_games.append(ResultGame(self.app_name, err))
|
||||
result.result = ImportResult.FAILED
|
||||
result.message = err
|
||||
else:
|
||||
result.successful_games.append(ResultGame(self.app_name))
|
||||
self.signals.finished.emit(result)
|
||||
result.result = ImportResult.SUCCESS
|
||||
else:
|
||||
result.message = self.tr("Could not find AppName for {}").format(str(path))
|
||||
return result
|
||||
|
||||
def __import_game(self, app_name: str, path: Path) -> str:
|
||||
if not (err := legendary_utils.import_game(self.core, app_name=app_name, path=str(path))):
|
||||
|
@ -205,12 +204,12 @@ class ImportGroup(QGroupBox):
|
|||
return False, path, ""
|
||||
|
||||
def path_changed(self, path):
|
||||
self.ui.info_label.setText(str())
|
||||
self.ui.info_label.setText("")
|
||||
self.ui.import_folder_check.setChecked(False)
|
||||
if self.path_edit.is_valid:
|
||||
self.app_name_edit.setText(find_app_name(path, self.core))
|
||||
else:
|
||||
self.app_name_edit.setText(str())
|
||||
self.app_name_edit.setText("")
|
||||
|
||||
def app_name_edit_cb(self, text) -> Tuple[bool, str, str]:
|
||||
if not text:
|
||||
|
@ -221,7 +220,7 @@ class ImportGroup(QGroupBox):
|
|||
return False, text, IndicatorLineEdit.reasons.game_not_installed
|
||||
|
||||
def app_name_changed(self, text):
|
||||
self.ui.info_label.setText(str())
|
||||
self.ui.info_label.setText("")
|
||||
if self.app_name_edit.is_valid:
|
||||
self.ui.import_button.setEnabled(True)
|
||||
else:
|
||||
|
@ -235,33 +234,63 @@ class ImportGroup(QGroupBox):
|
|||
worker.signals.progress.connect(self.import_progress)
|
||||
self.threadpool.start(worker)
|
||||
|
||||
def import_finished(self, result: Result):
|
||||
logger.info(f"Import finished: {result.__dict__}")
|
||||
if result.successful_games:
|
||||
self.signals.update_gamelist.emit([i.app_name for i in result.successful_games])
|
||||
if len(result.successful_games) == 1:
|
||||
@pyqtSlot(list)
|
||||
def import_finished(self, result: List):
|
||||
logger.info(f"Import finished: {result}")
|
||||
|
||||
self.signals.update_gamelist.emit([r.app_name for r in result if r.result == ImportResult.SUCCESS])
|
||||
|
||||
for failed in (f for f in result if f.result == ImportResult.FAILED):
|
||||
igame = self.core.get_installed_game(failed.app_name)
|
||||
if igame and igame.version != self.core.get_asset(igame.app_name, igame.platform, False).build_version:
|
||||
# update available
|
||||
self.signals.add_download.emit(igame.app_name)
|
||||
self.signals.update_download_tab_text.emit()
|
||||
|
||||
if len(result) == 1:
|
||||
res = result[0]
|
||||
if res.result == ImportResult.SUCCESS:
|
||||
self.ui.info_label.setText(
|
||||
self.tr(f"{self.core.get_game(result.successful_games[0].app_name).app_title} imported successfully: ")
|
||||
self.tr("{} was imported successfully").format(self.core.get_game(res.app_name).app_title)
|
||||
)
|
||||
elif res.result == ImportResult.FAILED:
|
||||
self.ui.info_label.setText(
|
||||
self.tr("Failed: {}").format(res.message)
|
||||
)
|
||||
else:
|
||||
self.ui.info_label.setText(
|
||||
self.tr("Imported {} games successfully".format(len(result.successful_games)))
|
||||
self.tr("Error: {}").format(res.message)
|
||||
)
|
||||
for res_game in result.failed_games:
|
||||
igame = self.core.get_installed_game(res_game.app_name)
|
||||
if igame.version != self.core.get_asset(igame.app_name, igame.platform, False).build_version:
|
||||
# update available
|
||||
self.signals.add_download.emit(igame.app_name)
|
||||
self.signals.update_download_tab_text.emit()
|
||||
|
||||
if result.failed_games:
|
||||
self.ui.info_label.setText(
|
||||
self.tr(f"Failed to import: "
|
||||
f"{', '.join([self.core.get_game(i.app_name).app_title for i in result.failed_games])}")
|
||||
else:
|
||||
success = [r for r in result if r.result == ImportResult.SUCCESS]
|
||||
failure = [r for r in result if r.result == ImportResult.FAILED]
|
||||
errored = [r for r in result if r.result == ImportResult.ERROR]
|
||||
messagebox = QMessageBox(
|
||||
QMessageBox.Information,
|
||||
self.tr("Import summary"),
|
||||
self.tr(
|
||||
"Tried to import {} folders.\n\n"
|
||||
"Successfully imported {} games, failed to import {} games and {} errors occurred"
|
||||
).format(len(success) + len(failure) + len(errored), len(success), len(failure), len(errored)),
|
||||
buttons=QMessageBox.StandardButton.Close,
|
||||
parent=self,
|
||||
)
|
||||
if result.error_messages:
|
||||
QMessageBox.warning(self, self.tr("Error"), self.tr("\n".join(result.error_messages)))
|
||||
|
||||
messagebox.setWindowModality(Qt.NonModal)
|
||||
details: List = []
|
||||
for res in success:
|
||||
details.append(
|
||||
self.tr("{} was imported successfully").format(self.core.get_game(res.app_name).app_title)
|
||||
)
|
||||
for res in failure:
|
||||
details.append(
|
||||
self.tr("Failed: {}").format(res.message)
|
||||
)
|
||||
for res in errored:
|
||||
details.append(
|
||||
self.tr("Error: {}").format(res.message)
|
||||
)
|
||||
messagebox.setDetailedText("\n".join(details))
|
||||
messagebox.show()
|
||||
|
||||
def import_progress(self, progress: int):
|
||||
pass
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Form implementation generated from reading ui file 'rare/ui/components/tabs/games/import_sync/import_group.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.6
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
@ -14,31 +14,34 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||
class Ui_ImportGroup(object):
|
||||
def setupUi(self, ImportGroup):
|
||||
ImportGroup.setObjectName("ImportGroup")
|
||||
ImportGroup.resize(501, 154)
|
||||
ImportGroup.resize(501, 136)
|
||||
ImportGroup.setWindowTitle("ImportGroup")
|
||||
ImportGroup.setWindowFilePath("")
|
||||
self.import_layout = QtWidgets.QFormLayout(ImportGroup)
|
||||
self.import_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.import_layout.setObjectName("import_layout")
|
||||
self.formLayout = QtWidgets.QFormLayout(ImportGroup)
|
||||
self.formLayout.setObjectName("formLayout")
|
||||
self.path_edit_label = QtWidgets.QLabel(ImportGroup)
|
||||
self.path_edit_label.setObjectName("path_edit_label")
|
||||
self.import_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.path_edit_label)
|
||||
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.path_edit_label)
|
||||
self.path_edit_layout = QtWidgets.QHBoxLayout()
|
||||
self.path_edit_layout.setObjectName("path_edit_layout")
|
||||
self.import_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.path_edit_layout)
|
||||
self.formLayout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.path_edit_layout)
|
||||
self.app_name_label = QtWidgets.QLabel(ImportGroup)
|
||||
self.app_name_label.setObjectName("app_name_label")
|
||||
self.import_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.app_name_label)
|
||||
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.app_name_label)
|
||||
self.app_name_layout = QtWidgets.QHBoxLayout()
|
||||
self.app_name_layout.setObjectName("app_name_layout")
|
||||
self.import_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.app_name_layout)
|
||||
self.formLayout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.app_name_layout)
|
||||
self.import_folder_label = QtWidgets.QLabel(ImportGroup)
|
||||
self.import_folder_label.setObjectName("import_folder_label")
|
||||
self.import_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.import_folder_label)
|
||||
self.info_label = QtWidgets.QLabel(ImportGroup)
|
||||
self.info_label.setText("")
|
||||
self.info_label.setObjectName("info_label")
|
||||
self.import_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.info_label)
|
||||
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.import_folder_label)
|
||||
self.import_folder_check = QtWidgets.QCheckBox(ImportGroup)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
self.import_folder_check.setFont(font)
|
||||
self.import_folder_check.setObjectName("import_folder_check")
|
||||
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.import_folder_check)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.import_button = QtWidgets.QPushButton(ImportGroup)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
|
@ -46,13 +49,12 @@ class Ui_ImportGroup(object):
|
|||
sizePolicy.setHeightForWidth(self.import_button.sizePolicy().hasHeightForWidth())
|
||||
self.import_button.setSizePolicy(sizePolicy)
|
||||
self.import_button.setObjectName("import_button")
|
||||
self.import_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.import_button)
|
||||
self.import_folder_check = QtWidgets.QCheckBox(ImportGroup)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
self.import_folder_check.setFont(font)
|
||||
self.import_folder_check.setObjectName("import_folder_check")
|
||||
self.import_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.import_folder_check)
|
||||
self.horizontalLayout.addWidget(self.import_button)
|
||||
self.info_label = QtWidgets.QLabel(ImportGroup)
|
||||
self.info_label.setText("")
|
||||
self.info_label.setObjectName("info_label")
|
||||
self.horizontalLayout.addWidget(self.info_label)
|
||||
self.formLayout.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout)
|
||||
|
||||
self.retranslateUi(ImportGroup)
|
||||
QtCore.QMetaObject.connectSlotsByName(ImportGroup)
|
||||
|
@ -63,8 +65,8 @@ class Ui_ImportGroup(object):
|
|||
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_button.setText(_translate("ImportGroup", "Import Game"))
|
||||
self.import_folder_check.setText(_translate("ImportGroup", "Scan the installation path for game folders and import them"))
|
||||
self.import_button.setText(_translate("ImportGroup", "Import Game"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>501</width>
|
||||
<height>154</height>
|
||||
<height>136</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -19,10 +19,7 @@
|
|||
<property name="title">
|
||||
<string>Import EGL game from a directory</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="import_layout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="path_edit_label">
|
||||
<property name="text">
|
||||
|
@ -50,26 +47,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="info_label">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QPushButton" name="import_button">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Import Game</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="import_folder_check">
|
||||
<property name="font">
|
||||
|
@ -82,6 +59,30 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="import_button">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Import Game</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="info_label">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
|
Loading…
Reference in a new issue