1
0
Fork 0
mirror of synced 2024-07-03 05:31:23 +12:00
Rare/rare/components/tabs/downloads/groups.py
loathingKernel 523391d166 QueueWidget: Prepare requeued downloads after adding it.
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.`
2023-02-04 17:38:07 +02:00

224 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)