Add unit tests for QgsFilterLineEdit, improve docs, add clearValue slot

This commit is contained in:
Nyall Dawson 2016-09-08 07:56:29 +10:00
parent 0f5f09401e
commit edcc247c3e
5 changed files with 209 additions and 25 deletions

View File

@ -1,46 +1,84 @@
/** LineEdit with builtin clear button
*/
/** \class QgsFilterLineEdit
* \ingroup gui
* QLineEdit subclass with built in support for clearing the widget's value and
* handling custom null value representations.
*
* When using QgsFilterLineEdit the value(), setValue() and clearValue() methods should be used
* instead of QLineEdit's text(), setText() and clear() methods, and the valueChanged()
* signal should be used instead of textChanged().
**/
class QgsFilterLineEdit : QLineEdit
{
%TypeHeaderCode
#include <qgsfilterlineedit.h>
%End
public:
/** Constructor for QgsFilterLineEdit.
* @param parent parent widget
* @param nullValue string for representing null values
*/
QgsFilterLineEdit( QWidget* parent /TransferThis/ = 0, const QString& nullValue = QString::null );
/** Sets the string representation for null values in the widget. This does not
* affect the values returned for null values by value(), rather it only affects
* the text that is shown to users when the widget's value is null.
* @param nullValue string to show when widget's value is null
* @see nullValue()
*/
void setNullValue( const QString& nullValue );
/** Returns the string used for representating null values in the widget.
* @see setNullValue()
* @see isNull()
*/
QString nullValue() const;
/**
* Sets the current text with NULL support
* Sets the current text for the widget with support for handling null values.
*
* @param value The text to set. If a Null string is provided, the text will match the nullValue.
* @param value The text to set. If a null string is provided, the text shown in the
* widget will be set to the current nullValue().
* @see value()
*/
void setValue( const QString& value );
/**
* Returns the text of this edit with NULL support
* Returns the text of this edit with support for handling null values. If the text
* in the widget matches the current nullValue() then the returned value will be
* a null string.
*
* @return Current text (Null string if it matches the nullValue property )
* @return Current text (or null string if it matches the nullValue() property )
* @see setValue()
*/
QString value() const;
/**
* Determine if the current text represents Null.
* Determine if the current text represents null.
*
* @return True if the value is Null.
* @return True if the widget's value is null.
* @see nullValue()
*/
bool isNull() const;
public slots:
/** Clears the widget and resets it to the null value.
* @see nullValue()
*/
virtual void clearValue();
signals:
/** Emitted when the widget is cleared
* @see clearValue()
*/
void cleared();
/**
* Same as textChanged(const QString& ) but with support for Null values.
* Same as textChanged() but with support for null values.
*
* @param value The current text or Null string if it matches the nullValue property.
* @param value The current text or null string if it matches the nullValue() property.
*/
void valueChanged( const QString& value );

View File

@ -51,8 +51,7 @@ void QgsFilterLineEdit::mousePressEvent( QMouseEvent* e )
if ( shouldShowClear() && clearRect().contains( e->pos() ) )
{
clear();
emit cleared();
clearValue();
}
}
@ -86,10 +85,11 @@ void QgsFilterLineEdit::focusInEvent( QFocusEvent* e )
}
}
void QgsFilterLineEdit::clear()
void QgsFilterLineEdit::clearValue()
{
setText( mNullValue );
setModified( true );
emit cleared();
}
void QgsFilterLineEdit::paintEvent( QPaintEvent* e )

View File

@ -22,49 +22,88 @@
class QToolButton;
/** \ingroup gui
* Lineedit with builtin clear button
/** \class QgsFilterLineEdit
* \ingroup gui
* QLineEdit subclass with built in support for clearing the widget's value and
* handling custom null value representations.
*
* When using QgsFilterLineEdit the value(), setValue() and clearValue() methods should be used
* instead of QLineEdit's text(), setText() and clear() methods, and the valueChanged()
* signal should be used instead of textChanged().
**/
class GUI_EXPORT QgsFilterLineEdit : public QLineEdit
{
Q_OBJECT
Q_PROPERTY( QString nullValue READ nullValue WRITE setNullValue )
Q_PROPERTY( QString value READ value WRITE setValue NOTIFY valueChanged )
public:
/** Constructor for QgsFilterLineEdit.
* @param parent parent widget
* @param nullValue string for representing null values
*/
QgsFilterLineEdit( QWidget* parent = nullptr, const QString& nullValue = QString::null );
/** Sets the string representation for null values in the widget. This does not
* affect the values returned for null values by value(), rather it only affects
* the text that is shown to users when the widget's value is null.
* @param nullValue string to show when widget's value is null
* @see nullValue()
*/
void setNullValue( const QString& nullValue ) { mNullValue = nullValue; }
/** Returns the string used for representating null values in the widget.
* @see setNullValue()
* @see isNull()
*/
QString nullValue() const { return mNullValue; }
/**
* Sets the current text with NULL support
* Sets the current text for the widget with support for handling null values.
*
* @param value The text to set. If a Null string is provided, the text will match the nullValue.
* @param value The text to set. If a null string is provided, the text shown in the
* widget will be set to the current nullValue().
* @see value()
*/
void setValue( const QString& value ) { setText( value.isNull() ? mNullValue : value ); }
/**
* Returns the text of this edit with NULL support
* Returns the text of this edit with support for handling null values. If the text
* in the widget matches the current nullValue() then the returned value will be
* a null string.
*
* @return Current text (Null string if it matches the nullValue property )
* @return Current text (or null string if it matches the nullValue() property )
* @see setValue()
*/
QString value() const { return isNull() ? QString::null : text(); }
/**
* Determine if the current text represents Null.
* Determine if the current text represents null.
*
* @return True if the value is Null.
* @return True if the widget's value is null.
* @see nullValue()
*/
inline bool isNull() const { return text() == mNullValue; }
public slots:
/** Clears the widget and resets it to the null value.
* @see nullValue()
*/
virtual void clearValue();
signals:
/** Emitted when the widget is cleared
* @see clearValue()
*/
void cleared();
/**
* Same as textChanged(const QString& ) but with support for Null values.
* Same as textChanged() but with support for null values.
*
* @param value The current text or Null string if it matches the nullValue property.
* @param value The current text or null string if it matches the nullValue() property.
*/
void valueChanged( const QString& value );
@ -76,7 +115,6 @@ class GUI_EXPORT QgsFilterLineEdit : public QLineEdit
void leaveEvent( QEvent* e ) override;
private slots:
void clear();
void onTextChanged( const QString &text );
private:

View File

@ -46,6 +46,7 @@ ADD_PYTHON_TEST(PyQgsFeature test_qgsfeature.py)
ADD_PYTHON_TEST(PyQgsProject test_qgsproject.py)
ADD_PYTHON_TEST(PyQgsFeatureIterator test_qgsfeatureiterator.py)
ADD_PYTHON_TEST(PyQgsField test_qgsfield.py)
ADD_PYTHON_TEST(PyQgsFilterLineEdit test_qgsfilterlineedit.py)
ADD_PYTHON_TEST(PyQgsFontUtils test_qgsfontutils.py)
ADD_PYTHON_TEST(PyQgsGeometryAvoidIntersections test_qgsgeometry_avoid_intersections.py)
ADD_PYTHON_TEST(PyQgsGeometryGeneratorSymbolLayer test_qgsgeometrygeneratorsymbollayer.py)

View File

@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsFilterLineEdit
.. 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__ = '20/08/2016'
__copyright__ = 'Copyright 2016, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
from qgis.gui import QgsFilterLineEdit
try:
from qgis.PyQt.QtTest import QSignalSpy
use_signal_spy = True
except:
use_signal_spy = False
from qgis.testing import start_app, unittest
start_app()
class TestQgsFilterLineEdit(unittest.TestCase):
def testGettersSetters(self):
""" test widget getters/setters """
w = qgis.gui.QgsFilterLineEdit()
w.setNullValue('null')
self.assertEqual(w.nullValue(), 'null')
w.setValue('value')
self.assertEqual(w.value(), 'value')
self.assertEqual(w.text(), 'value')
def testNullValueHandling(self):
""" test widget handling of null values """
w = qgis.gui.QgsFilterLineEdit()
# start with no null value
w.setValue(None)
self.assertTrue(w.isNull())
w.setValue('a')
self.assertEqual(w.text(), 'a')
self.assertFalse(w.isNull())
# set a null value
w.setNullValue('null')
self.assertEqual(w.value(), 'a')
self.assertEqual(w.text(), 'a')
self.assertFalse(w.isNull())
w.setValue(None)
self.assertTrue(w.isNull())
self.assertFalse(w.value())
self.assertEqual(w.text(), 'null')
w.setValue('null')
self.assertEqual(w.text(), 'null')
# ND: I don't think this following logic is correct - should be a distinction between
# the widget's representation of null and the actual value. Ie isNull()
# should be false and value() should return 'null'
# in other words - if you break this test to match my desired behaviour, feel free to remove it!
self.assertTrue(w.isNull())
self.assertFalse(w.value())
def testClear(self):
""" test clearing widget """
w = qgis.gui.QgsFilterLineEdit()
w.setValue('abc')
w.clearValue()
self.assertTrue(w.isNull())
self.assertFalse(w.value())
w.clearValue()
self.assertTrue(w.isNull())
self.assertFalse(w.value())
w.setNullValue('def')
w.setValue('abc')
self.assertFalse(w.isNull())
w.clearValue()
self.assertEqual(w.text(), 'def')
self.assertTrue(w.isNull())
self.assertFalse(w.value())
@unittest.skipIf(not use_signal_spy, "No QSignalSpy available")
def test_ChangedSignals(self):
""" test that signals are correctly emitted when clearing"""
w = qgis.gui.QgsFilterLineEdit()
cleared_spy = QSignalSpy(w.cleared)
w.setValue('1')
w.clearValue()
self.assertEqual(len(cleared_spy), 1)
if __name__ == '__main__':
unittest.main()