Exemplo n.º 1
0
QgsExpressionContextScope *QgsExpressionContextUtils::compositionScope( const QgsComposition *composition )
{
  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Composition" ) );
  if ( !composition )
    return scope;

  //add variables defined in composition properties
  QStringList variableNames = composition->customProperty( "variableNames" ).toStringList();
  QStringList variableValues = composition->customProperty( "variableValues" ).toStringList();

  int varIndex = 0;
  Q_FOREACH ( const QString& variableName, variableNames )
  {
    if ( varIndex >= variableValues.length() )
    {
      break;
    }

    QVariant varValue = variableValues.at( varIndex );
    varIndex++;
    scope->setVariable( variableName, varValue );
  }

  //add known composition context variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "layout_numpages", composition->numPages(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "layout_pageheight", composition->paperHeight(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "layout_pagewidth", composition->paperWidth(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "layout_dpi", composition->printResolution(), true ) );

  return scope;
}
Exemplo n.º 2
0
QgsExpressionContextScope* QgsExpressionContextUtils::projectScope()
{
  QgsProject* project = QgsProject::instance();

  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Project" ) );

  //add variables defined in project file
  QStringList variableNames = project->readListEntry( "Variables", "/variableNames" );
  QStringList variableValues = project->readListEntry( "Variables", "/variableValues" );

  int varIndex = 0;
  Q_FOREACH ( const QString& variableName, variableNames )
  {
    if ( varIndex >= variableValues.length() )
    {
      break;
    }

    QString varValueString = variableValues.at( varIndex );
    varIndex++;
    scope->setVariable( variableName, varValueString );
  }

  //add other known project variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "project_title", project->title(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "project_path", project->fileInfo().filePath(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "project_folder", project->fileInfo().dir().path(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "project_filename", project->fileInfo().fileName(), true ) );

  scope->addFunction( "project_color", new GetNamedProjectColor() );
  return scope;
}
Exemplo n.º 3
0
QgsExpressionContextScope *QgsExpressionContextUtils::composerItemScope( const QgsComposerItem *composerItem )
{
  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Composer Item" ) );
  if ( !composerItem )
    return scope;

  //add variables defined in composer item properties
  QStringList variableNames = composerItem->customProperty( "variableNames" ).toStringList();
  QStringList variableValues = composerItem->customProperty( "variableValues" ).toStringList();

  int varIndex = 0;
  Q_FOREACH ( const QString& variableName, variableNames )
  {
    if ( varIndex >= variableValues.length() )
    {
      break;
    }

    QVariant varValue = variableValues.at( varIndex );
    varIndex++;
    scope->setVariable( variableName, varValue );
  }

  //add known composer item context variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "item_id", composerItem->id(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "item_uuid", composerItem->uuid(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "layout_page", composerItem->page(), true ) );

  return scope;
}
Exemplo n.º 4
0
QgsExpressionContextScope* QgsExpressionContextUtils::projectScope( const QgsProject* project )
{
  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Project" ) );

  if ( !project )
    return scope;

  const QVariantMap vars = project->customVariables();

  QVariantMap::const_iterator it = vars.constBegin();

  for ( ; it != vars.constEnd(); ++it )
  {
    scope->setVariable( it.key(), it.value() );
  }

  //add other known project variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), project->title(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_path" ), project->fileInfo().filePath(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_folder" ), project->fileInfo().dir().path(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_filename" ), project->fileInfo().fileName(), true ) );
  QgsCoordinateReferenceSystem projectCrs = project->crs();
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj4(), true ) );

  scope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor() );
  return scope;
}
Exemplo n.º 5
0
void QgsPointDisplacementRendererWidget::on_mRendererSettingsButton_clicked()
{
  if ( !mRenderer )
    return;

  QgsRendererAbstractMetadata* m = QgsRendererRegistry::instance()->rendererMetadata( mRenderer->embeddedRenderer()->type() );
  if ( m )
  {
    QgsRendererWidget* w = m->createRendererWidget( mLayer, mStyle, mRenderer->embeddedRenderer()->clone() );
    w->setPanelTitle( tr( "Renderer settings" ) );

    QgsSymbolWidgetContext context = mContext;

    QgsExpressionContextScope scope;
    scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, "", true ) );
    scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, 0, true ) );
    QList< QgsExpressionContextScope > scopes = context.additionalExpressionContextScopes();
    scopes << scope;
    context.setAdditionalExpressionContextScopes( scopes );
    w->setContext( context );

    connect( w, SIGNAL( widgetChanged() ), this, SLOT( updateRendererFromWidget() ) );
    openPanel( w );
  }
}
Exemplo n.º 6
0
void QgsActionManager::doAction( const QUuid& actionId, const QgsFeature& feature, int defaultValueIndex )
{
  QgsExpressionContext context = createExpressionContext();
  QgsExpressionContextScope* actionScope = new QgsExpressionContextScope();
  actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_index" ), defaultValueIndex, true ) );
  if ( defaultValueIndex >= 0 && defaultValueIndex < feature.fields().size() )
    actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_name" ), feature.fields().at( defaultValueIndex ).name(), true ) );
  actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_value" ), feature.attribute( defaultValueIndex ), true ) );
  context << actionScope;
  doAction( actionId, feature, context );
}
Exemplo n.º 7
0
void QgsActionMenu::triggerAction()
{
  if ( !feature().isValid() )
    return;

  QAction* action = qobject_cast<QAction*>( sender() );
  if ( !action )
    return;

  if ( !action->data().isValid() || !action->data().canConvert<ActionData>() )
    return;

  ActionData data = action->data().value<ActionData>();

  if ( data.actionType == Invalid )
    return;

  if ( data.actionType == MapLayerAction )
  {
    QgsMapLayerAction* mapLayerAction = data.actionData.value<QgsMapLayerAction*>();
    mapLayerAction->triggerForFeature( data.mapLayer, &mFeature );
  }
  else if ( data.actionType == AttributeAction )
  {
    // define custom substitutions: layer id and clicked coords
    QgsExpressionContext context = mLayer->createExpressionContext();

    QgsExpressionContextScope* actionScope = new QgsExpressionContextScope();
    actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "action_scope" ), mActionScope, true ) );
    context << actionScope;
    QgsAction act = data.actionData.value<QgsAction>();
    act.run( context );
  }
}
QgsExpressionContext QgsPointDisplacementRendererWidget::createExpressionContext() const
{
  QgsExpressionContext context;
  if ( mContext.expressionContext() )
    context = *mContext.expressionContext();
  else
    context.appendScopes( mContext.globalProjectAtlasMapLayerScopes( mLayer ) );
  QgsExpressionContextScope scope;
  scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, "", true ) );
  scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, 0, true ) );
  QList< QgsExpressionContextScope > scopes = mContext.additionalExpressionContextScopes();
  scopes << scope;
  Q_FOREACH ( const QgsExpressionContextScope &s, scopes )
  {
    context << new QgsExpressionContextScope( s );
  }
QgsExpressionContext QgsPointClusterRendererWidget::createExpressionContext() const
{
  QgsExpressionContext context;
  if ( mContext.expressionContext() )
    context = *mContext.expressionContext();
  else
    context.appendScopes( mContext.globalProjectAtlasMapLayerScopes( mLayer ) );
  QgsExpressionContextScope scope;
  scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, "", true ) );
  scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, 0, true ) );
  QList< QgsExpressionContextScope > scopes = mContext.additionalExpressionContextScopes();
  scopes << scope;
  const auto constScopes = scopes;
  for ( const QgsExpressionContextScope &s : constScopes )
  {
    context << new QgsExpressionContextScope( s );
  }
  return context;
}
Exemplo n.º 10
0
QgsExpressionContextScope* QgsExpressionContextUtils::layerScope( const QgsMapLayer* layer )
{
  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) );

  if ( !layer )
    return scope;

  //add variables defined in layer properties
  QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
  QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();

  int varIndex = 0;
  Q_FOREACH ( const QString& variableName, variableNames )
  {
    if ( varIndex >= variableValues.length() )
    {
      break;
    }

    QVariant varValue = variableValues.at( varIndex );
    varIndex++;
    scope->setVariable( variableName, varValue );
  }

  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer" ), QVariant::fromValue<QPointer<QgsMapLayer> >( QPointer<QgsMapLayer>( const_cast<QgsMapLayer*>( layer ) ) ), true ) );

  const QgsVectorLayer* vLayer = dynamic_cast< const QgsVectorLayer* >( layer );
  if ( vLayer )
  {
    scope->setFields( vLayer->fields() );
  }

  //TODO - add functions. Possibilities include:
  //is_selected
  //field summary stats

  return scope;
}
Exemplo n.º 11
0
void QgsPointDisplacementRendererWidget::on_mCenterSymbolPushButton_clicked()
{
  if ( !mRenderer || !mRenderer->centerSymbol() )
  {
    return;
  }
  QgsMarkerSymbol* markerSymbol = mRenderer->centerSymbol()->clone();
  QgsSymbolSelectorWidget* dlg = new QgsSymbolSelectorWidget( markerSymbol, QgsStyle::defaultStyle(), mLayer, this );
  dlg->setPanelTitle( tr( "Center symbol" ) );

  QgsSymbolWidgetContext context = mContext;

  QgsExpressionContextScope scope;
  scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, "", true ) );
  scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, 0, true ) );
  QList< QgsExpressionContextScope > scopes = context.additionalExpressionContextScopes();
  scopes << scope;
  context.setAdditionalExpressionContextScopes( scopes );
  dlg->setContext( context );

  connect( dlg, SIGNAL( widgetChanged() ), this, SLOT( updateCenterSymbolFromWidget() ) );
  connect( dlg, SIGNAL( panelAccepted( QgsPanelWidget* ) ), this, SLOT( cleanUpSymbolSelector( QgsPanelWidget* ) ) );
  openPanel( dlg );
}
Exemplo n.º 12
0
QgsExpressionContextScope* QgsExpressionContextUtils::atlasScope( const QgsAtlasComposition* atlas )
{
  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Atlas" ) );
  if ( !atlas )
  {
    //add some dummy atlas variables. This is done so that as in certain contexts we want to show
    //users that these variables are available even if they have no current value
    scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_pagename", QString(), true ) );
    scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_feature", QVariant::fromValue( QgsFeature() ), true ) );
    scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_featureid", 0, true ) );
    scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_geometry", QVariant::fromValue( QgsGeometry() ), true ) );
    return scope;
  }

  //add known atlas variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_totalfeatures", atlas->numFeatures(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_featurenumber", atlas->currentFeatureNumber() + 1, true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_filename", atlas->currentFilename(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_pagename", atlas->currentPageName(), true ) );

  if ( atlas->enabled() && atlas->coverageLayer() )
  {
    scope->setFields( atlas->coverageLayer()->fields() );
  }

  if ( atlas->enabled() )
  {
    QgsFeature atlasFeature = atlas->feature();
    scope->setFeature( atlasFeature );
    scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_feature", QVariant::fromValue( atlasFeature ), true ) );
    scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_featureid", atlasFeature.id(), true ) );
    scope->addVariable( QgsExpressionContextScope::StaticVariable( "atlas_geometry", QVariant::fromValue( *atlasFeature.constGeometry() ), true ) );
  }

  return scope;
}
Exemplo n.º 13
0
void QgsPointClusterRendererWidget::mRendererSettingsButton_clicked()
{
  if ( !mRenderer )
    return;

  QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( mRenderer->embeddedRenderer()->type() );
  if ( m )
  {
    QgsRendererWidget *w = m->createRendererWidget( mLayer, mStyle, mRenderer->embeddedRenderer()->clone() );
    w->setPanelTitle( tr( "Renderer Settings" ) );

    QgsExpressionContextScope scope;
    scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, "", true ) );
    scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, 0, true ) );
    QList< QgsExpressionContextScope > scopes = mContext.additionalExpressionContextScopes();
    scopes << scope;
    QgsSymbolWidgetContext context = mContext;
    context.setAdditionalExpressionContextScopes( scopes );
    w->setContext( context );
    connect( w, &QgsPanelWidget::widgetChanged, this, &QgsPointClusterRendererWidget::updateRendererFromWidget );
    w->setDockMode( this->dockMode() );
    openPanel( w );
  }
}
Exemplo n.º 14
0
QgsExpressionContextScope* QgsExpressionContextUtils::mapSettingsScope( const QgsMapSettings& mapSettings )
{
  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Map Settings" ) );

  //add known map settings context variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_id", "canvas", true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_rotation", mapSettings.rotation(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_scale", mapSettings.scale(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_extent_width", mapSettings.extent().width() ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_extent_height", mapSettings.extent().height() ) );
  QgsGeometry* centerPoint = QgsGeometry::fromPoint( mapSettings.visibleExtent().center() );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_extent_center", QVariant::fromValue( *centerPoint ), true ) );
  delete centerPoint;

  return scope;
}
Exemplo n.º 15
0
QgsExpressionContextScope* QgsExpressionContextUtils::mapSettingsScope( const QgsMapSettings& mapSettings )
{
  // IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsComposerMap::createExpressionContext()
  // (rationale is described in QgsComposerMap::createExpressionContext() )

  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Map Settings" ) );

  //add known map settings context variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_id" ), "canvas", true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_rotation" ), mapSettings.rotation(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_scale" ), mapSettings.scale(), true ) );
  QgsGeometry extent = QgsGeometry::fromRect( mapSettings.visibleExtent() );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent" ), QVariant::fromValue( extent ), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_width" ), mapSettings.visibleExtent().width(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_height" ), mapSettings.visibleExtent().height(), true ) );
  QgsGeometry centerPoint = QgsGeometry::fromPoint( mapSettings.visibleExtent().center() );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_center" ), QVariant::fromValue( centerPoint ), true ) );

  return scope;
}
Exemplo n.º 16
0
QgsExpressionContextScope* QgsExpressionContextUtils::globalScope()
{
  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Global" ) );

  //read values from QSettings
  QSettings settings;

  //check if settings contains any variables
  if ( settings.contains( QString( "/variables/values" ) ) )
  {
    QList< QVariant > customVariableVariants = settings.value( QString( "/variables/values" ) ).toList();
    QList< QVariant > customVariableNames = settings.value( QString( "/variables/names" ) ).toList();
    int variableIndex = 0;
    for ( QList< QVariant >::const_iterator it = customVariableVariants.constBegin();
          it != customVariableVariants.constEnd(); ++it )
    {
      if ( variableIndex >= customVariableNames.length() )
      {
        break;
      }

      QVariant value = ( *it );
      QString name = customVariableNames.at( variableIndex ).toString();

      scope->setVariable( name, value );
      variableIndex++;
    }
  }

  //add some extra global variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_version", QGis::QGIS_VERSION, true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_version_no", QGis::QGIS_VERSION_INT, true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_release_name", QGis::QGIS_RELEASE_NAME, true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_platform", QgsApplication::platform(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "qgis_os_name", QgsApplication::osName(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "user_account_name", QgsApplication::userLoginName(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( "user_full_name", QgsApplication::userFullName(), true ) );

  return scope;
}
Exemplo n.º 17
0
QgsExpressionContextScope* QgsExpressionContextUtils::globalScope()
{
  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Global" ) );

  QVariantMap customVariables = QgsApplication::customVariables();

  for ( QVariantMap::const_iterator it = customVariables.constBegin(); it != customVariables.constEnd(); ++it )
  {
    scope->setVariable( it.key(), it.value() );
  }

  //add some extra global variables
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version" ), Qgis::QGIS_VERSION, true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version_no" ), Qgis::QGIS_VERSION_INT, true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_release_name" ), Qgis::QGIS_RELEASE_NAME, true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_platform" ), QgsApplication::platform(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_os_name" ), QgsApplication::osName(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_account_name" ), QgsApplication::userLoginName(), true ) );
  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_full_name" ), QgsApplication::userFullName(), true ) );

  return scope;
}
Exemplo n.º 18
0
bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y )
{
  if ( !layer )
    return false;

  QgsPointXY point = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y );

  QgsRectangle r;

  // create the search rectangle
  double searchRadius = searchRadiusMU( mCanvas );

  r.setXMinimum( point.x() - searchRadius );
  r.setXMaximum( point.x() + searchRadius );
  r.setYMinimum( point.y() - searchRadius );
  r.setYMaximum( point.y() + searchRadius );

  // toLayerCoordinates will throw an exception for an 'invalid' point.
  // For example, if you project a world map onto a globe using EPSG 2163
  // and then click somewhere off the globe, an exception will be thrown.
  try
  {
    r = toLayerCoordinates( layer, r );
  }
  catch ( QgsCsException &cse )
  {
    Q_UNUSED( cse );
    // catch exception for 'invalid' point and proceed with no features found
    QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
  }

  QgsAction defaultAction = layer->actions()->defaultAction( QStringLiteral( "Canvas" ) );

  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) );
  QgsFeature feat;
  while ( fit.nextFeature( feat ) )
  {
    if ( defaultAction.isValid() )
    {
      // define custom substitutions: layer id and clicked coords
      QgsExpressionContext context;
      context << QgsExpressionContextUtils::globalScope()
              << QgsExpressionContextUtils::projectScope( QgsProject::instance() )
              << QgsExpressionContextUtils::mapSettingsScope( mCanvas->mapSettings() );
      QgsExpressionContextScope *actionScope = new QgsExpressionContextScope();
      actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "click_x" ), point.x(), true ) );
      actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "click_y" ), point.y(), true ) );
      actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "action_scope" ), QStringLiteral( "Canvas" ), true ) );
      context << actionScope;

      defaultAction.run( layer, feat, context );
    }
    else
    {
      QgsMapLayerAction *mapLayerAction = QgsGui::mapLayerActionRegistry()->defaultActionForLayer( layer );
      if ( mapLayerAction )
      {
        mapLayerAction->triggerForFeature( layer, &feat );
      }
    }
  }

  return true;
}