00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "qgslogger.h"
00021 #include "qgsdistancearea.h"
00022 #include "qgsfield.h"
00023 #include "qgsgeometry.h"
00024 #include "qgssearchtreenode.h"
00025 #include <QRegExp>
00026 #include <QObject>
00027 #include <QSet>
00028 #include <QSettings>
00029 #include <iostream>
00030
00031 #ifndef Q_OS_MACX
00032 #include <cmath>
00033 #else
00034 #include <math.h>
00035 #endif
00036
00037
00038
00039 #define EVAL_STR(x) (x.length() ? x : "(empty)")
00040
00041 QgsSearchTreeNode::QgsSearchTreeNode( QgsSearchTreeNode::Type t )
00042 {
00043 Q_ASSERT( t == tNodeList );
00044 mType = t;
00045 mLeft = NULL;
00046 mRight = NULL;
00047
00048 init();
00049 }
00050
00051 QgsSearchTreeNode::QgsSearchTreeNode( double number )
00052 {
00053 mType = tNumber;
00054 mNumber = number;
00055 mLeft = NULL;
00056 mRight = NULL;
00057
00058 init();
00059 }
00060
00061
00062 QgsSearchTreeNode::QgsSearchTreeNode( Operator op,
00063 QgsSearchTreeNode* left,
00064 QgsSearchTreeNode* right )
00065 {
00066 mType = tOperator;
00067 mOp = op;
00068 mLeft = left;
00069 mRight = right;
00070
00071 init();
00072 }
00073
00074
00075 QgsSearchTreeNode::QgsSearchTreeNode( QString text, bool isColumnRef )
00076 {
00077 mLeft = NULL;
00078 mRight = NULL;
00079
00080 if ( isColumnRef )
00081 {
00082 mType = tColumnRef;
00083 mText = text;
00084 if ( text.at( 0 ) == '\"' )
00085 {
00086
00087 stripColRef();
00088 }
00089 }
00090 else
00091 {
00092 mType = tString;
00093 mText = text;
00094 stripText();
00095 }
00096
00097 init();
00098 }
00099
00100 QgsSearchTreeNode::QgsSearchTreeNode( const QgsSearchTreeNode& node )
00101 {
00102 mType = node.mType;
00103 mOp = node.mOp;
00104 mNumber = node.mNumber;
00105 mText = node.mText;
00106
00107
00108 if ( node.mLeft )
00109 mLeft = new QgsSearchTreeNode( *node.mLeft );
00110 else
00111 mLeft = NULL;
00112
00113 if ( node.mRight )
00114 mRight = new QgsSearchTreeNode( *node.mRight );
00115 else
00116 mRight = NULL;
00117
00118 foreach( QgsSearchTreeNode *lnode, node.mNodeList )
00119 mNodeList.append( new QgsSearchTreeNode( *lnode ) );
00120
00121 init();
00122 }
00123
00124
00125 QgsSearchTreeNode::~QgsSearchTreeNode()
00126 {
00127
00128
00129 if ( mLeft )
00130 delete mLeft;
00131
00132 if ( mRight )
00133 delete mRight;
00134
00135 while ( !mNodeList.isEmpty() )
00136 delete mNodeList.takeFirst();
00137
00138 delete mCalc;
00139 }
00140
00141
00142 void QgsSearchTreeNode::init()
00143 {
00144 mCalc = NULL;
00145
00146 if ( mType == tOperator && ( mOp == opLENGTH || mOp == opAREA ) )
00147 {
00148
00149 mCalc = new QgsDistanceArea;
00150 mCalc->setProjectionsEnabled( false );
00151 QSettings settings;
00152 QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", "WGS84" ).toString();
00153 mCalc->setEllipsoid( ellipsoid );
00154 }
00155 else if ( mType == tOperator && mOp == opROWNUM )
00156 {
00157
00158 mNumber = 0;
00159 }
00160 }
00161
00162 void QgsSearchTreeNode::stripText()
00163 {
00164
00165 mText = mText.mid( 1, mText.length() - 2 );
00166
00167
00168 mText.replace( QRegExp( "''" ), "'" );
00169
00170
00171 int index = 0;
00172 while (( index = mText.indexOf( '\\', index ) ) != -1 )
00173 {
00174 mText.remove( index, 1 );
00175 QChar chr;
00176 switch ( mText[index].toLatin1() )
00177 {
00178 case 'n': chr = '\n'; break;
00179 case 't': chr = '\t'; break;
00180 case '\\': chr = '\\'; break;
00181 case '\'': chr = '\''; break;
00182 default: chr = '?'; break;
00183 }
00184 mText[index++] = chr;
00185 }
00186
00187 }
00188
00189 void QgsSearchTreeNode::stripColRef()
00190 {
00191
00192 mText = mText.mid( 1, mText.length() - 2 );
00193
00194
00195 mText.replace( QRegExp( "\"\"" ), "\"" );
00196 }
00197
00198 QString QgsSearchTreeNode::quotedColumnRef( QString name )
00199 {
00200 return QString( "\"%1\"" ).arg( name.replace( "\"", "\"\"" ) );
00201 }
00202
00203
00204 QString QgsSearchTreeNode::makeSearchString()
00205 {
00206 QString str;
00207 if ( mType == tOperator )
00208 {
00209 if ( mOp == opSQRT || mOp == opSIN || mOp == opCOS || mOp == opTAN ||
00210 mOp == opASIN || mOp == opACOS || mOp == opATAN ||
00211 mOp == opTOINT || mOp == opTOREAL || mOp == opTOSTRING ||
00212 mOp == opLOWER || mOp == opUPPER )
00213 {
00214
00215 switch ( mOp )
00216 {
00217 case opSQRT: str += "sqrt"; break;
00218 case opSIN: str += "sin"; break;
00219 case opCOS: str += "cos"; break;
00220 case opTAN: str += "tan"; break;
00221 case opASIN: str += "asin"; break;
00222 case opACOS: str += "acos"; break;
00223 case opATAN: str += "atan"; break;
00224 case opTOINT: str += "to int"; break;
00225 case opTOREAL: str += "to real"; break;
00226 case opTOSTRING: str += "to string"; break;
00227 case opLOWER: str += "lower"; break;
00228 case opUPPER: str += "upper"; break;
00229 default: str += "?";
00230 }
00231
00232 str += QString( "(%1)" ).arg( mLeft->makeSearchString() );
00233 }
00234 else if ( mOp == opLENGTH || mOp == opAREA || mOp == opROWNUM || mOp == opID )
00235 {
00236
00237 switch ( mOp )
00238 {
00239 case opLENGTH: str += "$length"; break;
00240 case opAREA: str += "$area"; break;
00241 case opROWNUM: str += "$rownum"; break;
00242 case opID: str += "$id"; break;
00243 default: str += "?";
00244 }
00245 }
00246 else if ( mOp == opNOT )
00247 {
00248
00249 str += "(NOT " + mLeft->makeSearchString() + ")";
00250 }
00251 else
00252 {
00253
00254 str += "(";
00255 if ( mLeft )
00256 {
00257 str += mLeft->makeSearchString();
00258 }
00259 switch ( mOp )
00260 {
00261 case opAND: str += " AND "; break;
00262 case opOR: str += " OR "; break;
00263
00264 case opPLUS: str += "+"; break;
00265 case opMINUS: str += "-"; break;
00266 case opMUL: str += "*"; break;
00267 case opDIV: str += "/"; break;
00268 case opPOW: str += "^"; break;
00269
00270 case opEQ: str += " = "; break;
00271 case opNE: str += " != "; break;
00272 case opGT: str += " > "; break;
00273 case opLT: str += " < "; break;
00274 case opGE: str += " >= "; break;
00275 case opLE: str += " <= "; break;
00276
00277 case opISNULL: str += " IS NULL"; break;
00278 case opISNOTNULL: str += " IS NOT NULL"; break;
00279
00280 case opRegexp: str += " ~ "; break;
00281 case opLike: str += " LIKE "; break;
00282 case opILike: str += " ILIKE "; break;
00283 case opIN: str += " IN "; break;
00284 case opNOTIN: str += " NOT IN "; break;
00285
00286 case opCONCAT: str += " || "; break;
00287
00288 default: str += " ? ";
00289 }
00290
00291 if ( mRight )
00292 {
00293 str += mRight->makeSearchString();
00294 }
00295 str += ")";
00296 }
00297 }
00298 else if ( mType == tNumber )
00299 {
00300 str += QString::number( mNumber );
00301 }
00302 else if ( mType == tString || mType == tColumnRef )
00303 {
00304 str += mText;
00305 }
00306 else if ( mType == tNodeList )
00307 {
00308 QStringList items;
00309 foreach( QgsSearchTreeNode *node, mNodeList )
00310 {
00311 items << node->makeSearchString();
00312 }
00313
00314 str += "(" + items.join( "," ) + ")";
00315 }
00316 else
00317 {
00318 str += "unknown_node_type:";
00319 str += QString::number( mType );
00320 }
00321
00322 return str;
00323 }
00324
00325 QStringList QgsSearchTreeNode::referencedColumns()
00326 {
00327 QList<QgsSearchTreeNode*> columnNodeList = columnRefNodes();
00328 QSet<QString> columnStringSet;
00329
00330 QList<QgsSearchTreeNode*>::const_iterator nodeIt = columnNodeList.constBegin();
00331 for ( ; nodeIt != columnNodeList.constEnd(); ++nodeIt )
00332 {
00333 columnStringSet.insert(( *nodeIt )->columnRef() );
00334 }
00335 return columnStringSet.toList();
00336 }
00337
00338 QList<QgsSearchTreeNode*> QgsSearchTreeNode::columnRefNodes()
00339 {
00340 QList<QgsSearchTreeNode*> nodeList;
00341 if ( mType == tOperator )
00342 {
00343 if ( mLeft )
00344 {
00345 nodeList += mLeft->columnRefNodes();
00346 }
00347 if ( mRight )
00348 {
00349 nodeList += mRight->columnRefNodes();
00350 }
00351 }
00352 else if ( mType == tColumnRef )
00353 {
00354 nodeList.push_back( this );
00355 }
00356 return nodeList;
00357 }
00358
00359 bool QgsSearchTreeNode::needsGeometry()
00360 {
00361 if ( mType == tOperator )
00362 {
00363 if ( mOp == opLENGTH || mOp == opAREA )
00364 return true;
00365
00366 if ( mLeft && mLeft->needsGeometry() )
00367 return true;
00368 if ( mRight && mRight->needsGeometry() )
00369 return true;
00370 return false;
00371 }
00372 else
00373 {
00374 return false;
00375 }
00376 }
00377
00378 bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, const QgsAttributeMap &attributes, QgsGeometry* geom )
00379 {
00380 QgsFeature f;
00381 f.setAttributeMap( attributes );
00382 if ( geom )
00383 f.setGeometry( *geom );
00384 return checkAgainst( fields, f );
00385 }
00386
00387 bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, QgsFeature &f )
00388 {
00389 QgsDebugMsgLevel( "checkAgainst: " + makeSearchString(), 2 );
00390
00391 mError = "";
00392
00393
00394 if ( mType != tOperator )
00395 {
00396 mError = QObject::tr( "Expected operator, got scalar value!" );
00397 return false;
00398 }
00399
00400 QgsSearchTreeValue value1, value2;
00401 int res;
00402
00403 switch ( mOp )
00404 {
00405 case opNOT:
00406 return !mLeft->checkAgainst( fields, f );
00407
00408 case opAND:
00409 if ( !mLeft->checkAgainst( fields, f ) )
00410 return false;
00411 return mRight->checkAgainst( fields, f );
00412
00413 case opOR:
00414 if ( mLeft->checkAgainst( fields, f ) )
00415 return true;
00416 return mRight->checkAgainst( fields, f );
00417
00418 case opISNULL:
00419 case opISNOTNULL:
00420 if ( !getValue( value1, mLeft, fields, f ) )
00421 return false;
00422
00423 return ( mOp == opISNULL ) == value1.isNull();
00424
00425 case opEQ:
00426 case opNE:
00427 case opGT:
00428 case opLT:
00429 case opGE:
00430 case opLE:
00431 if ( !getValue( value1, mLeft, fields, f ) || !getValue( value2, mRight, fields, f ) )
00432 return false;
00433
00434 if ( value1.isNull() || value2.isNull() )
00435 {
00436
00437 return false;
00438 }
00439
00440 res = QgsSearchTreeValue::compare( value1, value2 );
00441
00442 switch ( mOp )
00443 {
00444 case opEQ: return res == 0;
00445 case opNE: return res != 0;
00446 case opGT: return res > 0;
00447 case opLT: return res < 0;
00448 case opGE: return res >= 0;
00449 case opLE: return res <= 0;
00450 default:
00451 mError = QObject::tr( "Unexpected state when evaluating operator!" );
00452 return false;
00453 }
00454
00455 case opIN:
00456 case opNOTIN:
00457 {
00458 if ( !getValue( value1, mLeft, fields, f ) ||
00459 !mRight || mRight->type() != tNodeList )
00460 {
00461 return false;
00462 }
00463
00464 foreach( QgsSearchTreeNode *node, mRight->mNodeList )
00465 {
00466 if ( !getValue( value2, node, fields, f ) )
00467 {
00468 mError = QObject::tr( "Could not retrieve value of list value" );
00469 return false;
00470 }
00471
00472 res = QgsSearchTreeValue::compare( value1, value2 );
00473
00474 if ( res == 0 )
00475 {
00476
00477 return mOp == opIN;
00478 }
00479 }
00480
00481 return mOp == opNOTIN;
00482 }
00483 break;
00484
00485 case opRegexp:
00486 case opLike:
00487 case opILike:
00488 {
00489 if ( !getValue( value1, mLeft, fields, f ) ||
00490 !getValue( value2, mRight, fields, f ) )
00491 return false;
00492
00493
00494
00495
00496
00497
00498 if ( value1.isNumeric() || value2.isNumeric() )
00499 {
00500 mError = QObject::tr( "Regular expressions on numeric values don't make sense. Use comparison instead." );
00501 return false;
00502 }
00503
00504
00505
00506 QString str = value2.string();
00507 if ( mOp == opLike || mOp == opILike )
00508 {
00509
00510 str.replace( "%", ".*" );
00511 str.replace( "_", "." );
00512 return QRegExp( str, mOp == opLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( value1.string() );
00513 }
00514 else
00515 {
00516 return QRegExp( str ).indexIn( value1.string() ) != -1;
00517 }
00518 }
00519
00520 default:
00521 mError = QObject::tr( "Unknown operator: %1" ).arg( mOp );
00522 }
00523
00524 return false;
00525 }
00526
00527 bool QgsSearchTreeNode::getValue( QgsSearchTreeValue& value,
00528 QgsSearchTreeNode* node,
00529 const QgsFieldMap &fields,
00530 const QgsAttributeMap &attributes,
00531 QgsGeometry* geom )
00532 {
00533 QgsFeature f;
00534 f.setAttributeMap( attributes );
00535 if ( geom )
00536 f.setGeometry( *geom );
00537 return getValue( value, node, fields, f );
00538 }
00539
00540 bool QgsSearchTreeNode::getValue( QgsSearchTreeValue& value,
00541 QgsSearchTreeNode* node,
00542 const QgsFieldMap& fields,
00543 QgsFeature &f )
00544 {
00545 value = node->valueAgainst( fields, f );
00546 if ( value.isError() )
00547 {
00548 switch (( int )value.number() )
00549 {
00550 case 1:
00551 mError = QObject::tr( "Referenced column wasn't found: %1" ).arg( value.string() );
00552 break;
00553 case 2:
00554 mError = QObject::tr( "Division by zero." );
00555 break;
00556
00557
00558 case 3:
00559 mError = QObject::tr( "Unknown operator: %1" ).arg( value.string() );
00560 break;
00561 case 4:
00562 mError = QObject::tr( "Unknown token: %1" ).arg( value.string() );
00563 break;
00564 default:
00565 mError = QObject::tr( "Unknown error!" );
00566 break;
00567 }
00568 return false;
00569 }
00570 return true;
00571 }
00572
00573 QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields,
00574 const QgsAttributeMap &attributes,
00575 QgsGeometry* geom )
00576 {
00577 QgsFeature f;
00578 f.setAttributeMap( attributes );
00579 if ( geom )
00580 f.setGeometry( *geom );
00581 return valueAgainst( fields, f );
00582 }
00583
00584 QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields, QgsFeature &f )
00585 {
00586 QgsDebugMsgLevel( "valueAgainst: " + makeSearchString(), 2 );
00587
00588 switch ( mType )
00589 {
00590
00591 case tNumber:
00592 QgsDebugMsgLevel( "number: " + QString::number( mNumber ), 2 );
00593 return QgsSearchTreeValue( mNumber );
00594
00595 case tString:
00596 QgsDebugMsgLevel( "text: " + EVAL_STR( mText ), 2 );
00597 return QgsSearchTreeValue( mText );
00598
00599 case tColumnRef:
00600 {
00601 QgsDebugMsgLevel( "column (" + mText.toLower() + "): ", 2 );
00602
00603 QgsFieldMap::const_iterator it;
00604 for ( it = fields.begin(); it != fields.end(); it++ )
00605 {
00606 if ( it->name().toLower() == mText.toLower() )
00607 break;
00608 }
00609
00610 if ( it == fields.end() )
00611 {
00612
00613 QgsDebugMsgLevel( "ERROR!", 2 );
00614 return QgsSearchTreeValue( 1, mText );
00615 }
00616
00617
00618 QVariant val = f.attributeMap()[it.key()];
00619 if ( val.isNull() )
00620 {
00621 QgsDebugMsgLevel( " NULL", 2 );
00622 return QgsSearchTreeValue();
00623 }
00624 else if ( val.type() == QVariant::Bool || val.type() == QVariant::Int || val.type() == QVariant::Double )
00625 {
00626 QgsDebugMsgLevel( " number: " + QString::number( val.toDouble() ), 2 );
00627 return QgsSearchTreeValue( val.toDouble() );
00628 }
00629 else
00630 {
00631 QgsDebugMsgLevel( " text: " + EVAL_STR( val.toString() ), 2 );
00632 return QgsSearchTreeValue( val.toString() );
00633 }
00634
00635 }
00636
00637
00638 case tOperator:
00639 {
00640 QgsSearchTreeValue value1, value2;
00641 if ( mLeft )
00642 {
00643 if ( !getValue( value1, mLeft, fields, f ) ) return value1;
00644 }
00645 if ( mRight )
00646 {
00647 if ( !getValue( value2, mRight, fields, f ) ) return value2;
00648 }
00649
00650 if ( mOp == opLENGTH || mOp == opAREA )
00651 {
00652 if ( !f.geometry() )
00653 {
00654 return QgsSearchTreeValue( 2, "Geometry is 0" );
00655 }
00656
00657
00658 if ( mOp == opLENGTH && f.geometry()->type() != QGis::Line )
00659 {
00660 return QgsSearchTreeValue( 0 );
00661 }
00662 if ( mOp == opAREA && f.geometry()->type() != QGis::Polygon )
00663 {
00664 return QgsSearchTreeValue( 0 );
00665 }
00666 return QgsSearchTreeValue( mCalc->measure( f.geometry() ) );
00667 }
00668
00669 if ( mOp == opID )
00670 {
00671 return QgsSearchTreeValue( f.id() );
00672 }
00673
00674 if ( mOp == opROWNUM )
00675 {
00676
00677 return QgsSearchTreeValue( mNumber );
00678 }
00679
00680
00681 if ( !mRight && !value1.isNumeric() )
00682 {
00683 if ( mOp == opTOINT )
00684 {
00685 return QgsSearchTreeValue( value1.string().toInt() );
00686 }
00687 else if ( mOp == opTOREAL )
00688 {
00689 return QgsSearchTreeValue( value1.string().toDouble() );
00690 }
00691 }
00692
00693
00694 if ( mLeft && mRight && !value1.isNumeric() && !value2.isNumeric() )
00695 {
00696
00697
00698 if ( mOp == opPLUS )
00699 {
00700 return QgsSearchTreeValue( value1.string() + value2.string() );
00701 }
00702 }
00703
00704
00705 if ( mLeft && mRight && mOp == opCONCAT )
00706 {
00707 if ( value1.isNumeric() && value2.isNumeric() )
00708 {
00709 return QgsSearchTreeValue( 5, "Operator doesn't match the argument types." );
00710 }
00711 else
00712 {
00713 QString arg1 = value1.isNumeric() ? QString::number( value1.number() ) : value1.string();
00714 QString arg2 = value2.isNumeric() ? QString::number( value2.number() ) : value2.string();
00715 return QgsSearchTreeValue( arg1 + arg2 );
00716 }
00717 }
00718
00719
00720 double val1, val2;
00721 if ( value1.isNumeric() )
00722 val1 = value1.number();
00723 else
00724 val1 = value1.string().toDouble();
00725 if ( value2.isNumeric() )
00726 val2 = value2.number();
00727 else
00728 val2 = value2.string().toDouble();
00729
00730 switch ( mOp )
00731 {
00732 case opPLUS:
00733 return QgsSearchTreeValue( val1 + val2 );
00734 case opMINUS:
00735 return QgsSearchTreeValue( val1 - val2 );
00736 case opMUL:
00737 return QgsSearchTreeValue( val1 * val2 );
00738 case opDIV:
00739 if ( val2 == 0 )
00740 return QgsSearchTreeValue( 2, "" );
00741 else
00742 return QgsSearchTreeValue( val1 / val2 );
00743 default:
00744 return QgsSearchTreeValue( 3, QString::number( mOp ) );
00745 case opPOW:
00746 if (( val1 == 0 && val2 < 0 ) || ( val2 < 0 && ( val2 - floor( val2 ) ) > 0 ) )
00747 {
00748 return QgsSearchTreeValue( 4, "Error in power function" );
00749 }
00750 return QgsSearchTreeValue( pow( val1, val2 ) );
00751 case opSQRT:
00752 return QgsSearchTreeValue( sqrt( val1 ) );
00753 case opSIN:
00754 return QgsSearchTreeValue( sin( val1 ) );
00755 case opCOS:
00756 return QgsSearchTreeValue( cos( val1 ) );
00757 case opTAN:
00758 return QgsSearchTreeValue( tan( val1 ) );
00759 case opASIN:
00760 return QgsSearchTreeValue( asin( val1 ) );
00761 case opACOS:
00762 return QgsSearchTreeValue( acos( val1 ) );
00763 case opATAN:
00764 return QgsSearchTreeValue( atan( val1 ) );
00765 case opTOINT:
00766 return QgsSearchTreeValue( int( val1 ) );
00767 case opTOREAL:
00768 return QgsSearchTreeValue( val1 );
00769 case opTOSTRING:
00770 return QgsSearchTreeValue( QString::number( val1 ) );
00771 case opLOWER:
00772 return QgsSearchTreeValue( value1.string().toLower() );
00773 case opUPPER:
00774 return QgsSearchTreeValue( value1.string().toUpper() );
00775 }
00776 }
00777
00778 default:
00779 return QgsSearchTreeValue( 4, QString::number( mType ) );
00780 }
00781 }
00782
00783
00784 void QgsSearchTreeNode::setCurrentRowNumber( int rownum )
00785 {
00786 if ( mType == tOperator )
00787 {
00788 if ( mOp == opROWNUM )
00789 mNumber = rownum;
00790 else
00791 {
00792
00793 if ( mLeft )
00794 mLeft->setCurrentRowNumber( rownum );
00795 if ( mRight )
00796 mRight->setCurrentRowNumber( rownum );
00797 }
00798 }
00799 }
00800
00801 void QgsSearchTreeNode::append( QgsSearchTreeNode *node )
00802 {
00803 Q_ASSERT( mType == tNodeList );
00804 mNodeList.append( node );
00805 }
00806
00807 void QgsSearchTreeNode::append( QList<QgsSearchTreeNode *> nodes )
00808 {
00809 foreach( QgsSearchTreeNode *node, nodes )
00810 mNodeList.append( node );
00811 }
00812
00813 int QgsSearchTreeValue::compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2, Qt::CaseSensitivity cs )
00814 {
00815 if ( value1.isNumeric() || value2.isNumeric() )
00816 {
00817
00818
00819
00820 double val1, val2;
00821 if ( value1.isNumeric() )
00822 val1 = value1.number();
00823 else
00824 val1 = value1.string().toDouble();
00825 if ( value2.isNumeric() )
00826 val2 = value2.number();
00827 else
00828 val2 = value2.string().toDouble();
00829
00830 QgsDebugMsgLevel( "NUM_COMP: " + QString::number( val1 ) + " ~ " + QString::number( val2 ), 2 );
00831
00832 if ( val1 < val2 )
00833 return -1;
00834 else if ( val1 > val2 )
00835 return 1;
00836 else
00837 return 0;
00838 }
00839 else
00840 {
00841
00842 return value1.string().compare( value2.string(), cs );
00843 }
00844 }