1
0
Fork 0
mirror of synced 2024-10-03 02:37:12 +13:00
Rare/rare/components/tabs/downloads/groups.py
loathingKernel c523fa9210 UpdateGroup: Keep updates' app_names in a list too.
Because `deleteLater()` doesn't delete the widget immediately (duh!)
`count()` and `contains()` can report false results while the widget
is queued for deletion.

Hide container and list/queue by name mangling.

Remove test code.
2023-02-04 17:38:07 +02:00

228 lines
8.4 KiB
Python

from argparse import Namespace
from collections import deque
from enum import IntEnum
from logging import getLogger
from typing import Optional, List, Deque
from PyQt5.QtCore import pyqtSignal, pyqtSlot
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
logger = getLogger("QueueGroup")
class UpdateGroup(QGroupBox):
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)
self.__list: List[str] = []
@staticmethod
def __widget_name(app_name: str) -> str:
return f"UpdateWidget_{app_name}"
def __find_widget(self, app_name: str) -> Optional[UpdateWidget]:
return self.__container.findChild(UpdateWidget, name=self.__widget_name(app_name))
def count(self) -> int:
return len(self.__list)
def contains(self, app_name: str) -> bool:
if app_name in self.__list:
return self.__find_widget(app_name) is not None
else:
return False
def append(self, game: Game, igame: InstalledGame):
self.__text.setVisible(False)
self.__container.setVisible(True)
self.__list.append(game.app_name)
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.enqueue.connect(self.enqueue)
self.__container.layout().addWidget(widget)
def remove(self, app_name: str):
self.__list.remove(app_name)
widget: UpdateWidget = self.__find_widget(app_name)
self.__container.layout().removeWidget(widget)
widget.deleteLater()
self.__text.setVisible(not bool(self.count()))
self.__container.setVisible(bool(self.count()))
def set_widget_enabled(self, app_name: str, enabled: bool):
widget: UpdateWidget = self.__find_widget(app_name)
widget.set_enabled(enabled)
def get_update_version(self, app_name: str) -> str:
widget: UpdateWidget = self.__find_widget(app_name)
return widget.version()
class QueueGroup(QGroupBox):
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()
@staticmethod
def __widget_name(app_name:str) -> str:
return f"QueueWidget_{app_name}"
def __find_widget(self, app_name: str) -> Optional[QueueWidget]:
return self.__container.findChild(QueueWidget, name=self.__widget_name(app_name))
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 count(self) -> int:
return len(self.__queue)
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.download.game.app_name), len(self.__queue))
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.download.game.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()
self.__text.setVisible(not bool(self.count()))
self.__container.setVisible(bool(self.count()))
return item
def __update_queue(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_queue()
self.__text.setVisible(not bool(self.count()))
self.__container.setVisible(bool(self.count()))
@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_queue()
@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)