mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
275 lines
8.0 KiB
C++
275 lines
8.0 KiB
C++
#include "qgsgeometryvalidationmodel.h"
|
|
|
|
#include "qgsvectorlayer.h"
|
|
#include "qgssinglegeometrycheck.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 );
|
|
connect( mGeometryValidationService, &QgsGeometryValidationService::topologyChecksUpdated, this, &QgsGeometryValidationModel::onTopologyChecksUpdated );
|
|
connect( mGeometryValidationService, &QgsGeometryValidationService::topologyChecksCleared, this, &QgsGeometryValidationModel::onTopologyChecksCleared );
|
|
}
|
|
|
|
QModelIndex QgsGeometryValidationModel::index( int row, int column, const QModelIndex &parent ) const
|
|
{
|
|
Q_UNUSED( parent )
|
|
return createIndex( row, column );
|
|
}
|
|
|
|
QModelIndex QgsGeometryValidationModel::parent( const QModelIndex &child ) const
|
|
{
|
|
Q_UNUSED( child )
|
|
return QModelIndex();
|
|
}
|
|
|
|
int QgsGeometryValidationModel::rowCount( const QModelIndex &parent ) const
|
|
{
|
|
Q_UNUSED( parent )
|
|
return mErrorStorage.value( mCurrentLayer ).size() + mTopologyErrorStorage.value( mCurrentLayer ).size();
|
|
}
|
|
|
|
int QgsGeometryValidationModel::columnCount( const QModelIndex &parent ) const
|
|
{
|
|
Q_UNUSED( parent )
|
|
return 1;
|
|
}
|
|
|
|
QVariant QgsGeometryValidationModel::data( const QModelIndex &index, int role ) const
|
|
{
|
|
const auto &layerErrors = mErrorStorage.value( mCurrentLayer );
|
|
|
|
if ( index.row() >= layerErrors.size() )
|
|
{
|
|
// Topology error
|
|
const auto &topologyErrors = mTopologyErrorStorage.value( mCurrentLayer );
|
|
auto topologyError = topologyErrors.at( index.row() - layerErrors.size() );
|
|
|
|
switch ( role )
|
|
{
|
|
case Qt::DisplayRole:
|
|
{
|
|
const QgsFeatureId fid = topologyError->featureId();
|
|
const QgsFeature feature = mCurrentLayer->getFeature( fid ); // TODO: this should be cached!
|
|
mExpressionContext.setFeature( feature );
|
|
QString featureTitle = mDisplayExpression.evaluate( &mExpressionContext ).toString();
|
|
if ( featureTitle.isEmpty() )
|
|
featureTitle = fid;
|
|
|
|
return tr( "%1: %2" ).arg( featureTitle, topologyError->description() );
|
|
}
|
|
|
|
case FeatureExtentRole:
|
|
{
|
|
const QgsFeatureId fid = topologyError->featureId();
|
|
const QgsFeature feature = mCurrentLayer->getFeature( fid ); // TODO: this should be cached!
|
|
return feature.geometry().boundingBox();
|
|
}
|
|
|
|
case ProblemExtentRole:
|
|
{
|
|
return topologyError->affectedAreaBBox();
|
|
}
|
|
|
|
case ErrorGeometryRole:
|
|
{
|
|
return topologyError->geometry();
|
|
}
|
|
|
|
case FeatureGeometryRole:
|
|
{
|
|
const QgsFeatureId fid = topologyError->featureId();
|
|
const QgsFeature feature = mCurrentLayer->getFeature( fid ); // TODO: this should be cached!
|
|
return feature.geometry();
|
|
}
|
|
|
|
case ErrorLocationGeometryRole:
|
|
{
|
|
return topologyError->location();
|
|
}
|
|
|
|
case GeometryCheckErrorRole:
|
|
{
|
|
return QVariant::fromValue<QgsGeometryCheckError *>( topologyError.get() );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Geometry error
|
|
const auto &featureItem = layerErrors.at( index.row() );
|
|
|
|
switch ( role )
|
|
{
|
|
case Qt::DisplayRole:
|
|
{
|
|
QgsFeature feature = mCurrentLayer->getFeature( featureItem.fid ); // TODO: this should be cached!
|
|
mExpressionContext.setFeature( feature );
|
|
QString featureTitle = mDisplayExpression.evaluate( &mExpressionContext ).toString();
|
|
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 )->description() );
|
|
else
|
|
return QVariant();
|
|
}
|
|
|
|
case Qt::DecorationRole:
|
|
{
|
|
if ( mGeometryValidationService->validationActive( mCurrentLayer, featureItem.fid ) )
|
|
return QgsApplication::getThemeIcon( "/mActionTracing.svg" );
|
|
else
|
|
return QVariant();
|
|
}
|
|
|
|
default:
|
|
return QVariant();
|
|
}
|
|
}
|
|
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
QgsVectorLayer *QgsGeometryValidationModel::currentLayer() const
|
|
{
|
|
return mCurrentLayer;
|
|
}
|
|
|
|
void QgsGeometryValidationModel::setCurrentLayer( QgsVectorLayer *currentLayer )
|
|
{
|
|
if ( mCurrentLayer == currentLayer )
|
|
return;
|
|
|
|
beginResetModel();
|
|
mCurrentLayer = currentLayer;
|
|
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<std::shared_ptr<QgsSingleGeometryCheckError>> &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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void QgsGeometryValidationModel::onTopologyChecksUpdated( QgsVectorLayer *layer, const QList<std::shared_ptr<QgsGeometryCheckError> > &errors )
|
|
{
|
|
auto &topologyLayerErrors = mTopologyErrorStorage[layer];
|
|
|
|
if ( layer == currentLayer() )
|
|
{
|
|
const int oldRowCount = rowCount();
|
|
beginInsertRows( QModelIndex(), oldRowCount, oldRowCount + errors.size() );
|
|
}
|
|
|
|
topologyLayerErrors.append( errors );
|
|
|
|
if ( layer == currentLayer() )
|
|
{
|
|
endInsertRows();
|
|
}
|
|
}
|
|
|
|
void QgsGeometryValidationModel::onTopologyChecksCleared( QgsVectorLayer *layer )
|
|
{
|
|
auto &topologyLayerErrors = mTopologyErrorStorage[layer];
|
|
if ( topologyLayerErrors.empty() )
|
|
return;
|
|
|
|
if ( layer == currentLayer() )
|
|
{
|
|
beginRemoveRows( QModelIndex(), mErrorStorage.size(), rowCount() - 1 );
|
|
}
|
|
topologyLayerErrors.clear();
|
|
if ( layer == currentLayer() )
|
|
{
|
|
endRemoveRows();
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|