Remove substitution map from QgsExpression::replaceExpressionText

Since expression context variables should now be used instead. Also
remove all the deprecated methods which relied on this API.
This commit is contained in:
Nyall Dawson 2016-08-06 22:09:46 +10:00
parent c39088bace
commit a0360a6400
12 changed files with 27 additions and 280 deletions

View File

@ -128,6 +128,15 @@ corresponding counterparts in QgsUnitTypes should be used instead.</li>
<li>fileMenu() has been removed, use projectMenu() instead. <li>fileMenu() has been removed, use projectMenu() instead.
</ul> </ul>
\subsection qgis_api_break_3_0_QgsActionManager QgsActionManager
<ul>
<li>doAction() no longer accepts a substitution map. Use expression context variables instead.</li>
<li>The doAction() variant which takes a QgsFeature along has been removed. Use the expression context
variant instead.</li>
<li>expandAction() has been removed. Use QgsExpression::replaceExpressionText() instead.</li>
</ul>
\subsection qgis_api_break_3_0_QgsAtlasComposition QgsAtlasComposition \subsection qgis_api_break_3_0_QgsAtlasComposition QgsAtlasComposition
<ul> <ul>
@ -146,6 +155,15 @@ corresponding counterparts in QgsUnitTypes should be used instead.</li>
<li>GenericDataSourceURI has been renamed to GenericDataSourceUri</li> <li>GenericDataSourceURI has been renamed to GenericDataSourceUri</li>
</ul> </ul>
\subsection qgis_api_break_3_0_QgsComposerLabel QgsComposerLabel
<ul>
<li>setExpressionContext() has been removed. Setup the composition using an atlas and with
expression variables in the composer label item instead.</li>
<li>setSubstitutions has been removed. Use expression context variables in the composer
label item instead.</li>
</ul>
\subsection qgis_api_break_3_0_QgsComposerLegend QgsComposerLegend \subsection qgis_api_break_3_0_QgsComposerLegend QgsComposerLegend
<ul> <ul>
@ -313,6 +331,7 @@ version instead.</li>
<li>QgsExpression::Function::func has been modified to use a QgsExpressionContext argument rather than a QgsFeature.</li> <li>QgsExpression::Function::func has been modified to use a QgsExpressionContext argument rather than a QgsFeature.</li>
<li>The QgsExpression::Node::eval and prepare versions which take a QgsFeature has been removed, use the QgsExpressionContext versions instead.</li> <li>The QgsExpression::Node::eval and prepare versions which take a QgsFeature has been removed, use the QgsExpressionContext versions instead.</li>
<li>QgsExpression::Interval has been removed. Use QgsInterval instead.</li> <li>QgsExpression::Interval has been removed. Use QgsInterval instead.</li>
<li>replaceExpressionText() no longer accepts a substitution map parameter. Use expression context variables instead.</li>
</ul> </ul>
\subsection qgis_api_break_3_0_QgsFeature QgsFeature \subsection qgis_api_break_3_0_QgsFeature QgsFeature

View File

@ -28,16 +28,6 @@ class QgsComposerLabel : QgsComposerItem
/** Returns the text as it appears on screen (with replaced data field) */ /** Returns the text as it appears on screen (with replaced data field) */
QString displayText() const; QString displayText() const;
/** Sets the current feature, the current layer and a list of local variable substitutions for evaluating expressions.
* @deprecated use atlas features and setSubstitutions() instead
*/
void setExpressionContext( QgsFeature* feature, QgsVectorLayer* layer, const QMap<QString, QVariant>& substitutions = QMap<QString, QVariant>() ) /Deprecated/;
/** Sets the list of local variable substitutions for evaluating expressions in label text.
* @note added in QGIS 2.12
*/
void setSubstitutions( const QMap<QString, QVariant>& substitutions = QMap<QString, QVariant>() );
QFont font() const; QFont font() const;
void setFont( const QFont& f ); void setFont( const QFont& f );
/** Accessor for the vertical alignment of the label /** Accessor for the vertical alignment of the label

View File

@ -75,24 +75,10 @@ class QgsActionManager
* @param index action index * @param index action index
* @param feature feature to run action for * @param feature feature to run action for
* @param context expression context to evalute expressions under * @param context expression context to evalute expressions under
* @param substitutionMap deprecated - kept for compatibility with projects, will be removed for 3.0
*/ */
// TODO QGIS 3.0 remove substition map - force use of expression variables
void doAction( int index, void doAction( int index,
const QgsFeature& feature, const QgsFeature& feature,
const QgsExpressionContext& context, const QgsExpressionContext& context );
const QMap<QString, QVariant> *substitutionMap = nullptr );
/** Does the action using the expression builder to expand it
* and getting values from the passed feature attribute map.
* substitutionMap is used to pass custom substitutions, to replace
* each key in the map with the associated value
* @note available in python bindings as doActionFeatureWithSubstitution
*/
void doAction( int index,
const QgsFeature &feat,
const QMap<QString, QVariant> *substitutionMap ) /PyName=doActionFeatureWithSubstitution/;
//! Removes all actions //! Removes all actions
void clearActions(); void clearActions();
@ -103,26 +89,6 @@ class QgsActionManager
//! Return the layer //! Return the layer
QgsVectorLayer* layer() const; QgsVectorLayer* layer() const;
/** Expands the given action, replacing all %'s with the value as
* given.
* @deprecated use QgsExpression::replaceExpressionText() instead
*/
QString expandAction( QString action, const QMap<int, QVariant> &attributes, uint defaultValueIndex ) /Deprecated/;
/** Expands the given action using the expression builder
* This function currently replaces each expression between [% and %]
* placeholders in the action with the result of its evaluation on
* the feature passed as argument.
*
* Additional substitutions can be passed through the substitutionMap
* parameter
* @deprecated use QgsExpression::replaceExpressionText() instead
*/
QString expandAction( const QString& action,
QgsFeature &feat,
const QMap<QString, QVariant> *substitutionMap = 0 ) /Deprecated/;
//! Writes the actions out in XML format //! Writes the actions out in XML format
bool writeXml( QDomNode& layer_node, QDomDocument& doc ) const; bool writeXml( QDomNode& layer_node, QDomDocument& doc ) const;

View File

@ -140,13 +140,11 @@ class QgsExpression
* Additional substitutions can be passed through the substitutionMap parameter * Additional substitutions can be passed through the substitutionMap parameter
* @param action * @param action
* @param context expression context * @param context expression context
* @param substitutionMap
* @param distanceArea optional QgsDistanceArea. If specified, the QgsDistanceArea is used for distance * @param distanceArea optional QgsDistanceArea. If specified, the QgsDistanceArea is used for distance
* and area conversion * and area conversion
* @note added in QGIS 2.12 * @note added in QGIS 2.12
*/ */
static QString replaceExpressionText( const QString &action, const QgsExpressionContext* context, static QString replaceExpressionText( const QString &action, const QgsExpressionContext* context,
const QMap<QString, QVariant> *substitutionMap = 0,
const QgsDistanceArea* distanceArea = 0 ); const QgsDistanceArea* distanceArea = 0 );
/** Attempts to evaluate a text string as an expression to a resultant double /** Attempts to evaluate a text string as an expression to a resultant double

View File

@ -138,14 +138,6 @@ bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y )
if ( layer->actions()->defaultAction() >= 0 ) if ( layer->actions()->defaultAction() >= 0 )
{ {
// define custom substitutions: layer id and clicked coords // define custom substitutions: layer id and clicked coords
// TODO QGIS 3.0 - remove these deprecated global expression variables!
QMap<QString, QVariant> substitutionMap;
substitutionMap.insert( "$layerid", layer->id() );
point = toLayerCoordinates( layer, point );
substitutionMap.insert( "$clickx", point.x() );
substitutionMap.insert( "$clicky", point.y() );
QgsExpressionContext context; QgsExpressionContext context;
context << QgsExpressionContextUtils::globalScope() context << QgsExpressionContextUtils::globalScope()
<< QgsExpressionContextUtils::projectScope() << QgsExpressionContextUtils::projectScope()
@ -156,7 +148,7 @@ bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y )
context << actionScope; context << actionScope;
int actionIdx = layer->actions()->defaultAction(); int actionIdx = layer->actions()->defaultAction();
layer->actions()->doAction( actionIdx, feat, context, &substitutionMap ); layer->actions()->doAction( actionIdx, feat, context );
} }
else else
{ {

View File

@ -179,7 +179,7 @@ void QgsComposerHtml::loadHtml( const bool useCache, const QgsExpressionContext
//evaluate expressions //evaluate expressions
if ( mEvaluateExpressions ) if ( mEvaluateExpressions )
{ {
loadedHtml = QgsExpression::replaceExpressionText( loadedHtml, evalContext, nullptr, mDistanceArea ); loadedHtml = QgsExpression::replaceExpressionText( loadedHtml, evalContext, mDistanceArea );
} }
mLoaded = false; mLoaded = false;

View File

@ -240,38 +240,6 @@ void QgsComposerLabel::setHtmlState( int state )
} }
} }
void QgsComposerLabel::setExpressionContext( QgsFeature *feature, QgsVectorLayer* layer, const QMap<QString, QVariant>& substitutions )
{
mExpressionFeature.reset( feature ? new QgsFeature( *feature ) : nullptr );
mExpressionLayer = layer;
mSubstitutions = substitutions;
//setup distance area conversion
if ( layer )
{
mDistanceArea->setSourceCrs( layer->crs().srsid() );
}
else if ( mComposition )
{
//set to composition's mapsettings' crs
mDistanceArea->setSourceCrs( mComposition->mapSettings().destinationCrs().srsid() );
}
if ( mComposition )
{
mDistanceArea->setEllipsoidalMode( mComposition->mapSettings().hasCrsTransformEnabled() );
}
mDistanceArea->setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
contentChanged();
// Force label to redraw -- fixes label printing for labels with blend modes when used with atlas
update();
}
void QgsComposerLabel::setSubstitutions( const QMap<QString, QVariant>& substitutions )
{
mSubstitutions = substitutions;
}
void QgsComposerLabel::refreshExpressionContext() void QgsComposerLabel::refreshExpressionContext()
{ {
mExpressionLayer = nullptr; mExpressionLayer = nullptr;
@ -307,7 +275,6 @@ QString QgsComposerLabel::displayText() const
{ {
QString displayText = mText; QString displayText = mText;
replaceDateText( displayText ); replaceDateText( displayText );
QMap<QString, QVariant> subs = mSubstitutions;
QScopedPointer<QgsExpressionContext> context( createExpressionContext() ); QScopedPointer<QgsExpressionContext> context( createExpressionContext() );
//overwrite layer/feature if they have been set via setExpressionContext //overwrite layer/feature if they have been set via setExpressionContext
@ -317,7 +284,7 @@ QString QgsComposerLabel::displayText() const
if ( mExpressionLayer ) if ( mExpressionLayer )
context->setFields( mExpressionLayer->fields() ); context->setFields( mExpressionLayer->fields() );
return QgsExpression::replaceExpressionText( displayText, context.data(), &subs, mDistanceArea ); return QgsExpression::replaceExpressionText( displayText, context.data(), mDistanceArea );
} }
void QgsComposerLabel::replaceDateText( QString& text ) const void QgsComposerLabel::replaceDateText( QString& text ) const

View File

@ -53,16 +53,6 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
/** Returns the text as it appears on screen (with replaced data field) */ /** Returns the text as it appears on screen (with replaced data field) */
QString displayText() const; QString displayText() const;
/** Sets the current feature, the current layer and a list of local variable substitutions for evaluating expressions.
* @deprecated use atlas features and setSubstitutions() instead
*/
Q_DECL_DEPRECATED void setExpressionContext( QgsFeature* feature, QgsVectorLayer* layer, const QMap<QString, QVariant>& substitutions = ( QMap<QString, QVariant>() ) );
/** Sets the list of local variable substitutions for evaluating expressions in label text.
* @note added in QGIS 2.12
*/
void setSubstitutions( const QMap<QString, QVariant>& substitutions = ( QMap<QString, QVariant>() ) );
QFont font() const; QFont font() const;
void setFont( const QFont& f ); void setFont( const QFont& f );
/** Accessor for the vertical alignment of the label /** Accessor for the vertical alignment of the label
@ -213,7 +203,6 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
QScopedPointer<QgsFeature> mExpressionFeature; QScopedPointer<QgsFeature> mExpressionFeature;
QgsVectorLayer* mExpressionLayer; QgsVectorLayer* mExpressionLayer;
QMap<QString, QVariant> mSubstitutions;
QgsDistanceArea* mDistanceArea; QgsDistanceArea* mDistanceArea;
QgsWebPage* mWebPage; QgsWebPage* mWebPage;

View File

@ -72,7 +72,7 @@ void QgsActionManager::doAction( int index, const QgsFeature& feat, int defaultV
doAction( index, feat, context ); doAction( index, feat, context );
} }
void QgsActionManager::doAction( int index, const QgsFeature& feat, const QgsExpressionContext& context, const QMap<QString, QVariant> *substitutionMap ) void QgsActionManager::doAction( int index, const QgsFeature& feat, const QgsExpressionContext& context )
{ {
if ( index < 0 || index >= size() ) if ( index < 0 || index >= size() )
return; return;
@ -87,27 +87,7 @@ void QgsActionManager::doAction( int index, const QgsFeature& feat, const QgsExp
actionContext << QgsExpressionContextUtils::layerScope( mLayer ); actionContext << QgsExpressionContextUtils::layerScope( mLayer );
actionContext.setFeature( feat ); actionContext.setFeature( feat );
QString expandedAction = QgsExpression::replaceExpressionText( action.action(), &actionContext, substitutionMap ); QString expandedAction = QgsExpression::replaceExpressionText( action.action(), &actionContext );
if ( expandedAction.isEmpty() )
return;
QgsAction newAction( action.type(), action.name(), expandedAction, action.capture() );
runAction( newAction );
}
void QgsActionManager::doAction( int index, const QgsFeature &feat, const QMap<QString, QVariant> *substitutionMap )
{
if ( index < 0 || index >= size() )
return;
const QgsAction &action = at( index );
if ( !action.runable() )
return;
// search for expressions while expanding actions
QgsExpressionContext context = createExpressionContext();
context.setFeature( feat );
QString expandedAction = QgsExpression::replaceExpressionText( action.action(), &context, substitutionMap );
if ( expandedAction.isEmpty() ) if ( expandedAction.isEmpty() )
return; return;
@ -172,124 +152,6 @@ QgsExpressionContext QgsActionManager::createExpressionContext() const
return context; return context;
} }
QString QgsActionManager::expandAction( QString action, const QgsAttributeMap &attributes,
uint clickedOnValue )
{
// This function currently replaces all %% characters in the action
// with the value from values[clickedOnValue].second, and then
// searches for all strings that go %attribute_name, where
// attribute_name is found in values[x].first, and replaces any that
// it finds by values[s].second.
// Additional substitutions could include symbols for $CWD, $HOME,
// etc (and their OSX and Windows equivalents)
// This function will potentially fall apart if any of the
// substitutions produce text that could match another
// substitution. May be better to adopt a two pass approach - identify
// all matches and their substitutions and then do a second pass
// for the actual substitutions.
QString expanded_action;
if ( attributes.contains( clickedOnValue ) )
expanded_action = action.replace( "%%", attributes[clickedOnValue].toString() );
else
expanded_action = action;
const QgsFields &fields = mLayer->fields();
for ( int i = 0; i < 4; i++ )
{
for ( QgsAttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
{
int attrIdx = it.key();
if ( attrIdx < 0 || attrIdx >= fields.count() )
continue;
QString to_replace;
switch ( i )
{
case 0:
to_replace = "[%" + fields.at( attrIdx ).name() + ']';
break;
case 1:
to_replace = "[%" + mLayer->attributeDisplayName( attrIdx ) + ']';
break;
case 2:
to_replace = '%' + fields.at( attrIdx ).name();
break;
case 3:
to_replace = '%' + mLayer->attributeDisplayName( attrIdx );
break;
}
expanded_action = expanded_action.replace( to_replace, it.value().toString() );
}
}
return expanded_action;
}
QString QgsActionManager::expandAction( const QString& action, QgsFeature &feat, const QMap<QString, QVariant> *substitutionMap )
{
// This function currently replaces each expression between [% and %]
// in the action with the result of its evaluation on the feature
// passed as argument.
// Additional substitutions can be passed through the substitutionMap
// parameter
QString expr_action;
int index = 0;
while ( index < action.size() )
{
QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
int pos = rx.indexIn( action, index );
if ( pos < 0 )
break;
int start = index;
index = pos + rx.matchedLength();
QString to_replace = rx.cap( 1 ).trimmed();
QgsDebugMsg( "Found expression: " + to_replace );
if ( substitutionMap && substitutionMap->contains( to_replace ) )
{
expr_action += action.mid( start, pos - start ) + substitutionMap->value( to_replace ).toString();
continue;
}
QgsExpression exp( to_replace );
if ( exp.hasParserError() )
{
QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
expr_action += action.midRef( start, index - start );
continue;
}
QgsExpressionContext context = createExpressionContext();
context.setFeature( feat );
QVariant result = exp.evaluate( &context );
if ( exp.hasEvalError() )
{
QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
expr_action += action.midRef( start, index - start );
continue;
}
QgsDebugMsg( "Expression result is: " + result.toString() );
expr_action += action.mid( start, pos - start ) + result.toString();
}
expr_action += action.midRef( index );
return expr_action;
}
bool QgsActionManager::writeXml( QDomNode& layer_node, QDomDocument& doc ) const bool QgsActionManager::writeXml( QDomNode& layer_node, QDomDocument& doc ) const
{ {
QDomElement aActions = doc.createElement( "attributeactions" ); QDomElement aActions = doc.createElement( "attributeactions" );

View File

@ -90,24 +90,10 @@ class CORE_EXPORT QgsActionManager
* @param index action index * @param index action index
* @param feature feature to run action for * @param feature feature to run action for
* @param context expression context to evalute expressions under * @param context expression context to evalute expressions under
* @param substitutionMap deprecated - kept for compatibility with projects, will be removed for 3.0
*/ */
// TODO QGIS 3.0 remove substition map - force use of expression variables
void doAction( int index, void doAction( int index,
const QgsFeature& feature, const QgsFeature& feature,
const QgsExpressionContext& context, const QgsExpressionContext& context );
const QMap<QString, QVariant> *substitutionMap = nullptr );
/** Does the action using the expression builder to expand it
* and getting values from the passed feature attribute map.
* substitutionMap is used to pass custom substitutions, to replace
* each key in the map with the associated value
* @note available in python bindings as doActionFeatureWithSubstitution
* @deprecated use QgsExpressionContext variant instead
*/
Q_DECL_DEPRECATED void doAction( int index,
const QgsFeature &feat,
const QMap<QString, QVariant> *substitutionMap );
//! Removes all actions //! Removes all actions
void clearActions(); void clearActions();
@ -120,26 +106,6 @@ class CORE_EXPORT QgsActionManager
//! Return the layer //! Return the layer
QgsVectorLayer* layer() const { return mLayer; } QgsVectorLayer* layer() const { return mLayer; }
/** Expands the given action, replacing all %'s with the value as
* given.
* @deprecated use QgsExpression::replaceExpressionText() instead
*/
Q_DECL_DEPRECATED QString expandAction( QString action, const QgsAttributeMap &attributes, uint defaultValueIndex );
/** Expands the given action using the expression builder
* This function currently replaces each expression between [% and %]
* placeholders in the action with the result of its evaluation on
* the feature passed as argument.
*
* Additional substitutions can be passed through the substitutionMap
* parameter
* @deprecated use QgsExpression::replaceExpressionText() instead
*/
Q_DECL_DEPRECATED QString expandAction( const QString& action,
QgsFeature &feat,
const QMap<QString, QVariant> *substitutionMap = nullptr );
//! Writes the actions out in XML format //! Writes the actions out in XML format
bool writeXml( QDomNode& layer_node, QDomDocument& doc ) const; bool writeXml( QDomNode& layer_node, QDomDocument& doc ) const;

View File

@ -3604,7 +3604,7 @@ void QgsExpression::acceptVisitor( QgsExpression::Visitor& v ) const
d->mRootNode->accept( v ); d->mRootNode->accept( v );
} }
QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea ) QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea )
{ {
QString expr_action; QString expr_action;

View File

@ -262,13 +262,11 @@ class CORE_EXPORT QgsExpression
* Additional substitutions can be passed through the substitutionMap parameter * Additional substitutions can be passed through the substitutionMap parameter
* @param action * @param action
* @param context expression context * @param context expression context
* @param substitutionMap
* @param distanceArea optional QgsDistanceArea. If specified, the QgsDistanceArea is used for distance * @param distanceArea optional QgsDistanceArea. If specified, the QgsDistanceArea is used for distance
* and area conversion * and area conversion
* @note added in QGIS 2.12 * @note added in QGIS 2.12
*/ */
static QString replaceExpressionText( const QString &action, const QgsExpressionContext* context, static QString replaceExpressionText( const QString &action, const QgsExpressionContext* context,
const QMap<QString, QVariant> *substitutionMap = nullptr,
const QgsDistanceArea* distanceArea = nullptr ); const QgsDistanceArea* distanceArea = nullptr );
/** Attempts to evaluate a text string as an expression to a resultant double /** Attempts to evaluate a text string as an expression to a resultant double