Skip to content
Snippets Groups Projects
Commit 986e84bc authored by Lan Dam's avatar Lan Dam
Browse files

implement AddEditSingleChannelDialog with QLineEdit for valueColors

parent 922b36a5
No related branches found
No related tags found
1 merge request!211Implement dialog to add/edit a single channel in database
Pipeline #3182 passed with stage
in 4 minutes and 35 seconds
import sys
import platform
import os
from typing import Optional, Dict
from PySide2 import QtWidgets, QtGui
from PySide2.QtWidgets import QWidget, QDialog, QLineEdit
from sohstationviewer.view.util.plot_func_names import plot_functions
from sohstationviewer.view.db_config.add_edit_single_channel_helper import (
get_params, get_channel_info, get_param_info)
def get_db_str_with_null(col, val):
"""
Create assign db string that assign to NULL if val is empty str
:param col: column in the db table
:param val: value to be assigned to the column
:return: the assign db string
"""
return f"{col}='{val}'" if val != '' else f"{col}=NULL"
def add_separation_line(layout):
"""
Add a line for separation to the given layout.
:param layout: QLayout - the layout that contains the line
"""
label = QtWidgets.QLabel()
label.setFrameStyle(QtWidgets.QFrame.HLine | QtWidgets.QFrame.Sunken)
label.setLineWidth(1)
layout.addWidget(label)
class AddEditSingleChannelDialog(QDialog):
def __init__(self, parent: Optional[QWidget],
chan_id: str, data_type: str):
"""
Dialog to add info for channel not in database or edit the existing
channel
:param parent: the parent widget
:param chan_id: name of channel to be added/edited
:param data_type: type of the data being processed
"""
self.parent = parent
# name of the channel
self.chan_id = chan_id
# data_type of the channel
self.data_type = data_type
# True if this channel isn't in DB yet
self.new = False
# To skip on_param_chkbox_changed() when param is changed by the
# program at the beginning
self.param_changed_by_signal = False
# database info of the channel
self.channel_info: Dict = {}
# database info of the channel's parameter
self.param_info: Dict = {}
super(AddEditSingleChannelDialog, self).__init__(parent)
# short name of thechannel
self.name_lnedit = QtWidgets.QLineEdit(self)
# description added to channel name
self.label_lnedit = QtWidgets.QLineEdit(self)
self.label_lnedit.setPlaceholderText(
"added to channel name to be displayed")
# convert factor to change from count to actual value
self.convesion_lnedit = QtWidgets.QLineEdit(self)
self.convesion_lnedit.setPlaceholderText(
"to convert from count to actual value"
)
validator = QtGui.QDoubleValidator(0.0, 5.0, 6)
validator.setNotation(QtGui.QDoubleValidator.StandardNotation)
self.convesion_lnedit.setValidator(validator)
self.convesion_lnedit.setText('1')
# channel's unit
self.unit_lnedit = QtWidgets.QLineEdit(self)
# dedimal point for channel's value
self.fix_point_spnbox = QtWidgets.QSpinBox()
self.fix_point_spnbox.setToolTip("Decimal point that allow in display")
self.fix_point_spnbox.setMinimum(0)
self.fix_point_spnbox.setMaximum(5)
# data_type
self.data_type_lnedit = QtWidgets.QLineEdit(self)
self.data_type_lnedit.setReadOnly(True)
# channel's parameter which decides how channel is plotted
self.param_cbobox = QtWidgets.QComboBox(self)
self.param_cbobox.addItems(get_params())
# parameter's plot type which decides the shape of the plot
self.plot_type_cbo_box = QtWidgets.QComboBox(self)
self.plot_type_cbo_box.addItems([""] + list(plot_functions.keys()))
# value color in black mode
self.value_colorb_widget = QLineEdit(self)
self.value_colorb_widget.setPlaceholderText(
"Click edit button to add value color string")
self.value_colorb_widget.setToolTip("Priority from left to right")
# value, color in white mode
self.value_colorw_widget = QLineEdit(self)
self.value_colorw_widget.setPlaceholderText(
"Click edit button to add value color string")
self.value_colorw_widget.setToolTip("Priority from left to right")
# height of the plot
self.height_spnbox = QtWidgets.QSpinBox()
self.height_spnbox.setMinimum(0)
self.height_spnbox.setMaximum(8)
self.height_spnbox.setToolTip("Relative height of the plot")
# button to save change to DB
self.submit_btn = QtWidgets.QPushButton("SUBMIT", self)
# button to close dialog without doing anything
self.cancel_btn = QtWidgets.QPushButton('CANCEL', self)
self.setup_ui()
self.set_channel_info()
self.connect_signals()
def setup_ui(self) -> None:
dlg_type = 'Add' if 'DEFAULT' in self.chan_id else 'Edit'
self.setWindowTitle(f"{dlg_type} channel {self.chan_id}"
f" - {self.data_type}")
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
instruction = (
f"This dialog is to {dlg_type} channel {self.chan_id}. "
"To apply changes, click RePlot.")
main_layout.addWidget(QtWidgets.QLabel(instruction))
channel_layout = QtWidgets.QGridLayout()
main_layout.addLayout(channel_layout)
channel_layout.addWidget(QtWidgets.QLabel('Name'), 0, 0, 1, 1)
channel_layout.addWidget(self.name_lnedit, 0, 1, 1, 1)
self.name_lnedit.setReadOnly(True)
channel_layout.addWidget(QtWidgets.QLabel('Label'), 1, 0, 1, 1)
channel_layout.addWidget(self.label_lnedit, 1, 1, 1, 1)
channel_layout.addWidget(QtWidgets.QLabel('Conversion'), 2, 0, 1, 1)
channel_layout.addWidget(self.convesion_lnedit, 2, 1, 1, 1)
channel_layout.addWidget(QtWidgets.QLabel('Unit'), 3, 0, 1, 1)
channel_layout.addWidget(self.unit_lnedit, 3, 1, 1, 1)
channel_layout.addWidget(QtWidgets.QLabel('Fix Point'), 4, 0, 1, 1)
channel_layout.addWidget(self.fix_point_spnbox, 4, 1, 1, 1)
channel_layout.addWidget(QtWidgets.QLabel('Data Type'), 5, 0, 1, 1)
channel_layout.addWidget(self.data_type_lnedit, 5, 1, 1, 1)
channel_layout.addWidget(QtWidgets.QLabel('Parameter'), 6, 0, 1, 1)
channel_layout.addWidget(self.param_cbobox, 6, 1, 1, 1)
add_separation_line(main_layout)
warning = ("Plotting info that AFFECT other channels that belong to "
"the above parameter.\n"
"BE CAREFUL when you change any info under this line.")
label_widget = QtWidgets.QLabel(warning)
# highlight warning in special colors
label_widget.setStyleSheet("QLabel {background-color: red;"
" color: white;"
" padding: 5px}")
label_widget.setFixedWidth(450)
label_widget.setWordWrap(True)
main_layout.addWidget(label_widget)
param_layout = QtWidgets.QGridLayout()
main_layout.addLayout(param_layout)
param_layout.addWidget(QtWidgets.QLabel('Plot Type'), 0, 0, 1, 1)
param_layout.addWidget(self.plot_type_cbo_box, 0, 1, 1, 1)
param_layout.addWidget(QtWidgets.QLabel(
'Value Color (black)'), 1, 0, 1, 1)
param_layout.addWidget(self.value_colorb_widget, 1, 1, 1, 1)
param_layout.addWidget(QtWidgets.QLabel(
'Value Color (white)'), 2, 0, 1, 1)
param_layout.addWidget(self.value_colorw_widget, 2, 1, 1, 1)
param_layout.addWidget(QtWidgets.QLabel('Height'), 3, 0, 1, 1)
param_layout.addWidget(self.height_spnbox, 3, 1, 1, 1)
param_layout.addWidget(self.cancel_btn, 4, 0, 1, 1)
param_layout.addWidget(self.submit_btn, 4, 1, 1, 1)
def connect_signals(self) -> None:
self.param_cbobox.currentTextChanged.connect(
lambda new_param, old_param=self.param_cbobox.currentText():
self.on_param_chkbox_changed(new_param, old_param))
self.plot_type_cbo_box.currentTextChanged.connect(self.set_plot_type)
self.cancel_btn.clicked.connect(self.close)
self.submit_btn.clicked.connect(self.on_submit)
def set_channel_info(self):
"""
Add all Channel related info according to information got from DB.
In case Channel isn't in the DB, use the info of DEFAULT channel.
Call set_param_info to set Parameter related info.
"""
try:
self.channel_info = get_channel_info(self.chan_id, self.data_type)
except IndexError:
self.new = True
self.channel_info = get_channel_info('DEFAULT', 'Default')
self.name_lnedit.setText(self.chan_id)
self.label_lnedit.setText(self.channel_info['label'])
self.convesion_lnedit.setText(
str(float(self.channel_info['convertFactor'])))
self.unit_lnedit.setText(self.channel_info['unit'])
if self.channel_info['fixPoint'] is not None:
self.fix_point_spnbox.setValue(self.channel_info['fixPoint'])
self.data_type_lnedit.setText(self.data_type)
self.param_cbobox.setCurrentText(self.channel_info['param'])
self.set_param_info(self.channel_info['param'])
def on_param_chkbox_changed(self, new_param: str, old_param: str) -> None:
"""
When changing text in param_chkbox, give warning if channel exists.
param_changed_by_signal is given to prevent recall on this function
from changing back to old value of param.
:param new_param: the new selected value of param
:param old_param: the previous value of param
:return:
"""
if self.param_changed_by_signal:
self.param_changed_by_signal = False
return
if not self.new:
msg = ("ARE YOU SURE YOU WANT TO CHANGE PARAMETER FOR CHANNEL "
f"'{self.chan_id}'?")
result = QtWidgets.QMessageBox.question(
self, "Confirmation", msg,
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
if result == QtWidgets.QMessageBox.No:
self.param_changed_by_signal = True
self.param_cbobox.setCurrentText(old_param)
return
self.set_param_info(new_param)
def set_param_info(self, param: str) -> None:
"""
Add all Parameter related info. Value Color strings depend on Plot Type
and will be fill in set_plot_type()
:param param: name of Parameter
"""
self.param_info = get_param_info(param)
self.set_plot_type(self.param_info['plotType'])
self.height_spnbox.setValue(self.param_info['height'])
def set_plot_type(self, plot_type: str) -> None:
"""
Add Plot Type, Value Color strings.
If there is no Plot Type, no Value Color or Height because no plot.
:param plot_type: name of Plot Type
"""
if plot_type in ["", None]:
self.plot_type_cbo_box.setCurrentText('')
self.value_colorb_widget.setEnabled(False)
self.value_colorb_widget.clear()
self.value_colorw_widget.setEnabled(False)
self.value_colorw_widget.clear()
self.height_spnbox.setValue(0)
else:
self.plot_type_cbo_box.setCurrentText(plot_type)
value_color_b = self.param_info['valueColorsB']
value_color_w = self.param_info['valueColorsW']
self.value_colorb_widget.setText(value_color_b)
self.value_colorw_widget.setText(value_color_w)
def on_submit(self):
"""
Save info from GUI to DB
"""
if self.param_cbobox.currentText() == 'Default':
QtWidgets.QMessageBox.information(
self, 'Warning', 'A real parameter need to be assigned.')
return
param = f"param='{self.param_cbobox.currentText()}'"
self.update_para_info(param)
if self.new:
self.insert_channel_info()
else:
self.update_channel_info()
self.close()
def update_para_info(self, param):
"""
Save parameter related info to Parameters table
:param param: param condition string
"""
plot_type = get_db_str_with_null(
'plotType', self.plot_type_cbo_box.currentText())
value_colorb = get_db_str_with_null(
'valueColorsB', self.value_colorb_widget.text())
value_colorw = get_db_str_with_null(
'valueColorsW', self.value_colorw_widget.text())
height = f"height={self.height_spnbox.value()}"
sql = (f"UPDATE Parameters SET {plot_type}, {value_colorb}, "
f"{value_colorw}, {height} WHERE {param}")
print('NEED TO EXECUTE: param sql:', sql)
def insert_channel_info(self):
sql = ("INSERT INTO Channels VALUES ("
f"'{self.name_lnedit.text()}', "
f"'{self.label_lnedit.text()}', "
f"'{self.param_cbobox.currentText()}', "
f"NULL, " # linkedChan for RT130 only and won't be changed
f"{self.convesion_lnedit.text()}, "
f"'{self.unit_lnedit.text()}', "
f"{self.fix_point_spnbox.value()}, "
f"'{self.data_type_lnedit.text()}')")
print('NEED TO EXECUTE: insert channel sql:', sql)
def update_channel_info(self):
channel = f"channel='{self.name_lnedit.text()}'"
label = f"label='{self.label_lnedit.text()}'"
param = f"param='{self.param_cbobox.currentText()}'"
linked_chan = "linkedChan=NULL"
convert_factor = f"convertFactor={self.convesion_lnedit.text()}"
unit = f"unit='{self.unit_lnedit.text()}'"
fix_point = f"fixPoint={self.fix_point_spnbox.value()}"
data_type = f"dataType='{self.data_type_lnedit.text()}'"
sql = (f"UPDATE Channels SET {label}, {param}, {linked_chan}, "
f"{convert_factor}, {unit}, {fix_point}, {data_type} "
f"WHERE {channel}")
print('NEED TO EXECUTE: update channel sql:', sql)
if __name__ == '__main__':
os_name, version, *_ = platform.platform().split('-')
if os_name == 'macOS':
os.environ['QT_MAC_WANTS_LAYER'] = '1'
app = QtWidgets.QApplication(sys.argv)
# test new channel
# test = AddEditSingleChannelDialog(None, 'VEE', 'Q330')
# test linesDots. Ex: param: Input power supply current
# test = AddEditSingleChannelDialog(None, 'VEC', 'Q330')
# test MultiColorDotsLowerBound. Ex: param:Backup volt
# test = AddEditSingleChannelDialog(None, 'Backup Volt', 'RT130')
# test MultiColorDotsUpperBound. Ex: param:GNSS Status
test = AddEditSingleChannelDialog(None, 'VST', 'Pegasus')
# test UpDownDots. Ex: param. Ex: param:Net Up/down
# test = AddEditSingleChannelDialog(None, 'Net Up/Down', 'RT130')
# test TriColorLInes. Ex: param. Ex: param:Error/warning
# test = AddEditSingleChannelDialog(None, 'Error/Warning', 'RT130')
test.exec_()
sys.exit(app.exec_())
from sohstationviewer.database.process_db import execute_db_dict, execute_db
def get_params():
# get parameter list from database
param_rows = execute_db("SELECT param from parameters")
return sorted([d[0] for d in param_rows])
def get_channel_info(chan_id: str, data_type: str):
# get channel info from DB
sql = f"SELECT * FROM Channels " \
f"WHERE channel='{chan_id}' AND dataType='{data_type}'"
chan_info = execute_db_dict(sql)[0]
return chan_info
def get_param_info(param: str):
# get param info from DB
sql = f"SELECT * FROM Parameters WHERE param='{param}'"
param_info = execute_db_dict(sql)[0]
return param_info
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment