Skip to content
Snippets Groups Projects

Implement dialog to add/edit a single channel in database

Merged Lan Dam requested to merge i69-add-edit-single-channel-dialog into master
1 file
+ 20
21
Compare changes
  • Side-by-side
  • Inline
 
import sys
 
import platform
 
import os
 
from typing import Optional, Dict
 
 
from PySide2 import QtWidgets, QtGui
 
from PySide2.QtWidgets import QWidget, QDialog
 
 
from sohstationviewer.database.process_db import execute_db
 
from sohstationviewer.database.extract_data import (
 
get_params, get_channel_info, create_assign_string_for_db_query
 
)
 
 
from sohstationviewer.view.db_config.edit_single_param_dialog import \
 
EditSingleParamDialog
 
 
from sohstationviewer.conf.dbSettings import modify_db_path
 
 
 
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):
 
"""
 
Dialog to add info for channel not in database or edit the existing channel
 
"""
 
def __init__(self, parent: Optional[QWidget],
 
chan_id: str, data_type: str):
 
"""
 
: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
 
 
# param of the channel
 
self.param: str = 'Default'
 
# True if this channel isn't in DB yet
 
self.is_new_db_channel: bool = False
 
# To skip on_param_chkbox_changed() when param is changed by the
 
# program at the beginning
 
self.param_changed_by_signal: bool = 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 the channel
 
self.channel_name_lnedit = QtWidgets.QLineEdit(self)
 
self.channel_name_lnedit.setReadOnly(True)
 
 
# 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.conversion_lnedit = QtWidgets.QLineEdit(self)
 
self.conversion_lnedit.setPlaceholderText(
 
"to convert from count to actual value"
 
)
 
validator = QtGui.QDoubleValidator(0.0, 5.0, 6)
 
validator.setNotation(QtGui.QDoubleValidator.StandardNotation)
 
self.conversion_lnedit.setValidator(validator)
 
self.conversion_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())
 
 
# button to edit param
 
self.edit_param_btn = QtWidgets.QPushButton("EDIT PARAMETER", self)
 
# button to save changes to DB
 
self.save_btn = QtWidgets.QPushButton("SAVE CHANNEL", self)
 
# button to save changes and replot channel
 
self.save_replot_btn = QtWidgets.QPushButton("SAVE & REPLOT", 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}.\n"
 
"Parameter need to be any value different than 'Default' to be "
 
"saved.")
 
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.channel_name_lnedit, 0, 1, 1, 1)
 
 
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.conversion_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)
 
 
channel_layout.addWidget(self.save_btn, 7, 0, 1, 1)
 
channel_layout.addWidget(self.save_replot_btn, 7, 1, 1, 1)
 
 
channel_layout.addWidget(self.edit_param_btn, 8, 1, 1, 1)
 
channel_layout.addWidget(self.cancel_btn, 8, 0, 1, 1)
 
self.save_replot_btn.setFocus()
 
 
def connect_signals(self) -> None:
 
self.param_cbobox.currentTextChanged.connect(
 
self.on_param_cbobox_changed)
 
self.cancel_btn.clicked.connect(self.close)
 
self.save_btn.clicked.connect(self.on_save)
 
self.save_replot_btn.clicked.connect(self.on_save_replot)
 
self.edit_param_btn.clicked.connect(self.on_edit_param)
 
 
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.is_new_db_channel = True
 
self.channel_info = get_channel_info('DEFAULT', 'Default')
 
 
self.channel_name_lnedit.setText(self.chan_id)
 
 
self.label_lnedit.setText(self.channel_info['label'])
 
 
self.conversion_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.param = self.channel_info['param']
 
self.set_buttons_enabled()
 
 
def on_param_cbobox_changed(self):
 
"""
 
+ Check self.param_changed_by_signal to make sure the signal come from
 
user selecting a parameter from param_cbobox, not the signal from
 
changing back to original value when condition not pass fo the set
 
value
 
+ Not allow parameter 'Default' to be select because it is only the
 
parameter for the channel that has no record in DB
 
+ If the channel already has a record in DB, give a warning when user's
 
trying to change its parameter.
 
"""
 
if self.param_changed_by_signal:
 
self.param_changed_by_signal = False
 
return
 
new_param = self.param_cbobox.currentText()
 
if new_param == 'Default':
 
# Parameter Default is only for channel that has no record in DB.
 
# So it isn't allowed to be selected
 
self.param_changed_by_signal = True
 
self.param_cbobox.setCurrentText(self.param)
 
return
 
if not self.is_new_db_channel:
 
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(self.param)
 
return
 
self.param = new_param
 
self.set_buttons_enabled()
 
 
def save(self):
 
"""
 
Save info from GUI to DB
 
"""
 
if self.is_new_db_channel:
 
self.insert_channel_info()
 
else:
 
self.update_channel_info()
 
 
def on_save(self):
 
"""
 
Save new channel info to DB
 
"""
 
self.save()
 
self.close()
 
 
def on_save_replot(self):
 
"""
 
Save new channel info to DB
 
TODO: Replot the channel in the plotting area
 
"""
 
self.save()
 
print("Do REPLOT")
 
self.close()
 
 
def set_buttons_enabled(self):
 
"""
 
Disable the 3 buttons to save and to edit parameters so that user are
 
forced to change param before they want to continue.
 
"""
 
if self.param == 'Default':
 
self.edit_param_btn.setEnabled(False)
 
self.save_btn.setEnabled(False)
 
self.save_replot_btn.setEnabled(False)
 
else:
 
self.edit_param_btn.setEnabled(True)
 
self.save_btn.setEnabled(True)
 
self.save_replot_btn.setEnabled(True)
 
 
def on_edit_param(self):
 
"""
 
Give user a warning when they want to change parameter's info then
 
open EditSingleParamDialog for user to edit parameter's info after
 
they give their confirmation.
 
"""
 
msg = ("Changing parameter will affect all of other channels that "
 
"have the same parameter.\n\n"
 
"Are you sure you want to continue?")
 
result = QtWidgets.QMessageBox.question(
 
self, "Confirmation", msg,
 
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
 
if result == QtWidgets.QMessageBox.No:
 
return
 
win = EditSingleParamDialog(self, self.param_cbobox.currentText())
 
win.exec_()
 
 
def update_para_info(self, param):
 
"""
 
Save parameter related info to Parameters table
 
:param param: param condition string
 
"""
 
plot_type = create_assign_string_for_db_query(
 
'plotType', self.plot_type_cbo_box.currentText())
 
value_colorb = create_assign_string_for_db_query(
 
'valueColorsB', self.value_colorb_widget.text())
 
value_colorw = create_assign_string_for_db_query(
 
'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}")
 
execute_db(sql)
 
 
def insert_channel_info(self):
 
sql = ("INSERT INTO Channels VALUES ("
 
f"'{self.channel_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.conversion_lnedit.text()}, "
 
f"'{self.unit_lnedit.text()}', "
 
f"{self.fix_point_spnbox.value()}, "
 
f"'{self.data_type_lnedit.text()}')")
 
execute_db(sql)
 
 
def update_channel_info(self):
 
channel = f"channel='{self.channel_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.conversion_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}")
 
execute_db(sql)
 
 
 
if __name__ == '__main__':
 
modify_db_path()
 
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_())
Loading