QGIS API Documentation  master-6227475
src/core/qgsexpression.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               qgsexpression.cpp
00003                              -------------------
00004     begin                : August 2011
00005     copyright            : (C) 2011 Martin Dobias
00006     email                : wonder.sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 #include "qgsexpression.h"
00017 
00018 #include <QtDebug>
00019 #include <QDomDocument>
00020 #include <QSettings>
00021 #include <QDate>
00022 #include <QRegExp>
00023 #include <QColor>
00024 
00025 #include <math.h>
00026 #include <limits>
00027 
00028 #include "qgsdistancearea.h"
00029 #include "qgsfeature.h"
00030 #include "qgsgeometry.h"
00031 #include "qgslogger.h"
00032 #include "qgsogcutils.h"
00033 #include "qgsvectorlayer.h"
00034 #include "qgssymbollayerv2utils.h"
00035 #include "qgsvectorcolorrampv2.h"
00036 #include "qgsstylev2.h"
00037 
00038 // from parser
00039 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
00040 
00041 QgsExpression::Interval::~Interval() {}
00042 
00043 QgsExpression::Interval QgsExpression::Interval::invalidInterVal()
00044 {
00045   QgsExpression::Interval inter = QgsExpression::Interval();
00046   inter.setValid( false );
00047   return inter;
00048 }
00049 
00050 QgsExpression::Interval QgsExpression::Interval::fromString( QString string )
00051 {
00052   int seconds = 0;
00053   QRegExp rx( "(\\d?\\.?\\d+\\s+[a-z]+)", Qt::CaseInsensitive );
00054   QStringList list;
00055   int pos = 0;
00056 
00057   while (( pos = rx.indexIn( string, pos ) ) != -1 )
00058   {
00059     list << rx.cap( 1 );
00060     pos += rx.matchedLength();
00061   }
00062 
00063   foreach ( QString match, list )
00064   {
00065     QStringList split = match.split( QRegExp( "\\s+" ) );
00066     bool ok;
00067     int value = split.at( 0 ).toInt( &ok );
00068     if ( !ok )
00069     {
00070       continue;
00071     }
00072 
00073     if ( match.contains( "day", Qt::CaseInsensitive ) ||
00074          match.contains( QObject::tr( "day", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) ||
00075          match.contains( QObject::tr( "days", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) )
00076       seconds += value * QgsExpression::Interval::DAY;
00077     if ( match.contains( "week", Qt::CaseInsensitive ) ||
00078          match.contains( QObject::tr( "week", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) ||
00079          match.contains( QObject::tr( "weeks", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) )
00080       seconds += value * QgsExpression::Interval::WEEKS;
00081     if ( match.contains( "month", Qt::CaseInsensitive ) ||
00082          match.contains( QObject::tr( "month", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) ||
00083          match.contains( QObject::tr( "months", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) )
00084       seconds += value * QgsExpression::Interval::MONTHS;
00085     if ( match.contains( "year", Qt::CaseInsensitive ) ||
00086          match.contains( QObject::tr( "year", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) ||
00087          match.contains( QObject::tr( "years", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) )
00088       seconds += value * QgsExpression::Interval::YEARS;
00089     if ( match.contains( "second", Qt::CaseInsensitive ) ||
00090          match.contains( QObject::tr( "second", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) ||
00091          match.contains( QObject::tr( "seconds", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) )
00092       seconds += value;
00093     if ( match.contains( "minute", Qt::CaseInsensitive ) ||
00094          match.contains( QObject::tr( "minute", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) ||
00095          match.contains( QObject::tr( "minutes", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) )
00096       seconds += value * QgsExpression::Interval::MINUTE;
00097     if ( match.contains( "hour", Qt::CaseInsensitive ) ||
00098          match.contains( QObject::tr( "hour", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) ||
00099          match.contains( QObject::tr( "hours", "Note: Word is part matched in code" ), Qt::CaseInsensitive ) )
00100       seconds += value * QgsExpression::Interval::HOUR;
00101   }
00102 
00103   // If we can't parse the string at all then we just return invalid
00104   if ( seconds == 0 )
00105     return QgsExpression::Interval::invalidInterVal();
00106 
00107   return QgsExpression::Interval( seconds );
00108 }
00109 
00110 bool QgsExpression::Interval::operator==( const QgsExpression::Interval& other ) const
00111 {
00112   return ( mSeconds == other.mSeconds );
00113 }
00114 
00116 // three-value logic
00117 
00118 enum TVL
00119 {
00120   False,
00121   True,
00122   Unknown
00123 };
00124 
00125 static TVL AND[3][3] =
00126 {
00127   // false  true    unknown
00128   { False, False,   False },   // false
00129   { False, True,    Unknown }, // true
00130   { False, Unknown, Unknown }  // unknown
00131 };
00132 
00133 static TVL OR[3][3] =
00134 {
00135   { False,   True, Unknown },  // false
00136   { True,    True, True },     // true
00137   { Unknown, True, Unknown }   // unknown
00138 };
00139 
00140 static TVL NOT[3] = { True, False, Unknown };
00141 
00142 static QVariant tvl2variant( TVL v )
00143 {
00144   switch ( v )
00145   {
00146     case False: return 0;
00147     case True: return 1;
00148     case Unknown:
00149     default:
00150       return QVariant();
00151   }
00152 }
00153 
00154 #define TVL_True     QVariant(1)
00155 #define TVL_False    QVariant(0)
00156 #define TVL_Unknown  QVariant()
00157 
00159 // QVariant checks and conversions
00160 
00161 inline bool isIntSafe( const QVariant& v )
00162 {
00163   if ( v.type() == QVariant::Int ) return true;
00164   if ( v.type() == QVariant::Double ) return false;
00165   if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
00166   return false;
00167 }
00168 inline bool isDoubleSafe( const QVariant& v )
00169 {
00170   if ( v.type() == QVariant::Double || v.type() == QVariant::Int ) return true;
00171   if ( v.type() == QVariant::String ) { bool ok; v.toString().toDouble( &ok ); return ok; }
00172   return false;
00173 }
00174 
00175 inline bool isDateTimeSafe( const QVariant& v )
00176 {
00177   return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
00178          v.type() == QVariant::Time;
00179 }
00180 
00181 inline bool isIntervalSafe( const QVariant& v )
00182 {
00183   if ( v.canConvert<QgsExpression::Interval>() )
00184   {
00185     return true;
00186   }
00187 
00188   if ( v.type() == QVariant::String )
00189   {
00190     return QgsExpression::Interval::fromString( v.toString() ).isValid();
00191   }
00192   return false;
00193 }
00194 
00195 inline bool isNull( const QVariant& v ) { return v.isNull(); }
00196 
00198 // evaluation error macros
00199 
00200 #define ENSURE_NO_EVAL_ERROR   {  if (parent->hasEvalError()) return QVariant(); }
00201 #define SET_EVAL_ERROR(x)   { parent->setEvalErrorString(x); return QVariant(); }
00202 
00204 // operators
00205 
00206 const char* QgsExpression::BinaryOperatorText[] =
00207 {
00208   "OR", "AND",
00209   "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
00210   "+", "-", "*", "/", "%", "^",
00211   "||"
00212 };
00213 
00214 const char* QgsExpression::UnaryOperatorText[] =
00215 {
00216   "NOT", "-"
00217 };
00218 
00220 // functions
00221 
00222 // implicit conversion to string
00223 static QString getStringValue( const QVariant& value, QgsExpression* )
00224 {
00225   return value.toString();
00226 }
00227 
00228 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
00229 {
00230   bool ok;
00231   double x = value.toDouble( &ok );
00232   if ( !ok )
00233   {
00234     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
00235     return 0;
00236   }
00237   return x;
00238 }
00239 
00240 static int getIntValue( const QVariant& value, QgsExpression* parent )
00241 {
00242   bool ok;
00243   qint64 x = value.toLongLong( &ok );
00244   if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
00245   {
00246     return x;
00247   }
00248   else
00249   {
00250     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
00251     return 0;
00252   }
00253 }
00254 
00255 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
00256 {
00257   QDateTime d = value.toDateTime();
00258   if ( d.isValid() )
00259   {
00260     return d;
00261   }
00262   else
00263   {
00264     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
00265     return QDateTime();
00266   }
00267 }
00268 
00269 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
00270 {
00271   QDate d = value.toDate();
00272   if ( d.isValid() )
00273   {
00274     return d;
00275   }
00276   else
00277   {
00278     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
00279     return QDate();
00280   }
00281 }
00282 
00283 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
00284 {
00285   QTime t = value.toTime();
00286   if ( t.isValid() )
00287   {
00288     return t;
00289   }
00290   else
00291   {
00292     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
00293     return QTime();
00294   }
00295 }
00296 
00297 static QgsExpression::Interval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
00298 {
00299   if ( value.canConvert<QgsExpression::Interval>() )
00300     return value.value<QgsExpression::Interval>();
00301 
00302   QgsExpression::Interval inter = QgsExpression::Interval::fromString( value.toString() );
00303   if ( inter.isValid() )
00304   {
00305     return inter;
00306   }
00307   // If we get here then we can't convert so we just error and return invalid.
00308   if ( report_error )
00309     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
00310 
00311   return QgsExpression::Interval::invalidInterVal();
00312 }
00313 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
00314 {
00315   if ( value.canConvert<QgsGeometry>() )
00316     return value.value<QgsGeometry>();
00317 
00318   parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
00319   return QgsGeometry();
00320 }
00321 
00322 
00323 // this handles also NULL values
00324 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
00325 {
00326   // we need to convert to TVL
00327   if ( value.isNull() )
00328     return Unknown;
00329 
00330   if ( value.type() == QVariant::Int )
00331     return value.toInt() != 0 ? True : False;
00332 
00333   bool ok;
00334   double x = value.toDouble( &ok );
00335   if ( !ok )
00336   {
00337     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
00338     return Unknown;
00339   }
00340   return x != 0 ? True : False;
00341 }
00342 
00344 
00345 static QVariant fcnSqrt( const QVariantList& values, const QgsFeature* /*f*/, QgsExpression* parent )
00346 {
00347   double x = getDoubleValue( values.at( 0 ), parent );
00348   return QVariant( sqrt( x ) );
00349 }
00350 
00351 static QVariant fcnAbs( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
00352 {
00353   double val = getDoubleValue( values.at( 0 ), parent );
00354   return QVariant( fabs( val ) );
00355 }
00356 
00357 static QVariant fcnSin( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00358 {
00359   double x = getDoubleValue( values.at( 0 ), parent );
00360   return QVariant( sin( x ) );
00361 }
00362 static QVariant fcnCos( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00363 {
00364   double x = getDoubleValue( values.at( 0 ), parent );
00365   return QVariant( cos( x ) );
00366 }
00367 static QVariant fcnTan( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00368 {
00369   double x = getDoubleValue( values.at( 0 ), parent );
00370   return QVariant( tan( x ) );
00371 }
00372 static QVariant fcnAsin( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00373 {
00374   double x = getDoubleValue( values.at( 0 ), parent );
00375   return QVariant( asin( x ) );
00376 }
00377 static QVariant fcnAcos( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00378 {
00379   double x = getDoubleValue( values.at( 0 ), parent );
00380   return QVariant( acos( x ) );
00381 }
00382 static QVariant fcnAtan( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00383 {
00384   double x = getDoubleValue( values.at( 0 ), parent );
00385   return QVariant( atan( x ) );
00386 }
00387 static QVariant fcnAtan2( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00388 {
00389   double y = getDoubleValue( values.at( 0 ), parent );
00390   double x = getDoubleValue( values.at( 1 ), parent );
00391   return QVariant( atan2( y, x ) );
00392 }
00393 static QVariant fcnExp( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00394 {
00395   double x = getDoubleValue( values.at( 0 ), parent );
00396   return QVariant( exp( x ) );
00397 }
00398 static QVariant fcnLn( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00399 {
00400   double x = getDoubleValue( values.at( 0 ), parent );
00401   if ( x <= 0 )
00402     return QVariant();
00403   return QVariant( log( x ) );
00404 }
00405 static QVariant fcnLog10( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00406 {
00407   double x = getDoubleValue( values.at( 0 ), parent );
00408   if ( x <= 0 )
00409     return QVariant();
00410   return QVariant( log10( x ) );
00411 }
00412 static QVariant fcnLog( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00413 {
00414   double b = getDoubleValue( values.at( 0 ), parent );
00415   double x = getDoubleValue( values.at( 1 ), parent );
00416   if ( x <= 0 || b <= 0 )
00417     return QVariant();
00418   return QVariant( log( x ) / log( b ) );
00419 }
00420 static QVariant fcnRndF( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00421 {
00422   double min = getDoubleValue( values.at( 0 ), parent );
00423   double max = getDoubleValue( values.at( 1 ), parent );
00424   if ( max < min )
00425     return QVariant();
00426 
00427   // Return a random double in the range [min, max] (inclusive)
00428   double f = ( double )rand() / RAND_MAX;
00429   return QVariant( min + f * ( max - min ) ) ;
00430 }
00431 static QVariant fcnRnd( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00432 {
00433   int min = getIntValue( values.at( 0 ), parent );
00434   int max = getIntValue( values.at( 1 ), parent );
00435   if ( max < min )
00436     return QVariant();
00437 
00438   // Return a random integer in the range [min, max] (inclusive)
00439   return QVariant( min + ( rand() % ( int )( max - min + 1 ) ) );
00440 }
00441 
00442 static QVariant fcnLinearScale( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00443 {
00444   double val = getDoubleValue( values.at( 0 ), parent );
00445   double domainMin = getDoubleValue( values.at( 1 ), parent );
00446   double domainMax = getDoubleValue( values.at( 2 ), parent );
00447   double rangeMin = getDoubleValue( values.at( 3 ), parent );
00448   double rangeMax = getDoubleValue( values.at( 4 ), parent );
00449 
00450   if ( domainMin >= domainMax )
00451   {
00452     parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
00453     return QVariant();
00454   }
00455 
00456   // outside of domain?
00457   if ( val >= domainMax )
00458   {
00459     return rangeMax;
00460   }
00461   else if ( val <= domainMin )
00462   {
00463     return rangeMin;
00464   }
00465 
00466   // calculate linear scale
00467   double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
00468   double c = rangeMin - ( domainMin * m );
00469 
00470   // Return linearly scaled value
00471   return QVariant( m * val + c );
00472 }
00473 
00474 static QVariant fcnExpScale( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00475 {
00476   double val = getDoubleValue( values.at( 0 ), parent );
00477   double domainMin = getDoubleValue( values.at( 1 ), parent );
00478   double domainMax = getDoubleValue( values.at( 2 ), parent );
00479   double rangeMin = getDoubleValue( values.at( 3 ), parent );
00480   double rangeMax = getDoubleValue( values.at( 4 ), parent );
00481   double exponent = getDoubleValue( values.at( 5 ), parent );
00482 
00483   if ( domainMin >= domainMax )
00484   {
00485     parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
00486     return QVariant();
00487   }
00488   if ( exponent <= 0 )
00489   {
00490     parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
00491     return QVariant();
00492   }
00493 
00494   // outside of domain?
00495   if ( val >= domainMax )
00496   {
00497     return rangeMax;
00498   }
00499   else if ( val <= domainMin )
00500   {
00501     return rangeMin;
00502   }
00503 
00504   // Return exponentially scaled value
00505   return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
00506 }
00507 
00508 static QVariant fcnMax( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00509 {
00510   //initially set max as first value
00511   double maxVal = getDoubleValue( values.at( 0 ), parent );
00512 
00513   //check against all other values
00514   for ( int i = 1; i < values.length(); ++i )
00515   {
00516     double testVal = getDoubleValue( values[i], parent );
00517     if ( testVal > maxVal )
00518     {
00519       maxVal = testVal;
00520     }
00521   }
00522 
00523   return QVariant( maxVal );
00524 }
00525 
00526 static QVariant fcnMin( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00527 {
00528   //initially set min as first value
00529   double minVal = getDoubleValue( values.at( 0 ), parent );
00530 
00531   //check against all other values
00532   for ( int i = 1; i < values.length(); ++i )
00533   {
00534     double testVal = getDoubleValue( values[i], parent );
00535     if ( testVal < minVal )
00536     {
00537       minVal = testVal;
00538     }
00539   }
00540 
00541   return QVariant( minVal );
00542 }
00543 
00544 static QVariant fcnClamp( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00545 {
00546   double minValue = getDoubleValue( values.at( 0 ), parent );
00547   double testValue = getDoubleValue( values.at( 1 ), parent );
00548   double maxValue = getDoubleValue( values.at( 2 ), parent );
00549 
00550   // force testValue to sit inside the range specified by the min and max value
00551   if ( testValue <= minValue )
00552   {
00553     return QVariant( minValue );
00554   }
00555   else if ( testValue >= maxValue )
00556   {
00557     return QVariant( maxValue );
00558   }
00559   else
00560   {
00561     return QVariant( testValue );
00562   }
00563 }
00564 
00565 static QVariant fcnFloor( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00566 {
00567   double x = getDoubleValue( values.at( 0 ), parent );
00568   return QVariant( floor( x ) );
00569 }
00570 
00571 static QVariant fcnCeil( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00572 {
00573   double x = getDoubleValue( values.at( 0 ), parent );
00574   return QVariant( ceil( x ) );
00575 }
00576 
00577 static QVariant fcnToInt( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00578 {
00579   return QVariant( getIntValue( values.at( 0 ), parent ) );
00580 }
00581 static QVariant fcnToReal( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00582 {
00583   return QVariant( getDoubleValue( values.at( 0 ), parent ) );
00584 }
00585 static QVariant fcnToString( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00586 {
00587   return QVariant( getStringValue( values.at( 0 ), parent ) );
00588 }
00589 
00590 static QVariant fcnToDateTime( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00591 {
00592   return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
00593 }
00594 
00595 static QVariant fcnCoalesce( const QVariantList& values, const QgsFeature* , QgsExpression* )
00596 {
00597   foreach ( const QVariant &value, values )
00598   {
00599     if ( value.isNull() )
00600       continue;
00601     return value;
00602   }
00603   return QVariant();
00604 }
00605 static QVariant fcnLower( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00606 {
00607   QString str = getStringValue( values.at( 0 ), parent );
00608   return QVariant( str.toLower() );
00609 }
00610 static QVariant fcnUpper( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00611 {
00612   QString str = getStringValue( values.at( 0 ), parent );
00613   return QVariant( str.toUpper() );
00614 }
00615 static QVariant fcnTitle( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00616 {
00617   QString str = getStringValue( values.at( 0 ), parent );
00618   QStringList elems = str.split( " " );
00619   for ( int i = 0; i < elems.size(); i++ )
00620   {
00621     if ( elems[i].size() > 1 )
00622       elems[i] = elems[i].left( 1 ).toUpper() + elems[i].mid( 1 ).toLower();
00623   }
00624   return QVariant( elems.join( " " ) );
00625 }
00626 
00627 static QVariant fcnTrim( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00628 {
00629   QString str = getStringValue( values.at( 0 ), parent );
00630   return QVariant( str.trimmed() );
00631 }
00632 
00633 static QVariant fcnLength( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00634 {
00635   QString str = getStringValue( values.at( 0 ), parent );
00636   return QVariant( str.length() );
00637 }
00638 static QVariant fcnReplace( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00639 {
00640   QString str = getStringValue( values.at( 0 ), parent );
00641   QString before = getStringValue( values.at( 1 ), parent );
00642   QString after = getStringValue( values.at( 2 ), parent );
00643   return QVariant( str.replace( before, after ) );
00644 }
00645 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00646 {
00647   QString str = getStringValue( values.at( 0 ), parent );
00648   QString regexp = getStringValue( values.at( 1 ), parent );
00649   QString after = getStringValue( values.at( 2 ), parent );
00650 
00651   QRegExp re( regexp );
00652   if ( !re.isValid() )
00653   {
00654     parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
00655     return QVariant();
00656   }
00657   return QVariant( str.replace( re, after ) );
00658 }
00659 
00660 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00661 {
00662   QString str = getStringValue( values.at( 0 ), parent );
00663   QString regexp = getStringValue( values.at( 1 ), parent );
00664 
00665   QRegExp re( regexp );
00666   if ( !re.isValid() )
00667   {
00668     parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
00669     return QVariant();
00670   }
00671   return QVariant( str.contains( re ) ? 1 : 0 );
00672 }
00673 
00674 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00675 {
00676   QString str = getStringValue( values.at( 0 ), parent );
00677   QString regexp = getStringValue( values.at( 1 ), parent );
00678 
00679   QRegExp re( regexp );
00680   if ( !re.isValid() )
00681   {
00682     parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
00683     return QVariant();
00684   }
00685 
00686   // extract substring
00687   re.indexIn( str );
00688   if ( re.captureCount() > 0 )
00689   {
00690     // return first capture
00691     return QVariant( re.capturedTexts()[0] );
00692   }
00693   else
00694   {
00695     return QVariant( "" );
00696   }
00697 }
00698 
00699 static QVariant fcnSubstr( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
00700 {
00701   QString str = getStringValue( values.at( 0 ), parent );
00702   int from = getIntValue( values.at( 1 ), parent );
00703   int len = getIntValue( values.at( 2 ), parent );
00704   return QVariant( str.mid( from -1, len ) );
00705 }
00706 
00707 static QVariant fcnRowNumber( const QVariantList& , const QgsFeature* , QgsExpression* parent )
00708 {
00709   return QVariant( parent->currentRowNumber() );
00710 }
00711 
00712 static QVariant fcnFeatureId( const QVariantList& , const QgsFeature* f, QgsExpression* )
00713 {
00714   // TODO: handling of 64-bit feature ids?
00715   return f ? QVariant(( int )f->id() ) : QVariant();
00716 }
00717 
00718 static QVariant fcnConcat( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00719 {
00720   QString concat;
00721   foreach ( const QVariant &value, values )
00722   {
00723     concat += getStringValue( value, parent );
00724   }
00725   return concat;
00726 }
00727 
00728 static QVariant fcnStrpos( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00729 {
00730   QString string = getStringValue( values.at( 0 ), parent );
00731   return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) );
00732 }
00733 
00734 static QVariant fcnRight( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00735 {
00736   QString string = getStringValue( values.at( 0 ), parent );
00737   int pos = getIntValue( values.at( 1 ), parent );
00738   return string.right( pos );
00739 }
00740 
00741 static QVariant fcnLeft( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00742 {
00743   QString string = getStringValue( values.at( 0 ), parent );
00744   int pos = getIntValue( values.at( 1 ), parent );
00745   return string.left( pos );
00746 }
00747 
00748 static QVariant fcnRPad( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00749 {
00750   QString string = getStringValue( values.at( 0 ), parent );
00751   int length = getIntValue( values.at( 1 ), parent );
00752   QString fill = getStringValue( values.at( 2 ), parent );
00753   return string.rightJustified( length, fill.at( 0 ), true );
00754 }
00755 
00756 static QVariant fcnLPad( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00757 {
00758   QString string = getStringValue( values.at( 0 ), parent );
00759   int length = getIntValue( values.at( 1 ), parent );
00760   QString fill = getStringValue( values.at( 2 ), parent );
00761   return string.leftJustified( length, fill.at( 0 ), true );
00762 }
00763 
00764 static QVariant fcnFormatString( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00765 {
00766   QString string = getStringValue( values.at( 0 ), parent );
00767   for ( int n = 1; n < values.length(); n++ )
00768   {
00769     string = string.arg( getStringValue( values.at( n ), parent ) );
00770   }
00771   return string;
00772 }
00773 
00774 
00775 static QVariant fcnNow( const QVariantList&, const QgsFeature* , QgsExpression * )
00776 {
00777   return QVariant( QDateTime::currentDateTime() );
00778 }
00779 
00780 static QVariant fcnToDate( const QVariantList& values, const QgsFeature* , QgsExpression * parent )
00781 {
00782   return QVariant( getDateValue( values.at( 0 ), parent ) );
00783 }
00784 
00785 static QVariant fcnToTime( const QVariantList& values, const QgsFeature* , QgsExpression * parent )
00786 {
00787   return QVariant( getTimeValue( values.at( 0 ), parent ) );
00788 }
00789 
00790 static QVariant fcnToInterval( const QVariantList& values, const QgsFeature* , QgsExpression * parent )
00791 {
00792   return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
00793 }
00794 
00795 static QVariant fcnAge( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00796 {
00797   QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
00798   QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
00799   int seconds = d2.secsTo( d1 );
00800   return QVariant::fromValue( QgsExpression::Interval( seconds ) );
00801 }
00802 
00803 static QVariant fcnDay( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00804 {
00805   QVariant value = values.at( 0 );
00806   QgsExpression::Interval inter = getInterval( value, parent, false );
00807   if ( inter.isValid() )
00808   {
00809     return QVariant( inter.days() );
00810   }
00811   else
00812   {
00813     QDateTime d1 =  getDateTimeValue( value, parent );
00814     return QVariant( d1.date().day() );
00815   }
00816 }
00817 
00818 static QVariant fcnYear( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00819 {
00820   QVariant value = values.at( 0 );
00821   QgsExpression::Interval inter = getInterval( value, parent, false );
00822   if ( inter.isValid() )
00823   {
00824     return QVariant( inter.years() );
00825   }
00826   else
00827   {
00828     QDateTime d1 =  getDateTimeValue( value, parent );
00829     return QVariant( d1.date().year() );
00830   }
00831 }
00832 
00833 static QVariant fcnMonth( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00834 {
00835   QVariant value = values.at( 0 );
00836   QgsExpression::Interval inter = getInterval( value, parent, false );
00837   if ( inter.isValid() )
00838   {
00839     return QVariant( inter.months() );
00840   }
00841   else
00842   {
00843     QDateTime d1 =  getDateTimeValue( value, parent );
00844     return QVariant( d1.date().month() );
00845   }
00846 }
00847 
00848 static QVariant fcnWeek( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00849 {
00850   QVariant value = values.at( 0 );
00851   QgsExpression::Interval inter = getInterval( value, parent, false );
00852   if ( inter.isValid() )
00853   {
00854     return QVariant( inter.weeks() );
00855   }
00856   else
00857   {
00858     QDateTime d1 =  getDateTimeValue( value, parent );
00859     return QVariant( d1.date().weekNumber() );
00860   }
00861 }
00862 
00863 static QVariant fcnHour( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00864 {
00865   QVariant value = values.at( 0 );
00866   QgsExpression::Interval inter = getInterval( value, parent, false );
00867   if ( inter.isValid() )
00868   {
00869     return QVariant( inter.hours() );
00870   }
00871   else
00872   {
00873     QDateTime d1 =  getDateTimeValue( value, parent );
00874     return QVariant( d1.time().hour() );
00875   }
00876 }
00877 
00878 static QVariant fcnMinute( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00879 {
00880   QVariant value = values.at( 0 );
00881   QgsExpression::Interval inter = getInterval( value, parent, false );
00882   if ( inter.isValid() )
00883   {
00884     return QVariant( inter.minutes() );
00885   }
00886   else
00887   {
00888     QDateTime d1 =  getDateTimeValue( value, parent );
00889     return QVariant( d1.time().minute() );
00890   }
00891 }
00892 
00893 static QVariant fcnSeconds( const QVariantList& values, const QgsFeature* , QgsExpression *parent )
00894 {
00895   QVariant value = values.at( 0 );
00896   QgsExpression::Interval inter = getInterval( value, parent, false );
00897   if ( inter.isValid() )
00898   {
00899     return QVariant( inter.seconds() );
00900   }
00901   else
00902   {
00903     QDateTime d1 =  getDateTimeValue( value, parent );
00904     return QVariant( d1.time().second() );
00905   }
00906 }
00907 
00908 
00909 #define ENSURE_GEOM_TYPE(f, g, geomtype)   if (!f) return QVariant(); \
00910   QgsGeometry* g = f->geometry(); \
00911   if (!g || g->type() != geomtype) return QVariant();
00912 
00913 
00914 static QVariant fcnX( const QVariantList& , const QgsFeature* f, QgsExpression* )
00915 {
00916   ENSURE_GEOM_TYPE( f, g, QGis::Point );
00917   if ( g->isMultipart() )
00918   {
00919     return g->asMultiPoint()[ 0 ].x();
00920   }
00921   else
00922   {
00923     return g->asPoint().x();
00924   }
00925 }
00926 static QVariant fcnY( const QVariantList& , const QgsFeature* f, QgsExpression* )
00927 {
00928   ENSURE_GEOM_TYPE( f, g, QGis::Point );
00929   if ( g->isMultipart() )
00930   {
00931     return g->asMultiPoint()[ 0 ].y();
00932   }
00933   else
00934   {
00935     return g->asPoint().y();
00936   }
00937 }
00938 
00939 static QVariant pointAt( const QVariantList& values, const QgsFeature* f, QgsExpression* parent ) // helper function
00940 {
00941   int idx = getIntValue( values.at( 0 ), parent );
00942   ENSURE_GEOM_TYPE( f, g, QGis::Line );
00943   QgsPolyline polyline = g->asPolyline();
00944   if ( idx < 0 )
00945     idx += polyline.count();
00946 
00947   if ( idx < 0 || idx >= polyline.count() )
00948   {
00949     parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
00950     return QVariant();
00951   }
00952   return QVariant( QPointF( polyline[idx].x(), polyline[idx].y() ) );
00953 }
00954 
00955 static QVariant fcnXat( const QVariantList& values, const QgsFeature* f, QgsExpression* parent )
00956 {
00957   QVariant v = pointAt( values, f, parent );
00958   if ( v.type() == QVariant::PointF )
00959     return QVariant( v.toPointF().x() );
00960   else
00961     return QVariant();
00962 }
00963 static QVariant fcnYat( const QVariantList& values, const QgsFeature* f, QgsExpression* parent )
00964 {
00965   QVariant v = pointAt( values, f, parent );
00966   if ( v.type() == QVariant::PointF )
00967     return QVariant( v.toPointF().y() );
00968   else
00969     return QVariant();
00970 }
00971 static QVariant fcnGeometry( const QVariantList& , const QgsFeature* f, QgsExpression* )
00972 {
00973   QgsGeometry* geom = f->geometry();
00974   if ( geom )
00975     return  QVariant::fromValue( *geom );
00976   else
00977     return QVariant();
00978 }
00979 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
00980 {
00981   QString wkt = getStringValue( values.at( 0 ), parent );
00982   QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
00983   if ( geom )
00984     return QVariant::fromValue( *geom );
00985   else
00986     return QVariant();
00987 }
00988 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
00989 {
00990   QString gml = getStringValue( values.at( 0 ), parent );
00991   QgsGeometry* geom = QgsOgcUtils::geometryFromGML( gml );
00992 
00993   if ( geom )
00994     return QVariant::fromValue( *geom );
00995   else
00996     return QVariant();
00997 }
00998 
00999 static QVariant fcnGeomArea( const QVariantList& , const QgsFeature* f, QgsExpression* parent )
01000 {
01001   ENSURE_GEOM_TYPE( f, g, QGis::Polygon );
01002   QgsDistanceArea* calc = parent->geomCalculator();
01003   return QVariant( calc->measure( f->geometry() ) );
01004 }
01005 static QVariant fcnGeomLength( const QVariantList& , const QgsFeature* f, QgsExpression* parent )
01006 {
01007   ENSURE_GEOM_TYPE( f, g, QGis::Line );
01008   QgsDistanceArea* calc = parent->geomCalculator();
01009   return QVariant( calc->measure( f->geometry() ) );
01010 }
01011 static QVariant fcnGeomPerimeter( const QVariantList& , const QgsFeature* f, QgsExpression* parent )
01012 {
01013   ENSURE_GEOM_TYPE( f, g, QGis::Polygon );
01014   QgsDistanceArea* calc = parent->geomCalculator();
01015   return QVariant( calc->measurePerimeter( f->geometry() ) );
01016 }
01017 
01018 static QVariant fcnBbox( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01019 {
01020   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01021   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01022   return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
01023 }
01024 static QVariant fcnDisjoint( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01025 {
01026   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01027   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01028   return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
01029 }
01030 static QVariant fcnIntersects( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01031 {
01032   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01033   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01034   return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
01035 }
01036 static QVariant fcnTouches( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01037 {
01038   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01039   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01040   return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
01041 }
01042 static QVariant fcnCrosses( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01043 {
01044   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01045   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01046   return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
01047 }
01048 static QVariant fcnContains( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01049 {
01050   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01051   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01052   return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
01053 }
01054 static QVariant fcnOverlaps( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01055 {
01056   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01057   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01058   return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
01059 }
01060 static QVariant fcnWithin( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01061 {
01062   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01063   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01064   return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
01065 }
01066 static QVariant fcnBuffer( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
01067 {
01068   if ( values.length() < 2 || values.length() > 3 )
01069     return QVariant();
01070 
01071   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01072   double dist = getDoubleValue( values.at( 1 ), parent );
01073   int seg = 8;
01074   if ( values.length() == 3 )
01075     seg = getIntValue( values.at( 2 ), parent );
01076 
01077   QgsGeometry* geom = fGeom.buffer( dist, seg );
01078   if ( geom )
01079     return QVariant::fromValue( *geom );
01080   return QVariant();
01081 }
01082 static QVariant fcnCentroid( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
01083 {
01084   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01085   QgsGeometry* geom = fGeom.centroid();
01086   if ( geom )
01087     return QVariant::fromValue( *geom );
01088   return QVariant();
01089 }
01090 static QVariant fcnConvexHull( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
01091 {
01092   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01093   QgsGeometry* geom = fGeom.convexHull();
01094   if ( geom )
01095     return QVariant::fromValue( *geom );
01096   return QVariant();
01097 }
01098 static QVariant fcnDifference( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01099 {
01100   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01101   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01102   QgsGeometry* geom = fGeom.difference( &sGeom );
01103   if ( geom )
01104     return QVariant::fromValue( *geom );
01105   return QVariant();
01106 }
01107 static QVariant fcnDistance( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01108 {
01109   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01110   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01111   return QVariant( fGeom.distance( sGeom ) );
01112 }
01113 static QVariant fcnIntersection( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01114 {
01115   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01116   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01117   QgsGeometry* geom = fGeom.intersection( &sGeom );
01118   if ( geom )
01119     return QVariant::fromValue( *geom );
01120   return QVariant();
01121 }
01122 static QVariant fcnSymDifference( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01123 {
01124   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01125   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01126   QgsGeometry* geom = fGeom.symDifference( &sGeom );
01127   if ( geom )
01128     return QVariant::fromValue( *geom );
01129   return QVariant();
01130 }
01131 static QVariant fcnCombine( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01132 {
01133   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01134   QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
01135   QgsGeometry* geom = fGeom.combine( &sGeom );
01136   if ( geom )
01137     return QVariant::fromValue( *geom );
01138   return QVariant();
01139 }
01140 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsFeature* , QgsExpression* parent )
01141 {
01142   QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
01143   QString wkt = fGeom.exportToWkt();
01144   return QVariant( wkt );
01145 }
01146 
01147 static QVariant fcnRound( const QVariantList& values , const QgsFeature *f, QgsExpression* parent )
01148 {
01149   Q_UNUSED( f );
01150   if ( values.length() == 2 )
01151   {
01152     double number = getDoubleValue( values.at( 0 ), parent );
01153     double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
01154     return QVariant( qRound( number * scaler ) / scaler );
01155   }
01156 
01157   if ( values.length() == 1 )
01158   {
01159     double number = getIntValue( values.at( 0 ), parent );
01160     return QVariant( qRound( number ) ).toInt();
01161   }
01162 
01163   return QVariant();
01164 }
01165 
01166 static QVariant fcnPi( const QVariantList& values , const QgsFeature *f, QgsExpression* parent )
01167 {
01168   Q_UNUSED( values );
01169   Q_UNUSED( f );
01170   Q_UNUSED( parent );
01171   return M_PI;
01172 }
01173 
01174 static QVariant fcnScale( const QVariantList&, const QgsFeature*, QgsExpression* parent )
01175 {
01176   return QVariant( parent->scale() );
01177 }
01178 
01179 static QVariant fcnFormatNumber( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
01180 {
01181   double value = getDoubleValue( values.at( 0 ), parent );
01182   int places = getIntValue( values.at( 1 ), parent );
01183   return QString( "%L1" ).arg( value, 0, 'f', places );
01184 }
01185 
01186 static QVariant fcnFormatDate( const QVariantList& values, const QgsFeature*, QgsExpression* parent )
01187 {
01188   QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
01189   QString format = getStringValue( values.at( 1 ), parent );
01190   return dt.toString( format );
01191 }
01192 
01193 static QVariant fcnColorRgb( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01194 {
01195   int red = getIntValue( values.at( 0 ), parent );
01196   int green = getIntValue( values.at( 1 ), parent );
01197   int blue = getIntValue( values.at( 2 ), parent );
01198   QColor color = QColor( red, green, blue );
01199   if ( ! color.isValid() )
01200   {
01201     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
01202     color = QColor( 0, 0, 0 );
01203   }
01204 
01205   return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
01206 }
01207 
01208 static QVariant fncColorRgba( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01209 {
01210   int red = getIntValue( values.at( 0 ), parent );
01211   int green = getIntValue( values.at( 1 ), parent );
01212   int blue = getIntValue( values.at( 2 ), parent );
01213   int alpha = getIntValue( values.at( 3 ), parent );
01214   QColor color = QColor( red, green, blue, alpha );
01215   if ( ! color.isValid() )
01216   {
01217     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
01218     color = QColor( 0, 0, 0 );
01219   }
01220   return QgsSymbolLayerV2Utils::encodeColor( color );
01221 }
01222 
01223 QVariant fcnRampColor( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01224 {
01225   QString rampName = getStringValue( values.at( 0 ), parent );
01226   const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
01227   if ( ! mRamp )
01228   {
01229     parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
01230     return QColor( 0, 0, 0 ).name();
01231   }
01232   double value = getDoubleValue( values.at( 1 ), parent );
01233   QColor color = mRamp->color( value );
01234   return QgsSymbolLayerV2Utils::encodeColor( color );
01235 }
01236 
01237 static QVariant fcnColorHsl( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01238 {
01239   // Hue ranges from 0 - 360
01240   double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
01241   // Saturation ranges from 0 - 100
01242   double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
01243   // Lightness ranges from 0 - 100
01244   double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
01245 
01246   QColor color = QColor::fromHslF( hue, saturation, lightness );
01247 
01248   if ( ! color.isValid() )
01249   {
01250     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
01251     color = QColor( 0, 0, 0 );
01252   }
01253 
01254   return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
01255 }
01256 
01257 static QVariant fncColorHsla( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01258 {
01259   // Hue ranges from 0 - 360
01260   double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
01261   // Saturation ranges from 0 - 100
01262   double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
01263   // Lightness ranges from 0 - 100
01264   double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
01265   // Alpha ranges from 0 - 255
01266   double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
01267 
01268   QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
01269   if ( ! color.isValid() )
01270   {
01271     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
01272     color = QColor( 0, 0, 0 );
01273   }
01274   return QgsSymbolLayerV2Utils::encodeColor( color );
01275 }
01276 
01277 static QVariant fcnColorHsv( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01278 {
01279   // Hue ranges from 0 - 360
01280   double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
01281   // Saturation ranges from 0 - 100
01282   double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
01283   // Value ranges from 0 - 100
01284   double value = getIntValue( values.at( 2 ), parent ) / 100.0;
01285 
01286   QColor color = QColor::fromHsvF( hue, saturation, value );
01287 
01288   if ( ! color.isValid() )
01289   {
01290     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
01291     color = QColor( 0, 0, 0 );
01292   }
01293 
01294   return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
01295 }
01296 
01297 static QVariant fncColorHsva( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01298 {
01299   // Hue ranges from 0 - 360
01300   double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
01301   // Saturation ranges from 0 - 100
01302   double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
01303   // Value ranges from 0 - 100
01304   double value = getIntValue( values.at( 2 ), parent ) / 100.0;
01305   // Alpha ranges from 0 - 255
01306   double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
01307 
01308   QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
01309   if ( ! color.isValid() )
01310   {
01311     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
01312     color = QColor( 0, 0, 0 );
01313   }
01314   return QgsSymbolLayerV2Utils::encodeColor( color );
01315 }
01316 
01317 static QVariant fcnColorCmyk( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01318 {
01319   // Cyan ranges from 0 - 100
01320   double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
01321   // Magenta ranges from 0 - 100
01322   double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
01323   // Yellow ranges from 0 - 100
01324   double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
01325   // Black ranges from 0 - 100
01326   double black = getIntValue( values.at( 3 ), parent ) / 100.0;
01327 
01328   QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
01329 
01330   if ( ! color.isValid() )
01331   {
01332     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
01333     color = QColor( 0, 0, 0 );
01334   }
01335 
01336   return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
01337 }
01338 
01339 static QVariant fncColorCmyka( const QVariantList &values, const QgsFeature *, QgsExpression *parent )
01340 {
01341   // Cyan ranges from 0 - 100
01342   double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
01343   // Magenta ranges from 0 - 100
01344   double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
01345   // Yellow ranges from 0 - 100
01346   double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
01347   // Black ranges from 0 - 100
01348   double black = getIntValue( values.at( 3 ), parent ) / 100.0;
01349   // Alpha ranges from 0 - 255
01350   double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
01351 
01352   QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
01353   if ( ! color.isValid() )
01354   {
01355     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
01356     color = QColor( 0, 0, 0 );
01357   }
01358   return QgsSymbolLayerV2Utils::encodeColor( color );
01359 }
01360 
01361 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsFeature* /*f*/, QgsExpression* parent )
01362 {
01363   QString varName = getStringValue( values.at( 0 ), parent );
01364   return QgsExpression::specialColumn( varName );
01365 }
01366 
01367 bool QgsExpression::registerFunction( QgsExpression::Function* function )
01368 {
01369   int fnIdx = functionIndex( function->name() );
01370   if ( fnIdx != -1 )
01371   {
01372     return false;
01373   }
01374   QgsExpression::gmFunctions.append( function );
01375   return true;
01376 }
01377 
01378 bool QgsExpression::unregisterFunction( QString name )
01379 {
01380   // You can never override the built in functions.
01381   if ( QgsExpression::BuiltinFunctions().contains( name ) )
01382   {
01383     return false;
01384   }
01385   int fnIdx = functionIndex( name );
01386   if ( fnIdx != -1 )
01387   {
01388     QgsExpression::gmFunctions.removeAt( fnIdx );
01389     return true;
01390   }
01391   return false;
01392 }
01393 
01394 
01395 
01396 QStringList QgsExpression::gmBuiltinFunctions;
01397 
01398 const QStringList &QgsExpression::BuiltinFunctions()
01399 {
01400   if ( gmBuiltinFunctions.isEmpty() )
01401   {
01402     gmBuiltinFunctions
01403     << "abs" << "sqrt" << "cos" << "sin" << "tan"
01404     << "asin" << "acos" << "atan" << "atan2"
01405     << "exp" << "ln" << "log10" << "log"
01406     << "round" << "rand" << "randf" << "max" << "min" << "clamp"
01407     << "scale_linear" << "scale_exp" << "floor" << "ceil"
01408     << "toint" << "toreal" << "tostring"
01409     << "todatetime" << "todate" << "totime" << "tointerval"
01410     << "coalesce" << "regexp_match" << "$now" << "age" << "year"
01411     << "month" << "week" << "day" << "hour"
01412     << "minute" << "second" << "lower" << "upper"
01413     << "title" << "length" << "replace" << "trim"
01414     << "regexp_replace" << "regexp_substr"
01415     << "substr" << "concat" << "strpos" << "left"
01416     << "right" << "rpad" << "lpad"
01417     << "format_number" << "format_date"
01418     << "color_rgb" << "color_rgba" << "ramp_color"
01419     << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
01420     << "color_cymk" << "color_cymka"
01421     << "xat" << "yat" << "$area"
01422     << "$length" << "$perimeter" << "$x" << "$y"
01423     << "$rownum" << "$id" << "$scale" << "_specialcol_";
01424   }
01425   return gmBuiltinFunctions;
01426 }
01427 
01428 QList<QgsExpression::Function*> QgsExpression::gmFunctions;
01429 
01430 const QList<QgsExpression::Function*> &QgsExpression::Functions()
01431 {
01432   if ( gmFunctions.isEmpty() )
01433   {
01434     gmFunctions
01435     << new StaticFunction( "sqrt", 1, fcnSqrt, "Math" )
01436     << new StaticFunction( "abs", 1, fcnAbs, "Math" )
01437     << new StaticFunction( "cos", 1, fcnCos, "Math" )
01438     << new StaticFunction( "sin", 1, fcnSin, "Math" )
01439     << new StaticFunction( "tan", 1, fcnTan, "Math" )
01440     << new StaticFunction( "asin", 1, fcnAsin, "Math" )
01441     << new StaticFunction( "acos", 1, fcnAcos, "Math" )
01442     << new StaticFunction( "atan", 1, fcnAtan, "Math" )
01443     << new StaticFunction( "atan2", 2, fcnAtan2, "Math" )
01444     << new StaticFunction( "exp", 1, fcnExp, "Math" )
01445     << new StaticFunction( "ln", 1, fcnLn, "Math" )
01446     << new StaticFunction( "log10", 1, fcnLog10, "Math" )
01447     << new StaticFunction( "log", 2, fcnLog, "Math" )
01448     << new StaticFunction( "round", -1, fcnRound, "Math" )
01449     << new StaticFunction( "rand", 2, fcnRnd, "Math" )
01450     << new StaticFunction( "randf", 2, fcnRndF, "Math" )
01451     << new StaticFunction( "max", -1, fcnMax, "Math" )
01452     << new StaticFunction( "min", -1, fcnMin, "Math" )
01453     << new StaticFunction( "clamp", 3, fcnClamp, "Math" )
01454     << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
01455     << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
01456     << new StaticFunction( "floor", 1, fcnFloor, "Math" )
01457     << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
01458     << new StaticFunction( "$pi", 0, fcnPi, "Math" )
01459     << new StaticFunction( "toint", 1, fcnToInt, "Conversions" )
01460     << new StaticFunction( "toreal", 1, fcnToReal, "Conversions" )
01461     << new StaticFunction( "tostring", 1, fcnToString, "Conversions" )
01462     << new StaticFunction( "todatetime", 1, fcnToDateTime, "Conversions" )
01463     << new StaticFunction( "todate", 1, fcnToDate, "Conversions" )
01464     << new StaticFunction( "totime", 1, fcnToTime, "Conversions" )
01465     << new StaticFunction( "tointerval", 1, fcnToInterval, "Conversions" )
01466     << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals" )
01467     << new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
01468     << new StaticFunction( "$now", 0, fcnNow, "Date and Time" )
01469     << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
01470     << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
01471     << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
01472     << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
01473     << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
01474     << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
01475     << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
01476     << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
01477     << new StaticFunction( "lower", 1, fcnLower, "String" )
01478     << new StaticFunction( "upper", 1, fcnUpper, "String" )
01479     << new StaticFunction( "title", 1, fcnTitle, "String" )
01480     << new StaticFunction( "trim", 1, fcnTrim, "String" )
01481     << new StaticFunction( "length", 1, fcnLength, "String" )
01482     << new StaticFunction( "replace", 3, fcnReplace, "String" )
01483     << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
01484     << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
01485     << new StaticFunction( "substr", 3, fcnSubstr, "String" )
01486     << new StaticFunction( "concat", -1, fcnConcat, "String" )
01487     << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
01488     << new StaticFunction( "left", 2, fcnLeft, "String" )
01489     << new StaticFunction( "right", 2, fcnRight, "String" )
01490     << new StaticFunction( "rpad", 3, fcnRPad, "String" )
01491     << new StaticFunction( "lpad", 3, fcnLPad, "String" )
01492     << new StaticFunction( "format", -1, fcnFormatString, "String" )
01493     << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
01494     << new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
01495     << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
01496     << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
01497     << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
01498     << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
01499     << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
01500     << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
01501     << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
01502     << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
01503     << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
01504     << new StaticFunction( "xat", 1, fcnXat, "Geometry", "", true )
01505     << new StaticFunction( "yat", 1, fcnYat, "Geometry", "", true )
01506     << new StaticFunction( "$area", 0, fcnGeomArea, "Geometry", "", true )
01507     << new StaticFunction( "$length", 0, fcnGeomLength, "Geometry", "", true )
01508     << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "Geometry", "", true )
01509     << new StaticFunction( "$x", 0, fcnX, "Geometry", "", true )
01510     << new StaticFunction( "$y", 0, fcnY, "Geometry", "" , true )
01511     << new StaticFunction( "$geometry", 0, fcnGeometry, "Geometry", "" , true )
01512     << new StaticFunction( "geomFromWKT", 1, fcnGeomFromWKT, "Geometry" )
01513     << new StaticFunction( "geomFromGML", 1, fcnGeomFromGML, "Geometry" )
01514     << new StaticFunction( "bbox", 2, fcnBbox, "Geometry" )
01515     << new StaticFunction( "disjoint", 2, fcnDisjoint, "Geometry" )
01516     << new StaticFunction( "intersects", 2, fcnIntersects, "Geometry" )
01517     << new StaticFunction( "touches", 2, fcnTouches, "Geometry" )
01518     << new StaticFunction( "crosses", 2, fcnCrosses, "Geometry" )
01519     << new StaticFunction( "contains", 2, fcnContains, "Geometry" )
01520     << new StaticFunction( "overlaps", 2, fcnOverlaps, "Geometry" )
01521     << new StaticFunction( "within", 2, fcnWithin, "Geometry" )
01522     << new StaticFunction( "buffer", -1, fcnBuffer, "Geometry" )
01523     << new StaticFunction( "centroid", 1, fcnCentroid, "Geometry" )
01524     << new StaticFunction( "convexHull", 1, fcnConvexHull, "Geometry" )
01525     << new StaticFunction( "difference", 2, fcnDifference, "Geometry" )
01526     << new StaticFunction( "distance", 2, fcnDistance, "Geometry" )
01527     << new StaticFunction( "intersection", 2, fcnIntersection, "Geometry" )
01528     << new StaticFunction( "symDifference", 2, fcnSymDifference, "Geometry" )
01529     << new StaticFunction( "combine", 2, fcnCombine, "Geometry" )
01530     << new StaticFunction( "union", 2, fcnCombine, "Geometry" )
01531     << new StaticFunction( "geomToWKT", 1, fcnGeomToWKT, "Geometry" )
01532     << new StaticFunction( "$rownum", 0, fcnRowNumber, "Record" )
01533     << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
01534     << new StaticFunction( "$scale", 0, fcnScale, "Record" )
01535     << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
01536     ;
01537   }
01538   return gmFunctions;
01539 }
01540 
01541 QMap<QString, QVariant> QgsExpression::gmSpecialColumns;
01542 
01543 void QgsExpression::setSpecialColumn( const QString& name, QVariant variant )
01544 {
01545   int fnIdx = functionIndex( name );
01546   if ( fnIdx != -1 )
01547   {
01548     // function of the same name already exists
01549     return;
01550   }
01551   gmSpecialColumns[ name ] = variant;
01552 }
01553 
01554 void QgsExpression::unsetSpecialColumn( const QString& name )
01555 {
01556   QMap<QString, QVariant>::iterator fit = gmSpecialColumns.find( name );
01557   if ( fit != gmSpecialColumns.end() )
01558   {
01559     gmSpecialColumns.erase( fit );
01560   }
01561 }
01562 
01563 QVariant QgsExpression::specialColumn( const QString& name )
01564 {
01565   int fnIdx = functionIndex( name );
01566   if ( fnIdx != -1 )
01567   {
01568     // function of the same name already exists
01569     return QVariant();
01570   }
01571   QMap<QString, QVariant>::iterator it = gmSpecialColumns.find( name );
01572   if ( it == gmSpecialColumns.end() )
01573   {
01574     return QVariant();
01575   }
01576   return it.value();
01577 }
01578 
01579 QList<QgsExpression::Function*> QgsExpression::specialColumns()
01580 {
01581   QList<Function*> defs;
01582   for ( QMap<QString, QVariant>::const_iterator it = gmSpecialColumns.begin(); it != gmSpecialColumns.end(); ++it )
01583   {
01584     defs << new StaticFunction( it.key(), 0, 0, "Record" );
01585   }
01586   return defs;
01587 }
01588 
01589 bool QgsExpression::isFunctionName( QString name )
01590 {
01591   return functionIndex( name ) != -1;
01592 }
01593 
01594 int QgsExpression::functionIndex( QString name )
01595 {
01596   int count = functionCount();
01597   for ( int i = 0; i < count; i++ )
01598   {
01599     if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
01600       return i;
01601   }
01602   return -1;
01603 }
01604 
01605 int QgsExpression::functionCount()
01606 {
01607   return Functions().size();
01608 }
01609 
01610 
01611 QgsExpression::QgsExpression( const QString& expr )
01612     : mExpression( expr )
01613     , mRowNumber( 0 )
01614     , mScale( 0 )
01615 
01616 {
01617   initGeomCalculator();
01618 
01619   mRootNode = ::parseExpression( mExpression, mParserErrorString );
01620 
01621   if ( mParserErrorString.isNull() )
01622   {
01623     Q_ASSERT( mRootNode != NULL );
01624   }
01625 }
01626 
01627 QgsExpression::~QgsExpression()
01628 {
01629   delete mRootNode;
01630 }
01631 
01632 QStringList QgsExpression::referencedColumns()
01633 {
01634   if ( !mRootNode )
01635     return QStringList();
01636   QStringList columns = mRootNode->referencedColumns();
01637 
01638   // filter out duplicates
01639   for ( int i = 0; i < columns.count(); i++ )
01640   {
01641     QString col = columns.at( i );
01642     for ( int j = i + 1; j < columns.count(); j++ )
01643     {
01644       if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
01645       {
01646         // this column is repeated: remove it!
01647         columns.removeAt( j-- );
01648       }
01649     }
01650   }
01651 
01652   return columns;
01653 }
01654 
01655 bool QgsExpression::needsGeometry()
01656 {
01657   if ( !mRootNode )
01658     return false;
01659   return mRootNode->needsGeometry();
01660 }
01661 
01662 void QgsExpression::initGeomCalculator()
01663 {
01664   // Use planimetric as default
01665   mCalc.setEllipsoidalMode( false );
01666 }
01667 
01668 void QgsExpression::setGeomCalculator( QgsDistanceArea& calc )
01669 {
01670   // Copy from supplied calculator
01671   mCalc.setEllipsoid( calc.ellipsoid() );
01672   mCalc.setEllipsoidalMode( calc.ellipsoidalEnabled() );
01673   mCalc.setSourceCrs( calc.sourceCrs() );
01674 }
01675 
01676 bool QgsExpression::prepare( const QgsFields& fields )
01677 {
01678   mEvalErrorString = QString();
01679   if ( !mRootNode )
01680   {
01681     mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
01682     return false;
01683   }
01684 
01685   return mRootNode->prepare( this, fields );
01686 }
01687 
01688 QVariant QgsExpression::evaluate( const QgsFeature* f )
01689 {
01690   mEvalErrorString = QString();
01691   if ( !mRootNode )
01692   {
01693     mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
01694     return QVariant();
01695   }
01696 
01697   return mRootNode->eval( this, f );
01698 }
01699 
01700 QVariant QgsExpression::evaluate( const QgsFeature* f, const QgsFields& fields )
01701 {
01702   // first prepare
01703   bool res = prepare( fields );
01704   if ( !res )
01705     return QVariant();
01706 
01707   // then evaluate
01708   return evaluate( f );
01709 }
01710 
01711 QString QgsExpression::dump() const
01712 {
01713   if ( !mRootNode )
01714     return QObject::tr( "(no root)" );
01715 
01716   return mRootNode->dump();
01717 }
01718 
01719 void QgsExpression::acceptVisitor( QgsExpression::Visitor& v ) const
01720 {
01721   if ( mRootNode )
01722     mRootNode->accept( v );
01723 }
01724 
01725 QString QgsExpression::replaceExpressionText( QString action, QgsFeature* feat,
01726     QgsVectorLayer* layer,
01727     const QMap<QString, QVariant> *substitutionMap )
01728 {
01729   QString expr_action;
01730 
01731   QMap<QString, QVariant> savedValues;
01732   if ( substitutionMap )
01733   {
01734     // variables with a local scope (must be restored after evaluation)
01735     for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
01736     {
01737       QVariant oldValue = QgsExpression::specialColumn( sit.key() );
01738       if ( !oldValue.isNull() )
01739         savedValues.insert( sit.key(), oldValue );
01740 
01741       // set the new value
01742       QgsExpression::setSpecialColumn( sit.key(), sit.value() );
01743     }
01744   }
01745 
01746   int index = 0;
01747   while ( index < action.size() )
01748   {
01749     QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
01750 
01751     int pos = rx.indexIn( action, index );
01752     if ( pos < 0 )
01753       break;
01754 
01755     int start = index;
01756     index = pos + rx.matchedLength();
01757     QString to_replace = rx.cap( 1 ).trimmed();
01758     QgsDebugMsg( "Found expression: " + to_replace );
01759 
01760     QgsExpression exp( to_replace );
01761     if ( exp.hasParserError() )
01762     {
01763       QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
01764       expr_action += action.mid( start, index - start );
01765       continue;
01766     }
01767 
01768     QVariant result;
01769     if ( layer )
01770     {
01771       result = exp.evaluate( feat, layer->pendingFields() );
01772     }
01773     else
01774     {
01775       result = exp.evaluate( feat );
01776     }
01777     if ( exp.hasEvalError() )
01778     {
01779       QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
01780       expr_action += action.mid( start, index - start );
01781       continue;
01782     }
01783 
01784     QgsDebugMsg( "Expression result is: " + result.toString() );
01785     expr_action += action.mid( start, pos - start ) + result.toString();
01786   }
01787 
01788   expr_action += action.mid( index );
01789 
01790   // restore overwritten local values
01791   for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
01792   {
01793     QgsExpression::setSpecialColumn( sit.key(), sit.value() );
01794   }
01795 
01796   return expr_action;
01797 }
01798 
01799 
01800 QString QgsExpression::replaceExpressionText( QString action, QgsFeature& feat,
01801     QgsVectorLayer* layer,
01802     const QMap<QString, QVariant> *substitutionMap )
01803 {
01804   return replaceExpressionText( action, &feat, layer, substitutionMap );
01805 }
01806 
01807 
01809 // nodes
01810 
01811 QString QgsExpression::NodeList::dump() const
01812 {
01813   QString msg; bool first = true;
01814   foreach ( Node* n, mList )
01815   {
01816     if ( !first ) msg += ", "; else first = false;
01817     msg += n->dump();
01818   }
01819   return msg;
01820 }
01821 
01822 
01823 //
01824 
01825 QVariant QgsExpression::NodeUnaryOperator::eval( QgsExpression* parent, const QgsFeature* f )
01826 {
01827   QVariant val = mOperand->eval( parent, f );
01828   ENSURE_NO_EVAL_ERROR;
01829 
01830   switch ( mOp )
01831   {
01832     case uoNot:
01833     {
01834       TVL tvl = getTVLValue( val, parent );
01835       ENSURE_NO_EVAL_ERROR;
01836       return tvl2variant( NOT[tvl] );
01837     }
01838 
01839     case uoMinus:
01840       if ( isIntSafe( val ) )
01841         return QVariant( - getIntValue( val, parent ) );
01842       else if ( isDoubleSafe( val ) )
01843         return QVariant( - getDoubleValue( val, parent ) );
01844       else
01845         SET_EVAL_ERROR( QObject::tr( "Unary minus only for numeric values." ) );
01846       break;
01847     default:
01848       Q_ASSERT( 0 && "unknown unary operation" );
01849   }
01850   return QVariant();
01851 }
01852 
01853 bool QgsExpression::NodeUnaryOperator::prepare( QgsExpression* parent, const QgsFields& fields )
01854 {
01855   return mOperand->prepare( parent, fields );
01856 }
01857 
01858 QString QgsExpression::NodeUnaryOperator::dump() const
01859 {
01860   return QString( "%1 %2" ).arg( UnaryOperatorText[mOp] ).arg( mOperand->dump() );
01861 }
01862 
01863 //
01864 
01865 QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, const QgsFeature* f )
01866 {
01867   QVariant vL = mOpLeft->eval( parent, f );
01868   ENSURE_NO_EVAL_ERROR;
01869   QVariant vR = mOpRight->eval( parent, f );
01870   ENSURE_NO_EVAL_ERROR;
01871 
01872   switch ( mOp )
01873   {
01874     case boPlus:
01875     case boMinus:
01876     case boMul:
01877     case boDiv:
01878     case boMod:
01879       if ( isNull( vL ) || isNull( vR ) )
01880         return QVariant();
01881       else if ( isIntSafe( vL ) && isIntSafe( vR ) )
01882       {
01883         // both are integers - let's use integer arithmetics
01884         int iL = getIntValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01885         int iR = getIntValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01886         if ( mOp == boDiv && iR == 0 ) return QVariant(); // silently handle division by zero and return NULL
01887         return QVariant( computeInt( iL, iR ) );
01888       }
01889       else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
01890       {
01891         QDateTime dL = getDateTimeValue( vL, parent );  ENSURE_NO_EVAL_ERROR;
01892         QgsExpression::Interval iL = getInterval( vR, parent ); ENSURE_NO_EVAL_ERROR;
01893         if ( mOp == boDiv || mOp == boMul || mOp == boMod )
01894         {
01895           parent->setEvalErrorString( QObject::tr( "Can't preform /, *, or % on DateTime and Interval" ) );
01896           return QVariant();
01897         }
01898         return QVariant( computeDateTimeFromInterval( dL, &iL ) );
01899       }
01900       else
01901       {
01902         // general floating point arithmetic
01903         double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01904         double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01905         if ( mOp == boDiv && fR == 0 )
01906           return QVariant(); // silently handle division by zero and return NULL
01907         return QVariant( computeDouble( fL, fR ) );
01908       }
01909 
01910     case boPow:
01911       if ( isNull( vL ) || isNull( vR ) )
01912         return QVariant();
01913       else
01914       {
01915         double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01916         double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01917         return QVariant( pow( fL, fR ) );
01918       }
01919 
01920     case boAnd:
01921     {
01922       TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
01923       ENSURE_NO_EVAL_ERROR;
01924       return tvl2variant( AND[tvlL][tvlR] );
01925     }
01926 
01927     case boOr:
01928     {
01929       TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
01930       ENSURE_NO_EVAL_ERROR;
01931       return tvl2variant( OR[tvlL][tvlR] );
01932     }
01933 
01934     case boEQ:
01935     case boNE:
01936     case boLT:
01937     case boGT:
01938     case boLE:
01939     case boGE:
01940       if ( isNull( vL ) || isNull( vR ) )
01941       {
01942         return TVL_Unknown;
01943       }
01944       else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
01945       {
01946         // do numeric comparison if both operators can be converted to numbers
01947         double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01948         double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01949         return compare( fL - fR ) ? TVL_True : TVL_False;
01950       }
01951       else
01952       {
01953         // do string comparison otherwise
01954         QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01955         QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01956         int diff = QString::compare( sL, sR );
01957         return compare( diff ) ? TVL_True : TVL_False;
01958       }
01959 
01960     case boIs:
01961     case boIsNot:
01962       if ( isNull( vL ) && isNull( vR ) ) // both operators null
01963         return ( mOp == boIs ? TVL_True : TVL_False );
01964       else if ( isNull( vL ) || isNull( vR ) ) // one operator null
01965         return ( mOp == boIs ? TVL_False : TVL_True );
01966       else // both operators non-null
01967       {
01968         bool equal = false;
01969         if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
01970         {
01971           double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01972           double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01973           equal = fL == fR;
01974         }
01975         else
01976         {
01977           QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01978           QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01979           equal = QString::compare( sL, sR ) == 0;
01980         }
01981         if ( equal )
01982           return mOp == boIs ? TVL_True : TVL_False;
01983         else
01984           return mOp == boIs ? TVL_False : TVL_True;
01985       }
01986 
01987     case boRegexp:
01988     case boLike:
01989     case boNotLike:
01990     case boILike:
01991     case boNotILike:
01992       if ( isNull( vL ) || isNull( vR ) )
01993         return TVL_Unknown;
01994       else
01995       {
01996         QString str    = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01997         QString regexp = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01998         // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
01999         bool matches;
02000         if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
02001         {
02002           QString esc_regexp = QRegExp::escape( regexp );
02003           // XXX escape % and _  ???
02004           esc_regexp.replace( "%", ".*" );
02005           esc_regexp.replace( "_", "." );
02006           matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
02007         }
02008         else
02009         {
02010           matches = QRegExp( regexp ).indexIn( str ) != -1;
02011         }
02012 
02013         if ( mOp == boNotLike || mOp == boNotILike )
02014         {
02015           matches = !matches;
02016         }
02017 
02018         return matches ? TVL_True : TVL_False;
02019       }
02020 
02021     case boConcat:
02022       if ( isNull( vL ) || isNull( vR ) )
02023         return QVariant();
02024       else
02025       {
02026         QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
02027         QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
02028         return QVariant( sL + sR );
02029       }
02030 
02031     default: break;
02032   }
02033   Q_ASSERT( false );
02034   return QVariant();
02035 }
02036 
02037 bool QgsExpression::NodeBinaryOperator::compare( double diff )
02038 {
02039   switch ( mOp )
02040   {
02041     case boEQ: return diff == 0;
02042     case boNE: return diff != 0;
02043     case boLT: return diff < 0;
02044     case boGT: return diff > 0;
02045     case boLE: return diff <= 0;
02046     case boGE: return diff >= 0;
02047     default: Q_ASSERT( false ); return false;
02048   }
02049 }
02050 
02051 int QgsExpression::NodeBinaryOperator::computeInt( int x, int y )
02052 {
02053   switch ( mOp )
02054   {
02055     case boPlus: return x+y;
02056     case boMinus: return x-y;
02057     case boMul: return x*y;
02058     case boDiv: return x/y;
02059     case boMod: return x%y;
02060     default: Q_ASSERT( false ); return 0;
02061   }
02062 }
02063 
02064 QDateTime QgsExpression::NodeBinaryOperator::computeDateTimeFromInterval( QDateTime d, QgsExpression::Interval *i )
02065 {
02066   switch ( mOp )
02067   {
02068     case boPlus: return d.addSecs( i->seconds() );
02069     case boMinus: return d.addSecs( -i->seconds() );
02070     default: Q_ASSERT( false ); return QDateTime();
02071   }
02072 }
02073 
02074 double QgsExpression::NodeBinaryOperator::computeDouble( double x, double y )
02075 {
02076   switch ( mOp )
02077   {
02078     case boPlus: return x+y;
02079     case boMinus: return x-y;
02080     case boMul: return x*y;
02081     case boDiv: return x/y;
02082     case boMod: return fmod( x,y );
02083     default: Q_ASSERT( false ); return 0;
02084   }
02085 }
02086 
02087 
02088 bool QgsExpression::NodeBinaryOperator::prepare( QgsExpression* parent, const QgsFields& fields )
02089 {
02090   bool resL = mOpLeft->prepare( parent, fields );
02091   bool resR = mOpRight->prepare( parent, fields );
02092   return resL && resR;
02093 }
02094 
02095 QString QgsExpression::NodeBinaryOperator::dump() const
02096 {
02097   return QString( "%1 %2 %3" ).arg( mOpLeft->dump() ).arg( BinaryOperatorText[mOp] ).arg( mOpRight->dump() );
02098 }
02099 
02100 //
02101 
02102 QVariant QgsExpression::NodeInOperator::eval( QgsExpression* parent, const QgsFeature* f )
02103 {
02104   if ( mList->count() == 0 )
02105     return mNotIn ? TVL_True : TVL_False;
02106   QVariant v1 = mNode->eval( parent, f );
02107   ENSURE_NO_EVAL_ERROR;
02108   if ( isNull( v1 ) )
02109     return TVL_Unknown;
02110 
02111   bool listHasNull = false;
02112 
02113   foreach ( Node* n, mList->list() )
02114   {
02115     QVariant v2 = n->eval( parent, f );
02116     ENSURE_NO_EVAL_ERROR;
02117     if ( isNull( v2 ) )
02118       listHasNull = true;
02119     else
02120     {
02121       bool equal = false;
02122       // check whether they are equal
02123       if ( isDoubleSafe( v1 ) && isDoubleSafe( v2 ) )
02124       {
02125         double f1 = getDoubleValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
02126         double f2 = getDoubleValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
02127         equal = f1 == f2;
02128       }
02129       else
02130       {
02131         QString s1 = getStringValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
02132         QString s2 = getStringValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
02133         equal = QString::compare( s1, s2 ) == 0;
02134       }
02135 
02136       if ( equal ) // we know the result
02137         return mNotIn ? TVL_False : TVL_True;
02138     }
02139   }
02140 
02141   // item not found
02142   if ( listHasNull )
02143     return TVL_Unknown;
02144   else
02145     return mNotIn ? TVL_True : TVL_False;
02146 }
02147 
02148 bool QgsExpression::NodeInOperator::prepare( QgsExpression* parent, const QgsFields& fields )
02149 {
02150   bool res = mNode->prepare( parent, fields );
02151   foreach ( Node* n, mList->list() )
02152   {
02153     res = res && n->prepare( parent, fields );
02154   }
02155   return res;
02156 }
02157 
02158 QString QgsExpression::NodeInOperator::dump() const
02159 {
02160   return QString( "%1 IN (%2)" ).arg( mNode->dump() ).arg( mList->dump() );
02161 }
02162 
02163 //
02164 
02165 QVariant QgsExpression::NodeFunction::eval( QgsExpression* parent, const QgsFeature* f )
02166 {
02167   Function* fd = Functions()[mFnIndex];
02168 
02169   // evaluate arguments
02170   QVariantList argValues;
02171   if ( mArgs )
02172   {
02173     foreach ( Node* n, mArgs->list() )
02174     {
02175       QVariant v = n->eval( parent, f );
02176       ENSURE_NO_EVAL_ERROR;
02177       if ( isNull( v ) && fd->name() != "coalesce" )
02178         return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
02179       argValues.append( v );
02180     }
02181   }
02182 
02183   // run the function
02184   QVariant res = fd->func( argValues, f, parent );
02185   ENSURE_NO_EVAL_ERROR;
02186 
02187   // everything went fine
02188   return res;
02189 }
02190 
02191 bool QgsExpression::NodeFunction::prepare( QgsExpression* parent, const QgsFields& fields )
02192 {
02193   bool res = true;
02194   if ( mArgs )
02195   {
02196     foreach ( Node* n, mArgs->list() )
02197     {
02198       res = res && n->prepare( parent, fields );
02199     }
02200   }
02201   return res;
02202 }
02203 
02204 QString QgsExpression::NodeFunction::dump() const
02205 {
02206   Function* fd = Functions()[mFnIndex];
02207   if ( fd->params() == 0 )
02208     return fd->name(); // special column
02209   else
02210     return QString( "%1(%2)" ).arg( fd->name() ).arg( mArgs ? mArgs->dump() : QString() ); // function
02211 }
02212 
02213 //
02214 
02215 QVariant QgsExpression::NodeLiteral::eval( QgsExpression* , const QgsFeature* )
02216 {
02217   return mValue;
02218 }
02219 
02220 bool QgsExpression::NodeLiteral::prepare( QgsExpression* /*parent*/, const QgsFields& /*fields*/ )
02221 {
02222   return true;
02223 }
02224 
02225 
02226 QString QgsExpression::NodeLiteral::dump() const
02227 {
02228   if ( mValue.isNull() )
02229     return "NULL";
02230 
02231   switch ( mValue.type() )
02232   {
02233     case QVariant::Int: return QString::number( mValue.toInt() );
02234     case QVariant::Double: return QString::number( mValue.toDouble() );
02235     case QVariant::String: return QString( "'%1'" ).arg( mValue.toString() );
02236     default: return QObject::tr( "[unsupported type;%1; value:%2]" ).arg( mValue.typeName() ).arg( mValue.toString() );
02237   }
02238 }
02239 
02240 //
02241 
02242 QVariant QgsExpression::NodeColumnRef::eval( QgsExpression* /*parent*/, const QgsFeature* f )
02243 {
02244   if ( f )
02245   {
02246     if ( mIndex >= 0 )
02247       return f->attribute( mIndex );
02248     else
02249       return f->attribute( mName );
02250   }
02251   return QVariant( "[" + mName + "]" );
02252 }
02253 
02254 bool QgsExpression::NodeColumnRef::prepare( QgsExpression* parent, const QgsFields& fields )
02255 {
02256   for ( int i = 0; i < fields.count(); ++i )
02257   {
02258     if ( QString::compare( fields[i].name(), mName, Qt::CaseInsensitive ) == 0 )
02259     {
02260       mIndex = i;
02261       return true;
02262     }
02263   }
02264   parent->mEvalErrorString = QObject::tr( "Column '%1' not found" ).arg( mName );
02265   mIndex = -1;
02266   return false;
02267 }
02268 
02269 QString QgsExpression::NodeColumnRef::dump() const
02270 {
02271   return mName;
02272 }
02273 
02274 //
02275 
02276 QVariant QgsExpression::NodeCondition::eval( QgsExpression* parent, const QgsFeature* f )
02277 {
02278   foreach ( WhenThen* cond, mConditions )
02279   {
02280     QVariant vWhen = cond->mWhenExp->eval( parent, f );
02281     TVL tvl = getTVLValue( vWhen, parent );
02282     ENSURE_NO_EVAL_ERROR;
02283     if ( tvl == True )
02284     {
02285       QVariant vRes = cond->mThenExp->eval( parent, f );
02286       ENSURE_NO_EVAL_ERROR;
02287       return vRes;
02288     }
02289   }
02290 
02291   if ( mElseExp )
02292   {
02293     QVariant vElse = mElseExp->eval( parent, f );
02294     ENSURE_NO_EVAL_ERROR;
02295     return vElse;
02296   }
02297 
02298   // return NULL if no condition is matching
02299   return QVariant();
02300 }
02301 
02302 bool QgsExpression::NodeCondition::prepare( QgsExpression* parent, const QgsFields& fields )
02303 {
02304   bool res;
02305   foreach ( WhenThen* cond, mConditions )
02306   {
02307     res = cond->mWhenExp->prepare( parent, fields )
02308           & cond->mThenExp->prepare( parent, fields );
02309     if ( !res ) return false;
02310   }
02311 
02312   if ( mElseExp )
02313     return mElseExp->prepare( parent, fields );
02314 
02315   return true;
02316 }
02317 
02318 QString QgsExpression::NodeCondition::dump() const
02319 {
02320   QString msg = "CONDITION:\n";
02321   foreach ( WhenThen* cond, mConditions )
02322   {
02323     msg += QString( "- WHEN %1 THEN %2\n" ).arg( cond->mWhenExp->dump() ).arg( cond->mThenExp->dump() );
02324   }
02325   if ( mElseExp )
02326     msg += QString( "- ELSE %1" ).arg( mElseExp->dump() );
02327   return msg;
02328 }
02329 
02330 QStringList QgsExpression::NodeCondition::referencedColumns() const
02331 {
02332   QStringList lst;
02333   foreach ( WhenThen* cond, mConditions )
02334   {
02335     lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
02336   }
02337 
02338   if ( mElseExp )
02339     lst += mElseExp->referencedColumns();
02340 
02341   return lst;
02342 }
02343 
02344 bool QgsExpression::NodeCondition::needsGeometry() const
02345 {
02346   foreach ( WhenThen* cond, mConditions )
02347   {
02348     if ( cond->mWhenExp->needsGeometry() ||
02349          cond->mThenExp->needsGeometry() )
02350       return true;
02351   }
02352 
02353   if ( mElseExp && mElseExp->needsGeometry() )
02354     return true;
02355 
02356   return false;
02357 }
02358 
02359 QString QgsExpression::helptext( QString name )
02360 {
02361   QgsExpression::initFunctionHelp();
02362   return gFunctionHelpTexts.value( name, QObject::tr( "function help for %1 missing" ).arg( name ) );
02363 }
02364 
02365 QHash<QString, QString> QgsExpression::gGroups;
02366 
02367 QString QgsExpression::group( QString name )
02368 {
02369   if ( gGroups.isEmpty() )
02370   {
02371     gGroups.insert( "Operators", QObject::tr( "Operators" ) );
02372     gGroups.insert( "Conditionals", QObject::tr( "Conditionals" ) );
02373     gGroups.insert( "Fields and Values", QObject::tr( "Fields and Values" ) );
02374     gGroups.insert( "Math", QObject::tr( "Math" ) );
02375     gGroups.insert( "Conversions", QObject::tr( "Conversions" ) );
02376     gGroups.insert( "Date and Time", QObject::tr( "Date and Time" ) );
02377     gGroups.insert( "String", QObject::tr( "String" ) );
02378     gGroups.insert( "Color", QObject::tr( "Color" ) );
02379     gGroups.insert( "Geometry", QObject::tr( "Geometry" ) );
02380     gGroups.insert( "Record", QObject::tr( "Record" ) );
02381   }
02382 
02383   return gGroups.value( name, QObject::tr( "Missing group %1" ).arg( name ) );
02384 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines