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

Benjamin Jakimow
committed
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
from eotimeseriesviewer import CursorLocationMapTool
from qgis.core import *
from qgis.gui import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtXml import QDomDocument
from .timeseries import TimeSeriesDate, SensorProxyLayer, SensorInstrument
from .externals.qps.crosshair.crosshair import CrosshairDialog, CrosshairStyle, CrosshairMapCanvasItem
from .externals.qps.maptools import *
from .labeling import quickLabelLayers, labelShortcutLayerClassificationSchemes, setQuickTSDLabelsForRegisteredLayers
from .externals.qps.classification.classificationscheme import ClassificationScheme, ClassInfo
from .externals.qps.utils import *
from .externals.qps.layerproperties import showLayerPropertiesDialog
import eotimeseriesviewer.settings
PROGRESS_TIMER = QTimer()
PROGRESS_TIMER.start(100)
def toQgsMimeDataUtilsUri(mapLayer:QgsMapLayer):
uri = QgsMimeDataUtils.Uri()
uri.name = mapLayer.name()
uri.providerKey = mapLayer.dataProvider().name()
uri.uri = mapLayer.source()
if isinstance(mapLayer, QgsRasterLayer):
uri.layerType = 'raster'
elif isinstance(mapLayer, QgsVectorLayer):
uri.layerType = 'vector'
else:
raise NotImplementedError()
return uri
class MapLoadingInfoItem(QgsMapCanvasItem):
def __init__(self, mapCanvas):
assert isinstance(mapCanvas, QgsMapCanvas)
super(MapLoadingInfoItem, self).__init__(mapCanvas)
self.mCanvas = mapCanvas
self.mProgressConnection = None
self.mCanvas.renderStarting.connect(lambda: self.showLoadingProgress(True))
#self.mCanvas.renderComplete.connect(lambda: self.showLoadingProgress(False))
PROGRESS_TIMER.timeout.connect(self.onProgressTimeOut)
self.mShowProgress = False
self.mIsVisible = True
def showLoadingProgress(self, showProgress: bool):
self.mShowProgress = showProgress
self.update()
def onProgressTimeOut(self):
if self.mShowProgress:
self.mCanvas.update()
def paint(self, painter, QStyleOptionGraphicsItem=None, QWidget_widget=None):
"""
Paints the crosshair
:param painter:
:param QStyleOptionGraphicsItem:
:param QWidget_widget:
:return:
"""
if True:
options = QStyleOptionProgressBar()
options.rect = QRect(0, 0, painter.window().width(), 25)
options.textAlignment = Qt.AlignCenter
options.progress = 0
options.maximum = 0
options.minimum = 0
QApplication.style().drawControl(QStyle.CE_ProgressBar, options, painter)
class MapCanvasInfoItem(QgsMapCanvasItem):
def __init__(self, mapCanvas):
assert isinstance(mapCanvas, QgsMapCanvas)
super(MapCanvasInfoItem, self).__init__(mapCanvas)
self.mCanvas = mapCanvas
self.mLRText = None
self.mURText = None
self.mVisibility = True
"""
Sets the map info color
:param color: QColor
"""
self.mPenColor = color
def color(self)->QColor:
"""
Returns the info text color
:return: QColor
"""
def setVisibility(self, b:bool):
:param b:
:return:
assert isinstance(b, bool)
old = self.mShow
self.mVisibility = b
if old != b:
self.mCanvas.update()
def visibility(self)->bool:
return self.mVisibility
def paintText(self, painter, text:str, flags, width=10, color=QColor('black') ):
pen = QPen(Qt.SolidLine)
pen.setWidth(width)
pen.setColor(self.mPenColor)
text = text.replace('\\n', '\n')
font = QFont('Helvetica', pointSize=10)
painter.setFont(font)
brush = self.mCanvas.backgroundBrush()
c = brush.color()
c.setAlpha(170)
brush.setColor(c)
painter.setBrush(brush)
painter.setPen(Qt.NoPen)
fm = QFontMetrics(font)
#background = QPolygonF(QRectF(backGroundPos, backGroundSize))
#painter.drawPolygon(background)
painter.setPen(pen)
rect = painter.viewport()
painter.drawText(rect, flags, text)
#painter.drawText(position, text)
def clearText(self):
self.mULText = self.mUCText = self.mURText = None
self.mLLText = self.mLCText = self.mLRText = None
def paint(self, painter, QStyleOptionGraphicsItem=None, QWidget_widget=None):
"""
Paints the crosshair
:param painter:
:param QStyleOptionGraphicsItem:
:param QWidget_widget:
:return:
"""
h = painter.viewport().height()
w = painter.viewport().width()
if self.mLLText:
self.paintText(painter, self.mLLText, Qt.AlignBottom | Qt.AlignLeft )
self.paintText(painter, self.mLRText, Qt.AlignBottom | Qt.AlignRight)
if self.mULText:
self.paintText(painter, self.mULText, Qt.AlignTop | Qt.AlignRight)
if self.mURText:
self.paintText(painter, self.mURText, Qt.AlignTop | Qt.AlignLeft)
if self.mUCText:
self.paintText(painter, self.mUCText, Qt.AlignTop | Qt.AlignHCenter)
if self.mLCText:
self.paintText(painter, self.mLCText, Qt.AlignBottom | Qt.AlignHCenter)
class MapCanvasMapTools(QObject):
def __init__(self, canvas:QgsMapCanvas, cadDock:QgsAdvancedDigitizingDockWidget):
super(MapCanvasMapTools, self).__init__(canvas)
self.mCanvas = canvas
self.mCadDock = cadDock
self.mtZoomIn = QgsMapToolZoom(canvas, False)
self.mtZoomOut = QgsMapToolZoom(canvas, True)
self.mtMoveToCenter = MapToolCenter(canvas)
self.mtPan = QgsMapToolPan(canvas)
self.mtPixelScaleExtent = PixelScaleExtentMapTool(canvas)
self.mtFullExtentMapTool = FullExtentMapTool(canvas)
self.mtCursorLocation = CursorLocationMapTool(canvas, True)

Benjamin Jakimow
committed
self.mtAddFeature = QgsMapToolAddFeature(canvas, QgsMapToolCapture.CaptureNone, cadDock)
self.mtSelectFeature = QgsMapToolSelect(canvas)
from .externals.qps.maptools import MapTools
if mapToolKey == MapTools.ZoomIn:
self.mCanvas.setMapTool(self.mtZoomIn)
elif mapToolKey == MapTools.ZoomOut:
self.mCanvas.setMapTool(self.mtZoomOut)
elif mapToolKey == MapTools.Pan:
self.mCanvas.setMapTool(self.mtPan)
elif mapToolKey == MapTools.ZoomFull:
self.mCanvas.setMapTool(self.mtFullExtentMapTool)
elif mapToolKey == MapTools.ZoomPixelScale:
self.mCanvas.setMapTool(self.mtPixelScaleExtent)
elif mapToolKey == MapTools.CursorLocation:
self.mCanvas.setMapTool(self.mtCursorLocation)
elif mapToolKey == MapTools.SpectralProfile:
pass
elif mapToolKey == MapTools.TemporalProfile:
pass
elif mapToolKey == MapTools.MoveToCenter:
self.mCanvas.setMapTool(self.mtMoveToCenter)
elif mapToolKey == MapTools.AddFeature:
self.mCanvas.setMapTool(self.mtAddFeature)
elif mapToolKey == MapTools.SelectFeature:
self.mCanvas.setMapTool(self.mtSelectFeature)
self.mtSelectFeature.setSelectionMode(QgsMapToolSelectionHandler.SelectionMode.SelectSimple)
elif mapToolKey == MapTools.SelectFeatureByPolygon:
self.mCanvas.setMapTool(self.mtSelectFeature)
self.mtSelectFeature.setSelectionMode(QgsMapToolSelectionHandler.SelectionMode.SelectPolygon)
elif mapToolKey == MapTools.SelectFeatureByFreehand:
self.mCanvas.setMapTool(self.mtSelectFeature)
self.mtSelectFeature.setSelectionMode(QgsMapToolSelectionHandler.SelectionMode.SelectFreehand)
elif mapToolKey == MapTools.SelectFeatureByRadius:
self.mCanvas.setMapTool(self.mtSelectFeature)
self.mtSelectFeature.setSelectionMode(QgsMapToolSelectionHandler.SelectionMode.SelectRadius)
else:
print('Unknown MapTool key: {}'.format(mapToolKey))
# if undefined, set a current vector layer
if mapToolKey in [MapTools.SelectFeature, MapTools.SelectFeatureByPolygon, MapTools.SelectFeatureByRadius, MapTools.SelectFeatureByFreehand] \
and self.mCanvas.currentLayer() is None:
for vl in self.mCanvas.layers():
if isinstance(vl, QgsVectorLayer):
self.mCanvas.setCurrentLayer(vl)
break
class MapCanvas(QgsMapCanvas):
"""
A widget based on QgsMapCanvas to draw spatial data
"""
"""
Canvas specific commands
"""
UpdateMapItems = 5
saveFileDirectories = dict()
#sigShowProfiles = pyqtSignal(SpatialPoint, str)
sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
#sigChangeDVRequest = pyqtSignal(QgsMapCanvas, str)
#sigChangeMVRequest = pyqtSignal(QgsMapCanvas, str)
#sigChangeSVRequest = pyqtSignal(QgsMapCanvas, QgsRasterRenderer)

Benjamin Jakimow
committed
sigCrosshairPositionChanged = pyqtSignal(SpatialPoint)
sigCrosshairVisibilityChanged = pyqtSignal(bool)
sigDestinationCrsChanged = pyqtSignal(QgsCoordinateReferenceSystem)

Benjamin Jakimow
committed
sigCrosshairStyleChanged = pyqtSignal(CrosshairStyle)
def __init__(self, parent=None):
super(MapCanvas, self).__init__(parent=parent)
self.mMapLayerStore = QgsProject.instance()
self.mMapTools = None
self.initMapTools()

benjamin.jakimow@geo.hu-berlin.de
committed
self.mCrosshairItem = CrosshairMapCanvasItem(self)
self.mInfoItem = MapCanvasInfoItem(self)
self.mProgressItem = MapLoadingInfoItem(self)
self.mUserInputWidget = QgsUserInputWidget(self)
self.mUserInputWidget.setObjectName('UserInputDockWidget')
self.mUserInputWidget.setAnchorWidget(self)
self.mUserInputWidget.setAnchorWidgetPoint(QgsFloatingWidget.TopRight)
self.mUserInputWidget.setAnchorPoint(QgsFloatingWidget.TopRight)
#self.mProgressBar = QProgressBar()
#self.mUserInputWidget.addUserInputWidget(self.mProgressBar)
self.mNeedsRefresh = False
self.mRenderingFinished = True
self.mIsRefreshing = False
t2 = time.time()
dt = t2 - self.mRefreshStartTime
self.sigMapRefreshed[float].emit(dt)
self.sigMapRefreshed[float, float].emit(self.mRefreshStartTime, t2)

benjamin.jakimow@geo.hu-berlin.de
committed
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
bg = eotimeseriesviewer.settings.value(eotimeseriesviewer.settings.Keys.MapBackgroundColor, default=QColor(0, 0, 0))
self.setContextMenuPolicy(Qt.DefaultContextMenu)
self.extentsChanged.connect(lambda : self.sigSpatialExtentChanged.emit(self.spatialExtent()))
self.destinationCrsChanged.connect(lambda : self.sigDestinationCrsChanged.emit(self.crs()))
def userInputWidget(self)->QgsUserInputWidget:
"""
Returns the mapcanvas QgsUserInputWidget
:return: QgsUserInputWidget
"""
return self.mUserInputWidget
def infoItem(self)->MapCanvasInfoItem:
"""
Returns the MapCanvasInfoItem, e.g. to plot text on top of the map canvas
:return: MapCanvasInfoItem
"""
return self.mInfoItem
def mapView(self):
"""
Returns the MapView this MapCanvas is linked to
:return:
"""
return self.mMapView
def mapTools(self)->MapCanvasMapTools:
"""
Returns the map tools of this MapCanvas
:return: MapCanvasMapTools
"""
return self.mMapTools
def initMapTools(self):
self.mCadDock = QgsAdvancedDigitizingDockWidget(self)
self.mCadDock.setVisible(False)
self.mMapTools = MapCanvasMapTools(self, self.mCadDock)
def setMapLayerStore(self, store):
"""
Sets the QgsMapLayerStore or QgsProject instance that is used to register map layers
:param store: QgsMapLayerStore | QgsProject
"""
assert isinstance(store, (QgsMapLayerStore, QgsProject))
self.mMapLayerStore = store
def renderingFinished(self)->bool:
"""
Returns whether the MapCanvas is processing a rendering task
:return: bool
"""
return self.mRenderingFinished

Benjamin Jakimow
committed
def mousePressEvent(self, event:QMouseEvent):
b = event.button() == Qt.LeftButton
if b and isinstance(self.mapTool(), QgsMapTool):
b = isinstance(self.mapTool(), (QgsMapToolIdentify,
CursorLocationMapTool,
SpectralProfileMapTool, TemporalProfileMapTool))
super(MapCanvas, self).mousePressEvent(event)
if b:
ms = self.mapSettings()
pointXY = ms.mapToPixel().toMapCoordinates(event.x(), event.y())
spatialPoint = SpatialPoint(ms.destinationCrs(), pointXY)
self.setCrosshairPosition(spatialPoint)
"""
Sets the map canvas MapView
:param mapView: MapView
"""
from eotimeseriesviewer.mapvisualization import MapView
self.mInfoItem.setColor(mapView.mapTextColor())
self.addToRefreshPipeLine(mapView.mapBackgroundColor())
self.addToRefreshPipeLine(MapCanvas.Command.UpdateMapItems)
def setTSD(self, tsd:TimeSeriesDate):
Sets the TimeSeriesDate this map-canvas is linked to
if self.mTSD == tsd:
return
# disconnect old TSD
if isinstance(self.mTSD, TimeSeriesDate):
self.mTSD.sensor().sigNameChanged.disconnect(self.updateScope)
self.mTSD = tsd
if isinstance(tsd, TimeSeriesDate):
self.mTSD.sensor().sigNameChanged.connect(self.updateScope)
self.updateScope()
def updateScope(self):
"""
Updates map-canvas TSD variables
"""

Benjamin Jakimow
committed
scope = self.expressionContextScope()
tsd = self.tsd()
if isinstance(tsd, TimeSeriesDate):
scope.setVariable('map_date', str(tsd.date()), isStatic=False)
scope.setVariable('map_doy', tsd.doy(), isStatic=False)
scope.setVariable('map_sensor', tsd.sensor().name(), isStatic=False)
else:
scope.setVariable('map_date', None, isStatic=False)
scope.setVariable('map_doy', None, isStatic=False)
scope.setVariable('map_sensor', None, isStatic=False)
def tsd(self)->TimeSeriesDate:
Returns the TimeSeriesDate
:return: TimeSeriesDate

Benjamin Jakimow
committed
def setSpatialExtent(self, extent:SpatialExtent):
"""
Sets the spatial extent
:param extent: SpatialExtent
"""
assert isinstance(extent, SpatialExtent)
extent = extent.toCrs(self.crs())
self.setExtent(extent)
def setSpatialCenter(self, center:SpatialPoint):
"""
Sets the SpatialCenter
:param center: SpatialPoint
"""
assert isinstance(center, SpatialPoint)
center = center.toCrs(self.crs())
self.setCenter(center)
def setFixedSize(self, size:QSize):
"""
Changes the map-canvas size
:param size: QSize
"""
assert isinstance(size, QSize)
if self.size() != size:
super(MapCanvas, self).setFixedSize(size)
if self.crs() != crs:
self.setDestinationCrs(crs)
"""
Shortcut to return self.mapSettings().destinationCrs()
:return: QgsCoordinateReferenceSystem
"""
return self.mapSettings().destinationCrs()
def setLayers(self, mapLayers):
"""
Set the map layers and, if necessary, registers the in a QgsMapLayerStore
:param mapLayers:
"""
self.mMapLayerStore.addMapLayers(mapLayers)
super(MapCanvas, self).setLayers(mapLayers)
def isVisibleToViewport(self)->bool:
"""
Returns whether the MapCanvas is visible to a user and not hidden behind the invisible regions of a scroll area.
:return: bool
"""
return self.visibleRegion().boundingRect().isValid()
def addToRefreshPipeLine(self, arguments: list):
"""
Adds commands or other arguments to a pipeline which will be handled during the next timed refresh.
:param arguments: argument | [list-of-arguments]
"""
if not isinstance(arguments, list):
arguments = [arguments]
if isinstance(a, SpatialExtent):
self.mTimedRefreshPipeLine[SpatialPoint] = a
elif isinstance(a, QColor):
self.mTimedRefreshPipeLine[QColor] = a
elif isinstance(a, MapCanvas.Command):
if not MapCanvas.Command in self.mTimedRefreshPipeLine.keys():
self.mTimedRefreshPipeLine[MapCanvas.Command] = []
# remove previous commands of same type, append command to end
while a in self.mTimedRefreshPipeLine[MapCanvas.Command]:
self.mTimedRefreshPipeLine[MapCanvas.Command].remove(a)
self.mTimedRefreshPipeLine[MapCanvas.Command].append(a)
else:
raise NotImplementedError('Unsupported argument: {}'.format(str(a)))
def timedRefresh(self):
"""
Called to refresh the map canvas with all things needed to be done with lazy evaluation
expected = []
existing = self.layers()
existingSources = [l.source() for l in existing]
if self.mapView() is None or self.tsd() is None:
self.setLayers([])
self.mInfoItem.clearText()
self.update()
return
for lyr in self.mMapView.layers():
assert isinstance(lyr, QgsMapLayer)
if isinstance(lyr, SensorProxyLayer):
if self.tsd().sensor() == lyr.sensor():
for source in self.tsd().sourceUris():
sourceLayer = None
if source in existingSources:
sourceLayer = existing[existingSources.index(source)]
else:
sourceLayer = SensorProxyLayer(source, sensor=self.tsd().sensor())
sourceLayer.setName(lyr.name())
sourceLayer.setCustomProperty('eotsv/sensorid', self.tsd().sensor().id())
try:
renderer = lyr.renderer()
if isinstance(renderer, QgsRasterRenderer):
sourceLayer.setRenderer(renderer.clone())
except Exception as exR:
s = ""
assert isinstance(sourceLayer, QgsRasterLayer)
expected.append(sourceLayer)
else:
# skip any other SensorProxyLayer that relates to another sensor
pass
else:
expected.append(lyr)
if len(self.mTimedRefreshPipeLine) == 0 and self.layers() == expected:
# there is nothing to do.
# look for new layers
lyrs = self.layers()
if lyrs != expected:
self.setLayers(expected)
if True:
# set sources first
keys = self.mTimedRefreshPipeLine.keys()
if QgsCoordinateReferenceSystem in keys:
self.setDestinationCrs(self.mTimedRefreshPipeLine[QgsCoordinateReferenceSystem])
if SpatialExtent in keys:
self.setSpatialExtent(self.mTimedRefreshPipeLine[SpatialExtent])
if SpatialPoint in keys:
self.setSpatialCenter(self.mTimedRefreshPipeLine[SpatialPoint])
if QColor in keys:
self.setCanvasColor(self.mTimedRefreshPipeLine[QColor])
if MapCanvas.Command in keys:
commands = self.mTimedRefreshPipeLine[MapCanvas.Command]
for command in commands:
assert isinstance(command, MapCanvas.Command)
if command == MapCanvas.Command.RefreshRenderer:
for px in [px for px in self.mMapView.layers() if isinstance(px, SensorProxyLayer)]:
for l in self.layers():
if isinstance(l, SensorProxyLayer) and l.sensor() == px.sensor():
try:
renderer = px.renderer().clone()
renderer.setInput(l.dataProvider())
l.setRenderer(renderer)
except Exception as ex:
s = ""
if command == MapCanvas.Command.UpdateMapItems:
#self.update()
self.mTimedRefreshPipeLine.clear()
def setLayerVisibility(self, cls, isVisible:bool):
"""
:param cls: type of layer, e.g. QgsRasterLayer to set visibility of all layers of same type
QgsMapLayer instance to the visibility of a specific layer
:param isVisible: bool
"""
self.mMapLayerModel.setLayerVisibility(cls, isVisible)
self.addToRefreshPipeLine(MapCanvas.Command.RefreshVisibility)
def setCrosshairStyle(self, crosshairStyle:CrosshairStyle, emitSignal=True):
"""
Sets the CrosshairStyle
:param crosshairStyle: CrosshairStyle
:param emitSignal: Set to Fals to no emit a signal.
"""
from eotimeseriesviewer import CrosshairStyle
if crosshairStyle is None:

Benjamin Jakimow
committed
self.mCrosshairItem.crosshairStyle.setShow(False)
self.mCrosshairItem.update()
else:
assert isinstance(crosshairStyle, CrosshairStyle)

Benjamin Jakimow
committed
self.mCrosshairItem.setCrosshairStyle(crosshairStyle)

Benjamin Jakimow
committed
if emitSignal:
self.sigCrosshairStyleChanged.emit(self.mCrosshairItem.crosshairStyle())

Benjamin Jakimow
committed
def crosshairStyle(self)->CrosshairStyle:
"""
Returns the style of the Crosshair.
:return: CrosshairStyle
"""

Benjamin Jakimow
committed
return self.mCrosshairItem.crosshairStyle
def setCrosshairPosition(self, spatialPoint:SpatialPoint):

Benjamin Jakimow
committed
"""
Sets the position of the Crosshair.
:param spatialPoint: SpatialPoint
:param emitSignal: True (default). Set False to avoid emitting sigCrosshairPositionChanged
:return:
"""

Benjamin Jakimow
committed
point = spatialPoint.toCrs(self.mapSettings().destinationCrs())
if self.mCrosshairItem.mPosition != point:
self.mCrosshairItem.setPosition(point)

Benjamin Jakimow
committed
self.sigCrosshairPositionChanged.emit(point)
def crosshairPosition(self)->SpatialPoint:
"""Returns the last crosshair position"""
return self.mCrosshairItem.mPosition
def setCrosshairVisibility(self, b:bool, emitSignal=True):
"""
Sets the Crosshair visbility
:param b: bool
"""
if b and self.mCrosshairItem.mPosition is None:
self.mCrosshairItem.setPosition(self.spatialCenter())
self.sigCrosshairPositionChanged.emit(self.spatialCenter())
if b != self.mCrosshairItem.visibility():
self.mCrosshairItem.setVisibility(b)
if emitSignal:
self.sigCrosshairVisibilityChanged.emit(b)
def layerPaths(self):
:return: [list-of-str]

benjamin.jakimow@geo.hu-berlin.de
committed
return [str(l.source()) for l in self.layers()]
def pixmap(self):
"""
Returns the current map image as pixmap
return self.grab()
def contextMenu(self, pos:QPoint)->QMenu:
"""
Create the MapCanvas context menu with options relevant for pixel position ``pos``.
:param pos: QPoint
:return: QMenu
"""
mapSettings = self.mapSettings()
assert isinstance(mapSettings, QgsMapSettings)
pointGeo = mapSettings.mapToPixel().toMapCoordinates(pos.x(), pos.y())
assert isinstance(pointGeo, QgsPointXY)
from .main import TimeSeriesViewer
eotsv = TimeSeriesViewer.instance()

Benjamin Jakimow
committed
viewPortMapLayers = [l for l in self.layers() if isinstance(l, QgsMapLayer)]

Benjamin Jakimow
committed

Benjamin Jakimow
committed
viewPortRasterLayers = [l for l in viewPortMapLayers if isinstance(l, QgsRasterLayer) and SpatialExtent.fromLayer(l).toCrs(self.crs()).contains(pointGeo)]
viewPortSensorLayers = [l for l in viewPortRasterLayers if isinstance(l, SensorProxyLayer)]
viewPortVectorLayers = [l for l in viewPortMapLayers if isinstance(l, QgsVectorLayer)]

Benjamin Jakimow
committed
refSensorLayer = None
refRasterLayer = None
if len(viewPortRasterLayers) > 0:
refRasterLayer = viewPortRasterLayers[0]
if len(viewPortSensorLayers) > 0:
refSensorLayer = viewPortSensorLayers[0]
menu = QMenu()
if isinstance(self.tsd(), TimeSeriesDate):

Benjamin Jakimow
committed
tss = None
sourceUris = self.tsd().sourceUris()
for sl in viewPortSensorLayers:
if sl.source() in sourceUris:
tss = self.tsd()[sourceUris.index(sl.source())]
break
lyrWithSelectedFeatures = [l for l in quickLabelLayers() if l.isEditable() and l.selectedFeatureCount() > 0]
layerNames = ', '.join([l.name() for l in lyrWithSelectedFeatures])
m = menu.addMenu('Quick Labels'.format(self.tsd().date()))
nQuickLabelLayers = len(lyrWithSelectedFeatures)
m.setEnabled(nQuickLabelLayers > 0)
a = m.addAction('Set Date/Sensor attributes')
a.setToolTip('Writes the date ate and sensor quick labels of selected features in {}.'.format(layerNames))

Benjamin Jakimow
committed
a.triggered.connect(lambda *args, tsd = self.tsd(), tss=tss: setQuickTSDLabelsForRegisteredLayers(tsd, tss))
from .labeling import EDITOR_WIDGET_REGISTRY_KEY as QUICK_LABEL_KEY
from .labeling import CONFKEY_CLASSIFICATIONSCHEME, layerClassSchemes, setQuickClassInfo
for layer in lyrWithSelectedFeatures:
assert isinstance(layer, QgsVectorLayer)
csf = layerClassSchemes(layer)
if len(csf) > 0:
m.addSection(layer.name())
for (cs, field) in csf:
assert isinstance(cs, ClassificationScheme)
assert isinstance(field, QgsField)
classMenu = m.addMenu('"{}" ({})'.format(field.name(), field.typeName()))
for classInfo in cs:
assert isinstance(classInfo, ClassInfo)
a = classMenu.addAction('{} "{}"'.format(classInfo.label(), classInfo.name()))
a.setIcon(classInfo.icon())
a.triggered.connect(lambda _, vl=layer, f=field, c=classInfo: setQuickClassInfo(vl, f, c))

Benjamin Jakimow
committed
if isinstance(refSensorLayer, SensorProxyLayer):
m = menu.addMenu('Raster stretch...')
action = m.addAction('Linear')
action.triggered.connect(lambda *args, lyr=refSensorLayer: self.stretchToExtent(self.spatialExtent(), 'linear_minmax', layer=lyr, p=0.0))
action = m.addAction('Linear 5%')
action.triggered.connect(lambda *args, lyr=refSensorLayer: self.stretchToExtent(self.spatialExtent(), 'linear_minmax', layer=lyr, p=0.05))
action = m.addAction('Gaussian')
action.triggered.connect(lambda *args, lyr=refSensorLayer: self.stretchToExtent(self.spatialExtent(), 'gaussian', layer=lyr, n=3))
menu.addSeparator()
from .externals.qps.layerproperties import pasteStyleFromClipboard, pasteStyleToClipboard
b = isinstance(refRasterLayer, QgsRasterLayer)
a = menu.addAction('Copy Style')
a.setEnabled(b)
a.setToolTip('Copy the current layer style to clipboard')
a.triggered.connect(lambda *args, lyr=refRasterLayer: pasteStyleToClipboard(lyr))

Benjamin Jakimow
committed
a = menu.addAction('Paste Style')
a.setEnabled(b)
a.setEnabled('application/qgis.style' in QApplication.clipboard().mimeData().formats())
a.triggered.connect(lambda *args, lyr=refRasterLayer: self.onPasteStyleFromClipboard(lyr))
menu.addSeparator()
m = menu.addMenu('Layers...')
visibleLayers = viewPortRasterLayers + viewPortVectorLayers
for mapLayer in visibleLayers:
#sub = m.addMenu(mapLayer.name())
sub = m.addMenu(os.path.basename(mapLayer.source()))
if isinstance(mapLayer, SensorProxyLayer):
sub.setIcon(QIcon(':/timeseriesviewer/icons/icon.svg'))
elif isinstance(mapLayer, QgsRasterLayer):
sub.setIcon(QIcon(''))
elif isinstance(mapLayer, QgsVectorLayer):
wkbType = QgsWkbTypes.displayString(int(mapLayer.wkbType()))
if re.search('polygon', wkbType, re.I):
sub.setIcon(QIcon(r':/images/themes/default/mIconPolygonLayer.svg'))
elif re.search('line', wkbType, re.I):
sub.setIcon(QIcon(r':/images/themes/default/mIconLineLayer.svg'))
elif re.search('point', wkbType, re.I):
sub.setIcon(QIcon(r':/images/themes/default/mIconPointLayer.svg'))
a = sub.addAction('Properties...')
a.triggered.connect(lambda *args,
lyr = mapLayer,
c = self,
b = isinstance(mapLayer, SensorProxyLayer) == False:
showLayerPropertiesDialog(lyr, c, useQGISDialog=b))
a = sub.addAction('Zoom to Layer')
a.setIcon(QIcon(':/images/themes/default/mActionZoomToLayer.svg'))
a.triggered.connect(lambda *args, lyr=mapLayer: self.setSpatialExtent(SpatialExtent.fromLayer(lyr)))

Benjamin Jakimow
committed
a = sub.addAction('Copy Style')
a.setToolTip('Copy layer style to clipboard')
a.triggered.connect(lambda *args, lyr=mapLayer: pasteStyleToClipboard(lyr))
a = sub.addAction('Paste Style')
a.setToolTip('Paster layer style from clipboard')
a.setEnabled('application/qgis.style' in QApplication.clipboard().mimeData().formats())
a.triggered.connect(lambda *args, lyr=mapLayer: self.onPasteStyleFromClipboard(lyr))
menu.addSeparator()
action = menu.addAction('Zoom to full extent')
action.setIcon(QIcon(':/images/themes/default/mActionZoomFullExtent.svg'))
action.triggered.connect(lambda: self.setExtent(self.fullExtent()))
menu.addSeparator()
m = menu.addMenu('Crosshair...')
action = m.addAction('Show')
action.setCheckable(True)
action.setChecked(self.mCrosshairItem.visibility())
action.toggled.connect(self.setCrosshairVisibility)

Benjamin Jakimow
committed
def onCrosshairChange(*args):
style = CrosshairDialog.getCrosshairStyle(parent=self,
mapCanvas=self,
crosshairStyle=self.mCrosshairItem.crosshairStyle)

Benjamin Jakimow
committed
if isinstance(style, CrosshairStyle):
self.setCrosshairStyle(style)
action.triggered.connect(onCrosshairChange)
if isinstance(tsd, TimeSeriesDate):
menu.addSeparator()
m = menu.addMenu('Copy...')
action = m.addAction('Date')
action.triggered.connect(lambda: QApplication.clipboard().setText(str(tsd.date())))
action.setToolTip('Sends "" to the clipboard.'.format(str(tsd.date())))
action = m.addAction('Sensor')
action.triggered.connect(lambda: QApplication.clipboard().setText(tsd.sensor().name()))
action.setToolTip('Sends "" to the clipboard.'.format(tsd.sensor().name()))
action = m.addAction('Path')
action.triggered.connect(lambda: QApplication.clipboard().setText('\n'.join(tsd.sourceUris())))
action.setToolTip('Sends the {} source URI(s) to the clipboard.'.format(len(tsd)))
action = m.addAction('Map')
action.triggered.connect(lambda: QApplication.clipboard().setPixmap(self.pixmap()))
action.setToolTip('Copies this map into the clipboard.')

benjamin.jakimow@geo.hu-berlin.de
committed
m = menu.addMenu('Map Coordinates...')
ext = self.spatialExtent()
center = self.spatialExtent().spatialCenter()
action = m.addAction('Extent (WKT Coordinates)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.asWktCoordinates()))
action = m.addAction('Extent (WKT Polygon)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.asWktPolygon()))
m.addSeparator()
action = m.addAction('Map Center (WKT)')
action.triggered.connect(lambda: QApplication.clipboard().setText(center.asWkt()))

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

benjamin.jakimow@geo.hu-berlin.de
committed
action.triggered.connect(lambda: QApplication.clipboard().setText(center.toString()))
action = m.addAction('Map Extent (WKT)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.asWktPolygon()))
action = m.addAction('Map Extent')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.toString()))

benjamin.jakimow@geo.hu-berlin.de
committed
m.addSeparator()
action = m.addAction('CRS (EPSG)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().authid()))
action = m.addAction('CRS (WKT)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().toWkt()))
action = m.addAction('CRS (Proj4)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().toProj4()))
action = m.addAction('PNG')
action.triggered.connect(lambda: self.saveMapImageDialog('PNG'))
action = m.addAction('JPEG')
action.triggered.connect(lambda: self.saveMapImageDialog('JPG'))

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

Benjamin Jakimow
committed
classSchemes = []
for layer in lyrWithSelectedFeaturs:
for classScheme in layerClassSchemes(layer):
assert isinstance(classScheme, ClassificationScheme)
if classScheme in classSchemes:
continue
classMenu = m.addMenu('Classification "{}"'.format(classScheme.name()))
assert isinstance(classMenu, QMenu)
for classInfo in classScheme:
assert isinstance(classInfo, ClassInfo)
a = classMenu.addAction(classInfo.name())
a.setIcon(classInfo.icon())
a.setToolTip('Write "{}" or "{}" to connected vector field attributes'.format(classInfo.name(), classInfo.label()))

Benjamin Jakimow
committed
a.triggered.connect(