Commit caa9813e authored by PIERSON Julie's avatar PIERSON Julie
Browse files

first poc for using custom widget based on ReliefColorsWidget

parent 71cac81d
# -*- coding: utf-8 -*-
"""
***************************************************************************
BandTableWidget.py
---------------------
Date : 2021-09-14
Copyright : (C) 2021 by J. Pierson, UMR 6554 LETG, CNRS
Email : julie.pierson@univ-brest.fr
Based upon : ReliefColorsWidget.py (C) 2016 by Alexander Bruy
***************************************************************************
* *
* 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. *
* *
***************************************************************************
"""
__author__ = 'J. Pierson, UMR 6554 LETG, CNRS'
__date__ = '2021-09-14'
__copyright__ = '(C) 2021 by J. Pierson, UMR 6554 LETG, CNRS'
import os
import codecs
from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSlot, QDir
from qgis.PyQt.QtGui import QColor, QBrush
from qgis.PyQt.QtWidgets import (QTreeWidgetItem,
QFileDialog,
QMessageBox,
QInputDialog,
QColorDialog
)
from qgis.PyQt.QtXml import QDomDocument
from qgis.core import QgsApplication, QgsMapLayer
from qgis.analysis import QgsRelief
from processing.gui.wrappers import WidgetWrapper
from processing.tools import system
pluginPath = os.path.dirname(__file__)
WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'bandtablewidgetbase.ui'))
class BandTableWidget(BASE, WIDGET):
def __init__(self):
super(BandTableWidget, self).__init__(None)
self.setupUi(self)
self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
self.btnUp.setIcon(QgsApplication.getThemeIcon('/mActionArrowUp.svg'))
self.btnDown.setIcon(QgsApplication.getThemeIcon('/mActionArrowDown.svg'))
self.btnLoad.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
self.btnAuto.setIcon(QgsApplication.getThemeIcon('/mActionReload.svg'))
self.layer = None
@pyqtSlot()
def on_btnAdd_clicked(self):
item = QTreeWidgetItem()
item.setText(0, '0.00')
item.setText(1, '0.00')
item.setBackground(2, QBrush(QColor(127, 127, 127)))
self.bandClassTree.addTopLevelItem(item)
@pyqtSlot()
def on_btnRemove_clicked(self):
selectedItems = self.bandClassTree.selectedItems()
for item in selectedItems:
self.bandClassTree.invisibleRootItem().removeChild(item)
item = None
@pyqtSlot()
def on_btnDown_clicked(self):
selectedItems = self.bandClassTree.selectedItems()
for item in selectedItems:
currentIndex = self.bandClassTree.indexOfTopLevelItem(item)
if currentIndex < self.bandClassTree.topLevelItemCount() - 1:
self.bandClassTree.takeTopLevelItem(currentIndex)
self.bandClassTree.insertTopLevelItem(currentIndex + 1, item)
self.bandClassTree.setCurrentItem(item)
@pyqtSlot()
def on_btnUp_clicked(self):
selectedItems = self.bandClassTree.selectedItems()
for item in selectedItems:
currentIndex = self.bandClassTree.indexOfTopLevelItem(item)
if currentIndex > 0:
self.bandClassTree.takeTopLevelItem(currentIndex)
self.bandClassTree.insertTopLevelItem(currentIndex - 1, item)
self.bandClassTree.setCurrentItem(item)
@pyqtSlot()
def on_btnLoad_clicked(self):
fileName, _ = QFileDialog.getOpenFileName(None,
self.tr('Import Colors and elevations from XML'),
QDir.homePath(),
self.tr('XML files (*.xml *.XML)'))
if fileName == '':
return
doc = QDomDocument()
with codecs.open(fileName, 'r', encoding='utf-8') as f:
content = f.read()
if not doc.setContent(content):
QMessageBox.critical(None,
self.tr('Error parsing XML'),
self.tr('The XML file could not be loaded'))
return
self.bandClassTree.clear()
reliefColorList = doc.elementsByTagName('ReliefColor')
for i in range(reliefColorList.length()):
elem = reliefColorList.at(i).toElement()
item = QTreeWidgetItem()
item.setText(0, elem.attribute('MinElevation'))
item.setText(1, elem.attribute('MaxElevation'))
item.setBackground(2, QBrush(QColor(int(elem.attribute('red')),
int(elem.attribute('green')),
int(elem.attribute('blue')))))
self.bandClassTree.addTopLevelItem(item)
@pyqtSlot()
def on_btnSave_clicked(self):
fileName, _ = QFileDialog.getSaveFileName(None,
self.tr('Export Colors and elevations as XML'),
QDir.homePath(),
self.tr('XML files (*.xml *.XML)'))
if fileName == '':
return
if not fileName.lower().endswith('.xml'):
fileName += '.xml'
doc = QDomDocument()
colorsElem = doc.createElement('ReliefColors')
doc.appendChild(colorsElem)
colors = self.reliefColors()
for c in colors:
elem = doc.createElement('ReliefColor')
elem.setAttribute('MinElevation', str(c.minElevation))
elem.setAttribute('MaxElevation', str(c.maxElevation))
elem.setAttribute('red', str(c.color.red()))
elem.setAttribute('green', str(c.color.green()))
elem.setAttribute('blue', str(c.color.blue()))
colorsElem.appendChild(elem)
with codecs.open(fileName, 'w', encoding='utf-8') as f:
f.write(doc.toString(2))
@pyqtSlot()
def on_btnAuto_clicked(self):
if self.layer is None:
return
relief = QgsRelief(self.layer, system.getTempFilename(), 'GTiff')
colors = relief.calculateOptimizedReliefClasses()
self.populateColors(colors)
@pyqtSlot(QTreeWidgetItem, int)
def on_bandClassTree_itemDoubleClicked(self, item, column):
if not item:
return
if column == 0:
d, ok = QInputDialog.getDouble(None,
self.tr('Enter lower elevation class bound'),
self.tr('Elevation'),
float(item.text(0)),
decimals=2)
if ok:
item.setText(0, str(d))
elif column == 1:
d, ok = QInputDialog.getDouble(None,
self.tr('Enter upper elevation class bound'),
self.tr('Elevation'),
float(item.text(1)),
decimals=2)
if ok:
item.setText(1, str(d))
elif column == 2:
c = QColorDialog.getColor(item.background(2).color(),
None,
self.tr('Select color for relief class'))
if c.isValid():
item.setBackground(2, QBrush(c))
def reliefColors(self):
colors = []
for i in range(self.bandClassTree.topLevelItemCount()):
item = self.bandClassTree.topLevelItem(i)
if item:
c = QgsRelief.ReliefColor(item.background(2).color(),
float(item.text(0)),
float(item.text(1)))
colors.append(c)
return colors
def populateColors(self, colors):
self.bandClassTree.clear()
for c in colors:
item = QTreeWidgetItem()
item.setText(0, str(c.minElevation))
item.setText(1, str(c.maxElevation))
item.setBackground(2, QBrush(c.color))
self.bandClassTree.addTopLevelItem(item)
def setLayer(self, layer):
self.layer = layer
def setValue(self, value):
self.bandClassTree.clear()
rows = value.split(';')
for r in rows:
v = r.split(',')
item = QTreeWidgetItem()
item.setText(0, v[0])
item.setText(1, v[1])
color = QColor(int(v[2]), int(v[3]), int(v[4]))
item.setBackground(2, QBrush(color))
self.bandClassTree.addTopLevelItem(item)
def value(self):
rColors = self.reliefColors()
colors = ''
for c in rColors:
colors += '{:f}, {:f}, {:d}, {:d}, {:d};'.format(c.minElevation,
c.maxElevation,
c.color.red(),
c.color.green(),
c.color.blue())
return colors[:-1]
class BandTableWidgetWrapper(WidgetWrapper):
def createWidget(self):
return BandTableWidget()
def postInitialize(self, wrappers):
for wrapper in wrappers:
if wrapper.param.name == self.param.parent:
self.setLayer(wrapper.value())
wrapper.widgetValueHasChanged.connect(self.parentValueChanged)
break
def parentValueChanged(self, wrapper):
self.setLayer(wrapper.parameterValue())
def setLayer(self, layer):
if isinstance(layer, QgsMapLayer):
layer = layer.source()
self.widget.setLayer(layer)
def setValue(self, value):
self.widget.setValue(value)
def value(self):
return self.widget.value()
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>505</width>
<height>209</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTreeWidget" name="bandClassTree">
<column>
<property name="text">
<string>Lower bound</string>
</property>
</column>
<column>
<property name="text">
<string>Upper bound</string>
</property>
</column>
<column>
<property name="text">
<string>Color</string>
</property>
</column>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QToolButton" name="btnAdd">
<property name="toolTip">
<string>Add row</string>
</property>
<property name="text">
<string></string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnRemove">
<property name="toolTip">
<string>Remove row</string>
</property>
<property name="text">
<string></string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnUp">
<property name="toolTip">
<string>Move up</string>
</property>
<property name="text">
<string></string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnDown">
<property name="toolTip">
<string>Move down</string>
</property>
<property name="text">
<string></string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="btnLoad">
<property name="toolTip">
<string>Load colors from file</string>
</property>
<property name="text">
<string></string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnSave">
<property name="toolTip">
<string>Save colors to file</string>
</property>
<property name="text">
<string></string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnAuto">
<property name="toolTip">
<string>Generate color table automatically</string>
</property>
<property name="text">
<string></string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
......@@ -31,13 +31,85 @@ __copyright__ = '(C) 2021 by J. Pierson, UMR 6554 LETG, CNRS'
__revision__ = '$Format:%H$'
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtGui import QIcon, QColor
from qgis.core import (QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterMatrix,
QgsProcessingParameterDefinition,
QgsProcessingParameterString,
QgsProcessingParameterRasterDestination)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.gui.wrappers import WidgetWrapper
#import BandTableWidget
from qgis.PyQt.QtWidgets import QTableWidget
from osgeo import gdal
# custom table widget
class ParameterBandTable(QgsProcessingParameterDefinition):
def __init__(self, name='', description='', parent=None, optional=True):
super().__init__(name, description, None, optional)
self.parent = parent
self.setMetadata({'widget_wrapper': 'BandTableWidget.BandTableWidgetWrapper'})
def type(self):
return 'band table'
def clone(self):
return ParameterBandTable(self.name(), self.description(), self.parent,
self.flags() & QgsProcessingParameterDefinition.FlagOptional)
@staticmethod
def valueToColors(value):
if value is None:
return None
if value == '':
return None
if isinstance(value, str):
return value.split(';')
else:
return ParameterBandTable.colorsToString(value)
@staticmethod
def colorsToString(colors):
s = ''
for c in colors:
s += '{:f}, {:f}, {:d}, {:d}, {:d};'.format(c[0],
c[1],
c[2],
c[3],
c[4])
return s[:-1]
class TableWidget(WidgetWrapper):
"""
QTable widget
"""
def createWidget(self):
self._combo = QTableWidget()
# row count
self._combo.setRowCount(1)
# column count
self._combo.setColumnCount(2)
# column headers
self._combo.setHorizontalHeaderLabels(["Name", "Future name"])
return self._combo
def value(self):
# retrieve table values [["name 1", "future name 1"], ["name 2", "future name 2"], ...]
table = []
nrow = self._combo.rowCount()
#ncol = self._combo.columnCount()
for i in range(nrow):
table.append([self._combo.cellWidget(i, 0), self._combo.cellWidget(i, 1)])
return table
class MergeAndRenameAlgorithm(QgsProcessingAlgorithm):
"""
......@@ -51,6 +123,8 @@ class MergeAndRenameAlgorithm(QgsProcessingAlgorithm):
INPUT = 'INPUT'
TABLE = 'TABLE'
TABLEWIDGET = 'TABLEWIDGET'
BANDTABLEWIDGET = 'BANDTABLEWIDGET'
OUTPUT = 'OUTPUT'
def initAlgorithm(self, config):
......@@ -79,6 +153,19 @@ class MergeAndRenameAlgorithm(QgsProcessingAlgorithm):
defaultValue=[None,None]
)
)
# custom parameter
param = QgsProcessingParameterString(self.TABLEWIDGET, 'Band table')
param.setMetadata({
'widget_wrapper': {
'class': TableWidget}})
self.addParameter(param)
# custom parameter : band table widget
self.addParameter(ParameterBandTable(self.BANDTABLEWIDGET,
self.tr('Band table'),
self.INPUT,
True))
# output raster layer
self.addParameter(
......@@ -89,7 +176,6 @@ class MergeAndRenameAlgorithm(QgsProcessingAlgorithm):
)
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
......@@ -98,6 +184,7 @@ class MergeAndRenameAlgorithm(QgsProcessingAlgorithm):
# RETRIEVE INPUTS AND OUTPUT
input_raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)
band_table = self.parameterAsMatrix(parameters, self.TABLE, context)
mytable = self.parameterAsString(parameters, self.TABLEWIDGET, context)
output_raster_path = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
# GETTING USEFUL PAREMETERS
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment