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