From 9ef3c4bd51fa8f167c88094b560a128a8b12a072 Mon Sep 17 00:00:00 2001 From: destinyk <destiny.kuehn@student.nmt.edu> Date: Mon, 3 Apr 2023 16:31:09 -0600 Subject: [PATCH] now uses pyside2 and verion number updated --- HISTORY.rst | 6 + conda.recipe/meta.yaml | 2 +- mseedpeek/mseedpeek.py | 2461 ++++++++++++++++++++-------------------- setup.py | 5 +- 4 files changed, 1251 insertions(+), 1223 deletions(-) mode change 100755 => 100644 mseedpeek/mseedpeek.py diff --git a/HISTORY.rst b/HISTORY.rst index 16e6d57..f95e757 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -22,3 +22,9 @@ History 2022.1.0.0 (2022-01-11) ------------------ * New versioning scheme + +2023.1.0.0 (2023-04-03) +------------------ +* Gui updated to PySide2 +* Pmw dependency dropped +* Version number updated diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 381116c..ca4f3bf 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -15,7 +15,7 @@ requirements: - pip run: - python >=3.6 - - pmw + - pyside2 test: source_files: diff --git a/mseedpeek/mseedpeek.py b/mseedpeek/mseedpeek.py old mode 100755 new mode 100644 index 7383dd0..d820daf --- a/mseedpeek/mseedpeek.py +++ b/mseedpeek/mseedpeek.py @@ -1,4 +1,5 @@ -#!/usr/bin/env python +""" +!/usr/bin/env python # gui for viewing mseed headers @@ -120,27 +121,40 @@ # # Update versioning scheme ################################################################ +# +# modification +# version: 2023.1.0.0 +# author: Destiny Kuehn +# +# GUI updated to PySide2 +# Pmw dependency dropped +# Version number updated +""" -import Pmw import sys +import os +import itertools from getopt import getopt from glob import glob from operator import mod -from os import * -from tkinter import * -from tkinter.filedialog import * +from PySide2 import QtCore, QtGui, QtWidgets + +#from libtrace import * +#from mseedInfo import * from mseedpeek.libtrace import * from mseedpeek.mseedInfo import * -VERSION = "2022.1.0.0" +VERSION = "2023.1.0.0" SPACE = " " - def main(): + """ + Main class for mseedpeek + """ # return version number if -# command line option - ListInFiles = [] + file_list = [] try: opts, pargs = getopt(sys.argv[1:], 'f#') for flag, arg in opts: @@ -148,7 +162,7 @@ def main(): InFiles = pargs for fl in InFiles: for f in glob(fl): - ListInFiles.append(f) + file_list.append(f) if flag == "-#": print(VERSION) sys.exit(0) @@ -156,638 +170,681 @@ def main(): print("\nInvalid command line usage\n") print("Usage:\nmseedpeek\nmseedpeek -#\nmseedpeek -f file(s)\n") sys.exit(1) - print("\n", os.path.basename(sys.argv[0]), VERSION) - if ListInFiles: - mw = MainWindow("mseedpeek %s" % VERSION, ListInFiles) - mw.root.geometry("775x545") - mw.root.mainloop() + app = QtWidgets.QApplication(sys.argv) + # mc = main class + if file_list: + mc = MainWindow("mseedpeek %s" % VERSION, file_list) else: - mw = MainWindow("mseedpeek %s" % VERSION) - mw.root.geometry("775x545") - mw.root.mainloop() + mc = MainWindow("mseedpeek %s" % VERSION, file_list=None) + mc.show() + sys.exit(app.exec_()) -# From "Python and Tkinter Programming", J.E. Grayson, pg.103 -class Command: - def __init__(self, func, *args, **kw): - self.func = func - self.args = args - self.kw = kw +class MainWindow(QtWidgets.QWidget): + """ + Main class for mseedpeek + """ + def __init__(self, title, file_list): + """ + Init everything for startup + """ + super().__init__() - def __call__(self, *args, **kw): - args = self.args + args - kw.update(self.kw) - self.func(*args, **kw) + # window settings + self.resize(self.minimumSize()) + self.setWindowTitle(title) -# -# Over ride some methods in FileDialog so we only select directories -# From TraceBuilder.py, auth Steve Azevedo & Lloyd Carothers -# + # init vars + self.data_init() + # set up main window + self.create_main_window() + self.build_blockettes() + self.build_help() + self.hide_show("hide") -class DirectoryDialog(FileDialog): - - title = "Directory Select" - - def __init__(self, root): - FileDialog.__init__(self, root) - - # Only allow selection of directories (single click) - def files_select_event(self, e): - pass - # Double click - - def files_double_event(self, e): - pass - - # Make sure it's a directory and accessable - def ok_command(self): - ifile = self.get_selection() - if not path.isdir(ifile): - if not access(ifile, R_OK): - self.root.bell() - ifile = None - self.quit(ifile) - - -class MainWindow: - def __init__(self, title='', InFiles=''): - - self.root = Tk() - Pmw.initialise(self.root) - self.root.title(title) - - self.e_width = 8 - self.InfoString = StringVar() - - # if files entered on commandline set self.ListInFiles - self.ListInFiles = {} - if InFiles: - self.ListInFiles = InFiles - # some standard vars - self.DataDirs = StringVar() - self.StatSel = StringVar() - self.StatSelList = [] - self.Trace = StringVar() - self.SelDir = StringVar() - self.SelDir.set("") - self.Station = StringVar() - self.NetCode = StringVar() - self.SampleRate = IntVar() - self.Channel = StringVar() - self.LocCode = StringVar() - self.ByteOrder = StringVar() - - # positional vars - self.ByteOffset = IntVar() - self.BlkSize = IntVar() - - # dictionaries, lists and misc vars - self.BlockNum = IntVar() - self.JumpNum = IntVar() - self.NumBlocks = IntVar() - self.FixedHdrDict = {} - self.RateDict = {} - self.Blockettes = {} - self.BlockettesList = [] - self.UniqueList = [] - self.UniqueSelectList = [] - self.UniqueSelect = StringVar() - self.TraceList = [] - self.TraceListDict = {} - - # file and verbosity vars - self.MseedFile = StringVar() - self.Blockette = StringVar() - self.BlocketteType = StringVar() - self.OldMseedFile = StringVar() - self.VerbVar = IntVar() - self.OldVerbVar = IntVar() - self.VerbList = [ - ["Standard", 0], - ["Verbose", 1], - ["Very Verbose", 2], - ["Unique", 3] - ] - self.VerbVar.set(0) - self.OldVerbVar.set(0) - - # verbosity lists - each builds on the previous - self.StandardVars = [ - ["Station Name:", self.Station], - ["Location Code:", self.LocCode], - ["Channel:", self.Channel], - ["Net Code:", self.NetCode], - ["Sps (nominal):", self.SampleRate] - ] + # if files entered on commandline call build trace + if file_list: + self.dd_text.setText(':'.join(str(file) for file in file_list)) + self.build_trace_list(self.dd_text.text()) - self.Year = StringVar() - self.Jday = StringVar() - self.Hour = StringVar() - self.Min = StringVar() - self.Sec = StringVar() - self.Micro = StringVar() - self.VerboseVars = [ - ["Year:", self.Year], - ["Day:", self.Jday], - ["Hour:", self.Hour], - ["Min:", self.Min], - ["Sec:", self.Sec], - ["0.0001s:", self.Micro] - ] - self.VerboseVars = self.StandardVars + self.VerboseVars - - self.SeqNum = StringVar() - self.DQual = StringVar() - self.Resv = StringVar() - self.AddVVVars = [ - ["Sequence Number:", self.SeqNum], - ["Data Hdr/Qaul:", self.DQual], - ["Reserved:", self.Resv] + def data_init(self): + """ + Init starting vars + """ + self.verb_var = 0 + self.blk_size = 0 + self.num_blocks = 0 + self.dir_list = [] + self.stat_sel_list = [] + self.old_mseed_file = "" + + self.standard_vars = [ + "Station Name:", + "Location Code:", + "Channel:", + "Net Code:", + "Sps (nominal):", ] - self.NumSamp = IntVar() - self.SampFact = IntVar() - self.SampMult = IntVar() - self.ActFlag = StringVar() - self.IOFlag = StringVar() - self.DQFlag = StringVar() - self.NumBlockettes = IntVar() - self.TimeCorr = IntVar() - self.BeginData = IntVar() - self.FstBlkett = IntVar() - self.VeryVerboseVars = [ - ["Number Samples:", self.NumSamp], - ["Sample Factor:", self.SampFact], - ["Sample Multiplier:", self.SampMult], - ["Activity Flags:", self.ActFlag], - ["I/O & Clk Flags:", self.IOFlag], - ["Data Qaul Flags:", self.DQFlag], - ["Number Blockettes:", self.NumBlockettes], - ["Time Corr:", self.TimeCorr], - ["Offet Data:", self.BeginData], - ["Offset Blockette:", self.FstBlkett] + self.v_vars = [ + "Year:", + "Day:", + "Hour:", + "Min:", + "Sec:", + "0.0001s:" ] - self.VeryVerboseVars = (self.AddVVVars + self.VerboseVars + - self.VeryVerboseVars) - - # set up notebooks - self.createMainButtons(self.root) - self.createNoteBooks(self.root) - -######################################## - def createMainButtons(self, master): - """ - Build info bar and buttons for root window - """ - self.InfoString_l = Label(master, - bg="yellow", - relief="ridge") - self.InfoString_l.pack(side='bottom', fill='x') - - self.Button_fm = Frame(master, relief='groove', borderwidth=2) - self.Button_fm.pack(side='bottom', pady=5, fill='x') - - self.exit_b = Button(self.Button_fm, - text="Exit", - relief="ridge", - cursor='pirate', - command=Command(self.Exit), - activebackground='red', - activeforeground='black') - self.exit_b.pack(side='right', anchor='e') - - self.flush_b = Button(self.Button_fm, - text="Flush Dictionaries", - relief="ridge", - command=Command(self.FlushDict), - activebackground='orange', - activeforeground='black') - self.flush_b.pack(side='left', anchor='w') - -######################################## - def createNoteBooks(self, master): - """ - Set up notebooks in root window - """ - nb = Pmw.NoteBook(master) - self.buildHdrDisplay(nb) - self.buildBlockette(nb) - self.buildHelp(nb) - nb.pack(padx=5, pady=5, fill='both', expand=1) - # If commandline trace input - if self.ListInFiles: - (self.TraceListDict, NumFiles) = self.IndexFiles(self.ListInFiles) - self.UpdateDirList(self.HdrSelect_fm) - if NumFiles == 1: - vdir = list(self.TraceListDict.keys())[0] - self.SelDir.set(vdir) - self.UpdateTrcList() - trace = self.TraceListDict[vdir][0] - self.MseedFile.set(trace) - self.ReadHdrs() - - # clear any lingering updates - # self.MseedFile.set("") - # self.ClearAll(self.VeryVerboseVars) - # self.Hdrs_fm.destroy() - # self.Blks_fm.destroy() - - self.root.bell() - text = "Done. " + str(NumFiles) + " mseed files found." - self.addTextInfoBar(self.InfoString_l, text, "green") -################################################################## - - def buildHdrDisplay(self, master): - """ - Populate HdrDisplay NoteBook - """ - self.FixedHdr_nb = master.add('Trace Headers') - - # data selection frame - self.DataDirs_fm = Frame(self.FixedHdr_nb, relief='groove', - borderwidth=2) - self.DataDirs_fm.pack(side='top', pady=5, fill='x') - self.DataDirs_l = Label(self.DataDirs_fm, text='Data Directories: ') - self.DataDirs_l.pack(side='left') - self.DataDirs_e = Entry(self.DataDirs_fm, - selectbackground='yellow', - textvariable=self.DataDirs) - self.DataDirs_e.pack(side='left', anchor='w', expand=1, fill='x') - self.ClearDataDir_b = Button(self.DataDirs_fm, - activebackground='orange', - relief="ridge", - text="Clear", - command=Command(self.setValue, - self.DataDirs)) - self.ClearDataDir_b.pack(side='right') - self.FindDataDir_b = Button(self.DataDirs_fm, - activebackground='green', - relief="ridge", - text="Find", - command=Command(self.getPath, - self.DataDirs, - None)) - self.FindDataDir_b.pack(side='right') - self.DataDirs.set(getcwd()) - - self.BuildTrcList_b = Button(self.DataDirs_fm, - activebackground='green', - relief="ridge", - background='lightblue', - text="Build Trace db", - command=Command(self.BuildTrcList) - ) - self.BuildTrcList_b.pack(side='right') - - # station selection frame and entry box - self.StatSel_fm = Frame(self.FixedHdr_nb, relief='groove', - borderwidth=2) - self.StatSel_fm.pack(side='top', pady=5, fill='x') - self.StatSel_l = Label(self.StatSel_fm, - text='Find only stations (colon separated ' - 'list): ') - self.StatSel_l.pack(side='left') - self.StatSel_e = Entry(self.StatSel_fm, - selectbackground='yellow', - textvariable=self.StatSel) - self.StatSel_e.pack(side='left', anchor='w', expand=1, fill='x') - - self.ClearStatSel_b = Button(self.StatSel_fm, - activebackground='orange', - relief="ridge", - text="Clear", - command=Command(self.setValue, - self.StatSel)) - self.ClearStatSel_b.pack(side='right') - - # verbosity buttons - self.RadButtons_fm = Frame( - self.FixedHdr_nb, relief='groove', borderwidth=2) - self.RadButtons_fm.pack(side='top', pady=5, fill='x') - - for text, value in self.VerbList: - Radiobutton(self.RadButtons_fm, - text=text, - value=value, - command=Command(self.ReadHdrs, None), - variable=self.VerbVar).pack(side='left', anchor='e') - - Entry(self.RadButtons_fm, - width=self.e_width, - background='yellow', - relief='ridge', - textvariable=self.ByteOrder).pack(side='right', anchor='e') - Label(self.RadButtons_fm, - text="Header Endianess").pack(side='right', anchor='e') - - # set up frames that get filled when traces are selected - self.HdrScale_fm = Frame(self.FixedHdr_nb, borderwidth=2) - self.HdrScale_fm.pack(side='bottom', padx=5, pady=5, fill='x') - - self.HdrSelect_fm = Frame( - self.FixedHdr_nb, relief='groove', borderwidth=2) - self.HdrSelect_fm.pack(side='top', pady=5, fill='x') - - self.Hdrs_fm = Frame(self.FixedHdr_nb, relief='groove', borderwidth=2) - self.Hdrs_fm.pack(side='top', pady=5, fill='x') - -################################################################## - def buildBlockette(self, master): - """ - Populate Blockettes NoteBook - """ - self.Blockette_nb = master.add('Blockettes') - - # these get filled when traces are selected - self.BlkScale_fm = Frame(self.Blockette_nb, borderwidth=2) - self.BlkScale_fm.pack(side='bottom', padx=5, pady=5, fill='x') - - self.BlksSelect_fm = Frame( - self.Blockette_nb, relief='groove', borderwidth=2) - self.BlksSelect_fm.pack(side='top', pady=5, fill='x') - - self.BlksTitle_fm = Frame( - self.Blockette_nb, relief='groove', borderwidth=2) - self.BlksTitle_fm.pack(side='top', pady=5, fill='x') - - self.Blks_fm = Frame(self.Blockette_nb, relief='groove', borderwidth=2) - self.Blks_fm.pack(side='top', pady=5, fill='x') - -################################################################## - def buildBlkInfo(self, blktype, master): - """ - Provide information window for blockettes - """ - try: - self.tl_State = self.BlkInfo_tl.winfo_exists() - except Exception: - self.tl_State = 0 + self.first_vv_vars = [ + "Sequence Number:", + "Data Hdr/Qaul:", + "Reserved:" + ] - if self.tl_State == 1: - self.BlkInfo_tl.tkraise() - # display info on selected block - self.BlocketteType.set(blktype) - self.displayBlkInfo(blktype) + self.vv_vars = [ + "Number Samples:", + "Sample Factor:", + "Sample Multiplier:", + "Activity Flags:", + "I/O & Clk Flags:", + "Data Qaul Flags:", + "Number Blockettes:", + "Time Corr:", + "Offet Data:", + "Offset Blockette:" + ] - else: - self.BlkInfo_tl = Toplevel(master) - self.BlkInfo_tl.title("Blockette Information") - - self.BlkInfoSelect_fm = Frame( - self.BlkInfo_tl, relief='groove', borderwidth=2) - self.BlkInfoSelect_fm.pack(side='top', pady=5, fill='x') - - List = ["Fixed Header", "Data Fields", "BTime", 100, 200, 201, - 300, 310, 320, 390, 395, 400, 405, 500, 1000, 1001, 2000] - Label(self.BlkInfoSelect_fm, text="Blockette:").grid(row=1, - sticky=W) - Pmw.ComboBox(self.BlkInfoSelect_fm, - history=0, - entry_width=self.e_width + 15, - entry_textvariable=self.BlocketteType, - selectioncommand=Command(self.displayBlkInfo), - scrolledlist_items=(List) - ).grid(row=1, column=1, sticky=W) - - self.ExitBlkInfo_b = Button(self.BlkInfo_tl, - activebackground='red', - cursor='pirate', - background='lightblue', - text="Done", - command=Command(self.killWindow, - self.BlkInfo_tl)) - self.ExitBlkInfo_b.pack(side='bottom', fill='x', expand=1) - - self.BlkInfoText = Pmw.ScrolledText(self.BlkInfo_tl, - borderframe=1) - self.BlkInfoText.pack(side='bottom', fill='both', expand=1) - - # display info on selected block - self.BlocketteType.set(blktype) - self.displayBlkInfo(blktype) - -################################################################## - - def buildUniqueSelectBox(self, master): - """ - In unique view allows user to select block to jump to - """ - if "*" not in self.UniqueSelectList: - self.UniqueSelectList.append("*") - self.UniqueSelectList.sort() - Label(master, text="Select Keys:").pack(side='top', anchor='w') - - Pmw.ComboBox(master, - history=1, - entry_width=self.e_width + 15, - entry_textvariable=self.UniqueSelect, - selectioncommand=Command(self.SelectKeys), - scrolledlist_items=self.UniqueSelectList - ).pack(side='top', anchor='w') - self.UniqueSelect.set("*") - -################################################################## - - def buildJumpBox(self, master, numblocks=0): - """ - In unique view allows user to select block to jump to - """ - if self.VerbVar.get() == 3: - Label(master, text="Jump To Block #:").pack(side='top', anchor='w') - else: - Label(master, text="Jump To Block #:").pack(side='top', anchor='n') - - jumpbox_cb = Pmw.ComboBox(master, - history=1, - entry_width=self.e_width, - entry_textvariable=self.JumpNum, - selectioncommand=Command(self.Jump), - scrolledlist_items=(list(range(numblocks)))) - if self.VerbVar.get() == 3: - jumpbox_cb.pack(side='top', anchor='w') - else: - jumpbox_cb.pack(side='top', anchor='n') - -################################################################## - def Jump(self, value): - """ - Fills hdr values based on block selected in JumpBox - """ - if int(value) < 0: - value = 0 - if int(value) > (self.NumBlocks.get() - 1): - value = self.NumBlocks.get() - 1 - self.BlockNum.set(value) - if self.VerbVar.get() == 3: - self.VerbVar.set(2) - self.ReadHdrs() - self.FillHdr(value) - -################################################################## - def SelectKeys(self, value): - """ - Fills hdr values based on block selected in JumpBox - """ - self.UniqueText.clear() - self.UniqueText.tag_config("list", foreground="blue") - self.UniqueText.tag_config("odd", backgroun="lightblue") - - self.UniqueText.insert( - "end", "Block\tStat\tChan\tLoc\tNet\tRate\n", "list") - - selectkey = self.UniqueSelect.get() - c = 0 - for key in self.UniqueList: - testkey = key.split(":")[1:].join(":") - if selectkey != "*": - if selectkey != testkey: - continue - for var in key.split(":"): - if c: - self.UniqueText.insert("end", """%s\t""" % var, "odd") - else: - self.UniqueText.insert("end", """%s\t""" % var) - self.UniqueText.insert("end", """\n""") - if c: - c = 0 + def create_main_window(self): + """ + Build tabs and info bar for root window + """ + # tab widget + self.tabwidget = QtWidgets.QTabWidget() + self.trace_headers_tab = QtWidgets.QWidget() + self.blockettes_tab = QtWidgets.QWidget() + self.help_tab = QtWidgets.QWidget() + self.tabwidget.addTab(self.trace_headers_tab, "Trace Headers") + self.tabwidget.addTab(self.blockettes_tab, "Blockettes") + self.tabwidget.addTab(self.help_tab, "Help") + + # info bar widget + self.infobar = QtWidgets.QLineEdit() + self.infobar.setStyleSheet("background-color:yellow") + self.infobar.setReadOnly(True) + self.infobar.setAlignment(QtGui.Qt.AlignCenter) + + # main window layout + self.window_layout = QtWidgets.QVBoxLayout() + self.setLayout(self.window_layout) + + # add tab widget and info bar to main window layout + self.window_layout.addWidget(self.tabwidget) + self.build_trace_headers() # build widgets for Trace Headers tab + self.window_layout.addWidget(self.infobar) + self.window_layout.setMargin(0) # set spacing + + def build_help(self): + """ + Build Help tab + """ + # init tab layout + layout = QtWidgets.QVBoxLayout(self.help_tab) + + # Help textbox + Blue = QtGui.QColor(0,0,153) + Green = QtGui.QColor(0,100,0) + Red = QtGui.QColor(136, 8, 8) + Black = QtGui.QColor(0,0,0) + + help_text = QtWidgets.QTextEdit() + layout.addWidget(help_text) + help_text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + help_text.setAcceptRichText(False) + + # Name + help_text.setTextColor(Blue) + text = "NAME" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = "\n" + SPACE + "mseedpeek - GUI for displaying mseed file headers.\n\n" + help_text.insertPlainText(text) + + # Version + help_text.setTextColor(Blue) + text = "VERSION" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = "\n" + SPACE + str(VERSION) + "\n\n" + help_text.insertPlainText(text) + + # Synopsis + help_text.setTextColor(Blue) + text = "SYNOPSIS" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = "\n" + SPACE + "mseedpeek\n" + SPACE +\ + "mseedpeek -#\n" + SPACE + "mseedpeek -f file_names\n\n" + help_text.insertPlainText(text) + + # Options + help_text.setTextColor(Blue) + text = "OPTIONS" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = "\n" + SPACE + "-# returns version number\n" + \ + SPACE + "-f file_name(s) - accepts command line \ + input for files to inspect (wildcards accepted)\n\n" + help_text.insertPlainText(text) + + # Description + help_text.setTextColor(Blue) + text = "DESCRIPTION" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = "\n" + SPACE + "mseedpeek has three notebooks: " + help_text.insertPlainText(text) + help_text.setTextColor(Green) + text = "[Trace Headers][Blockettes]" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ", and " + help_text.insertPlainText(text) + help_text.setTextColor(Green) + text = "[Help]" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ". The " + help_text.insertPlainText(text) + help_text.setTextColor(Green) + text = "[Trace Headers]\n" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = SPACE + "notebook displays various the fixed \ + header in four levels of verbosity. The " + help_text.insertPlainText(text) + help_text.setTextColor(Green) + text = "[Blockettes]\n" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = SPACE + "notebook displays blockette information.\n\n" + help_text.insertPlainText(text) + help_text.setTextColor(Green) + text = SPACE + "[Trace Headers]\n" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = SPACE + "General:\n" + SPACE + " \ + >> specify/load directories for building trace db\n" + SPACE + \ + " >> select trace for header display\n" + SPACE + \ + " >> select level of verbosity for display\n\n" + SPACE + \ + "Buttons:\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + " <Build Trace db>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": Searchs the directories listed in the \"Data-Directories\" \ + entry box \n" + SPACE + " (a colon separated list) and builds a \ + list of mseed files found indexing them on unique values of\n" + \ + SPACE + " <dir>:<file_name>. It then creates a dropdown menu \ + with entries for each data directory\n" + SPACE + " found.\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + " <Find>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": Launches a file browser allowing the user to add directories to \ + the \"Data Directories\" entry\n" + SPACE + " box. \ + Double clicking selects the new directory.\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + " <Clear>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": Clears the \"Data Directories\" entry box.\n\n" + help_text.insertPlainText(text) + text = SPACE + " By selecting a data directory a dropdown \ + menu is created for trace selection. Selecting a trace from\n" \ + + SPACE + " this menu will create a header display.\n\n" + help_text.insertPlainText(text) + text = SPACE + "Radio Buttons:\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + " <Standard>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": This is the default. It displays Station, Channel, \ + Location Code, Net Code, and the\n" + SPACE + \ + " nominal Sample Rate.\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + " <Verbose>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": Standard display plus time of block.\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + " <Very Verbose>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": Verbose plus the rest of the mseed fixed header fields.\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + " <Unique>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": This displays changes in the Standard fields within a mseed file.\n\n" + help_text.insertPlainText(text) + text = SPACE + "Slider Scale and " + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = "<Jump To Block #> " + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = "Button:\n" + SPACE + " At the bottom of the page \ + is a scale bar showing block numbers. Sliding the bar \ + scans through all\n" + SPACE + \ + " fixed headers for the selected mseed file.\n\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + "<Flush Directories>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": Clears cached trace header data. As you view \ + mseed headers, mseedpeek\n" + SPACE + \ + " maintains a cache of previously viewed headers \ + for quick, future access. If you wish to monitor\n" + \ + SPACE + " changes to mseed files you need to \ + flush the dictionaries so that the \ + new changes will be displayed.\n\n" + help_text.insertPlainText(text) + help_text.setTextColor(Green) + text = SPACE + "[Blockettes]" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ":\n" + help_text.insertPlainText(text) + text = SPACE + " The 'Blockettes' notebook displays all blockettes \ + found for the select mseed file in a dropdown menu.\n" + SPACE + \ + " By selecting a blockette from the dropdown menu, the contents \ + of the blockette will be\n" + SPACE + " displayed.\n" + help_text.insertPlainText(text) + help_text.setTextColor(Red) + text = SPACE + " <Blockette Info>" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = ": Displays a pop-up window with a definition of the SEED Blockette.\n\n" + help_text.insertPlainText(text) + text = SPACE + " At the bottom of the page is a scale bar showing \ + block numbers and sliding the bar scans through all\n" + SPACE + \ + " blockettes for the selected mseed file.\n\n" + help_text.insertPlainText(text) + help_text.setTextColor(Blue) + text = "KEYWORDS\n" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = SPACE + "mseed; header information\n\n" + help_text.insertPlainText(text) + help_text.setTextColor(Blue) + text = "SEE ALSO\n" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = SPACE + "SEED manual (pdf), fixhdr, mseedhdr\n\n" + help_text.insertPlainText(text) + help_text.setTextColor(Blue) + text = "AUTHOR\n" + help_text.insertPlainText(text) + help_text.setTextColor(Black) + text = SPACE + "Bruce Beaudoin <bruce@passcal.nmt.edu>" + help_text.insertPlainText(text) + + def build_blockettes(self): + """ + Create initial widgets for Blockettes tab + """ + # data boxes + self.blktype_box = QtWidgets.QGroupBox() + self.blktype_box.setObjectName("Box1") + + self.blkinfo_box = QtWidgets.QGroupBox() + self.blkinfo_box.setLayout(QtWidgets.QHBoxLayout()) + self.blkinfo_box.setObjectName("Box2") + + self.blk_vars_box = QtWidgets.QGroupBox() + self.blk_vars_box.setLayout(QtWidgets.QVBoxLayout()) + self.blk_vars_box.setObjectName("Box3") + + # widgets + blk_label = QtWidgets.QLabel("Blockette:") + blk_menu = QtWidgets.QComboBox() + blk_menu.setObjectName("type_menu") + + self.blkinfo_btn = QtWidgets.QPushButton("Blockette Info") + self.blkinfo_btn.setStyleSheet("QPushButton{background-color:lightblue;}\ + QPushButton::hover{background-color:green;}") + self.blkinfo_btn.clicked.connect(self.blkinfo_window) + + # box layouts + l1 = QtWidgets.QHBoxLayout(self.blktype_box) + l1.addWidget(blk_label) + l1.addWidget(blk_menu) + l1.addStretch() + + # add to tab's main layout + main_layout = QtWidgets.QVBoxLayout() + main_layout.addWidget(self.blktype_box) + main_layout.addWidget(self.blkinfo_box) + main_layout.addWidget(self.blk_vars_box) + main_layout.addStretch() + self.blockettes_tab.setLayout(main_layout) + + def build_trace_headers(self): + """ + Build widgets for Trace Headers tab + """ + # tab layout + self.trace_headers_layout = QtWidgets.QVBoxLayout(self.trace_headers_tab) + + # groupboxes for data fields + self.datadir_box = QtWidgets.QGroupBox() + self.datadir_box.setCheckable(False) + sp = self.datadir_box.sizePolicy() + sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed) + self.datadir_box.setSizePolicy(sp) + + self.stations_box = QtWidgets.QGroupBox() + self.stations_box.setCheckable(False) + sp = self.stations_box.sizePolicy() + sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed) + self.stations_box.setSizePolicy(sp) + + self.radio_box = QtWidgets.QGroupBox() + self.radio_box.setCheckable(False) + sp = self.radio_box.sizePolicy() + sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed) + self.radio_box.setSizePolicy(sp) + + self.dir_trace_box = QtWidgets.QGroupBox() + self.dir_trace_box.setCheckable(False) + sp = self.dir_trace_box.sizePolicy() + sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed) + self.dir_trace_box.setSizePolicy(sp) + + self.flush_exit_box = QtWidgets.QGroupBox() + self.flush_exit_box.setCheckable(False) + sp = self.flush_exit_box.sizePolicy() + sp.setVerticalPolicy(QtWidgets.QSizePolicy.Fixed) + self.flush_exit_box.setSizePolicy(sp) + self.window_layout.addWidget(self.flush_exit_box) + + # layouts for groupboxes + datadir_layout = QtWidgets.QHBoxLayout(self.datadir_box) + stations_layout = QtWidgets.QHBoxLayout(self.stations_box) + rbuttons_layout = QtWidgets.QHBoxLayout(self.radio_box) + flush_exit_layout = QtWidgets.QHBoxLayout(self.flush_exit_box) + flush_exit_layout.setMargin(0) + flush_exit_layout.setSpacing(450) + dir_trace_layout = QtWidgets.QFormLayout(self.dir_trace_box) + + # fill flush / exit groubpx + self.exit_btn = QtWidgets.QPushButton("Exit") + self.exit_btn.setStyleSheet("QPushButton::hover{background-color:darkred;}") + self.exit_btn.clicked.connect(lambda: quit()) + self.flush_btn = QtWidgets.QPushButton("Flush Directories") + self.flush_btn.clicked.connect(self.flush_dict) + self.flush_btn.setStyleSheet("QPushButton::hover{background-color:orange;}") + flush_exit_layout.addWidget(self.flush_btn) + flush_exit_layout.addWidget(self.exit_btn) + + # fill data dir groupbox + self.dd_label = QtWidgets.QLabel("Data Directories:") + self.dd_text = QtWidgets.QLineEdit() + self.build_trace_btn = QtWidgets.QPushButton("Build Trace db") + self.build_trace_btn.setStyleSheet("QPushButton{background-color:lightblue;} \ + QPushButton::hover{background-color:green;}") + self.build_trace_btn.clicked.connect(self.clicked_build_trace) + self.find_btn = QtWidgets.QPushButton("Find") + self.find_btn.clicked.connect(self.clicked_find) + self.clear_btn = QtWidgets.QPushButton("Clear") + self.clear_btn.clicked.connect(lambda: self.dd_text.clear()) + datadir_layout.addWidget(self.dd_label) + datadir_layout.addWidget(self.dd_text) + datadir_layout.addWidget(self.build_trace_btn) + datadir_layout.addWidget(self.find_btn) + datadir_layout.addWidget(self.clear_btn) + + # stations widgets + self.stations_label = QtWidgets.QLabel("Find only stations (colon separated list):") + self.stations_text = QtWidgets.QLineEdit() + self.stations_clear_btn = QtWidgets.QPushButton("Clear") + self.stations_clear_btn.clicked.connect(lambda: self.stations_text.clear()) + stations_layout.addWidget(self.stations_label) + stations_layout.addWidget(self.stations_text) + stations_layout.addWidget(self.stations_clear_btn) + + # fill stations groupbox + self.standard_rbtn = QtWidgets.QRadioButton("Standard") + self.standard_rbtn.setChecked(True) + self.standard_rbtn.clicked.connect(lambda: self.clicked_scan_type(0)) + self.verbose_rbtn = QtWidgets.QRadioButton("Verbose") + self.verbose_rbtn.setChecked(False) + self.verbose_rbtn.clicked.connect(lambda: self.clicked_scan_type(1)) + self.vv_rbtn = QtWidgets.QRadioButton("Very Verbose") + self.vv_rbtn.setChecked(False) + self.vv_rbtn.clicked.connect(lambda: self.clicked_scan_type(2)) + self.unique_rbtn = QtWidgets.QRadioButton("Unique") + self.unique_rbtn.setChecked(False) + self.unique_rbtn.clicked.connect(lambda: self.clicked_scan_type(3)) + + # spacer item + # adds distance between rbuttons and "Header Endianess" + spacerItem = QtWidgets.QSpacerItem(250, 0, + QtWidgets.QSizePolicy.Expanding, + QtWidgets.QSizePolicy.Minimum) + + self.header_endianess_label = QtWidgets.QLabel("Header Endianess") + self.header_endianess_text = QtWidgets.QLineEdit() + self.header_endianess_text.setStyleSheet("background-color:yellow") + + rbuttons_layout.addWidget(self.standard_rbtn) + rbuttons_layout.addWidget(self.verbose_rbtn) + rbuttons_layout.addWidget(self.vv_rbtn) + rbuttons_layout.addWidget(self.unique_rbtn) + rbuttons_layout.addItem(spacerItem) + rbuttons_layout.addWidget(self.header_endianess_label) + rbuttons_layout.addWidget(self.header_endianess_text) + + # fill dir / trace groupbox + self.dir_label = QtWidgets.QLabel("Directory:") + self.dir_menu = QtWidgets.QComboBox() + self.dir_menu.activated.connect(lambda: self.select_dir_trace("dir")) + self.trace_label = QtWidgets.QLabel("Trace:") + self.trace_menu = QtWidgets.QComboBox() + self.trace_menu.activated.connect(lambda: self.select_dir_trace("trace")) + dir_trace_layout.addRow(self.dir_label, self.dir_menu) + dir_trace_layout.addRow(self.trace_label, self.trace_menu) + self.dir_trace_box.hide() + self.trace_label.hide() + self.trace_menu.hide() + + # stacked widget (jump box) + self.standard_box = StandardBox(self.standard_vars) + self.verbose_box = VerboseBox(self.standard_vars, self.v_vars) + self.vv_box = VVBox(self.first_vv_vars, self.standard_vars, self.v_vars, self.vv_vars) + self.unique_box = UniqueBox() + + self.jump_box = QtWidgets.QStackedWidget() + self.jump_box.setStyleSheet("QGroupBox{border:0;}") + self.jump_box.setMinimumSize(0,200) + self.jump_box.addWidget(self.standard_box) + self.jump_box.addWidget(self.verbose_box) + self.jump_box.addWidget(self.vv_box) + self.jump_box.addWidget(self.unique_box) + + # slider + self.slider_box = SliderBox() + self.slider_box.slider.valueChanged.connect(lambda: self.update_slider("slider")) + self.slider_box.jump_menu.currentTextChanged.connect(lambda: self.update_slider("menu")) + self.unique_box.unique_jump.currentIndexChanged.connect(lambda: + self.update_slider("unique")) + + # add everything to trace headers layout + self.trace_headers_layout.addWidget(self.datadir_box) + self.trace_headers_layout.addWidget(self.stations_box) + self.trace_headers_layout.addWidget(self.radio_box) + self.trace_headers_layout.addWidget(self.dir_trace_box) + self.trace_headers_layout.addWidget(self.jump_box) + self.trace_headers_layout.addWidget(self.slider_box) + + # set data directory widget to display cwd + default_dir = os.getcwd() + self.dd_text.setText(default_dir) + + def clicked_scan_type(self, index): + """ + Show data related to selected scan type + """ + self.verb_var = index + self.jump_box.setCurrentIndex(self.verb_var) + if self.trace_menu.isHidden(): + self.jump_box.hide() + self.maybe_read_hdrs() + + def clicked_find(self): + """ + Open file dialogue to search for mseed files + """ + search = QtWidgets.QFileDialog.getExistingDirectory() + directories = self.dd_text.text() + + if search: + if directories: + self.dd_text.insert(":" + search) else: - c += 1 -########################################## + self.dd_text.insert(search) - def UpdateDirList(self, fm): + def clicked_build_trace(self): """ - build dropdown for selecting data filled directories + Check directories have been provided before building trace list """ - self.DirList = list(self.TraceListDict.keys()) - - self.DirList.sort() - self.SelDir.set("") - if not self.DirList: - self.root.bell() - self.addTextInfoBar(self.InfoString_l, "No Data Found", 'orange') - + directories = self.dd_text.text() + if directories: + self.dir_list.clear() + self.build_trace_list(directories) + self.hide_show("hide") else: - Label(fm, text="Directory:").grid(row=0, sticky=W) - Pmw.ComboBox(fm, - history=0, - entry_width=self.e_width + 40, - entry_textvariable=self.SelDir, - selectioncommand=Command(self.UpdateTrcList), - scrolledlist_items=(self.DirList) - ).grid(row=0, column=1, sticky=W) - -################################################################## - - def UpdateTrcList(self, name=""): - """ - create dropdown file list based on selected directory - """ - self.MseedFile.set("") - self.TraceList = self.TraceListDict[self.SelDir.get()] - self.TraceList.sort() - self.ClearAll(self.VeryVerboseVars) - if not self.TraceList: - self.root.bell() - self.addTextInfoBar(self.InfoString_l, "No Data Found", 'orange') - - Label(self.HdrSelect_fm, text="Trace:").grid(row=1, sticky=W) - Pmw.ComboBox(self.HdrSelect_fm, - history=0, - entry_width=self.e_width + 40, - entry_textvariable=self.MseedFile, - selectioncommand=Command(self.ReadHdrs), - scrolledlist_items=(self.TraceList) - ).grid(row=1, column=1, sticky=W) - -####################################### - - def BuildTrcList(self): - """ - build a trace list using DataDirList as base directories - """ - self.addTextInfoBar(self.InfoString_l) - - self.ByteOrder.set("") - DataDirList = [] - self.StatSelList = [] - for idir in self.DataDirs.get().split(":"): - dirlist = glob(idir) - for newdir in dirlist: - if not path.isdir(newdir): - err = "***WARNING*** Directory " + newdir + " not found." - self.root.bell() - self.addTextInfoBar(self.InfoString_l, err, "red") - return - DataDirList.append(newdir) - - # split station select list if it exists - if self.StatSel.get() == "*" or self.StatSel.get() == "": - pass + error_msg = QtWidgets.QMessageBox() + error_msg.setIcon(QtWidgets.QMessageBox.Critical) + error_msg.setText("Error") + error_msg.setInformativeText("No directories listed.") + error_msg.setWindowTitle("Error") + error_msg.exec_() + + def build_trace_list(self, directories): + """ + Build trace list from given directories + """ + for dir in str(directories).split(":"): + if not os.path.isdir(dir): + err = "***WARNING*** Directory " + dir + " not found." + self.infobar(err, "red") + QtWidgets.QApplication.beep() + else: + self.dir_list.append(dir) + + stat_sel = self.stations_text.text() + if stat_sel: + for stat in str(stat_sel).split(":"): + statsel = stat.strip() + self.stat_sel_list.append(statsel) + + if self.dir_list: + (num_files, err_files) = self.find_trace() + text = "Done. " + str(num_files) + " mseed files found. ***" \ + + str(err_files) + " files with errors." + self.update_infobar(text, "green") + + def hide_show(self, action): + """ + Hide/show widgets between scans + """ + if action == "hide": + widget = self.jump_box.currentWidget() + for child in widget.findChildren(QtWidgets.QWidget): + if not child.isHidden(): + child.hide() + for child in self.slider_box.findChildren(QtWidgets.QWidget): + if not child.isHidden(): + child.hide() + widgets = self.blockettes_tab.findChildren(QtWidgets.QGroupBox) + for widget in widgets: + if not widget.isHidden(): + widget.hide() + self.trace_label.hide() + self.trace_menu.hide() + self.blktype_box.hide() + self.blkinfo_box.hide() + self.blk_vars_box.hide() else: - for statsel in str(self.StatSel.get()).split(":"): - statsel = statsel.strip() - self.StatSelList.append(statsel) - - (self.TraceListDict, NumFiles, errfiles) = self.FindTrace(DataDirList) - self.UpdateDirList(self.HdrSelect_fm) - - # clear any lingering updates - self.MseedFile.set("") - self.ClearAll(self.VeryVerboseVars) - self.Hdrs_fm.destroy() - self.Blks_fm.destroy() - - self.root.bell() - text = "Done. " + str(NumFiles) + " mseed files found. ***" \ - + str(errfiles) + " files with errors." - self.addTextInfoBar(self.InfoString_l, text, "green") - -####################################### - - def FindTrace(self, DataDir): + widget = self.jump_box.currentWidget() + for child in widget.findChildren(QtWidgets.QWidget): + if child.isHidden(): + child.show() + for child in self.slider_box.findChildren(QtWidgets.QWidget): + if child.isHidden(): + child.show() + widgets = self.blockettes_tab.findChildren(QtWidgets.QGroupBox) + for widget in widgets: + if widget.isHidden(): + widget.show() + self.blktype_box.show() + self.blkinfo_box.show() + self.blk_vars_box.show() + + def find_trace(self): """ based on traverse routine in "python standard library", Lundh pg 34 """ stack = [] - for k in range(len(DataDir)): - stack.append(DataDir[k]) + for k in range(len(self.dir_list)): + stack.append(self.dir_list[k]) + file_list = {} - NumMseedFiles = 0 - rwError = 0 + num_mseed_files = 0 + rw_error = 0 cnt = 1 while stack: directory = stack.pop() - if not path.isdir(directory): - print("\n***WARNING*** Directory \"%s\" not found.\n" % - directory) - continue - try: - listfiles = listdir(directory) + listfiles = os.listdir(directory) except Exception as e: print("Directory Read Error: %s" % e) - for ifile in listfiles: + for file in listfiles: if mod(cnt, 25): pass else: self.wait("Examining File: ", cnt) - fullname = path.join(directory, ifile) - if path.isfile(fullname): + fullname = os.path.join(directory, file) + if os.path.isfile(fullname): if not os.access(fullname, 6): err = "ERROR: Read/Write permission denied." err1 = "\t File: " + fullname print(err) print(err1) - rwError += 1 + rw_error += 1 continue try: msfile = Mseed(fullname) if msfile.isMseed(): + num_mseed_files += 1 + if directory in file_list: + file_list[directory].append(file) + else: + file_list[directory] = [] + file_list[directory].append(file) try: # simple test to determine if correct size file filesize = msfile.filesize @@ -800,146 +857,106 @@ class MainWindow: str(blksize) + "). \n\t File: " + fullname) print(warn) - rwError += 1 + rw_error += 1 continue except Exception: err = ("ERROR: Cannot determine file and " "block sizes. \n\t File:" + fullname) print(err) - rwError += 1 + rw_error += 1 continue - NumMseedFiles += 1 - stat = msfile.FH.Stat.strip() - - if self.StatSelList: - if stat not in self.StatSelList: - continue - - if directory in file_list: - file_list[directory].append(ifile) - else: - file_list[directory] = [] - file_list[directory].append(ifile) msfile.close() except Exception as e: - rwError += 1 + rw_error += 1 print("File Open Error: %s" % fullname, e) cnt += 1 - - if (path.isdir(fullname) or (path.islink(fullname) and - not path.isfile(fullname))): + if (os.path.isdir(fullname) or (os.path.islink(fullname) and + not os.path.isfile(fullname))): stack.append(fullname) - return file_list, NumMseedFiles, rwError + self.dir_trace_dict = {} + self.dir_trace_dict = file_list + self.update_dir_list() + return num_mseed_files, rw_error -####################################### - - def IndexFiles(self, ListInFiles): + def select_dir_trace(self, menu): """ - based on traverse routine in "python standard library", Lundh pg 34 + If directory menu selected, show trace menu + If trace menu selected, read hdrs """ - file_list = {} - cnt = 1 - NumMseedFiles = 0 - directory = getcwd() - self.DataDirs.set(getcwd()) - for ifile in ListInFiles: - if mod(cnt, 25): - pass + if menu == "dir": + dir = self.dir_menu.currentText() + if dir: + self.update_trace_list(dir) + self.trace_label.show() + self.trace_menu.show() else: - self.wait("Examining File: ", cnt) - fullname = path.join(directory, ifile) - if path.isfile(fullname): - try: - newfile = Mseed(fullname) - if newfile.isMseed(): - stat = newfile.FH.Stat.strip() - if self.StatSelList: - if stat not in self.StatSelList: - continue - - NumMseedFiles += 1 - if directory in file_list: - file_list[directory].append(ifile) - else: - file_list[directory] = [] - file_list[directory].append(ifile) - newfile.close() - except Exception as e: - print("File Open Error: %s" % e) - cnt += 1 - - return file_list, NumMseedFiles -####################################### + self.trace_label.hide() + self.trace_menu.hide() + else: + trace = self.trace_menu.currentText() + if trace: + dir = self.dir_menu.currentText() + self.next_scan(dir, trace) - def ReadHdrs(self, ifile=""): + def next_scan(self, dir, trace): """ - read headers of a given file build dictionary for quick access + Prepare for next scan, i.e. reset/clear/hide some widgets """ + self.clear_slider() + self.read_hdrs(dir, trace, 0) + self.fill_slider() + self.hide_show("show") + self.header_endianess_text.setText(self.byte_order) + self.jump_box.setCurrentIndex(self.verb_var) + self.update_infobar("", "yellow") - # this is a bit of a hack, but I am unable to pass self.MseedFile.get() - # from buildHdrDisplay:Radiobutton:command - if not ifile: - ifile = self.MseedFile.get() - # if someone changes VerbVar before selecting file do nothing - if not ifile: - return + # hack, widget was behaving weird for some reason + # after showing it + self.slider_box.jump_menu.setEnabled(False) + self.slider_box.jump_menu.setEnabled(True) - FileAbsolutePath = path.join(self.SelDir.get(), ifile) + def read_hdrs(self, dir, trace, blk): + """ + Read headers of a given file, build dictionary for quick access + """ + file_absolute_path = os.path.join(dir, trace) - # create object (we've already tested all files for mseed) - # and get some base info - rdfile = Mseed(FileAbsolutePath) + rdfile = Mseed(file_absolute_path) if rdfile.isMseed(): try: filesize = rdfile.filesize blksize = rdfile.blksize except Exception: - self.ClearAll(self.VeryVerboseVars) - self.Hdrs_fm.destroy() - self.HdrScale_fm.destroy() - self.BlkScale_fm.destroy() - self.BlksSelect_fm.destroy() - self.BlksTitle_fm.destroy() - self.Blks_fm.destroy() - err = "Cannot determine file and block sizes. File: " + ifile - self.addTextInfoBar(self.InfoString_l, err, 'red') + err = "Cannot determine file and block sizes. File: " + trace + self.update_infobar(err, "red") rdfile.close() return - else: - return - # initialize variables, lists, and dicts for later - self.BlkSize.set(blksize) - (numblocks, self.odd_size) = divmod(filesize, blksize) - self.NumBlocks.set(numblocks) - verbose = self.VerbVar.get() - if not self.OldMseedFile.get() or \ - self.OldMseedFile.get() != FileAbsolutePath: - self.FixedHdrDict = {} - self.RateDict = {} - self.Blockettes = {} - self.keyList = [] - self.UniqueList = [] - self.UniqueSelectList = [] + self.blk_size = blksize + (numblocks, self.odd_size) = divmod(filesize, blksize) + self.num_blocks = numblocks + verbose = self.verb_var + + self.fixed_hdr_dict = {} + self.rate_dict = {} + self.blockettes_dict = {} + self.key_list = [] + self.unique_list = [] + self.unique_select_list = [] n = 0 # now build a dictionary of all fixed header info keyed to block # number looping over total number of blocks in files lastkey = -1 while n < numblocks: - hdrs = rdfile.fixedhdr(n * blksize) - self.FixedHdrDict[n] = hdrs - # fact=hdrs[2][1] - # mult=hdrs[2][2] - # self.RateDict[n]=rdfile.calcrate(mult,fact) - self.RateDict[n] = rdfile.rate + self.fixed_hdr_dict[n] = hdrs + self.rate_dict[n] = rdfile.rate # if unique selected build unique list - # if verbose == 3: (SeqNum, DHQual, res, Stat, Loc, Chan, Net) = hdrs[0] - Rate = str(self.RateDict[n]) + Rate = str(self.rate_dict[n]) Stat = Stat.strip().decode() Chan = Chan.strip().decode() Loc = Loc.strip().decode() @@ -949,27 +966,25 @@ class MainWindow: if key == lastkey: pass else: - # self.keyList.append(key) lastkey = key - if key not in self.UniqueSelectList: - self.UniqueSelectList.append(key) - key = str(n) + ":" + key - self.UniqueList.append(key) + if key not in self.unique_select_list: + self.unique_select_list.append(key) + key = str(blk) + ":" + key + self.unique_list.append(key) # build Blockette dictionary keyed to block number numblk = hdrs[3][3] addseek = hdrs[3][6] b = 0 + # loop over number of blockettes following fixed header at # block n while b < numblk: seekval = (n * blksize) + addseek (blktype, next) = rdfile.typenxt(seekval) # builds command to read specific blockette - # getBlkCmd="blklist=rdfile.blk" + str(blktype) + \ - # "(" + str(seekval) + ")" blklist = eval("rdfile.blk" + str(blktype) + - "(" + str(seekval) + ")") + "(" + str(seekval) + ")") if blklist: # handle awkward lists w/ muli-byte reserve, array, or # calib fields @@ -991,581 +1006,587 @@ class MainWindow: tmplist.append(tup) blklist = tmplist # build Blockettes - if n in self.Blockettes: - self.Blockettes[n].append(blklist) + if n in self.blockettes_dict: + self.blockettes_dict[n].append(blklist) else: - self.Blockettes[n] = [] - self.Blockettes[n].append(blklist) - + self.blockettes_dict[n] = [] + self.blockettes_dict[n].append(blklist) addseek = next b += 1 n += 1 - # get endianess before closing - self.ByteOrder.set(rdfile.byteorder) - rdfile.close() + # get endianess before closing + self.byte_order = rdfile.byteorder + rdfile.close() - # if unique proceed, else set up scales and entry fields. - if verbose == 3: - self.Unique(numblocks) - else: - try: - self.HdrScale_fm.destroy() - self.HdrScale_fm = Frame(self.FixedHdr_nb, borderwidth=2) - self.HdrScale_fm.pack(side='bottom', padx=5, pady=5, fill='x') - self.BlkScale_fm.destroy() - self.BlkScale_fm = Frame(self.Blockette_nb, borderwidth=2) - self.BlkScale_fm.pack(side='bottom', padx=5, pady=5, fill='x') - except Exception: - pass - self.buildJumpBox(self.HdrScale_fm, numblocks) - - if FileAbsolutePath != self.OldMseedFile.get(): - self.BlockNum.set(0) - self.JumpNum.set(0) - - Label(self.HdrScale_fm, text='Block Number').pack( - side='left', anchor='w') - - Scale(self.HdrScale_fm, - variable=self.BlockNum, - length=625, - orient='horizontal', - from_=0, - to=numblocks - 1, - tickinterval=numblocks / 6, - command=Command(self.FillHdr) - ).pack(side='left', anchor='w') - - Label(self.BlkScale_fm, text='Block Number').pack( - side='left', anchor='w') - Scale(self.BlkScale_fm, - variable=self.BlockNum, - length=625, - orient='horizontal', - from_=0, - to=numblocks - 1, - tickinterval=numblocks / 6, - command=Command(self.FillHdr) - ).pack(side='left', anchor='w') - - self.SetBlockettes(0) + self.set_blockettes(0) if not verbose: - self.Standard(0, 1) + self.fill_standard(int(blk)) elif verbose == 1: - self.Verbose(0, 1) + self.fill_verbose(int(blk)) elif verbose == 2: - self.VeryVerbose(0, 1) - - self.OldMseedFile.set(FileAbsolutePath) - -####################################### - def SetBlockettes(self, key): - """ - setup blockette frames for new key entry - """ - self.BlockettesList = [] - for blk in self.Blockettes[key]: - self.BlockettesList.append(blk[0]) - self.BlockettesList.sort() - self.Blockette.set(self.BlockettesList[0]) - - self.BlksSelect_fm.destroy() - self.BlksSelect_fm = Frame( - self.Blockette_nb, relief='groove', borderwidth=2) - self.BlksSelect_fm.pack(side='top', pady=5, fill='x') - - Label(self.BlksSelect_fm, text="Blockette:").grid(row=1, sticky=W) - Pmw.ComboBox(self.BlksSelect_fm, - history=0, - entry_width=self.e_width, - entry_textvariable=self.Blockette, - selectioncommand=Command(self.FillSelectBlk, key), - scrolledlist_items=(self.BlockettesList) - ).grid(row=1, column=1, sticky=W) - -# fill blockette info for first blockette found - self.FillSelectBlk(key, self.BlockettesList[0]) - -####################################### - def VarInit(self, Vars): - """ - clears/initializes entry fields on HdrDisplay - """ - - self.Hdrs_fm.destroy() - self.Hdrs_fm = Frame(self.FixedHdr_nb, relief='groove', borderwidth=2) - self.Hdrs_fm.pack(side='top', pady=5, fill='x') - - c = r = n = 0 - for var in Vars: - Label(self.Hdrs_fm, text=var[0]).grid(row=r, column=c, sticky=W) - Entry(self.Hdrs_fm, - width=self.e_width, - selectbackground='yellow', - textvariable=var[1]).grid(row=r, column=c + 1, sticky=W) - if n == 5: - n = r = 0 - c += 2 + self.fill_vv(int(blk)) else: - n += 1 - r += 1 + self.fill_unique() -####################################### - def Unique(self, numblocks=0): + def clear_slider(self): """ - setup hdr frames for new unique display + Reset blk slider between scans """ - self.ClearAll(self.VeryVerboseVars) - self.Hdrs_fm.destroy() - self.Hdrs_fm = Frame(self.FixedHdr_nb, relief='groove', borderwidth=2) - self.Hdrs_fm.pack(side='top', pady=5, fill='x') - self.HdrScale_fm.destroy() - self.HdrScale_fm = Frame(self.FixedHdr_nb, borderwidth=2) - self.HdrScale_fm.pack(side='bottom', padx=5, pady=5, fill='x') - self.buildUniqueSelectBox(self.Hdrs_fm) - self.buildJumpBox(self.Hdrs_fm, numblocks) + # block/unblock widget signals + self.slider_box.slider.blockSignals(True) + self.slider_box.jump_menu.blockSignals(True) + self.slider_box.slider.setValue(0) + self.slider_box.jump_menu.clear() + self.slider_box.jump_menu.insertItem(0, "0") + self.slider_box.jump_menu.setCurrentIndex(0) + self.slider_box.jump_menu.blockSignals(False) + self.slider_box.slider.blockSignals(False) - self.FillUnique() - -####################################### - def Standard(self, key, init=0): + def fill_slider(self): """ - setup standard vars for new key entry + Set slider range for chosen trace """ - if init: - self.VarInit(self.StandardVars) - - self.FillStandard(key) + # block/unblock widget signals + self.slider_box.slider.blockSignals(True) + self.slider_box.jump_menu.blockSignals(True) + self.slider_box.slider.setTickPosition(self.slider_box.slider.TicksBelow) + self.slider_box.slider.setRange(0, self.num_blocks-1) + i = 0 + self.slider_box.jump_menu.clear() + while i < self.num_blocks: + self.slider_box.jump_menu.insertItem(i, str(i)) + i += 1 + self.slider_box.slider.setTickInterval(self.slider_box.slider.maximum() / 5) + self.slider_box.jump_menu.blockSignals(False) + self.slider_box.slider.blockSignals(False) -####################################### - def Verbose(self, key, init=0): + def set_blockettes(self, key): """ - setup verbose vars for new key entry + Setup blockette frames for new key entry """ + self.blockettes_list = [] + for blk in self.blockettes_dict[key]: + self.blockettes_list.append(blk[0]) + self.blockettes_list.sort() - if init: - self.VarInit(self.VerboseVars) - - self.FillVerbose(key) + # fill blockette info for first blockette found + self.fill_blockettes_tab(key, self.blockettes_list[0]) -####################################### - def VeryVerbose(self, key, init=0): + def fill_blockettes_tab(self, key, blktype): """ - setup very verbose vars for new key entry + clears/initializes entry fields in Blockettes tab """ - - if init: - self.VarInit(self.VeryVerboseVars) - - self.FillVeryVerbose(key) - -####################################### - def FillHdr(self, value): - """ - fill header field on page based on block number - """ - key = int(value) - self.JumpNum.set(value) - self.ByteOffset.set(self.BlockNum.get() * self.BlkSize.get()) - verbose = self.VerbVar.get() - self.SetBlockettes(key) - if not verbose: - self.Standard(key) - elif verbose == 1: - self.Verbose(key) - elif verbose == 2: - self.VeryVerbose(key) - - if self.odd_size: - info = ("WARNING: File size is not an integer number of block " - "size (" + str(self.BlkSize.get()) + ")") - self.addTextInfoBar(self.InfoString_l, info, "orange") - self.odd_size = 0 - else: - info = "Byte Offset: " + \ - str(self.BlockNum.get() * self.BlkSize.get()) - self.addTextInfoBar(self.InfoString_l, info) - -####################################### - def FillSelectBlk(self, key, blktype): - """ - clears/initializes entry fields on Blockette Display - """ - self.BlksTitle_fm.destroy() - self.BlksTitle_fm = Frame(self.Blockette_nb, relief='groove', - borderwidth=2) - self.BlksTitle_fm.pack(side='top', pady=5, fill='x') - - self.BlkInfo_b = Button(self.BlksTitle_fm, - activebackground='green', - background='lightblue', - text="Blockette Info", - activeforeground='black', - command=Command(self.buildBlkInfo, blktype, - self.Blockette_nb)) - self.BlkInfo_b.grid(row=0, column=1, padx=10) - - self.Blks_fm.destroy() - self.Blks_fm = Frame(self.Blockette_nb, relief='groove', borderwidth=2) - self.Blks_fm.pack(side='top', pady=5, fill='x') - - for block in self.Blockettes[key]: + for block in self.blockettes_dict[key]: if block[0] == blktype: blocktuple = block - - Label(self.BlksTitle_fm, text=BlkVars[blktype][0]).grid( - row=0, column=0) - - c = r = n = 0 - for var in range(len(BlkVars[blktype]) - 1): - Label(self.Blks_fm, - text=BlkVars[blktype][var + 1]).grid(row=r, column=c, - sticky=W) - Label(self.Blks_fm, - text=blocktuple[var]).grid(row=r, column=c + 1, sticky=W) - if n == 5: - n = r = 0 - c += 2 - else: - n += 1 - r += 1 - -####################################### - def FillUnique(self): - """ - Fills unique info on HdrDisplay - """ - self.UniqueText = Pmw.ScrolledText(self.Hdrs_fm, - borderframe=1) - self.UniqueText.pack(side='bottom', fill='both', expand=1) - - self.UniqueText.tag_config("list", foreground="blue") - self.UniqueText.tag_config("odd", backgroun="lightblue") - - self.UniqueText.insert("end", "Block\tStat\tChan\tLoc\tNet\tRate\n", - "list") - - c = 0 - for key in self.UniqueList: - for var in key.split(":"): - if c: - self.UniqueText.insert("end", """%s\t""" % var, "odd") - else: - self.UniqueText.insert("end", """%s\t""" % var) - self.UniqueText.insert("end", """\n""") - if c: - c = 0 - else: - c += 1 - -####################################### - def FillStandard(self, key): + for key, values in BlkVars.items(): + if blktype == key: + boxes = self.blockettes_tab.findChildren(QtWidgets.QGroupBox) + for box in boxes: + if box.objectName() == "Box1": + menu = box.findChild(QtWidgets.QComboBox, "type_menu") + menu.clear() + menu.insertItem(0, str(blktype)) + elif box.objectName() == "Box2": + layout = box.layout() + # delete previous labels if they exist + if layout is not None: + while layout.count(): + item = layout.takeAt(0) + widget = item.widget() + if widget is not None: + widget.setParent(None) + # create new labels + label = QtWidgets.QLabel() + label.setText(str(values[0])) + layout.addWidget(label) + layout.addWidget(self.blkinfo_btn) + layout.addStretch() + else: + layout = box.layout() + # delete previous labels if they exist + if layout is not None: + while layout.count(): + item = layout.takeAt(0) + widget = item.widget() + if widget is not None: + widget.setParent(None) + # create new labels + for x in range(1, len(values)): + label = QtWidgets.QLabel() + label.setText(str(values[x]) + " " + str(blocktuple[x-1])) + layout.addWidget(label) + + def blkinfo_window(self): + """ + Popup window for blk info button + """ + self.info_window = QtWidgets.QWidget() + self.info_window.resize(650,400) + self.info_window.setWindowTitle("Blockette Information") + + # widgets + blk_label = QtWidgets.QLabel("Blockette:") + blk_menu = QtWidgets.QComboBox() + blk_menu.activated.connect(lambda: info_box.setText( + BlkInfoDict[int(blk_menu.currentText())])\ + if blk_menu.currentText().isdigit() else \ + info_box.setText(BlkInfoDict[blk_menu.currentText()])) + info_box = QtWidgets.QTextEdit() + done_btn = QtWidgets.QPushButton("Done") + done_btn.setStyleSheet("QPushButton{background-color:lightblue;}\ + QPushButton::hover{background-color:red;}") + done_btn.clicked.connect(lambda: self.info_window.close()) + + top_layout = QtWidgets.QHBoxLayout() + top_layout.addWidget(blk_label) + top_layout.addWidget(blk_menu) + top_layout.addStretch() + + main_layout = QtWidgets.QVBoxLayout(self.info_window) + main_layout.addLayout(top_layout) + main_layout.addWidget(info_box) + main_layout.addWidget(done_btn) + + for key in BlkInfoDict.keys(): + blk_menu.addItem(str(key)) + blk_menu.setCurrentText(str(self.blockettes_list[0])) + + info_box.setText(BlkInfoDict[self.blockettes_list[0]]) + + self.info_window.show() + + def fill_standard(self, key): """ Fills standard info on HdrDisplay """ + try: + standard_widgets = self.standard_box.findChildren(QtWidgets.QLineEdit) + rate = self.rate_dict[key] + vars = [] + # SeqNum, DHQual, res, Stat, Loc, Chan, Net + vars.append(self.fixed_hdr_dict[key][0]) + vars = list(itertools.chain.from_iterable(vars)) + vars = vars[3:] # remove SeqNum, DHQual, res + vars.append(rate) + + for x in range(len(vars)): + widget = standard_widgets[x] + var = vars[x] + try: + var = var.strip().decode() + except Exception: + pass + widget.setText(str(var)) - # cleanup existing vars and reset to new key location - self.ClearAll(self.StandardVars) - (SeqNum, DHQual, res, Stat, Loc, Chan, Net) = self.FixedHdrDict[key][0] - self.SeqNum.set(SeqNum) - self.DQual.set(DHQual) - self.Resv.set(res) - self.Station.set(Stat) - self.Channel.set(Chan) - self.LocCode.set(Loc) - self.NetCode.set(Net) - (numsamp, sampfact, sampmult) = self.FixedHdrDict[key][2] - rate = self.RateDict[key] - self.SampleRate.set(rate) + # if user inputs invalid blk num + except Exception: + return -####################################### - def FillVerbose(self, key): + def fill_verbose(self, key): """ Fills verbose info on HdrDisplay """ + try: + verbose_widgets = self.verbose_box.findChildren(QtWidgets.QLineEdit) + rate = self.rate_dict[key] + vars = [] + # SeqNum, DHQual, res, Stat, Loc, Chan, Net + vars.append(self.fixed_hdr_dict[key][0]) + vars.append([str(rate)]) + # Year, Day, Hour, Min, Sec, junk, Micro + vars.append(self.fixed_hdr_dict[key][1]) + vars = list(itertools.chain.from_iterable(vars)) + vars = vars[3:] # remove SeqNum, DHQual, res + del vars[-2] # remove junk + + for x in range(len(vars)): + widget = verbose_widgets[x] + var = vars[x] + try: + var = var.strip().decode() + except Exception: + pass + widget.setText(str(var)) - # cleanup existing vars and reset to new key location - self.ClearAll(self.VerboseVars) - self.FillStandard(key) - (Year, Day, Hour, Min, Sec, junk, Micro) = self.FixedHdrDict[key][1] - self.Year.set(Year) - self.Jday.set(Day) - self.Hour.set(Hour) - self.Min.set(Min) - self.Sec.set(Sec) - self.Micro.set(Micro) + # if user inputs invalid blk num + except Exception: + return -####################################### - def FillVeryVerbose(self, key): + def fill_vv(self, key): """ Fills very verbose info on HdrDisplay """ + try: + vv_widgets = self.vv_box.findChildren(QtWidgets.QLineEdit) + rate = self.rate_dict[key] + vars = [] + # SeqNum, DHQual, res, Stat, Loc, Chan, Net + vars.append(self.fixed_hdr_dict[key][0]) + vars.append([str(rate)]) + # Year, Day, Hour, Min, Sec, junk, Micro + vars.append(self.fixed_hdr_dict[key][1]) + # NumSamp, SampFact, SampMult + vars.append(self.fixed_hdr_dict[key][2]) + # act, io, DQual, numblk, timcorr, bdata, bblock + vars.append(self.fixed_hdr_dict[key][3]) + vars = list(itertools.chain.from_iterable(vars)) + del vars[-12] # remove junk + + for x in range(len(vars)): + widget = vv_widgets[x] + var = vars[x] + try: + var = var.strip().decode() + except Exception: + pass + widget.setText(str(var)) - # cleanup existing vars and reset to new key location - self.ClearAll(self.VeryVerboseVars) - self.FillVerbose(key) - (NumSamp, SampFact, SampMult) = self.FixedHdrDict[key][2] - (act, io, DQual, numblk, timcorr, bdata, - bblock) = self.FixedHdrDict[key][3] - self.NumSamp.set(NumSamp) - self.SampFact.set(SampFact) - self.SampMult.set(SampMult) - self.ActFlag.set(act) - self.IOFlag.set(io) - self.DQFlag.set(DQual) - self.NumBlockettes.set(numblk) - self.TimeCorr.set(timcorr) - self.BeginData.set(bdata) - self.FstBlkett.set(bblock) - -########################################## - def FlushDict(self): - """ - clears dictionaries and OldMseedFile. Allows user to apply a reset and - dynamically monitor changes to mseed files. - """ - - # clear selected directory and file - self.MseedFile.set("") - self.SelDir.set("") - - # clear variables and destroy frames - self.ClearAll(self.VeryVerboseVars) - self.Hdrs_fm.destroy() - self.HdrScale_fm.destroy() - self.BlkScale_fm.destroy() - self.BlksSelect_fm.destroy() - self.BlksTitle_fm.destroy() - self.Blks_fm.destroy() - - # now clear dictionaries and set OldMseedFile to blank - self.OldMseedFile.set("") - self.FixedHdrDict = {} - self.RateDict = {} - self.Blockettes = {} - self.keyList = [] - self.UniqueList = [] - -########################################## - - def getPath(self, var, clear=1): - """ - Concatonate paths - """ - self.var = var - if clear: - self.var.set('') - newpath_dd = DirectoryDialog(self.root) - self.path = newpath_dd.go(dir_or_file=getcwd()) - if self.path is not None: - if self.var.get(): - self.var.set(self.var.get() + ':') - if len(self.path) == 1 and self.path[0] == "/": - self.var.set(self.var.get() + self.path) - elif self.path[-1] == "/": - self.var.set(self.var.get() + self.path[:-1]) - else: - self.var.set(self.var.get() + self.path) - -################################################################## + # if user inputs invalid blk num + except Exception: + return - def ClearTxt(self, var): + def fill_unique(self): """ - clear text + Fills unique info on HdrDisplay """ - var.clear() - -################################################################## + # text colors + Blue = QtGui.QColor(0,0,153) + Black = QtGui.QColor(0,0,0) + + # fill drop down menus + self.unique_box.keys_menu.clear() + self.unique_box.keys_menu.addItem("*") + self.unique_box.keys_menu.addItem(f'{self.unique_select_list[0]}') + + self.unique_box.unique_jump.blockSignals(True) + i = 0 + while i < self.num_blocks: + self.unique_box.unique_jump.addItem(str(i)) + i += 1 + self.unique_box.unique_jump.blockSignals(False) + + # fill text box + text = "Block\tStat\tChan\tLoc\tNet\tRate" + self.unique_box.unique_infobox.setTextColor(Blue) + self.unique_box.unique_infobox.setText(text) + self.unique_box.unique_infobox.setTextColor(Black) + data = [] + data.append(self.unique_list[0].split(":")) + data = list(itertools.chain.from_iterable(data)) + data = '\t'.join(str(i) for i in data) + self.unique_box.unique_infobox.append(data) - def ClearAll(self, varlist): + def wait(self, words, cnt): """ - clear a variable list + routine to put words on info bar, used to count traces + being examined """ - self.addTextInfoBar(self.InfoString_l) - for var in varlist: - self.setValue(var[1]) - -####################################### + text = words + str(cnt) + self.update_infobar(text, "lightblue") - def setValue(self, var, value=''): + def update_dir_list(self): """ - Sets Value of var + Update directory list for each scan """ - var.set(value) + self.dir_menu.clear() + self.dir_menu.insertItem(0, "") + for key in self.dir_trace_dict: + self.dir_menu.addItem(key) + self.dir_trace_box.show() -####################################### - - def addTextInfoBar(self, widget, str='', bg='yellow'): + def update_trace_list(self, dir): """ - Adds Text To InfoBar + Update trace list for each scan """ - widget.configure(background=bg, text=str) + self.trace_menu.clear() + self.trace_menu.insertItem(0, "") + for key, values in self.dir_trace_dict.items(): + if dir == key: + values.sort() + for trace in values: + self.trace_menu.addItem(trace) -################################################################## + def update_infobar(self, text, color): + """ + Update info bar when certain actions happen + """ + self.infobar.setText(text) + self.infobar.setStyleSheet("background-color:" + color) + QtWidgets.QApplication.beep() - def killWindow(self, widget): + def update_slider(self, widget): """ - Destroy Widget and Set InfoBar to Default + Get new blk number if any of the slider related widgets + are toggled, and update hdr info """ - widget.destroy() - self.addTextInfoBar(self.InfoString_l) + try: + if widget == "slider": + value = self.slider_box.slider.value() + self.slider_box.jump_menu.setCurrentText(str(value)) + self.unique_box.unique_jump.setCurrentText(str(value)) + elif widget == "menu": + value = self.slider_box.jump_menu.currentText() + self.slider_box.slider.setValue(int(value)) + self.unique_box.unique_jump.setCurrentText(str(value)) + else: + value = self.unique_box.unique_jump.currentText() + self.slider_box.slider.setValue(int(value)) + self.slider_box.jump_menu.setCurrentText(str(value)) + self.vv_rbtn.setChecked(True) + self.verb_var = 2 + self.jump_box.setCurrentIndex(2) + + # update hdr info & info bar + self.maybe_read_hdrs() + byte_offset = int(value) * int(self.blk_size) + text = "Byte Offset: " + str(byte_offset) + self.update_infobar(text, "yellow") + + # if user inputs invalid blk num + except Exception: + return -####################################### + def maybe_read_hdrs(self): + """ + If certain conditions are met, call read hdrs + """ + if not self.dir_menu.isHidden(): + dir = self.dir_menu.currentText() + if dir: + if not self.trace_menu.isHidden(): + trace = self.trace_menu.currentText() + if trace: + blk = self.slider_box.jump_menu.currentText() + self.read_hdrs(dir, trace, blk) - def wait(self, words, cnt): + def flush_dict(self): """ - routine to put words on info bar, used to count traces - being examined + clears dictionaries. Allows user to apply a reset and + dynamically monitor changes to mseed files. """ + self.fixed_hdr_dict = {} + self.rate_dict = {} + self.blockettes_dict = {} + self.key_list = [] + self.unique_list = [] + self.clear_slider() + self.header_endianess_text.clear() + self.hide_show("hide") + QtWidgets.QApplication.beep() + +class SliderBox(QtWidgets.QGroupBox): + """ + Box that holds all the blockette slider widgets + """ + def __init__(self): + """ + Init widgets for blockette parsing + """ + super().__init__() + self.setStyleSheet("QGroupBox{border:0;}") + # widgets + label1 = QtWidgets.QLabel("Jump To Block #:") + self.jump_menu = QtWidgets.QComboBox() + self.jump_menu.setMinimumWidth(100) + self.jump_menu.setEditable(True) + self.jump_menu.insertItem(0, "0") + label2 = QtWidgets.QLabel("Block Number") + self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) + self.slider.setTickPosition(self.slider.NoTicks) + + # layouts + main_layout = QtWidgets.QVBoxLayout(self) + menu_layout = QtWidgets.QVBoxLayout() + slider_layout = QtWidgets.QHBoxLayout() + menu_layout.addWidget(label1, alignment=QtCore.Qt.AlignCenter) + menu_layout.addWidget(self.jump_menu, alignment=QtCore.Qt.AlignCenter) + slider_layout.addWidget(label2) + slider_layout.addWidget(self.slider) + + # add to main layout + main_layout.addLayout(menu_layout) + main_layout.addLayout(slider_layout) + +class StandardBox(QtWidgets.QGroupBox): + """ + Box that holds all the standard info widgets + """ + def __init__(self, standard_vars): + """ + Create standard widgets + """ + super().__init__() + + # layout + v_layout = QtWidgets.QVBoxLayout(self) + h_layout = QtWidgets.QHBoxLayout() + col1 = QtWidgets.QVBoxLayout() + col2 = QtWidgets.QVBoxLayout() + + # widgets + for x in range(len(standard_vars)): + label = QtWidgets.QLabel(str(standard_vars[x])) + line_edit = QtWidgets.QLineEdit() + + col1.addWidget(label) + col2.addWidget(line_edit) + + # add to layout + h_layout.addLayout(col1) + h_layout.addLayout(col2) + v_layout.addLayout(h_layout) + + v_layout.addStretch() + +class VerboseBox(QtWidgets.QGroupBox): + """ + Box that holds all the verbose info widgets + """ + def __init__(self, standard_vars, v_vars): + """ + Create verbose widgets + """ + super().__init__() + # layout + v_layout = QtWidgets.QVBoxLayout(self) + h_layout = QtWidgets.QHBoxLayout() + col1 = QtWidgets.QVBoxLayout() + col2 = QtWidgets.QVBoxLayout() + col3 = QtWidgets.QVBoxLayout() + col4 = QtWidgets.QVBoxLayout() + + # widgets + for x in range(len(standard_vars)): + label = QtWidgets.QLabel(str(standard_vars[x])) + line_edit = QtWidgets.QLineEdit() + + col1.addWidget(label) + col2.addWidget(line_edit) + + for x in range(len(v_vars)): + label = QtWidgets.QLabel(str(v_vars[x])) + line_edit = QtWidgets.QLineEdit() + + if x == 0: + col1.addWidget(label) + col2.addWidget(line_edit) + else: + col3.addWidget(label) + col4.addWidget(line_edit) + + col3.addSpacing(25) + col4.addSpacing(25) + + # add to layout + h_layout.addLayout(col1) + h_layout.addLayout(col2) + h_layout.addLayout(col3) + h_layout.addLayout(col4) + v_layout.addLayout(h_layout) + v_layout.addStretch() + +class VVBox(QtWidgets.QGroupBox): + """ + Box that holds all the very verbose info widgets + """ + def __init__(self, first_vv_vars, standard_vars, v_vars, vv_vars): + """ + Create very verbose widgets + """ + super().__init__() + # layout + v_layout = QtWidgets.QVBoxLayout(self) + h_layout = QtWidgets.QHBoxLayout() + col1 = QtWidgets.QVBoxLayout() + col2 = QtWidgets.QVBoxLayout() + col3 = QtWidgets.QVBoxLayout() + col4 = QtWidgets.QVBoxLayout() + col5 = QtWidgets.QVBoxLayout() + col6 = QtWidgets.QVBoxLayout() + col7 = QtWidgets.QVBoxLayout() + col8 = QtWidgets.QVBoxLayout() + + # widgets + for x in range(len(first_vv_vars)): + label = QtWidgets.QLabel(str(first_vv_vars[x])) + line_edit = QtWidgets.QLineEdit() + + col1.addWidget(label) + col2.addWidget(line_edit) + + for x in range(len(standard_vars)): + label = QtWidgets.QLabel(str(standard_vars[x])) + line_edit = QtWidgets.QLineEdit() + + if x <= 2: + col1.addWidget(label) + col2.addWidget(line_edit) + else: + col3.addWidget(label) + col4.addWidget(line_edit) + + for x in range(len(v_vars)): + label = QtWidgets.QLabel(str(v_vars[x])) + line_edit = QtWidgets.QLineEdit() - txt = words + str(cnt) - self.root.update() - self.addTextInfoBar(self.InfoString_l, txt, 'lightblue') - -################################################################## - - def Exit(self): - """ - a no questions asked exit - """ - sys.exit(0) - -################################################################## - - def displayBlkInfo(self, type): - text = BlkInfoDict[type] - self.BlkInfoText.settext(text) - -################################################################## - def buildHelp(self, master): - """ - Populate Help NoteBook - """ - self.Help_nb = master.add('Help') - - self.HelpText = Pmw.ScrolledText(self.Help_nb, - borderframe=1) - self.HelpText.pack(side='bottom', fill='both', expand=1) - - self.HelpText.tag_config("hdr1", foreground="blue") - self.HelpText.tag_config("hdr2", foreground="darkgreen") - self.HelpText.tag_config("bttn", foreground="red") - - self.HelpText.insert("end", "NAME", "hdr1") - self.HelpText.insert("end", """ - mseedpeek - GUI for displaying mseed file headers.\n""") - - self.HelpText.insert("end", "\nVERSION", "hdr1") - self.HelpText.insert("end", """ - %s\n""" % VERSION) - - self.HelpText.insert("end", "\nSYNOPSIS", "hdr1") - self.HelpText.insert("end", """ - mseedpeek - mseedpeek -# - mseedpeek -f file_names\n""") - - self.HelpText.insert("end", "\nOPTIONS", "hdr1") - self.HelpText.insert("end", """ - -# returns version number - -f file_name(s) - accepts command line input for files to inspect (wildcards accepted)\n""") # noqa: E501 - - self.HelpText.insert("end", "\nDESCRIPTION", "hdr1") - self.HelpText.insert("end", """ - mseedpeek has three notebooks: """) - self.HelpText.insert("end", "[Trace Headers]", "hdr2") - self.HelpText.insert("end", "[Blockettes]", "hdr2") - self.HelpText.insert("end", """, and """) - self.HelpText.insert("end", "[Help]", "hdr2") - self.HelpText.insert("end", """.""") - - self.HelpText.insert("end", """ - The """) - self.HelpText.insert("end", "[Trace Headers]", "hdr2") - self.HelpText.insert("end", """ notebook displays various the fixed - header in four levels of verbosity.\n The """) - self.HelpText.insert("end", "[Blockettes]", "hdr2") - self.HelpText.insert("end", """ notebook displays blockette information.\n""") # noqa: E501 - - self.HelpText.insert("end", "\n [Trace Headers]", "hdr2") - self.HelpText.insert("end", """ - General: - >> specify/load directories for building trace db - >> select trace for header display - >> select level of verbosity for display - - Buttons:\n""") - self.HelpText.insert("end", " <Build Trace db>", "bttn") - self.HelpText.insert("end", """: Searchs the directories listed in the "Data- - Directories" entry box (a colon separated list) and builds a list of mseed - files found indexing them on unique values of <dir>:<file_name>. It then - creates a dropdown menu with entries for each data directory found.\n""") # noqa: E501 - self.HelpText.insert("end", " <Find>", "bttn") - self.HelpText.insert("end", """: Launches a file browser allowing the user to - add directories to the "Data Directories" entry box. Double clicking selects - the new directory.\n""") # noqa: E501 - self.HelpText.insert("end", " <Clear>", "bttn") - self.HelpText.insert( - "end", """: Clears the "Data Directories" entry box.\n""") - - self.HelpText.insert("end", """ - By selecting a data directory a dropdown menu is created for - trace selection. Selecting a trace from this menu will create - a header display. - - Radio Buttons:\n""") - self.HelpText.insert("end", " <Standard>", "bttn") - self.HelpText.insert("end", """: This is the default. It displays Station, Channel, Location Code, - Net Code, and the nominal Sample Rate.\n""") # noqa: E501 - self.HelpText.insert("end", " <Verbose>", "bttn") - self.HelpText.insert( - "end", """: Standard display plus time of block.\n""") - self.HelpText.insert("end", " <Very Verbose>", "bttn") - self.HelpText.insert( - "end", """: Verbose plus the rest of the mseed fixed header fields.\n""") # noqa: E501 - self.HelpText.insert("end", " <Unique>", "bttn") - self.HelpText.insert( - "end", """: This displays changes in the Standard fields within a mseed file.\n""") # noqa: E501 - self.HelpText.insert("end", """ - - Slider Scale and """) - self.HelpText.insert("end", "<Jump To Block #>", "bttn") - self.HelpText.insert("end", """ Button: - At the bottom of the page is a scale bar showing block numbers. Sliding - the bar scans through all fixed headers for the selected mseed file.\n""") # noqa: E501 - - self.HelpText.insert("end", "\n <Flush Dictionaries>", "bttn") - self.HelpText.insert("end", """: Clears cached trace header data. - As you view mseed headers, mseedpeek maintains a cache of previously - viewed headers for quick, future access. If you wish to monitor changes - to mseed files you need to flush the dictionaries so that the new - changes will be displayed.\n\n""") - - self.HelpText.insert("end", " [Blockettes]", "hdr2") - self.HelpText.insert("end", """: - The 'Blockettes' notebook displays all blockettes found for the select - mseed file in a dropdown menu. By selecting a blockette from the dropdown - menu, the contents of the blockette will be displayed.\n""") # noqa: E501 - - self.HelpText.insert("end", " <Blockette Info>", "bttn") - self.HelpText.insert("end", """: Displays a pop-up window with a definition of the SEED Blockette. - - At the bottom of the page is a scale bar showing block numbers and - Sliding the bar scans through all blockettes for the selected mseed file.\n""") # noqa: E501 - - self.HelpText.insert("end", "\nKEYWORDS", "hdr1") - self.HelpText.insert("end", """ - mseed; header information\n""") - - self.HelpText.insert("end", "\nSEE ALSO", "hdr1") - self.HelpText.insert("end", """ - SEED manual (pdf), fixhdr, mseedhdr\n""") - - self.HelpText.insert("end", "\nAUTHOR", "hdr1") - self.HelpText.insert("end", """ - Bruce Beaudoin <bruce@passcal.nmt.edu> -""") - - -if __name__ == '__main__': + if x <= 3: + col3.addWidget(label) + col4.addWidget(line_edit) + else: + col5.addWidget(label) + col6.addWidget(line_edit) + + for x in range(len(vv_vars)): + label = QtWidgets.QLabel(str(vv_vars[x])) + line_edit = QtWidgets.QLineEdit() + + if x <= 3: + col5.addWidget(label) + col6.addWidget(line_edit) + elif x > 3 and x <= 6: + col7.addWidget(label) + col8.addWidget(line_edit) + else: + col7.addWidget(label) + col8.addWidget(line_edit) + + # add to layout + h_layout.addLayout(col1) + h_layout.addLayout(col2) + h_layout.addLayout(col3) + h_layout.addLayout(col4) + h_layout.addLayout(col5) + h_layout.addLayout(col6) + h_layout.addLayout(col7) + h_layout.addLayout(col8) + v_layout.addLayout(h_layout) + v_layout.addStretch() + +class UniqueBox(QtWidgets.QGroupBox): + """ + Box that holds all the unique info widgets + """ + def __init__(self): + """ + Create unique widgets + """ + super().__init__() + layout = QtWidgets.QVBoxLayout(self) + select_keys_label = QtWidgets.QLabel("Select Keys:") + self.keys_menu = QtWidgets.QComboBox() + self.keys_menu.setEditable(True) + jump_label = QtWidgets.QLabel("Jump To Block #:") + self.unique_jump = QtWidgets.QComboBox() + self.unique_jump.setEditable(True) + self.unique_infobox = QtWidgets.QTextEdit() + + layout.addWidget(select_keys_label) + layout.addWidget(self.keys_menu) + layout.addWidget(jump_label) + layout.addWidget(self.unique_jump) + layout.addWidget(self.unique_infobox) + layout.addStretch() + +if __name__ == "__main__": main() diff --git a/setup.py b/setup.py index fb8a9df..d7bb59b 100644 --- a/setup.py +++ b/setup.py @@ -30,12 +30,13 @@ setup( 'mseedpeek=mseedpeek.mseedpeek:main', ], }, - install_requires=['Pmw @ https://github.com/schrodinger/pmw-patched/archive/master.tar.gz'], + install_requires=['pyside2'], setup_requires=[], extras_require={ 'dev': [ 'flake8', 'tox', + 'pyside2', ] }, license="GNU General Public License v3", @@ -45,6 +46,6 @@ setup( name='mseedpeek', packages=find_packages(include=['mseedpeek']), url='https://git.passcal.nmt.edu/passoft/mseedpeek', - version='2022.1.0.0', + version='2023.1.0.0', zip_safe=False, ) -- GitLab