#! /usr/bin/env python3 # -*- coding: utf-8 -*- """ Copyright 2021, 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 . """ import logging; logger = logging.getLogger(__name__); logger.info("import") #Standard Library #Engine import engine.api as api #Third Party from PyQt5 import QtCore, QtWidgets class PromptWidget(QtWidgets.QDialog): wordlist = None minlen = None def __init__(self, parent): 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) self.comboBox = QtWidgets.QComboBox(self) self.comboBox.setEditable(True) self.comboBox.currentTextChanged.connect(self.check) #not called when text is changed programatically if PromptWidget.wordlist: completer = QtWidgets.QCompleter(PromptWidget.wordlist) completer.setModelSorting(QtWidgets.QCompleter.CaseInsensitivelySortedModel) completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) completer.setCompletionMode(QtWidgets.QCompleter.PopupCompletion) completer.activated.connect(self.process) #To avoid double-press enter to select one we hook into the activated signal and trigger process self.comboBox.setCompleter(completer) self.comboBox.setMinimumContentsLength(PromptWidget.minlen) labelString = QtCore.QCoreApplication.translate("PromptWidget", "Type in the name of an executable file on your system.") else: labelString = QtCore.QCoreApplication.translate("PromptWidget", "No program database found. Please update through Control menu.") label = QtWidgets.QLabel(labelString) layout.addWidget(label) self.comboBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength) layout.addWidget(self.comboBox) errorString = QtCore.QCoreApplication.translate("PromptWidget", "Command not found or not accepted!
Parameters, --switches and relative paths are not allowed.
Use nsm-proxy or write a starter-script instead.") errorString = "" + errorString + "" self.errorLabel = QtWidgets.QLabel(errorString) layout.addWidget(self.errorLabel) self.errorLabel.hide() #shown in process or check self.buttonBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) self.buttonBox.accepted.connect(self.process) self.buttonBox.rejected.connect(self.reject) layout.addWidget(self.buttonBox) self.exec() #blocks until the dialog gets closed def abortHandler(self): pass def check(self, currentText): """Called every keypress. We do preliminary error and collision checking here, so the engine does not have to throw an error """ self.errorLabel.hide() #start in good faith ok = self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok) if currentText in PromptWidget.wordlist: #this is taken literally. Any extra char or whitespace counts as false ok.setEnabled(True) else: ok.setEnabled(False) self.errorLabel.show() def process(self): """Careful! Calling this eats python errors without notice. Make sure your objects exists and your syntax is correct""" assert PromptWidget.wordlist 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") self.done(True) else: logger.info(f"Prompt did not accept {curText}.Showing info to the user.") self.errorLabel.show() def updateWordlist(): """in case programs are installed while the session is running the user can manually call a database update""" PromptWidget.wordlist = api.getUnfilteredExecutables() if PromptWidget.wordlist: PromptWidget.minlen = len(max(PromptWidget.wordlist, key=len)) else: logger.error("Executable list came back empty! Most likely an error in application database build. Not trivial!") def askForExecutable(parent): PromptWidget(parent)