QGIS API Documentation  2.5.0-Master
 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, layerList, layerType );
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.testFlag( RasterLayer ) )
256  {
257  return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), point, viewExtent, mapUnitsPerPixel );
258  }
259  else if ( layer->type() == QgsMapLayer::VectorLayer && layerType.testFlag( 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  QApplication::setOverrideCursor(Qt::WaitCursor);
283 
284  QMap< QString, QString > commonDerivedAttributes;
285 
286  commonDerivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
287 
288  int featureCount = 0;
289 
290  QgsFeatureList featureList;
291 
292  // toLayerCoordinates will throw an exception for an 'invalid' point.
293  // For example, if you project a world map onto a globe using EPSG 2163
294  // and then click somewhere off the globe, an exception will be thrown.
295  try
296  {
297  // create the search rectangle
298  double searchRadius = searchRadiusMU( mCanvas );
299 
300  QgsRectangle r;
301  r.setXMinimum( point.x() - searchRadius );
302  r.setXMaximum( point.x() + searchRadius );
303  r.setYMinimum( point.y() - searchRadius );
304  r.setYMaximum( point.y() + searchRadius );
305 
306  r = toLayerCoordinates( layer, r );
307 
308  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) );
309  QgsFeature f;
310  while ( fit.nextFeature( f ) )
311  featureList << QgsFeature( f );
312  }
313  catch ( QgsCsException & cse )
314  {
315  Q_UNUSED( cse );
316  // catch exception for 'invalid' point and proceed with no features found
317  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
318  }
319 
320  QgsFeatureList::iterator f_it = featureList.begin();
321 
322  bool filter = false;
323 
325  QgsFeatureRendererV2* renderer = layer->rendererV2();
326  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
327  {
328  // setup scale for scale dependent visibility (rule based)
329  renderer->startRender( context, layer->pendingFields() );
330  filter = renderer->capabilities() & QgsFeatureRendererV2::Filter;
331  }
332 
333  for ( ; f_it != featureList.end(); ++f_it )
334  {
335  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
336 
337  QgsFeatureId fid = f_it->id();
338 
339  if ( filter && !renderer->willRenderFeature( *f_it ) )
340  continue;
341 
342  featureCount++;
343 
344  derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer ) );
345 
346  derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) );
347 
348  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) );
349  }
350 
351  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
352  {
353  renderer->stopRender( context );
354  }
355 
356  QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );
357 
358  QApplication::restoreOverrideCursor();
359  return featureCount > 0;
360 }
361 
362 QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeature *feature, QgsMapLayer *layer )
363 {
364  // Calculate derived attributes and insert:
365  // measure distance or area depending on geometry type
366  QMap< QString, QString > derivedAttributes;
367 
368  // init distance/area calculator
369  QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
370  QgsDistanceArea calc;
372  calc.setEllipsoid( ellipsoid );
373  calc.setSourceCrs( layer->crs().srsid() );
374 
376  QGis::GeometryType geometryType = QGis::NoGeometry;
377 
378  if ( feature->geometry() )
379  {
380  geometryType = feature->geometry()->type();
381  wkbType = feature->geometry()->wkbType();
382  }
383 
384  if ( geometryType == QGis::Line )
385  {
386  double dist = calc.measure( feature->geometry() );
387  QGis::UnitType myDisplayUnits;
388  convertMeasurement( calc, dist, myDisplayUnits, false );
389  QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params
390  derivedAttributes.insert( tr( "Length" ), str );
391  if ( wkbType == QGis::WKBLineString || wkbType == QGis::WKBLineString25D )
392  {
393  // Add the start and end points in as derived attributes
394  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->geometry()->asPolyline().first() );
395  str = QLocale::system().toString( pnt.x(), 'g', 10 );
396  derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
397  str = QLocale::system().toString( pnt.y(), 'g', 10 );
398  derivedAttributes.insert( tr( "firstY" ), str );
399  pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->geometry()->asPolyline().last() );
400  str = QLocale::system().toString( pnt.x(), 'g', 10 );
401  derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
402  str = QLocale::system().toString( pnt.y(), 'g', 10 );
403  derivedAttributes.insert( tr( "lastY" ), str );
404  }
405  }
406  else if ( geometryType == QGis::Polygon )
407  {
408  double area = calc.measure( feature->geometry() );
409  double perimeter = calc.measurePerimeter( feature->geometry() );
410  QGis::UnitType myDisplayUnits;
411  convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params
412  QString str = calc.textUnit( area, 3, myDisplayUnits, true );
413  derivedAttributes.insert( tr( "Area" ), str );
414  convertMeasurement( calc, perimeter, myDisplayUnits, false ); // perimeter and myDisplayUnits are out params
415  str = calc.textUnit( perimeter, 3, myDisplayUnits, false );
416  derivedAttributes.insert( tr( "Perimeter" ), str );
417  }
418  else if ( geometryType == QGis::Point &&
419  ( wkbType == QGis::WKBPoint || wkbType == QGis::WKBPoint25D ) )
420  {
421  // Include the x and y coordinates of the point as a derived attribute
422  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->geometry()->asPoint() );
423  QString str = QLocale::system().toString( pnt.x(), 'g', 10 );
424  derivedAttributes.insert( "X", str );
425  str = QLocale::system().toString( pnt.y(), 'g', 10 );
426  derivedAttributes.insert( "Y", str );
427  }
428 
429  return derivedAttributes;
430 }
431 
432 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPoint point, QgsRectangle viewExtent, double mapUnitsPerPixel )
433 {
434  QgsDebugMsg( "point = " + point.toString() );
435  if ( !layer )
436  return false;
437 
438  QgsRasterDataProvider *dprovider = layer->dataProvider();
439  int capabilities = dprovider->capabilities();
440  if ( !dprovider || !( capabilities & QgsRasterDataProvider::Identify ) )
441  return false;
442 
443  QgsPoint pointInCanvasCrs = point;
444  try
445  {
446  point = toLayerCoordinates( layer, point );
447  }
448  catch ( QgsCsException &cse )
449  {
450  Q_UNUSED( cse );
451  QgsDebugMsg( QString( "coordinate not reprojectable: %1" ).arg( cse.what() ) );
452  return false;
453  }
454  QgsDebugMsg( QString( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) );
455 
456  if ( !layer->extent().contains( point ) ) return false;
457 
458  QMap< QString, QString > attributes, derivedAttributes;
459 
460  QgsRaster::IdentifyFormat format = QgsRasterDataProvider::identifyFormatFromName( layer->customProperty( "identify/format" ).toString() );
461 
462  // check if the format is really supported otherwise use first supported format
463  if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) )
464  {
466  else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRaster::IdentifyFormatValue;
467  else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRaster::IdentifyFormatHtml;
468  else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRaster::IdentifyFormatText;
469  else return false;
470  }
471 
472  QgsRasterIdentifyResult identifyResult;
473  // We can only use current map canvas context (extent, width, height) if layer is not reprojected,
474  if ( mCanvas->hasCrsTransformEnabled() && dprovider->crs() != mCanvas->mapSettings().destinationCrs() )
475  {
476  // To get some reasonable response for point/line WMS vector layers we must
477  // use a context with approximately a resolution in layer CRS units
478  // corresponding to current map canvas resolution (for examplei UMN Mapserver
479  // in msWMSFeatureInfo() -> msQueryByRect() is using requested pixel
480  // + TOLERANCE (layer param) for feature selection)
481  //
482  QgsRectangle r;
483  r.setXMinimum( pointInCanvasCrs.x() - mapUnitsPerPixel / 2. );
484  r.setXMaximum( pointInCanvasCrs.x() + mapUnitsPerPixel / 2. );
485  r.setYMinimum( pointInCanvasCrs.y() - mapUnitsPerPixel / 2. );
486  r.setYMaximum( pointInCanvasCrs.y() + mapUnitsPerPixel / 2. );
487  r = toLayerCoordinates( layer, r ); // will be a bit larger
488  // Mapserver (6.0.3, for example) does not work with 1x1 pixel box
489  // but that is fixed (the rect is enlarged) in the WMS provider
490  identifyResult = dprovider->identify( point, format, r, 1, 1 );
491  }
492  else
493  {
494  // It would be nice to use the same extent and size which was used for drawing,
495  // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw()
496  // is doing some tricks with extent and size to allign raster to output which
497  // would be difficult to replicate here.
498  // Note: cutting the extent may result in slightly different x and y resolutions
499  // and thus shifted point calculated back in QGIS WMS (using average resolution)
500  //viewExtent = dprovider->extent().intersect( &viewExtent );
501 
502  // Width and height are calculated from not projected extent and we hope that
503  // are similar to source width and height used to reproject layer for drawing.
504  // TODO: may be very dangerous, because it may result in different resolutions
505  // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution.
506  int width = qRound( viewExtent.width() / mapUnitsPerPixel );
507  int height = qRound( viewExtent.height() / mapUnitsPerPixel );
508 
509  QgsDebugMsg( QString( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) );
510  QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) );
511  QgsDebugMsg( QString( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) );
512 
513  identifyResult = dprovider->identify( point, format, viewExtent, width, height );
514  }
515 
516  derivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
517 
518  if ( identifyResult.isValid() )
519  {
520  QMap<int, QVariant> values = identifyResult.results();
521  QgsGeometry geometry;
522  if ( format == QgsRaster::IdentifyFormatValue )
523  {
524  foreach ( int bandNo, values.keys() )
525  {
526  QString valueString;
527  if ( values.value( bandNo ).isNull() )
528  {
529  valueString = tr( "no data" );
530  }
531  else
532  {
533  double value = values.value( bandNo ).toDouble();
534  valueString = QgsRasterBlock::printValue( value );
535  }
536  attributes.insert( dprovider->generateBandName( bandNo ), valueString );
537  }
538  QString label = layer->name();
539  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
540  }
541  else if ( format == QgsRaster::IdentifyFormatFeature )
542  {
543  foreach ( int i, values.keys() )
544  {
545  QVariant value = values.value( i );
546  if ( value.type() == QVariant::Bool && !value.toBool() )
547  {
548  // sublayer not visible or not queryable
549  continue;
550  }
551 
552  if ( value.type() == QVariant::String )
553  {
554  // error
555  // TODO: better error reporting
556  QString label = layer->subLayers().value( i );
557  attributes.clear();
558  attributes.insert( tr( "Error" ), value.toString() );
559 
560  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
561  continue;
562  }
563 
564  // list of feature stores for a single sublayer
565  QgsFeatureStoreList featureStoreList = values.value( i ).value<QgsFeatureStoreList>();
566 
567  foreach ( QgsFeatureStore featureStore, featureStoreList )
568  {
569  foreach ( QgsFeature feature, featureStore.features() )
570  {
571  attributes.clear();
572  // WMS sublayer and feature type, a sublayer may contain multiple feature types.
573  // Sublayer name may be the same as layer name and feature type name
574  // may be the same as sublayer. We try to avoid duplicities in label.
575  QString sublayer = featureStore.params().value( "sublayer" ).toString();
576  QString featureType = featureStore.params().value( "featureType" ).toString();
577  // Strip UMN MapServer '_feature'
578  featureType.remove( "_feature" );
579  QStringList labels;
580  if ( sublayer.compare( layer->name(), Qt::CaseInsensitive ) != 0 )
581  {
582  labels << sublayer;
583  }
584  if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
585  {
586  labels << featureType;
587  }
588 
589  QMap< QString, QString > derAttributes = derivedAttributes;
590  derAttributes.unite( featureDerivedAttributes( &feature, layer ) );
591 
592  IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( " / " ), featureStore.fields(), feature, derAttributes );
593 
594  identifyResult.mParams.insert( "getFeatureInfoUrl", featureStore.params().value( "getFeatureInfoUrl" ) );
595  results->append( identifyResult );
596  }
597  }
598  }
599  }
600  else // text or html
601  {
602  QgsDebugMsg( QString( "%1 html or text values" ).arg( values.size() ) );
603  foreach ( int bandNo, values.keys() )
604  {
605  QString value = values.value( bandNo ).toString();
606  attributes.clear();
607  attributes.insert( "", value );
608 
609  QString label = layer->subLayers().value( bandNo );
610  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
611  }
612  }
613  }
614  else
615  {
616  attributes.clear();
617  QString value = identifyResult.error().message( QgsErrorMessage::Text );
618  attributes.insert( tr( "Error" ), value );
619  QString label = tr( "Identify error" );
620  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
621  }
622 
623  return true;
624 }
625 
626 void QgsMapToolIdentify::convertMeasurement( QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea )
627 {
628  // Helper for converting between meters and feet
629  // The parameter &u is out only...
630 
631  // Get the canvas units
632  QGis::UnitType myUnits = mCanvas->mapUnits();
633 
634  calc.convertMeasurement( measure, myUnits, displayUnits(), isArea );
635  u = myUnits;
636 }
637 
639 {
640  return mCanvas->mapUnits();
641 }
642 
644 {
645  QgsDebugMsg( "Entered" );
646  QList<IdentifyResult> results;
648  {
649  emit changedRasterResults( results );
650  }
651 }
652 
654 {
655  if ( !mCanvas )
656  {
657  return;
658  }
659 
661  QAction* senderAction = qobject_cast<QAction*>( sender() );
662  if ( senderAction )
663  {
664  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( senderAction->data().toString() ) );
665  if ( vl )
666  {
667  QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator lIt = mLayerIdResults.find( vl );
668  if ( lIt != mLayerIdResults.constEnd() )
669  {
670  const QList<IdentifyResult>& idList = lIt.value();
671  QList<IdentifyResult>::const_iterator idListIt = idList.constBegin();
672  for ( ; idListIt != idList.constEnd(); ++idListIt )
673  {
674  QgsHighlight *hl = new QgsHighlight( mCanvas, idListIt->mFeature.geometry(), vl );
675  hl->setColor( QColor( 255, 0, 0 ) );
676  hl->setWidth( 2 );
677  mRubberBands.append( hl );
678  connect( vl, SIGNAL( destroyed() ), this, SLOT( layerDestroyed() ) );
679  }
680  }
681  }
682  else
683  {
684  for ( QMap< QgsMapLayer*, QList<IdentifyResult> >::const_iterator lIt = mLayerIdResults.constBegin(); lIt != mLayerIdResults.constEnd(); ++lIt )
685  {
686  const QList<IdentifyResult>& idList = lIt.value();
687  QList<IdentifyResult>::const_iterator idListIt = idList.constBegin();
688  for ( ; idListIt != idList.constEnd(); ++idListIt )
689  {
690  QgsHighlight *hl = new QgsHighlight( mCanvas, idListIt->mFeature.geometry(), lIt.key() );
691  hl->setColor( QColor( 255, 0, 0 ) );
692  hl->setWidth( 2 );
693  mRubberBands.append( hl );
694  connect( lIt.key(), SIGNAL( destroyed() ), this, SLOT( layerDestroyed() ) );
695  }
696  }
697  }
698  }
699 }
700 
702 {
703  QList<QgsHighlight*>::const_iterator it = mRubberBands.constBegin();
704  for ( ; it != mRubberBands.constEnd(); ++it )
705  delete *it;
706  mRubberBands.clear();
707 }
708 
710 {
711  QList<QgsHighlight*>::iterator it = mRubberBands.begin();
712  while ( it != mRubberBands.end() )
713  {
714  if (( *it )->layer() == sender() )
715  {
716  delete *it;
717  it = mRubberBands.erase( it );
718  }
719  else
720  {
721  ++it;
722  }
723  }
724 }
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:48
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:89
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:212
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:190
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:193
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:95
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:93
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:117
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)