Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Display variables and functions from contexts in expression builder
  • Loading branch information
nyalldawson committed Aug 22, 2015
1 parent c9c12bc commit bfc8f56
Show file tree
Hide file tree
Showing 18 changed files with 245 additions and 30 deletions.
6 changes: 6 additions & 0 deletions python/core/composer/qgscomposition.sip
Expand Up @@ -678,6 +678,12 @@ class QgsComposition : QGraphicsScene
*/
void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = 0 );

/** Creates an expression context relating to the compositions's current state. The context includes
* scopes for global, project, composition and atlas properties.
* @note added in QGIS 2.12
*/
QgsExpressionContext* createExpressionContext() const;

protected:
void init();

Expand Down
35 changes: 29 additions & 6 deletions python/core/qgsexpressioncontext.sip
Expand Up @@ -121,6 +121,7 @@ class QgsExpressionContextScope
QVariant variable( const QString& name ) const;

/** Returns a list of variable names contained within the scope.
* @see functionNames()
*/
QStringList variableNames() const;

Expand All @@ -147,10 +148,17 @@ class QgsExpressionContextScope
* @param name function name
* @returns function, or null if matching function could not be found
* @see hasFunction()
* @see functionNames()
* @see variable()
*/
QgsExpression::Function* function( const QString &name ) const;

/** Retrieves a list of names of functions contained in the scope.
* @see function()
* @see variableNames()
*/
QStringList functionNames() const;

/** Adds a function to the scope.
* @param name function name
* @param function function to insert. Ownership is transferred to the scope.
Expand All @@ -163,7 +171,7 @@ class QgsExpressionContextScope
* @param feature feature for scope
*/
void setFeature( const QgsFeature& feature );

/** Convenience function for setting a fields for the scope. Any existing
* fields set by the scope will be overwritten.
* @param fields fields for scope
Expand Down Expand Up @@ -253,11 +261,20 @@ class QgsExpressionContext

/** Returns a list of variables names set by all scopes in the context.
* @returns list of unique variable names
* @see filteredVariableNames
* @see functionNames
* @see hasVariable
* @see variable
*/
QStringList variableNames() const;

/** Returns a filtered list of variables names set by all scopes in the context. The included
* variables are those which should be seen by users.
* @returns filtered list of unique variable names
* @see variableNames
*/
QStringList filteredVariableNames() const;

/** Returns whether a variable is read only, and should not be modifiable by users.
* @param name variable name
* @returns true if variable is read only. Read only status will be taken from last
Expand All @@ -272,6 +289,12 @@ class QgsExpressionContext
*/
bool hasFunction( const QString& name ) const;

/** Retrieves a list of function names contained in the context.
* @see function()
* @see variableNames()
*/
QStringList functionNames() const;

/** Fetches a matching function from the context. The function will be fetched
* from the last scope contained within the context which has a matching
* function set.
Expand All @@ -297,21 +320,21 @@ class QgsExpressionContext
* context. Ownership of the scope is transferred to the stack.
*/
QgsExpressionContext& operator<< ( QgsExpressionContextScope* scope /Transfer/ );

/** Convenience function for setting a feature for the context. The feature
* will be set within the last scope of the context, so will override any
* existing features within the context.
* @param feature feature for context
*/
void setFeature( const QgsFeature& feature );
void setFeature( const QgsFeature& feature );

/** Convenience function for setting a fields for the context. The fields
* will be set within the last scope of the context, so will override any
* existing fields within the context.
* @param fields fields for context
*/
void setFields( const QgsFields& fields );

};

/** \ingroup core
Expand Down Expand Up @@ -378,12 +401,12 @@ class QgsExpressionContextUtils
* For instance, layer name, id and fields.
*/
static QgsExpressionContextScope* layerScope( QgsMapLayer* layer ) /Factory/;

/** Helper function for creating an expression context which contains just a feature and fields
* collection. Generally this method should not be used as the created context does not include
* standard scopes such as the global and project scopes.
*/
static QgsExpressionContext createFeatureBasedContext( const QgsFeature& feature, const QgsFields& fields );
static QgsExpressionContext createFeatureBasedContext( const QgsFeature& feature, const QgsFields& fields );

/** Sets a layer context variable. This variable will be contained within scopes retrieved via
* layerScope().
Expand Down
18 changes: 17 additions & 1 deletion python/gui/qgsexpressionbuilderdialog.sip
Expand Up @@ -8,7 +8,8 @@ class QgsExpressionBuilderDialog : QDialog
%End

public:
QgsExpressionBuilderDialog( QgsVectorLayer* layer, QString startText = QString(), QWidget* parent /TransferThis/ = NULL, QString key = "generic" );
QgsExpressionBuilderDialog( QgsVectorLayer* layer, QString startText = QString(), QWidget* parent /TransferThis/ = NULL, QString key = "generic",
const QgsExpressionContext& context = QgsExpressionContext() );

/** The builder widget that is used by the dialog */
QgsExpressionBuilderWidget* expressionBuilder();
Expand All @@ -17,6 +18,21 @@ class QgsExpressionBuilderDialog : QDialog

QString expressionText();

/** Returns the expression context for the dialog. The context is used for the expression
* preview result and for populating the list of available functions and variables.
* @see setExpressionContext
* @note added in QGIS 2.12
*/
QgsExpressionContext expressionContext() const;

/** Sets the expression context for the dialog. The context is used for the expression
* preview result and for populating the list of available functions and variables.
* @param context expression context
* @see expressionContext
* @note added in QGIS 2.12
*/
void setExpressionContext( const QgsExpressionContext& context );

/** Sets geometry calculator used in distance/area calculations. */
void setGeomCalculator( const QgsDistanceArea & da );

Expand Down
15 changes: 15 additions & 0 deletions python/gui/qgsexpressionbuilderwidget.sip
Expand Up @@ -100,6 +100,21 @@ class QgsExpressionBuilderWidget : QWidget
/** Sets the expression string for the widget */
void setExpressionText( const QString& expression );

/** Returns the expression context for the widget. The context is used for the expression
* preview result and for populating the list of available functions and variables.
* @see setExpressionContext
* @note added in QGIS 2.12
*/
QgsExpressionContext expressionContext() const;

/** Sets the expression context for the widget. The context is used for the expression
* preview result and for populating the list of available functions and variables.
* @param context expression context
* @see expressionContext
* @note added in QGIS 2.12
*/
void setExpressionContext( const QgsExpressionContext& context );

/** Registers a node item for the expression builder.
* @param group The group the item will be show in the tree view. If the group doesn't exsit it will be created.
* @param label The label that is show to the user for the item in the tree.
Expand Down
8 changes: 6 additions & 2 deletions src/app/composer/qgsatlascompositionwidget.cpp
Expand Up @@ -94,8 +94,10 @@ void QgsAtlasCompositionWidget::on_mAtlasFilenameExpressionButton_clicked()
return;
}

QgsExpressionBuilderDialog exprDlg( atlasMap->coverageLayer(), mAtlasFilenamePatternEdit->text(), this );
QScopedPointer<QgsExpressionContext> context( mComposition->createExpressionContext() );
QgsExpressionBuilderDialog exprDlg( atlasMap->coverageLayer(), mAtlasFilenamePatternEdit->text(), this, "generic", *context );
exprDlg.setWindowTitle( tr( "Expression based filename" ) );

if ( exprDlg.exec() == QDialog::Accepted )
{
QString expression = exprDlg.expressionText();
Expand Down Expand Up @@ -233,8 +235,10 @@ void QgsAtlasCompositionWidget::on_mAtlasFeatureFilterButton_clicked()
return;
}

QgsExpressionBuilderDialog exprDlg( vl, mAtlasFeatureFilterEdit->text(), this );
QScopedPointer<QgsExpressionContext> context( mComposition->createExpressionContext() );
QgsExpressionBuilderDialog exprDlg( vl, mAtlasFeatureFilterEdit->text(), this, "generic", *context );
exprDlg.setWindowTitle( tr( "Expression based filter" ) );

if ( exprDlg.exec() == QDialog::Accepted )
{
QString expression = exprDlg.expressionText();
Expand Down
3 changes: 2 additions & 1 deletion src/app/composer/qgscomposerattributetablewidget.cpp
Expand Up @@ -798,7 +798,8 @@ void QgsComposerAttributeTableWidget::on_mFeatureFilterButton_clicked()
return;
}

QgsExpressionBuilderDialog exprDlg( mComposerTable->sourceLayer(), mFeatureFilterEdit->text(), this );
QScopedPointer<QgsExpressionContext> context( mComposerTable->createExpressionContext() );
QgsExpressionBuilderDialog exprDlg( mComposerTable->sourceLayer(), mFeatureFilterEdit->text(), this, "generic", *context );
exprDlg.setWindowTitle( tr( "Expression based filter" ) );
if ( exprDlg.exec() == QDialog::Accepted )
{
Expand Down
3 changes: 2 additions & 1 deletion src/app/composer/qgscomposerhtmlwidget.cpp
Expand Up @@ -369,7 +369,8 @@ void QgsComposerHtmlWidget::on_mInsertExpressionButton_clicked()

// use the atlas coverage layer, if any
QgsVectorLayer* coverageLayer = atlasCoverageLayer();
QgsExpressionBuilderDialog exprDlg( coverageLayer, selText, this );
QScopedPointer<QgsExpressionContext> context( mHtml->createExpressionContext() );
QgsExpressionBuilderDialog exprDlg( coverageLayer, selText, this, "generic", *context );
exprDlg.setWindowTitle( tr( "Insert expression" ) );
if ( exprDlg.exec() == QDialog::Accepted )
{
Expand Down
4 changes: 3 additions & 1 deletion src/app/composer/qgscomposerlabelwidget.cpp
Expand Up @@ -152,7 +152,9 @@ void QgsComposerLabelWidget::on_mInsertExpressionButton_clicked()

// use the atlas coverage layer, if any
QgsVectorLayer* coverageLayer = atlasCoverageLayer();
QgsExpressionBuilderDialog exprDlg( coverageLayer, selText, this );
QScopedPointer<QgsExpressionContext> context( mComposerLabel->createExpressionContext() );
QgsExpressionBuilderDialog exprDlg( coverageLayer, selText, this, "generic", *context );

exprDlg.setWindowTitle( tr( "Insert expression" ) );
if ( exprDlg.exec() == QDialog::Accepted )
{
Expand Down
4 changes: 3 additions & 1 deletion src/app/composer/qgscomposertablewidget.cpp
Expand Up @@ -464,7 +464,9 @@ void QgsComposerTableWidget::on_mFeatureFilterButton_clicked()
return;
}

QgsExpressionBuilderDialog exprDlg( mComposerTable->vectorLayer(), mFeatureFilterEdit->text(), this );
QScopedPointer<QgsExpressionContext> context( mComposerTable->createExpressionContext() );
QgsExpressionBuilderDialog exprDlg( mComposerTable->vectorLayer(), mFeatureFilterEdit->text(), this, "generic", *context );

exprDlg.setWindowTitle( tr( "Expression based filter" ) );
if ( exprDlg.exec() == QDialog::Accepted )
{
Expand Down
12 changes: 6 additions & 6 deletions src/core/composer/qgscomposition.h
Expand Up @@ -741,6 +741,12 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
*/
void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = 0 );

/** Creates an expression context relating to the compositions's current state. The context includes
* scopes for global, project, composition and atlas properties.
* @note added in QGIS 2.12
*/
QgsExpressionContext* createExpressionContext() const;

protected:
void init();

Expand Down Expand Up @@ -900,12 +906,6 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
*/
void prepareDataDefinedExpression( QgsDataDefined *dd, QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined* >* dataDefinedProperties, const QgsExpressionContext& context ) const;

/** Creates an expression context relating to the compositions's current state. The context includes
* scopes for global, project, composition and atlas properties.
* @note added in QGIS 2.12
*/
QgsExpressionContext* createExpressionContext() const;

/** Check whether any data defined page settings are active.
* @returns true if any data defined page settings are active.
* @note this method was added in version 2.5
Expand Down
1 change: 1 addition & 0 deletions src/core/qgsexpression.cpp
Expand Up @@ -3041,6 +3041,7 @@ QString QgsExpression::group( QString name )
gGroups.insert( "Color", QObject::tr( "Color" ) );
gGroups.insert( "GeometryGroup", QObject::tr( "Geometry" ) );
gGroups.insert( "Record", QObject::tr( "Record" ) );
gGroups.insert( "Variables", QObject::tr( "Variables" ) );
}

//return the translated name for this group. If group does not
Expand Down
33 changes: 33 additions & 0 deletions src/core/qgsexpressioncontext.cpp
Expand Up @@ -127,6 +127,11 @@ QgsExpression::Function* QgsExpressionContextScope::function( const QString& nam
return mFunctions.contains( name ) ? mFunctions.value( name ) : 0;
}

QStringList QgsExpressionContextScope::functionNames() const
{
return mFunctions.keys();
}

void QgsExpressionContextScope::addFunction( const QString& name, QgsScopedExpressionFunction* function )
{
mFunctions.insert( name, function );
Expand Down Expand Up @@ -248,6 +253,22 @@ QStringList QgsExpressionContext::variableNames() const
return names.toSet().toList();
}

QStringList QgsExpressionContext::filteredVariableNames() const
{
QStringList allVariables = variableNames();
QStringList filtered;
Q_FOREACH ( QString variable, allVariables )
{
if ( variable.startsWith( "_" ) )
continue;

filtered << variable;
}

filtered.sort();
return filtered;
}

bool QgsExpressionContext::isReadOnly( const QString& name ) const { Q_UNUSED( name ); return true; }

bool QgsExpressionContext::hasFunction( const QString &name ) const
Expand All @@ -260,6 +281,18 @@ bool QgsExpressionContext::hasFunction( const QString &name ) const
return false;
}

QStringList QgsExpressionContext::functionNames() const
{
QStringList result;
Q_FOREACH ( const QgsExpressionContextScope* scope, mStack )
{
result << scope->functionNames();
}
result = result.toSet().toList();
result.sort();
return result;
}

QgsExpression::Function *QgsExpressionContext::function( const QString &name ) const
{
//iterate through stack backwards, so that higher priority variables take precedence
Expand Down
23 changes: 23 additions & 0 deletions src/core/qgsexpressioncontext.h
Expand Up @@ -150,6 +150,7 @@ class CORE_EXPORT QgsExpressionContextScope
QVariant variable( const QString& name ) const;

/** Returns a list of variable names contained within the scope.
* @see functionNames()
*/
QStringList variableNames() const;

Expand All @@ -176,10 +177,17 @@ class CORE_EXPORT QgsExpressionContextScope
* @param name function name
* @returns function, or null if matching function could not be found
* @see hasFunction()
* @see functionNames()
* @see variable()
*/
QgsExpression::Function* function( const QString &name ) const;

/** Retrieves a list of names of functions contained in the scope.
* @see function()
* @see variableNames()
*/
QStringList functionNames() const;

/** Adds a function to the scope.
* @param name function name
* @param function function to insert. Ownership is transferred to the scope.
Expand Down Expand Up @@ -284,11 +292,20 @@ class CORE_EXPORT QgsExpressionContext

/** Returns a list of variables names set by all scopes in the context.
* @returns list of unique variable names
* @see filteredVariableNames
* @see functionNames
* @see hasVariable
* @see variable
*/
QStringList variableNames() const;

/** Returns a filtered list of variables names set by all scopes in the context. The included
* variables are those which should be seen by users.
* @returns filtered list of unique variable names
* @see variableNames
*/
QStringList filteredVariableNames() const;

/** Returns whether a variable is read only, and should not be modifiable by users.
* @param name variable name
* @returns true if variable is read only. Read only status will be taken from last
Expand All @@ -303,6 +320,12 @@ class CORE_EXPORT QgsExpressionContext
*/
bool hasFunction( const QString& name ) const;

/** Retrieves a list of function names contained in the context.
* @see function()
* @see variableNames()
*/
QStringList functionNames() const;

/** Fetches a matching function from the context. The function will be fetched
* from the last scope contained within the context which has a matching
* function set.
Expand Down

0 comments on commit bfc8f56

Please sign in to comment.