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): ...@@ -26,8 +26,8 @@ class WaveformWidget(plotting_widget.PlottingWidget):
finished = QtCore.Signal() finished = QtCore.Signal()
def __init__(self, parent, tracking_box, *args): def __init__(self, parent, tracking_box, name):
super().__init__(parent, tracking_box) super().__init__(parent, tracking_box, name)
self.data_processors: List[WaveformChannelProcessor] = [] self.data_processors: List[WaveformChannelProcessor] = []
...@@ -83,12 +83,20 @@ class WaveformWidget(plotting_widget.PlottingWidget): ...@@ -83,12 +83,20 @@ class WaveformWidget(plotting_widget.PlottingWidget):
self.min_x = max(data_time[0], start_tm) self.min_x = max(data_time[0], start_tm)
self.max_x = min(data_time[1], end_tm) self.max_x = min(data_time[1], end_tm)
self.plot_total = len(self.plotting_data1) + len(self.plotting_data2) 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 = const.BOTTOM
self.plotting_bot_pixel = const.BOTTOM_PX self.plotting_bot_pixel = const.BOTTOM_PX
self.axes = [] self.axes = []
self.timestamp_bar_top = self.plotting_axes.add_timestamp_bar(0.003) self.timestamp_bar_top = self.plotting_axes.add_timestamp_bar(0.003)
self.plotting_axes.set_title(title) self.plotting_axes.set_title(title)
if waveform_data == {}:
return False
else:
return True
def plot_channels(self, start_tm, end_tm, key, def plot_channels(self, start_tm, end_tm, key,
data_time, time_ticks_total, data_time, time_ticks_total,
...@@ -115,9 +123,12 @@ class WaveformWidget(plotting_widget.PlottingWidget): ...@@ -115,9 +123,12 @@ class WaveformWidget(plotting_widget.PlottingWidget):
self.is_working = True self.is_working = True
start_msg = 'Plotting waveform data...' start_msg = 'Plotting waveform data...'
display_tracking_info(self.tracking_box, start_msg, 'info') display_tracking_info(self.tracking_box, start_msg, 'info')
self.init_plot(start_tm, end_tm, key, ret = self.init_plot(start_tm, end_tm, key,
data_time, time_ticks_total, data_time, time_ticks_total,
waveform_data, mass_pos_data) waveform_data, mass_pos_data)
if not ret:
self.draw()
return
self.create_waveform_channel_processors() self.create_waveform_channel_processors()
self.process_channel() self.process_channel()
...@@ -354,7 +365,7 @@ class WaveformDialog(QtWidgets.QWidget): ...@@ -354,7 +365,7 @@ class WaveformDialog(QtWidgets.QWidget):
mass position channel mass position channel
""" """
self.plotting_widget = WaveformWidget( self.plotting_widget = WaveformWidget(
self, self.info_text_browser) self, self.info_text_browser, 'RAWWidget')
self.plotting_widget.finished.connect(self.plot_finished) self.plotting_widget.finished.connect(self.plot_finished)
main_layout.addWidget(self.plotting_widget, 2) main_layout.addWidget(self.plotting_widget, 2)
......
# UI and connectSignals for main_window # 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 from sohstationviewer.view.calendar.calendar_widget import CalendarWidget
...@@ -14,8 +21,8 @@ def add_separation_line(layout): ...@@ -14,8 +21,8 @@ def add_separation_line(layout):
Add a line for separation to the given layout. Add a line for separation to the given layout.
:param layout: QLayout - the layout that contains the line :param layout: QLayout - the layout that contains the line
""" """
label = QtWidgets.QLabel() label = QLabel()
label.setFrameStyle(QtWidgets.QFrame.HLine | QtWidgets.QFrame.Sunken) label.setFrameStyle(QFrame.HLine | QFrame.Sunken)
label.setLineWidth(1) label.setLineWidth(1)
layout.addWidget(label) layout.addWidget(label)
...@@ -27,242 +34,244 @@ class UIMainWindow(object): ...@@ -27,242 +34,244 @@ class UIMainWindow(object):
""" """
super().__init__() super().__init__()
""" """
main_window: QMainWindow - Main window that contains main widget main_window: Main window that contains main widget and menus
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 tracking_info_text_browser: textbox that can set color and background
and background color for displaying tracking info of processing color for displaying tracking info of processing data
data
""" """
self.tracking_info_text_browser = None self.tracking_info_text_browser: Union[QTextBrowser, None] = None
# =================== top row ======================== # =================== top row ========================
""" """
curr_dir_button: QPushButton - Button that helps browse to the curr_dir_button: Button that helps browse to the directory for
directory for selecting data set 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 curr_dir_line_edit: textbox that display the current directory
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 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 from the data set
""" """
self.time_to_date_edit = None self.time_to_date_edit: Union[QDateEdit, None] = None
# ======================= second row ====================== # ======================= 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 open_files_list: Widget that display the list of directories in
directories in current directory for user to select 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 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.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 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 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, background_black_radio_button: If selected, plotting_widget will turn
plotting_widget will turn to black mode 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, background_white_radio_button: If selected, plotting_widget will turn
plotting_widget will turn to white mode 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) 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 mass_pos_123_check_box: QCheckBox: If checked, mass position 1,2,3
will be read 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. 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 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 mseed_wildcard_edit: For user to enter wildcard of mseed
channels for mseed data 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 tps_check_box: If checked, time-power-squared will be
to be read 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 raw_check_box: If checked, waveform will be displayed in
displayed in time_power_squared_dialog 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 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 prefer_soh_chan_button: Button to open self.channel_prefer_dialog to
self.channel_prefer_dialog to view/add/edit/select a preferred IDs 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 curr_soh_ids_name_line_edit: textbox to display name of current IDs.
current IDs. When all_soh_chan_check_box is checked, no name show When all_soh_chans_check_box is checked, no name show up, when
up, when all_soh_chan_check_box is unchecked, current selected name all_soh_chans_check_box is unchecked, current selected name show up
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 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. 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 save_plot_button: QPushButton - Button to save the plots in
self.plotting_widget to file 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 processing
""" """
self.info_list_widget = None self.info_list_widget: Union[QListWidget, None] = None
# ========================= Menus ============================= # ========================= 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 that user can select a dialog to put it on top of others to even
if the dialog has been closed by user. 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 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 ====================== # ========================== 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 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 lines containing the entered string
""" """
self.log_search_action = None self.log_search_action: Union[QAction, None] = None
# ========================== Option Menu ======================= # ========================== Option Menu =======================
""" """
mp_regular_color_action: QAction - set self.mass_pos_volt_range_opt to mp_regular_color_action: set self.mass_pos_volt_range_opt to 'regular'
'regular' mp_trillium_color_action: set self.mass_pos_volt_range_opt to
mp_trillium_color_action: QAction - set self.mass_pos_volt_range_opt to
'trillium' 'trillium'
""" """
self.mp_regular_color_action = None self.mp_regular_color_action: Union[QAction, None] = None
self.mp_trillium_color_action = 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 Set self.date_format
yyyy_doy_action: QAction - set format to be "YYYY:DOY" yyyy_doy_action: set format to be "YYYY:DOY"
yyyy_mm_dd_action: QAction - set format to be "YYYY-MM-DD" yyyy_mm_dd_action: set format to be "YYYY-MM-DD"
yyyymmmdd_action: QAction - set format to be "YYYYMMDD" yyyymmmdd_action: set format to be "YYYYMMDD"
""" """
self.yyyy_doy_action = None self.yyyy_doy_action: Union[QAction, None] = None
self.yyyy_mm_dd_action = None self.yyyy_mm_dd_action: Union[QAction, None] = None
self.yyyymmmdd_action = None self.yyyymmmdd_action: Union[QAction, None] = None
# ======================== Database Menu ========================== # ======================== Database Menu ==========================
""" """
add_edit_data_type_action: QAction - open DataTypes table to add/edit add_edit_data_type_action: open DataTypes table to add/edit
add_edit_param_action: QAction - open Parameters table to add/edit add_edit_param_action: open Parameters table to add/edit
add_edit_channel_action: QAction - open Channels table to add/edit add_edit_channel_action: open Channels table to add/edit
view_plot_type_action: QAction - view all plot types available and view_plot_type_action: view all plot types available and
their description their description
""" """
self.add_edit_data_type_action = None self.add_edit_data_type_action: Union[QAction, None] = None
self.add_edit_param_action = None self.add_edit_param_action: Union[QAction, None] = None
self.add_edit_channel_action = None self.add_edit_channel_action: Union[QAction, None] = None
self.add_edit_channel_action = None self.add_edit_channel_action: Union[QAction, None] = None
self.view_plot_type_action = None self.view_plot_type_action: Union[QAction, None] = None
# ========================= Help Menu ============================= # ========================= 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 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/ help documents in the folder Documentation/
""" """
self.doc_action = None self.doc_action: Union[QAction, None] = None
def setup_ui(self, main_window): def setup_ui(self, main_window):
""" """
...@@ -272,13 +281,13 @@ class UIMainWindow(object): ...@@ -272,13 +281,13 @@ class UIMainWindow(object):
self.main_window = main_window self.main_window = main_window
main_window.resize(1798, 1110) main_window.resize(1798, 1110)
main_window.setWindowTitle("SOH Station Viewer") 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) main_window.setCentralWidget(self.central_widget)
self.tracking_info_text_browser = QtWidgets.QTextBrowser( self.tracking_info_text_browser = QTextBrowser(
self.central_widget) self.central_widget)
main_layout = QtWidgets.QVBoxLayout() main_layout = QVBoxLayout()
main_layout.setContentsMargins(5, 5, 5, 5) main_layout.setContentsMargins(5, 5, 5, 5)
main_layout.setSpacing(0) main_layout.setSpacing(0)
self.central_widget.setLayout(main_layout) self.central_widget.setLayout(main_layout)
...@@ -298,30 +307,30 @@ class UIMainWindow(object): ...@@ -298,30 +307,30 @@ class UIMainWindow(object):
:param main_layout: QVBoxLayout - main layout to arrange other layouts :param main_layout: QVBoxLayout - main layout to arrange other layouts
from top to bottom from top to bottom
""" """
h_layout = QtWidgets.QHBoxLayout() h_layout = QHBoxLayout()
h_layout.setContentsMargins(2, 2, 2, 2) h_layout.setContentsMargins(2, 2, 2, 2)
h_layout.setSpacing(8) h_layout.setSpacing(8)
main_layout.addLayout(h_layout) main_layout.addLayout(h_layout)
self.curr_dir_button = QtWidgets.QPushButton( self.curr_dir_button = QPushButton(
"Main Data Directory", self.central_widget) "Main Data Directory", self.central_widget)
h_layout.addWidget(self.curr_dir_button) h_layout.addWidget(self.curr_dir_button)
self.curr_dir_line_edit = QtWidgets.QLineEdit( self.curr_dir_line_edit = QLineEdit(
self.central_widget) self.central_widget)
h_layout.addWidget(self.curr_dir_line_edit, 1) h_layout.addWidget(self.curr_dir_line_edit, 1)
h_layout.addSpacing(40) h_layout.addSpacing(40)
h_layout.addWidget(QtWidgets.QLabel('From')) h_layout.addWidget(QLabel('From'))
self.time_from_date_edit = QtWidgets.QDateEdit( self.time_from_date_edit = QDateEdit(
self.central_widget) self.central_widget)
self.time_from_date_edit.setCalendarPopup(True) self.time_from_date_edit.setCalendarPopup(True)
self.time_from_date_edit.setDisplayFormat("yyyy-MM-dd") self.time_from_date_edit.setDisplayFormat("yyyy-MM-dd")
h_layout.addWidget(self.time_from_date_edit) h_layout.addWidget(self.time_from_date_edit)
h_layout.addWidget(QtWidgets.QLabel('To')) h_layout.addWidget(QLabel('To'))
self.time_to_date_edit = QtWidgets.QDateEdit( self.time_to_date_edit = QDateEdit(
self.central_widget) self.central_widget)
self.time_to_date_edit.setCalendarPopup(True) self.time_to_date_edit.setCalendarPopup(True)
self.time_to_date_edit.setDisplayFormat("yyyy-MM-dd") self.time_to_date_edit.setDisplayFormat("yyyy-MM-dd")
...@@ -334,15 +343,15 @@ class UIMainWindow(object): ...@@ -334,15 +343,15 @@ class UIMainWindow(object):
:param main_layout: QVBoxLayout - main layout to arrange other layouts :param main_layout: QVBoxLayout - main layout to arrange other layouts
from top to bottom from top to bottom
""" """
h_layout = QtWidgets.QHBoxLayout() h_layout = QHBoxLayout()
main_layout.addLayout(h_layout) main_layout.addLayout(h_layout)
h_layout.setContentsMargins(0, 0, 0, 0) 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) h_layout.addWidget(left_widget)
left_widget.setFixedWidth(240) left_widget.setFixedWidth(240)
left_widget.setMinimumHeight(650) left_widget.setMinimumHeight(650)
left_layout = QtWidgets.QVBoxLayout() left_layout = QVBoxLayout()
left_layout.setContentsMargins(0, 0, 0, 0) left_layout.setContentsMargins(0, 0, 0, 0)
left_layout.setSpacing(0) left_layout.setSpacing(0)
left_widget.setLayout(left_layout) left_widget.setLayout(left_layout)
...@@ -360,7 +369,7 @@ class UIMainWindow(object): ...@@ -360,7 +369,7 @@ class UIMainWindow(object):
Setting up necessary widgets for user to setup options for plotting Setting up necessary widgets for user to setup options for plotting
:param left_layout: QVBoxLayout - layout of the left column of controls :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) self.central_widget)
left_layout.addWidget(self.open_files_list, 1) left_layout.addWidget(self.open_files_list, 1)
pal = self.open_files_list.palette() pal = self.open_files_list.palette()
...@@ -369,32 +378,31 @@ class UIMainWindow(object): ...@@ -369,32 +378,31 @@ class UIMainWindow(object):
self.open_files_list.setPalette(pal) self.open_files_list.setPalette(pal)
# allow multiple-line selection # allow multiple-line selection
self.open_files_list.setSelectionMode( 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) 'Inside Directory', self.central_widget)
left_layout.addWidget(self.inside_dir_check_box) left_layout.addWidget(self.inside_dir_check_box)
search_grid = QtWidgets.QGridLayout() search_grid = QGridLayout()
left_layout.addLayout(search_grid) 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...') self.search_line_edit.setPlaceholderText('Search...')
search_grid.addWidget(self.search_line_edit, 0, 0, 1, 3) 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) self.clear_button.setFixedWidth(65)
search_grid.addWidget(self.clear_button, 0, 3, 1, 1) 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 = QCheckBox(
self.file_list_log_check_box = QtWidgets.QCheckBox(
'.log', self.central_widget) '.log', self.central_widget)
search_grid.addWidget(self.file_list_log_check_box, 1, 1, 1, 1) 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) '.zip', self.central_widget)
search_grid.addWidget(self.file_list_zip_check_box, 1, 2, 1, 1) 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) 'RePlot', self.central_widget)
self.replot_button.setFixedWidth(95) self.replot_button.setFixedWidth(95)
...@@ -403,16 +411,16 @@ class UIMainWindow(object): ...@@ -403,16 +411,16 @@ class UIMainWindow(object):
color_tip_fmt = ('Set the background color of the plot ' color_tip_fmt = ('Set the background color of the plot '
' to {0}') ' to {0}')
background_layout = QtWidgets.QHBoxLayout() background_layout = QHBoxLayout()
# background_layout.setContentsMargins(0, 0, 0, 0) # background_layout.setContentsMargins(0, 0, 0, 0)
left_layout.addLayout(background_layout) left_layout.addLayout(background_layout)
background_layout.addWidget(QtWidgets.QLabel('Background: ')) background_layout.addWidget(QLabel('Background: '))
self.background_black_radio_button = QtWidgets.QRadioButton( self.background_black_radio_button = QRadioButton(
'B', self.central_widget) 'B', self.central_widget)
self.background_black_radio_button.setToolTip( self.background_black_radio_button.setToolTip(
color_tip_fmt.format('black')) color_tip_fmt.format('black'))
background_layout.addWidget(self.background_black_radio_button) 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) 'W', self.central_widget)
self.background_white_radio_button.setToolTip( self.background_white_radio_button.setToolTip(
color_tip_fmt.format('white')) color_tip_fmt.format('white'))
...@@ -420,35 +428,38 @@ class UIMainWindow(object): ...@@ -420,35 +428,38 @@ class UIMainWindow(object):
add_separation_line(left_layout) add_separation_line(left_layout)
gap_layout = QtWidgets.QHBoxLayout() gap_layout = QHBoxLayout()
left_layout.addLayout(gap_layout) left_layout.addLayout(gap_layout)
self.detect_gap_check_box = QtWidgets.QCheckBox( self.detect_gap_check_box = QCheckBox(
'DetectGap Len:', self.central_widget) 'DetectGap Len:', self.central_widget)
gap_layout.addWidget(self.detect_gap_check_box) 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(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) left_layout.addLayout(mass_pos_layout)
mass_pos_layout.addWidget(QtWidgets.QLabel('Mass Pos:')) mass_pos_layout.addWidget(QLabel('Mass Pos:'))
self.mass_pos_123_check_box = QtWidgets.QCheckBox( self.mass_pos_123_check_box = QCheckBox(
'123', self.central_widget) '123', self.central_widget)
mass_pos_layout.addWidget(self.mass_pos_123_check_box) 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) '456', self.central_widget)
mass_pos_layout.addWidget(self.mass_pos_456_check_box) mass_pos_layout.addWidget(self.mass_pos_456_check_box)
add_separation_line(left_layout) add_separation_line(left_layout)
ds_grid = QtWidgets.QGridLayout() self.all_wf_chans_check_box = QCheckBox(
# ds_grid.setContentsMargins(0, 0, 0, 0) 'All Waveform Channels', self.central_widget)
left_layout.addLayout(ds_grid) 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) QtGui.Qt.AlignVCenter)
self.ds_check_boxes = [] self.ds_check_boxes = []
count = 0 count = 0
...@@ -456,62 +467,67 @@ class UIMainWindow(object): ...@@ -456,62 +467,67 @@ class UIMainWindow(object):
for c in range(4): for c in range(4):
count += 1 count += 1
self.ds_check_boxes.append( 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) ds_grid.addWidget(self.ds_check_boxes[count - 1], r, c + 1)
wf_grid = QtWidgets.QGridLayout() left_layout.addSpacing(5)
left_layout.addLayout(wf_grid) mseed_wildcard_layout = QHBoxLayout()
self.wf_all_check_box = QtWidgets.QCheckBox( left_layout.addLayout(mseed_wildcard_layout)
'All WF:', self.central_widget) mseed_wildcard_layout.addWidget(QLabel('MSeed Wildcard'))
wf_grid.addWidget(self.wf_all_check_box, 0, 0, 1, 2) 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) add_separation_line(left_layout)
chan_layout = QtWidgets.QHBoxLayout() chan_layout = QHBoxLayout()
chan_layout.setContentsMargins(0, 0, 0, 0) chan_layout.setContentsMargins(0, 0, 0, 0)
chan_layout.setSpacing(0) chan_layout.setSpacing(0)
left_layout.addLayout(chan_layout) 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) 'All SOH ', self.central_widget)
self.all_soh_chan_check_box.setChecked(True) self.all_soh_chans_check_box.setChecked(True)
chan_layout.addWidget(self.all_soh_chan_check_box) 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) 'Pref', self.central_widget)
self.prefer_soh_chan_button.setFixedWidth(47) self.prefer_soh_chan_button.setFixedWidth(47)
chan_layout.addWidget(self.prefer_soh_chan_button) chan_layout.addWidget(self.prefer_soh_chan_button)
chan_layout.addWidget(QtWidgets.QLabel('Cur')) chan_layout.addWidget(QLabel('Cur'))
self.curr_soh_ids_name_line_edit = QtWidgets.QLineEdit( self.curr_soh_ids_name_line_edit = QLineEdit(
self.central_widget) self.central_widget)
chan_layout.addWidget(self.curr_soh_ids_name_line_edit) chan_layout.addWidget(self.curr_soh_ids_name_line_edit)
submit_layout = QtWidgets.QHBoxLayout() submit_layout = QHBoxLayout()
submit_layout.setSpacing(5) submit_layout.setSpacing(5)
left_layout.addLayout(submit_layout) 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') self.read_button.setToolTip('Read selected files')
submit_layout.addWidget(self.read_button) 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') self.stop_button.setToolTip('Halt ongoing read')
submit_layout.addWidget(self.stop_button) submit_layout.addWidget(self.stop_button)
self.save_plot_button = QtWidgets.QPushButton( self.save_plot_button = QPushButton(
'Save plot', self.central_widget) 'Save plot', self.central_widget)
self.save_plot_button.setToolTip('Save plots to disk') self.save_plot_button.setToolTip('Save plots to disk')
submit_layout.addWidget(self.save_plot_button) 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) left_layout.addWidget(self.info_list_widget, 1)
def create_shortcuts(self, main_window): def create_shortcuts(self, main_window):
seq = QtGui.QKeySequence('Ctrl+F') seq = QtGui.QKeySequence('Ctrl+F')
chdir_shortcut = QtWidgets.QShortcut(seq, main_window) chdir_shortcut = QShortcut(seq, main_window)
chdir_shortcut.activated.connect( chdir_shortcut.activated.connect(
main_window.change_current_directory) main_window.change_current_directory)
...@@ -529,7 +545,7 @@ class UIMainWindow(object): ...@@ -529,7 +545,7 @@ class UIMainWindow(object):
help_menu = main_menu.addMenu("Help") 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") # exitAction.setShortcut("Ctrl+X")
self.create_file_menu(main_window, file_menu) self.create_file_menu(main_window, file_menu)
self.create_command_menu(main_window, command_menu) self.create_command_menu(main_window, command_menu)
...@@ -544,7 +560,7 @@ class UIMainWindow(object): ...@@ -544,7 +560,7 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with :param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - File Menu :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) menu.addAction(self.exit_action)
def create_command_menu(self, main_window, menu): def create_command_menu(self, main_window, menu):
...@@ -554,11 +570,11 @@ class UIMainWindow(object): ...@@ -554,11 +570,11 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with :param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - Commands Menu :param menu: QMenu - Commands Menu
""" """
self.gps_plotter_action = QtWidgets.QAction( self.gps_plotter_action = QAction(
'GPS Plotter', main_window) 'GPS Plotter', main_window)
menu.addAction(self.gps_plotter_action) menu.addAction(self.gps_plotter_action)
self.log_search_action = QtWidgets.QAction( self.log_search_action = QAction(
'Log Search', main_window) 'Log Search', main_window)
menu.addAction(self.log_search_action) menu.addAction(self.log_search_action)
...@@ -568,37 +584,37 @@ class UIMainWindow(object): ...@@ -568,37 +584,37 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with :param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - Options Menu :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) menu.addMenu(mp_coloring_menu)
mp_coloring_group = QtWidgets.QActionGroup(main_window) mp_coloring_group = QActionGroup(main_window)
self.mp_regular_color_action = QtWidgets.QAction( self.mp_regular_color_action = QAction(
'0.5, 2.0, 4.0, 7.0 (Regular)', main_window) '0.5, 2.0, 4.0, 7.0 (Regular)', main_window)
self.mp_regular_color_action.setCheckable(True) self.mp_regular_color_action.setCheckable(True)
mp_coloring_menu.addAction(self.mp_regular_color_action) mp_coloring_menu.addAction(self.mp_regular_color_action)
mp_coloring_group.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) '0.5, 1.8, 2.4, 3.5 (Trillium)', main_window)
self.mp_trillium_color_action.setCheckable(True) self.mp_trillium_color_action.setCheckable(True)
mp_coloring_menu.addAction(self.mp_trillium_color_action) mp_coloring_menu.addAction(self.mp_trillium_color_action)
mp_coloring_group.addAction(self.mp_trillium_color_action) mp_coloring_group.addAction(self.mp_trillium_color_action)
menu.addSeparator() menu.addSeparator()
self.add_positions_to_et_action = QtWidgets.QAction( self.add_positions_to_et_action = QAction(
'Add Positions to ET Lines', main_window) 'Add Positions to ET Lines', main_window)
self.add_positions_to_et_action.setCheckable(True) self.add_positions_to_et_action.setCheckable(True)
menu.addAction(self.add_positions_to_et_action) 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) menu.addMenu(date_format_menu)
self.yyyy_doy_action = QtWidgets.QAction( self.yyyy_doy_action = QAction(
'YYYY:DOY', main_window) 'YYYY:DOY', main_window)
self.yyyy_doy_action.setCheckable(True) self.yyyy_doy_action.setCheckable(True)
date_format_menu.addAction(self.yyyy_doy_action) 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) 'YYYY-MM-DD', main_window)
self.yyyy_mm_dd_action.setCheckable(True) self.yyyy_mm_dd_action.setCheckable(True)
date_format_menu.addAction(self.yyyy_mm_dd_action) date_format_menu.addAction(self.yyyy_mm_dd_action)
self.yyyymmmdd_action = QtWidgets.QAction( self.yyyymmmdd_action = QAction(
'YYYYMMMDD', main_window) 'YYYYMMMDD', main_window)
self.yyyymmmdd_action.setCheckable(True) self.yyyymmmdd_action.setCheckable(True)
date_format_menu.addAction(self.yyyymmmdd_action) date_format_menu.addAction(self.yyyymmmdd_action)
...@@ -610,19 +626,19 @@ class UIMainWindow(object): ...@@ -610,19 +626,19 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with :param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - Database Menu :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) 'Add/Edit Data Types', main_window)
menu.addAction(self.add_edit_data_type_action) 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) 'Add/Edit Parameters', main_window)
menu.addAction(self.add_edit_param_action) 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) 'Add/Edit Channels', main_window)
menu.addAction(self.add_edit_channel_action) 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) 'View Plot Types', main_window)
menu.addAction(self.view_plot_type_action) menu.addAction(self.view_plot_type_action)
...@@ -633,19 +649,19 @@ class UIMainWindow(object): ...@@ -633,19 +649,19 @@ class UIMainWindow(object):
:param main_window: QMainWindow - main GUI for user to interact with :param main_window: QMainWindow - main GUI for user to interact with
:param menu: QMenu - Help Menu :param menu: QMenu - Help Menu
""" """
self.calendar_action = QtWidgets.QAction( self.calendar_action = QAction(
'Calendar', main_window) 'Calendar', main_window)
menu.addAction(self.calendar_action) menu.addAction(self.calendar_action)
self.about_action = QtWidgets.QAction( self.about_action = QAction(
'About', main_window) 'About', main_window)
menu.addAction(self.about_action) 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) menu.addAction(self.doc_action)
def create_forms_menu(self, main_window, menu): 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) "No Forms Are Open", main_window)
menu.addAction(self.no_forms_action) menu.addAction(self.no_forms_action)
self.no_forms_action.setEnabled(False) self.no_forms_action.setEnabled(False)
...@@ -720,8 +736,18 @@ class UIMainWindow(object): ...@@ -720,8 +736,18 @@ class UIMainWindow(object):
self.replot_button.clicked.connect(main_window.replot_loaded_data) self.replot_button.clicked.connect(main_window.replot_loaded_data)
self.all_soh_chan_check_box.clicked.connect( self.all_wf_chans_check_box.clicked.connect(
main_window.all_chan_clicked) 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( self.prefer_soh_chan_button.clicked.connect(
main_window.open_channel_preferences) main_window.open_channel_preferences)
self.read_button.clicked.connect(main_window.read_selected_files) self.read_button.clicked.connect(main_window.read_selected_files)
......
import re
from pathlib import Path from pathlib import Path
from typing import Dict, List, Tuple, Union from typing import Dict, List, Tuple, Union
from sohstationviewer.view.util.enums import LogType from sohstationviewer.view.util.enums import LogType
from sohstationviewer.conf import constants as const 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)\ 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: ...@@ -160,5 +163,46 @@ def log_str(log_info: Tuple[str, LogType]) -> str:
return f"{log_type.name}: {log_text}" 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__': if __name__ == '__main__':
create_table_of_content_file(Path('../../../documentation')) 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 ...@@ -6,10 +6,13 @@ from unittest import TestCase
from sohstationviewer.view.util.functions import ( from sohstationviewer.view.util.functions import (
get_soh_messages_for_view, log_str, is_doc_file, 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.view.util.enums import LogType
from sohstationviewer.conf import constants as const from sohstationviewer.conf import constants as const
from sohstationviewer.conf.constants import (WF_1ST, WF_2ND, WF_3RD)
class TestGetSOHMessageForView(TestCase): class TestGetSOHMessageForView(TestCase):
...@@ -208,3 +211,165 @@ class TestCreateTableOfContentFile(TestCase): ...@@ -208,3 +211,165 @@ class TestCreateTableOfContentFile(TestCase):
"+ [file1](file1.help.md)\n\n", "+ [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."
)