523391d166
By preparing the download inside the widget, the delay after stopping the running download and visual feedback of adding the widget is reduced. The widget will now appear containing the basic information and will be populated with the information about the download when it is ready. The widget is disabled in the meantime. Move `InstallInfoWorker` to `rare.shared.workers` module and revert it to emitting a `InstallDownloadItem` model only instead of a `InstallQueueItemModel.`
223 lines
8.3 KiB
Python
223 lines
8.3 KiB
Python
from collections import deque
|
|
from enum import IntEnum
|
|
from logging import getLogger
|
|
from typing import Optional, Deque, Union
|
|
|
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt
|
|
from PyQt5.QtWidgets import (
|
|
QWidget,
|
|
QGroupBox,
|
|
QVBoxLayout,
|
|
QLabel,
|
|
QSizePolicy,
|
|
)
|
|
from legendary.models.game import Game, InstalledGame
|
|
|
|
from rare.components.tabs.downloads.widgets import QueueWidget, UpdateWidget
|
|
from rare.models.install import InstallOptionsModel, InstallQueueItemModel
|
|
from rare.utils.misc import widget_object_name
|
|
|
|
logger = getLogger("QueueGroup")
|
|
|
|
|
|
class UpdateGroup(QGroupBox):
|
|
update_count = pyqtSignal(int)
|
|
enqueue = pyqtSignal(InstallOptionsModel)
|
|
|
|
def __init__(self, parent=None):
|
|
super(UpdateGroup, self).__init__(parent=parent)
|
|
self.setObjectName(type(self).__name__)
|
|
self.setTitle(self.tr("Updates"))
|
|
self.__text = QLabel(self.tr("No updates available"))
|
|
self.__text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
|
|
|
# lk: For findChildren to work, the upates's layout has to be in a widget
|
|
self.__container = QWidget(self)
|
|
self.__container.setLayout(QVBoxLayout())
|
|
self.__container.layout().setContentsMargins(0, 0, 0, 0)
|
|
|
|
self.setLayout(QVBoxLayout())
|
|
self.layout().addWidget(self.__text)
|
|
self.layout().addWidget(self.__container)
|
|
|
|
def __find_widget(self, app_name: str) -> Optional[UpdateWidget]:
|
|
return self.__container.findChild(UpdateWidget, name=widget_object_name(UpdateWidget, app_name))
|
|
|
|
def count(self) -> int:
|
|
return len(self.__container.findChildren(UpdateWidget, options=Qt.FindDirectChildrenOnly))
|
|
|
|
def contains(self, app_name: str) -> bool:
|
|
return self.__find_widget(app_name) is not None
|
|
|
|
def __update_group(self):
|
|
count = self.count()
|
|
self.__text.setVisible(not count)
|
|
self.__container.setVisible(bool(count))
|
|
self.update_count.emit(count)
|
|
|
|
def append(self, game: Game, igame: InstalledGame):
|
|
self.__text.setVisible(False)
|
|
self.__container.setVisible(True)
|
|
widget: UpdateWidget = self.__find_widget(game.app_name)
|
|
if widget is not None:
|
|
self.__container.layout().removeWidget(widget)
|
|
widget.deleteLater()
|
|
widget = UpdateWidget(game, igame, parent=self.__container)
|
|
widget.destroyed.connect(self.__update_group)
|
|
widget.enqueue.connect(self.enqueue)
|
|
self.__container.layout().addWidget(widget)
|
|
|
|
def remove(self, app_name: str):
|
|
widget: UpdateWidget = self.__find_widget(app_name)
|
|
self.__container.layout().removeWidget(widget)
|
|
widget.deleteLater()
|
|
|
|
def set_widget_enabled(self, app_name: str, enabled: bool):
|
|
widget: UpdateWidget = self.__find_widget(app_name)
|
|
widget.set_enabled(enabled)
|
|
|
|
def get_widget_version(self, app_name: str) -> str:
|
|
widget: UpdateWidget = self.__find_widget(app_name)
|
|
return widget.version()
|
|
|
|
|
|
class QueueGroup(QGroupBox):
|
|
update_count = pyqtSignal(int)
|
|
removed = pyqtSignal(str)
|
|
force = pyqtSignal(InstallQueueItemModel)
|
|
|
|
def __init__(self, parent=None):
|
|
super(QueueGroup, self).__init__(parent=parent)
|
|
self.setObjectName(type(self).__name__)
|
|
self.setTitle(self.tr("Queue"))
|
|
self.__text = QLabel(self.tr("No downloads in queue"), self)
|
|
self.__text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
|
|
|
# lk: For findChildren to work, the queue's layout has to be in a widget
|
|
self.__container = QWidget(self)
|
|
self.__container.setLayout(QVBoxLayout())
|
|
self.__container.layout().setContentsMargins(0, 0, 0, 0)
|
|
self.__container.setVisible(False)
|
|
|
|
self.setLayout(QVBoxLayout())
|
|
self.layout().addWidget(self.__text)
|
|
self.layout().addWidget(self.__container)
|
|
|
|
self.__queue: Deque[str] = deque()
|
|
|
|
def __find_widget(self, app_name: str) -> Optional[QueueWidget]:
|
|
return self.__container.findChild(QueueWidget, name=widget_object_name(QueueWidget, app_name))
|
|
|
|
def count(self) -> int:
|
|
return len(self.__queue)
|
|
|
|
def contains(self, app_name: str) -> bool:
|
|
if app_name in self.__queue:
|
|
return self.__find_widget(app_name) is not None
|
|
else:
|
|
return False
|
|
|
|
def __update_group(self):
|
|
count = self.count()
|
|
self.__text.setVisible(not count)
|
|
self.__container.setVisible(bool(count))
|
|
self.update_count.emit(count)
|
|
|
|
def __create_widget(self, item: InstallQueueItemModel, old_igame: InstalledGame) -> QueueWidget:
|
|
widget: QueueWidget = QueueWidget(item, old_igame, parent=self.__container)
|
|
widget.toggle_arrows(self.__queue.index(item.options.app_name), len(self.__queue))
|
|
widget.destroyed.connect(self.__update_group)
|
|
widget.remove.connect(self.remove)
|
|
widget.force.connect(self.__on_force)
|
|
widget.move_up.connect(self.__on_move_up)
|
|
widget.move_down.connect(self.__on_move_down)
|
|
return widget
|
|
|
|
def push_front(self, item: InstallQueueItemModel, old_igame: InstalledGame):
|
|
self.__text.setVisible(False)
|
|
self.__container.setVisible(True)
|
|
self.__queue.appendleft(item.options.app_name)
|
|
widget = self.__create_widget(item, old_igame)
|
|
self.__container.layout().insertWidget(0, widget)
|
|
if self.count() > 1:
|
|
app_name = self.__queue[1]
|
|
other: QueueWidget = self.__find_widget(app_name)
|
|
other.toggle_arrows(1, len(self.__queue))
|
|
|
|
def push_back(self, item: InstallQueueItemModel, old_igame: InstalledGame):
|
|
self.__text.setVisible(False)
|
|
self.__container.setVisible(True)
|
|
self.__queue.append(item.download.game.app_name)
|
|
widget = self.__create_widget(item, old_igame)
|
|
self.__container.layout().addWidget(widget)
|
|
if self.count() > 1:
|
|
app_name = self.__queue[-2]
|
|
other: QueueWidget = self.__find_widget(app_name)
|
|
other.toggle_arrows(len(self.__queue) - 2, len(self.__queue))
|
|
|
|
def pop_front(self) -> InstallQueueItemModel:
|
|
app_name = self.__queue.popleft()
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
|
item = widget.item
|
|
widget.deleteLater()
|
|
return item
|
|
|
|
def __update_arrows(self):
|
|
"""
|
|
Check the first, second, last and second to last widgets in the list
|
|
and update their arrows
|
|
:return: None
|
|
"""
|
|
for idx in [0, 1]:
|
|
if self.count() > idx:
|
|
app_name = self.__queue[idx]
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
|
widget.toggle_arrows(idx, len(self.__queue))
|
|
for idx in [1, 2]:
|
|
if self.count() > idx:
|
|
app_name = self.__queue[-idx]
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
|
widget.toggle_arrows(len(self.__queue) - idx, len(self.__queue))
|
|
|
|
def __remove(self, app_name: str):
|
|
self.__queue.remove(app_name)
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
|
self.__container.layout().removeWidget(widget)
|
|
widget.deleteLater()
|
|
self.__update_arrows()
|
|
|
|
@pyqtSlot(str)
|
|
def remove(self, app_name: str):
|
|
self.__remove(app_name)
|
|
self.removed.emit(app_name)
|
|
|
|
@pyqtSlot(InstallQueueItemModel)
|
|
def __on_force(self, item: InstallQueueItemModel):
|
|
self.__remove(item.options.app_name)
|
|
self.force.emit(item)
|
|
|
|
class MoveDirection(IntEnum):
|
|
UP = -1
|
|
DOWN = 1
|
|
|
|
def __move(self, app_name: str, direction: MoveDirection):
|
|
"""
|
|
Moved the widget for `app_name` up or down in the queue and the container
|
|
:param app_name: The app_name associated with the widget
|
|
:param direction: -1 to move up, +1 to move down
|
|
:return: None
|
|
"""
|
|
index = self.__queue.index(app_name)
|
|
self.__queue.remove(app_name)
|
|
self.__queue.insert(index + int(direction), app_name)
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
|
self.__container.layout().insertWidget(index + int(direction), widget)
|
|
self.__update_arrows()
|
|
|
|
@pyqtSlot(str)
|
|
def __on_move_up(self, app_name: str):
|
|
self.__move(app_name, QueueGroup.MoveDirection.UP)
|
|
|
|
@pyqtSlot(str)
|
|
def __on_move_down(self, app_name: str):
|
|
self.__move(app_name, QueueGroup.MoveDirection.DOWN)
|