16 #include <QMouseEvent>    34   , mAllowMultipleReturn( true )
    35   , mExecWithSingleResult( false )
    36   , mShowFeatureActions( false )
    37   , mResultsIfExternalAction( false )
    38   , mMaxLayerDisplay( 10 )
    39   , mMaxFeatureDisplay( 10 )
    40   , mDefaultActionName( tr( 
"Identify" ) )
    52   if ( maxLayerDisplay < 0 )
    54     QgsDebugMsg( QStringLiteral( 
"invalid value for number of layers displayed." ) );
    62   if ( maxFeatureDisplay < 0 )
    64     QgsDebugMsg( QStringLiteral( 
"invalid value for number of layers displayed." ) );
    70 QList<QgsMapToolIdentify::IdentifyResult> 
QgsIdentifyMenu::exec( 
const QList<QgsMapToolIdentify::IdentifyResult> &idResults, QPoint pos )
    73   mLayerIdResults.clear();
    75   QList<QgsMapToolIdentify::IdentifyResult> returnResults = QList<QgsMapToolIdentify::IdentifyResult>();
    77   if ( idResults.isEmpty() )
    81   if ( idResults.count() == 1 && !mExecWithSingleResult )
    83     returnResults << idResults[0];
    88   const auto constIdResults = idResults;
    92     if ( mLayerIdResults.contains( layer ) )
    94       mLayerIdResults[layer].append( result );
    98       mLayerIdResults.insert( layer, QList<QgsMapToolIdentify::IdentifyResult>() << result );
   103   bool singleLayer = mLayerIdResults.count() == 1;
   105   QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
   106   while ( it.hasNext() )
   108     if ( mMaxLayerDisplay != 0 && count > mMaxLayerDisplay )
   113     switch ( layer->
type() )
   117         addRasterLayer( layer );
   125         addVectorLayer( vl, it.value(), singleLayer );
   136   if ( !singleLayer && mAllowMultipleReturn && idResults.count() > 1 )
   139     QAction *allAction = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"/mActionIdentify.svg" ) ), tr( 
"%1 All (%2)" ).arg( mDefaultActionName ).arg( idResults.count() ), 
this );
   140     allAction->setData( QVariant::fromValue<ActionData>( 
ActionData( 
nullptr ) ) );
   141     connect( allAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   142     addAction( allAction );
   146   QAction *selectedAction = QMenu::exec( pos );
   148   returnResults = results( selectedAction, externalAction );
   153   qDeleteAll( findChildren<QgsActionMenu *>() );
   155   if ( externalAction && !mResultsIfExternalAction )
   157     return QList<QgsMapToolIdentify::IdentifyResult>();
   161     return returnResults;
   168   QMenu::closeEvent( e );
   171 void QgsIdentifyMenu::addRasterLayer( 
QgsMapLayer *layer )
   173   QAction *layerAction = 
nullptr;
   174   QMenu *layerMenu = 
nullptr;
   176   QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
   178   int nCustomActions = layerActions.count();
   179   if ( nCustomActions )
   181     separators.append( layerActions[0] );
   183   if ( mShowFeatureActions )
   186     if ( layerActions.count() > nCustomActions )
   188       separators.append( layerActions[nCustomActions] );
   193   if ( layerActions.isEmpty() )
   195     layerAction = 
new QAction( layer->
name(), this );
   199     layerMenu = 
new QMenu( layer->
name(), this );
   200     layerAction = layerMenu->menuAction();
   205   layerAction->setData( QVariant::fromValue<ActionData>( 
ActionData( layer ) ) );
   206   connect( layerAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   207   addAction( layerAction );
   214   QAction *identifyFeatureAction = 
new QAction( mDefaultActionName, layerMenu );
   215   connect( identifyFeatureAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   216   identifyFeatureAction->setData( QVariant::fromValue<ActionData>( 
ActionData( layer ) ) );
   217   layerMenu->addAction( identifyFeatureAction );
   220   const auto constLayerActions = layerActions;
   223     QAction *action = 
new QAction( mapLayerAction->icon(), mapLayerAction->text(), layerMenu );
   224     action->setData( QVariant::fromValue<ActionData>( 
ActionData( layer, 
true ) ) );
   225     connect( action, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   226     connect( action, &QAction::triggered, 
this, &QgsIdentifyMenu::triggerMapLayerAction );
   227     layerMenu->addAction( action );
   228     if ( separators.contains( mapLayerAction ) )
   230       layerMenu->insertSeparator( action );
   235 void QgsIdentifyMenu::addVectorLayer( 
QgsVectorLayer *layer, 
const QList<QgsMapToolIdentify::IdentifyResult> &results, 
bool singleLayer )
   237   QAction *layerAction = 
nullptr;
   238   QMenu *layerMenu = 
nullptr;
   244   QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
   245   QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, targets );
   246   int nCustomActions = layerActions.count();
   247   if ( nCustomActions )
   249     separators << layerActions[0];
   251   if ( mShowFeatureActions )
   255     if ( layerActions.count() > nCustomActions )
   257       separators << layerActions[nCustomActions];
   266   bool createMenu = results.count() > 1 || !layerActions.isEmpty();
   273     if ( !createMenu && mShowFeatureActions )
   277       createMenu  = !featureActionMenu->actions().isEmpty();
   278       delete featureActionMenu;
   290     QString featureTitle = exp.evaluate( &context ).toString();
   291     if ( featureTitle.isEmpty() )
   292       featureTitle = QStringLiteral( 
"%1" ).arg( results[0].mFeature.id() );
   293     layerAction = 
new QAction( QStringLiteral( 
"%1 (%2)" ).arg( layer->
name(), featureTitle ), 
this );
   305       if ( results.count() > 1 )
   307         layerMenu = 
new QMenu( layer->
name(), this );
   312         QString featureTitle = exp.evaluate( &context ).toString();
   313         if ( featureTitle.isEmpty() )
   314           featureTitle = QStringLiteral( 
"%1" ).arg( results[0].mFeature.id() );
   315         layerMenu = 
new QMenu( QStringLiteral( 
"%1 (%2)" ).arg( layer->
name(), featureTitle ), 
this );
   317       layerAction = layerMenu->menuAction();
   341     layerAction->setData( QVariant::fromValue<ActionData>( 
ActionData( layer ) ) );
   342     connect( layerAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   343     addAction( layerAction );
   352   const auto constResults = results;
   355     if ( mMaxFeatureDisplay != 0 && count > mMaxFeatureDisplay )
   359     QAction *featureAction = 
nullptr;
   360     QMenu *featureMenu = 
nullptr;
   364     if ( mShowFeatureActions )
   366       featureActionMenu = 
new QgsActionMenu( layer, result.mFeature, QStringLiteral( 
"Feature" ), layerMenu );
   373     QString featureTitle = exp.evaluate( &context ).toString();
   374     if ( featureTitle.isEmpty() )
   375       featureTitle = QStringLiteral( 
"%1" ).arg( result.mFeature.id() );
   377     if ( customFeatureActions.isEmpty() && ( !featureActionMenu || featureActionMenu->actions().isEmpty() ) )
   379       featureAction = 
new QAction( featureTitle, layerMenu );
   381       featureAction->setData( QVariant::fromValue<ActionData>( 
ActionData( layer, result.mFeature.
id() ) ) );
   382       connect( featureAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   383       layerMenu->addAction( featureAction );
   385     else if ( results.count() == 1 )
   390       featureMenu = layerMenu;
   394       featureMenu = 
new QMenu( featureTitle, layerMenu );
   397       featureAction = featureMenu->menuAction();
   399       featureAction->setData( QVariant::fromValue<ActionData>( 
ActionData( layer, result.mFeature.
id() ) ) );
   400       connect( featureAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   401       layerMenu->addAction( featureAction );
   409     QAction *identifyFeatureAction = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"/mActionIdentify.svg" ) ), mDefaultActionName, featureMenu );
   410     connect( identifyFeatureAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   411     identifyFeatureAction->setData( QVariant::fromValue<ActionData>( 
ActionData( layer, result.mFeature.
id() ) ) );
   412     featureMenu->addAction( identifyFeatureAction );
   413     featureMenu->addSeparator();
   416     const auto constCustomFeatureActions = customFeatureActions;
   419       QAction *action = 
new QAction( mapLayerAction->icon(), mapLayerAction->text(), featureMenu );
   420       action->setData( QVariant::fromValue<ActionData>( 
ActionData( layer, result.mFeature.
id(), mapLayerAction ) ) );
   421       connect( action, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   422       connect( action, &QAction::triggered, 
this, &QgsIdentifyMenu::triggerMapLayerAction );
   423       featureMenu->addAction( action );
   426     if ( featureActionMenu )
   428       const auto constActions = featureActionMenu->actions();
   429       for ( QAction *action : constActions )
   431         connect( action, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   432         featureMenu->addAction( action );
   440   if ( mAllowMultipleReturn && results.count() > 1 )
   442     layerMenu->addSeparator();
   443     QAction *allAction = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"/mActionIdentify.svg" ) ), tr( 
"%1 All (%2)" ).arg( mDefaultActionName ).arg( results.count() ), layerMenu );
   444     allAction->setData( QVariant::fromValue<ActionData>( 
ActionData( layer ) ) );
   445     connect( allAction, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   446     layerMenu->addAction( allAction );
   450   const auto constLayerActions = layerActions;
   453     QString title = mapLayerAction->text();
   455       title.append( QStringLiteral( 
" (%1)" ).arg( results.count() ) );
   456     QAction *action = 
new QAction( mapLayerAction->icon(), title, layerMenu );
   457     action->setData( QVariant::fromValue<ActionData>( 
ActionData( layer, mapLayerAction ) ) );
   458     connect( action, &QAction::hovered, 
this, &QgsIdentifyMenu::handleMenuHover );
   459     connect( action, &QAction::triggered, 
this, &QgsIdentifyMenu::triggerMapLayerAction );
   460     layerMenu->addAction( action );
   461     if ( separators.contains( mapLayerAction ) )
   463       layerMenu->insertSeparator( action );
   468 void QgsIdentifyMenu::triggerMapLayerAction()
   470   QAction *action = qobject_cast<QAction *>( sender() );
   473   QVariant varData = action->data();
   474   if ( !varData.isValid() || !varData.canConvert<
ActionData>() )
   490       QList<QgsFeature> featureList;
   491       const auto results { mLayerIdResults[actData.
mLayer] };
   494         featureList << result.mFeature;
   502       const auto results { mLayerIdResults[actData.
mLayer] };
   505         if ( result.mFeature.id() == actData.
mFeatureId )
   511       QgsDebugMsg( QStringLiteral( 
"Identify menu: could not retrieve feature for action %1" ).arg( action->text() ) );
   517 QList<QgsMapToolIdentify::IdentifyResult> QgsIdentifyMenu::results( QAction *action, 
bool &externalAction )
   519   QList<QgsMapToolIdentify::IdentifyResult> idResults = QList<QgsMapToolIdentify::IdentifyResult>();
   521   externalAction = 
false;
   524   bool hasData = 
false;
   529   QVariant varData = action->data();
   530   if ( !varData.isValid() )
   532     QgsDebugMsg( QStringLiteral( 
"Identify menu: could not retrieve results from menu entry (invalid data)" ) );
   551       externalAction = 
true;
   559     QgsDebugMsg( QStringLiteral( 
"Identify menu: could not retrieve results from menu entry (no data found)" ) );
   567     QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
   568     while ( it.hasNext() )
   571       idResults << it.value();
   576   if ( !mLayerIdResults.contains( actData.
mLayer ) )
   578     QgsDebugMsg( QStringLiteral( 
"Identify menu: could not retrieve results from menu entry (layer not found)" ) );
   584     return mLayerIdResults[actData.
mLayer];
   589     const auto results {mLayerIdResults[actData.
mLayer]};
   592       if ( res.mFeature.id() == actData.
mFeatureId )
   600   QgsDebugMsg( QStringLiteral( 
"Identify menu: could not retrieve results from menu entry (don't know what happened')" ) );
   604 void QgsIdentifyMenu::handleMenuHover()
   611   QAction *senderAction = qobject_cast<QAction *>( sender() );
   616   QList<QgsMapToolIdentify::IdentifyResult> idResults = results( senderAction, externalAction );
   618   const auto constIdResults = idResults;
   627     mRubberBands.append( hl );
   628     connect( vl, &QObject::destroyed, 
this, &QgsIdentifyMenu::layerDestroyed );
   641   color.setAlpha( alpha );
   647 void QgsIdentifyMenu::deleteRubberBands()
   649   QList<QgsHighlight *>::const_iterator it = mRubberBands.constBegin();
   650   for ( ; it != mRubberBands.constEnd(); ++it )
   652   mRubberBands.clear();
   655 void QgsIdentifyMenu::layerDestroyed()
   657   QList<QgsHighlight *>::iterator it = mRubberBands.begin();
   658   while ( it != mRubberBands.end() )
   660     if ( ( *it )->layer() == sender() )
   663       it = mRubberBands.erase( it );
   674   mCustomActionRegistry.clear();
   680   mExpressionContextScope = scope;
   685   return mExpressionContextScope;
 Class for parsing and evaluation of expressions (formerly called "search strings"). 
 
Base class for all map layer types. 
 
void triggerForFeature(QgsMapLayer *layer, const QgsFeature &feature)
Triggers the action with the specified layer and feature. 
 
QgsMapLayerType type() const
Returns the type of the layer. 
 
This class is a composition of two QSettings instances: 
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key. 
 
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context. 
 
void setFillColor(const QColor &fillColor)
Fill color for the highlight. 
 
static const QColor DEFAULT_HIGHLIGHT_COLOR
Default highlight color. 
 
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon. 
 
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon. 
 
Map canvas is a class for displaying all GIS data types on a canvas. 
 
void setBuffer(double buffer)
Set line / stroke buffer in millimeters. 
 
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject. 
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
A class for highlight features on the map. 
 
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer. 
 
Single scope for storing variables and functions for use within a QgsExpressionContext. 
 
const Targets & targets() const
Returns availibity of action. 
 
QString displayExpression
 
void triggerForFeatures(QgsMapLayer *layer, const QList< QgsFeature > &featureList)
Triggers the action with the specified layer and list of feature. 
 
void setColor(const QColor &color)
Set line/stroke to color, polygon fill to color with alpha = 63. 
 
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes. 
 
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer. 
 
static const double DEFAULT_HIGHLIGHT_MIN_WIDTH_MM
Default highlight line/stroke minimum width in mm. 
 
static const double DEFAULT_HIGHLIGHT_BUFFER_MM
Default highlight buffer in mm. 
 
Represents a vector layer which manages a vector based data sets. 
 
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions. 
 
void triggerForLayer(QgsMapLayer *layer)
Triggers the action with the specified layer. 
 
An action which can run on map layers. 
 
void setMinWidth(double width)
Set minimum line / stroke width in millimeters.