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.