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