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