From fc73f18a0d7dcf8c4fca488d97a6bb1c5df72ff9 Mon Sep 17 00:00:00 2001
From: destinyk <destiny.kuehn@student.nmt.edu>
Date: Mon, 21 Aug 2023 16:54:28 -0600
Subject: [PATCH] create main window and trace headers tab

---
 fixhdr/pyside.py | 580 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 580 insertions(+)
 create mode 100644 fixhdr/pyside.py

diff --git a/fixhdr/pyside.py b/fixhdr/pyside.py
new file mode 100644
index 0000000..5416215
--- /dev/null
+++ b/fixhdr/pyside.py
@@ -0,0 +1,580 @@
+import os
+import sys
+import time
+from itertools import repeat
+
+from getopt import getopt
+from glob import glob
+from operator import mod
+from PySide2 import QtWidgets, QtGui, QtCore
+
+#from fixhdr.LibTrace import *
+from LibTrace import *
+
+VERSION = "2022.1.0.0"
+
+SPACE = " "
+DATALOC = ""
+
+# vars used for batchmode
+BatchFile = ""
+Endianess = ""
+RunHeaderBatch = 0
+RunTimeBatch = 0
+RunEndianBatch = 0
+BATCHMODE = 0
+
+
+def Usage(err=''):
+    print(err)
+    print("Usage\nfixhdr \nfixhdr -#\nfixhdr -h\nfixhdr [-d DataDirs] "
+          "[-m batch_file] [-t batch_file] [-e endianess]")
+    print("\n       Invoked with no arguements, fixhdr will launch the GUI\n")
+    print("       -d DataDirs - colon separated list of data directories "
+          "[default: cwd]")
+    print("       -e endianess - convert trace headers to endianess ["
+          "big or little]")
+    print("       -h - this usage page")
+    print("       -m batch_file - correct mseed headers in batch mode using "
+          "batch_file")
+    print("       -t batch_file - correct trace timing in batch mode using "
+          "batch_file")
+    print("       -# - print version number")
+    print("      NOTE: -m, -t & -e are mutually exclusive. If you wish to do")
+    print("             both timing and headers, run time corrections first.")
+
+
+# get commandline args
+try:
+    opts, pargs = getopt(sys.argv[1:], 'hd:t:m:e:#')
+except Exception:
+    err = "\nERROR: Invalid command line usage\n"
+    Usage(err)
+    sys.exit(1)
+else:
+    for flag, arg in opts:
+        if flag == "-h":
+            Usage()
+            sys.exit(0)
+        if flag == "-d":
+            DATALOC = arg
+        if flag == "-e":
+            Endianess = arg
+            if Endianess != "big" and Endianess != "little":
+                err = "\nError: Endianess must be either 'big' or 'little'"
+                Usage(err)
+            RunEndianBatch = 1
+            BATCHMODE = 1
+        if flag == "-m":
+            BatchFile = arg
+            RunHeaderBatch = 1
+            BATCHMODE = 1
+        if flag == "-t":
+            BatchFile = arg
+            RunTimeBatch = 1
+            BATCHMODE = 1
+        if flag == "-#":
+            print(VERSION)
+            sys.exit(0)
+    if RunTimeBatch + RunHeaderBatch + RunEndianBatch > 1:
+        err = ("\nERROR: Cannot correct timing, headers and/or endianess "
+               "simultaniously\n")
+        Usage(err)
+        sys.exit(1)
+print("\n", os.path.basename(sys.argv[0]), VERSION)
+
+
+# main
+class MainWindow(QtWidgets.QWidget):
+    def __init__(self, BatchFile=''):
+        super().__init__()
+        self.resize(600,400)
+        self.setWindowTitle("fixhdr " + VERSION)
+
+        # set timezone to UTC
+        os.environ['TZ'] = 'GMT'
+        time.tzname = ('GMT', 'GMT')
+        time.timezone = 0
+
+        # set global vars
+        self.initVars()
+
+        # build main window and tabs
+        self.buildWindow()
+        self.buildTraceHeaders()
+        self.buildGlobalModify()
+        self.buildTimeShift()
+        self.buildEndianess()
+        self.buildLog()
+        self.buildHelp()
+        self.buildMSEEDformat()
+
+    def initVars(self):
+        """
+        Initialize variables, lists, and dictionaries 
+        associated with traces and trace headers
+        """
+
+        self.e_width = 24
+        self.OldSID = ""
+        self.DataDirs = ""
+        self.StatSel = ""
+        self.StatSelList = []
+        self.TraceDict = {}
+        self.UpdateHdrDict = {}
+        self.StatChanList = []
+        self.StationName = ""
+        self.Station = ""
+        self.NetCode = ""
+        self.SampleRate = 0
+        self.Channel = ""
+        self.LocCode = ""
+        self.StatChanListVars = [
+            ["Stat:Chan:Loc:Net:Sps", self.StationName],
+            ["Station_Name", self.Station],
+            ["Channel", self.Channel],
+            ["Location_Code", self.LocCode],
+            ["Network_Code", self.NetCode],
+            ["Sample_Rate", self.SampleRate]
+        ]
+
+        # New Values on Trace Headers notebook
+        self.NStation = ""
+        self.NChannel = ""
+        self.NLocCode = ""
+        self.NNetCode = ""
+        self.NewVars = [
+            ["Station_Name", self.NStation],
+            ["Channel", self.NChannel],
+            ["Location_Code", self.NLocCode],
+            ["Network_Code", self.NNetCode]
+        ]
+
+        # Modified button on Trace Headers notebook
+        # denote whether applied updates or not
+        self.SetStat = 0
+        self.SetChan = 0
+        self.SetLoc = 0
+        self.SetNet = 0
+        self.SetHdrVars = [
+            ["Station_Name", self.SetStat],
+            ["Channel", self.SetChan],
+            ["Location_Code", self.SetLoc],
+            ["Network_Code", self.SetNet]
+        ]
+        self.SetHdrDict = {}
+
+        # vars used in global nb
+        self.GlobalStation = ""
+        self.GlobalChannel = ""
+        self.GlobalLocCode = ""
+        self.GlobalSps = ""
+        self.GlobalNetCode = ""
+
+        # global update variables
+        self.GUStation = ""
+        self.GUChannel = ""
+        self.GULocCode = ""
+        self.GUSps = ""
+        self.GUNetCode = ""
+
+        # lists for dropdown menus on Global Modify notebook
+        self.StationList = []
+        self.ChannelList = []
+        self.LocList = []
+        self.NetList = []
+        self.SpsList = []
+
+        self.GlobalListVars = [
+            ["Station_Name", self.GlobalStation, self.StationList,
+             self.GUStation],
+            ["Channel", self.GlobalChannel, self.ChannelList, self.GUChannel],
+            ["Location_Code", self.GlobalLocCode, self.LocList,
+             self.GULocCode],
+            ["Network_Code", self.GlobalNetCode, self.NetList,
+             self.GUNetCode],
+            ["Sample_Rate", self.GlobalSps, self.SpsList, self.GUSps]
+        ]
+
+        # vars used in TimeShift nb
+        self.TimeShiftName = ""
+        self.OldShiftName = ""
+        self.TSStartTime = ""
+        self.TSEndTime = ""
+        self.TSShift = 0
+        self.TypeTimeCor = 0
+        self.TimeTagQuest = ""
+        self.WildLoc = 0
+        self.PopUpHelp = 0
+        self.UpdateTimeDict = {}
+        self.TraceTimeDict = {}
+        self.SetTimeDict = {}
+        self.TimeCorrectedFiles = {}
+
+        self.ShiftVars = [
+            ["Start_Time", self.TSStartTime],
+            ["End_Time", self.TSEndTime],
+            ["Time_Shift_sec", self.TSShift],
+            ["Time_Tag_Quest", self.TimeTagQuest],
+            ["Corr_Type", self.TypeTimeCor]
+        ]
+
+        self.SetTime = 0
+        self.SetTQuest = 0
+        self.SetTimeVars = [
+            ["Time_Shift_sec", self.SetTime],
+            ["Time_Tag_Quest", self.SetTQuest]
+        ]
+
+        # vars used in Endianess nb
+        self.Savefile = ""
+        self.DataDirList = []
+        self.BigEndianList = []
+        self.LittleEndianList = []
+        self.NumLittleFiles = 0
+        self.NumBigFiles = 0
+        self.ToEndian = ""
+
+        # log vars and lists
+        self.LogList = [
+            ["All", 0],
+            ["Header", 1],
+            ["Timing", 2],
+            ["Endian", 3]
+        ]
+
+        self.LogVar = 0
+        self.LogAll = []
+        self.LogHeader = []
+        self.LogTime = []
+        self.LogEndian = []
+        self.LogSummary = []
+
+        # activity and warning vars
+        self.ActiveText = ""
+        self.AlteredText = ""
+
+        # set of vars watched for active threading event
+        self.RunBuilddb = 0
+        self.RunModHdrs = 0
+        self.RunApplyTimeCor = 0
+        self.RunChangeEndian = 0
+        self.FoundFiles = 0
+        self.RWErrors = 0
+        self.CancelWarn = 0
+        self.IgnoreWarn = 0
+        self.UseNewOnlyTime = 0
+
+        # if DATALOC not set on commandline set here
+        if DATALOC:
+            self.DataDirs = DATALOC
+        else:
+            self.DataDirs = os.getcwd()
+
+        # if a batch file exists on the command line,
+        # we just run necessary processes for modifying headers
+        self.BatchFile = ""
+        self.BatchFile = BatchFile
+
+        # INSERT BATCHMODE HERE
+        """
+        if BATCHMODE:
+            # address endian change first since unique i.e. no batchfile
+            print("Running in Batch Mode")
+            if RunEndianBatch:
+                print("Changing Endianess to: ", Endianess)
+                self.ToEndian.set(Endianess)
+                self.RunChangeEndian.set(1)
+                print("Finding Files beneath directory: ",
+                      self.DataDirs.get())
+                self.BuildTrcList()
+                self.ChangeEndian()
+            else:
+                if RunTimeBatch:
+                    print("Correcting Timing")
+                if RunHeaderBatch:
+                    print("Correcting Headers")
+
+                print("Using Template: ", self.BatchFile.get())
+                self.LoadTemplate()
+                if RunTimeBatch:
+                    if not self.UpdateTimeDict:
+                        print("No Timing Corrections in Template.\nDone")
+                        sys.exit(1)
+                    print("Finding Files beneath directory: ",
+                          self.DataDirs.get())
+                    self.BuildTrcList()
+                    self.RunApplyTimeCor.set(1)
+                    self.ApplyTimeCor()
+                if RunHeaderBatch:
+                    if not self.UpdateHdrDict:
+                        print("No Header Corrections in Template.\nDone")
+                        sys.exit(1)
+                    print("Finding Files beneath directory: ",
+                          self.DataDirs.get())
+                    self.BuildTrcList()
+                    self.RunModHdrs.set(1)
+                    self.ModHdrs()
+            print("Done")
+            sys.exit(0)
+            """
+
+    def buildWindow(self):
+        """
+        Build widgets for root window
+        """
+
+        # tab widget
+        self.tabWidget = QtWidgets.QTabWidget()
+        self.tabWidget.addTab(QtWidgets.QWidget(), "Trace Headers")
+        self.tabWidget.addTab(QtWidgets.QWidget(), "Global Modify")
+        self.tabWidget.addTab(QtWidgets.QWidget(), "Time Shift")
+        self.tabWidget.addTab(QtWidgets.QWidget(), "Endianess")
+        self.tabWidget.addTab(QtWidgets.QWidget(), "Log")
+        self.tabWidget.addTab(QtWidgets.QWidget(), "Help")
+        self.tabWidget.addTab(QtWidgets.QWidget(), "MSEED format")
+
+        # save
+        self.save_b = QtWidgets.QPushButton("Save Template")
+        self.save_b.clicked.connect(self.clickedSaveTemplate)
+        self.save_b.setToolTip("Export saved header & \ntiming corrections to file")
+        self.save_b.setStyleSheet("QPushButton::hover{background-color:green;}")
+
+        # load
+        self.load_b = QtWidgets.QPushButton("Load Template")
+        self.load_b.clicked.connect(self.clickedLoadTemplate)
+        self.load_b.setToolTip("Import saved header &\ntiming corrections file")
+        self.load_b.setStyleSheet("QPushButton::hover{background-color:green;}")
+
+        # exit
+        exit_b = QtWidgets.QPushButton("Exit")
+        exit_b.clicked.connect(lambda: quit())
+        exit_b.setToolTip("Exit program")
+        exit_b.setStyleSheet("QPushButton::hover{background-color:red;}")
+
+        # groupbox for buttons/widgets under tab widget
+        box = QtWidgets.QGroupBox()
+        
+        self.PopUpHelp_cb = QtWidgets.QCheckBox("PopUp Help")
+        self.PopUpHelp_cb.setChecked(True)
+        self.PopUpHelp_cb.clicked.connect(self.clickedPopUpHelp)
+        self.PopUpHelp_cb.setToolTip("Toggles 'PopUp Help' on and off")
+
+
+        # groupbox layout
+        boxLayout = QtWidgets.QHBoxLayout()
+        boxLayout.addWidget(self.PopUpHelp_cb)
+        boxLayout.addStretch()
+        boxLayout.addWidget(self.load_b)
+        boxLayout.addWidget(self.save_b)
+        boxLayout.addWidget(exit_b)
+        boxLayout.setMargin(0)
+        box.setLayout(boxLayout)
+
+        # info bar
+        self.InfoString_l = QtWidgets.QLineEdit()
+        self.InfoString_l.setReadOnly(True)
+        self.InfoString_l.setStyleSheet("background-color:yellow")
+
+        # main window layout
+        mainLayout = QtWidgets.QVBoxLayout()
+        mainLayout.addWidget(self.tabWidget)
+        mainLayout.addWidget(box)
+        mainLayout.addWidget(self.InfoString_l)
+        mainLayout.setMargin(0)
+        self.setLayout(mainLayout)
+
+
+    def buildTraceHeaders(self):
+        """
+        Build widgets for Trace Headers tab for selecting traces, building trace database, and correcting
+        headers one key at a time
+        """
+
+        # data directory find and clear buttons, and entry field
+        # button to build trace db
+        box1 = QtWidgets.QGroupBox()
+
+        DataDirs_l = QtWidgets.QLabel("Data Directories:")
+        DataDirs_l.setToolTip("Search path(s) for finding mseed files.\n"
+                              "Colon separate multiple entries")
+        
+        self.DataDir_le = QtWidgets.QLineEdit()
+        self.DataDir_le.setText(self.DataDirs)
+        
+        self.BuildTrcList_b = QtWidgets.QPushButton("Build Trace db")
+        self.BuildTrcList_b.setStyleSheet("""
+                                          QPushButton{background-color:lightblue;}
+                                          QPushButton::hover{background-color:green;}
+                                          """)
+        self.BuildTrcList_b.setToolTip("Build a Trace db using\n"
+                                       "'Data Directories'\n"
+                                       "as top level directories")
+
+        self.FindDataDir_b = QtWidgets.QPushButton("Find")
+        self.FindDataDir_b.setStyleSheet("QPushButton::hover{background-color:green;}")
+        self.FindDataDir_b.setToolTip("Dialog window to\n"
+                                      "select Data Directories")
+
+        self.ClearDataDir_b = QtWidgets.QPushButton("Clear")
+        self.ClearDataDir_b.setStyleSheet("QPushButton::hover{background-color:orange;}")
+        self.ClearDataDir_b.setToolTip("Clears 'Data Directories' entry")
+
+        layout1 = QtWidgets.QHBoxLayout(box1)
+        layout1.addWidget(DataDirs_l)
+        layout1.addWidget(self.DataDir_le)
+        layout1.addWidget(self.BuildTrcList_b)
+        layout1.addWidget(self.FindDataDir_b)
+        layout1.addWidget(self.ClearDataDir_b)
+        layout1.setMargin(0)
+
+        # station selection frame and entry box
+        box2 = QtWidgets.QGroupBox()
+
+        StatSel_l = QtWidgets.QLabel("Find only stations (colon separated list):")
+        
+        self.StatSel_le = QtWidgets.QLineEdit()
+        self.StatSel_le.setToolTip("Filter trace search\n"
+                                   "for these stations")
+        
+        self.ClearStatSel_b = QtWidgets.QPushButton("Clear")
+        self.ClearStatSel_b.setStyleSheet("QPushButton::hover{background-color:orange;}")
+        self.ClearStatSel_b.setToolTip("Clear station filter")
+
+        layout2 = QtWidgets.QHBoxLayout(box2)
+        layout2.addWidget(StatSel_l)
+        layout2.addWidget(self.StatSel_le)
+        layout2.addWidget(self.ClearStatSel_b)
+        layout2.setMargin(0)
+
+        # global substitutions
+        box3 = QtWidgets.QGroupBox()
+
+        layout3 = QtWidgets.QHBoxLayout(box3)
+        layout31 = QtWidgets.QFormLayout()
+        layout32 = QtWidgets.QFormLayout()
+        layout3.addLayout(layout31)
+        layout3.addLayout(layout32)
+
+        for widget in self.StatChanListVars:
+            if widget[0] == "Stat:Chan:Loc:Net:Sps":
+                layout31.addRow(QtWidgets.QLabel(widget[0]), QtWidgets.QComboBox())
+            else:
+                layout31.addRow(QtWidgets.QLabel(widget[0]), QtWidgets.QLineEdit())
+        
+        layout32.addRow(QtWidgets.QLabel("New Values"), QtWidgets.QLabel("Applied"))
+
+        for _ in repeat(None, 4):
+            layout32.addRow(QtWidgets.QLineEdit(), QtWidgets.QCheckBox())
+
+
+        # 4th groupbox
+        box4 = QtWidgets.QGroupBox()
+        box4.setStyleSheet("QGroupBox{border:0px;}")
+
+        self.ListTraces_b = QtWidgets.QPushButton("List Traces")
+        self.ListTraces_b.setStyleSheet("QPushButton::hover{background-color:green;}")
+        self.ListTraces_b.setToolTip("Lists traces for selected\n"
+                                     "Stat:Chan:Loc:Net:Sps")
+
+        self.ModHdr_b = QtWidgets.QPushButton("Modify Headers")
+        self.ModHdr_b.setStyleSheet("""
+                                    QPushButton{background-color:lightblue;}
+                                    QPushButton::hover{background-color:green;}
+                                    """)
+        self.ModHdr_b.setToolTip("Modifies headers using current entries\n"
+                                 "and all entries in 'Update Dictionary")
+        
+        self.ClearCurrent_b = QtWidgets.QPushButton("Clear Current")
+        self.ClearCurrent_b.setStyleSheet("QPushButton::hover{background-color:orange;}")
+        self.ClearCurrent_b.setToolTip("Clears entries in 'Update Dictionary'\n"
+                                       "for selected Stat:Chan:Loc:Net:Sps")
+
+        self.ClearUpdateDict_b = QtWidgets.QPushButton("Clear Update Dictionary")
+        self.ClearUpdateDict_b.setStyleSheet("QPushButton::hover{background-color:orange;}")
+        self.ClearUpdateDict_b.setToolTip("Clears all entries\n"
+                                             "in 'Update Dictionary'")
+
+        layout4 = QtWidgets.QHBoxLayout(box4)
+        layout4.addWidget(self.ListTraces_b)
+        layout4.addStretch()
+        layout4.addWidget(self.ModHdr_b)
+        layout4.addWidget(self.ClearCurrent_b)
+        layout4.addWidget(self.ClearUpdateDict_b)
+        layout4.setMargin(0)
+
+        tabLayout = QtWidgets.QVBoxLayout(self.tabWidget.widget(0))
+        tabLayout.addWidget(box1)
+        tabLayout.addWidget(box2)
+        tabLayout.addWidget(box3)
+        tabLayout.addStretch()
+        tabLayout.addWidget(box4)
+        tabLayout.setMargin(0)
+
+
+    def buildGlobalModify(self):
+        """
+        Build widgets for Global Modify tab for making global changes to headers
+        """
+
+
+    def buildTimeShift(self):
+        """
+        Build widgets for Time Shift tab for applying time corrections to headers
+        """
+
+
+    def buildEndianess(self):
+        """
+        Build widgets for Endianness tab for swapping endianess of headers
+        """
+
+
+    def buildLog(self):
+        """
+        Build widgets for Log tab for keeping track of changes
+        """
+
+
+    def buildHelp(self):
+        """
+        Build widgets for Help tab
+        """
+
+
+    def buildMSEEDformat(self):
+        """
+        Build widgets for MSEED format tab
+        """
+
+
+    def clickedPopUpHelp(self):
+        """
+        """
+        
+
+    def clickedLoadTemplate(self):
+        """
+        """
+
+
+    def clickedSaveTemplate(self):
+        """
+        """
+    
+    def clickedBuildTrace(self):
+        """
+        """
+    
+    def clickedFind(self):
+        """
+        """
+
+
+
+if __name__ == "__main__":
+    app = QtWidgets.QApplication()
+    window = MainWindow()
+    window.show()
+    sys.exit(app.exec_())
+
-- 
GitLab