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 }