mirror of
https://github.com/naruxde/revpicommander.git
synced 2025-11-08 16:43:53 +01:00
Merge tag '0.11.0' into pkg/debian
Release 0.11.0
This commit is contained in:
116
Makefile
116
Makefile
@@ -19,7 +19,7 @@ endif
|
||||
SYSTEM_PYTHON = python3
|
||||
PYTHON = $(or $(wildcard $(VENV_PATH)/bin/python), $(SYSTEM_PYTHON))
|
||||
|
||||
APP_VERSION = $(shell $(PYTHON) src/$(PACKAGE) --version)
|
||||
APP_VERSION = $(shell "$(PYTHON)" src/$(PACKAGE) --version | cut -d ' ' -f 2)
|
||||
|
||||
all: build_ui build_rc test build
|
||||
|
||||
@@ -27,55 +27,105 @@ all: build_ui build_rc test build
|
||||
|
||||
## Environment
|
||||
venv-info:
|
||||
echo Using path: "$(VENV_PATH)"
|
||||
@echo Environment for $(APP_NAME) $(APP_VERSION)
|
||||
@echo Using path: "$(VENV_PATH)"
|
||||
exit 0
|
||||
|
||||
venv:
|
||||
$(SYSTEM_PYTHON) -m venv --system-site-packages "$(VENV_PATH)"
|
||||
source $(VENV_PATH)/bin/activate && \
|
||||
# Start with empty environment
|
||||
"$(SYSTEM_PYTHON)" -m venv "$(VENV_PATH)"
|
||||
source "$(VENV_PATH)/bin/activate" && \
|
||||
python3 -m pip install --upgrade pip && \
|
||||
python3 -m pip install -r requirements.txt
|
||||
exit 0
|
||||
|
||||
.PHONY: venv-info venv
|
||||
venv-ssp:
|
||||
# Include system installed site-packages and add just missing modules
|
||||
"$(SYSTEM_PYTHON)" -m venv --system-site-packages "$(VENV_PATH)"
|
||||
source "$(VENV_PATH)/bin/activate" && \
|
||||
python3 -m pip install --upgrade pip && \
|
||||
python3 -m pip install -r requirements.txt
|
||||
exit 0
|
||||
|
||||
.PHONY: venv-info venv venv-ssp
|
||||
|
||||
## Compile Qt UI files to python code
|
||||
build_ui:
|
||||
build-ui:
|
||||
cd ui_dev && for ui_file in *.ui; do \
|
||||
file_name=$${ui_file%.ui}; \
|
||||
$(PYTHON) -m PyQt5.uic.pyuic $${ui_file} -o ../src/$(PACKAGE)/ui/$${file_name}_ui.py -x --from-imports; \
|
||||
"$(PYTHON)" -m PyQt5.uic.pyuic $${ui_file} -o ../src/$(PACKAGE)/ui/$${file_name}_ui.py -x --from-imports; \
|
||||
echo $${file_name}; \
|
||||
done
|
||||
|
||||
build_rc:
|
||||
build-rc:
|
||||
cd ui_dev && for rc_file in *.qrc; do \
|
||||
file_name=$${rc_file%.qrc}; \
|
||||
$(PYTHON) -m PyQt5.pyrcc_main $${rc_file} -o ../src/$(PACKAGE)/ui/$${file_name}_rc.py; \
|
||||
"$(PYTHON)" -m PyQt5.pyrcc_main $${rc_file} -o ../src/$(PACKAGE)/ui/$${file_name}_rc.py; \
|
||||
echo $${file_name}; \
|
||||
done
|
||||
|
||||
update_translation:
|
||||
$(PYTHON) -m PyQt5.pylupdate_main translate.pro
|
||||
update-translation:
|
||||
"$(PYTHON)" -m PyQt5.pylupdate_main translate.pro
|
||||
|
||||
.PHONY: build_ui build_rc update_translation
|
||||
.PHONY: build-ui build-rc update-translation
|
||||
|
||||
## Build steps
|
||||
build: build_ui build_rc
|
||||
$(PYTHON) -m setup sdist
|
||||
$(PYTHON) -m setup bdist_wheel
|
||||
build:
|
||||
"$(PYTHON)" -m setup sdist
|
||||
"$(PYTHON)" -m setup bdist_wheel
|
||||
|
||||
install: test build
|
||||
$(PYTHON) -m pip install dist/$(PACKAGE)-*.whl
|
||||
install: build
|
||||
"$(PYTHON)" -m pip install dist/$(PACKAGE)-$(APP_VERSION)-*.whl
|
||||
|
||||
uninstall:
|
||||
$(PYTHON) -m pip uninstall --yes $(PACKAGE)
|
||||
"$(PYTHON)" -m pip uninstall --yes $(PACKAGE)
|
||||
|
||||
.PHONY: test build install uninstall
|
||||
|
||||
## PyInstaller
|
||||
installer_mac: build_ui build_rc
|
||||
$(PYTHON) -m PyInstaller -n $(APP_NAME) \
|
||||
app-licenses:
|
||||
mkdir -p dist
|
||||
# Create a list of all installed libraries, their versions and licenses
|
||||
"$(PYTHON)" -m piplicenses \
|
||||
--format=markdown \
|
||||
--output-file dist/bundled-libraries.md
|
||||
# Create a list of installed libraries with complete project information
|
||||
"$(PYTHON)" -m piplicenses \
|
||||
--with-authors \
|
||||
--with-urls \
|
||||
--with-description \
|
||||
--with-license-file \
|
||||
--no-license-path \
|
||||
--format=json \
|
||||
--output-file dist/open-source-licenses.json
|
||||
"$(PYTHON)" -m piplicenses \
|
||||
--with-authors \
|
||||
--with-urls \
|
||||
--with-description \
|
||||
--with-license-file \
|
||||
--no-license-path \
|
||||
--format=plain-vertical \
|
||||
--output-file dist/open-source-licenses.txt
|
||||
|
||||
app: build-ui build-rc app-licenses
|
||||
"$(PYTHON)" -m PyInstaller -n $(APP_NAME) \
|
||||
--add-data="src/$(PACKAGE)/locale:./$(PACKAGE)/locale" \
|
||||
--add-data="dist/bundled-libraries.md:$(PACKAGE)/open-source-licenses" \
|
||||
--add-data="dist/open-source-licenses.*:$(PACKAGE)/open-source-licenses" \
|
||||
--add-data="data/$(PACKAGE).ico:." \
|
||||
--add-data="data/$(PACKAGE).png:." \
|
||||
--icon=data/$(PACKAGE).ico \
|
||||
--noconfirm \
|
||||
--clean \
|
||||
--onedir \
|
||||
--windowed \
|
||||
src/$(PACKAGE)/__main__.py
|
||||
|
||||
app-mac: build-ui build-rc app-licenses
|
||||
"$(PYTHON)" -m PyInstaller -n $(APP_NAME) \
|
||||
--add-data="src/$(PACKAGE)/locale:./$(PACKAGE)/locale" \
|
||||
--add-data="dist/bundled-libraries.md:$(PACKAGE)/open-source-licenses" \
|
||||
--add-data="dist/open-source-licenses.*:$(PACKAGE)/open-source-licenses" \
|
||||
--add-data="data/$(PACKAGE).icns:." \
|
||||
--icon=data/$(PACKAGE).icns \
|
||||
--noconfirm \
|
||||
@@ -86,7 +136,7 @@ installer_mac: build_ui build_rc
|
||||
--codesign-identity $(APPLE_SIG) \
|
||||
src/$(PACKAGE)/__main__.py
|
||||
|
||||
installer_mac_dmg: installer_mac
|
||||
app-mac-dmg: app-mac
|
||||
mkdir dist/dmg
|
||||
mv dist/$(APP_NAME).app dist/dmg
|
||||
create-dmg \
|
||||
@@ -104,25 +154,19 @@ installer_mac_dmg: installer_mac
|
||||
dist/$(APP_NAME)\ $(APP_VERSION).dmg \
|
||||
dist/dmg
|
||||
|
||||
installer_linux: build_ui build_rc
|
||||
$(PYTHON) -m PyInstaller -n $(APP_NAME) \
|
||||
--add-data="src/$(PACKAGE)/locale:./$(PACKAGE)/locale" \
|
||||
--add-data="data/$(PACKAGE).ico:." \
|
||||
--add-data="data/$(PACKAGE).png:." \
|
||||
--icon=data/$(PACKAGE).ico \
|
||||
--noconfirm \
|
||||
--clean \
|
||||
--onedir \
|
||||
--windowed \
|
||||
src/$(PACKAGE)/__main__.py
|
||||
|
||||
.PHONY: installer_mac installer_mac_dmg installer_linux
|
||||
.PHONY: app-licenses app app-mac app-mac-dmg
|
||||
|
||||
## Clean
|
||||
clean:
|
||||
rm -rf build dist src/*.egg-info *.spec
|
||||
# PyTest caches
|
||||
rm -rf .pytest_cache
|
||||
# Build artifacts
|
||||
rm -rf build dist src/*.egg-info
|
||||
# PyInstaller created files
|
||||
rm -rf *.spec
|
||||
|
||||
distclean: clean
|
||||
rm -rf $(VENV_PATH)
|
||||
# Virtual environment
|
||||
rm -rf "$(VENV_PATH)"
|
||||
|
||||
.PHONY: clean distclean
|
||||
|
||||
85
make.bat
85
make.bat
@@ -2,38 +2,81 @@
|
||||
set PACKAGE=revpicommander
|
||||
set APP_NAME=RevPi Commander
|
||||
|
||||
set PYTHON=venv\\Scripts\\python.exe
|
||||
|
||||
if "%1" == "venv" goto venv
|
||||
if "%1" == "installer" goto installer
|
||||
if "%1" == "test" goto test
|
||||
if "%1" == "build" goto build
|
||||
if "%1" == "app" goto app
|
||||
if "%1" == "clean" goto clean
|
||||
if "%1" == "distclean" goto distclean
|
||||
|
||||
echo Make script for "%APP_NAME%" on Windows
|
||||
echo.
|
||||
echo Need action:
|
||||
echo venv Create / update your virtual environment for build process
|
||||
echo installer Build this application with PyInstaller
|
||||
echo clean Clean up your environment after build process
|
||||
echo venv Create your virtual environment for build process
|
||||
echo test Run defined tests of the project
|
||||
echo build Build PIP packages as source distribution and Wheel
|
||||
echo app Build this application with PyInstaller
|
||||
echo clean Clean up build artifacts after build process
|
||||
echo distclean Same as clean plus removing virtual environment
|
||||
goto end
|
||||
|
||||
:venv
|
||||
python -m venv venv
|
||||
venv\\Scripts\\pip.exe install --upgrade -r requirements.txt
|
||||
goto end
|
||||
python -m venv venv
|
||||
venv\\Scripts\\pip.exe install -r requirements.txt
|
||||
goto end
|
||||
|
||||
:installer
|
||||
venv\\Scripts\\pyinstaller -n "%APP_NAME%" ^
|
||||
--add-data="src\%PACKAGE%\locale;.\%PACKAGE%\locale" ^
|
||||
--add-data="data\%PACKAGE%.ico;." ^
|
||||
--icon=data\\%PACKAGE%.ico ^
|
||||
--noconfirm ^
|
||||
--clean ^
|
||||
--onedir ^
|
||||
--windowed ^
|
||||
src\\%PACKAGE%\\__main__.py
|
||||
goto end
|
||||
:test
|
||||
set PYTHONPATH=src
|
||||
%PYTHON% -m pytest
|
||||
goto end
|
||||
|
||||
:build
|
||||
%PYTHON% -m setup sdist
|
||||
%PYTHON% -m setup bdist_wheel
|
||||
goto end
|
||||
|
||||
:app
|
||||
mkdir dist
|
||||
%PYTHON% -m piplicenses ^
|
||||
--format=markdown ^
|
||||
--output-file dist/bundled-libraries.md
|
||||
%PYTHON% -m piplicenses ^
|
||||
--with-authors ^
|
||||
--with-urls ^
|
||||
--with-description ^
|
||||
--with-license-file ^
|
||||
--no-license-path ^
|
||||
--format=json ^
|
||||
--output-file dist/open-source-licenses.json
|
||||
%PYTHON% -m piplicenses ^
|
||||
--with-authors ^
|
||||
--with-urls ^
|
||||
--with-description ^
|
||||
--with-license-file ^
|
||||
--no-license-path ^
|
||||
--format=plain-vertical ^
|
||||
--output-file dist/open-source-licenses.txt
|
||||
%PYTHON% -m PyInstaller -n "%APP_NAME%" ^
|
||||
--add-data="dist/bundled-libraries.md;%PACKAGE%\open-source-licenses" ^
|
||||
--add-data="dist/open-source-licenses.*;%PACKAGE%\open-source-licenses" ^
|
||||
--add-data="src\%PACKAGE%\locale;.\%PACKAGE%\locale" ^
|
||||
--add-data="data\%PACKAGE%.ico;." ^
|
||||
--icon=data\\%PACKAGE%.ico ^
|
||||
--noconfirm ^
|
||||
--clean ^
|
||||
--onedir ^
|
||||
--windowed ^
|
||||
src\\%PACKAGE%\\__main__.py
|
||||
goto end
|
||||
|
||||
:distclean
|
||||
rmdir /S /Q venv
|
||||
|
||||
:clean
|
||||
rmdir /S /Q build dist
|
||||
rmdir /S /Q src\%PACKAGE%.egg-info
|
||||
del *.spec
|
||||
rmdir /S /Q .pytest_cache
|
||||
rmdir /S /Q build dist src\%PACKAGE%.egg-info
|
||||
del /Q *.spec
|
||||
|
||||
:end
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
setuptools>=65.6.3
|
||||
wheel
|
||||
# Build dependencies
|
||||
pip-licenses
|
||||
Pyinstaller
|
||||
setuptools
|
||||
wheel
|
||||
|
||||
# Runtime dependencies, must match install_requires in setup.py
|
||||
keyring>=23.13.1
|
||||
PyQt5>=5.14.1
|
||||
paramiko>=2.12.0
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||
|
||||
#define MyAppName "RevPi Commander"
|
||||
#define MyAppVersion "0.10.0"
|
||||
#define MyAppVersion "0.11.0"
|
||||
#define MyAppPublisher "Sven Sager"
|
||||
#define MyAppURL "https://revpimodio.org/"
|
||||
#define MyAppICO "data\revpicommander.ico"
|
||||
|
||||
@@ -4,4 +4,4 @@ __author__ = "Sven Sager"
|
||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
__package__ = "revpicommander"
|
||||
__version__ = "0.10.0"
|
||||
__version__ = "0.11.0"
|
||||
|
||||
@@ -17,14 +17,14 @@ if __package__ == "":
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 2 and "--version" in sys.argv:
|
||||
# Catch --version, if this is the only argument (sys.argv[0] is always the script name)
|
||||
from revpicommander import __version__
|
||||
print(__version__)
|
||||
sys.exit(0)
|
||||
|
||||
else:
|
||||
try:
|
||||
# Use absolut import in the __main__ module
|
||||
from revpicommander.revpicommander import main
|
||||
|
||||
# Run the main application of this package
|
||||
sys.exit(main())
|
||||
|
||||
except Exception as e:
|
||||
sys.stdout.write(f"Can not start __main__ module: {e}")
|
||||
sys.stdout.write("\n")
|
||||
sys.exit(1)
|
||||
|
||||
@@ -5,6 +5,7 @@ __copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
import webbrowser
|
||||
from logging import getLogger
|
||||
from re import compile
|
||||
from sys import platform
|
||||
|
||||
@@ -12,10 +13,11 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from zeroconf import IPVersion, ServiceBrowser, Zeroconf
|
||||
|
||||
from . import helper
|
||||
from . import proginit as pi
|
||||
from .helper import RevPiSettings, WidgetData, all_revpi_settings
|
||||
from .ui.avahisearch_ui import Ui_diag_search
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class AvahiSearchThread(QtCore.QThread):
|
||||
"""Search thread for Revolution Pi with installed RevPiPyLoad."""
|
||||
@@ -34,12 +36,12 @@ class AvahiSearchThread(QtCore.QThread):
|
||||
|
||||
def remove_service(self, zeroconf: Zeroconf, conf_type: str, name: str) -> None:
|
||||
"""Revolution Pi disappeared."""
|
||||
pi.logger.debug("AvahiSearchThread.remove_service")
|
||||
log.debug("AvahiSearchThread.remove_service")
|
||||
self.removed.emit(name, conf_type)
|
||||
|
||||
def add_service(self, zeroconf: Zeroconf, conf_type: str, name: str) -> None:
|
||||
"""New Revolution Pi found."""
|
||||
pi.logger.debug("AvahiSearchThread.add_service")
|
||||
log.debug("AvahiSearchThread.add_service")
|
||||
info = zeroconf.get_service_info(conf_type, name)
|
||||
if not info:
|
||||
return
|
||||
@@ -49,7 +51,7 @@ class AvahiSearchThread(QtCore.QThread):
|
||||
|
||||
def update_service(self, zeroconf: Zeroconf, conf_type: str, name: str) -> None:
|
||||
"""New data of revolution pi"""
|
||||
pi.logger.debug("AvahiSearchThread.add_service")
|
||||
log.debug("AvahiSearchThread.add_service")
|
||||
info = zeroconf.get_service_info(conf_type, name)
|
||||
if not info:
|
||||
return
|
||||
@@ -58,14 +60,14 @@ class AvahiSearchThread(QtCore.QThread):
|
||||
self.updated.emit(name, info.server, info.port, conf_type, ip)
|
||||
|
||||
def run(self) -> None:
|
||||
pi.logger.debug("Started zero conf discovery.")
|
||||
log.debug("Started zero conf discovery.")
|
||||
zeroconf = Zeroconf()
|
||||
revpi_browser = ServiceBrowser(zeroconf, "_revpipyload._tcp.local.", self)
|
||||
while not self.isInterruptionRequested():
|
||||
# Just hanging around :)
|
||||
self.msleep(self._cycle_wait_ms)
|
||||
zeroconf.close()
|
||||
pi.logger.debug("Stopped zero conf discovery.")
|
||||
log.debug("Stopped zero conf discovery.")
|
||||
|
||||
|
||||
class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
||||
@@ -191,7 +193,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_act_connect_triggered(self) -> None:
|
||||
"""Connect via existing settings or ask for type."""
|
||||
pi.logger.debug("AvahiSearch.on_act_connect_triggered")
|
||||
log.debug("AvahiSearch.on_act_connect_triggered")
|
||||
selected_items = self.tb_revpi.selectedItems()
|
||||
if not selected_items:
|
||||
return
|
||||
@@ -206,7 +208,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_act_connect_ssh_triggered(self) -> None:
|
||||
"""Create new revpi settings with ssh, save and connect."""
|
||||
pi.logger.debug("AvahiSearch.on_act_connect_ssh_triggered")
|
||||
log.debug("AvahiSearch.on_act_connect_ssh_triggered")
|
||||
if self.tb_revpi.currentRow() == -1:
|
||||
return
|
||||
|
||||
@@ -218,7 +220,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_act_connect_xmlrpc_triggered(self) -> None:
|
||||
"""Create new revpi settings with XML-RPC, save and connect."""
|
||||
pi.logger.debug("AvahiSearch.on_act_connect_xmlrpc_triggered")
|
||||
log.debug("AvahiSearch.on_act_connect_xmlrpc_triggered")
|
||||
if self.tb_revpi.currentRow() == -1:
|
||||
return
|
||||
|
||||
@@ -331,7 +333,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
||||
@QtCore.pyqtSlot(int, int)
|
||||
def on_tb_revpi_cellDoubleClicked(self, row: int, column: int) -> None:
|
||||
"""Connect to double-clicked Revolution Pi."""
|
||||
pi.logger.debug("AvahiSearch.on_tb_revpi_cellDoubleClicked")
|
||||
log.debug("AvahiSearch.on_tb_revpi_cellDoubleClicked")
|
||||
selected_items = self.tb_revpi.selectedItems()
|
||||
if not selected_items:
|
||||
return
|
||||
@@ -353,7 +355,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_connect_clicked(self) -> None:
|
||||
"""Connect to selected Revolution Pi."""
|
||||
pi.logger.debug("AvahiSearch.on_btn_connect_clicked")
|
||||
log.debug("AvahiSearch.on_btn_connect_clicked")
|
||||
selected_items = self.tb_revpi.selectedItems()
|
||||
if not selected_items:
|
||||
return
|
||||
@@ -370,7 +372,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_save_clicked(self) -> None:
|
||||
"""Save selected Revolution Pi."""
|
||||
pi.logger.debug("AvahiSearch.on_btn_save_clicked")
|
||||
log.debug("AvahiSearch.on_btn_save_clicked")
|
||||
row_index = self.tb_revpi.currentRow()
|
||||
if row_index == -1:
|
||||
return
|
||||
|
||||
@@ -10,7 +10,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from .ui.backgroundworker_ui import Ui_diag_backgroundworker
|
||||
|
||||
log = getLogger()
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class BackgroundWorker(QtCore.QThread):
|
||||
|
||||
@@ -5,6 +5,7 @@ __copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
import pickle
|
||||
from logging import getLogger
|
||||
from xmlrpc.client import Binary, Fault, MultiCall, MultiCallIterator
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
@@ -14,6 +15,8 @@ from . import proginit as pi
|
||||
from .debugios import DebugIos
|
||||
from .ui.debugcontrol_ui import Ui_wid_debugcontrol
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class PsValues(QtCore.QThread):
|
||||
"""
|
||||
@@ -31,7 +34,7 @@ class PsValues(QtCore.QThread):
|
||||
|
||||
def run(self):
|
||||
"""Read IO values of Revolution Pi."""
|
||||
pi.logger.debug("PsValues.run enter")
|
||||
log.debug("PsValues.run enter")
|
||||
|
||||
while not self.isInterruptionRequested():
|
||||
try:
|
||||
@@ -39,16 +42,16 @@ class PsValues(QtCore.QThread):
|
||||
helper.cm.call_remote_function("ps_values", raise_exception=True)
|
||||
)
|
||||
except Fault:
|
||||
pi.logger.warning("Detected piCtory reset.")
|
||||
log.warning("Detected piCtory reset.")
|
||||
self.requestInterruption()
|
||||
self.driver_reset_detected.emit()
|
||||
except Exception as e:
|
||||
pi.logger.error(e)
|
||||
log.error(e)
|
||||
self.process_image_received.emit(Binary())
|
||||
|
||||
self.msleep(self._cycle_time)
|
||||
|
||||
pi.logger.debug("PsValues.run exit")
|
||||
log.debug("PsValues.run exit")
|
||||
|
||||
|
||||
class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
@@ -87,11 +90,11 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
self.shc_write_o.activated.connect(self.on_btn_write_o_clicked)
|
||||
|
||||
def __del__(self):
|
||||
pi.logger.debug("DebugControl.__del__")
|
||||
log.debug("DebugControl.__del__")
|
||||
|
||||
def _set_gui_control_states(self):
|
||||
"""Set states depending on acl level."""
|
||||
pi.logger.debug("DebugControl._set_gui_control_states")
|
||||
log.debug("DebugControl._set_gui_control_states")
|
||||
# xml_mode view >= 1
|
||||
# xml_mode write >= 3
|
||||
self.btn_read_io.setEnabled(not self.cbx_write.isChecked())
|
||||
@@ -109,7 +112,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
|
||||
:param device_position: Only device position or -1 for all
|
||||
"""
|
||||
pi.logger.debug("DebugControl._destroy_io_view")
|
||||
log.debug("DebugControl._destroy_io_view")
|
||||
for position in sorted(self.dict_devices) if device_position == -1 else [device_position]:
|
||||
if position in self.dict_windows:
|
||||
# Remove singe window and button
|
||||
@@ -151,11 +154,11 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
try:
|
||||
ba_values = helper.cm.call_remote_function("ps_values", raise_exception=True)
|
||||
except Fault:
|
||||
pi.logger.warning("Detected piCtory reset.")
|
||||
log.warning("Detected piCtory reset.")
|
||||
self._driver_reset_detected()
|
||||
return
|
||||
except Exception as e:
|
||||
pi.logger.error(e)
|
||||
log.error(e)
|
||||
ba_values = Binary()
|
||||
|
||||
# From now on use bytes instead of Binary
|
||||
@@ -255,7 +258,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
return
|
||||
elif not isinstance(return_list, list):
|
||||
return
|
||||
pi.logger.debug("DebugControl._validate_multicall")
|
||||
log.debug("DebugControl._validate_multicall")
|
||||
|
||||
str_errmsg = ""
|
||||
for lst_result in return_list: # type: list
|
||||
@@ -272,13 +275,13 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
self.dict_windows[lst_result[0]].reset_change_value_colors(lst_result[1])
|
||||
|
||||
if str_errmsg != "":
|
||||
pi.logger.error(str_errmsg)
|
||||
log.error(str_errmsg)
|
||||
if not self.cbx_refresh.isChecked():
|
||||
QtWidgets.QMessageBox.critical(self, self.tr("Error"), str_errmsg)
|
||||
|
||||
def deleteLater(self):
|
||||
"""Clean up all sub windows."""
|
||||
pi.logger.debug("DebugControl.deleteLater")
|
||||
log.debug("DebugControl.deleteLater")
|
||||
|
||||
self.cbx_write.setChecked(False)
|
||||
self.cbx_refresh.setChecked(False)
|
||||
@@ -288,7 +291,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
|
||||
def reload_devices(self):
|
||||
"""Rebuild GUI depending on devices and ios of Revolution Pi."""
|
||||
pi.logger.debug("DebugControl.reload_devices")
|
||||
log.debug("DebugControl.reload_devices")
|
||||
|
||||
if not helper.cm.call_remote_function("psstart", default_value=False):
|
||||
# RevPiPyLoad does not support psstart (too old)
|
||||
@@ -358,7 +361,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
@QtCore.pyqtSlot(bool)
|
||||
def on_btn_device_clicked(self, checked: bool):
|
||||
"""Open or close IO window."""
|
||||
pi.logger.debug("DebugControl.on_btn_device_clicked")
|
||||
log.debug("DebugControl.on_btn_device_clicked")
|
||||
|
||||
position = int(self.sender().objectName())
|
||||
if position in self.dict_windows:
|
||||
@@ -369,14 +372,14 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
@QtCore.pyqtSlot(int)
|
||||
def on_device_closed(self, position: int):
|
||||
"""Change the check state of button, if window was closed."""
|
||||
pi.logger.debug("DebugControl.on_device_closed")
|
||||
log.debug("DebugControl.on_device_closed")
|
||||
btn = self.gb_devices.findChild(QtWidgets.QPushButton, str(position)) # type: QtWidgets.QPushButton
|
||||
btn.setChecked(False)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_read_io_pressed(self):
|
||||
"""Read all IO values and replace changed ones."""
|
||||
pi.logger.debug("DebugControl.on_btn_read_io_pressed")
|
||||
log.debug("DebugControl.on_btn_read_io_pressed")
|
||||
for win in self.dict_windows.values(): # type: DebugIos
|
||||
win.reset_label_colors()
|
||||
self._work_values()
|
||||
@@ -384,14 +387,14 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_refresh_io_pressed(self):
|
||||
"""Read all IO values but do not touch changed ones."""
|
||||
pi.logger.debug("DebugControl.on_btn_refresh_io_pressed")
|
||||
log.debug("DebugControl.on_btn_refresh_io_pressed")
|
||||
if not self.cbx_refresh.isChecked():
|
||||
self._work_values(refresh=True)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_write_o_clicked(self):
|
||||
"""Write outputs."""
|
||||
pi.logger.debug("DebugControl.on_btn_write_o_clicked")
|
||||
log.debug("DebugControl.on_btn_write_o_clicked")
|
||||
if not self.cbx_write.isChecked() and (helper.cm.xml_mode >= 3 or helper.cm.simulating):
|
||||
for win in self.dict_windows.values(): # type: DebugIos
|
||||
win.reset_label_colors()
|
||||
@@ -400,7 +403,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
@QtCore.pyqtSlot(int)
|
||||
def on_cbx_refresh_stateChanged(self, state: int):
|
||||
"""Start or stop the auto refresh thread."""
|
||||
pi.logger.debug("DebugControl.cbx_refresh_stateChanged")
|
||||
log.debug("DebugControl.cbx_refresh_stateChanged")
|
||||
|
||||
# Start / stop worker thread
|
||||
if state == QtCore.Qt.Checked and (helper.cm.connected or helper.cm.simulating):
|
||||
@@ -433,7 +436,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def on_cbx_write_stateChanged(self, state: int):
|
||||
pi.logger.debug("DebugControl.cbx_write_stateChanged")
|
||||
log.debug("DebugControl.cbx_write_stateChanged")
|
||||
checked = state == QtCore.Qt.Checked
|
||||
for win in self.dict_windows.values(): # type: DebugIos
|
||||
win.write_values = checked
|
||||
|
||||
@@ -5,13 +5,15 @@ __copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
import struct
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from . import helper
|
||||
from . import proginit as pi
|
||||
from .ui.debugios_ui import Ui_win_debugios
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
"""IO window of one device."""
|
||||
@@ -46,10 +48,10 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
self.style_sheet = "background-color: red;"
|
||||
|
||||
def __del__(self):
|
||||
pi.logger.debug("DebugIos.__del__")
|
||||
log.debug("DebugIos.__del__")
|
||||
|
||||
def closeEvent(self, a0: QtGui.QCloseEvent):
|
||||
pi.logger.debug("DebugIos.closeEvent")
|
||||
log.debug("DebugIos.closeEvent")
|
||||
helper.cm.settings.debug_geos[self.position] = self.saveGeometry()
|
||||
self.device_closed.emit(self.position)
|
||||
|
||||
@@ -99,6 +101,12 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
signed = io[6]
|
||||
word_order = io[7] if len(io) > 7 else "ignored"
|
||||
|
||||
# Since RevPiPyLoad 0.11.0rc2 we have a list with async functions
|
||||
if len(io) > 8:
|
||||
async_call = io[8]
|
||||
else:
|
||||
async_call = []
|
||||
|
||||
val = container.findChild(self.search_class, name)
|
||||
if val is not None:
|
||||
# Destroy IO if the properties was changed
|
||||
@@ -108,28 +116,45 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
signed != val.property("signed"):
|
||||
del self.__qwa[name]
|
||||
layout.removeRow(layout.getWidgetPosition(val)[0])
|
||||
pi.logger.debug("Destroy property changed IO '{0}'".format(name))
|
||||
log.debug("Destroy property changed IO '{0}'".format(name))
|
||||
else:
|
||||
continue
|
||||
|
||||
lbl = QtWidgets.QLabel(name, container)
|
||||
lbl.setObjectName("lbl_".format(name))
|
||||
lbl.setStyleSheet(self.style_sheet)
|
||||
|
||||
val = self._create_widget(name, byte_length, bit_address, byteorder, signed, read_only, word_order)
|
||||
lbl, val = self._create_widgets(
|
||||
name,
|
||||
byte_length,
|
||||
bit_address,
|
||||
byteorder,
|
||||
signed,
|
||||
read_only,
|
||||
word_order,
|
||||
async_call,
|
||||
)
|
||||
lbl.setParent(container)
|
||||
val.setParent(container)
|
||||
layout.insertRow(counter, val, lbl)
|
||||
|
||||
self.splitter.setSizes([1, 1])
|
||||
|
||||
def _create_widget(
|
||||
def _create_widgets(
|
||||
self, name: str, byte_length: int, bit_address: int, byteorder: str, signed: bool, read_only: bool,
|
||||
word_order: str):
|
||||
word_order: str, async_call: list):
|
||||
"""Create widget in functions address space to use lambda functions."""
|
||||
# Create lable to set same properties of value widget for context menues
|
||||
lbl = QtWidgets.QLabel(name)
|
||||
lbl.setObjectName("lbl_".format(name))
|
||||
lbl.setStyleSheet(self.style_sheet)
|
||||
|
||||
if bit_address >= 0:
|
||||
val = QtWidgets.QCheckBox()
|
||||
val.setEnabled(not read_only)
|
||||
|
||||
if async_call:
|
||||
lbl.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
val.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
lbl.customContextMenuRequested.connect(self.on_context_menu)
|
||||
val.customContextMenuRequested.connect(self.on_context_menu)
|
||||
|
||||
# Set alias to use the same function name on all widget types
|
||||
val.setValue = val.setChecked
|
||||
if not read_only:
|
||||
@@ -140,9 +165,12 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
# Bytes or string
|
||||
val = QtWidgets.QLineEdit()
|
||||
val.setReadOnly(read_only)
|
||||
lbl.setProperty("struct_type", "text")
|
||||
val.setProperty("struct_type", "text")
|
||||
|
||||
lbl.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
val.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
lbl.customContextMenuRequested.connect(self.on_context_menu)
|
||||
val.customContextMenuRequested.connect(self.on_context_menu)
|
||||
|
||||
# Set alias to use the same function name on all widget types
|
||||
@@ -156,13 +184,20 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
|
||||
val = QtWidgets.QDoubleSpinBox()
|
||||
val.setReadOnly(read_only)
|
||||
lbl.setProperty("struct_type", struct_type)
|
||||
val.setProperty("struct_type", struct_type)
|
||||
lbl.setProperty("frm", "{0}{1}".format(
|
||||
">" if byteorder == "big" else "<",
|
||||
struct_type.lower() if signed else struct_type
|
||||
))
|
||||
val.setProperty("frm", "{0}{1}".format(
|
||||
">" if byteorder == "big" else "<",
|
||||
struct_type.lower() if signed else struct_type
|
||||
))
|
||||
|
||||
lbl.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
val.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
lbl.customContextMenuRequested.connect(self.on_context_menu)
|
||||
val.customContextMenuRequested.connect(self.on_context_menu)
|
||||
|
||||
val.setDecimals(0)
|
||||
@@ -172,15 +207,23 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
if not read_only:
|
||||
val.valueChanged.connect(self._change_sbx_dvalue)
|
||||
|
||||
lbl.setObjectName(name)
|
||||
val.setObjectName(name)
|
||||
lbl.setProperty("big_endian", byteorder == "big")
|
||||
val.setProperty("big_endian", byteorder == "big")
|
||||
lbl.setProperty("bit_address", bit_address)
|
||||
val.setProperty("bit_address", bit_address)
|
||||
lbl.setProperty("byte_length", byte_length)
|
||||
val.setProperty("byte_length", byte_length)
|
||||
lbl.setProperty("signed", signed)
|
||||
val.setProperty("signed", signed)
|
||||
lbl.setProperty("word_order", word_order)
|
||||
val.setProperty("word_order", word_order)
|
||||
lbl.setProperty("async_call", async_call)
|
||||
val.setProperty("async_call", async_call)
|
||||
|
||||
self.__qwa[name] = val
|
||||
return val
|
||||
return lbl, val
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def _change_cbx_value(self, value: int):
|
||||
@@ -209,11 +252,36 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
@QtCore.pyqtSlot(QtCore.QPoint)
|
||||
def on_context_menu(self, point: QtCore.QPoint):
|
||||
"""Generate menu for data format changes."""
|
||||
pi.logger.debug("DebugIos.on_context_menu")
|
||||
log.debug("DebugIos.on_context_menu")
|
||||
|
||||
sender = self.sender()
|
||||
men = QtWidgets.QMenu(sender)
|
||||
|
||||
act_reset = QtWidgets.QAction(self.tr("Reset counter"))
|
||||
if "di_reset" in sender.property("async_call"):
|
||||
men.addAction(act_reset)
|
||||
men.addSeparator()
|
||||
|
||||
if "ro_get_switching_cycles" in sender.property("async_call"):
|
||||
switching_cycles = helper.cm.call_remote_function(
|
||||
"ps_switching_cycles",
|
||||
sender.objectName(),
|
||||
default_value=self.tr("Can not display"),
|
||||
)
|
||||
if type(switching_cycles) is not list:
|
||||
switching_cycles = [switching_cycles]
|
||||
for i in range(len(switching_cycles)):
|
||||
relais_counter = self.tr(" Relais {0}").format(i + 1)
|
||||
if len(switching_cycles) == 1:
|
||||
relais_counter = ""
|
||||
men.addAction(
|
||||
self.tr("Switching cycles{0}: {1}").format(
|
||||
relais_counter,
|
||||
switching_cycles[i],
|
||||
)
|
||||
)
|
||||
men.addSeparator()
|
||||
|
||||
if sender.property("byte_length") > 4:
|
||||
# Textbox needs format buttons
|
||||
act_as_text = QtWidgets.QAction(self.tr("as text"))
|
||||
@@ -228,12 +296,14 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
act_signed = QtWidgets.QAction(self.tr("signed"), men)
|
||||
act_signed.setCheckable(True)
|
||||
act_signed.setChecked(sender.property("signed") or False)
|
||||
men.addAction(act_signed)
|
||||
if sender.property("bit_address") == -1:
|
||||
men.addAction(act_signed)
|
||||
|
||||
act_byteorder = QtWidgets.QAction(self.tr("big_endian"), men)
|
||||
act_byteorder.setCheckable(True)
|
||||
act_byteorder.setChecked(sender.property("big_endian") or False)
|
||||
men.addAction(act_byteorder)
|
||||
if sender.property("bit_address") == -1:
|
||||
men.addAction(act_byteorder)
|
||||
|
||||
if sender.property("byte_length") > 2:
|
||||
act_wordorder = QtWidgets.QAction(self.tr("switch wordorder"))
|
||||
@@ -263,6 +333,12 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
sender.setProperty("big_endian", act_byteorder.isChecked())
|
||||
elif rc == act_wordorder:
|
||||
sender.setProperty("word_order", "big" if act_wordorder.isChecked() else "little")
|
||||
elif rc == act_reset:
|
||||
try:
|
||||
helper.cm.call_remote_function("ps_reset_counter", sender.objectName(), raise_exception=True)
|
||||
except Exception as e:
|
||||
log.error(e)
|
||||
QtWidgets.QMessageBox.critical(self, self.tr("Error"), self.tr("Could not reset the counter value"))
|
||||
|
||||
if sender.property("frm"):
|
||||
sender.setProperty("frm", "{0}{1}".format(
|
||||
@@ -289,7 +365,7 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
|
||||
:param io_name: Clean up only this IO
|
||||
"""
|
||||
pi.logger.debug("DebugIos.reset_change_value_colors")
|
||||
log.debug("DebugIos.reset_change_value_colors")
|
||||
if io_name is None:
|
||||
lst_wid = self.saw_out.findChildren(
|
||||
self.search_class, options=QtCore.Qt.FindDirectChildrenOnly)
|
||||
@@ -346,7 +422,7 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||
)
|
||||
return actual_value, last_value
|
||||
except Exception:
|
||||
pi.logger.error("Could not convert '{0}' to bytes".format(actual_value))
|
||||
log.error("Could not convert '{0}' to bytes".format(actual_value))
|
||||
pass
|
||||
|
||||
return actual_value.encode(), last_value.encode()
|
||||
|
||||
@@ -8,6 +8,7 @@ import pickle
|
||||
import socket
|
||||
from enum import IntEnum
|
||||
from http.client import CannotSendRequest
|
||||
from logging import getLogger
|
||||
from os import environ, remove
|
||||
from os.path import exists
|
||||
from queue import Queue
|
||||
@@ -22,6 +23,8 @@ from paramiko.ssh_exception import AuthenticationException
|
||||
from . import proginit as pi
|
||||
from .ssh_tunneling.server import SSHLocalTunnel
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
settings = QtCore.QSettings("revpimodio.org", "revpicommander")
|
||||
"""Global application settings."""
|
||||
|
||||
@@ -45,6 +48,7 @@ class WidgetData(IntEnum):
|
||||
host_name = 267
|
||||
host_name_full = 268
|
||||
file_name = 309
|
||||
is_plc_program = 310
|
||||
revpi_settings = 320
|
||||
|
||||
|
||||
@@ -222,6 +226,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
self._cli = None
|
||||
self._cli_connect = Queue()
|
||||
self._cycle_time = cycle_time_ms
|
||||
self._has_error = False
|
||||
self._lck_cli = Lock()
|
||||
self._ps_started = False
|
||||
self._revpi = None
|
||||
@@ -243,7 +248,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
self._xml_mode_refresh = False
|
||||
|
||||
def __call_simulator(self, function_name: str, *args, default_value=None, **kwargs):
|
||||
pi.logger.debug("ConnectionManager.__call_simulator({0})".format(function_name))
|
||||
log.debug("ConnectionManager.__call_simulator({0})".format(function_name))
|
||||
if function_name == "ps_values":
|
||||
if self._revpi.readprocimg():
|
||||
bytebuff = bytearray()
|
||||
@@ -387,7 +392,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
xml_funcs = sp.system.listMethods()
|
||||
xml_mode = sp.xmlmodus()
|
||||
except Exception as e:
|
||||
pi.logger.exception(e)
|
||||
log.exception(e)
|
||||
self.connection_error_observed.emit(str(e))
|
||||
|
||||
if revpi_settings.ssh_use_tunnel:
|
||||
@@ -451,7 +456,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
self._revpi = None
|
||||
self._revpi_output = None
|
||||
|
||||
pi.logger.debug("Simulator destroyed.")
|
||||
log.debug("Simulator destroyed.")
|
||||
self.connection_disconnected.emit()
|
||||
|
||||
elif self._cli is not None:
|
||||
@@ -483,7 +488,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
:param procimg: Process image, which is a 4 kByte file for simulation
|
||||
:param clean_existing: Reset the file to ZERO \x00 bytes
|
||||
"""
|
||||
pi.logger.debug("ConnectionManager.start_simulate")
|
||||
log.debug("ConnectionManager.start_simulate")
|
||||
|
||||
if not exists(procimg) or clean_existing:
|
||||
with open(procimg, "wb") as fh:
|
||||
@@ -507,7 +512,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
self.connection_established.emit()
|
||||
|
||||
except Exception as e:
|
||||
pi.logger.exception(e)
|
||||
log.exception(e)
|
||||
self.connection_error_observed.emit(str(e))
|
||||
self._revpi_output = None
|
||||
self._revpi = None
|
||||
@@ -522,7 +527,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
|
||||
def reset_simulator(self):
|
||||
"""Reset all io to piCtory defaults."""
|
||||
pi.logger.debug("ConnectionManager.reset_simulator")
|
||||
log.debug("ConnectionManager.reset_simulator")
|
||||
if settings.value("simulator/restart_zero", False, bool):
|
||||
with open(self._revpi.procimg, "wb") as fh:
|
||||
fh.write(b'\x00' * 4096)
|
||||
@@ -558,10 +563,11 @@ class ConnectionManager(QtCore.QThread):
|
||||
self.xml_mode = sp.xmlmodus()
|
||||
self._xml_mode_refresh = False
|
||||
except CannotSendRequest as e:
|
||||
pi.logger.warning(e)
|
||||
log.warning(e)
|
||||
except Exception as e:
|
||||
pi.logger.warning(e)
|
||||
log.warning(e)
|
||||
self.status_changed.emit(self.tr("SERVER ERROR"), "red")
|
||||
self._has_error = True
|
||||
self.connection_error_observed.emit("{0} | {1}".format(e, type(e)))
|
||||
|
||||
if self.ssh_tunnel_server and not self.ssh_tunnel_server.connected:
|
||||
@@ -585,6 +591,10 @@ class ConnectionManager(QtCore.QThread):
|
||||
pass
|
||||
|
||||
else:
|
||||
if self._has_error:
|
||||
self._has_error = False
|
||||
self.connection_recovered.emit()
|
||||
|
||||
if plc_exit_code == -1:
|
||||
self.status_changed.emit(self.tr("RUNNING"), "green")
|
||||
elif plc_exit_code == -2:
|
||||
@@ -614,7 +624,7 @@ class ConnectionManager(QtCore.QThread):
|
||||
:return: Return value of remote function or default_value
|
||||
"""
|
||||
if self._cli is None and self._revpi is None:
|
||||
pi.logger.error("Not connected while calling {0}".format(function_name))
|
||||
log.error("Not connected while calling {0}".format(function_name))
|
||||
if raise_exception:
|
||||
raise ConnectionError("Connection manager not connected")
|
||||
return default_value
|
||||
@@ -638,7 +648,8 @@ class ConnectionManager(QtCore.QThread):
|
||||
if reload_funcs:
|
||||
self.xml_funcs = self._cli.system.listMethods()
|
||||
except Exception as e:
|
||||
pi.logger.error(e)
|
||||
self._has_error = True
|
||||
log.error(e)
|
||||
if raise_exception:
|
||||
self._lck_cli.release()
|
||||
raise
|
||||
@@ -722,7 +733,7 @@ def import_old_settings():
|
||||
revpi_setting._settings = settings
|
||||
revpi_setting.save_settings()
|
||||
except Exception:
|
||||
pi.logger.warning("Could not import saved connection {0}".format(i))
|
||||
log.warning("Could not import saved connection {0}".format(i))
|
||||
|
||||
|
||||
import_old_settings()
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -5,11 +5,14 @@ __author__ = "Sven Sager"
|
||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5 import QtGui, QtWidgets
|
||||
|
||||
from . import proginit as pi
|
||||
from .ui.mqttmanager_ui import Ui_diag_mqtt
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class MqttManager(QtWidgets.QDialog, Ui_diag_mqtt):
|
||||
"""MQTT settings for option window."""
|
||||
@@ -55,7 +58,7 @@ class MqttManager(QtWidgets.QDialog, Ui_diag_mqtt):
|
||||
self.txt_password.setText(self.dc["mqttpassword"])
|
||||
self.txt_client_id.setText(self.dc["mqttclient_id"])
|
||||
except Exception as e:
|
||||
pi.logger.exception(e)
|
||||
log.exception(e)
|
||||
self.dc = {}
|
||||
return False
|
||||
return True
|
||||
|
||||
84
src/revpicommander/oss_licenses.py
Normal file
84
src/revpicommander/oss_licenses.py
Normal file
@@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Open-Source softwrae licenses."""
|
||||
__author__ = "Sven Sager"
|
||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
from json import load
|
||||
from logging import getLogger
|
||||
from os.path import exists
|
||||
from typing import List
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from revpicommander.ui.oss_licenses_ui import Ui_diag_oss_licenses
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class OssLicenses(QtWidgets.QDialog, Ui_diag_oss_licenses):
|
||||
def __init__(self, oss_license_file: str, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self._lst_licenses: List[dict] = []
|
||||
self._oss_license_file = oss_license_file
|
||||
|
||||
self.action_start.setVisible(exists(oss_license_file))
|
||||
|
||||
def _load_license_file(self) -> None:
|
||||
if exists(self._oss_license_file):
|
||||
try:
|
||||
with open(self._oss_license_file) as fh:
|
||||
self._lst_licenses = load(fh)
|
||||
except Exception as e:
|
||||
log.error("Could not load oss license file: '{0}'".format(e))
|
||||
|
||||
for i in range(len(self._lst_licenses)):
|
||||
dict_license = self._lst_licenses[i]
|
||||
tb_item_name = QtWidgets.QTableWidgetItem(dict_license.get("Name", ""))
|
||||
tb_item_name.setData(QtCore.Qt.UserRole, i)
|
||||
tb_item_license = QtWidgets.QTableWidgetItem(dict_license.get("License", ""))
|
||||
tb_item_license.setToolTip(tb_item_license.text())
|
||||
tb_item_license.setData(QtCore.Qt.UserRole, i)
|
||||
|
||||
self.tb_oss_licenses.insertRow(i)
|
||||
self.tb_oss_licenses.setItem(i, 0, tb_item_name)
|
||||
self.tb_oss_licenses.setItem(i, 1, tb_item_license)
|
||||
|
||||
self.tb_oss_licenses.resizeColumnsToContents()
|
||||
|
||||
def exec(self) -> int:
|
||||
# Prevent loading every time the program is starting
|
||||
if not self._lst_licenses:
|
||||
self._load_license_file()
|
||||
|
||||
return super().exec()
|
||||
|
||||
@QtCore.pyqtSlot(QtWidgets.QTableWidgetItem, QtWidgets.QTableWidgetItem)
|
||||
def on_tb_oss_licenses_currentItemChanged(
|
||||
self,
|
||||
current: QtWidgets.QTableWidgetItem,
|
||||
previous: QtWidgets.QTableWidgetItem,
|
||||
):
|
||||
log.debug("Enter slot on_tb_oss_licenses_currentItemChanged")
|
||||
license_index = current.data(QtCore.Qt.UserRole)
|
||||
license_object = self._lst_licenses[license_index]
|
||||
license_object["LicenseText"] = license_object["LicenseText"].replace("\n", "<br>")
|
||||
self.txt_license.setHtml(
|
||||
"""<h2>{Name}</h2>
|
||||
<p>{Description}</p>
|
||||
<p>
|
||||
<ul>
|
||||
<li>Version: {Version}</li>
|
||||
<li>Author: {Author}</li>
|
||||
<li>URL: <a href="{URL}">{URL}</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<h3>License: {License}</h3>
|
||||
<p>
|
||||
<code>{LicenseText}</code>
|
||||
</p>""".format(
|
||||
**license_object
|
||||
)
|
||||
)
|
||||
@@ -1,45 +1,130 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Global program initialization."""
|
||||
# SPDX-FileCopyrightText: 2018-2023 Sven Sager
|
||||
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
__author__ = "Sven Sager"
|
||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
__copyright__ = "Copyright (C) 2018-2023 Sven Sager"
|
||||
__license__ = "LGPL-2.0-or-later"
|
||||
__version__ = "1.3.1"
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
from configparser import ConfigParser
|
||||
from os import R_OK, W_OK, access
|
||||
from os.path import abspath, dirname, join
|
||||
from os import R_OK, W_OK, access, environ, getpid, remove
|
||||
from os.path import abspath, dirname, exists, join
|
||||
from shutil import copy, move
|
||||
from threading import Event
|
||||
|
||||
try:
|
||||
# Import program version from meta data module of your program
|
||||
from . import __version__ as external_version
|
||||
except Exception:
|
||||
external_version = None
|
||||
|
||||
# Program name
|
||||
programname = "revpicommander"
|
||||
program_version = external_version
|
||||
|
||||
# Set to True, if you want to save config file
|
||||
conf_rw = False
|
||||
conf_rw = False # If you want so save the configuration with .save_conf() set to True
|
||||
conf_rw_save = False # Create new conf file in same directory and move to old one
|
||||
conf_rw_backup = False # Keep a backup of old conf file [filename].bak
|
||||
_extend_daemon_startup_timeout = 0.0 # Default startup timeout is 90 seconds
|
||||
|
||||
conf = ConfigParser()
|
||||
logger = logging.getLogger()
|
||||
pidfile = "/var/run/{0}.pid".format(programname)
|
||||
_daemon_started_up = Event()
|
||||
_daemon_main_pid = getpid()
|
||||
_systemd_notify = environ.get("NOTIFY_SOCKET", None)
|
||||
if _systemd_notify:
|
||||
from socket import AF_UNIX, SOCK_DGRAM, socket
|
||||
|
||||
# Set up the notification socket for systemd communication
|
||||
_systemd_socket = socket(family=AF_UNIX, type=SOCK_DGRAM)
|
||||
if _extend_daemon_startup_timeout:
|
||||
# Extend systemd TimeoutStartSec by defined timeout extension in micro seconds
|
||||
_systemd_socket.sendto(
|
||||
f"EXTEND_TIMEOUT_USEC={_extend_daemon_startup_timeout * 1000000}\n",
|
||||
_systemd_notify,
|
||||
)
|
||||
|
||||
|
||||
def can_be_forked():
|
||||
"""
|
||||
Check the possibility of forking the process.
|
||||
|
||||
Under certain circumstances, a process cannot be forked. These include
|
||||
certain build settings or packaging, as well as the missing function on
|
||||
some operating systems.
|
||||
|
||||
:return: True, if forking is possible
|
||||
"""
|
||||
from sys import platform
|
||||
|
||||
# Windows operating system does not support the .fork() call
|
||||
if platform.startswith("win"):
|
||||
return False
|
||||
|
||||
# A PyInstaller bundle does not support the .fork() call
|
||||
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def cleanup():
|
||||
"""Clean up program."""
|
||||
"""
|
||||
Clean up before exit the program.
|
||||
|
||||
This function must be called at the end of the program. It flushes
|
||||
the logging buffers and deletes the PID file in daemon mode.
|
||||
"""
|
||||
if pargs.daemon and exists(pidfile):
|
||||
remove(pidfile)
|
||||
|
||||
# Shutdown logging system
|
||||
logging.shutdown()
|
||||
|
||||
# Close logfile
|
||||
if pargs.daemon:
|
||||
sys.stdout.close()
|
||||
|
||||
|
||||
def reconfigure_logger():
|
||||
"""Configure logging module of program."""
|
||||
|
||||
class FilterDebug(logging.Filter):
|
||||
"""Set this filter to log handler if verbose level is > 1."""
|
||||
|
||||
def filter(self, record: logging.LogRecord) -> bool:
|
||||
remove_record = False
|
||||
|
||||
# Remove paramiko ssh module
|
||||
remove_record = remove_record or record.name.startswith("paramiko")
|
||||
|
||||
return not remove_record
|
||||
|
||||
# Clear all log handler
|
||||
for lhandler in logger.handlers.copy():
|
||||
lhandler.close()
|
||||
logger.removeHandler(lhandler)
|
||||
|
||||
if pargs.daemon:
|
||||
# Create daemon log file
|
||||
fh_logfile = open("/var/log/{0}.log".format(programname), "a")
|
||||
|
||||
# Close stdout and use logfile
|
||||
sys.stdout.close()
|
||||
sys.stdout = fh_logfile
|
||||
sys.stderr = sys.stdout
|
||||
|
||||
# Create new log handler
|
||||
logformat = logging.Formatter(
|
||||
"{asctime} [{levelname:8}] {message}",
|
||||
datefmt="%Y-%m-%d %H:%M:%S", style="{"
|
||||
)
|
||||
if pargs.verbose > 2:
|
||||
log_frm = "{asctime} [{levelname:8}] {name} {message}"
|
||||
else:
|
||||
log_frm = "{asctime} [{levelname:8}] {message}"
|
||||
logformat = logging.Formatter(log_frm, datefmt="%Y-%m-%d %H:%M:%S", style="{")
|
||||
lhandler = logging.StreamHandler(sys.stdout)
|
||||
lhandler.setFormatter(logformat)
|
||||
logger.addHandler(lhandler)
|
||||
@@ -54,59 +139,193 @@ def reconfigure_logger():
|
||||
if pargs.verbose == 1:
|
||||
loglevel = logging.INFO
|
||||
elif pargs.verbose > 1:
|
||||
lhandler.addFilter(FilterDebug())
|
||||
loglevel = logging.DEBUG
|
||||
else:
|
||||
loglevel = logging.WARNING
|
||||
logger.setLevel(loglevel)
|
||||
|
||||
|
||||
def reload_conf():
|
||||
"""Reload config file."""
|
||||
if "conffile" in pargs:
|
||||
def reload_conf(clear_load=False) -> None:
|
||||
"""
|
||||
Reload config file.
|
||||
|
||||
After successful reload, call set_startup_complete() function to inform
|
||||
systemd that all functions are available again.
|
||||
|
||||
If keys are commented out in conf file, they will still be in the conf file.
|
||||
To remove not existing keys set clear_load to True.
|
||||
|
||||
:param clear_load: Clear conf before reload
|
||||
"""
|
||||
if _systemd_notify:
|
||||
# Inform systemd about reloading configuration
|
||||
_systemd_socket.sendto(b"RELOADING=1\n", _systemd_notify)
|
||||
|
||||
# Reset started up event for the set_startup_complete function
|
||||
_daemon_started_up.clear()
|
||||
|
||||
if "conffile" in pargs:
|
||||
# Check config file
|
||||
if not access(pargs.conffile, R_OK):
|
||||
raise RuntimeError(
|
||||
"can not access config file '{0}'".format(pargs.conffile)
|
||||
)
|
||||
if conf_rw and not access(pargs.conffile, W_OK):
|
||||
raise RuntimeError(
|
||||
"can not write to config file '{0}'".format(pargs.conffile)
|
||||
)
|
||||
raise RuntimeError("can not access config file '{0}'".format(pargs.conffile))
|
||||
if conf_rw:
|
||||
if (conf_rw_save or conf_rw_backup) and not access(dirname(pargs.conffile), W_OK):
|
||||
raise RuntimeError(
|
||||
"can not wirte to directory '{0}' to create files"
|
||||
"".format(dirname(pargs.conffile))
|
||||
)
|
||||
if not access(pargs.conffile, W_OK):
|
||||
raise RuntimeError("can not write to config file '{0}'".format(pargs.conffile))
|
||||
|
||||
# Create global config
|
||||
global conf
|
||||
if clear_load:
|
||||
# Clear all sections and do not create a new instance
|
||||
for section in conf.sections():
|
||||
conf.remove_section(section)
|
||||
|
||||
# Read configuration
|
||||
logger.info("loading config file: {0}".format(pargs.conffile))
|
||||
conf.read(pargs.conffile)
|
||||
|
||||
|
||||
def save_conf():
|
||||
"""Save configuration."""
|
||||
if not conf_rw:
|
||||
raise RuntimeError("You have to set conf_rw to True.")
|
||||
if "conffile" in pargs:
|
||||
if conf_rw_backup:
|
||||
copy(pargs.conffile, pargs.conffile + ".bak")
|
||||
if conf_rw_save:
|
||||
with open(pargs.conffile + ".new", "w") as fh:
|
||||
conf.write(fh)
|
||||
move(pargs.conffile + ".new", pargs.conffile)
|
||||
else:
|
||||
with open(pargs.conffile, "w") as fh:
|
||||
conf.write(fh)
|
||||
|
||||
|
||||
def startup_complete():
|
||||
"""
|
||||
Call this when the daemon is completely started.
|
||||
|
||||
When a daemon is started, it may take some time for everything to be
|
||||
available. This function notifies the init system when all functions of
|
||||
this daemon are available so that the starts of further daemons can be
|
||||
properly timed.
|
||||
|
||||
The systemd unit file that is supposed to start this demon must be set
|
||||
to 'Type=notify'. If the daemon supports reloading the settings,
|
||||
'ExecReload=/bin/kill -HUP $MAINPID' must also be set. The daemon must
|
||||
call this function again after the reload in order to signal systemd the
|
||||
completed reload.
|
||||
|
||||
If systemd is available from version 250 and the daemon supports reloading
|
||||
the settings, 'Type=notify-reload' can be used without 'ExecReload'. The
|
||||
type 'notify-reload' is preferable if possible, as the reloading of the
|
||||
daemon is also synchronized with systemd.
|
||||
|
||||
If the '--fork' parameter is used, the main process ends after calling
|
||||
this function to prevent the further start of demons by other init systems.
|
||||
"""
|
||||
if _daemon_started_up.is_set():
|
||||
# Everyone was notified about complete start, if set
|
||||
return
|
||||
|
||||
if _systemd_notify:
|
||||
# Inform systemd about complete startup of daemon process
|
||||
_systemd_socket.sendto(b"READY=1\n", _systemd_notify)
|
||||
|
||||
if pargs.daemon:
|
||||
from os import kill
|
||||
|
||||
# Send SIGTERM signal to main process
|
||||
kill(_daemon_main_pid, 15)
|
||||
|
||||
_daemon_started_up.set()
|
||||
|
||||
|
||||
# Generate command arguments of the program
|
||||
parser = ArgumentParser(
|
||||
prog=programname,
|
||||
description="Program description"
|
||||
# todo: Add program description for help
|
||||
description="Program description",
|
||||
)
|
||||
parser.add_argument("--version", action="version", version=f"%(prog)s {program_version}")
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--logfile",
|
||||
dest="logfile",
|
||||
help="save log entries to this file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f", "--logfile", dest="logfile",
|
||||
help="Save log entries to this file"
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="count",
|
||||
dest="verbose",
|
||||
default=0,
|
||||
help="switch on verbose logging",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", action="count", dest="verbose", default=0,
|
||||
help="Switch on verbose logging"
|
||||
)
|
||||
# The __main__ script will process the version number argument
|
||||
parser.add_argument("--version", action="store_true", help="Print version number of program and exit")
|
||||
# If packed with opensource licenses, add argument to print license information about bundled modules
|
||||
open_source_licenses = join(dirname(__file__), "open-source-licenses", "open-source-licenses.txt")
|
||||
if exists(open_source_licenses):
|
||||
parser.add_argument(
|
||||
"--open-source-licenses",
|
||||
action="store_true",
|
||||
dest="oss_licenses",
|
||||
help="print packed open-source-licenses and exit",
|
||||
)
|
||||
pargs = parser.parse_args()
|
||||
|
||||
# Process open-source-licenses argument, if set (only affects bundled apps)
|
||||
if "oss_licenses" in pargs and pargs.oss_licenses:
|
||||
with open(open_source_licenses, "r") as fh:
|
||||
sys.stdout.write(fh.read())
|
||||
sys.exit(0)
|
||||
|
||||
# Check important objects and set to default if they do not exists
|
||||
if "daemon" not in pargs:
|
||||
pargs.daemon = False
|
||||
if "verbose" not in pargs:
|
||||
pargs.verbose = 0
|
||||
|
||||
# Check if the program should run as a daemon
|
||||
if pargs.daemon:
|
||||
# Check if daemon is already running
|
||||
if exists(pidfile):
|
||||
logger.error("Program already running as daemon. Check '{0}'".format(pidfile))
|
||||
sys.exit(1)
|
||||
|
||||
# Fork to daemon
|
||||
from os import fork
|
||||
|
||||
pid = fork()
|
||||
if pid > 0:
|
||||
# Main process waits for exit till startup is complete
|
||||
from os import kill
|
||||
from signal import SIGKILL, SIGTERM, signal
|
||||
|
||||
# Catch the TERM signal, which will be sent from the forked process after startup_complete
|
||||
signal(SIGTERM, lambda number, frame: _daemon_started_up.set())
|
||||
|
||||
# Use the default timeout of 90 seconds from systemd also for the '--daemon' flag
|
||||
if not _daemon_started_up.wait(90.0 + _extend_daemon_startup_timeout):
|
||||
sys.stderr.write(
|
||||
"Run into startup complete timout! Killing fork and exit main process\n"
|
||||
)
|
||||
kill(pid, SIGKILL)
|
||||
sys.exit(1)
|
||||
|
||||
# Main process writes pidfile with pid of forked process
|
||||
with open(pidfile, "w") as f:
|
||||
f.write(str(pid))
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
# Get absolute paths
|
||||
pwd = abspath(".")
|
||||
|
||||
# Configure logger
|
||||
if "logfile" in pargs and pargs.logfile is not None \
|
||||
and dirname(pargs.logfile) == "":
|
||||
if "logfile" in pargs and pargs.logfile is not None and dirname(pargs.logfile) == "":
|
||||
pargs.logfile = join(pwd, pargs.logfile)
|
||||
reconfigure_logger()
|
||||
|
||||
|
||||
@@ -7,10 +7,12 @@ __copyright__ = "Copyright (C) 2018 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
import webbrowser
|
||||
from logging import getLogger
|
||||
from os.path import dirname, join
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from revpicommander.oss_licenses import OssLicenses
|
||||
from . import __version__
|
||||
from . import helper
|
||||
from . import proginit as pi
|
||||
@@ -28,6 +30,8 @@ from .simulator import Simulator
|
||||
from .sshauth import SSHAuth
|
||||
from .ui.revpicommander_ui import Ui_win_revpicommander
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class ConnectingPyload(QtCore.QThread):
|
||||
"""
|
||||
@@ -87,8 +91,14 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
||||
|
||||
self.setWindowFlag(QtCore.Qt.WindowMaximizeButtonHint, False)
|
||||
|
||||
# Load oss licenses dialog, to show licenses, if this is build with app target
|
||||
self.diag_oss_licenses = OssLicenses(pi.open_source_licenses[:-3] + "json", self)
|
||||
self.men_help.addAction(self.diag_oss_licenses.action_start)
|
||||
|
||||
pi.startup_complete()
|
||||
|
||||
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
||||
pi.logger.debug("RevPiCommander.closeEvent")
|
||||
log.debug("RevPiCommander.closeEvent")
|
||||
helper.cm.pyload_disconnect()
|
||||
helper.settings.setValue("revpicommander/geo", self.saveGeometry())
|
||||
|
||||
@@ -157,7 +167,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_cm_connection_disconnected(self):
|
||||
"""Connection of connection manager was disconnected."""
|
||||
pi.logger.debug("RevPiCommander.on_cm_connection_disconnected")
|
||||
log.debug("RevPiCommander.on_cm_connection_disconnected")
|
||||
|
||||
self._set_gui_control_states()
|
||||
self.txt_host.setVisible(True)
|
||||
@@ -167,7 +177,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_cm_connection_disconnecting(self):
|
||||
"""Connection of connection manager will now disconnect."""
|
||||
pi.logger.debug("RevPiCommander.on_cm_connection_disconnecting")
|
||||
log.debug("RevPiCommander.on_cm_connection_disconnecting")
|
||||
|
||||
# This will remove the widgets in the button functions
|
||||
self.btn_plc_debug.setChecked(False)
|
||||
@@ -184,7 +194,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_cm_connection_established(self):
|
||||
"""Connection manager established a new connection and loaded values."""
|
||||
pi.logger.debug("RevPiCommander.on_cm_connection_established")
|
||||
log.debug("RevPiCommander.on_cm_connection_established")
|
||||
|
||||
self._set_gui_control_states()
|
||||
if helper.cm.simulating:
|
||||
@@ -325,7 +335,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
||||
).format(procimg_file, configrsc_file)
|
||||
)
|
||||
else:
|
||||
pi.logger.error("Can not start simulator")
|
||||
log.error("Can not start simulator")
|
||||
QtWidgets.QMessageBox.critical(
|
||||
self, self.tr("Can not start..."), self.tr(
|
||||
"Can not start the simulator! Maybe the piCtory file is corrupt "
|
||||
|
||||
@@ -7,16 +7,18 @@ __license__ = "GPLv2"
|
||||
import gzip
|
||||
import os
|
||||
from enum import IntEnum
|
||||
from logging import getLogger
|
||||
from xmlrpc.client import Binary
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from . import helper
|
||||
from . import proginit as pi
|
||||
from .backgroundworker import BackgroundWorker
|
||||
from .helper import WidgetData
|
||||
from .ui.files_ui import Ui_win_files
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class NodeType(IntEnum):
|
||||
FILE = 1000
|
||||
@@ -58,7 +60,7 @@ class UploadFiles(BackgroundWorker):
|
||||
default_value=False
|
||||
)
|
||||
except Exception as e:
|
||||
pi.logger.error(e)
|
||||
log.error(e)
|
||||
self.ec = -2
|
||||
return
|
||||
|
||||
@@ -99,10 +101,10 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
self.splitter.setSizes(list(map(int, helper.settings.value("files/splitter", [0, 0]))))
|
||||
|
||||
def __del__(self):
|
||||
pi.logger.debug("RevPiFiles.__del__")
|
||||
log.debug("RevPiFiles.__del__")
|
||||
|
||||
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
||||
pi.logger.debug("RevPiFiles.closeEvent")
|
||||
log.debug("RevPiFiles.closeEvent")
|
||||
helper.settings.setValue("files/geo", self.saveGeometry())
|
||||
helper.settings.setValue("files/splitter", self.splitter.sizes())
|
||||
|
||||
@@ -164,22 +166,44 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
state_local = len(self.tree_files_local.selectedItems()) > 0
|
||||
state_revpi = len(self.tree_files_revpi.selectedItems()) > 0
|
||||
|
||||
if "set_plcprogram" in helper.cm.xml_funcs:
|
||||
self.btn_mark_plcprogram.setEnabled(False)
|
||||
self.btn_mark_plcprogram.setToolTip(self.tr(
|
||||
"Set as start file"
|
||||
))
|
||||
if len(self.tree_files_revpi.selectedItems()) == 1:
|
||||
item = self.tree_files_revpi.selectedItems()[0]
|
||||
self.btn_mark_plcprogram.setEnabled(not item.data(0, WidgetData.is_plc_program))
|
||||
else:
|
||||
self.btn_mark_plcprogram.setEnabled(False)
|
||||
self.btn_mark_plcprogram.setToolTip(self.tr(
|
||||
"Upgrade your Revolution Pi! This function needs at least 'revpipyload' 0.11.0"
|
||||
))
|
||||
|
||||
self.btn_all.setEnabled(state_local)
|
||||
self.btn_to_right.setEnabled(state_local)
|
||||
|
||||
if "plcdeletefile" not in helper.cm.xml_funcs:
|
||||
self.btn_delete_revpi.setEnabled(False)
|
||||
self.btn_delete_revpi.setToolTip(self.tr("The RevPiPyLoad version on the Revolution Pi is to old."))
|
||||
self.btn_delete_revpi.setToolTip(self.tr(
|
||||
"Upgrade your Revolution Pi! This function needs at least 'revpipyload' 0.9.5"
|
||||
))
|
||||
else:
|
||||
self.btn_delete_revpi.setEnabled(state_revpi)
|
||||
self.btn_delete_revpi.setToolTip(self.tr(
|
||||
"Deletes selected files immediately on the Revolution Pi"
|
||||
))
|
||||
if "plcdownload_file" not in helper.cm.xml_funcs:
|
||||
self.btn_to_left.setEnabled(False)
|
||||
self.btn_to_left.setToolTip(self.tr("The RevPiPyLoad version on the Revolution Pi is to old."))
|
||||
self.btn_to_left.setToolTip(self.tr(
|
||||
"Upgrade your Revolution Pi! This function needs at least 'revpipyload' 0.9.5"
|
||||
))
|
||||
elif not helper.cm.settings.watch_path:
|
||||
self.btn_to_left.setEnabled(False)
|
||||
self.btn_to_left.setToolTip(self.tr("Choose a local directory first."))
|
||||
else:
|
||||
self.btn_to_left.setEnabled(state_revpi)
|
||||
self.btn_to_left.setToolTip("")
|
||||
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# region # REGION: Tree management
|
||||
@@ -197,7 +221,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
|
||||
def _select_children(self, top_item: QtWidgets.QTreeWidgetItem, value: bool):
|
||||
"""Recursive select children from parent."""
|
||||
pi.logger.debug("RevPiFiles._select_children")
|
||||
log.debug("RevPiFiles._select_children")
|
||||
|
||||
for i in range(top_item.childCount()):
|
||||
item = top_item.child(i)
|
||||
@@ -213,7 +237,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
if item is None:
|
||||
return
|
||||
|
||||
pi.logger.debug("RevPiFiles.__itemSelectionChanged")
|
||||
log.debug("RevPiFiles.__itemSelectionChanged")
|
||||
|
||||
# Block while preselect other entries
|
||||
tree_view.blockSignals(True)
|
||||
@@ -296,7 +320,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
|
||||
:param silent: Do not show message boxes
|
||||
"""
|
||||
pi.logger.debug("RevPiFiles._load_files_local")
|
||||
log.debug("RevPiFiles._load_files_local")
|
||||
|
||||
self.tree_files_counter = 0
|
||||
self.tree_files_local.blockSignals(True)
|
||||
@@ -316,7 +340,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
|
||||
def file_list_local(self):
|
||||
"""Generate a file list with full path of selected entries."""
|
||||
pi.logger.debug("RevPiFiles.file_list_local")
|
||||
log.debug("RevPiFiles.file_list_local")
|
||||
lst = []
|
||||
for item in self.tree_files_local.selectedItems():
|
||||
if item.type() == NodeType.DIR:
|
||||
@@ -337,7 +361,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
|
||||
:param silent: Do not show message boxes
|
||||
"""
|
||||
pi.logger.debug("RevPiFiles._load_files_revpi")
|
||||
log.debug("RevPiFiles._load_files_revpi")
|
||||
|
||||
self.tree_files_revpi.blockSignals(True)
|
||||
self.tree_files_revpi.clear()
|
||||
@@ -347,13 +371,13 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
lst_revpi = None
|
||||
else:
|
||||
lst_revpi = helper.cm.call_remote_function("get_filelist")
|
||||
# Just load settings once
|
||||
if not self.dc_settings:
|
||||
self.dc_settings = helper.cm.call_remote_function("get_config", default_value={})
|
||||
self.lbl_path_revpi.setText(
|
||||
self.dc_settings.get("plcworkdir", self.tr("Could not load path of working dir"))
|
||||
)
|
||||
self.lbl_path_revpi.setToolTip(self.lbl_path_revpi.text())
|
||||
self.dc_settings = helper.cm.call_remote_function("get_config", default_value={})
|
||||
self.lbl_path_revpi.setText(
|
||||
self.dc_settings.get("plcworkdir", self.tr("Could not load path of working dir"))
|
||||
)
|
||||
self.lbl_path_revpi.setToolTip(self.lbl_path_revpi.text())
|
||||
|
||||
plc_program = self.dc_settings.get("plcprogram", "")
|
||||
|
||||
if lst_revpi is not None:
|
||||
lst_revpi.sort()
|
||||
@@ -399,7 +423,9 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
item = QtWidgets.QTreeWidgetItem(NodeType.FILE)
|
||||
item.setText(0, object_name)
|
||||
item.setData(0, WidgetData.file_name, path_file)
|
||||
item.setData(0, WidgetData.is_plc_program, path_file == plc_program)
|
||||
item.setIcon(0, QtGui.QIcon(
|
||||
":/file/ico/autostart.ico" if path_file == plc_program else
|
||||
":/file/ico/file-else.ico" if object_name.find(".py") == -1 else
|
||||
":/file/ico/file-python.ico"
|
||||
))
|
||||
@@ -421,7 +447,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
|
||||
def file_list_revpi(self):
|
||||
"""Generate a file list with full path of selected entries."""
|
||||
pi.logger.debug("RevPiFiles.file_list_revpi")
|
||||
log.debug("RevPiFiles.file_list_revpi")
|
||||
lst = []
|
||||
for item in self.tree_files_revpi.selectedItems():
|
||||
if item.type() == NodeType.DIR:
|
||||
@@ -435,13 +461,13 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_all_clicked(self):
|
||||
pi.logger.debug("RevPiFiles.on_btn_all_clicked")
|
||||
log.debug("RevPiFiles.on_btn_all_clicked")
|
||||
self._do_my_job(True)
|
||||
self.file_list_revpi()
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_select_local_clicked(self):
|
||||
pi.logger.debug("RevPiFiles.on_btn_select_clicked")
|
||||
log.debug("RevPiFiles.on_btn_select_clicked")
|
||||
|
||||
diag_folder = QtWidgets.QFileDialog(
|
||||
self, self.tr("Select folder..."),
|
||||
@@ -472,25 +498,25 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_refresh_local_clicked(self):
|
||||
pi.logger.debug("RevPiFiles.on_btn_refresh_clicked")
|
||||
log.debug("RevPiFiles.on_btn_refresh_clicked")
|
||||
self._load_files_local(False)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_refresh_revpi_clicked(self):
|
||||
pi.logger.debug("RevPiFiles.on_btn_refresh_revpi_clicked")
|
||||
log.debug("RevPiFiles.on_btn_refresh_revpi_clicked")
|
||||
self._load_files_revpi(False)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_to_right_clicked(self):
|
||||
"""Upload selected files to revolution pi."""
|
||||
pi.logger.debug("RevPiFiles.on_btn_to_right_clicked")
|
||||
log.debug("RevPiFiles.on_btn_to_right_clicked")
|
||||
self._do_my_job(False)
|
||||
self._load_files_revpi(True)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_to_left_clicked(self):
|
||||
"""Download selected file."""
|
||||
pi.logger.debug("RevPiFiles.on_btn_to_left_clicked")
|
||||
log.debug("RevPiFiles.on_btn_to_left_clicked")
|
||||
|
||||
override = None
|
||||
for item in self.tree_files_revpi.selectedItems():
|
||||
@@ -524,7 +550,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
override = rc_diag == QtWidgets.QMessageBox.Yes
|
||||
|
||||
if os.path.exists(file_name) and not override:
|
||||
pi.logger.debug("Skip existing file '{0}'".format(file_name))
|
||||
log.debug("Skip existing file '{0}'".format(file_name))
|
||||
continue
|
||||
|
||||
os.makedirs(os.path.dirname(file_name), exist_ok=True)
|
||||
@@ -537,7 +563,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_delete_revpi_clicked(self):
|
||||
"""Remove selected files from working directory on revolution pi."""
|
||||
pi.logger.debug("RevPiFiles.btn_delete_revpi_clicked")
|
||||
log.debug("RevPiFiles.btn_delete_revpi_clicked")
|
||||
|
||||
lst_delete = []
|
||||
for item in self.tree_files_revpi.selectedItems():
|
||||
@@ -562,3 +588,23 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
||||
)
|
||||
|
||||
self._load_files_revpi()
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_btn_mark_plcprogram_clicked(self):
|
||||
"""Mark selected file as plc autostart file."""
|
||||
log.debug("RevPiFiles.on_btn_mark_plcprogram_clicked")
|
||||
|
||||
selected_item = self.tree_files_revpi.selectedItems()[0]
|
||||
|
||||
saved = helper.cm.call_remote_function("set_plcprogram", selected_item.data(0, WidgetData.file_name))
|
||||
|
||||
if saved is None:
|
||||
QtWidgets.QMessageBox.critical(
|
||||
self, self.tr("Error"), self.tr(
|
||||
"The settings could not be saved on the Revolution Pi!\n"
|
||||
"Try to save the values one mor time and check the log "
|
||||
"files of RevPiPyLoad if the error rises again."
|
||||
)
|
||||
)
|
||||
|
||||
self._load_files_revpi(True)
|
||||
|
||||
@@ -5,13 +5,15 @@ __copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
from enum import IntEnum
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from . import helper
|
||||
from . import proginit as pi
|
||||
from .ui.revpilogfile_ui import Ui_win_revpilogfile
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class LogType(IntEnum):
|
||||
NONE = 0
|
||||
@@ -60,7 +62,7 @@ class DataThread(QtCore.QThread):
|
||||
# The log file was rotated by log rotate on the Revolution Pi
|
||||
start_position = 0
|
||||
eof = False
|
||||
pi.logger.info("RevPi started a new log file.")
|
||||
log.info("RevPi started a new log file.")
|
||||
|
||||
elif buff_log:
|
||||
start_position += len(buff_log)
|
||||
@@ -71,16 +73,16 @@ class DataThread(QtCore.QThread):
|
||||
|
||||
def pause(self):
|
||||
"""Stop checking new log lines, but leave thread alive."""
|
||||
pi.logger.debug("DataThread.pause")
|
||||
log.debug("DataThread.pause")
|
||||
self._paused = True
|
||||
|
||||
def resume(self):
|
||||
"""Start checking for new log lines."""
|
||||
pi.logger.debug("DataThread.resume")
|
||||
log.debug("DataThread.resume")
|
||||
self._paused = False
|
||||
|
||||
def run(self) -> None:
|
||||
pi.logger.debug("DataThread.run")
|
||||
log.debug("DataThread.run")
|
||||
|
||||
while not self.isInterruptionRequested():
|
||||
eof_app = False
|
||||
@@ -191,7 +193,7 @@ class RevPiLogfile(QtWidgets.QMainWindow, Ui_win_revpilogfile):
|
||||
|
||||
@QtCore.pyqtSlot(LogType, bool, str)
|
||||
def on_line_logged(self, log_type: LogType, success: bool, text: str):
|
||||
pi.logger.debug("RevPiLogfile.on_line_logged")
|
||||
log.debug("RevPiLogfile.on_line_logged")
|
||||
|
||||
if log_type == LogType.APP:
|
||||
textwidget = self.txt_app
|
||||
|
||||
@@ -4,14 +4,17 @@ __author__ = "Sven Sager"
|
||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from . import helper
|
||||
from . import proginit as pi
|
||||
from .aclmanager import AclManager
|
||||
from .mqttmanager import MqttManager
|
||||
from .ui.revpioption_ui import Ui_diag_options
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
|
||||
"""Set options of RevPiPyLoad."""
|
||||
@@ -110,7 +113,7 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
|
||||
|
||||
def _load_settings(self):
|
||||
"""Load values to GUI widgets."""
|
||||
pi.logger.debug("RevPiOption._load_settings")
|
||||
log.debug("RevPiOption._load_settings")
|
||||
|
||||
self.mrk_xml_ask = True
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ __copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||
__license__ = "GPLv2"
|
||||
|
||||
from enum import IntEnum
|
||||
from logging import getLogger
|
||||
|
||||
import keyring
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
@@ -15,6 +16,8 @@ from . import proginit as pi
|
||||
from .helper import RevPiSettings, WidgetData
|
||||
from .ui.revpiplclist_ui import Ui_diag_connections
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class NodeType(IntEnum):
|
||||
CON = 1000
|
||||
@@ -58,7 +61,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
|
||||
def _load_settings(self):
|
||||
"""Load values to GUI widgets."""
|
||||
pi.logger.debug("RevPiPlcList._load_settings")
|
||||
log.debug("RevPiPlcList._load_settings")
|
||||
|
||||
self.tre_connections.clear()
|
||||
|
||||
@@ -95,7 +98,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
self._edit_state()
|
||||
|
||||
def accept(self) -> None:
|
||||
pi.logger.debug("RevPiPlcList.accept")
|
||||
log.debug("RevPiPlcList.accept")
|
||||
|
||||
for internal_id, ssh_user in self._keyring_cleanup_id_user:
|
||||
service_name = "{0}.{1}_{2}".format(
|
||||
@@ -107,7 +110,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
# Remove information from os keyring, which we collected on_btn_delete_clicked
|
||||
keyring.delete_password(service_name, ssh_user)
|
||||
except KeyringError as e:
|
||||
pi.logger.error(e)
|
||||
log.error(e)
|
||||
|
||||
helper.settings.remove("connections")
|
||||
|
||||
@@ -127,7 +130,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
super().accept()
|
||||
|
||||
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
||||
pi.logger.debug("RevPiPlcList.closeEvent")
|
||||
log.debug("RevPiPlcList.closeEvent")
|
||||
if self.changes:
|
||||
ask = QtWidgets.QMessageBox.question(
|
||||
self, self.tr("Question"), self.tr(
|
||||
@@ -165,7 +168,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
|
||||
def _edit_state(self):
|
||||
"""Set enabled status of all controls, depending on selected item."""
|
||||
pi.logger.debug("RevPiPlcList._edit_state")
|
||||
log.debug("RevPiPlcList._edit_state")
|
||||
|
||||
item = self.tre_connections.currentItem()
|
||||
if item is None:
|
||||
@@ -409,7 +412,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
|
||||
@QtCore.pyqtSlot(str)
|
||||
def on_cbb_folder_currentIndexChanged(self, text: str):
|
||||
pi.logger.debug("RevPiPlcList.on_cbb_folder_currentIndexChanged({0})".format(text))
|
||||
log.debug("RevPiPlcList.on_cbb_folder_currentIndexChanged({0})".format(text))
|
||||
|
||||
if self.__current_item.type() == NodeType.CON:
|
||||
new_dir_node = self._get_folder_item(text)
|
||||
@@ -443,7 +446,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
||||
|
||||
@QtCore.pyqtSlot(str)
|
||||
def on_cbb_folder_editTextChanged(self, text: str):
|
||||
pi.logger.debug("RevPiPlcList.on_cbb_folder_editTextChanged({0})".format(text))
|
||||
log.debug("RevPiPlcList.on_cbb_folder_editTextChanged({0})".format(text))
|
||||
|
||||
if self.__current_item.type() == NodeType.DIR and self.__current_item.text(0) != text:
|
||||
# We just have to rename the dir node
|
||||
|
||||
@@ -8,6 +8,7 @@ import gzip
|
||||
import os
|
||||
import tarfile
|
||||
import zipfile
|
||||
from logging import getLogger
|
||||
from shutil import rmtree
|
||||
from tempfile import mkdtemp
|
||||
from xmlrpc.client import Binary
|
||||
@@ -15,9 +16,10 @@ from xmlrpc.client import Binary
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from . import helper
|
||||
from . import proginit as pi
|
||||
from .ui.revpiprogram_ui import Ui_diag_program
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
||||
"""Program options of RevPiPyLoad."""
|
||||
@@ -39,8 +41,6 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
||||
# Setting properties require level 4
|
||||
self.cbb_plcprogram.setEnabled(helper.cm.xml_mode >= 4)
|
||||
self.txt_plcarguments.setEnabled(helper.cm.xml_mode >= 4)
|
||||
self.rbn_pythonversion_2.setEnabled(helper.cm.xml_mode >= 4)
|
||||
self.rbn_pythonversion_3.setEnabled(helper.cm.xml_mode >= 4)
|
||||
self.cbx_plcworkdir_set_uid.setEnabled(helper.cm.xml_mode >= 4)
|
||||
|
||||
# Downloads require level 2
|
||||
@@ -60,14 +60,12 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
||||
"""
|
||||
return self.cbb_plcprogram.currentText() != self.dc.get("plcprogram", "") or \
|
||||
self.txt_plcarguments.text() != self.dc.get("plcarguments", "") or \
|
||||
self.rbn_pythonversion_2.isChecked() != (self.dc.get("pythonversion", 3) == 2) or \
|
||||
self.rbn_pythonversion_3.isChecked() != (self.dc.get("pythonversion", 3) == 3) or \
|
||||
int(self.cbx_plcworkdir_set_uid.isChecked()) != self.dc.get("plcworkdir_set_uid", 0) or \
|
||||
self.sbx_plcprogram_watchdog.value() != self.dc.get("plcprogram_watchdog", 0)
|
||||
|
||||
def _load_settings(self, files_only=False):
|
||||
"""Load values to GUI widgets."""
|
||||
pi.logger.debug("RevPiProgram._load_settings")
|
||||
log.debug("RevPiProgram._load_settings")
|
||||
|
||||
if files_only:
|
||||
mrk_program = self.cbb_plcprogram.currentText()
|
||||
@@ -88,15 +86,13 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
||||
is_in_list = True
|
||||
|
||||
if not is_in_list:
|
||||
pi.logger.warning("File {0} is not in list".format(mrk_program or self.dc.get("plcprogram", "")))
|
||||
log.warning("File {0} is not in list".format(mrk_program or self.dc.get("plcprogram", "")))
|
||||
|
||||
if files_only:
|
||||
self.cbb_plcprogram.setCurrentText(mrk_program)
|
||||
else:
|
||||
self.cbb_plcprogram.setCurrentText(self.dc.get("plcprogram", ""))
|
||||
self.txt_plcarguments.setText(self.dc.get("plcarguments", ""))
|
||||
self.rbn_pythonversion_2.setChecked(self.dc.get("pythonversion", 3) == 2)
|
||||
self.rbn_pythonversion_3.setChecked(self.dc.get("pythonversion", 3) == 3)
|
||||
self.cbx_plcworkdir_set_uid.setChecked(bool(self.dc.get("plcworkdir_set_uid", 0)))
|
||||
self.sbx_plcprogram_watchdog.setValue(self.dc.get("plcprogram_watchdog", 0))
|
||||
|
||||
@@ -128,7 +124,6 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
||||
|
||||
self.dc["plcprogram"] = self.cbb_plcprogram.currentText()
|
||||
self.dc["plcarguments"] = self.txt_plcarguments.text()
|
||||
self.dc["pythonversion"] = 2 if self.rbn_pythonversion_2.isChecked() else 3
|
||||
self.dc["plcworkdir_set_uid"] = int(self.cbx_plcworkdir_set_uid.isChecked())
|
||||
self.dc["plcprogram_watchdog"] = self.sbx_plcprogram_watchdog.value()
|
||||
|
||||
@@ -382,7 +377,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
||||
fh.close()
|
||||
|
||||
except Exception as e:
|
||||
pi.logger.error(e)
|
||||
log.error(e)
|
||||
QtWidgets.QMessageBox.critical(
|
||||
self, self.tr("Error"), self.tr(
|
||||
"Coud not save the archive or extract the files!\n"
|
||||
|
||||
@@ -43,8 +43,6 @@ class Handler(BaseRequestHandler):
|
||||
log.error("Could not create a ssh channel")
|
||||
return
|
||||
|
||||
log.info("Starting tunnel exchange loop")
|
||||
|
||||
while True:
|
||||
r, w, x = select.select([self.request, chan], [], [], 5.0)
|
||||
if self.request in r:
|
||||
@@ -58,8 +56,6 @@ class Handler(BaseRequestHandler):
|
||||
break
|
||||
self.request.send(data)
|
||||
|
||||
log.info("Stopped tunnel exchange loop")
|
||||
|
||||
chan.close()
|
||||
self.request.close()
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from keyring.errors import KeyringError
|
||||
|
||||
from .ui.sshauth_ui import Ui_diag_sshauth
|
||||
|
||||
log = getLogger()
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class SSHAuth(QtWidgets.QDialog, Ui_diag_sshauth):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'aclmanager.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'avahisearch.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'backgroundworker.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'debugcontrol.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'debugios.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'files.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
@@ -78,7 +78,7 @@ class Ui_win_files(object):
|
||||
self.vl_local.addLayout(self.hl_revpi_2)
|
||||
self.tree_files_local = QtWidgets.QTreeWidget(self.verticalLayoutWidget)
|
||||
self.tree_files_local.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.tree_files_local.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
self.tree_files_local.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
self.tree_files_local.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.tree_files_local.setIconSize(QtCore.QSize(24, 24))
|
||||
self.tree_files_local.setObjectName("tree_files_local")
|
||||
@@ -136,10 +136,19 @@ class Ui_win_files(object):
|
||||
self.hl_revpi.addWidget(self.btn_delete_revpi)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.hl_revpi.addItem(spacerItem1)
|
||||
self.btn_mark_plcprogram = QtWidgets.QPushButton(self.gridLayoutWidget_2)
|
||||
self.btn_mark_plcprogram.setText("")
|
||||
icon5 = QtGui.QIcon()
|
||||
icon5.addPixmap(QtGui.QPixmap(":/file/ico/autostart.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.btn_mark_plcprogram.setIcon(icon5)
|
||||
self.btn_mark_plcprogram.setIconSize(QtCore.QSize(24, 24))
|
||||
self.btn_mark_plcprogram.setAutoDefault(False)
|
||||
self.btn_mark_plcprogram.setObjectName("btn_mark_plcprogram")
|
||||
self.hl_revpi.addWidget(self.btn_mark_plcprogram)
|
||||
self.vl_revpi.addLayout(self.hl_revpi)
|
||||
self.tree_files_revpi = QtWidgets.QTreeWidget(self.gridLayoutWidget_2)
|
||||
self.tree_files_revpi.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.tree_files_revpi.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
self.tree_files_revpi.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
self.tree_files_revpi.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.tree_files_revpi.setIconSize(QtCore.QSize(24, 24))
|
||||
self.tree_files_revpi.setObjectName("tree_files_revpi")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'mqttmanager.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
79
src/revpicommander/ui/oss_licenses_ui.py
Normal file
79
src/revpicommander/ui/oss_licenses_ui.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'oss_licenses.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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_diag_oss_licenses(object):
|
||||
def setupUi(self, diag_oss_licenses):
|
||||
diag_oss_licenses.setObjectName("diag_oss_licenses")
|
||||
diag_oss_licenses.resize(640, 480)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(diag_oss_licenses)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.splitter = QtWidgets.QSplitter(diag_oss_licenses)
|
||||
self.splitter.setOrientation(QtCore.Qt.Vertical)
|
||||
self.splitter.setChildrenCollapsible(False)
|
||||
self.splitter.setObjectName("splitter")
|
||||
self.tb_oss_licenses = QtWidgets.QTableWidget(self.splitter)
|
||||
self.tb_oss_licenses.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.tb_oss_licenses.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||
self.tb_oss_licenses.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.tb_oss_licenses.setCornerButtonEnabled(False)
|
||||
self.tb_oss_licenses.setObjectName("tb_oss_licenses")
|
||||
self.tb_oss_licenses.setColumnCount(2)
|
||||
self.tb_oss_licenses.setRowCount(0)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tb_oss_licenses.setHorizontalHeaderItem(0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tb_oss_licenses.setHorizontalHeaderItem(1, item)
|
||||
self.tb_oss_licenses.horizontalHeader().setSortIndicatorShown(True)
|
||||
self.tb_oss_licenses.horizontalHeader().setStretchLastSection(True)
|
||||
self.tb_oss_licenses.verticalHeader().setVisible(False)
|
||||
self.txt_license = QtWidgets.QTextEdit(self.splitter)
|
||||
self.txt_license.setTabChangesFocus(True)
|
||||
self.txt_license.setUndoRedoEnabled(False)
|
||||
self.txt_license.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)
|
||||
self.txt_license.setReadOnly(True)
|
||||
self.txt_license.setObjectName("txt_license")
|
||||
self.verticalLayout.addWidget(self.splitter)
|
||||
self.btn_box = QtWidgets.QDialogButtonBox(diag_oss_licenses)
|
||||
self.btn_box.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.btn_box.setStandardButtons(QtWidgets.QDialogButtonBox.Close)
|
||||
self.btn_box.setObjectName("btn_box")
|
||||
self.verticalLayout.addWidget(self.btn_box)
|
||||
self.action_start = QtWidgets.QAction(diag_oss_licenses)
|
||||
self.action_start.setObjectName("action_start")
|
||||
|
||||
self.retranslateUi(diag_oss_licenses)
|
||||
self.btn_box.accepted.connect(diag_oss_licenses.accept) # type: ignore
|
||||
self.btn_box.rejected.connect(diag_oss_licenses.reject) # type: ignore
|
||||
self.action_start.triggered.connect(diag_oss_licenses.exec) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(diag_oss_licenses)
|
||||
|
||||
def retranslateUi(self, diag_oss_licenses):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
diag_oss_licenses.setWindowTitle(_translate("diag_oss_licenses", "Open-Source licenses"))
|
||||
self.tb_oss_licenses.setSortingEnabled(True)
|
||||
item = self.tb_oss_licenses.horizontalHeaderItem(0)
|
||||
item.setText(_translate("diag_oss_licenses", "Software"))
|
||||
item = self.tb_oss_licenses.horizontalHeaderItem(1)
|
||||
item.setText(_translate("diag_oss_licenses", "License"))
|
||||
self.action_start.setText(_translate("diag_oss_licenses", "More licenses..."))
|
||||
self.action_start.setToolTip(_translate("diag_oss_licenses", "Show more open-source software licenses"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
diag_oss_licenses = QtWidgets.QDialog()
|
||||
ui = Ui_diag_oss_licenses()
|
||||
ui.setupUi(diag_oss_licenses)
|
||||
diag_oss_licenses.show()
|
||||
sys.exit(app.exec_())
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'revpicommander.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'revpiinfo.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'revpilogfile.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'revpioption.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'revpiplclist.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'revpiprogram.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
@@ -14,44 +14,35 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
class Ui_diag_program(object):
|
||||
def setupUi(self, diag_program):
|
||||
diag_program.setObjectName("diag_program")
|
||||
diag_program.resize(400, 501)
|
||||
diag_program.resize(434, 509)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(diag_program)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.gb_plc = QtWidgets.QGroupBox(diag_program)
|
||||
self.gb_plc.setObjectName("gb_plc")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.gb_plc)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.cbb_plcprogram = QtWidgets.QComboBox(self.gb_plc)
|
||||
self.cbb_plcprogram.setObjectName("cbb_plcprogram")
|
||||
self.gridLayout.addWidget(self.cbb_plcprogram, 1, 0, 1, 3)
|
||||
self.rbn_pythonversion_3 = QtWidgets.QRadioButton(self.gb_plc)
|
||||
self.rbn_pythonversion_3.setObjectName("rbn_pythonversion_3")
|
||||
self.gridLayout.addWidget(self.rbn_pythonversion_3, 3, 2, 1, 1)
|
||||
self.cbx_plcworkdir_set_uid = QtWidgets.QCheckBox(self.gb_plc)
|
||||
self.cbx_plcworkdir_set_uid.setObjectName("cbx_plcworkdir_set_uid")
|
||||
self.gridLayout.addWidget(self.cbx_plcworkdir_set_uid, 4, 0, 1, 3)
|
||||
self.lbl_plcprogram = QtWidgets.QLabel(self.gb_plc)
|
||||
self.lbl_plcprogram.setObjectName("lbl_plcprogram")
|
||||
self.gridLayout.addWidget(self.lbl_plcprogram, 0, 0, 1, 3)
|
||||
self.lbl_pythonversion = QtWidgets.QLabel(self.gb_plc)
|
||||
self.lbl_pythonversion.setObjectName("lbl_pythonversion")
|
||||
self.gridLayout.addWidget(self.lbl_pythonversion, 3, 0, 1, 1)
|
||||
self.rbn_pythonversion_2 = QtWidgets.QRadioButton(self.gb_plc)
|
||||
self.rbn_pythonversion_2.setObjectName("rbn_pythonversion_2")
|
||||
self.gridLayout.addWidget(self.rbn_pythonversion_2, 3, 1, 1, 1)
|
||||
self.lbl_plcarguments = QtWidgets.QLabel(self.gb_plc)
|
||||
self.lbl_plcarguments.setObjectName("lbl_plcarguments")
|
||||
self.gridLayout.addWidget(self.lbl_plcarguments, 2, 0, 1, 1)
|
||||
self.lbl_plcprogram_watchdog = QtWidgets.QLabel(self.gb_plc)
|
||||
self.lbl_plcprogram_watchdog.setObjectName("lbl_plcprogram_watchdog")
|
||||
self.gridLayout.addWidget(self.lbl_plcprogram_watchdog, 4, 0, 1, 2)
|
||||
self.cbx_plcworkdir_set_uid = QtWidgets.QCheckBox(self.gb_plc)
|
||||
self.cbx_plcworkdir_set_uid.setObjectName("cbx_plcworkdir_set_uid")
|
||||
self.gridLayout.addWidget(self.cbx_plcworkdir_set_uid, 3, 0, 1, 3)
|
||||
self.lbl_plcprogram = QtWidgets.QLabel(self.gb_plc)
|
||||
self.lbl_plcprogram.setObjectName("lbl_plcprogram")
|
||||
self.gridLayout.addWidget(self.lbl_plcprogram, 0, 0, 1, 3)
|
||||
self.txt_plcarguments = QtWidgets.QLineEdit(self.gb_plc)
|
||||
self.txt_plcarguments.setObjectName("txt_plcarguments")
|
||||
self.gridLayout.addWidget(self.txt_plcarguments, 2, 1, 1, 2)
|
||||
self.cbb_plcprogram = QtWidgets.QComboBox(self.gb_plc)
|
||||
self.cbb_plcprogram.setObjectName("cbb_plcprogram")
|
||||
self.gridLayout.addWidget(self.cbb_plcprogram, 1, 0, 1, 3)
|
||||
self.sbx_plcprogram_watchdog = QtWidgets.QSpinBox(self.gb_plc)
|
||||
self.sbx_plcprogram_watchdog.setMaximum(600)
|
||||
self.sbx_plcprogram_watchdog.setObjectName("sbx_plcprogram_watchdog")
|
||||
self.gridLayout.addWidget(self.sbx_plcprogram_watchdog, 5, 2, 1, 1)
|
||||
self.lbl_plcprogram_watchdog = QtWidgets.QLabel(self.gb_plc)
|
||||
self.lbl_plcprogram_watchdog.setObjectName("lbl_plcprogram_watchdog")
|
||||
self.gridLayout.addWidget(self.lbl_plcprogram_watchdog, 5, 0, 1, 2)
|
||||
self.gridLayout.addWidget(self.sbx_plcprogram_watchdog, 4, 2, 1, 1)
|
||||
self.verticalLayout.addWidget(self.gb_plc)
|
||||
self.cb_transfair = QtWidgets.QGroupBox(diag_program)
|
||||
self.cb_transfair.setObjectName("cb_transfair")
|
||||
@@ -109,9 +100,7 @@ class Ui_diag_program(object):
|
||||
self.btn_box.rejected.connect(diag_program.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(diag_program)
|
||||
diag_program.setTabOrder(self.cbb_plcprogram, self.txt_plcarguments)
|
||||
diag_program.setTabOrder(self.txt_plcarguments, self.rbn_pythonversion_2)
|
||||
diag_program.setTabOrder(self.rbn_pythonversion_2, self.rbn_pythonversion_3)
|
||||
diag_program.setTabOrder(self.rbn_pythonversion_3, self.cbx_plcworkdir_set_uid)
|
||||
diag_program.setTabOrder(self.txt_plcarguments, self.cbx_plcworkdir_set_uid)
|
||||
diag_program.setTabOrder(self.cbx_plcworkdir_set_uid, self.cbb_format)
|
||||
diag_program.setTabOrder(self.cbb_format, self.cbx_pictory)
|
||||
diag_program.setTabOrder(self.cbx_pictory, self.cbx_clear)
|
||||
@@ -125,14 +114,11 @@ class Ui_diag_program(object):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
diag_program.setWindowTitle(_translate("diag_program", "PLC program"))
|
||||
self.gb_plc.setTitle(_translate("diag_program", "PLC program"))
|
||||
self.rbn_pythonversion_3.setText(_translate("diag_program", "Python 3"))
|
||||
self.lbl_plcarguments.setText(_translate("diag_program", "Program arguments:"))
|
||||
self.lbl_plcprogram_watchdog.setText(_translate("diag_program", "Software watchdog (0=disabled):"))
|
||||
self.cbx_plcworkdir_set_uid.setText(_translate("diag_program", "Set write permissions for plc program to workdirectory"))
|
||||
self.lbl_plcprogram.setText(_translate("diag_program", "Python PLC start program:"))
|
||||
self.lbl_pythonversion.setText(_translate("diag_program", "Python version:"))
|
||||
self.rbn_pythonversion_2.setText(_translate("diag_program", "Python 2"))
|
||||
self.lbl_plcarguments.setText(_translate("diag_program", "Program arguments:"))
|
||||
self.sbx_plcprogram_watchdog.setSuffix(_translate("diag_program", " sec."))
|
||||
self.lbl_plcprogram_watchdog.setText(_translate("diag_program", "Software watchdog (0=disabled):"))
|
||||
self.cb_transfair.setTitle(_translate("diag_program", "Transfair PLC program"))
|
||||
self.cbb_format.setItemText(0, _translate("diag_program", "ZIP archive"))
|
||||
self.cbb_format.setItemText(1, _translate("diag_program", "TGZ archive"))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'simulator.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'sshauth.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# 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.
|
||||
|
||||
@@ -21,6 +21,7 @@ FORMS = ui_dev/aclmanager.ui \
|
||||
ui_dev/debugios.ui \
|
||||
ui_dev/files.ui \
|
||||
ui_dev/mqttmanager.ui \
|
||||
ui_dev/oss_licenses.ui \
|
||||
ui_dev/revpiinfo.ui \
|
||||
ui_dev/revpilogfile.ui \
|
||||
ui_dev/revpioption.ui \
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
@@ -269,6 +269,26 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_mark_plcprogram">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="ressources.qrc">
|
||||
<normaloff>:/file/ico/autostart.ico</normaloff>:/file/ico/autostart.ico</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@@ -277,7 +297,7 @@
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
|
||||
BIN
ui_dev/ico/autostart.ico
Normal file
BIN
ui_dev/ico/autostart.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
148
ui_dev/oss_licenses.ui
Normal file
148
ui_dev/oss_licenses.ui
Normal file
@@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>diag_oss_licenses</class>
|
||||
<widget class="QDialog" name="diag_oss_licenses">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>640</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Open-Source licenses</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QTableWidget" name="tb_oss_licenses">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Software</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>License</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
<widget class="QTextEdit" name="txt_license">
|
||||
<property name="tabChangesFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="btn_box">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="action_start">
|
||||
<property name="text">
|
||||
<string>More licenses...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Show more open-source software licenses</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>btn_box</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>diag_oss_licenses</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>btn_box</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>diag_oss_licenses</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>
|
||||
<connection>
|
||||
<sender>action_start</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>diag_oss_licenses</receiver>
|
||||
<slot>exec()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>267</x>
|
||||
<y>237</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -5,6 +5,7 @@
|
||||
<file>ico/revpipycontrol.ico</file>
|
||||
</qresource>
|
||||
<qresource prefix="file">
|
||||
<file>ico/autostart.ico</file>
|
||||
<file>ico/file-else.ico</file>
|
||||
<file>ico/file-python.ico</file>
|
||||
</qresource>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>501</height>
|
||||
<width>434</width>
|
||||
<height>509</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -20,17 +20,21 @@
|
||||
<string>PLC program</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QComboBox" name="cbb_plcprogram"/>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QRadioButton" name="rbn_pythonversion_3">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lbl_plcarguments">
|
||||
<property name="text">
|
||||
<string>Python 3</string>
|
||||
<string>Program arguments:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="3">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLabel" name="lbl_plcprogram_watchdog">
|
||||
<property name="text">
|
||||
<string>Software watchdog (0=disabled):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="cbx_plcworkdir_set_uid">
|
||||
<property name="text">
|
||||
<string>Set write permissions for plc program to workdirectory</string>
|
||||
@@ -44,31 +48,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lbl_pythonversion">
|
||||
<property name="text">
|
||||
<string>Python version:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QRadioButton" name="rbn_pythonversion_2">
|
||||
<property name="text">
|
||||
<string>Python 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lbl_plcarguments">
|
||||
<property name="text">
|
||||
<string>Program arguments:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="txt_plcarguments"/>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QComboBox" name="cbb_plcprogram"/>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QSpinBox" name="sbx_plcprogram_watchdog">
|
||||
<property name="suffix">
|
||||
<string> sec.</string>
|
||||
@@ -78,13 +64,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QLabel" name="lbl_plcprogram_watchdog">
|
||||
<property name="text">
|
||||
<string>Software watchdog (0=disabled):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -205,8 +184,6 @@
|
||||
<tabstops>
|
||||
<tabstop>cbb_plcprogram</tabstop>
|
||||
<tabstop>txt_plcarguments</tabstop>
|
||||
<tabstop>rbn_pythonversion_2</tabstop>
|
||||
<tabstop>rbn_pythonversion_3</tabstop>
|
||||
<tabstop>cbx_plcworkdir_set_uid</tabstop>
|
||||
<tabstop>cbb_format</tabstop>
|
||||
<tabstop>cbx_pictory</tabstop>
|
||||
|
||||
Reference in New Issue
Block a user