From ff5c3bf684b9acb865ec8d41d3c0946584b75789 Mon Sep 17 00:00:00 2001 From: Nils <> Date: Sun, 12 Jul 2020 18:30:20 +0200 Subject: [PATCH] Better icon routine --- engine/findicons.py | 13 +++++++++++-- engine/findprograms.py | 16 ++++++++++++++++ qtgui/mainwindow.py | 19 ++++++++++++------- qtgui/opensessioncontroller.py | 24 +++++++++++++++++++----- 4 files changed, 58 insertions(+), 14 deletions(-) diff --git a/engine/findicons.py b/engine/findicons.py index 08fd319..059d5b9 100644 --- a/engine/findicons.py +++ b/engine/findicons.py @@ -86,7 +86,11 @@ def _buildCache()->set: return set(result) -_cache = _buildCache() +global _cache +_cache = None +def updateCache(): + global _cache + _cache = _buildCache() rePattern = re.compile("\d+x\d+") #we don't put .* around this because we are searching for the subpattern @@ -97,7 +101,8 @@ def findIconPath(executableName:str)->list: It is not guaranteed that [1], or even [0] exists. This is not a sorted list, these extra variants are just added to the front of the list again""" - executableName = executableName.lower() + if not _cache: + raise ValueError("You need to call updateCache() first") svg = None bestr = 0 #resolution @@ -124,9 +129,13 @@ def findIconPath(executableName:str)->list: return result +updateCache() + if __name__ == "__main__": """Example that tries to find a few icons""" + updateCache() + print("Search paths:") print(SEARCH_DIRECTORIES) print() diff --git a/engine/findprograms.py b/engine/findprograms.py index 50dc73a..9d10a45 100644 --- a/engine/findprograms.py +++ b/engine/findprograms.py @@ -28,6 +28,7 @@ import os import stat from engine.start import PATHS +import engine.findicons as findicons def nothing(*args): pass @@ -57,6 +58,9 @@ class SupportedProgramsDatabase(object): In case there is a file in PATH or database but has no .desktop we create our own entry with missing data. + We add two keys ourselves: + "argodejoExec" : this is the one we will send to nsmd. + "argodejoIconPath" : absolute path as str if we found an icon, so that a GUI does need to search on its own """ def __init__(self): @@ -206,6 +210,8 @@ class SupportedProgramsDatabase(object): def _build(self): self.executables = self.buildCache_grepExecutablePaths() self.desktopEntries = self.buildCache_DesktopEntries() + findicons.updateCache() + leftovers = set(self.executables) matches = [] #list of dicts @@ -216,6 +222,16 @@ class SupportedProgramsDatabase(object): entry["argodejoFullPath"] = fullPath #We don't want .desktop syntax like "qmidiarp %F" entry["argodejoExec"] = exe + + if entry["icon"]: + foundIcon = findicons.findIconPath(entry["icon"]) + else: + foundIcon = findicons.findIconPath(entry["argodejoExec"]) + if foundIcon: + entry["argodejoIconPath"] = str(foundIcon[0]) #pick best resolution + else: + entry["argodejoIconPath"] = None + matches.append(entry) try: diff --git a/qtgui/mainwindow.py b/qtgui/mainwindow.py index 22821b2..7da5da8 100644 --- a/qtgui/mainwindow.py +++ b/qtgui/mainwindow.py @@ -253,16 +253,21 @@ class MainWindow(QtWidgets.QMainWindow): self.programIcons.clear() for entry in programs: exe = entry["argodejoExec"] - if "icon" in entry: - icon = QtGui.QIcon.fromTheme(entry["icon"]) + + if "argodejoIconPath" in entry: + icon = QtGui.QIcon(entry["argodejoIconPath"]) + assert not icon.isNull() else: - icon = QtGui.QIcon.fromTheme(exe) + if "icon" in entry: + icon = QtGui.QIcon.fromTheme(entry["icon"]) + else: + icon = QtGui.QIcon.fromTheme(exe) - if icon.isNull(): - icon = QtGui.QIcon.fromTheme(exe) + if icon.isNull(): + icon = QtGui.QIcon.fromTheme(exe) - if icon.isNull(): - icon = iconFromString(exe) + if icon.isNull(): + icon = iconFromString(exe) assert not icon.isNull() diff --git a/qtgui/opensessioncontroller.py b/qtgui/opensessioncontroller.py index c3a322c..26db142 100644 --- a/qtgui/opensessioncontroller.py +++ b/qtgui/opensessioncontroller.py @@ -28,6 +28,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets #Engine import engine.api as api +import engine.findicons as findicons #Qt from .descriptiontextwidget import DescriptionController @@ -65,6 +66,7 @@ class ClientItem(QtWidgets.QTreeWidgetItem): self.setFlags(self.defaultFlags | QtCore.Qt.ItemIsEditable) #We have editTrigger to none so we can explicitly allow to only edit the name column on menuAction #self.treeWidget() not ready at this point self.updateData(clientDict) + self.updateIcon(clientDict) def dataClientNameOverride(self, name:str): """Either string or None. If None we reset to nsmd name""" @@ -105,6 +107,12 @@ class ClientItem(QtWidgets.QTreeWidgetItem): t = str(value) self.setText(index, t) + nameColumn = self.parentController.clientsTreeWidgetColumns.index("reportedName") + if clientDict["reportedName"] is None: + self.setText(nameColumn, clientDict["executable"]) + + def updateIcon(self, clientDict:dict): + """Just called during init""" programIcons = self.parentController.mainWindow.programIcons assert programIcons assert "executable" in clientDict, clientDict @@ -114,16 +122,17 @@ class ClientItem(QtWidgets.QTreeWidgetItem): assert icon, icon self.setIcon(iconColumn, icon) #reported name is correct here. this is just the column. else: #Not NSM client added by the prompt widget - icon = QtGui.QIcon.fromTheme(clientDict["executable"]) + result = findicons.findIconPath(clientDict["executable"]) + if result: + icon = QtGui.QIcon.fromTheme(str(result[0])) + else: + icon = QtGui.QIcon.fromTheme(clientDict["executable"]) + if not icon.isNull(): self.setIcon(iconColumn, icon) else: self.setIcon(iconColumn, iconFromString(clientDict["executable"])) - nameColumn = self.parentController.clientsTreeWidgetColumns.index("reportedName") - if clientDict["reportedName"] is None: - self.setText(nameColumn, clientDict["executable"]) - class ClientTable(object): """Controls the QTreeWidget that holds loaded clients""" @@ -384,6 +393,11 @@ class LauncherProgram(QtWidgets.QTreeWidgetItem): 'type': 'Application', 'version': '1.0', #desktop spec version, not progra, 'x-nsm-capable': 'true'} + + Also: + 'argodejoExec' : the actual nsm exe + 'argodejoIconPath' : a priority path the engine found for us + """ allItems = {} # clientId : ClientItem