36  , mAllowMultipleReturn( true )
 
   37  , mExecWithSingleResult( false )
 
   38  , mShowFeatureActions( false )
 
   39  , mResultsIfExternalAction( false )
 
   40  , mMaxLayerDisplay( 10 )
 
   41  , mMaxFeatureDisplay( 10 )
 
   42  , mDefaultActionName( tr( 
"Identify" ) )
 
 
   53  QList<QgsMapToolIdentify::IdentifyResult> results;
 
   54  const QMap< QString, QString > derivedAttributes;
 
   57  const double x = mapPoint.
x();
 
   58  const double y = mapPoint.
y();
 
   61  const QList<QgsMapLayer *> layers = canvas->
layers( 
true );
 
   66      QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
 
   68      bool typeIsSelectable = 
false;
 
   73          typeIsSelectable = 
true;
 
   77      if ( typeIsSelectable )
 
   89          QgsDebugError( QStringLiteral( 
"Could not transform geometry to layer CRS" ) );
 
   93                                 .setFilterRect( rect )
 
 
  111    QgsDebugError( QStringLiteral( 
"invalid value for number of layers displayed." ) );
 
 
  121    QgsDebugError( QStringLiteral( 
"invalid value for number of layers displayed." ) );
 
 
  127QList<QgsMapToolIdentify::IdentifyResult> 
QgsIdentifyMenu::exec( 
const QList<QgsMapToolIdentify::IdentifyResult> &idResults, QPoint pos )
 
  130  mLayerIdResults.clear();
 
  132  QList<QgsMapToolIdentify::IdentifyResult> returnResults = QList<QgsMapToolIdentify::IdentifyResult>();
 
  134  if ( idResults.isEmpty() )
 
  136    return returnResults;
 
  138  if ( idResults.count() == 1 && !mExecWithSingleResult )
 
  140    returnResults << idResults[0];
 
  141    return returnResults;
 
  145  const auto constIdResults = idResults;
 
  149    if ( mLayerIdResults.contains( layer ) )
 
  151      mLayerIdResults[layer].append( result );
 
  155      mLayerIdResults.insert( layer, QList<QgsMapToolIdentify::IdentifyResult>() << result );
 
  160  const bool singleLayer = mLayerIdResults.count() == 1;
 
  162  QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
 
  163  while ( it.hasNext() )
 
  165    if ( mMaxLayerDisplay != 0 && count > mMaxLayerDisplay )
 
  170    switch ( layer->
type() )
 
  174        addRasterLayer( layer );
 
  182        addVectorLayer( vl, it.value(), singleLayer );
 
  201  if ( !singleLayer && mAllowMultipleReturn && idResults.count() > 1 )
 
  204    QAction *allAction = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"/mActionIdentify.svg" ) ), tr( 
"%1 All (%2)" ).arg( mDefaultActionName ).arg( idResults.count() ), 
this );
 
  205    allAction->setData( QVariant::fromValue<ActionData>( 
ActionData( 
nullptr ) ) );
 
  206    connect( allAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  207    addAction( allAction );
 
  211  QAction *selectedAction = QMenu::exec( pos );
 
  213  returnResults = results( selectedAction, externalAction );
 
  218  qDeleteAll( findChildren<QgsActionMenu *>() );
 
  220  if ( externalAction && !mResultsIfExternalAction )
 
  222    return QList<QgsMapToolIdentify::IdentifyResult>();
 
  226    return returnResults;
 
 
  233  QMenu::closeEvent( e );
 
 
  236void QgsIdentifyMenu::addRasterLayer( 
QgsMapLayer *layer )
 
  238  QAction *layerAction = 
nullptr;
 
  239  QMenu *layerMenu = 
nullptr;
 
  241  QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
 
  244  const int nCustomActions = layerActions.count();
 
  245  if ( nCustomActions )
 
  247    separators.append( layerActions[0] );
 
  249  if ( mShowFeatureActions )
 
  252    if ( layerActions.count() > nCustomActions )
 
  254      separators.append( layerActions[nCustomActions] );
 
  259  if ( layerActions.isEmpty() )
 
  261    layerAction = 
new QAction( layer->
name(), 
this );
 
  265    layerMenu = 
new QMenu( layer->
name(), 
this );
 
  266    layerAction = layerMenu->menuAction();
 
  271  layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
 
  272  connect( layerAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  273  addAction( layerAction );
 
  280  QAction *identifyFeatureAction = 
new QAction( mDefaultActionName, layerMenu );
 
  281  connect( identifyFeatureAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  282  identifyFeatureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
 
  283  layerMenu->addAction( identifyFeatureAction );
 
  286  const auto constLayerActions = layerActions;
 
  289    QAction *action = 
new QAction( mapLayerAction->icon(), mapLayerAction->text(), layerMenu );
 
  290    action->setData( QVariant::fromValue<ActionData>( ActionData( layer, 
true ) ) );
 
  291    connect( action, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  292    connect( action, &QAction::triggered, 
this, &QgsIdentifyMenu::triggerMapLayerAction );
 
  293    layerMenu->addAction( action );
 
  294    if ( separators.contains( mapLayerAction ) )
 
  296      layerMenu->insertSeparator( action );
 
  301void QgsIdentifyMenu::addVectorLayer( 
QgsVectorLayer *layer, 
const QList<QgsMapToolIdentify::IdentifyResult> &results, 
bool singleLayer )
 
  303  QAction *layerAction = 
nullptr;
 
  304  QMenu *layerMenu = 
nullptr;
 
  310  QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
 
  312  QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, targets, actionContext );
 
  313  const int nCustomActions = layerActions.count();
 
  314  if ( nCustomActions )
 
  316    separators << layerActions[0];
 
  318  if ( mShowFeatureActions )
 
  322    if ( layerActions.count() > nCustomActions )
 
  324      separators << layerActions[nCustomActions];
 
  333  bool createMenu = results.count() > 1 || !layerActions.isEmpty();
 
  340    if ( !createMenu && mShowFeatureActions )
 
  344      createMenu  = !featureActionMenu->actions().
isEmpty();
 
  345      delete featureActionMenu;
 
  351  exp.prepare( &context );
 
  352  context.setFeature( results[0].mFeature );
 
  357    QString featureTitle = exp.evaluate( &context ).toString();
 
  358    if ( featureTitle.isEmpty() )
 
  359      featureTitle = QString::number( results[0].mFeature.id() );
 
  360    layerAction = 
new QAction( QStringLiteral( 
"%1 (%2)" ).arg( layer->
name(), featureTitle ), 
this );
 
  372      if ( results.count() > 1 )
 
  374        layerMenu = 
new QMenu( layer->
name(), 
this );
 
  379        QString featureTitle = exp.evaluate( &context ).toString();
 
  380        if ( featureTitle.isEmpty() )
 
  381          featureTitle = QString::number( results[0].mFeature.id() );
 
  382        layerMenu = 
new QMenu( QStringLiteral( 
"%1 (%2)" ).arg( layer->
name(), featureTitle ), 
this );
 
  384      layerAction = layerMenu->menuAction();
 
  394    layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
 
  395    connect( layerAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  396    addAction( layerAction );
 
  405  const auto constResults = results;
 
  408    if ( mMaxFeatureDisplay != 0 && count > mMaxFeatureDisplay )
 
  412    QAction *featureAction = 
nullptr;
 
  413    QMenu *featureMenu = 
nullptr;
 
  417    if ( mShowFeatureActions )
 
  419      featureActionMenu = 
new QgsActionMenu( layer, result.mFeature, QStringLiteral( 
"Feature" ), layerMenu );
 
  425    context.setFeature( result.mFeature );
 
  426    QString featureTitle = exp.evaluate( &context ).toString();
 
  427    if ( featureTitle.isEmpty() )
 
  428      featureTitle = QString::number( result.mFeature.id() );
 
  430    if ( customFeatureActions.isEmpty() && ( !featureActionMenu || featureActionMenu->actions().
isEmpty() ) )
 
  432      featureAction = 
new QAction( featureTitle, layerMenu );
 
  434      featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
 
  435      connect( featureAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  436      layerMenu->addAction( featureAction );
 
  438    else if ( results.count() == 1 )
 
  443      featureMenu = layerMenu;
 
  447      featureMenu = 
new QMenu( featureTitle, layerMenu );
 
  450      featureAction = featureMenu->menuAction();
 
  452      featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
 
  453      connect( featureAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  454      layerMenu->addAction( featureAction );
 
  462    QAction *identifyFeatureAction = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"/mActionIdentify.svg" ) ), mDefaultActionName, featureMenu );
 
  463    connect( identifyFeatureAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  464    identifyFeatureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
 
  465    featureMenu->addAction( identifyFeatureAction );
 
  466    featureMenu->addSeparator();
 
  469    const auto constCustomFeatureActions = customFeatureActions;
 
  472      QAction *action = 
new QAction( mapLayerAction->icon(), mapLayerAction->text(), featureMenu );
 
  473      action->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id(), mapLayerAction ) ) );
 
  474      connect( action, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  475      connect( action, &QAction::triggered, 
this, &QgsIdentifyMenu::triggerMapLayerAction );
 
  476      featureMenu->addAction( action );
 
  479    if ( featureActionMenu )
 
  481      const auto constActions = featureActionMenu->actions();
 
  482      for ( QAction *action : constActions )
 
  484        connect( action, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  485        featureMenu->addAction( action );
 
  493  if ( mAllowMultipleReturn && results.count() > 1 )
 
  495    layerMenu->addSeparator();
 
  496    QAction *allAction = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"/mActionIdentify.svg" ) ), tr( 
"%1 All (%2)" ).arg( mDefaultActionName ).arg( results.count() ), layerMenu );
 
  497    allAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
 
  498    connect( allAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  499    layerMenu->addAction( allAction );
 
  503  const auto constLayerActions = layerActions;
 
  506    QString title = mapLayerAction->text();
 
  508      title.append( QStringLiteral( 
" (%1)" ).arg( results.count() ) );
 
  509    QAction *action = 
new QAction( mapLayerAction->icon(), title, layerMenu );
 
  510    action->setData( QVariant::fromValue<ActionData>( ActionData( layer, mapLayerAction ) ) );
 
  511    connect( action, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
 
  512    connect( action, &QAction::triggered, 
this, &QgsIdentifyMenu::triggerMapLayerAction );
 
  513    layerMenu->addAction( action );
 
  514    if ( separators.contains( mapLayerAction ) )
 
  516      layerMenu->insertSeparator( action );
 
  521void QgsIdentifyMenu::triggerMapLayerAction()
 
  523  QAction *action = qobject_cast<QAction *>( sender() );
 
  526  const QVariant varData = action->data();
 
  527  if ( !varData.isValid() || !varData.canConvert<ActionData>() )
 
  530  ActionData actData = action->data().value<ActionData>();
 
  532  if ( actData.mIsValid && actData.mMapLayerAction )
 
  540      actData.mMapLayerAction->triggerForLayer( actData.mLayer );
 
  542      actData.mMapLayerAction->triggerForLayer( actData.mLayer, context );
 
  548      QList<QgsFeature> featureList;
 
  549      const auto results { mLayerIdResults[actData.mLayer] };
 
  552        featureList << result.mFeature;
 
  555      actData.mMapLayerAction->triggerForFeatures( actData.mLayer, featureList );
 
  557      actData.mMapLayerAction->triggerForFeatures( actData.mLayer, featureList, context );
 
  563      const auto results { mLayerIdResults[actData.mLayer] };
 
  566        if ( result.mFeature.id() == actData.mFeatureId )
 
  569          actData.mMapLayerAction->triggerForFeature( actData.mLayer, result.mFeature );
 
  571          actData.mMapLayerAction->triggerForFeature( actData.mLayer, result.mFeature, context );
 
  575      QgsDebugError( QStringLiteral( 
"Identify menu: could not retrieve feature for action %1" ).arg( action->text() ) );
 
  581QList<QgsMapToolIdentify::IdentifyResult> QgsIdentifyMenu::results( QAction *action, 
bool &externalAction )
 
  583  QList<QgsMapToolIdentify::IdentifyResult> idResults = QList<QgsMapToolIdentify::IdentifyResult>();
 
  585  externalAction = 
false;
 
  588  bool hasData = 
false;
 
  593  const QVariant varData = action->data();
 
  594  if ( !varData.isValid() )
 
  596    QgsDebugError( QStringLiteral( 
"Identify menu: could not retrieve results from menu entry (invalid data)" ) );
 
  600  if ( varData.canConvert<ActionData>() )
 
  602    actData = action->data().value<ActionData>();
 
  603    if ( actData.mIsValid )
 
  605      externalAction = actData.mIsExternalAction;
 
  615      externalAction = 
true;
 
  623    QgsDebugError( QStringLiteral( 
"Identify menu: could not retrieve results from menu entry (no data found)" ) );
 
  628  if ( actData.mAllResults )
 
  631    QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
 
  632    while ( it.hasNext() )
 
  635      idResults << it.value();
 
  640  if ( !mLayerIdResults.contains( actData.mLayer ) )
 
  642    QgsDebugError( QStringLiteral( 
"Identify menu: could not retrieve results from menu entry (layer not found)" ) );
 
  648    return mLayerIdResults[actData.mLayer];
 
  653    const auto results {mLayerIdResults[actData.mLayer]};
 
  656      if ( res.mFeature.id() == actData.mFeatureId )
 
  664  QgsDebugError( QStringLiteral( 
"Identify menu: could not retrieve results from menu entry (don't know what happened')" ) );
 
  668void QgsIdentifyMenu::handleMenuHover()
 
  675  QAction *senderAction = qobject_cast<QAction *>( sender() );
 
  680  const QList<QgsMapToolIdentify::IdentifyResult> idResults = results( senderAction, externalAction );
 
  682  const auto constIdResults = idResults;
 
  685    QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( result.mLayer );
 
  691    mRubberBands.append( hl );
 
  692    connect( vl, &QObject::destroyed, 
this, &QgsIdentifyMenu::layerDestroyed );
 
  701void QgsIdentifyMenu::deleteRubberBands()
 
  703  QList<QgsHighlight *>::const_iterator it = mRubberBands.constBegin();
 
  704  for ( ; it != mRubberBands.constEnd(); ++it )
 
  706  mRubberBands.clear();
 
  709void QgsIdentifyMenu::layerDestroyed()
 
  711  QList<QgsHighlight *>::iterator it = mRubberBands.begin();
 
  712  while ( it != mRubberBands.end() )
 
  714    if ( ( *it )->layer() == sender() )
 
  717      it = mRubberBands.erase( it );
 
  728  mCustomActionRegistry.clear();
 
 
  734  mExpressionContextScope = scope;
 
 
  739  return mExpressionContextScope;
 
 
The Qgis class provides global constants for use throughout the application.
 
QFlags< MapLayerActionTarget > MapLayerActionTargets
Map layer action targets.
 
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
 
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
 
@ MultipleFeatures
Action targets multiple features from a layer.
 
@ Layer
Action targets a complete layer.
 
@ SingleFeature
Action targets a single feature from a layer.
 
@ Group
Composite group layer. Added in QGIS 3.24.
 
@ Plugin
Plugin based layer.
 
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
 
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
 
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
 
@ Mesh
Mesh layer. Added in QGIS 3.2.
 
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
 
@ Reverse
Reverse/inverse transform (from destination to source)
 
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
 
@ IdentifyMode
Identify the feature.
 
Custom exception class for Coordinate Reference System related exceptions.
 
Single scope for storing variables and functions for use within a QgsExpressionContext.
 
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
Class for parsing and evaluation of expressions (formerly called "search strings").
 
Wrapper for iterator of features from vector data provider or vector layer.
 
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
 
This class wraps a request for features to a vector layer (or directly its vector data provider).
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
 
A class for highlight features on the map.
 
void applyDefaultStyle()
Applies the default style from the user settings to the highlight.
 
static QIcon iconForWkbType(Qgis::WkbType type)
Returns the icon for a vector layer whose geometry type is provided.
 
Map canvas is a class for displaying all GIS data types on a canvas.
 
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers shown within the map canvas.
 
const QgsMapToPixel * getCoordinateTransform()
Gets the current coordinate transform.
 
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
 
Encapsulates the context in which a QgsMapLayerAction action is executed.
 
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, Qgis::MapLayerActionTargets targets=Qgis::MapLayerActionTarget::AllActions, const QgsMapLayerActionContext &context=QgsMapLayerActionContext())
Returns the map layer actions which can run on the specified layer.
 
An action which can run on map layers The class can be used in two manners:
 
Base class for all map layer types.
 
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
 
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Returns the coordinate transform from layer's CRS to destination CRS.
 
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
 
A class to represent a 2D point.
 
A rectangle specified with double values.
 
Represents a vector layer which manages a vector based data sets.
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
 
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
 
QString displayExpression
 
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
 
#define Q_NOWARN_DEPRECATED_POP
 
#define Q_NOWARN_DEPRECATED_PUSH
 
#define QgsDebugError(str)