QGIS/src/core/qgsfieldmodel.cpp
Nyall Dawson a87d352bd7 Run clang-tidy modernize-use-default-member-init to move member
initialization to headers (c++11 style)
2017-09-27 05:02:34 +10:00

429 lines
10 KiB
C++

/***************************************************************************
qgsfieldmodel.cpp
--------------------------------------
Date : 01.04.2014
Copyright : (C) 2014 Denis Rouzaud
Email : denis.rouzaud@gmail.com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <QFont>
#include <QIcon>
#include "qgsfieldmodel.h"
#include "qgsmaplayermodel.h"
#include "qgsmaplayerproxymodel.h"
#include "qgslogger.h"
#include "qgsapplication.h"
#include "qgsvectorlayer.h"
QgsFieldModel::QgsFieldModel( QObject *parent )
: QAbstractItemModel( parent )
{
}
QModelIndex QgsFieldModel::indexFromName( const QString &fieldName )
{
QString fldName( fieldName ); // we may need a copy
if ( mLayer )
{
// the name could be an alias
// it would be better to have "display name" directly in QgsFields
// rather than having to consult layer in various places in code!
QString fieldNameWithAlias = mLayer->attributeAliases().key( fldName );
if ( !fieldNameWithAlias.isNull() )
fldName = fieldNameWithAlias;
}
if ( mAllowEmpty && fieldName.isEmpty() )
return index( 0, 0 );
int r = mFields.lookupField( fldName );
if ( r >= 0 )
{
if ( mAllowEmpty )
r++;
QModelIndex idx = index( r, 0 );
if ( idx.isValid() )
{
return idx;
}
}
if ( mAllowExpression )
{
int exprIdx = mExpression.indexOf( fldName );
if ( exprIdx != -1 )
{
return index( ( mAllowEmpty ? 1 : 0 ) + mFields.count() + exprIdx, 0 );
}
}
return QModelIndex();
}
bool QgsFieldModel::isField( const QString &expression ) const
{
int index = mFields.indexFromName( expression );
return index >= 0;
}
void QgsFieldModel::setLayer( QgsVectorLayer *layer )
{
if ( mLayer )
{
disconnect( mLayer, &QgsVectorLayer::updatedFields, this, &QgsFieldModel::updateModel );
disconnect( mLayer, &QObject::destroyed, this, &QgsFieldModel::layerDeleted );
}
mLayer = layer;
if ( mLayer )
{
connect( mLayer, &QgsVectorLayer::updatedFields, this, &QgsFieldModel::updateModel );
connect( mLayer, &QObject::destroyed, this, &QgsFieldModel::layerDeleted );
}
updateModel();
}
void QgsFieldModel::layerDeleted()
{
mLayer = nullptr;
updateModel();
}
void QgsFieldModel::updateModel()
{
int offset = mAllowEmpty ? 1 : 0;
if ( mLayer )
{
QgsFields newFields = mLayer->fields();
if ( mFields.toList() != newFields.toList() )
{
// Try to handle two special cases: addition of a new field and removal of a field.
// It would be better to listen directly to attributeAdded/attributeDeleted
// so we would not have to check for addition/removal here.
if ( mFields.count() == newFields.count() - 1 )
{
QgsFields tmpNewFields = newFields;
tmpNewFields.remove( tmpNewFields.count() - 1 );
if ( mFields.toList() == tmpNewFields.toList() )
{
// the only change is a new field at the end
beginInsertRows( QModelIndex(), mFields.count() + offset, mFields.count() + offset );
mFields = newFields;
endInsertRows();
return;
}
}
if ( mFields.count() == newFields.count() + 1 )
{
QgsFields tmpOldFields = mFields;
tmpOldFields.remove( tmpOldFields.count() - 1 );
if ( tmpOldFields.toList() == newFields.toList() )
{
// the only change is a field removed at the end
beginRemoveRows( QModelIndex(), mFields.count() - 1 + offset, mFields.count() - 1 + offset );
mFields = newFields;
endRemoveRows();
return;
}
for ( int i = 0; i < newFields.count(); ++i )
{
if ( mFields.at( i ) != newFields.at( i ) )
{
QgsFields tmpOldFields = mFields;
tmpOldFields.remove( i );
if ( tmpOldFields.toList() != newFields.toList() )
break; // the change is more complex - go with general case
// the only change is a field removed at index i
beginRemoveRows( QModelIndex(), i + offset, i + offset );
mFields = newFields;
endRemoveRows();
return;
}
}
}
// general case with reset - not good - resets selections
beginResetModel();
mFields = mLayer->fields();
endResetModel();
}
else
emit dataChanged( index( 0 + offset, 0 ), index( rowCount(), 0 ) );
}
else
{
beginResetModel();
mFields = QgsFields();
endResetModel();
}
}
void QgsFieldModel::setAllowExpression( bool allowExpression )
{
if ( allowExpression == mAllowExpression )
return;
mAllowExpression = allowExpression;
if ( !mAllowExpression )
{
int start = mFields.count();
int end = start + mExpression.count() - 1;
beginRemoveRows( QModelIndex(), start, end );
mExpression = QList<QString>();
endRemoveRows();
}
}
void QgsFieldModel::setAllowEmptyFieldName( bool allowEmpty )
{
if ( allowEmpty == mAllowEmpty )
return;
if ( allowEmpty )
{
beginInsertRows( QModelIndex(), 0, 0 );
mAllowEmpty = true;
endInsertRows();
}
else
{
beginRemoveRows( QModelIndex(), 0, 0 );
mAllowEmpty = false;
endRemoveRows();
}
}
void QgsFieldModel::setExpression( const QString &expression )
{
if ( !mAllowExpression )
return;
QModelIndex idx = indexFromName( expression );
if ( idx.isValid() )
return;
beginResetModel();
mExpression = QList<QString>();
if ( !expression.isEmpty() )
mExpression << expression;
endResetModel();
}
void QgsFieldModel::removeExpression()
{
beginResetModel();
mExpression = QList<QString>();
endResetModel();
}
QModelIndex QgsFieldModel::index( int row, int column, const QModelIndex &parent ) const
{
if ( hasIndex( row, column, parent ) )
{
return createIndex( row, column, row );
}
return QModelIndex();
}
QModelIndex QgsFieldModel::parent( const QModelIndex &child ) const
{
Q_UNUSED( child );
return QModelIndex();
}
int QgsFieldModel::rowCount( const QModelIndex &parent ) const
{
if ( parent.isValid() )
{
return 0;
}
return ( mAllowEmpty ? 1 : 0 ) + ( mAllowExpression ? mFields.count() + mExpression.count() : mFields.count() );
}
int QgsFieldModel::columnCount( const QModelIndex &parent ) const
{
Q_UNUSED( parent );
return 1;
}
QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
{
if ( !index.isValid() )
return QVariant();
int exprIdx = index.row() - mFields.count();
if ( mAllowEmpty )
exprIdx--;
bool isEmpty = mAllowEmpty && index.row() == 0;
int fieldOffset = mAllowEmpty ? 1 : 0;
switch ( role )
{
case FieldNameRole:
{
if ( isEmpty || exprIdx >= 0 )
{
return "";
}
QgsField field = mFields.at( index.row() - fieldOffset );
return field.name();
}
case ExpressionRole:
{
if ( exprIdx >= 0 )
{
return mExpression.at( exprIdx );
}
else if ( isEmpty )
{
return QVariant();
}
else
{
QgsField field = mFields.at( index.row() - fieldOffset );
return field.name();
}
}
case FieldIndexRole:
{
if ( isEmpty || exprIdx >= 0 )
{
return QVariant();
}
return index.row() - fieldOffset;
}
case IsExpressionRole:
{
return exprIdx >= 0;
}
case ExpressionValidityRole:
{
if ( exprIdx >= 0 )
{
QgsExpression exp( mExpression.at( exprIdx ) );
QgsExpressionContext context;
if ( mLayer )
context.setFields( mLayer->fields() );
exp.prepare( &context );
return !exp.hasParserError();
}
return true;
}
case FieldTypeRole:
{
if ( exprIdx < 0 && !isEmpty )
{
QgsField field = mFields.at( index.row() - fieldOffset );
return static_cast< int >( field.type() );
}
return QVariant();
}
case FieldOriginRole:
{
if ( exprIdx < 0 && !isEmpty )
{
return static_cast< int >( mFields.fieldOrigin( index.row() - fieldOffset ) );
}
return QVariant();
}
case IsEmptyRole:
{
return isEmpty;
}
case Qt::DisplayRole:
case Qt::EditRole:
{
if ( isEmpty )
{
return QVariant();
}
else if ( exprIdx >= 0 )
{
return mExpression.at( exprIdx );
}
else if ( role == Qt::EditRole )
{
return mFields.at( index.row() - fieldOffset ).name();
}
else if ( mLayer )
{
return mLayer->attributeDisplayName( index.row() - fieldOffset );
}
else
return QVariant();
}
case Qt::ForegroundRole:
{
if ( !isEmpty && exprIdx >= 0 )
{
// if expression, test validity
QgsExpression exp( mExpression.at( exprIdx ) );
QgsExpressionContext context;
if ( mLayer )
context.setFields( mLayer->fields() );
exp.prepare( &context );
if ( exp.hasParserError() )
{
return QBrush( QColor( Qt::red ) );
}
}
return QVariant();
}
case Qt::FontRole:
{
if ( !isEmpty && exprIdx >= 0 )
{
// if the line is an expression, set it as italic
QFont font = QFont();
font.setItalic( true );
return font;
}
return QVariant();
}
case Qt::DecorationRole:
{
if ( !isEmpty && exprIdx < 0 )
{
return mFields.iconForField( index.row() - fieldOffset );
}
return QIcon();
}
default:
return QVariant();
}
}