16 #include <QMouseEvent> 33 , mAllowMultipleReturn( true )
34 , mExecWithSingleResult( false )
35 , mShowFeatureActions( false )
36 , mResultsIfExternalAction( false )
37 , mMaxLayerDisplay( 10 )
38 , mMaxFeatureDisplay( 10 )
39 , mDefaultActionName( tr(
"Identify" ) )
51 if ( maxLayerDisplay < 0 )
53 QgsDebugMsg( QStringLiteral(
"invalid value for number of layers displayed." ) );
61 if ( maxFeatureDisplay < 0 )
63 QgsDebugMsg( QStringLiteral(
"invalid value for number of layers displayed." ) );
69 QList<QgsMapToolIdentify::IdentifyResult>
QgsIdentifyMenu::exec(
const QList<QgsMapToolIdentify::IdentifyResult> &idResults, QPoint pos )
72 mLayerIdResults.clear();
74 QList<QgsMapToolIdentify::IdentifyResult> returnResults = QList<QgsMapToolIdentify::IdentifyResult>();
76 if ( idResults.isEmpty() )
80 if ( idResults.count() == 1 && !mExecWithSingleResult )
82 returnResults << idResults[0];
87 const auto constIdResults = idResults;
91 if ( mLayerIdResults.contains( layer ) )
93 mLayerIdResults[layer].append( result );
97 mLayerIdResults.insert( layer, QList<QgsMapToolIdentify::IdentifyResult>() << result );
102 bool singleLayer = mLayerIdResults.count() == 1;
104 QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
105 while ( it.hasNext() )
107 if ( mMaxLayerDisplay != 0 && count > mMaxLayerDisplay )
112 switch ( layer->
type() )
116 addRasterLayer( layer );
124 addVectorLayer( vl, it.value(), singleLayer );
135 if ( !singleLayer && mAllowMultipleReturn && idResults.count() > 1 )
138 QAction *allAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), tr(
"%1 All (%2)" ).arg( mDefaultActionName ).arg( idResults.count() ),
this );
139 allAction->setData( QVariant::fromValue<ActionData>(
ActionData(
nullptr ) ) );
140 connect( allAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
141 addAction( allAction );
145 QAction *selectedAction = QMenu::exec( pos );
147 returnResults = results( selectedAction, externalAction );
152 qDeleteAll( findChildren<QgsActionMenu *>() );
154 if ( externalAction && !mResultsIfExternalAction )
156 return QList<QgsMapToolIdentify::IdentifyResult>();
160 return returnResults;
167 QMenu::closeEvent( e );
170 void QgsIdentifyMenu::addRasterLayer(
QgsMapLayer *layer )
172 QAction *layerAction =
nullptr;
173 QMenu *layerMenu =
nullptr;
175 QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
177 int nCustomActions = layerActions.count();
178 if ( nCustomActions )
180 separators.append( layerActions[0] );
182 if ( mShowFeatureActions )
185 if ( layerActions.count() > nCustomActions )
187 separators.append( layerActions[nCustomActions] );
192 if ( layerActions.isEmpty() )
194 layerAction =
new QAction( layer->
name(), this );
198 layerMenu =
new QMenu( layer->
name(), this );
199 layerAction = layerMenu->menuAction();
204 layerAction->setData( QVariant::fromValue<ActionData>(
ActionData( layer ) ) );
205 connect( layerAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
206 addAction( layerAction );
213 QAction *identifyFeatureAction =
new QAction( mDefaultActionName, layerMenu );
214 connect( identifyFeatureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
215 identifyFeatureAction->setData( QVariant::fromValue<ActionData>(
ActionData( layer ) ) );
216 layerMenu->addAction( identifyFeatureAction );
219 const auto constLayerActions = layerActions;
222 QAction *action =
new QAction( mapLayerAction->icon(), mapLayerAction->text(), layerMenu );
223 action->setData( QVariant::fromValue<ActionData>(
ActionData( layer,
true ) ) );
224 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
225 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
226 layerMenu->addAction( action );
227 if ( separators.contains( mapLayerAction ) )
229 layerMenu->insertSeparator( action );
234 void QgsIdentifyMenu::addVectorLayer(
QgsVectorLayer *layer,
const QList<QgsMapToolIdentify::IdentifyResult> &results,
bool singleLayer )
236 QAction *layerAction =
nullptr;
237 QMenu *layerMenu =
nullptr;
243 QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
244 QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, targets );
245 int nCustomActions = layerActions.count();
246 if ( nCustomActions )
248 separators << layerActions[0];
250 if ( mShowFeatureActions )
254 if ( layerActions.count() > nCustomActions )
256 separators << layerActions[nCustomActions];
265 bool createMenu = results.count() > 1 || !layerActions.isEmpty();
272 if ( !createMenu && mShowFeatureActions )
276 createMenu = !featureActionMenu->actions().isEmpty();
277 delete featureActionMenu;
285 QString featureTitle = results[0].mFeature.attribute( layer->
displayField() ).toString();
286 if ( featureTitle.isEmpty() )
287 featureTitle = QStringLiteral(
"%1" ).arg( results[0].mFeature.id() );
288 layerAction =
new QAction( QStringLiteral(
"%1 (%2)" ).arg( layer->
name(), featureTitle ),
this );
300 if ( results.count() > 1 )
302 layerMenu =
new QMenu( layer->
name(), this );
307 QString featureTitle = results[0].mFeature.attribute( layer->
displayField() ).toString();
308 if ( featureTitle.isEmpty() )
309 featureTitle = QStringLiteral(
"%1" ).arg( results[0].mFeature.id() );
310 layerMenu =
new QMenu( QStringLiteral(
"%1 (%2)" ).arg( layer->
name(), featureTitle ),
this );
312 layerAction = layerMenu->menuAction();
336 layerAction->setData( QVariant::fromValue<ActionData>(
ActionData( layer ) ) );
337 connect( layerAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
338 addAction( layerAction );
347 const auto constResults = results;
350 if ( mMaxFeatureDisplay != 0 && count > mMaxFeatureDisplay )
354 QAction *featureAction =
nullptr;
355 QMenu *featureMenu =
nullptr;
359 if ( mShowFeatureActions )
361 featureActionMenu =
new QgsActionMenu( layer, result.mFeature, QStringLiteral(
"Feature" ), layerMenu );
367 QString featureTitle = result.mFeature.attribute( layer->
displayField() ).toString();
368 if ( featureTitle.isEmpty() )
369 featureTitle = QStringLiteral(
"%1" ).arg( result.mFeature.id() );
371 if ( customFeatureActions.isEmpty() && ( !featureActionMenu || featureActionMenu->actions().isEmpty() ) )
373 featureAction =
new QAction( featureTitle, layerMenu );
375 featureAction->setData( QVariant::fromValue<ActionData>(
ActionData( layer, result.mFeature.
id() ) ) );
376 connect( featureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
377 layerMenu->addAction( featureAction );
379 else if ( results.count() == 1 )
384 featureMenu = layerMenu;
388 featureMenu =
new QMenu( featureTitle, layerMenu );
391 featureAction = featureMenu->menuAction();
393 featureAction->setData( QVariant::fromValue<ActionData>(
ActionData( layer, result.mFeature.
id() ) ) );
394 connect( featureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
395 layerMenu->addAction( featureAction );
403 QAction *identifyFeatureAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), mDefaultActionName, featureMenu );
404 connect( identifyFeatureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
405 identifyFeatureAction->setData( QVariant::fromValue<ActionData>(
ActionData( layer, result.mFeature.
id() ) ) );
406 featureMenu->addAction( identifyFeatureAction );
407 featureMenu->addSeparator();
410 const auto constCustomFeatureActions = customFeatureActions;
413 QAction *action =
new QAction( mapLayerAction->icon(), mapLayerAction->text(), featureMenu );
414 action->setData( QVariant::fromValue<ActionData>(
ActionData( layer, result.mFeature.
id(), mapLayerAction ) ) );
415 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
416 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
417 featureMenu->addAction( action );
420 if ( featureActionMenu )
422 const auto constActions = featureActionMenu->actions();
423 for ( QAction *action : constActions )
425 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
426 featureMenu->addAction( action );
434 if ( mAllowMultipleReturn && results.count() > 1 )
436 layerMenu->addSeparator();
437 QAction *allAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), tr(
"%1 All (%2)" ).arg( mDefaultActionName ).arg( results.count() ), layerMenu );
438 allAction->setData( QVariant::fromValue<ActionData>(
ActionData( layer ) ) );
439 connect( allAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
440 layerMenu->addAction( allAction );
444 const auto constLayerActions = layerActions;
447 QString title = mapLayerAction->text();
449 title.append( QStringLiteral(
" (%1)" ).arg( results.count() ) );
450 QAction *action =
new QAction( mapLayerAction->icon(), title, layerMenu );
451 action->setData( QVariant::fromValue<ActionData>(
ActionData( layer, mapLayerAction ) ) );
452 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
453 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
454 layerMenu->addAction( action );
455 if ( separators.contains( mapLayerAction ) )
457 layerMenu->insertSeparator( action );
462 void QgsIdentifyMenu::triggerMapLayerAction()
464 QAction *action = qobject_cast<QAction *>( sender() );
467 QVariant varData = action->data();
468 if ( !varData.isValid() || !varData.canConvert<
ActionData>() )
484 QList<QgsFeature> featureList;
485 const auto results { mLayerIdResults[actData.
mLayer] };
488 featureList << result.mFeature;
496 const auto results { mLayerIdResults[actData.
mLayer] };
499 if ( result.mFeature.id() == actData.
mFeatureId )
505 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve feature for action %1" ).arg( action->text() ) );
511 QList<QgsMapToolIdentify::IdentifyResult> QgsIdentifyMenu::results( QAction *action,
bool &externalAction )
513 QList<QgsMapToolIdentify::IdentifyResult> idResults = QList<QgsMapToolIdentify::IdentifyResult>();
515 externalAction =
false;
518 bool hasData =
false;
523 QVariant varData = action->data();
524 if ( !varData.isValid() )
526 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (invalid data)" ) );
545 externalAction =
true;
553 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (no data found)" ) );
561 QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
562 while ( it.hasNext() )
565 idResults << it.value();
570 if ( !mLayerIdResults.contains( actData.
mLayer ) )
572 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (layer not found)" ) );
578 return mLayerIdResults[actData.
mLayer];
583 const auto results {mLayerIdResults[actData.
mLayer]};
586 if ( res.mFeature.id() == actData.
mFeatureId )
594 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (don't know what happened')" ) );
598 void QgsIdentifyMenu::handleMenuHover()
605 QAction *senderAction = qobject_cast<QAction *>( sender() );
610 QList<QgsMapToolIdentify::IdentifyResult> idResults = results( senderAction, externalAction );
612 const auto constIdResults = idResults;
621 mRubberBands.append( hl );
622 connect( vl, &QObject::destroyed,
this, &QgsIdentifyMenu::layerDestroyed );
635 color.setAlpha( alpha );
641 void QgsIdentifyMenu::deleteRubberBands()
643 QList<QgsHighlight *>::const_iterator it = mRubberBands.constBegin();
644 for ( ; it != mRubberBands.constEnd(); ++it )
646 mRubberBands.clear();
649 void QgsIdentifyMenu::layerDestroyed()
651 QList<QgsHighlight *>::iterator it = mRubberBands.begin();
652 while ( it != mRubberBands.end() )
654 if ( ( *it )->layer() == sender() )
657 it = mRubberBands.erase( it );
668 mCustomActionRegistry.clear();
674 mExpressionContextScope = scope;
679 return mExpressionContextScope;
Base class for all map layer types.
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 setFillColor(const QColor &fillColor)
Fill color for the highlight.
static const QColor DEFAULT_HIGHLIGHT_COLOR
Default highlight color.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
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.
A class for highlight features on the map.
Single scope for storing variables and functions for use within a QgsExpressionContext.
const Targets & targets() const
Returns availibity of action.
QString displayField() const
This is a shorthand for accessing the displayExpression if it is a simple field.
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.
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.
void triggerForFeature(QgsMapLayer *layer, const QgsFeature *feature)
Triggers the action with the specified layer and feature.
An action which can run on map layers.
void setMinWidth(double width)
Set minimum line / stroke width in millimeters.