Skip to content
Snippets Groups Projects
mapvisualization.py 102 KiB
Newer Older
  • Learn to ignore specific revisions
  • # noinspection PyPep8Naming
    
    """
    /***************************************************************************
    
                                  -------------------
            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.                                   *
     *                                                                         *
     ***************************************************************************/
    """
    
    
    import os, sys, re, fnmatch, collections, copy, traceback, bisect
    
    from qgis.core import QgsContrastEnhancement, QgsRasterShader, QgsColorRampShader,  QgsProject, QgsCoordinateReferenceSystem, \
        QgsRasterLayer, QgsVectorLayer, QgsMapLayer, QgsMapLayerProxyModel, QgsColorRamp, QgsSingleBandPseudoColorRenderer
    
    
    from qgis.gui import *
    from qgis.gui import QgsDockWidget, QgsMapCanvas, QgsMapTool, QgsCollapsibleGroupBox
    
    from PyQt5.QtXml import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    
    import numpy as np
    from timeseriesviewer.utils import *
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    from timeseriesviewer.timeseries import SensorInstrument, TimeSeriesDatum, TimeSeries
    
    from timeseriesviewer.ui.docks import loadUI
    
    from timeseriesviewer.ui.mapviewscrollarea import MapViewScrollArea
    
    from timeseriesviewer.mapcanvas import MapCanvas
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    from timeseriesviewer.crosshair import CrosshairStyle
    
    
    
    #assert os.path.isfile(dummyPath)
    #lyr = QgsRasterLayer(dummyPath)
    #assert lyr.isValid()
    DUMMY_RASTERINTERFACE = QgsSingleBandGrayRenderer(None, 0)
    
    
    
    
    class MapViewUI(QFrame, loadUI('mapviewdefinition.ui')):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def __init__(self, parent=None):
            super(MapViewUI, self).__init__(parent)
            self.setupUi(self)
            self.mSensors = collections.OrderedDict()
    
            m = QMenu(self.btnToggleCrosshair)
            m.addAction(self.actionSetCrosshairStyle)
            #a = m.addAction('Set Crosshair Style')
    
            self.btnToggleCrosshair.setMenu(m)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            from timeseriesviewer.main import TimeSeriesViewer
            tsv = TimeSeriesViewer.instance()
            if isinstance(tsv, TimeSeriesViewer):
    
                self.mStore = tsv.mapLayerStore()
                self.mVectorSourceModel = self.cbQgsVectorLayer.model().sourceModel()
                self.mStore.layersAdded.connect(self.mVectorSourceModel.addLayers)
                self.mStore.layersRemoved.connect(self.mVectorSourceModel.removeLayers)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            #connect the QActions with the QgsCollapsibleGroupBoxes
    
            self.gbVectorRendering.toggled.connect(self.actionToggleVectorVisibility.setChecked)
            self.gbRasterRendering.toggled.connect(self.actionToggleRasterVisibility.setChecked)
    
            #self.connectActionWithGroupBox(self.actionToggleVectorVisibility, self.gbVectorRendering)
            #self.connectActionWithGroupBox(self.actionToggleRasterVisibility, self.gbRasterRendering)
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            #self.gbVectorRendering.toggled.connect(self.actionToggleVectorVisibility.toggle)
            #self.gbRasterRendering.toggled.connect(self.actionToggleRasterVisibility.toggle)
            #self.actionToggleVectorVisibility.toggled.connect(self.gbVectorRendering.setChecked)
            #self.actionToggleRasterVisibility.toggled.connect(self.gbRasterRendering.setChecked)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.btnToggleCrosshair.setDefaultAction(self.actionToggleCrosshairVisibility)
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            self.btnToggleMapViewVisibility.setDefaultAction(self.actionToggleMapViewHidden)
    
            self.btnSetVectorStyle.setDefaultAction(self.actionSetVectorStyle)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
        def addSensor(self, sensor):
            assert isinstance(sensor, SensorInstrument)
    
    
            #w = MapViewSensorSettings(sensor)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            w = MapViewRenderSettings(sensor)
    
            w.collapsedStateChanged.connect(self.onSensorBoxCollapsed)
    
            l = self.gbRasterRendering.layout()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert sensor not in self.mSensors.keys()
    
    
            i = l.count()-1
            while i > 0 and not isinstance(l.itemAt(i), QWidget):
                i -= 1
            l.insertWidget(i, w, stretch=0, alignment=Qt.AlignTop)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.mSensors[sensor] = w
            #self.resize(self.sizeHint())
    
            return w
    
    
        def removeSensor(self, sensor):
    
            assert isinstance(sensor, SensorInstrument)
            sensorSettings = self.mSensors.pop(sensor)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert isinstance(sensorSettings, MapViewRenderSettings)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            #l = self.renderSettingsLayout
            l = self.gbRasterRendering.layout()
    
            l.removeWidget(sensorSettings)
            sensorSettings.close()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            #self.resize(self.sizeHint())
    
        def onSensorBoxCollapsed(self, b:bool):
            l = self.gbRasterRendering.layout()
            for i in range(l.count()):
                item = l.itemAt(i)
    
    
    class RendererWidgetModifications(object):
    
    
        def __init__(self):
            self.mBandComboBoxes = []
    
        def modifyGridLayout(self):
            gridLayoutOld = self.layout().children()[0]
            self.gridLayout = QGridLayout()
            while gridLayoutOld.count() > 0:
                w = gridLayoutOld.takeAt(0)
                w = w.widget()
                gridLayoutOld.removeWidget(w)
                w.setVisible(False)
                setattr(self, w.objectName(), w)
            self.layout().removeItem(gridLayoutOld)
            self.layout().insertItem(0, self.gridLayout)
            self.gridLayout.setSpacing(2)
            self.layout().addStretch()
    
        def connectSliderWithBandComboBox(self, slider, combobox):
            """
            Connects a band-selection slider with a band-selection combobox
            :param widget: QgsRasterRendererWidget
            :param slider: QSlider to show the band number
            :param combobox: QComboBox to show the band name
            :return:
            """
            assert isinstance(self, QgsRasterRendererWidget)
            assert isinstance(slider, QSlider)
            assert isinstance(combobox, QComboBox)
    
            # init the slider
            nb = self.rasterLayer().dataProvider().bandCount()
            slider.setTickPosition(QSlider.TicksAbove)
            slider.valueChanged.connect(combobox.setCurrentIndex)
            slider.setMinimum(1)
            slider.setMaximum(nb)
            intervals = [1, 2, 5, 10, 25, 50]
            for interval in intervals:
                if nb / interval < 10:
                    break
            slider.setTickInterval(interval)
            slider.setPageStep(interval)
    
            def onBandValueChanged(self, idx, slider):
                assert isinstance(self, QgsRasterRendererWidget)
                assert isinstance(idx, int)
                assert isinstance(slider, QSlider)
    
                # i = slider.value()
                slider.blockSignals(True)
                slider.setValue(idx)
                slider.blockSignals(False)
    
                # self.minMaxWidget().setBands(myBands)
                # self.widgetChanged.emit()
    
            if self.comboBoxWithNotSetItem(combobox):
                combobox.currentIndexChanged[int].connect(lambda idx: onBandValueChanged(self, idx, slider))
            else:
                combobox.currentIndexChanged[int].connect(lambda idx: onBandValueChanged(self, idx + 1, slider))
    
        def comboBoxWithNotSetItem(self, cb):
            assert isinstance(cb, QComboBox)
            return cb.itemData(0, role=Qt.DisplayRole) == 'not set'
    
        def setLayoutItemVisibility(self, grid, isVisible):
            assert isinstance(self, QgsRasterRendererWidget)
            for i in range(grid.count()):
                item = grid.itemAt(i)
                if isinstance(item, QLayout):
                    s = ""
                elif isinstance(item, QWidgetItem):
                    item.widget().setVisible(isVisible)
                    item.widget().setParent(self)
                else:
                    s = ""
    
    
    
    
    
    def displayBandNames(provider_or_dataset, bands=None):
        results = None
        if isinstance(provider_or_dataset, QgsRasterLayer):
            return displayBandNames(provider_or_dataset.dataProvider())
        elif isinstance(provider_or_dataset, QgsRasterDataProvider):
            if provider_or_dataset.name() == 'gdal':
                ds = gdal.Open(provider_or_dataset.dataSourceUri())
                results = displayBandNames(ds, bands=bands)
            else:
                # same as in QgsRasterRendererWidget::displayBandName
                results = []
                if bands is None:
                    bands = range(1, provider_or_dataset.bandCount() + 1)
                for band in bands:
                    result = provider_or_dataset.generateBandName(band)
                    colorInterp ='{}'.format(provider_or_dataset.colorInterpretationName(band))
                    if colorInterp != 'Undefined':
                        result += '({})'.format(colorInterp)
                    results.append(result)
    
        elif isinstance(provider_or_dataset, gdal.Dataset):
            results = []
            if bands is None:
                bands = range(1, provider_or_dataset.RasterCount+1)
            for band in bands:
                b = provider_or_dataset.GetRasterBand(band)
                descr = b.GetDescription()
                if len(descr) == 0:
                    descr = 'Band {}'.format(band)
                results.append(descr)
    
        return results
    
    class SingleBandGrayRendererWidget(QgsSingleBandGrayRendererWidget, RendererWidgetModifications):
        @staticmethod
        def create(layer, extent):
            return SingleBandGrayRendererWidget(layer, extent)
    
        def __init__(self, layer, extent):
            super(SingleBandGrayRendererWidget, self).__init__(layer, extent)
    
            self.modifyGridLayout()
            self.mGrayBandSlider = QSlider(Qt.Horizontal)
            self.mBandComboBoxes.append(self.mGrayBandComboBox)
            self.fixBandNames(self.mGrayBandComboBox)
            self.connectSliderWithBandComboBox(self.mGrayBandSlider, self.mGrayBandComboBox)
    
            self.mBtnBar = QFrame()
            self.initActionButtons()
    
            self.gridLayout.addWidget(self.mGrayBandLabel, 0, 0)
            self.gridLayout.addWidget(self.mBtnBar, 0, 1, 1, 4, Qt.AlignLeft)
    
            self.gridLayout.addWidget(self.mGrayBandSlider, 1, 1, 1, 2)
            self.gridLayout.addWidget(self.mGrayBandComboBox, 1, 3,1,2)
    
            self.gridLayout.addWidget(self.label, 2, 0)
            self.gridLayout.addWidget(self.mGradientComboBox, 2, 1, 1, 4)
    
            self.gridLayout.addWidget(self.mMinLabel, 3, 1)
            self.gridLayout.addWidget(self.mMinLineEdit, 3, 2)
            self.gridLayout.addWidget(self.mMaxLabel, 3, 3)
            self.gridLayout.addWidget(self.mMaxLineEdit, 3, 4)
    
            self.gridLayout.addWidget(self.mContrastEnhancementLabel, 4, 0)
            self.gridLayout.addWidget(self.mContrastEnhancementComboBox, 4, 1, 1 ,4)
            self.gridLayout.setSpacing(2)
    
            self.setLayoutItemVisibility(self.gridLayout, True)
    
            self.mDefaultRenderer = layer.renderer()
    
    
        def initActionButtons(self):
                wl, wlu = parseWavelength(self.rasterLayer())
                self.wavelengths = wl
                self.wavelengthUnit = wlu
    
                self.mBtnBar.setLayout(QHBoxLayout())
                self.mBtnBar.layout().addStretch()
                self.mBtnBar.layout().setContentsMargins(0, 0, 0, 0)
                self.mBtnBar.layout().setSpacing(2)
    
                self.actionSetDefault = QAction('Default')
                self.actionSetRed = QAction('R')
                self.actionSetGreen = QAction('G')
                self.actionSetBlue = QAction('B')
                self.actionSetNIR = QAction('nIR')
                self.actionSetSWIR = QAction('swIR')
    
                self.actionSetDefault.triggered.connect(lambda: self.setBandSelection('default'))
                self.actionSetRed.triggered.connect(lambda: self.setBandSelection('R'))
                self.actionSetGreen.triggered.connect(lambda: self.setBandSelection('G'))
                self.actionSetBlue.triggered.connect(lambda: self.setBandSelection('B'))
                self.actionSetNIR.triggered.connect(lambda: self.setBandSelection('nIR'))
                self.actionSetSWIR.triggered.connect(lambda: self.setBandSelection('swIR'))
    
    
                def addBtnAction(action):
                    btn = QToolButton()
                    btn.setDefaultAction(action)
                    self.mBtnBar.layout().addWidget(btn)
                    self.insertAction(None, action)
                    return btn
    
                self.btnDefault = addBtnAction(self.actionSetDefault)
                self.btnRed = addBtnAction(self.actionSetRed)
                self.btnGreen = addBtnAction(self.actionSetGreen)
                self.btnBlue = addBtnAction(self.actionSetRed)
                self.btnNIR = addBtnAction(self.actionSetNIR)
                self.btnSWIR = addBtnAction(self.actionSetSWIR)
    
                b = self.wavelengths is not None
                for a in [self.actionSetRed, self.actionSetGreen, self.actionSetBlue, self.actionSetNIR, self.actionSetSWIR]:
                    a.setEnabled(b)
    
    
    
    class SingleBandPseudoColorRendererWidget(QgsSingleBandPseudoColorRendererWidget, RendererWidgetModifications):
        @staticmethod
        def create(layer, extent):
            return SingleBandPseudoColorRendererWidget(layer, extent)
    
        def __init__(self, layer, extent):
            super(SingleBandPseudoColorRendererWidget, self).__init__(layer, extent)
    
            self.gridLayout = self.layout()
            assert isinstance(self.gridLayout, QGridLayout)
            for i in range(self.gridLayout.count()):
                w = self.gridLayout.itemAt(i)
                w = w.widget()
                if isinstance(w, QWidget):
                    setattr(self, w.objectName(), w)
    
            toReplace = [self.mBandComboBox,self.mMinLabel,self.mMaxLabel, self.mMinLineEdit, self.mMaxLineEdit ]
            for w in toReplace:
                self.gridLayout.removeWidget(w)
                w.setVisible(False)
            self.mBandSlider = QSlider(Qt.Horizontal)
            self.mBandComboBoxes.append(self.mBandComboBox)
            self.fixBandNames(self.mBandComboBox)
            self.connectSliderWithBandComboBox(self.mBandSlider, self.mBandComboBox)
    
            self.mBtnBar = QFrame()
            self.initActionButtons()
            grid = QGridLayout()
            grid.addWidget(self.mBtnBar,0,0,1,4, Qt.AlignLeft)
            grid.addWidget(self.mBandSlider, 1,0, 1,2)
            grid.addWidget(self.mBandComboBox, 1,2, 1,2)
            grid.addWidget(self.mMinLabel, 2, 0)
            grid.addWidget(self.mMinLineEdit, 2, 1)
            grid.addWidget(self.mMaxLabel, 2, 2)
            grid.addWidget(self.mMaxLineEdit, 2, 3)
            #grid.setContentsMargins(2, 2, 2, 2, )
            grid.setColumnStretch(0, 0)
            grid.setColumnStretch(1, 2)
            grid.setColumnStretch(2, 0)
            grid.setColumnStretch(3, 2)
            grid.setSpacing(2)
            self.gridLayout.addItem(grid, 0,1,2,4)
            self.gridLayout.setSpacing(2)
            self.setLayoutItemVisibility(grid, True)
    
    
        def initActionButtons(self):
    
                wl, wlu = parseWavelength(self.rasterLayer())
                self.wavelengths = wl
                self.wavelengthUnit = wlu
    
                self.mBtnBar.setLayout(QHBoxLayout())
                self.mBtnBar.layout().addStretch()
                self.mBtnBar.layout().setContentsMargins(0, 0, 0, 0)
                self.mBtnBar.layout().setSpacing(2)
    
                self.actionSetDefault = QAction('Default')
                self.actionSetRed = QAction('R')
                self.actionSetGreen = QAction('G')
                self.actionSetBlue = QAction('B')
                self.actionSetNIR = QAction('nIR')
                self.actionSetSWIR = QAction('swIR')
    
                self.actionSetDefault.triggered.connect(lambda: self.setBandSelection('default'))
                self.actionSetRed.triggered.connect(lambda: self.setBandSelection('R'))
                self.actionSetGreen.triggered.connect(lambda: self.setBandSelection('G'))
                self.actionSetBlue.triggered.connect(lambda: self.setBandSelection('B'))
                self.actionSetNIR.triggered.connect(lambda: self.setBandSelection('nIR'))
                self.actionSetSWIR.triggered.connect(lambda: self.setBandSelection('swIR'))
    
    
                def addBtnAction(action):
                    btn = QToolButton()
                    btn.setDefaultAction(action)
                    self.mBtnBar.layout().addWidget(btn)
                    self.insertAction(None, action)
                    return btn
    
                self.btnDefault = addBtnAction(self.actionSetDefault)
                self.btnRed = addBtnAction(self.actionSetRed)
                self.btnGreen = addBtnAction(self.actionSetGreen)
                self.btnBlue = addBtnAction(self.actionSetRed)
                self.btnNIR = addBtnAction(self.actionSetNIR)
                self.btnSWIR = addBtnAction(self.actionSetSWIR)
    
                b = self.wavelengths is not None
                for a in [self.actionSetRed, self.actionSetGreen, self.actionSetBlue, self.actionSetNIR, self.actionSetSWIR]:
                    a.setEnabled(b)
    
    
    
    
    class MultiBandColorRendererWidget(QgsMultiBandColorRendererWidget, RendererWidgetModifications):
        @staticmethod
        def create(layer, extent):
            return MultiBandColorRendererWidget(layer, extent)
    
        def __init__(self, layer, extent):
            super(MultiBandColorRendererWidget, self).__init__(layer, extent)
    
            self.modifyGridLayout()
    
            self.mRedBandSlider = QSlider(Qt.Horizontal)
            self.mGreenBandSlider = QSlider(Qt.Horizontal)
            self.mBlueBandSlider = QSlider(Qt.Horizontal)
    
            self.mBandComboBoxes.extend([self.mRedBandComboBox, self.mGreenBandComboBox, self.mBlueBandComboBox])
            self.mSliders = [self.mRedBandSlider, self.mGreenBandSlider, self.mBlueBandSlider]
            nb = self.rasterLayer().dataProvider().bandCount()
            for cbox, slider in zip(self.mBandComboBoxes, self.mSliders):
                self.connectSliderWithBandComboBox(slider, cbox)
    
    
            self.fixBandNames(self.mRedBandComboBox)
            self.fixBandNames(self.mGreenBandComboBox)
            self.fixBandNames(self.mBlueBandComboBox)
    
            self.mBtnBar = QFrame()
            self.mBtnBar.setLayout(QHBoxLayout())
            self.initActionButtons()
            self.mBtnBar.layout().addStretch()
            self.mBtnBar.layout().setContentsMargins(0, 0, 0, 0)
            self.mBtnBar.layout().setSpacing(2)
    
            #self.gridLayout.deleteLater()
    #        self.gridLayout = newGrid
            self.gridLayout.addWidget(self.mBtnBar, 0, 1, 1, 3)
            self.gridLayout.addWidget(self.mRedBandLabel, 1, 0)
            self.gridLayout.addWidget(self.mRedBandSlider, 1, 1)
            self.gridLayout.addWidget(self.mRedBandComboBox, 1, 2)
            self.gridLayout.addWidget(self.mRedMinLineEdit, 1, 3)
            self.gridLayout.addWidget(self.mRedMaxLineEdit, 1, 4)
    
            self.gridLayout.addWidget(self.mGreenBandLabel, 2, 0)
            self.gridLayout.addWidget(self.mGreenBandSlider, 2, 1)
            self.gridLayout.addWidget(self.mGreenBandComboBox, 2, 2)
            self.gridLayout.addWidget(self.mGreenMinLineEdit, 2, 3)
            self.gridLayout.addWidget(self.mGreenMaxLineEdit, 2, 4)
    
            self.gridLayout.addWidget(self.mBlueBandLabel, 3, 0)
            self.gridLayout.addWidget(self.mBlueBandSlider, 3, 1)
            self.gridLayout.addWidget(self.mBlueBandComboBox, 3, 2)
            self.gridLayout.addWidget(self.mBlueMinLineEdit, 3, 3)
            self.gridLayout.addWidget(self.mBlueMaxLineEdit, 3, 4)
    
            self.gridLayout.addWidget(self.mContrastEnhancementAlgorithmLabel, 4, 0, 1, 2)
            self.gridLayout.addWidget(self.mContrastEnhancementAlgorithmComboBox, 4, 2, 1, 3)
    
            self.setLayoutItemVisibility(self.gridLayout, True)
    
    
            self.mRedBandLabel.setText('R')
            self.mGreenBandLabel.setText('G')
            self.mBlueBandLabel.setText('B')
    
            self.mDefaultRenderer = layer.renderer()
    
    
    
        def initActionButtons(self):
    
            wl, wlu = parseWavelength(self.rasterLayer())
            self.wavelengths = wl
            self.wavelengthUnit = wlu
    
            self.actionSetDefault = QAction('Default')
            self.actionSetTrueColor = QAction('RGB')
            self.actionSetCIR = QAction('nIR')
            self.actionSet453 = QAction('swIR')
    
            self.actionSetDefault.triggered.connect(lambda: self.setBandSelection('default'))
            self.actionSetTrueColor.triggered.connect(lambda: self.setBandSelection('R,G,B'))
            self.actionSetCIR.triggered.connect(lambda: self.setBandSelection('nIR,R,G'))
            self.actionSet453.triggered.connect(lambda: self.setBandSelection('nIR,swIR,R'))
    
    
            def addBtnAction(action):
                btn = QToolButton()
                btn.setDefaultAction(action)
                self.mBtnBar.layout().addWidget(btn)
                self.insertAction(None, action)
                return btn
    
            self.btnDefault = addBtnAction(self.actionSetDefault)
            self.btnTrueColor = addBtnAction(self.actionSetTrueColor)
            self.btnCIR = addBtnAction(self.actionSetCIR)
            self.btn453 = addBtnAction(self.actionSet453)
    
            b = self.wavelengths is not None
            for a in [self.actionSetCIR, self.actionSet453, self.actionSetTrueColor]:
                a.setEnabled(b)
    
    class RendererWidgetModifications(object):
    
    
        def __init__(self, *args):
    
            self.mBandComboBoxes = []
    
    
        def modifyGridLayout(self):
    
            gridLayoutOld = self.layout().children()[0]
            self.gridLayout = QGridLayout()
            while gridLayoutOld.count() > 0:
                w = gridLayoutOld.takeAt(0)
                w = w.widget()
                gridLayoutOld.removeWidget(w)
                w.setVisible(False)
    
    
            self.gridLayout.setSpacing(2)
    
            l.removeItem(gridLayoutOld)
            if isinstance(l, QBoxLayout):
                l.insertItem(0, self.gridLayout)
                self.layout().addStretch()
            elif isinstance(l, QGridLayout):
                l.addItem(self.gridLayout, 0, 0)
    
    
            minMaxWidget = self.minMaxWidget()
            if isinstance(minMaxWidget, QWidget):
                minMaxWidget.layout().itemAt(0).widget().collapsedStateChanged.connect(self.onCollapsed)
    
        def initWidgetNames(self, parent=None):
            """
            Create a python variables to access QObjects which are child of parent
            :param parent: QObject, self by default
            """
            if parent is None:
                parent = self
    
            for c in parent.children():
                setattr(parent, c.objectName(), c)
    
    
    
    
    
        def onCollapsed(self, b):
            hint = self.sizeHint()
            self.parent().adjustSize()
    
           # self.parent().setFixedSize(hint)
    
            self.parent().parent().adjustSize()
    
        def connectSliderWithBandComboBox(self, slider, combobox):
            """
            Connects a band-selection slider with a band-selection combobox
            :param widget: QgsRasterRendererWidget
            :param slider: QSlider to show the band number
            :param combobox: QComboBox to show the band name
            :return:
            """
            assert isinstance(self, QgsRasterRendererWidget)
            assert isinstance(slider, QSlider)
            assert isinstance(combobox, QComboBox)
    
            # init the slider
    
            lyr = self.rasterLayer()
            if lyr.isValid():
                nb = lyr.dataProvider().bandCount()
            else:
                ds = gdal.Open(lyr.source())
                if isinstance(ds, gdal.Dataset):
                    nb = ds.RasterCount
                else:
                    nb = 1
    
            slider.setTickPosition(QSlider.TicksAbove)
            slider.valueChanged.connect(combobox.setCurrentIndex)
            slider.setMinimum(1)
            slider.setMaximum(nb)
            intervals = [1, 2, 5, 10, 25, 50]
            for interval in intervals:
                if nb / interval < 10:
                    break
            slider.setTickInterval(interval)
            slider.setPageStep(interval)
    
            def onBandValueChanged(self, idx, slider):
                assert isinstance(self, QgsRasterRendererWidget)
                assert isinstance(idx, int)
                assert isinstance(slider, QSlider)
    
                # i = slider.value()
                slider.blockSignals(True)
                slider.setValue(idx)
                slider.blockSignals(False)
    
                # self.minMaxWidget().setBands(myBands)
                # self.widgetChanged.emit()
    
            if self.comboBoxWithNotSetItem(combobox):
                combobox.currentIndexChanged[int].connect(lambda idx: onBandValueChanged(self, idx, slider))
            else:
                combobox.currentIndexChanged[int].connect(lambda idx: onBandValueChanged(self, idx + 1, slider))
    
    
        def comboBoxWithNotSetItem(self, cb)->bool:
    
            assert isinstance(cb, QComboBox)
    
            return re.search(r'^(not set|none|nonetype)$',str(data).strip(), re.I) is not None
    
    
        def setLayoutItemVisibility(self, grid, isVisible):
            assert isinstance(self, QgsRasterRendererWidget)
            for i in range(grid.count()):
                item = grid.itemAt(i)
                if isinstance(item, QLayout):
                    s = ""
                elif isinstance(item, QWidgetItem):
                    item.widget().setVisible(isVisible)
                    item.widget().setParent(self)
                else:
                    s = ""
    
        def setBandSelection(self, key):
    
            key = key.upper()
            if key == 'DEFAULT':
    
                bandIndices = defaultBands(self.rasterLayer())
    
            else:
                colors = re.split('[ ,;:]', key)
    
    
                bandIndices = [bandClosestToWavelength(self.rasterLayer(), c) for c in colors]
    
            n = min(len(bandIndices), len(self.mBandComboBoxes))
    
            for i in range(n):
                cb = self.mBandComboBoxes[i]
    
                bandIndex = bandIndices[i]
    
                if self.comboBoxWithNotSetItem(cb):
                    cb.setCurrentIndex(bandIndex+1)
                else:
                    cb.setCurrentIndex(bandIndex)
    
    
        def fixBandNames(self, comboBox):
            """
    
            Changes the QGIS default bandnames ("Band 001") to more meaningfull information including gdal.Dataset.Descriptions.
    
            :param widget:
            :param comboBox:
            """
    
            nb = self.rasterLayer().bandCount()
    
    
            assert isinstance(self, QgsRasterRendererWidget)
    
            assert isinstance(comboBox, QComboBox)
            #comboBox.clear()
            m = comboBox.model()
            assert isinstance(m, QStandardItemModel)
            bandNames = displayBandNames(self.rasterLayer())
    
    
            b = 1 if nb < comboBox.count() else 0
            for i in range(nb):
                item = m.item(i+b,0)
                assert isinstance(item, QStandardItem)
                item.setData(bandNames[i], Qt.DisplayRole)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                item.setData('Band {} "{}"'.format(i+1, bandNames[i]), Qt.ToolTipRole)
    
    
    
    def displayBandNames(provider_or_dataset, bands=None):
        results = None
        if isinstance(provider_or_dataset, QgsRasterLayer):
            return displayBandNames(provider_or_dataset.dataProvider())
        elif isinstance(provider_or_dataset, QgsRasterDataProvider):
            if provider_or_dataset.name() == 'gdal':
                ds = gdal.Open(provider_or_dataset.dataSourceUri())
                results = displayBandNames(ds, bands=bands)
            else:
                # same as in QgsRasterRendererWidget::displayBandName
                results = []
                if bands is None:
                    bands = range(1, provider_or_dataset.bandCount() + 1)
                for band in bands:
                    result = provider_or_dataset.generateBandName(band)
                    colorInterp ='{}'.format(provider_or_dataset.colorInterpretationName(band))
                    if colorInterp != 'Undefined':
                        result += '({})'.format(colorInterp)
                    results.append(result)
    
        elif isinstance(provider_or_dataset, gdal.Dataset):
            results = []
            if bands is None:
                bands = range(1, provider_or_dataset.RasterCount+1)
            for band in bands:
                b = provider_or_dataset.GetRasterBand(band)
                descr = b.GetDescription()
                if len(descr) == 0:
                    descr = 'Band {}'.format(band)
                results.append(descr)
    
        return results
    
    class SingleBandGrayRendererWidget(QgsSingleBandGrayRendererWidget, RendererWidgetModifications):
        @staticmethod
        def create(layer, extent):
            return SingleBandGrayRendererWidget(layer, extent)
    
        def __init__(self, layer, extent):
            super(SingleBandGrayRendererWidget, self).__init__(layer, extent)
    
            self.modifyGridLayout()
            self.mGrayBandSlider = QSlider(Qt.Horizontal)
            self.mBandComboBoxes.append(self.mGrayBandComboBox)
            self.fixBandNames(self.mGrayBandComboBox)
            self.connectSliderWithBandComboBox(self.mGrayBandSlider, self.mGrayBandComboBox)
    
            self.mBtnBar = QFrame()
            self.initActionButtons()
    
            self.gridLayout.addWidget(self.mGrayBandLabel, 0, 0)
            self.gridLayout.addWidget(self.mBtnBar, 0, 1, 1, 4, Qt.AlignLeft)
    
            self.gridLayout.addWidget(self.mGrayBandSlider, 1, 1, 1, 2)
            self.gridLayout.addWidget(self.mGrayBandComboBox, 1, 3,1,2)
    
            self.gridLayout.addWidget(self.label, 2, 0)
            self.gridLayout.addWidget(self.mGradientComboBox, 2, 1, 1, 4)
    
            self.gridLayout.addWidget(self.mMinLabel, 3, 1)
            self.gridLayout.addWidget(self.mMinLineEdit, 3, 2)
            self.gridLayout.addWidget(self.mMaxLabel, 3, 3)
            self.gridLayout.addWidget(self.mMaxLineEdit, 3, 4)
    
            self.gridLayout.addWidget(self.mContrastEnhancementLabel, 4, 0)
            self.gridLayout.addWidget(self.mContrastEnhancementComboBox, 4, 1, 1 ,4)
            self.gridLayout.setSpacing(2)
    
            self.setLayoutItemVisibility(self.gridLayout, True)
    
            self.mDefaultRenderer = layer.renderer()
    
            self.setFromRenderer(self.mDefaultRenderer)
    
    
        def initActionButtons(self):
    
            wl, wlu = parseWavelength(self.rasterLayer())
            self.wavelengths = wl
            self.wavelengthUnit = wlu
    
            self.mBtnBar.setLayout(QHBoxLayout())
            self.mBtnBar.layout().addStretch()
            self.mBtnBar.layout().setContentsMargins(0, 0, 0, 0)
            self.mBtnBar.layout().setSpacing(2)
    
            self.actionSetDefault = QAction('Default')
            self.actionSetRed = QAction('R')
            self.actionSetGreen = QAction('G')
            self.actionSetBlue = QAction('B')
            self.actionSetNIR = QAction('nIR')
            self.actionSetSWIR = QAction('swIR')
    
            self.actionSetDefault.triggered.connect(lambda: self.setBandSelection('default'))
            self.actionSetRed.triggered.connect(lambda: self.setBandSelection('R'))
            self.actionSetGreen.triggered.connect(lambda: self.setBandSelection('G'))
            self.actionSetBlue.triggered.connect(lambda: self.setBandSelection('B'))
            self.actionSetNIR.triggered.connect(lambda: self.setBandSelection('nIR'))
            self.actionSetSWIR.triggered.connect(lambda: self.setBandSelection('swIR'))
    
    
            def addBtnAction(action):
                btn = QToolButton()
                btn.setDefaultAction(action)
                self.mBtnBar.layout().addWidget(btn)
                self.insertAction(None, action)
                return btn
    
            self.btnDefault = addBtnAction(self.actionSetDefault)
    
            self.btnBlue = addBtnAction(self.actionSetBlue)
    
            self.btnGreen = addBtnAction(self.actionSetGreen)
    
            self.btnRed = addBtnAction(self.actionSetRed)
    
            self.btnNIR = addBtnAction(self.actionSetNIR)
            self.btnSWIR = addBtnAction(self.actionSetSWIR)
    
            b = self.wavelengths is not None
            for a in [self.actionSetRed, self.actionSetGreen, self.actionSetBlue, self.actionSetNIR, self.actionSetSWIR]:
                a.setEnabled(b)
    
    
    
    class SingleBandPseudoColorRendererWidget(QgsSingleBandPseudoColorRendererWidget, RendererWidgetModifications):
        @staticmethod
        def create(layer, extent):
            return SingleBandPseudoColorRendererWidget(layer, extent)
    
        def __init__(self, layer, extent):
            super(SingleBandPseudoColorRendererWidget, self).__init__(layer, extent)
    
    
            #self.mColormapTreeWidget.setMinimumSize(QSize(1,1))
    
            self.gridLayout = self.layout().children()[0]
    
            assert isinstance(self.gridLayout, QGridLayout)
            for i in range(self.gridLayout.count()):
                w = self.gridLayout.itemAt(i)
                w = w.widget()
                if isinstance(w, QWidget):
                    setattr(self, w.objectName(), w)
    
            toReplace = [self.mBandComboBox,self.mMinLabel,self.mMaxLabel, self.mMinLineEdit, self.mMaxLineEdit ]
            for w in toReplace:
                self.gridLayout.removeWidget(w)
                w.setVisible(False)
            self.mBandSlider = QSlider(Qt.Horizontal)
            self.mBandComboBoxes.append(self.mBandComboBox)
            self.fixBandNames(self.mBandComboBox)
            self.connectSliderWithBandComboBox(self.mBandSlider, self.mBandComboBox)
    
            self.mBtnBar = QFrame()
            self.initActionButtons()
            grid = QGridLayout()
            grid.addWidget(self.mBtnBar,0,0,1,4, Qt.AlignLeft)
            grid.addWidget(self.mBandSlider, 1,0, 1,2)
            grid.addWidget(self.mBandComboBox, 1,2, 1,2)
            grid.addWidget(self.mMinLabel, 2, 0)
            grid.addWidget(self.mMinLineEdit, 2, 1)
            grid.addWidget(self.mMaxLabel, 2, 2)
            grid.addWidget(self.mMaxLineEdit, 2, 3)
            #grid.setContentsMargins(2, 2, 2, 2, )
            grid.setColumnStretch(0, 0)
            grid.setColumnStretch(1, 2)
            grid.setColumnStretch(2, 0)
            grid.setColumnStretch(3, 2)
            grid.setSpacing(2)
            self.gridLayout.addItem(grid, 0,1,2,4)
            self.gridLayout.setSpacing(2)
            self.setLayoutItemVisibility(grid, True)
    
    
    
        def initActionButtons(self):
                wl, wlu = parseWavelength(self.rasterLayer())
                self.wavelengths = wl
                self.wavelengthUnit = wlu
    
                self.mBtnBar.setLayout(QHBoxLayout())
                self.mBtnBar.layout().addStretch()
                self.mBtnBar.layout().setContentsMargins(0, 0, 0, 0)
                self.mBtnBar.layout().setSpacing(2)
    
                self.actionSetDefault = QAction('Default')
                self.actionSetRed = QAction('R')
                self.actionSetGreen = QAction('G')
                self.actionSetBlue = QAction('B')
                self.actionSetNIR = QAction('nIR')
                self.actionSetSWIR = QAction('swIR')
    
                self.actionSetDefault.triggered.connect(lambda: self.setBandSelection('default'))
                self.actionSetRed.triggered.connect(lambda: self.setBandSelection('R'))
                self.actionSetGreen.triggered.connect(lambda: self.setBandSelection('G'))
                self.actionSetBlue.triggered.connect(lambda: self.setBandSelection('B'))
                self.actionSetNIR.triggered.connect(lambda: self.setBandSelection('nIR'))
                self.actionSetSWIR.triggered.connect(lambda: self.setBandSelection('swIR'))
    
    
                def addBtnAction(action):
                    btn = QToolButton()
                    btn.setDefaultAction(action)
                    self.mBtnBar.layout().addWidget(btn)
                    self.insertAction(None, action)
                    return btn
    
                self.btnDefault = addBtnAction(self.actionSetDefault)
    
                self.btnBlue = addBtnAction(self.actionSetBlue)
    
                self.btnGreen = addBtnAction(self.actionSetGreen)
    
                self.btnRed = addBtnAction(self.actionSetRed)
    
                self.btnNIR = addBtnAction(self.actionSetNIR)
                self.btnSWIR = addBtnAction(self.actionSetSWIR)
    
                b = self.wavelengths is not None
                for a in [self.actionSetRed, self.actionSetGreen, self.actionSetBlue, self.actionSetNIR, self.actionSetSWIR]:
                    a.setEnabled(b)
    
    
    
    class PalettedRendererWidget(QgsPalettedRendererWidget, RendererWidgetModifications):
        @staticmethod
        def create(layer, extent):
            return PalettedRendererWidget(layer, extent)
    
        def __init__(self, layer, extent):
            super(PalettedRendererWidget, self).__init__(layer, extent)
    
            #self.modifyGridLayout()
    
    
            self.fixBandNames(self.mBandComboBox)
    
            self.mTreeView.setMinimumSize(QSize(10,10))
            s = ""
    
    
    
    
    class MultiBandColorRendererWidget(QgsMultiBandColorRendererWidget, RendererWidgetModifications):
        @staticmethod
        def create(layer, extent):
            return MultiBandColorRendererWidget(layer, extent)
    
    
        def __init__(self, layer, extent):
            super(MultiBandColorRendererWidget, self).__init__(layer, extent)
    
            self.modifyGridLayout()
    
            self.mRedBandSlider = QSlider(Qt.Horizontal)
            self.mGreenBandSlider = QSlider(Qt.Horizontal)
            self.mBlueBandSlider = QSlider(Qt.Horizontal)
    
            self.mBandComboBoxes.extend([self.mRedBandComboBox, self.mGreenBandComboBox, self.mBlueBandComboBox])
            self.mSliders = [self.mRedBandSlider, self.mGreenBandSlider, self.mBlueBandSlider]
            for cbox, slider in zip(self.mBandComboBoxes, self.mSliders):
                self.connectSliderWithBandComboBox(slider, cbox)
    
    
            self.fixBandNames(self.mRedBandComboBox)
            self.fixBandNames(self.mGreenBandComboBox)
            self.fixBandNames(self.mBlueBandComboBox)
    
            self.mBtnBar = QFrame()
            self.mBtnBar.setLayout(QHBoxLayout())
            self.initActionButtons()
            self.mBtnBar.layout().addStretch()
            self.mBtnBar.layout().setContentsMargins(0, 0, 0, 0)
            self.mBtnBar.layout().setSpacing(2)
    
            #self.gridLayout.deleteLater()
    #        self.gridLayout = newGrid
            self.gridLayout.addWidget(self.mBtnBar, 0, 1, 1, 3)
            self.gridLayout.addWidget(self.mRedBandLabel, 1, 0)
            self.gridLayout.addWidget(self.mRedBandSlider, 1, 1)
            self.gridLayout.addWidget(self.mRedBandComboBox, 1, 2)
            self.gridLayout.addWidget(self.mRedMinLineEdit, 1, 3)
            self.gridLayout.addWidget(self.mRedMaxLineEdit, 1, 4)
    
            self.gridLayout.addWidget(self.mGreenBandLabel, 2, 0)
            self.gridLayout.addWidget(self.mGreenBandSlider, 2, 1)
            self.gridLayout.addWidget(self.mGreenBandComboBox, 2, 2)
            self.gridLayout.addWidget(self.mGreenMinLineEdit, 2, 3)
            self.gridLayout.addWidget(self.mGreenMaxLineEdit, 2, 4)
    
            self.gridLayout.addWidget(self.mBlueBandLabel, 3, 0)
            self.gridLayout.addWidget(self.mBlueBandSlider, 3, 1)
            self.gridLayout.addWidget(self.mBlueBandComboBox, 3, 2)
            self.gridLayout.addWidget(self.mBlueMinLineEdit, 3, 3)
            self.gridLayout.addWidget(self.mBlueMaxLineEdit, 3, 4)
    
            self.gridLayout.addWidget(self.mContrastEnhancementAlgorithmLabel, 4, 0, 1, 2)
            self.gridLayout.addWidget(self.mContrastEnhancementAlgorithmComboBox, 4, 2, 1, 3)
    
            self.setLayoutItemVisibility(self.gridLayout, True)
    
    
            self.mRedBandLabel.setText('R')
            self.mGreenBandLabel.setText('G')
            self.mBlueBandLabel.setText('B')
    
            self.mDefaultRenderer = layer.renderer()
    
    
    
        def initActionButtons(self):
    
            wl, wlu = parseWavelength(self.rasterLayer())
            self.wavelengths = wl
            self.wavelengthUnit = wlu
    
            self.actionSetDefault = QAction('Default')
            self.actionSetTrueColor = QAction('RGB')
            self.actionSetCIR = QAction('nIR')
            self.actionSet453 = QAction('swIR')
    
            self.actionSetDefault.triggered.connect(lambda: self.setBandSelection('default'))
            self.actionSetTrueColor.triggered.connect(lambda: self.setBandSelection('R,G,B'))
            self.actionSetCIR.triggered.connect(lambda: self.setBandSelection('nIR,R,G'))