QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsmaptoolidentify.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaptoolidentify.cpp - map tool for identifying features
3  ---------------------
4  begin : January 2006
5  copyright : (C) 2006 by Martin Dobias
6  email : wonder.sk at gmail dot com
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 "qgsapplication.h"
17 #include "qgscursors.h"
18 #include "qgsdistancearea.h"
19 #include "qgsfeature.h"
20 #include "qgsfeaturestore.h"
21 #include "qgsfield.h"
22 #include "qgsgeometry.h"
23 #include "qgshighlight.h"
24 #include "qgslogger.h"
25 #include "qgsmapcanvas.h"
26 #include "qgsmaptoolidentify.h"
27 #include "qgsmaptopixel.h"
28 #include "qgsmessageviewer.h"
29 #include "qgsmaplayer.h"
30 #include "qgsrasterlayer.h"
33 #include "qgsvectordataprovider.h"
34 #include "qgsvectorlayer.h"
35 #include "qgsproject.h"
36 #include "qgsmaplayerregistry.h"
37 #include "qgsrendererv2.h"
38 
39 #include <QSettings>
40 #include <QMessageBox>
41 #include <QMouseEvent>
42 #include <QCursor>
43 #include <QPixmap>
44 #include <QStatusBar>
45 #include <QVariant>
46 #include <QMenu>
47 
49  : QgsMapTool( canvas )
50 {
51  // set cursor
52  QPixmap myIdentifyQPixmap = QPixmap(( const char ** ) identify_cursor );
53  mCursor = QCursor( myIdentifyQPixmap, 1, 1 );
54 }
55 
57 {
58 }
59 
60 void QgsMapToolIdentify::canvasMoveEvent( QMouseEvent * e )
61 {
62  Q_UNUSED( e );
63 }
64 
65 void QgsMapToolIdentify::canvasPressEvent( QMouseEvent * e )
66 {
67  Q_UNUSED( e );
68 }
69 
71 {
72  Q_UNUSED( e );
73 }
74 
75 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, QList<QgsMapLayer *> layerList, IdentifyMode mode )
76 {
77  return identify( x, y, mode, layerList, AllLayers );
78 }
79 
80 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, IdentifyMode mode, LayerType layerType )
81 {
82  return identify( x, y, mode, QList<QgsMapLayer*>(), layerType );
83 }
84 
85 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, IdentifyMode mode, QList<QgsMapLayer*> layerList, LayerType layerType )
86 {
87  QList<IdentifyResult> results;
88 
92 
93  if ( !mCanvas || mCanvas->isDrawing() )
94  {
95  return results;
96  }
97 
98  if ( mode == DefaultQgsSetting )
99  {
100  QSettings settings;
101  mode = static_cast<IdentifyMode>( settings.value( "/Map/identifyMode", 0 ).toInt() );
102  }
103 
104  if ( mode == LayerSelection )
105  {
106  // fill map of layer / identify results
107  mLayerIdResults.clear();
108  QList<IdentifyResult> idResult = identify( x, y, TopDownAll );
109  QList<IdentifyResult>::const_iterator it = idResult.constBegin();
110  for ( ; it != idResult.constEnd(); ++it )
111  {
112  QgsMapLayer *layer = it->mLayer;
113  if ( mLayerIdResults.contains( layer ) )
114  {
115  mLayerIdResults[layer].append( *it );
116  }
117  else
118  {
119  mLayerIdResults.insert( layer, QList<IdentifyResult>() << *it );
120  }
121  }
122 
123  //fill selection menu with entries from mmLayerIdResults
124  QMenu layerSelectionMenu;
125  QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator resultIt = mLayerIdResults.constBegin();
126  for ( ; resultIt != mLayerIdResults.constEnd(); ++resultIt )
127  {
128  QAction* action = new QAction( resultIt.key()->name(), 0 );
129  action->setData( resultIt.key()->id() );
130  //add point/line/polygon icon
131  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( resultIt.key() );
132  if ( vl )
133  {
134  switch ( vl->geometryType() )
135  {
136  case QGis::Point:
137  action->setIcon( QgsApplication::getThemeIcon( "/mIconPointLayer.png" ) );
138  break;
139  case QGis::Line:
140  action->setIcon( QgsApplication::getThemeIcon( "/mIconLineLayer.png" ) );
141  break;
142  case QGis::Polygon:
143  action->setIcon( QgsApplication::getThemeIcon( "/mIconPolygonLayer.png" ) );
144  break;
145  default:
146  break;
147  }
148  }
149  else if ( resultIt.key()->type() == QgsMapLayer::RasterLayer )
150  {
151  action->setIcon( QgsApplication::getThemeIcon( "/mIconRaster.png" ) );
152  }
153  QObject::connect( action, SIGNAL( hovered() ), this, SLOT( handleMenuHover() ) );
154  layerSelectionMenu.addAction( action );
155  }
156 
157  // exec layer selection menu
158  QPoint globalPos = mCanvas->mapToGlobal( QPoint( x + 5, y + 5 ) );
159  QAction* selectedAction = layerSelectionMenu.exec( globalPos );
160  if ( selectedAction )
161  {
162  QgsMapLayer* selectedLayer = QgsMapLayerRegistry::instance()->mapLayer( selectedAction->data().toString() );
163  QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator sIt = mLayerIdResults.find( selectedLayer );
164  if ( sIt != mLayerIdResults.constEnd() )
165  {
166  results = sIt.value();
167  }
168  }
169 
171  }
172  else if ( mode == ActiveLayer && layerList.isEmpty() )
173  {
174  QgsMapLayer *layer = mCanvas->currentLayer();
175 
176  if ( !layer )
177  {
178  emit identifyMessage( tr( "No active layer. To identify features, you must choose an active layer." ) );
179  return results;
180  }
181 
182  QApplication::setOverrideCursor( Qt::WaitCursor );
183 
184  identifyLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel, layerType );
185  }
186  else
187  {
188  QApplication::setOverrideCursor( Qt::WaitCursor );
189 
190  QStringList noIdentifyLayerIdList = QgsProject::instance()->readListEntry( "Identify", "/disabledLayers" );
191 
192  int layerCount;
193  if ( layerList.isEmpty() )
194  layerCount = mCanvas->layerCount();
195  else
196  layerCount = layerList.count();
197 
198 
199  for ( int i = 0; i < layerCount; i++ )
200  {
201 
202  QgsMapLayer *layer ;
203  if ( layerList.isEmpty() )
204  layer = mCanvas->layer( i );
205  else
206  layer = layerList.value( i );
207 
208  emit identifyProgress( i, mCanvas->layerCount() );
209  emit identifyMessage( tr( "Identifying on %1..." ).arg( layer->name() ) );
210 
211  if ( noIdentifyLayerIdList.contains( layer->id() ) )
212  continue;
213 
214  if ( identifyLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel, layerType ) )
215  {
216  if ( mode == TopDownStopAtFirst )
217  break;
218  }
219  }
220 
222  emit identifyMessage( tr( "Identifying done." ) );
223  }
224 
225  QApplication::restoreOverrideCursor();
226 
227  return results;
228 }
229 
231 {
233 }
234 
236 {
238 }
239 
240 bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, QgsPoint point, QgsRectangle viewExtent, double mapUnitsPerPixel, LayerType layerType )
241 {
242  if ( layer->type() == QgsMapLayer::RasterLayer && ( layerType == AllLayers || layerType == RasterLayer ) )
243  {
244  return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), point, viewExtent, mapUnitsPerPixel );
245  }
246  else if ( layer->type() == QgsMapLayer::VectorLayer && ( layerType == AllLayers || layerType == VectorLayer ) )
247  {
248  return identifyVectorLayer( results, qobject_cast<QgsVectorLayer *>( layer ), point );
249  }
250  else
251  {
252  return false;
253  }
254 }
255 
256 bool QgsMapToolIdentify::identifyVectorLayer( QList<IdentifyResult> *results, QgsVectorLayer *layer, QgsPoint point )
257 {
258  if ( !layer )
259  return false;
260 
261  if ( layer->hasScaleBasedVisibility() &&
262  ( layer->minimumScale() > mCanvas->mapRenderer()->scale() ||
263  layer->maximumScale() <= mCanvas->mapRenderer()->scale() ) )
264  {
265  QgsDebugMsg( "Out of scale limits" );
266  return false;
267  }
268 
269  QMap< QString, QString > commonDerivedAttributes;
270 
271  commonDerivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
272 
273  // load identify radius from settings
274  QSettings settings;
275  double identifyValue = settings.value( "/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS ).toDouble();
276 
277  if ( identifyValue <= 0.0 )
278  identifyValue = QGis::DEFAULT_IDENTIFY_RADIUS;
279 
280  int featureCount = 0;
281 
282  QgsFeatureList featureList;
283 
284  // toLayerCoordinates will throw an exception for an 'invalid' point.
285  // For example, if you project a world map onto a globe using EPSG 2163
286  // and then click somewhere off the globe, an exception will be thrown.
287  try
288  {
289  // create the search rectangle
290  double searchRadius = mCanvas->extent().width() * ( identifyValue / 100.0 );
291 
292  QgsRectangle r;
293  r.setXMinimum( point.x() - searchRadius );
294  r.setXMaximum( point.x() + searchRadius );
295  r.setYMinimum( point.y() - searchRadius );
296  r.setYMaximum( point.y() + searchRadius );
297 
298  r = toLayerCoordinates( layer, r );
299 
300  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) );
301  QgsFeature f;
302  while ( fit.nextFeature( f ) )
303  featureList << QgsFeature( f );
304  }
305  catch ( QgsCsException & cse )
306  {
307  Q_UNUSED( cse );
308  // catch exception for 'invalid' point and proceed with no features found
309  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
310  }
311 
312  QgsFeatureList::iterator f_it = featureList.begin();
313 
314  bool filter = false;
315 
316  QgsFeatureRendererV2* renderer = layer->rendererV2();
317  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
318  {
319  // setup scale for scale dependent visibility (rule based)
320  renderer->startRender( *( mCanvas->mapRenderer()->rendererContext() ), layer );
321  filter = renderer->capabilities() & QgsFeatureRendererV2::Filter;
322  }
323 
324  for ( ; f_it != featureList.end(); ++f_it )
325  {
326  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
327 
328  QgsFeatureId fid = f_it->id();
329 
330  if ( filter && !renderer->willRenderFeature( *f_it ) )
331  continue;
332 
333  featureCount++;
334 
335  derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer ) );
336 
337  derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) );
338 
339  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) );
340  }
341 
342  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
343  {
344  renderer->stopRender( *( mCanvas->mapRenderer()->rendererContext() ) );
345  }
346 
347  QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );
348 
349  return featureCount > 0;
350 }
351 
352 QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeature *feature, QgsMapLayer *layer )
353 {
354  // Calculate derived attributes and insert:
355  // measure distance or area depending on geometry type
356  QMap< QString, QString > derivedAttributes;
357 
358  // init distance/area calculator
359  QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
360  QgsDistanceArea calc;
362  calc.setEllipsoid( ellipsoid );
363  calc.setSourceCrs( layer->crs().srsid() );
364 
366  QGis::GeometryType geometryType = QGis::NoGeometry;
367 
368  if ( feature->geometry() )
369  {
370  geometryType = feature->geometry()->type();
371  wkbType = feature->geometry()->wkbType();
372  }
373 
374  if ( geometryType == QGis::Line )
375  {
376  double dist = calc.measure( feature->geometry() );
377  QGis::UnitType myDisplayUnits;
378  convertMeasurement( calc, dist, myDisplayUnits, false );
379  QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params
380  derivedAttributes.insert( tr( "Length" ), str );
381  if ( wkbType == QGis::WKBLineString || wkbType == QGis::WKBLineString25D )
382  {
383  // Add the start and end points in as derived attributes
384  QgsPoint pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, feature->geometry()->asPolyline().first() );
385  str = QLocale::system().toString( pnt.x(), 'g', 10 );
386  derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
387  str = QLocale::system().toString( pnt.y(), 'g', 10 );
388  derivedAttributes.insert( tr( "firstY" ), str );
389  pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, feature->geometry()->asPolyline().last() );
390  str = QLocale::system().toString( pnt.x(), 'g', 10 );
391  derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
392  str = QLocale::system().toString( pnt.y(), 'g', 10 );
393  derivedAttributes.insert( tr( "lastY" ), str );
394  }
395  }
396  else if ( geometryType == QGis::Polygon )
397  {
398  double area = calc.measure( feature->geometry() );
399  double perimeter = calc.measurePerimeter( feature->geometry() );
400  QGis::UnitType myDisplayUnits;
401  convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params
402  QString str = calc.textUnit( area, 3, myDisplayUnits, true );
403  derivedAttributes.insert( tr( "Area" ), str );
404  convertMeasurement( calc, perimeter, myDisplayUnits, false ); // perimeter and myDisplayUnits are out params
405  str = calc.textUnit( perimeter, 3, myDisplayUnits, false );
406  derivedAttributes.insert( tr( "Perimeter" ), str );
407  }
408  else if ( geometryType == QGis::Point &&
409  ( wkbType == QGis::WKBPoint || wkbType == QGis::WKBPoint25D ) )
410  {
411  // Include the x and y coordinates of the point as a derived attribute
412  QgsPoint pnt = mCanvas->mapRenderer()->layerToMapCoordinates( layer, feature->geometry()->asPoint() );
413  QString str = QLocale::system().toString( pnt.x(), 'g', 10 );
414  derivedAttributes.insert( "X", str );
415  str = QLocale::system().toString( pnt.y(), 'g', 10 );
416  derivedAttributes.insert( "Y", str );
417  }
418 
419  return derivedAttributes;
420 }
421 
422 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPoint point, QgsRectangle viewExtent, double mapUnitsPerPixel )
423 {
424  QgsDebugMsg( "point = " + point.toString() );
425  if ( !layer ) return false;
426 
427  QgsRasterDataProvider *dprovider = layer->dataProvider();
428  int capabilities = dprovider->capabilities();
429  if ( !dprovider || !( capabilities & QgsRasterDataProvider::Identify ) )
430  {
431  return false;
432  }
433 
434  QgsPoint pointInCanvasCrs = point;
435  try
436  {
437  point = toLayerCoordinates( layer, point );
438  }
439  catch ( QgsCsException &cse )
440  {
441  Q_UNUSED( cse );
442  QgsDebugMsg( QString( "coordinate not reprojectable: %1" ).arg( cse.what() ) );
443  return false;
444  }
445  QgsDebugMsg( QString( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) );
446 
447  if ( !layer->extent().contains( point ) ) return false;
448 
449  QMap< QString, QString > attributes, derivedAttributes;
450 
451  QgsRaster::IdentifyFormat format = QgsRasterDataProvider::identifyFormatFromName( layer->customProperty( "identify/format" ).toString() );
452 
453  // check if the format is really supported otherwise use first supported format
454  if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) )
455  {
457  else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRaster::IdentifyFormatValue;
458  else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRaster::IdentifyFormatHtml;
459  else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRaster::IdentifyFormatText;
460  else return false;
461  }
462 
463  QgsRasterIdentifyResult identifyResult;
464  // We can only use current map canvas context (extent, width, height) if layer is not reprojected,
465  if ( mCanvas->hasCrsTransformEnabled() && dprovider->crs() != mCanvas->mapRenderer()->destinationCrs() )
466  {
467  // To get some reasonable response for point/line WMS vector layers we must
468  // use a context with approximately a resolution in layer CRS units
469  // corresponding to current map canvas resolution (for examplei UMN Mapserver
470  // in msWMSFeatureInfo() -> msQueryByRect() is using requested pixel
471  // + TOLERANCE (layer param) for feature selection)
472  //
473  QgsRectangle r;
474  r.setXMinimum( pointInCanvasCrs.x() - mapUnitsPerPixel / 2. );
475  r.setXMaximum( pointInCanvasCrs.x() + mapUnitsPerPixel / 2. );
476  r.setYMinimum( pointInCanvasCrs.y() - mapUnitsPerPixel / 2. );
477  r.setYMaximum( pointInCanvasCrs.y() + mapUnitsPerPixel / 2. );
478  r = toLayerCoordinates( layer, r ); // will be a bit larger
479  // Mapserver (6.0.3, for example) does not work with 1x1 pixel box
480  // but that is fixed (the rect is enlarged) in the WMS provider
481  identifyResult = dprovider->identify( point, format, r, 1, 1 );
482  }
483  else
484  {
485  // It would be nice to use the same extent and size which was used for drawing,
486  // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw()
487  // is doing some tricks with extent and size to allign raster to output which
488  // would be difficult to replicate here.
489  // Note: cutting the extent may result in slightly different x and y resolutions
490  // and thus shifted point calculated back in QGIS WMS (using average resolution)
491  //viewExtent = dprovider->extent().intersect( &viewExtent );
492 
493  // Width and height are calculated from not projected extent and we hope that
494  // are similar to source width and height used to reproject layer for drawing.
495  // TODO: may be very dangerous, because it may result in different resolutions
496  // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution.
497  int width = qRound( viewExtent.width() / mapUnitsPerPixel );
498  int height = qRound( viewExtent.height() / mapUnitsPerPixel );
499 
500  QgsDebugMsg( QString( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) );
501  QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) );
502  QgsDebugMsg( QString( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) );
503 
504  identifyResult = dprovider->identify( point, format, viewExtent, width, height );
505  }
506 
507  derivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
508 
509  if ( identifyResult.isValid() )
510  {
511  QMap<int, QVariant> values = identifyResult.results();
512  QgsGeometry geometry;
513  if ( format == QgsRaster::IdentifyFormatValue )
514  {
515  foreach ( int bandNo, values.keys() )
516  {
517  QString valueString;
518  if ( values.value( bandNo ).isNull() )
519  {
520  valueString = tr( "no data" );
521  }
522  else
523  {
524  double value = values.value( bandNo ).toDouble();
525  valueString = QgsRasterBlock::printValue( value );
526  }
527  attributes.insert( dprovider->generateBandName( bandNo ), valueString );
528  }
529  QString label = layer->name();
530  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
531  }
532  else if ( format == QgsRaster::IdentifyFormatFeature )
533  {
534  foreach ( int i, values.keys() )
535  {
536  QVariant value = values.value( i );
537  if ( value.type() == QVariant::Bool && !value.toBool() )
538  {
539  // sublayer not visible or not queryable
540  continue;
541  }
542 
543  if ( value.type() == QVariant::String )
544  {
545  // error
546  // TODO: better error reporting
547  QString label = layer->subLayers().value( i );
548  attributes.clear();
549  attributes.insert( tr( "Error" ), value.toString() );
550 
551  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
552  continue;
553  }
554 
555  // list of feature stores for a single sublayer
556  QgsFeatureStoreList featureStoreList = values.value( i ).value<QgsFeatureStoreList>();
557 
558  foreach ( QgsFeatureStore featureStore, featureStoreList )
559  {
560  foreach ( QgsFeature feature, featureStore.features() )
561  {
562  attributes.clear();
563  // WMS sublayer and feature type, a sublayer may contain multiple feature types.
564  // Sublayer name may be the same as layer name and feature type name
565  // may be the same as sublayer. We try to avoid duplicities in label.
566  QString sublayer = featureStore.params().value( "sublayer" ).toString();
567  QString featureType = featureStore.params().value( "featureType" ).toString();
568  // Strip UMN MapServer '_feature'
569  featureType.remove( "_feature" );
570  QStringList labels;
571  if ( sublayer.compare( layer->name(), Qt::CaseInsensitive ) != 0 )
572  {
573  labels << sublayer;
574  }
575  if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
576  {
577  labels << featureType;
578 
579 
580  }
581 
582  QMap< QString, QString > derAttributes = derivedAttributes;
583  derAttributes.unite( featureDerivedAttributes( &feature, layer ) );
584 
585  IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( " / " ), featureStore.fields(), feature, derAttributes );
586 
587  identifyResult.mParams.insert( "getFeatureInfoUrl", featureStore.params().value( "getFeatureInfoUrl" ) );
588  results->append( identifyResult );
589  }
590  }
591  }
592  }
593  else // text or html
594  {
595  QgsDebugMsg( QString( "%1 html or text values" ).arg( values.size() ) );
596  foreach ( int bandNo, values.keys() )
597  {
598  QString value = values.value( bandNo ).toString();
599  attributes.clear();
600  attributes.insert( "", value );
601 
602  QString label = layer->subLayers().value( bandNo );
603  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
604  }
605  }
606  }
607  else
608  {
609  attributes.clear();
610  QString value = identifyResult.error().message( QgsErrorMessage::Text );
611  attributes.insert( tr( "Error" ), value );
612  QString label = tr( "Identify error" );
613  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
614  }
615 
616  return true;
617 }
618 
619 void QgsMapToolIdentify::convertMeasurement( QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea )
620 {
621  // Helper for converting between meters and feet
622  // The parameter &u is out only...
623 
624  // Get the canvas units
625  QGis::UnitType myUnits = mCanvas->mapUnits();
626 
627  calc.convertMeasurement( measure, myUnits, displayUnits(), isArea );
628  u = myUnits;
629 }
630 
632 {
633  return mCanvas->mapUnits();
634 }
635 
637 {
638  QgsDebugMsg( "Entered" );
639  QList<IdentifyResult> results;
641  {
642  emit changedRasterResults( results );
643  }
644 }
645 
647 {
648  if ( !mCanvas )
649  {
650  return;
651  }
652 
654  QAction* senderAction = qobject_cast<QAction*>( sender() );
655  if ( senderAction )
656  {
657  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( senderAction->data().toString() ) );
658  if ( vl )
659  {
660  QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator lIt = mLayerIdResults.find( vl );
661  if ( lIt != mLayerIdResults.constEnd() )
662  {
663  const QList<IdentifyResult>& idList = lIt.value();
664  QList<IdentifyResult>::const_iterator idListIt = idList.constBegin();
665  for ( ; idListIt != idList.constEnd(); ++idListIt )
666  {
667  QgsHighlight* hl = new QgsHighlight( mCanvas, idListIt->mFeature.geometry(), vl );
668  hl->setColor( QColor( 255, 0, 0 ) );
669  hl->setWidth( 2 );
670  mRubberBands.append( hl );
671  }
672  }
673  }
674  }
675 }
676 
678 {
679  QList<QgsHighlight*>::const_iterator it = mRubberBands.constBegin();
680  for ( ; it != mRubberBands.constEnd(); ++it )
681  {
682  delete *it;
683  }
684  mRubberBands.clear();
685 }
bool isValid() const
Returns true if valid.
Wrapper for iterator of features from vector data provider or vector layer.
QMap< QString, QVariant > mParams
Additional params (e.g.
Container for features with the same fields and crs.
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
IdentifyFormat
Definition: qgsraster.h:54
virtual bool willRenderFeature(QgsFeature &feat)
return whether the renderer will render a feature or not.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:45
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:88
static QString printValue(double value)
Print double value with all necessary significant digits.
QgsRenderContext * rendererContext()
Accessor for render context.
GeometryType
Definition: qgis.h:155
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
void changedRasterResults(QList< IdentifyResult > &)
int layerCount() const
return number of layers on the map
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:164
Use exact geometry intersection (slower) instead of bounding boxes.
void identifyProgress(int, int)
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
virtual QgsCoordinateReferenceSystem crs()=0
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
QList< QgsFeatureStore > QgsFeatureStoreList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:327
void setSourceCrs(long srsid)
sets source spatial reference system (by QGIS CRS)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:113
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
float minimumScale() const
bool hasCrsTransformEnabled()
A simple helper method to find out if on the fly projections are enabled or not.
#define FID_TO_STRING(fid)
Definition: qgsfeature.h:83
virtual void activate()
called when set as currently active map tool
virtual void canvasMoveEvent(QMouseEvent *e)
Overridden mouse move event.
QGis::GeometryType type()
Returns type of the vector.
static Capability identifyFormatToCapability(QgsRaster::IdentifyFormat format)
WkbType
Used for symbology operations.
Definition: qgis.h:53
static const double DEFAULT_IDENTIFY_RADIUS
Definition: qgis.h:267
bool setEllipsoid(const QString &ellipsoid)
sets ellipsoid by its acronym
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:114
bool identifyLayer(QList< IdentifyResult > *results, QgsMapLayer *layer, QgsPoint point, QgsRectangle viewExtent, double mapUnitsPerPixel, LayerType layerType=AllLayers)
call the right method depending on layer type
QgsMapToolIdentify(QgsMapCanvas *canvas)
constructor
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:99
QMap< int, QVariant > results() const
Get results.
double x() const
Definition: qgspoint.h:110
QgsPoint layerToMapCoordinates(QgsMapLayer *theLayer, QgsPoint point)
transform point coordinates from layer's CRS to output CRS
virtual void canvasPressEvent(QMouseEvent *e)
Overridden mouse press event.
virtual void stopRender(QgsRenderContext &context)=0
QMap< QString, QString > featureDerivedAttributes(QgsFeature *feature, QgsMapLayer *layer)
Raster identify results container.
const QString & name() const
Get the display name of the layer.
virtual void activate()
called when set as currently active map tool
Definition: qgsmaptool.cpp:71
QgsMapCanvas * mCanvas
pointer to map canvas
Definition: qgsmaptool.h:147
virtual QgsRasterIdentifyResult identify(const QgsPoint &thePoint, QgsRaster::IdentifyFormat theFormat, const QgsRectangle &theExtent=QgsRectangle(), int theWidth=0, int theHeight=0)
Identify raster value(s) found on the point position.
QCursor mCursor
cursor used in map tool
Definition: qgsmaptool.h:150
QStringList readListEntry(const QString &scope, const QString &key, QStringList def=QStringList(), bool *ok=0) const
key value accessors
void formatChanged(QgsRasterLayer *layer)
virtual QStringList subLayers() const
Returns the sublayers of this layer - Useful for providers that manage their own layers, such as WMS.
virtual void deactivate()
called when map tool is being deactivated
bool hasScaleBasedVisibility() const
double measurePerimeter(QgsGeometry *geometry)
measures perimeter of polygon
double measure(QgsGeometry *geometry)
general measurement (line distance or polygon area)
QList< QgsHighlight * > mRubberBands
rubber bands for layer select mode
float maximumScale() const
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:169
double scale() const
Scale denominator.
QgsPoint toLayerCoordinates(QgsMapLayer *layer, const QPoint &point)
transformation from screen coordinates to layer's coordinates
Definition: qgsmaptool.cpp:42
A class for highlight features on the map.
Definition: qgshighlight.h:35
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QString toString() const
String representation of the point (x,y)
Definition: qgspoint.cpp:121
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:94
virtual QString generateBandName(int theBandNumber) const
helper function to create zero padded band names
QGis::WkbType wkbType() const
Returns type of wkb (point / linestring / polygon etc.)
void identifyMessage(QString)
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QGis::UnitType mapUnits() const
Get the current canvas map units.
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:85
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QString message(QgsErrorMessage::Format theFormat=QgsErrorMessage::Html) const
Full error messages description.
Definition: qgserror.cpp:50
void handleMenuHover()
menu for layer selection
A class to represent a point geometry.
Definition: qgspoint.h:63
bool isDrawing()
true if canvas currently drawing
virtual void canvasReleaseEvent(QMouseEvent *e)
Overridden mouse release event.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
QAction * action()
Return associated action with map tool or NULL if no action is associated.
Definition: qgsmaptool.cpp:98
QgsPoint toMapCoordinates(int x, int y) const
static QString textUnit(double value, int decimals, QGis::UnitType u, bool isArea, bool keepBaseUnit=false)
Abstract base class for all map tools.
Definition: qgsmaptool.h:46
General purpose distance and area calculator.
QgsPolyline asPolyline() const
return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list ...
QString what() const
Definition: qgsexception.h:35
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=0) const
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QMap< QgsMapLayer *, QList< IdentifyResult > > mLayerIdResults
layer id map for layer select mode
virtual void convertMeasurement(QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea)
Private helper.
void setColor(const QColor &color)
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:174
QList< IdentifyResult > identify(int x, int y, QList< QgsMapLayer * > layerList=QList< QgsMapLayer * >(), IdentifyMode mode=DefaultQgsSetting)
Performs the identification.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
QgsMapRenderer * mapRenderer()
const CORE_EXPORT QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.cpp:72
UnitType
Map units that qgis supports.
Definition: qgis.h:229
const QgsMapToPixel * getCoordinateTransform()
Get the current coordinate transform.
bool identifyRasterLayer(QList< IdentifyResult > *results, QgsRasterLayer *layer, QgsPoint point, QgsRectangle viewExtent, double mapUnitsPerPixel)
qint64 QgsFeatureId
Definition: qgsfeature.h:30
double y() const
Definition: qgspoint.h:118
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
QgsFields & fields()
Get fields list.
virtual void startRender(QgsRenderContext &context, const QgsVectorLayer *vlayer)=0
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
void convertMeasurement(double &measure, QGis::UnitType &measureUnits, QGis::UnitType displayUnits, bool isArea)
Helper for conversion between physical units.
static QgsRaster::IdentifyFormat identifyFormatFromName(QString formatName)
QgsRasterDataProvider * dataProvider()
Returns the data provider.
QgsRectangle extent() const
Returns the current zoom exent of the map canvas.
Custom exception class for Coordinate Reference System related exceptions.
const char * identify_cursor[]
Definition: qgscursors.cpp:135
virtual int capabilities()
returns bitwise OR-ed capabilities of the renderer
bool nextFeature(QgsFeature &f)
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:199
QgsPoint asPoint() const
return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
QgsError error() const
Get error.
virtual QgsRectangle extent()
Return the extent of the layer.
Represents a vector layer which manages a vector based data sets.
void deleteRubberBands()
rubber bands for layer select mode
QMap< QString, QVariant > params() const
Get map of optional parameters.
QgsFeatureList & features()
Get features list reference.
QgsMapLayer * layer(int index)
return the map layer at position index in the layer stack
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:159
virtual QGis::UnitType displayUnits()
Transforms the measurements of derived attributes in the desired units.
void setEllipsoidalMode(bool flag)
sets whether coordinates must be projected to ellipsoid before measuring
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:204
Base class for raster data providers.
bool identifyVectorLayer(QList< IdentifyResult > *results, QgsVectorLayer *layer, QgsPoint point)
void setWidth(int width)
Set width.
#define tr(sourceText)