Browse Source

Add settings dialog with option to add custom executable paths and a white- and blacklist for the program launcher. This should make custom scenarios much easier without compromising the 'everything must be in the PATH' rule

master
Nils 4 years ago
parent
commit
fd11e1b662
  1. 11
      engine/api.py
  2. 19
      engine/findprograms.py
  3. 9
      qtgui/addclientprompt.py
  4. 9
      qtgui/designer/mainwindow.py
  5. 6
      qtgui/designer/mainwindow.ui
  6. 2
      qtgui/designer/newsession.py
  7. 2
      qtgui/designer/newsession.ui
  8. 82
      qtgui/designer/settings.py
  9. 142
      qtgui/designer/settings.ui
  10. 20
      qtgui/mainwindow.py
  11. BIN
      qtgui/resources/translations/de.qm
  12. 32
      qtgui/resources/translations/de.ts
  13. 116
      qtgui/settings.py

11
engine/api.py

@ -199,6 +199,16 @@ def buildSystemPrograms():
present on the system"""
programDatabase.build()
def systemProgramsSetWhitelist(executableNames:tuple):
"""will replace the current list"""
programDatabase.userWhitelist = tuple(executableNames)
#Needs rebuild through the GUI. We have no callback for this.
def systemProgramsSetBlacklist(executableNames:tuple):
"""will replace the current list"""
programDatabase.userBlacklist = tuple(executableNames)
#Needs rebuild through the GUI. We have no callback for this.
def getSystemPrograms()->list:
"""Returns the cached database from buildProgramDatabase. No automatic update. Empty on program
start"""
@ -215,6 +225,7 @@ def getUnfilteredExecutables()->list:
"""Return a list of unique names without paths or directories of all exectuables in users $PATH.
This is intended for a program starter prompt. GUI needs to supply tab completition or search
itself"""
programDatabase.unfilteredExecutables = programDatabase.buildCache_unfilteredExecutables() #quick call
return programDatabase.unfilteredExecutables

19
engine/findprograms.py

@ -58,6 +58,8 @@ class SupportedProgramsDatabase(object):
def __init__(self):
self.blacklist = ("nsmd", "non-daw", "carla")
self.morePrograms = ("thisdoesnotexisttest", "carla-rack", "carla-patchbay", "carla-jack-multi", "ardour5", "ardour6", "nsm-data", "nsm-jack") #only programs not found by buildCache_grepExecutablePaths because they are just shellscripts and do not contain /nsm/server/announce.
self.userWhitelist = () #added dynamically to morePrograms
self.userBlacklist = () #added dynamically to blacklist
self.knownDesktopFiles = { #shortcuts to the correct desktop files. Reverse lookup binary->desktop creates false entries, for example ZynAddSubFx and Carla.
"zynaddsubfx": "zynaddsubfx-jack.desktop", #value will later get replaced with the .desktop entry
"carla-jack-multi" : "carla.desktop",
@ -65,7 +67,8 @@ class SupportedProgramsDatabase(object):
self.programs = [] #list of dicts. guaranteed keys: argodejoExec, name, argodejoFullPath. And probably others, like description and version.
self.nsmExecutables = set() #set of executables for fast membership, if a GUI wants to know if they are available. Needs to be build "manually" with self.programs. no auto-property for a list. at least we don't want to do the work.
#.build needs to be called from the api/GUI.
self.unfilteredExecutables = self.buildCache_unfilteredExecutables() #This doesn't take too long. we can start that every time. It will get updated in build as well.
#self.unfilteredExecutables = self.buildCache_unfilteredExecutables() #This doesn't take too long. we can start that every time. It will get updated in build as well.
self.unfilteredExecutables = None #in build()
#self.build() #fills self.programs and
def buildCache_grepExecutablePaths(self):
@ -74,19 +77,23 @@ class SupportedProgramsDatabase(object):
-s silent. No errors, eventhough subprocess uses stdout only
-R recursive with symlinks. We don't want to look in subdirs because that is not allowed by
PATH and nsm, but we want to follow symlinks
If you have a custom user path that does not mean that all its executables will
automatically show up here. They still need to contain /nsm/server/announce
Your binaries will be in unfilteredExecutables though
"""
result = []
executablePaths = [pathlib.Path(p) for p in os.environ["PATH"].split(":")]
executablePaths = [pathlib.Path(p) for p in os.environ["PATH"].split(os.pathsep)]
for path in executablePaths:
command = f"grep -iRsnl {path} -e /nsm/server/announce"
#Py>=3.7 completedProcess = subprocess.run(command, capture_output=True, text=True, shell=True)
completedProcess = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) #universal_newlines is an alias for text, which was deprecated in 3.7 because text is more understandable. capture_output replaces the two PIPEs in 3.7
for fullPath in completedProcess.stdout.split():
exe = pathlib.Path(fullPath).relative_to(path)
if not str(exe) in self.blacklist:
if not str(exe) in self.blacklist + self.userBlacklist:
result.append((str(exe), str(fullPath)))
for prg in self.morePrograms:
for prg in self.morePrograms + self.userWhitelist:
for path in executablePaths:
if pathlib.Path(path, prg).is_file():
result.append((str(prg), str(pathlib.Path(path, prg))))
@ -199,7 +206,7 @@ class SupportedProgramsDatabase(object):
return path.is_file() and stat.S_IXUSR & os.stat(path)[stat.ST_MODE] == 64
result = []
executablePaths = [pathlib.Path(p) for p in os.environ["PATH"].split(":")]
executablePaths = [pathlib.Path(p) for p in os.environ["PATH"].split(os.pathsep)]
for path in executablePaths:
result += [str(pathlib.Path(f).relative_to(path)) for f in path.glob("*") if isexe(f)]
@ -210,7 +217,7 @@ class SupportedProgramsDatabase(object):
It will be populated from a template-list of well-working clients and then all binaries not
in the path are filtered out. This can be presented to the user without worries."""
#Assumes to be called only from self.build
startexecutables = set(("doesnotexist", "laborejo2", "patroneo", "vico", "fluajho", "carla-rack", "carla-patchbay", "carla-jack-multi", "ardour6", "drumkv1_jack", "synthv1_jack", "padthv1_jack", "samplv1_jack", "zynaddsubfx", "ADLplug", "OPNplug", "non-mixer", "non-sequencer", "non-timeline"))
startexecutables = set(("doesnotexist", "laborejo", "patroneo", "vico", "fluajho", "carla-rack", "carla-patchbay", "carla-jack-multi", "ardour6", "drumkv1_jack", "synthv1_jack", "padthv1_jack", "samplv1_jack", "zynaddsubfx", "ADLplug", "OPNplug", "non-mixer", "non-sequencer", "non-timeline") + self.userWhitelist)
for prog in self.programs:
prog["whitelist"] = prog["argodejoExec"] in startexecutables

9
qtgui/addclientprompt.py

@ -38,6 +38,9 @@ class PromptWidget(QtWidgets.QDialog):
super().__init__(parent)
layout = QtWidgets.QFormLayout()
#layout = QtWidgets.QVBoxLayout()
updateWordlist() #this is a fast index update, we can call that every time to be sure. Otherwise newly added executable-PATHs will not be reflected in the dialog without a program-database update, which takes too long to be convenient.
self.setLayout(layout)
self.setWindowFlag(QtCore.Qt.Popup, True)
@ -75,8 +78,6 @@ class PromptWidget(QtWidgets.QDialog):
self.exec() #blocks until the dialog gets closed
def abortHandler(self):
pass
@ -87,6 +88,10 @@ class PromptWidget(QtWidgets.QDialog):
assert PromptWidget.minlen
curText = self.comboBox.currentText()
if not curText or curText == " ": #TODO: qt weirdness. This is a case when focus is lost from a valid entry. The field is filled from a chosen value, from the list. But it says " ".
#Do not show the errorLabel. This is a qt bug or so.
return
if curText in PromptWidget.wordlist:
api.clientAdd(curText)
logger.info(f"Prompt accepted {curText} and will send it to clientAdd")

9
qtgui/designer/mainwindow.py

@ -2,9 +2,10 @@
# Form implementation generated from reading ui file 'mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.14.2
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
@ -310,8 +311,11 @@ class Ui_MainWindow(object):
self.actionRebuild_Program_Database.setObjectName("actionRebuild_Program_Database")
self.actionClientRename = QtWidgets.QAction(MainWindow)
self.actionClientRename.setObjectName("actionClientRename")
self.actionSettings = QtWidgets.QAction(MainWindow)
self.actionSettings.setObjectName("actionSettings")
self.menuControl.addAction(self.actionRebuild_Program_Database)
self.menuControl.addAction(self.actionHide_in_System_Tray)
self.menuControl.addAction(self.actionSettings)
self.menuControl.addAction(self.actionMenuQuit)
self.menuSession.addAction(self.actionSessionAddClient)
self.menuSession.addAction(self.actionSessionSave)
@ -405,3 +409,4 @@ class Ui_MainWindow(object):
self.actionRebuild_Program_Database.setText(_translate("MainWindow", "Rebuild Program Database"))
self.actionClientRename.setText(_translate("MainWindow", "Rename"))
self.actionClientRename.setShortcut(_translate("MainWindow", "F2"))
self.actionSettings.setText(_translate("MainWindow", "Settings"))

6
qtgui/designer/mainwindow.ui

@ -636,6 +636,7 @@
</property>
<addaction name="actionRebuild_Program_Database"/>
<addaction name="actionHide_in_System_Tray"/>
<addaction name="actionSettings"/>
<addaction name="actionMenuQuit"/>
</widget>
<widget class="QMenu" name="menuSession">
@ -796,6 +797,11 @@
<string>F2</string>
</property>
</action>
<action name="actionSettings">
<property name="text">
<string>Settings</string>
</property>
</action>
</widget>
<resources/>
<connections/>

2
qtgui/designer/newsession.py

@ -47,6 +47,6 @@ class Ui_NewSession(object):
NewSession.setWindowTitle(_translate("NewSession", "Dialog"))
self.nameGroupBox.setTitle(_translate("NewSession", "New Session Name"))
self.checkBoxJack.setText(_translate("NewSession", "Save JACK Connections\n"
"(adds clients \'nsm-jack\')"))
"(adds clients \'jackpatch\')"))
self.checkBoxData.setText(_translate("NewSession", "Client Renaming and Session Notes\n"
"(adds client \'nsm-data\')"))

2
qtgui/designer/newsession.ui

@ -42,7 +42,7 @@
<widget class="QCheckBox" name="checkBoxJack">
<property name="text">
<string>Save JACK Connections
(adds clients 'nsm-jack')</string>
(adds clients 'jackpatch')</string>
</property>
<property name="checked">
<bool>true</bool>

82
qtgui/designer/settings.py

@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'settings.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(626, 387)
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.SettingsTab = QtWidgets.QTabWidget(Dialog)
self.SettingsTab.setTabPosition(QtWidgets.QTabWidget.North)
self.SettingsTab.setTabShape(QtWidgets.QTabWidget.Rounded)
self.SettingsTab.setObjectName("SettingsTab")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tab_2)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.label_help_launcher_whitelist = QtWidgets.QLabel(self.tab_2)
self.label_help_launcher_whitelist.setWordWrap(True)
self.label_help_launcher_whitelist.setObjectName("label_help_launcher_whitelist")
self.verticalLayout_3.addWidget(self.label_help_launcher_whitelist)
self.launcherWhitelistPlainTextEdit = QtWidgets.QPlainTextEdit(self.tab_2)
self.launcherWhitelistPlainTextEdit.setObjectName("launcherWhitelistPlainTextEdit")
self.verticalLayout_3.addWidget(self.launcherWhitelistPlainTextEdit)
self.label_help_launcher_blacklist = QtWidgets.QLabel(self.tab_2)
self.label_help_launcher_blacklist.setWordWrap(True)
self.label_help_launcher_blacklist.setObjectName("label_help_launcher_blacklist")
self.verticalLayout_3.addWidget(self.label_help_launcher_blacklist)
self.launcherBlacklistPlainTextEdit = QtWidgets.QPlainTextEdit(self.tab_2)
self.launcherBlacklistPlainTextEdit.setObjectName("launcherBlacklistPlainTextEdit")
self.verticalLayout_3.addWidget(self.launcherBlacklistPlainTextEdit)
self.SettingsTab.addTab(self.tab_2, "")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label_help_programstart = QtWidgets.QLabel(self.tab)
self.label_help_programstart.setWordWrap(True)
self.label_help_programstart.setObjectName("label_help_programstart")
self.verticalLayout_2.addWidget(self.label_help_programstart)
self.label_help_path_rules = QtWidgets.QLabel(self.tab)
self.label_help_path_rules.setWordWrap(True)
self.label_help_path_rules.setObjectName("label_help_path_rules")
self.verticalLayout_2.addWidget(self.label_help_path_rules)
self.programPathsPlainTextEdit = QtWidgets.QPlainTextEdit(self.tab)
self.programPathsPlainTextEdit.setObjectName("programPathsPlainTextEdit")
self.verticalLayout_2.addWidget(self.programPathsPlainTextEdit)
self.SettingsTab.addTab(self.tab, "")
self.verticalLayout.addWidget(self.SettingsTab)
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)
self.buttonBox.raise_()
self.SettingsTab.raise_()
self.retranslateUi(Dialog)
self.SettingsTab.setCurrentIndex(0)
self.buttonBox.accepted.connect(Dialog.accept)
self.buttonBox.rejected.connect(Dialog.reject)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Settings"))
self.label_help_launcher_whitelist.setText(_translate("Dialog", "Whitelist - Add executable names (not paths) to the program launcher. One executable per line."))
self.label_help_launcher_blacklist.setText(_translate("Dialog", "Blacklist - Exclude executable names (not paths) from the program launcher. One executable per line."))
self.SettingsTab.setTabText(self.SettingsTab.indexOf(self.tab_2), _translate("Dialog", "Launcher"))
self.label_help_programstart.setText(_translate("Dialog", "For advanced users only! Add executable paths to the environment, just for Argodejo and NSM. Changes need a program restart afterwards. If you want your programs in the application launcher use the launcher tab."))
self.label_help_path_rules.setText(_translate("Dialog", "Add one absolute path to a directory (e.g. /home/user/audio-bin) per line. No wildcards. Trailing slashes/ don\'t matter."))
self.SettingsTab.setTabText(self.SettingsTab.indexOf(self.tab), _translate("Dialog", "$PATH"))

142
qtgui/designer/settings.ui

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>626</width>
<height>387</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="SettingsTab">
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="tabShape">
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Launcher</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_help_launcher_whitelist">
<property name="text">
<string>Whitelist - Add executable names (not paths) to the program launcher. One executable per line.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="launcherWhitelistPlainTextEdit"/>
</item>
<item>
<widget class="QLabel" name="label_help_launcher_blacklist">
<property name="text">
<string>Blacklist - Exclude executable names (not paths) from the program launcher. One executable per line.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="launcherBlacklistPlainTextEdit"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>$PATH</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_help_programstart">
<property name="text">
<string>For advanced users only! Add executable paths to the environment, just for Argodejo and NSM. Changes need a program restart afterwards. If you want your programs in the application launcher use the launcher tab.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_help_path_rules">
<property name="text">
<string>Add one absolute path to a directory (e.g. /home/user/audio-bin) per line. No wildcards. Trailing slashes/ don't matter.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="programPathsPlainTextEdit"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
<zorder>buttonBox</zorder>
<zorder>SettingsTab</zorder>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

20
qtgui/mainwindow.py

@ -48,6 +48,7 @@ from .projectname import ProjectNameWidget
from .addclientprompt import askForExecutable, updateWordlist
from .waitdialog import WaitDialog
from .resources import *
from .settings import SettingsDialog
api.eventLoop = EventLoop()
@ -116,18 +117,16 @@ class MainWindow(QtWidgets.QMainWindow):
self.ui.mainPageSwitcher.setCurrentIndex(0) #1 is messageLabel 0 is the tab widget
SettingsDialog.loadFromSettingsAndSendToEngine() #set blacklist, whitelist for programdatabase and addtional executable paths for environment
#TODO: Hide information tab until the feature is ready
self.ui.tabbyCat.removeTab(2)
self.programIcons = {} #executableName:QIcon. Filled by self.updateProgramDatabase
self.sessionController = SessionController(mainWindow=self)
self.systemTray = SystemTray(mainWindow=self)
self.connectMenu()
self.recentlyOpenedSessions = RecentlyOpenedSessions()
self.programIcons = {} #executableName:QIcon. Filled by self.updateProgramDatabase
#Menu
self.ui.actionRebuild_Program_Database.triggered.connect(self.updateProgramDatabase)
#Api Callbacks
api.callbacks.sessionClosed.append(self.reactCallback_sessionClosed)
@ -316,7 +315,6 @@ class MainWindow(QtWidgets.QMainWindow):
self.storeWindowSettings()
self._callSysExit()
def closeEvent(self, event):
"""Window manager close.
Ignore. We use it to send the GUI into hiding."""
@ -325,9 +323,17 @@ class MainWindow(QtWidgets.QMainWindow):
def connectMenu(self):
#Control
self.ui.actionRebuild_Program_Database.triggered.connect(self.updateProgramDatabase)
self.ui.actionSettings.triggered.connect(self._reactMenu_settings)
self.ui.actionHide_in_System_Tray.triggered.connect(lambda: self.toggleVisible(force=False))
self.ui.actionMenuQuit.triggered.connect(self.menuRealQuit)
def _reactMenu_settings(self):
widget = SettingsDialog(self) #blocks until closed
if widget.success:
self.updateProgramDatabase()
def storeWindowSettings(self):
"""Window state is not saved in the real save file. That would lead to portability problems
between computers, like different screens and resolutions.

BIN
qtgui/resources/translations/de.qm

Binary file not shown.

32
qtgui/resources/translations/de.ts

@ -77,7 +77,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="346"/>
<source>Session Name Goes Here</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
@ -138,55 +137,46 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="362"/>
<source>version and running</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="363"/>
<source>NSM Server Mode</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="364"/>
<source>Self-started, connected to, environment var</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="365"/>
<source>NSM Url</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="366"/>
<source>osc.upd ip port</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="367"/>
<source>Session Root</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="368"/>
<source>/home/usr/NSM Sessions</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="369"/>
<source>Program Database</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="370"/>
<source>Last Updated</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
@ -197,7 +187,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="373"/>
<source>Processing</source>
<translatorcomment>Nicht in benutzung</translatorcomment>
<translation>Arbeitet</translation>
</message>
<message>
@ -208,13 +197,11 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="375"/>
<source>SessionName</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="376"/>
<source>ClientNameId</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
@ -225,7 +212,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="378"/>
<source>Ctrl+Shift+Q</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -246,7 +232,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="382"/>
<source>Ctrl+Q</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -257,13 +242,11 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="384"/>
<source>A</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="386"/>
<source>Ctrl+S</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -274,13 +257,11 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="388"/>
<source>Ctrl+Shift+S</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../designer/mainwindow.py" line="390"/>
<source>Ctrl+W</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -291,7 +272,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="392"/>
<source>Ctrl+Shift+W</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -302,7 +282,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="394"/>
<source>Alt+O</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -313,7 +292,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="396"/>
<source>Alt+R</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -324,7 +302,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="398"/>
<source>Alt+S</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -335,7 +312,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="400"/>
<source>Alt+X</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -346,7 +322,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="402"/>
<source>Alt+T</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
<message>
@ -372,7 +347,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/mainwindow.py" line="407"/>
<source>F2</source>
<translatorcomment>Keine Shortcuts übersetzen</translatorcomment>
<translation></translation>
</message>
</context>
@ -381,7 +355,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/newsession.py" line="47"/>
<source>Dialog</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>
@ -392,8 +365,8 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/newsession.py" line="49"/>
<source>Save JACK Connections
(adds clients &apos;nsm-jack&apos;)</source>
<translation>Speichere JACK-Verbindungen (mit Client &apos;nsm-jack&apos;)</translation>
(adds clients &apos;jackpatch&apos;)</source>
<translation>Speichere JACK-Verbindungen (mit Client &apos;jackpatch&apos;)</translation>
</message>
<message>
<location filename="../../designer/newsession.py" line="51"/>
@ -470,7 +443,6 @@ Für Notizen, TODO, Referenzen, Quellen etc…</translation>
<message>
<location filename="../../designer/projectname.py" line="43"/>
<source>Form</source>
<translatorcomment>Platzhalter</translatorcomment>
<translation></translation>
</message>
<message>

116
qtgui/settings.py

@ -0,0 +1,116 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2020, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),
This application is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import logging; logger = logging.getLogger(__name__); logger.info("import")
#Standard Library
import pathlib
import os
#Third Party
from PyQt5 import QtCore, QtWidgets
#Engine
import engine.api as api
from engine.config import METADATA #includes METADATA only. No other environmental setup is executed.
#QtGui
from .designer.settings import Ui_Dialog
class SettingsDialog(QtWidgets.QDialog):
def __init__(self, mainWindow):
super().__init__(mainWindow)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.mainWindow = mainWindow
self.success = False
settings = QtCore.QSettings("LaborejoSoftwareSuite", METADATA["shortName"])
if settings.contains("launcherBlacklistPlainTextEdit"):
self.ui.launcherBlacklistPlainTextEdit.setPlainText(settings.value("launcherBlacklistPlainTextEdit", type=str))
else:
self.ui.launcherBlacklistPlainTextEdit.setPlainText("")
if settings.contains("launcherWhitelistPlainTextEdit"):
self.ui.launcherWhitelistPlainTextEdit.setPlainText(settings.value("launcherWhitelistPlainTextEdit", type=str))
else:
self.ui.launcherWhitelistPlainTextEdit.setPlainText("")
if settings.contains("programPathsPlainTextEdit"):
self.ui.programPathsPlainTextEdit.setPlainText(settings.value("programPathsPlainTextEdit", type=str))
else:
self.ui.programPathsPlainTextEdit.setPlainText("")
#self.ui.name.textEdited.connect(self.check) #not called when text is changed programatically
self.ui.buttonBox.accepted.connect(self.process)
self.ui.buttonBox.rejected.connect(self.reject)
self.setWindowFlag(QtCore.Qt.Popup, True)
self.setModal(True)
self.setFocus(True)
self.exec_()
@staticmethod
def loadFromSettingsAndSendToEngine():
"""Called on program start and in self.process, which has a bit overhead because
it is saving to file and then reloading from file (qsettings)"""
settings = QtCore.QSettings("LaborejoSoftwareSuite", METADATA["shortName"])
if settings.contains("launcherBlacklistPlainTextEdit"):
bl = settings.value("launcherBlacklistPlainTextEdit", type=str)
else:
bl = None
if settings.contains("launcherWhitelistPlainTextEdit"):
wl = settings.value("launcherWhitelistPlainTextEdit", type=str)
else:
wl = None
if settings.contains("programPathsPlainTextEdit"):
pth = settings.value("programPathsPlainTextEdit", type=str)
else:
pth = None
blacklist = bl.split("\n") if bl else []
whitelist = wl.split("\n") if wl else []
api.systemProgramsSetBlacklist(blacklist)
api.systemProgramsSetWhitelist(whitelist)
#Depends on SettingsDialog: More executable paths for the engine. We do this in mainwindow because it has access to the qsettings safe file and is started before engine, program-database or nsmd.
additionalExecutablePaths = pth.split("\n") if pth else []
if additionalExecutablePaths:
os.environ["PATH"] = os.pathsep.join(additionalExecutablePaths) + os.pathsep + os.environ["PATH"]
def process(self):
settings = QtCore.QSettings("LaborejoSoftwareSuite", METADATA["shortName"])
settings.setValue("launcherBlacklistPlainTextEdit", self.ui.launcherBlacklistPlainTextEdit.toPlainText())
settings.setValue("launcherWhitelistPlainTextEdit", self.ui.launcherWhitelistPlainTextEdit.toPlainText())
settings.setValue("programPathsPlainTextEdit", self.ui.programPathsPlainTextEdit.toPlainText())
SettingsDialog.loadFromSettingsAndSendToEngine()
self.success = True
self.done(True)
Loading…
Cancel
Save