Skip to content

Commit 56d299e

Browse files
committed
YAY, it is working
1 parent f5486ee commit 56d299e

6 files changed

+175
-40
lines changed

src/app/qgisapp.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,10 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
925925
mGeometryValidationService = qgis::make_unique<QgsGeometryValidationService>( QgsProject::instance() );
926926
mGeometryValidationDock = new QgsGeometryValidationDock( tr( "Geometry Validation" ) );
927927
mGeometryValidationModel = new QgsGeometryValidationModel( mGeometryValidationService.get(), mGeometryValidationDock );
928+
connect( this, &QgisApp::activeLayerChanged, mGeometryValidationModel, [this]( QgsMapLayer * layer )
929+
{
930+
mGeometryValidationModel->setCurrentLayer( qobject_cast<QgsVectorLayer *>( layer ) );
931+
} );
928932
mGeometryValidationDock->setGeometryValidationModel( mGeometryValidationModel );
929933
addDockWidget( Qt::RightDockWidgetArea, mGeometryValidationDock );
930934
endProfile();

src/app/qgsgeometryvalidationdock.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ QgsGeometryValidationModel *QgsGeometryValidationDock::geometryValidationModel()
3030
void QgsGeometryValidationDock::setGeometryValidationModel( QgsGeometryValidationModel *geometryValidationModel )
3131
{
3232
mGeometryValidationModel = geometryValidationModel;
33+
mErrorListView->setModel( mGeometryValidationModel );
3334
}

src/app/qgsgeometryvalidationmodel.cpp

+116-8
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
#include "qgsvectorlayer.h"
44

5+
#include <QIcon>
6+
57
QgsGeometryValidationModel::QgsGeometryValidationModel( QgsGeometryValidationService *geometryValidationService, QObject *parent )
68
: QAbstractItemModel( parent )
79
, mGeometryValidationService( geometryValidationService )
810
{
9-
11+
connect( mGeometryValidationService, &QgsGeometryValidationService::geometryCheckCompleted, this, &QgsGeometryValidationModel::onGeometryCheckCompleted );
12+
connect( mGeometryValidationService, &QgsGeometryValidationService::geometryCheckStarted, this, &QgsGeometryValidationModel::onGeometryCheckStarted );
1013
}
1114

1215
QModelIndex QgsGeometryValidationModel::index( int row, int column, const QModelIndex &parent ) const
@@ -24,7 +27,7 @@ QModelIndex QgsGeometryValidationModel::parent( const QModelIndex &child ) const
2427
int QgsGeometryValidationModel::rowCount( const QModelIndex &parent ) const
2528
{
2629
Q_UNUSED( parent )
27-
return mGeometryValidationService->featureErrors( mCurrentLayer ).size();
30+
return mErrorStorage.value( mCurrentLayer ).size();
2831
}
2932

3033
int QgsGeometryValidationModel::columnCount( const QModelIndex &parent ) const
@@ -35,14 +38,37 @@ int QgsGeometryValidationModel::columnCount( const QModelIndex &parent ) const
3538

3639
QVariant QgsGeometryValidationModel::data( const QModelIndex &index, int role ) const
3740
{
41+
const auto &layerErrors = mErrorStorage.value( mCurrentLayer );
42+
43+
const auto &featureItem = layerErrors.at( index.row() );
44+
3845
switch ( role )
3946
{
4047
case Qt::DisplayRole:
41-
QgsGeometryValidationService::FeatureError error = mGeometryValidationService->featureError( mCurrentLayer, index.row() );
42-
QgsFeature feature = mCurrentLayer->getFeature( error.featureId );
48+
{
49+
QgsFeature feature = mCurrentLayer->getFeature( featureItem.fid ); // TODO: this should be cached!
4350
mExpressionContext.setFeature( feature );
4451
QString featureTitle = mDisplayExpression.evaluate( &mExpressionContext ).toString();
45-
return QStringLiteral( "<b>%1</b>: %2" ).arg( featureTitle, error.error.what() );
52+
if ( featureTitle.isEmpty() )
53+
featureTitle = featureItem.fid;
54+
55+
if ( featureItem.errors.count() > 1 )
56+
return tr( "%1: %n Errors", "", featureItem.errors.count() ).arg( featureTitle );
57+
else if ( featureItem.errors.count() == 1 )
58+
return tr( "%1: %2" ).arg( featureTitle, featureItem.errors.at( 0 ).what() );
59+
#if 0
60+
else
61+
return tr( "%1: No Errors" ).arg( featureTitle );
62+
#endif
63+
}
64+
65+
case Qt::DecorationRole:
66+
{
67+
if ( mGeometryValidationService->validationActive( mCurrentLayer, featureItem.fid ) )
68+
return QgsApplication::getThemeIcon( "/mActionTracing.svg" );
69+
else
70+
return QVariant();
71+
}
4672
}
4773

4874
return QVariant();
@@ -60,8 +86,90 @@ void QgsGeometryValidationModel::setCurrentLayer( QgsVectorLayer *currentLayer )
6086

6187
beginResetModel();
6288
mCurrentLayer = currentLayer;
63-
mDisplayExpression = mCurrentLayer->displayExpression();
64-
mExpressionContext = QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( mCurrentLayer ) );
65-
mDisplayExpression.prepare( &mExpressionContext );
89+
if ( mCurrentLayer )
90+
{
91+
mDisplayExpression = mCurrentLayer ? mCurrentLayer->displayExpression() : QString();
92+
mExpressionContext = QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( mCurrentLayer ) );
93+
mDisplayExpression.prepare( &mExpressionContext );
94+
}
95+
else
96+
{
97+
mDisplayExpression = QString();
98+
mExpressionContext = QgsExpressionContext();
99+
}
66100
endResetModel();
67101
}
102+
103+
void QgsGeometryValidationModel::onGeometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid, const QList<QgsGeometry::Error> &errors )
104+
{
105+
auto &layerErrors = mErrorStorage[layer];
106+
107+
int featureIdx = errorsForFeature( layer, fid );
108+
109+
// The last check for this feature finished: remove
110+
if ( featureIdx > -1 && errors.empty() && !mGeometryValidationService->validationActive( layer, fid ) )
111+
{
112+
if ( mCurrentLayer == layer )
113+
beginRemoveRows( QModelIndex(), featureIdx, featureIdx );
114+
115+
layerErrors.removeAt( featureIdx );
116+
117+
if ( mCurrentLayer == layer )
118+
endRemoveRows();
119+
}
120+
else if ( !errors.empty() )
121+
{
122+
// a new or updated feature
123+
if ( featureIdx == -1 )
124+
{
125+
featureIdx = layerErrors.count();
126+
if ( mCurrentLayer == layer )
127+
beginInsertRows( QModelIndex(), featureIdx, featureIdx );
128+
129+
layerErrors << FeatureErrors( fid );
130+
131+
if ( mCurrentLayer == layer )
132+
endInsertRows();
133+
}
134+
135+
auto &featureItem = layerErrors[featureIdx];
136+
featureItem.errors.append( errors );
137+
if ( mCurrentLayer == layer )
138+
{
139+
QModelIndex modelIndex = index( featureIdx, 0, QModelIndex() );
140+
emit dataChanged( modelIndex, modelIndex );
141+
}
142+
}
143+
}
144+
145+
void QgsGeometryValidationModel::onGeometryCheckStarted( QgsVectorLayer *layer, QgsFeatureId fid )
146+
{
147+
auto &layerErrors = mErrorStorage[layer];
148+
int featureIdx = errorsForFeature( layer, fid );
149+
if ( featureIdx != -1 )
150+
{
151+
auto &featureItem = layerErrors[featureIdx];
152+
153+
featureItem.errors.clear();
154+
155+
if ( mCurrentLayer == layer )
156+
{
157+
QModelIndex modelIndex = index( featureIdx, 0, QModelIndex() );
158+
emit dataChanged( modelIndex, modelIndex );
159+
}
160+
}
161+
}
162+
163+
int QgsGeometryValidationModel::errorsForFeature( QgsVectorLayer *layer, QgsFeatureId fid )
164+
{
165+
const auto &layerErrors = mErrorStorage[layer];
166+
int idx = 0;
167+
168+
for ( const auto &feature : layerErrors )
169+
{
170+
if ( feature.fid == fid )
171+
return idx;
172+
idx++;
173+
}
174+
return -1;
175+
}

src/app/qgsgeometryvalidationmodel.h

+25
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,44 @@ class QgsGeometryValidationModel : public QAbstractItemModel
1212

1313
public:
1414
QgsGeometryValidationModel( QgsGeometryValidationService *geometryValidationService, QObject *parent = nullptr );
15+
1516
QModelIndex index( int row, int column, const QModelIndex &parent ) const override;
1617
QModelIndex parent( const QModelIndex &child ) const override;
1718
int rowCount( const QModelIndex &parent ) const override;
1819
int columnCount( const QModelIndex &parent ) const override;
1920
QVariant data( const QModelIndex &index, int role ) const override;
21+
2022
QgsVectorLayer *currentLayer() const;
23+
24+
public slots:
2125
void setCurrentLayer( QgsVectorLayer *currentLayer );
2226

27+
private slots:
28+
void onGeometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid, const QList<QgsGeometry::Error> &errors );
29+
void onGeometryCheckStarted( QgsVectorLayer *layer, QgsFeatureId fid );
30+
2331
private:
32+
struct FeatureErrors
33+
{
34+
FeatureErrors()
35+
{}
36+
37+
FeatureErrors( QgsFeatureId fid )
38+
: fid( fid )
39+
{}
40+
41+
QgsFeatureId fid; // TODO INITIALIZE PROPERLY
42+
QList<QgsGeometry::Error> errors;
43+
};
44+
45+
int errorsForFeature( QgsVectorLayer *layer, QgsFeatureId fid );
46+
2447
QgsGeometryValidationService *mGeometryValidationService = nullptr;
2548
QgsVectorLayer *mCurrentLayer = nullptr;
2649
mutable QgsExpression mDisplayExpression;
2750
mutable QgsExpressionContext mExpressionContext;
51+
52+
QMap<QgsVectorLayer *, QList< FeatureErrors > > mErrorStorage;
2853
};
2954

3055
#endif // QGSGEOMETRYVALIDATIONMODEL_H

src/app/qgsgeometryvalidationservice.cpp

+18-26
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ QgsGeometryValidationService::~QgsGeometryValidationService()
3333
delete mIsValidGeometryCheck;
3434
}
3535

36+
bool QgsGeometryValidationService::validationActive( QgsVectorLayer *layer, QgsFeatureId feature ) const
37+
{
38+
return false;
39+
}
40+
3641
void QgsGeometryValidationService::onLayersAdded( const QList<QgsMapLayer *> &layers )
3742
{
3843
for ( QgsMapLayer *layer : layers )
@@ -58,45 +63,32 @@ void QgsGeometryValidationService::onLayersAdded( const QList<QgsMapLayer *> &la
5863

5964
void QgsGeometryValidationService::onFeatureAdded( QgsVectorLayer *layer, QgsFeatureId fid )
6065
{
61-
emit geometryCheckStarted( layer, fid );
62-
63-
QgsFeature feature = layer->getFeature( fid );
64-
const auto errors = mIsValidGeometryCheck->collectErrors( feature );
65-
for ( const auto &error : errors )
66-
{
67-
qDebug() << error.what();
68-
}
69-
70-
emit geometryCheckCompleted( layer, fid );
66+
processFeature( layer, fid );
7167
}
7268

7369
void QgsGeometryValidationService::onGeometryChanged( QgsVectorLayer *layer, QgsFeatureId fid, const QgsGeometry &geometry )
7470
{
75-
emit geometryCheckStarted( layer, fid );
71+
Q_UNUSED( geometry )
7672

77-
QgsFeature feature = layer->getFeature( fid );
78-
const auto errors = mIsValidGeometryCheck->collectErrors( feature );
79-
for ( const auto &error : errors )
80-
{
81-
qDebug() << error.what();
82-
}
83-
84-
emit geometryCheckCompleted( layer, fid );
73+
cancelChecks( layer, fid );
74+
processFeature( layer, fid );
8575
}
8676

8777
void QgsGeometryValidationService::onFeatureDeleted( QgsVectorLayer *layer, QgsFeatureId fid )
8878
{
89-
// TODO: cleanup any ongoing validation threads.
90-
91-
emit geometryCheckCompleted( layer, fid );
79+
cancelChecks( layer, fid );
9280
}
9381

94-
QgsGeometryValidationService::FeatureErrors QgsGeometryValidationService::featureErrors( QgsVectorLayer *layer ) const
82+
void QgsGeometryValidationService::cancelChecks( QgsVectorLayer *layer, QgsFeatureId fid )
9583
{
96-
return mFeatureErrors.value( layer );
84+
9785
}
9886

99-
QgsGeometryValidationService::FeatureError QgsGeometryValidationService::featureError( QgsVectorLayer *layer, int errorIndex )
87+
void QgsGeometryValidationService::processFeature( QgsVectorLayer *layer, QgsFeatureId fid )
10088
{
101-
return mFeatureErrors.value( layer ).value( errorIndex );
89+
emit geometryCheckStarted( layer, fid );
90+
91+
QgsFeature feature = layer->getFeature( fid );
92+
const auto errors = mIsValidGeometryCheck->collectErrors( feature );
93+
emit geometryCheckCompleted( layer, fid, errors );
10294
}

src/app/qgsgeometryvalidationservice.h

+11-6
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@ class QgsGeometryValidationService : public QObject
3434
public:
3535
struct FeatureError
3636
{
37-
QgsFeatureId featureId;
37+
FeatureError()
38+
{}
39+
FeatureError( QgsFeatureId fid, QgsGeometry::Error error )
40+
: featureId( fid )
41+
, error( error )
42+
{}
43+
QgsFeatureId featureId = std::numeric_limits<QgsFeatureId>::min();
3844
QgsGeometry::Error error;
3945
};
4046

@@ -43,13 +49,11 @@ class QgsGeometryValidationService : public QObject
4349
QgsGeometryValidationService( QgsProject *project );
4450
~QgsGeometryValidationService();
4551

46-
FeatureErrors featureErrors( QgsVectorLayer *layer ) const;
47-
48-
FeatureError featureError( QgsVectorLayer *layer, int errorIndex );
52+
bool validationActive( QgsVectorLayer *layer, QgsFeatureId feature ) const;
4953

5054
signals:
5155
void geometryCheckStarted( QgsVectorLayer *layer, QgsFeatureId fid );
52-
void geometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid );
56+
void geometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid, const QList<QgsGeometry::Error> &errors );
5357

5458
private slots:
5559
void onLayersAdded( const QList<QgsMapLayer *> &layers );
@@ -60,12 +64,13 @@ class QgsGeometryValidationService : public QObject
6064
private:
6165
void cancelChecks( QgsVectorLayer *layer, QgsFeatureId fid );
6266

67+
void processFeature( QgsVectorLayer *layer, QgsFeatureId fid );
68+
6369
QgsIsValidGeometryCheck *mIsValidGeometryCheck;
6470

6571
QgsProject *mProject;
6672

6773
QMap<QgsVectorLayer *, bool> mActiveChecks;
68-
QMap<QgsVectorLayer *, FeatureErrors> mFeatureErrors;
6974
};
7075

7176
#endif // QGSGEOMETRYVALIDATIONSERVICE_H

0 commit comments

Comments
 (0)