# -*- coding: utf-8 -*- """ /*************************************************************************** EO Time Series Viewer ------------------- begin : 2015-08-20 git sha : $Format:%H$ copyright : (C) 2017 by HU-Berlin email : benjamin.jakimow@geo.hu-berlin.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ """ # noinspection PyPep8Naming import sys, os from qgis.core import * from qgis.gui import * from qgis.PyQt.QtCore import * from qgis.PyQt.QtGui import * from qgis.PyQt.QtWidgets import * from eotimeseriesviewer.timeseries import TimeSeries, SensorInstrument, TimeSeriesDate, TimeSeriesSource from eotimeseriesviewer.utils import loadUI class SensorDockUI(QgsDockWidget, loadUI('sensordock.ui')): def __init__(self, parent=None): super(SensorDockUI, self).__init__(parent) self.setupUi(self) self.TS = None def setTimeSeries(self, timeSeries): from eotimeseriesviewer.timeseries import TimeSeries from eotimeseriesviewer.sensorvisualization import SensorTableModel assert isinstance(timeSeries, TimeSeries) self.TS = timeSeries self.mSensorModel = SensorTableModel(self.TS) self.mSortedModel = QSortFilterProxyModel() self.mSortedModel.setSourceModel(self.mSensorModel) self.sensorView.setModel(self.mSortedModel) self.sensorView.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) s = "" class SensorTableModel(QAbstractTableModel): def __init__(self, TS, parent=None, *args): super(SensorTableModel, self).__init__() assert isinstance(TS, TimeSeries) # define column names self.mCN_Name = "Name" self.mCN_Band = "Band" self.mCN_Dates = "Dates" self.mCN_Images = "Images" self.mCN_WL = "Wavelength" self.mCN_ID = "ID" self.mColumNames = [self.mCN_Name, self.mCN_Band, self.mCN_Dates, self.mCN_Images, self.mCN_WL, self.mCN_ID] self.TS = TS self.TS.sigSensorAdded.connect(self.addSensor) self.TS.sigSensorRemoved.connect(self.removeSensor) self.TS.sigTimeSeriesDatesAdded.connect(self.onTimeSeriesSourceChanges) self.TS.sigTimeSeriesDatesRemoved.connect(self.onTimeSeriesSourceChanges) self.mSensors = [] for s in self.TS.sensors(): self.addSensor(s) def onTimeSeriesSourceChanges(self, timeSeriesDates:list): """ Reaction on changes in the time series data sources :param timeSeriesDates: list """ sensors = set() for tsd in timeSeriesDates: assert isinstance(tsd, TimeSeriesDate) sensors.add(tsd.sensor()) for sensor in sensors: self.updateSensor(sensor) def addSensor(self, sensor:SensorInstrument): """ Adds a sensor :param sensor: SensorInstrument """ assert isinstance(sensor, SensorInstrument) i = self.rowCount() self.beginInsertRows(QModelIndex(),i,i) self.mSensors.append(sensor) sensor.sigNameChanged.connect(lambda *args, sensor=sensor: self.updateSensor(sensor)) self.endInsertRows() def updateSensor(self, sensor:SensorInstrument): assert isinstance(sensor, SensorInstrument) if sensor in self.mSensors: tl = self.getIndexFromSensor(sensor) br = self.createIndex(tl.row(), self.columnCount()-1) self.dataChanged.emit(tl, br) def removeSensor(self, sensor:SensorInstrument): """ Removes a SensorInstrument :param sensor: SensorInstrument """ assert isinstance(sensor, SensorInstrument) if sensor in self.mSensors: i = self.mSensors.index(sensor) self.beginRemoveRows(QModelIndex(), i, i) self.mSensors.remove(sensor) self.endRemoveRows() def rowCount(self, parent = QModelIndex()): return len(self.mSensors) def removeRows(self, row, count , parent=QModelIndex()): self.beginRemoveRows(parent, row, row+count-1) toRemove = self.mSensors[row:row + count] for tsd in toRemove: self.mSensors.remove(tsd) self.endRemoveRows() def getIndexFromSensor(self, sensor)->QModelIndex: return self.createIndex(self.mSensors.index(sensor), 0) def getSensorFromIndex(self, index)->SensorInstrument: if index.isValid(): return self.mSensors[index.row()] return None def columnCount(self, parent = QModelIndex()): return len(self.mColumNames) def data(self, index, role = Qt.DisplayRole): if role is None or not index.isValid(): return None value = None columnName = self.mColumNames[index.column()] sensor = self.getSensorFromIndex(index) assert isinstance(sensor, SensorInstrument) if role in [Qt.DisplayRole, Qt.EditRole]: if columnName == self.mCN_Name: value = sensor.name() elif columnName == self.mCN_Band: value = str(sensor.nb) elif columnName == self.mCN_Images: n = 0 for tsd in self.TS.tsds(sensor=sensor): assert isinstance(tsd, TimeSeriesDate) n += len(tsd.sources()) value = n elif columnName == self.mCN_Dates: value = len(self.TS.tsds(sensor=sensor)) elif columnName == self.mCN_ID: value = sensor.id() elif columnName == self.mCN_WL: if sensor.wl is None or sensor.wl.ndim == 0: value = 'undefined' else: value = ','.join([str(w) for w in sensor.wl]) if sensor.wlu is not None: value += '[{}]'.format(sensor.wlu) elif role == Qt.CheckStateRole: if columnName == self.mCN_Name: value = None elif role == Qt.UserRole: value = sensor return value def setData(self, index, value, role=None): if role is None or not index.isValid(): return None columnName = self.mColumNames[index.column()] sensor = self.getSensorFromIndex(index) assert isinstance(sensor, SensorInstrument) b = False if role == Qt.EditRole and columnName == self.mCN_Name: if len(value) == 0: #do not accept empty strings b = False else: sensor.setName(str(value)) b = True #data changed will be emitted via signal from sensor in updateSensor return b def flags(self, index): if index.isValid(): columnName = self.mColumNames[index.column()] flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable if columnName in [self.mCN_Name]: #allow check state flags = flags | Qt.ItemIsUserCheckable | Qt.ItemIsEditable return flags #return item.qt_flags(index.column()) return None def headerData(self, col, orientation, role): if Qt is None: return None if orientation == Qt.Horizontal and role == Qt.DisplayRole: return self.mColumNames[col] elif orientation == Qt.Vertical and role == Qt.DisplayRole: return col + 1 return None class SensorListModel(QAbstractListModel): def __init__(self, TS, parent=None, *args): super(SensorListModel, self).__init__() assert isinstance(TS, TimeSeries) self.TS = TS self.TS.sigSensorAdded.connect(self.insertSensor) self.TS.sigSensorRemoved.connect(self.removeSensor) self.mSensors = [] self.sortColumnIndex = 0 self.sortOrder = Qt.AscendingOrder for s in self.TS.sensors(): self.insertSensor(s) def insertSensor(self, sensor, i=None): assert isinstance(sensor, SensorInstrument) if i is None: i = len(self.mSensors) self.beginInsertRows(QModelIndex(), i, i) self.mSensors.insert(i, sensor) self.endInsertRows() def removeSensor(self, sensor): assert isinstance(sensor, SensorInstrument) if sensor in self.mSensors: i = self.mSensors.index(sensor) self.beginRemoveRows(QModelIndex(), i, i) self.mSensors.remove(sensor) self.endRemoveRows() def sort(self, col, order): if self.rowCount() == 0: return self.layoutAboutToBeChanged.emit() r = order != Qt.AscendingOrder self.mSensors.sort(key = lambda s:s.name(), reverse=r) self.layoutChanged.emit() def rowCount(self, parent = QModelIndex()): return len(self.mSensors) def removeRows(self, row, count , parent=QModelIndex()): self.beginRemoveRows(parent, row, row+count-1) toRemove = self.mSensors[row:row + count] for tsd in toRemove: self.mSensors.remove(tsd) self.endRemoveRows() def sensor2idx(self, sensor): assert isinstance(sensor, SensorInstrument) return self.createIndex(self.mSensors.index(sensor), 0) def idx2sensor(self, index): assert isinstance(index, QModelIndex) if index.isValid(): return self.mSensors[index.row()] return None def data(self, index, role = Qt.DisplayRole): if role is None or not index.isValid(): return None value = None sensor = self.idx2sensor(index) assert isinstance(sensor, SensorInstrument) if role == Qt.DisplayRole: value = sensor.name() elif role == Qt.UserRole: value = sensor return value def flags(self, index): if index.isValid(): flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable return flags #return item.qt_flags(index.column()) return None def headerData(self, col, orientation, role): if Qt is None: return None if orientation == Qt.Horizontal and role == Qt.DisplayRole: return self.columnames[col] elif orientation == Qt.Vertical and role == Qt.DisplayRole: return col return None