Newer
Older
# -*- coding: utf-8 -*-
"""
/***************************************************************************

Benjamin Jakimow
committed
EO Time Series Viewer
-------------------
begin : 2017-08-04
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 os, sys, pickle, datetime
from qgis.gui import *
from qgis.core import *

Benjamin Jakimow
committed
from qgis.PyQt.QtCore import *
from qgis.PyQt.QtXml import *
from qgis.PyQt.QtGui import *
from .timeseries import *
from .utils import SpatialExtent, SpatialPoint, px2geo, loadUI, nextColor

Benjamin Jakimow
committed
from .externals.qps.plotstyling.plotstyling import PlotStyle, PlotStyleButton, PlotStyleDialog
from .externals import pyqtgraph as pg
from .sensorvisualization import SensorListModel
from .temporalprofiles2d import *
from .temporalprofiles3d import *
import numpy as np
#import OpenGL
from eotimeseriesviewer.temporalprofiles3d import *
except Exception as ex:
print('unable to import OpenGL based packages:\n{}'.format(ex))
def getTextColorWithContrast(c):
assert isinstance(c, QColor)
if c.lightness() < 0.5:
return QColor('white')
else:
return QColor('black')
def selectedModelIndices(tableView):
assert isinstance(tableView, QTableView)
result = {}
sm = tableView.selectionModel()
m = tableView.model()
if isinstance(sm, QItemSelectionModel) and isinstance(m, QAbstractItemModel):
for idx in sm.selectedIndexes():
assert isinstance(idx, QModelIndex)
if idx.row() not in result.keys():
result[idx.row()] = idx
return result.values()
def __init__(self, *args, **kwds):
# menu creation is deferred because it is expensive and often
# the user will never see the menu anyway.
self.menu = None
def boundingRect(self):
return super(_SensorPoints,self).boundingRect()
def paint(self, p, *args):
super(_SensorPoints, self).paint(p, *args)
# On right-click, raise the context menu
def mouseClickEvent(self, ev):
if ev.button() == QtCore.Qt.RightButton:
if self.raiseContextMenu(ev):
ev.accept()
def raiseContextMenu(self, ev):
menu = self.getContextMenus()
# Let the scene add on to the end of our context menu
# (this is optional)
menu = self.scene().addParentContextMenus(self, menu, ev)
pos = ev.screenPos()
menu.popup(QtCore.QPoint(pos.x(), pos.y()))
return True
# This method will be called when this item's _children_ want to raise
# a context menu that includes their parents' menus.
def getContextMenus(self, event=None):
if self.menu is None:
self.menu = QMenu()
self.menu.setTitle(self.name + " options..")
green = QAction("Turn green", self.menu)
green.triggered.connect(self.setGreen)
self.menu.addAction(green)
self.menu.green = green
blue = QAction("Turn blue", self.menu)
blue.triggered.connect(self.setBlue)
self.menu.addAction(blue)
self.menu.green = blue
alpha = QWidgetAction(self.menu)
alphaSlider = QSlider()
alphaSlider.setOrientation(QtCore.Qt.Horizontal)
alphaSlider.setMaximum(255)
alphaSlider.setValue(255)
alphaSlider.valueChanged.connect(self.setAlpha)
alpha.setDefaultWidget(alphaSlider)
self.menu.addAction(alpha)
self.menu.alpha = alpha
self.menu.alphaSlider = alphaSlider
return self.menu
class SensorPixelDataMemoryLayer(QgsVectorLayer):
def __init__(self, sensor, crs=None):
assert isinstance(sensor, SensorInstrument)
if crs is None:
crs = QgsCoordinateReferenceSystem('EPSG:4862')
uri = 'Point?crs={}'.format(crs.authid())
super(SensorPixelDataMemoryLayer, self).__init__(uri, 'Pixels_sensor_' + sensor.name(), 'memory', False)
self.mSensor = sensor
#initialize fields
assert self.startEditing()
# standard field names, types, etc.
fieldDefs = [('pxid', QVariant.String, 'integer'),
('date', QVariant.String, 'char'),
('doy', QVariant.Int, 'integer'),
('geo_x', QVariant.Double, 'decimal'),
('geo_y', QVariant.Double, 'decimal'),
('px_x', QVariant.Int, 'integer'),
('px_y', QVariant.Int, 'integer'),
]
# one field for each band
for b in range(sensor.nb):
fName = 'b{}'.format(b + 1)
fieldDefs.append((fName, QVariant.Double, 'decimal'))
# initialize fields
for fieldDef in fieldDefs:
field = QgsField(fieldDef[0], fieldDef[1], fieldDef[2])
self.addAttribute(field)
self.commitChanges()
def sensor(self):
return self.mSensor
def nPixels(self):
raise NotImplementedError()
def dates(self):
raise NotImplementedError()
class PlotSettingsModel3D(QAbstractTableModel):
#sigSensorAdded = pyqtSignal(SensorPlotSettings)
sigVisibilityChanged = pyqtSignal(TemporalProfile2DPlotStyle)
sigPlotStylesAdded = pyqtSignal(list)
sigPlotStylesRemoved = pyqtSignal(list)
def __init__(self, parent=None, *args):
#assert isinstance(tableView, QTableView)
super(PlotSettingsModel3D, self).__init__(parent=parent)
self.mTimeSeries = None
self.cnID = 'ID'
self.cnExpression = LABEL_EXPRESSION_3D
self.cnTemporalProfile = 'Coordinate'
self.cnStyle = 'Style'
self.cnSensor = 'Sensor'
self.columnNames = [self.cnTemporalProfile, self.cnSensor, self.cnStyle, self.cnExpression]
self.mPlotSettings = []
#assert isinstance(plotWidget, DateTimePlotWidget)
self.sortColumnIndex = 0
self.sortOrder = Qt.AscendingOrder
self.sort(0, Qt.AscendingOrder)
def hasStyleForSensor(self, sensor):
assert isinstance(sensor, SensorInstrument)
for plotStyle in self.mPlotSettings:
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if plotStyle.sensor() == sensor:
return True
return False
def onSensorRemoved(self, sensor):
assert isinstance(sensor, SensorInstrument)
self.removePlotStyles([s for s in self.mPlotSettings if s.sensor() == sensor])
def __len__(self):
return len(self.mPlotSettings)
def __iter__(self):
return iter(self.mPlotSettings)
def __getitem__(self, slice):
return self.mPlotSettings[slice]
def __contains__(self, item):
return item in self.mPlotSettings
def columnIndex(self, name):
return self.columnNames.index(name)
def insertPlotStyles(self, plotStyles, i=None):
"""
Inserts PlotStyle
:param plotStyles: TemporalProfilePlotStyle | [list-of-TemporalProfilePlotStyle]
:param i: index to insert, defaults to the last list position
"""
if isinstance(plotStyles, TemporalProfile3DPlotStyle):
plotStyles = [plotStyles]
assert isinstance(plotStyles, list)
for plotStyle in plotStyles:
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if i is None:
i = len(self.mPlotSettings)
if len(plotStyles) > 0:
self.beginInsertRows(QModelIndex(), i, i + len(plotStyles)-1)
for j, plotStyle in enumerate(plotStyles):
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
self.mPlotSettings.insert(i+j, plotStyle)
self.endInsertRows()
self.sigPlotStylesAdded.emit(plotStyles)
def removePlotStyles(self, plotStyles):
"""
Removes PlotStyle instances
:param plotStyles: TemporalProfilePlotStyle | [list-of-TemporalProfilePlotStyle]
"""
if isinstance(plotStyles, TemporalProfile3DPlotStyle):
plotStyles = [plotStyles]
assert isinstance(plotStyles, list)
if len(plotStyles) > 0:
for plotStyle in plotStyles:
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if plotStyle in self.mPlotSettings:
idx = self.plotStyle2idx(plotStyle)
self.beginRemoveRows(QModelIndex(), idx.row(),idx.row())
self.mPlotSettings.remove(plotStyle)
self.endRemoveRows()
self.sigPlotStylesRemoved.emit(plotStyles)
def sort(self, col, order):
if self.rowCount() == 0:
return
colName = self.columnames[col]
r = order != Qt.AscendingOrder
#self.beginMoveRows(idxSrc,
if colName == self.cnSensor:
self.mPlotSettings.sort(key = lambda sv:sv.sensor().name(), reverse=r)
def rowCount(self, parent = QModelIndex()):
return len(self.mPlotSettings)
def removeRows(self, row, count , parent = QModelIndex()):
self.beginRemoveRows(parent, row, row + count-1)
toRemove = self.mPlotSettings[row:row + count]
for tsd in toRemove:
self.mPlotSettings.remove(tsd)
def plotStyle2idx(self, plotStyle):
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if plotStyle in self.mPlotSettings:
i = self.mPlotSettings.index(plotStyle)
return self.createIndex(i, 0)
else:
return QModelIndex()
def idx2plotStyle(self, index):
if index.isValid() and index.row() < self.rowCount():
return self.mPlotSettings[index.row()]
def columnCount(self, parent = QModelIndex()):
return len(self.columnNames)
def data(self, index, role = Qt.DisplayRole):
if role is None or not index.isValid():
return None
value = None
columnName = self.columnNames[index.column()]
plotStyle = self.idx2plotStyle(index)
if isinstance(plotStyle, TemporalProfile3DPlotStyle):
sensor = plotStyle.sensor()
#print(('data', columnName, role))
if role == Qt.DisplayRole:
if columnName == self.cnSensor:
if isinstance(sensor, SensorInstrument):
value = sensor.name()
else:
value = '<Select Sensor>'
elif columnName == self.cnExpression:
value = plotStyle.expression()
elif columnName == self.cnTemporalProfile:
tp = plotStyle.temporalProfile()
if isinstance(tp, TemporalProfile):
value = tp.name()
else:
value = 'undefined'
elif role == Qt.EditRole:
if columnName == self.cnExpression:
value = plotStyle.expression()
elif role == Qt.CheckStateRole:
if columnName == self.cnTemporalProfile:
value = Qt.Checked if plotStyle.isVisible() else Qt.Unchecked
elif role == Qt.UserRole:
value = plotStyle
if columnName == self.cnSensor:
value = plotStyle.sensor()
elif columnName == self.cnStyle:
value = plotStyle
else:
value = plotStyle
#print(('get data',value))
return value
def setData(self, index, value, role=None):
if role is None or not index.isValid():
return False
#print(('Set data', index.row(), index.column(), value, role))
columnName = self.columnNames[index.column()]
if value is None:
return False
result = False
plotStyle = self.idx2plotStyle(index)
if isinstance(plotStyle, TemporalProfile3DPlotStyle):
"""
if role in [Qt.DisplayRole]:
if columnName == self.cnExpression and isinstance(value, str):
plotStyle.setExpression(value)
result = True
elif columnName == self.cnStyle:
if isinstance(value, PlotStyle):
plotStyle.copyFrom(value)
result = True
"""
if role == Qt.CheckStateRole:
if columnName == self.cnTemporalProfile:
plotStyle.setVisibility(value == Qt.Checked)
result = True
if role == Qt.EditRole:
if columnName == self.cnSensor:
plotStyle.setSensor(value)
result = True
elif columnName == self.cnExpression:
plotStyle.setExpression(value)
result = True
elif columnName == self.cnTemporalProfile:
plotStyle.setTemporalProfile(value)
result = True
elif columnName == self.cnStyle:
#set the style and trigger an update
lastItemType = plotStyle.itemType()
lastExpression = plotStyle.expression()
plotStyle.copyFrom(value)
if lastItemType != plotStyle.itemType() or \
lastExpression != plotStyle.expression():
plotStyle.updateDataProperties()
else:
plotStyle.updateStyleProperties()
def flags(self, index):
if index.isValid():
stype = self.idx2plotStyle(index)
columnName = self.columnNames[index.column()]
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if columnName in [self.cnTemporalProfile]:
flags = flags | Qt.ItemIsUserCheckable
if columnName in [self.cnTemporalProfile, self.cnSensor, self.cnExpression, self.cnStyle]: #allow check state
flags = flags | Qt.ItemIsEditable
return flags
#return item.qt_flags(index.column())
return Qt.NoItemFlags
def headerData(self, col, orientation, role):
if Qt is None:
return None
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columnNames[col]
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
return col
return None
class PlotSettingsModel2D(QAbstractTableModel):
# sigSensorAdded = pyqtSignal(SensorPlotSettings)
sigVisibilityChanged = pyqtSignal(TemporalProfile2DPlotStyle)
sigDataChanged = pyqtSignal(TemporalProfile2DPlotStyle)
sigPlotStylesAdded = pyqtSignal(list)
sigPlotStylesRemoved = pyqtSignal(list)
def __init__(self, parent=None, *args):
super(PlotSettingsModel2D, self).__init__(parent=parent)
self.cnID = 'ID'
self.cnSensor = 'Sensor'
self.cnExpression = LABEL_EXPRESSION_2D
self.cnStyle = 'Style'
self.cnTemporalProfile = 'Coordinate'
self.columnNames = [self.cnTemporalProfile, self.cnSensor, self.cnStyle, self.cnExpression]
self.mPlotSettings = []

Benjamin Jakimow
committed
self.mIconSize = QSize(25, 25)
self.dataChanged.connect(self.signaler)
def __len__(self):
return len(self.mPlotSettings)
def __iter__(self):
return iter(self.mPlotSettings)
def __getitem__(self, slice):
return self.mPlotSettings[slice]
def __contains__(self, item):
return item in self.mPlotSettings
def testSlot(self, *args):
print(('TESTSLOT', args))
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
def signaler(self, idxUL, idxLR):
if idxUL.isValid():
plotStyle = self.idx2plotStyle(idxUL)
cname = self.columnNames[idxUL.column()]
if cname in [self.cnSensor,self.cnStyle]:
self.sigVisibilityChanged.emit(plotStyle)
if cname in [self.cnExpression]:
self.sigDataChanged.emit(plotStyle)
def requiredBandsIndices(self, sensor):
"""
Returns the band indices required to calculate the values for
the different PlotStyle expressions making use of sensor
:param sensor: SensorInstrument for which the band indices are to be returned.
:return: [list-of-band-indices]
"""
bandIndices = set()
assert isinstance(sensor, SensorInstrument)
for p in [p for p in self.mPlotSettings if p.sensor() == sensor]:
assert isinstance(p, TemporalProfile2DPlotStyle)
expression = p.expression()
#remove leading & tailing "
bandKeys = regBandKey.findall(expression)
for bandIndex in [bandKey2bandIndex(key) for key in bandKeys]:
bandIndices.add(bandIndex)
return bandIndices
def insertPlotStyles(self, plotStyles, i=None):
"""
Inserts PlotStyle
:param plotStyles: TemporalProfilePlotStyle | [list-of-TemporalProfilePlotStyle]
:param i: index to insert, defaults to the last list position
"""
if isinstance(plotStyles, TemporalProfile2DPlotStyle):
plotStyles = [plotStyles]
assert isinstance(plotStyles, list)
for plotStyle in plotStyles:
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
if i is None:
i = len(self.mPlotSettings)
if len(plotStyles) > 0:
self.beginInsertRows(QModelIndex(), i, i + len(plotStyles)-1)
for j, plotStyle in enumerate(plotStyles):
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
plotStyle.sigExpressionUpdated.connect(lambda s = plotStyle: self.onStyleUpdated(s))
self.mPlotSettings.insert(i+j, plotStyle)
self.endInsertRows()
self.sigPlotStylesAdded.emit(plotStyles)
def onStyleUpdated(self, style):
idx = self.plotStyle2idx(style)
r = idx.row()
self.dataChanged.emit(self.createIndex(r, 0), self.createIndex(r, self.columnCount()))
s = ""
def removePlotStyles(self, plotStyles):
"""
Removes PlotStyle instances
:param plotStyles: TemporalProfilePlotStyle | [list-of-TemporalProfilePlotStyle]
"""
if isinstance(plotStyles, PlotStyle):
plotStyles = [plotStyles]
assert isinstance(plotStyles, list)
if len(plotStyles) > 0:
for plotStyle in plotStyles:
assert isinstance(plotStyle, PlotStyle)
if plotStyle in self.mPlotSettings:
idx = self.plotStyle2idx(plotStyle)
self.beginRemoveRows(QModelIndex(), idx.row(),idx.row())
self.mPlotSettings.remove(plotStyle)
self.endRemoveRows()
self.sigPlotStylesRemoved.emit(plotStyles)
def rowCount(self, parent = QModelIndex()):
return len(self.mPlotSettings)
def removeRows(self, row, count , parent = QModelIndex()):
self.beginRemoveRows(parent, row, row + count-1)
toRemove = self.mPlotSettings[row:row + count]
for tsd in toRemove:
self.mPlotSettings.remove(tsd)
self.endRemoveRows()
def plotStyle2idx(self, plotStyle):
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
if plotStyle in self.mPlotSettings:
i = self.mPlotSettings.index(plotStyle)
return self.createIndex(i, 0)
else:
return QModelIndex()
def idx2plotStyle(self, index):
if index.isValid() and index.row() < self.rowCount():
return self.mPlotSettings[index.row()]
return None
def columnCount(self, parent = QModelIndex()):
def data(self, index, role = Qt.DisplayRole):
if role is None or not index.isValid():
return None
value = None
columnName = self.columnNames[index.column()]
if isinstance(plotStyle, TemporalProfile2DPlotStyle):
sensor = plotStyle.sensor()
#print(('data', columnName, role))
if role == Qt.DisplayRole:
if columnName == self.cnSensor:
if isinstance(sensor, SensorInstrument):
value = sensor.name()
else:
value = '<Select Sensor>'
elif columnName == self.cnExpression:
value = plotStyle.expression()
elif columnName == self.cnTemporalProfile:
tp = plotStyle.temporalProfile()
if isinstance(tp, TemporalProfile):

Benjamin Jakimow
committed
value = '{} {}'.format(tp.id(), tp.name())
else:
value = 'undefined'
if columnName == self.cnTemporalProfile:
value = Qt.Checked if plotStyle.isVisible() else Qt.Unchecked
elif role == Qt.UserRole:
value = plotStyle
if columnName == self.cnSensor:
value = plotStyle.sensor()
elif columnName == self.cnExpression:
value = plotStyle.expression()
elif columnName == self.cnStyle:
value = plotStyle
elif columnName == self.cnTemporalProfile:
value == plotStyle.temporalProfile()
else:
value = plotStyle
#print(('get data',value))
return value
def setData(self, index, value, role=None):
if role is None or not index.isValid():
return False
#print(('Set data', index.row(), index.column(), value, role))
columnName = self.columnNames[index.column()]
result = False
plotStyle = self.idx2plotStyle(index)
if isinstance(plotStyle, TemporalProfile2DPlotStyle):
if columnName == self.cnExpression:
plotStyle.setExpression(value)
plotStyle.updateDataProperties()
result = True
elif columnName == self.cnStyle:
if isinstance(value, PlotStyle):
plotStyle.copyFrom(value)
plotStyle.updateStyleProperties()
result = True
if role == Qt.CheckStateRole:
if columnName == self.cnTemporalProfile:
plotStyle.setVisibility(value == Qt.Checked)
result = True
if role == Qt.EditRole:
if columnName == self.cnExpression:
plotStyle.setExpression(value)
result = True
elif columnName == self.cnStyle:
plotStyle.copyFrom(value)
result = True
elif columnName == self.cnSensor:
plotStyle.setSensor(value)
elif columnName == self.cnTemporalProfile:
plotStyle.setTemporalProfile(value)
if result:
#save plot-style
self.savePlotSettings(plotStyle, index='DEFAULT')
self.dataChanged.emit(index, index)
def savePlotSettings(self, sensorPlotSettings, index='DEFAULT'):
return
def restorePlotSettings(self, sensor, index='DEFAULT'):
return None
def flags(self, index):
if index.isValid():
columnName = self.columnNames[index.column()]
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if columnName in [self.cnTemporalProfile]:
if columnName in [self.cnTemporalProfile, self.cnSensor, self.cnExpression, self.cnStyle]: #allow check state
flags = flags | Qt.ItemIsEditable
return flags
#return item.qt_flags(index.column())
return Qt.NoItemFlags
def headerData(self, col, orientation, role):
if Qt is None:
return None
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
return col
return None

Benjamin Jakimow
committed
class PlotSettingsTableView(QTableView):

Benjamin Jakimow
committed
def __init__(self, *args, **kwds):
super(PlotSettingsTableView, self).__init__(*args, **kwds)
pal = self.palette()
cSelected = pal.color(QPalette.Active, QPalette.Highlight)
pal.setColor(QPalette.Inactive, QPalette.Highlight, cSelected)
self.setPalette(pal)

Benjamin Jakimow
committed
def contextMenuEvent(self, event: QContextMenuEvent):
"""
Creates and shows the QMenu
:param event: QContextMenuEvent
"""

Benjamin Jakimow
committed
indices = self.selectionModel().selectedIndexes()

Benjamin Jakimow
committed
indices2 = [self.model().mapToSource(idx) for idx in indices]

Benjamin Jakimow
committed
if len(indices2) > 0:
menu = QMenu(self)
a = menu.addAction('Set Style')
a.triggered.connect(lambda *args, i=indices2: self.onSetStyle(i))

Benjamin Jakimow
committed
menu.popup(QCursor.pos())

Benjamin Jakimow
committed
def onSetStyle(self, indices):

Benjamin Jakimow
committed
if len(indices) > 0:
refStyle = None

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
model = self.model().sourceModel()
assert isinstance(model, PlotSettingsModel2D)

Benjamin Jakimow
committed
colStyle = model.columnIndex(model.cnStyle)

Benjamin Jakimow
committed
for idx in indices:
style = self.model().sourceModel().idx2plotStyle(idx)
if isinstance(style, PlotStyle):
refStyle = style
break
if isinstance(refStyle, PlotStyle):
newStyle = PlotStyleDialog.getPlotStyle(plotStyle=refStyle)
if isinstance(newStyle, PlotStyle):
for idx in indices:
assert isinstance(idx, QModelIndex)
idxStyle = model.createIndex(idx.row(), colStyle)
model.setData(idxStyle, newStyle, role=Qt.EditRole)

Benjamin Jakimow
committed
class PlotSettingsModel2DWidgetDelegate(QStyledItemDelegate):
"""

Benjamin Jakimow
committed
"""
def __init__(self, tableView, temporalProfileLayer, parent=None):
assert isinstance(tableView, QTableView)
assert isinstance(temporalProfileLayer, TemporalProfileLayer)
super(PlotSettingsModel2DWidgetDelegate, self).__init__(parent=parent)
self._preferedSize = QgsFieldExpressionWidget().sizeHint()
self.mTableView = tableView
self.mTemporalProfileLayer = temporalProfileLayer
self.mTimeSeries = temporalProfileLayer.timeSeries()

Benjamin Jakimow
committed
self.mSensorLayers = {}

Benjamin Jakimow
committed
def paint(self, painter: QPainter, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex):

Benjamin Jakimow
committed
if index.column() == 2:
style = self.style(index)
h = self.mTableView.verticalHeader().defaultSectionSize()
w = self.mTableView.horizontalHeader().defaultSectionSize()
if h > 0 and w > 0:
px = style.createPixmap(size=QSize(w, h))
label = QLabel()
label.setPixmap(px)
painter.drawPixmap(option.rect, px)
#QApplication.style().drawControl(QStyle.CE_CustomBase, label, painter)
else:
super(PlotSettingsModel2DWidgetDelegate, self).paint(painter, option, index)
else:
super(PlotSettingsModel2DWidgetDelegate, self).paint(painter, option, index)

Benjamin Jakimow
committed
def sortFilterProxyModel(self)->QSortFilterProxyModel:
return self.mTableView.model()

Benjamin Jakimow
committed
def plotSettingsModel(self)->PlotSettingsModel2D:
return self.sortFilterProxyModel().sourceModel()

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
def setItemDelegates(self, tableView):
assert isinstance(tableView, QTableView)
model = self.plotSettingsModel()
assert isinstance(model, PlotSettingsModel2D)
for c in [model.cnSensor, model.cnExpression, model.cnStyle, model.cnTemporalProfile]:
i = model.columnNames.index(c)
tableView.setItemDelegateForColumn(i, self)

Benjamin Jakimow
committed
def getColumnName(self, index):
assert index.isValid()
model = self.plotSettingsModel()
assert isinstance(model, PlotSettingsModel2D)
return model.columnNames[index.column()]

Benjamin Jakimow
committed
def sizeHint(self, options, index):
s = super(ExpressionDelegate, self).sizeHint(options, index)
exprString = self.tableView.model().data(index)
l = QLabel()
l.setText(exprString)
x = l.sizeHint().width() + 100
s = QSize(x, s.height())
return self._preferedSize

Benjamin Jakimow
committed
def exampleLyr(self, sensor):
# if isinstance(sensor, SensorInstrument):
if sensor not in self.mSensorLayers.keys():

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
crs = QgsCoordinateReferenceSystem('EPSG:4862')
uri = 'Point?crs={}'.format(crs.authid())
lyr = QgsVectorLayer(uri, 'LOCATIONS', 'memory')
f = sensorExampleQgsFeature(sensor)
assert isinstance(f, QgsFeature)
assert lyr.startEditing()
for field in f.fields():
lyr.addAttribute(field)
lyr.addFeature(f)
lyr.commitChanges()
self.mSensorLayers[sensor] = lyr
return self.mSensorLayers[sensor]

Benjamin Jakimow
committed
def createEditor(self, parent, option, index):
cname = self.getColumnName(index)
model = self.plotSettingsModel()
pmodel = self.sortFilterProxyModel()

Benjamin Jakimow
committed
w = None
if index.isValid() and isinstance(model, PlotSettingsModel2D):

Benjamin Jakimow
committed

Benjamin Jakimow
committed
plotStyle = model.idx2plotStyle(pmodel.mapToSource(index))

Benjamin Jakimow
committed

Benjamin Jakimow
committed
if isinstance(plotStyle, TemporalProfile2DPlotStyle):
if cname == model.cnExpression:

Benjamin Jakimow
committed

Benjamin Jakimow
committed
w = QgsFieldExpressionWidget(parent=parent)
w.setExpressionDialogTitle('Values')
w.setToolTip('Set an expression to specify the image band or calculate a spectral index.')
w.fieldChanged[str, bool].connect(lambda n, b: self.checkData(index, w, w.expression()))
w.setExpression(plotStyle.expression())

Benjamin Jakimow
committed
if isinstance(plotStyle.sensor(), SensorInstrument):
w.setLayer(self.exampleLyr(plotStyle.sensor()))

Benjamin Jakimow
committed

Benjamin Jakimow
committed
elif cname == model.cnStyle:
w = PlotStyleButton(parent=parent)
w.setPlotStyle(plotStyle)
w.setToolTip('Set style.')
w.sigPlotStyleChanged.connect(lambda: self.checkData(index, w, w.plotStyle()))

Benjamin Jakimow
committed
elif cname == model.cnSensor:
w = QComboBox(parent=parent)
m = SensorListModel(self.mTimeSeries)
w.setModel(m)

Benjamin Jakimow
committed
elif cname == model.cnTemporalProfile:
w = QgsFeatureListComboBox(parent=parent)
w.setSourceLayer(self.mTemporalProfileLayer)
w.setIdentifierField(FN_ID)
w.setDisplayExpression('to_string("{}")+\' \'+"name"'.format(FN_ID))
w.setAllowNull(False)
else:
raise NotImplementedError()
return w

Benjamin Jakimow
committed
def checkData(self, index, w, value):
assert isinstance(index, QModelIndex)
model = self.mTableView.model()
if index.isValid() and isinstance(model, PlotSettingsModel2D):
plotStyle = model.idx2plotStyle(index)
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
if isinstance(w, QgsFieldExpressionWidget):
assert value == w.expression()
assert w.isExpressionValid(value) == w.isValidExpression()

Benjamin Jakimow
committed
if w.isValidExpression():
self.commitData.emit(w)
else:
s = ""
#print(('Delegate commit failed',w.asExpression()))
if isinstance(w, PlotStyleButton):

Benjamin Jakimow
committed
self.commitData.emit(w)

Benjamin Jakimow
committed
def style(self, proxyIndex:QModelIndex)->PlotStyle:
model = self.plotSettingsModel()
index = self.sortFilterProxyModel().mapToSource(proxyIndex)
return model.data(index, role=Qt.UserRole)

Benjamin Jakimow
committed
def setEditorData(self, editor, proxyIndex):

Benjamin Jakimow
committed
model = self.plotSettingsModel()
index = self.sortFilterProxyModel().mapToSource(proxyIndex)
w = None
if index.isValid() and isinstance(model, PlotSettingsModel2D):
cname = self.getColumnName(proxyIndex)
if cname == model.cnExpression:
lastExpr = model.data(index, Qt.DisplayRole)
assert isinstance(editor, QgsFieldExpressionWidget)
editor.setProperty('lastexpr', lastExpr)
editor.setField(lastExpr)

Benjamin Jakimow
committed
elif cname == model.cnStyle:
style = model.data(index, Qt.UserRole)
assert isinstance(editor, PlotStyleButton)
editor.setPlotStyle(style)

Benjamin Jakimow
committed
elif cname == model.cnSensor:
assert isinstance(editor, QComboBox)
m = editor.model()
assert isinstance(m, SensorListModel)
sensor = index.data(role=Qt.UserRole)
if isinstance(sensor, SensorInstrument):
idx = m.sensor2idx(sensor)
editor.setCurrentIndex(idx.row())
elif cname == model.cnTemporalProfile:
assert isinstance(editor, QgsFeatureListComboBox)
value = editor.identifierValue()
if value != QVariant():
plotStyle = index.data(role=Qt.UserRole)
TP = plotStyle.temporalProfile()
editor.setIdentifierValue(TP.id())
else:
s = ""
else:
raise NotImplementedError()

Benjamin Jakimow
committed
def setModelData(self, w, model, proxyIndex):
index = self.sortFilterProxyModel().mapToSource(proxyIndex)
cname = self.getColumnName(proxyIndex)
model = self.plotSettingsModel()

Benjamin Jakimow
committed
if index.isValid() and isinstance(model, PlotSettingsModel2D):
if cname == model.cnExpression:
assert isinstance(w, QgsFieldExpressionWidget)
expr = w.asExpression()
exprLast = model.data(index, Qt.DisplayRole)

Benjamin Jakimow
committed
if w.isValidExpression() and expr != exprLast: