mirror of
https://github.com/NinjaCheetah/NUSGet.git
synced 2025-04-25 15:11:02 -04:00
Title trees are now model-based rather than item based. Coming with this is proper item metadata, so the data and UI are finally disconnected, making future development much easier. There are also some minor visual improvements as a result of using a TreeView instead of a TreeWidget. vWii System Menus now have public versions defined in the database. Public version display code has also been entirely rewritten, as the version displayed in the interface and the version used by the code are no longer the same.
137 lines
5.2 KiB
Python
137 lines
5.2 KiB
Python
# "modules/tree.py", licensed under the MIT license
|
|
# Copyright 2024 NinjaCheetah
|
|
|
|
from modules.core import TitleData
|
|
from PySide6.QtCore import QAbstractItemModel, QModelIndex, Qt
|
|
from PySide6.QtGui import QIcon
|
|
|
|
|
|
class TreeItem:
|
|
def __init__(self, data, parent=None, metadata=None):
|
|
self.data = data
|
|
self.parent = parent
|
|
self.children = []
|
|
self.metadata = metadata # Store hidden metadata
|
|
|
|
def add_child(self, item):
|
|
self.children.append(item)
|
|
|
|
def child(self, row):
|
|
return self.children[row]
|
|
|
|
def child_count(self):
|
|
return len(self.children)
|
|
|
|
def column_count(self):
|
|
return len(self.data)
|
|
|
|
def data_at(self, column):
|
|
if 0 <= column < len(self.data):
|
|
return self.data[column]
|
|
return None
|
|
|
|
def row(self):
|
|
if self.parent:
|
|
return self.parent.children.index(self)
|
|
return 0
|
|
|
|
|
|
class NUSGetTreeModel(QAbstractItemModel):
|
|
def __init__(self, data, parent=None, root_name=""):
|
|
super().__init__(parent)
|
|
self.root_item = TreeItem([root_name])
|
|
self.setup_model_data(data, self.root_item)
|
|
|
|
def setup_model_data(self, title, parent):
|
|
if isinstance(title, dict):
|
|
for key, value in title.items():
|
|
if isinstance(value, list):
|
|
key_item = TreeItem([key, ""], parent)
|
|
parent.add_child(key_item)
|
|
for entry in value:
|
|
tid = entry.get("TID")
|
|
name = entry.get("Name")
|
|
versions = entry.get("Versions", {})
|
|
if tid:
|
|
tid_item = TreeItem([f"{tid} - {name}", ""], key_item)
|
|
key_item.add_child(tid_item)
|
|
for region, version_list in versions.items():
|
|
region_item = TreeItem([region, ""], tid_item)
|
|
tid_item.add_child(region_item)
|
|
for version in version_list:
|
|
danger = entry.get("Danger") if entry.get("Danger") is not None else ""
|
|
metadata = TitleData(entry.get("TID"), entry.get("Name"), entry.get("Archive Name"),
|
|
version, entry.get("Ticket"), region, key, danger)
|
|
public_versions = entry.get("Public Versions")
|
|
if public_versions is not None:
|
|
try:
|
|
public_ver = public_versions[str(version)]
|
|
version_str = f"v{version} ({public_ver})"
|
|
except KeyError:
|
|
version_str = f"v{version}"
|
|
else:
|
|
version_str = f"v{version}"
|
|
version_item = TreeItem([version_str, ""], region_item, metadata)
|
|
region_item.add_child(version_item)
|
|
|
|
def rowCount(self, parent=QModelIndex()):
|
|
if parent.isValid():
|
|
parent_item = parent.internalPointer()
|
|
else:
|
|
parent_item = self.root_item
|
|
return parent_item.child_count()
|
|
|
|
def columnCount(self, parent=QModelIndex()):
|
|
return self.root_item.column_count()
|
|
|
|
def data(self, index, role=Qt.DisplayRole):
|
|
if not index.isValid():
|
|
return None
|
|
|
|
item = index.internalPointer()
|
|
|
|
if role == Qt.DisplayRole:
|
|
item = index.internalPointer()
|
|
return item.data_at(index.column())
|
|
|
|
if role == Qt.DecorationRole and index.column() == 0:
|
|
# Check for icons based on the "Ticket" metadata only at the TID level
|
|
if item.parent and item.parent.data_at(0) == "System":
|
|
if item.metadata and "Ticket" in item.metadata:
|
|
if item.metadata["Ticket"]:
|
|
return QIcon.fromTheme("dialog-ok") # Checkmark icon
|
|
else:
|
|
return QIcon.fromTheme("dialog-cancel") # X icon
|
|
return None
|
|
|
|
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
|
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
|
return self.root_item.data_at(section)
|
|
return None
|
|
|
|
def index(self, row, column, parent=QModelIndex()):
|
|
if not self.hasIndex(row, column, parent):
|
|
return QModelIndex()
|
|
|
|
if not parent.isValid():
|
|
parent_item = self.root_item
|
|
else:
|
|
parent_item = parent.internalPointer()
|
|
|
|
child_item = parent_item.child(row)
|
|
if child_item:
|
|
return self.createIndex(row, column, child_item)
|
|
return QModelIndex()
|
|
|
|
def parent(self, index):
|
|
if not index.isValid():
|
|
return QModelIndex()
|
|
|
|
child_item = index.internalPointer()
|
|
parent_item = child_item.parent
|
|
|
|
if parent_item == self.root_item:
|
|
return QModelIndex()
|
|
|
|
return self.createIndex(parent_item.row(), 0, parent_item)
|