Skip to content

Commit

Permalink
[FEATURE] add search string support for feature ids ($id)
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.osgeo.org/qgis/trunk@14247 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
jef committed Sep 18, 2010
1 parent aa9aa01 commit bab2eff
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 65 deletions.
20 changes: 16 additions & 4 deletions python/core/qgssearchtreenode.sip
Expand Up @@ -46,6 +46,9 @@ class QgsSearchTreeNode
opLENGTH,
opAREA,

// feature id
opID,

// comparison
opEQ, // =
opNE, // != resp. <>
Expand Down Expand Up @@ -98,7 +101,10 @@ class QgsSearchTreeNode
QString makeSearchString();

//! checks whether the node tree is valid against supplied attributes
//! @note optional geom parameter added in 1.5
//! @note attributes and optional geom parameter replace with feature in 1.6
bool checkAgainst( const QMap<int,QgsField>& fields, QgsFeature &f );

//! @note deprecated
bool checkAgainst( const QMap<int,QgsField>& fields, const QMap<int, QVariant>& attributes, QgsGeometry* geom = 0 );

//! checks if there were errors during evaluation
Expand All @@ -109,6 +115,11 @@ class QgsSearchTreeNode

//! wrapper around valueAgainst()
//! @note added in 1.4
//! @note attribute/geom replaced by feature in 1.6
bool getValue( QgsSearchTreeValue& value /Out/, QgsSearchTreeNode* node,
const QMap<int,QgsField>& fields, QgsFeature &f );

//! @note deprecated
bool getValue( QgsSearchTreeValue& value /Out/, QgsSearchTreeNode* node,
const QMap<int,QgsField>& fields, const QMap<int,QVariant>& attributes, QgsGeometry* geom = 0 );

Expand All @@ -134,14 +145,15 @@ class QgsSearchTreeNode
void setCurrentRowNumber( int rownum );

protected:


//! returns scalar value of node
//! @note attribute/geom replaced by feature in 1.6
QgsSearchTreeValue valueAgainst( const QMap<int,QgsField>& fields, QgsFeature &f );

//! @note deprecated
QgsSearchTreeValue valueAgainst( const QMap<int,QgsField>& fields, const QMap<int,QVariant>& attributes, QgsGeometry* geom = 0 );

//! strips mText when node is of string type
void stripText();

};


Expand Down
4 changes: 2 additions & 2 deletions src/app/attributetable/qgsattributetabledialog.cpp
Expand Up @@ -568,7 +568,7 @@ void QgsAttributeTableDialog::doSearch( QString searchString )
QgsFeatureList selectedFeatures = mLayer->selectedFeatures();
for ( QgsFeatureList::Iterator it = selectedFeatures.begin(); it != selectedFeatures.end(); ++it )
{
if ( searchTree->checkAgainst( mLayer->pendingFields(), it->attributeMap(), it->geometry() ) )
if ( searchTree->checkAgainst( mLayer->pendingFields(), *it ) )
mSelectedFeatures << it->id();

// check if there were errors during evaluating
Expand All @@ -583,7 +583,7 @@ void QgsAttributeTableDialog::doSearch( QString searchString )

while ( mLayer->nextFeature( f ) )
{
if ( searchTree->checkAgainst( mLayer->pendingFields(), f.attributeMap(), f.geometry() ) )
if ( searchTree->checkAgainst( mLayer->pendingFields(), f ) )
mSelectedFeatures << f.id();

// check if there were errors during evaluating
Expand Down
9 changes: 1 addition & 8 deletions src/app/qgsfieldcalculator.cpp
Expand Up @@ -170,14 +170,7 @@ void QgsFieldCalculator::accept()
searchTree->setCurrentRowNumber( rownum );

QgsSearchTreeValue value;
if ( useGeometry )
{
searchTree->getValue( value, searchTree, mVectorLayer->pendingFields(), feature.attributeMap(), feature.geometry() );
}
else
{
searchTree->getValue( value, searchTree, mVectorLayer->pendingFields(), feature.attributeMap() );
}
searchTree->getValue( value, searchTree, mVectorLayer->pendingFields(), feature );
if ( value.isError() )
{
calculationSuccess = false;
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgssearchquerybuilder.cpp
Expand Up @@ -216,7 +216,7 @@ long QgsSearchQueryBuilder::countRecords( QString searchString )

while ( provider->nextFeature( feat ) )
{
if ( searchTree->checkAgainst( fields, feat.attributeMap(), feat.geometry() ) )
if ( searchTree->checkAgainst( fields, feat ) )
{
count++;
}
Expand Down
1 change: 1 addition & 0 deletions src/core/qgssearchstringlexer.ll
Expand Up @@ -110,6 +110,7 @@ string "'"{str_char}*"'"
"$area" { return AREA; }
"$length" { return LENGTH; }
"$id" { return ID; }
{column_ref} { return COLUMN_REF; }
{column_ref_quoted} { return COLUMN_REF; }
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgssearchstringparser.yy
Expand Up @@ -68,6 +68,7 @@ void addToTmpNodes(QgsSearchTreeNode* node);
%token ROWNUM
%token AREA
%token LENGTH
%token ID
%token NULLVALUE

%token STRING
Expand Down Expand Up @@ -151,6 +152,7 @@ scalar_exp:
| ROWNUM { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opROWNUM, 0, 0); addToTmpNodes($$); }
| AREA { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opAREA, 0, 0); addToTmpNodes($$); }
| LENGTH { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opLENGTH, 0, 0); addToTmpNodes($$); }
| ID { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opID, 0, 0); addToTmpNodes($$); }
| NUMBER { $$ = new QgsSearchTreeNode($1); addToTmpNodes($$); }
| STRING { $$ = new QgsSearchTreeNode(QString::fromUtf8(yytext), 0); addToTmpNodes($$); }
| COLUMN_REF { $$ = new QgsSearchTreeNode(QString::fromUtf8(yytext), 1); addToTmpNodes($$); }
Expand Down
106 changes: 65 additions & 41 deletions src/core/qgssearchtreenode.cpp
Expand Up @@ -231,14 +231,15 @@ QString QgsSearchTreeNode::makeSearchString()
// currently all functions take one parameter
str += QString( "(%1)" ).arg( mLeft->makeSearchString() );
}
else if ( mOp == opLENGTH || mOp == opAREA || mOp == opROWNUM )
else if ( mOp == opLENGTH || mOp == opAREA || mOp == opROWNUM || mOp == opID )
{
// special nullary opeators
switch ( mOp )
{
case opLENGTH: str += "$length"; break;
case opAREA: str += "$area"; break;
case opROWNUM: str += "$rownum"; break;
case opID: str += "$id"; break;
default: str += "?";
}
}
Expand Down Expand Up @@ -374,8 +375,16 @@ bool QgsSearchTreeNode::needsGeometry()
}
}

bool QgsSearchTreeNode::checkAgainst( const QMap<int,QgsField>& fields, const QMap<int, QVariant>& attributes, QgsGeometry* geom )
{
QgsFeature f;
f.setAttributeMap( attributes );
if ( geom )
f.setGeometry( *geom );
return checkAgainst( fields, f );
}

bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, const QgsAttributeMap& attributes, QgsGeometry* geom )
bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, QgsFeature &f )
{
QgsDebugMsgLevel( "checkAgainst: " + makeSearchString(), 2 );

Expand All @@ -394,40 +403,32 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, const QgsAttrib
switch ( mOp )
{
case opNOT:
return !mLeft->checkAgainst( fields, attributes, geom );
return !mLeft->checkAgainst( fields, f );

case opAND:
if ( !mLeft->checkAgainst( fields, attributes, geom ) )
if ( !mLeft->checkAgainst( fields, f ) )
return false;
return mRight->checkAgainst( fields, attributes, geom );
return mRight->checkAgainst( fields, f );

case opOR:
if ( mLeft->checkAgainst( fields, attributes, geom ) )
if ( mLeft->checkAgainst( fields, f ) )
return true;
return mRight->checkAgainst( fields, attributes, geom );
return mRight->checkAgainst( fields, f );

case opISNULL:
case opISNOTNULL:
if ( !getValue( value1, mLeft, fields, attributes, geom ) )
if ( !getValue( value1, mLeft, fields, f ) )
return false;

if ( mOp == opISNULL )
{
return value1.isNull();
}
else if ( mOp == opISNOTNULL )
{
return !value1.isNull();
}
return ( mOp == opISNULL ) == value1.isNull();

case opEQ:
case opNE:
case opGT:
case opLT:
case opGE:
case opLE:

if ( !getValue( value1, mLeft, fields, attributes, geom ) || !getValue( value2, mRight, fields, attributes, geom ) )
if ( !getValue( value1, mLeft, fields, f ) || !getValue( value2, mRight, fields, f ) )
return false;

if ( value1.isNull() || value2.isNull() )
Expand All @@ -440,12 +441,12 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, const QgsAttrib

switch ( mOp )
{
case opEQ: return ( res == 0 );
case opNE: return ( res != 0 );
case opGT: return ( res > 0 );
case opLT: return ( res < 0 );
case opGE: return ( res >= 0 );
case opLE: return ( res <= 0 );
case opEQ: return res == 0;
case opNE: return res != 0;
case opGT: return res > 0;
case opLT: return res < 0;
case opGE: return res >= 0;
case opLE: return res <= 0;
default:
mError = QObject::tr( "Unexpected state when evaluating operator!" );
return false;
Expand All @@ -454,15 +455,15 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, const QgsAttrib
case opIN:
case opNOTIN:
{
if ( !getValue( value1, mLeft, fields, attributes, geom ) ||
if ( !getValue( value1, mLeft, fields, f ) ||
!mRight || mRight->type() != tNodeList )
{
return false;
}

foreach( QgsSearchTreeNode *node, mRight->mNodeList )
{
if ( !getValue( value2, node, fields, attributes, geom ) )
if ( !getValue( value2, node, fields, f ) )
{
mError = QObject::tr( "Could not retrieve value of list value" );
return false;
Expand All @@ -485,8 +486,8 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, const QgsAttrib
case opLike:
case opILike:
{
if ( !getValue( value1, mLeft, fields, attributes, geom ) ||
!getValue( value2, mRight, fields, attributes, geom ) )
if ( !getValue( value1, mLeft, fields, f ) ||
!getValue( value2, mRight, fields, f ) )
return false;

// value1 is string to be matched
Expand All @@ -512,20 +513,29 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, const QgsAttrib
}
else
{
return ( QRegExp( str ).indexIn( value1.string() ) != -1 );
return QRegExp( str ).indexIn( value1.string() ) != -1;
}

}

default:
mError = QObject::tr( "Unknown operator: %1" ).arg( mOp );
return false;
}

return false;
}

bool QgsSearchTreeNode::getValue( QgsSearchTreeValue& value, QgsSearchTreeNode* node, const QgsFieldMap& fields, const QgsAttributeMap& attributes, QgsGeometry* geom )
bool QgsSearchTreeNode::getValue( QgsSearchTreeValue& value, QgsSearchTreeNode* node, const QgsFieldMap& fields, const QMap<int, QVariant>& attributes, QgsGeometry* geom )
{
value = node->valueAgainst( fields, attributes, geom );
QgsFeature f;
f.setAttributeMap( attributes );
if ( geom )
f.setGeometry( *geom );
return getValue( value, node, fields, f );
}

bool QgsSearchTreeNode::getValue( QgsSearchTreeValue& value, QgsSearchTreeNode* node, const QgsFieldMap& fields, QgsFeature &f )
{
value = node->valueAgainst( fields, f );
if ( value.isError() )
{
switch (( int )value.number() )
Expand Down Expand Up @@ -553,7 +563,16 @@ bool QgsSearchTreeNode::getValue( QgsSearchTreeValue& value, QgsSearchTreeNode*
return true;
}

QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields, const QgsAttributeMap& attributes, QgsGeometry* geom )
QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields, const QMap<int, QVariant>& attributes, QgsGeometry* geom )
{
QgsFeature f;
f.setAttributeMap( attributes );
if ( geom )
f.setGeometry( *geom );
return valueAgainst( fields, f );
}

QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields, QgsFeature &f )
{
QgsDebugMsgLevel( "valueAgainst: " + makeSearchString(), 2 );

Expand Down Expand Up @@ -587,7 +606,7 @@ QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields, c
}

// get the value
QVariant val = attributes[it.key()];
QVariant val = f.attributeMap()[it.key()];
if ( val.isNull() )
{
QgsDebugMsgLevel( " NULL", 2 );
Expand All @@ -612,30 +631,35 @@ QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields, c
QgsSearchTreeValue value1, value2;
if ( mLeft )
{
if ( !getValue( value1, mLeft, fields, attributes, geom ) ) return value1;
if ( !getValue( value1, mLeft, fields, f ) ) return value1;
}
if ( mRight )
{
if ( !getValue( value2, mRight, fields, attributes, geom ) ) return value2;
if ( !getValue( value2, mRight, fields, f ) ) return value2;
}

if ( mOp == opLENGTH || mOp == opAREA )
{
if ( !geom )
if ( !f.geometry() )
{
return QgsSearchTreeValue( 2, "Geometry is 0" );
}

//check that we don't use area for lines or length for polygons
if ( mOp == opLENGTH && geom->type() != QGis::Line )
if ( mOp == opLENGTH && f.geometry()->type() != QGis::Line )
{
return QgsSearchTreeValue( 0 );
}
if ( mOp == opAREA && geom->type() != QGis::Polygon )
if ( mOp == opAREA && f.geometry()->type() != QGis::Polygon )
{
return QgsSearchTreeValue( 0 );
}
return QgsSearchTreeValue( mCalc->measure( geom ) );
return QgsSearchTreeValue( mCalc->measure( f.geometry() ) );
}

if ( mOp == opID )
{
return QgsSearchTreeValue( f.id() );
}

if ( mOp == opROWNUM )
Expand Down

0 comments on commit bab2eff

Please sign in to comment.