Skip to content

Commit

Permalink
Add Is Not Null and Is Not Between type search/filters
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed May 23, 2016
1 parent 383fc05 commit 1c4811f
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 11 deletions.
2 changes: 2 additions & 0 deletions python/gui/editorwidgets/core/qgssearchwidgetwrapper.sip
Expand Up @@ -77,6 +77,8 @@ class QgsSearchWidgetWrapper : QgsWidgetWrapper
Contains, /*!< Supports value "contains" searching */
DoesNotContain, /*!< Supports value does not contain searching */
IsNull, /*!< Supports searching for null values */
IsNotBetween, /*!< Supports searching for values outside of a set range */
IsNotNull, /*!< Supports searching for non-null values */
};
typedef QFlags<QgsSearchWidgetWrapper::FilterFlag> FilterFlags;

Expand Down
9 changes: 8 additions & 1 deletion src/gui/editorwidgets/core/qgssearchwidgetwrapper.cpp
Expand Up @@ -32,7 +32,9 @@ QList<QgsSearchWidgetWrapper::FilterFlag> QgsSearchWidgetWrapper::exclusiveFilte
<< Between
<< Contains
<< DoesNotContain
<< IsNull;
<< IsNull
<< IsNotBetween
<< IsNotNull;
}

QList<QgsSearchWidgetWrapper::FilterFlag> QgsSearchWidgetWrapper::nonExclusiveFilterFlags()
Expand Down Expand Up @@ -67,6 +69,11 @@ QString QgsSearchWidgetWrapper::toString( QgsSearchWidgetWrapper::FilterFlag fla
return QObject::tr( "Does not contain" );
case IsNull:
return QObject::tr( "Is missing (null)" );
case IsNotNull:
return QObject::tr( "Is not missing (null)" );
case IsNotBetween:
return QObject::tr( "Is not between (inclusive)" );

}
return QString();
}
Expand Down
2 changes: 2 additions & 0 deletions src/gui/editorwidgets/core/qgssearchwidgetwrapper.h
Expand Up @@ -57,6 +57,8 @@ class GUI_EXPORT QgsSearchWidgetWrapper : public QgsWidgetWrapper
Contains = 1 << 9, /*!< Supports value "contains" searching */
DoesNotContain = 1 << 10, /*!< Supports value does not contain searching */
IsNull = 1 << 11, /*!< Supports searching for null values */
IsNotBetween = 1 << 12, /*!< Supports searching for values outside of a set range */
IsNotNull = 1 << 13, /*!< Supports searching for non-null values */
};
Q_DECLARE_FLAGS( FilterFlags, FilterFlag )

Expand Down
5 changes: 4 additions & 1 deletion src/gui/editorwidgets/qgscheckboxsearchwidgetwrapper.cpp
Expand Up @@ -51,7 +51,7 @@ QVariant QgsCheckboxSearchWidgetWrapper::value() const

QgsSearchWidgetWrapper::FilterFlags QgsCheckboxSearchWidgetWrapper::supportedFlags() const
{
return EqualTo | IsNull;
return EqualTo | IsNull | IsNotNull;
}

QgsSearchWidgetWrapper::FilterFlags QgsCheckboxSearchWidgetWrapper::defaultFlags() const
Expand All @@ -69,6 +69,9 @@ QString QgsCheckboxSearchWidgetWrapper::createExpression( QgsSearchWidgetWrapper
if ( flags & IsNull )
return fieldName + " IS NULL";

if ( flags & IsNotNull )
return fieldName + " IS NOT NULL";

QVariant v = value();
if ( !v.isValid() )
return QString();
Expand Down
4 changes: 3 additions & 1 deletion src/gui/editorwidgets/qgsdatetimesearchwidgetwrapper.cpp
Expand Up @@ -51,7 +51,7 @@ QVariant QgsDateTimeSearchWidgetWrapper::value() const

QgsSearchWidgetWrapper::FilterFlags QgsDateTimeSearchWidgetWrapper::supportedFlags() const
{
return EqualTo | NotEqualTo | GreaterThan | LessThan | GreaterThanOrEqualTo | LessThanOrEqualTo | IsNull | Between;
return EqualTo | NotEqualTo | GreaterThan | LessThan | GreaterThanOrEqualTo | LessThanOrEqualTo | IsNull | Between | IsNotNull | IsNotBetween;
}

QgsSearchWidgetWrapper::FilterFlags QgsDateTimeSearchWidgetWrapper::defaultFlags() const
Expand All @@ -67,6 +67,8 @@ QString QgsDateTimeSearchWidgetWrapper::createExpression( QgsSearchWidgetWrapper
flags &= supportedFlags();
if ( flags & IsNull )
return fieldName + " IS NULL";
if ( flags & IsNotNull )
return fieldName + " IS NOT NULL";

QVariant v = value();
if ( !v.isValid() )
Expand Down
6 changes: 4 additions & 2 deletions src/gui/editorwidgets/qgsdefaultsearchwidgetwrapper.cpp
Expand Up @@ -90,7 +90,7 @@ bool QgsDefaultSearchWidgetWrapper::applyDirectly()

QgsSearchWidgetWrapper::FilterFlags QgsDefaultSearchWidgetWrapper::supportedFlags() const
{
FilterFlags flags = EqualTo | NotEqualTo | IsNull;
FilterFlags flags = EqualTo | NotEqualTo | IsNull | IsNotNull;

QVariant::Type fldType = layer()->fields().at( mFieldIdx ).type();
switch ( fldType )
Expand All @@ -107,7 +107,7 @@ QgsSearchWidgetWrapper::FilterFlags QgsDefaultSearchWidgetWrapper::supportedFlag
case QVariant::Date:
case QVariant::DateTime:
case QVariant::Time:
flags |= GreaterThan | LessThan | GreaterThanOrEqualTo | LessThanOrEqualTo | Between;
flags |= GreaterThan | LessThan | GreaterThanOrEqualTo | LessThanOrEqualTo | Between | IsNotBetween;
break;

case QVariant::String:
Expand Down Expand Up @@ -157,6 +157,8 @@ QString QgsDefaultSearchWidgetWrapper::createExpression( QgsSearchWidgetWrapper:

if ( flags & IsNull )
return fieldName + " IS NULL";
if ( flags & IsNotNull )
return fieldName + " IS NOT NULL";

switch ( fldType )
{
Expand Down
4 changes: 3 additions & 1 deletion src/gui/editorwidgets/qgsvaluemapsearchwidgetwrapper.cpp
Expand Up @@ -68,7 +68,7 @@ bool QgsValueMapSearchWidgetWrapper::valid() const

QgsSearchWidgetWrapper::FilterFlags QgsValueMapSearchWidgetWrapper::supportedFlags() const
{
return EqualTo | NotEqualTo | IsNull;
return EqualTo | NotEqualTo | IsNull | IsNotNull;
}

QgsSearchWidgetWrapper::FilterFlags QgsValueMapSearchWidgetWrapper::defaultFlags() const
Expand All @@ -90,6 +90,8 @@ QString QgsValueMapSearchWidgetWrapper::createExpression( QgsSearchWidgetWrapper

if ( flags & IsNull )
return fieldName + " IS NULL";
if ( flags & IsNotNull )
return fieldName + " IS NOT NULL";

QString currentKey = mComboBox->itemData( mComboBox->currentIndex() ).toString();

Expand Down
Expand Up @@ -91,7 +91,7 @@ QVariant QgsValueRelationSearchWidgetWrapper::value() const

QgsSearchWidgetWrapper::FilterFlags QgsValueRelationSearchWidgetWrapper::supportedFlags() const
{
return EqualTo | NotEqualTo | IsNull;
return EqualTo | NotEqualTo | IsNull | IsNotNull;
}

QgsSearchWidgetWrapper::FilterFlags QgsValueRelationSearchWidgetWrapper::defaultFlags() const
Expand All @@ -107,6 +107,8 @@ QString QgsValueRelationSearchWidgetWrapper::createExpression( QgsSearchWidgetWr
flags &= supportedFlags();
if ( flags & IsNull )
return fieldName + " IS NULL";
if ( flags & IsNotNull )
return fieldName + " IS NOT NULL";

QVariant v = value();
if ( !v.isValid() )
Expand Down
16 changes: 13 additions & 3 deletions src/gui/qgsattributeformeditorwidget.cpp
Expand Up @@ -100,7 +100,8 @@ void QgsAttributeFormEditorWidget::createSearchWidgetWrappers( const QString& wi
QgsSearchWidgetWrapper* sww = QgsEditorWidgetRegistry::instance()->createSearchWidget( widgetId, layer(), fieldIdx, config,
mSearchFrame, context );
setSearchWidgetWrapper( sww );
if ( sww->supportedFlags() & QgsSearchWidgetWrapper::Between )
if ( sww->supportedFlags() & QgsSearchWidgetWrapper::Between ||
sww->supportedFlags() & QgsSearchWidgetWrapper::IsNotBetween )
{
// create secondary widget for between type searches
QgsSearchWidgetWrapper* sww2 = QgsEditorWidgetRegistry::instance()->createSearchWidget( widgetId, layer(), fieldIdx, config,
Expand Down Expand Up @@ -200,6 +201,13 @@ QString QgsAttributeFormEditorWidget::currentFilterExpression() const
QString filter2 = mSearchWidgets.at( 1 )->createExpression( QgsSearchWidgetWrapper::LessThanOrEqualTo );
return QString( "%1 AND %2" ).arg( filter1, filter2 );
}
else if ( mSearchWidgetToolButton->activeFlags() & QgsSearchWidgetWrapper::IsNotBetween )
{
// special case: Is Not Between search
QString filter1 = mSearchWidgets.at( 0 )->createExpression( QgsSearchWidgetWrapper::LessThan );
QString filter2 = mSearchWidgets.at( 1 )->createExpression( QgsSearchWidgetWrapper::GreaterThan );
return QString( "%1 OR %2" ).arg( filter1, filter2 );
}

return mSearchWidgets.at( 0 )->createExpression( mSearchWidgetToolButton->activeFlags() );
}
Expand Down Expand Up @@ -255,7 +263,8 @@ void QgsAttributeFormEditorWidget::searchWidgetFlagsChanged( QgsSearchWidgetWrap
{
Q_FOREACH ( QgsSearchWidgetWrapper* widget, mSearchWidgets )
{
widget->setEnabled( !( flags & QgsSearchWidgetWrapper::IsNull ) );
widget->setEnabled( !( flags & QgsSearchWidgetWrapper::IsNull )
&& !( flags & QgsSearchWidgetWrapper::IsNotNull ) );
if ( !mSearchWidgetToolButton->isActive() )
{
widget->clearWidget();
Expand All @@ -264,7 +273,8 @@ void QgsAttributeFormEditorWidget::searchWidgetFlagsChanged( QgsSearchWidgetWrap

if ( mSearchWidgets.count() >= 2 )
{
mSearchWidgets.at( 1 )->widget()->setVisible( flags & QgsSearchWidgetWrapper::Between );
mSearchWidgets.at( 1 )->widget()->setVisible( flags & QgsSearchWidgetWrapper::Between ||
flags & QgsSearchWidgetWrapper::IsNotBetween );
}
}

Expand Down
2 changes: 2 additions & 0 deletions tests/src/python/test_qgsattributeformeditorwidget.py
Expand Up @@ -89,6 +89,8 @@ def testBetweenFilter(self):

af.searchWidgetToolButton().setActiveFlags(QgsSearchWidgetWrapper.Between)
self.assertEquals(af.currentFilterExpression(), '"fldtext">=\'2013-05-06\' AND "fldtext"<=\'2013-05-16\'')
af.searchWidgetToolButton().setActiveFlags(QgsSearchWidgetWrapper.IsNotBetween)
self.assertEquals(af.currentFilterExpression(), '"fldtext"<\'2013-05-06\' OR "fldtext">\'2013-05-16\'')


if __name__ == '__main__':
Expand Down
22 changes: 21 additions & 1 deletion tests/src/python/test_qgssearchwidgetwrapper.py
Expand Up @@ -46,7 +46,9 @@ def testFlagToString(self):
QgsSearchWidgetWrapper.CaseInsensitive,
QgsSearchWidgetWrapper.Contains,
QgsSearchWidgetWrapper.DoesNotContain,
QgsSearchWidgetWrapper.IsNull
QgsSearchWidgetWrapper.IsNull,
QgsSearchWidgetWrapper.IsNotNull,
QgsSearchWidgetWrapper.IsNotBetween
]
for t in tests:
self.assertTrue(len(QgsSearchWidgetWrapper.toString(t)) > 0)
Expand Down Expand Up @@ -76,6 +78,7 @@ def testCreateExpression(self):

case_sensitive.setChecked(False)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), 'lower("fldtxt")=lower(\'test\')')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), 'lower("fldtxt")<>lower(\'test\')')
case_sensitive.setChecked(True)
Expand Down Expand Up @@ -136,15 +139,18 @@ def testCreateExpression(self):
c.setCurrentIndex(0)

self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '')

c.setCurrentIndex(1)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'1\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldtxt"<>\'1\'')
c.setCurrentIndex(2)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'200\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldtxt"<>\'200\'')

Expand All @@ -154,6 +160,7 @@ def testCreateExpression(self):
c = w.widget()
c.setCurrentIndex(1)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=1')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>1')

Expand Down Expand Up @@ -186,15 +193,18 @@ def testCreateExpression(self):
c.setCurrentIndex(0)

self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '')

c.setCurrentIndex(1)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'a\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldtxt"<>\'a\'')
c.setCurrentIndex(2)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'b\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldtxt"<>\'b\'')

Expand All @@ -206,6 +216,7 @@ def testCreateExpression(self):
c.setCurrentIndex(c.findText('value c'))
self.assertEqual(c.currentIndex(), 3)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=3')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>3')

Expand All @@ -216,6 +227,7 @@ def testCreateExpression(self):
c = w.widget()
c.setCurrentIndex(c.findText('value c'))
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=3')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>3')

Expand All @@ -226,6 +238,7 @@ def testCreateExpression(self):
l = w.widget()
l.setText('value b')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=2')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>2')

Expand All @@ -245,9 +258,11 @@ def testCreateExpression(self):
# first check with string field type
c.setChecked(True)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'5\'')
c.setChecked(False)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'9\'')

# try with numeric field
Expand All @@ -256,9 +271,11 @@ def testCreateExpression(self):
c = w.widget()
c.setChecked(True)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=5')
c.setChecked(False)
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=9')


Expand All @@ -277,6 +294,7 @@ def testCreateExpression(self):
# first check with date field type
c.setDateTime(QDateTime(QDate(2013, 4, 5), QTime()))
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"date" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"date" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"date"=\'2013-04-05\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"date"<>\'2013-04-05\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.GreaterThan), '"date">\'2013-04-05\'')
Expand All @@ -293,6 +311,7 @@ def testCreateExpression(self):

c.setDateTime(QDateTime(QDate(2013, 4, 5), QTime(13, 14, 15)))
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"time" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"time" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"time"=\'13:14:15\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"time"<>\'13:14:15\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.GreaterThan), '"time">\'13:14:15\'')
Expand All @@ -309,6 +328,7 @@ def testCreateExpression(self):

c.setDateTime(QDateTime(QDate(2013, 4, 5), QTime(13, 14, 15)))
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"datetime" IS NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"datetime" IS NOT NULL')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"datetime"=\'2013-04-05 13:14:15\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"datetime"<>\'2013-04-05 13:14:15\'')
self.assertEquals(w.createExpression(QgsSearchWidgetWrapper.GreaterThan), '"datetime">\'2013-04-05 13:14:15\'')
Expand Down

0 comments on commit 1c4811f

Please sign in to comment.