Skip to content
Permalink
Browse files

Fix transparency widget syncToLayer causes corruption of widget values

Fixes a small bug in the QgsTransparencyWidget which changed a QgsRasterLayers' no-data-values just by the order of calling .syncToLayer or .apply, even withouht changing the no-data value explicitly
  • Loading branch information
jakimowb committed Mar 17, 2020
1 parent b2af13b commit 1b2ae9db91aed51dd24d09d2ed1eefc9d900b1b1
@@ -120,11 +120,11 @@ void QgsRasterTransparencyWidget::syncToLayer()
QgsDebugMsg( QStringLiteral( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ) );
if ( !noDataRangeList.isEmpty() )
{
leNoDataValue->insert( QgsRasterBlock::printValue( noDataRangeList.value( 0 ).min() ) );
leNoDataValue->setText( QgsRasterBlock::printValue( noDataRangeList.value( 0 ).min() ) );
}
else
{
leNoDataValue->insert( QString() );
leNoDataValue->setText( QString() );
}

populateTransparencyTable( mRasterLayer->renderer() );
@@ -201,6 +201,7 @@ ADD_PYTHON_TEST(PyQgsRasterLayer test_qgsrasterlayer.py)
ADD_PYTHON_TEST(PyQgsRasterColorRampShader test_qgsrastercolorrampshader.py)
ADD_PYTHON_TEST(PyQgsRasterRange test_qgsrasterrange.py)
ADD_PYTHON_TEST(PyQgsRasterResampler test_qgsrasterresampler.py)
ADD_PYTHON_TEST(PyQgsRasterTransparencyWidget test_qgsrastertransparencywidget.py)
ADD_PYTHON_TEST(PyQgsRatioLockButton test_qgsratiolockbutton.py)
ADD_PYTHON_TEST(PyQgsRectangle test_qgsrectangle.py)
ADD_PYTHON_TEST(PyQgsReferencedGeometry test_qgsreferencedgeometry.py)
@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsRasterRange.
.. note:: 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__ = 'Nyall Dawson'
__date__ = '07/06/2018'
__copyright__ = 'Copyright 2018, The QGIS Project'

import qgis # NOQA switch sip api

import pathlib
from qgis.gui import QgsRasterTransparencyWidget, QgsMapCanvas
from qgis.core import QgsRasterLayer, QgsRasterRange

from qgis.testing import TestCase, unittest
from qgis.testing.mocked import get_iface

from utilities import unitTestDataPath


class TestQgsRasterTransparencyWidget(TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.iface = get_iface()

@staticmethod
def no_data_values(layer: QgsRasterLayer):
return [n.min() for n in layer.dataProvider().userNoDataValues(1)]

def test_transparency_widget(self):
path = pathlib.Path(unitTestDataPath()) / 'landsat_4326.tif'
self.assertTrue(path.is_file())
layer = QgsRasterLayer(path.as_posix())
self.assertTrue(layer.isValid())
canvas = QgsMapCanvas()
canvas.setLayers([layer])

no_data_value = -99
nd_ref = [no_data_value]
layer.dataProvider().setUserNoDataValue(1, [QgsRasterRange(no_data_value, no_data_value)])
nd0 = self.no_data_values(layer)
self.assertListEqual(nd0, nd_ref)

w = QgsRasterTransparencyWidget(layer, canvas)
self.assertIsInstance(w, QgsRasterTransparencyWidget)
nd1 = self.no_data_values(layer)
self.assertListEqual(nd1, nd_ref, msg='Widget initialization should not change the "no data value"')

w.syncToLayer()
nd2 = self.no_data_values(layer)
self.assertListEqual(nd2, nd_ref, msg='syncToLayer changed the "no data value"')

w.syncToLayer()
nd3 = self.no_data_values(layer)
self.assertListEqual(nd3, nd_ref, msg='repeated syncToLayer changed the "no data value"')

w.apply()
nd4 = self.no_data_values(layer)
self.assertListEqual(nd4, nd_ref, msg='apply changed the "no data value" but should not')

w.apply()
nd5 = self.no_data_values(layer)
self.assertListEqual(nd5, nd_ref, msg='repeated apply changed the "no data value" but should not')


if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,69 @@
import pathlib
from qgis.testing import start_app, unittest, TestCase
from qgis.testing.mocked import get_iface
from qgis.core import QgsRasterLayer, QgsProject, QgsMultiBandColorRenderer, QgsRasterRenderer, QgsSingleBandGrayRenderer
from qgis.gui import QgsRendererRasterPropertiesWidget, QgsMapCanvas, QgsMultiBandColorRendererWidget, QgsRasterRendererWidget


class QgsRendererRasterPropertiesTestCases(TestCase):

def setUp(self):
self.iface = get_iface()

def multibandRasterLayer(self) -> QgsRasterLayer:

try:
from utilities import unitTestDataPath
path = pathlib.Path(unitTestDataPath()) / 'landsat_4326.tif'
except ModuleNotFoundError:
path = pathlib.Path(__file__).parent / 'landsat_4326.tif'

assert isinstance(path, pathlib.Path) and path.is_file()
lyr = QgsRasterLayer(path.as_posix())
lyr.setName(path.name)
self.assertIsInstance(lyr, QgsRasterLayer)
self.assertTrue(lyr.isValid())
self.assertTrue(lyr.bandCount() > 1)

return lyr

def test_syncToLayer_SingleBandGray(self):

lyr = self.multibandRasterLayer()
lyr.setRenderer(QgsSingleBandGrayRenderer(lyr.dataProvider(), 1))
c = QgsMapCanvas()
w = QgsRendererRasterPropertiesWidget(lyr, c)
assert isinstance(w.currentRenderWidget().renderer(), QgsSingleBandGrayRenderer)
assert w.currentRenderWidget().renderer().grayBand() == 1
lyr.renderer().setGrayBand(2)
w.syncToLayer(lyr)
assert w.currentRenderWidget().renderer().grayBand() == 2

def test_syncToLayer_MultiBand(self):

lyr = self.multibandRasterLayer()
assert isinstance(lyr.renderer(), QgsMultiBandColorRenderer)
lyr.renderer().setRedBand(1)
lyr.renderer().setGreenBand(2)
lyr.renderer().setBlueBand(3)

c = QgsMapCanvas()
w = QgsRendererRasterPropertiesWidget(lyr, c)
assert isinstance(w.currentRenderWidget().renderer(), QgsMultiBandColorRenderer)
r = w.currentRenderWidget().renderer()
assert isinstance(r, QgsMultiBandColorRenderer)
assert r.usesBands() == [1, 2, 3]

lyr.renderer().setRedBand(3)
lyr.renderer().setGreenBand(1)
lyr.renderer().setBlueBand(2)

w.syncToLayer(lyr)

r = w.currentRenderWidget().renderer()
assert isinstance(r, QgsMultiBandColorRenderer)
assert r.usesBands() == [3, 1, 2]


if __name__ == '__main__':
unittest.main()
@@ -140,22 +140,22 @@ def compareWkt(a, b, tol=0.000001):
b0 = b.lower()

# remove optional spaces before z/m
r = re.compile("\s+([zm])")
r = re.compile(r"\s+([zm])")
a0 = r.sub(r'\1', a0)
b0 = r.sub(r'\1', b0)

# spaces before brackets are optional
r = re.compile("\s*\(\s*")
r = re.compile(r"\s*\(\s*")
a0 = r.sub('(', a0)
b0 = r.sub('(', b0)
# spaces after brackets are optional
r = re.compile("\s*\)\s*")
r = re.compile(r"\s*\)\s*")
a0 = r.sub(')', a0)
b0 = r.sub(')', b0)

# compare the structure
r0 = re.compile("-?\d+(?:\.\d+)?(?:[eE]\d+)?")
r1 = re.compile("\s*,\s*")
r0 = re.compile(r"-?\d+(?:\.\d+)?(?:[eE]\d+)?")
r1 = re.compile(r"\s*,\s*")
a0 = r1.sub(",", r0.sub("#", a0))
b0 = r1.sub(",", r0.sub("#", b0))
if a0 != b0:

0 comments on commit 1b2ae9d

Please sign in to comment.
You can’t perform that action at this time.