QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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  const 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 
139  break;
140  }
141  }
142 
143  // add an "identify all" action on the top level
144  if ( !singleLayer && mAllowMultipleReturn && idResults.count() > 1 )
145  {
146  addSeparator();
147  QAction *allAction = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionIdentify.svg" ) ), tr( "%1 All (%2)" ).arg( mDefaultActionName ).arg( idResults.count() ), this );
148  allAction->setData( QVariant::fromValue<ActionData>( ActionData( nullptr ) ) );
149  connect( allAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
150  addAction( allAction );
151  }
152 
153  // exec
154  QAction *selectedAction = QMenu::exec( pos );
155  bool externalAction;
156  returnResults = results( selectedAction, externalAction );
157 
158  // delete actions
159  clear();
160  // also remove the QgsActionMenu
161  qDeleteAll( findChildren<QgsActionMenu *>() );
162 
163  if ( externalAction && !mResultsIfExternalAction )
164  {
165  return QList<QgsMapToolIdentify::IdentifyResult>();
166  }
167  else
168  {
169  return returnResults;
170  }
171 }
172 
173 void QgsIdentifyMenu::closeEvent( QCloseEvent *e )
174 {
175  deleteRubberBands();
176  QMenu::closeEvent( e );
177 }
178 
179 void QgsIdentifyMenu::addRasterLayer( QgsMapLayer *layer )
180 {
181  QAction *layerAction = nullptr;
182  QMenu *layerMenu = nullptr;
183 
184  QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
185  QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, QgsMapLayerAction::Layer );
186  const int nCustomActions = layerActions.count();
187  if ( nCustomActions )
188  {
189  separators.append( layerActions[0] );
190  }
191  if ( mShowFeatureActions )
192  {
193  layerActions.append( QgsGui::mapLayerActionRegistry()->mapLayerActions( layer, QgsMapLayerAction::Layer ) );
194  if ( layerActions.count() > nCustomActions )
195  {
196  separators.append( layerActions[nCustomActions] );
197  }
198  }
199 
200  // use a menu only if actions will be listed
201  if ( layerActions.isEmpty() )
202  {
203  layerAction = new QAction( layer->name(), this );
204  }
205  else
206  {
207  layerMenu = new QMenu( layer->name(), this );
208  layerAction = layerMenu->menuAction();
209  }
210 
211  // add layer action to the top menu
212  layerAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconRasterLayer.svg" ) ) );
213  layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
214  connect( layerAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
215  addAction( layerAction );
216 
217  // no need to go further if there is no menu
218  if ( !layerMenu )
219  return;
220 
221  // add default identify action
222  QAction *identifyFeatureAction = new QAction( mDefaultActionName, layerMenu );
223  connect( identifyFeatureAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
224  identifyFeatureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
225  layerMenu->addAction( identifyFeatureAction );
226 
227  // add custom/layer actions
228  const auto constLayerActions = layerActions;
229  for ( QgsMapLayerAction *mapLayerAction : constLayerActions )
230  {
231  QAction *action = new QAction( mapLayerAction->icon(), mapLayerAction->text(), layerMenu );
232  action->setData( QVariant::fromValue<ActionData>( ActionData( layer, true ) ) );
233  connect( action, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
234  connect( action, &QAction::triggered, this, &QgsIdentifyMenu::triggerMapLayerAction );
235  layerMenu->addAction( action );
236  if ( separators.contains( mapLayerAction ) )
237  {
238  layerMenu->insertSeparator( action );
239  }
240  }
241 }
242 
243 void QgsIdentifyMenu::addVectorLayer( QgsVectorLayer *layer, const QList<QgsMapToolIdentify::IdentifyResult> &results, bool singleLayer )
244 {
245  QAction *layerAction = nullptr;
246  QMenu *layerMenu = nullptr;
247 
248  // do not add actions with MultipleFeatures as target if only 1 feature is found for this layer
249  // targets defines which actions will be shown
250  const QgsMapLayerAction::Targets targets = results.count() > 1 ? QgsMapLayerAction::Layer | QgsMapLayerAction::MultipleFeatures : QgsMapLayerAction::Layer;
251 
252  QList<QgsMapLayerAction *> separators = QList<QgsMapLayerAction *>();
253  QList<QgsMapLayerAction *> layerActions = mCustomActionRegistry.mapLayerActions( layer, targets );
254  const int nCustomActions = layerActions.count();
255  if ( nCustomActions )
256  {
257  separators << layerActions[0];
258  }
259  if ( mShowFeatureActions )
260  {
261  layerActions << QgsGui::mapLayerActionRegistry()->mapLayerActions( layer, targets );
262 
263  if ( layerActions.count() > nCustomActions )
264  {
265  separators << layerActions[nCustomActions];
266  }
267  }
268 
269  // determines if a menu should be created or not. Following cases:
270  // 1. only one result and no feature action to be shown => just create an action
271  // 2. several features (2a) or display feature actions (2b) => create a menu
272  // 3. case 2 but only one layer (singeLayer) => do not create a menu, but give the top menu instead
273 
274  bool createMenu = results.count() > 1 || !layerActions.isEmpty();
275 
276  // case 2b: still create a menu for layer, if there is a sub-level for features
277  // i.e custom actions or map layer actions at feature level
278  if ( !createMenu )
279  {
280  createMenu = !mCustomActionRegistry.mapLayerActions( layer, QgsMapLayerAction::SingleFeature ).isEmpty();
281  if ( !createMenu && mShowFeatureActions )
282  {
283  QgsActionMenu *featureActionMenu = new QgsActionMenu( layer, results[0].mFeature, QStringLiteral( "Feature" ), this );
284  featureActionMenu->setMode( QgsAttributeEditorContext::IdentifyMode );
285  createMenu = !featureActionMenu->actions().isEmpty();
286  delete featureActionMenu;
287  }
288  }
289 
291  QgsExpression exp( layer->displayExpression() );
292  exp.prepare( &context );
293  context.setFeature( results[0].mFeature );
294  // use a menu only if actions will be listed
295  if ( !createMenu )
296  {
297  // case 1
298  QString featureTitle = exp.evaluate( &context ).toString();
299  if ( featureTitle.isEmpty() )
300  featureTitle = QString::number( results[0].mFeature.id() );
301  layerAction = new QAction( QStringLiteral( "%1 (%2)" ).arg( layer->name(), featureTitle ), this );
302  }
303  else
304  {
305  if ( singleLayer )
306  {
307  // case 3
308  layerMenu = this;
309  }
310  else
311  {
312  // case 2a
313  if ( results.count() > 1 )
314  {
315  layerMenu = new QMenu( layer->name(), this );
316  }
317  // case 2b
318  else
319  {
320  QString featureTitle = exp.evaluate( &context ).toString();
321  if ( featureTitle.isEmpty() )
322  featureTitle = QString::number( results[0].mFeature.id() );
323  layerMenu = new QMenu( QStringLiteral( "%1 (%2)" ).arg( layer->name(), featureTitle ), this );
324  }
325  layerAction = layerMenu->menuAction();
326  }
327  }
328 
329  // case 1 or 2
330  if ( layerAction )
331  {
332  layerAction->setIcon( QgsIconUtils::iconForWkbType( layer->wkbType() ) );
333 
334  // add layer action to the top menu
335  layerAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
336  connect( layerAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
337  addAction( layerAction );
338  }
339 
340  // case 1. no need to go further
341  if ( !layerMenu )
342  return;
343 
344  // add results to the menu
345  int count = 0;
346  const auto constResults = results;
347  for ( const QgsMapToolIdentify::IdentifyResult &result : constResults )
348  {
349  if ( mMaxFeatureDisplay != 0 && count > mMaxFeatureDisplay )
350  break;
351  ++count;
352 
353  QAction *featureAction = nullptr;
354  QMenu *featureMenu = nullptr;
355  QgsActionMenu *featureActionMenu = nullptr;
356 
357  const QList<QgsMapLayerAction *> customFeatureActions = mCustomActionRegistry.mapLayerActions( layer, QgsMapLayerAction::SingleFeature );
358  if ( mShowFeatureActions )
359  {
360  featureActionMenu = new QgsActionMenu( layer, result.mFeature, QStringLiteral( "Feature" ), layerMenu );
361  featureActionMenu->setMode( QgsAttributeEditorContext::IdentifyMode );
362  featureActionMenu->setExpressionContextScope( mExpressionContextScope );
363  }
364 
365  // feature title
366  context.setFeature( result.mFeature );
367  QString featureTitle = exp.evaluate( &context ).toString();
368  if ( featureTitle.isEmpty() )
369  featureTitle = QString::number( result.mFeature.id() );
370 
371  if ( customFeatureActions.isEmpty() && ( !featureActionMenu || featureActionMenu->actions().isEmpty() ) )
372  {
373  featureAction = new QAction( featureTitle, layerMenu );
374  // add the feature action (or menu) to the layer menu
375  featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
376  connect( featureAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
377  layerMenu->addAction( featureAction );
378  }
379  else if ( results.count() == 1 )
380  {
381  // if we are here with only one results, this means there is a sub-feature level (for actions)
382  // => skip the feature level since there would be only a single entry
383  // => give the layer menu as pointer instead of a new feature menu
384  featureMenu = layerMenu;
385  }
386  else
387  {
388  featureMenu = new QMenu( featureTitle, layerMenu );
389 
390  // get the action from the menu
391  featureAction = featureMenu->menuAction();
392  // add the feature action (or menu) to the layer menu
393  featureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
394  connect( featureAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
395  layerMenu->addAction( featureAction );
396  }
397 
398  // if no feature menu, no need to go further
399  if ( !featureMenu )
400  continue;
401 
402  // add default identify action
403  QAction *identifyFeatureAction = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionIdentify.svg" ) ), mDefaultActionName, featureMenu );
404  connect( identifyFeatureAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
405  identifyFeatureAction->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id() ) ) );
406  featureMenu->addAction( identifyFeatureAction );
407  featureMenu->addSeparator();
408 
409  // custom action at feature level
410  const auto constCustomFeatureActions = customFeatureActions;
411  for ( QgsMapLayerAction *mapLayerAction : constCustomFeatureActions )
412  {
413  QAction *action = new QAction( mapLayerAction->icon(), mapLayerAction->text(), featureMenu );
414  action->setData( QVariant::fromValue<ActionData>( ActionData( layer, result.mFeature.id(), mapLayerAction ) ) );
415  connect( action, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
416  connect( action, &QAction::triggered, this, &QgsIdentifyMenu::triggerMapLayerAction );
417  featureMenu->addAction( action );
418  }
419  // use QgsActionMenu for feature actions
420  if ( featureActionMenu )
421  {
422  const auto constActions = featureActionMenu->actions();
423  for ( QAction *action : constActions )
424  {
425  connect( action, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
426  featureMenu->addAction( action );
427  }
428  }
429  }
430 
431  // back to layer level
432 
433  // identify all action
434  if ( mAllowMultipleReturn && results.count() > 1 )
435  {
436  layerMenu->addSeparator();
437  QAction *allAction = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionIdentify.svg" ) ), tr( "%1 All (%2)" ).arg( mDefaultActionName ).arg( results.count() ), layerMenu );
438  allAction->setData( QVariant::fromValue<ActionData>( ActionData( layer ) ) );
439  connect( allAction, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
440  layerMenu->addAction( allAction );
441  }
442 
443  // add custom/layer actions
444  const auto constLayerActions = layerActions;
445  for ( QgsMapLayerAction *mapLayerAction : constLayerActions )
446  {
447  QString title = mapLayerAction->text();
448  if ( mapLayerAction->targets().testFlag( QgsMapLayerAction::MultipleFeatures ) )
449  title.append( QStringLiteral( " (%1)" ).arg( results.count() ) );
450  QAction *action = new QAction( mapLayerAction->icon(), title, layerMenu );
451  action->setData( QVariant::fromValue<ActionData>( ActionData( layer, mapLayerAction ) ) );
452  connect( action, &QAction::hovered, this, &QgsIdentifyMenu::handleMenuHover );
453  connect( action, &QAction::triggered, this, &QgsIdentifyMenu::triggerMapLayerAction );
454  layerMenu->addAction( action );
455  if ( separators.contains( mapLayerAction ) )
456  {
457  layerMenu->insertSeparator( action );
458  }
459  }
460 }
461 
462 void QgsIdentifyMenu::triggerMapLayerAction()
463 {
464  QAction *action = qobject_cast<QAction *>( sender() );
465  if ( !action )
466  return;
467  const QVariant varData = action->data();
468  if ( !varData.isValid() || !varData.canConvert<ActionData>() )
469  return;
470 
471  ActionData actData = action->data().value<ActionData>();
472 
473  if ( actData.mIsValid && actData.mMapLayerAction )
474  {
475  // layer
476  if ( actData.mMapLayerAction->targets().testFlag( QgsMapLayerAction::Layer ) )
477  {
478  actData.mMapLayerAction->triggerForLayer( actData.mLayer );
479  }
480 
481  // multiples features
482  if ( actData.mMapLayerAction->targets().testFlag( QgsMapLayerAction::MultipleFeatures ) )
483  {
484  QList<QgsFeature> featureList;
485  const auto results { mLayerIdResults[actData.mLayer] };
486  for ( const QgsMapToolIdentify::IdentifyResult &result : results )
487  {
488  featureList << result.mFeature;
489  }
490  actData.mMapLayerAction->triggerForFeatures( actData.mLayer, featureList );
491  }
492 
493  // single feature
494  if ( actData.mMapLayerAction->targets().testFlag( QgsMapLayerAction::SingleFeature ) )
495  {
496  const auto results { mLayerIdResults[actData.mLayer] };
497  for ( const QgsMapToolIdentify::IdentifyResult &result : results )
498  {
499  if ( result.mFeature.id() == actData.mFeatureId )
500  {
501  actData.mMapLayerAction->triggerForFeature( actData.mLayer, result.mFeature );
502  return;
503  }
504  }
505  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve feature for action %1" ).arg( action->text() ) );
506  }
507  }
508 }
509 
510 
511 QList<QgsMapToolIdentify::IdentifyResult> QgsIdentifyMenu::results( QAction *action, bool &externalAction )
512 {
513  QList<QgsMapToolIdentify::IdentifyResult> idResults = QList<QgsMapToolIdentify::IdentifyResult>();
514 
515  externalAction = false;
516 
517  ActionData actData;
518  bool hasData = false;
519 
520  if ( !action )
521  return idResults;
522 
523  const QVariant varData = action->data();
524  if ( !varData.isValid() )
525  {
526  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve results from menu entry (invalid data)" ) );
527  return idResults;
528  }
529 
530  if ( varData.canConvert<ActionData>() )
531  {
532  actData = action->data().value<ActionData>();
533  if ( actData.mIsValid )
534  {
535  externalAction = actData.mIsExternalAction;
536  hasData = true;
537  }
538  }
539 
540  if ( !hasData && varData.canConvert<QgsActionMenu::ActionData>() )
541  {
542  const QgsActionMenu::ActionData dataSrc = action->data().value<QgsActionMenu::ActionData>();
543  if ( dataSrc.actionType != QgsActionMenu::Invalid )
544  {
545  externalAction = true;
546  actData = ActionData( dataSrc.mapLayer, dataSrc.featureId );
547  hasData = true;
548  }
549  }
550 
551  if ( !hasData )
552  {
553  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve results from menu entry (no data found)" ) );
554  return idResults;
555  }
556 
557  // return all results
558  if ( actData.mAllResults )
559  {
560  // this means "All" action was triggered
561  QMapIterator< QgsMapLayer *, QList<QgsMapToolIdentify::IdentifyResult> > it( mLayerIdResults );
562  while ( it.hasNext() )
563  {
564  it.next();
565  idResults << it.value();
566  }
567  return idResults;
568  }
569 
570  if ( !mLayerIdResults.contains( actData.mLayer ) )
571  {
572  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve results from menu entry (layer not found)" ) );
573  return idResults;
574  }
575 
576  if ( actData.mLevel == LayerLevel )
577  {
578  return mLayerIdResults[actData.mLayer];
579  }
580 
581  if ( actData.mLevel == FeatureLevel )
582  {
583  const auto results {mLayerIdResults[actData.mLayer]};
584  for ( const QgsMapToolIdentify::IdentifyResult &res : results )
585  {
586  if ( res.mFeature.id() == actData.mFeatureId )
587  {
588  idResults << res;
589  return idResults;
590  }
591  }
592  }
593 
594  QgsDebugMsg( QStringLiteral( "Identify menu: could not retrieve results from menu entry (don't know what happened')" ) );
595  return idResults;
596 }
597 
598 void QgsIdentifyMenu::handleMenuHover()
599 {
600  if ( !mCanvas )
601  return;
602 
603  deleteRubberBands();
604 
605  QAction *senderAction = qobject_cast<QAction *>( sender() );
606  if ( !senderAction )
607  return;
608 
609  bool externalAction;
610  const QList<QgsMapToolIdentify::IdentifyResult> idResults = results( senderAction, externalAction );
611 
612  const auto constIdResults = idResults;
613  for ( const QgsMapToolIdentify::IdentifyResult &result : constIdResults )
614  {
615  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( result.mLayer );
616  if ( !vl )
617  continue;
618 
619  QgsHighlight *hl = new QgsHighlight( mCanvas, result.mFeature.geometry(), vl );
620  styleHighlight( hl );
621  mRubberBands.append( hl );
622  connect( vl, &QObject::destroyed, this, &QgsIdentifyMenu::layerDestroyed );
623  }
624 }
625 
627 {
628  const QgsSettings settings;
629  QColor color = QColor( settings.value( QStringLiteral( "Map/highlight/color" ), Qgis::DEFAULT_HIGHLIGHT_COLOR.name() ).toString() );
630  const int alpha = settings.value( QStringLiteral( "Map/highlight/colorAlpha" ), Qgis::DEFAULT_HIGHLIGHT_COLOR.alpha() ).toInt();
631  const double buffer = settings.value( QStringLiteral( "Map/highlight/buffer" ), Qgis::DEFAULT_HIGHLIGHT_BUFFER_MM ).toDouble();
632  const double minWidth = settings.value( QStringLiteral( "Map/highlight/minWidth" ), Qgis::DEFAULT_HIGHLIGHT_MIN_WIDTH_MM ).toDouble();
633 
634  highlight->setColor( color ); // sets also fill with default alpha
635  color.setAlpha( alpha );
636  highlight->setFillColor( color ); // sets fill with alpha
637  highlight->setBuffer( buffer );
638  highlight->setMinWidth( minWidth );
639 }
640 
641 void QgsIdentifyMenu::deleteRubberBands()
642 {
643  QList<QgsHighlight *>::const_iterator it = mRubberBands.constBegin();
644  for ( ; it != mRubberBands.constEnd(); ++it )
645  delete *it;
646  mRubberBands.clear();
647 }
648 
649 void QgsIdentifyMenu::layerDestroyed()
650 {
651  QList<QgsHighlight *>::iterator it = mRubberBands.begin();
652  while ( it != mRubberBands.end() )
653  {
654  if ( ( *it )->layer() == sender() )
655  {
656  delete *it;
657  it = mRubberBands.erase( it );
658  }
659  else
660  {
661  ++it;
662  }
663  }
664 }
665 
667 {
668  mCustomActionRegistry.clear();
669 
670 }
671 
673 {
674  mExpressionContextScope = scope;
675 }
676 
678 {
679  return mExpressionContextScope;
680 }
static const double DEFAULT_HIGHLIGHT_MIN_WIDTH_MM
Default highlight line/stroke minimum width in mm.
Definition: qgis.h:1351
static const double DEFAULT_HIGHLIGHT_BUFFER_MM
Default highlight buffer in mm.
Definition: qgis.h:1345
static const QColor DEFAULT_HIGHLIGHT_COLOR
Default highlight color.
Definition: qgis.h:1339
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:119
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:90
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:73
QString name
Definition: qgsmaplayer.h:76
QgsMapLayerType type
Definition: qgsmaplayer.h:80
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
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
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsActionMenu::ActionType actionType
Definition: qgsactionmenu.h:59