1# -*- coding: utf-8 -*- 2 3""" 4*************************************************************************** 5 ReliefColorsWidget.py 6 --------------------- 7 Date : December 2016 8 Copyright : (C) 2016 by Alexander Bruy 9 Email : alexander dot bruy at gmail dot com 10*************************************************************************** 11* * 12* This program is free software; you can redistribute it and/or modify * 13* it under the terms of the GNU General Public License as published by * 14* the Free Software Foundation; either version 2 of the License, or * 15* (at your option) any later version. * 16* * 17*************************************************************************** 18""" 19 20__author__ = 'Alexander Bruy' 21__date__ = 'December 2016' 22__copyright__ = '(C) 2016, Alexander Bruy' 23 24import os 25import codecs 26 27from qgis.PyQt import uic 28from qgis.PyQt.QtCore import pyqtSlot, QDir 29from qgis.PyQt.QtGui import QColor, QBrush 30from qgis.PyQt.QtWidgets import (QTreeWidgetItem, 31 QFileDialog, 32 QMessageBox, 33 QInputDialog, 34 QColorDialog 35 ) 36from qgis.PyQt.QtXml import QDomDocument 37 38from qgis.core import QgsApplication, QgsMapLayer 39from qgis.analysis import QgsRelief 40 41from processing.gui.wrappers import WidgetWrapper 42from processing.tools import system 43 44pluginPath = os.path.dirname(__file__) 45WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'reliefcolorswidgetbase.ui')) 46 47 48class ReliefColorsWidget(BASE, WIDGET): 49 50 def __init__(self): 51 super(ReliefColorsWidget, self).__init__(None) 52 self.setupUi(self) 53 54 self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg')) 55 self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg')) 56 self.btnUp.setIcon(QgsApplication.getThemeIcon('/mActionArrowUp.svg')) 57 self.btnDown.setIcon(QgsApplication.getThemeIcon('/mActionArrowDown.svg')) 58 self.btnLoad.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg')) 59 self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg')) 60 self.btnAuto.setIcon(QgsApplication.getThemeIcon('/mActionReload.svg')) 61 62 self.layer = None 63 64 @pyqtSlot() 65 def on_btnAdd_clicked(self): 66 item = QTreeWidgetItem() 67 item.setText(0, '0.00') 68 item.setText(1, '0.00') 69 item.setBackground(2, QBrush(QColor(127, 127, 127))) 70 self.reliefClassTree.addTopLevelItem(item) 71 72 @pyqtSlot() 73 def on_btnRemove_clicked(self): 74 selectedItems = self.reliefClassTree.selectedItems() 75 for item in selectedItems: 76 self.reliefClassTree.invisibleRootItem().removeChild(item) 77 item = None 78 79 @pyqtSlot() 80 def on_btnDown_clicked(self): 81 selectedItems = self.reliefClassTree.selectedItems() 82 for item in selectedItems: 83 currentIndex = self.reliefClassTree.indexOfTopLevelItem(item) 84 if currentIndex < self.reliefClassTree.topLevelItemCount() - 1: 85 self.reliefClassTree.takeTopLevelItem(currentIndex) 86 self.reliefClassTree.insertTopLevelItem(currentIndex + 1, item) 87 self.reliefClassTree.setCurrentItem(item) 88 89 @pyqtSlot() 90 def on_btnUp_clicked(self): 91 selectedItems = self.reliefClassTree.selectedItems() 92 for item in selectedItems: 93 currentIndex = self.reliefClassTree.indexOfTopLevelItem(item) 94 if currentIndex > 0: 95 self.reliefClassTree.takeTopLevelItem(currentIndex) 96 self.reliefClassTree.insertTopLevelItem(currentIndex - 1, item) 97 self.reliefClassTree.setCurrentItem(item) 98 99 @pyqtSlot() 100 def on_btnLoad_clicked(self): 101 fileName, _ = QFileDialog.getOpenFileName(None, 102 self.tr('Import Colors and elevations from XML'), 103 QDir.homePath(), 104 self.tr('XML files (*.xml *.XML)')) 105 if fileName == '': 106 return 107 108 doc = QDomDocument() 109 with codecs.open(fileName, 'r', encoding='utf-8') as f: 110 content = f.read() 111 112 if not doc.setContent(content): 113 QMessageBox.critical(None, 114 self.tr('Error parsing XML'), 115 self.tr('The XML file could not be loaded')) 116 return 117 118 self.reliefClassTree.clear() 119 reliefColorList = doc.elementsByTagName('ReliefColor') 120 for i in range(reliefColorList.length()): 121 elem = reliefColorList.at(i).toElement() 122 item = QTreeWidgetItem() 123 item.setText(0, elem.attribute('MinElevation')) 124 item.setText(1, elem.attribute('MaxElevation')) 125 item.setBackground(2, QBrush(QColor(int(elem.attribute('red')), 126 int(elem.attribute('green')), 127 int(elem.attribute('blue'))))) 128 self.reliefClassTree.addTopLevelItem(item) 129 130 @pyqtSlot() 131 def on_btnSave_clicked(self): 132 fileName, _ = QFileDialog.getSaveFileName(None, 133 self.tr('Export Colors and elevations as XML'), 134 QDir.homePath(), 135 self.tr('XML files (*.xml *.XML)')) 136 137 if fileName == '': 138 return 139 140 if not fileName.lower().endswith('.xml'): 141 fileName += '.xml' 142 143 doc = QDomDocument() 144 colorsElem = doc.createElement('ReliefColors') 145 doc.appendChild(colorsElem) 146 147 colors = self.reliefColors() 148 for c in colors: 149 elem = doc.createElement('ReliefColor') 150 elem.setAttribute('MinElevation', str(c.minElevation)) 151 elem.setAttribute('MaxElevation', str(c.maxElevation)) 152 elem.setAttribute('red', str(c.color.red())) 153 elem.setAttribute('green', str(c.color.green())) 154 elem.setAttribute('blue', str(c.color.blue())) 155 colorsElem.appendChild(elem) 156 157 with codecs.open(fileName, 'w', encoding='utf-8') as f: 158 f.write(doc.toString(2)) 159 160 @pyqtSlot() 161 def on_btnAuto_clicked(self): 162 if self.layer is None: 163 return 164 165 relief = QgsRelief(self.layer, system.getTempFilename(), 'GTiff') 166 colors = relief.calculateOptimizedReliefClasses() 167 self.populateColors(colors) 168 169 @pyqtSlot(QTreeWidgetItem, int) 170 def on_reliefClassTree_itemDoubleClicked(self, item, column): 171 if not item: 172 return 173 174 if column == 0: 175 d, ok = QInputDialog.getDouble(None, 176 self.tr('Enter lower elevation class bound'), 177 self.tr('Elevation'), 178 float(item.text(0)), 179 decimals=2) 180 if ok: 181 item.setText(0, str(d)) 182 elif column == 1: 183 d, ok = QInputDialog.getDouble(None, 184 self.tr('Enter upper elevation class bound'), 185 self.tr('Elevation'), 186 float(item.text(1)), 187 decimals=2) 188 if ok: 189 item.setText(1, str(d)) 190 elif column == 2: 191 c = QColorDialog.getColor(item.background(2).color(), 192 None, 193 self.tr('Select color for relief class')) 194 if c.isValid(): 195 item.setBackground(2, QBrush(c)) 196 197 def reliefColors(self): 198 colors = [] 199 for i in range(self.reliefClassTree.topLevelItemCount()): 200 item = self.reliefClassTree.topLevelItem(i) 201 if item: 202 c = QgsRelief.ReliefColor(item.background(2).color(), 203 float(item.text(0)), 204 float(item.text(1))) 205 colors.append(c) 206 return colors 207 208 def populateColors(self, colors): 209 self.reliefClassTree.clear() 210 for c in colors: 211 item = QTreeWidgetItem() 212 item.setText(0, str(c.minElevation)) 213 item.setText(1, str(c.maxElevation)) 214 item.setBackground(2, QBrush(c.color)) 215 self.reliefClassTree.addTopLevelItem(item) 216 217 def setLayer(self, layer): 218 self.layer = layer 219 220 def setValue(self, value): 221 self.reliefClassTree.clear() 222 rows = value.split(';') 223 for r in rows: 224 v = r.split(',') 225 item = QTreeWidgetItem() 226 item.setText(0, v[0]) 227 item.setText(1, v[1]) 228 color = QColor(int(v[2]), int(v[3]), int(v[4])) 229 item.setBackground(2, QBrush(color)) 230 self.reliefClassTree.addTopLevelItem(item) 231 232 def value(self): 233 rColors = self.reliefColors() 234 colors = '' 235 for c in rColors: 236 colors += '{:f}, {:f}, {:d}, {:d}, {:d};'.format(c.minElevation, 237 c.maxElevation, 238 c.color.red(), 239 c.color.green(), 240 c.color.blue()) 241 return colors[:-1] 242 243 244class ReliefColorsWidgetWrapper(WidgetWrapper): 245 246 def createWidget(self): 247 return ReliefColorsWidget() 248 249 def postInitialize(self, wrappers): 250 for wrapper in wrappers: 251 if wrapper.param.name == self.param.parent: 252 self.setLayer(wrapper.value()) 253 wrapper.widgetValueHasChanged.connect(self.parentValueChanged) 254 break 255 256 def parentValueChanged(self, wrapper): 257 self.setLayer(wrapper.parameterValue()) 258 259 def setLayer(self, layer): 260 if isinstance(layer, QgsMapLayer): 261 layer = layer.source() 262 self.widget.setLayer(layer) 263 264 def setValue(self, value): 265 self.widget.setValue(value) 266 267 def value(self): 268 return self.widget.value() 269