diff --git a/python/plugins/processing/gui/NumberInputPanel.py b/python/plugins/processing/gui/NumberInputPanel.py index 156c8d4c9c8..bf4e65356af 100755 --- a/python/plugins/processing/gui/NumberInputPanel.py +++ b/python/plugins/processing/gui/NumberInputPanel.py @@ -32,7 +32,7 @@ import warnings from qgis.PyQt import uic from qgis.PyQt.QtCore import pyqtSignal, QSize -from qgis.PyQt.QtWidgets import QDialog, QLabel +from qgis.PyQt.QtWidgets import QDialog, QLabel, QComboBox from qgis.core import (QgsApplication, QgsExpression, @@ -268,10 +268,21 @@ class DistanceInputPanel(NumberInputPanel): super().__init__(param) self.label = QLabel('') + + self.units_combo = QComboBox() + self.base_units = QgsUnitTypes.DistanceUnknownUnit + for u in (QgsUnitTypes.DistanceMeters, + QgsUnitTypes.DistanceKilometers, + QgsUnitTypes.DistanceFeet, + QgsUnitTypes.DistanceMiles, + QgsUnitTypes.DistanceYards): + self.units_combo.addItem(QgsUnitTypes.toString(u), u) + label_margin = self.fontMetrics().width('X') self.layout().insertSpacing(1, label_margin / 2) self.layout().insertWidget(2, self.label) - self.layout().insertSpacing(3, label_margin / 2) + self.layout().insertWidget(3, self.units_combo) + self.layout().insertSpacing(4, label_margin / 2) self.warning_label = QLabel() icon = QgsApplication.getThemeIcon('mIconWarning.svg') size = max(24, self.spnValue.height() * 0.5) @@ -279,11 +290,20 @@ class DistanceInputPanel(NumberInputPanel): self.warning_label.setToolTip(self.tr('Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results.')) self.layout().insertWidget(4, self.warning_label) self.layout().insertSpacing(5, label_margin) + self.setUnits(QgsUnitTypes.DistanceUnknownUnit) def setUnits(self, units): self.label.setText(QgsUnitTypes.toString(units)) + if QgsUnitTypes.unitType(units) != QgsUnitTypes.Standard: + self.units_combo.hide() + self.label.show() + else: + self.units_combo.setCurrentIndex(self.units_combo.findData(units)) + self.units_combo.show() + self.label.hide() self.warning_label.setVisible(units == QgsUnitTypes.DistanceDegrees) + self.base_units = units def setUnitParameterValue(self, value): units = QgsUnitTypes.DistanceUnknownUnit @@ -297,3 +317,17 @@ class DistanceInputPanel(NumberInputPanel): if crs.isValid(): units = crs.mapUnits() self.setUnits(units) + + def getValue(self): + val = super().getValue() + if isinstance(val, float) and self.units_combo.isVisible(): + display_unit = self.units_combo.currentData() + return val * QgsUnitTypes.fromUnitToUnitFactor(display_unit, self.base_units) + + return val + + def setValue(self, value): + try: + self.spnValue.setValue(float(value)) + except: + return diff --git a/python/plugins/processing/tests/GuiTest.py b/python/plugins/processing/tests/GuiTest.py index 833466a2e3a..63f9d49fa93 100644 --- a/python/plugins/processing/tests/GuiTest.py +++ b/python/plugins/processing/tests/GuiTest.py @@ -176,35 +176,72 @@ class WrappersTest(unittest.TestCase): widget.setUnitParameterValue('EPSG:3111') self.assertEqual(widget.label.text(), 'meters') self.assertFalse(widget.warning_label.isVisible()) + self.assertTrue(widget.units_combo.isVisible()) + self.assertFalse(widget.label.isVisible()) + self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceMeters) + widget.setUnitParameterValue('EPSG:4326') self.assertEqual(widget.label.text(), 'degrees') self.assertTrue(widget.warning_label.isVisible()) + self.assertFalse(widget.units_combo.isVisible()) + self.assertTrue(widget.label.isVisible()) + widget.setUnitParameterValue(QgsCoordinateReferenceSystem('EPSG:3111')) self.assertEqual(widget.label.text(), 'meters') self.assertFalse(widget.warning_label.isVisible()) + self.assertTrue(widget.units_combo.isVisible()) + self.assertFalse(widget.label.isVisible()) + self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceMeters) + widget.setUnitParameterValue(QgsCoordinateReferenceSystem('EPSG:4326')) self.assertEqual(widget.label.text(), 'degrees') self.assertTrue(widget.warning_label.isVisible()) + self.assertFalse(widget.units_combo.isVisible()) + self.assertTrue(widget.label.isVisible()) # layer values vl = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory") widget.setUnitParameterValue(vl) self.assertEqual(widget.label.text(), 'meters') self.assertFalse(widget.warning_label.isVisible()) + self.assertTrue(widget.units_combo.isVisible()) + self.assertFalse(widget.label.isVisible()) + self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceMeters) + vl2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=pk:int", "vl", "memory") widget.setUnitParameterValue(vl2) self.assertEqual(widget.label.text(), 'degrees') self.assertTrue(widget.warning_label.isVisible()) + self.assertFalse(widget.units_combo.isVisible()) + self.assertTrue(widget.label.isVisible()) # unresolvable values widget.setUnitParameterValue(vl.id()) self.assertEqual(widget.label.text(), '') self.assertFalse(widget.warning_label.isVisible()) + self.assertFalse(widget.units_combo.isVisible()) + self.assertTrue(widget.label.isVisible()) + # resolvable text value QgsProject.instance().addMapLayer(vl) widget.setUnitParameterValue(vl.id()) self.assertEqual(widget.label.text(), 'meters') self.assertFalse(widget.warning_label.isVisible()) + self.assertTrue(widget.units_combo.isVisible()) + self.assertFalse(widget.label.isVisible()) + self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceMeters) + + widget.setValue(5) + self.assertEqual(widget.getValue(), 5) + widget.units_combo.setCurrentIndex(widget.units_combo.findData(QgsUnitTypes.DistanceKilometers)) + self.assertEqual(widget.getValue(), 5000) + widget.setValue(2) + self.assertEqual(widget.getValue(), 2000) + + widget.setUnitParameterValue(vl.id()) + self.assertEqual(widget.getValue(), 2) + widget.setValue(5) + self.assertEqual(widget.getValue(), 5) widget.deleteLater()