NinjaCheetah 62fa5ef7b1
Entirely rewrote title tree backend
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.
2024-12-13 22:39:09 -05:00

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)