Merge branch 'filemanager' into develop

# Conflicts:
#	include/ui/revpidevelop_ui.py
#	include/ui_dev/revpidevelop.ui
This commit is contained in:
2020-09-24 19:39:50 +02:00
20 changed files with 3612 additions and 2603 deletions

182
include/ui/files_ui.py Normal file
View File

@@ -0,0 +1,182 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'files.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_win_files(object):
def setupUi(self, win_files):
win_files.setObjectName("win_files")
win_files.resize(725, 519)
self.centralwidget = QtWidgets.QWidget(win_files)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.splitter = QtWidgets.QSplitter(self.centralwidget)
self.splitter.setOrientation(QtCore.Qt.Horizontal)
self.splitter.setChildrenCollapsible(False)
self.splitter.setObjectName("splitter")
self.verticalLayoutWidget = QtWidgets.QWidget(self.splitter)
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.vl_local = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.vl_local.setContentsMargins(0, 0, 0, 0)
self.vl_local.setObjectName("vl_local")
self.gb_select_local = QtWidgets.QGroupBox(self.verticalLayoutWidget)
self.gb_select_local.setObjectName("gb_select_local")
self.gridLayout_2 = QtWidgets.QGridLayout(self.gb_select_local)
self.gridLayout_2.setObjectName("gridLayout_2")
self.lbl_select_local = QtWidgets.QLabel(self.gb_select_local)
self.lbl_select_local.setObjectName("lbl_select_local")
self.gridLayout_2.addWidget(self.lbl_select_local, 0, 0, 1, 1)
self.btn_select_local = QtWidgets.QPushButton(self.gb_select_local)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/action/ico/folder-open.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btn_select_local.setIcon(icon)
self.btn_select_local.setIconSize(QtCore.QSize(24, 24))
self.btn_select_local.setAutoDefault(False)
self.btn_select_local.setObjectName("btn_select_local")
self.gridLayout_2.addWidget(self.btn_select_local, 0, 1, 1, 1)
self.btn_refresh_local = QtWidgets.QPushButton(self.gb_select_local)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(":/action/ico/refresh.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btn_refresh_local.setIcon(icon1)
self.btn_refresh_local.setIconSize(QtCore.QSize(24, 24))
self.btn_refresh_local.setObjectName("btn_refresh_local")
self.gridLayout_2.addWidget(self.btn_refresh_local, 0, 2, 1, 1)
self.lbl_path_local = QtWidgets.QLabel(self.gb_select_local)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lbl_path_local.sizePolicy().hasHeightForWidth())
self.lbl_path_local.setSizePolicy(sizePolicy)
self.lbl_path_local.setObjectName("lbl_path_local")
self.gridLayout_2.addWidget(self.lbl_path_local, 1, 0, 1, 3)
self.gridLayout_2.setColumnStretch(0, 1)
self.vl_local.addWidget(self.gb_select_local)
self.hl_revpi_2 = QtWidgets.QHBoxLayout()
self.hl_revpi_2.setObjectName("hl_revpi_2")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.hl_revpi_2.addItem(spacerItem)
self.btn_to_right = QtWidgets.QPushButton(self.verticalLayoutWidget)
self.btn_to_right.setText("")
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(":/action/ico/arrow-right.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btn_to_right.setIcon(icon2)
self.btn_to_right.setIconSize(QtCore.QSize(24, 24))
self.btn_to_right.setAutoDefault(False)
self.btn_to_right.setObjectName("btn_to_right")
self.hl_revpi_2.addWidget(self.btn_to_right)
self.vl_local.addLayout(self.hl_revpi_2)
self.tree_files_local = QtWidgets.QTreeWidget(self.verticalLayoutWidget)
self.tree_files_local.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.tree_files_local.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
self.tree_files_local.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.tree_files_local.setIconSize(QtCore.QSize(24, 24))
self.tree_files_local.setObjectName("tree_files_local")
self.tree_files_local.headerItem().setText(0, "1")
self.tree_files_local.header().setVisible(False)
self.vl_local.addWidget(self.tree_files_local)
self.gridLayoutWidget_2 = QtWidgets.QWidget(self.splitter)
self.gridLayoutWidget_2.setObjectName("gridLayoutWidget_2")
self.vl_revpi = QtWidgets.QVBoxLayout(self.gridLayoutWidget_2)
self.vl_revpi.setContentsMargins(0, 0, 0, 0)
self.vl_revpi.setObjectName("vl_revpi")
self.gb_select_revpi = QtWidgets.QGroupBox(self.gridLayoutWidget_2)
self.gb_select_revpi.setObjectName("gb_select_revpi")
self.gridLayout_3 = QtWidgets.QGridLayout(self.gb_select_revpi)
self.gridLayout_3.setObjectName("gridLayout_3")
self.lbl_path_revpi = QtWidgets.QLabel(self.gb_select_revpi)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lbl_path_revpi.sizePolicy().hasHeightForWidth())
self.lbl_path_revpi.setSizePolicy(sizePolicy)
self.lbl_path_revpi.setObjectName("lbl_path_revpi")
self.gridLayout_3.addWidget(self.lbl_path_revpi, 1, 0, 1, 2)
self.lbl_select_revpi = QtWidgets.QLabel(self.gb_select_revpi)
self.lbl_select_revpi.setObjectName("lbl_select_revpi")
self.gridLayout_3.addWidget(self.lbl_select_revpi, 0, 0, 1, 1)
self.btn_refresh_revpi = QtWidgets.QPushButton(self.gb_select_revpi)
self.btn_refresh_revpi.setIcon(icon1)
self.btn_refresh_revpi.setIconSize(QtCore.QSize(24, 24))
self.btn_refresh_revpi.setObjectName("btn_refresh_revpi")
self.gridLayout_3.addWidget(self.btn_refresh_revpi, 0, 1, 1, 1)
self.gridLayout_3.setColumnStretch(0, 1)
self.vl_revpi.addWidget(self.gb_select_revpi)
self.hl_revpi = QtWidgets.QHBoxLayout()
self.hl_revpi.setObjectName("hl_revpi")
self.btn_to_left = QtWidgets.QPushButton(self.gridLayoutWidget_2)
self.btn_to_left.setText("")
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(":/action/ico/arrow-left.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btn_to_left.setIcon(icon3)
self.btn_to_left.setIconSize(QtCore.QSize(24, 24))
self.btn_to_left.setAutoDefault(False)
self.btn_to_left.setObjectName("btn_to_left")
self.hl_revpi.addWidget(self.btn_to_left)
self.btn_delete_revpi = QtWidgets.QPushButton(self.gridLayoutWidget_2)
self.btn_delete_revpi.setText("")
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(":/action/ico/edit-delete.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btn_delete_revpi.setIcon(icon4)
self.btn_delete_revpi.setIconSize(QtCore.QSize(24, 24))
self.btn_delete_revpi.setAutoDefault(False)
self.btn_delete_revpi.setObjectName("btn_delete_revpi")
self.hl_revpi.addWidget(self.btn_delete_revpi)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.hl_revpi.addItem(spacerItem1)
self.vl_revpi.addLayout(self.hl_revpi)
self.tree_files_revpi = QtWidgets.QTreeWidget(self.gridLayoutWidget_2)
self.tree_files_revpi.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.tree_files_revpi.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
self.tree_files_revpi.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.tree_files_revpi.setIconSize(QtCore.QSize(24, 24))
self.tree_files_revpi.setObjectName("tree_files_revpi")
self.tree_files_revpi.headerItem().setText(0, "1")
self.tree_files_revpi.header().setVisible(False)
self.vl_revpi.addWidget(self.tree_files_revpi)
self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1)
self.btn_all = QtWidgets.QPushButton(self.centralwidget)
self.btn_all.setObjectName("btn_all")
self.gridLayout.addWidget(self.btn_all, 1, 0, 1, 1)
win_files.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(win_files)
self.statusbar.setObjectName("statusbar")
win_files.setStatusBar(self.statusbar)
self.retranslateUi(win_files)
QtCore.QMetaObject.connectSlotsByName(win_files)
def retranslateUi(self, win_files):
_translate = QtCore.QCoreApplication.translate
win_files.setWindowTitle(_translate("win_files", "File manager"))
self.gb_select_local.setTitle(_translate("win_files", "Local computer"))
self.lbl_select_local.setText(_translate("win_files", "Path to development root:"))
self.btn_select_local.setToolTip(_translate("win_files", "Open developer root directory"))
self.btn_refresh_local.setToolTip(_translate("win_files", "Reload file list"))
self.lbl_path_local.setToolTip(_translate("win_files", "/"))
self.lbl_path_local.setText(_translate("win_files", "/"))
self.tree_files_local.setSortingEnabled(True)
self.gb_select_revpi.setTitle(_translate("win_files", "Revolution Pi"))
self.lbl_path_revpi.setToolTip(_translate("win_files", "/"))
self.lbl_path_revpi.setText(_translate("win_files", "/"))
self.lbl_select_revpi.setText(_translate("win_files", "RevPiPyLoad working directory:"))
self.btn_refresh_revpi.setToolTip(_translate("win_files", "Reload file list"))
self.tree_files_revpi.setSortingEnabled(True)
self.btn_all.setText(_translate("win_files", "Stop - Upload - Start"))
from . import ressources_rc
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win_files = QtWidgets.QMainWindow()
ui = Ui_win_files()
ui.setupUi(win_files)
win_files.show()
sys.exit(app.exec_())

File diff suppressed because it is too large Load Diff

View File

@@ -81,7 +81,6 @@ class Ui_win_revpicommander(object):
self.act_program = QtWidgets.QAction(win_revpicommander)
self.act_program.setObjectName("act_program")
self.act_developer = QtWidgets.QAction(win_revpicommander)
self.act_developer.setCheckable(True)
self.act_developer.setObjectName("act_developer")
self.act_pictory = QtWidgets.QAction(win_revpicommander)
self.act_pictory.setObjectName("act_pictory")

View File

@@ -1,88 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'revpidevelop.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_wid_develop(object):
def setupUi(self, wid_develop):
wid_develop.setObjectName("wid_develop")
wid_develop.resize(374, 444)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(wid_develop.sizePolicy().hasHeightForWidth())
wid_develop.setSizePolicy(sizePolicy)
self.gridLayout = QtWidgets.QGridLayout(wid_develop)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.btn_all = QtWidgets.QPushButton(wid_develop)
self.btn_all.setObjectName("btn_all")
self.gridLayout.addWidget(self.btn_all, 2, 0, 1, 1)
self.btn_upload = QtWidgets.QPushButton(wid_develop)
self.btn_upload.setObjectName("btn_upload")
self.gridLayout.addWidget(self.btn_upload, 2, 1, 1, 1)
self.tree_files = QtWidgets.QTreeWidget(wid_develop)
self.tree_files.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.tree_files.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
self.tree_files.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.tree_files.setIconSize(QtCore.QSize(24, 24))
self.tree_files.setObjectName("tree_files")
self.tree_files.headerItem().setText(0, "1")
self.tree_files.header().setVisible(False)
self.gridLayout.addWidget(self.tree_files, 1, 0, 1, 2)
self.gb_select = QtWidgets.QGroupBox(wid_develop)
self.gb_select.setObjectName("gb_select")
self.gridLayout_2 = QtWidgets.QGridLayout(self.gb_select)
self.gridLayout_2.setObjectName("gridLayout_2")
self.lbl_select = QtWidgets.QLabel(self.gb_select)
self.lbl_select.setObjectName("lbl_select")
self.gridLayout_2.addWidget(self.lbl_select, 0, 0, 1, 1)
self.btn_select = QtWidgets.QPushButton(self.gb_select)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/action/ico/folder-open.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btn_select.setIcon(icon)
self.btn_select.setIconSize(QtCore.QSize(24, 24))
self.btn_select.setObjectName("btn_select")
self.gridLayout_2.addWidget(self.btn_select, 0, 1, 1, 1)
self.btn_refresh = QtWidgets.QPushButton(self.gb_select)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(":/action/ico/refresh.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btn_refresh.setIcon(icon1)
self.btn_refresh.setIconSize(QtCore.QSize(24, 24))
self.btn_refresh.setObjectName("btn_refresh")
self.gridLayout_2.addWidget(self.btn_refresh, 0, 2, 1, 1)
self.lbl_path = QtWidgets.QLabel(self.gb_select)
self.lbl_path.setObjectName("lbl_path")
self.gridLayout_2.addWidget(self.lbl_path, 1, 0, 1, 3)
self.gridLayout_2.setColumnStretch(0, 1)
self.gridLayout.addWidget(self.gb_select, 0, 0, 1, 2)
self.retranslateUi(wid_develop)
QtCore.QMetaObject.connectSlotsByName(wid_develop)
def retranslateUi(self, wid_develop):
_translate = QtCore.QCoreApplication.translate
self.btn_all.setText(_translate("wid_develop", "Stop / Upload / Start"))
self.btn_upload.setText(_translate("wid_develop", "Just upload"))
self.gb_select.setTitle(_translate("wid_develop", "File watcher for PLC development"))
self.lbl_select.setText(_translate("wid_develop", "Path to development root:"))
self.btn_select.setToolTip(_translate("wid_develop", "Open developer root directory"))
self.btn_refresh.setToolTip(_translate("wid_develop", "Reload file list"))
self.lbl_path.setText(_translate("wid_develop", "/"))
from . import ressources_rc
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
wid_develop = QtWidgets.QWidget()
ui = Ui_wid_develop()
ui.setupUi(wid_develop)
wid_develop.show()
sys.exit(app.exec_())

View File

@@ -51,8 +51,6 @@ class Ui_diag_program(object):
self.cbb_format.setObjectName("cbb_format")
self.cbb_format.addItem("")
self.cbb_format.addItem("")
self.cbb_format.addItem("")
self.cbb_format.addItem("")
self.gridLayout_2.addWidget(self.cbb_format, 0, 1, 1, 1)
self.btn_program_upload = QtWidgets.QPushButton(self.cb_transfair)
self.btn_program_upload.setObjectName("btn_program_upload")
@@ -124,10 +122,8 @@ class Ui_diag_program(object):
self.lbl_pythonversion.setText(_translate("diag_program", "Python version:"))
self.lbl_plcarguments.setText(_translate("diag_program", "Program arguments:"))
self.cb_transfair.setTitle(_translate("diag_program", "Transfair PLC program"))
self.cbb_format.setItemText(0, _translate("diag_program", "Files"))
self.cbb_format.setItemText(1, _translate("diag_program", "Folder"))
self.cbb_format.setItemText(2, _translate("diag_program", "ZIP archive"))
self.cbb_format.setItemText(3, _translate("diag_program", "TGZ archive"))
self.cbb_format.setItemText(0, _translate("diag_program", "ZIP archive"))
self.cbb_format.setItemText(1, _translate("diag_program", "TGZ archive"))
self.btn_program_upload.setText(_translate("diag_program", "Upload"))
self.btn_program_download.setText(_translate("diag_program", "Download"))
self.lbl_format.setText(_translate("diag_program", "Transfair format:"))

323
include/ui_dev/files.ui Normal file
View File

@@ -0,0 +1,323 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>win_files</class>
<widget class="QMainWindow" name="win_files">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>725</width>
<height>519</height>
</rect>
</property>
<property name="windowTitle">
<string>File manager</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="childrenCollapsible">
<bool>false</bool>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="vl_local">
<item>
<widget class="QGroupBox" name="gb_select_local">
<property name="title">
<string>Local computer</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="1,0,0">
<item row="0" column="0">
<widget class="QLabel" name="lbl_select_local">
<property name="text">
<string>Path to development root:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="btn_select_local">
<property name="toolTip">
<string>Open developer root directory</string>
</property>
<property name="icon">
<iconset resource="ressources.qrc">
<normaloff>:/action/ico/folder-open.ico</normaloff>:/action/ico/folder-open.ico</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btn_refresh_local">
<property name="toolTip">
<string>Reload file list</string>
</property>
<property name="icon">
<iconset resource="ressources.qrc">
<normaloff>:/action/ico/refresh.ico</normaloff>:/action/ico/refresh.ico</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QLabel" name="lbl_path_local">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>/</string>
</property>
<property name="text">
<string>/</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="hl_revpi_2">
<item>
<spacer name="hs_local">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_to_right">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="ressources.qrc">
<normaloff>:/action/ico/arrow-right.ico</normaloff>:/action/ico/arrow-right.ico</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeWidget" name="tree_files_local">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="gridLayoutWidget_2">
<layout class="QVBoxLayout" name="vl_revpi">
<item>
<widget class="QGroupBox" name="gb_select_revpi">
<property name="title">
<string>Revolution Pi</string>
</property>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="1,0">
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="lbl_path_revpi">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>/</string>
</property>
<property name="text">
<string>/</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lbl_select_revpi">
<property name="text">
<string>RevPiPyLoad working directory:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="btn_refresh_revpi">
<property name="toolTip">
<string>Reload file list</string>
</property>
<property name="icon">
<iconset resource="ressources.qrc">
<normaloff>:/action/ico/refresh.ico</normaloff>:/action/ico/refresh.ico</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="hl_revpi">
<item>
<widget class="QPushButton" name="btn_to_left">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="ressources.qrc">
<normaloff>:/action/ico/arrow-left.ico</normaloff>:/action/ico/arrow-left.ico</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_delete_revpi">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="ressources.qrc">
<normaloff>:/action/ico/edit-delete.ico</normaloff>:/action/ico/edit-delete.ico</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="hs_revpi">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTreeWidget" name="tree_files_revpi">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="btn_all">
<property name="text">
<string>Stop - Upload - Start</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources>
<include location="ressources.qrc"/>
</resources>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -9,6 +9,8 @@
<file>ico/file-python.ico</file>
</qresource>
<qresource prefix="action">
<file>ico/arrow-left.ico</file>
<file>ico/arrow-right.ico</file>
<file>ico/folder-open.ico</file>
<file>ico/refresh.ico</file>
<file>ico/reload.ico</file>

View File

@@ -199,9 +199,6 @@
</property>
</action>
<action name="act_developer">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>PLC de&amp;veloper...</string>
</property>

View File

@@ -1,136 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>wid_develop</class>
<widget class="QWidget" name="wid_develop">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>374</width>
<height>444</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="2" column="0">
<widget class="QPushButton" name="btn_all">
<property name="text">
<string>Stop / Upload / Start</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="btn_upload">
<property name="text">
<string>Just upload</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTreeWidget" name="tree_files">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="gb_select">
<property name="title">
<string>File watcher for PLC development</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="1,0,0">
<item row="0" column="0">
<widget class="QLabel" name="lbl_select">
<property name="text">
<string>Path to development root:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="btn_select">
<property name="toolTip">
<string>Open developer root directory</string>
</property>
<property name="icon">
<iconset resource="ressources.qrc">
<normaloff>:/action/ico/folder-open.ico</normaloff>:/action/ico/folder-open.ico</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btn_refresh">
<property name="toolTip">
<string>Reload file list</string>
</property>
<property name="icon">
<iconset resource="ressources.qrc">
<normaloff>:/action/ico/refresh.ico</normaloff>:/action/ico/refresh.ico</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QLabel" name="lbl_path">
<property name="text">
<string>/</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="ressources.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -79,16 +79,6 @@
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QComboBox" name="cbb_format">
<item>
<property name="text">
<string>Files</string>
</property>
</item>
<item>
<property name="text">
<string>Folder</string>
</property>
</item>
<item>
<property name="text">
<string>ZIP archive</string>

View File

@@ -33,6 +33,7 @@ class AvahiSearchThread(QtCore.QThread):
)
def _update_arp(self):
"""Find mac address in arp table."""
if osname == "posix":
with open("/proc/net/arp") as fh:
for line in fh.readlines():
@@ -41,7 +42,13 @@ class AvahiSearchThread(QtCore.QThread):
self.__dict_arp[ip_mac.group("ip")] = ip_mac.group("mac")
def get_mac(self, ip: str):
return self.__dict_arp.get(ip, None)
"""
Get mac address of ip, if known.
:param ip: IP address to find mac address
:return: MAC address as string or empty string, if unknown
"""
return self.__dict_arp.get(ip, "")
def remove_service(self, zeroconf: Zeroconf, conf_type: str, name: str):
"""Revolution Pi disappeared."""
@@ -184,7 +191,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
item_name.setIcon(QtGui.QIcon(":/main/ico/cpu.ico"))
item_name.setText(server[:-1])
item_name.setData(WidgetData.object_name, name)
item_name.setData(WidgetData.address, server[:-1])
item_name.setData(WidgetData.address, ip)
item_name.setData(WidgetData.port, port)
item_ip.setText(ip)

View File

@@ -241,7 +241,7 @@ class ConnectionManager(QtCore.QThread):
# Load values and test connection to Revolution Pi
try:
pyload_version = list(map(int, sp.version().split(".")))
pyload_version = tuple(map(int, sp.version().split(".")))
xml_funcs = sp.system.listMethods()
xml_mode = sp.xmlmodus()
except Exception as e:

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<!DOCTYPE TS><TS version="2.0" language="de_DE" sourcelanguage="">
<context>
<name>AclManager</name>
<message>
@@ -65,27 +64,27 @@ Unsaved changes will be lost</source>
<context>
<name>AvahiSearch</name>
<message>
<location filename="../avahisearch.py" line="112"/>
<location filename="../avahisearch.py" line="119"/>
<source>Auto discovered</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../avahisearch.py" line="125"/>
<location filename="../avahisearch.py" line="132"/>
<source>Already in list...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../avahisearch.py" line="125"/>
<location filename="../avahisearch.py" line="132"/>
<source>The selected Revolution Pi is already saved in your connection list as &apos;{0}.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../avahisearch.py" line="146"/>
<location filename="../avahisearch.py" line="153"/>
<source>Success</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../avahisearch.py" line="146"/>
<location filename="../avahisearch.py" line="153"/>
<source>The connection with the name &apos;{0}&apos; was successfully saved to folder &apos;{1}&apos; in your connections.</source>
<translation type="unfinished"></translation>
</message>
@@ -93,7 +92,7 @@ Unsaved changes will be lost</source>
<context>
<name>AvahiSearchThread</name>
<message>
<location filename="../avahisearch.py" line="61"/>
<location filename="../avahisearch.py" line="68"/>
<source>N/A</source>
<translation type="unfinished"></translation>
</message>
@@ -135,12 +134,12 @@ Unsaved changes will be lost</source>
<context>
<name>DebugIos</name>
<message>
<location filename="../debugios.py" line="185"/>
<location filename="../debugios.py" line="190"/>
<source>signed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugios.py" line="190"/>
<location filename="../debugios.py" line="195"/>
<source>big_endian</source>
<translation type="unfinished"></translation>
</message>
@@ -172,22 +171,22 @@ Unsaved changes will be lost!</source>
<context>
<name>RevPiCommander</name>
<message>
<location filename="../revpicommander.py" line="201"/>
<location filename="../revpicommander.py" line="198"/>
<source>Select downloaded piCtory file...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="201"/>
<location filename="../revpicommander.py" line="198"/>
<source>piCtory file (*.rsc);;All files (*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="221"/>
<location filename="../revpicommander.py" line="218"/>
<source>Simulator started...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="221"/>
<location filename="../revpicommander.py" line="218"/>
<source>The simulator is running!
You can work with this simulator if your call RevPiModIO with this additional parameters:
@@ -198,164 +197,221 @@ You can copy that from header textbox.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="238"/>
<location filename="../revpicommander.py" line="235"/>
<source>Can not start...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="238"/>
<location filename="../revpicommander.py" line="235"/>
<source>Can not start the simulator! Maybe the piCtory file is corrupt or you can not write to the location &apos;{0}&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="456"/>
<location filename="../revpicommander.py" line="433"/>
<source>Warning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="252"/>
<location filename="../revpicommander.py" line="249"/>
<source>This version of Logviewer ist not supported in version {0} of RevPiPyLoad on your RevPi! You need at least version 0.4.1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="325"/>
<location filename="../revpicommander.py" line="300"/>
<source>XML-RPC access mode in the RevPiPyLoad configuration is too small to access this dialog!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="483"/>
<location filename="../revpicommander.py" line="460"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="283"/>
<location filename="../revpicommander.py" line="280"/>
<source>The Version of RevPiPyLoad on your Revolution Pi ({0}) is to old. This Version of RevPiCommander require at least version 0.6.0 of RevPiPyLoad. Please update your Revolution Pi!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="356"/>
<location filename="../revpicommander.py" line="333"/>
<source>Question</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="356"/>
<location filename="../revpicommander.py" line="333"/>
<source>Are you sure to reset piControl?
The pictory configuration will be reloaded. During that time the process image will be interrupted and could rise errors on running control programs!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="369"/>
<location filename="../revpicommander.py" line="346"/>
<source>Success</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="369"/>
<location filename="../revpicommander.py" line="346"/>
<source>piControl reset executed successfully</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="376"/>
<location filename="../revpicommander.py" line="353"/>
<source>piControl reset could not be executed successfully</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="391"/>
<location filename="../revpicommander.py" line="368"/>
<source>Can not connect to RevPi XML-RPC Service!
This could have the following reasons: The RevPi is not online, the XML-RPC service is not running or the ACL permission is not set for your IP!!!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="432"/>
<location filename="../revpicommander.py" line="409"/>
<source>Reset to piCtory defaults...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="432"/>
<location filename="../revpicommander.py" line="409"/>
<source>Do you want to reset your process image to piCtory default values?
You have to stop other RevPiModIO programs before doing that, because they could reset the outputs.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="456"/>
<location filename="../revpicommander.py" line="433"/>
<source>The watch mode ist not supported in version {0} of RevPiPyLoad on your RevPi! You need at least version 0.5.3! Maybe the python3-revpimodio2 module is not installed on your RevPi at least version 2.0.0.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="468"/>
<location filename="../revpicommander.py" line="445"/>
<source>Can not load this function, because your ACL level is to low!
You need at least level 1 to read or level 3 to write.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpicommander.py" line="483"/>
<location filename="../revpicommander.py" line="460"/>
<source>Can not load piCtory configuration.
Did you create a hardware configuration? Please check this in piCtory!</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RevPiDevelop</name>
<name>RevPiFiles</name>
<message>
<location filename="../revpidevelop.py" line="35"/>
<location filename="../revpifiles.py" line="35"/>
<source>Please select...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="276"/>
<location filename="../revpifiles.py" line="431"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="56"/>
<location filename="../revpifiles.py" line="69"/>
<source>Can not stop plc program on Revolution Pi.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="97"/>
<location filename="../revpifiles.py" line="110"/>
<source>Information...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="97"/>
<location filename="../revpifiles.py" line="110"/>
<source>A PLC program has been uploaded. Please check the PLC options to see if the correct program is specified as the start program.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="106"/>
<location filename="../revpifiles.py" line="119"/>
<source>The Revolution Pi could not process some parts of the transmission.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="114"/>
<location filename="../revpifiles.py" line="127"/>
<source>Errors occurred during transmission</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="120"/>
<location filename="../revpifiles.py" line="133"/>
<source>Warning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="120"/>
<location filename="../revpifiles.py" line="133"/>
<source>Could not start the plc program on Revolution Pi.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="198"/>
<location filename="../revpifiles.py" line="154"/>
<source>The RevPiPyLoad version on the Revolution Pi is to old.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="226"/>
<source>Can not open last directory &apos;{0}&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="283"/>
<source>Stop scanning for files, because we found more than {0} files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="265"/>
<location filename="../revpifiles.py" line="327"/>
<source>Could not load path of working dir</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="388"/>
<source>Can not load file list from Revolution Pi.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="420"/>
<source>Select folder...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpidevelop.py" line="276"/>
<location filename="../revpifiles.py" line="431"/>
<source>Can not access the folder &apos;{0}&apos; to read files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="533"/>
<source>Error...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="482"/>
<source>Error while download file &apos;{0}&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="490"/>
<source>Override files...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="490"/>
<source>One or more files does exist on your computer! Do you want to override the existingfiles?
Select &apos;Yes&apos; to override, &apos;No&apos; to download only missing files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="522"/>
<source>Delete files from Revolution Pi...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="522"/>
<source>Do you want to delete {0} files from revolution pi?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpifiles.py" line="533"/>
<source>Error while delete file &apos;{0}&apos;.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RevPiInfo</name>
@@ -487,7 +543,7 @@ Unsaved changes will be lost.</source>
<context>
<name>RevPiProgram</name>
<message>
<location filename="../revpiprogram.py" line="759"/>
<location filename="../revpiprogram.py" line="690"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
@@ -538,7 +594,7 @@ Please try again.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="769"/>
<location filename="../revpiprogram.py" line="700"/>
<source>Success</source>
<translation type="unfinished"></translation>
</message>
@@ -589,176 +645,156 @@ An error occurred on piControl reset!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="331"/>
<source>Select folder...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="348"/>
<location filename="../revpiprogram.py" line="330"/>
<source>Save ZIP archive...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="497"/>
<location filename="../revpiprogram.py" line="428"/>
<source>ZIP archive (*.zip);;All files (*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="369"/>
<location filename="../revpiprogram.py" line="351"/>
<source>Save TGZ archive...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="369"/>
<location filename="../revpiprogram.py" line="351"/>
<source>TGZ archive (*.tgz);;All files (*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="399"/>
<location filename="../revpiprogram.py" line="381"/>
<source>Could not load PLC program from Revolution Pi.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="426"/>
<location filename="../revpiprogram.py" line="394"/>
<source>Coud not save the archive or extract the files!
Please retry.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="432"/>
<location filename="../revpiprogram.py" line="400"/>
<source>Transfer successfully completed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="460"/>
<source>Upload plc files...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="460"/>
<source>Python file (*.py);;Config file (*.conf);;;JSON file (*.json);;All files (*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="479"/>
<source>Select folder to upload...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="497"/>
<location filename="../revpiprogram.py" line="428"/>
<source>Upload content of ZIP archive...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="522"/>
<location filename="../revpiprogram.py" line="453"/>
<source>The selected file ist not a ZIP archive.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="531"/>
<location filename="../revpiprogram.py" line="462"/>
<source>Upload content of TAR archive...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="531"/>
<location filename="../revpiprogram.py" line="462"/>
<source>TAR archive (*.tgz);;All files (*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="556"/>
<location filename="../revpiprogram.py" line="487"/>
<source>The selected file ist not a TAR archive.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="565"/>
<location filename="../revpiprogram.py" line="496"/>
<source>No files to upload...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="565"/>
<location filename="../revpiprogram.py" line="496"/>
<source>Found no files to upload in given location or archive.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="576"/>
<location filename="../revpiprogram.py" line="507"/>
<source>There was an error deleting the files on the Revolution Pi.
Upload aborted! Please try again.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="622"/>
<location filename="../revpiprogram.py" line="553"/>
<source>The PLC program was transferred successfully.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="630"/>
<location filename="../revpiprogram.py" line="561"/>
<source>Information</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="630"/>
<location filename="../revpiprogram.py" line="561"/>
<source>Could not find the selected PLC start program in uploaded files.
This is not an error, if the file was already on the Revolution Pi. Check PLC start program field</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="643"/>
<location filename="../revpiprogram.py" line="574"/>
<source>There is no piCtory configuration in this archive.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="650"/>
<location filename="../revpiprogram.py" line="581"/>
<source>The Revolution Pi could not process some parts of the transmission.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="657"/>
<location filename="../revpiprogram.py" line="588"/>
<source>Errors occurred during transmission.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="676"/>
<location filename="../revpiprogram.py" line="607"/>
<source>Save piCtory file...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="717"/>
<location filename="../revpiprogram.py" line="648"/>
<source>piCtory file (*.rsc);;All files (*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="695"/>
<location filename="../revpiprogram.py" line="626"/>
<source>Could not load piCtory file from Revolution Pi.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="705"/>
<location filename="../revpiprogram.py" line="636"/>
<source>piCtory configuration successfully loaded and saved to:
{0}.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="717"/>
<location filename="../revpiprogram.py" line="648"/>
<source>Upload piCtory file...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="738"/>
<location filename="../revpiprogram.py" line="669"/>
<source>Save piControl file...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="738"/>
<location filename="../revpiprogram.py" line="669"/>
<source>Process image file (*.img);;All files (*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="759"/>
<location filename="../revpiprogram.py" line="690"/>
<source>Could not load process image from Revolution Pi.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../revpiprogram.py" line="769"/>
<location filename="../revpiprogram.py" line="700"/>
<source>Process image successfully loaded and saved to:
{0}.</source>
<translation type="unfinished"></translation>
@@ -1127,61 +1163,51 @@ Publish values with topic: [basetopic]/set/[outputname]</source>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="84"/>
<source>Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="89"/>
<source>Folder</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="94"/>
<source>ZIP archive</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="99"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="89"/>
<source>TGZ archive</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="165"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="155"/>
<source>Upload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="158"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="148"/>
<source>Download</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="121"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="111"/>
<source>Transfair format:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="128"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="118"/>
<source>Including piCtory configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="135"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="125"/>
<source>Remove all files on Revolution Pi before upload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="145"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="135"/>
<source>Control files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="172"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="162"/>
<source>piCtory configuraiton</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpiprogram.ui" line="179"/>
<location filename="../../include/ui_dev/revpiprogram.ui" line="169"/>
<source>Process image from piControl0</source>
<translation type="unfinished"></translation>
</message>
@@ -1339,44 +1365,6 @@ applicable law.
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>wid_develop</name>
<message>
<location filename="../../include/ui_dev/revpidevelop.ui" line="35"/>
<source>Stop / Upload / Start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpidevelop.ui" line="42"/>
<source>Just upload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpidevelop.ui" line="76"/>
<source>File watcher for PLC development</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpidevelop.ui" line="82"/>
<source>Path to development root:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpidevelop.ui" line="89"/>
<source>Open developer root directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpidevelop.ui" line="106"/>
<source>/</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpidevelop.ui" line="113"/>
<source>Reload file list</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>win_debugios</name>
<message>
@@ -1385,6 +1373,54 @@ applicable law.
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>win_files</name>
<message>
<location filename="../../include/ui_dev/files.ui" line="14"/>
<source>File manager</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/files.ui" line="31"/>
<source>Local computer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/files.ui" line="37"/>
<source>Path to development root:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/files.ui" line="44"/>
<source>Open developer root directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/files.ui" line="200"/>
<source>Reload file list</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/files.ui" line="186"/>
<source>/</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/files.ui" line="171"/>
<source>Revolution Pi</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/files.ui" line="193"/>
<source>RevPiPyLoad working directory:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/files.ui" line="311"/>
<source>Stop - Upload - Start</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>win_revpicommander</name>
<message>
@@ -1498,37 +1534,37 @@ applicable law.
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpicommander.ui" line="206"/>
<location filename="../../include/ui_dev/revpicommander.ui" line="203"/>
<source>PLC de&amp;veloper...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpicommander.ui" line="209"/>
<location filename="../../include/ui_dev/revpicommander.ui" line="206"/>
<source>F9</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpicommander.ui" line="214"/>
<location filename="../../include/ui_dev/revpicommander.ui" line="211"/>
<source>piCtory configuraiton...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpicommander.ui" line="219"/>
<location filename="../../include/ui_dev/revpicommander.ui" line="216"/>
<source>&amp;Disconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpicommander.ui" line="222"/>
<location filename="../../include/ui_dev/revpicommander.ui" line="219"/>
<source>Ctrl+X</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpicommander.ui" line="227"/>
<location filename="../../include/ui_dev/revpicommander.ui" line="224"/>
<source>Reset driver...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../include/ui_dev/revpicommander.ui" line="232"/>
<location filename="../../include/ui_dev/revpicommander.ui" line="229"/>
<source>Start local si&amp;mulator...</source>
<translation type="unfinished"></translation>
</message>

View File

@@ -17,7 +17,7 @@ import proginit as pi
import revpilogfile
from avahisearch import AvahiSearch
from debugcontrol import DebugControl
from revpidevelop import RevPiDevelop
from revpifiles import RevPiFiles
from revpiinfo import RevPiInfo
from revpioption import RevPiOption
from revpiplclist import RevPiPlcList
@@ -35,17 +35,11 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
self.wid_debugcontrol = None # type: DebugControl
"""Holds the widget of DebugControl."""
self.wid_develop = None # type: RevPiDevelop
"""Holds the widget of RevPiDevelop."""
self.simulating = False
"""True, if simulation is running."""
self.dict_men_connections_subfolder = {}
"""Submenus for folder entries."""
# fixme: Prepare gui
#self.__base_size = self.size()
#self.setFixedSize(self.__base_size)
self._set_gui_control_states()
self._load_men_connections()
@@ -55,6 +49,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
self.diag_info = RevPiInfo(__version__, self)
self.diag_options = RevPiOption(self)
self.diag_program = RevPiProgram(self)
self.win_files = RevPiFiles(self)
self.win_log = revpilogfile.RevPiLogfile(self)
self.btn_plc_logs.pressed.connect(self.on_act_logs_triggered)
@@ -116,11 +111,12 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
# This will remove the widgets in the button functions
self.btn_plc_debug.setChecked(False)
self.act_developer.setChecked(False)
self.diag_info.reject()
self.diag_options.reject()
self.diag_program.reject()
self.win_files.close()
self.win_files.deleteLater()
self.centralwidget.adjustSize()
self.adjustSize()
@@ -136,6 +132,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
helper.cm.address,
helper.cm.port
))
self.win_files = RevPiFiles(self)
@QtCore.pyqtSlot(str, str)
def on_cm_status_changed(self, text: str, color: str):
@@ -279,7 +276,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
return
# Check version of RevPiPyLoad, must be greater than 0.5!
if helper.cm.pyload_version[0] == 0 and helper.cm.pyload_version[1] < 6:
if helper.cm.pyload_version < (0, 6, 0):
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"The Version of RevPiPyLoad on your Revolution Pi ({0}) is to old. "
@@ -310,36 +307,16 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
self.diag_program.exec()
@QtCore.pyqtSlot(bool)
def on_act_developer_toggled(self, state: bool):
@QtCore.pyqtSlot()
def on_act_developer_triggered(self):
"""Extent developer mode to main window."""
if not (state or self.wid_develop is None):
# Remove widget
self.gl.removeWidget(self.wid_develop)
self.wid_develop.deleteLater()
self.wid_develop = None
self.gl.setColumnStretch(1, 0)
if not helper.cm.connected:
return
elif state and helper.cm.connected:
if helper.cm.xml_mode < 2:
QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr(
"XML-RPC access mode in the RevPiPyLoad "
"configuration is too small to access this dialog!"
)
)
self.act_developer.setChecked(False)
else:
self.wid_develop = RevPiDevelop(self.centralwidget)
self.gl.addWidget(self.wid_develop, 0, 1, 8, 1)
self.gl.setColumnStretch(1, 1)
elif state:
self.act_developer.setChecked(False)
self.centralwidget.adjustSize()
self.adjustSize()
if self.win_files.isHidden():
self.win_files.show()
else:
self.win_files.activateWindow()
@QtCore.pyqtSlot()
def on_act_pictory_triggered(self):

View File

@@ -1,299 +0,0 @@
# -*- coding: utf-8 -*-
"""PLC developer to upload your active development."""
__author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "GPLv3"
import gzip
import os
from enum import IntEnum
from os import DirEntry
from xmlrpc.client import Binary
from PyQt5 import QtCore, QtGui, QtWidgets
import helper
import proginit as pi
from helper import WidgetData
from ui.revpidevelop_ui import Ui_wid_develop
class NodeType(IntEnum):
FILE = 1000
DIR = 1001
class RevPiDevelop(QtWidgets.QWidget, Ui_wid_develop):
"""Developer extension for RevPiCommander."""
def __init__(self, parent=None):
super(RevPiDevelop, self).__init__(parent)
self.setupUi(self)
self.tree_files_counter = 0
self.tree_files_counter_max = 10000
self.lbl_path.setText(helper.cm.develop_watch_path or self.tr("Please select..."))
self.btn_all.setEnabled(False)
self.btn_upload.setEnabled(False)
if helper.cm.develop_watch_path:
self._load_path_files(True)
def __del__(self):
pi.logger.debug("RevPiDevelop.__del__")
def _do_my_job(self, stop_restart=True):
"""
Upload the selected files and do a optionally restart.
:param stop_restart: True will restart program
"""
if not helper.cm.connected:
return
if stop_restart and helper.cm.call_remote_function("plcstop") is None:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"Can not stop plc program on Revolution Pi."
)
)
return
# Get config to find actual auto start program for warnings
opt_program = helper.cm.call_remote_function("get_config", default_value={})
opt_program = opt_program.get("plcprogram", "none.py")
uploaded = True # Will be False, when opt_program was found in files
ec = 0
for file_name in self.file_list():
# todo: Check exception of local file
with open(file_name, "rb") as fh:
# Remove base dir of file to set relative for PyLoad
send_name = file_name.replace(helper.cm.develop_watch_path, "")[1:]
# Check whether this is the auto start program
if send_name == opt_program:
uploaded = False
# Transfer file
try:
upload_status = helper.cm.call_remote_function(
"plcupload", Binary(gzip.compress(fh.read())), send_name,
default_value=False
)
except Exception as e:
pi.logger.error(e)
ec = -2
break
if not upload_status:
ec = -1
break
if ec == 0:
# Tell user, we did not find the auto start program in files
if uploaded:
QtWidgets.QMessageBox.information(
self, self.tr("Information..."), self.tr(
"A PLC program has been uploaded. Please check the "
"PLC options to see if the correct program is "
"specified as the start program."
)
)
elif ec == -1:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"The Revolution Pi could not process some parts of the "
"transmission."
)
)
elif ec == -2:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"),
self.tr("Errors occurred during transmission")
)
if stop_restart and helper.cm.call_remote_function("plcstart", default_value=1) != 0:
QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr(
"Could not start the plc program on Revolution Pi."
)
)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# region # REGION: Tree management
def __insert_files(self, base_dir: str, child=None):
"""
Recursively add files to tree view.
:param base_dir: Directory to scan for files
:param child: Child widget to add new widgets
"""
for de in os.scandir(base_dir): # type: DirEntry
if self.tree_files_counter > self.tree_files_counter_max:
return
if de.is_dir(follow_symlinks=False):
item = QtWidgets.QTreeWidgetItem(NodeType.DIR)
item.setText(0, de.name)
item.setIcon(0, QtGui.QIcon(":/main/ico/folder.ico"))
if child:
child.addChild(item)
else:
self.tree_files.addTopLevelItem(item)
self.__insert_files(de.path, item)
elif de.is_file(follow_symlinks=False):
self.tree_files_counter += 1
item = QtWidgets.QTreeWidgetItem(NodeType.FILE)
item.setText(0, de.name)
item.setData(0, WidgetData.file_name, de.path)
item.setIcon(0, QtGui.QIcon(
":/file/ico/file-else.ico" if de.name.find(".py") == -1 else
":/file/ico/file-python.ico"
))
if child:
child.addChild(item)
else:
self.tree_files.addTopLevelItem(item)
item.setSelected(de.path in helper.cm.develop_watch_files)
self._parent_selected(item)
def __select_children(self, top_item: QtWidgets.QTreeWidgetItem, value: bool):
"""Recursive select files from directory."""
pi.logger.debug("RevPiDevelop.__select_children")
for i in range(top_item.childCount()):
item = top_item.child(i)
if item.type() == NodeType.DIR:
self.__select_children(item, value)
elif item.type() == NodeType.FILE:
item.setSelected(value)
def _load_path_files(self, silent=False):
"""
Refresh the file list.
:param silent: Do not show message boxes
"""
pi.logger.debug("RevPiDevelop._load_path_files")
self.tree_files_counter = 0
self.tree_files.blockSignals(True)
self.tree_files.clear()
self.tree_files.blockSignals(False)
self.__insert_files(helper.cm.develop_watch_path)
self.tree_files.sortItems(0, QtCore.Qt.AscendingOrder)
if not silent and self.tree_files_counter > self.tree_files_counter_max:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"Stop scanning for files, because we found more than {0} files."
).format(self.tree_files_counter_max)
)
state = len(self.tree_files.selectedItems()) > 0
self.btn_all.setEnabled(state)
self.btn_upload.setEnabled(state)
def _parent_selected(self, item: QtWidgets.QTreeWidgetItem):
"""Check all children of a parent are selected."""
if item.parent():
all_selected = True
for i in range(item.parent().childCount()):
if not item.parent().child(i).isSelected():
all_selected = False
break
item.parent().setSelected(all_selected)
def file_list(self):
"""Generate a file list with full path of selected entries."""
pi.logger.debug("RevPiDevelop.file_list")
lst = []
for item in self.tree_files.selectedItems():
if item.type() == NodeType.DIR:
continue
lst.append(item.data(0, WidgetData.file_name))
return lst
@QtCore.pyqtSlot()
def on_tree_files_itemSelectionChanged(self):
item = self.tree_files.currentItem()
if item is None:
return
pi.logger.debug("RevPiDevelop.on_tree_files_itemSelectionChanged")
# Block while preselect other entries
self.tree_files.blockSignals(True)
if item.type() == NodeType.DIR:
self.__select_children(item, item.isSelected())
elif item.type() == NodeType.FILE:
self._parent_selected(item)
self.tree_files.blockSignals(False)
state = len(self.tree_files.selectedItems()) > 0
self.btn_all.setEnabled(state)
self.btn_upload.setEnabled(state)
helper.cm.develop_watch_files = self.file_list()
# endregion # # # # #
@QtCore.pyqtSlot()
def on_btn_all_pressed(self):
pi.logger.debug("RevPiDevelop.on_btn_all_pressed")
self._do_my_job(True)
@QtCore.pyqtSlot()
def on_btn_select_pressed(self):
pi.logger.debug("RevPiDevelop.on_btn_select_pressed")
diag_folder = QtWidgets.QFileDialog(
self, self.tr("Select folder..."),
helper.cm.develop_watch_path,
)
diag_folder.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
if diag_folder.exec() != QtWidgets.QFileDialog.Accepted:
return
selected_dir = diag_folder.selectedFiles()[0]
if not os.access(selected_dir, os.R_OK):
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"Can not access the folder '{0}' to read files."
)
)
helper.cm.develop_watch_files = []
helper.cm.develop_watch_path = ""
return
self.lbl_path.setText(selected_dir)
helper.cm.develop_watch_path = selected_dir
helper.cm.develop_watch_files = []
self._load_path_files(False)
@QtCore.pyqtSlot()
def on_btn_refresh_pressed(self):
pi.logger.debug("RevPiDevelop.on_btn_refresh_pressed")
self._load_path_files(False)
@QtCore.pyqtSlot()
def on_btn_upload_pressed(self):
pi.logger.debug("RevPiDevelop.on_btn_upload_pressed")
self._do_my_job(False)

View File

@@ -0,0 +1,538 @@
# -*- coding: utf-8 -*-
"""File manager for up und download PLC program."""
__author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2020 Sven Sager"
__license__ = "GPLv3"
import gzip
import os
from enum import IntEnum
from os import DirEntry, scandir
from xmlrpc.client import Binary
from PyQt5 import QtCore, QtGui, QtWidgets
import helper
import proginit as pi
from helper import WidgetData
from ui.files_ui import Ui_win_files
class NodeType(IntEnum):
FILE = 1000
DIR = 1001
class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
def __init__(self, parent=None):
super(RevPiFiles, self).__init__(parent)
self.setupUi(self)
self.dc_settings = {}
self.tree_files_counter = 0
self.tree_files_counter_max = 10000
self.lbl_path_local.setText(helper.cm.develop_watch_path or self.tr("Please select..."))
self.lbl_path_local.setToolTip(self.lbl_path_local.text())
self.btn_all.setEnabled(False)
self.btn_to_left.setEnabled(False)
self.btn_to_right.setEnabled(False)
self.btn_delete_revpi.setEnabled(False)
if helper.cm.develop_watch_path:
self._load_files_local(True)
if helper.cm.connected:
self._load_files_revpi(True)
self.restoreGeometry(helper.settings.value("files/geo", b''))
self.splitter.setSizes(list(map(int, helper.settings.value("files/splitter", [0, 0]))))
def __del__(self):
pi.logger.debug("RevPiFiles.__del__")
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
pi.logger.debug("RevPiFiles.closeEvent")
helper.settings.setValue("files/geo", self.saveGeometry())
helper.settings.setValue("files/splitter", self.splitter.sizes())
def _do_my_job(self, stop_restart=True):
"""
Upload the selected files and do a optionally restart.
:param stop_restart: True will restart program
"""
if not helper.cm.connected:
return
if stop_restart and helper.cm.call_remote_function("plcstop") is None:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"Can not stop plc program on Revolution Pi."
)
)
return
# Get config to find actual auto start program for warnings
opt_program = helper.cm.call_remote_function("get_config", default_value={})
opt_program = opt_program.get("plcprogram", "none.py")
uploaded = True # Will be False, when opt_program was found in files
ec = 0
for file_name in self.file_list_local():
# todo: Check exception of local file
with open(file_name, "rb") as fh:
# Remove base dir of file to set relative for PyLoad
send_name = file_name.replace(helper.cm.develop_watch_path, "")[1:]
# Check whether this is the auto start program
if send_name == opt_program:
uploaded = False
# Transfer file
try:
upload_status = helper.cm.call_remote_function(
"plcupload", Binary(gzip.compress(fh.read())), send_name,
default_value=False
)
except Exception as e:
pi.logger.error(e)
ec = -2
break
if not upload_status:
ec = -1
break
if ec == 0:
# Tell user, we did not find the auto start program in files
if uploaded:
QtWidgets.QMessageBox.information(
self, self.tr("Information..."), self.tr(
"A PLC program has been uploaded. Please check the "
"PLC options to see if the correct program is "
"specified as the start program."
)
)
elif ec == -1:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"The Revolution Pi could not process some parts of the "
"transmission."
)
)
elif ec == -2:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"),
self.tr("Errors occurred during transmission")
)
if stop_restart and helper.cm.call_remote_function("plcstart", default_value=1) != 0:
QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr(
"Could not start the plc program on Revolution Pi."
)
)
def _set_gui_control_states(self):
"""Setup states of actions and buttons."""
state_local = len(self.tree_files_local.selectedItems()) > 0
state_revpi = len(self.tree_files_revpi.selectedItems()) > 0
self.btn_all.setEnabled(state_local)
self.btn_to_right.setEnabled(state_local)
if "plcdeletefile" not in helper.cm.xml_funcs:
self.btn_delete_revpi.setEnabled(False)
self.btn_delete_revpi.setToolTip(self.tr("The RevPiPyLoad version on the Revolution Pi is to old."))
else:
self.btn_delete_revpi.setEnabled(state_revpi)
if "plcdownload_file" not in helper.cm.xml_funcs:
self.btn_to_left.setEnabled(False)
self.btn_to_left.setToolTip(self.tr("The RevPiPyLoad version on the Revolution Pi is to old."))
else:
self.btn_to_left.setEnabled(state_revpi)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# region # REGION: Tree management
@staticmethod
def _parent_selection_state(item: QtWidgets.QTreeWidgetItem):
"""Set selected, if all children are selected."""
if item.parent():
all_selected = True
for i in range(item.parent().childCount()):
if not item.parent().child(i).isSelected():
all_selected = False
break
item.parent().setSelected(all_selected)
def _select_children(self, top_item: QtWidgets.QTreeWidgetItem, value: bool):
"""Recursive select children from parent."""
pi.logger.debug("RevPiFiles._select_children")
for i in range(top_item.childCount()):
item = top_item.child(i)
if item.type() == NodeType.DIR:
item.setSelected(value)
self._select_children(item, value)
elif item.type() == NodeType.FILE:
item.setSelected(value)
def __item_selection_changed(self, tree_view: QtWidgets.QTreeView):
"""Manager vor item selection of three views."""
item = tree_view.currentItem()
if item is None:
return
pi.logger.debug("RevPiFiles.__itemSelectionChanged")
# Block while preselect other entries
tree_view.blockSignals(True)
if item.type() == NodeType.DIR:
self._select_children(item, item.isSelected())
elif item.type() == NodeType.FILE:
self._parent_selection_state(item)
tree_view.blockSignals(False)
self._set_gui_control_states()
@QtCore.pyqtSlot()
def on_tree_files_local_itemSelectionChanged(self):
self.__item_selection_changed(self.tree_files_local)
helper.cm.develop_watch_files = self.file_list_local()
@QtCore.pyqtSlot()
def on_tree_files_revpi_itemSelectionChanged(self):
self.__item_selection_changed(self.tree_files_revpi)
# endregion # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# region # REGION: Local file lists
def __insert_files_local(self, base_dir: str, child=None):
"""
Recursively add files to tree view.
:param base_dir: Directory to scan for files
:param child: Child widget to add new widgets
"""
if not os.path.exists(base_dir):
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"Can not open last directory '{0}'."
).format(base_dir)
)
return
for de in os.scandir(base_dir): # type: DirEntry
if self.tree_files_counter > self.tree_files_counter_max:
return
if de.is_dir(follow_symlinks=False):
item = QtWidgets.QTreeWidgetItem(NodeType.DIR)
item.setText(0, de.name)
item.setIcon(0, QtGui.QIcon(":/main/ico/folder.ico"))
if child:
child.addChild(item)
else:
self.tree_files_local.addTopLevelItem(item)
self.__insert_files_local(de.path, item)
elif de.is_file(follow_symlinks=False):
self.tree_files_counter += 1
item = QtWidgets.QTreeWidgetItem(NodeType.FILE)
item.setText(0, de.name)
item.setData(0, WidgetData.file_name, de.path)
item.setIcon(0, QtGui.QIcon(
":/file/ico/file-else.ico" if de.name.find(".py") == -1 else
":/file/ico/file-python.ico"
))
if child:
child.addChild(item)
else:
self.tree_files_local.addTopLevelItem(item)
item.setSelected(de.path in helper.cm.develop_watch_files)
self._parent_selection_state(item)
def _load_files_local(self, silent=False):
"""
Refresh the file list.
:param silent: Do not show message boxes
"""
pi.logger.debug("RevPiFiles._load_files_local")
self.tree_files_counter = 0
self.tree_files_local.blockSignals(True)
self.tree_files_local.clear()
self.__insert_files_local(helper.cm.develop_watch_path)
self.tree_files_local.sortItems(0, QtCore.Qt.AscendingOrder)
self.tree_files_local.blockSignals(False)
if not silent and self.tree_files_counter > self.tree_files_counter_max:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"Stop scanning for files, because we found more than {0} files."
).format(self.tree_files_counter_max)
)
self._set_gui_control_states()
def file_list_local(self):
"""Generate a file list with full path of selected entries."""
pi.logger.debug("RevPiFiles.file_list_local")
lst = []
for item in self.tree_files_local.selectedItems():
if item.type() == NodeType.DIR:
# We just want files
continue
lst.append(item.data(0, WidgetData.file_name))
return lst
# endregion # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# region # REGION: RevPi file lists
def _load_files_revpi(self, silent=False):
"""
Refresh the file list of revolution pi.
:param silent: Do not show message boxes
"""
pi.logger.debug("RevPiFiles._load_files_revpi")
self.tree_files_revpi.blockSignals(True)
self.tree_files_revpi.clear()
self.tree_files_revpi.blockSignals(False)
if not helper.cm.connected:
lst_revpi = None
else:
lst_revpi = helper.cm.call_remote_function("get_filelist")
# Just load settings once
if not self.dc_settings:
self.dc_settings = helper.cm.call_remote_function("get_config", default_value={})
self.lbl_path_revpi.setText(
self.dc_settings.get("plcworkdir", self.tr("Could not load path of working dir"))
)
self.lbl_path_revpi.setToolTip(self.lbl_path_revpi.text())
if lst_revpi:
lst_revpi.sort()
for path_file in lst_revpi:
lst_path_file = path_file.split("/")
dir_node = None # type: QtWidgets.QTreeWidgetItem
for folder in lst_path_file[:-1]:
new_dir_node = QtWidgets.QTreeWidgetItem(NodeType.DIR)
new_dir_node.setText(0, folder)
new_dir_node.setIcon(0, QtGui.QIcon(":/main/ico/folder.ico"))
if dir_node:
# Subfolder of top level
for i in range(dir_node.childCount()):
item = dir_node.child(i)
if item.type() != NodeType.DIR:
continue
if item.text(0) == new_dir_node.text(0):
dir_node = item
new_dir_node = None
break
if new_dir_node:
dir_node.addChild(new_dir_node)
dir_node = new_dir_node
else:
# Search in top level
for i in range(self.tree_files_revpi.topLevelItemCount()):
item = self.tree_files_revpi.topLevelItem(i)
if item.type() != NodeType.DIR:
continue
if item.text(0) == new_dir_node.text(0):
dir_node = item
new_dir_node = None
break
if new_dir_node:
self.tree_files_revpi.addTopLevelItem(new_dir_node)
dir_node = new_dir_node
# This is the file name
object_name = lst_path_file[-1]
item = QtWidgets.QTreeWidgetItem(NodeType.FILE)
item.setText(0, object_name)
item.setData(0, WidgetData.file_name, path_file)
item.setIcon(0, QtGui.QIcon(
":/file/ico/file-else.ico" if object_name.find(".py") == -1 else
":/file/ico/file-python.ico"
))
if dir_node:
dir_node.addChild(item)
else:
self.tree_files_revpi.addTopLevelItem(item)
self.tree_files_revpi.sortItems(0, QtCore.Qt.AscendingOrder)
elif not silent:
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"Can not load file list from Revolution Pi."
)
)
self._set_gui_control_states()
def file_list_revpi(self):
"""Generate a file list with full path of selected entries."""
pi.logger.debug("RevPiFiles.file_list_revpi")
lst = []
for item in self.tree_files_revpi.selectedItems():
if item.type() == NodeType.DIR:
# We just want files
continue
lst.append(item.data(0, WidgetData.file_name))
return lst
# endregion # # # # #
@QtCore.pyqtSlot()
def on_btn_all_pressed(self):
pi.logger.debug("RevPiFiles.on_btn_all_pressed")
self._do_my_job(True)
self.file_list_revpi()
@QtCore.pyqtSlot()
def on_btn_select_local_pressed(self):
pi.logger.debug("RevPiFiles.on_btn_select_pressed")
diag_folder = QtWidgets.QFileDialog(
self, self.tr("Select folder..."),
helper.cm.develop_watch_path,
)
diag_folder.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
if diag_folder.exec() != QtWidgets.QFileDialog.Accepted:
return
selected_dir = diag_folder.selectedFiles()[0]
if not os.access(selected_dir, os.R_OK):
QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr(
"Can not access the folder '{0}' to read files."
)
)
helper.cm.develop_watch_files = []
helper.cm.develop_watch_path = ""
return
self.lbl_path_local.setText(selected_dir)
self.lbl_path_local.setToolTip(self.lbl_path_local.text())
helper.cm.develop_watch_path = selected_dir
helper.cm.develop_watch_files = []
self._load_files_local(False)
@QtCore.pyqtSlot()
def on_btn_refresh_local_pressed(self):
pi.logger.debug("RevPiFiles.on_btn_refresh_pressed")
self._load_files_local(False)
@QtCore.pyqtSlot()
def on_btn_refresh_revpi_pressed(self):
pi.logger.debug("RevPiFiles.on_btn_refresh_revpi_pressed")
self._load_files_revpi(False)
@QtCore.pyqtSlot()
def on_btn_to_right_pressed(self):
"""Upload selected files to revolution pi."""
pi.logger.debug("RevPiFiles.on_btn_to_right_pressed")
self._do_my_job(False)
self.file_list_revpi()
@QtCore.pyqtSlot()
def on_btn_to_left_pressed(self):
"""Download selected file."""
pi.logger.debug("RevPiFiles.on_btn_to_left_pressed")
override = None
for item in self.tree_files_revpi.selectedItems():
if item.type() != NodeType.FILE:
continue
file_name = item.data(0, WidgetData.file_name)
rc = helper.cm.call_remote_function(
"plcdownload_file", file_name,
default_value=Binary()
)
rc = rc.data
if not rc:
QtWidgets.QMessageBox.critical(
self, self.tr("Error..."), self.tr(
"Error while download file '{0}'."
).format(file_name)
)
else:
file_name = os.path.join(helper.cm.develop_watch_path, file_name)
if override is None and os.path.exists(file_name):
rc = QtWidgets.QMessageBox.question(
self, self.tr("Override files..."), self.tr(
"One or more files does exist on your computer! Do you want to override the existing"
"files?\n\nSelect 'Yes' to override, 'No' to download only missing files."
),
buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel
)
if rc == QtWidgets.QMessageBox.Cancel:
return
override = rc == QtWidgets.QMessageBox.Yes
if os.path.exists(file_name) and not override:
pi.logger.debug("Skip existing file '{0}'".format(file_name))
continue
os.makedirs(os.path.dirname(file_name), exist_ok=True)
file_data = gzip.decompress(rc)
with open(os.path.join(helper.cm.develop_watch_path, file_name), "wb") as fh:
fh.write(file_data)
self._load_files_local()
@QtCore.pyqtSlot()
def on_btn_delete_revpi_pressed(self):
"""Remove selected files from working directory on revolution pi."""
pi.logger.debug("RevPiFiles.btn_delete_revpi_pressed")
lst_delete = []
for item in self.tree_files_revpi.selectedItems():
if item.type() == NodeType.FILE:
lst_delete.append(item.data(0, WidgetData.file_name))
rc = QtWidgets.QMessageBox.question(
self, self.tr("Delete files from Revolution Pi..."), self.tr(
"Do you want to delete {0} files from revolution pi?"
).format(len(lst_delete))
)
if rc != QtWidgets.QMessageBox.Yes:
return
for file_name in lst_delete:
rc = helper.cm.call_remote_function("plcdeletefile", file_name, default_value=False)
if not rc:
QtWidgets.QMessageBox.critical(
self, self.tr("Error..."), self.tr(
"Error while delete file '{0}'."
).format(file_name)
)
self._load_files_revpi()

View File

@@ -313,8 +313,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
@QtCore.pyqtSlot(int)
def on_cbb_format_currentIndexChanged(self, index: int):
helper.settings.setValue("program/cbb_format_index", index)
self.cbx_pictory.setEnabled(index >= 2)
self.btn_program_download.setEnabled(index != 1)
self.cbx_pictory.setEnabled(index >= 1)
@QtCore.pyqtSlot()
def on_btn_program_download_pressed(self):
@@ -325,23 +324,6 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
selected_dir = ""
if self.cbb_format.currentIndex() == 0:
# Save files to selected directory
diag_folder = QtWidgets.QFileDialog(
self, self.tr("Select folder..."),
helper.cm.program_last_dir_selected,
)
diag_folder.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
self.rejected.connect(diag_folder.reject)
if diag_folder.exec() != QtWidgets.QFileDialog.Accepted:
return
selected_dir = diag_folder.selectedFiles()[0]
fh = open(mkstemp()[1], "wb")
helper.cm.program_last_dir_selected = selected_dir
elif self.cbb_format.currentIndex() == 2:
# Save files as zip archive
diag_save = QtWidgets.QFileDialog(
self, self.tr("Save ZIP archive..."),
@@ -362,7 +344,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
helper.cm.program_last_zip_file = filename
elif self.cbb_format.currentIndex() == 3:
elif self.cbb_format.currentIndex() == 1:
# Save files as TarGz archive
diag_save = QtWidgets.QFileDialog(
self, self.tr("Save TGZ archive..."),
@@ -389,7 +371,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
plcfile = helper.cm.call_remote_function(
"plcdownload",
"zip" if self.cbb_format.currentIndex() == 2 else "tar",
"zip" if self.cbb_format.currentIndex() == 0 else "tar",
self.cbx_pictory.isChecked()
)
@@ -405,20 +387,6 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
fh.write(plcfile.data)
fh.close()
if self.cbb_format.currentIndex() == 0:
# Extract archive to selected directory
os.makedirs(selected_dir, exist_ok=True)
fh_pack = tarfile.open(fh.name)
for tar_item in fh_pack.getmembers():
if tar_item.name == "revpipyload":
# Ignore root folder in Tar file
continue
tar_item.name = tar_item.name.replace("revpipyload/", "")
fh_pack.extract(tar_item, selected_dir)
fh_pack.close()
except Exception as e:
pi.logger.error(e)
QtWidgets.QMessageBox.critical(
@@ -452,43 +420,6 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
rscfile = None
if self.cbb_format.currentIndex() == 0:
# Upload files
diag_open = QtWidgets.QFileDialog(
self,
self.tr("Upload plc files..."),
helper.cm.program_last_dir_upload,
self.tr("Python file (*.py);;Config file (*.conf);;;JSON file (*.json);;All files (*.*)")
)
diag_open.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen)
diag_open.setFileMode(QtWidgets.QFileDialog.ExistingFiles)
self.rejected.connect(diag_open.reject)
if diag_open.exec() != QtWidgets.QFileDialog.AcceptSave or len(diag_open.selectedFiles()) != 1:
return
lst_files = diag_open.selectedFiles()
if len(lst_files) > 0:
helper.cm.program_last_dir_upload = os.path.dirname(lst_files[0])
elif self.cbb_format.currentIndex() == 1:
# Select folder to upload
diag_folder = QtWidgets.QFileDialog(
self, self.tr("Select folder to upload..."),
helper.cm.program_last_dir_upload,
)
diag_folder.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
self.rejected.connect(diag_folder.reject)
if diag_folder.exec() != QtWidgets.QFileDialog.Accepted:
return
selected_dir = diag_folder.selectedFiles()[0]
helper.cm.program_last_dir_upload = selected_dir
folder_name = os.path.basename(selected_dir)
lst_files = self.create_filelist(selected_dir)
elif self.cbb_format.currentIndex() == 2:
# Upload zip archive content
diag_open = QtWidgets.QFileDialog(
self, self.tr("Upload content of ZIP archive..."),
@@ -522,7 +453,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
)
return
elif self.cbb_format.currentIndex() == 3:
elif self.cbb_format.currentIndex() == 1:
# Upload TarGz content
diag_open = QtWidgets.QFileDialog(
self, self.tr("Upload content of TAR archive..."),

View File

@@ -3,7 +3,7 @@ SOURCES = revpicommander/aclmanager.py \
revpicommander/debugcontrol.py \
revpicommander/debugios.py \
revpicommander/mqttmanager.py \
revpicommander/revpidevelop.py \
revpicommander/revpifiles.py \
revpicommander/revpiinfo.py \
revpicommander/revpilogfile.py \
revpicommander/revpioption.py \
@@ -16,7 +16,7 @@ FORMS = include/ui_dev/aclmanager.ui \
include/ui_dev/debugcontrol.ui \
include/ui_dev/debugios.ui \
include/ui_dev/mqttmanager.ui \
include/ui_dev/revpidevelop.ui \
include/ui_dev/files.ui \
include/ui_dev/revpiinfo.ui \
include/ui_dev/revpilogfile.ui \
include/ui_dev/revpioption.ui \