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 );
141 if ( !singleLayer && mAllowMultipleReturn && idResults.count() > 1 )
144 QAction *allAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), tr(
"%1 All (%2)" ).arg( mDefaultActionName ).arg( idResults.count() ),
this );
145 allAction->setData( QVariant::fromValue<ActionData>(
ActionData(
nullptr ) ) );
146 connect( allAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
147 addAction( allAction );
151 QAction *selectedAction = QMenu::exec( pos );
153 returnResults = results( selectedAction, externalAction );
158 qDeleteAll( findChildren<QgsActionMenu *>() );
160 if ( externalAction && !mResultsIfExternalAction )
162 return QList<QgsMapToolIdentify::IdentifyResult>();
166 return returnResults;
173 QMenu::closeEvent( e );
176 void QgsIdentifyMenu::addRasterLayer(
QgsMapLayer *layer )
178 QAction *layerAction =
nullptr;
179 QMenu *layerMenu =
nullptr;
181 QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
183 int nCustomActions = layerActions.count();
184 if ( nCustomActions )
186 separators.append( layerActions[0] );
188 if ( mShowFeatureActions )
191 if ( layerActions.count() > nCustomActions )
193 separators.append( layerActions[nCustomActions] );
198 if ( layerActions.isEmpty() )
200 layerAction =
new QAction( layer->
name(),
this );
204 layerMenu =
new QMenu( layer->
name(),
this );
205 layerAction = layerMenu->menuAction();
210 layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
211 connect( layerAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
212 addAction( layerAction );
219 QAction *identifyFeatureAction =
new QAction( mDefaultActionName, layerMenu );
220 connect( identifyFeatureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
221 identifyFeatureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
222 layerMenu->addAction( identifyFeatureAction );
225 const auto constLayerActions = layerActions;
228 QAction *action =
new QAction( mapLayerAction->icon(), mapLayerAction->text(), layerMenu );
229 action->setData( QVariant::fromValue<ActionData>( ActionData( layer,
true ) ) );
230 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
231 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
232 layerMenu->addAction( action );
233 if ( separators.contains( mapLayerAction ) )
235 layerMenu->insertSeparator( action );
240 void QgsIdentifyMenu::addVectorLayer(
QgsVectorLayer *layer,
const QList<QgsMapToolIdentify::IdentifyResult> &results,
bool singleLayer )
242 QAction *layerAction =
nullptr;
243 QMenu *layerMenu =
nullptr;
249 QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
250 QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, targets );
251 int nCustomActions = layerActions.count();
252 if ( nCustomActions )
254 separators << layerActions[0];
256 if ( mShowFeatureActions )
260 if ( layerActions.count() > nCustomActions )
262 separators << layerActions[nCustomActions];
271 bool createMenu = results.count() > 1 || !layerActions.isEmpty();
278 if ( !createMenu && mShowFeatureActions )
282 createMenu = !featureActionMenu->actions().isEmpty();
283 delete featureActionMenu;
289 exp.prepare( &context );
290 context.setFeature( results[0].mFeature );
295 QString featureTitle = exp.evaluate( &context ).toString();
296 if ( featureTitle.isEmpty() )
297 featureTitle = QString::number( results[0].mFeature.id() );
298 layerAction =
new QAction( QStringLiteral(
"%1 (%2)" ).arg( layer->
name(), featureTitle ),
this );
310 if ( results.count() > 1 )
312 layerMenu =
new QMenu( layer->
name(),
this );
317 QString featureTitle = exp.evaluate( &context ).toString();
318 if ( featureTitle.isEmpty() )
319 featureTitle = QString::number( results[0].mFeature.id() );
320 layerMenu =
new QMenu( QStringLiteral(
"%1 (%2)" ).arg( layer->
name(), featureTitle ),
this );
322 layerAction = layerMenu->menuAction();
346 layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
347 connect( layerAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
348 addAction( layerAction );
357 const auto constResults = results;
360 if ( mMaxFeatureDisplay != 0 && count > mMaxFeatureDisplay )
364 QAction *featureAction =
nullptr;
365 QMenu *featureMenu =
nullptr;
369 if ( mShowFeatureActions )
371 featureActionMenu =
new QgsActionMenu( layer, result.mFeature, QStringLiteral(
"Feature" ), layerMenu );
377 context.setFeature( result.mFeature );
378 QString featureTitle = exp.evaluate( &context ).toString();
379 if ( featureTitle.isEmpty() )
380 featureTitle = QString::number( result.mFeature.id() );
382 if ( customFeatureActions.isEmpty() && ( !featureActionMenu || featureActionMenu->actions().isEmpty() ) )
384 featureAction =
new QAction( featureTitle, layerMenu );
386 featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
387 connect( featureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
388 layerMenu->addAction( featureAction );
390 else if ( results.count() == 1 )
395 featureMenu = layerMenu;
399 featureMenu =
new QMenu( featureTitle, layerMenu );
402 featureAction = featureMenu->menuAction();
404 featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
405 connect( featureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
406 layerMenu->addAction( featureAction );
414 QAction *identifyFeatureAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), mDefaultActionName, featureMenu );
415 connect( identifyFeatureAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
416 identifyFeatureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
417 featureMenu->addAction( identifyFeatureAction );
418 featureMenu->addSeparator();
421 const auto constCustomFeatureActions = customFeatureActions;
424 QAction *action =
new QAction( mapLayerAction->icon(), mapLayerAction->text(), featureMenu );
425 action->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id(), mapLayerAction ) ) );
426 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
427 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
428 featureMenu->addAction( action );
431 if ( featureActionMenu )
433 const auto constActions = featureActionMenu->actions();
434 for ( QAction *action : constActions )
436 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
437 featureMenu->addAction( action );
445 if ( mAllowMultipleReturn && results.count() > 1 )
447 layerMenu->addSeparator();
448 QAction *allAction =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/mActionIdentify.svg" ) ), tr(
"%1 All (%2)" ).arg( mDefaultActionName ).arg( results.count() ), layerMenu );
449 allAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
450 connect( allAction, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
451 layerMenu->addAction( allAction );
455 const auto constLayerActions = layerActions;
458 QString title = mapLayerAction->text();
460 title.append( QStringLiteral(
" (%1)" ).arg( results.count() ) );
461 QAction *action =
new QAction( mapLayerAction->icon(), title, layerMenu );
462 action->setData( QVariant::fromValue<ActionData>( ActionData( layer, mapLayerAction ) ) );
463 connect( action, &QAction::hovered,
this, &QgsIdentifyMenu::handleMenuHover );
464 connect( action, &QAction::triggered,
this, &QgsIdentifyMenu::triggerMapLayerAction );
465 layerMenu->addAction( action );
466 if ( separators.contains( mapLayerAction ) )
468 layerMenu->insertSeparator( action );
473 void QgsIdentifyMenu::triggerMapLayerAction()
475 QAction *action = qobject_cast<QAction *>( sender() );
478 QVariant varData = action->data();
479 if ( !varData.isValid() || !varData.canConvert<ActionData>() )
482 ActionData actData = action->data().value<ActionData>();
484 if ( actData.mIsValid && actData.mMapLayerAction )
489 actData.mMapLayerAction->triggerForLayer( actData.mLayer );
495 QList<QgsFeature> featureList;
496 const auto results { mLayerIdResults[actData.mLayer] };
499 featureList << result.mFeature;
501 actData.mMapLayerAction->triggerForFeatures( actData.mLayer, featureList );
507 const auto results { mLayerIdResults[actData.mLayer] };
510 if ( result.mFeature.id() == actData.mFeatureId )
512 actData.mMapLayerAction->triggerForFeature( actData.mLayer, result.mFeature );
516 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve feature for action %1" ).arg( action->text() ) );
522 QList<QgsMapToolIdentify::IdentifyResult> QgsIdentifyMenu::results( QAction *action,
bool &externalAction )
524 QList<QgsMapToolIdentify::IdentifyResult> idResults = QList<QgsMapToolIdentify::IdentifyResult>();
526 externalAction =
false;
529 bool hasData =
false;
534 QVariant varData = action->data();
535 if ( !varData.isValid() )
537 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (invalid data)" ) );
541 if ( varData.canConvert<ActionData>() )
543 actData = action->data().value<ActionData>();
544 if ( actData.mIsValid )
546 externalAction = actData.mIsExternalAction;
556 externalAction =
true;
564 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (no data found)" ) );
569 if ( actData.mAllResults )
572 QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
573 while ( it.hasNext() )
576 idResults << it.value();
581 if ( !mLayerIdResults.contains( actData.mLayer ) )
583 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (layer not found)" ) );
589 return mLayerIdResults[actData.mLayer];
594 const auto results {mLayerIdResults[actData.mLayer]};
597 if ( res.mFeature.id() == actData.mFeatureId )
605 QgsDebugMsg( QStringLiteral(
"Identify menu: could not retrieve results from menu entry (don't know what happened')" ) );
609 void QgsIdentifyMenu::handleMenuHover()
616 QAction *senderAction = qobject_cast<QAction *>( sender() );
621 QList<QgsMapToolIdentify::IdentifyResult> idResults = results( senderAction, externalAction );
623 const auto constIdResults = idResults;
626 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( result.mLayer );
632 mRubberBands.append( hl );
633 connect( vl, &QObject::destroyed,
this, &QgsIdentifyMenu::layerDestroyed );
646 color.setAlpha( alpha );
652 void QgsIdentifyMenu::deleteRubberBands()
654 QList<QgsHighlight *>::const_iterator it = mRubberBands.constBegin();
655 for ( ; it != mRubberBands.constEnd(); ++it )
657 mRubberBands.clear();
660 void QgsIdentifyMenu::layerDestroyed()
662 QList<QgsHighlight *>::iterator it = mRubberBands.begin();
663 while ( it != mRubberBands.end() )
665 if ( ( *it )->layer() == sender() )
668 it = mRubberBands.erase( it );
679 mCustomActionRegistry.clear();
685 mExpressionContextScope = scope;
690 return mExpressionContextScope;