From db7f9b85795e409a264029e28e15fea55cd1d338 Mon Sep 17 00:00:00 2001
From: Kien Le <kienle@passcal.nmt.edu>
Date: Fri, 21 Apr 2023 14:12:44 -0600
Subject: [PATCH] Save read options to config file

---
 .gitignore                           |   3 +
 sohstationviewer/view/main_window.py |  43 +++++++-
 sohstationviewer/view/ui/main_ui.py  | 144 +++++++++++++++++++++++++++
 3 files changed, 189 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 2baa0937c..e8dc4f63e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,3 +86,6 @@ ENV/
 .idea/
 
 .DS_Store
+
+# program config
+sohstationviewer/conf/read_settings.ini
diff --git a/sohstationviewer/view/main_window.py b/sohstationviewer/view/main_window.py
index e55b13a24..6f587cd57 100755
--- a/sohstationviewer/view/main_window.py
+++ b/sohstationviewer/view/main_window.py
@@ -182,7 +182,9 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         self.is_plotting_tps: bool = False
         self.is_stopping: bool = False
 
-        self.background_black_radio_button.toggle()
+        self.read_config()
+        self.validate_config()
+        self.apply_config()
 
     @QtCore.Slot()
     def open_data_type(self) -> None:
@@ -953,6 +955,45 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         for window in QtWidgets.QApplication.topLevelWidgets():
             window.close()
 
+        self.write_config()
+
+    def write_config(self):
+        """
+        Write the current state of the program to the config file.
+        """
+        self.config.set('FileRead', 'from_data_card',
+                        str(self.from_data_card_check_box.isChecked()))
+        self.config.set('FileRead', 'data',
+                        str(self.data_radio_button.isChecked()))
+        self.config.set('FileRead', 'sdata',
+                        str(self.sdata_radio_button.isChecked()))
+        self.config.set('ColorMode', 'black',
+                        str(self.background_black_radio_button.isChecked()))
+        self.config.set('ColorMode', 'white',
+                        str(self.background_white_radio_button.isChecked()))
+        self.config.set('Gap', 'min_gap_length',
+                        self.gap_len_line_edit.text())
+        self.config.set('Channels', 'mp123zne',
+                        str(self.mass_pos_123zne_check_box.isChecked()))
+        self.config.set('Channels', 'mp456uvw',
+                        str(self.mass_pos_456uvw_check_box.isChecked()))
+        self.config.set('Channels', 'all_waveform_chans',
+                        str(self.all_wf_chans_check_box.isChecked()))
+        for i, checkbox in enumerate(self.ds_check_boxes, start=1):
+            self.config.set('Channels', f'ds{i}', str(checkbox.isChecked()))
+        self.config.set('Channels', 'mseed_wildcard',
+                        self.mseed_wildcard_edit.text())
+        self.config.set('Channels', 'plot_tps',
+                        str(self.tps_check_box.isChecked()))
+        self.config.set('Channels', 'plot_raw',
+                        str(self.raw_check_box.isChecked()))
+        self.config.set('ChannelsPreference', 'all_soh',
+                        str(self.all_soh_chans_check_box.isChecked()))
+        self.config.set('ChannelsPreference', 'pref_code',
+                        self.curr_pref_soh_list_name_txtbox.text())
+        with open('sohstationviewer/conf/read_settings.ini', 'w') as file:
+            self.config.write(file)
+
     def delete_old_temp_data_folder(self) -> None:
         """
         Delete temp_data_folder which is used for keeping memmap files in case
diff --git a/sohstationviewer/view/ui/main_ui.py b/sohstationviewer/view/ui/main_ui.py
index 2fa1d897d..29ea00c64 100755
--- a/sohstationviewer/view/ui/main_ui.py
+++ b/sohstationviewer/view/ui/main_ui.py
@@ -1,4 +1,6 @@
 # UI and connectSignals for main_window
+import configparser
+from pathlib import Path
 from typing import Union, List, Optional
 
 from PySide2 import QtCore, QtGui, QtWidgets
@@ -263,6 +265,8 @@ class UIMainWindow(object):
         """
         self.doc_action: Union[QAction, None] = None
 
+        self.config: Union[configparser.ConfigParser, None] = None
+
     def setup_ui(self, main_window):
         """
         Setting up layout, widgets, menus for main_window
@@ -451,6 +455,8 @@ class UIMainWindow(object):
         gap_layout.addWidget(self.gap_len_line_edit)
         gap_layout.addWidget(QLabel(' m'))
 
+        add_separation_line(left_layout)
+
         mass_pos_layout = QHBoxLayout()
         left_layout.addLayout(mass_pos_layout)
         mass_pos_layout.addWidget(QLabel('Mass Pos '))
@@ -785,3 +791,141 @@ class UIMainWindow(object):
         self.read_button.clicked.connect(main_window.read_selected_files)
 
         self.stop_button.clicked.connect(main_window.stop)
+
+    def read_config(self):
+        self.config = configparser.ConfigParser()
+        config_path = Path('sohstationviewer/conf/read_settings.ini')
+        if not config_path.exists():
+            default_config = '''
+            [FileRead]
+            from_data_card = False
+            data = False
+            sdata = False
+            
+            [ColorMode]
+            black = True
+            white = False
+            
+            [Gap]
+            min_gap_length =
+            
+            [Channels]
+            mp123zne = False
+            mp456uvw = False
+            all_waveform_chans = False
+            ds1 = False
+            ds2 = False
+            ds3 = False
+            ds4 = False
+            ds5 = False
+            ds6 = False
+            ds7 = False
+            ds8 = False
+            mseed_wildcard =
+            plot_tps = False
+            plot_raw = False
+            
+            [ChannelsPreference]
+            all_soh = True
+            pref_code =
+            '''
+            self.config.read_string(default_config)
+        else:
+            self.config.read(config_path)
+
+    def validate_config(self):
+        class BadConfigError(RuntimeError):
+            """
+            Error raised when there is a problem with the configuration
+            """
+            pass
+
+        expected_keys = {'from_data_card', 'data', 'sdata',
+                         'black', 'white',
+                         'min_gap_length',
+                         'mp123zne', 'mp456uvw', 'all_waveform_chans', 'ds1',
+                         'ds2', 'ds3', 'ds4', 'ds5', 'ds6', 'ds7', 'ds8',
+                         # noqa
+                         'mseed_wildcard', 'plot_tps', 'plot_raw',
+                         'all_soh', 'pref_code'}
+        loaded_keys = {item[0]
+                       for (section, _) in self.config.items()
+                       for item in self.config.items(section)}
+        missing_keys = expected_keys - loaded_keys
+        if missing_keys:
+            raise BadConfigError(f'Some required keys are missing. Please'
+                                 f'make sure they are in the config file. The '
+                                 f'missing keys are: {", ".join(missing_keys)}'
+                                 )
+
+        data_checked = self.config.getboolean('FileRead', 'data')
+        sdata_checked = self.config.getboolean('FileRead', 'sdata')
+        if data_checked and sdata_checked:
+            raise BadConfigError('data and sdata cannot both be chosen.')
+
+        black_color_mode = self.config.getboolean('ColorMode', 'black')
+        white_color_mode = self.config.getboolean('ColorMode', 'white')
+        if black_color_mode and white_color_mode:
+            raise BadConfigError('Cannot be in both color modes at once.')
+
+        all_waveform_chans = self.config.getboolean('Channels',
+                                                    'all_waveform_chans')
+        data_stream_chosen = any(self.config.getboolean('Channels', f'ds{i}')
+                                 for i in range(1, 9)
+                                 )
+        mseed_wildcard = self.config.get('Channels',
+                                         'mseed_wildcard')
+        wildcard_not_empty = (mseed_wildcard != '')
+        if all_waveform_chans and (data_stream_chosen or wildcard_not_empty):
+            raise BadConfigError(
+                'Waveform channel selector can only be in one mode at a time.')
+
+        all_soh = self.config.getboolean('ChannelsPreference', 'all_soh')
+        channel_pref_code = self.config.get('ChannelsPreference', 'pref_code')
+        if all_soh and (channel_pref_code != ''):
+            raise BadConfigError('You can only choose one list of channels to '
+                                 'be plotted.')
+
+    def apply_config(self):
+        get_bool = self.config.getboolean
+
+        self.from_data_card_check_box.setChecked(
+            get_bool('FileRead', 'from_data_card')
+        )
+        self.data_radio_button.setChecked(get_bool('FileRead', 'data'))
+        self.sdata_radio_button.setChecked(get_bool('FileRead', 'sdata'))
+
+        self.background_black_radio_button.setChecked(
+            get_bool('ColorMode', 'black')
+        )
+        self.background_white_radio_button.setChecked(
+            get_bool('ColorMode', 'white')
+        )
+
+        self.gap_len_line_edit.setText(
+            self.config.get('Gap', 'min_gap_length')
+        )
+
+        self.mass_pos_123zne_check_box.setChecked(
+            get_bool('Channels', 'mp123zne')
+        )
+        self.mass_pos_456uvw_check_box.setChecked(
+            get_bool('Channels', 'mp456uvw')
+        )
+        self.all_wf_chans_check_box.setChecked(
+            get_bool('Channels', 'all_waveform_chans')
+        )
+        for i, checkbox in enumerate(self.ds_check_boxes, start=1):
+            checkbox.setChecked(get_bool('Channels', f'ds{i}'))
+        self.mseed_wildcard_edit.setText(
+            self.config.get('Channels', 'mseed_wildcard')
+        )
+        self.tps_check_box.setChecked(get_bool('Channels', 'plot_tps'))
+        self.raw_check_box.setChecked(get_bool('Channels', 'plot_raw'))
+
+        self.all_soh_chans_check_box.setChecked(
+            get_bool('ChannelsPreference', 'all_soh')
+        )
+        self.curr_pref_soh_list_name_txtbox.setText(
+            self.config.get('ChannelsPreference', 'pref_code')
+        )
-- 
GitLab