mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-18 00:03:05 -04:00
[API] removed QgsSearchString - QgsExpression should be used instead
This commit is contained in:
parent
a0a0e04a39
commit
e35b115881
@ -73,8 +73,6 @@
|
|||||||
%Include qgsrenderer.sip
|
%Include qgsrenderer.sip
|
||||||
%Include qgsrunprocess.sip
|
%Include qgsrunprocess.sip
|
||||||
%Include qgsscalecalculator.sip
|
%Include qgsscalecalculator.sip
|
||||||
%Include qgssearchstring.sip
|
|
||||||
%Include qgssearchtreenode.sip
|
|
||||||
%Include qgssinglesymbolrenderer.sip
|
%Include qgssinglesymbolrenderer.sip
|
||||||
%Include qgssnapper.sip
|
%Include qgssnapper.sip
|
||||||
%Include qgsspatialindex.sip
|
%Include qgsspatialindex.sip
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
class QgsSearchString
|
|
||||||
{
|
|
||||||
%TypeHeaderCode
|
|
||||||
#include "qgssearchstring.h"
|
|
||||||
%End
|
|
||||||
|
|
||||||
public:
|
|
||||||
//! constructor
|
|
||||||
QgsSearchString();
|
|
||||||
|
|
||||||
//! construct and parse a string
|
|
||||||
//! @note added in v1.6
|
|
||||||
QgsSearchString( const QString & str );
|
|
||||||
|
|
||||||
//! copy constructor - makes also copy of search tree
|
|
||||||
QgsSearchString( const QgsSearchString& str );
|
|
||||||
|
|
||||||
//! destructor - deletes node tree
|
|
||||||
~QgsSearchString();
|
|
||||||
|
|
||||||
//! assignment operator takes care to copy search tree correctly
|
|
||||||
// unable to wrap QgsSearchString& operator=( const QgsSearchString& str );
|
|
||||||
|
|
||||||
/** sets search string and parses search tree
|
|
||||||
on success returns true and sets member variables to the new values */
|
|
||||||
bool setString( QString str );
|
|
||||||
|
|
||||||
/** copies tree and makes search string for it
|
|
||||||
on success returns true and sets member variables to the new values */
|
|
||||||
bool setTree( QgsSearchTreeNode* tree );
|
|
||||||
|
|
||||||
//! getter functions
|
|
||||||
QgsSearchTreeNode* tree();
|
|
||||||
QString string();
|
|
||||||
|
|
||||||
//! returns parser error message - valid only after unsuccessfull parsing
|
|
||||||
const QString& parserErrorMsg();
|
|
||||||
|
|
||||||
//! returns true if no string is set
|
|
||||||
bool isEmpty();
|
|
||||||
|
|
||||||
//! clear search string
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
};
|
|
@ -1,210 +0,0 @@
|
|||||||
|
|
||||||
class QgsSearchTreeNode
|
|
||||||
{
|
|
||||||
%TypeHeaderCode
|
|
||||||
#include "qgssearchtreenode.h"
|
|
||||||
%End
|
|
||||||
|
|
||||||
public:
|
|
||||||
//! defines possible types of node
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
tOperator = 1,
|
|
||||||
tNumber,
|
|
||||||
tColumnRef,
|
|
||||||
tString,
|
|
||||||
tNodeList,
|
|
||||||
};
|
|
||||||
|
|
||||||
//! possible operators
|
|
||||||
enum Operator
|
|
||||||
{
|
|
||||||
// binary
|
|
||||||
opAND = 1,
|
|
||||||
opOR,
|
|
||||||
opNOT,
|
|
||||||
|
|
||||||
// arithmetic
|
|
||||||
opPLUS,
|
|
||||||
opMINUS,
|
|
||||||
opMUL,
|
|
||||||
opMOD,
|
|
||||||
opDIV,
|
|
||||||
opPOW,
|
|
||||||
opSQRT,
|
|
||||||
opSIN,
|
|
||||||
opCOS,
|
|
||||||
opTAN,
|
|
||||||
opASIN,
|
|
||||||
opACOS,
|
|
||||||
opATAN,
|
|
||||||
opATAN2,
|
|
||||||
|
|
||||||
// conversion
|
|
||||||
opTOINT,
|
|
||||||
opTOREAL,
|
|
||||||
opTOSTRING,
|
|
||||||
|
|
||||||
// coordinates
|
|
||||||
opX,
|
|
||||||
opY,
|
|
||||||
opXAT,
|
|
||||||
opYAT,
|
|
||||||
|
|
||||||
// measuring
|
|
||||||
opLENGTH,
|
|
||||||
opAREA,
|
|
||||||
opPERIMETER,
|
|
||||||
|
|
||||||
// feature id
|
|
||||||
opID,
|
|
||||||
|
|
||||||
// comparison
|
|
||||||
opISNULL, // IS NULL
|
|
||||||
opISNOTNULL, // IS NOT NULL
|
|
||||||
opEQ, // =
|
|
||||||
opNE, // != resp. <>
|
|
||||||
opGT, // >
|
|
||||||
opLT, // <
|
|
||||||
opGE, // >=
|
|
||||||
opLE, // <=
|
|
||||||
opRegexp, // ~
|
|
||||||
opLike, // LIKE
|
|
||||||
opILike, // ILIKE
|
|
||||||
opIN, // IN
|
|
||||||
opNOTIN, // NOT IN
|
|
||||||
|
|
||||||
// string handling
|
|
||||||
opCONCAT,
|
|
||||||
opLOWER,
|
|
||||||
opUPPER,
|
|
||||||
opREPLACE,
|
|
||||||
opREGEXPREPLACE,
|
|
||||||
opSTRLEN,
|
|
||||||
opSUBSTR,
|
|
||||||
|
|
||||||
opROWNUM
|
|
||||||
};
|
|
||||||
|
|
||||||
//! constructors
|
|
||||||
QgsSearchTreeNode( double number );
|
|
||||||
QgsSearchTreeNode( Operator o, QgsSearchTreeNode* left, QgsSearchTreeNode* right );
|
|
||||||
QgsSearchTreeNode( QString text, bool isColumnRef );
|
|
||||||
|
|
||||||
//! copy contructor - copies whole tree!
|
|
||||||
QgsSearchTreeNode( const QgsSearchTreeNode& node );
|
|
||||||
|
|
||||||
//! destructor - deletes children nodes (if any)
|
|
||||||
~QgsSearchTreeNode();
|
|
||||||
|
|
||||||
//! returns type of current node
|
|
||||||
Type type() const;
|
|
||||||
|
|
||||||
//! node value getters
|
|
||||||
Operator op() const;
|
|
||||||
double number() const;
|
|
||||||
QString columnRef() const;
|
|
||||||
QString string() const;
|
|
||||||
|
|
||||||
//! node value setters (type is set also)
|
|
||||||
void setOp( Operator o );
|
|
||||||
void setNumber( double number );
|
|
||||||
void setColumnRef( const QString& str );
|
|
||||||
void setString( const QString& str );
|
|
||||||
|
|
||||||
//! children
|
|
||||||
QgsSearchTreeNode* Left();
|
|
||||||
QgsSearchTreeNode* Right();
|
|
||||||
void setLeft( QgsSearchTreeNode* left );
|
|
||||||
void setRight( QgsSearchTreeNode* right );
|
|
||||||
|
|
||||||
//! returns search string that should be equal to original parsed string
|
|
||||||
QString makeSearchString();
|
|
||||||
|
|
||||||
//! checks whether the node tree is valid against supplied attributes
|
|
||||||
//! @note attributes and optional geom parameter replace with feature in 1.6
|
|
||||||
bool checkAgainst( const QMap<int,QgsField>& fields, QgsFeature &f );
|
|
||||||
|
|
||||||
//! @deprecated
|
|
||||||
bool checkAgainst( const QMap<int,QgsField>& fields, const QMap<int, QVariant>& attributes, QgsGeometry* geom = 0 ) /Deprecated/;
|
|
||||||
|
|
||||||
//! checks if there were errors during evaluation
|
|
||||||
bool hasError();
|
|
||||||
|
|
||||||
//! returns error message
|
|
||||||
const QString& errorMsg();
|
|
||||||
|
|
||||||
//! 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 );
|
|
||||||
|
|
||||||
//! @deprecated
|
|
||||||
bool getValue( QgsSearchTreeValue& value /Out/, QgsSearchTreeNode* node,
|
|
||||||
const QMap<int,QgsField>& fields, const QMap<int,QVariant>& attributes, QgsGeometry* geom = 0 ) /Deprecated/;
|
|
||||||
|
|
||||||
//! return a list of referenced columns in the tree
|
|
||||||
//! @note added in 1.5
|
|
||||||
QStringList referencedColumns();
|
|
||||||
|
|
||||||
//! return a list of all attribute nodes
|
|
||||||
//! @note added in 1.5
|
|
||||||
QList<QgsSearchTreeNode*> columnRefNodes();
|
|
||||||
|
|
||||||
//! check whether there are any operators that need geometry (for area, length)
|
|
||||||
//! @note added in 1.5
|
|
||||||
bool needsGeometry();
|
|
||||||
|
|
||||||
//! return quoted column reference (in double quotes)
|
|
||||||
//! @note added in 1.5
|
|
||||||
static QString quotedColumnRef( QString name );
|
|
||||||
|
|
||||||
//! Set current row number within this tree.
|
|
||||||
//! This value is stored only in the nodes being $rownum operator - in mNumber
|
|
||||||
//! @note added in 1.6
|
|
||||||
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 );
|
|
||||||
|
|
||||||
//! @deprecated
|
|
||||||
QgsSearchTreeValue valueAgainst( const QMap<int,QgsField>& fields, const QMap<int,QVariant>& attributes, QgsGeometry* geom = 0 ) /Deprecated/;
|
|
||||||
|
|
||||||
//! strips mText when node is of string type
|
|
||||||
void stripText();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class QgsSearchTreeValue
|
|
||||||
{
|
|
||||||
%TypeHeaderCode
|
|
||||||
#include "qgssearchtreenode.h"
|
|
||||||
%End
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
valError,
|
|
||||||
valString,
|
|
||||||
valNumber
|
|
||||||
};
|
|
||||||
|
|
||||||
QgsSearchTreeValue();
|
|
||||||
QgsSearchTreeValue( QString string );
|
|
||||||
QgsSearchTreeValue( double number );
|
|
||||||
QgsSearchTreeValue( int error, QString errorMsg );
|
|
||||||
|
|
||||||
static QgsSearchTreeValue compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2,
|
|
||||||
Qt::CaseSensitivity = Qt::CaseSensitive );
|
|
||||||
|
|
||||||
bool isNumeric();
|
|
||||||
bool isError();
|
|
||||||
|
|
||||||
QString& string();
|
|
||||||
double number();
|
|
||||||
|
|
||||||
};
|
|
@ -98,8 +98,6 @@ SET(QGIS_CORE_SRCS
|
|||||||
qgsrectangle.cpp
|
qgsrectangle.cpp
|
||||||
qgsrunprocess.cpp
|
qgsrunprocess.cpp
|
||||||
qgsscalecalculator.cpp
|
qgsscalecalculator.cpp
|
||||||
qgssearchstring.cpp
|
|
||||||
qgssearchtreenode.cpp
|
|
||||||
qgssnapper.cpp
|
qgssnapper.cpp
|
||||||
qgscoordinatereferencesystem.cpp
|
qgscoordinatereferencesystem.cpp
|
||||||
qgstolerance.cpp
|
qgstolerance.cpp
|
||||||
@ -244,9 +242,9 @@ IF (WITH_INTERNAL_SPATIALITE)
|
|||||||
INCLUDE_DIRECTORIES(BEFORE spatialite/headers/spatialite)
|
INCLUDE_DIRECTORIES(BEFORE spatialite/headers/spatialite)
|
||||||
ENDIF (WITH_INTERNAL_SPATIALITE)
|
ENDIF (WITH_INTERNAL_SPATIALITE)
|
||||||
|
|
||||||
ADD_FLEX_FILES(QGIS_CORE_SRCS qgssearchstringlexer.ll qgsexpressionlexer.ll)
|
ADD_FLEX_FILES(QGIS_CORE_SRCS qgsexpressionlexer.ll)
|
||||||
|
|
||||||
ADD_BISON_FILES(QGIS_CORE_SRCS qgssearchstringparser.yy qgsexpressionparser.yy)
|
ADD_BISON_FILES(QGIS_CORE_SRCS qgsexpressionparser.yy)
|
||||||
|
|
||||||
SET(QGIS_CORE_MOC_HDRS
|
SET(QGIS_CORE_MOC_HDRS
|
||||||
qgsapplication.h
|
qgsapplication.h
|
||||||
@ -362,8 +360,6 @@ SET(QGIS_CORE_HDRS
|
|||||||
qgsrendercontext.h
|
qgsrendercontext.h
|
||||||
qgsrunprocess.h
|
qgsrunprocess.h
|
||||||
qgsscalecalculator.h
|
qgsscalecalculator.h
|
||||||
qgssearchstring.h
|
|
||||||
qgssearchtreenode.h
|
|
||||||
qgssnapper.h
|
qgssnapper.h
|
||||||
qgscoordinatereferencesystem.h
|
qgscoordinatereferencesystem.h
|
||||||
qgsvectordataprovider.h
|
qgsvectordataprovider.h
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
qgssearchstring.cpp
|
|
||||||
interface for parsing and evaluation of search strings
|
|
||||||
--------------------
|
|
||||||
begin : 2005-07-26
|
|
||||||
copyright : (C) 2005 by Martin Dobias
|
|
||||||
email : won.der at centrum.sk
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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. *
|
|
||||||
* *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include "qgssearchstring.h"
|
|
||||||
#include "qgssearchtreenode.h"
|
|
||||||
|
|
||||||
|
|
||||||
//! global function from parser.y that interfaces parser
|
|
||||||
extern QgsSearchTreeNode* parseSearchString( const QString& str, QString& parserErrorMsg );
|
|
||||||
|
|
||||||
QgsSearchString::QgsSearchString()
|
|
||||||
{
|
|
||||||
mTree = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchString::QgsSearchString( const QString & str )
|
|
||||||
{
|
|
||||||
mTree = NULL;
|
|
||||||
setString( str );
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchString::QgsSearchString( const QgsSearchString& str )
|
|
||||||
{
|
|
||||||
if ( str.mTree )
|
|
||||||
mTree = new QgsSearchTreeNode( *str.mTree );
|
|
||||||
else
|
|
||||||
mTree = NULL;
|
|
||||||
mString = str.mString;
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchString& QgsSearchString::operator=( const QgsSearchString & str )
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
if ( str.mTree )
|
|
||||||
mTree = new QgsSearchTreeNode( *str.mTree );
|
|
||||||
else
|
|
||||||
mTree = NULL;
|
|
||||||
mString = str.mString;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QgsSearchString::~QgsSearchString()
|
|
||||||
{
|
|
||||||
delete mTree; // deletes complete tree
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool QgsSearchString::setString( QString str )
|
|
||||||
{
|
|
||||||
mParserErrorMsg.clear();
|
|
||||||
|
|
||||||
// empty string
|
|
||||||
if ( str.isEmpty() )
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calls external C function that does all parsing
|
|
||||||
QgsSearchTreeNode* tree = parseSearchString( str, mParserErrorMsg );
|
|
||||||
if ( tree )
|
|
||||||
{
|
|
||||||
delete mTree;
|
|
||||||
mTree = tree;
|
|
||||||
mString = str;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool QgsSearchString::setTree( QgsSearchTreeNode* tree )
|
|
||||||
{
|
|
||||||
if ( tree == NULL )
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete mTree;
|
|
||||||
mTree = new QgsSearchTreeNode( *tree );
|
|
||||||
mString = mTree->makeSearchString();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QgsSearchString::isEmpty()
|
|
||||||
{
|
|
||||||
return ( mTree == NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
void QgsSearchString::clear()
|
|
||||||
{
|
|
||||||
delete mTree;
|
|
||||||
mTree = NULL;
|
|
||||||
mString.clear();
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
qgssearchstring.h
|
|
||||||
interface for parsing and evaluation of search strings
|
|
||||||
--------------------
|
|
||||||
begin : 2005-07-26
|
|
||||||
copyright : (C) 2005 by Martin Dobias
|
|
||||||
email : won.der at centrum.sk
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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. *
|
|
||||||
* *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QGSSEARCHSTRING_H
|
|
||||||
#define QGSSEARCHSTRING_H
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
class QgsSearchTreeNode;
|
|
||||||
|
|
||||||
/** \ingroup core
|
|
||||||
* A class to represent a search string.
|
|
||||||
* - interface for 'search string' parser
|
|
||||||
* - when a string is set, it parses it and creates parsed tree of it
|
|
||||||
* - owns node tree and coresponding search string
|
|
||||||
* - keeps string and node tree always in sync
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class CORE_EXPORT QgsSearchString
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//! construct an empty string
|
|
||||||
QgsSearchString();
|
|
||||||
|
|
||||||
//! construct and parse a string
|
|
||||||
//! @note added in v1.6
|
|
||||||
QgsSearchString( const QString & str );
|
|
||||||
|
|
||||||
//! copy constructor - makes also copy of search tree
|
|
||||||
QgsSearchString( const QgsSearchString& str );
|
|
||||||
|
|
||||||
//! destructor - deletes node tree
|
|
||||||
~QgsSearchString();
|
|
||||||
|
|
||||||
//! assignment operator takes care to copy search tree correctly
|
|
||||||
QgsSearchString& operator=( const QgsSearchString& str );
|
|
||||||
|
|
||||||
/** sets search string and parses search tree
|
|
||||||
on success returns true and sets member variables to the new values */
|
|
||||||
bool setString( QString str );
|
|
||||||
|
|
||||||
/* copies tree and makes search string for it
|
|
||||||
on success returns true and sets member variables to the new values */
|
|
||||||
bool setTree( QgsSearchTreeNode* tree );
|
|
||||||
|
|
||||||
//! getter functions
|
|
||||||
QgsSearchTreeNode* tree() { return mTree; }
|
|
||||||
QString string() { return mString; }
|
|
||||||
|
|
||||||
//! returns parser error message - valid only after unsuccessfull parsing
|
|
||||||
const QString& parserErrorMsg() { return mParserErrorMsg; }
|
|
||||||
|
|
||||||
//! returns true if no string is set
|
|
||||||
bool isEmpty();
|
|
||||||
|
|
||||||
//! clear search string
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
private:
|
|
||||||
//! search string and coresponding tree
|
|
||||||
QgsSearchTreeNode* mTree;
|
|
||||||
QString mString;
|
|
||||||
|
|
||||||
//! error message from parser
|
|
||||||
QString mParserErrorMsg;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,144 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
qgssearchstringparser.ll
|
|
||||||
Rules for lexical analysis of search strings done by Flex
|
|
||||||
--------------------
|
|
||||||
begin : 2005-07-26
|
|
||||||
copyright : (C) 2005 by Martin Dobias
|
|
||||||
email : won.der at centrum.sk
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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. *
|
|
||||||
* *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
%option noyywrap
|
|
||||||
%option case-insensitive
|
|
||||||
%option never-interactive
|
|
||||||
%option nounput
|
|
||||||
|
|
||||||
// ensure that lexer will be 8-bit (and not just 7-bit)
|
|
||||||
%option 8bit
|
|
||||||
|
|
||||||
%{
|
|
||||||
|
|
||||||
#include <stdlib.h> // atof()
|
|
||||||
|
|
||||||
#include "qgssearchtreenode.h"
|
|
||||||
#include "qgssearchstringparser.hpp"
|
|
||||||
|
|
||||||
// if not defined, searches for isatty()
|
|
||||||
// which doesn't in MSVC compiler
|
|
||||||
#define YY_NEVER_INTERACTIVE 1
|
|
||||||
|
|
||||||
#ifndef YY_NO_UNPUT
|
|
||||||
#define YY_NO_UNPUT // unused
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define YY_NO_UNISTD_H
|
|
||||||
#endif
|
|
||||||
|
|
||||||
%}
|
|
||||||
|
|
||||||
white [ \t\r\n]+
|
|
||||||
|
|
||||||
non_ascii [\x80-\xFF]
|
|
||||||
|
|
||||||
col_first [A-Za-z_]|{non_ascii}
|
|
||||||
col_next [A-Za-z0-9_]|{non_ascii}
|
|
||||||
column_ref {col_first}{col_next}*
|
|
||||||
|
|
||||||
col_str_char "\"\""|[^\"]
|
|
||||||
column_ref_quoted "\""{col_str_char}*"\""
|
|
||||||
|
|
||||||
dig [0-9]
|
|
||||||
num1 {dig}+\.?([eE][-+]?{dig}+)?
|
|
||||||
num2 {dig}*\.{dig}+([eE][-+]?{dig}+)?
|
|
||||||
number {num1}|{num2}
|
|
||||||
|
|
||||||
str_char ('')|(\\.)|[^'\\]
|
|
||||||
string "'"{str_char}*"'"
|
|
||||||
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
"NOT" { return NOT; }
|
|
||||||
"AND" { return AND; }
|
|
||||||
"OR" { return OR; }
|
|
||||||
|
|
||||||
"NULL" { return NULLVALUE; }
|
|
||||||
|
|
||||||
"IS" { return IS; }
|
|
||||||
"IN" { return IN; }
|
|
||||||
|
|
||||||
"=" { yylval.op = QgsSearchTreeNode::opEQ; return COMPARISON; }
|
|
||||||
"!=" { yylval.op = QgsSearchTreeNode::opNE; return COMPARISON; }
|
|
||||||
"<=" { yylval.op = QgsSearchTreeNode::opLE; return COMPARISON; }
|
|
||||||
">=" { yylval.op = QgsSearchTreeNode::opGE; return COMPARISON; }
|
|
||||||
"<>" { yylval.op = QgsSearchTreeNode::opNE; return COMPARISON; }
|
|
||||||
"<" { yylval.op = QgsSearchTreeNode::opLT; return COMPARISON; }
|
|
||||||
">" { yylval.op = QgsSearchTreeNode::opGT; return COMPARISON; }
|
|
||||||
"~" { yylval.op = QgsSearchTreeNode::opRegexp; return COMPARISON; }
|
|
||||||
"LIKE" { yylval.op = QgsSearchTreeNode::opLike; return COMPARISON; }
|
|
||||||
"ILIKE" { yylval.op = QgsSearchTreeNode::opILike; return COMPARISON; }
|
|
||||||
|
|
||||||
"sqrt" { yylval.op = QgsSearchTreeNode::opSQRT; return FUNCTION1;}
|
|
||||||
"sin" { yylval.op = QgsSearchTreeNode::opSIN; return FUNCTION1;}
|
|
||||||
"cos" { yylval.op = QgsSearchTreeNode::opCOS; return FUNCTION1;}
|
|
||||||
"tan" { yylval.op = QgsSearchTreeNode::opTAN; return FUNCTION1;}
|
|
||||||
"asin" { yylval.op = QgsSearchTreeNode::opASIN; return FUNCTION1;}
|
|
||||||
"acos" { yylval.op = QgsSearchTreeNode::opACOS; return FUNCTION1;}
|
|
||||||
"atan" { yylval.op = QgsSearchTreeNode::opATAN; return FUNCTION1;}
|
|
||||||
"to int" { yylval.op = QgsSearchTreeNode::opTOINT; return FUNCTION1;}
|
|
||||||
"to real" { yylval.op = QgsSearchTreeNode::opTOREAL; return FUNCTION1;}
|
|
||||||
"to string" { yylval.op = QgsSearchTreeNode::opTOSTRING; return FUNCTION1;}
|
|
||||||
"lower" { yylval.op = QgsSearchTreeNode::opLOWER; return FUNCTION1;}
|
|
||||||
"upper" { yylval.op = QgsSearchTreeNode::opUPPER; return FUNCTION1;}
|
|
||||||
"length" { yylval.op = QgsSearchTreeNode::opSTRLEN; return FUNCTION1;}
|
|
||||||
"xat" { yylval.op = QgsSearchTreeNode::opXAT; return FUNCTION1;}
|
|
||||||
"yat" { yylval.op = QgsSearchTreeNode::opYAT; return FUNCTION1;}
|
|
||||||
|
|
||||||
"atan2" { yylval.op = QgsSearchTreeNode::opATAN2; return FUNCTION2;}
|
|
||||||
|
|
||||||
"replace" { yylval.op = QgsSearchTreeNode::opREPLACE; return FUNCTION3;}
|
|
||||||
"regexp_replace" { yylval.op = QgsSearchTreeNode::opREGEXPREPLACE; return FUNCTION3;}
|
|
||||||
"substr" { yylval.op = QgsSearchTreeNode::opSUBSTR; return FUNCTION3;}
|
|
||||||
|
|
||||||
"||" { return CONCAT; }
|
|
||||||
|
|
||||||
[+-/*^%] { return yytext[0]; }
|
|
||||||
|
|
||||||
[()] { return yytext[0]; }
|
|
||||||
|
|
||||||
{number} { yylval.number = atof(yytext); return NUMBER; }
|
|
||||||
|
|
||||||
{string} { return STRING; }
|
|
||||||
|
|
||||||
"$rownum" { return ROWNUM; }
|
|
||||||
|
|
||||||
"$area" { return AREA; }
|
|
||||||
"$length" { return LENGTH; }
|
|
||||||
"$perimeter" { return PERIMETER; }
|
|
||||||
"$x" { return X; }
|
|
||||||
"$y" { return Y; }
|
|
||||||
"$id" { return ID; }
|
|
||||||
|
|
||||||
{column_ref} { return COLUMN_REF; }
|
|
||||||
{column_ref_quoted} { return COLUMN_REF; }
|
|
||||||
|
|
||||||
{white} /* skip blanks and tabs */
|
|
||||||
|
|
||||||
. { return Unknown_CHARACTER; }
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
void set_input_buffer(const char* buffer)
|
|
||||||
{
|
|
||||||
yy_scan_string(buffer);
|
|
||||||
}
|
|
||||||
|
|
@ -1,266 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
qgssearchstringparser.yy
|
|
||||||
Grammar rules for search string used by Bison
|
|
||||||
--------------------
|
|
||||||
begin : 2005-07-26
|
|
||||||
copyright : (C) 2005 by Martin Dobias
|
|
||||||
email : won.der at centrum.sk
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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. *
|
|
||||||
* *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <qglobal.h>
|
|
||||||
#include <QList>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include "qgssearchtreenode.h"
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# pragma warning( disable: 4065 ) // switch statement contains 'default' but no 'case' labels
|
|
||||||
# pragma warning( disable: 4702 ) // unreachable code
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// don't redeclare malloc/free
|
|
||||||
#define YYINCLUDED_STDLIB_H 1
|
|
||||||
|
|
||||||
/** returns parsed tree, otherwise returns NULL and sets parserErrorMsg
|
|
||||||
(interface function to be called from QgsSearchString)
|
|
||||||
*/
|
|
||||||
QgsSearchTreeNode* parseSearchString(const QString& str, QString& parserErrorMsg);
|
|
||||||
|
|
||||||
|
|
||||||
//! from lex.yy.c
|
|
||||||
extern int yylex();
|
|
||||||
extern char* yytext;
|
|
||||||
extern void set_input_buffer(const char* buffer);
|
|
||||||
|
|
||||||
//! varible where the parser error will be stored
|
|
||||||
QString gParserErrorMsg;
|
|
||||||
|
|
||||||
//! sets gParserErrorMsg
|
|
||||||
void yyerror(const char* msg);
|
|
||||||
|
|
||||||
//! temporary list for nodes without parent (if parsing fails these nodes are removed)
|
|
||||||
QList<QgsSearchTreeNode*> gTmpNodes;
|
|
||||||
void joinTmpNodes(QgsSearchTreeNode* parent, QgsSearchTreeNode* left, QgsSearchTreeNode* right);
|
|
||||||
void addToTmpNodes(QgsSearchTreeNode* node);
|
|
||||||
|
|
||||||
// we want verbose error messages
|
|
||||||
#define YYERROR_VERBOSE 1
|
|
||||||
|
|
||||||
%}
|
|
||||||
|
|
||||||
%union { QgsSearchTreeNode* node; double number; QgsSearchTreeNode::Operator op;}
|
|
||||||
|
|
||||||
%start root
|
|
||||||
|
|
||||||
/* http://docs.openlinksw.com/virtuoso/GRAMMAR.html */
|
|
||||||
|
|
||||||
%token <number> NUMBER
|
|
||||||
%token <op> COMPARISON
|
|
||||||
%token <op> FUNCTION1
|
|
||||||
%token <op> FUNCTION2
|
|
||||||
%token <op> FUNCTION3
|
|
||||||
%token CONCAT
|
|
||||||
%token IS
|
|
||||||
%token IN
|
|
||||||
%token ROWNUM
|
|
||||||
%token AREA
|
|
||||||
%token PERIMETER
|
|
||||||
%token LENGTH
|
|
||||||
%token X
|
|
||||||
%token Y
|
|
||||||
%token ID
|
|
||||||
%token NULLVALUE
|
|
||||||
|
|
||||||
%token STRING
|
|
||||||
%token COLUMN_REF
|
|
||||||
|
|
||||||
%token Unknown_CHARACTER
|
|
||||||
|
|
||||||
%token NOT
|
|
||||||
%token AND
|
|
||||||
%token OR
|
|
||||||
|
|
||||||
%type <node> root
|
|
||||||
%type <node> search_cond
|
|
||||||
%type <node> predicate
|
|
||||||
%type <node> comp_predicate
|
|
||||||
%type <node> scalar_exp
|
|
||||||
%type <node> scalar_exp_list
|
|
||||||
|
|
||||||
// debugging
|
|
||||||
//%error-verbose
|
|
||||||
|
|
||||||
// operator precedence
|
|
||||||
// all operators have left associativity, i.e. 1+2+3 translates to (1+2)+3
|
|
||||||
// the order of operators here determines their precedence
|
|
||||||
|
|
||||||
%left OR
|
|
||||||
%left AND
|
|
||||||
%left NOT
|
|
||||||
|
|
||||||
%left COMPARISON
|
|
||||||
%left CONCAT
|
|
||||||
%left IN
|
|
||||||
|
|
||||||
%left '+' '-'
|
|
||||||
%left '*' '/' '%'
|
|
||||||
%left '^'
|
|
||||||
%left UMINUS // fictitious symbol (for unary minus)
|
|
||||||
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
root: search_cond { /*gParserRootNode = $1;*/ }
|
|
||||||
| scalar_exp {}
|
|
||||||
;
|
|
||||||
|
|
||||||
search_cond:
|
|
||||||
search_cond OR search_cond { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opOR, $1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
| search_cond AND search_cond { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opAND, $1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
| NOT search_cond { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opNOT, $2, 0); joinTmpNodes($$,$2, 0); }
|
|
||||||
| '(' search_cond ')' { $$ = $2; }
|
|
||||||
| predicate
|
|
||||||
;
|
|
||||||
|
|
||||||
// more predicates to come
|
|
||||||
predicate:
|
|
||||||
comp_predicate
|
|
||||||
| scalar_exp IN '(' scalar_exp_list ')' { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opIN, $1, $4); joinTmpNodes($$,$1,$4); }
|
|
||||||
| scalar_exp NOT IN '(' scalar_exp_list ')' { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opNOTIN, $1, $5); joinTmpNodes($$,$1,$5); }
|
|
||||||
;
|
|
||||||
|
|
||||||
comp_predicate:
|
|
||||||
scalar_exp IS NULLVALUE { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opISNULL, $1, 0); joinTmpNodes($$,$1,0); }
|
|
||||||
| scalar_exp IS NOT NULLVALUE { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opISNOTNULL, $1, 0); joinTmpNodes($$,$1,0); }
|
|
||||||
| scalar_exp COMPARISON scalar_exp { $$ = new QgsSearchTreeNode($2, $1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
;
|
|
||||||
|
|
||||||
scalar_exp_list:
|
|
||||||
scalar_exp_list ',' scalar_exp { $$ = $1; $1->append($3); joinTmpNodes($1,$1,$3); }
|
|
||||||
| scalar_exp
|
|
||||||
{
|
|
||||||
$$ = new QgsSearchTreeNode( QgsSearchTreeNode::tNodeList );
|
|
||||||
$$->append($1);
|
|
||||||
joinTmpNodes($$,$1,0);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
scalar_exp:
|
|
||||||
FUNCTION1 '(' scalar_exp ')' { $$ = new QgsSearchTreeNode($1, $3, 0); joinTmpNodes($$, $3, 0); }
|
|
||||||
| FUNCTION2 '(' scalar_exp ',' scalar_exp ')' { $$ = new QgsSearchTreeNode($1, $3, $5); joinTmpNodes($$, $3, $5); }
|
|
||||||
| FUNCTION3 '(' scalar_exp ',' scalar_exp ',' scalar_exp ')'
|
|
||||||
{
|
|
||||||
QgsSearchTreeNode *args = new QgsSearchTreeNode( QgsSearchTreeNode::tNodeList );
|
|
||||||
args->append($3);
|
|
||||||
args->append($5);
|
|
||||||
args->append($7);
|
|
||||||
|
|
||||||
$$ = new QgsSearchTreeNode($1, args, 0);
|
|
||||||
joinTmpNodes($$, $3, $5);
|
|
||||||
joinTmpNodes($$, $$, $7);
|
|
||||||
}
|
|
||||||
| scalar_exp '^' scalar_exp { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opPOW, $1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
| scalar_exp '*' scalar_exp { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opMUL, $1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
| scalar_exp '%' scalar_exp { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opMOD, $1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
| scalar_exp '/' scalar_exp { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opDIV, $1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
| scalar_exp '+' scalar_exp { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opPLUS, $1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
| scalar_exp '-' scalar_exp { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opMINUS,$1, $3); joinTmpNodes($$,$1,$3); }
|
|
||||||
| '(' scalar_exp ')' { $$ = $2; }
|
|
||||||
| '+' scalar_exp %prec UMINUS { $$ = $2; }
|
|
||||||
| '-' scalar_exp %prec UMINUS
|
|
||||||
{
|
|
||||||
if ( $2->type() == QgsSearchTreeNode::tNumber )
|
|
||||||
{
|
|
||||||
$$ = $2;
|
|
||||||
$$->setNumber(- $$->number());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QgsSearchTreeNode *null = new QgsSearchTreeNode( 0.0 );
|
|
||||||
$$ = new QgsSearchTreeNode( QgsSearchTreeNode::opMINUS, null, $2);
|
|
||||||
joinTmpNodes($$, $2, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
| scalar_exp CONCAT scalar_exp { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opCONCAT, $1, $3); joinTmpNodes($$, $1, $3); }
|
|
||||||
| ROWNUM { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opROWNUM, 0, 0); addToTmpNodes($$); }
|
|
||||||
| AREA { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opAREA, 0, 0); addToTmpNodes($$); }
|
|
||||||
| PERIMETER { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opPERIMETER, 0, 0); addToTmpNodes($$); }
|
|
||||||
| LENGTH { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opLENGTH, 0, 0); addToTmpNodes($$); }
|
|
||||||
| X { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opX, 0, 0); addToTmpNodes($$); }
|
|
||||||
| Y { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opY, 0, 0); addToTmpNodes($$); }
|
|
||||||
| ID { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opID, 0, 0); addToTmpNodes($$); }
|
|
||||||
| NUMBER { $$ = new QgsSearchTreeNode($1); addToTmpNodes($$); }
|
|
||||||
| STRING { $$ = new QgsSearchTreeNode(QString::fromUtf8(yytext), 0); addToTmpNodes($$); }
|
|
||||||
| NULLVALUE { $$ = new QgsSearchTreeNode(QString::null, 0); addToTmpNodes($$); }
|
|
||||||
| COLUMN_REF { $$ = new QgsSearchTreeNode(QString::fromUtf8(yytext), 1); addToTmpNodes($$); }
|
|
||||||
;
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
void addToTmpNodes(QgsSearchTreeNode* node)
|
|
||||||
{
|
|
||||||
gTmpNodes.append(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void joinTmpNodes(QgsSearchTreeNode* parent, QgsSearchTreeNode* left, QgsSearchTreeNode* right)
|
|
||||||
{
|
|
||||||
bool res;
|
|
||||||
Q_UNUSED(res);
|
|
||||||
|
|
||||||
if (left)
|
|
||||||
{
|
|
||||||
res = gTmpNodes.removeAll(left);
|
|
||||||
Q_ASSERT(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (right)
|
|
||||||
{
|
|
||||||
res = gTmpNodes.removeAll(right);
|
|
||||||
Q_ASSERT(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
gTmpNodes.append(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns parsed tree, otherwise returns NULL and sets parserErrorMsg
|
|
||||||
QgsSearchTreeNode* parseSearchString(const QString& str, QString& parserErrorMsg)
|
|
||||||
{
|
|
||||||
// list should be empty when starting
|
|
||||||
Q_ASSERT(gTmpNodes.count() == 0);
|
|
||||||
|
|
||||||
set_input_buffer(str.toUtf8().constData());
|
|
||||||
int res = yyparse();
|
|
||||||
|
|
||||||
// list should be empty when parsing was OK
|
|
||||||
if (res == 0) // success?
|
|
||||||
{
|
|
||||||
Q_ASSERT(gTmpNodes.count() == 1);
|
|
||||||
return gTmpNodes.takeFirst();
|
|
||||||
}
|
|
||||||
else // error?
|
|
||||||
{
|
|
||||||
parserErrorMsg = gParserErrorMsg;
|
|
||||||
// remove nodes without parents - to prevent memory leaks
|
|
||||||
while (gTmpNodes.size() > 0)
|
|
||||||
delete gTmpNodes.takeFirst();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void yyerror(const char* msg)
|
|
||||||
{
|
|
||||||
gParserErrorMsg = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,953 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
qgssearchtreenode.cpp
|
|
||||||
Implementation for evaluating parsed tree
|
|
||||||
--------------------
|
|
||||||
begin : 2005-07-26
|
|
||||||
copyright : (C) 2005 by Martin Dobias
|
|
||||||
email : won.der at centrum.sk
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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. *
|
|
||||||
* *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include "qgslogger.h"
|
|
||||||
#include "qgsdistancearea.h"
|
|
||||||
#include "qgsfield.h"
|
|
||||||
#include "qgsgeometry.h"
|
|
||||||
#include "qgssearchtreenode.h"
|
|
||||||
#include <QRegExp>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QSettings>
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#define EVAL_STR(x) (x.length() ? x : "(empty)")
|
|
||||||
|
|
||||||
QgsSearchTreeNode::QgsSearchTreeNode( QgsSearchTreeNode::Type t )
|
|
||||||
{
|
|
||||||
Q_ASSERT( t == tNodeList );
|
|
||||||
mType = t;
|
|
||||||
mLeft = NULL;
|
|
||||||
mRight = NULL;
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchTreeNode::QgsSearchTreeNode( double number )
|
|
||||||
{
|
|
||||||
mType = tNumber;
|
|
||||||
mNumber = number;
|
|
||||||
mLeft = NULL;
|
|
||||||
mRight = NULL;
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QgsSearchTreeNode::QgsSearchTreeNode( Operator op,
|
|
||||||
QgsSearchTreeNode* left,
|
|
||||||
QgsSearchTreeNode* right )
|
|
||||||
{
|
|
||||||
mType = tOperator;
|
|
||||||
mOp = op;
|
|
||||||
mLeft = left;
|
|
||||||
mRight = right;
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QgsSearchTreeNode::QgsSearchTreeNode( QString text, bool isColumnRef )
|
|
||||||
{
|
|
||||||
mLeft = NULL;
|
|
||||||
mRight = NULL;
|
|
||||||
|
|
||||||
if ( isColumnRef )
|
|
||||||
{
|
|
||||||
mType = tColumnRef;
|
|
||||||
mText = text;
|
|
||||||
if ( text.at( 0 ) == '\"' )
|
|
||||||
{
|
|
||||||
// column reference is quoted
|
|
||||||
stripColRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mType = tString;
|
|
||||||
mText = text;
|
|
||||||
stripText();
|
|
||||||
}
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchTreeNode::QgsSearchTreeNode( const QgsSearchTreeNode& node )
|
|
||||||
{
|
|
||||||
mType = node.mType;
|
|
||||||
mOp = node.mOp;
|
|
||||||
mNumber = node.mNumber;
|
|
||||||
mText = node.mText;
|
|
||||||
|
|
||||||
// recursively copy children
|
|
||||||
if ( node.mLeft )
|
|
||||||
mLeft = new QgsSearchTreeNode( *node.mLeft );
|
|
||||||
else
|
|
||||||
mLeft = NULL;
|
|
||||||
|
|
||||||
if ( node.mRight )
|
|
||||||
mRight = new QgsSearchTreeNode( *node.mRight );
|
|
||||||
else
|
|
||||||
mRight = NULL;
|
|
||||||
|
|
||||||
foreach( QgsSearchTreeNode * lnode, node.mNodeList )
|
|
||||||
{
|
|
||||||
mNodeList.append( new QgsSearchTreeNode( *lnode ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QgsSearchTreeNode::~QgsSearchTreeNode()
|
|
||||||
{
|
|
||||||
// delete children
|
|
||||||
|
|
||||||
if ( mLeft )
|
|
||||||
delete mLeft;
|
|
||||||
|
|
||||||
if ( mRight )
|
|
||||||
delete mRight;
|
|
||||||
|
|
||||||
while ( !mNodeList.isEmpty() )
|
|
||||||
delete mNodeList.takeFirst();
|
|
||||||
|
|
||||||
delete mCalc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void QgsSearchTreeNode::init()
|
|
||||||
{
|
|
||||||
mCalc = NULL;
|
|
||||||
|
|
||||||
if ( mType == tOperator && ( mOp == opLENGTH || mOp == opAREA || mOp == opPERIMETER ) )
|
|
||||||
{
|
|
||||||
//initialize QgsDistanceArea
|
|
||||||
mCalc = new QgsDistanceArea;
|
|
||||||
mCalc->setProjectionsEnabled( false );
|
|
||||||
QSettings settings;
|
|
||||||
QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", "WGS84" ).toString();
|
|
||||||
mCalc->setEllipsoid( ellipsoid );
|
|
||||||
}
|
|
||||||
else if ( mType == tOperator && mOp == opROWNUM )
|
|
||||||
{
|
|
||||||
// initialize row number to a sane value
|
|
||||||
mNumber = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QgsSearchTreeNode::stripText()
|
|
||||||
{
|
|
||||||
// strip single quotes on start,end
|
|
||||||
mText = mText.mid( 1, mText.length() - 2 );
|
|
||||||
|
|
||||||
// make single "single quotes" from double "single quotes"
|
|
||||||
mText.replace( QRegExp( "''" ), "'" );
|
|
||||||
|
|
||||||
// strip \n \' etc.
|
|
||||||
int index = 0;
|
|
||||||
while (( index = mText.indexOf( '\\', index ) ) != -1 )
|
|
||||||
{
|
|
||||||
mText.remove( index, 1 ); // delete backslash
|
|
||||||
QChar chr;
|
|
||||||
switch ( mText[index].toLatin1() ) // evaluate backslashed character
|
|
||||||
{
|
|
||||||
case 'n': chr = '\n'; break;
|
|
||||||
case 't': chr = '\t'; break;
|
|
||||||
case '\\': chr = '\\'; break;
|
|
||||||
case '\'': chr = '\''; break;
|
|
||||||
default: chr = '?'; break;
|
|
||||||
}
|
|
||||||
mText[index++] = chr; // set new character and push index +1
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void QgsSearchTreeNode::stripColRef()
|
|
||||||
{
|
|
||||||
// strip double quotes on start,end
|
|
||||||
mText = mText.mid( 1, mText.length() - 2 );
|
|
||||||
|
|
||||||
// make single "double quotes" from double "double quotes"
|
|
||||||
mText.replace( QRegExp( "\"\"" ), "\"" );
|
|
||||||
}
|
|
||||||
|
|
||||||
QString QgsSearchTreeNode::quotedColumnRef( QString name )
|
|
||||||
{
|
|
||||||
return QString( "\"%1\"" ).arg( name.replace( "\"", "\"\"" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString QgsSearchTreeNode::makeSearchString()
|
|
||||||
{
|
|
||||||
QString str;
|
|
||||||
if ( mType == tOperator )
|
|
||||||
{
|
|
||||||
if ( mOp == opSQRT || mOp == opSIN || mOp == opCOS || mOp == opTAN ||
|
|
||||||
mOp == opASIN || mOp == opACOS || mOp == opATAN ||
|
|
||||||
mOp == opTOINT || mOp == opTOREAL || mOp == opTOSTRING ||
|
|
||||||
mOp == opLOWER || mOp == opUPPER || mOp == opSTRLEN ||
|
|
||||||
mOp == opATAN2 || mOp == opREPLACE || mOp == opREGEXPREPLACE ||
|
|
||||||
mOp == opSUBSTR || mOp == opXAT || mOp == opYAT )
|
|
||||||
{
|
|
||||||
// functions
|
|
||||||
switch ( mOp )
|
|
||||||
{
|
|
||||||
case opSQRT: str += "sqrt"; break;
|
|
||||||
case opSIN: str += "sin"; break;
|
|
||||||
case opCOS: str += "cos"; break;
|
|
||||||
case opTAN: str += "tan"; break;
|
|
||||||
case opASIN: str += "asin"; break;
|
|
||||||
case opACOS: str += "acos"; break;
|
|
||||||
case opATAN: str += "atan"; break;
|
|
||||||
case opTOINT: str += "to int"; break;
|
|
||||||
case opTOREAL: str += "to real"; break;
|
|
||||||
case opTOSTRING: str += "to string"; break;
|
|
||||||
case opLOWER: str += "lower"; break;
|
|
||||||
case opUPPER: str += "upper"; break;
|
|
||||||
case opATAN2: str += "atan2"; break;
|
|
||||||
case opSTRLEN: str += "length"; break;
|
|
||||||
case opREPLACE: str += "replace"; break;
|
|
||||||
case opREGEXPREPLACE: str += "regexp_replace"; break;
|
|
||||||
case opSUBSTR: str += "substr"; break;
|
|
||||||
case opXAT: str += "xat"; break;
|
|
||||||
case opYAT: str += "yat"; break;
|
|
||||||
default: str += "?";
|
|
||||||
}
|
|
||||||
// currently all functions take one parameter
|
|
||||||
str += QString( "(%1)" ).arg( mLeft->makeSearchString() );
|
|
||||||
}
|
|
||||||
else if ( mOp == opLENGTH || mOp == opAREA || mOp == opPERIMETER || mOp == opROWNUM || mOp == opID || mOp == opX || mOp == opY )
|
|
||||||
{
|
|
||||||
// special nullary opeators
|
|
||||||
switch ( mOp )
|
|
||||||
{
|
|
||||||
case opLENGTH: str += "$length"; break;
|
|
||||||
case opAREA: str += "$area"; break;
|
|
||||||
case opPERIMETER: str += "$perimeter"; break;
|
|
||||||
case opROWNUM: str += "$rownum"; break;
|
|
||||||
case opX: str += "$x"; break;
|
|
||||||
case opY: str += "$y"; break;
|
|
||||||
case opID: str += "$id"; break;
|
|
||||||
default: str += "?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( mOp == opNOT )
|
|
||||||
{
|
|
||||||
// unary NOT operator
|
|
||||||
str += "(NOT " + mLeft->makeSearchString() + ")";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// the rest of operator using infix notation
|
|
||||||
str += "(";
|
|
||||||
if ( mLeft )
|
|
||||||
{
|
|
||||||
str += mLeft->makeSearchString();
|
|
||||||
}
|
|
||||||
switch ( mOp )
|
|
||||||
{
|
|
||||||
case opAND: str += " AND "; break;
|
|
||||||
case opOR: str += " OR "; break;
|
|
||||||
|
|
||||||
case opPLUS: str += "+"; break;
|
|
||||||
case opMINUS: str += "-"; break;
|
|
||||||
case opMUL: str += "*"; break;
|
|
||||||
case opMOD: str += "%"; break;
|
|
||||||
case opDIV: str += "/"; break;
|
|
||||||
case opPOW: str += "^"; break;
|
|
||||||
|
|
||||||
case opEQ: str += " = "; break;
|
|
||||||
case opNE: str += " != "; break;
|
|
||||||
case opGT: str += " > "; break;
|
|
||||||
case opLT: str += " < "; break;
|
|
||||||
case opGE: str += " >= "; break;
|
|
||||||
case opLE: str += " <= "; break;
|
|
||||||
|
|
||||||
case opISNULL: str += " IS NULL"; break;
|
|
||||||
case opISNOTNULL: str += " IS NOT NULL"; break;
|
|
||||||
|
|
||||||
case opRegexp: str += " ~ "; break;
|
|
||||||
case opLike: str += " LIKE "; break;
|
|
||||||
case opILike: str += " ILIKE "; break;
|
|
||||||
case opIN: str += " IN "; break;
|
|
||||||
case opNOTIN: str += " NOT IN "; break;
|
|
||||||
|
|
||||||
case opCONCAT: str += " || "; break;
|
|
||||||
|
|
||||||
default: str += " ? ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mRight )
|
|
||||||
{
|
|
||||||
str += mRight->makeSearchString();
|
|
||||||
}
|
|
||||||
str += ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( mType == tNumber )
|
|
||||||
{
|
|
||||||
str += QString::number( mNumber );
|
|
||||||
}
|
|
||||||
else if ( mType == tString || mType == tColumnRef )
|
|
||||||
{
|
|
||||||
str += mText;
|
|
||||||
}
|
|
||||||
else if ( mType == tNodeList )
|
|
||||||
{
|
|
||||||
QStringList items;
|
|
||||||
foreach( QgsSearchTreeNode * node, mNodeList )
|
|
||||||
{
|
|
||||||
items << node->makeSearchString();
|
|
||||||
}
|
|
||||||
|
|
||||||
str += "(" + items.join( "," ) + ")";
|
|
||||||
}
|
|
||||||
else // unknown type
|
|
||||||
{
|
|
||||||
str += "unknown_node_type:";
|
|
||||||
str += QString::number( mType );
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList QgsSearchTreeNode::referencedColumns()
|
|
||||||
{
|
|
||||||
QList<QgsSearchTreeNode*> columnNodeList = columnRefNodes();
|
|
||||||
QSet<QString> columnStringSet;
|
|
||||||
|
|
||||||
QList<QgsSearchTreeNode*>::const_iterator nodeIt = columnNodeList.constBegin();
|
|
||||||
for ( ; nodeIt != columnNodeList.constEnd(); ++nodeIt )
|
|
||||||
{
|
|
||||||
columnStringSet.insert(( *nodeIt )->columnRef() );
|
|
||||||
}
|
|
||||||
return columnStringSet.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QgsSearchTreeNode*> QgsSearchTreeNode::columnRefNodes()
|
|
||||||
{
|
|
||||||
QList<QgsSearchTreeNode*> nodeList;
|
|
||||||
if ( mType == tOperator )
|
|
||||||
{
|
|
||||||
if ( mLeft )
|
|
||||||
{
|
|
||||||
nodeList += mLeft->columnRefNodes();
|
|
||||||
}
|
|
||||||
if ( mRight )
|
|
||||||
{
|
|
||||||
nodeList += mRight->columnRefNodes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( mType == tColumnRef )
|
|
||||||
{
|
|
||||||
nodeList.push_back( this );
|
|
||||||
}
|
|
||||||
return nodeList;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QgsSearchTreeNode::needsGeometry()
|
|
||||||
{
|
|
||||||
if ( mType == tOperator )
|
|
||||||
{
|
|
||||||
if ( mOp == opLENGTH || mOp == opAREA || mOp == opPERIMETER || mOp == opX || mOp == opY || mOp == opXAT || mOp == opYAT )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if ( mLeft && mLeft->needsGeometry() )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if ( mRight && mRight->needsGeometry() )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, const QgsAttributeMap &attributes, QgsGeometry* geom )
|
|
||||||
{
|
|
||||||
QgsFeature f;
|
|
||||||
f.setAttributeMap( attributes );
|
|
||||||
if ( geom )
|
|
||||||
f.setGeometry( *geom );
|
|
||||||
return checkAgainst( fields, f );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, QgsFeature &f )
|
|
||||||
{
|
|
||||||
QgsDebugMsgLevel( "checkAgainst: " + makeSearchString(), 2 );
|
|
||||||
|
|
||||||
mError = "";
|
|
||||||
|
|
||||||
// this error should be caught when checking syntax, but for sure...
|
|
||||||
if ( mType != tOperator )
|
|
||||||
{
|
|
||||||
mError = QObject::tr( "Expected operator, got scalar value!" );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchTreeValue value1, value2;
|
|
||||||
|
|
||||||
switch ( mOp )
|
|
||||||
{
|
|
||||||
case opNOT:
|
|
||||||
return !mLeft->checkAgainst( fields, f );
|
|
||||||
|
|
||||||
case opAND:
|
|
||||||
if ( !mLeft->checkAgainst( fields, f ) )
|
|
||||||
return false;
|
|
||||||
return mRight->checkAgainst( fields, f );
|
|
||||||
|
|
||||||
case opOR:
|
|
||||||
if ( mLeft->checkAgainst( fields, f ) )
|
|
||||||
return true;
|
|
||||||
return mRight->checkAgainst( fields, f );
|
|
||||||
|
|
||||||
case opISNULL:
|
|
||||||
case opISNOTNULL:
|
|
||||||
if ( !getValue( value1, mLeft, fields, f ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return ( mOp == opISNULL ) == value1.isNull();
|
|
||||||
|
|
||||||
case opEQ:
|
|
||||||
case opNE:
|
|
||||||
case opGT:
|
|
||||||
case opLT:
|
|
||||||
case opGE:
|
|
||||||
case opLE:
|
|
||||||
{
|
|
||||||
if ( !getValue( value1, mLeft, fields, f ) || !getValue( value2, mRight, fields, f ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( value1.isNull() || value2.isNull() )
|
|
||||||
{
|
|
||||||
// NULL values never match
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchTreeValue res = QgsSearchTreeValue::compare( value1, value2 );
|
|
||||||
if ( res.isError() )
|
|
||||||
{
|
|
||||||
mError = QString( "%1 [%2]" ).arg( res.string() ).arg( res.number() );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ( mOp )
|
|
||||||
{
|
|
||||||
case opEQ: return res.number() == 0.0;
|
|
||||||
case opNE: return res.number() != 0.0;
|
|
||||||
case opGT: return res.number() > 0.0;
|
|
||||||
case opLT: return res.number() < 0.0;
|
|
||||||
case opGE: return res.number() >= 0.0;
|
|
||||||
case opLE: return res.number() <= 0.0;
|
|
||||||
default:
|
|
||||||
mError = QObject::tr( "Unexpected state when evaluating operator!" );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case opIN:
|
|
||||||
case opNOTIN:
|
|
||||||
{
|
|
||||||
if ( !getValue( value1, mLeft, fields, f ) ||
|
|
||||||
!mRight || mRight->type() != tNodeList )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach( QgsSearchTreeNode * node, mRight->mNodeList )
|
|
||||||
{
|
|
||||||
if ( !getValue( value2, node, fields, f ) )
|
|
||||||
{
|
|
||||||
mError = QObject::tr( "Could not retrieve value of list value" );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchTreeValue res = QgsSearchTreeValue::compare( value1, value2 );
|
|
||||||
|
|
||||||
if ( res.isNumeric() && res.number() == 0.0 )
|
|
||||||
{
|
|
||||||
// found
|
|
||||||
return mOp == opIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mOp == opNOTIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
case opRegexp:
|
|
||||||
case opLike:
|
|
||||||
case opILike:
|
|
||||||
{
|
|
||||||
if ( !getValue( value1, mLeft, fields, f ) ||
|
|
||||||
!getValue( value2, mRight, fields, f ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// value1 is string to be matched
|
|
||||||
// value2 is regular expression
|
|
||||||
|
|
||||||
// XXX does it make sense to use regexp on numbers?
|
|
||||||
// in what format should they be?
|
|
||||||
if ( value1.isNumeric() || value2.isNumeric() )
|
|
||||||
{
|
|
||||||
mError = QObject::tr( "Regular expressions on numeric values don't make sense. Use comparison instead." );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: reuse QRegExp
|
|
||||||
|
|
||||||
QString str = value2.string();
|
|
||||||
if ( mOp == opLike || mOp == opILike ) // change from LIKE syntax to regexp
|
|
||||||
{
|
|
||||||
// XXX escape % and _ ???
|
|
||||||
str.replace( "%", ".*" );
|
|
||||||
str.replace( "_", "." );
|
|
||||||
return QRegExp( str, mOp == opLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( value1.string() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return QRegExp( str ).indexIn( value1.string() ) != -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
mError = QObject::tr( "Unknown operator: %1" ).arg( mOp );
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QgsSearchTreeNode::getValue( QgsSearchTreeValue& value,
|
|
||||||
QgsSearchTreeNode* node,
|
|
||||||
const QgsFieldMap &fields,
|
|
||||||
const QgsAttributeMap &attributes,
|
|
||||||
QgsGeometry* 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() )
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
mError = QObject::tr( "Referenced column wasn't found: %1" ).arg( value.string() );
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
mError = QObject::tr( "Division by zero." );
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
mError = QObject::tr( "Unknown operator: %1" ).arg( value.string() );
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
mError = QObject::tr( "Unknown token: %1" ).arg( value.string() );
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
mError = QObject::tr( "Expression error: %1" ).arg( value.string() );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mError = QObject::tr( "Unknown error %1: %2" ).arg( value.number() ).arg( value.string() );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields,
|
|
||||||
const QgsAttributeMap &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 );
|
|
||||||
|
|
||||||
switch ( mType )
|
|
||||||
{
|
|
||||||
case tNumber:
|
|
||||||
QgsDebugMsgLevel( "number: " + QString::number( mNumber ), 2 );
|
|
||||||
return QgsSearchTreeValue( mNumber );
|
|
||||||
|
|
||||||
case tString:
|
|
||||||
QgsDebugMsgLevel( "text: " + EVAL_STR( mText ), 2 );
|
|
||||||
return QgsSearchTreeValue( mText );
|
|
||||||
|
|
||||||
case tColumnRef:
|
|
||||||
{
|
|
||||||
QgsDebugMsgLevel( "column (" + mText.toLower() + "): ", 2 );
|
|
||||||
// find field index for the column
|
|
||||||
QgsFieldMap::const_iterator it;
|
|
||||||
for ( it = fields.begin(); it != fields.end(); it++ )
|
|
||||||
{
|
|
||||||
if ( QString::compare( it->name(), mText, Qt::CaseInsensitive ) == 0 )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( it == fields.end() )
|
|
||||||
{
|
|
||||||
// report missing column if not found
|
|
||||||
QgsDebugMsgLevel( "ERROR!", 2 );
|
|
||||||
return QgsSearchTreeValue( 1, mText );
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the value
|
|
||||||
QVariant val = f.attributeMap()[it.key()];
|
|
||||||
if ( val.isNull() )
|
|
||||||
{
|
|
||||||
QgsDebugMsgLevel( " NULL", 2 );
|
|
||||||
return QgsSearchTreeValue();
|
|
||||||
}
|
|
||||||
else if ( val.type() == QVariant::Bool || val.type() == QVariant::Int || val.type() == QVariant::Double )
|
|
||||||
{
|
|
||||||
QgsDebugMsgLevel( " number: " + QString::number( val.toDouble() ), 2 );
|
|
||||||
return QgsSearchTreeValue( val.toDouble() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QgsDebugMsgLevel( " text: " + EVAL_STR( val.toString() ), 2 );
|
|
||||||
return QgsSearchTreeValue( val.toString() );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// arithmetic operators
|
|
||||||
case tOperator:
|
|
||||||
{
|
|
||||||
QgsSearchTreeValue value1, value2, value3;
|
|
||||||
if ( mLeft )
|
|
||||||
{
|
|
||||||
if ( mLeft->type() != tNodeList )
|
|
||||||
{
|
|
||||||
if ( !getValue( value1, mLeft, fields, f ) )
|
|
||||||
return value1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( mLeft->mNodeList.size() > 0 && !getValue( value1, mLeft->mNodeList[0], fields, f ) )
|
|
||||||
return value1;
|
|
||||||
if ( mLeft->mNodeList.size() > 1 && !getValue( value2, mLeft->mNodeList[1], fields, f ) )
|
|
||||||
return value2;
|
|
||||||
if ( mLeft->mNodeList.size() > 2 && !getValue( value3, mLeft->mNodeList[2], fields, f ) )
|
|
||||||
return value3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( mRight )
|
|
||||||
{
|
|
||||||
Q_ASSERT( !mLeft || mLeft->type() != tNodeList );
|
|
||||||
if ( !getValue( value2, mRight, fields, f ) )
|
|
||||||
return value2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mOp == opLENGTH || mOp == opAREA || mOp == opPERIMETER || mOp == opX || mOp == opY || mOp == opXAT || mOp == opYAT )
|
|
||||||
{
|
|
||||||
if ( !f.geometry() )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( 2, QObject::tr( "Geometry is 0" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
//check that we don't use area for lines or length for polygons
|
|
||||||
if ( mOp == opLENGTH && f.geometry()->type() == QGis::Line )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( mCalc->measure( f.geometry() ) );
|
|
||||||
}
|
|
||||||
if ( mOp == opAREA && f.geometry()->type() == QGis::Polygon )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( mCalc->measure( f.geometry() ) );
|
|
||||||
}
|
|
||||||
if ( mOp == opPERIMETER && f.geometry()->type() == QGis::Polygon )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( mCalc->measurePerimeter( f.geometry() ) );
|
|
||||||
}
|
|
||||||
if ( mOp == opX && f.geometry()->type() == QGis::Point )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( f.geometry()->asPoint().x() );
|
|
||||||
}
|
|
||||||
if ( mOp == opY && f.geometry()->type() == QGis::Point )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( f.geometry()->asPoint().y() );
|
|
||||||
}
|
|
||||||
if (( mOp == opXAT || mOp == opYAT ) && f.geometry()->type() == QGis::Line && value1.isNumeric() )
|
|
||||||
{
|
|
||||||
QgsPolyline p = f.geometry()->asPolyline();
|
|
||||||
|
|
||||||
int idx = value1.number();
|
|
||||||
if ( idx < 0 )
|
|
||||||
{
|
|
||||||
idx += p.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( idx < 0 || idx >= p.size() )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( 2, QObject::tr( "Index %1 out of range [0;%2[" ).arg( idx ).arg( p.size() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return QgsSearchTreeValue( mOp == opXAT ? p[idx].x() : p[idx].y() );
|
|
||||||
}
|
|
||||||
|
|
||||||
return QgsSearchTreeValue( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mOp == opID )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( f.id() );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mOp == opROWNUM )
|
|
||||||
{
|
|
||||||
// the row number has to be previously set by the caller using setCurrentRowNumber
|
|
||||||
return QgsSearchTreeValue( mNumber );
|
|
||||||
}
|
|
||||||
|
|
||||||
//string operations with one argument
|
|
||||||
if ( !mRight && !value1.isNumeric() )
|
|
||||||
{
|
|
||||||
if ( mOp == opTOINT )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( value1.string().toInt() );
|
|
||||||
}
|
|
||||||
else if ( mOp == opTOREAL )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( value1.string().toDouble() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//don't convert to numbers in case of string concatenation
|
|
||||||
if ( mLeft && mRight && !value1.isNumeric() && !value2.isNumeric() )
|
|
||||||
{
|
|
||||||
// TODO: concatenation using '+' operator should be removed in favor of '||' operator
|
|
||||||
// because it may lead to surprising behavior if numbers are stored in a string
|
|
||||||
if ( mOp == opPLUS )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( value1.string() + value2.string() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// string concatenation ||
|
|
||||||
if ( mLeft && mRight && mOp == opCONCAT )
|
|
||||||
{
|
|
||||||
if ( value1.isNumeric() && value2.isNumeric() )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( 5, QObject::tr( "Operator doesn't match the argument types." ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QString arg1 = value1.isNumeric() ? QString::number( value1.number() ) : value1.string();
|
|
||||||
QString arg2 = value2.isNumeric() ? QString::number( value2.number() ) : value2.string();
|
|
||||||
return QgsSearchTreeValue( arg1 + arg2 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// string operations
|
|
||||||
switch ( mOp )
|
|
||||||
{
|
|
||||||
case opLOWER:
|
|
||||||
return QgsSearchTreeValue( value1.string().toLower() );
|
|
||||||
case opUPPER:
|
|
||||||
return QgsSearchTreeValue( value1.string().toUpper() );
|
|
||||||
case opSTRLEN:
|
|
||||||
return QgsSearchTreeValue( value1.string().length() );
|
|
||||||
case opREPLACE:
|
|
||||||
return QgsSearchTreeValue( value1.string().replace( value2.string(), value3.string() ) );
|
|
||||||
case opREGEXPREPLACE:
|
|
||||||
{
|
|
||||||
QRegExp re( value2.string() );
|
|
||||||
if ( !re.isValid() )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( 5, QObject::tr( "Invalid regular expression '%1': %2" ).arg( value2.string() ).arg( re.errorString() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return QgsSearchTreeValue( value1.string().replace( re, value3.string() ) );
|
|
||||||
}
|
|
||||||
case opSUBSTR:
|
|
||||||
return QgsSearchTreeValue( value1.string().mid( value2.number() - 1, value3.number() ) );
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for other operators, convert strings to numbers if needed
|
|
||||||
double val1, val2;
|
|
||||||
if ( value1.isNumeric() )
|
|
||||||
val1 = value1.number();
|
|
||||||
else
|
|
||||||
val1 = value1.string().toDouble();
|
|
||||||
if ( value2.isNumeric() )
|
|
||||||
val2 = value2.number();
|
|
||||||
else
|
|
||||||
val2 = value2.string().toDouble();
|
|
||||||
|
|
||||||
switch ( mOp )
|
|
||||||
{
|
|
||||||
case opPLUS:
|
|
||||||
return QgsSearchTreeValue( val1 + val2 );
|
|
||||||
case opMINUS:
|
|
||||||
return QgsSearchTreeValue( val1 - val2 );
|
|
||||||
case opMUL:
|
|
||||||
return QgsSearchTreeValue( val1 * val2 );
|
|
||||||
case opMOD:
|
|
||||||
// NOTE: we _might_ support float operators, like postgresql does
|
|
||||||
// see 83c94a886c059 commit in postgresql git repo for more info
|
|
||||||
return QgsSearchTreeValue( int( val1 ) % int( val2 ) );
|
|
||||||
case opDIV:
|
|
||||||
if ( val2 == 0 )
|
|
||||||
return QgsSearchTreeValue( 2, "" ); // division by zero
|
|
||||||
else
|
|
||||||
return QgsSearchTreeValue( val1 / val2 );
|
|
||||||
case opPOW:
|
|
||||||
if (( val1 == 0 && val2 < 0 ) || ( val2 < 0 && ( val2 - floor( val2 ) ) > 0 ) )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( 4, QObject::tr( "Error in power function" ) );
|
|
||||||
}
|
|
||||||
return QgsSearchTreeValue( pow( val1, val2 ) );
|
|
||||||
case opSQRT:
|
|
||||||
return QgsSearchTreeValue( sqrt( val1 ) );
|
|
||||||
case opSIN:
|
|
||||||
return QgsSearchTreeValue( sin( val1 ) );
|
|
||||||
case opCOS:
|
|
||||||
return QgsSearchTreeValue( cos( val1 ) );
|
|
||||||
case opTAN:
|
|
||||||
return QgsSearchTreeValue( tan( val1 ) );
|
|
||||||
case opASIN:
|
|
||||||
return QgsSearchTreeValue( asin( val1 ) );
|
|
||||||
case opACOS:
|
|
||||||
return QgsSearchTreeValue( acos( val1 ) );
|
|
||||||
case opATAN:
|
|
||||||
return QgsSearchTreeValue( atan( val1 ) );
|
|
||||||
case opATAN2:
|
|
||||||
return QgsSearchTreeValue( atan2( val1, val2 ) );
|
|
||||||
case opTOINT:
|
|
||||||
return QgsSearchTreeValue( int( val1 ) );
|
|
||||||
case opTOREAL:
|
|
||||||
return QgsSearchTreeValue( val1 );
|
|
||||||
case opTOSTRING:
|
|
||||||
return QgsSearchTreeValue( QString::number( val1 ) );
|
|
||||||
|
|
||||||
default:
|
|
||||||
return QgsSearchTreeValue( 3, QString::number( mOp ) ); // unknown operator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return QgsSearchTreeValue( 4, QString::number( mType ) ); // unknown token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void QgsSearchTreeNode::setCurrentRowNumber( int rownum )
|
|
||||||
{
|
|
||||||
if ( mType == tOperator )
|
|
||||||
{
|
|
||||||
if ( mOp == opROWNUM )
|
|
||||||
mNumber = rownum;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// propagate the new row number to children
|
|
||||||
if ( mLeft )
|
|
||||||
mLeft->setCurrentRowNumber( rownum );
|
|
||||||
if ( mRight )
|
|
||||||
mRight->setCurrentRowNumber( rownum );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QgsSearchTreeNode::append( QgsSearchTreeNode *node )
|
|
||||||
{
|
|
||||||
Q_ASSERT( mType == tNodeList );
|
|
||||||
mNodeList.append( node );
|
|
||||||
}
|
|
||||||
|
|
||||||
void QgsSearchTreeNode::append( QList<QgsSearchTreeNode *> nodes )
|
|
||||||
{
|
|
||||||
foreach( QgsSearchTreeNode * node, nodes )
|
|
||||||
{
|
|
||||||
mNodeList.append( node );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsSearchTreeValue QgsSearchTreeValue::compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2, Qt::CaseSensitivity cs )
|
|
||||||
{
|
|
||||||
if ( value1.isNumeric() || value2.isNumeric() )
|
|
||||||
{
|
|
||||||
// numeric comparison
|
|
||||||
|
|
||||||
// convert to numbers if needed
|
|
||||||
double val1, val2;
|
|
||||||
bool ok;
|
|
||||||
if ( value1.isNumeric() )
|
|
||||||
{
|
|
||||||
val1 = value1.number();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
val1 = value1.string().toDouble( &ok );
|
|
||||||
if ( !ok )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( 5, QObject::tr( "Value '%1' is not numeric" ).arg( value1.string() ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( value2.isNumeric() )
|
|
||||||
{
|
|
||||||
val2 = value2.number();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
val2 = value2.string().toDouble( &ok );
|
|
||||||
if ( !ok )
|
|
||||||
{
|
|
||||||
return QgsSearchTreeValue( 5, QObject::tr( "Value '%1' is not numeric" ).arg( value2.string() ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsDebugMsgLevel( "NUM_COMP: " + QString::number( val1 ) + " ~ " + QString::number( val2 ), 2 );
|
|
||||||
|
|
||||||
if ( val1 < val2 )
|
|
||||||
return QgsSearchTreeValue( -1.0 );
|
|
||||||
else if ( val1 > val2 )
|
|
||||||
return QgsSearchTreeValue( 1.0 );
|
|
||||||
else
|
|
||||||
return QgsSearchTreeValue( 0.0 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// string comparison
|
|
||||||
return QgsSearchTreeValue(( double ) value1.string().compare( value2.string(), cs ) );
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,292 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
qgssearchtreenode.h
|
|
||||||
Definition of node for parsed tree of search string
|
|
||||||
--------------------
|
|
||||||
begin : 2005-07-26
|
|
||||||
copyright : (C) 2005 by Martin Dobias
|
|
||||||
email : won.der at centrum.sk
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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. *
|
|
||||||
* *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QGSSEARCHTREENODE_H
|
|
||||||
#define QGSSEARCHTREENODE_H
|
|
||||||
|
|
||||||
#include <QMap>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
#include <qgis.h>
|
|
||||||
#include <qgsfield.h>
|
|
||||||
#include <qgsfeature.h>
|
|
||||||
|
|
||||||
class QgsDistanceArea;
|
|
||||||
class QgsSearchTreeValue;
|
|
||||||
|
|
||||||
/** \ingroup core
|
|
||||||
* A representation of a node in a search tree.
|
|
||||||
*
|
|
||||||
* node in tree of parsed search string
|
|
||||||
* node is terminal (has no children) if it's a number, column ref or string
|
|
||||||
* non-terminal is only node with operator - with 1 or 2 children
|
|
||||||
*/
|
|
||||||
class CORE_EXPORT QgsSearchTreeNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
//! defines possible types of node
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
tOperator = 1,
|
|
||||||
tNumber,
|
|
||||||
tColumnRef,
|
|
||||||
tString,
|
|
||||||
tNodeList,
|
|
||||||
};
|
|
||||||
|
|
||||||
//! possible operators
|
|
||||||
//! TODO: sync the python bindings
|
|
||||||
enum Operator
|
|
||||||
{
|
|
||||||
// binary
|
|
||||||
opAND = 1,
|
|
||||||
opOR,
|
|
||||||
opNOT,
|
|
||||||
|
|
||||||
// arithmetic
|
|
||||||
opPLUS,
|
|
||||||
opMINUS,
|
|
||||||
opMUL,
|
|
||||||
opMOD,
|
|
||||||
opDIV,
|
|
||||||
opPOW,
|
|
||||||
opSQRT,
|
|
||||||
opSIN,
|
|
||||||
opCOS,
|
|
||||||
opTAN,
|
|
||||||
opASIN,
|
|
||||||
opACOS,
|
|
||||||
opATAN,
|
|
||||||
opATAN2,
|
|
||||||
|
|
||||||
// conversion
|
|
||||||
opTOINT,
|
|
||||||
opTOREAL,
|
|
||||||
opTOSTRING,
|
|
||||||
|
|
||||||
// coordinates
|
|
||||||
opX,
|
|
||||||
opY,
|
|
||||||
opXAT,
|
|
||||||
opYAT,
|
|
||||||
|
|
||||||
// measuring
|
|
||||||
opLENGTH,
|
|
||||||
opAREA,
|
|
||||||
opPERIMETER,
|
|
||||||
|
|
||||||
// feature id
|
|
||||||
opID,
|
|
||||||
|
|
||||||
// comparison
|
|
||||||
opISNULL, // IS NULL
|
|
||||||
opISNOTNULL, // IS NOT NULL
|
|
||||||
opEQ, // =
|
|
||||||
opNE, // != resp. <>
|
|
||||||
opGT, // >
|
|
||||||
opLT, // <
|
|
||||||
opGE, // >=
|
|
||||||
opLE, // <=
|
|
||||||
opRegexp, // ~
|
|
||||||
opLike, // LIKE
|
|
||||||
opILike, // ILIKE
|
|
||||||
opIN, // IN
|
|
||||||
opNOTIN, // NOT IN
|
|
||||||
|
|
||||||
// string handling
|
|
||||||
opCONCAT,
|
|
||||||
opLOWER,
|
|
||||||
opUPPER,
|
|
||||||
opREPLACE,
|
|
||||||
opREGEXPREPLACE,
|
|
||||||
opSTRLEN,
|
|
||||||
opSUBSTR,
|
|
||||||
|
|
||||||
opROWNUM
|
|
||||||
};
|
|
||||||
|
|
||||||
//! constructors
|
|
||||||
QgsSearchTreeNode( Type type );
|
|
||||||
QgsSearchTreeNode( double number );
|
|
||||||
QgsSearchTreeNode( Operator op, QgsSearchTreeNode* left, QgsSearchTreeNode* right );
|
|
||||||
QgsSearchTreeNode( QString text, bool isColumnRef );
|
|
||||||
|
|
||||||
//! copy contructor - copies whole tree!
|
|
||||||
QgsSearchTreeNode( const QgsSearchTreeNode& node );
|
|
||||||
|
|
||||||
//! destructor - deletes children nodes (if any)
|
|
||||||
~QgsSearchTreeNode();
|
|
||||||
|
|
||||||
//! returns type of current node
|
|
||||||
Type type() const { return mType; }
|
|
||||||
|
|
||||||
//! node value getters
|
|
||||||
Operator op() const { return mOp; }
|
|
||||||
double number() const { return mNumber; }
|
|
||||||
QString columnRef() const { return mText; }
|
|
||||||
QString string() const { return mText; }
|
|
||||||
|
|
||||||
//! node value setters (type is set also)
|
|
||||||
void setOp( Operator op ) { mType = tOperator; mOp = op; }
|
|
||||||
void setNumber( double number ) { mType = tNumber; mNumber = number; }
|
|
||||||
void setColumnRef( const QString& str ) { mType = tColumnRef; mText = str; }
|
|
||||||
void setString( const QString& str ) { mType = tString; mText = str; stripText(); }
|
|
||||||
|
|
||||||
//! children
|
|
||||||
QgsSearchTreeNode* Left() { return mLeft; }
|
|
||||||
QgsSearchTreeNode* Right() { return mRight; }
|
|
||||||
void setLeft( QgsSearchTreeNode* left ) { mLeft = left; }
|
|
||||||
void setRight( QgsSearchTreeNode* right ) { mRight = right; }
|
|
||||||
|
|
||||||
//! returns search string that should be equal to original parsed string
|
|
||||||
QString makeSearchString();
|
|
||||||
|
|
||||||
//! checks whether the node tree is valid against supplied attributes
|
|
||||||
//! @note attribute and optional geom parameter replaced with feature in 1.6
|
|
||||||
bool checkAgainst( const QgsFieldMap& fields, QgsFeature &f );
|
|
||||||
|
|
||||||
//! @deprecated
|
|
||||||
Q_DECL_DEPRECATED bool checkAgainst( const QgsFieldMap& fields, const QgsAttributeMap& attributes, QgsGeometry* geom = 0 );
|
|
||||||
|
|
||||||
//! checks if there were errors during evaluation
|
|
||||||
bool hasError() { return ( !mError.isEmpty() ); }
|
|
||||||
|
|
||||||
//! returns error message
|
|
||||||
const QString& errorMsg() { return mError; }
|
|
||||||
|
|
||||||
//! wrapper around valueAgainst()
|
|
||||||
//! @note added in 1.4
|
|
||||||
bool getValue( QgsSearchTreeValue& value,
|
|
||||||
QgsSearchTreeNode* node,
|
|
||||||
const QgsFieldMap& fields,
|
|
||||||
QgsFeature &f );
|
|
||||||
|
|
||||||
//! @deprecated
|
|
||||||
Q_DECL_DEPRECATED bool getValue( QgsSearchTreeValue& value,
|
|
||||||
QgsSearchTreeNode* node,
|
|
||||||
const QgsFieldMap &fields,
|
|
||||||
const QgsAttributeMap &attributes,
|
|
||||||
QgsGeometry* geom = 0 );
|
|
||||||
|
|
||||||
//! return a list of referenced columns in the tree
|
|
||||||
//! @note added in 1.5
|
|
||||||
QStringList referencedColumns();
|
|
||||||
|
|
||||||
//! return a list of all attribute nodes
|
|
||||||
//! @note added in 1.5
|
|
||||||
QList<QgsSearchTreeNode*> columnRefNodes();
|
|
||||||
|
|
||||||
//! check whether there are any operators that need geometry (for area, length)
|
|
||||||
//! @note added in 1.5
|
|
||||||
bool needsGeometry();
|
|
||||||
|
|
||||||
//! return quoted column reference (in double quotes)
|
|
||||||
//! @note added in 1.5
|
|
||||||
static QString quotedColumnRef( QString name );
|
|
||||||
|
|
||||||
//! Set current row number within this tree.
|
|
||||||
//! This value is stored only in the nodes being $rownum operator - in mNumber
|
|
||||||
//! @note added in 1.6
|
|
||||||
void setCurrentRowNumber( int rownum );
|
|
||||||
|
|
||||||
//! append a node to the list
|
|
||||||
//! @note added in 1.6
|
|
||||||
void append( QgsSearchTreeNode * );
|
|
||||||
|
|
||||||
//! append nodelist to the list
|
|
||||||
//! @note added in 1.6
|
|
||||||
void append( QList<QgsSearchTreeNode*> );
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//! returns scalar value of node
|
|
||||||
QgsSearchTreeValue valueAgainst( const QgsFieldMap& fields, QgsFeature &f );
|
|
||||||
|
|
||||||
//! @deprecated
|
|
||||||
Q_DECL_DEPRECATED QgsSearchTreeValue valueAgainst( const QgsFieldMap& fields, const QgsAttributeMap& attributes, QgsGeometry* geom = 0 );
|
|
||||||
|
|
||||||
//! strips mText when node is of string type
|
|
||||||
void stripText();
|
|
||||||
|
|
||||||
//! strip mText when column reference is quoted
|
|
||||||
void stripColRef();
|
|
||||||
|
|
||||||
//! initialize node's internals
|
|
||||||
void init();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
//! node type
|
|
||||||
Type mType;
|
|
||||||
|
|
||||||
//! data
|
|
||||||
Operator mOp;
|
|
||||||
double mNumber;
|
|
||||||
QString mText;
|
|
||||||
QList<QgsSearchTreeNode *> mNodeList;
|
|
||||||
|
|
||||||
QString mError;
|
|
||||||
|
|
||||||
//! children
|
|
||||||
QgsSearchTreeNode* mLeft;
|
|
||||||
QgsSearchTreeNode* mRight;
|
|
||||||
|
|
||||||
/**For length() and area() functions*/
|
|
||||||
QgsDistanceArea* mCalc;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: put it into separate file
|
|
||||||
class CORE_EXPORT QgsSearchTreeValue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
valError,
|
|
||||||
valString,
|
|
||||||
valNumber,
|
|
||||||
valNull
|
|
||||||
};
|
|
||||||
|
|
||||||
QgsSearchTreeValue() { mType = valNull; }
|
|
||||||
QgsSearchTreeValue( QString string ) { mType = string.isNull() ? valNull : valString; mString = string; }
|
|
||||||
QgsSearchTreeValue( double number ) { mType = valNumber; mNumber = number; }
|
|
||||||
QgsSearchTreeValue( int error, QString errorMsg ) { mType = valError; mNumber = error; mString = errorMsg; }
|
|
||||||
|
|
||||||
static QgsSearchTreeValue compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2,
|
|
||||||
Qt::CaseSensitivity = Qt::CaseSensitive );
|
|
||||||
|
|
||||||
bool isNumeric() { return mType == valNumber; }
|
|
||||||
bool isError() { return mType == valError; }
|
|
||||||
bool isNull() { return mType == valNull; }
|
|
||||||
|
|
||||||
QString& string() { return mString; }
|
|
||||||
double number() { return mNumber; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type mType;
|
|
||||||
QString mString;
|
|
||||||
double mNumber;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -92,7 +92,6 @@ ADD_QGIS_TEST(geometrytest testqgsgeometry.cpp)
|
|||||||
ADD_QGIS_TEST(coordinatereferencesystemtest testqgscoordinatereferencesystem.cpp)
|
ADD_QGIS_TEST(coordinatereferencesystemtest testqgscoordinatereferencesystem.cpp)
|
||||||
ADD_DEPENDENCIES(qgis_coordinatereferencesystemtest synccrsdb)
|
ADD_DEPENDENCIES(qgis_coordinatereferencesystemtest synccrsdb)
|
||||||
ADD_QGIS_TEST(pointtest testqgspoint.cpp)
|
ADD_QGIS_TEST(pointtest testqgspoint.cpp)
|
||||||
ADD_QGIS_TEST(searchstringtest testqgssearchstring.cpp)
|
|
||||||
ADD_QGIS_TEST(vectorlayertest testqgsvectorlayer.cpp)
|
ADD_QGIS_TEST(vectorlayertest testqgsvectorlayer.cpp)
|
||||||
ADD_QGIS_TEST(rulebasedrenderertest testqgsrulebasedrenderer.cpp)
|
ADD_QGIS_TEST(rulebasedrenderertest testqgsrulebasedrenderer.cpp)
|
||||||
ADD_QGIS_TEST(ziplayertest testziplayer.cpp)
|
ADD_QGIS_TEST(ziplayertest testziplayer.cpp)
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
testqgssearchstring.cpp
|
|
||||||
--------------------------------------
|
|
||||||
Date : March 28, 2010
|
|
||||||
Copyright : (C) 2010 Martin Dobias
|
|
||||||
Email : wonder.sk at gmail.com
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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. *
|
|
||||||
* *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <QtTest>
|
|
||||||
|
|
||||||
#include <qgssearchstring.h>
|
|
||||||
#include <qgssearchtreenode.h>
|
|
||||||
#include <qgsfeature.h>
|
|
||||||
|
|
||||||
class TestQgsSearchString : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT;
|
|
||||||
private slots:
|
|
||||||
//void initTestCase();// will be called before the first testfunction is executed.
|
|
||||||
//void cleanupTestCase();// will be called after the last testfunction was executed.
|
|
||||||
//void init();// will be called before each testfunction is executed.
|
|
||||||
//void cleanup();// will be called after every testfunction.
|
|
||||||
|
|
||||||
void testLike();
|
|
||||||
void testRegexp();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString mReport;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool evalString( QString str )
|
|
||||||
{
|
|
||||||
QgsFeature f;
|
|
||||||
QgsSearchString ss;
|
|
||||||
ss.setString( str );
|
|
||||||
return ss.tree()->checkAgainst( QgsFieldMap(), f );
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestQgsSearchString::testLike()
|
|
||||||
{
|
|
||||||
QVERIFY( evalString( "'a' LIKE 'a'" ) );
|
|
||||||
QVERIFY( ! evalString( "'aa' LIKE 'a'" ) );
|
|
||||||
QVERIFY( ! evalString( "'a' LIKE 'b'" ) );
|
|
||||||
|
|
||||||
QVERIFY( evalString( "'abba' LIKE 'a%'" ) );
|
|
||||||
QVERIFY( ! evalString( "'abba' LIKE 'b%'" ) );
|
|
||||||
QVERIFY( evalString( "'abba' LIKE '%a'" ) );
|
|
||||||
QVERIFY( ! evalString( "'abba' LIKE '%b'" ) );
|
|
||||||
|
|
||||||
QVERIFY( evalString( "'abba' LIKE '%bb%'" ) );
|
|
||||||
QVERIFY( evalString( "'abba' LIKE 'a%a'" ) );
|
|
||||||
QVERIFY( ! evalString( "'abba' LIKE 'b%b'" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestQgsSearchString::testRegexp()
|
|
||||||
{
|
|
||||||
QVERIFY( evalString( "'a' ~ 'a'" ) );
|
|
||||||
QVERIFY( ! evalString( "'b' ~ 'a'" ) );
|
|
||||||
|
|
||||||
QVERIFY( evalString( "'abba' ~ 'a'" ) );
|
|
||||||
QVERIFY( ! evalString( "'abba' ~ 'aba'" ) );
|
|
||||||
QVERIFY( evalString( "'abba' ~ 'a.*a'" ) );
|
|
||||||
QVERIFY( evalString( "'abba' ~ 'a[b]+a'" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
QTEST_MAIN( TestQgsSearchString )
|
|
||||||
#include "moc_testqgssearchstring.cxx"
|
|
Loading…
x
Reference in New Issue
Block a user