Skip to content

Commit dc2c78f

Browse files
committedOct 15, 2018
Implement zoom to feature
1 parent 4988382 commit dc2c78f

7 files changed

+109
-16
lines changed
 

‎src/app/qgisapp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
932932
{
933933
mInfoBar->pushWarning( tr( "Geometry Validation" ), message );
934934
} );
935-
mGeometryValidationDock = new QgsGeometryValidationDock( tr( "Geometry Validation" ) );
935+
mGeometryValidationDock = new QgsGeometryValidationDock( tr( "Geometry Validation" ), mMapCanvas );
936936
mGeometryValidationModel = new QgsGeometryValidationModel( mGeometryValidationService.get(), mGeometryValidationDock );
937937
connect( this, &QgisApp::activeLayerChanged, mGeometryValidationModel, [this]( QgsMapLayer * layer )
938938
{

‎src/app/qgsgeometryvalidationdock.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,23 @@ email : matthias@opengis.ch
1515

1616
#include "qgsgeometryvalidationdock.h"
1717
#include "qgsgeometryvalidationmodel.h"
18+
#include "qgsmapcanvas.h"
1819

1920
#include <QButtonGroup>
2021

21-
QgsGeometryValidationDock::QgsGeometryValidationDock( const QString &title, QWidget *parent, Qt::WindowFlags flags )
22+
QgsGeometryValidationDock::QgsGeometryValidationDock( const QString &title, QgsMapCanvas *mapCanvas, QWidget *parent, Qt::WindowFlags flags )
2223
: QgsDockWidget( title, parent, flags )
24+
, mMapCanvas( mapCanvas )
2325
{
2426
setupUi( this );
2527

2628
connect( mNextButton, &QPushButton::clicked, this, &QgsGeometryValidationDock::gotoNextError );
2729
connect( mPreviousButton, &QPushButton::clicked, this, &QgsGeometryValidationDock::gotoPreviousError );
2830
connect( mZoomToProblemButton, &QPushButton::clicked, this, &QgsGeometryValidationDock::zoomToProblem );
2931
connect( mZoomToFeatureButton, &QPushButton::clicked, this, &QgsGeometryValidationDock::zoomToFeature );
30-
31-
onCurrentErrorChanged( QModelIndex(), QModelIndex() );
32+
connect( mMapCanvas, &QgsMapCanvas::currentLayerChanged, this, &QgsGeometryValidationDock::updateLayerTransform );
33+
connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsGeometryValidationDock::updateLayerTransform );
34+
connect( mMapCanvas, &QgsMapCanvas::transformContextChanged, this, &QgsGeometryValidationDock::updateLayerTransform );
3235
}
3336

3437
QgsGeometryValidationModel *QgsGeometryValidationDock::geometryValidationModel() const
@@ -59,16 +62,41 @@ void QgsGeometryValidationDock::gotoPreviousError()
5962
void QgsGeometryValidationDock::zoomToProblem()
6063
{
6164
mLastZoomToAction = ZoomToProblem;
65+
if ( !currentIndex().isValid() )
66+
return;
67+
68+
QgsRectangle problemExtent = currentIndex().data( QgsGeometryValidationModel::ProblemExtentRole ).value<QgsRectangle>();
69+
QgsRectangle mapExtent = mLayerTransform.transform( problemExtent );
70+
mMapCanvas->zoomToFeatureExtent( mapExtent );
6271
}
6372

6473
void QgsGeometryValidationDock::zoomToFeature()
6574
{
6675
mLastZoomToAction = ZoomToFeature;
67-
// mErrorListView->currentIndex().data( )
76+
if ( !currentIndex().isValid() )
77+
return;
78+
79+
QgsRectangle featureExtent = currentIndex().data( QgsGeometryValidationModel::FeatureExtentRole ).value<QgsRectangle>();
80+
QgsRectangle mapExtent = mLayerTransform.transform( featureExtent );
81+
mMapCanvas->zoomToFeatureExtent( mapExtent );
82+
}
83+
84+
void QgsGeometryValidationDock::updateLayerTransform()
85+
{
86+
if ( !mMapCanvas->currentLayer() )
87+
return;
88+
89+
mLayerTransform = QgsCoordinateTransform( mMapCanvas->currentLayer()->crs(), mMapCanvas->mapSettings().destinationCrs(), mMapCanvas->mapSettings().transformContext() );
90+
}
91+
92+
QModelIndex QgsGeometryValidationDock::currentIndex() const
93+
{
94+
return mErrorListView->selectionModel()->currentIndex();
6895
}
6996

7097
void QgsGeometryValidationDock::onCurrentErrorChanged( const QModelIndex &current, const QModelIndex &previous )
7198
{
99+
Q_UNUSED( previous )
72100
mNextButton->setEnabled( current.isValid() && current.row() < mGeometryValidationModel->rowCount() - 1 );
73101
mPreviousButton->setEnabled( current.isValid() && current.row() > 0 );
74102

@@ -83,5 +111,6 @@ void QgsGeometryValidationDock::onCurrentErrorChanged( const QModelIndex &curren
83111

84112
case ZoomToFeature:
85113
zoomToFeature();
114+
break;
86115
}
87116
}

‎src/app/qgsgeometryvalidationdock.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ email : matthias@opengis.ch
1818

1919
#include "ui_qgsgeometryvalidationdockbase.h"
2020
#include "qgsdockwidget.h"
21+
#include "qgscoordinatetransform.h"
2122

23+
class QgsMapCanvas;
2224
class QgsGeometryValidationModel;
2325

2426
/**
@@ -29,7 +31,7 @@ class QgsGeometryValidationDock : public QgsDockWidget, public Ui_QgsGeometryVal
2931
Q_OBJECT
3032

3133
public:
32-
QgsGeometryValidationDock( const QString &title, QWidget *parent = nullptr, Qt::WindowFlags flags = nullptr );
34+
QgsGeometryValidationDock( const QString &title, QgsMapCanvas *mapCanvas, QWidget *parent = nullptr, Qt::WindowFlags flags = nullptr );
3335

3436
QgsGeometryValidationModel *geometryValidationModel() const;
3537
void setGeometryValidationModel( QgsGeometryValidationModel *geometryValidationModel );
@@ -40,6 +42,7 @@ class QgsGeometryValidationDock : public QgsDockWidget, public Ui_QgsGeometryVal
4042
void gotoPreviousError();
4143
void zoomToProblem();
4244
void zoomToFeature();
45+
void updateLayerTransform();
4346

4447
private:
4548
enum ZoomToAction
@@ -50,6 +53,9 @@ class QgsGeometryValidationDock : public QgsDockWidget, public Ui_QgsGeometryVal
5053
ZoomToAction mLastZoomToAction = ZoomToFeature;
5154
QgsGeometryValidationModel *mGeometryValidationModel = nullptr;
5255
QButtonGroup *mZoomToButtonGroup = nullptr;
56+
QgsMapCanvas *mMapCanvas = nullptr;
57+
QgsCoordinateTransform mLayerTransform;
58+
QModelIndex currentIndex() const;
5359
};
5460

5561
#endif // QGSGEOMETRYVALIDATIONPANEL_H

‎src/app/qgsgeometryvalidationmodel.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ QgsGeometryValidationModel::QgsGeometryValidationModel( QgsGeometryValidationSer
1111
{
1212
connect( mGeometryValidationService, &QgsGeometryValidationService::geometryCheckCompleted, this, &QgsGeometryValidationModel::onGeometryCheckCompleted );
1313
connect( mGeometryValidationService, &QgsGeometryValidationService::geometryCheckStarted, this, &QgsGeometryValidationModel::onGeometryCheckStarted );
14-
connect( mGeometryValidationService, &QgsGeometryValidationService::topologyChecksUpdated, this, &QgsGeometryValidationModel::onTopologyChecksUpdated, Qt::QueuedConnection );
14+
connect( mGeometryValidationService, &QgsGeometryValidationService::topologyChecksUpdated, this, &QgsGeometryValidationModel::onTopologyChecksUpdated );
15+
connect( mGeometryValidationService, &QgsGeometryValidationService::topologyChecksCleared, this, &QgsGeometryValidationModel::onTopologyChecksCleared );
1516
}
1617

1718
QModelIndex QgsGeometryValidationModel::index( int row, int column, const QModelIndex &parent ) const
@@ -61,6 +62,18 @@ QVariant QgsGeometryValidationModel::data( const QModelIndex &index, int role )
6162

6263
return tr( "%1: %2" ).arg( featureTitle, topologyError->description() );
6364
}
65+
66+
case FeatureExtentRole:
67+
{
68+
const QgsFeatureId fid = topologyError->featureId();
69+
const QgsFeature feature = mCurrentLayer->getFeature( fid ); // TODO: this should be cached!
70+
return feature.geometry().boundingBox();
71+
}
72+
73+
case ProblemExtentRole:
74+
{
75+
return topologyError->affectedAreaBBox();
76+
}
6477
}
6578
}
6679
else
@@ -195,7 +208,7 @@ void QgsGeometryValidationModel::onTopologyChecksUpdated( QgsVectorLayer *layer,
195208

196209
if ( layer == currentLayer() )
197210
{
198-
const int oldRowCount = rowCount( QModelIndex() );
211+
const int oldRowCount = rowCount();
199212
beginInsertRows( QModelIndex(), oldRowCount, oldRowCount + errors.size() );
200213
}
201214

@@ -207,6 +220,23 @@ void QgsGeometryValidationModel::onTopologyChecksUpdated( QgsVectorLayer *layer,
207220
}
208221
}
209222

223+
void QgsGeometryValidationModel::onTopologyChecksCleared( QgsVectorLayer *layer )
224+
{
225+
auto &topologyLayerErrors = mTopologyErrorStorage[layer];
226+
if ( topologyLayerErrors.empty() )
227+
return;
228+
229+
if ( layer == currentLayer() )
230+
{
231+
beginRemoveRows( QModelIndex(), mErrorStorage.size(), rowCount() - 1 );
232+
}
233+
topologyLayerErrors.clear();
234+
if ( layer == currentLayer() )
235+
{
236+
endRemoveRows();
237+
}
238+
}
239+
210240
int QgsGeometryValidationModel::errorsForFeature( QgsVectorLayer *layer, QgsFeatureId fid )
211241
{
212242
const auto &layerErrors = mErrorStorage[layer];

‎src/app/qgsgeometryvalidationmodel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class QgsGeometryValidationModel : public QAbstractItemModel
3636
void onGeometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid, const QList<std::shared_ptr<QgsSingleGeometryCheckError> > &errors );
3737
void onGeometryCheckStarted( QgsVectorLayer *layer, QgsFeatureId fid );
3838
void onTopologyChecksUpdated( QgsVectorLayer *layer, const QList<std::shared_ptr<QgsGeometryCheckError> > &errors );
39+
void onTopologyChecksCleared( QgsVectorLayer *layer );
3940

4041
private:
4142
struct FeatureErrors

‎src/app/qgsgeometryvalidationservice.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,24 @@ void QgsGeometryValidationService::processFeature( QgsVectorLayer *layer, QgsFea
196196

197197
void QgsGeometryValidationService::triggerTopologyChecks( QgsVectorLayer *layer )
198198
{
199+
emit topologyChecksCleared( layer );
200+
199201
QFutureWatcher<void> *futureWatcher = mLayerCheckStates[layer].topologyCheckFutureWatcher;
200202
if ( futureWatcher )
201203
{
202-
// TODO: kill!!
203-
delete futureWatcher;
204+
// Make sure no more checks are started first
205+
futureWatcher->cancel();
206+
207+
// Tell all checks to stop asap
208+
const auto feedbacks = mLayerCheckStates[layer].topologyCheckFeedbacks;
209+
for ( QgsFeedback *feedback : feedbacks )
210+
{
211+
if ( feedback )
212+
feedback->cancel();
213+
}
214+
215+
// The future watcher will take care of deleting
216+
mLayerCheckStates[layer].topologyCheckFeedbacks.clear();
204217
}
205218

206219
QgsFeatureIds checkFeatureIds = layer->editBuffer()->changedGeometries().keys().toSet();
@@ -209,7 +222,6 @@ void QgsGeometryValidationService::triggerTopologyChecks( QgsVectorLayer *layer
209222
// TODO: ownership of these objects...
210223
QgsVectorLayerFeaturePool *featurePool = new QgsVectorLayerFeaturePool( layer );
211224
QList<QgsGeometryCheckError *> &allErrors = mLayerCheckStates[layer].topologyCheckErrors;
212-
QgsFeedback *feedback = new QgsFeedback();
213225
QMap<QString, QgsFeatureIds> layerIds;
214226
layerIds.insert( layer->id(), checkFeatureIds );
215227
QgsGeometryCheck::LayerFeatureIds layerFeatureIds( layerIds );
@@ -219,12 +231,19 @@ void QgsGeometryValidationService::triggerTopologyChecks( QgsVectorLayer *layer
219231

220232
const QList<QgsGeometryCheck *> checks = mLayerCheckStates[layer].topologyChecks;
221233

222-
QFuture<void> future = QtConcurrent::map( checks, [featurePools, &allErrors, feedback, layerFeatureIds, layer, this]( const QgsGeometryCheck * check )
234+
QMap<const QgsGeometryCheck *, QgsFeedback *> feedbacks;
235+
for ( QgsGeometryCheck *check : checks )
236+
feedbacks.insert( check, new QgsFeedback() );
237+
238+
mLayerCheckStates[layer].topologyCheckFeedbacks = feedbacks.values();
239+
240+
QFuture<void> future = QtConcurrent::map( checks, [featurePools, &allErrors, layerFeatureIds, layer, feedbacks, this]( const QgsGeometryCheck * check )
223241
{
224242
// Watch out with the layer pointer in here. We are running in a thread, so we do not want to actually use it
225243
// except for using its address to report the error.
226244
QList<QgsGeometryCheckError *> errors;
227245
QStringList messages; // Do we really need these?
246+
QgsFeedback *feedback = feedbacks.value( check );
228247

229248
check->collectErrors( featurePools, errors, messages, feedback, layerFeatureIds );
230249
QgsReadWriteLocker errorLocker( mTopologyCheckLock, QgsReadWriteLocker::Write );
@@ -235,18 +254,24 @@ void QgsGeometryValidationService::triggerTopologyChecks( QgsVectorLayer *layer
235254
{
236255
sharedErrors.append( std::shared_ptr<QgsGeometryCheckError>( error ) );
237256
}
238-
emit topologyChecksUpdated( layer, sharedErrors );
257+
if ( !feedback->isCanceled() )
258+
emit topologyChecksUpdated( layer, sharedErrors );
259+
239260
errorLocker.unlock();
240261
} );
241262

242263
futureWatcher = new QFutureWatcher<void>();
243264
futureWatcher->setFuture( future );
244265

245-
connect( futureWatcher, &QFutureWatcherBase::finished, this, [&allErrors, layer, this]()
266+
connect( futureWatcher, &QFutureWatcherBase::finished, this, [&allErrors, layer, feedbacks, futureWatcher, this]()
246267
{
247268
QgsReadWriteLocker errorLocker( mTopologyCheckLock, QgsReadWriteLocker::Read );
248269
layer->setAllowCommit( allErrors.empty() );
249270
errorLocker.unlock();
271+
qDeleteAll( feedbacks.values() );
272+
futureWatcher->deleteLater();
273+
if ( mLayerCheckStates[layer].topologyCheckFutureWatcher == futureWatcher )
274+
mLayerCheckStates[layer].topologyCheckFutureWatcher = nullptr;
250275
} );
251276

252277
mLayerCheckStates[layer].topologyCheckFutureWatcher = futureWatcher;

‎src/app/qgsgeometryvalidationservice.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class QgsGeometryCheck;
3030
class QgsSingleGeometryCheck;
3131
class QgsSingleGeometryCheckError;
3232
class QgsGeometryCheckError;
33-
33+
class QgsFeedback;
3434

3535
/**
3636
* This service connects to all layers in a project and triggers validation
@@ -68,6 +68,7 @@ class QgsGeometryValidationService : public QObject
6868
void geometryCheckStarted( QgsVectorLayer *layer, QgsFeatureId fid );
6969
void geometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid, const QList<std::shared_ptr<QgsSingleGeometryCheckError>> &errors );
7070
void topologyChecksUpdated( QgsVectorLayer *layer, const QList<std::shared_ptr<QgsGeometryCheckError> > &errors );
71+
void topologyChecksCleared( QgsVectorLayer *layer );
7172

7273
void warning( const QString &message );
7374

@@ -92,8 +93,9 @@ class QgsGeometryValidationService : public QObject
9293
struct VectorCheckState
9394
{
9495
QList< QgsSingleGeometryCheck * > singleFeatureChecks;
95-
QList< QgsGeometryCheck * > topologyChecks;
96+
QList< QgsGeometryCheck *> topologyChecks;
9697
QFutureWatcher<void> *topologyCheckFutureWatcher = nullptr;
98+
QList<QgsFeedback *> topologyCheckFeedbacks; // will be deleted when topologyCheckFutureWatcher is delteed
9799
QList<QgsGeometryCheckError *> topologyCheckErrors;
98100
};
99101

0 commit comments

Comments
 (0)
Please sign in to comment.