Skip to content

Commit edcc247

Browse files
committed
Add unit tests for QgsFilterLineEdit, improve docs, add clearValue slot
1 parent 0f5f094 commit edcc247

File tree

5 files changed

+209
-25
lines changed

5 files changed

+209
-25
lines changed

python/gui/qgsfilterlineedit.sip

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,84 @@
1-
2-
/** LineEdit with builtin clear button
3-
*/
1+
/** \class QgsFilterLineEdit
2+
* \ingroup gui
3+
* QLineEdit subclass with built in support for clearing the widget's value and
4+
* handling custom null value representations.
5+
*
6+
* When using QgsFilterLineEdit the value(), setValue() and clearValue() methods should be used
7+
* instead of QLineEdit's text(), setText() and clear() methods, and the valueChanged()
8+
* signal should be used instead of textChanged().
9+
**/
410
class QgsFilterLineEdit : QLineEdit
511
{
612
%TypeHeaderCode
713
#include <qgsfilterlineedit.h>
814
%End
915
public:
16+
17+
/** Constructor for QgsFilterLineEdit.
18+
* @param parent parent widget
19+
* @param nullValue string for representing null values
20+
*/
1021
QgsFilterLineEdit( QWidget* parent /TransferThis/ = 0, const QString& nullValue = QString::null );
1122

23+
/** Sets the string representation for null values in the widget. This does not
24+
* affect the values returned for null values by value(), rather it only affects
25+
* the text that is shown to users when the widget's value is null.
26+
* @param nullValue string to show when widget's value is null
27+
* @see nullValue()
28+
*/
1229
void setNullValue( const QString& nullValue );
1330

31+
/** Returns the string used for representating null values in the widget.
32+
* @see setNullValue()
33+
* @see isNull()
34+
*/
1435
QString nullValue() const;
1536

1637
/**
17-
* Sets the current text with NULL support
38+
* Sets the current text for the widget with support for handling null values.
1839
*
19-
* @param value The text to set. If a Null string is provided, the text will match the nullValue.
40+
* @param value The text to set. If a null string is provided, the text shown in the
41+
* widget will be set to the current nullValue().
42+
* @see value()
2043
*/
2144
void setValue( const QString& value );
2245

2346
/**
24-
* Returns the text of this edit with NULL support
47+
* Returns the text of this edit with support for handling null values. If the text
48+
* in the widget matches the current nullValue() then the returned value will be
49+
* a null string.
2550
*
26-
* @return Current text (Null string if it matches the nullValue property )
51+
* @return Current text (or null string if it matches the nullValue() property )
52+
* @see setValue()
2753
*/
2854
QString value() const;
2955

3056
/**
31-
* Determine if the current text represents Null.
57+
* Determine if the current text represents null.
3258
*
33-
* @return True if the value is Null.
59+
* @return True if the widget's value is null.
60+
* @see nullValue()
3461
*/
3562
bool isNull() const;
3663

64+
public slots:
65+
66+
/** Clears the widget and resets it to the null value.
67+
* @see nullValue()
68+
*/
69+
virtual void clearValue();
70+
3771
signals:
72+
73+
/** Emitted when the widget is cleared
74+
* @see clearValue()
75+
*/
3876
void cleared();
3977

4078
/**
41-
* Same as textChanged(const QString& ) but with support for Null values.
79+
* Same as textChanged() but with support for null values.
4280
*
43-
* @param value The current text or Null string if it matches the nullValue property.
81+
* @param value The current text or null string if it matches the nullValue() property.
4482
*/
4583
void valueChanged( const QString& value );
4684

src/gui/qgsfilterlineedit.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ void QgsFilterLineEdit::mousePressEvent( QMouseEvent* e )
5151

5252
if ( shouldShowClear() && clearRect().contains( e->pos() ) )
5353
{
54-
clear();
55-
emit cleared();
54+
clearValue();
5655
}
5756
}
5857

@@ -86,10 +85,11 @@ void QgsFilterLineEdit::focusInEvent( QFocusEvent* e )
8685
}
8786
}
8887

89-
void QgsFilterLineEdit::clear()
88+
void QgsFilterLineEdit::clearValue()
9089
{
9190
setText( mNullValue );
9291
setModified( true );
92+
emit cleared();
9393
}
9494

9595
void QgsFilterLineEdit::paintEvent( QPaintEvent* e )

src/gui/qgsfilterlineedit.h

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,49 +22,88 @@
2222

2323
class QToolButton;
2424

25-
/** \ingroup gui
26-
* Lineedit with builtin clear button
25+
/** \class QgsFilterLineEdit
26+
* \ingroup gui
27+
* QLineEdit subclass with built in support for clearing the widget's value and
28+
* handling custom null value representations.
29+
*
30+
* When using QgsFilterLineEdit the value(), setValue() and clearValue() methods should be used
31+
* instead of QLineEdit's text(), setText() and clear() methods, and the valueChanged()
32+
* signal should be used instead of textChanged().
2733
**/
2834
class GUI_EXPORT QgsFilterLineEdit : public QLineEdit
2935
{
3036
Q_OBJECT
3137
Q_PROPERTY( QString nullValue READ nullValue WRITE setNullValue )
38+
Q_PROPERTY( QString value READ value WRITE setValue NOTIFY valueChanged )
3239

3340
public:
41+
42+
/** Constructor for QgsFilterLineEdit.
43+
* @param parent parent widget
44+
* @param nullValue string for representing null values
45+
*/
3446
QgsFilterLineEdit( QWidget* parent = nullptr, const QString& nullValue = QString::null );
3547

48+
/** Sets the string representation for null values in the widget. This does not
49+
* affect the values returned for null values by value(), rather it only affects
50+
* the text that is shown to users when the widget's value is null.
51+
* @param nullValue string to show when widget's value is null
52+
* @see nullValue()
53+
*/
3654
void setNullValue( const QString& nullValue ) { mNullValue = nullValue; }
3755

56+
/** Returns the string used for representating null values in the widget.
57+
* @see setNullValue()
58+
* @see isNull()
59+
*/
3860
QString nullValue() const { return mNullValue; }
3961

4062
/**
41-
* Sets the current text with NULL support
63+
* Sets the current text for the widget with support for handling null values.
4264
*
43-
* @param value The text to set. If a Null string is provided, the text will match the nullValue.
65+
* @param value The text to set. If a null string is provided, the text shown in the
66+
* widget will be set to the current nullValue().
67+
* @see value()
4468
*/
4569
void setValue( const QString& value ) { setText( value.isNull() ? mNullValue : value ); }
4670

4771
/**
48-
* Returns the text of this edit with NULL support
72+
* Returns the text of this edit with support for handling null values. If the text
73+
* in the widget matches the current nullValue() then the returned value will be
74+
* a null string.
4975
*
50-
* @return Current text (Null string if it matches the nullValue property )
76+
* @return Current text (or null string if it matches the nullValue() property )
77+
* @see setValue()
5178
*/
5279
QString value() const { return isNull() ? QString::null : text(); }
5380

5481
/**
55-
* Determine if the current text represents Null.
82+
* Determine if the current text represents null.
5683
*
57-
* @return True if the value is Null.
84+
* @return True if the widget's value is null.
85+
* @see nullValue()
5886
*/
5987
inline bool isNull() const { return text() == mNullValue; }
6088

89+
public slots:
90+
91+
/** Clears the widget and resets it to the null value.
92+
* @see nullValue()
93+
*/
94+
virtual void clearValue();
95+
6196
signals:
97+
98+
/** Emitted when the widget is cleared
99+
* @see clearValue()
100+
*/
62101
void cleared();
63102

64103
/**
65-
* Same as textChanged(const QString& ) but with support for Null values.
104+
* Same as textChanged() but with support for null values.
66105
*
67-
* @param value The current text or Null string if it matches the nullValue property.
106+
* @param value The current text or null string if it matches the nullValue() property.
68107
*/
69108
void valueChanged( const QString& value );
70109

@@ -76,7 +115,6 @@ class GUI_EXPORT QgsFilterLineEdit : public QLineEdit
76115
void leaveEvent( QEvent* e ) override;
77116

78117
private slots:
79-
void clear();
80118
void onTextChanged( const QString &text );
81119

82120
private:

tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ ADD_PYTHON_TEST(PyQgsFeature test_qgsfeature.py)
4646
ADD_PYTHON_TEST(PyQgsProject test_qgsproject.py)
4747
ADD_PYTHON_TEST(PyQgsFeatureIterator test_qgsfeatureiterator.py)
4848
ADD_PYTHON_TEST(PyQgsField test_qgsfield.py)
49+
ADD_PYTHON_TEST(PyQgsFilterLineEdit test_qgsfilterlineedit.py)
4950
ADD_PYTHON_TEST(PyQgsFontUtils test_qgsfontutils.py)
5051
ADD_PYTHON_TEST(PyQgsGeometryAvoidIntersections test_qgsgeometry_avoid_intersections.py)
5152
ADD_PYTHON_TEST(PyQgsGeometryGeneratorSymbolLayer test_qgsgeometrygeneratorsymbollayer.py)
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# -*- coding: utf-8 -*-
2+
"""QGIS Unit tests for QgsFilterLineEdit
3+
4+
.. note:: This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
"""
9+
__author__ = 'Nyall Dawson'
10+
__date__ = '20/08/2016'
11+
__copyright__ = 'Copyright 2016, The QGIS Project'
12+
# This will get replaced with a git SHA1 when you do a git archive
13+
__revision__ = '$Format:%H$'
14+
15+
import qgis # NOQA
16+
17+
from qgis.gui import QgsFilterLineEdit
18+
19+
try:
20+
from qgis.PyQt.QtTest import QSignalSpy
21+
use_signal_spy = True
22+
except:
23+
use_signal_spy = False
24+
25+
from qgis.testing import start_app, unittest
26+
27+
start_app()
28+
29+
30+
class TestQgsFilterLineEdit(unittest.TestCase):
31+
32+
def testGettersSetters(self):
33+
""" test widget getters/setters """
34+
w = qgis.gui.QgsFilterLineEdit()
35+
36+
w.setNullValue('null')
37+
self.assertEqual(w.nullValue(), 'null')
38+
w.setValue('value')
39+
self.assertEqual(w.value(), 'value')
40+
self.assertEqual(w.text(), 'value')
41+
42+
def testNullValueHandling(self):
43+
""" test widget handling of null values """
44+
w = qgis.gui.QgsFilterLineEdit()
45+
46+
# start with no null value
47+
w.setValue(None)
48+
self.assertTrue(w.isNull())
49+
w.setValue('a')
50+
self.assertEqual(w.text(), 'a')
51+
self.assertFalse(w.isNull())
52+
53+
# set a null value
54+
w.setNullValue('null')
55+
self.assertEqual(w.value(), 'a')
56+
self.assertEqual(w.text(), 'a')
57+
self.assertFalse(w.isNull())
58+
59+
w.setValue(None)
60+
self.assertTrue(w.isNull())
61+
self.assertFalse(w.value())
62+
self.assertEqual(w.text(), 'null')
63+
64+
w.setValue('null')
65+
self.assertEqual(w.text(), 'null')
66+
# ND: I don't think this following logic is correct - should be a distinction between
67+
# the widget's representation of null and the actual value. Ie isNull()
68+
# should be false and value() should return 'null'
69+
# in other words - if you break this test to match my desired behaviour, feel free to remove it!
70+
self.assertTrue(w.isNull())
71+
self.assertFalse(w.value())
72+
73+
def testClear(self):
74+
""" test clearing widget """
75+
w = qgis.gui.QgsFilterLineEdit()
76+
77+
w.setValue('abc')
78+
w.clearValue()
79+
self.assertTrue(w.isNull())
80+
self.assertFalse(w.value())
81+
w.clearValue()
82+
self.assertTrue(w.isNull())
83+
self.assertFalse(w.value())
84+
85+
w.setNullValue('def')
86+
w.setValue('abc')
87+
self.assertFalse(w.isNull())
88+
w.clearValue()
89+
self.assertEqual(w.text(), 'def')
90+
self.assertTrue(w.isNull())
91+
self.assertFalse(w.value())
92+
93+
@unittest.skipIf(not use_signal_spy, "No QSignalSpy available")
94+
def test_ChangedSignals(self):
95+
""" test that signals are correctly emitted when clearing"""
96+
97+
w = qgis.gui.QgsFilterLineEdit()
98+
99+
cleared_spy = QSignalSpy(w.cleared)
100+
w.setValue('1')
101+
w.clearValue()
102+
103+
self.assertEqual(len(cleared_spy), 1)
104+
105+
106+
if __name__ == '__main__':
107+
unittest.main()

0 commit comments

Comments
 (0)