Skip to content

Commit

Permalink
Use QgsFieldProxyModel for filtering read only fields
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jun 15, 2016
1 parent 8563285 commit ae93ee3
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 86 deletions.
20 changes: 2 additions & 18 deletions python/gui/qgsfieldmodel.sip
Expand Up @@ -19,16 +19,9 @@ class QgsFieldModel : QAbstractItemModel
ExpressionRole, /*!< return field name or expression */
IsExpressionRole, /*!< return if index corresponds to an expression */
ExpressionValidityRole, /*!< return if expression is valid or not */
FieldTypeRole /*!< return the field type (if a field, return QVariant if expression) */
FieldTypeRole, /*!< return the field type (if a field, return QVariant if expression) */
FieldOriginRole, /*!< return the field origin (if a field, returns QVariant if expression) */
};
/**
* Filters for which fields should be shown
*/
enum Filter
{
WritableFields = 1 //!< Only show writable fields
};
typedef QFlags<QgsFieldModel::Filter> Filters;

/**
* @brief QgsFieldModel creates a model to display the fields of a given layer
Expand All @@ -54,15 +47,6 @@ class QgsFieldModel : QAbstractItemModel

//! returns the currently used layer
QgsVectorLayer* layer();
/**
* The currently applied filters that define which fields are shown.
*/
Filters filters() const;

/**
* The currently applied filters that define which fields are shown.
*/
void setFilters( const Filters& filter );

public slots:
//! set the layer of whch fields are displayed
Expand Down
3 changes: 2 additions & 1 deletion python/gui/qgsfieldproxymodel.sip
Expand Up @@ -21,7 +21,8 @@ class QgsFieldProxyModel : QSortFilterProxyModel
Numeric, /*!< All numeric fields */
Date, /*!< Date or datetime fields */
Time, /*!< Time fields */
All, /*!< All fields */
HideReadOnly, /*!< Hide read-only fields */
All, /*!< All field types */
};
typedef QFlags<QgsFieldProxyModel::Filter> Filters;

Expand Down
14 changes: 8 additions & 6 deletions src/app/qgsattributetabledialog.cpp
Expand Up @@ -47,6 +47,7 @@
#include "qgsrubberband.h"
#include "qgsfield.h"
#include "qgseditorwidgetregistry.h"
#include "qgsfieldproxymodel.h"

static QgsExpressionContext _getExpressionContext( const void* context )
{
Expand Down Expand Up @@ -248,11 +249,9 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
}

mUpdateExpressionText->registerGetExpressionContextCallback( &_getExpressionContext, mLayer );
mFieldCombo->setFilters( QgsFieldProxyModel::All | QgsFieldProxyModel::HideReadOnly );
mFieldCombo->setLayer( mLayer );

mFieldModel = new QgsFieldModel( this );
mFieldModel->setFilters( QgsFieldModel::WritableFields );
mFieldModel->setLayer( mLayer );
mFieldCombo->setModel( mFieldModel );
connect( mRunFieldCalc, SIGNAL( clicked() ), this, SLOT( updateFieldFromExpression() ) );
connect( mRunFieldCalcSelected, SIGNAL( clicked() ), this, SLOT( updateFieldFromExpressionSelected() ) );
// NW TODO Fix in 2.6 - Doesn't work with field model for some reason.
Expand Down Expand Up @@ -411,8 +410,7 @@ void QgsAttributeTableDialog::runFieldCalculation( QgsVectorLayer* layer, const

mLayer->beginEditCommand( "Field calculator" );

QModelIndex modelindex = mFieldModel->indexFromName( fieldName );
int fieldindex = modelindex.data( QgsFieldModel::FieldIndexRole ).toInt();
int fieldindex = layer->fields().indexFromName( fieldName );

bool calculationSuccess = true;
QString error;
Expand Down Expand Up @@ -738,6 +736,10 @@ void QgsAttributeTableDialog::editingToggled()
mAddFeature->setEnabled( canAddFeatures && mLayer->isEditable() );

mUpdateExpressionBox->setVisible( mLayer->isEditable() );
if ( mLayer->isEditable() && mFieldCombo->currentIndex() == -1 )
{
mFieldCombo->setCurrentIndex( 0 );
}
// not necessary to set table read only if layer is not editable
// because model always reflects actual state when returning item flags
}
Expand Down
3 changes: 0 additions & 3 deletions src/app/qgsattributetabledialog.h
Expand Up @@ -28,7 +28,6 @@

#include "qgsattributedialog.h"
#include "qgsvectorlayer.h" //QgsFeatureIds
#include "qgsfieldmodel.h"
#include "qgssearchwidgetwrapper.h"
#include "qgsdockwidget.h"

Expand Down Expand Up @@ -222,8 +221,6 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
QSignalMapper* mFilterActionMapper;

QgsVectorLayer* mLayer;
QgsFieldModel* mFieldModel;

QgsRubberBand* mRubberBand;
QgsSearchWidgetWrapper* mCurrentSearchWidgetWrapper;
QStringList mVisibleFields;
Expand Down
51 changes: 18 additions & 33 deletions src/gui/qgsfieldmodel.cpp
Expand Up @@ -94,35 +94,11 @@ void QgsFieldModel::layerDeleted()
updateModel();
}

QgsFieldModel::Filters QgsFieldModel::filters() const
{
return mFilters;
}

void QgsFieldModel::setFilters( const Filters& filters )
{
if ( filters == mFilters )
return;

mFilters = filters;

updateModel();
}

void QgsFieldModel::updateModel()
{
if ( mLayer )
{
QgsFields fields = mLayer->fields();
QgsFields newFields;
for ( int i = 0; i < fields.count(); ++i )
{
if ( fields.fieldOrigin( i ) != QgsFields::OriginExpression && fields.fieldOrigin( i ) != QgsFields::OriginJoin )
{
newFields.append( fields.at( i ), fields.fieldOrigin( i ), fields.fieldOriginIndex( i ) );
}
}

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.
Expand Down Expand Up @@ -277,19 +253,19 @@ QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
{
return "";
}
QgsField field = mFields[index.row()];
QgsField field = mFields.at( index.row() );
return field.name();
}

case ExpressionRole:
{
if ( exprIdx >= 0 )
{
return mExpression[exprIdx];
return mExpression.at( exprIdx );
}
else
{
QgsField field = mFields[index.row()];
QgsField field = mFields.at( index.row() );
return field.name();
}
}
Expand All @@ -312,7 +288,7 @@ QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
{
if ( exprIdx >= 0 )
{
QgsExpression exp( mExpression[exprIdx] );
QgsExpression exp( mExpression.at( exprIdx ) );
QgsExpressionContext context;
if ( mLayer )
context.setFields( mLayer->fields() );
Expand All @@ -327,22 +303,31 @@ QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
{
if ( exprIdx < 0 )
{
QgsField field = mFields[index.row()];
QgsField field = mFields.at( index.row() );
return static_cast< int >( field.type() );
}
return QVariant();
}

case FieldOriginRole:
{
if ( exprIdx < 0 )
{
return static_cast< int >( mFields.fieldOrigin( index.row() ) );
}
return QVariant();
}

case Qt::DisplayRole:
case Qt::EditRole:
{
if ( exprIdx >= 0 )
{
return mExpression[exprIdx];
return mExpression.at( exprIdx );
}
else if ( role == Qt::EditRole )
{
return mFields[index.row()].name();
return mFields.at( index.row() ).name();
}
else if ( mLayer )
{
Expand All @@ -357,7 +342,7 @@ QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
if ( exprIdx >= 0 )
{
// if expression, test validity
QgsExpression exp( mExpression[exprIdx] );
QgsExpression exp( mExpression.at( exprIdx ) );
QgsExpressionContext context;
if ( mLayer )
context.setFields( mLayer->fields() );
Expand Down
26 changes: 4 additions & 22 deletions src/gui/qgsfieldmodel.h
Expand Up @@ -39,18 +39,10 @@ class GUI_EXPORT QgsFieldModel : public QAbstractItemModel
ExpressionRole = Qt::UserRole + 3, /*!< return field name or expression */
IsExpressionRole = Qt::UserRole + 4, /*!< return if index corresponds to an expression */
ExpressionValidityRole = Qt::UserRole + 5, /*!< return if expression is valid or not */
FieldTypeRole = Qt::UserRole + 6 /*!< return the field type (if a field, return QVariant if expression) */
FieldTypeRole = Qt::UserRole + 6, /*!< return the field type (if a field, return QVariant if expression) */
FieldOriginRole = Qt::UserRole + 7, /*!< return the field origin (if a field, returns QVariant if expression) */
};

/**
* Filters for which fields should be shown
*/
enum Filter
{
WritableFields = 1 //!< Only show writable fields
};
Q_DECLARE_FLAGS( Filters, Filter )

/**
* @brief QgsFieldModel creates a model to display the fields of a given layer
*/
Expand Down Expand Up @@ -83,16 +75,6 @@ class GUI_EXPORT QgsFieldModel : public QAbstractItemModel
int columnCount( const QModelIndex &parent ) const override;
QVariant data( const QModelIndex &index, int role ) const override;

/**
* The currently applied filters that define which fields are shown.
*/
Filters filters() const;

/**
* The currently applied filters that define which fields are shown.
*/
void setFilters( const Filters& filter );

public slots:
//! set the layer of whch fields are displayed
void setLayer( QgsVectorLayer *layer );
Expand All @@ -103,14 +85,14 @@ class GUI_EXPORT QgsFieldModel : public QAbstractItemModel
private slots:
void layerDeleted();

private:
protected:
QgsFields mFields;
QList<QString> mExpression;

QgsVectorLayer* mLayer;
bool mAllowExpression;
Filters mFilters;

private:
void fetchFeature();
};

Expand Down
32 changes: 31 additions & 1 deletion src/gui/qgsfieldproxymodel.cpp
Expand Up @@ -32,12 +32,42 @@ QgsFieldProxyModel *QgsFieldProxyModel::setFilters( const Filters& filters )
return this;
}

bool QgsFieldProxyModel::isReadOnly( const QModelIndex& index ) const
{
QVariant originVariant = sourceModel()->data( index, QgsFieldModel::FieldOriginRole );
if ( originVariant.isNull() )
{
//expression
return true;
}

QgsFields::FieldOrigin origin = static_cast< QgsFields::FieldOrigin >( originVariant.toInt() );
switch ( origin )
{
case QgsFields::OriginUnknown:
case QgsFields::OriginJoin:
case QgsFields::OriginExpression:
//read only
return true;

case QgsFields::OriginEdit:
case QgsFields::OriginProvider:
//not read only
return false;
}
return false; // avoid warnings
}

bool QgsFieldProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
{
QModelIndex index = sourceModel()->index( source_row, 0, source_parent );

if ( mFilters.testFlag( HideReadOnly ) && isReadOnly( index ) )
return false;

if ( mFilters.testFlag( All ) )
return true;

QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
QVariant typeVar = sourceModel()->data( index, QgsFieldModel::FieldTypeRole );

// if expression, consider valid
Expand Down
6 changes: 5 additions & 1 deletion src/gui/qgsfieldproxymodel.h
Expand Up @@ -41,7 +41,8 @@ class GUI_EXPORT QgsFieldProxyModel : public QSortFilterProxyModel
Numeric = Int | LongLong | Double, /*!< All numeric fields */
Date = 16, /*!< Date or datetime fields */
Time = 32, /*!< Time fields */
All = Numeric | Date | String | Time, /*!< All fields */
HideReadOnly = 64, /*!< Hide read-only fields */
All = Numeric | Date | String | Time, /*!< All field types */ //TODO QGIS 3 - rename to AllTypes
};
Q_DECLARE_FLAGS( Filters, Filter )

Expand Down Expand Up @@ -70,6 +71,9 @@ class GUI_EXPORT QgsFieldProxyModel : public QSortFilterProxyModel
Filters mFilters;
QgsFieldModel* mModel;

//! Returns true if the specified index represents a read only field
bool isReadOnly( const QModelIndex& index ) const;

// QSortFilterProxyModel interface
public:
bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
Expand Down
7 changes: 6 additions & 1 deletion src/ui/qgsattributetabledialog.ui
Expand Up @@ -787,7 +787,7 @@
<number>3</number>
</property>
<item>
<widget class="QComboBox" name="mFieldCombo"/>
<widget class="QgsFieldComboBox" name="mFieldCombo"/>
</item>
<item>
<widget class="QLabel" name="label">
Expand Down Expand Up @@ -910,6 +910,11 @@
<header>qgsdualview.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsFieldComboBox</class>
<extends>QComboBox</extends>
<header>qgsfieldcombobox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mToggleEditingButton</tabstop>
Expand Down

0 comments on commit ae93ee3

Please sign in to comment.