Skip to content

Commit

Permalink
YAY, it is working
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Oct 15, 2018
1 parent f5486ee commit 56d299e
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 40 deletions.
4 changes: 4 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -925,6 +925,10 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
mGeometryValidationService = qgis::make_unique<QgsGeometryValidationService>( QgsProject::instance() );
mGeometryValidationDock = new QgsGeometryValidationDock( tr( "Geometry Validation" ) );
mGeometryValidationModel = new QgsGeometryValidationModel( mGeometryValidationService.get(), mGeometryValidationDock );
connect( this, &QgisApp::activeLayerChanged, mGeometryValidationModel, [this]( QgsMapLayer * layer )
{
mGeometryValidationModel->setCurrentLayer( qobject_cast<QgsVectorLayer *>( layer ) );
} );
mGeometryValidationDock->setGeometryValidationModel( mGeometryValidationModel );
addDockWidget( Qt::RightDockWidgetArea, mGeometryValidationDock );
endProfile();
Expand Down
1 change: 1 addition & 0 deletions src/app/qgsgeometryvalidationdock.cpp
Expand Up @@ -30,4 +30,5 @@ QgsGeometryValidationModel *QgsGeometryValidationDock::geometryValidationModel()
void QgsGeometryValidationDock::setGeometryValidationModel( QgsGeometryValidationModel *geometryValidationModel )
{
mGeometryValidationModel = geometryValidationModel;
mErrorListView->setModel( mGeometryValidationModel );
}
124 changes: 116 additions & 8 deletions src/app/qgsgeometryvalidationmodel.cpp
Expand Up @@ -2,11 +2,14 @@

#include "qgsvectorlayer.h"

#include <QIcon>

QgsGeometryValidationModel::QgsGeometryValidationModel( QgsGeometryValidationService *geometryValidationService, QObject *parent )
: QAbstractItemModel( parent )
, mGeometryValidationService( geometryValidationService )
{

connect( mGeometryValidationService, &QgsGeometryValidationService::geometryCheckCompleted, this, &QgsGeometryValidationModel::onGeometryCheckCompleted );
connect( mGeometryValidationService, &QgsGeometryValidationService::geometryCheckStarted, this, &QgsGeometryValidationModel::onGeometryCheckStarted );
}

QModelIndex QgsGeometryValidationModel::index( int row, int column, const QModelIndex &parent ) const
Expand All @@ -24,7 +27,7 @@ QModelIndex QgsGeometryValidationModel::parent( const QModelIndex &child ) const
int QgsGeometryValidationModel::rowCount( const QModelIndex &parent ) const
{
Q_UNUSED( parent )
return mGeometryValidationService->featureErrors( mCurrentLayer ).size();
return mErrorStorage.value( mCurrentLayer ).size();
}

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

QVariant QgsGeometryValidationModel::data( const QModelIndex &index, int role ) const
{
const auto &layerErrors = mErrorStorage.value( mCurrentLayer );

const auto &featureItem = layerErrors.at( index.row() );

switch ( role )
{
case Qt::DisplayRole:
QgsGeometryValidationService::FeatureError error = mGeometryValidationService->featureError( mCurrentLayer, index.row() );
QgsFeature feature = mCurrentLayer->getFeature( error.featureId );
{
QgsFeature feature = mCurrentLayer->getFeature( featureItem.fid ); // TODO: this should be cached!
mExpressionContext.setFeature( feature );
QString featureTitle = mDisplayExpression.evaluate( &mExpressionContext ).toString();
return QStringLiteral( "<b>%1</b>: %2" ).arg( featureTitle, error.error.what() );
if ( featureTitle.isEmpty() )
featureTitle = featureItem.fid;

if ( featureItem.errors.count() > 1 )
return tr( "%1: %n Errors", "", featureItem.errors.count() ).arg( featureTitle );
else if ( featureItem.errors.count() == 1 )
return tr( "%1: %2" ).arg( featureTitle, featureItem.errors.at( 0 ).what() );
#if 0
else
return tr( "%1: No Errors" ).arg( featureTitle );
#endif
}

case Qt::DecorationRole:
{
if ( mGeometryValidationService->validationActive( mCurrentLayer, featureItem.fid ) )
return QgsApplication::getThemeIcon( "/mActionTracing.svg" );
else
return QVariant();
}
}

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

beginResetModel();
mCurrentLayer = currentLayer;
mDisplayExpression = mCurrentLayer->displayExpression();
mExpressionContext = QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( mCurrentLayer ) );
mDisplayExpression.prepare( &mExpressionContext );
if ( mCurrentLayer )
{
mDisplayExpression = mCurrentLayer ? mCurrentLayer->displayExpression() : QString();
mExpressionContext = QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( mCurrentLayer ) );
mDisplayExpression.prepare( &mExpressionContext );
}
else
{
mDisplayExpression = QString();
mExpressionContext = QgsExpressionContext();
}
endResetModel();
}

void QgsGeometryValidationModel::onGeometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid, const QList<QgsGeometry::Error> &errors )
{
auto &layerErrors = mErrorStorage[layer];

int featureIdx = errorsForFeature( layer, fid );

// The last check for this feature finished: remove
if ( featureIdx > -1 && errors.empty() && !mGeometryValidationService->validationActive( layer, fid ) )
{
if ( mCurrentLayer == layer )
beginRemoveRows( QModelIndex(), featureIdx, featureIdx );

layerErrors.removeAt( featureIdx );

if ( mCurrentLayer == layer )
endRemoveRows();
}
else if ( !errors.empty() )
{
// a new or updated feature
if ( featureIdx == -1 )
{
featureIdx = layerErrors.count();
if ( mCurrentLayer == layer )
beginInsertRows( QModelIndex(), featureIdx, featureIdx );

layerErrors << FeatureErrors( fid );

if ( mCurrentLayer == layer )
endInsertRows();
}

auto &featureItem = layerErrors[featureIdx];
featureItem.errors.append( errors );
if ( mCurrentLayer == layer )
{
QModelIndex modelIndex = index( featureIdx, 0, QModelIndex() );
emit dataChanged( modelIndex, modelIndex );
}
}
}

void QgsGeometryValidationModel::onGeometryCheckStarted( QgsVectorLayer *layer, QgsFeatureId fid )
{
auto &layerErrors = mErrorStorage[layer];
int featureIdx = errorsForFeature( layer, fid );
if ( featureIdx != -1 )
{
auto &featureItem = layerErrors[featureIdx];

featureItem.errors.clear();

if ( mCurrentLayer == layer )
{
QModelIndex modelIndex = index( featureIdx, 0, QModelIndex() );
emit dataChanged( modelIndex, modelIndex );
}
}
}

int QgsGeometryValidationModel::errorsForFeature( QgsVectorLayer *layer, QgsFeatureId fid )
{
const auto &layerErrors = mErrorStorage[layer];
int idx = 0;

for ( const auto &feature : layerErrors )
{
if ( feature.fid == fid )
return idx;
idx++;
}
return -1;
}
25 changes: 25 additions & 0 deletions src/app/qgsgeometryvalidationmodel.h
Expand Up @@ -12,19 +12,44 @@ class QgsGeometryValidationModel : public QAbstractItemModel

public:
QgsGeometryValidationModel( QgsGeometryValidationService *geometryValidationService, QObject *parent = nullptr );

QModelIndex index( int row, int column, const QModelIndex &parent ) const override;
QModelIndex parent( const QModelIndex &child ) const override;
int rowCount( const QModelIndex &parent ) const override;
int columnCount( const QModelIndex &parent ) const override;
QVariant data( const QModelIndex &index, int role ) const override;

QgsVectorLayer *currentLayer() const;

public slots:
void setCurrentLayer( QgsVectorLayer *currentLayer );

private slots:
void onGeometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid, const QList<QgsGeometry::Error> &errors );
void onGeometryCheckStarted( QgsVectorLayer *layer, QgsFeatureId fid );

private:
struct FeatureErrors
{
FeatureErrors()
{}

FeatureErrors( QgsFeatureId fid )
: fid( fid )
{}

QgsFeatureId fid; // TODO INITIALIZE PROPERLY
QList<QgsGeometry::Error> errors;
};

int errorsForFeature( QgsVectorLayer *layer, QgsFeatureId fid );

QgsGeometryValidationService *mGeometryValidationService = nullptr;
QgsVectorLayer *mCurrentLayer = nullptr;
mutable QgsExpression mDisplayExpression;
mutable QgsExpressionContext mExpressionContext;

QMap<QgsVectorLayer *, QList< FeatureErrors > > mErrorStorage;
};

#endif // QGSGEOMETRYVALIDATIONMODEL_H
44 changes: 18 additions & 26 deletions src/app/qgsgeometryvalidationservice.cpp
Expand Up @@ -33,6 +33,11 @@ QgsGeometryValidationService::~QgsGeometryValidationService()
delete mIsValidGeometryCheck;
}

bool QgsGeometryValidationService::validationActive( QgsVectorLayer *layer, QgsFeatureId feature ) const
{
return false;
}

void QgsGeometryValidationService::onLayersAdded( const QList<QgsMapLayer *> &layers )
{
for ( QgsMapLayer *layer : layers )
Expand All @@ -58,45 +63,32 @@ void QgsGeometryValidationService::onLayersAdded( const QList<QgsMapLayer *> &la

void QgsGeometryValidationService::onFeatureAdded( QgsVectorLayer *layer, QgsFeatureId fid )
{
emit geometryCheckStarted( layer, fid );

QgsFeature feature = layer->getFeature( fid );
const auto errors = mIsValidGeometryCheck->collectErrors( feature );
for ( const auto &error : errors )
{
qDebug() << error.what();
}

emit geometryCheckCompleted( layer, fid );
processFeature( layer, fid );
}

void QgsGeometryValidationService::onGeometryChanged( QgsVectorLayer *layer, QgsFeatureId fid, const QgsGeometry &geometry )
{
emit geometryCheckStarted( layer, fid );
Q_UNUSED( geometry )

QgsFeature feature = layer->getFeature( fid );
const auto errors = mIsValidGeometryCheck->collectErrors( feature );
for ( const auto &error : errors )
{
qDebug() << error.what();
}

emit geometryCheckCompleted( layer, fid );
cancelChecks( layer, fid );
processFeature( layer, fid );
}

void QgsGeometryValidationService::onFeatureDeleted( QgsVectorLayer *layer, QgsFeatureId fid )
{
// TODO: cleanup any ongoing validation threads.

emit geometryCheckCompleted( layer, fid );
cancelChecks( layer, fid );
}

QgsGeometryValidationService::FeatureErrors QgsGeometryValidationService::featureErrors( QgsVectorLayer *layer ) const
void QgsGeometryValidationService::cancelChecks( QgsVectorLayer *layer, QgsFeatureId fid )
{
return mFeatureErrors.value( layer );

}

QgsGeometryValidationService::FeatureError QgsGeometryValidationService::featureError( QgsVectorLayer *layer, int errorIndex )
void QgsGeometryValidationService::processFeature( QgsVectorLayer *layer, QgsFeatureId fid )
{
return mFeatureErrors.value( layer ).value( errorIndex );
emit geometryCheckStarted( layer, fid );

QgsFeature feature = layer->getFeature( fid );
const auto errors = mIsValidGeometryCheck->collectErrors( feature );
emit geometryCheckCompleted( layer, fid, errors );
}
17 changes: 11 additions & 6 deletions src/app/qgsgeometryvalidationservice.h
Expand Up @@ -34,7 +34,13 @@ class QgsGeometryValidationService : public QObject
public:
struct FeatureError
{
QgsFeatureId featureId;
FeatureError()
{}
FeatureError( QgsFeatureId fid, QgsGeometry::Error error )
: featureId( fid )
, error( error )
{}
QgsFeatureId featureId = std::numeric_limits<QgsFeatureId>::min();
QgsGeometry::Error error;
};

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

FeatureErrors featureErrors( QgsVectorLayer *layer ) const;

FeatureError featureError( QgsVectorLayer *layer, int errorIndex );
bool validationActive( QgsVectorLayer *layer, QgsFeatureId feature ) const;

signals:
void geometryCheckStarted( QgsVectorLayer *layer, QgsFeatureId fid );
void geometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid );
void geometryCheckCompleted( QgsVectorLayer *layer, QgsFeatureId fid, const QList<QgsGeometry::Error> &errors );

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

void processFeature( QgsVectorLayer *layer, QgsFeatureId fid );

QgsIsValidGeometryCheck *mIsValidGeometryCheck;

QgsProject *mProject;

QMap<QgsVectorLayer *, bool> mActiveChecks;
QMap<QgsVectorLayer *, FeatureErrors> mFeatureErrors;
};

#endif // QGSGEOMETRYVALIDATIONSERVICE_H

0 comments on commit 56d299e

Please sign in to comment.