Skip to content

Commit

Permalink
Port from expressions+ plugin: color_part, set_color_part, day_of_week
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Sep 21, 2015
1 parent fae0654 commit a4d980d
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 2 deletions.
10 changes: 10 additions & 0 deletions resources/function_help/json/color_part
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "color_part",
"type": "function",
"description": "Returns a specific component from a color string, eg the red component or alpha component.",
"arguments": [
{"arg":"color", "description":"a color string"},
{"arg":"component", "description":"a string corresponding to the color component to return. Valid options are:<br /><ul><li>red: RGB red component (0-255)</li><li>green: RGB green component (0-255)</li><li>blue: RGB blue component (0-255)</li><li>alpha: alpha (transparency) value (0-255)</li><li>hue: HSV hue (0-360)</li><li>saturation: HSV saturation (0-100)</li><li>value: HSV value (0-100)</li><li>hsl_hue: HSL hue (0-360)</li><li>hsl_saturation: HSL saturation (0-100)</li><li>lightness: HSL lightness (0-100)</li><li>cyan: CMYK cyan component (0-100)</li><li>magenta: CMYK magenta component (0-100)</li><li>yellow: CMYK yellow component (0-100)</li> <li>black: CMYK black component (0-100)</li></ul>"}
],
"examples": [ { "expression":"color_part('200,10,30','green')", "returns":"10"}]
}
8 changes: 8 additions & 0 deletions resources/function_help/json/day_of_week
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "day_of_week",
"type": "function",
"description": "Returns the day of the week for a specified date or datetime. The returned value ranges from 0 to 6, where 0 corresponds to a Sunday and 6 to a Saturday.",
"arguments": [ {"arg":"date","description":"date or datetime value"} ],
"examples": [ { "expression":"day_of_week(todate('2015-09-21'))", "returns":"1"}
]
}
11 changes: 11 additions & 0 deletions resources/function_help/json/set_color_part
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "set_color_part",
"type": "function",
"description": "Sets a specific color component for a color string, eg the red component or alpha component.",
"arguments": [
{"arg":"color", "description":"a color string"},
{"arg":"component", "description":"a string corresponding to the color component to set. Valid options are:<br /><ul><li>red: RGB red component (0-255)</li><li>green: RGB green component (0-255)</li><li>blue: RGB blue component (0-255)</li><li>alpha: alpha (transparency) value (0-255)</li><li>hue: HSV hue (0-360)</li><li>saturation: HSV saturation (0-100)</li><li>value: HSV value (0-100)</li><li>hsl_hue: HSL hue (0-360)</li><li>hsl_saturation: HSL saturation (0-100)</li><li>lightness: HSL lightness (0-100)</li><li>cyan: CMYK cyan component (0-100)</li><li>magenta: CMYK magenta component (0-100)</li><li>yellow: CMYK yellow component (0-100)</li> <li>black: CMYK black component (0-100)</li></ul>"},
{"arg":"value", "description":"new value for color component, respecting the ranges listed above"}
],
"examples": [ { "expression":"set_color_part('200,10,30','green',50)", "returns":"200,50,30"}]
}
111 changes: 109 additions & 2 deletions src/core/qgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,20 @@ static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*,
return QVariant::fromValue( QgsExpression::Interval( seconds ) );
}

static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
{
if ( !values.at( 0 ).canConvert<QDate>() )
return QVariant();

QDate date = getDateValue( values.at( 0 ), parent );
if ( !date.isValid() )
return QVariant();

// return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
// (to match PostgreSQL behaviour)
return date.dayOfWeek() % 7;
}

static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
{
QVariant value = values.at( 0 );
Expand Down Expand Up @@ -1835,6 +1849,96 @@ static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionCo
return QgsSymbolLayerV2Utils::encodeColor( color );
}

static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
{
QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
if ( ! color.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
return QVariant();
}

QString part = getStringValue( values.at( 1 ), parent );
if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
return color.red();
else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
return color.green();
else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
return color.blue();
else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
return color.alpha();
else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
return color.hsvHueF() * 360;
else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
return color.hsvSaturationF() * 100;
else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
return color.valueF() * 100;
else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
return color.hslHueF() * 360;
else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
return color.hslSaturationF() * 100;
else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
return color.lightnessF() * 100;
else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
return color.cyanF() * 100;
else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
return color.magentaF() * 100;
else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
return color.yellowF() * 100;
else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
return color.blackF() * 100;

parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
return QVariant();
}

static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
{
QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
if ( ! color.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
return QVariant();
}

QString part = getStringValue( values.at( 1 ), parent );
int value = getIntValue( values.at( 2 ), parent );
if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
color.setRed( value );
else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
color.setGreen( value );
else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
color.setBlue( value );
else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
color.setAlpha( value );
else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
else
{
parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
return QVariant();
}
return QgsSymbolLayerV2Utils::encodeColor( color );
}

static QVariant fcnSpecialColumn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QString varName = getStringValue( values.at( 0 ), parent );
Expand Down Expand Up @@ -2050,7 +2154,7 @@ const QStringList& QgsExpression::BuiltinFunctions()
<< "todatetime" << "to_datetime" << "todate" << "to_date"
<< "totime" << "to_time" << "tointerval" << "to_interval"
<< "coalesce" << "if" << "regexp_match" << "age" << "year"
<< "month" << "week" << "day" << "hour"
<< "month" << "week" << "day" << "hour" << "day_of_week"
<< "minute" << "second" << "lower" << "upper"
<< "title" << "length" << "replace" << "trim" << "wordwrap"
<< "regexp_replace" << "regexp_substr"
Expand All @@ -2059,7 +2163,7 @@ const QStringList& QgsExpression::BuiltinFunctions()
<< "format_number" << "format_date"
<< "color_rgb" << "color_rgba" << "ramp_color"
<< "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
<< "color_cymk" << "color_cymka"
<< "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
<< "xat" << "yat" << "$area" << "area" << "perimeter"
<< "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "num_points"
<< "point_n" << "start_point" << "end_point" << "make_point"
Expand Down Expand Up @@ -2131,6 +2235,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
<< new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
<< new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
<< new StaticFunction( "day_of_week", 1, fcnDayOfWeek, "Date and Time" )
<< new StaticFunction( "lower", 1, fcnLower, "String" )
<< new StaticFunction( "upper", 1, fcnUpper, "String" )
<< new StaticFunction( "title", 1, fcnTitle, "String" )
Expand Down Expand Up @@ -2163,6 +2268,8 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
<< new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
<< new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
<< new StaticFunction( "color_part", 2, fncColorPart, "Color" )
<< new StaticFunction( "set_color_part", 3, fncSetColorPart, "Color" )
<< new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", QString(), true )
<< new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", QString(), true )
<< new StaticFunction( "area", 1, fcnArea, "GeometryGroup" )
Expand Down
37 changes: 37 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,8 @@ class TestQgsExpression: public QObject
QTest::newRow( "year with interval" ) << "year(tointerval('2 years'))" << false << QVariant( 2.0 );
QTest::newRow( "age" ) << "age('2012-06-30','2012-06-28')" << false << QVariant::fromValue( QgsExpression::Interval( 172800 ) );
QTest::newRow( "negative age" ) << "age('2012-06-28','2012-06-30')" << false << QVariant::fromValue( QgsExpression::Interval( -172800 ) );
QTest::newRow( "day of week date" ) << "day_of_week(todate('2015-09-21'))" << false << QVariant( 1 );
QTest::newRow( "day of week datetime" ) << "day_of_week(to_datetime('2015-09-20 13:01:43'))" << false << QVariant( 0 );

// Color functions
QTest::newRow( "ramp color" ) << "ramp_color('Spectral',0.3)" << false << QVariant( "253,190,115,255" );
Expand All @@ -522,6 +524,41 @@ class TestQgsExpression: public QObject
QTest::newRow( "color cmyk" ) << "color_cmyk(100,50,33,10)" << false << QVariant( "0,115,154" );
QTest::newRow( "color cmyka" ) << "color_cmyka(50,25,90,60,200)" << false << QVariant( "51,76,10,200" );

QTest::newRow( "color part bad color" ) << "color_part('notacolor','red')" << true << QVariant();
QTest::newRow( "color part bad part" ) << "color_part(color_rgb(255,127,0),'bad')" << true << QVariant();
QTest::newRow( "color part red" ) << "color_part(color_rgba(200,127,150,100),'red')" << false << QVariant( 200 );
QTest::newRow( "color part green" ) << "color_part(color_rgba(200,127,150,100),'green')" << false << QVariant( 127 );
QTest::newRow( "color part blue" ) << "color_part(color_rgba(200,127,150,100),'blue')" << false << QVariant( 150 );
QTest::newRow( "color part alpha" ) << "color_part(color_rgba(200,127,150,100),'alpha')" << false << QVariant( 100 );
QTest::newRow( "color part hue" ) << "color_part(color_hsv(40,100,80),'hue')" << false << QVariant( 40.0 );
QTest::newRow( "color part saturation" ) << "color_part(color_hsv(40,100,80),'saturation')" << false << QVariant( 100.0 );
//some rounding due to conversions between color spaces:
QTest::newRow( "color part value" ) << "to_int(color_part(color_hsv(40,100,80),'value'))" << false << QVariant( 80 );
QTest::newRow( "color part hsl_hue" ) << "to_int(color_part(color_hsl(100,50,70),'hsl_hue'))" << false << QVariant( 100 );
QTest::newRow( "color part hsl_saturation" ) << "to_int(color_part(color_hsl(100,50,70),'hsl_saturation'))" << false << QVariant( 50 );
QTest::newRow( "color part lightness" ) << "to_int(color_part(color_hsl(100,50,70),'lightness'))" << false << QVariant( 70 );
QTest::newRow( "color part cyan" ) << "to_int(color_part(color_cmyk(21,0,92,70),'cyan'))" << false << QVariant( 21 );
QTest::newRow( "color part magenta" ) << "to_int(color_part(color_cmyk(0,10,90,76),'magenta'))" << false << QVariant( 10 );
QTest::newRow( "color part yellow" ) << "to_int(color_part(color_cmyk(21,0,92,70),'yellow'))" << false << QVariant( 92 );
QTest::newRow( "color part black" ) << "to_int(color_part(color_cmyk(21,0,92,70),'black'))" << false << QVariant( 70 );
QTest::newRow( "set color part bad color" ) << "set_color_part('notacolor','red', 5)" << true << QVariant();
QTest::newRow( "set color part bad part" ) << "set_color_part(color_rgb(255,127,0),'bad', 5)" << true << QVariant();
QTest::newRow( "set color part red" ) << "color_part(set_color_part(color_rgba(200,127,150,100),'red',100),'red')" << false << QVariant( 100 );
QTest::newRow( "set color part green" ) << "color_part(set_color_part(color_rgba(200,127,150,100),'green',30),'green')" << false << QVariant( 30 );
QTest::newRow( "set color part blue" ) << "color_part(set_color_part(color_rgba(200,127,150,100),'blue',120),'blue')" << false << QVariant( 120 );
QTest::newRow( "set color part alpha" ) << "color_part(set_color_part(color_rgba(200,127,150,100),'alpha',120),'alpha')" << false << QVariant( 120 );
//some rounding due to conversions between color spaces:
QTest::newRow( "set color part hue" ) << "to_int(color_part(set_color_part(color_hsv(40,100,80),'hue',30),'hue'))" << false << QVariant( 30 );
QTest::newRow( "set color part saturation" ) << "to_int(color_part(set_color_part(color_hsv(40,100,80),'saturation',40),'saturation'))" << false << QVariant( 40 );
QTest::newRow( "set color part value" ) << "to_int(color_part(set_color_part(color_hsv(40,100,80),'value',50),'value'))" << false << QVariant( 50 );
QTest::newRow( "set color part hsl_hue" ) << "to_int(color_part(set_color_part(color_hsl(100,50,70),'hsl_hue',270),'hsl_hue'))" << false << QVariant( 270 );
QTest::newRow( "set color part hsl_saturation" ) << "to_int(color_part(set_color_part(color_hsl(100,50,70),'hsl_saturation',30),'hsl_saturation'))" << false << QVariant( 30 );
QTest::newRow( "set color part lightness" ) << "to_int(color_part(set_color_part(color_hsl(100,50,70),'lightness',20),'lightness'))" << false << QVariant( 20 );
QTest::newRow( "set color part cyan" ) << "to_int(color_part(set_color_part(color_cmyk(21,0,92,70),'cyan',12),'cyan'))" << false << QVariant( 12 );
QTest::newRow( "set color part magenta" ) << "to_int(color_part(set_color_part(color_cmyk(0,10,90,76),'magenta',31),'magenta'))" << false << QVariant( 31 );
QTest::newRow( "set color part yellow" ) << "to_int(color_part(set_color_part(color_cmyk(21,0,92,70),'yellow',96),'yellow'))" << false << QVariant( 96 );
QTest::newRow( "set color part black" ) << "to_int(color_part(set_color_part(color_cmyk(21,0,92,70),'black',100),'black'))" << false << QVariant( 100 );

// Precedence and associativity
QTest::newRow( "multiplication first" ) << "1+2*3" << false << QVariant( 7 );
QTest::newRow( "brackets first" ) << "(1+2)*(3+4)" << false << QVariant( 21 );
Expand Down

0 comments on commit a4d980d

Please sign in to comment.