mirror of
https://github.com/naruxde/revpicommander.git
synced 2025-11-09 00:53:53 +01:00
Compare commits
21 Commits
debian/0.1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f08ea8ebc6 | |||
| 1a087f213d | |||
| 44d9ea4561 | |||
| 6a1e989e19 | |||
| 6619a172c7 | |||
| eb48557c77 | |||
| 356f1d29ff | |||
| af68db167c | |||
| 90fde110f3 | |||
| 0050e7ed94 | |||
| 49298d40a7 | |||
| a24035be0f | |||
| 6984945a30 | |||
| 649f6cdafa | |||
| e147c57bf9 | |||
| 929f7d04d2 | |||
| 844ebcb234 | |||
| 24f4d688ba | |||
| d2be450d98 | |||
| 8c2f66b2b5 | |||
| 32ee413d9b |
155
Makefile
155
Makefile
@@ -3,11 +3,14 @@ MAKEFLAGS = --no-print-directory --no-builtin-rules
|
|||||||
.DEFAULT_GOAL = all
|
.DEFAULT_GOAL = all
|
||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
PACKAGE = revpicommander
|
PACKAGE = revpicommander
|
||||||
APP_NAME = RevPi\ Commander
|
APP_NAME = RevPi\ Commander
|
||||||
APP_IDENT = org.revpimodio.revpicommander
|
APP_IDENT = org.revpimodio.revpicommander
|
||||||
APPLE_SIG = "Developer ID Application: Sven Sager (U3N5843D9K)"
|
APPLE_SIG = "Developer ID Application: Sven Sager (U3N5843D9K)"
|
||||||
|
|
||||||
|
# Python interpreter to use for venv creation
|
||||||
|
SYSTEM_PYTHON = python3
|
||||||
|
|
||||||
# Set path to create the virtual environment with package name
|
# Set path to create the virtual environment with package name
|
||||||
ifdef PYTHON3_VENV
|
ifdef PYTHON3_VENV
|
||||||
VENV_PATH = $(PYTHON3_VENV)/$(PACKAGE)
|
VENV_PATH = $(PYTHON3_VENV)/$(PACKAGE)
|
||||||
@@ -15,67 +18,117 @@ else
|
|||||||
VENV_PATH = venv
|
VENV_PATH = venv
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# If virtualenv exists, use it. If not, use PATH to find commands
|
# Set targets for "all"-target
|
||||||
SYSTEM_PYTHON = python3
|
all: build-ui build-rc build
|
||||||
PYTHON = $(or $(wildcard $(VENV_PATH)/bin/python), $(SYSTEM_PYTHON))
|
|
||||||
|
|
||||||
APP_VERSION = $(shell $(PYTHON) src/$(PACKAGE) --version)
|
|
||||||
|
|
||||||
all: build_ui build_rc test build
|
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
|
|
||||||
## Environment
|
## Virtual environment creation with SYSTEM_PYTHON
|
||||||
venv-info:
|
|
||||||
echo Using path: "$(VENV_PATH)"
|
|
||||||
exit 0
|
|
||||||
|
|
||||||
venv:
|
venv:
|
||||||
$(SYSTEM_PYTHON) -m venv --system-site-packages "$(VENV_PATH)"
|
# Start with empty environment
|
||||||
source $(VENV_PATH)/bin/activate && \
|
"$(SYSTEM_PYTHON)" -m venv "$(VENV_PATH)"
|
||||||
python3 -m pip install --upgrade pip && \
|
"$(VENV_PATH)/bin/pip" install --upgrade pip
|
||||||
python3 -m pip install -r requirements.txt
|
"$(VENV_PATH)/bin/pip" install --upgrade -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)"
|
||||||
|
"$(VENV_PATH)/bin/pip" install --upgrade pip
|
||||||
|
"$(VENV_PATH)/bin/pip" install --upgrade -r requirements.txt
|
||||||
|
|
||||||
|
.PHONY: venv venv-ssp
|
||||||
|
|
||||||
|
# Choose python interpreter from venv or system
|
||||||
|
PYTHON = $(or $(wildcard $(VENV_PATH)/bin/python), $(SYSTEM_PYTHON))
|
||||||
|
|
||||||
|
# Read app version from program
|
||||||
|
APP_VERSION = $(shell "$(PYTHON)" src/$(PACKAGE) --version | cut -d ' ' -f 2)
|
||||||
|
|
||||||
|
# Environment info
|
||||||
|
venv-info:
|
||||||
|
@echo Environment for $(APP_NAME) $(APP_VERSION)
|
||||||
|
@echo Using path: "$(VENV_PATH)"
|
||||||
|
|
||||||
|
.PHONY: venv-info
|
||||||
|
|
||||||
## Compile Qt UI files to python code
|
## Compile Qt UI files to python code
|
||||||
build_ui:
|
build-ui:
|
||||||
cd ui_dev && for ui_file in *.ui; do \
|
cd ui_dev && for ui_file in *.ui; do \
|
||||||
file_name=$${ui_file%.ui}; \
|
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}; \
|
echo $${file_name}; \
|
||||||
done
|
done
|
||||||
|
|
||||||
build_rc:
|
build-rc:
|
||||||
cd ui_dev && for rc_file in *.qrc; do \
|
cd ui_dev && for rc_file in *.qrc; do \
|
||||||
file_name=$${rc_file%.qrc}; \
|
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}; \
|
echo $${file_name}; \
|
||||||
done
|
done
|
||||||
|
|
||||||
update_translation:
|
update-translation:
|
||||||
$(PYTHON) -m PyQt5.pylupdate_main translate.pro
|
"$(PYTHON)" -m PyQt5.pylupdate_main translate.pro
|
||||||
|
|
||||||
.PHONY: build_ui build_rc update_translation
|
.PHONY: build-ui build-rc update-translation
|
||||||
|
|
||||||
## Build steps
|
## Build steps
|
||||||
build: build_ui build_rc
|
build:
|
||||||
$(PYTHON) -m setup sdist
|
"$(PYTHON)" -m setup sdist
|
||||||
$(PYTHON) -m setup bdist_wheel
|
"$(PYTHON)" -m setup bdist_wheel
|
||||||
|
|
||||||
install: test build
|
install: build
|
||||||
$(PYTHON) -m pip install dist/$(PACKAGE)-*.whl
|
"$(PYTHON)" -m pip install dist/$(PACKAGE)-$(APP_VERSION)-*.whl
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
$(PYTHON) -m pip uninstall --yes $(PACKAGE)
|
"$(PYTHON)" -m pip uninstall --yes $(PACKAGE)
|
||||||
|
|
||||||
.PHONY: test build install uninstall
|
.PHONY: test build install uninstall
|
||||||
|
|
||||||
## PyInstaller
|
## PyInstaller
|
||||||
installer_mac: build_ui build_rc
|
app-licenses:
|
||||||
$(PYTHON) -m PyInstaller -n $(APP_NAME) \
|
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) \
|
||||||
|
--collect-submodules=zeroconf \
|
||||||
--add-data="src/$(PACKAGE)/locale:./$(PACKAGE)/locale" \
|
--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) \
|
||||||
|
--collect-submodules=zeroconf \
|
||||||
|
--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:." \
|
--add-data="data/$(PACKAGE).icns:." \
|
||||||
--icon=data/$(PACKAGE).icns \
|
--icon=data/$(PACKAGE).icns \
|
||||||
--noconfirm \
|
--noconfirm \
|
||||||
@@ -86,7 +139,7 @@ installer_mac: build_ui build_rc
|
|||||||
--codesign-identity $(APPLE_SIG) \
|
--codesign-identity $(APPLE_SIG) \
|
||||||
src/$(PACKAGE)/__main__.py
|
src/$(PACKAGE)/__main__.py
|
||||||
|
|
||||||
installer_mac_dmg: installer_mac
|
app-mac-dmg: app-mac
|
||||||
mkdir dist/dmg
|
mkdir dist/dmg
|
||||||
mv dist/$(APP_NAME).app dist/dmg
|
mv dist/$(APP_NAME).app dist/dmg
|
||||||
create-dmg \
|
create-dmg \
|
||||||
@@ -104,25 +157,21 @@ installer_mac_dmg: installer_mac
|
|||||||
dist/$(APP_NAME)\ $(APP_VERSION).dmg \
|
dist/$(APP_NAME)\ $(APP_VERSION).dmg \
|
||||||
dist/dmg
|
dist/dmg
|
||||||
|
|
||||||
installer_linux: build_ui build_rc
|
.PHONY: app-licenses app app-mac app-mac-dmg
|
||||||
$(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
|
|
||||||
|
|
||||||
## Clean
|
## Clean
|
||||||
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
|
||||||
|
# Pycaches
|
||||||
|
find . -type d -name '__pycache__' -exec rm -r {} \+
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -rf $(VENV_PATH)
|
# Virtual environment
|
||||||
|
rm -rf "$(VENV_PATH)"
|
||||||
|
|
||||||
.PHONY: clean distclean
|
.PHONY: clean distclean
|
||||||
|
|||||||
86
make.bat
86
make.bat
@@ -2,38 +2,82 @@
|
|||||||
set PACKAGE=revpicommander
|
set PACKAGE=revpicommander
|
||||||
set APP_NAME=RevPi Commander
|
set APP_NAME=RevPi Commander
|
||||||
|
|
||||||
|
set PYTHON=venv\Scripts\python.exe
|
||||||
|
|
||||||
if "%1" == "venv" goto venv
|
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" == "clean" goto clean
|
||||||
|
if "%1" == "distclean" goto distclean
|
||||||
|
|
||||||
echo Make script for "%APP_NAME%" on Windows
|
echo Make script for "%APP_NAME%" on Windows
|
||||||
echo.
|
echo.
|
||||||
echo Need action:
|
echo Need action:
|
||||||
echo venv Create / update your virtual environment for build process
|
echo venv Create your virtual environment for build process
|
||||||
echo installer Build this application with PyInstaller
|
echo test Run defined tests of the project
|
||||||
echo clean Clean up your environment after build process
|
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
|
goto end
|
||||||
|
|
||||||
:venv
|
:venv
|
||||||
python -m venv venv
|
python -m venv venv
|
||||||
venv\\Scripts\\pip.exe install --upgrade -r requirements.txt
|
venv\Scripts\pip.exe install -r requirements.txt
|
||||||
goto end
|
goto end
|
||||||
|
|
||||||
:installer
|
:test
|
||||||
venv\\Scripts\\pyinstaller -n "%APP_NAME%" ^
|
set PYTHONPATH=src
|
||||||
--add-data="src\%PACKAGE%\locale;.\%PACKAGE%\locale" ^
|
%PYTHON% -m pytest
|
||||||
--add-data="data\%PACKAGE%.ico;." ^
|
goto end
|
||||||
--icon=data\\%PACKAGE%.ico ^
|
|
||||||
--noconfirm ^
|
:build
|
||||||
--clean ^
|
%PYTHON% -m setup sdist
|
||||||
--onedir ^
|
%PYTHON% -m setup bdist_wheel
|
||||||
--windowed ^
|
goto end
|
||||||
src\\%PACKAGE%\\__main__.py
|
|
||||||
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%" ^
|
||||||
|
--collect-submodules=zeroconf ^
|
||||||
|
--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
|
:clean
|
||||||
rmdir /S /Q build dist
|
rmdir /S /Q .pytest_cache
|
||||||
rmdir /S /Q src\%PACKAGE%.egg-info
|
rmdir /S /Q build dist src\\%PACKAGE%.egg-info
|
||||||
del *.spec
|
del /Q *.spec
|
||||||
|
|
||||||
:end
|
:end
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
setuptools>=65.6.3
|
# Build dependencies
|
||||||
wheel
|
pip-licenses
|
||||||
Pyinstaller
|
Pyinstaller
|
||||||
|
setuptools
|
||||||
|
wheel
|
||||||
|
|
||||||
|
# Runtime dependencies, must match install_requires in setup.py
|
||||||
keyring>=23.13.1
|
keyring>=23.13.1
|
||||||
PyQt5>=5.14.1
|
PyQt5>=5.14.1
|
||||||
paramiko>=2.12.0
|
paramiko>=2.12.0
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||||
|
|
||||||
#define MyAppName "RevPi Commander"
|
#define MyAppName "RevPi Commander"
|
||||||
#define MyAppVersion "0.10.0"
|
#define MyAppVersion "0.11.0"
|
||||||
#define MyAppPublisher "Sven Sager"
|
#define MyAppPublisher "Sven Sager"
|
||||||
#define MyAppURL "https://revpimodio.org/"
|
#define MyAppURL "https://revpimodio.org/"
|
||||||
#define MyAppICO "data\revpicommander.ico"
|
#define MyAppICO "data\revpicommander.ico"
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ __author__ = "Sven Sager"
|
|||||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
__package__ = "revpicommander"
|
__package__ = "revpicommander"
|
||||||
__version__ = "0.10.0"
|
__version__ = "0.11.0"
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ if __package__ == "":
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if len(sys.argv) == 2 and "--version" in sys.argv:
|
try:
|
||||||
# Catch --version, if this is the only argument (sys.argv[0] is always the script name)
|
# Use absolut import in the __main__ module
|
||||||
from revpicommander import __version__
|
|
||||||
print(__version__)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
else:
|
|
||||||
from revpicommander.revpicommander import main
|
from revpicommander.revpicommander import main
|
||||||
|
|
||||||
# Run the main application of this package
|
# Run the main application of this package
|
||||||
sys.exit(main())
|
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"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
from logging import getLogger
|
||||||
from re import compile
|
from re import compile
|
||||||
from sys import platform
|
from sys import platform
|
||||||
|
|
||||||
@@ -12,10 +13,11 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||||||
from zeroconf import IPVersion, ServiceBrowser, Zeroconf
|
from zeroconf import IPVersion, ServiceBrowser, Zeroconf
|
||||||
|
|
||||||
from . import helper
|
from . import helper
|
||||||
from . import proginit as pi
|
|
||||||
from .helper import RevPiSettings, WidgetData, all_revpi_settings
|
from .helper import RevPiSettings, WidgetData, all_revpi_settings
|
||||||
from .ui.avahisearch_ui import Ui_diag_search
|
from .ui.avahisearch_ui import Ui_diag_search
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AvahiSearchThread(QtCore.QThread):
|
class AvahiSearchThread(QtCore.QThread):
|
||||||
"""Search thread for Revolution Pi with installed RevPiPyLoad."""
|
"""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:
|
def remove_service(self, zeroconf: Zeroconf, conf_type: str, name: str) -> None:
|
||||||
"""Revolution Pi disappeared."""
|
"""Revolution Pi disappeared."""
|
||||||
pi.logger.debug("AvahiSearchThread.remove_service")
|
log.debug("AvahiSearchThread.remove_service")
|
||||||
self.removed.emit(name, conf_type)
|
self.removed.emit(name, conf_type)
|
||||||
|
|
||||||
def add_service(self, zeroconf: Zeroconf, conf_type: str, name: str) -> None:
|
def add_service(self, zeroconf: Zeroconf, conf_type: str, name: str) -> None:
|
||||||
"""New Revolution Pi found."""
|
"""New Revolution Pi found."""
|
||||||
pi.logger.debug("AvahiSearchThread.add_service")
|
log.debug("AvahiSearchThread.add_service")
|
||||||
info = zeroconf.get_service_info(conf_type, name)
|
info = zeroconf.get_service_info(conf_type, name)
|
||||||
if not info:
|
if not info:
|
||||||
return
|
return
|
||||||
@@ -49,7 +51,7 @@ class AvahiSearchThread(QtCore.QThread):
|
|||||||
|
|
||||||
def update_service(self, zeroconf: Zeroconf, conf_type: str, name: str) -> None:
|
def update_service(self, zeroconf: Zeroconf, conf_type: str, name: str) -> None:
|
||||||
"""New data of revolution pi"""
|
"""New data of revolution pi"""
|
||||||
pi.logger.debug("AvahiSearchThread.add_service")
|
log.debug("AvahiSearchThread.add_service")
|
||||||
info = zeroconf.get_service_info(conf_type, name)
|
info = zeroconf.get_service_info(conf_type, name)
|
||||||
if not info:
|
if not info:
|
||||||
return
|
return
|
||||||
@@ -58,14 +60,14 @@ class AvahiSearchThread(QtCore.QThread):
|
|||||||
self.updated.emit(name, info.server, info.port, conf_type, ip)
|
self.updated.emit(name, info.server, info.port, conf_type, ip)
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
pi.logger.debug("Started zero conf discovery.")
|
log.debug("Started zero conf discovery.")
|
||||||
zeroconf = Zeroconf()
|
zeroconf = Zeroconf()
|
||||||
revpi_browser = ServiceBrowser(zeroconf, "_revpipyload._tcp.local.", self)
|
revpi_browser = ServiceBrowser(zeroconf, "_revpipyload._tcp.local.", self)
|
||||||
while not self.isInterruptionRequested():
|
while not self.isInterruptionRequested():
|
||||||
# Just hanging around :)
|
# Just hanging around :)
|
||||||
self.msleep(self._cycle_wait_ms)
|
self.msleep(self._cycle_wait_ms)
|
||||||
zeroconf.close()
|
zeroconf.close()
|
||||||
pi.logger.debug("Stopped zero conf discovery.")
|
log.debug("Stopped zero conf discovery.")
|
||||||
|
|
||||||
|
|
||||||
class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
||||||
@@ -191,7 +193,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_act_connect_triggered(self) -> None:
|
def on_act_connect_triggered(self) -> None:
|
||||||
"""Connect via existing settings or ask for type."""
|
"""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()
|
selected_items = self.tb_revpi.selectedItems()
|
||||||
if not selected_items:
|
if not selected_items:
|
||||||
return
|
return
|
||||||
@@ -206,7 +208,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_act_connect_ssh_triggered(self) -> None:
|
def on_act_connect_ssh_triggered(self) -> None:
|
||||||
"""Create new revpi settings with ssh, save and connect."""
|
"""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:
|
if self.tb_revpi.currentRow() == -1:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -218,7 +220,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_act_connect_xmlrpc_triggered(self) -> None:
|
def on_act_connect_xmlrpc_triggered(self) -> None:
|
||||||
"""Create new revpi settings with XML-RPC, save and connect."""
|
"""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:
|
if self.tb_revpi.currentRow() == -1:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -331,7 +333,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
|||||||
@QtCore.pyqtSlot(int, int)
|
@QtCore.pyqtSlot(int, int)
|
||||||
def on_tb_revpi_cellDoubleClicked(self, row: int, column: int) -> None:
|
def on_tb_revpi_cellDoubleClicked(self, row: int, column: int) -> None:
|
||||||
"""Connect to double-clicked Revolution Pi."""
|
"""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()
|
selected_items = self.tb_revpi.selectedItems()
|
||||||
if not selected_items:
|
if not selected_items:
|
||||||
return
|
return
|
||||||
@@ -353,7 +355,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_connect_clicked(self) -> None:
|
def on_btn_connect_clicked(self) -> None:
|
||||||
"""Connect to selected Revolution Pi."""
|
"""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()
|
selected_items = self.tb_revpi.selectedItems()
|
||||||
if not selected_items:
|
if not selected_items:
|
||||||
return
|
return
|
||||||
@@ -370,7 +372,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_save_clicked(self) -> None:
|
def on_btn_save_clicked(self) -> None:
|
||||||
"""Save selected Revolution Pi."""
|
"""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()
|
row_index = self.tb_revpi.currentRow()
|
||||||
if row_index == -1:
|
if row_index == -1:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||||||
|
|
||||||
from .ui.backgroundworker_ui import Ui_diag_backgroundworker
|
from .ui.backgroundworker_ui import Ui_diag_backgroundworker
|
||||||
|
|
||||||
log = getLogger()
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BackgroundWorker(QtCore.QThread):
|
class BackgroundWorker(QtCore.QThread):
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ __copyright__ = "Copyright (C) 2023 Sven Sager"
|
|||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
import pickle
|
import pickle
|
||||||
|
from logging import getLogger
|
||||||
from xmlrpc.client import Binary, Fault, MultiCall, MultiCallIterator
|
from xmlrpc.client import Binary, Fault, MultiCall, MultiCallIterator
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
@@ -14,6 +15,8 @@ from . import proginit as pi
|
|||||||
from .debugios import DebugIos
|
from .debugios import DebugIos
|
||||||
from .ui.debugcontrol_ui import Ui_wid_debugcontrol
|
from .ui.debugcontrol_ui import Ui_wid_debugcontrol
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PsValues(QtCore.QThread):
|
class PsValues(QtCore.QThread):
|
||||||
"""
|
"""
|
||||||
@@ -31,7 +34,7 @@ class PsValues(QtCore.QThread):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Read IO values of Revolution Pi."""
|
"""Read IO values of Revolution Pi."""
|
||||||
pi.logger.debug("PsValues.run enter")
|
log.debug("PsValues.run enter")
|
||||||
|
|
||||||
while not self.isInterruptionRequested():
|
while not self.isInterruptionRequested():
|
||||||
try:
|
try:
|
||||||
@@ -39,16 +42,16 @@ class PsValues(QtCore.QThread):
|
|||||||
helper.cm.call_remote_function("ps_values", raise_exception=True)
|
helper.cm.call_remote_function("ps_values", raise_exception=True)
|
||||||
)
|
)
|
||||||
except Fault:
|
except Fault:
|
||||||
pi.logger.warning("Detected piCtory reset.")
|
log.warning("Detected piCtory reset.")
|
||||||
self.requestInterruption()
|
self.requestInterruption()
|
||||||
self.driver_reset_detected.emit()
|
self.driver_reset_detected.emit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.error(e)
|
log.error(e)
|
||||||
self.process_image_received.emit(Binary())
|
self.process_image_received.emit(Binary())
|
||||||
|
|
||||||
self.msleep(self._cycle_time)
|
self.msleep(self._cycle_time)
|
||||||
|
|
||||||
pi.logger.debug("PsValues.run exit")
|
log.debug("PsValues.run exit")
|
||||||
|
|
||||||
|
|
||||||
class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
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)
|
self.shc_write_o.activated.connect(self.on_btn_write_o_clicked)
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
pi.logger.debug("DebugControl.__del__")
|
log.debug("DebugControl.__del__")
|
||||||
|
|
||||||
def _set_gui_control_states(self):
|
def _set_gui_control_states(self):
|
||||||
"""Set states depending on acl level."""
|
"""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 view >= 1
|
||||||
# xml_mode write >= 3
|
# xml_mode write >= 3
|
||||||
self.btn_read_io.setEnabled(not self.cbx_write.isChecked())
|
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
|
: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]:
|
for position in sorted(self.dict_devices) if device_position == -1 else [device_position]:
|
||||||
if position in self.dict_windows:
|
if position in self.dict_windows:
|
||||||
# Remove singe window and button
|
# Remove singe window and button
|
||||||
@@ -151,11 +154,11 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
|||||||
try:
|
try:
|
||||||
ba_values = helper.cm.call_remote_function("ps_values", raise_exception=True)
|
ba_values = helper.cm.call_remote_function("ps_values", raise_exception=True)
|
||||||
except Fault:
|
except Fault:
|
||||||
pi.logger.warning("Detected piCtory reset.")
|
log.warning("Detected piCtory reset.")
|
||||||
self._driver_reset_detected()
|
self._driver_reset_detected()
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.error(e)
|
log.error(e)
|
||||||
ba_values = Binary()
|
ba_values = Binary()
|
||||||
|
|
||||||
# From now on use bytes instead of Binary
|
# From now on use bytes instead of Binary
|
||||||
@@ -255,7 +258,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
|||||||
return
|
return
|
||||||
elif not isinstance(return_list, list):
|
elif not isinstance(return_list, list):
|
||||||
return
|
return
|
||||||
pi.logger.debug("DebugControl._validate_multicall")
|
log.debug("DebugControl._validate_multicall")
|
||||||
|
|
||||||
str_errmsg = ""
|
str_errmsg = ""
|
||||||
for lst_result in return_list: # type: list
|
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])
|
self.dict_windows[lst_result[0]].reset_change_value_colors(lst_result[1])
|
||||||
|
|
||||||
if str_errmsg != "":
|
if str_errmsg != "":
|
||||||
pi.logger.error(str_errmsg)
|
log.error(str_errmsg)
|
||||||
if not self.cbx_refresh.isChecked():
|
if not self.cbx_refresh.isChecked():
|
||||||
QtWidgets.QMessageBox.critical(self, self.tr("Error"), str_errmsg)
|
QtWidgets.QMessageBox.critical(self, self.tr("Error"), str_errmsg)
|
||||||
|
|
||||||
def deleteLater(self):
|
def deleteLater(self):
|
||||||
"""Clean up all sub windows."""
|
"""Clean up all sub windows."""
|
||||||
pi.logger.debug("DebugControl.deleteLater")
|
log.debug("DebugControl.deleteLater")
|
||||||
|
|
||||||
self.cbx_write.setChecked(False)
|
self.cbx_write.setChecked(False)
|
||||||
self.cbx_refresh.setChecked(False)
|
self.cbx_refresh.setChecked(False)
|
||||||
@@ -288,7 +291,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
|||||||
|
|
||||||
def reload_devices(self):
|
def reload_devices(self):
|
||||||
"""Rebuild GUI depending on devices and ios of Revolution Pi."""
|
"""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):
|
if not helper.cm.call_remote_function("psstart", default_value=False):
|
||||||
# RevPiPyLoad does not support psstart (too old)
|
# RevPiPyLoad does not support psstart (too old)
|
||||||
@@ -358,7 +361,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
|||||||
@QtCore.pyqtSlot(bool)
|
@QtCore.pyqtSlot(bool)
|
||||||
def on_btn_device_clicked(self, checked: bool):
|
def on_btn_device_clicked(self, checked: bool):
|
||||||
"""Open or close IO window."""
|
"""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())
|
position = int(self.sender().objectName())
|
||||||
if position in self.dict_windows:
|
if position in self.dict_windows:
|
||||||
@@ -369,14 +372,14 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
|||||||
@QtCore.pyqtSlot(int)
|
@QtCore.pyqtSlot(int)
|
||||||
def on_device_closed(self, position: int):
|
def on_device_closed(self, position: int):
|
||||||
"""Change the check state of button, if window was closed."""
|
"""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 = self.gb_devices.findChild(QtWidgets.QPushButton, str(position)) # type: QtWidgets.QPushButton
|
||||||
btn.setChecked(False)
|
btn.setChecked(False)
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_read_io_pressed(self):
|
def on_btn_read_io_pressed(self):
|
||||||
"""Read all IO values and replace changed ones."""
|
"""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
|
for win in self.dict_windows.values(): # type: DebugIos
|
||||||
win.reset_label_colors()
|
win.reset_label_colors()
|
||||||
self._work_values()
|
self._work_values()
|
||||||
@@ -384,14 +387,14 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_refresh_io_pressed(self):
|
def on_btn_refresh_io_pressed(self):
|
||||||
"""Read all IO values but do not touch changed ones."""
|
"""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():
|
if not self.cbx_refresh.isChecked():
|
||||||
self._work_values(refresh=True)
|
self._work_values(refresh=True)
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_write_o_clicked(self):
|
def on_btn_write_o_clicked(self):
|
||||||
"""Write outputs."""
|
"""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):
|
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
|
for win in self.dict_windows.values(): # type: DebugIos
|
||||||
win.reset_label_colors()
|
win.reset_label_colors()
|
||||||
@@ -400,7 +403,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
|
|||||||
@QtCore.pyqtSlot(int)
|
@QtCore.pyqtSlot(int)
|
||||||
def on_cbx_refresh_stateChanged(self, state: int):
|
def on_cbx_refresh_stateChanged(self, state: int):
|
||||||
"""Start or stop the auto refresh thread."""
|
"""Start or stop the auto refresh thread."""
|
||||||
pi.logger.debug("DebugControl.cbx_refresh_stateChanged")
|
log.debug("DebugControl.cbx_refresh_stateChanged")
|
||||||
|
|
||||||
# Start / stop worker thread
|
# Start / stop worker thread
|
||||||
if state == QtCore.Qt.Checked and (helper.cm.connected or helper.cm.simulating):
|
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)
|
@QtCore.pyqtSlot(int)
|
||||||
def on_cbx_write_stateChanged(self, state: 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
|
checked = state == QtCore.Qt.Checked
|
||||||
for win in self.dict_windows.values(): # type: DebugIos
|
for win in self.dict_windows.values(): # type: DebugIos
|
||||||
win.write_values = checked
|
win.write_values = checked
|
||||||
|
|||||||
@@ -5,13 +5,15 @@ __copyright__ = "Copyright (C) 2023 Sven Sager"
|
|||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
import struct
|
import struct
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from . import helper
|
from . import helper
|
||||||
from . import proginit as pi
|
|
||||||
from .ui.debugios_ui import Ui_win_debugios
|
from .ui.debugios_ui import Ui_win_debugios
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
||||||
"""IO window of one device."""
|
"""IO window of one device."""
|
||||||
@@ -46,10 +48,10 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
|||||||
self.style_sheet = "background-color: red;"
|
self.style_sheet = "background-color: red;"
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
pi.logger.debug("DebugIos.__del__")
|
log.debug("DebugIos.__del__")
|
||||||
|
|
||||||
def closeEvent(self, a0: QtGui.QCloseEvent):
|
def closeEvent(self, a0: QtGui.QCloseEvent):
|
||||||
pi.logger.debug("DebugIos.closeEvent")
|
log.debug("DebugIos.closeEvent")
|
||||||
helper.cm.settings.debug_geos[self.position] = self.saveGeometry()
|
helper.cm.settings.debug_geos[self.position] = self.saveGeometry()
|
||||||
self.device_closed.emit(self.position)
|
self.device_closed.emit(self.position)
|
||||||
|
|
||||||
@@ -99,6 +101,12 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
|||||||
signed = io[6]
|
signed = io[6]
|
||||||
word_order = io[7] if len(io) > 7 else "ignored"
|
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)
|
val = container.findChild(self.search_class, name)
|
||||||
if val is not None:
|
if val is not None:
|
||||||
# Destroy IO if the properties was changed
|
# Destroy IO if the properties was changed
|
||||||
@@ -108,28 +116,45 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
|||||||
signed != val.property("signed"):
|
signed != val.property("signed"):
|
||||||
del self.__qwa[name]
|
del self.__qwa[name]
|
||||||
layout.removeRow(layout.getWidgetPosition(val)[0])
|
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:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
lbl = QtWidgets.QLabel(name, container)
|
lbl, val = self._create_widgets(
|
||||||
lbl.setObjectName("lbl_".format(name))
|
name,
|
||||||
lbl.setStyleSheet(self.style_sheet)
|
byte_length,
|
||||||
|
bit_address,
|
||||||
val = self._create_widget(name, byte_length, bit_address, byteorder, signed, read_only, word_order)
|
byteorder,
|
||||||
|
signed,
|
||||||
|
read_only,
|
||||||
|
word_order,
|
||||||
|
async_call,
|
||||||
|
)
|
||||||
|
lbl.setParent(container)
|
||||||
val.setParent(container)
|
val.setParent(container)
|
||||||
layout.insertRow(counter, val, lbl)
|
layout.insertRow(counter, val, lbl)
|
||||||
|
|
||||||
self.splitter.setSizes([1, 1])
|
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,
|
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 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:
|
if bit_address >= 0:
|
||||||
val = QtWidgets.QCheckBox()
|
val = QtWidgets.QCheckBox()
|
||||||
val.setEnabled(not read_only)
|
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
|
# Set alias to use the same function name on all widget types
|
||||||
val.setValue = val.setChecked
|
val.setValue = val.setChecked
|
||||||
if not read_only:
|
if not read_only:
|
||||||
@@ -140,9 +165,12 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
|||||||
# Bytes or string
|
# Bytes or string
|
||||||
val = QtWidgets.QLineEdit()
|
val = QtWidgets.QLineEdit()
|
||||||
val.setReadOnly(read_only)
|
val.setReadOnly(read_only)
|
||||||
|
lbl.setProperty("struct_type", "text")
|
||||||
val.setProperty("struct_type", "text")
|
val.setProperty("struct_type", "text")
|
||||||
|
|
||||||
|
lbl.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
val.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
val.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
|
lbl.customContextMenuRequested.connect(self.on_context_menu)
|
||||||
val.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
|
# 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 = QtWidgets.QDoubleSpinBox()
|
||||||
val.setReadOnly(read_only)
|
val.setReadOnly(read_only)
|
||||||
|
lbl.setProperty("struct_type", struct_type)
|
||||||
val.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(
|
val.setProperty("frm", "{0}{1}".format(
|
||||||
">" if byteorder == "big" else "<",
|
">" if byteorder == "big" else "<",
|
||||||
struct_type.lower() if signed else struct_type
|
struct_type.lower() if signed else struct_type
|
||||||
))
|
))
|
||||||
|
|
||||||
|
lbl.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
val.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
val.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
|
lbl.customContextMenuRequested.connect(self.on_context_menu)
|
||||||
val.customContextMenuRequested.connect(self.on_context_menu)
|
val.customContextMenuRequested.connect(self.on_context_menu)
|
||||||
|
|
||||||
val.setDecimals(0)
|
val.setDecimals(0)
|
||||||
@@ -172,15 +207,23 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
|||||||
if not read_only:
|
if not read_only:
|
||||||
val.valueChanged.connect(self._change_sbx_dvalue)
|
val.valueChanged.connect(self._change_sbx_dvalue)
|
||||||
|
|
||||||
|
lbl.setObjectName(name)
|
||||||
val.setObjectName(name)
|
val.setObjectName(name)
|
||||||
|
lbl.setProperty("big_endian", byteorder == "big")
|
||||||
val.setProperty("big_endian", byteorder == "big")
|
val.setProperty("big_endian", byteorder == "big")
|
||||||
|
lbl.setProperty("bit_address", bit_address)
|
||||||
val.setProperty("bit_address", bit_address)
|
val.setProperty("bit_address", bit_address)
|
||||||
|
lbl.setProperty("byte_length", byte_length)
|
||||||
val.setProperty("byte_length", byte_length)
|
val.setProperty("byte_length", byte_length)
|
||||||
|
lbl.setProperty("signed", signed)
|
||||||
val.setProperty("signed", signed)
|
val.setProperty("signed", signed)
|
||||||
|
lbl.setProperty("word_order", word_order)
|
||||||
val.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
|
self.__qwa[name] = val
|
||||||
return val
|
return lbl, val
|
||||||
|
|
||||||
@QtCore.pyqtSlot(int)
|
@QtCore.pyqtSlot(int)
|
||||||
def _change_cbx_value(self, value: int):
|
def _change_cbx_value(self, value: int):
|
||||||
@@ -209,11 +252,36 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
|||||||
@QtCore.pyqtSlot(QtCore.QPoint)
|
@QtCore.pyqtSlot(QtCore.QPoint)
|
||||||
def on_context_menu(self, point: QtCore.QPoint):
|
def on_context_menu(self, point: QtCore.QPoint):
|
||||||
"""Generate menu for data format changes."""
|
"""Generate menu for data format changes."""
|
||||||
pi.logger.debug("DebugIos.on_context_menu")
|
log.debug("DebugIos.on_context_menu")
|
||||||
|
|
||||||
sender = self.sender()
|
sender = self.sender()
|
||||||
men = QtWidgets.QMenu(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:
|
if sender.property("byte_length") > 4:
|
||||||
# Textbox needs format buttons
|
# Textbox needs format buttons
|
||||||
act_as_text = QtWidgets.QAction(self.tr("as text"))
|
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 = QtWidgets.QAction(self.tr("signed"), men)
|
||||||
act_signed.setCheckable(True)
|
act_signed.setCheckable(True)
|
||||||
act_signed.setChecked(sender.property("signed") or False)
|
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 = QtWidgets.QAction(self.tr("big_endian"), men)
|
||||||
act_byteorder.setCheckable(True)
|
act_byteorder.setCheckable(True)
|
||||||
act_byteorder.setChecked(sender.property("big_endian") or False)
|
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:
|
if sender.property("byte_length") > 2:
|
||||||
act_wordorder = QtWidgets.QAction(self.tr("switch wordorder"))
|
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())
|
sender.setProperty("big_endian", act_byteorder.isChecked())
|
||||||
elif rc == act_wordorder:
|
elif rc == act_wordorder:
|
||||||
sender.setProperty("word_order", "big" if act_wordorder.isChecked() else "little")
|
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"):
|
if sender.property("frm"):
|
||||||
sender.setProperty("frm", "{0}{1}".format(
|
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
|
: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:
|
if io_name is None:
|
||||||
lst_wid = self.saw_out.findChildren(
|
lst_wid = self.saw_out.findChildren(
|
||||||
self.search_class, options=QtCore.Qt.FindDirectChildrenOnly)
|
self.search_class, options=QtCore.Qt.FindDirectChildrenOnly)
|
||||||
@@ -346,7 +422,7 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
|
|||||||
)
|
)
|
||||||
return actual_value, last_value
|
return actual_value, last_value
|
||||||
except Exception:
|
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
|
pass
|
||||||
|
|
||||||
return actual_value.encode(), last_value.encode()
|
return actual_value.encode(), last_value.encode()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import pickle
|
|||||||
import socket
|
import socket
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from http.client import CannotSendRequest
|
from http.client import CannotSendRequest
|
||||||
|
from logging import getLogger
|
||||||
from os import environ, remove
|
from os import environ, remove
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
@@ -22,6 +23,8 @@ from paramiko.ssh_exception import AuthenticationException
|
|||||||
from . import proginit as pi
|
from . import proginit as pi
|
||||||
from .ssh_tunneling.server import SSHLocalTunnel
|
from .ssh_tunneling.server import SSHLocalTunnel
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
settings = QtCore.QSettings("revpimodio.org", "revpicommander")
|
settings = QtCore.QSettings("revpimodio.org", "revpicommander")
|
||||||
"""Global application settings."""
|
"""Global application settings."""
|
||||||
|
|
||||||
@@ -45,6 +48,7 @@ class WidgetData(IntEnum):
|
|||||||
host_name = 267
|
host_name = 267
|
||||||
host_name_full = 268
|
host_name_full = 268
|
||||||
file_name = 309
|
file_name = 309
|
||||||
|
is_plc_program = 310
|
||||||
revpi_settings = 320
|
revpi_settings = 320
|
||||||
|
|
||||||
|
|
||||||
@@ -222,6 +226,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
self._cli = None
|
self._cli = None
|
||||||
self._cli_connect = Queue()
|
self._cli_connect = Queue()
|
||||||
self._cycle_time = cycle_time_ms
|
self._cycle_time = cycle_time_ms
|
||||||
|
self._has_error = False
|
||||||
self._lck_cli = Lock()
|
self._lck_cli = Lock()
|
||||||
self._ps_started = False
|
self._ps_started = False
|
||||||
self._revpi = None
|
self._revpi = None
|
||||||
@@ -243,7 +248,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
self._xml_mode_refresh = False
|
self._xml_mode_refresh = False
|
||||||
|
|
||||||
def __call_simulator(self, function_name: str, *args, default_value=None, **kwargs):
|
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 function_name == "ps_values":
|
||||||
if self._revpi.readprocimg():
|
if self._revpi.readprocimg():
|
||||||
bytebuff = bytearray()
|
bytebuff = bytearray()
|
||||||
@@ -387,7 +392,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
xml_funcs = sp.system.listMethods()
|
xml_funcs = sp.system.listMethods()
|
||||||
xml_mode = sp.xmlmodus()
|
xml_mode = sp.xmlmodus()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.exception(e)
|
log.exception(e)
|
||||||
self.connection_error_observed.emit(str(e))
|
self.connection_error_observed.emit(str(e))
|
||||||
|
|
||||||
if revpi_settings.ssh_use_tunnel:
|
if revpi_settings.ssh_use_tunnel:
|
||||||
@@ -451,7 +456,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
self._revpi = None
|
self._revpi = None
|
||||||
self._revpi_output = None
|
self._revpi_output = None
|
||||||
|
|
||||||
pi.logger.debug("Simulator destroyed.")
|
log.debug("Simulator destroyed.")
|
||||||
self.connection_disconnected.emit()
|
self.connection_disconnected.emit()
|
||||||
|
|
||||||
elif self._cli is not None:
|
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 procimg: Process image, which is a 4 kByte file for simulation
|
||||||
:param clean_existing: Reset the file to ZERO \x00 bytes
|
: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:
|
if not exists(procimg) or clean_existing:
|
||||||
with open(procimg, "wb") as fh:
|
with open(procimg, "wb") as fh:
|
||||||
@@ -507,7 +512,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
self.connection_established.emit()
|
self.connection_established.emit()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.exception(e)
|
log.exception(e)
|
||||||
self.connection_error_observed.emit(str(e))
|
self.connection_error_observed.emit(str(e))
|
||||||
self._revpi_output = None
|
self._revpi_output = None
|
||||||
self._revpi = None
|
self._revpi = None
|
||||||
@@ -522,7 +527,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
|
|
||||||
def reset_simulator(self):
|
def reset_simulator(self):
|
||||||
"""Reset all io to piCtory defaults."""
|
"""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):
|
if settings.value("simulator/restart_zero", False, bool):
|
||||||
with open(self._revpi.procimg, "wb") as fh:
|
with open(self._revpi.procimg, "wb") as fh:
|
||||||
fh.write(b'\x00' * 4096)
|
fh.write(b'\x00' * 4096)
|
||||||
@@ -558,10 +563,11 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
self.xml_mode = sp.xmlmodus()
|
self.xml_mode = sp.xmlmodus()
|
||||||
self._xml_mode_refresh = False
|
self._xml_mode_refresh = False
|
||||||
except CannotSendRequest as e:
|
except CannotSendRequest as e:
|
||||||
pi.logger.warning(e)
|
log.warning(e)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.warning(e)
|
log.warning(e)
|
||||||
self.status_changed.emit(self.tr("SERVER ERROR"), "red")
|
self.status_changed.emit(self.tr("SERVER ERROR"), "red")
|
||||||
|
self._has_error = True
|
||||||
self.connection_error_observed.emit("{0} | {1}".format(e, type(e)))
|
self.connection_error_observed.emit("{0} | {1}".format(e, type(e)))
|
||||||
|
|
||||||
if self.ssh_tunnel_server and not self.ssh_tunnel_server.connected:
|
if self.ssh_tunnel_server and not self.ssh_tunnel_server.connected:
|
||||||
@@ -585,6 +591,10 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
if self._has_error:
|
||||||
|
self._has_error = False
|
||||||
|
self.connection_recovered.emit()
|
||||||
|
|
||||||
if plc_exit_code == -1:
|
if plc_exit_code == -1:
|
||||||
self.status_changed.emit(self.tr("RUNNING"), "green")
|
self.status_changed.emit(self.tr("RUNNING"), "green")
|
||||||
elif plc_exit_code == -2:
|
elif plc_exit_code == -2:
|
||||||
@@ -614,7 +624,7 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
:return: Return value of remote function or default_value
|
:return: Return value of remote function or default_value
|
||||||
"""
|
"""
|
||||||
if self._cli is None and self._revpi is None:
|
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:
|
if raise_exception:
|
||||||
raise ConnectionError("Connection manager not connected")
|
raise ConnectionError("Connection manager not connected")
|
||||||
return default_value
|
return default_value
|
||||||
@@ -638,7 +648,8 @@ class ConnectionManager(QtCore.QThread):
|
|||||||
if reload_funcs:
|
if reload_funcs:
|
||||||
self.xml_funcs = self._cli.system.listMethods()
|
self.xml_funcs = self._cli.system.listMethods()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.error(e)
|
self._has_error = True
|
||||||
|
log.error(e)
|
||||||
if raise_exception:
|
if raise_exception:
|
||||||
self._lck_cli.release()
|
self._lck_cli.release()
|
||||||
raise
|
raise
|
||||||
@@ -722,7 +733,7 @@ def import_old_settings():
|
|||||||
revpi_setting._settings = settings
|
revpi_setting._settings = settings
|
||||||
revpi_setting.save_settings()
|
revpi_setting.save_settings()
|
||||||
except Exception:
|
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()
|
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"
|
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from PyQt5 import QtGui, QtWidgets
|
from PyQt5 import QtGui, QtWidgets
|
||||||
|
|
||||||
from . import proginit as pi
|
|
||||||
from .ui.mqttmanager_ui import Ui_diag_mqtt
|
from .ui.mqttmanager_ui import Ui_diag_mqtt
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class MqttManager(QtWidgets.QDialog, Ui_diag_mqtt):
|
class MqttManager(QtWidgets.QDialog, Ui_diag_mqtt):
|
||||||
"""MQTT settings for option window."""
|
"""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_password.setText(self.dc["mqttpassword"])
|
||||||
self.txt_client_id.setText(self.dc["mqttclient_id"])
|
self.txt_client_id.setText(self.dc["mqttclient_id"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.exception(e)
|
log.exception(e)
|
||||||
self.dc = {}
|
self.dc = {}
|
||||||
return False
|
return False
|
||||||
return True
|
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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Global program initialization."""
|
"""Global program initialization."""
|
||||||
|
# SPDX-FileCopyrightText: 2018-2023 Sven Sager
|
||||||
|
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
__author__ = "Sven Sager"
|
__author__ = "Sven Sager"
|
||||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
__copyright__ = "Copyright (C) 2018-2023 Sven Sager"
|
||||||
__license__ = "GPLv2"
|
__license__ = "LGPL-2.0-or-later"
|
||||||
|
__version__ = "1.3.1"
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from os import R_OK, W_OK, access
|
from os import R_OK, W_OK, access, environ, getpid, remove
|
||||||
from os.path import abspath, dirname, join
|
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
|
# Program name
|
||||||
programname = "revpicommander"
|
programname = "revpicommander"
|
||||||
|
program_version = external_version
|
||||||
|
|
||||||
# Set to True, if you want to save config file
|
conf_rw = False # If you want so save the configuration with .save_conf() set to True
|
||||||
conf_rw = False
|
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()
|
conf = ConfigParser()
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
pidfile = "/var/run/{0}.pid".format(programname)
|
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():
|
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
|
# Shutdown logging system
|
||||||
logging.shutdown()
|
logging.shutdown()
|
||||||
|
|
||||||
|
# Close logfile
|
||||||
|
if pargs.daemon:
|
||||||
|
sys.stdout.close()
|
||||||
|
|
||||||
|
|
||||||
def reconfigure_logger():
|
def reconfigure_logger():
|
||||||
"""Configure logging module of program."""
|
"""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
|
# Clear all log handler
|
||||||
for lhandler in logger.handlers.copy():
|
for lhandler in logger.handlers.copy():
|
||||||
lhandler.close()
|
lhandler.close()
|
||||||
logger.removeHandler(lhandler)
|
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
|
# Create new log handler
|
||||||
logformat = logging.Formatter(
|
if pargs.verbose > 2:
|
||||||
"{asctime} [{levelname:8}] {message}",
|
log_frm = "{asctime} [{levelname:8}] {name} {message}"
|
||||||
datefmt="%Y-%m-%d %H:%M:%S", style="{"
|
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 = logging.StreamHandler(sys.stdout)
|
||||||
lhandler.setFormatter(logformat)
|
lhandler.setFormatter(logformat)
|
||||||
logger.addHandler(lhandler)
|
logger.addHandler(lhandler)
|
||||||
@@ -54,59 +139,193 @@ def reconfigure_logger():
|
|||||||
if pargs.verbose == 1:
|
if pargs.verbose == 1:
|
||||||
loglevel = logging.INFO
|
loglevel = logging.INFO
|
||||||
elif pargs.verbose > 1:
|
elif pargs.verbose > 1:
|
||||||
|
lhandler.addFilter(FilterDebug())
|
||||||
loglevel = logging.DEBUG
|
loglevel = logging.DEBUG
|
||||||
else:
|
else:
|
||||||
loglevel = logging.WARNING
|
loglevel = logging.WARNING
|
||||||
logger.setLevel(loglevel)
|
logger.setLevel(loglevel)
|
||||||
|
|
||||||
|
|
||||||
def reload_conf():
|
def reload_conf(clear_load=False) -> None:
|
||||||
"""Reload config file."""
|
"""
|
||||||
if "conffile" in pargs:
|
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
|
# Check config file
|
||||||
if not access(pargs.conffile, R_OK):
|
if not access(pargs.conffile, R_OK):
|
||||||
raise RuntimeError(
|
raise RuntimeError("can not access config file '{0}'".format(pargs.conffile))
|
||||||
"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):
|
||||||
if conf_rw and not access(pargs.conffile, W_OK):
|
raise RuntimeError(
|
||||||
raise RuntimeError(
|
"can not wirte to directory '{0}' to create files"
|
||||||
"can not write to config file '{0}'".format(pargs.conffile)
|
"".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
|
if clear_load:
|
||||||
global conf
|
# 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))
|
logger.info("loading config file: {0}".format(pargs.conffile))
|
||||||
conf.read(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
|
# Generate command arguments of the program
|
||||||
parser = ArgumentParser(
|
parser = ArgumentParser(
|
||||||
prog=programname,
|
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(
|
parser.add_argument(
|
||||||
"-f", "--logfile", dest="logfile",
|
"-v",
|
||||||
help="Save log entries to this file"
|
"--verbose",
|
||||||
|
action="count",
|
||||||
|
dest="verbose",
|
||||||
|
default=0,
|
||||||
|
help="switch on verbose logging",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
# If packed with opensource licenses, add argument to print license information about bundled modules
|
||||||
"-v", "--verbose", action="count", dest="verbose", default=0,
|
open_source_licenses = join(dirname(__file__), "open-source-licenses", "open-source-licenses.txt")
|
||||||
help="Switch on verbose logging"
|
if exists(open_source_licenses):
|
||||||
)
|
parser.add_argument(
|
||||||
# The __main__ script will process the version number argument
|
"--open-source-licenses",
|
||||||
parser.add_argument("--version", action="store_true", help="Print version number of program and exit")
|
action="store_true",
|
||||||
|
dest="oss_licenses",
|
||||||
|
help="print packed open-source-licenses and exit",
|
||||||
|
)
|
||||||
pargs = parser.parse_args()
|
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
|
# 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:
|
if "verbose" not in pargs:
|
||||||
pargs.verbose = 0
|
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
|
# Get absolute paths
|
||||||
pwd = abspath(".")
|
pwd = abspath(".")
|
||||||
|
|
||||||
# Configure logger
|
# Configure logger
|
||||||
if "logfile" in pargs and pargs.logfile is not None \
|
if "logfile" in pargs and pargs.logfile is not None and dirname(pargs.logfile) == "":
|
||||||
and dirname(pargs.logfile) == "":
|
|
||||||
pargs.logfile = join(pwd, pargs.logfile)
|
pargs.logfile = join(pwd, pargs.logfile)
|
||||||
reconfigure_logger()
|
reconfigure_logger()
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ __copyright__ = "Copyright (C) 2018 Sven Sager"
|
|||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
from logging import getLogger
|
||||||
from os.path import dirname, join
|
from os.path import dirname, join
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
from revpicommander.oss_licenses import OssLicenses
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from . import helper
|
from . import helper
|
||||||
from . import proginit as pi
|
from . import proginit as pi
|
||||||
@@ -28,6 +30,8 @@ from .simulator import Simulator
|
|||||||
from .sshauth import SSHAuth
|
from .sshauth import SSHAuth
|
||||||
from .ui.revpicommander_ui import Ui_win_revpicommander
|
from .ui.revpicommander_ui import Ui_win_revpicommander
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ConnectingPyload(QtCore.QThread):
|
class ConnectingPyload(QtCore.QThread):
|
||||||
"""
|
"""
|
||||||
@@ -87,8 +91,14 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
|||||||
|
|
||||||
self.setWindowFlag(QtCore.Qt.WindowMaximizeButtonHint, False)
|
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:
|
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
||||||
pi.logger.debug("RevPiCommander.closeEvent")
|
log.debug("RevPiCommander.closeEvent")
|
||||||
helper.cm.pyload_disconnect()
|
helper.cm.pyload_disconnect()
|
||||||
helper.settings.setValue("revpicommander/geo", self.saveGeometry())
|
helper.settings.setValue("revpicommander/geo", self.saveGeometry())
|
||||||
|
|
||||||
@@ -157,7 +167,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_cm_connection_disconnected(self):
|
def on_cm_connection_disconnected(self):
|
||||||
"""Connection of connection manager was disconnected."""
|
"""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._set_gui_control_states()
|
||||||
self.txt_host.setVisible(True)
|
self.txt_host.setVisible(True)
|
||||||
@@ -167,7 +177,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_cm_connection_disconnecting(self):
|
def on_cm_connection_disconnecting(self):
|
||||||
"""Connection of connection manager will now disconnect."""
|
"""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
|
# This will remove the widgets in the button functions
|
||||||
self.btn_plc_debug.setChecked(False)
|
self.btn_plc_debug.setChecked(False)
|
||||||
@@ -184,7 +194,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_cm_connection_established(self):
|
def on_cm_connection_established(self):
|
||||||
"""Connection manager established a new connection and loaded values."""
|
"""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()
|
self._set_gui_control_states()
|
||||||
if helper.cm.simulating:
|
if helper.cm.simulating:
|
||||||
@@ -325,7 +335,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
|
|||||||
).format(procimg_file, configrsc_file)
|
).format(procimg_file, configrsc_file)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pi.logger.error("Can not start simulator")
|
log.error("Can not start simulator")
|
||||||
QtWidgets.QMessageBox.critical(
|
QtWidgets.QMessageBox.critical(
|
||||||
self, self.tr("Can not start..."), self.tr(
|
self, self.tr("Can not start..."), self.tr(
|
||||||
"Can not start the simulator! Maybe the piCtory file is corrupt "
|
"Can not start the simulator! Maybe the piCtory file is corrupt "
|
||||||
|
|||||||
@@ -7,16 +7,18 @@ __license__ = "GPLv2"
|
|||||||
import gzip
|
import gzip
|
||||||
import os
|
import os
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
from logging import getLogger
|
||||||
from xmlrpc.client import Binary
|
from xmlrpc.client import Binary
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from . import helper
|
from . import helper
|
||||||
from . import proginit as pi
|
|
||||||
from .backgroundworker import BackgroundWorker
|
from .backgroundworker import BackgroundWorker
|
||||||
from .helper import WidgetData
|
from .helper import WidgetData
|
||||||
from .ui.files_ui import Ui_win_files
|
from .ui.files_ui import Ui_win_files
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class NodeType(IntEnum):
|
class NodeType(IntEnum):
|
||||||
FILE = 1000
|
FILE = 1000
|
||||||
@@ -58,7 +60,7 @@ class UploadFiles(BackgroundWorker):
|
|||||||
default_value=False
|
default_value=False
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.error(e)
|
log.error(e)
|
||||||
self.ec = -2
|
self.ec = -2
|
||||||
return
|
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]))))
|
self.splitter.setSizes(list(map(int, helper.settings.value("files/splitter", [0, 0]))))
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
pi.logger.debug("RevPiFiles.__del__")
|
log.debug("RevPiFiles.__del__")
|
||||||
|
|
||||||
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
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/geo", self.saveGeometry())
|
||||||
helper.settings.setValue("files/splitter", self.splitter.sizes())
|
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_local = len(self.tree_files_local.selectedItems()) > 0
|
||||||
state_revpi = len(self.tree_files_revpi.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_all.setEnabled(state_local)
|
||||||
self.btn_to_right.setEnabled(state_local)
|
self.btn_to_right.setEnabled(state_local)
|
||||||
|
|
||||||
if "plcdeletefile" not in helper.cm.xml_funcs:
|
if "plcdeletefile" not in helper.cm.xml_funcs:
|
||||||
self.btn_delete_revpi.setEnabled(False)
|
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:
|
else:
|
||||||
self.btn_delete_revpi.setEnabled(state_revpi)
|
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:
|
if "plcdownload_file" not in helper.cm.xml_funcs:
|
||||||
self.btn_to_left.setEnabled(False)
|
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:
|
elif not helper.cm.settings.watch_path:
|
||||||
self.btn_to_left.setEnabled(False)
|
self.btn_to_left.setEnabled(False)
|
||||||
self.btn_to_left.setToolTip(self.tr("Choose a local directory first."))
|
self.btn_to_left.setToolTip(self.tr("Choose a local directory first."))
|
||||||
else:
|
else:
|
||||||
self.btn_to_left.setEnabled(state_revpi)
|
self.btn_to_left.setEnabled(state_revpi)
|
||||||
|
self.btn_to_left.setToolTip("")
|
||||||
|
|
||||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
# region # REGION: Tree management
|
# 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):
|
def _select_children(self, top_item: QtWidgets.QTreeWidgetItem, value: bool):
|
||||||
"""Recursive select children from parent."""
|
"""Recursive select children from parent."""
|
||||||
pi.logger.debug("RevPiFiles._select_children")
|
log.debug("RevPiFiles._select_children")
|
||||||
|
|
||||||
for i in range(top_item.childCount()):
|
for i in range(top_item.childCount()):
|
||||||
item = top_item.child(i)
|
item = top_item.child(i)
|
||||||
@@ -213,7 +237,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
if item is None:
|
if item is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
pi.logger.debug("RevPiFiles.__itemSelectionChanged")
|
log.debug("RevPiFiles.__itemSelectionChanged")
|
||||||
|
|
||||||
# Block while preselect other entries
|
# Block while preselect other entries
|
||||||
tree_view.blockSignals(True)
|
tree_view.blockSignals(True)
|
||||||
@@ -296,7 +320,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
|
|
||||||
:param silent: Do not show message boxes
|
: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_counter = 0
|
||||||
self.tree_files_local.blockSignals(True)
|
self.tree_files_local.blockSignals(True)
|
||||||
@@ -316,7 +340,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
|
|
||||||
def file_list_local(self):
|
def file_list_local(self):
|
||||||
"""Generate a file list with full path of selected entries."""
|
"""Generate a file list with full path of selected entries."""
|
||||||
pi.logger.debug("RevPiFiles.file_list_local")
|
log.debug("RevPiFiles.file_list_local")
|
||||||
lst = []
|
lst = []
|
||||||
for item in self.tree_files_local.selectedItems():
|
for item in self.tree_files_local.selectedItems():
|
||||||
if item.type() == NodeType.DIR:
|
if item.type() == NodeType.DIR:
|
||||||
@@ -337,7 +361,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
|
|
||||||
:param silent: Do not show message boxes
|
: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.blockSignals(True)
|
||||||
self.tree_files_revpi.clear()
|
self.tree_files_revpi.clear()
|
||||||
@@ -347,13 +371,13 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
lst_revpi = None
|
lst_revpi = None
|
||||||
else:
|
else:
|
||||||
lst_revpi = helper.cm.call_remote_function("get_filelist")
|
lst_revpi = helper.cm.call_remote_function("get_filelist")
|
||||||
# Just load settings once
|
self.dc_settings = helper.cm.call_remote_function("get_config", default_value={})
|
||||||
if not self.dc_settings:
|
self.lbl_path_revpi.setText(
|
||||||
self.dc_settings = helper.cm.call_remote_function("get_config", default_value={})
|
self.dc_settings.get("plcworkdir", self.tr("Could not load path of working dir"))
|
||||||
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.lbl_path_revpi.setToolTip(self.lbl_path_revpi.text())
|
plc_program = self.dc_settings.get("plcprogram", "")
|
||||||
|
|
||||||
if lst_revpi is not None:
|
if lst_revpi is not None:
|
||||||
lst_revpi.sort()
|
lst_revpi.sort()
|
||||||
@@ -399,7 +423,9 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
item = QtWidgets.QTreeWidgetItem(NodeType.FILE)
|
item = QtWidgets.QTreeWidgetItem(NodeType.FILE)
|
||||||
item.setText(0, object_name)
|
item.setText(0, object_name)
|
||||||
item.setData(0, WidgetData.file_name, path_file)
|
item.setData(0, WidgetData.file_name, path_file)
|
||||||
|
item.setData(0, WidgetData.is_plc_program, path_file == plc_program)
|
||||||
item.setIcon(0, QtGui.QIcon(
|
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-else.ico" if object_name.find(".py") == -1 else
|
||||||
":/file/ico/file-python.ico"
|
":/file/ico/file-python.ico"
|
||||||
))
|
))
|
||||||
@@ -421,7 +447,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
|
|
||||||
def file_list_revpi(self):
|
def file_list_revpi(self):
|
||||||
"""Generate a file list with full path of selected entries."""
|
"""Generate a file list with full path of selected entries."""
|
||||||
pi.logger.debug("RevPiFiles.file_list_revpi")
|
log.debug("RevPiFiles.file_list_revpi")
|
||||||
lst = []
|
lst = []
|
||||||
for item in self.tree_files_revpi.selectedItems():
|
for item in self.tree_files_revpi.selectedItems():
|
||||||
if item.type() == NodeType.DIR:
|
if item.type() == NodeType.DIR:
|
||||||
@@ -435,13 +461,13 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_all_clicked(self):
|
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._do_my_job(True)
|
||||||
self.file_list_revpi()
|
self.file_list_revpi()
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_select_local_clicked(self):
|
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(
|
diag_folder = QtWidgets.QFileDialog(
|
||||||
self, self.tr("Select folder..."),
|
self, self.tr("Select folder..."),
|
||||||
@@ -472,25 +498,25 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_refresh_local_clicked(self):
|
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)
|
self._load_files_local(False)
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_refresh_revpi_clicked(self):
|
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)
|
self._load_files_revpi(False)
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_to_right_clicked(self):
|
def on_btn_to_right_clicked(self):
|
||||||
"""Upload selected files to revolution pi."""
|
"""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._do_my_job(False)
|
||||||
self._load_files_revpi(True)
|
self._load_files_revpi(True)
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_to_left_clicked(self):
|
def on_btn_to_left_clicked(self):
|
||||||
"""Download selected file."""
|
"""Download selected file."""
|
||||||
pi.logger.debug("RevPiFiles.on_btn_to_left_clicked")
|
log.debug("RevPiFiles.on_btn_to_left_clicked")
|
||||||
|
|
||||||
override = None
|
override = None
|
||||||
for item in self.tree_files_revpi.selectedItems():
|
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
|
override = rc_diag == QtWidgets.QMessageBox.Yes
|
||||||
|
|
||||||
if os.path.exists(file_name) and not override:
|
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
|
continue
|
||||||
|
|
||||||
os.makedirs(os.path.dirname(file_name), exist_ok=True)
|
os.makedirs(os.path.dirname(file_name), exist_ok=True)
|
||||||
@@ -537,7 +563,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def on_btn_delete_revpi_clicked(self):
|
def on_btn_delete_revpi_clicked(self):
|
||||||
"""Remove selected files from working directory on revolution pi."""
|
"""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 = []
|
lst_delete = []
|
||||||
for item in self.tree_files_revpi.selectedItems():
|
for item in self.tree_files_revpi.selectedItems():
|
||||||
@@ -562,3 +588,23 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self._load_files_revpi()
|
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"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from . import helper
|
from . import helper
|
||||||
from . import proginit as pi
|
|
||||||
from .ui.revpilogfile_ui import Ui_win_revpilogfile
|
from .ui.revpilogfile_ui import Ui_win_revpilogfile
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LogType(IntEnum):
|
class LogType(IntEnum):
|
||||||
NONE = 0
|
NONE = 0
|
||||||
@@ -60,7 +62,7 @@ class DataThread(QtCore.QThread):
|
|||||||
# The log file was rotated by log rotate on the Revolution Pi
|
# The log file was rotated by log rotate on the Revolution Pi
|
||||||
start_position = 0
|
start_position = 0
|
||||||
eof = False
|
eof = False
|
||||||
pi.logger.info("RevPi started a new log file.")
|
log.info("RevPi started a new log file.")
|
||||||
|
|
||||||
elif buff_log:
|
elif buff_log:
|
||||||
start_position += len(buff_log)
|
start_position += len(buff_log)
|
||||||
@@ -71,16 +73,16 @@ class DataThread(QtCore.QThread):
|
|||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
"""Stop checking new log lines, but leave thread alive."""
|
"""Stop checking new log lines, but leave thread alive."""
|
||||||
pi.logger.debug("DataThread.pause")
|
log.debug("DataThread.pause")
|
||||||
self._paused = True
|
self._paused = True
|
||||||
|
|
||||||
def resume(self):
|
def resume(self):
|
||||||
"""Start checking for new log lines."""
|
"""Start checking for new log lines."""
|
||||||
pi.logger.debug("DataThread.resume")
|
log.debug("DataThread.resume")
|
||||||
self._paused = False
|
self._paused = False
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
pi.logger.debug("DataThread.run")
|
log.debug("DataThread.run")
|
||||||
|
|
||||||
while not self.isInterruptionRequested():
|
while not self.isInterruptionRequested():
|
||||||
eof_app = False
|
eof_app = False
|
||||||
@@ -191,7 +193,7 @@ class RevPiLogfile(QtWidgets.QMainWindow, Ui_win_revpilogfile):
|
|||||||
|
|
||||||
@QtCore.pyqtSlot(LogType, bool, str)
|
@QtCore.pyqtSlot(LogType, bool, str)
|
||||||
def on_line_logged(self, log_type: LogType, success: bool, text: 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:
|
if log_type == LogType.APP:
|
||||||
textwidget = self.txt_app
|
textwidget = self.txt_app
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ __author__ = "Sven Sager"
|
|||||||
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
__copyright__ = "Copyright (C) 2023 Sven Sager"
|
||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from . import helper
|
from . import helper
|
||||||
from . import proginit as pi
|
|
||||||
from .aclmanager import AclManager
|
from .aclmanager import AclManager
|
||||||
from .mqttmanager import MqttManager
|
from .mqttmanager import MqttManager
|
||||||
from .ui.revpioption_ui import Ui_diag_options
|
from .ui.revpioption_ui import Ui_diag_options
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
|
class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
|
||||||
"""Set options of RevPiPyLoad."""
|
"""Set options of RevPiPyLoad."""
|
||||||
@@ -110,7 +113,7 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
|
|||||||
|
|
||||||
def _load_settings(self):
|
def _load_settings(self):
|
||||||
"""Load values to GUI widgets."""
|
"""Load values to GUI widgets."""
|
||||||
pi.logger.debug("RevPiOption._load_settings")
|
log.debug("RevPiOption._load_settings")
|
||||||
|
|
||||||
self.mrk_xml_ask = True
|
self.mrk_xml_ask = True
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ __copyright__ = "Copyright (C) 2023 Sven Sager"
|
|||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
|
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
import keyring
|
import keyring
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
@@ -15,6 +16,8 @@ from . import proginit as pi
|
|||||||
from .helper import RevPiSettings, WidgetData
|
from .helper import RevPiSettings, WidgetData
|
||||||
from .ui.revpiplclist_ui import Ui_diag_connections
|
from .ui.revpiplclist_ui import Ui_diag_connections
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class NodeType(IntEnum):
|
class NodeType(IntEnum):
|
||||||
CON = 1000
|
CON = 1000
|
||||||
@@ -58,7 +61,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
|||||||
|
|
||||||
def _load_settings(self):
|
def _load_settings(self):
|
||||||
"""Load values to GUI widgets."""
|
"""Load values to GUI widgets."""
|
||||||
pi.logger.debug("RevPiPlcList._load_settings")
|
log.debug("RevPiPlcList._load_settings")
|
||||||
|
|
||||||
self.tre_connections.clear()
|
self.tre_connections.clear()
|
||||||
|
|
||||||
@@ -95,7 +98,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
|||||||
self._edit_state()
|
self._edit_state()
|
||||||
|
|
||||||
def accept(self) -> None:
|
def accept(self) -> None:
|
||||||
pi.logger.debug("RevPiPlcList.accept")
|
log.debug("RevPiPlcList.accept")
|
||||||
|
|
||||||
for internal_id, ssh_user in self._keyring_cleanup_id_user:
|
for internal_id, ssh_user in self._keyring_cleanup_id_user:
|
||||||
service_name = "{0}.{1}_{2}".format(
|
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
|
# Remove information from os keyring, which we collected on_btn_delete_clicked
|
||||||
keyring.delete_password(service_name, ssh_user)
|
keyring.delete_password(service_name, ssh_user)
|
||||||
except KeyringError as e:
|
except KeyringError as e:
|
||||||
pi.logger.error(e)
|
log.error(e)
|
||||||
|
|
||||||
helper.settings.remove("connections")
|
helper.settings.remove("connections")
|
||||||
|
|
||||||
@@ -127,7 +130,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
|||||||
super().accept()
|
super().accept()
|
||||||
|
|
||||||
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
||||||
pi.logger.debug("RevPiPlcList.closeEvent")
|
log.debug("RevPiPlcList.closeEvent")
|
||||||
if self.changes:
|
if self.changes:
|
||||||
ask = QtWidgets.QMessageBox.question(
|
ask = QtWidgets.QMessageBox.question(
|
||||||
self, self.tr("Question"), self.tr(
|
self, self.tr("Question"), self.tr(
|
||||||
@@ -165,7 +168,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
|||||||
|
|
||||||
def _edit_state(self):
|
def _edit_state(self):
|
||||||
"""Set enabled status of all controls, depending on selected item."""
|
"""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()
|
item = self.tre_connections.currentItem()
|
||||||
if item is None:
|
if item is None:
|
||||||
@@ -409,7 +412,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
|||||||
|
|
||||||
@QtCore.pyqtSlot(str)
|
@QtCore.pyqtSlot(str)
|
||||||
def on_cbb_folder_currentIndexChanged(self, text: 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:
|
if self.__current_item.type() == NodeType.CON:
|
||||||
new_dir_node = self._get_folder_item(text)
|
new_dir_node = self._get_folder_item(text)
|
||||||
@@ -443,7 +446,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
|
|||||||
|
|
||||||
@QtCore.pyqtSlot(str)
|
@QtCore.pyqtSlot(str)
|
||||||
def on_cbb_folder_editTextChanged(self, text: 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:
|
if self.__current_item.type() == NodeType.DIR and self.__current_item.text(0) != text:
|
||||||
# We just have to rename the dir node
|
# We just have to rename the dir node
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import gzip
|
|||||||
import os
|
import os
|
||||||
import tarfile
|
import tarfile
|
||||||
import zipfile
|
import zipfile
|
||||||
|
from logging import getLogger
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from xmlrpc.client import Binary
|
from xmlrpc.client import Binary
|
||||||
@@ -15,9 +16,10 @@ from xmlrpc.client import Binary
|
|||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from . import helper
|
from . import helper
|
||||||
from . import proginit as pi
|
|
||||||
from .ui.revpiprogram_ui import Ui_diag_program
|
from .ui.revpiprogram_ui import Ui_diag_program
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
||||||
"""Program options of RevPiPyLoad."""
|
"""Program options of RevPiPyLoad."""
|
||||||
@@ -39,8 +41,6 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
|||||||
# Setting properties require level 4
|
# Setting properties require level 4
|
||||||
self.cbb_plcprogram.setEnabled(helper.cm.xml_mode >= 4)
|
self.cbb_plcprogram.setEnabled(helper.cm.xml_mode >= 4)
|
||||||
self.txt_plcarguments.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)
|
self.cbx_plcworkdir_set_uid.setEnabled(helper.cm.xml_mode >= 4)
|
||||||
|
|
||||||
# Downloads require level 2
|
# 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 \
|
return self.cbb_plcprogram.currentText() != self.dc.get("plcprogram", "") or \
|
||||||
self.txt_plcarguments.text() != self.dc.get("plcarguments", "") 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 \
|
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)
|
self.sbx_plcprogram_watchdog.value() != self.dc.get("plcprogram_watchdog", 0)
|
||||||
|
|
||||||
def _load_settings(self, files_only=False):
|
def _load_settings(self, files_only=False):
|
||||||
"""Load values to GUI widgets."""
|
"""Load values to GUI widgets."""
|
||||||
pi.logger.debug("RevPiProgram._load_settings")
|
log.debug("RevPiProgram._load_settings")
|
||||||
|
|
||||||
if files_only:
|
if files_only:
|
||||||
mrk_program = self.cbb_plcprogram.currentText()
|
mrk_program = self.cbb_plcprogram.currentText()
|
||||||
@@ -88,15 +86,13 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
|||||||
is_in_list = True
|
is_in_list = True
|
||||||
|
|
||||||
if not is_in_list:
|
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:
|
if files_only:
|
||||||
self.cbb_plcprogram.setCurrentText(mrk_program)
|
self.cbb_plcprogram.setCurrentText(mrk_program)
|
||||||
else:
|
else:
|
||||||
self.cbb_plcprogram.setCurrentText(self.dc.get("plcprogram", ""))
|
self.cbb_plcprogram.setCurrentText(self.dc.get("plcprogram", ""))
|
||||||
self.txt_plcarguments.setText(self.dc.get("plcarguments", ""))
|
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.cbx_plcworkdir_set_uid.setChecked(bool(self.dc.get("plcworkdir_set_uid", 0)))
|
||||||
self.sbx_plcprogram_watchdog.setValue(self.dc.get("plcprogram_watchdog", 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["plcprogram"] = self.cbb_plcprogram.currentText()
|
||||||
self.dc["plcarguments"] = self.txt_plcarguments.text()
|
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["plcworkdir_set_uid"] = int(self.cbx_plcworkdir_set_uid.isChecked())
|
||||||
self.dc["plcprogram_watchdog"] = self.sbx_plcprogram_watchdog.value()
|
self.dc["plcprogram_watchdog"] = self.sbx_plcprogram_watchdog.value()
|
||||||
|
|
||||||
@@ -382,7 +377,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
|
|||||||
fh.close()
|
fh.close()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pi.logger.error(e)
|
log.error(e)
|
||||||
QtWidgets.QMessageBox.critical(
|
QtWidgets.QMessageBox.critical(
|
||||||
self, self.tr("Error"), self.tr(
|
self, self.tr("Error"), self.tr(
|
||||||
"Coud not save the archive or extract the files!\n"
|
"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")
|
log.error("Could not create a ssh channel")
|
||||||
return
|
return
|
||||||
|
|
||||||
log.info("Starting tunnel exchange loop")
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
r, w, x = select.select([self.request, chan], [], [], 5.0)
|
r, w, x = select.select([self.request, chan], [], [], 5.0)
|
||||||
if self.request in r:
|
if self.request in r:
|
||||||
@@ -58,8 +56,6 @@ class Handler(BaseRequestHandler):
|
|||||||
break
|
break
|
||||||
self.request.send(data)
|
self.request.send(data)
|
||||||
|
|
||||||
log.info("Stopped tunnel exchange loop")
|
|
||||||
|
|
||||||
chan.close()
|
chan.close()
|
||||||
self.request.close()
|
self.request.close()
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from keyring.errors import KeyringError
|
|||||||
|
|
||||||
from .ui.sshauth_ui import Ui_diag_sshauth
|
from .ui.sshauth_ui import Ui_diag_sshauth
|
||||||
|
|
||||||
log = getLogger()
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SSHAuth(QtWidgets.QDialog, Ui_diag_sshauth):
|
class SSHAuth(QtWidgets.QDialog, Ui_diag_sshauth):
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'aclmanager.ui'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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.vl_local.addLayout(self.hl_revpi_2)
|
||||||
self.tree_files_local = QtWidgets.QTreeWidget(self.verticalLayoutWidget)
|
self.tree_files_local = QtWidgets.QTreeWidget(self.verticalLayoutWidget)
|
||||||
self.tree_files_local.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
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.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
self.tree_files_local.setIconSize(QtCore.QSize(24, 24))
|
self.tree_files_local.setIconSize(QtCore.QSize(24, 24))
|
||||||
self.tree_files_local.setObjectName("tree_files_local")
|
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)
|
self.hl_revpi.addWidget(self.btn_delete_revpi)
|
||||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||||
self.hl_revpi.addItem(spacerItem1)
|
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.vl_revpi.addLayout(self.hl_revpi)
|
||||||
self.tree_files_revpi = QtWidgets.QTreeWidget(self.gridLayoutWidget_2)
|
self.tree_files_revpi = QtWidgets.QTreeWidget(self.gridLayoutWidget_2)
|
||||||
self.tree_files_revpi.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
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.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
self.tree_files_revpi.setIconSize(QtCore.QSize(24, 24))
|
self.tree_files_revpi.setIconSize(QtCore.QSize(24, 24))
|
||||||
self.tree_files_revpi.setObjectName("tree_files_revpi")
|
self.tree_files_revpi.setObjectName("tree_files_revpi")
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'mqttmanager.ui'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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):
|
class Ui_diag_program(object):
|
||||||
def setupUi(self, diag_program):
|
def setupUi(self, diag_program):
|
||||||
diag_program.setObjectName("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 = QtWidgets.QVBoxLayout(diag_program)
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
self.gb_plc = QtWidgets.QGroupBox(diag_program)
|
self.gb_plc = QtWidgets.QGroupBox(diag_program)
|
||||||
self.gb_plc.setObjectName("gb_plc")
|
self.gb_plc.setObjectName("gb_plc")
|
||||||
self.gridLayout = QtWidgets.QGridLayout(self.gb_plc)
|
self.gridLayout = QtWidgets.QGridLayout(self.gb_plc)
|
||||||
self.gridLayout.setObjectName("gridLayout")
|
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 = QtWidgets.QLabel(self.gb_plc)
|
||||||
self.lbl_plcarguments.setObjectName("lbl_plcarguments")
|
self.lbl_plcarguments.setObjectName("lbl_plcarguments")
|
||||||
self.gridLayout.addWidget(self.lbl_plcarguments, 2, 0, 1, 1)
|
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 = QtWidgets.QLineEdit(self.gb_plc)
|
||||||
self.txt_plcarguments.setObjectName("txt_plcarguments")
|
self.txt_plcarguments.setObjectName("txt_plcarguments")
|
||||||
self.gridLayout.addWidget(self.txt_plcarguments, 2, 1, 1, 2)
|
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 = QtWidgets.QSpinBox(self.gb_plc)
|
||||||
self.sbx_plcprogram_watchdog.setMaximum(600)
|
self.sbx_plcprogram_watchdog.setMaximum(600)
|
||||||
self.sbx_plcprogram_watchdog.setObjectName("sbx_plcprogram_watchdog")
|
self.sbx_plcprogram_watchdog.setObjectName("sbx_plcprogram_watchdog")
|
||||||
self.gridLayout.addWidget(self.sbx_plcprogram_watchdog, 5, 2, 1, 1)
|
self.gridLayout.addWidget(self.sbx_plcprogram_watchdog, 4, 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.verticalLayout.addWidget(self.gb_plc)
|
self.verticalLayout.addWidget(self.gb_plc)
|
||||||
self.cb_transfair = QtWidgets.QGroupBox(diag_program)
|
self.cb_transfair = QtWidgets.QGroupBox(diag_program)
|
||||||
self.cb_transfair.setObjectName("cb_transfair")
|
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
|
self.btn_box.rejected.connect(diag_program.reject) # type: ignore
|
||||||
QtCore.QMetaObject.connectSlotsByName(diag_program)
|
QtCore.QMetaObject.connectSlotsByName(diag_program)
|
||||||
diag_program.setTabOrder(self.cbb_plcprogram, self.txt_plcarguments)
|
diag_program.setTabOrder(self.cbb_plcprogram, self.txt_plcarguments)
|
||||||
diag_program.setTabOrder(self.txt_plcarguments, self.rbn_pythonversion_2)
|
diag_program.setTabOrder(self.txt_plcarguments, self.cbx_plcworkdir_set_uid)
|
||||||
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.cbx_plcworkdir_set_uid, self.cbb_format)
|
diag_program.setTabOrder(self.cbx_plcworkdir_set_uid, self.cbb_format)
|
||||||
diag_program.setTabOrder(self.cbb_format, self.cbx_pictory)
|
diag_program.setTabOrder(self.cbb_format, self.cbx_pictory)
|
||||||
diag_program.setTabOrder(self.cbx_pictory, self.cbx_clear)
|
diag_program.setTabOrder(self.cbx_pictory, self.cbx_clear)
|
||||||
@@ -125,14 +114,11 @@ class Ui_diag_program(object):
|
|||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
diag_program.setWindowTitle(_translate("diag_program", "PLC program"))
|
diag_program.setWindowTitle(_translate("diag_program", "PLC program"))
|
||||||
self.gb_plc.setTitle(_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.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_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.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.cb_transfair.setTitle(_translate("diag_program", "Transfair PLC program"))
|
||||||
self.cbb_format.setItemText(0, _translate("diag_program", "ZIP archive"))
|
self.cbb_format.setItemText(0, _translate("diag_program", "ZIP archive"))
|
||||||
self.cbb_format.setItemText(1, _translate("diag_program", "TGZ archive"))
|
self.cbb_format.setItemText(1, _translate("diag_program", "TGZ archive"))
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'simulator.ui'
|
# 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
|
# 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.
|
# 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'
|
# 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
|
# 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.
|
# 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/debugios.ui \
|
||||||
ui_dev/files.ui \
|
ui_dev/files.ui \
|
||||||
ui_dev/mqttmanager.ui \
|
ui_dev/mqttmanager.ui \
|
||||||
|
ui_dev/oss_licenses.ui \
|
||||||
ui_dev/revpiinfo.ui \
|
ui_dev/revpiinfo.ui \
|
||||||
ui_dev/revpilogfile.ui \
|
ui_dev/revpilogfile.ui \
|
||||||
ui_dev/revpioption.ui \
|
ui_dev/revpioption.ui \
|
||||||
|
|||||||
@@ -137,7 +137,7 @@
|
|||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="selectionMode">
|
<property name="selectionMode">
|
||||||
<enum>QAbstractItemView::MultiSelection</enum>
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="selectionBehavior">
|
<property name="selectionBehavior">
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
@@ -269,6 +269,26 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -277,7 +297,7 @@
|
|||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="selectionMode">
|
<property name="selectionMode">
|
||||||
<enum>QAbstractItemView::MultiSelection</enum>
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="selectionBehavior">
|
<property name="selectionBehavior">
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
<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>
|
<file>ico/revpipycontrol.ico</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="file">
|
<qresource prefix="file">
|
||||||
|
<file>ico/autostart.ico</file>
|
||||||
<file>ico/file-else.ico</file>
|
<file>ico/file-else.ico</file>
|
||||||
<file>ico/file-python.ico</file>
|
<file>ico/file-python.ico</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>434</width>
|
||||||
<height>501</height>
|
<height>509</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -20,17 +20,21 @@
|
|||||||
<string>PLC program</string>
|
<string>PLC program</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="1" column="0" colspan="3">
|
<item row="2" column="0">
|
||||||
<widget class="QComboBox" name="cbb_plcprogram"/>
|
<widget class="QLabel" name="lbl_plcarguments">
|
||||||
</item>
|
|
||||||
<item row="3" column="2">
|
|
||||||
<widget class="QRadioButton" name="rbn_pythonversion_3">
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Python 3</string>
|
<string>Program arguments:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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">
|
<widget class="QCheckBox" name="cbx_plcworkdir_set_uid">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Set write permissions for plc program to workdirectory</string>
|
<string>Set write permissions for plc program to workdirectory</string>
|
||||||
@@ -44,31 +48,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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">
|
<item row="2" column="1" colspan="2">
|
||||||
<widget class="QLineEdit" name="txt_plcarguments"/>
|
<widget class="QLineEdit" name="txt_plcarguments"/>
|
||||||
</item>
|
</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">
|
<widget class="QSpinBox" name="sbx_plcprogram_watchdog">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string> sec.</string>
|
<string> sec.</string>
|
||||||
@@ -78,13 +64,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -205,8 +184,6 @@
|
|||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>cbb_plcprogram</tabstop>
|
<tabstop>cbb_plcprogram</tabstop>
|
||||||
<tabstop>txt_plcarguments</tabstop>
|
<tabstop>txt_plcarguments</tabstop>
|
||||||
<tabstop>rbn_pythonversion_2</tabstop>
|
|
||||||
<tabstop>rbn_pythonversion_3</tabstop>
|
|
||||||
<tabstop>cbx_plcworkdir_set_uid</tabstop>
|
<tabstop>cbx_plcworkdir_set_uid</tabstop>
|
||||||
<tabstop>cbb_format</tabstop>
|
<tabstop>cbb_format</tabstop>
|
||||||
<tabstop>cbx_pictory</tabstop>
|
<tabstop>cbx_pictory</tabstop>
|
||||||
|
|||||||
Reference in New Issue
Block a user