Skip to content
Permalink
Browse files

[attrtable] Selection model and request filter

* With a selection model, the way the attribute table handles selections
  can be customized. E.g. synchronized to layer selection or used to pick
  features.
* With request filters, the visible features on an attribute table can be
  limited. This will effectively reduce the subset of features the attribute
  table works on. Additional filters by means of a proxy model can of course
  further reduce the visible subset subsequently.
  • Loading branch information
m-kuhn committed Oct 7, 2013
1 parent 5e30831 commit 331f71acba72c3b5d63228c8f409771cd3fe8783
@@ -174,9 +174,8 @@ class QgsAttributeTableModel : QAbstractTableModel
/**
* Launched when a feature has been added
* @param fid feature id
* @param inOperation guard insertion with beginInsertRows() / endInsertRows()
*/
virtual void featureAdded( QgsFeatureId fid, bool inOperation = true );
virtual void featureAdded( QgsFeatureId fid );

/**
* Launched when layer has been deleted
@@ -10,15 +10,6 @@ class QgsAttributeTableView : QTableView

virtual void setModel( QgsAttributeTableFilterModel* filterModel );

/**
* Autocreates the models
* @param layerCache The @link QgsVectorLayerCache @endlink to use ( as backend )
* @param canvas The @link QgsMapCanvas @endlink to use ( for the currently visible features filter )
*
* @deprecated
*/
void setCanvasAndLayerCache( QgsMapCanvas *canvas, QgsVectorLayerCache *layerCache );

protected:
/**
* Called for mouse press events on a table cell.
@@ -31,16 +31,6 @@ class QgsDualView : QStackedWidget
explicit QgsDualView( QWidget* parent = 0 );
virtual ~QgsDualView();

/**
* Has to be called to initialize the dual view.
*
* @param layer The layer which should be used to fetch features
* @param mapCanvas The mapCanvas (used for the FilterMode
* {@link QgsAttributeTableFilterModel::ShowVisible}
* @param myDa Used for attribute dialog creation
*/
void init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, QgsDistanceArea myDa );

/**
* Change the current view mode.
*
@@ -1,10 +1,10 @@
class QgsFeatureSelectionModel : QItemSelectionModel
{
%TypeHeaderCode
#include <qgsfeatureselectionmodel.h>
#include <attributetable/qgsfeatureselectionmodel.h>
%End
public:
explicit QgsFeatureSelectionModel( QAbstractItemModel* model, QgsFeatureModel* featureModel, QgsVectorLayer* layer, QObject* parent );
explicit QgsFeatureSelectionModel( QAbstractItemModel* model, QgsFeatureModel* featureModel, QgsIFeatureSelectionManager* featureSelectionManager, QObject* parent );

/**
* Enables or disables synchronisation to the {@link QgsVectorLayer}
@@ -0,0 +1,77 @@
/***************************************************************************
qgsifeatureselectionmanager.sip
--------------------------------------
Date : 6.6.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* 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. *
* *
***************************************************************************/

/**
* Is an interface class to abstract feature selection handling.
*
* e.g. @link{QgsVectorLayer} implements this interface to manage its selections.
*/

class QgsIFeatureSelectionManager : QObject
{
%TypeHeaderCode
#include <qgsifeatureselectionmanager.h>
%End
public:
QgsIFeatureSelectionManager( QObject* parent );

/**
* The number of features that are selected in this layer
*
* @return See description
*/
virtual int selectedFeatureCount() = 0;

/**
* Select features
*
* @param ids Feature ids to select
*/
virtual void select( const QgsFeatureIds& ids ) = 0;

/**
* Deselect features
*
* @param ids Feature ids to deselect
*/
virtual void deselect( const QgsFeatureIds& ids ) = 0;

/**
* Change selection to the new set of features. Dismisses the current selection.
* Will emit the { @link selectionChanged( QgsFeatureIds, QgsFeatureIds, bool ) } signal with the
* clearAndSelect flag set.
*
* @param ids The ids which will be the new selection
*/
virtual void setSelectedFeatures( const QgsFeatureIds& ids ) = 0;

/**
* Return reference to identifiers of selected features
*
* @return A list of { @link QgsFeatureId } 's
* @see selectedFeatures()
*/
virtual const QgsFeatureIds &selectedFeaturesIds() const = 0;

signals:
/**
* This signal is emitted when selection was changed
*
* @param selected Newly selected feature ids
* @param deselected Ids of all features which have previously been selected but are not any more
* @param clearAndSelect In case this is set to true, the old selection was dismissed and the new selection corresponds to selected
*/
void selectionChanged( const QgsFeatureIds selected, const QgsFeatureIds deselected, const bool clearAndSelect );
};
@@ -90,6 +90,7 @@
%Include attributetable/qgsfeaturelistviewdelegate.sip
%Include attributetable/qgsfeaturemodel.sip
%Include attributetable/qgsfeatureselectionmodel.sip
%Include attributetable/qgsifeatureselectionmanager.sip

%Include raster/qgsmultibandcolorrendererwidget.sip
%Include raster/qgspalettedrendererwidget.sip
@@ -71,15 +71,18 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
// Initialize the window geometry
restoreGeometry( settings.value( "/Windows/BetterAttributeTable/geometry" ).toByteArray() );

QgsAttributeEditorContext context;

QgsDistanceArea myDa;

myDa.setSourceCrs( mLayer->crs() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );

context.setDistanceArea( myDa );

// Initialize dual view
mMainView->init( mLayer, QgisApp::instance()->mapCanvas(), myDa );
mMainView->init( mLayer, QgisApp::instance()->mapCanvas(), QgsFeatureRequest(), context );

// Initialize filter gui elements
mFilterActionMapper = new QSignalMapper( this );
@@ -38,15 +38,17 @@ symbology-ng/qgssvgselectorwidget.cpp
symbology-ng/qgslayerpropertieswidget.cpp
symbology-ng/qgssmartgroupeditordialog.cpp

attributetable/qgsattributetabledelegate.cpp
attributetable/qgsattributetablefiltermodel.cpp
attributetable/qgsattributetablemodel.cpp
attributetable/qgsattributetableview.cpp
attributetable/qgsattributetablefiltermodel.cpp
attributetable/qgsattributetabledelegate.cpp
attributetable/qgsfeaturelistview.cpp
attributetable/qgsdualview.cpp
attributetable/qgsfeaturelistmodel.cpp
attributetable/qgsfeaturelistview.cpp
attributetable/qgsfeaturelistviewdelegate.cpp
attributetable/qgsfeatureselectionmodel.cpp
attributetable/qgsdualview.cpp
attributetable/qgsgenericfeatureselectionmanager.cpp
attributetable/qgsvectorlayerselectionmanager.cpp

editorwidgets/core/qgseditorconfigwidget.cpp
editorwidgets/core/qgseditorwidgetfactory.cpp
@@ -173,15 +175,18 @@ symbology-ng/qgssvgselectorwidget.h
symbology-ng/qgslayerpropertieswidget.h
symbology-ng/qgssmartgroupeditordialog.h

attributetable/qgsattributetableview.h
attributetable/qgsattributetablemodel.h
attributetable/qgsattributetablefiltermodel.h
attributetable/qgsattributetabledelegate.h
attributetable/qgsfeaturelistview.h
attributetable/qgsattributetablefiltermodel.h
attributetable/qgsattributetablemodel.h
attributetable/qgsattributetableview.h
attributetable/qgsdualview.h
attributetable/qgsfeaturelistmodel.h
attributetable/qgsfeatureselectionmodel.h
attributetable/qgsfeaturelistview.h
attributetable/qgsfeaturelistviewdelegate.h
attributetable/qgsdualview.h
attributetable/qgsfeatureselectionmodel.h
attributetable/qgsgenericfeatureselectionmanager.h
attributetable/qgsifeatureselectionmanager.h
attributetable/qgsvectorlayerselectionmanager.h

editorwidgets/core/qgseditorconfigwidget.h
editorwidgets/core/qgseditorwidgetregistry.h
@@ -296,16 +301,19 @@ qgssvgannotationitem.h
qgscomposerruler.h
qgsdetaileditemdata.h

attributetable/qgsattributetabledelegate.h
attributetable/qgsattributetablefiltermodel.h
attributetable/qgsattributetablemodel.h
attributetable/qgsattributetableview.h
attributetable/qgsattributetablefiltermodel.h
attributetable/qgsattributetabledelegate.h
attributetable/qgsfeaturelistview.h
attributetable/qgsfeaturemodel.h
attributetable/qgsdualview.h
attributetable/qgsfeaturelistmodel.h
attributetable/qgsfeaturelistview.h
attributetable/qgsfeaturelistviewdelegate.h
attributetable/qgsfeaturemodel.h
attributetable/qgsfeatureselectionmodel.h
attributetable/qgsdualview.h
attributetable/qgsgenericfeatureselectionmanager.h
attributetable/qgsifeatureselectionmanager.h
attributetable/qgsvectorlayerselectionmanager.h

editorwidgets/core/qgseditorconfigwidget.h
editorwidgets/core/qgseditorwidgetfactory.h
@@ -33,7 +33,6 @@ QgsAttributeTableFilterModel::QgsAttributeTableFilterModel( QgsMapCanvas* canvas
, mFilterMode( ShowAll )
, mSelectedOnTop( false )
{
mMasterSelection = new QItemSelectionModel( this, this );
setSourceModel( sourceModel );
setDynamicSortFilter( true );
setSortRole( QgsAttributeTableModel::SortRole );
@@ -115,8 +114,6 @@ void QgsAttributeTableFilterModel::setSelectedOnTop( bool selectedOnTop )
void QgsAttributeTableFilterModel::setSourceModel( QgsAttributeTableModel* sourceModel )
{
mTableModel = sourceModel;
delete mMasterSelection;
mMasterSelection = new QItemSelectionModel( sourceModel, this );

QSortFilterProxyModel::setSourceModel( sourceModel );
}
@@ -167,7 +167,6 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
QgsMapCanvas* mCanvas;
FilterMode mFilterMode;
bool mSelectedOnTop;
QItemSelectionModel* mMasterSelection;
QgsAttributeTableModel* mTableModel;
};

@@ -50,11 +50,11 @@ QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayerCache *layerCache,

loadAttributes();

connect( layer(), SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
connect( layer(), SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) );
connect( mLayerCache, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
connect( layer(), SIGNAL( featureDeleted( QgsFeatureId ) ), this, SLOT( featureDeleted( QgsFeatureId ) ) );
connect( layer(), SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );
connect( layer(), SIGNAL( updatedFields() ), this, SLOT( updatedFields() ) );
connect( mLayerCache, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) );
connect( mLayerCache, SIGNAL( cachedLayerDeleted() ), this, SLOT( layerDeleted() ) );
}

@@ -77,13 +77,17 @@ bool QgsAttributeTableModel::loadFeatureAtId( QgsFeatureId fid ) const

void QgsAttributeTableModel::featureDeleted( QgsFeatureId fid )
{
prefetchColumnData( -1 ); // Invalidate cached column data
QgsDebugMsg( QString( "(%2) fid: %1" ).arg( fid ).arg( mFeatureRequest.filterType() ) );
mFieldCache.remove( fid );

int row = idToRow( fid );

beginRemoveRows( QModelIndex(), row, row );
removeRow( row );
endRemoveRows();
if ( row != -1 )
{
beginRemoveRows( QModelIndex(), row, row );
removeRow( row );
endRemoveRows();
}
}

bool QgsAttributeTableModel::removeRows( int row, int count, const QModelIndex &parent )
@@ -126,20 +130,23 @@ bool QgsAttributeTableModel::removeRows( int row, int count, const QModelIndex &
return true;
}

void QgsAttributeTableModel::featureAdded( QgsFeatureId fid, bool newOperation )
void QgsAttributeTableModel::featureAdded( QgsFeatureId fid )
{
prefetchColumnData( -1 ); // Invalidate cached column data
int n = mRowIdMap.size();
if ( newOperation )
QgsDebugMsg( QString( "(%2) fid: %1" ).arg( fid ).arg( mFeatureRequest.filterType() ) );
if ( loadFeatureAtId( fid ) && mFeatureRequest.acceptFeature( mFeat ) )
{
mFieldCache[ fid ] = mFeat.attribute( mCachedField );

int n = mRowIdMap.size();
beginInsertRows( QModelIndex(), n, n );

mIdRowMap.insert( fid, n );
mRowIdMap.insert( n, fid );
mIdRowMap.insert( fid, n );
mRowIdMap.insert( n, fid );

if ( newOperation )
endInsertRows();

reload( index( rowCount() - 1, 0 ), index( rowCount() - 1, columnCount() ) );
reload( index( rowCount() - 1, 0 ), index( rowCount() - 1, columnCount() ) );
}
}

void QgsAttributeTableModel::updatedFields()
@@ -176,14 +183,33 @@ void QgsAttributeTableModel::layerDeleted()

void QgsAttributeTableModel::attributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value )
{
if ( mCachedField == idx )
mFieldCache[ fid ] = value;

if ( fid == mFeat.id() )
QgsDebugMsg( QString( "(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.filterType() ) );
if ( loadFeatureAtId( fid ) )
{
mFeat.setValid( false );
if ( mFeatureRequest.acceptFeature( mFeat ) )
{
if ( !mIdRowMap.contains( fid ) )
{
// Feature changed in such a way, it will be shown now
featureAdded( fid );
}
else
{
mFieldCache[ fid ] = value;
// Update representation
setData( index( idToRow( fid ), fieldCol( idx ) ), value, Qt::EditRole );
}
}
else
{
if ( mIdRowMap.contains( fid ) )
{
// Feature changed such, that it is no longer shown
featureDeleted( fid );
}
// else: we don't care
}
}
setData( index( idToRow( fid ), fieldCol( idx ) ), value, Qt::EditRole );
}

void QgsAttributeTableModel::loadAttributes()
@@ -582,12 +608,6 @@ Qt::ItemFlags QgsAttributeTableModel::flags( const QModelIndex &index ) const

void QgsAttributeTableModel::reload( const QModelIndex &index1, const QModelIndex &index2 )
{
for ( int row = index1.row(); row <= index2.row(); row++ )
{
QgsFeatureId fid = rowToId( row );
mLayerCache->removeCachedFeature( fid );
}

mFeat.setFeatureId( std::numeric_limits<int>::min() );
emit dataChanged( index1, index2 );
}
@@ -646,6 +666,6 @@ void QgsAttributeTableModel::prefetchColumnData( int column )
void QgsAttributeTableModel::setRequest( const QgsFeatureRequest& request )
{
mFeatureRequest = request;
if( layer() && !layer()->hasGeometryType() )
if ( layer() && !layer()->hasGeometryType() )
mFeatureRequest.setFlags( mFeatureRequest.flags() | QgsFeatureRequest::NoGeometry );
}
@@ -227,9 +227,8 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
/**
* Launched when a feature has been added
* @param fid feature id
* @param inOperation guard insertion with beginInsertRows() / endInsertRows()
*/
virtual void featureAdded( QgsFeatureId fid, bool inOperation = true );
virtual void featureAdded( QgsFeatureId fid );

/**
* Launched when layer has been deleted

0 comments on commit 331f71a

Please sign in to comment.
You can’t perform that action at this time.