Skip to content

Commit

Permalink
Merge pull request #2619 from mhugent/zoom_to_feature
Browse files Browse the repository at this point in the history
[FEATURE]: Zoom to feature with right-click in attribute table
  • Loading branch information
mhugent committed Jan 12, 2016
2 parents e351d24 + fb996ae commit 3febba2
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 1 deletion.
3 changes: 3 additions & 0 deletions python/gui/attributetable/qgsattributetablefiltermodel.sip
Expand Up @@ -96,6 +96,9 @@ class QgsAttributeTableFilterModel: QSortFilterProxyModel, QgsFeatureModel


virtual QModelIndex mapFromMaster( const QModelIndex &sourceIndex ) const; virtual QModelIndex mapFromMaster( const QModelIndex &sourceIndex ) const;


/** Returns the map canvas*/
QgsMapCanvas* mapCanvas() const;

protected: protected:
/** /**
* Returns true if the source row will be accepted * Returns true if the source row will be accepted
Expand Down
12 changes: 12 additions & 0 deletions python/gui/qgsmapcanvas.sip
Expand Up @@ -168,6 +168,11 @@ class QgsMapCanvas : QGraphicsView
@param layer optionally specify different than current layer */ @param layer optionally specify different than current layer */
void zoomToSelected( QgsVectorLayer* layer = NULL ); void zoomToSelected( QgsVectorLayer* layer = NULL );


/** Set canvas extent to the bounding box of a feature
@param layer the vector layer
@param id the feature id*/
void zoomToFeatureId( QgsVectorLayer* layer, QgsFeatureId id );

/** Pan to the selected features of current (vector) layer keeping same extent. */ /** Pan to the selected features of current (vector) layer keeping same extent. */
void panToSelected( QgsVectorLayer* layer = NULL ); void panToSelected( QgsVectorLayer* layer = NULL );


Expand Down Expand Up @@ -501,6 +506,9 @@ class QgsMapCanvas : QGraphicsView
//! @note added in 2.12 //! @note added in 2.12
void layerStyleOverridesChanged(); void layerStyleOverridesChanged();


//! emit a message (usually to be displayed in a message bar)
void messageEmitted( const QString& title, const QString& message, QgsMessageBar::MessageLevel = QgsMessageBar::INFO );

protected: protected:
//! Overridden standard event to be gestures aware //! Overridden standard event to be gestures aware
bool event( QEvent * e ); bool event( QEvent * e );
Expand Down Expand Up @@ -538,6 +546,10 @@ class QgsMapCanvas : QGraphicsView
//! called when panning is in action, reset indicates end of panning //! called when panning is in action, reset indicates end of panning
void moveCanvasContents( bool reset = false ); void moveCanvasContents( bool reset = false );


//! Zooms to feature extent. Adds a small margin around the extent
//! and does a pan if rect is empty (point extent)
void zoomToFeatureExtent( QgsRectangle& rect );

//! called on resize or changed extent to notify canvas items to change their rectangle //! called on resize or changed extent to notify canvas items to change their rectangle
void updateCanvasItemPositions(); void updateCanvasItemPositions();


Expand Down
9 changes: 9 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -620,6 +620,8 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, QWidget * parent,


// "theMapCanvas" used to find this canonical instance later // "theMapCanvas" used to find this canonical instance later
mMapCanvas = new QgsMapCanvas( centralWidget, "theMapCanvas" ); mMapCanvas = new QgsMapCanvas( centralWidget, "theMapCanvas" );
connect( mMapCanvas, SIGNAL( messageEmitted( const QString&, const QString&, QgsMessageBar::MessageLevel ) ),
this, SLOT( displayMessage( const QString&, const QString&, QgsMessageBar::MessageLevel ) ) );
mMapCanvas->setWhatsThis( tr( "Map canvas. This is where raster and vector " mMapCanvas->setWhatsThis( tr( "Map canvas. This is where raster and vector "
"layers are displayed when added to the map" ) ); "layers are displayed when added to the map" ) );


Expand Down Expand Up @@ -1034,6 +1036,8 @@ QgisApp::QgisApp()
setupUi( this ); setupUi( this );
mInternalClipboard = new QgsClipboard; mInternalClipboard = new QgsClipboard;
mMapCanvas = new QgsMapCanvas(); mMapCanvas = new QgsMapCanvas();
connect( mMapCanvas, SIGNAL( messageEmitted( const QString&, const QString&, QgsMessageBar::MessageLevel ) ),
this, SLOT( displayMessage( const QString&, const QString&, QgsMessageBar::MessageLevel ) ) );
mMapCanvas->freeze(); mMapCanvas->freeze();
mLayerTreeView = new QgsLayerTreeView( this ); mLayerTreeView = new QgsLayerTreeView( this );
mUndoWidget = new QgsUndoWidget( nullptr, mMapCanvas ); mUndoWidget = new QgsUndoWidget( nullptr, mMapCanvas );
Expand Down Expand Up @@ -9459,6 +9463,11 @@ void QgisApp::displayMapToolMessage( const QString& message, QgsMessageBar::Mess
} }
} }


void QgisApp::displayMessage( const QString& title, const QString& message, QgsMessageBar::MessageLevel level )
{
messageBar()->pushMessage( title, message, level, messageTimeout() );
}

void QgisApp::removeMapToolMessage() void QgisApp::removeMapToolMessage()
{ {
// remove previous message // remove previous message
Expand Down
1 change: 1 addition & 0 deletions src/app/qgisapp.h
Expand Up @@ -1088,6 +1088,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void showRotation(); void showRotation();
void showStatusMessage( const QString& theMessage ); void showStatusMessage( const QString& theMessage );
void displayMapToolMessage( const QString& message, QgsMessageBar::MessageLevel level = QgsMessageBar::INFO ); void displayMapToolMessage( const QString& message, QgsMessageBar::MessageLevel level = QgsMessageBar::INFO );
void displayMessage( const QString& title, const QString& message, QgsMessageBar::MessageLevel level );
void removeMapToolMessage(); void removeMapToolMessage();
void updateMouseCoordinatePrecision(); void updateMouseCoordinatePrecision();
void hasCrsTransformEnabled( bool theFlag ); void hasCrsTransformEnabled( bool theFlag );
Expand Down
3 changes: 3 additions & 0 deletions src/gui/attributetable/qgsattributetablefiltermodel.h
Expand Up @@ -151,6 +151,9 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
*/ */
virtual void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override; virtual void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override;


/** Returns the map canvas*/
QgsMapCanvas* mapCanvas() const { return mCanvas; }

protected: protected:
/** /**
* Returns true if the source row will be accepted * Returns true if the source row will be accepted
Expand Down
28 changes: 28 additions & 0 deletions src/gui/attributetable/qgsdualview.cpp
Expand Up @@ -348,6 +348,18 @@ int QgsDualView::filteredFeatureCount()


void QgsDualView::viewWillShowContextMenu( QMenu* menu, const QModelIndex& atIndex ) void QgsDualView::viewWillShowContextMenu( QMenu* menu, const QModelIndex& atIndex )
{ {
if ( !menu )
{
return;
}

QgsVectorLayer* vl = mFilterModel->layer();
QgsMapCanvas* canvas = mFilterModel->mapCanvas();
if ( canvas && vl && vl->geometryType() != QGis::NoGeometry )
{
menu->addAction( tr( "Zoom to feature" ), this, SLOT( zoomToCurrentFeature() ) );
}

QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex ); QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );


//add user-defined actions to context menu //add user-defined actions to context menu
Expand Down Expand Up @@ -389,6 +401,22 @@ void QgsDualView::viewWillShowContextMenu( QMenu* menu, const QModelIndex& atInd
menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) ); menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
} }


void QgsDualView::zoomToCurrentFeature()
{
QModelIndex currentIndex = mTableView->currentIndex();
if ( !currentIndex.isValid() )
{
return;
}

QgsFeatureId id = mFilterModel->rowToId( currentIndex );
QgsMapCanvas* canvas = mFilterModel->mapCanvas();
if ( canvas )
{
canvas->zoomToFeatureId( mLayerCache->layer(), id );
}
}

void QgsDualView::previewExpressionChanged( const QString& expression ) void QgsDualView::previewExpressionChanged( const QString& expression )
{ {
mLayerCache->layer()->setDisplayExpression( expression ); mLayerCache->layer()->setDisplayExpression( expression );
Expand Down
3 changes: 3 additions & 0 deletions src/gui/attributetable/qgsdualview.h
Expand Up @@ -217,6 +217,9 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
*/ */
virtual void finished(); virtual void finished();


/** Zooms to the active feature*/
void zoomToCurrentFeature();

private: private:
void initLayerCache( QgsVectorLayer *layer, bool cacheGeometry ); void initLayerCache( QgsVectorLayer *layer, bool cacheGeometry );
void initModels( QgsMapCanvas* mapCanvas, const QgsFeatureRequest& request ); void initModels( QgsMapCanvas* mapCanvas, const QgsFeatureRequest& request );
Expand Down
41 changes: 40 additions & 1 deletion src/gui/qgsmapcanvas.cpp
Expand Up @@ -1044,7 +1044,11 @@ void QgsMapCanvas::zoomToSelected( QgsVectorLayer* layer )
return; return;


QgsRectangle rect = mapSettings().layerExtentToOutputExtent( layer, layer->boundingBoxOfSelected() ); QgsRectangle rect = mapSettings().layerExtentToOutputExtent( layer, layer->boundingBoxOfSelected() );
zoomToFeatureExtent( rect );
} // zoomToSelected


void QgsMapCanvas::zoomToFeatureExtent( QgsRectangle& rect )
{
// no selected features, only one selected point feature // no selected features, only one selected point feature
//or two point features with the same x- or y-coordinates //or two point features with the same x- or y-coordinates
if ( rect.isEmpty() ) if ( rect.isEmpty() )
Expand All @@ -1065,7 +1069,42 @@ void QgsMapCanvas::zoomToSelected( QgsVectorLayer* layer )


setExtent( rect ); setExtent( rect );
refresh(); refresh();
} // zoomToSelected }

void QgsMapCanvas::zoomToFeatureId( QgsVectorLayer* layer, QgsFeatureId id )
{
if ( !layer )
{
return;
}

QgsFeatureIterator it = layer->getFeatures( QgsFeatureRequest().setFilterFid( id ).setSubsetOfAttributes( QgsAttributeList() ) );
QgsFeature fet;
if ( !it.nextFeature( fet ) )
{
return;
}

QgsGeometry* geom = fet.geometry();

QString errorMessage;
if ( !geom || !geom->geometry() )
{
errorMessage = tr( "Feature does not have a geometry" );
}
else if ( geom->geometry()->isEmpty() )
{
errorMessage = tr( "Feature geometry is empty" );
}
if ( !errorMessage.isEmpty() )
{
emit messageEmitted( tr( "Zoom to feature id failed" ), errorMessage, QgsMessageBar::WARNING );
return;
}

QgsRectangle rect = mapSettings().layerExtentToOutputExtent( layer, geom->boundingBox() );
zoomToFeatureExtent( rect );
}


void QgsMapCanvas::panToSelected( QgsVectorLayer* layer ) void QgsMapCanvas::panToSelected( QgsVectorLayer* layer )
{ {
Expand Down
14 changes: 14 additions & 0 deletions src/gui/qgsmapcanvas.h
Expand Up @@ -21,6 +21,8 @@
#include "qgsconfig.h" #include "qgsconfig.h"


#include "qgsexpressioncontext.h" #include "qgsexpressioncontext.h"
#include "qgsfeature.h"
#include "qgsmessagebar.h"
#include "qgsrectangle.h" #include "qgsrectangle.h"
#include "qgspoint.h" #include "qgspoint.h"
#include "qgis.h" #include "qgis.h"
Expand Down Expand Up @@ -236,6 +238,11 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
@param layer optionally specify different than current layer */ @param layer optionally specify different than current layer */
void zoomToSelected( QgsVectorLayer* layer = nullptr ); void zoomToSelected( QgsVectorLayer* layer = nullptr );


/** Set canvas extent to the bounding box of a feature
@param layer the vector layer
@param id the feature id*/
void zoomToFeatureId( QgsVectorLayer* layer, QgsFeatureId id );

/** Pan to the selected features of current (vector) layer keeping same extent. */ /** Pan to the selected features of current (vector) layer keeping same extent. */
void panToSelected( QgsVectorLayer* layer = nullptr ); void panToSelected( QgsVectorLayer* layer = nullptr );


Expand Down Expand Up @@ -580,6 +587,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! @note added in 2.12 //! @note added in 2.12
void layerStyleOverridesChanged(); void layerStyleOverridesChanged();


//! emit a message (usually to be displayed in a message bar)
void messageEmitted( const QString& title, const QString& message, QgsMessageBar::MessageLevel = QgsMessageBar::INFO );

protected: protected:
#ifdef HAVE_TOUCH #ifdef HAVE_TOUCH
//! Overridden standard event to be gestures aware //! Overridden standard event to be gestures aware
Expand Down Expand Up @@ -619,6 +629,10 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! called when panning is in action, reset indicates end of panning //! called when panning is in action, reset indicates end of panning
void moveCanvasContents( bool reset = false ); void moveCanvasContents( bool reset = false );


//! Zooms to feature extent. Adds a small margin around the extent
//! and does a pan if rect is empty (point extent)
void zoomToFeatureExtent( QgsRectangle& rect );

//! called on resize or changed extent to notify canvas items to change their rectangle //! called on resize or changed extent to notify canvas items to change their rectangle
void updateCanvasItemPositions(); void updateCanvasItemPositions();


Expand Down

0 comments on commit 3febba2

Please sign in to comment.