QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsidentifymenu.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsidentifymenu.cpp - menu to be used in identify map tool
3  ---------------------
4  begin : August 2014
5  copyright : (C) 2014 by Denis Rouzaud
6  email : [email protected]
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QMouseEvent>
17 
18 #include "qgsidentifymenu.h"
19 #include "qgsapplication.h"
20 #include "qgsactionmanager.h"
21 #include "qgshighlight.h"
22 #include "qgsmapcanvas.h"
23 #include "qgsactionmenu.h"
24 #include "qgsvectorlayer.h"
25 #include "qgslogger.h"
26 #include "qgssettings.h"
27 #include "qgsgui.h"
29 
30 //TODO 4.0 add explicitly qobject parent to constructor
32  : QMenu( canvas )
33  , mCanvas( canvas )
34  , mAllowMultipleReturn( true )
35  , mExecWithSingleResult( false )
36  , mShowFeatureActions( false )
37  , mResultsIfExternalAction( false )
38  , mMaxLayerDisplay( 10 )
39  , mMaxFeatureDisplay( 10 )
40  , mDefaultActionName( tr( "Identify" ) )
41 {
42 }
43 
45 {
46  deleteRubberBands();
47 }
48 
49 
50 void QgsIdentifyMenu::setMaxLayerDisplay( int maxLayerDisplay )
51 {
52  if ( maxLayerDisplay < 0 )
53  {
54  QgsDebugMsg( QStringLiteral( "invalid value for number of layers displayed." ) );
55  }
56  mMaxLayerDisplay = maxLayerDisplay;
57 }
58 
59 
60 void QgsIdentifyMenu::setMaxFeatureDisplay( int maxFeatureDisplay )
61 {
62  if ( maxFeatureDisplay < 0 )
63  {
64  QgsDebugMsg( QStringLiteral( "invalid value for number of layers displayed." ) );
65  }
66  mMaxFeatureDisplay = maxFeatureDisplay;
67 }
68 
69 
70 QList<QgsMapToolIdentify::IdentifyResult> QgsIdentifyMenu::exec( const QList<QgsMapToolIdentify::IdentifyResult> &idResults, QPoint pos )
71 {
72  clear();
73  mLayerIdResults.clear();
74 
75  QList<QgsMapToolIdentify::IdentifyResult> returnResults = QList<QgsMapToolIdentify::IdentifyResult>();
76 
77  if ( idResults.isEmpty() )
78  {
79  return returnResults;
80  }
81  if ( idResults.count() == 1 && !mExecWithSingleResult )
82  {
83  returnResults << idResults[0];
84  return returnResults;
85  }
86 
87  // sort results by layer
88  const auto constIdResults = idResults;
89  for ( const QgsMapToolIdentify::IdentifyResult &result : constIdResults )
90  {
91  QgsMapLayer *layer = result.mLayer;
92  if ( mLayerIdResults.contains( layer ) )
93  {
94  mLayerIdResults[layer].append( result );
95  }
96  else
97  {
98  mLayerIdResults.insert( layer, QList<QgsMapToolIdentify::IdentifyResult>() << result );
99  }
100  }
101 
102  // add results to the menu
103  bool singleLayer = mLayerIdResults.count() == 1;
104  int count = 0;
105  QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
106  while ( it.hasNext() )
107  {
108  if ( mMaxLayerDisplay != 0 && count > mMaxLayerDisplay )
109  break;
110  ++count;
111  it.next();
112  QgsMapLayer *layer = it.key();
113  switch ( layer->type() )
114  {
116  {
117  addRasterLayer( layer );
118  break;
119  }
121  {
122  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
123  if ( !vl )
124  continue;
125  addVectorLayer( vl, it.value(), singleLayer );
126  break;
127  }
128 
130  // TODO: add support
131  break;
132 
135  break;
136  }
137  }
138 
139  // add an "identify all" action on the top level
140  if ( !singleLayer && mAllowMultipleReturn && idResults.count() > 1 )
141  {
142  addSeparator();
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 );
147  }
148 
149  // exec
150  QAction *selectedAction = QMenu::exec( pos );
151  bool externalAction;
152  returnResults = results( selectedAction, externalAction );
153 
154  // delete actions
155  clear();
156  // also remove the QgsActionMenu
157  qDeleteAll( findChildren<QgsActionMenu *>() );
158 
159  if ( externalAction && !mResultsIfExternalAction )
160  {
161  return QList<QgsMapToolIdentify::IdentifyResult>();
162  }
163  else
164  {
165  return returnResults;
166  }
167 }
168 
169 void QgsIdentifyMenu::closeEvent( QCloseEvent *e )
170 {
171  deleteRubberBands();
172  QMenu::closeEvent( e );
173 }
174 
175 void QgsIdentifyMenu::addRasterLayer( QgsMapLayer *layer )
176 {
177  QAction *layerAction = nullptr;
178  QMenu *layerMenu = nullptr;
179 
180  QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
181  QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, QgsMapLayerAction::Layer );
182  int nCustomActions = layerActions.count();
183  if ( nCustomActions )
184  {
185  separators.append( layerActions[0] );
186  }
187  if ( mShowFeatureActions )
188  {
189  layerActions.append( QgsGui::mapLayerActionRegistry()->mapLayerActions( layer, QgsMapLayerAction::Layer ) );
190  if ( layerActions.count() > nCustomActions )
191  {
192  separators.append( layerActions[nCustomActions] );
193  }
194  }
195 
196  // use a menu only if actions will be listed
197  if ( layerActions.isEmpty() )
198  {
199  layerAction = new QAction( layer->name(), this );
200  }
201  else
202  {
203  layerMenu = new QMenu( layer->name(), this );
204  layerAction = layerMenu->menuAction();
205  }
206 
207  // add layer action to the top menu
208  layerAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconRasterLayer.svg" ) ) );
209  layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
210  connect( layerAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
211  addAction( layerAction );
212 
213  // no need to go further if there is no menu
214  if ( !layerMenu )
215  return;
216 
217  // add default identify action
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 );
222 
223  // add custom/layer actions
224  const auto constLayerActions = layerActions;
225  for ( QgsMapLayerAction *mapLayerAction : constLayerActions )
226  {
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 ) )
233  {
234  layerMenu->insertSeparator( action );
235  }
236  }
237 }
238 
239 void QgsIdentifyMenu::addVectorLayer( QgsVectorLayer *layer, const QList<QgsMapToolIdentify::IdentifyResult> &results, bool singleLayer )
240 {
241  QAction *layerAction = nullptr;
242  QMenu *layerMenu = nullptr;
243 
244  // do not add actions with MultipleFeatures as target if only 1 feature is found for this layer
245  // targets defines which actions will be shown
246  QgsMapLayerAction::Targets targets = results.count() > 1 ? QgsMapLayerAction::Layer | QgsMapLayerAction::MultipleFeatures : QgsMapLayerAction::Layer;
247 
248  QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
249  QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, targets );
250  int nCustomActions = layerActions.count();
251  if ( nCustomActions )
252  {
253  separators << layerActions[0];
254  }
255  if ( mShowFeatureActions )
256  {
257  layerActions << QgsGui::mapLayerActionRegistry()->mapLayerActions( layer, targets );
258 
259  if ( layerActions.count() > nCustomActions )
260  {
261  separators << layerActions[nCustomActions];
262  }
263  }
264 
265  // determines if a menu should be created or not. Following cases:
266  // 1. only one result and no feature action to be shown => just create an action
267  // 2. several features (2a) or display feature actions (2b) => create a menu
268  // 3. case 2 but only one layer (singeLayer) => do not create a menu, but give the top menu instead
269 
270  bool createMenu = results.count() > 1 || !layerActions.isEmpty();
271 
272  // case 2b: still create a menu for layer, if there is a sub-level for features
273  // i.e custom actions or map layer actions at feature level
274  if ( !createMenu )
275  {
276  createMenu = !mCustomActionRegistry.mapLayerActions( layer, QgsMapLayerAction::SingleFeature ).isEmpty();
277  if ( !createMenu && mShowFeatureActions )
278  {
279  QgsActionMenu *featureActionMenu = new QgsActionMenu( layer, results[0].mFeature, QStringLiteral( "Feature" ), this );
280  featureActionMenu->setMode( QgsAttributeEditorContext::IdentifyMode );
281  createMenu = !featureActionMenu->actions().isEmpty();
282  delete featureActionMenu;
283  }
284  }
285 
287  QgsExpression exp( layer->displayExpression() );
288  exp.prepare( &context );
289  context.setFeature( results[0].mFeature );
290  // use a menu only if actions will be listed
291  if ( !createMenu )
292  {
293  // case 1
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 );
298  }
299  else
300  {
301  if ( singleLayer )
302  {
303  // case 3
304  layerMenu = this;
305  }
306  else
307  {
308  // case 2a
309  if ( results.count() > 1 )
310  {
311  layerMenu = new QMenu( layer->name(), this );
312  }
313  // case 2b
314  else
315  {
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 );
320  }
321  layerAction = layerMenu->menuAction();
322  }
323  }
324 
325  // case 1 or 2
326  if ( layerAction )
327  {
328  // icons
329  switch ( layer->geometryType() )
330  {
332  layerAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointLayer.svg" ) ) );
333  break;
335  layerAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) ) );
336  break;
338  layerAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconPolygonLayer.svg" ) ) );
339  break;
340  default:
341  break;
342  }
343 
344  // add layer action to the top menu
345  layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
346  connect( layerAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
347  addAction( layerAction );
348  }
349 
350  // case 1. no need to go further
351  if ( !layerMenu )
352  return;
353 
354  // add results to the menu
355  int count = 0;
356  const auto constResults = results;
357  for ( const QgsMapToolIdentify::IdentifyResult &result : constResults )
358  {
359  if ( mMaxFeatureDisplay != 0 && count > mMaxFeatureDisplay )
360  break;
361  ++count;
362 
363  QAction *featureAction = nullptr;
364  QMenu *featureMenu = nullptr;
365  QgsActionMenu *featureActionMenu = nullptr;
366 
367  QList<QgsMapLayerAction *> customFeatureActions = mCustomActionRegistry.mapLayerActions( layer, QgsMapLayerAction::SingleFeature );
368  if ( mShowFeatureActions )
369  {
370  featureActionMenu = new QgsActionMenu( layer, result.mFeature, QStringLiteral( "Feature" ), layerMenu );
371  featureActionMenu->setMode( QgsAttributeEditorContext::IdentifyMode );
372  featureActionMenu->setExpressionContextScope( mExpressionContextScope );
373  }
374 
375  // feature title
376  context.setFeature( result.mFeature );
377  QString featureTitle = exp.evaluate( &context ).toString();
378  if ( featureTitle.isEmpty() )
379  featureTitle = QStringLiteral( "%1" ).arg( result.mFeature.id() );
380 
381  if ( customFeatureActions.isEmpty() && ( !featureActionMenu || featureActionMenu->actions().isEmpty() ) )
382  {
383  featureAction = new QAction( featureTitle, layerMenu );
384  // add the feature action (or menu) to the layer menu
385  featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
386  connect( featureAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
387  layerMenu->addAction( featureAction );
388  }
389  else if ( results.count() == 1 )
390  {
391  // if we are here with only one results, this means there is a sub-feature level (for actions)
392  // => skip the feature level since there would be only a single entry
393  // => give the layer menu as pointer instead of a new feature menu
394  featureMenu = layerMenu;
395  }
396  else
397  {
398  featureMenu = new QMenu( featureTitle, layerMenu );
399 
400  // get the action from the menu
401  featureAction = featureMenu->menuAction();
402  // add the feature action (or menu) to the layer menu
403  featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
404  connect( featureAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
405  layerMenu->addAction( featureAction );
406  }
407 
408  // if no feature menu, no need to go further
409  if ( !featureMenu )
410  continue;
411 
412  // add default identify action
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();
418 
419  // custom action at feature level
420  const auto constCustomFeatureActions = customFeatureActions;
421  for ( QgsMapLayerAction *mapLayerAction : constCustomFeatureActions )
422  {
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 );
428  }
429  // use QgsActionMenu for feature actions
430  if ( featureActionMenu )
431  {
432  const auto constActions = featureActionMenu->actions();
433  for ( QAction *action : constActions )
434  {
435  connect( action, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
436  featureMenu->addAction( action );
437  }
438  }
439  }
440 
441  // back to layer level
442 
443  // identify all action
444  if ( mAllowMultipleReturn && results.count() > 1 )
445  {
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 );
451  }
452 
453  // add custom/layer actions
454  const auto constLayerActions = layerActions;
455  for ( QgsMapLayerAction *mapLayerAction : constLayerActions )
456  {
457  QString title = mapLayerAction->text();
458  if ( mapLayerAction->targets().testFlag( QgsMapLayerAction::MultipleFeatures ) )
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 ) )
466  {
467  layerMenu->insertSeparator( action );
468  }
469  }
470 }
471 
472 void QgsIdentifyMenu::triggerMapLayerAction()
473 {
474  QAction *action = qobject_cast<QAction *>( sender() );
475  if ( !action )
476  return;
477  QVariant varData = action->data();
478  if ( !varData.isValid() || !varData.canConvert<ActionData>() )
479  return;
480 
481  ActionData actData = action->data().value<ActionData>();
482 
483  if ( actData.mIsValid && actData.mMapLayerAction )
484  {
485  // layer
486  if ( actData.mMapLayerAction->targets().testFlag( QgsMapLayerAction::Layer ) )
487  {
488  actData.mMapLayerAction->triggerForLayer( actData.mLayer );
489  }
490 
491  // multiples features
492  if ( actData.mMapLayerAction->targets().testFlag( QgsMapLayerAction::MultipleFeatures ) )
493  {
494  QList<QgsFeature> featureList;
495  const auto results { mLayerIdResults[actData.mLayer] };
496  for ( const QgsMapToolIdentify::IdentifyResult &result : results )
497  {
498  featureList << result.mFeature;
499  }
500  actData.mMapLayerAction->triggerForFeatures( actData.mLayer, featureList );
501  }
502 
503  // single feature
504  if ( actData.mMapLayerAction->targets().testFlag( QgsMapLayerAction::SingleFeature ) )
505  {
506  const auto results { mLayerIdResults[actData.mLayer] };
507  for ( const QgsMapToolIdentify::IdentifyResult &result : results )
508  {
509  if ( result.mFeature.id() == actData.mFeatureId )
510  {
511  actData.mMapLayerAction->triggerForFeature( actData.mLayer, result.mFeature );
512  return;
513  }
514  }
515  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve feature for action %1" ).arg( action->text() ) );
516  }
517  }
518 }
519 
520 
521 QList<QgsMapToolIdentify::IdentifyResult> QgsIdentifyMenu::results( QAction *action, bool &externalAction )
522 {
523  QList<QgsMapToolIdentify::IdentifyResult> idResults = QList<QgsMapToolIdentify::IdentifyResult>();
524 
525  externalAction = false;
526 
527  ActionData actData;
528  bool hasData = false;
529 
530  if ( !action )
531  return idResults;
532 
533  QVariant varData = action->data();
534  if ( !varData.isValid() )
535  {
536  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve results from menu entry (invalid data)" ) );
537  return idResults;
538  }
539 
540  if ( varData.canConvert<ActionData>() )
541  {
542  actData = action->data().value<ActionData>();
543  if ( actData.mIsValid )
544  {
545  externalAction = actData.mIsExternalAction;
546  hasData = true;
547  }
548  }
549 
550  if ( !hasData && varData.canConvert<QgsActionMenu::ActionData>() )
551  {
552  QgsActionMenu::ActionData dataSrc = action->data().value<QgsActionMenu::ActionData>();
553  if ( dataSrc.actionType != QgsActionMenu::Invalid )
554  {
555  externalAction = true;
556  actData = ActionData( dataSrc.mapLayer, dataSrc.featureId );
557  hasData = true;
558  }
559  }
560 
561  if ( !hasData )
562  {
563  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve results from menu entry (no data found)" ) );
564  return idResults;
565  }
566 
567  // return all results
568  if ( actData.mAllResults )
569  {
570  // this means "All" action was triggered
571  QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
572  while ( it.hasNext() )
573  {
574  it.next();
575  idResults << it.value();
576  }
577  return idResults;
578  }
579 
580  if ( !mLayerIdResults.contains( actData.mLayer ) )
581  {
582  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve results from menu entry (layer not found)" ) );
583  return idResults;
584  }
585 
586  if ( actData.mLevel == LayerLevel )
587  {
588  return mLayerIdResults[actData.mLayer];
589  }
590 
591  if ( actData.mLevel == FeatureLevel )
592  {
593  const auto results {mLayerIdResults[actData.mLayer]};
594  for ( const QgsMapToolIdentify::IdentifyResult &res : results )
595  {
596  if ( res.mFeature.id() == actData.mFeatureId )
597  {
598  idResults << res;
599  return idResults;
600  }
601  }
602  }
603 
604  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve results from menu entry (don't know what happened')" ) );
605  return idResults;
606 }
607 
608 void QgsIdentifyMenu::handleMenuHover()
609 {
610  if ( !mCanvas )
611  return;
612 
613  deleteRubberBands();
614 
615  QAction *senderAction = qobject_cast<QAction *>( sender() );
616  if ( !senderAction )
617  return;
618 
619  bool externalAction;
620  QList<QgsMapToolIdentify::IdentifyResult> idResults = results( senderAction, externalAction );
621 
622  const auto constIdResults = idResults;
623  for ( const QgsMapToolIdentify::IdentifyResult &result : constIdResults )
624  {
625  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( result.mLayer );
626  if ( !vl )
627  continue;
628 
629  QgsHighlight *hl = new QgsHighlight( mCanvas, result.mFeature.geometry(), vl );
630  styleHighlight( hl );
631  mRubberBands.append( hl );
632  connect( vl, &QObject::destroyed, this, &QgsIdentifyMenu::layerDestroyed );
633  }
634 }
635 
637 {
638  QgsSettings settings;
639  QColor color = QColor( settings.value( QStringLiteral( "Map/highlight/color" ), Qgis::DEFAULT_HIGHLIGHT_COLOR.name() ).toString() );
640  int alpha = settings.value( QStringLiteral( "Map/highlight/colorAlpha" ), Qgis::DEFAULT_HIGHLIGHT_COLOR.alpha() ).toInt();
641  double buffer = settings.value( QStringLiteral( "Map/highlight/buffer" ), Qgis::DEFAULT_HIGHLIGHT_BUFFER_MM ).toDouble();
642  double minWidth = settings.value( QStringLiteral( "Map/highlight/minWidth" ), Qgis::DEFAULT_HIGHLIGHT_MIN_WIDTH_MM ).toDouble();
643 
644  highlight->setColor( color ); // sets also fill with default alpha
645  color.setAlpha( alpha );
646  highlight->setFillColor( color ); // sets fill with alpha
647  highlight->setBuffer( buffer );
648  highlight->setMinWidth( minWidth );
649 }
650 
651 void QgsIdentifyMenu::deleteRubberBands()
652 {
653  QList<QgsHighlight *>::const_iterator it = mRubberBands.constBegin();
654  for ( ; it != mRubberBands.constEnd(); ++it )
655  delete *it;
656  mRubberBands.clear();
657 }
658 
659 void QgsIdentifyMenu::layerDestroyed()
660 {
661  QList<QgsHighlight *>::iterator it = mRubberBands.begin();
662  while ( it != mRubberBands.end() )
663  {
664  if ( ( *it )->layer() == sender() )
665  {
666  delete *it;
667  it = mRubberBands.erase( it );
668  }
669  else
670  {
671  ++it;
672  }
673  }
674 }
675 
677 {
678  mCustomActionRegistry.clear();
679 
680 }
681 
683 {
684  mExpressionContextScope = scope;
685 }
686 
688 {
689  return mExpressionContextScope;
690 }
QgsHighlight::setColor
void setColor(const QColor &color)
Set line/stroke to color, polygon fill to color with alpha = 63.
Definition: qgshighlight.cpp:94
QgsActionMenu::Invalid
@ Invalid
Invalid.
Definition: qgsactionmenu.h:44
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:369
QgsIdentifyMenu::expressionContextScope
QgsExpressionContextScope expressionContextScope() const
Returns an expression context scope used to resolve underlying actions.
Definition: qgsidentifymenu.cpp:687
qgsexpressioncontextutils.h
QgsIdentifyMenu::removeCustomActions
void removeCustomActions()
remove all custom actions from the menu to be built
Definition: qgsidentifymenu.cpp:676
Qgis::DEFAULT_HIGHLIGHT_COLOR
static const QColor DEFAULT_HIGHLIGHT_COLOR
Default highlight color.
Definition: qgis.h:161
QgsMapLayerAction
Definition: qgsmaplayeractionregistry.h:34
QgsIdentifyMenu::QgsIdentifyMenu
QgsIdentifyMenu(QgsMapCanvas *canvas)
QgsIdentifyMenu is a menu to be used to choose within a list of QgsMapTool::IdentifyReults.
Definition: qgsidentifymenu.cpp:31
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
QgsMapLayerAction::SingleFeature
@ SingleFeature
Definition: qgsmaplayeractionregistry.h:42
QgsActionMenu::setMode
void setMode(QgsAttributeEditorContext::Mode mode)
Change the mode of the actions.
Definition: qgsactionmenu.cpp:70
Qgis::DEFAULT_HIGHLIGHT_MIN_WIDTH_MM
static const double DEFAULT_HIGHLIGHT_MIN_WIDTH_MM
Default highlight line/stroke minimum width in mm.
Definition: qgis.h:173
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsMapLayerType::MeshLayer
@ MeshLayer
Added in 3.2.
qgsmapcanvas.h
QgsMapLayerType::VectorLayer
@ VectorLayer
QgsGui::mapLayerActionRegistry
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition: qgsgui.cpp:93
QgsActionMenu::ActionData::mapLayer
QgsMapLayer * mapLayer
Definition: qgsactionmenu.h:62
qgsgui.h
QgsMapLayerAction::MultipleFeatures
@ MultipleFeatures
Definition: qgsmaplayeractionregistry.h:43
QgsMapCanvas
Definition: qgsmapcanvas.h:83
QgsActionMenu::setExpressionContextScope
void setExpressionContextScope(const QgsExpressionContextScope &scope)
Sets an expression context scope used to resolve underlying actions.
Definition: qgsactionmenu.cpp:198
QgsExpressionContextUtils::globalProjectLayerScopes
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Definition: qgsexpressioncontextutils.cpp:306
QgsSettings
Definition: qgssettings.h:61
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsIdentifyMenu::maxLayerDisplay
int maxLayerDisplay()
Definition: qgsidentifymenu.h:154
QgsIdentifyMenu::exec
QList< QgsMapToolIdentify::IdentifyResult > exec(const QList< QgsMapToolIdentify::IdentifyResult > &idResults, QPoint pos)
exec
Definition: qgsidentifymenu.cpp:70
qgsidentifymenu.h
QgsHighlight::setBuffer
void setBuffer(double buffer)
Set line / stroke buffer in millimeters.
Definition: qgshighlight.h:148
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:143
QgsIdentifyMenu::setMaxLayerDisplay
void setMaxLayerDisplay(int maxLayerDisplay)
Defines the maximum number of layers displayed in the menu (default is 10).
Definition: qgsidentifymenu.cpp:50
QgsActionMenu::ActionData
Definition: qgsactionmenu.h:49
QgsHighlight
Definition: qgshighlight.h:57
qgsapplication.h
QgsIdentifyMenu::FeatureLevel
@ FeatureLevel
Definition: qgsidentifymenu.h:83
QgsHighlight::setMinWidth
void setMinWidth(double width)
Set minimum line / stroke width in millimeters.
Definition: qgshighlight.h:155
qgsactionmanager.h
QgsMapLayerAction::Layer
@ Layer
Definition: qgsmaplayeractionregistry.h:41
QgsMapLayerType::RasterLayer
@ RasterLayer
QgsIdentifyMenu::~QgsIdentifyMenu
~QgsIdentifyMenu() override
Definition: qgsidentifymenu.cpp:44
QgsMapLayerActionRegistry::mapLayerActions
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
Definition: qgsmaplayeractionregistry.cpp:125
QgsActionMenu
Definition: qgsactionmenu.h:37
QgsIdentifyMenu::setMaxFeatureDisplay
void setMaxFeatureDisplay(int maxFeatureDisplay)
Defines the maximum number of features displayed in the menu for vector layers (default is 10).
Definition: qgsidentifymenu.cpp:60
QgsIdentifyMenu::setExpressionContextScope
void setExpressionContextScope(const QgsExpressionContextScope &scope)
Sets an expression context scope used to resolve underlying actions.
Definition: qgsidentifymenu.cpp:682
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:111
QgsHighlight::setFillColor
void setFillColor(const QColor &fillColor)
Fill color for the highlight.
Definition: qgshighlight.cpp:103
qgsvectorlayer.h
qgsactionmenu.h
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:142
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:141
qgshighlight.h
Qgis::DEFAULT_HIGHLIGHT_BUFFER_MM
static const double DEFAULT_HIGHLIGHT_BUFFER_MM
Default highlight buffer in mm.
Definition: qgis.h:167
QgsVectorLayer
Definition: qgsvectorlayer.h:385
QgsMapLayer
Definition: qgsmaplayer.h:81
qgssettings.h
QgsIdentifyMenu::closeEvent
void closeEvent(QCloseEvent *e) override
Definition: qgsidentifymenu.cpp:169
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Added in 3.14.
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:85
QgsIdentifyMenu::LayerLevel
@ LayerLevel
Definition: qgsidentifymenu.h:82
QgsIdentifyMenu::ActionData
Definition: qgsidentifymenu.h:73
qgslogger.h
QgsExpression
Definition: qgsexpression.h:113
QgsVectorLayer::displayExpression
QString displayExpression
Definition: qgsvectorlayer.h:390
QgsVectorLayer::geometryType
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Definition: qgsvectorlayer.cpp:659
QgsIdentifyMenu::styleHighlight
static void styleHighlight(QgsHighlight *highlight)
Applies style from the settings to the highlight.
Definition: qgsidentifymenu.cpp:636
QgsMapLayer::type
QgsMapLayerType type() const
Returns the type of the layer.
Definition: qgsmaplayer.cpp:129
QgsMapLayerType::PluginLayer
@ PluginLayer
QgsActionMenu::ActionData::featureId
QgsFeatureId featureId
Definition: qgsactionmenu.h:61
QgsAttributeEditorContext::IdentifyMode
@ IdentifyMode
Identify the feature.
Definition: qgsattributeeditorcontext.h:55
QgsMapToolIdentify::IdentifyResult
Definition: qgsmaptoolidentify.h:74
QgsIdentifyMenu::maxFeatureDisplay
int maxFeatureDisplay()
Definition: qgsidentifymenu.h:161
QgsActionMenu::ActionData::actionType
QgsActionMenu::ActionType actionType
Definition: qgsactionmenu.h:59