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" ) )
54 QgsDebugMsg( QStringLiteral(
"invalid value for number of layers displayed." ) );
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 );
140 if ( !singleLayer && mAllowMultipleReturn && idResults.count() > 1 )
143 QAction *allAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), tr(
"%1 All (%2)" ).arg( mDefaultActionName ).arg( idResults.count() ),
this );
144 allAction->setData( QVariant::fromValue<ActionData>(
ActionData(
nullptr ) ) );
145 connect( allAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
146 addAction( allAction );
150 QAction *selectedAction = QMenu::exec( pos );
152 returnResults = results( selectedAction, externalAction );
157 qDeleteAll( findChildren<QgsActionMenu *>() );
159 if ( externalAction && !mResultsIfExternalAction )
161 return QList<QgsMapToolIdentify::IdentifyResult>();
165 return returnResults;
172 QMenu::closeEvent( e );
175 void QgsIdentifyMenu::addRasterLayer(
QgsMapLayer *layer )
177 QAction *layerAction =
nullptr;
178 QMenu *layerMenu =
nullptr;
180 QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
182 int nCustomActions = layerActions.count();
183 if ( nCustomActions )
185 separators.append( layerActions[0] );
187 if ( mShowFeatureActions )
190 if ( layerActions.count() > nCustomActions )
192 separators.append( layerActions[nCustomActions] );
197 if ( layerActions.isEmpty() )
199 layerAction =
new QAction( layer->
name(),
this );
203 layerMenu =
new QMenu( layer->
name(),
this );
204 layerAction = layerMenu->menuAction();
209 layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
210 connect( layerAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
211 addAction( layerAction );
218 QAction *identifyFeatureAction =
new QAction( mDefaultActionName, layerMenu );
219 connect( identifyFeatureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
220 identifyFeatureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
221 layerMenu->addAction( identifyFeatureAction );
224 const auto constLayerActions = layerActions;
227 QAction *action =
new QAction( mapLayerAction->icon(), mapLayerAction->text(), layerMenu );
228 action->setData( QVariant::fromValue<ActionData>( ActionData( layer,
true ) ) );
229 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
230 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
231 layerMenu->addAction( action );
232 if ( separators.contains( mapLayerAction ) )
234 layerMenu->insertSeparator( action );
239 void QgsIdentifyMenu::addVectorLayer(
QgsVectorLayer *layer,
const QList<QgsMapToolIdentify::IdentifyResult> &results,
bool singleLayer )
241 QAction *layerAction =
nullptr;
242 QMenu *layerMenu =
nullptr;
248 QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
249 QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, targets );
250 int nCustomActions = layerActions.count();
251 if ( nCustomActions )
253 separators << layerActions[0];
255 if ( mShowFeatureActions )
259 if ( layerActions.count() > nCustomActions )
261 separators << layerActions[nCustomActions];
270 bool createMenu = results.count() > 1 || !layerActions.isEmpty();
277 if ( !createMenu && mShowFeatureActions )
281 createMenu = !featureActionMenu->actions().isEmpty();
282 delete featureActionMenu;
288 exp.prepare( &context );
289 context.setFeature( results[0].mFeature );
294 QString featureTitle = exp.evaluate( &context ).toString();
295 if ( featureTitle.isEmpty() )
296 featureTitle = QStringLiteral(
"%1" ).arg( results[0].mFeature.id() );
297 layerAction =
new QAction( QStringLiteral(
"%1 (%2)" ).arg( layer->
name(), featureTitle ),
this );
309 if ( results.count() > 1 )
311 layerMenu =
new QMenu( layer->
name(),
this );
316 QString featureTitle = exp.evaluate( &context ).toString();
317 if ( featureTitle.isEmpty() )
318 featureTitle = QStringLiteral(
"%1" ).arg( results[0].mFeature.id() );
319 layerMenu =
new QMenu( QStringLiteral(
"%1 (%2)" ).arg( layer->
name(), featureTitle ),
this );
321 layerAction = layerMenu->menuAction();
345 layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
346 connect( layerAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
347 addAction( layerAction );
356 const auto constResults = results;
359 if ( mMaxFeatureDisplay != 0 && count > mMaxFeatureDisplay )
363 QAction *featureAction =
nullptr;
364 QMenu *featureMenu =
nullptr;
368 if ( mShowFeatureActions )
370 featureActionMenu =
new QgsActionMenu( layer, result.mFeature, QStringLiteral(
"Feature" ), layerMenu );
376 context.setFeature( result.mFeature );
377 QString featureTitle = exp.evaluate( &context ).toString();
378 if ( featureTitle.isEmpty() )
379 featureTitle = QStringLiteral(
"%1" ).arg( result.mFeature.id() );
381 if ( customFeatureActions.isEmpty() && ( !featureActionMenu || featureActionMenu->actions().isEmpty() ) )
383 featureAction =
new QAction( featureTitle, layerMenu );
385 featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
386 connect( featureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
387 layerMenu->addAction( featureAction );
389 else if ( results.count() == 1 )
394 featureMenu = layerMenu;
398 featureMenu =
new QMenu( featureTitle, layerMenu );
401 featureAction = featureMenu->menuAction();
403 featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
404 connect( featureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
405 layerMenu->addAction( featureAction );
413 QAction *identifyFeatureAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), mDefaultActionName, featureMenu );
414 connect( identifyFeatureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
415 identifyFeatureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
416 featureMenu->addAction( identifyFeatureAction );
417 featureMenu->addSeparator();
420 const auto constCustomFeatureActions = customFeatureActions;
423 QAction *action =
new QAction( mapLayerAction->icon(), mapLayerAction->text(), featureMenu );
424 action->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id(), mapLayerAction ) ) );
425 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
426 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
427 featureMenu->addAction( action );
430 if ( featureActionMenu )
432 const auto constActions = featureActionMenu->actions();
433 for ( QAction *action : constActions )
435 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
436 featureMenu->addAction( action );
444 if ( mAllowMultipleReturn && results.count() > 1 )
446 layerMenu->addSeparator();
447 QAction *allAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), tr(
"%1 All (%2)" ).arg( mDefaultActionName ).arg( results.count() ), layerMenu );
448 allAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
449 connect( allAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
450 layerMenu->addAction( allAction );
454 const auto constLayerActions = layerActions;
457 QString title = mapLayerAction->text();
459 title.append( QStringLiteral(
" (%1)" ).arg( results.count() ) );
460 QAction *action =
new QAction( mapLayerAction->icon(), title, layerMenu );
461 action->setData( QVariant::fromValue<ActionData>( ActionData( layer, mapLayerAction ) ) );
462 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
463 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
464 layerMenu->addAction( action );
465 if ( separators.contains( mapLayerAction ) )
467 layerMenu->insertSeparator( action );
472 void QgsIdentifyMenu::triggerMapLayerAction()
474 QAction *action = qobject_cast<QAction *>( sender() );
477 QVariant varData = action->data();
478 if ( !varData.isValid() || !varData.canConvert<ActionData>() )
481 ActionData actData = action->data().value<ActionData>();
483 if ( actData.mIsValid && actData.mMapLayerAction )
488 actData.mMapLayerAction->triggerForLayer( actData.mLayer );
494 QList<QgsFeature> featureList;
495 const auto results { mLayerIdResults[actData.mLayer] };
498 featureList << result.mFeature;
500 actData.mMapLayerAction->triggerForFeatures( actData.mLayer, featureList );
506 const auto results { mLayerIdResults[actData.mLayer] };
509 if ( result.mFeature.id() == actData.mFeatureId )
511 actData.mMapLayerAction->triggerForFeature( actData.mLayer, result.mFeature );
515 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve feature for action %1" ).arg( action->text() ) );
521 QList<QgsMapToolIdentify::IdentifyResult> QgsIdentifyMenu::results( QAction *action,
bool &externalAction )
523 QList<QgsMapToolIdentify::IdentifyResult> idResults = QList<QgsMapToolIdentify::IdentifyResult>();
525 externalAction =
false;
528 bool hasData =
false;
533 QVariant varData = action->data();
534 if ( !varData.isValid() )
536 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (invalid data)" ) );
540 if ( varData.canConvert<ActionData>() )
542 actData = action->data().value<ActionData>();
543 if ( actData.mIsValid )
545 externalAction = actData.mIsExternalAction;
555 externalAction =
true;
563 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (no data found)" ) );
568 if ( actData.mAllResults )
571 QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
572 while ( it.hasNext() )
575 idResults << it.value();
580 if ( !mLayerIdResults.contains( actData.mLayer ) )
582 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (layer not found)" ) );
588 return mLayerIdResults[actData.mLayer];
593 const auto results {mLayerIdResults[actData.mLayer]};
596 if ( res.mFeature.id() == actData.mFeatureId )
604 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (don't know what happened')" ) );
608 void QgsIdentifyMenu::handleMenuHover()
615 QAction *senderAction = qobject_cast<QAction *>( sender() );
620 QList<QgsMapToolIdentify::IdentifyResult> idResults = results( senderAction, externalAction );
622 const auto constIdResults = idResults;
625 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( result.mLayer );
631 mRubberBands.append( hl );
632 connect( vl, &QObject::destroyed,
this, &QgsIdentifyMenu::layerDestroyed );
645 color.setAlpha( alpha );
651 void QgsIdentifyMenu::deleteRubberBands()
653 QList<QgsHighlight *>::const_iterator it = mRubberBands.constBegin();
654 for ( ; it != mRubberBands.constEnd(); ++it )
656 mRubberBands.clear();
659 void QgsIdentifyMenu::layerDestroyed()
661 QList<QgsHighlight *>::iterator it = mRubberBands.begin();
662 while ( it != mRubberBands.end() )
664 if ( ( *it )->layer() == sender() )
667 it = mRubberBands.erase( it );
678 mCustomActionRegistry.clear();
684 mExpressionContextScope = scope;
689 return mExpressionContextScope;