Skip to content

Commit 0c4bf94

Browse files
committed
Allow expression functions to appear in multiple groups (fix #15682)
Now functions which make sense for multiple contexts (eg length, to_date) can appear in more than one group.
1 parent 3b1dfa7 commit 0c4bf94

5 files changed

+163
-20
lines changed

python/core/qgsexpression.sip

+42-1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,19 @@ class QgsExpression
306306
bool handlesNull = false,
307307
bool isContextual = false );
308308

309+
/** Constructor for function which uses unnamed parameters and group list
310+
* @note added in QGIS 3.0
311+
*/
312+
Function( const QString& fnname,
313+
int params,
314+
const QStringList& groups,
315+
const QString& helpText = QString(),
316+
bool usesGeometry = false,
317+
const QSet<QString>& referencedColumns = QSet<QString>(),
318+
bool lazyEval = false,
319+
bool handlesNull = false,
320+
bool isContextual = false );
321+
309322
/** Constructor for function which uses named parameter list.
310323
* @note added in QGIS 2.16
311324
*/
@@ -319,6 +332,19 @@ class QgsExpression
319332
bool handlesNull = false,
320333
bool isContextual = false );
321334

335+
/** Constructor for function which uses named parameter list and group list.
336+
* @note added in QGIS 3.0
337+
*/
338+
Function( const QString& fnname,
339+
const QgsExpression::ParameterList& params,
340+
const QStringList& groups,
341+
const QString& helpText = QString(),
342+
bool usesGeometry = false,
343+
const QSet<QString>& referencedColumns = QSet<QString>(),
344+
bool lazyEval = false,
345+
bool handlesNull = false,
346+
bool isContextual = false );
347+
322348
virtual ~Function();
323349

324350
/** The name of the function. */
@@ -357,8 +383,23 @@ class QgsExpression
357383
*/
358384
bool isContextual() const;
359385

360-
/** The group the function belongs to. */
386+
/** Returns true if the function is deprecated and should not be presented as a valid option
387+
* to users in expression builders.
388+
* @note added in QGIS 3.0
389+
*/
390+
virtual bool isDeprecated() const;
391+
392+
/** Returns the first group which the function belongs to.
393+
* @note consider using groups() instead, as some functions naturally belong in multiple groups
394+
*/
361395
QString group() const;
396+
397+
/** Returns a list of the groups the function belongs to.
398+
* @note added in QGIS 3.0
399+
* @see group()
400+
*/
401+
QStringList groups() const;
402+
362403
/** The help text for the function. */
363404
const QString helpText() const;
364405

src/core/qgsexpression.cpp

+11-11
Original file line numberDiff line numberDiff line change
@@ -3403,7 +3403,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
34033403
<< new StaticFunction( "sqrt", ParameterList() << Parameter( "value" ), fcnSqrt, "Math" )
34043404
<< new StaticFunction( "radians", ParameterList() << Parameter( "degrees" ), fcnRadians, "Math" )
34053405
<< new StaticFunction( "degrees", ParameterList() << Parameter( "radians" ), fcnDegrees, "Math" )
3406-
<< new StaticFunction( "azimuth", ParameterList() << Parameter( "point_a" ) << Parameter( "point_b" ), fcnAzimuth, "Math" )
3406+
<< new StaticFunction( "azimuth", ParameterList() << Parameter( "point_a" ) << Parameter( "point_b" ), fcnAzimuth, QStringList() << "Math" << "GeometryGroup" )
34073407
<< new StaticFunction( "project", ParameterList() << Parameter( "point" ) << Parameter( "distance" ) << Parameter( "bearing" ), fcnProject, "GeometryGroup" )
34083408
<< new StaticFunction( "abs", ParameterList() << Parameter( "value" ), fcnAbs, "Math" )
34093409
<< new StaticFunction( "cos", ParameterList() << Parameter( "angle" ), fcnCos, "Math" )
@@ -3428,13 +3428,13 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
34283428
<< new StaticFunction( "floor", 1, fcnFloor, "Math" )
34293429
<< new StaticFunction( "ceil", 1, fcnCeil, "Math" )
34303430
<< new StaticFunction( "pi", 0, fcnPi, "Math", QString(), false, QSet<QString>(), false, QStringList() << "$pi" )
3431-
<< new StaticFunction( "to_int", 1, fcnToInt, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "toint" )
3432-
<< new StaticFunction( "to_real", 1, fcnToReal, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "toreal" )
3433-
<< new StaticFunction( "to_string", 1, fcnToString, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "tostring" )
3434-
<< new StaticFunction( "to_datetime", 1, fcnToDateTime, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "todatetime" )
3435-
<< new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "todate" )
3436-
<< new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "totime" )
3437-
<< new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "tointerval" )
3431+
<< new StaticFunction( "to_int", ParameterList() << Parameter( "value" ), fcnToInt, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "toint" )
3432+
<< new StaticFunction( "to_real", ParameterList() << Parameter( "value" ), fcnToReal, "Conversions", QString(), false, QSet<QString>(), false, QStringList() << "toreal" )
3433+
<< new StaticFunction( "to_string", ParameterList() << Parameter( "value" ), fcnToString, QStringList() << "Conversions" << "String", QString(), false, QSet<QString>(), false, QStringList() << "tostring" )
3434+
<< new StaticFunction( "to_datetime", ParameterList() << Parameter( "value" ), fcnToDateTime, QStringList() << "Conversions" << "Date and Time", QString(), false, QSet<QString>(), false, QStringList() << "todatetime" )
3435+
<< new StaticFunction( "to_date", ParameterList() << Parameter( "value" ), fcnToDate, QStringList() << "Conversions" << "Date and Time", QString(), false, QSet<QString>(), false, QStringList() << "todate" )
3436+
<< new StaticFunction( "to_time", ParameterList() << Parameter( "value" ), fcnToTime, QStringList() << "Conversions" << "Date and Time", QString(), false, QSet<QString>(), false, QStringList() << "totime" )
3437+
<< new StaticFunction( "to_interval", ParameterList() << Parameter( "value" ), fcnToInterval, QStringList() << "Conversions" << "Date and Time", QString(), false, QSet<QString>(), false, QStringList() << "tointerval" )
34383438
<< new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QSet<QString>(), false, QStringList(), true )
34393439
<< new StaticFunction( "if", 3, fcnIf, "Conditionals", QString(), False, QSet<QString>(), true )
34403440
<< new StaticFunction( "aggregate", ParameterList() << Parameter( "layer" ) << Parameter( "aggregate" ) << Parameter( "expression" )
@@ -3462,7 +3462,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
34623462
<< new StaticFunction( "collect", aggParams, fcnAggregateCollectGeometry, "Aggregates", QString(), False, QSet<QString>(), true )
34633463
<< new StaticFunction( "concatenate", aggParams << Parameter( "concatenator", true ), fcnAggregateStringConcat, "Aggregates", QString(), False, QSet<QString>(), true )
34643464

3465-
<< new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
3465+
<< new StaticFunction( "regexp_match", ParameterList() << Parameter( "string" ) << Parameter( "regex" ), fcnRegexpMatch, QStringList() << "Conditionals" << "String" )
34663466
<< new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QSet<QString>(), false, QStringList() << "$now" )
34673467
<< new StaticFunction( "age", 2, fcnAge, "Date and Time" )
34683468
<< new StaticFunction( "year", 1, fcnYear, "Date and Time" )
@@ -3483,7 +3483,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
34833483
<< new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
34843484
<< new StaticFunction( "char", 1, fcnChar, "String" )
34853485
<< new StaticFunction( "wordwrap", ParameterList() << Parameter( "text" ) << Parameter( "length" ) << Parameter( "delimiter", true, "" ), fcnWordwrap, "String" )
3486-
<< new StaticFunction( "length", 1, fcnLength, "String" )
3486+
<< new StaticFunction( "length", ParameterList() << Parameter( "text", true, "" ), fcnLength, QStringList() << "String" << "GeometryGroup" )
34873487
<< new StaticFunction( "replace", 3, fcnReplace, "String" )
34883488
<< new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
34893489
<< new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
@@ -3496,7 +3496,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
34963496
<< new StaticFunction( "lpad", 3, fcnLPad, "String" )
34973497
<< new StaticFunction( "format", -1, fcnFormatString, "String" )
34983498
<< new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
3499-
<< new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
3499+
<< new StaticFunction( "format_date", ParameterList() << Parameter( "date" ) << Parameter( "format" ), fcnFormatDate, QStringList() << "String" << "Date and Time" )
35003500
<< new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
35013501
<< new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
35023502
<< new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )

src/core/qgsexpression.h

+85-5
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,31 @@ class CORE_EXPORT QgsExpression
458458
: mName( fnname )
459459
, mParams( params )
460460
, mUsesGeometry( usesGeometry )
461-
, mGroup( group )
461+
, mGroups( group.isEmpty() ? QStringList() : QStringList() << group )
462+
, mHelpText( helpText )
463+
, mReferencedColumns( referencedColumns )
464+
, mLazyEval( lazyEval )
465+
, mHandlesNull( handlesNull )
466+
, mIsContextual( isContextual )
467+
{
468+
}
469+
470+
/** Constructor for function which uses unnamed parameters and group list
471+
* @note added in QGIS 3.0
472+
*/
473+
Function( const QString& fnname,
474+
int params,
475+
const QStringList& groups,
476+
const QString& helpText = QString(),
477+
bool usesGeometry = false,
478+
const QSet<QString>& referencedColumns = QSet<QString>(),
479+
bool lazyEval = false,
480+
bool handlesNull = false,
481+
bool isContextual = false )
482+
: mName( fnname )
483+
, mParams( params )
484+
, mUsesGeometry( usesGeometry )
485+
, mGroups( groups )
462486
, mHelpText( helpText )
463487
, mReferencedColumns( referencedColumns )
464488
, mLazyEval( lazyEval )
@@ -483,7 +507,31 @@ class CORE_EXPORT QgsExpression
483507
, mParams( 0 )
484508
, mParameterList( params )
485509
, mUsesGeometry( usesGeometry )
486-
, mGroup( group )
510+
, mGroups( group.isEmpty() ? QStringList() : QStringList() << group )
511+
, mHelpText( helpText )
512+
, mReferencedColumns( referencedColumns )
513+
, mLazyEval( lazyEval )
514+
, mHandlesNull( handlesNull )
515+
, mIsContextual( isContextual )
516+
{}
517+
518+
/** Constructor for function which uses named parameter list and group list.
519+
* @note added in QGIS 3.0
520+
*/
521+
Function( const QString& fnname,
522+
const ParameterList& params,
523+
const QStringList& groups,
524+
const QString& helpText = QString(),
525+
bool usesGeometry = false,
526+
const QSet<QString>& referencedColumns = QSet<QString>(),
527+
bool lazyEval = false,
528+
bool handlesNull = false,
529+
bool isContextual = false )
530+
: mName( fnname )
531+
, mParams( 0 )
532+
, mParameterList( params )
533+
, mUsesGeometry( usesGeometry )
534+
, mGroups( groups )
487535
, mHelpText( helpText )
488536
, mReferencedColumns( referencedColumns )
489537
, mLazyEval( lazyEval )
@@ -541,8 +589,22 @@ class CORE_EXPORT QgsExpression
541589
*/
542590
bool isContextual() const { return mIsContextual; }
543591

544-
/** The group the function belongs to. */
545-
QString group() const { return mGroup; }
592+
/** Returns true if the function is deprecated and should not be presented as a valid option
593+
* to users in expression builders.
594+
* @note added in QGIS 3.0
595+
*/
596+
virtual bool isDeprecated() const { return mGroups.isEmpty() ? false : mGroups.contains( "deprecated" ); }
597+
598+
/** Returns the first group which the function belongs to.
599+
* @note consider using groups() instead, as some functions naturally belong in multiple groups
600+
*/
601+
QString group() const { return mGroups.isEmpty() ? QString() : mGroups.at( 0 ); }
602+
603+
/** Returns a list of the groups the function belongs to.
604+
* @note added in QGIS 3.0
605+
* @see group()
606+
*/
607+
QStringList groups() const { return mGroups; }
546608

547609
/** The help text for the function. */
548610
const QString helpText() const { return mHelpText.isEmpty() ? QgsExpression::helpText( mName ) : mHelpText; }
@@ -564,7 +626,7 @@ class CORE_EXPORT QgsExpression
564626
int mParams;
565627
ParameterList mParameterList;
566628
bool mUsesGeometry;
567-
QString mGroup;
629+
QStringList mGroups;
568630
QString mHelpText;
569631
QSet<QString> mReferencedColumns;
570632
bool mLazyEval;
@@ -614,6 +676,24 @@ class CORE_EXPORT QgsExpression
614676
, mAliases( aliases )
615677
{}
616678

679+
/** Static function for evaluation against a QgsExpressionContext, using a named list of parameter values and list
680+
* of groups.
681+
*/
682+
StaticFunction( const QString& fnname,
683+
const ParameterList& params,
684+
FcnEval fcn,
685+
const QStringList& groups,
686+
const QString& helpText = QString(),
687+
bool usesGeometry = false,
688+
const QSet<QString>& referencedColumns = QSet<QString>(),
689+
bool lazyEval = false,
690+
const QStringList& aliases = QStringList(),
691+
bool handlesNull = false )
692+
: Function( fnname, params, groups, helpText, usesGeometry, referencedColumns, lazyEval, handlesNull )
693+
, mFnc( fcn )
694+
, mAliases( aliases )
695+
{}
696+
617697
virtual ~StaticFunction() {}
618698

619699
/** Returns result of evaluating the function.

src/gui/qgsexpressionbuilderwidget.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ void QgsExpressionBuilderWidget::updateFunctionTree()
479479
QString name = func->name();
480480
if ( name.startsWith( '_' ) ) // do not display private functions
481481
continue;
482-
if ( func->group() == "deprecated" ) // don't show deprecated functions
482+
if ( func->isDeprecated() ) // don't show deprecated functions
483483
continue;
484484
if ( func->isContextual() )
485485
{
@@ -491,7 +491,7 @@ void QgsExpressionBuilderWidget::updateFunctionTree()
491491
name += '(';
492492
else if ( !name.startsWith( '$' ) )
493493
name += "()";
494-
registerItem( func->group(), func->name(), ' ' + name + ' ', func->helpText() );
494+
registerItemForAllGroups( func->groups(), func->name(), ' ' + name + ' ', func->helpText() );
495495
}
496496

497497
loadExpressionContext();
@@ -614,7 +614,15 @@ void QgsExpressionBuilderWidget::loadExpressionContext()
614614
continue;
615615
if ( func->params() != 0 )
616616
name += '(';
617-
registerItem( func->group(), func->name(), ' ' + name + ' ', func->helpText() );
617+
registerItemForAllGroups( func->groups(), func->name(), ' ' + name + ' ', func->helpText() );
618+
}
619+
}
620+
621+
void QgsExpressionBuilderWidget::registerItemForAllGroups( const QStringList& groups, const QString& label, const QString& expressionText, const QString& helpText, QgsExpressionItem::ItemType type, bool highlightedItem, int sortOrder )
622+
{
623+
Q_FOREACH ( const QString& group, groups )
624+
{
625+
registerItem( group, label, expressionText, helpText, type, highlightedItem, sortOrder );
618626
}
619627
}
620628

src/gui/qgsexpressionbuilderwidget.h

+14
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,20 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
281281

282282
void loadExpressionContext();
283283

284+
/** Registers a node item for the expression builder, adding multiple items when the function exists in multiple groups
285+
* @param groups The groups the item will be show in the tree view. If a group doesn't exist it will be created.
286+
* @param label The label that is show to the user for the item in the tree.
287+
* @param expressionText The text that is inserted into the expression area when the user double clicks on the item.
288+
* @param helpText The help text that the user will see when item is selected.
289+
* @param type The type of the expression item.
290+
* @param highlightedItem set to true to make the item highlighted, which inserts a bold copy of the item at the top level
291+
* @param sortOrder sort ranking for item
292+
*/
293+
void registerItemForAllGroups( const QStringList& groups, const QString& label, const QString& expressionText,
294+
const QString& helpText = "",
295+
QgsExpressionItem::ItemType type = QgsExpressionItem::ExpressionNode,
296+
bool highlightedItem = false, int sortOrder = 1 );
297+
284298
bool mAutoSave;
285299
QString mFunctionsPath;
286300
QgsVectorLayer *mLayer;

0 commit comments

Comments
 (0)