Skip to content
Snippets Groups Projects
mapcanvas.py 58.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • # -*- coding: utf-8 -*-
    """
    /***************************************************************************
    
                                  -------------------
            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
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    import time
    
    import sys
    import typing
    import os
    import re
    import enum
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    import qgis.utils
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    from qgis.PyQt.QtGui import QIcon, QContextMenuEvent, QMouseEvent, QPainter, QFont, QColor
    from qgis.PyQt.QtWidgets import QApplication, QDialog, QMenu, QFileDialog, QSizePolicy, QStyle, QStyleOptionProgressBar
    from qgis.PyQt.QtCore import QSize, QDate, QDateTime, QDir, QFile, QMimeData, pyqtSignal, Qt, \
        QPoint, QObject, QRectF, QPointF, QRect, QTimer
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    from qgis.core import QgsMapLayer, QgsRasterLayer, QgsVectorLayer, QgsContrastEnhancement, \
        QgsDateTimeRange, QgsProject, QgsTextRenderer, QgsApplication, QgsCoordinateReferenceSystem, \
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        QgsMapToPixel, QgsRenderContext, QgsMapSettings, QgsRasterRenderer, \
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        QgsRasterBandStats, QgsPalettedRasterRenderer, QgsPointXY, \
        QgsSingleBandPseudoColorRenderer, QgsWkbTypes, QgsRasterLayerTemporalProperties, QgsRasterDataProvider, \
        QgsTextFormat, QgsMapLayerStore, QgsMultiBandColorRenderer, QgsSingleBandGrayRenderer, QgsField, \
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        QgsRectangle, QgsPolygon, QgsMultiBandColorRenderer, QgsRectangle, QgsSingleBandGrayRenderer, \
    
        QgsLayerTreeGroup, QgsUnitTypes, QgsMimeDataUtils
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    from qgis.gui import QgsMapCanvas, QgisInterface, QgsFloatingWidget, QgsUserInputWidget, \
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        QgsAdvancedDigitizingDockWidget, QgsMapCanvasItem, \
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        QgsMapTool, QgsMapToolPan, QgsMapToolZoom, QgsMapToolCapture, QgsMapToolIdentify, \
        QgsGeometryRubberBand
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    from .externals.qps.classification.classificationscheme import ClassificationScheme, ClassInfo
    from .externals.qps.crosshair.crosshair import CrosshairDialog, CrosshairStyle, CrosshairMapCanvasItem
    from .externals.qps.layerproperties import showLayerPropertiesDialog
    from .externals.qps.maptools import QgsMapToolSelectionHandler, \
        CursorLocationMapTool, QgsMapToolAddFeature, \
        SpectralProfileMapTool, TemporalProfileMapTool, MapToolCenter, PixelScaleExtentMapTool, FullExtentMapTool, QgsMapToolSelect
    from .externals.qps.utils import SpatialExtent, SpatialPoint
    from .labeling import quickLabelLayers, setQuickTSDLabelsForRegisteredLayers
    from .timeseries import TimeSeriesDate, TimeSeriesSource, SensorProxyLayer
    import eotimeseriesviewer.settings
    
    KEY_LAST_CLICKED = 'LAST_CLICKED'
    
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    def toQgsMimeDataUtilsUri(mapLayer: QgsMapLayer):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        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
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    class MapLoadingInfoItem(QgsMapCanvasItem):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        PROGRESS_TIMER = QTimer()
        PROGRESS_TIMER.start(100)
    
    
        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))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            # self.mCanvas.renderComplete.connect(lambda: self.showLoadingProgress(False))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            MapLoadingInfoItem.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):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
    
                Paints the crosshair
                :param painter:
                :param QStyleOptionGraphicsItem:
                :param QWidget_widget:
                :return:
                """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if False and self.mShowProgress:
    
                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):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def __init__(self, mapCanvas):
            assert isinstance(mapCanvas, QgsMapCanvas)
            super(MapCanvasInfoItem, self).__init__(mapCanvas)
            self.mCanvas = mapCanvas
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            self.mText = dict()
            self.mWrapChar = '\n'
            self.mTextFormat = QgsTextFormat()
            self.mTextFormat.setSizeUnit(QgsUnitTypes.RenderPixels)
            self.mTextFormat.setFont(QFont('Helvetica', pointSize=10))
            self.mTextFormat.setColor(QColor('yellow'))
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setWrapChar(self, c: str) -> str:
    
            """
            Sets a Wrap Character
            :param c:
            :return:
            """
            self.mWrapChar = c
            return self.wrapChar()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def wrapChar(self) -> str:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setText(self, text: str, alignment: Qt.Alignment = Qt.AlignTop | Qt.AlignHCenter):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setTextFormat(self, format: QgsTextFormat):
    
            assert isinstance(format, QgsTextFormat)
            self.mTextFormat = format
            self.updateCanvas()
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def textFormat(self) -> QgsTextFormat:
    
            """
            Returns the text format.
            :return: QgsTextFormat
            """
            return self.mTextFormat
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def font(self) -> QFont:
    
            """
            Returns the font used to write text on the map canvas.
            :return: QFont
            """
            return self.mTextFormat.font()
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setFont(self, font: QFont):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setColor(self, color: QColor):
    
            """
            Sets the map info color
            :param color: QColor
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def color(self) -> QColor:
    
            """
            Returns the info text color
            :return: QColor
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def paintText(self, painter, text: str, flags, rotation=0):
    
            padding = 5
            text = text.replace('\\n', '\n')
            text = text.split(self.wrapChar())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            # text = text.split('\\n')
    
            painter.setBrush(Qt.NoBrush)
            painter.setPen(Qt.NoPen)
            painter.setRenderHint(QPainter.Antialiasing)
    
            # taken from QGIS Repo src/core/qgspallabeling.cpp
            m2p = QgsMapToPixel(1, 0, 0, 0, 0, 0)
            context.setMapToPixel(m2p)
            context.setScaleFactor(QgsApplication.desktop().logicalDpiX() / 25.4)
            context.setUseAdvancedEffects(True)
            context.setPainter(painter)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            # context.setExtent(self.mCanvas.extent())
            # context.setExpressionContext(self.mCanvas.mapSettings().expressionContext())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            # rect = self.mCanvas.extent().toRectF()
    
            textFormat = self.mTextFormat
            assert isinstance(textFormat, QgsTextFormat)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            th = r.textHeight(context, textFormat, text, QgsTextRenderer.Rect)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            x = 0.5 * vp.width()
            y = 0.5 * vp.height()
    
            hAlign = QgsTextRenderer.AlignCenter
    
            # horizontal position
            if bool(flags & Qt.AlignLeft):
                x = padding
                hAlign = QgsTextRenderer.AlignLeft
    
            elif bool(flags & Qt.AlignHCenter):
                x = 0.5 * vp.width()
                hAlign = QgsTextRenderer.AlignCenter
    
            elif bool(flags & Qt.AlignRight):
                x = vp.width() - padding
                hAlign = QgsTextRenderer.AlignRight
    
            # vertical position
            if bool(flags & Qt.AlignTop):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                y = padding + th - 0.5 * (th / nl)
    
    
            elif bool(flags & Qt.AlignVCenter):
                y = 0.5 * (vp.height() + th)
    
            elif bool(flags & Qt.AlignBottom):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                y = vp.height() - padding  # - th
    
    
            poo = QPointF(x, y)
            r.drawText(poo, rotation, hAlign, text, context, textFormat)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setUpperLeft(self, text: str):
    
            self.setText(text, Qt.AlignTop | Qt.AlignLeft)
    
        def setMiddleLeft(self, text: str):
            self.setText(text, Qt.AlignVCenter | Qt.AlignLeft)
    
        def setLowerLeft(self, text: str):
            self.setText(text, Qt.AlignBottom | Qt.AlignLeft)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setUpperCenter(self, text: str):
    
            self.setText(text, Qt.AlignTop | Qt.AlignHCenter)
    
        def setMiddleCenter(self, text: str):
            self.setText(text, Qt.AlignVCenter | Qt.AlignHCenter)
    
        def setLowerCenter(self, text: str):
            self.setText(text, Qt.AlignBottom | Qt.AlignHCenter)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setUpperRight(self, text: str):
    
            self.setText(text, Qt.AlignTop | Qt.AlignRight)
    
        def setMiddleRight(self, text: str):
            self.setText(text, Qt.AlignVCenter | Qt.AlignRight)
    
        def setLowerRight(self, text: str):
            self.setText(text, Qt.AlignBottom | Qt.AlignRight)
    
        def clearText(self):
            self.mText.clear()
    
    
        def paint(self, painter, QStyleOptionGraphicsItem=None, QWidget_widget=None):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
    
                Paints the crosshair
                :param painter:
                :param QStyleOptionGraphicsItem:
                :param QWidget_widget:
                :return:
                """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            for alignment, text in self.mText.items():
                if isinstance(text, str) and len(text) > 0:
                    self.paintText(painter, text, alignment)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    class MapCanvasMapTools(QObject):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        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)
    
    
            self.mtAddFeature = QgsMapToolAddFeature(canvas, QgsMapToolCapture.CaptureNone, cadDock)
    
            self.mtSelectFeature = QgsMapToolSelect(canvas)
    
    
        def activate(self, mapToolKey, **kwds):
    
            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
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            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
        """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        class Command(enum.Enum):
    
            """
            Canvas specific commands
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            RefreshRenderer = 1
            Clear = 3
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        # sigShowProfiles = pyqtSignal(SpatialPoint, str)
    
        sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        # sigChangeDVRequest = pyqtSignal(QgsMapCanvas, str)
        # sigChangeMVRequest = pyqtSignal(QgsMapCanvas, str)
        # sigChangeSVRequest = pyqtSignal(QgsMapCanvas, QgsRasterRenderer)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        sigMapRefreshed = pyqtSignal([float, float], [float])
    
        sigCrosshairPositionChanged = pyqtSignal(SpatialPoint)
        sigCrosshairVisibilityChanged = pyqtSignal(bool)
    
        sigDestinationCrsChanged = pyqtSignal(QgsCoordinateReferenceSystem)
    
        sigCrosshairStyleChanged = pyqtSignal(CrosshairStyle)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        sigCanvasClicked = pyqtSignal(QMouseEvent)
    
        def __init__(self, parent=None):
            super(MapCanvas, self).__init__(parent=parent)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.setProperty(KEY_LAST_CLICKED, time.time())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.mMapLayerStore: QgsProject = QgsProject.instance()
    
            self.mMapTools = None
            self.initMapTools()
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.mTimedRefreshPipeLine = dict()
    
            self.mCrosshairItem = CrosshairMapCanvasItem(self)
            self.mInfoItem = MapCanvasInfoItem(self)
    
            self.mProgressItem = MapLoadingInfoItem(self)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.mTSD = self.mMapView = None
    
            self.mUserInputWidget = QgsUserInputWidget(self)
            self.mUserInputWidget.setObjectName('UserInputDockWidget')
            self.mUserInputWidget.setAnchorWidget(self)
            self.mUserInputWidget.setAnchorWidgetPoint(QgsFloatingWidget.TopRight)
            self.mUserInputWidget.setAnchorPoint(QgsFloatingWidget.TopRight)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            # self.mProgressBar = QProgressBar()
            # self.mUserInputWidget.addUserInputWidget(self.mProgressBar)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.mIsRefreshing = False
    
            self.mRenderingFinished = True
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.mRefreshStartTime = time.time()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            def onMapCanvasRefreshed(*args):
                self.mIsRefreshing = False
    
                self.mRenderingFinished = True
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                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's avatar
    Benjamin Jakimow committed
            self.mapCanvasRefreshed.connect(onMapCanvasRefreshed)
    
            self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
    
            bg = eotimeseriesviewer.settings.value(
                eotimeseriesviewer.settings.Keys.MapBackgroundColor, default=QColor(0, 0, 0))
    
            self.setCanvasColor(bg)
    
            self.setContextMenuPolicy(Qt.DefaultContextMenu)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.extentsChanged.connect(self.onExtentsChanged)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def onExtentsChanged(self):
            self.sigSpatialExtentChanged.emit(self.spatialExtent())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            # self.destinationCrsChanged.connect(lambda: self.sigDestinationCrsChanged.emit(self.crs()))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def userInputWidget(self) -> QgsUserInputWidget:
    
            """
            Returns the mapcanvas QgsUserInputWidget
            :return: QgsUserInputWidget
            """
            return self.mUserInputWidget
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        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):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            """
            Returns the MapView this MapCanvas is linked to
            :return:
            """
            return self.mMapView
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        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)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setMapLayerStore(self, store: typing.Union[QgsMapLayerStore, QgsProject]):
    
            """
            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
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def renderingFinished(self) -> bool:
    
            """
            Returns whether the MapCanvas is processing a rendering task
            :return: bool
            """
            return self.mRenderingFinished
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def mousePressEvent(self, event: QMouseEvent):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.setProperty(KEY_LAST_CLICKED, time.time())
    
    
            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)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.sigCanvasClicked.emit(event)
    
    
        def setMapView(self, mapView):
    
            """
            Sets the map canvas MapView
            :param mapView: MapView
            """
    
            from eotimeseriesviewer.mapvisualization import MapView
    
    
            assert isinstance(mapView, MapView)
    
            self.mMapView = mapView
    
            self.mInfoItem.setTextFormat(mapView.mapTextFormat())
    
            self.addToRefreshPipeLine(mapView.mapBackgroundColor())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.setCrosshairStyle(mapView.crosshairStyle())
            #self.setCrosshairVisibility(mapView.crosshairStyle())
    
    
            # self.addToRefreshPipeLine(MapCanvas.Command.UpdateMapItems)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setTSD(self, tsd: TimeSeriesDate):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
    
            Sets the TimeSeriesDate this map-canvas is linked to
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            :param tsd:
            :return:
            """
    
            # disconnect old TSD
            if isinstance(self.mTSD, TimeSeriesDate):
                self.mTSD.sensor().sigNameChanged.disconnect(self.updateScope)
    
    
            if isinstance(tsd, TimeSeriesDate):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.setTemporalRange(tsd.temporalRange())
    
                self.mTSD.sensor().sigNameChanged.connect(self.updateScope)
    
    
        def updateScope(self):
            """
            Updates map-canvas TSD variables
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            from .mapvisualization import MapView
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            from .main import EOTimeSeriesViewer
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
            varMVNumber = None
            varMVName = None
            varDate = None
            varDOY = None
            varSensor = None
    
    
            tsd = self.tsd()
            if isinstance(tsd, TimeSeriesDate):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                varDate = str(tsd.date())
                varDOY = tsd.doy()
                varSensor = tsd.sensor().name()
    
            mv = self.mapView()
            if isinstance(mv, MapView):
                varMVName = mv.name()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                if isinstance(EOTimeSeriesViewer.instance(), EOTimeSeriesViewer):
                    mapViews = EOTimeSeriesViewer.instance().mapViews()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    if mv in mapViews:
                        varMVNumber = mapViews.index(mv) + 1
    
            scope = self.expressionContextScope()
            scope.setVariable('map_view_num', varMVNumber, isStatic=False)
            scope.setVariable('map_view', varMVName, isStatic=False)
            scope.setVariable('map_date', varDate, isStatic=False)
            scope.setVariable('map_doy', varDOY, isStatic=False)
            scope.setVariable('map_sensor', varSensor, isStatic=False)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def tsd(self) -> TimeSeriesDate:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
    
            Returns the TimeSeriesDate
            :return: TimeSeriesDate
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            return self.mTSD
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setSpatialExtent(self, extent: SpatialExtent):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            Sets the spatial extent
            :param extent: SpatialExtent
            """
            assert isinstance(extent, SpatialExtent)
            extent = extent.toCrs(self.crs())
            self.setExtent(extent)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setSpatialCenter(self, center: SpatialPoint):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            Sets the SpatialCenter
            :param center: SpatialPoint
            """
            assert isinstance(center, SpatialPoint)
            center = center.toCrs(self.crs())
            self.setCenter(center)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setFixedSize(self, size: QSize):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            Changes the map-canvas size
            :param size: QSize
            """
    
            assert isinstance(size, QSize)
            if self.size() != size:
    
                super(MapCanvas, self).setFixedSize(size)
    
        def setCrs(self, crs: QgsCoordinateReferenceSystem):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            Sets the
            :param crs:
            :return:
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert isinstance(crs, QgsCoordinateReferenceSystem)
    
            if self.crs() != crs:
                self.setDestinationCrs(crs)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def crs(self) -> QgsCoordinateReferenceSystem:
    
            """
            Shortcut to return self.mapSettings().destinationCrs()
            :return: QgsCoordinateReferenceSystem
            """
    
            return self.mapSettings().destinationCrs()
    
    
            """
            Set the map layers and, if necessary, registers the in a QgsMapLayerStore
            :param mapLayers:
            """
    
            self.mMapLayerStore.addMapLayers(mapLayers)
            super(MapCanvas, self).setLayers(mapLayers)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def isRefreshing(self) -> bool:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            return self.mIsRefreshing
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        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]
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if not isinstance(arguments, list):
                arguments = [arguments]
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            for a in arguments:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                if isinstance(a, SpatialExtent):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    self.mTimedRefreshPipeLine[SpatialExtent] = a
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                elif isinstance(a, SpatialPoint):
    
                    self.mTimedRefreshPipeLine[SpatialPoint] = a
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
                elif isinstance(a, QColor):
                    self.mTimedRefreshPipeLine[QColor] = a
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                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
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    while a in self.mTimedRefreshPipeLine[MapCanvas.Command]:
                        self.mTimedRefreshPipeLine[MapCanvas.Command].remove(a)
                    self.mTimedRefreshPipeLine[MapCanvas.Command].append(a)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                else:
    
                    print('Unsupported argument: {} {}'.format(type(a), str(a)), file=sys.stderr)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            Called to refresh the map canvas with all things needed to be done with lazy evaluation
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            existing: typing.List[QgsMapLayer] = self.layers()
    
            existingSources = [l.source() for l in existing]
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            from .mapvisualization import MapView
            from .timeseries import SensorInstrument
    
            mapView: MapView = self.mapView()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if mapView is None or self.tsd() is None:
    
                self.setLayers([])
                self.mInfoItem.clearText()
                self.update()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            sensor: SensorInstrument = self.tsd().sensor()
    
            for lyr in mapView.visibleLayers():
    
                assert isinstance(lyr, QgsMapLayer)
    
                if isinstance(lyr, SensorProxyLayer):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    if sensor == lyr.sensor():
                        # check if we need to add a new source
    
                        for tss in self.tsd():
                            if not tss.isVisible():
                                continue
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                            source = tss.uri()
    
                            if source in existingSources:
                                sourceLayer = existing[existingSources.index(source)]
                            else:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                # add new layer
    
                                loadDefaultStyle = mapView.mLayerStyleInitialized.get(sensor, False) == False
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                master: SensorProxyLayer = mapView.sensorProxyLayer(sensor)
                                sourceLayer = SensorProxyLayer(source,
                                                               sensor=sensor,
                                                               options=QgsRasterLayer.LayerOptions(
    
                                                               loadDefaultStyle=loadDefaultStyle))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                sourceLayer.setName(f'{lyr.name()} {source}')
                                sourceLayer.setCustomProperty('eotsv/sensorid', sensor.id())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                sourceLayer.mTSS = tss
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                sourceLayer.setMapLayerStyle(master.mapLayerStyle())
                                sourceLayer.styleChanged.connect(lambda *args, l=sourceLayer: self.onSetMasterLayerStyle(l))
    
    
                            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.
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                return
            else:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                if True:
                    # set sources first
                    keys = self.mTimedRefreshPipeLine.keys()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                    if QgsCoordinateReferenceSystem in keys:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                        self.setDestinationCrs(self.mTimedRefreshPipeLine.pop(QgsCoordinateReferenceSystem))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                    if SpatialExtent in keys:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                        self.setSpatialExtent(self.mTimedRefreshPipeLine.pop(SpatialExtent))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                    if SpatialPoint in keys:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                        self.setSpatialCenter(self.mTimedRefreshPipeLine.pop(SpatialPoint))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
                    if QColor in keys:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                        self.setCanvasColor(self.mTimedRefreshPipeLine.pop(QColor))
    
                    if lyrs != expected:
                        self.setLayers(expected)
    
    
                    if MapCanvas.Command in keys:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                        commands = self.mTimedRefreshPipeLine.pop(MapCanvas.Command)
    
                        # print(commands)
    
                        for command in commands:
                            assert isinstance(command, MapCanvas.Command)
                            if command == MapCanvas.Command.RefreshRenderer:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                sensor = self.tsd().sensor()
    
    
                                # master = self.mapView().sensorProxyLayer(sensor)
                                # masterStyle = QgsMapLayerStyle()
                                # masterStyle.readFromLayer(master)
                                # masterStyleXML = masterStyle.xmlData()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                for l in self.layers():
                                    if isinstance(l, SensorProxyLayer) and l.sensor() == sensor:
                                        l.triggerRepaint()
    
                                        # style = QgsMapLayerStyle()
                                        # style.readFromLayer(l)
                                        # if style.xmlData() == masterStyleXML:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                        #    print(style.xmlData())
                                        #    s = ""
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                        #    style.writeToLayer(l)
    
                    self.mTimedRefreshPipeLine.clear()
    
                # self.freeze(False)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.refresh()
    
                # is this really required?
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def onSetMasterLayerStyle(self, lyr: SensorProxyLayer):
            if isinstance(lyr, SensorProxyLayer):
                master: SensorProxyLayer = self.mapView().sensorProxyLayer(lyr.sensor())
                if isinstance(master, SensorProxyLayer):
                    master.setMapLayerStyle(lyr.mapLayerStyle())
    
        def setLayerVisibility(self, cls, isVisible: bool):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            """
            :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)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        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:
    
                self.mCrosshairItem.crosshairStyle.setShow(False)
                self.mCrosshairItem.update()
    
                assert isinstance(crosshairStyle, CrosshairStyle)
    
                self.mCrosshairItem.setCrosshairStyle(crosshairStyle)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                s = ""
                #self.sigCrosshairStyleChanged.emit(self.mCrosshairItem.crosshairStyle())
            else:
                s = ""
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def crosshairStyle(self) -> CrosshairStyle:
    
            """
            Returns the style of the Crosshair.
            :return: CrosshairStyle
            """
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            return self.mCrosshairItem.crosshairStyle()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setCrosshairPosition(self, spatialPoint: SpatialPoint):
    
            """
            Sets the position of the Crosshair.
            :param spatialPoint: SpatialPoint
            :param emitSignal: True (default). Set False to avoid emitting sigCrosshairPositionChanged
            :return:
            """
    
            point = spatialPoint.toCrs(self.mapSettings().destinationCrs())
    
            if self.mCrosshairItem.mPosition != point:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                if self.mCrosshairItem.visibility() == False:
                    s = ""
                else:
                    s = ""
    
                self.mCrosshairItem.setPosition(point)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def crosshairPosition(self) -> SpatialPoint:
    
            """Returns the last crosshair position"""
            return self.mCrosshairItem.mPosition
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setCrosshairVisibility(self, b: bool, emitSignal=True):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            Sets the Crosshair visibility
    
            :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 pixmap(self):
            """
            Returns the current map image as pixmap
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            :return: QPixmap
    
        def contextMenu(self, pos: QPoint) -> QMenu:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            Creates 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)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
            tsd = self.tsd()
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            from .main import EOTimeSeriesViewer
            eotsv = EOTimeSeriesViewer.instance()
    
            viewPortMapLayers = [l for l in self.layers() if isinstance(l, QgsMapLayer)]
    
    Benjamin Jakimow's avatar
    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)]
    
            refSensorLayer = None
            refRasterLayer = None
    
            if len(viewPortRasterLayers) > 0:
                refRasterLayer = viewPortRasterLayers[0]
            if len(viewPortSensorLayers) > 0:
                refSensorLayer = viewPortSensorLayers[0]
    
            if isinstance(self.tsd(), TimeSeriesDate):
    
                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.selectedFeatureCount() > 0]
    
                layerNames = ', '.join([l.name() for l in lyrWithSelectedFeatures])
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                m = menu.addMenu('Quick Labels')
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                m.setToolTipsVisible(True)
    
                nQuickLabelLayers = len(lyrWithSelectedFeatures)
                m.setEnabled(nQuickLabelLayers > 0)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                a = m.addAction('Set Date/Sensor attributes')
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                a.setToolTip('Writes the dates and sensor quick labels of selected features in {}.'.format(layerNames))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                a.triggered.connect(lambda *args,
                                           tsd=self.tsd(),
                                           tss=tss: setQuickTSDLabelsForRegisteredLayers(tsd, tss))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                from .labeling import layerClassSchemes, setQuickClassInfo
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                if len(lyrWithSelectedFeatures) == 0:
                    a = m.addAction('No features selected.')
                    a.setToolTip('Select feature in the labeling panel to apply Quick label value on.')
                    a.setEnabled(False)
                else:
                    for layer in lyrWithSelectedFeatures:
                        assert isinstance(layer, QgsVectorLayer)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                        csf = layerClassSchemes(layer)
                        if len(csf) > 0:
                            m.addSection(layer.name())
                            for (cs, field) in csf:
                                assert isinstance(cs, ClassificationScheme)
                                assert isinstance(field, QgsField)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                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())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                                    a.triggered.connect(
                                        lambda _, vl=layer, f=field, c=classInfo: setQuickClassInfo(vl, f, c))
    
            if isinstance(refSensorLayer, SensorProxyLayer):
                m = menu.addMenu('Raster stretch...')
                action = m.addAction('Linear')
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                action.triggered.connect(lambda *args, lyr=refSensorLayer:
                                         self.stretchToExtent(self.spatialExtent(), 'linear_minmax', layer=lyr, p=0.0))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                action.triggered.connect(lambda *args, lyr=refSensorLayer:
                                         self.stretchToExtent(self.spatialExtent(), 'linear_minmax', layer=lyr, p=0.05))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                action.triggered.connect(lambda *args, lyr=refSensorLayer:
                                         self.stretchToExtent(self.spatialExtent(), 'gaussian', layer=lyr, n=3))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            from .externals.qps.layerproperties import 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))
            a = menu.addAction('Paste Style')
    
    
            a.setEnabled(False)
            clipBoardMime = QApplication.clipboard().mimeData()
            if isinstance(clipBoardMime, QMimeData) and 'application/qgis.style' in clipBoardMime.formats():
                a.setEnabled(True)
    
    
            a.triggered.connect(lambda *args, lyr=refRasterLayer: self.onPasteStyleFromClipboard(lyr))
    
            menu.addSeparator()
    
            m = menu.addMenu('Layers...')
    
            visibleLayers = viewPortRasterLayers + viewPortVectorLayers