QGIS API Documentation  2.4.0-Chugiak
 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 ( mode == DefaultQgsSetting )
94  {
95  QSettings settings;
96  mode = static_cast<IdentifyMode>( settings.value( "/Map/identifyMode", 0 ).toInt() );
97  }
98 
99  if ( mode == LayerSelection )
100  {
101  // fill map of layer / identify results
102  mLayerIdResults.clear();
103  QList<IdentifyResult> idResult = identify( x, y, TopDownAll );
104  QList<IdentifyResult>::const_iterator it = idResult.constBegin();
105  for ( ; it != idResult.constEnd(); ++it )
106  {
107  QgsMapLayer *layer = it->mLayer;
108  if ( mLayerIdResults.contains( layer ) )
109  {
110  mLayerIdResults[layer].append( *it );
111  }
112  else
113  {
114  mLayerIdResults.insert( layer, QList<IdentifyResult>() << *it );
115  }
116  }
117 
118  if ( mLayerIdResults.size() > 1 )
119  {
120  //fill selection menu with entries from mmLayerIdResults
121  QMenu layerSelectionMenu;
122  QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator resultIt = mLayerIdResults.constBegin();
123  for ( ; resultIt != mLayerIdResults.constEnd(); ++resultIt )
124  {
125  QAction* action = new QAction( QString( "%1 (%2)" ).arg( resultIt.key()->name() ).arg( resultIt.value().size() ), 0 );
126  action->setData( resultIt.key()->id() );
127  //add point/line/polygon icon
128  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( resultIt.key() );
129  if ( vl )
130  {
131  switch ( vl->geometryType() )
132  {
133  case QGis::Point:
134  action->setIcon( QgsApplication::getThemeIcon( "/mIconPointLayer.png" ) );
135  break;
136  case QGis::Line:
137  action->setIcon( QgsApplication::getThemeIcon( "/mIconLineLayer.png" ) );
138  break;
139  case QGis::Polygon:
140  action->setIcon( QgsApplication::getThemeIcon( "/mIconPolygonLayer.png" ) );
141  break;
142  default:
143  break;
144  }
145  }
146  else if ( resultIt.key()->type() == QgsMapLayer::RasterLayer )
147  {
148  action->setIcon( QgsApplication::getThemeIcon( "/mIconRaster.png" ) );
149  }
150  connect( action, SIGNAL( hovered() ), this, SLOT( handleMenuHover() ) );
151  layerSelectionMenu.addAction( action );
152  }
153 
154  QAction *action = new QAction( tr( "All (%1)" ).arg( idResult.size() ), 0 );
155  connect( action, SIGNAL( hovered() ), this, SLOT( handleMenuHover() ) );
156  layerSelectionMenu.addAction( action );
157 
158  // exec layer selection menu
159  QPoint globalPos = mCanvas->mapToGlobal( QPoint( x + 5, y + 5 ) );
160  QAction* selectedAction = layerSelectionMenu.exec( globalPos );
161  if ( selectedAction )
162  {
163  if ( selectedAction->data().toString().isEmpty() )
164  {
165  results = idResult;
166  }
167  else
168  {
169  QgsMapLayer* selectedLayer = QgsMapLayerRegistry::instance()->mapLayer( selectedAction->data().toString() );
170  QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator sIt = mLayerIdResults.find( selectedLayer );
171  if ( sIt != mLayerIdResults.constEnd() )
172  {
173  results = sIt.value();
174  }
175  }
176  }
177  }
178  else if ( mLayerIdResults.size() == 1 )
179  {
180  results = idResult;
181  }
182 
184  }
185  else if ( mode == ActiveLayer && layerList.isEmpty() )
186  {
187  QgsMapLayer *layer = mCanvas->currentLayer();
188 
189  if ( !layer )
190  {
191  emit identifyMessage( tr( "No active layer. To identify features, you must choose an active layer." ) );
192  return results;
193  }
194 
195  QApplication::setOverrideCursor( Qt::WaitCursor );
196 
197  identifyLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel, layerType );
198  }
199  else
200  {
201  QApplication::setOverrideCursor( Qt::WaitCursor );
202 
203  QStringList noIdentifyLayerIdList = QgsProject::instance()->readListEntry( "Identify", "/disabledLayers" );
204 
205  int layerCount;
206  if ( layerList.isEmpty() )
207  layerCount = mCanvas->layerCount();
208  else
209  layerCount = layerList.count();
210 
211 
212  for ( int i = 0; i < layerCount; i++ )
213  {
214 
215  QgsMapLayer *layer ;
216  if ( layerList.isEmpty() )
217  layer = mCanvas->layer( i );
218  else
219  layer = layerList.value( i );
220 
221  emit identifyProgress( i, mCanvas->layerCount() );
222  emit identifyMessage( tr( "Identifying on %1..." ).arg( layer->name() ) );
223 
224  if ( noIdentifyLayerIdList.contains( layer->id() ) )
225  continue;
226 
227  if ( identifyLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel, layerType ) )
228  {
229  if ( mode == TopDownStopAtFirst )
230  break;
231  }
232  }
233 
235  emit identifyMessage( tr( "Identifying done." ) );
236  }
237 
238  QApplication::restoreOverrideCursor();
239 
240  return results;
241 }
242 
244 {
246 }
247 
249 {
251 }
252 
253 bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, QgsPoint point, QgsRectangle viewExtent, double mapUnitsPerPixel, LayerType layerType )
254 {
255  if ( layer->type() == QgsMapLayer::RasterLayer && ( layerType == AllLayers || layerType == RasterLayer ) )
256  {
257  return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), point, viewExtent, mapUnitsPerPixel );
258  }
259  else if ( layer->type() == QgsMapLayer::VectorLayer && ( layerType == AllLayers || layerType == VectorLayer ) )
260  {
261  return identifyVectorLayer( results, qobject_cast<QgsVectorLayer *>( layer ), point );
262  }
263  else
264  {
265  return false;
266  }
267 }
268 
269 bool QgsMapToolIdentify::identifyVectorLayer( QList<IdentifyResult> *results, QgsVectorLayer *layer, QgsPoint point )
270 {
271  if ( !layer || !layer->hasGeometryType() )
272  return false;
273 
274  if ( layer->hasScaleBasedVisibility() &&
275  ( layer->minimumScale() > mCanvas->mapSettings().scale() ||
276  layer->maximumScale() <= mCanvas->mapSettings().scale() ) )
277  {
278  QgsDebugMsg( "Out of scale limits" );
279  return false;
280  }
281 
282  QMap< QString, QString > commonDerivedAttributes;
283 
284  commonDerivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
285 
286  int featureCount = 0;
287 
288  QgsFeatureList featureList;
289 
290  // toLayerCoordinates will throw an exception for an 'invalid' point.
291  // For example, if you project a world map onto a globe using EPSG 2163
292  // and then click somewhere off the globe, an exception will be thrown.
293  try
294  {
295  // create the search rectangle
296  double searchRadius = searchRadiusMU( mCanvas );
297 
298  QgsRectangle r;
299  r.setXMinimum( point.x() - searchRadius );
300  r.setXMaximum( point.x() + searchRadius );
301  r.setYMinimum( point.y() - searchRadius );
302  r.setYMaximum( point.y() + searchRadius );
303 
304  r = toLayerCoordinates( layer, r );
305 
306  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) );
307  QgsFeature f;
308  while ( fit.nextFeature( f ) )
309  featureList << QgsFeature( f );
310  }
311  catch ( QgsCsException & cse )
312  {
313  Q_UNUSED( cse );
314  // catch exception for 'invalid' point and proceed with no features found
315  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
316  }
317 
318  QgsFeatureList::iterator f_it = featureList.begin();
319 
320  bool filter = false;
321 
323  QgsFeatureRendererV2* renderer = layer->rendererV2();
324  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
325  {
326  // setup scale for scale dependent visibility (rule based)
327  renderer->startRender( context, layer->pendingFields() );
328  filter = renderer->capabilities() & QgsFeatureRendererV2::Filter;
329  }
330 
331  for ( ; f_it != featureList.end(); ++f_it )
332  {
333  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
334 
335  QgsFeatureId fid = f_it->id();
336 
337  if ( filter && !renderer->willRenderFeature( *f_it ) )
338  continue;
339 
340  featureCount++;
341 
342  derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer ) );
343 
344  derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) );
345 
346  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) );
347  }
348 
349  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
350  {
351  renderer->stopRender( context );
352  }
353 
354  QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );
355 
356  return featureCount > 0;
357 }
358 
359 QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeature *feature, QgsMapLayer *layer )
360 {
361  // Calculate derived attributes and insert:
362  // measure distance or area depending on geometry type
363  QMap< QString, QString > derivedAttributes;
364 
365  // init distance/area calculator
366  QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
367  QgsDistanceArea calc;
369  calc.setEllipsoid( ellipsoid );
370  calc.setSourceCrs( layer->crs().srsid() );
371 
373  QGis::GeometryType geometryType = QGis::NoGeometry;
374 
375  if ( feature->geometry() )
376  {
377  geometryType = feature->geometry()->type();
378  wkbType = feature->geometry()->wkbType();
379  }
380 
381  if ( geometryType == QGis::Line )
382  {
383  double dist = calc.measure( feature->geometry() );
384  QGis::UnitType myDisplayUnits;
385  convertMeasurement( calc, dist, myDisplayUnits, false );
386  QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params
387  derivedAttributes.insert( tr( "Length" ), str );
388  if ( wkbType == QGis::WKBLineString || wkbType == QGis::WKBLineString25D )
389  {
390  // Add the start and end points in as derived attributes
391  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->geometry()->asPolyline().first() );
392  str = QLocale::system().toString( pnt.x(), 'g', 10 );
393  derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
394  str = QLocale::system().toString( pnt.y(), 'g', 10 );
395  derivedAttributes.insert( tr( "firstY" ), str );
396  pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->geometry()->asPolyline().last() );
397  str = QLocale::system().toString( pnt.x(), 'g', 10 );
398  derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
399  str = QLocale::system().toString( pnt.y(), 'g', 10 );
400  derivedAttributes.insert( tr( "lastY" ), str );
401  }
402  }
403  else if ( geometryType == QGis::Polygon )
404  {
405  double area = calc.measure( feature->geometry() );
406  double perimeter = calc.measurePerimeter( feature->geometry() );
407  QGis::UnitType myDisplayUnits;
408  convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params
409  QString str = calc.textUnit( area, 3, myDisplayUnits, true );
410  derivedAttributes.insert( tr( "Area" ), str );
411  convertMeasurement( calc, perimeter, myDisplayUnits, false ); // perimeter and myDisplayUnits are out params
412  str = calc.textUnit( perimeter, 3, myDisplayUnits, false );
413  derivedAttributes.insert( tr( "Perimeter" ), str );
414  }
415  else if ( geometryType == QGis::Point &&
416  ( wkbType == QGis::WKBPoint || wkbType == QGis::WKBPoint25D ) )
417  {
418  // Include the x and y coordinates of the point as a derived attribute
419  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->geometry()->asPoint() );
420  QString str = QLocale::system().toString( pnt.x(), 'g', 10 );
421  derivedAttributes.insert( "X", str );
422  str = QLocale::system().toString( pnt.y(), 'g', 10 );
423  derivedAttributes.insert( "Y", str );
424  }
425 
426  return derivedAttributes;
427 }
428 
429 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPoint point, QgsRectangle viewExtent, double mapUnitsPerPixel )
430 {
431  QgsDebugMsg( "point = " + point.toString() );
432  if ( !layer )
433  return false;
434 
435  QgsRasterDataProvider *dprovider = layer->dataProvider();
436  int capabilities = dprovider->capabilities();
437  if ( !dprovider || !( capabilities & QgsRasterDataProvider::Identify ) )
438  return false;
439 
440  QgsPoint pointInCanvasCrs = point;
441  try
442  {
443  point = toLayerCoordinates( layer, point );
444  }
445  catch ( QgsCsException &cse )
446  {
447  Q_UNUSED( cse );
448  QgsDebugMsg( QString( "coordinate not reprojectable: %1" ).arg( cse.what() ) );
449  return false;
450  }
451  QgsDebugMsg( QString( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) );
452 
453  if ( !layer->extent().contains( point ) ) return false;
454 
455  QMap< QString, QString > attributes, derivedAttributes;
456 
457  QgsRaster::IdentifyFormat format = QgsRasterDataProvider::identifyFormatFromName( layer->customProperty( "identify/format" ).toString() );
458 
459  // check if the format is really supported otherwise use first supported format
460  if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) )
461  {
463  else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRaster::IdentifyFormatValue;
464  else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRaster::IdentifyFormatHtml;
465  else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRaster::IdentifyFormatText;
466  else return false;
467  }
468 
469  QgsRasterIdentifyResult identifyResult;
470  // We can only use current map canvas context (extent, width, height) if layer is not reprojected,
471  if ( mCanvas->hasCrsTransformEnabled() && dprovider->crs() != mCanvas->mapSettings().destinationCrs() )
472  {
473  // To get some reasonable response for point/line WMS vector layers we must
474  // use a context with approximately a resolution in layer CRS units
475  // corresponding to current map canvas resolution (for examplei UMN Mapserver
476  // in msWMSFeatureInfo() -> msQueryByRect() is using requested pixel
477  // + TOLERANCE (layer param) for feature selection)
478  //
479  QgsRectangle r;
480  r.setXMinimum( pointInCanvasCrs.x() - mapUnitsPerPixel / 2. );
481  r.setXMaximum( pointInCanvasCrs.x() + mapUnitsPerPixel / 2. );
482  r.setYMinimum( pointInCanvasCrs.y() - mapUnitsPerPixel / 2. );
483  r.setYMaximum( pointInCanvasCrs.y() + mapUnitsPerPixel / 2. );
484  r = toLayerCoordinates( layer, r ); // will be a bit larger
485  // Mapserver (6.0.3, for example) does not work with 1x1 pixel box
486  // but that is fixed (the rect is enlarged) in the WMS provider
487  identifyResult = dprovider->identify( point, format, r, 1, 1 );
488  }
489  else
490  {
491  // It would be nice to use the same extent and size which was used for drawing,
492  // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw()
493  // is doing some tricks with extent and size to allign raster to output which
494  // would be difficult to replicate here.
495  // Note: cutting the extent may result in slightly different x and y resolutions
496  // and thus shifted point calculated back in QGIS WMS (using average resolution)
497  //viewExtent = dprovider->extent().intersect( &viewExtent );
498 
499  // Width and height are calculated from not projected extent and we hope that
500  // are similar to source width and height used to reproject layer for drawing.
501  // TODO: may be very dangerous, because it may result in different resolutions
502  // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution.
503  int width = qRound( viewExtent.width() / mapUnitsPerPixel );
504  int height = qRound( viewExtent.height() / mapUnitsPerPixel );
505 
506  QgsDebugMsg( QString( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) );
507  QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) );
508  QgsDebugMsg( QString( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) );
509 
510  identifyResult = dprovider->identify( point, format, viewExtent, width, height );
511  }
512 
513  derivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
514 
515  if ( identifyResult.isValid() )
516  {
517  QMap<int, QVariant> values = identifyResult.results();
518  QgsGeometry geometry;
519  if ( format == QgsRaster::IdentifyFormatValue )
520  {
521  foreach ( int bandNo, values.keys() )
522  {
523  QString valueString;
524  if ( values.value( bandNo ).isNull() )
525  {
526  valueString = tr( "no data" );
527  }
528  else
529  {
530  double value = values.value( bandNo ).toDouble();
531  valueString = QgsRasterBlock::printValue( value );
532  }
533  attributes.insert( dprovider->generateBandName( bandNo ), valueString );
534  }
535  QString label = layer->name();
536  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
537  }
538  else if ( format == QgsRaster::IdentifyFormatFeature )
539  {
540  foreach ( int i, values.keys() )
541  {
542  QVariant value = values.value( i );
543  if ( value.type() == QVariant::Bool && !value.toBool() )
544  {
545  // sublayer not visible or not queryable
546  continue;
547  }
548 
549  if ( value.type() == QVariant::String )
550  {
551  // error
552  // TODO: better error reporting
553  QString label = layer->subLayers().value( i );
554  attributes.clear();
555  attributes.insert( tr( "Error" ), value.toString() );
556 
557  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
558  continue;
559  }
560 
561  // list of feature stores for a single sublayer
562  QgsFeatureStoreList featureStoreList = values.value( i ).value<QgsFeatureStoreList>();
563 
564  foreach ( QgsFeatureStore featureStore, featureStoreList )
565  {
566  foreach ( QgsFeature feature, featureStore.features() )
567  {
568  attributes.clear();
569  // WMS sublayer and feature type, a sublayer may contain multiple feature types.
570  // Sublayer name may be the same as layer name and feature type name
571  // may be the same as sublayer. We try to avoid duplicities in label.
572  QString sublayer = featureStore.params().value( "sublayer" ).toString();
573  QString featureType = featureStore.params().value( "featureType" ).toString();
574  // Strip UMN MapServer '_feature'
575  featureType.remove( "_feature" );
576  QStringList labels;
577  if ( sublayer.compare( layer->name(), Qt::CaseInsensitive ) != 0 )
578  {
579  labels << sublayer;
580  }
581  if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
582  {
583  labels << featureType;
584  }
585 
586  QMap< QString, QString > derAttributes = derivedAttributes;
587  derAttributes.unite( featureDerivedAttributes( &feature, layer ) );
588 
589  IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( " / " ), featureStore.fields(), feature, derAttributes );
590 
591  identifyResult.mParams.insert( "getFeatureInfoUrl", featureStore.params().value( "getFeatureInfoUrl" ) );
592  results->append( identifyResult );
593  }
594  }
595  }
596  }
597  else // text or html
598  {
599  QgsDebugMsg( QString( "%1 html or text values" ).arg( values.size() ) );
600  foreach ( int bandNo, values.keys() )
601  {
602  QString value = values.value( bandNo ).toString();
603  attributes.clear();
604  attributes.insert( "", value );
605 
606  QString label = layer->subLayers().value( bandNo );
607  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
608  }
609  }
610  }
611  else
612  {
613  attributes.clear();
614  QString value = identifyResult.error().message( QgsErrorMessage::Text );
615  attributes.insert( tr( "Error" ), value );
616  QString label = tr( "Identify error" );
617  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
618  }
619 
620  return true;
621 }
622 
623 void QgsMapToolIdentify::convertMeasurement( QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea )
624 {
625  // Helper for converting between meters and feet
626  // The parameter &u is out only...
627 
628  // Get the canvas units
629  QGis::UnitType myUnits = mCanvas->mapUnits();
630 
631  calc.convertMeasurement( measure, myUnits, displayUnits(), isArea );
632  u = myUnits;
633 }
634 
636 {
637  return mCanvas->mapUnits();
638 }
639 
641 {
642  QgsDebugMsg( "Entered" );
643  QList<IdentifyResult> results;
645  {
646  emit changedRasterResults( results );
647  }
648 }
649 
651 {
652  if ( !mCanvas )
653  {
654  return;
655  }
656 
658  QAction* senderAction = qobject_cast<QAction*>( sender() );
659  if ( senderAction )
660  {
661  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( senderAction->data().toString() ) );
662  if ( vl )
663  {
664  QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator lIt = mLayerIdResults.find( vl );
665  if ( lIt != mLayerIdResults.constEnd() )
666  {
667  const QList<IdentifyResult>& idList = lIt.value();
668  QList<IdentifyResult>::const_iterator idListIt = idList.constBegin();
669  for ( ; idListIt != idList.constEnd(); ++idListIt )
670  {
671  QgsHighlight *hl = new QgsHighlight( mCanvas, idListIt->mFeature.geometry(), vl );
672  hl->setColor( QColor( 255, 0, 0 ) );
673  hl->setWidth( 2 );
674  mRubberBands.append( hl );
675  connect( vl, SIGNAL( destroyed() ), this, SLOT( layerDestroyed() ) );
676  }
677  }
678  }
679  else
680  {
681  for ( QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator lIt = mLayerIdResults.constBegin(); lIt != mLayerIdResults.constEnd(); ++lIt )
682  {
683  const QList<IdentifyResult>& idList = lIt.value();
684  QList<IdentifyResult>::const_iterator idListIt = idList.constBegin();
685  for ( ; idListIt != idList.constEnd(); ++idListIt )
686  {
687  QgsHighlight *hl = new QgsHighlight( mCanvas, idListIt->mFeature.geometry(), lIt.key() );
688  hl->setColor( QColor( 255, 0, 0 ) );
689  hl->setWidth( 2 );
690  mRubberBands.append( hl );
691  connect( lIt.key(), SIGNAL( destroyed() ), this, SLOT( layerDestroyed() ) );
692  }
693  }
694  }
695  }
696 }
697 
699 {
700  QList<QgsHighlight*>::const_iterator it = mRubberBands.constBegin();
701  for ( ; it != mRubberBands.constEnd(); ++it )
702  delete *it;
703  mRubberBands.clear();
704 }
705 
707 {
708  QList<QgsHighlight*>::iterator it = mRubberBands.begin();
709  while ( it != mRubberBands.end() )
710  {
711  if (( *it )->layer() == sender() )
712  {
713  delete *it;
714  it = mRubberBands.erase( it );
715  }
716  else
717  {
718  ++it;
719  }
720  }
721 }
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:47
QgsPoint layerToMapCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from layer's CRS to output CRS
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:86
static QString printValue(double value)
Print double value with all necessary significant digits.
static double searchRadiusMU(const QgsRenderContext &context)
Get search radius in map units for given context.
Definition: qgsmaptool.cpp:208
GeometryType
Definition: qgis.h:155
double scale() const
Return the calculated scale of the map.
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:169
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:330
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:112
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)
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
WkbType
Used for symbology operations.
Definition: qgis.h:53
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:113
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:104
QMap< int, QVariant > results() const
Get results.
double x() const
Definition: qgspoint.h:110
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
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:77
QgsMapCanvas * mCanvas
pointer to map canvas
Definition: qgsmaptool.h:184
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:187
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:174
QgsPoint toLayerCoordinates(QgsMapLayer *layer, const QPoint &point)
transformation from screen coordinates to layer's coordinates
Definition: qgsmaptool.cpp:48
A class for highlight features on the map.
Definition: qgshighlight.h:36
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:92
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:91
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
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:113
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:48
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
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
Contains information about the context of a rendering operation.
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)
Set line/outline to color, polygon fill to color with alpha = 63.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:179
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
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
const CORE_EXPORT QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.cpp:73
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.
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 QgsFields & pendingFields() const
returns field list in the to-be-committed state
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:204
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:164
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:209
Base class for raster data providers.
bool identifyVectorLayer(QList< IdentifyResult > *results, QgsVectorLayer *layer, QgsPoint point)
void setWidth(int width)
Set width.
#define tr(sourceText)