diff --git a/nexus/ChannelSelectDialog.py b/nexus/ChannelSelectDialog.py index 8aa57c3ed2ee1d30fbfb5d7a00179d60c4600899..90621310a187b8a9cd30d8bb99b4ac84a9f7cb3c 100644 --- a/nexus/ChannelSelectDialog.py +++ b/nexus/ChannelSelectDialog.py @@ -12,7 +12,8 @@ import os from PySide6.QtCore import Qt from PySide6.QtGui import QFontMetrics from PySide6.QtUiTools import loadUiType -from PySide6.QtWidgets import QApplication, QTableWidgetItem +from PySide6.QtWidgets import (QApplication, QTableWidgetItem, + QAbstractItemView, QHeaderView) from .obspyImproved import utc_to_str @@ -61,6 +62,7 @@ class ChannelSelectDialog(*load_ui('ChannelSelectDialog.ui')): super().setupUi(self) self.setWindowTitle('Select channels') self.label.setText('Station: {}'.format(self.station.code)) + self.tableWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tableWidget.setRowCount(len(self.station)) self.tableWidget.horizontalHeader().sectionClicked.connect(self.sort_table) # Add channels @@ -87,6 +89,7 @@ class ChannelSelectDialog(*load_ui('ChannelSelectDialog.ui')): self.chan_map[row] = chan assert True self.tableWidget.resizeColumnsToContents() + self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) if __name__ == '__main__': diff --git a/nexus/StationSelectDialog.py b/nexus/StationSelectDialog.py new file mode 100644 index 0000000000000000000000000000000000000000..f1927b73afb2895f099ca6d6ba95689488e7f02f --- /dev/null +++ b/nexus/StationSelectDialog.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*-*# +""" +Dialog for selecting stations to copy +Datalogger Type, Sensor Type and Gain +""" + +import os + +from PySide6.QtGui import QFontMetrics, Qt +from PySide6.QtWidgets import QTableWidgetItem, QAbstractItemView, QHeaderView +from PySide6.QtUiTools import loadUiType + +from .obspyImproved import utc_to_str + +def load_ui(filename): + """ + Helper function + Load a ui file relative to this source file + """ + path = os.path.join(os.path.dirname(__file__), filename) + try: + ret = loadUiType(path) + except Exception as e: + print(e) + raise e + return ret + +class StationSelectDialog(*load_ui('StationSelectDialog.ui')): + def __init__(self, stations, action, values, parent=None): + super().__init__(parent) + self.stations = stations + self.sta_map = {} + self.action = action + self.values = values + self.setupUi() + + def accept(self): + rows = set(item.row() for item in self.tableWidget.selectedItems()) + self.selected_stations = [] + for row in rows: + self.selected_stations.append(self.sta_map[row]) + super().accept() + + def sort_table(self, column): + """ + Sort Station Select Dialog table based on column + header selected by user. + """ + row_map = {0: 'code', 1: 'start_date', 2: 'end_date'} + order = self.tableWidget.horizontalHeader().sortIndicatorOrder() + descending = False if order == Qt.AscendingOrder else True + self.sta_map = {ind: v for ind, (_, v) in enumerate(sorted(self.sta_map.items(), + key=lambda item: getattr(item[1], row_map[column]), + reverse=descending))} + + def setupUi(self): + super().setupUi(self) + self.setWindowTitle('Select Stations') + if self.action == 'type & gain': + self.uiGainCB.setChecked(True) + self.uiGainCB.setText(f"Copy Datalogger Gain: {self.values[0]}") + self.uiTypeCB.setChecked(True) + self.uiTypeCB.setText(f"Copy Datalogger Type: {self.values[1]}") + self.uiSensorLabel.setParent(None) + else: + self.uiSensorLabel.setText(f"Copy Sensor Type: {self.values[0]}") + self.uiTypeCB.setParent(None) + self.uiGainCB.setParent(None) + self.tableWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) + self.tableWidget.setRowCount(len(self.stations)) + self.tableWidget.horizontalHeader().sectionClicked.connect(self.sort_table) + # Add stations to table + for row, sta in enumerate(self.stations): + for col, value in enumerate(('{:<3s}'.format(sta.code), + utc_to_str(sta.start_date), + utc_to_str(sta.end_date))): + item = QTableWidgetItem() + item.setText(value) + # shorten start/end time + if col == 1 or col == 2: + # full time as tooltip + item.setToolTip(value) + # rounded time in table + value = QFontMetrics(self.tableWidget.font()).elidedText(value, + Qt.ElideRight, + 100) + item.setText(value) + self.tableWidget.setItem(row, col, item) + self.sta_map[row] = sta + self.tableWidget.resizeColumnsToContents() + self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) diff --git a/nexus/StationSelectDialog.ui b/nexus/StationSelectDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..4d960766eb07d478bf9a04608aaf6dbaf48f2d50 --- /dev/null +++ b/nexus/StationSelectDialog.ui @@ -0,0 +1,182 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>359</width> + <height>576</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="uiTypeCB"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Copy stated datalogger type to selected stations in table</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="uiGainCB"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Copy stated datalogger gain to selected stations in table</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="uiSensorLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Copy stated sensor type to selected stations in table</string> + </property> + </widget> + </item> + <item> + <widget class="QTableWidget" name="tableWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustToContents</enum> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::MultiSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + <property name="cornerButtonEnabled"> + <bool>false</bool> + </property> + <attribute name="horizontalHeaderDefaultSectionSize"> + <number>50</number> + </attribute> + <attribute name="horizontalHeaderShowSortIndicator" stdset="0"> + <bool>true</bool> + </attribute> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <attribute name="verticalHeaderShowSortIndicator" stdset="0"> + <bool>false</bool> + </attribute> + <attribute name="verticalHeaderStretchLastSection"> + <bool>false</bool> + </attribute> + <column> + <property name="text"> + <string>Stat</string> + </property> + <property name="textAlignment"> + <set>AlignCenter</set> + </property> + </column> + <column> + <property name="text"> + <string>Start</string> + </property> + <property name="textAlignment"> + <set>AlignCenter</set> + </property> + </column> + <column> + <property name="text"> + <string>End</string> + </property> + <property name="textAlignment"> + <set>AlignCenter</set> + </property> + </column> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>Dialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Dialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/nexus/StationWidget.ui b/nexus/StationWidget.ui index 04fab390a35103fc3cf70481beedc4a333be7cbe..c31e7468238d8e40eeef8cc9a69f3522fbb55354 100644 --- a/nexus/StationWidget.ui +++ b/nexus/StationWidget.ui @@ -71,6 +71,13 @@ </property> </widget> </item> + <item row="3" column="0" colspan="2"> + <widget class="QPushButton" name="copyDL_button"> + <property name="text"> + <string>Copy Type && Gain to More Stations</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -119,6 +126,13 @@ </property> </widget> </item> + <item row="3" column="0" colspan="2"> + <widget class="QPushButton" name="copySensor_button"> + <property name="text"> + <string>Copy Type to More Stations</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/nexus/nexus.py b/nexus/nexus.py index 377d34a35d66d8ebdc74e7bb0ee28418122d7bd4..49692fae8bc40ff390bb1692f447375e6ba570da 100755 --- a/nexus/nexus.py +++ b/nexus/nexus.py @@ -22,6 +22,7 @@ from .NRLWizard import NRLWizard, DATALOGGER, SENSOR from . import obspyImproved from . import hardware from .ChannelSelectDialog import ChannelSelectDialog +from .StationSelectDialog import StationSelectDialog # function to display status message, initially just print status_message = print @@ -911,7 +912,6 @@ class NexusWindow(*load_ui("NexusWindow.ui")): dialog.selected_channels, ) self.inv_model.add_inventory(self.inventory) - #self.reshape_tree() def scan_ms_dialog(self): dir_name = QtWidgets.QFileDialog.getExistingDirectory(self, 'Dir to scan for MSEED') @@ -1190,10 +1190,11 @@ class StationWidget(WidgetBase, *load_ui("StationWidget.ui")): def __init__(self, parent=None): super().__init__(parent) self.build_dl_combo() + self.copyDL_button.clicked.connect(self.copy_dltype_and_gain) + self.copySensor_button.clicked.connect(self.copy_sensor) self.uiDLType.activated.connect(self.combo_changed) self.build_sensor_combo() self.uiSensorType.activated.connect(self.combo_changed) - self.uiDLType.currentIndexChanged.connect(self.update_model) self.uiSensorType.currentIndexChanged.connect(self.update_model) self.uiDLGain.editingFinished.connect(self.update_model) @@ -1284,6 +1285,64 @@ class StationWidget(WidgetBase, *load_ui("StationWidget.ui")): self._data_mapper.addMapping(self.uiSiteRegion, n.col(n.site_region)) self._data_mapper.addMapping(self.uiSiteCountry, n.col(n.site_country)) + def copy_dltype_and_gain(self): + stations = self.get_stations() + self.copy_to_stations(stations, + 'type & gain', + [self.uiDLGain.text(), self.uiDLType.currentText()]) + + def copy_sensor(self): + stations = self.get_stations() + self.copy_to_stations(stations, + 'sensor', + [self.uiSensorType.currentText()]) + + def copy_to_stations(self, stations, action, values): + dialog = StationSelectDialog(stations, action, values, parent=self) + if dialog.exec_(): + if dialog.uiSensorLabel.parent() is None: + copy_this = {"DLtype": dialog.uiTypeCB.isChecked(), + "DLgain": dialog.uiGainCB.isChecked()} + else: + copy_this = {"Stype": True} + self.update_stations(dialog.selected_stations, copy_this) + + def update_stations(self, stations, copy_this): + for station in stations: + for node, obj in self.stat_node_to_obj_map.items(): + if station == obj: + for key, value in copy_this.items(): + if value is False: + continue + if key == "DLtype": + node.set_dl_type(self.uiDLType.currentIndex()) + elif key == "DLgain": + node.set_dl_gain(self.uiDLGain.text()) + else: + node.set_sensor_type(self.uiSensorType.currentIndex()) + + def get_stations(self): + """ + Get all stations from inventory to + add to Station Select Dialogue + """ + # get top most network + net = self._model.index(0, 0, QtCore.QModelIndex()) + self.stat_node_to_obj_map = {} + stations = [] + net_row = 0 + try: + while True: + for r in range(self._model.rowCount(net)): + station_index = self._model.index(r, 0, net) + station_node = station_index.model().get_node(station_index) + station_obj = station_node._inv_obj + stations.append(station_obj) + self.stat_node_to_obj_map[station_node] = station_obj + net_row += 1 + net = self._model.sibling(net_row, 0, net) + except IndexError: + return stations class ChannelWidget(WidgetBase, *load_ui("ChannelWidget.ui")):