ReliefColorsWidget.py 11 KB

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