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
......@@ -26,8 +26,8 @@ class WaveformWidget(plotting_widget.PlottingWidget):
finished = QtCore.Signal()
def __init__(self, parent, tracking_box, *args):
super().__init__(parent, tracking_box)
def __init__(self, parent, tracking_box, name):
super().__init__(parent, tracking_box, name)
self.data_processors: List[WaveformChannelProcessor] = []
......@@ -83,12 +83,20 @@ class WaveformWidget(plotting_widget.PlottingWidget):
self.min_x = max(data_time[0], start_tm)
self.max_x = min(data_time[1], end_tm)
self.plot_total = len(self.plotting_data1) + len(self.plotting_data2)
title = get_title(key, self.min_x, self.max_x, self.date_mode)
if waveform_data == {}:
title = "NO WAVEFORM DATA TO DISPLAY."
self.processing_log.append("No waveform data to display.")
else:
title = get_title(key, self.min_x, self.max_x, self.date_mode)
self.plotting_bot = const.BOTTOM
self.plotting_bot_pixel = const.BOTTOM_PX
self.axes = []
self.timestamp_bar_top = self.plotting_axes.add_timestamp_bar(0.003)
self.plotting_axes.set_title(title)
if waveform_data == {}:
return False
else:
return True
def plot_channels(self, start_tm, end_tm, key,
data_time, time_ticks_total,
......@@ -115,9 +123,12 @@ class WaveformWidget(plotting_widget.PlottingWidget):
self.is_working = True
start_msg = 'Plotting waveform data...'
display_tracking_info(self.tracking_box, start_msg, 'info')
self.init_plot(start_tm, end_tm, key,
data_time, time_ticks_total,
waveform_data, mass_pos_data)
ret = self.init_plot(start_tm, end_tm, key,
data_time, time_ticks_total,
waveform_data, mass_pos_data)
if not ret:
self.draw()
return
self.create_waveform_channel_processors()
self.process_channel()
......@@ -354,7 +365,7 @@ class WaveformDialog(QtWidgets.QWidget):
mass position channel
"""
self.plotting_widget = WaveformWidget(
self, self.info_text_browser)
self, self.info_text_browser, 'RAWWidget')
self.plotting_widget.finished.connect(self.plot_finished)
main_layout.addWidget(self.plotting_widget, 2)
......
# UI and connectSignals for main_window
from typing import Union, List
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2 import QtCore, QtGui
from PySide2.QtWidgets import (
QMainWindow, QWidget, QTextBrowser, QPushButton, QLineEdit, QDateEdit,
QListWidget, QCheckBox, QRadioButton, QMenu, QAction, QLabel, QFrame,
QVBoxLayout, QHBoxLayout, QGridLayout, QAbstractItemView, QShortcut,
QActionGroup
)
from sohstationviewer.view.calendar.calendar_widget import CalendarWidget
......@@ -14,8 +21,8 @@ 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 = QLabel()
label.setFrameStyle(QFrame.HLine | QFrame.Sunken)
label.setLineWidth(1)
layout.addWidget(label)
......@@ -27,242 +34,244 @@ class UIMainWindow(object):
"""
super().__init__()
"""
main_window: QMainWindow - Main window that contains main widget
and menus
main_window: Main window that contains main widget and menus
"""
self.main_window = None
self.main_window: Union[QMainWindow, None] = None
"""
central_widget: QWidget - Main widget that contains all widgets
central_widget: Main widget that contains all widgets
"""
self.central_widget = None
self.central_widget: Union[QWidget, None] = None
"""
tracking_info_text_browser: QTextBrowser - textbox that can set color
and background color for displaying tracking info of processing
data
tracking_info_text_browser: textbox that can set color and background
color for displaying tracking info of processing data
"""
self.tracking_info_text_browser = None
self.tracking_info_text_browser: Union[QTextBrowser, None] = None
# =================== top row ========================
"""
curr_dir_button: QPushButton - Button that helps browse to the
directory for selecting data set
curr_dir_button: Button that helps browse to the directory for
selecting data set
"""
self.curr_dir_button = None
self.curr_dir_button: Union[QPushButton, None] = None
"""
curr_dir_line_edit: QLineEdit - textbox that display the current
directory
curr_dir_line_edit: textbox that display the current directory
"""
self.curr_dir_line_edit = None
self.curr_dir_line_edit: Union[QLineEdit, None] = None
"""
time_from_date_edit: QDateEdit - to help user select start day to read
time_from_date_edit: to help user select start day to read
from the data set
"""
self.time_from_date_edit = None
self.time_from_date_edit: Union[QDateEdit, None] = None
"""
time_to_date_edit: QDateEdit - to help user select end day to read
time_to_date_edit: to help user select end day to read
from the data set
"""
self.time_to_date_edit = None
self.time_to_date_edit: Union[QDateEdit, None] = None
# ======================= second row ======================
"""
plotting_widget: PlottingWidget - Widget for plotting data
plotting_widget: Widget for plotting data
"""
self.plotting_widget = None
self.plotting_widget: Union[SOHWidget, None] = None
"""
open_files_list: QListWidget - Widget that display the list of
directories in current directory for user to select
open_files_list: Widget that display the list of directories in
current directory for user to select
"""
self.open_files_list = None
self.open_files_list: Union[QListWidget, None] = None
"""
inside_dir_check_box: QCheckBox - to tell SOHView if current directory
inside_dir_check_box: to tell SOHView if current directory
is inside the data set or the parent of the data set
"""
self.inside_dir_check_box = None
self.inside_dir_check_box: Union[QCheckBox, None] = None
"""
search_line_edit: QLineEdit - textbox for user to search in
search_line_edit: textbox for user to search in
self.open_file_list
"""
self.search_line_edit = None
self.search_line_edit: Union[QLineEdit, None] = None
"""
clear_button: QPushButton - clear search_line_edit
clear_button: clear search_line_edit
"""
self.clear_button = None
self.clear_button: Union[QPushButton, None] = None
"""
replot_button: QPushButton - reset plotting without re-loading data
replot_button: reset plotting without re-loading data
"""
self.replot_button = None
self.replot_button: Union[QPushButton, None] = None
"""
file_list_log_check_box: QCheckBox - If checked show only ".log" files
file_list_log_check_box: If checked show only ".log" files
in open_files_list
"""
self.file_list_log_check_box = None
self.file_list_log_check_box: Union[QCheckBox, None] = None
"""
file_list_zip_check_box: QCheckBox - If checked show only ".zip" files
file_list_zip_check_box: If checked show only ".zip" files
in open_files_list
"""
self.file_list_zip_check_box = None
self.file_list_zip_check_box: Union[QCheckBox, None] = None
"""
background_black_radio_button: QRadioButton - If selected,
plotting_widget will turn to black mode
background_black_radio_button: If selected, plotting_widget will turn
to black mode
"""
self.background_black_radio_button = None
self.background_black_radio_button: Union[QRadioButton, None] = None
"""
background_white_radio_button: QRadioButton - If selected,
plotting_widget will turn to white mode
background_white_radio_button: If selected, plotting_widget will turn
to white mode
"""
self.background_white_radio_button = None
self.background_white_radio_button: Union[QRadioButton, None] = None
"""
detect_gap_check_box: QCheckBox - If checked, gap bar will be displayed
detect_gap_check_box: If checked, gap bar will be displayed
"""
self.detect_gap_check_box = None
self.detect_gap_check_box: Union[QCheckBox, None] = None
"""
gap_len_line_edit: QLineEdit - For user to enter len of gap to detect
gap_len_line_edit: For user to enter len of gap to detect
with unit minute (m)
"""
self.gap_len_line_edit = None
self.gap_len_line_edit: Union[QLineEdit, None] = None
"""
mass_pos_123_check_box: QCheckBox: If checked, mass position 1,2,3
will be read
"""
self.mass_pos_123_check_box = None
self.mass_pos_123_check_box: Union[QCheckBox, None] = None
"""
mass_pos_456_check_box: QCheckBox: If checked, mass position 1,2,3
mass_pos_456_check_box: If checked, mass position 1,2,3
will be read.
"""
self.mass_pos_456_check_box = None
self.mass_pos_456_check_box: Union[QCheckBox, None] = None
"""
all_wf_chans_check_box: For user to select to read all
waveform channels for mseed data
"""
self.all_wf_chans_check_box: Union[QCheckBox, None] = None
"""
ds_check_boxes: [QCheckBox,] - For user to select which data stream
ds_check_boxes: For user to select which data stream
to be read in RT130
"""
self.ds_check_boxes = None
self.ds_check_boxes: Union[List[QCheckBox], None] = None
"""
wf_all_check_box: QCheckBox - For user to select to read all waveform
channels for mseed data
mseed_wildcard_edit: For user to enter wildcard of mseed
channels to be read
"""
self.wf_all_check_box = None
self.mseed_wildcard_edit: Union[QLineEdit, None] = None
"""
wf_chans_line_edit: QLineEdit - For user to enter wildcard of channels
to be read
tps_check_box: If checked, time-power-squared will be
displayed in time_power_squared dialog
"""
self.wf_chans_line_edit = None
self.tps_check_box: Union[QCheckBox, None] = None
"""
tps_check_box: QCheckBox - If checked, time-power-squared will be
displayed in time_power_squared_dialog
raw_check_box: If checked, waveform will be displayed in
waveform dialog
"""
self.tps_check_box = None
self.raw_check_box: Union[QCheckBox, None] = None
"""
all_soh_chan_check_box: QCheckBox - If checked, all soh channels will
all_soh_chans_check_box: If checked, all soh channels will
be read and displayed
"""
self.all_soh_chan_check_box = None
self.all_soh_chans_check_box: Union[QCheckBox, None] = None
"""
prefer_soh_chan_button: QPushButton - Button to open
self.channel_prefer_dialog to view/add/edit/select a preferred IDs
prefer_soh_chan_button: Button to open self.channel_prefer_dialog to
view/add/edit/select a preferred IDs
"""
self.prefer_soh_chan_button = None
self.prefer_soh_chan_button: Union[QPushButton, None] = None
"""
curr_soh_ids_name_line_edit: QLineEdit - textbox to display name of
current IDs. When all_soh_chan_check_box is checked, no name show
up, when all_soh_chan_check_box is unchecked, current selected name
show up.
curr_soh_ids_name_line_edit: textbox to display name of current IDs.
When all_soh_chans_check_box is checked, no name show up, when
all_soh_chans_check_box is unchecked, current selected name show up
"""
self.curr_soh_ids_name_line_edit = None
self.curr_soh_ids_name_line_edit: Union[QLineEdit, None] = None
"""
read_button: QPushButton - Button to read data from selected directory
read_button: Button to read data from selected directory
from open_files_list and plot it
"""
self.read_button = None
self.read_button: Union[QPushButton, None] = None
"""
stop_button: QPushButton - Button to stop processing the data when it
stop_button: Button to stop processing the data when it
takes too long, for example.
"""
self.stop_button = None
self.stop_button: Union[QPushButton, None] = None
"""
save_plot_button: QPushButton - Button to save the plots in
self.plotting_widget to file
"""
self.save_plot_button = None
self.save_plot_button: Union[QPushButton, None] = None
"""
info_list_widget: QListWidget - to list info of the read data after
info_list_widget: to list info of the read data after
processing
"""
self.info_list_widget = None
self.info_list_widget: Union[QListWidget, None] = None
# ========================= Menus =============================
"""
forms_menu: QMenu - to show all of the current available dialogs so
forms_menu: to show all of the current available dialogs so
that user can select a dialog to put it on top of others to even
if the dialog has been closed by user.
"""
self.forms_menu = None
self.forms_menu: Union[QMenu, None] = None
"""
no_forms_action: QAction - to show in forms_menu when there are no
no_forms_action: to show in forms_menu when there are no
dialogs available to let user know about that
"""
self.no_forms_action = None
self.no_forms_action: Union[QAction, None] = None
"""
exit_action: QAction - to exit SOHView
exit_action: to exit SOHView
"""
self.exit_action = None
self.exit_action: Union[QAction, None] = None
# ========================== Command Menu ======================
"""
gps_plotter_action: QAction - to open gps_dialog to plot all the
gps_plotter_action: to open gps_dialog to plot all the
latitude and longitude values of GPS position information
"""
self.gps_plotter_action = None
self.gps_plotter_action: Union[QAction, None] = None
"""
log_search_action: QAction - to open log_search_dialog to search for
log_search_action: to open log_search_dialog to search for
lines containing the entered string
"""
self.log_search_action = None
self.log_search_action: Union[QAction, None] = None
# ========================== Option Menu =======================
"""
mp_regular_color_action: QAction - set self.mass_pos_volt_range_opt to
'regular'
mp_trillium_color_action: QAction - set self.mass_pos_volt_range_opt to
mp_regular_color_action: set self.mass_pos_volt_range_opt to 'regular'
mp_trillium_color_action: set self.mass_pos_volt_range_opt to
'trillium'
"""
self.mp_regular_color_action = None
self.mp_trillium_color_action = None
self.mp_regular_color_action: Union[QAction, None] = None
self.mp_trillium_color_action: Union[QAction, None] = None
"""
add_positions_to_et_action: QAction - allow to add position to ET lines
add_positions_to_et_action: allow to add position to ET lines
"""
self.add_positions_to_et_action = None
self.add_positions_to_et_action: Union[QAction, None] = None
"""
Set self.date_format
yyyy_doy_action: QAction - set format to be "YYYY:DOY"
yyyy_mm_dd_action: QAction - set format to be "YYYY-MM-DD"
yyyymmmdd_action: QAction - set format to be "YYYYMMDD"
yyyy_doy_action: set format to be "YYYY:DOY"
yyyy_mm_dd_action: set format to be "YYYY-MM-DD"
yyyymmmdd_action: set format to be "YYYYMMDD"
"""
self.yyyy_doy_action = None
self.yyyy_mm_dd_action = None
self.yyyymmmdd_action = None
self.yyyy_doy_action: Union[QAction, None] = None
self.yyyy_mm_dd_action: Union[QAction, None] = None
self.yyyymmmdd_action: Union[QAction, None] = None
# ======================== Database Menu ==========================
"""
add_edit_data_type_action: QAction - open DataTypes table to add/edit
add_edit_param_action: QAction - open Parameters table to add/edit
add_edit_channel_action: QAction - open Channels table to add/edit
view_plot_type_action: QAction - view all plot types available and
add_edit_data_type_action: open DataTypes table to add/edit
add_edit_param_action: open Parameters table to add/edit
add_edit_channel_action: open Channels table to add/edit
view_plot_type_action: view all plot types available and
their description
"""
self.add_edit_data_type_action = None
self.add_edit_param_action = None
self.add_edit_channel_action = None
self.add_edit_channel_action = None
self.view_plot_type_action = None
self.add_edit_data_type_action: Union[QAction, None] = None
self.add_edit_param_action: Union[QAction, None] = None
self.add_edit_channel_action: Union[QAction, None] = None
self.add_edit_channel_action: Union[QAction, None] = None
self.view_plot_type_action: Union[QAction, None] = None
# ========================= Help Menu =============================
"""
calendar_action: QAction - Open Calendar Dialog as a helpful tool
calendar_action: Open Calendar Dialog as a helpful tool
"""
self.calendar_action = None
self.calendar_action: Union[QAction, None] = None
"""
about_action: QAction - Open About Dialog to give information about
about_action: Open About Dialog to give information about
SOHView
"""
self.about_action = None
self.about_action: Union[QAction, None] = None
"""
doc_action: QAction - Open a display allowing user to browse to the
doc_action: Open a display allowing user to browse to the
help documents in the folder Documentation/
"""
self.doc_action = None
self.doc_action: Union[QAction, None] = None
def setup_ui(self, main_window):
"""
......@@ -272,13 +281,13 @@ class UIMainWindow(object):
self.main_window = main_window
main_window.resize(1798, 1110)
main_window.setWindowTitle("SOH Station Viewer")
self.central_widget = QtWidgets.QWidget(main_window)
self.central_widget = QWidget(main_window)
main_window.setCentralWidget(self.central_widget)
self.tracking_info_text_browser = QtWidgets.QTextBrowser(
self.tracking_info_text_browser = QTextBrowser(
self.central_widget)
main_layout = QtWidgets.QVBoxLayout()
main_layout = QVBoxLayout()
main_layout.setContentsMargins(5, 5, 5, 5)
main_layout.setSpacing(0)
self.central_widget.setLayout(main_layout)
......@@ -298,30 +307,30 @@ class UIMainWindow(object):
:param main_layout: QVBoxLayout - main layout to arrange other layouts
from top to bottom
"""
h_layout = QtWidgets.QHBoxLayout()
h_layout = QHBoxLayout()
h_layout.setContentsMargins(2, 2, 2, 2)
h_layout.setSpacing(8)
main_layout.addLayout(h_layout)
self.curr_dir_button = QtWidgets.QPushButton(
self.curr_dir_button = QPushButton(
"Main Data Directory", self.central_widget)
h_layout.addWidget(self.curr_dir_button)
self.curr_dir_line_edit = QtWidgets.QLineEdit(
self.curr_dir_line_edit = QLineEdit(
self.central_widget)
h_layout.addWidget(self.curr_dir_line_edit, 1)
h_layout.addSpacing(40)
h_layout.addWidget(QtWidgets.QLabel('From'))
self.time_from_date_edit = QtWidgets.QDateEdit(
h_layout.addWidget(QLabel('From'))
self.time_from_date_edit = QDateEdit(
self.central_widget)
self.time_from_date_edit.setCalendarPopup(True)
self.time_from_date_edit.setDisplayFormat("yyyy-MM-dd")
h_layout.addWidget(self.time_from_date_edit)
h_layout.addWidget(QtWidgets.QLabel('To'))
self.time_to_date_edit = QtWidgets.QDateEdit(
h_layout.addWidget(QLabel('To'))
self.time_to_date_edit = QDateEdit(
self.central_widget)
self.time_to_date_edit.setCalendarPopup(True)
self.time_to_date_edit.setDisplayFormat("yyyy-MM-dd")
......@@ -334,15 +343,15 @@ class UIMainWindow(object):
:param main_layout: QVBoxLayout - main layout to arrange other layouts
from top to bottom
"""
h_layout = QtWidgets.QHBoxLayout()
h_layout = QHBoxLayout()
main_layout.addLayout(h_layout)
h_layout.setContentsMargins(0, 0, 0, 0)
left_widget = QtWidgets.QWidget(self.central_widget)
left_widget = QWidget(self.central_widget)
h_layout.addWidget(left_widget)
left_widget.setFixedWidth(240)
left_widget.setMinimumHeight(650)
left_layout = QtWidgets.QVBoxLayout()
left_layout = QVBoxLayout()
left_layout.setContentsMargins(0, 0, 0, 0)
left_layout.setSpacing(0)
left_widget.setLayout(left_layout)
......@@ -360,7 +369,7 @@ class UIMainWindow(object):
Setting up necessary widgets for user to setup options for plotting
:param left_layout: QVBoxLayout - layout of the left column of controls
"""
self.open_files_list = QtWidgets.QListWidget(
self.open_files_list = QListWidget(
self.central_widget)
left_layout.addWidget(self.open_files_list, 1)
pal = self.open_files_list.palette()
......@@ -369,32 +378,31 @@ class UIMainWindow(object):
self.open_files_list.setPalette(pal)
# allow multiple-line selection
self.open_files_list.setSelectionMode(
QtWidgets.QAbstractItemView.ExtendedSelection)
QAbstractItemView.ExtendedSelection)
self.inside_dir_check_box = QtWidgets.QCheckBox(
self.inside_dir_check_box = QCheckBox(
'Inside Directory', self.central_widget)
left_layout.addWidget(self.inside_dir_check_box)
search_grid = QtWidgets.QGridLayout()
search_grid = QGridLayout()
left_layout.addLayout(search_grid)
self.search_line_edit = QtWidgets.QLineEdit(self.central_widget)
self.search_line_edit = QLineEdit(self.central_widget)
self.search_line_edit.setPlaceholderText('Search...')
search_grid.addWidget(self.search_line_edit, 0, 0, 1, 3)
self.clear_button = QtWidgets.QPushButton('Clear', self.central_widget)
self.clear_button = QPushButton('Clear', self.central_widget)
self.clear_button.setFixedWidth(65)
search_grid.addWidget(self.clear_button, 0, 3, 1, 1)
search_grid.addWidget(QtWidgets.QLabel('List:'), 1, 0, 1, 1)
self.file_list_log_check_box = QtWidgets.QCheckBox(
self.file_list_log_check_box = QCheckBox(
'.log', self.central_widget)
search_grid.addWidget(self.file_list_log_check_box, 1, 1, 1, 1)
self.file_list_zip_check_box = QtWidgets.QCheckBox(
self.file_list_zip_check_box = QCheckBox(
'.zip', self.central_widget)
search_grid.addWidget(self.file_list_zip_check_box, 1, 2, 1, 1)
self.replot_button = QtWidgets.QPushButton(
self.replot_button = QPushButton(
'RePlot', self.central_widget)
self.replot_button.setFixedWidth(95)
......@@ -403,16 +411,16 @@ class UIMainWindow(object):
color_tip_fmt = ('Set the background color of the plot '
' to {0}')
background_layout = QtWidgets.QHBoxLayout()
background_layout = QHBoxLayout()
# background_layout.setContentsMargins(0, 0, 0, 0)
left_layout.addLayout(background_layout)
background_layout.addWidget(QtWidgets.QLabel('Background: '))
self.background_black_radio_button = QtWidgets.QRadioButton(
background_layout.addWidget(QLabel('Background: '))
self.background_black_radio_button = QRadioButton(
'B', self.central_widget)
self.background_black_radio_button.setToolTip(
color_tip_fmt.format('black'))
background_layout.addWidget(self.background_black_radio_button)
self.background_white_radio_button = QtWidgets.QRadioButton(
self.background_white_radio_button = QRadioButton(
'W', self.central_widget)
self.background_white_radio_button.setToolTip(
color_tip_fmt.format('white'))
......@@ -420,35 +428,38 @@ class UIMainWindow(object):
add_separation_line(left_layout)
gap_layout = QtWidgets.QHBoxLayout()
gap_layout = QHBoxLayout()
left_layout.addLayout(gap_layout)
self.detect_gap_check_box = QtWidgets.QCheckBox(
self.detect_gap_check_box = QCheckBox(
'DetectGap Len:', self.central_widget)
gap_layout.addWidget(self.detect_gap_check_box)
self.gap_len_line_edit = QtWidgets.QLineEdit(self.central_widget)
self.gap_len_line_edit = QLineEdit(self.central_widget)
gap_layout.addWidget(self.gap_len_line_edit)
gap_layout.addWidget(QtWidgets.QLabel('m'))
gap_layout.addWidget(QLabel('m'))
mass_pos_layout = QtWidgets.QHBoxLayout()
mass_pos_layout = QHBoxLayout()
left_layout.addLayout(mass_pos_layout)
mass_pos_layout.addWidget(QtWidgets.QLabel('Mass Pos:'))
self.mass_pos_123_check_box = QtWidgets.QCheckBox(
mass_pos_layout.addWidget(QLabel('Mass Pos:'))
self.mass_pos_123_check_box = QCheckBox(
'123', self.central_widget)
mass_pos_layout.addWidget(self.mass_pos_123_check_box)
self.mass_pos_456_check_box = QtWidgets.QCheckBox(
self.mass_pos_456_check_box = QCheckBox(
'456', self.central_widget)
mass_pos_layout.addWidget(self.mass_pos_456_check_box)
add_separation_line(left_layout)
ds_grid = QtWidgets.QGridLayout()
# ds_grid.setContentsMargins(0, 0, 0, 0)
left_layout.addLayout(ds_grid)
self.all_wf_chans_check_box = QCheckBox(
'All Waveform Channels', self.central_widget)
left_layout.addWidget(self.all_wf_chans_check_box)
ds_grid.addWidget(QtWidgets.QLabel('DSs:'), 0, 0, 2, 1,
left_layout.addSpacing(5)
ds_grid = QGridLayout()
left_layout.addLayout(ds_grid)
ds_grid.addWidget(QLabel('DSs:'), 0, 0, 2, 1,
QtGui.Qt.AlignVCenter)
self.ds_check_boxes = []
count = 0
......@@ -456,62 +467,67 @@ class UIMainWindow(object):
for c in range(4):
count += 1
self.ds_check_boxes.append(
QtWidgets.QCheckBox('%s' % count, self.central_widget))
QCheckBox('%s' % count, self.central_widget))
ds_grid.addWidget(self.ds_check_boxes[count - 1], r, c + 1)
wf_grid = QtWidgets.QGridLayout()
left_layout.addLayout(wf_grid)
self.wf_all_check_box = QtWidgets.QCheckBox(
'All WF:', self.central_widget)
wf_grid.addWidget(self.wf_all_check_box, 0, 0, 1, 2)
left_layout.addSpacing(5)
mseed_wildcard_layout = QHBoxLayout()
left_layout.addLayout(mseed_wildcard_layout)
mseed_wildcard_layout.addWidget(QLabel('MSeed Wildcard'))
self.mseed_wildcard_edit = QLineEdit(self.central_widget)
self.mseed_wildcard_edit.setToolTip('wildcards separated with commas')
mseed_wildcard_layout.addWidget(self.mseed_wildcard_edit)
left_layout.addSpacing(5)
tps_raw_layout = QHBoxLayout()
left_layout.addLayout(tps_raw_layout)
self.tps_check_box = QCheckBox('TPS', self.central_widget)
tps_raw_layout.addWidget(self.tps_check_box)
self.raw_check_box = QCheckBox('RAW', self.central_widget)
tps_raw_layout.addWidget(self.raw_check_box)
self.wf_chans_line_edit = QtWidgets.QLineEdit(self.central_widget)
wf_grid.addWidget(self.wf_chans_line_edit, 0, 3, 1, 2)
self.tps_check_box = QtWidgets.QCheckBox('TPS', self.central_widget)
wf_grid.addWidget(self.tps_check_box, 1, 0)
add_separation_line(left_layout)
chan_layout = QtWidgets.QHBoxLayout()
chan_layout = QHBoxLayout()
chan_layout.setContentsMargins(0, 0, 0, 0)
chan_layout.setSpacing(0)
left_layout.addLayout(chan_layout)
self.all_soh_chan_check_box = QtWidgets.QCheckBox(
self.all_soh_chans_check_box = QCheckBox(
'All SOH ', self.central_widget)
self.all_soh_chan_check_box.setChecked(True)
chan_layout.addWidget(self.all_soh_chan_check_box)
self.all_soh_chans_check_box.setChecked(True)
chan_layout.addWidget(self.all_soh_chans_check_box)
self.prefer_soh_chan_button = QtWidgets.QPushButton(
self.prefer_soh_chan_button = QPushButton(
'Pref', self.central_widget)
self.prefer_soh_chan_button.setFixedWidth(47)
chan_layout.addWidget(self.prefer_soh_chan_button)
chan_layout.addWidget(QtWidgets.QLabel('Cur'))
self.curr_soh_ids_name_line_edit = QtWidgets.QLineEdit(
chan_layout.addWidget(QLabel('Cur'))
self.curr_soh_ids_name_line_edit = QLineEdit(
self.central_widget)
chan_layout.addWidget(self.curr_soh_ids_name_line_edit)
submit_layout = QtWidgets.QHBoxLayout()
submit_layout = QHBoxLayout()
submit_layout.setSpacing(5)
left_layout.addLayout(submit_layout)
self.read_button = QtWidgets.QPushButton('Read', self.central_widget)
self.read_button = QPushButton('Read', self.central_widget)
self.read_button.setToolTip('Read selected files')
submit_layout.addWidget(self.read_button)
self.stop_button = QtWidgets.QPushButton('Stop', self.central_widget)
self.stop_button = QPushButton('Stop', self.central_widget)
self.stop_button.setToolTip('Halt ongoing read')
submit_layout.addWidget(self.stop_button)
self.save_plot_button = QtWidgets.QPushButton(
self.save_plot_button = QPushButton(
'Save plot', self.central_widget)
self.save_plot_button.setToolTip('Save plots to disk')
submit_layout.addWidget(self.save_plot_button)
self.info_list_widget = QtWidgets.QListWidget(self.central_widget)
self.info_list_widget = QListWidget(self.central_widget)
left_layout.addWidget(self.info_list_widget, 1)
def create_shortcuts(self, main_window):
seq = QtGui.QKeySequence('Ctrl+F')
chdir_shortcut = QtWidgets.QShortcut(seq, main_window)
chdir_shortcut = QShortcut(seq, main_window)
chdir_shortcut.activated.connect(
main_window.change_current_directory)
......@@ -529,7 +545,7 @@ class UIMainWindow(object):
help_menu = main_menu.addMenu("Help")
# exitAction = QtWidgets.QAction(QtGui.QIcon('exit.png'), "Exit", self)
# exitAction = QAction(QtGui.QIcon('exit.png'), "Exit", self)
# exitAction.setShortcut("Ctrl+X")
self.create_file_menu(main_window, file_menu)
self.create_command_menu(main_window, command_menu)
......@@ -544,7 +560,7 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - File Menu
"""
self.exit_action = QtWidgets.QAction('Close', main_window)
self.exit_action = QAction('Close', main_window)
menu.addAction(self.exit_action)
def create_command_menu(self, main_window, menu):
......@@ -554,11 +570,11 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - Commands Menu
"""
self.gps_plotter_action = QtWidgets.QAction(
self.gps_plotter_action = QAction(
'GPS Plotter', main_window)
menu.addAction(self.gps_plotter_action)
self.log_search_action = QtWidgets.QAction(
self.log_search_action = QAction(
'Log Search', main_window)
menu.addAction(self.log_search_action)
......@@ -568,37 +584,37 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - Options Menu
"""
mp_coloring_menu = QtWidgets.QMenu('MP Coloring:', main_window)
mp_coloring_menu = QMenu('MP Coloring:', main_window)
menu.addMenu(mp_coloring_menu)
mp_coloring_group = QtWidgets.QActionGroup(main_window)
self.mp_regular_color_action = QtWidgets.QAction(
mp_coloring_group = QActionGroup(main_window)
self.mp_regular_color_action = QAction(
'0.5, 2.0, 4.0, 7.0 (Regular)', main_window)
self.mp_regular_color_action.setCheckable(True)
mp_coloring_menu.addAction(self.mp_regular_color_action)
mp_coloring_group.addAction(self.mp_regular_color_action)
self.mp_trillium_color_action = QtWidgets.QAction(
self.mp_trillium_color_action = QAction(
'0.5, 1.8, 2.4, 3.5 (Trillium)', main_window)
self.mp_trillium_color_action.setCheckable(True)
mp_coloring_menu.addAction(self.mp_trillium_color_action)
mp_coloring_group.addAction(self.mp_trillium_color_action)
menu.addSeparator()
self.add_positions_to_et_action = QtWidgets.QAction(
self.add_positions_to_et_action = QAction(
'Add Positions to ET Lines', main_window)
self.add_positions_to_et_action.setCheckable(True)
menu.addAction(self.add_positions_to_et_action)
date_format_menu = QtWidgets.QMenu('Date Format:', main_window)
date_format_menu = QMenu('Date Format:', main_window)
menu.addMenu(date_format_menu)
self.yyyy_doy_action = QtWidgets.QAction(
self.yyyy_doy_action = QAction(
'YYYY:DOY', main_window)
self.yyyy_doy_action.setCheckable(True)
date_format_menu.addAction(self.yyyy_doy_action)
self.yyyy_mm_dd_action = QtWidgets.QAction(
self.yyyy_mm_dd_action = QAction(
'YYYY-MM-DD', main_window)
self.yyyy_mm_dd_action.setCheckable(True)
date_format_menu.addAction(self.yyyy_mm_dd_action)
self.yyyymmmdd_action = QtWidgets.QAction(
self.yyyymmmdd_action = QAction(
'YYYYMMMDD', main_window)
self.yyyymmmdd_action.setCheckable(True)
date_format_menu.addAction(self.yyyymmmdd_action)
......@@ -610,19 +626,19 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - Database Menu
"""
self.add_edit_data_type_action = QtWidgets.QAction(
self.add_edit_data_type_action = QAction(
'Add/Edit Data Types', main_window)
menu.addAction(self.add_edit_data_type_action)
self.add_edit_param_action = QtWidgets.QAction(
self.add_edit_param_action = QAction(
'Add/Edit Parameters', main_window)
menu.addAction(self.add_edit_param_action)
self.add_edit_channel_action = QtWidgets.QAction(
self.add_edit_channel_action = QAction(
'Add/Edit Channels', main_window)
menu.addAction(self.add_edit_channel_action)
self.view_plot_type_action = QtWidgets.QAction(
self.view_plot_type_action = QAction(
'View Plot Types', main_window)
menu.addAction(self.view_plot_type_action)
......@@ -633,19 +649,19 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - Help Menu
"""
self.calendar_action = QtWidgets.QAction(
self.calendar_action = QAction(
'Calendar', main_window)
menu.addAction(self.calendar_action)
self.about_action = QtWidgets.QAction(
self.about_action = QAction(
'About', main_window)
menu.addAction(self.about_action)
self.doc_action = QtWidgets.QAction('Documentation', main_window)
self.doc_action = QAction('Documentation', main_window)
menu.addAction(self.doc_action)
def create_forms_menu(self, main_window, menu):
self.no_forms_action = QtWidgets.QAction(
self.no_forms_action = QAction(
"No Forms Are Open", main_window)
menu.addAction(self.no_forms_action)
self.no_forms_action.setEnabled(False)
......@@ -720,8 +736,18 @@ class UIMainWindow(object):
self.replot_button.clicked.connect(main_window.replot_loaded_data)
self.all_soh_chan_check_box.clicked.connect(
main_window.all_chan_clicked)
self.all_wf_chans_check_box.clicked.connect(
main_window.all_wf_chans_clicked)
for cb in self.ds_check_boxes:
cb.clicked.connect(main_window.data_stream_clicked)
self.mseed_wildcard_edit.textChanged.connect(
main_window.mseed_wildcard_changed)
self.all_soh_chans_check_box.clicked.connect(
main_window.all_soh_chans_clicked)
self.prefer_soh_chan_button.clicked.connect(
main_window.open_channel_preferences)
self.read_button.clicked.connect(main_window.read_selected_files)
......
import re
from pathlib import Path
from typing import Dict, List, Tuple, Union
from sohstationviewer.view.util.enums import LogType
from sohstationviewer.conf import constants as const
from sohstationviewer.conf.constants import (WF_1ST, WF_2ND, WF_3RD)
def is_doc_file(file: Path, include_table_of_contents: bool = False)\
......@@ -160,5 +163,46 @@ def log_str(log_info: Tuple[str, LogType]) -> str:
return f"{log_type.name}: {log_text}"
def check_chan_wildcards_format(wildcards: str):
"""
Check format of channel's wildcards. Raise exception if invalid.
:param wildcards: wildcards that are separated with ','.
:type wildcards: str
"""
for wc in wildcards.split():
wc = wc.strip()
if len(wc) == 1 and wc != '*':
raise Exception(
f"Request '{wc}' has length=1 which must be '*'.")
if '**' in wc:
raise Exception(
f"Request '{wc}' includes '**' which isn't allowed.")
if len(wc) > 3:
raise Exception(
f"Request '{wc}' has length={len(wc)} > 3 which isn't allowed."
)
if len(wc) == 2 and '*' not in wc:
raise Exception(
f"Request '{wc}' has length=2 which required one '*'."
)
pattern = f"[{WF_1ST}*]"
if not re.compile(pattern).match(wc[0]):
raise Exception(
f"Request '{wc}' has first character not match {pattern}."
)
pattern = f"[{WF_3RD}*]"
if not re.compile(pattern).match(wc[-1]):
raise Exception(
f"Request '{wc}' has last character not match {pattern}."
)
if len(wc) == 3:
pattern = f"[{WF_2ND}*]"
if not re.compile(pattern).match(wc[1]):
raise Exception(
f"Request '{wc}' has second character not match {pattern}."
)
if __name__ == '__main__':
create_table_of_content_file(Path('../../../documentation'))
from unittest import TestCase
from unittest.mock import patch
from sohstationviewer.model.handling_data import (
check_chan,
check_wf_chan,
check_soh_chan
)
class TestCheckChan(TestCase):
def setUp(self) -> None:
self.req_soh_chans = ['LCE', 'LCQ']
self.req_wf_chans = ['LHE', 'HHE']
check_soh_chan_patcher = patch(
'sohstationviewer.model.handling_data.check_soh_chan',
wraps=check_soh_chan
)
self.addCleanup(check_soh_chan_patcher.stop)
self.mock_check_soh_chan = check_soh_chan_patcher.start()
check_wf_chan_patcher = patch(
'sohstationviewer.model.handling_data.check_wf_chan',
wraps=check_wf_chan
)
self.addCleanup(check_wf_chan_patcher.stop)
self.mock_check_wf_chan = check_wf_chan_patcher.start()
def test_channel_is_waveform_and_is_requested(self):
waveform_channel = 'LHE'
ret = check_chan(waveform_channel, self.req_soh_chans,
self.req_wf_chans)
self.assertEqual(ret, 'WF')
self.assertTrue(self.mock_check_wf_chan.called)
def test_channel_is_waveform_but_not_requested(self):
waveform_channel = 'HH1'
ret = check_chan(waveform_channel, self.req_soh_chans,
self.req_wf_chans)
self.assertFalse(ret)
self.assertTrue(self.mock_check_wf_chan.called)
def test_channel_is_soh_and_is_requested(self):
with self.subTest('test_normal_channel'):
soh_channel = 'LCE'
ret = check_chan(
soh_channel, self.req_soh_chans, self.req_wf_chans)
self.assertEqual(ret, 'SOH')
self.assertTrue(self.mock_check_soh_chan.called)
self.mock_check_soh_chan.reset_mock()
with self.subTest('test_mass_position_channel'):
soh_channel = 'VM1'
ret = check_chan(
soh_channel, self.req_soh_chans, self.req_wf_chans)
self.assertEqual(ret, 'SOH')
self.assertTrue(self.mock_check_soh_chan.called)
def test_channel_is_soh_but_not_requested(self):
soh_channel = 'VKI'
ret = check_chan(soh_channel, self.req_soh_chans, self.req_wf_chans)
self.assertFalse(ret)
self.assertTrue(self.mock_check_soh_chan.called)
class TestCheckSohChan(TestCase):
def setUp(self) -> None:
self.req_soh_chans = ['LCE', 'LCQ', 'EX?']
self.sample_channel_ids = ['ODV', 'QGA', 'NF4', 'OLY', 'UZM']
def test_all_channels_requested(self):
self.req_soh_chans = []
for channel_id in self.sample_channel_ids:
self.assertTrue(check_soh_chan(channel_id, self.req_soh_chans))
def test_channel_is_requested(self):
with self.subTest('test_normal_channels'):
channel_id = 'LCE'
self.assertTrue(check_soh_chan(channel_id, self.req_soh_chans))
with self.subTest('test_mass_position_channels'):
base_channel_id = 'VM'
channel_suffixes = ['0', '1', '2', '3', '4', '5', '6']
for suffix in channel_suffixes:
channel_id = base_channel_id + suffix
self.assertTrue(check_soh_chan(channel_id, self.req_soh_chans))
with self.subTest('test_external_soh_channels'):
base_channel_id = 'EX'
channel_suffixes = ['1', '2', '3']
for suffix in channel_suffixes:
channel_id = base_channel_id + suffix
self.assertTrue(check_soh_chan(channel_id, self.req_soh_chans))
def test_channel_not_requested(self):
for channel_id in self.sample_channel_ids:
self.assertFalse(check_soh_chan(channel_id, self.req_soh_chans))
class TestCheckWfChan(TestCase):
def test_channel_is_requested(self):
req_wf_chans = ['LHE', 'HHE']
channel_id = 'LHE'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', True)
)
def test_channel_not_requested(self):
req_wf_chans = ['LHE', 'HHE']
with self.subTest('test_waveform_channel'):
channel_id = 'AHE'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', False)
)
with self.subTest('test_non_waveform_channel'):
channel_id = 'Not a waveform channel'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('', False)
)
def test_len1_wildcard_request(self):
req_wf_chans = ['*']
sample_channel_ids = ['LHE', 'HHE', 'AL2', 'MNZ', 'VNN']
with self.subTest('test_waveform_channel'):
for channel_id in sample_channel_ids:
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', True)
)
with self.subTest('test_non_waveform_channel'):
channel_id = 'Not a waveform channel'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('', False)
)
def test_len2_wildcard_request(self):
req_wf_chans = ['H*']
with self.subTest('Requested start char'):
channel_id = 'HHE'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', True)
)
with self.subTest('None-requested start char'):
channel_id = 'LHE'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', False)
)
req_wf_chans = ['*E']
with self.subTest('Requested end char'):
channel_id = 'HHE'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', True)
)
with self.subTest('None-requested end char'):
channel_id = 'LHN'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', False)
)
def test_len3_wildcard_request(self):
req_wf_chans = ['HH*']
with self.subTest('Requested start 2 chars'):
channel_id = 'HHE'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', True)
)
with self.subTest('None-requested start 2 chars'):
channel_id = 'LHE'
ret = check_wf_chan(channel_id, req_wf_chans)
self.assertTupleEqual(
ret,
('WF', False)
)
req_wf_chans = ['H*E']
with self.subTest('Requested start or end char'):
channel_id = 'HHE'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', True)
)
with self.subTest('None-requested start or end char'):
channel_id = 'LHN'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', False)
)
req_wf_chans = ['*HE']
with self.subTest('Requested 2 end chars'):
channel_id = 'HHE'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', True)
)
with self.subTest('None-requested 2 end chars'):
channel_id = 'LHN'
self.assertTupleEqual(
check_wf_chan(channel_id, req_wf_chans),
('WF', False)
)
......@@ -6,10 +6,13 @@ from unittest import TestCase
from sohstationviewer.view.util.functions import (
get_soh_messages_for_view, log_str, is_doc_file,
create_search_results_file, create_table_of_content_file)
create_search_results_file, create_table_of_content_file,
check_chan_wildcards_format
)
from sohstationviewer.view.util.enums import LogType
from sohstationviewer.conf import constants as const
from sohstationviewer.conf.constants import (WF_1ST, WF_2ND, WF_3RD)
class TestGetSOHMessageForView(TestCase):
......@@ -208,3 +211,165 @@ class TestCreateTableOfContentFile(TestCase):
"+ [file1](file1.help.md)\n\n",
)
)
class TestCheckChanWildcardsFormat(TestCase):
def test_len1(self):
with self.subTest("Wildcard is *"):
wc = '*'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard isn't *"):
wc = 'L'
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' has length=1 which must be '*'."
)
def test_len2(self):
with self.subTest("Wildcard with first char matched"):
wc = 'L*'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard with first char not matched"):
wc = 'W*'
pattern = f"[{WF_1ST}*]"
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' has first character not match {pattern}."
)
with self.subTest("Wildcard with last char matched"):
wc = '*N'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard with last char not matched"):
wc = '*L'
pattern = f"[{WF_3RD}*]"
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' has last character not match {pattern}."
)
with self.subTest("Wildcard is **"):
wc = '**'
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' includes '**' which isn't allowed."
)
def test_len3(self):
with self.subTest("Wildcard with first char matched"):
wc = 'HL*'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard with first char is a '*'"):
wc = '*L*'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard with first char not matched"):
wc = 'WL*'
pattern = f"[{WF_1ST}*]"
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' has first character not match {pattern}."
)
with self.subTest("Wildcard with last char matched"):
wc = '*LN'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard with last char is a '*'"):
wc = 'HL*'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard with last char not matched"):
wc = '*LL'
pattern = f"[{WF_3RD}*]"
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' has last character not match {pattern}."
)
with self.subTest("Wildcard with second char matched"):
wc = 'HHN'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard with second char is a star"):
wc = 'H*N'
try:
check_chan_wildcards_format(wc)
except Exception:
self.fail(f"Wildcard '{wc}' raise Exception unexpectedly")
with self.subTest("Wildcard with second char not matched"):
wc = 'HWE'
pattern = f"[{WF_2ND}*]"
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' has second character not match {pattern}."
)
with self.subTest("Wildcard start with '**'"):
wc = '**E'
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' includes '**' which isn't allowed."
)
with self.subTest("Wildcard end with '**'"):
wc = 'H**'
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' includes '**' which isn't allowed."
)
def test_len_gt_3(self):
wc = 'HHLL'
with self.assertRaises(Exception) as context:
check_chan_wildcards_format(wc)
self.assertEqual(
str(context.exception),
f"Request '{wc}' has length={len(wc)} > 3 which isn't allowed."
)