Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • software_public/passoft/sohstationviewer
1 result
Show changes
Commits on Source (8)
Showing
with 785 additions and 42 deletions
......@@ -6,3 +6,8 @@ History
--------
* First release
2023.1.0.1
--------
* Fixed a problem with SOHViewer not fitting on smaller resolutions
package:
name: sohviewer
version: 2023.1.0.0
version: 2023.1.0.1
source:
path: ../
......
......@@ -51,6 +51,6 @@ setup(
name='sohstationviewer',
packages=find_packages(include=['sohstationviewer*']),
url='https://git.passcal.nmt.edu/software_public/passoft/sohstationviewer',
version='2023.1.0.0',
version='2023.1.0.1',
zip_safe=False,
)
from typing import Literal
# The current version of SOHStationViewer
SOFTWARE_VERSION = '2023.1.0.0'
SOFTWARE_VERSION = '2023.1.0.1'
# waveform pattern
WF_1ST = 'A-HLM-V'
......
......@@ -160,3 +160,35 @@ def get_color_ranges():
clr_labels[idx].append("+/- {:,} counts".format(cnt))
clr_labels[idx].append("> {:,} counts".format(cnt))
return range_names, all_square_counts, clr_labels
def create_assign_string_for_db_query(col: str, val: str) -> str:
"""
Create assign db string that assign value in single quote signs if val is
a string or to NULL if val is empty str
:param col: column name 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 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 all info of a param from DB
sql = f"SELECT * FROM Parameters WHERE param='{param}'"
param_info = execute_db_dict(sql)[0]
return param_info
sohstationviewer/images/edit_icon_black_background.png

1.14 KiB

sohstationviewer/images/edit_icon_white_background.png

7.12 KiB

......@@ -6,6 +6,7 @@ import traceback
from pathlib import Path
from PySide2 import QtWidgets
from PySide2.QtGui import QGuiApplication
from PySide2.QtWidgets import QMessageBox
from sohstationviewer.view.main_window import MainWindow
......@@ -14,7 +15,6 @@ from sohstationviewer.conf.config_processor import (
BadConfigError,
)
# Enable Layer-backing for MacOs version >= 11
# Only needed if using the pyside2 library with version>=5.15.
# Layer-backing is always enabled in pyside6.
......@@ -26,47 +26,91 @@ if os_name == 'macOS':
os.environ['QT_MAC_WANTS_LAYER'] = '1'
def main():
# Change the working directory so that relative paths work correctly.
def fix_relative_paths() -> None:
"""
Change the working directory so that the relative paths in the code work
correctly.
"""
current_file_path = os.path.abspath(__file__)
current_file_dir = Path(current_file_path).parent
os.chdir(current_file_dir)
def resize_windows(main_window: MainWindow):
"""
Resize the plotting windows in the program so that they fit well on all
screen resolutions.
"""
screen_size = QtWidgets.QApplication.primaryScreen().size().toTuple()
screen_width, screen_height = screen_size
main_window.resize(screen_width * 1, screen_height * 1)
main_window.waveform_dlg.resize(screen_width * (2 / 3),
screen_height * (2 / 3))
main_window.tps_dlg.resize(screen_width * (2 / 3), screen_height * (2 / 3))
main_right_x = (main_window.x() + main_window.frameSize().width())
# This offset is based on the hard-coded geometry previously assigned to
# the waveform and TPS dialogs
wf_tps_x_offset = 50
# We are moving the TPS dialog so that it is slightly offset from the right
# edge of the main window
tps_dlg_x = main_right_x - main_window.tps_dlg.width() - wf_tps_x_offset
wf_tps_y = 50
main_window.waveform_dlg.move(wf_tps_x_offset, wf_tps_y)
main_window.tps_dlg.move(tps_dlg_x, wf_tps_y)
gps_dlg_y = main_window.height() / 5
main_window.gps_dialog.move(main_window.gps_dialog.y(), gps_dlg_y)
def check_if_user_want_to_reset_config() -> bool:
"""
Show a dialog asking the user if they want to reset the config.
:return: whether the user wants to reset the config.
"""
bad_config_dialog = QMessageBox()
bad_config_dialog.setText('Something went wrong when reading the '
'config.')
bad_config_dialog.setDetailedText(traceback.format_exc())
bad_config_dialog.setInformativeText('Do you want to reset the config '
'file?')
bad_config_dialog.setStandardButtons(QMessageBox.Ok |
QMessageBox.Close)
bad_config_dialog.setDefaultButton(QMessageBox.Ok)
bad_config_dialog.setIcon(QMessageBox.Critical)
reset_choice = bad_config_dialog.exec_()
return reset_choice == QMessageBox.Ok
def main():
# Change the working directory so that relative paths work correctly.
fix_relative_paths()
app = QtWidgets.QApplication(sys.argv)
wnd = MainWindow()
config = ConfigProcessor()
config.load_config()
need_reset = False
do_reset = None
try:
config.validate_config()
config.apply_config(wnd)
except (BadConfigError, ValueError) as e:
bad_config_dialog = QMessageBox()
bad_config_dialog.setText('Something went wrong when reading the '
'config.')
bad_config_dialog.setDetailedText(traceback.format_exc())
bad_config_dialog.setInformativeText('Do you want to reset the config '
'file?')
bad_config_dialog.setStandardButtons(QMessageBox.Ok |
QMessageBox.Close)
bad_config_dialog.setDefaultButton(QMessageBox.Ok)
bad_config_dialog.setIcon(QMessageBox.Critical)
reset_choice = bad_config_dialog.exec_()
if reset_choice == QMessageBox.Ok:
need_reset = True
else:
sys.exit(1)
if need_reset:
do_reset = check_if_user_want_to_reset_config()
if do_reset:
try:
config.reset()
except OSError:
QMessageBox.critical(None, 'Cannot reset config',
'Config file cannot be reset. Please '
'ensure that it is not opened in another '
'program.',
'Config file cannot be reset. Please ensure '
'that it is not opened in another program.',
QMessageBox.Close)
sys.exit(1)
elif do_reset is not None:
sys.exit(1)
config.apply_config(wnd)
resize_windows(wnd)
wnd.show()
sys.exit(app.exec_())
......
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_())
import sys
import platform
import os
from typing import Optional, Dict
from PySide2 import QtWidgets
from PySide2.QtWidgets import QWidget, QDialog, QLineEdit
from sohstationviewer.view.util.plot_func_names import plot_functions
from sohstationviewer.database.process_db import execute_db
from sohstationviewer.database.extract_data import (
get_param_info, create_assign_string_for_db_query
)
from sohstationviewer.conf.dbSettings import modify_db_path
class EditSingleParamDialog(QDialog):
"""
Dialog to add info for channel not in database or edit the existing channel
"""
def __init__(self, parent: Optional[QWidget],
param: 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.param = param
# # 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(EditSingleParamDialog, self).__init__(parent)
# 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.save_param_btn = QtWidgets.QPushButton(
"SAVE PARAMETER", self)
# button to close dialog without doing anything
self.cancel_btn = QtWidgets.QPushButton('CANCEL', self)
self.setup_ui()
self.set_param_info()
self.connect_signals()
def setup_ui(self) -> None:
self.setWindowTitle(f"Edit Parameter {self.param}")
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
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.save_param_btn, 4, 1, 1, 1)
def connect_signals(self) -> None:
self.plot_type_cbo_box.currentTextChanged.connect(self.set_plot_type)
self.cancel_btn.clicked.connect(self.close)
self.save_param_btn.clicked.connect(self.on_save_param)
def set_param_info(self) -> None:
"""
Fill up all info boxes
"""
self.param_info = get_param_info(self.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_save_param(self):
"""
Save parameter info to Parameters table
"""
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='{self.param}'")
execute_db(sql)
self.close()
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 linesDots. Ex: param: Input power supply current
test = EditSingleParamDialog(None, 'Input power supply current')
# test MultiColorDotsLowerBound. Ex: param:Backup volt
# test = EditSingleParamDialog(None, 'Backup Volt', 'RT130')
# test MultiColorDotsUpperBound. Ex: param:GNSS status
# test = EditSingleParamDialog(None, 'GNSS status')
# test UpDownDots. Ex: param. Ex: param:Net Up/down
# test = EditSingleParamDialog(None, 'Net Up/Down', 'RT130')
# test TriColorLInes. Ex: param. Ex: param:Error/warning
# test = EditSingleParamDialog(None, 'Error/Warning', 'RT130')
test.exec_()
sys.exit(app.exec_())
import sys
import platform
import os
from pathlib import Path
from typing import Optional
from PySide2 import QtWidgets, QtGui, QtCore
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QWidget, QDialog, QTextEdit
from sohstationviewer.view.db_config.value_color_helper.functions import \
convert_value_color_str, prepare_value_color_html
class ValueColorWidget(QTextEdit):
def __init__(self, parent: Optional[QWidget], background: str):
"""
Widget to display valueColors and call a dialog to edit tha value
:param parent: the parent widget
:param background: 'B'/'W': flag indicating background color
"""
QtWidgets.QTextEdit.__init__(self, parent)
self.set_background(background)
# string for value color to be saved in DB
self.value_color_str: str = ''
# dialog that pop up when clicking on edit_button to help edit color
# and value
self.edit_value_color_dialog: Optional[QWidget] = None
# type of channel's plot
self.plot_type: str = ''
self.setReadOnly(True)
# change cursor to Arrow so user know they can't edit directly
self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
# to see all info
self.setFixedHeight(28)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.verticalScrollBar().setDisabled(True)
self.edit_button = QtWidgets.QToolButton(self)
self.edit_button.setCursor(Qt.PointingHandCursor)
current_file_path = os.path.abspath(__file__)
root_path = Path(current_file_path).parent.parent.parent.parent
if background == 'B':
img_file = f"{root_path}/images/edit_icon_black_background.png"
else:
img_file = f"{root_path}/images/edit_icon_white_background.png"
self.edit_button.setIcon(QtGui.QIcon(img_file))
self.edit_button.setStyleSheet(
"background: transparent; border: none;")
self.edit_button.clicked.connect(self.on_edit)
layout = QtWidgets.QHBoxLayout(self)
layout.addWidget(self.edit_button, 0, Qt.AlignRight)
layout.setSpacing(0)
layout.setMargin(5)
def set_background(self, background: str):
"""
Set black background for user to have better feeling how the colors
displayed on black background. Text and PlaceholderText's colors
have to be changed to be readable on the black background too.
:param background: 'B'/'W': sign for background color
"""
palette = self.palette()
if background == 'B':
palette.setColor(QtGui.QPalette.Text, Qt.white)
palette.setColor(QtGui.QPalette.Base, Qt.black)
palette.setColor(QtGui.QPalette.PlaceholderText, Qt.lightGray)
self.setPalette(palette)
def set_value_color(self, plot_type: str, value_color_str: str) \
-> None:
"""
Set value_color_str, value_color_edit_dialog and display value color
string in html to show color for user to have the feeling.
:param plot_type: type of channel's plot
:param value_color_str: string for value color to be saved in DB
"""
self.plot_type = plot_type
# Won't need to convert after database's valueColors are changed
self.value_color_str = convert_value_color_str(
plot_type, value_color_str)
value_color_html = prepare_value_color_html(self.value_color_str)
self.setHtml(value_color_html)
def on_edit(self):
print('edit value color')
class TestDialog(QDialog):
def __init__(self):
super(TestDialog, self).__init__(None)
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
self.value_colorb_widget = ValueColorWidget(self, 'B')
main_layout.addWidget(self.value_colorb_widget)
self.value_colorw_widget = ValueColorWidget(self, 'W')
main_layout.addWidget(self.value_colorw_widget)
# linesDots
self.value_colorb_widget.set_value_color('linesDots', 'L:R|D:G')
self.value_colorw_widget.set_value_color('linesDots', 'L:R|D:G')
# triColorLines
# self.value_colorb_widget.set_value_color(
# 'triColorLines', '-1:M|0:R|1:G')
# self.value_colorw_widget.set_value_color(
# 'triColorLines', '-1:M|0:R|1:G')
# multiColorDotsEqualOnUpperBound
# self.value_colorb_widget.set_value_color(
# 'multiColorDotsEqualOnUpperBound', '0:R|1:Y|2:G|+2:M')
# self.value_colorw_widget.set_value_color(
# 'multiColorDotsEqualOnUpperBound', '0:R|1:Y|2:G|+2:M')
# multiColorDotsEqualOnLowerBound
# self.value_colorb_widget.set_value_color('multiColorDotsEqualOnLowerBound',
# '3:R|3.3:Y|=3.3:G')
# self.value_colorw_widget.set_value_color('multiColorDotsEqualOnLowerBound',
# '3:R|3.3:Y|=3.3:G')
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 = TestDialog()
test.exec_()
sys.exit(app.exec_())
......@@ -3,7 +3,7 @@ import sys
import os
import traceback
from pathlib import Path
from typing import List, Optional, Literal, Iterable
from typing import List, Optional, Literal, Iterable, Any
from PySide2 import QtWidgets, QtCore
from matplotlib.axes import Axes
......@@ -31,7 +31,7 @@ class GPSWidget(QtWidgets.QWidget):
# one point for each coordinate.
self.unique_gps_points: Optional[List[GPSPoint]] = None
self.fig = Figure(figsize=(6, 6), dpi=100)
self.fig = Figure(figsize=(6, 6), dpi=100, facecolor='#ECECEC')
self.canvas = Canvas(self.fig)
self.canvas.mpl_connect('pick_event', self.on_pick_event)
......@@ -156,7 +156,7 @@ class GPSWidget(QtWidgets.QWidget):
self.repaint()
self.tracking_box.clear()
def on_pick_event(self, event) -> None:
def on_pick_event(self, event) -> Any:
"""
On a GPS point being picked, display the data of that point on the
tracking box.
......@@ -172,13 +172,13 @@ class GPSWidget(QtWidgets.QWidget):
# and longitude follows correspondingly.
lat_dir = 'N' if picked_point.latitude > 0 else 'S'
long_dir = 'E' if picked_point.longitude > 0 else 'W'
meta_separator = ' ' * 22
loc_separator = ' ' * 10
meta_separator = ' ' * 7
loc_separator = ' ' * 5
msg = (
f'Mark: {picked_point.last_timemark}{meta_separator}'
f' Mark: {picked_point.last_timemark}{meta_separator}'
f'Fix: {picked_point.fix_type}{meta_separator}'
f'Sats: {picked_point.num_satellite_used}<br>'
f'Lat: {lat_dir}{abs(picked_point.latitude):.6f}{loc_separator}'
f' Lat: {lat_dir}{abs(picked_point.latitude):.6f}{loc_separator}'
f'Long: {long_dir}{abs(picked_point.longitude):.6f}{loc_separator}'
f'Elev: {picked_point.height}{picked_point.height_unit}'
)
......@@ -254,7 +254,7 @@ class GPSDialog(QtWidgets.QWidget):
bottom_layout = QtWidgets.QVBoxLayout()
bottom_layout.addLayout(button_layout)
self.info_text_browser.setFixedHeight(42)
self.info_text_browser.setFixedHeight(45)
bottom_layout.addWidget(self.info_text_browser)
main_layout.addLayout(bottom_layout)
......
......@@ -40,7 +40,6 @@ class TimePowerSquaredDialog(QtWidgets.QWidget):
"""
self.date_format: str = 'YYYY-MM-DD'
self.setGeometry(50, 50, 1200, 800)
self.setWindowTitle("TPS Plot")
main_layout = QtWidgets.QVBoxLayout()
......
......@@ -231,7 +231,7 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
ax = self.create_axes(self.plotting_bot, plot_h)
ax.spines[['right', 'left', 'top', 'bottom']].set_visible(False)
ax.text(
-0.12, 1,
-0.15, 1,
f"{get_seismic_chan_label(chan_id)} {c_data['samplerate']}sps",
horizontalalignment='left',
verticalalignment='top',
......
......@@ -77,7 +77,6 @@ class WaveformDialog(QtWidgets.QWidget):
date_format: format for date
"""
self.date_format: str = 'YYYY-MM-DD'
self.setGeometry(50, 10, 1600, 700)
self.setWindowTitle("Raw Data Plot")
main_layout = QtWidgets.QVBoxLayout()
......
......@@ -7,6 +7,7 @@ from PySide2.QtWidgets import (
QMainWindow, QWidget, QTextBrowser, QPushButton, QLineEdit, QDateEdit,
QListWidget, QCheckBox, QRadioButton, QMenu, QLabel, QFrame,
QVBoxLayout, QHBoxLayout, QGridLayout, QAbstractItemView, QButtonGroup,
QSplitter,
)
from PySide2.QtWidgets import (
QAction, QActionGroup, QShortcut
......@@ -279,7 +280,6 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with
"""
self.main_window = main_window
main_window.resize(1798, 1110)
main_window.setWindowTitle("SOH Station Viewer")
self.central_widget = QWidget(main_window)
main_window.setCentralWidget(self.central_widget)
......@@ -294,8 +294,6 @@ class UIMainWindow(object):
self.set_first_row(main_layout)
self.set_second_row(main_layout)
self.tracking_info_text_browser.setFixedHeight(80)
main_layout.addWidget(self.tracking_info_text_browser)
self.create_menu_bar(main_window)
self.connect_signals(main_window)
self.create_shortcuts(main_window)
......@@ -352,7 +350,7 @@ class UIMainWindow(object):
left_widget = QWidget(self.central_widget)
h_layout.addWidget(left_widget)
left_widget.setFixedWidth(240)
left_widget.setMinimumHeight(650)
# left_widget.setMinimumHeight(650)
left_layout = QVBoxLayout()
left_layout.setContentsMargins(0, 0, 0, 0)
left_layout.setSpacing(0)
......@@ -360,12 +358,22 @@ class UIMainWindow(object):
self.set_control_column(left_layout)
plot_splitter = QSplitter(QtCore.Qt.Orientation.Vertical)
h_layout.addWidget(plot_splitter, 2)
self.plotting_widget = SOHWidget(self.main_window,
self.tracking_info_text_browser,
'SOH',
self.main_window)
plot_splitter.addWidget(self.plotting_widget)
h_layout.addWidget(self.plotting_widget, 2)
self.tracking_info_text_browser.setMinimumHeight(60)
self.tracking_info_text_browser.setMaximumHeight(80)
plot_splitter.addWidget(self.tracking_info_text_browser)
tracking_browser_idx = plot_splitter.indexOf(
self.tracking_info_text_browser
)
plot_splitter.setCollapsible(tracking_browser_idx, False)
def set_control_column(self, left_layout):
"""
......