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;

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

protected:
/**
* 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 */
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. */
void panToSelected( QgsVectorLayer* layer = NULL );

Expand Down Expand Up @@ -501,6 +506,9 @@ class QgsMapCanvas : QGraphicsView
//! @note added in 2.12
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:
//! Overridden standard event to be gestures aware
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
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
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
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 "
"layers are displayed when added to the map" ) );

Expand Down Expand Up @@ -1034,6 +1036,8 @@ QgisApp::QgisApp()
setupUi( this );
mInternalClipboard = new QgsClipboard;
mMapCanvas = new QgsMapCanvas();
connect( mMapCanvas, SIGNAL( messageEmitted( const QString&, const QString&, QgsMessageBar::MessageLevel ) ),
this, SLOT( displayMessage( const QString&, const QString&, QgsMessageBar::MessageLevel ) ) );
mMapCanvas->freeze();
mLayerTreeView = new QgsLayerTreeView( this );
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()
{
// 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 showStatusMessage( const QString& theMessage );
void displayMapToolMessage( const QString& message, QgsMessageBar::MessageLevel level = QgsMessageBar::INFO );
void displayMessage( const QString& title, const QString& message, QgsMessageBar::MessageLevel level );
void removeMapToolMessage();
void updateMouseCoordinatePrecision();
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;

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

protected:
/**
* 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 )
{
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 );

//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() ) );
}

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 )
{
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();

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

private:
void initLayerCache( QgsVectorLayer *layer, bool cacheGeometry );
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;

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

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

setExtent( rect );
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 )
{
Expand Down
14 changes: 14 additions & 0 deletions src/gui/qgsmapcanvas.h
Expand Up @@ -21,6 +21,8 @@
#include "qgsconfig.h"

#include "qgsexpressioncontext.h"
#include "qgsfeature.h"
#include "qgsmessagebar.h"
#include "qgsrectangle.h"
#include "qgspoint.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 */
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. */
void panToSelected( QgsVectorLayer* layer = nullptr );

Expand Down Expand Up @@ -580,6 +587,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! @note added in 2.12
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:
#ifdef HAVE_TOUCH
//! 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
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
void updateCanvasItemPositions();

Expand Down

0 comments on commit 3febba2

Please sign in to comment.