Browse Source

use relative path as unique session name

master
Nils 4 years ago
parent
commit
1662110c5d
  1. 17
      engine/api.py
  2. 17
      engine/findicons.py
  3. 16
      engine/findprograms.py
  4. 11
      engine/nsmservercontrol.py
  5. 20
      qtgui/mainwindow.py
  6. 7
      qtgui/opensessioncontroller.py
  7. 16
      qtgui/quickopensessioncontroller.py

17
engine/api.py

@ -225,13 +225,20 @@ def systemProgramsSetBlacklist(executableNames:tuple):
programDatabase.userBlacklist = tuple(executableNames)
#Needs rebuild through the GUI. We have no callback for this.
def getSystemPrograms()->list:
def getCache()->dict:
"""Returns the cached database from buildProgramDatabase. No automatic update. Empty on program
start"""
return programDatabase.programs
start
db = {
"programs" : list of dicts
iconPaths : list of strings
}
"""
return programDatabase.getCache()
def setCache(cache:dict):
programDatabase.setCache(cache)
def setSystemsPrograms(listOfDicts:list):
programDatabase.loadPrograms(listOfDicts)
def getNsmExecutables()->set:
"""Cached access fort fast membership tests. Is this program in the PATH?"""

17
engine/findicons.py

@ -88,10 +88,19 @@ def _buildCache()->set:
global _cache
_cache = None
def updateCache():
def updateCache(serializedCache:list=None):
global _cache
_cache = _buildCache()
if serializedCache:
#Convert str to real paths
_cache = set([pathlib.Path(r) for r in serializedCache if pathlib.Path(r).is_file()])
else:
#Already real paths as a set
_cache = _buildCache()
def getSerializedCache()->list: #list of strings, not paths. This is for saving in global system config for faster startup
global _cache
return [str(p) for p in _cache]
rePattern = re.compile("\d+x\d+") #we don't put .* around this because we are searching for the subpattern
@ -100,7 +109,7 @@ def findIconPath(executableName:str)->list:
so you can use result[0] for the best variant.
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"""
global _cache
if not _cache:
raise ValueError("You need to call updateCache() first")
@ -129,8 +138,6 @@ def findIconPath(executableName:str)->list:
return result
updateCache()
if __name__ == "__main__":
"""Example that tries to find a few icons"""

16
engine/findprograms.py

@ -166,11 +166,20 @@ class SupportedProgramsDatabase(object):
logger.warning(f"Bad desktop file. Skipping: {f}")
return allDesktopEntries
def loadPrograms(self, listOfDicts):
def setCache(self, cache:dict):
"""Qt Settings will send us this"""
self.programs = listOfDicts
self.programs = cache["programs"] #list of dicts
findicons.updateCache(cache["iconPaths"])
self.nsmExecutables = set(d["argodejoExec"] for d in self.programs)
def getCache(self)->dict:
"""To carry the DB over restarts. Saved by Qt Settings at the moment"""
cache = {
"programs" : self.programs, #list of dicts
"iconPaths" : findicons.getSerializedCache(), #list
}
return cache
def build(self, progressHook=None):
"""Can be called at any time by the user to update after installing new programs"""
@ -183,7 +192,7 @@ class SupportedProgramsDatabase(object):
logger.info("Building launcher database. This might take a minute")
self.progressHook("")
self.programs = self._build()
self.programs = self._build() #builds iconPaths as side-effect
self.unfilteredExecutables = self.buildCache_unfilteredExecutables()
self.nsmExecutables = set(d["argodejoExec"] for d in self.programs)
self._buildWhitelist()
@ -212,7 +221,6 @@ class SupportedProgramsDatabase(object):
self.desktopEntries = self.buildCache_DesktopEntries()
findicons.updateCache()
leftovers = set(self.executables)
matches = [] #list of dicts
for exe, fullPath in self.executables:

11
engine/nsmservercontrol.py

@ -1026,6 +1026,9 @@ class NsmServerControl(object):
We expect two parameters: [session name, session path] both of which could be "".
If we start nsmd ourselves into an empty state we expect session name to be empty
Session path is the subdirectory relative to session root. The session root is not included.
!The unqiue name is the session path, not the name!
Shortly before we received /nsm/gui/session/session which indicates the attempt to create a
new one, I guess! :)
@ -1036,6 +1039,7 @@ class NsmServerControl(object):
Empty string is "No session" or "Choose A Session" mode.
"""
l = len(parameters)
if l == 2:
nsmSessionName, sessionPath = parameters
@ -1044,12 +1048,13 @@ class NsmServerControl(object):
self.internalState["currentSession"] = None #sessionCloseHooked triggers rebuilding of the session list, which will not work when there is a current session.
self.sessionClosedHook()
else:
sessionPath = sessionPath.lstrip("/")
#Session path is the subdirectory relative to session root. The session root is not included.
sessionPath = sessionPath.lstrip("/") #we strip for technical reasons.
logger.info(f"Current Session changed. We are now {nsmSessionName} in {sessionPath}")
self.internalState["currentSession"] = nsmSessionName
self.internalState["currentSession"] = sessionPath
#This is after the session, received after all programs have loaded.
#We have a counterpart-message reaction that signals the attempt to load.
self.sessionOpenReadyHook(self.sessionAsDict(nsmSessionName)) #notify the api->UI
self.sessionOpenReadyHook(self.sessionAsDict(sessionPath)) #notify the api->UI
for autoClientExecutableInPath in self._addToNextSession:
self.clientAdd(autoClientExecutableInPath)
self._addToNextSession = [] #reset

20
qtgui/mainwindow.py

@ -164,12 +164,12 @@ class MainWindow(QtWidgets.QMainWindow):
#This must happen before engineStart. If a session is already running a set of initial
#client-callbacks will arrive immediately, even before the eventLoop starts.
#If not present instruct the engine to build one.
#This is also needed by the prompt in sessionController
#This is also needed by the prompt in sessionController and the icons
logger.info("Trying to restore cached program database")
settings = QtCore.QSettings("LaborejoSoftwareSuite", METADATA["shortName"])
if settings.contains("programDatabase"):
listOfDicts = settings.value("programDatabase", type=list)
api.setSystemsPrograms(listOfDicts)
if settings.contains("engineCache"):
engineCache = settings.value("engineCache", type=dict)
api.setCache(engineCache)
logger.info("Restored program database from qt cache to engine")
self._updateGUIWithCachedPrograms()
else: #First or fresh start
@ -248,7 +248,10 @@ class MainWindow(QtWidgets.QMainWindow):
def _updateIcons(self):
logger.info("Creating icon database")
programs = api.getSystemPrograms()
engineCache = api.getCache()
assert engineCache
programs = engineCache["programs"]
self.programIcons.clear()
for entry in programs:
@ -279,12 +282,13 @@ class MainWindow(QtWidgets.QMainWindow):
text = QtCore.QCoreApplication.translate("mainWindow", "Updating Program Database.\nThank you for your patience.")
settings = QtCore.QSettings("LaborejoSoftwareSuite", METADATA["shortName"])
settings.remove("programDatabase")
settings.remove("engineCache")
logger.info("Asking api to getSystemPrograms while waiting")
logger.info("Asking api to generate program and icon database while waiting")
diag = WaitDialog(self, text, api.buildSystemPrograms) #save in local var to keep alive
settings.setValue("programDatabase", api.getSystemPrograms())
assert api.getCache()
settings.setValue("engineCache", api.getCache()) # dict
self._updateGUIWithCachedPrograms()
def reactCallback_sessionClosed(self):

7
qtgui/opensessioncontroller.py

@ -451,8 +451,8 @@ class LauncherTable(object):
self.launcherWidget.setSortingEnabled(True)
self.launcherWidget.setAlternatingRowColors(True)
#The actual program entries are handled by the LauncherProgram item class
self.buildPrograms()
##The actual program entries are handled by the LauncherProgram item class
#self.buildPrograms() #Don't call here. MainWindow calls it when everything is ready.
#Signals
self.launcherWidget.itemDoubleClicked.connect(self._reactSignal_launcherItemDoubleClicked)
@ -477,7 +477,8 @@ class LauncherTable(object):
guaranteed to exist in the path.
"""
self.launcherWidget.clear()
programs = api.getSystemPrograms()
engineCache = api.getCache()
programs = engineCache["programs"]
for entry in programs:
item = LauncherProgram(parentController=self, launcherDict=entry)

16
qtgui/quickopensessioncontroller.py

@ -277,7 +277,10 @@ class QuickOpenSessionController(object):
but we combine both views. So we can't just delete-and-rebuild because that destroys
running client states.
"""
whitelist = [e for e in api.getSystemPrograms() if e["whitelist"]]
engineCache = api.getCache()
programs = engineCache["programs"]
whitelist = [e for e in programs if e["whitelist"]]
leftovers = set(StarterClientItem.allItems.keys()) #"argodejoExec"
notForQuickView = ("nsm-data", "jackpatch", "nsm-proxy", "non-midi-mapper", "non-mixer-noui", "ray-proxy", "ray-jackpatch", "carla-jack-single", "carla-jack-multi")
@ -305,17 +308,6 @@ class QuickOpenSessionController(object):
self.listWidget.takeItem(index)
del item
#old: rebuild from scratch
"""
self.listWidget.clear()
StarterClientItem.allItems.clear()
whitelist = [e for e in api.getSystemPrograms() if e["whitelist"]]
for entry in whitelist:
#Create new. Item will be parented by Qt, so Python GC will not delete
item = StarterClientItem(parentController=self, desktopEntry=entry)
self.listWidget.addItem(item)
StarterClientItem.allItems[entry["argodejoExec"]] = item
"""
def _clientStatusChanged(self, clientDict:dict):
"""Maps to nsmd status changes.

Loading…
Cancel
Save