2023-01-21 13:15:06 +13:00
|
|
|
from collections import deque
|
|
|
|
from enum import IntEnum
|
|
|
|
from logging import getLogger
|
2023-02-19 04:27:18 +13:00
|
|
|
from typing import Optional, Deque
|
2023-01-21 13:15:06 +13:00
|
|
|
|
2023-01-27 03:14:21 +13:00
|
|
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt
|
2023-01-21 13:15:06 +13:00
|
|
|
from PyQt5.QtWidgets import (
|
2023-01-26 00:51:36 +13:00
|
|
|
QWidget,
|
2023-01-21 13:15:06 +13:00
|
|
|
QGroupBox,
|
|
|
|
QVBoxLayout,
|
2023-01-26 00:51:36 +13:00
|
|
|
QLabel,
|
|
|
|
QSizePolicy,
|
2023-01-21 13:15:06 +13:00
|
|
|
)
|
|
|
|
from legendary.models.game import Game, InstalledGame
|
|
|
|
|
|
|
|
from rare.components.tabs.downloads.widgets import QueueWidget, UpdateWidget
|
|
|
|
from rare.models.install import InstallOptionsModel, InstallQueueItemModel
|
2023-01-27 03:14:21 +13:00
|
|
|
from rare.utils.misc import widget_object_name
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
logger = getLogger("QueueGroup")
|
|
|
|
|
|
|
|
|
|
|
|
class UpdateGroup(QGroupBox):
|
2023-01-27 04:38:50 +13:00
|
|
|
update_count = pyqtSignal(int)
|
2023-01-21 13:15:06 +13:00
|
|
|
enqueue = pyqtSignal(InstallOptionsModel)
|
|
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
super(UpdateGroup, self).__init__(parent=parent)
|
|
|
|
self.setObjectName(type(self).__name__)
|
|
|
|
self.setTitle(self.tr("Updates"))
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__text = QLabel(self.tr("No updates available"))
|
|
|
|
self.__text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
2023-02-20 22:32:48 +13:00
|
|
|
# lk: For findChildren to work, the update's layout has to be in a widget
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container = QWidget(self)
|
2023-02-06 06:41:08 +13:00
|
|
|
self.__container.setVisible(False)
|
|
|
|
container_layout = QVBoxLayout(self.__container)
|
|
|
|
container_layout.setContentsMargins(0, 0, 0, 0)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
2023-02-06 06:41:08 +13:00
|
|
|
layout = QVBoxLayout(self)
|
|
|
|
layout.addWidget(self.__text)
|
|
|
|
layout.addWidget(self.__container)
|
2023-01-26 00:51:36 +13:00
|
|
|
|
2023-01-21 13:15:06 +13:00
|
|
|
def __find_widget(self, app_name: str) -> Optional[UpdateWidget]:
|
2023-01-27 03:14:21 +13:00
|
|
|
return self.__container.findChild(UpdateWidget, name=widget_object_name(UpdateWidget, app_name))
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def count(self) -> int:
|
2023-01-27 03:14:21 +13:00
|
|
|
return len(self.__container.findChildren(UpdateWidget, options=Qt.FindDirectChildrenOnly))
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def contains(self, app_name: str) -> bool:
|
2023-01-27 03:14:21 +13:00
|
|
|
return self.__find_widget(app_name) is not None
|
|
|
|
|
|
|
|
def __update_group(self):
|
2023-01-27 04:38:50 +13:00
|
|
|
count = self.count()
|
|
|
|
self.__text.setVisible(not count)
|
|
|
|
self.__container.setVisible(bool(count))
|
|
|
|
self.update_count.emit(count)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def append(self, game: Game, igame: InstalledGame):
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__text.setVisible(False)
|
|
|
|
self.__container.setVisible(True)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget: UpdateWidget = self.__find_widget(game.app_name)
|
|
|
|
if widget is not None:
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container.layout().removeWidget(widget)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget.deleteLater()
|
2023-01-26 00:51:36 +13:00
|
|
|
widget = UpdateWidget(game, igame, parent=self.__container)
|
2023-01-27 03:14:21 +13:00
|
|
|
widget.destroyed.connect(self.__update_group)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget.enqueue.connect(self.enqueue)
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container.layout().addWidget(widget)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def remove(self, app_name: str):
|
|
|
|
widget: UpdateWidget = self.__find_widget(app_name)
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container.layout().removeWidget(widget)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget.deleteLater()
|
|
|
|
|
|
|
|
def set_widget_enabled(self, app_name: str, enabled: bool):
|
|
|
|
widget: UpdateWidget = self.__find_widget(app_name)
|
|
|
|
widget.set_enabled(enabled)
|
|
|
|
|
2023-01-27 03:14:21 +13:00
|
|
|
def get_widget_version(self, app_name: str) -> str:
|
2023-01-21 13:15:06 +13:00
|
|
|
widget: UpdateWidget = self.__find_widget(app_name)
|
|
|
|
return widget.version()
|
|
|
|
|
|
|
|
|
|
|
|
class QueueGroup(QGroupBox):
|
2023-01-27 04:38:50 +13:00
|
|
|
update_count = pyqtSignal(int)
|
2023-01-21 13:15:06 +13:00
|
|
|
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"))
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__text = QLabel(self.tr("No downloads in queue"), self)
|
|
|
|
self.__text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
# lk: For findChildren to work, the queue's layout has to be in a widget
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container = QWidget(self)
|
|
|
|
self.__container.setVisible(False)
|
2023-02-06 06:41:08 +13:00
|
|
|
container_layout = QVBoxLayout(self.__container)
|
|
|
|
container_layout.setContentsMargins(0, 0, 0, 0)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
2023-02-06 06:41:08 +13:00
|
|
|
layout = QVBoxLayout(self)
|
|
|
|
layout.addWidget(self.__text)
|
|
|
|
layout.addWidget(self.__container)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__queue: Deque[str] = deque()
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def __find_widget(self, app_name: str) -> Optional[QueueWidget]:
|
2023-01-27 03:14:21 +13:00
|
|
|
return self.__container.findChild(QueueWidget, name=widget_object_name(QueueWidget, app_name))
|
|
|
|
|
|
|
|
def count(self) -> int:
|
|
|
|
return len(self.__queue)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def contains(self, app_name: str) -> bool:
|
2023-01-26 00:51:36 +13:00
|
|
|
if app_name in self.__queue:
|
2023-01-27 03:14:21 +13:00
|
|
|
return self.__find_widget(app_name) is not None
|
2023-01-26 00:51:36 +13:00
|
|
|
else:
|
|
|
|
return False
|
2023-01-21 13:15:06 +13:00
|
|
|
|
2023-01-27 03:14:21 +13:00
|
|
|
def __update_group(self):
|
2023-01-27 04:38:50 +13:00
|
|
|
count = self.count()
|
|
|
|
self.__text.setVisible(not count)
|
|
|
|
self.__container.setVisible(bool(count))
|
|
|
|
self.update_count.emit(count)
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def __create_widget(self, item: InstallQueueItemModel, old_igame: InstalledGame) -> QueueWidget:
|
2023-01-26 00:51:36 +13:00
|
|
|
widget: QueueWidget = QueueWidget(item, old_igame, parent=self.__container)
|
2023-01-27 09:03:38 +13:00
|
|
|
widget.toggle_arrows(self.__queue.index(item.options.app_name), len(self.__queue))
|
2023-01-27 03:14:21 +13:00
|
|
|
widget.destroyed.connect(self.__update_group)
|
2023-02-04 10:53:30 +13:00
|
|
|
widget.destroyed.connect(self.__update_arrows)
|
2023-01-21 13:15:06 +13:00
|
|
|
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):
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__text.setVisible(False)
|
|
|
|
self.__container.setVisible(True)
|
2023-01-27 09:03:38 +13:00
|
|
|
self.__queue.appendleft(item.options.app_name)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget = self.__create_widget(item, old_igame)
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container.layout().insertWidget(0, widget)
|
2023-01-21 13:15:06 +13:00
|
|
|
if self.count() > 1:
|
2023-01-26 00:51:36 +13:00
|
|
|
app_name = self.__queue[1]
|
2023-02-21 02:31:04 +13:00
|
|
|
other: QueueWidget = self.__find_widget(app_name)
|
2023-01-26 00:51:36 +13:00
|
|
|
other.toggle_arrows(1, len(self.__queue))
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def push_back(self, item: InstallQueueItemModel, old_igame: InstalledGame):
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__text.setVisible(False)
|
|
|
|
self.__container.setVisible(True)
|
|
|
|
self.__queue.append(item.download.game.app_name)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget = self.__create_widget(item, old_igame)
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container.layout().addWidget(widget)
|
2023-01-21 13:15:06 +13:00
|
|
|
if self.count() > 1:
|
2023-01-26 00:51:36 +13:00
|
|
|
app_name = self.__queue[-2]
|
2023-02-21 02:31:04 +13:00
|
|
|
other: QueueWidget = self.__find_widget(app_name)
|
2023-01-26 00:51:36 +13:00
|
|
|
other.toggle_arrows(len(self.__queue) - 2, len(self.__queue))
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def pop_front(self) -> InstallQueueItemModel:
|
2023-01-26 00:51:36 +13:00
|
|
|
app_name = self.__queue.popleft()
|
2023-01-21 13:15:06 +13:00
|
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
|
|
|
item = widget.item
|
|
|
|
widget.deleteLater()
|
|
|
|
return item
|
|
|
|
|
2023-01-27 03:14:21 +13:00
|
|
|
def __update_arrows(self):
|
2023-01-21 13:15:06 +13:00
|
|
|
"""
|
2023-01-27 03:14:21 +13:00
|
|
|
Check the first, second, last and second to last widgets in the list
|
2023-01-21 13:15:06 +13:00
|
|
|
and update their arrows
|
|
|
|
:return: None
|
|
|
|
"""
|
|
|
|
for idx in [0, 1]:
|
|
|
|
if self.count() > idx:
|
2023-01-26 00:51:36 +13:00
|
|
|
app_name = self.__queue[idx]
|
2023-02-21 02:31:04 +13:00
|
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
2023-01-26 00:51:36 +13:00
|
|
|
widget.toggle_arrows(idx, len(self.__queue))
|
2023-01-21 13:15:06 +13:00
|
|
|
for idx in [1, 2]:
|
|
|
|
if self.count() > idx:
|
2023-01-26 00:51:36 +13:00
|
|
|
app_name = self.__queue[-idx]
|
2023-02-21 02:31:04 +13:00
|
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
2023-01-26 00:51:36 +13:00
|
|
|
widget.toggle_arrows(len(self.__queue) - idx, len(self.__queue))
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
def __remove(self, app_name: str):
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__queue.remove(app_name)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container.layout().removeWidget(widget)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget.deleteLater()
|
|
|
|
|
|
|
|
@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
|
|
|
|
"""
|
2023-01-26 00:51:36 +13:00
|
|
|
index = self.__queue.index(app_name)
|
|
|
|
self.__queue.remove(app_name)
|
|
|
|
self.__queue.insert(index + int(direction), app_name)
|
2023-01-21 13:15:06 +13:00
|
|
|
widget: QueueWidget = self.__find_widget(app_name)
|
2023-01-26 00:51:36 +13:00
|
|
|
self.__container.layout().insertWidget(index + int(direction), widget)
|
2023-01-27 03:14:21 +13:00
|
|
|
self.__update_arrows()
|
2023-01-21 13:15:06 +13:00
|
|
|
|
|
|
|
@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)
|