Better style for uninstalled info; add raw json view
This commit is contained in:
parent
61fe881c1a
commit
530cff2a14
5 changed files with 396 additions and 24 deletions
|
@ -73,7 +73,7 @@ class TabWidget(QTabWidget):
|
|||
self.games_tab.game_info.dlc_tab.install_dlc.connect(self.start_download)
|
||||
|
||||
# install game
|
||||
self.games_tab.uninstalled_info_widget.install_button.clicked.connect(self.install_game)
|
||||
self.games_tab.uninstalled_info_widget.info.install_game.connect(self.install_game)
|
||||
|
||||
# repair game
|
||||
self.games_tab.game_info.info.verify_game.connect(lambda app_name: self.downloadTab.install_game(
|
||||
|
@ -88,8 +88,7 @@ class TabWidget(QTabWidget):
|
|||
self.tabBarClicked.connect(lambda x: self.games_tab.layout.setCurrentIndex(0) if x == 0 else None)
|
||||
self.setIconSize(QSize(25, 25))
|
||||
|
||||
def install_game(self):
|
||||
app_name = self.games_tab.uninstalled_info_widget.game.app_name
|
||||
def install_game(self, app_name):
|
||||
infos = InstallDialog(app_name, self.core).get_information()
|
||||
if infos != 0:
|
||||
path, max_workers, force, ignore_free_space = infos
|
||||
|
|
|
@ -3,7 +3,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QLineE
|
|||
from qtawesome import icon
|
||||
|
||||
from rare.components.tabs.games.game_info import InfoTabs
|
||||
from rare.components.tabs.games.game_info.uninstalled_info import UninstalledInfo
|
||||
from rare.components.tabs.games.game_info.uninstalled_info import UninstalledInfo, UninstalledTabInfo
|
||||
from rare.components.tabs.games.game_list import GameList
|
||||
from rare.components.tabs.games.import_widget import ImportWidget
|
||||
from rare.utils.extra_widgets import SelectViewWidget
|
||||
|
@ -30,9 +30,9 @@ class GameTab(QWidget):
|
|||
self.import_widget.back_button.clicked.connect(lambda: self.layout.setCurrentIndex(0))
|
||||
self.import_widget.update_list.connect(self.update_list)
|
||||
|
||||
self.uninstalled_info_widget = UninstalledInfo(core)
|
||||
self.uninstalled_info_widget = UninstalledTabInfo(core, self)
|
||||
self.layout.addWidget(self.uninstalled_info_widget)
|
||||
self.uninstalled_info_widget.back.clicked.connect(lambda: self.layout.setCurrentIndex(0))
|
||||
# self.uninstalled_info_widget.back.clicked.connect(lambda: self.layout.setCurrentIndex(0))
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
|
@ -42,6 +42,7 @@ class GameTab(QWidget):
|
|||
|
||||
def show_uninstalled(self, app_name):
|
||||
self.uninstalled_info_widget.update_game(app_name)
|
||||
self.uninstalled_info_widget.setCurrentIndex(1)
|
||||
self.layout.setCurrentIndex(3)
|
||||
|
||||
def show_info(self, app_name):
|
||||
|
|
|
@ -1,12 +1,52 @@
|
|||
import os
|
||||
import json
|
||||
import os
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QSettings
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel
|
||||
from PyQt5.QtCore import pyqtSignal, QSettings, Qt
|
||||
from PyQt5.QtGui import QPixmap, QKeyEvent
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTabWidget, QTreeView
|
||||
from qtawesome import icon
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import Game
|
||||
from rare.utils.extra_widgets import SideTabBar
|
||||
from rare.utils.json_formatter import QJsonModel
|
||||
|
||||
|
||||
class UninstalledTabInfo(QTabWidget):
|
||||
def __init__(self, core, parent):
|
||||
super(UninstalledTabInfo, self).__init__(parent=parent)
|
||||
self.app_name = ""
|
||||
self.core = core
|
||||
self.setTabBar(SideTabBar())
|
||||
|
||||
self.setTabPosition(QTabWidget.West)
|
||||
|
||||
self.addTab(QWidget(), icon("mdi.keyboard-backspace", color="white"), self.tr("Back"))
|
||||
self.tabBarClicked.connect(lambda x: self.parent().layout.setCurrentIndex(0) if x == 0 else None)
|
||||
|
||||
self.info = UninstalledInfo(core, self)
|
||||
self.addTab(self.info, self.tr("Game Info"))
|
||||
|
||||
self.view = QTreeView()
|
||||
self.view.setColumnWidth(0, 300)
|
||||
self.view.setWordWrap(True)
|
||||
|
||||
self.model = QJsonModel()
|
||||
self.view.setModel(self.model)
|
||||
|
||||
self.addTab(self.view, self.tr("Metadata"))
|
||||
|
||||
# self.setTabEnabled(1, False)
|
||||
self.setCurrentIndex(1)
|
||||
|
||||
def update_game(self, app_name):
|
||||
self.info.update_game(app_name)
|
||||
self.model.clear()
|
||||
self.model.load(json.load(open(os.path.expanduser(f"~/.config/legendary/metadata/{app_name}.json"), "r")))
|
||||
|
||||
def keyPressEvent(self, e: QKeyEvent):
|
||||
if e.key() == Qt.Key_Escape:
|
||||
self.parent().layout.setCurrentIndex(0)
|
||||
|
||||
|
||||
class UninstalledInfo(QWidget):
|
||||
|
@ -15,11 +55,11 @@ class UninstalledInfo(QWidget):
|
|||
|
||||
grade_table = json.load(open(os.path.expanduser("~/.cache/rare/game_list.json")))
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(UninstalledInfo, self).__init__()
|
||||
def __init__(self, core: LegendaryCore, parent):
|
||||
super(UninstalledInfo, self).__init__(parent=parent)
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
self.ratings = {"platinum": self.tr("Platimum"),
|
||||
self.ratings = {"platinum": self.tr("Platinum"),
|
||||
"gold": self.tr("Gold"),
|
||||
"silver": self.tr("Silver"),
|
||||
"bronze": self.tr("Bronze"),
|
||||
|
@ -38,9 +78,6 @@ class UninstalledInfo(QWidget):
|
|||
self.top_layout.addLayout(left_layout)
|
||||
self.right_layout = QVBoxLayout()
|
||||
|
||||
self.back = QPushButton(self.tr("Back"))
|
||||
self.right_layout.addWidget(self.back)
|
||||
|
||||
self.title = QLabel("Error")
|
||||
self.right_layout.addWidget(self.title)
|
||||
|
||||
|
@ -51,7 +88,12 @@ class UninstalledInfo(QWidget):
|
|||
self.right_layout.addWidget(self.rating)
|
||||
|
||||
self.install_button = QPushButton(self.tr("Install"))
|
||||
self.install_button.setFixedWidth(300)
|
||||
self.install_button.setStyleSheet("""background-color: #090""")
|
||||
self.install_button.clicked.connect(lambda: self.install_game.emit(self.game.app_name))
|
||||
self.right_layout.addWidget(self.install_button)
|
||||
self.version = QLabel("Error")
|
||||
self.right_layout.addWidget(self.version)
|
||||
|
||||
self.right_layout.addStretch(1)
|
||||
self.top_layout.addLayout(self.right_layout)
|
||||
|
@ -65,7 +107,7 @@ class UninstalledInfo(QWidget):
|
|||
self.game = self.core.get_game(app_name)
|
||||
|
||||
self.title.setText(f"<h2>{self.game.app_title}</h2>")
|
||||
self.app_name.setText(app_name)
|
||||
self.app_name.setText("Appname: " + app_name)
|
||||
|
||||
IMAGE_DIR = self.settings.value("img_dir", os.path.expanduser("~/.cache/rare/images"), str)
|
||||
|
||||
|
@ -83,6 +125,10 @@ class UninstalledInfo(QWidget):
|
|||
pixmap = pixmap.scaled(w, int(w * 4 / 3))
|
||||
self.image.setPixmap(pixmap)
|
||||
|
||||
rating = self.grade_table[app_name]["grade"]
|
||||
self.rating.setText(self.ratings[rating])
|
||||
self.version.setText(self.game.asset_info.build_version)
|
||||
|
||||
rating = self.grade_table[app_name]["grade"]
|
||||
if rating not in ["fail", "pending"]:
|
||||
self.rating.setText(self.tr("Rating from ProtonDB: ") + self.ratings[rating])
|
||||
else:
|
||||
self.rating.setText(self.ratings[rating])
|
||||
|
|
|
@ -58,11 +58,6 @@ QGroupBox#group {
|
|||
padding: 8px;
|
||||
}
|
||||
|
||||
QTabBar::tab:disabled {
|
||||
color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
QToolButton {
|
||||
padding: 6px;
|
||||
|
@ -142,6 +137,11 @@ QTabBar::tab::selected#settings_bar {
|
|||
background-color: #334;
|
||||
}
|
||||
|
||||
QTabBar::tab:disabled#settings_bar {
|
||||
color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/*
|
||||
QScrollBar:vertical{
|
||||
border: 1px solid white;
|
||||
|
|
326
rare/utils/json_formatter.py
Normal file
326
rare/utils/json_formatter.py
Normal file
|
@ -0,0 +1,326 @@
|
|||
"""Python adaptation of https://github.com/dridk/QJsonModel
|
||||
|
||||
Supports Python 2 and 3 with PySide, PySide2, PyQt4 or PyQt5.
|
||||
Requires https://github.com/mottosso/Qt.py
|
||||
|
||||
Usage:
|
||||
Use it like you would the C++ version.
|
||||
|
||||
>>> import qjsonmodel
|
||||
>>> model = qjsonmodel.QJsonModel()
|
||||
>>> model.load({"key": "value"})
|
||||
|
||||
Test:
|
||||
Run the provided example to sanity check your Python,
|
||||
dependencies and Qt binding.
|
||||
|
||||
$ python qjsonmodel.py
|
||||
|
||||
Changes:
|
||||
This module differs from the C++ version in the following ways.
|
||||
|
||||
1. Setters and getters are replaced by Python properties
|
||||
2. Objects are sorted by default, disabled via load(sort=False)
|
||||
3. load() takes a Python dictionary as opposed to
|
||||
a string or file handle.
|
||||
|
||||
- To load from a string, use built-in `json.loads()`
|
||||
>>> import json
|
||||
>>> document = json.loads("{'key': 'value'}")
|
||||
>>> model.load(document)
|
||||
|
||||
- To load from a file, use `with open(fname)`
|
||||
>>> import json
|
||||
>>> with open("file.json") as f:
|
||||
... document = json.load(f)
|
||||
... model.load(document)
|
||||
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
|
||||
class QJsonTreeItem(object):
|
||||
def __init__(self, parent=None):
|
||||
self._parent = parent
|
||||
|
||||
self._key = ""
|
||||
self._value = ""
|
||||
self._type = None
|
||||
self._children = list()
|
||||
|
||||
def appendChild(self, item):
|
||||
self._children.append(item)
|
||||
|
||||
def child(self, row):
|
||||
return self._children[row]
|
||||
|
||||
def parent(self):
|
||||
return self._parent
|
||||
|
||||
def childCount(self):
|
||||
return len(self._children)
|
||||
|
||||
def row(self):
|
||||
return (
|
||||
self._parent._children.index(self)
|
||||
if self._parent else 0
|
||||
)
|
||||
|
||||
@property
|
||||
def key(self):
|
||||
return self._key
|
||||
|
||||
@key.setter
|
||||
def key(self, key):
|
||||
self._key = key
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self, value):
|
||||
self._value = value
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@type.setter
|
||||
def type(self, typ):
|
||||
self._type = typ
|
||||
|
||||
@classmethod
|
||||
def load(self, value, parent=None, sort=True):
|
||||
rootItem = QJsonTreeItem(parent)
|
||||
rootItem.key = "root"
|
||||
|
||||
if isinstance(value, dict):
|
||||
items = (
|
||||
sorted(value.items())
|
||||
if sort else value.items()
|
||||
)
|
||||
|
||||
for key, value in items:
|
||||
child = self.load(value, rootItem)
|
||||
child.key = key
|
||||
child.type = type(value)
|
||||
rootItem.appendChild(child)
|
||||
|
||||
elif isinstance(value, list):
|
||||
for index, value in enumerate(value):
|
||||
child = self.load(value, rootItem)
|
||||
child.key = index
|
||||
child.type = type(value)
|
||||
rootItem.appendChild(child)
|
||||
|
||||
else:
|
||||
rootItem.value = value
|
||||
rootItem.type = type(value)
|
||||
|
||||
return rootItem
|
||||
|
||||
|
||||
class QJsonModel(QtCore.QAbstractItemModel):
|
||||
def __init__(self, parent=None):
|
||||
super(QJsonModel, self).__init__(parent)
|
||||
|
||||
self._rootItem = QJsonTreeItem()
|
||||
self._headers = ("key", "value")
|
||||
|
||||
def clear(self):
|
||||
self.load({})
|
||||
|
||||
def load(self, document):
|
||||
"""Load from dictionary
|
||||
|
||||
Arguments:
|
||||
document (dict): JSON-compatible dictionary
|
||||
|
||||
"""
|
||||
|
||||
assert isinstance(document, (dict, list, tuple)), (
|
||||
"`document` must be of dict, list or tuple, "
|
||||
"not %s" % type(document)
|
||||
)
|
||||
|
||||
self.beginResetModel()
|
||||
|
||||
self._rootItem = QJsonTreeItem.load(document)
|
||||
self._rootItem.type = type(document)
|
||||
|
||||
self.endResetModel()
|
||||
|
||||
return True
|
||||
|
||||
def json(self, root=None):
|
||||
"""Serialise model as JSON-compliant dictionary
|
||||
|
||||
Arguments:
|
||||
root (QJsonTreeItem, optional): Serialise from here
|
||||
defaults to the the top-level item
|
||||
|
||||
Returns:
|
||||
model as dict
|
||||
|
||||
"""
|
||||
|
||||
root = root or self._rootItem
|
||||
return self.genJson(root)
|
||||
|
||||
def data(self, index, role):
|
||||
if not index.isValid():
|
||||
return None
|
||||
|
||||
item = index.internalPointer()
|
||||
|
||||
if role == QtCore.Qt.DisplayRole:
|
||||
if index.column() == 0:
|
||||
return item.key
|
||||
|
||||
if index.column() == 1:
|
||||
return item.value
|
||||
|
||||
elif role == QtCore.Qt.EditRole:
|
||||
if index.column() == 1:
|
||||
return item.value
|
||||
|
||||
def setData(self, index, value, role):
|
||||
if role == QtCore.Qt.EditRole:
|
||||
if index.column() == 1:
|
||||
item = index.internalPointer()
|
||||
item.value = str(value)
|
||||
|
||||
|
||||
self.dataChanged.emit(index, index, [QtCore.Qt.EditRole])
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
if role != QtCore.Qt.DisplayRole:
|
||||
return None
|
||||
|
||||
if orientation == QtCore.Qt.Horizontal:
|
||||
return self._headers[section]
|
||||
|
||||
def index(self, row, column, parent=QtCore.QModelIndex()):
|
||||
if not self.hasIndex(row, column, parent):
|
||||
return QtCore.QModelIndex()
|
||||
|
||||
if not parent.isValid():
|
||||
parentItem = self._rootItem
|
||||
else:
|
||||
parentItem = parent.internalPointer()
|
||||
|
||||
childItem = parentItem.child(row)
|
||||
if childItem:
|
||||
return self.createIndex(row, column, childItem)
|
||||
else:
|
||||
return QtCore.QModelIndex()
|
||||
|
||||
def parent(self, index):
|
||||
if not index.isValid():
|
||||
return QtCore.QModelIndex()
|
||||
|
||||
childItem = index.internalPointer()
|
||||
parentItem = childItem.parent()
|
||||
|
||||
if parentItem == self._rootItem:
|
||||
return QtCore.QModelIndex()
|
||||
|
||||
return self.createIndex(parentItem.row(), 0, parentItem)
|
||||
|
||||
def rowCount(self, parent=QtCore.QModelIndex()):
|
||||
if parent.column() > 0:
|
||||
return 0
|
||||
|
||||
if not parent.isValid():
|
||||
parentItem = self._rootItem
|
||||
else:
|
||||
parentItem = parent.internalPointer()
|
||||
|
||||
return parentItem.childCount()
|
||||
|
||||
def columnCount(self, parent=QtCore.QModelIndex()):
|
||||
return 2
|
||||
|
||||
def flags(self, index):
|
||||
flags = super(QJsonModel, self).flags(index)
|
||||
|
||||
if index.column() == 1:
|
||||
return QtCore.Qt.ItemIsEditable | flags
|
||||
else:
|
||||
return flags
|
||||
|
||||
def genJson(self, item):
|
||||
nchild = item.childCount()
|
||||
|
||||
if item.type is dict:
|
||||
document = {}
|
||||
for i in range(nchild):
|
||||
ch = item.child(i)
|
||||
document[ch.key] = self.genJson(ch)
|
||||
return document
|
||||
|
||||
elif item.type == list:
|
||||
document = []
|
||||
for i in range(nchild):
|
||||
ch = item.child(i)
|
||||
document.append(self.genJson(ch))
|
||||
return document
|
||||
|
||||
else:
|
||||
return item.value
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
view = QtWidgets.QTreeView()
|
||||
model = QJsonModel()
|
||||
|
||||
view.setModel(model)
|
||||
|
||||
document = json.loads("""\
|
||||
{
|
||||
"firstName": "John",
|
||||
"lastName": "Smith",
|
||||
"age": 25,
|
||||
"address": {
|
||||
"streetAddress": "21 2nd Street",
|
||||
"city": "New York",
|
||||
"state": "NY",
|
||||
"postalCode": "10021"
|
||||
},
|
||||
"phoneNumber": [
|
||||
{
|
||||
"type": "home",
|
||||
"number": "212 555-1234"
|
||||
},
|
||||
{
|
||||
"type": "fax",
|
||||
"number": "646 555-4567"
|
||||
}
|
||||
]
|
||||
}
|
||||
""")
|
||||
|
||||
model.load(document)
|
||||
model.clear()
|
||||
model.load(document)
|
||||
|
||||
# Sanity check
|
||||
assert (
|
||||
json.dumps(model.json(), sort_keys=True) ==
|
||||
json.dumps(document, sort_keys=True)
|
||||
)
|
||||
|
||||
view.show()
|
||||
view.resize(500, 300)
|
||||
app.exec_()
|
Loading…
Reference in a new issue