Skip to content

Commit 43dfeb5

Browse files
committed
Attribute table selection: performance improvements
When selecting features with the mouse (click and drag) only redraw the map canvas, once the mouse is released.
1 parent af4c4be commit 43dfeb5

File tree

7 files changed

+108
-37
lines changed

7 files changed

+108
-37
lines changed

src/gui/attributetable/qgsattributetablefiltermodel.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ void QgsAttributeTableFilterModel::masterSelectionChanged( const QItemSelection
179179
}
180180

181181
// Now emit the signal
182-
layer()->setSelectedFeatures( layer()->selectedFeaturesIds() );
182+
if ( mSyncSelection )
183+
{
184+
layer()->setSelectedFeatures( layer()->selectedFeaturesIds() );
185+
}
183186

184187
connect( layer(), SIGNAL( selectionChanged() ), this, SLOT( selectionChanged() ) );
185188
}
@@ -321,6 +324,17 @@ QItemSelectionModel* QgsAttributeTableFilterModel::masterSelection()
321324
return mMasterSelection;
322325
}
323326

327+
void QgsAttributeTableFilterModel::disableSelectionSync()
328+
{
329+
mSyncSelection = false;
330+
}
331+
332+
void QgsAttributeTableFilterModel::enableSelectionSync()
333+
{
334+
mSyncSelection = true;
335+
layer()->setSelectedFeatures( layer()->selectedFeaturesIds() );
336+
}
337+
324338
QModelIndex QgsAttributeTableFilterModel::mapToMaster( const QModelIndex &proxyIndex ) const
325339
{
326340
// Master is source

src/gui/attributetable/qgsattributetablefiltermodel.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel
9191
*/
9292
inline QgsVectorLayer *layer() const { return masterModel()->layer(); }
9393

94+
/**
95+
* Returns the layerCache this filter acts on.
96+
*
97+
* @return The layer cache
98+
*/
9499
inline QgsVectorLayerCache *layerCache() const { return masterModel()->layerCache(); }
95100

96101
/**
@@ -120,6 +125,21 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel
120125
*/
121126
QItemSelectionModel* masterSelection();
122127

128+
/**
129+
* Disables selection synchronisation with the map canvas. Changes to the selection in the master
130+
* model are propagated to the layer, but no redraw is requested until @link{enableSelectionSync()}
131+
* is called.
132+
*/
133+
void disableSelectionSync();
134+
135+
/**
136+
* Enables selection synchronisation with the map canvas. Changes to the selection in the master
137+
* are propagated and upon every change, a redraw will be requested. This method will update the
138+
* selection to account for any cached selection change since @link{disableSelectionSync()} was
139+
* called.
140+
*/
141+
void enableSelectionSync();
142+
123143
virtual QModelIndex mapToMaster( const QModelIndex &proxyIndex ) const;
124144

125145
virtual QModelIndex mapFromMaster( const QModelIndex &sourceIndex ) const;
@@ -194,6 +214,7 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel
194214
bool mSelectedOnTop;
195215
QItemSelectionModel* mMasterSelection;
196216
QgsAttributeTableModel* mTableModel;
217+
bool mSyncSelection;
197218
};
198219

199220
#endif

src/gui/attributetable/qgsattributetableview.cpp

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ QgsAttributeTableView::QgsAttributeTableView( QWidget *parent )
4646
setSelectionMode( QAbstractItemView::ExtendedSelection );
4747
setSortingEnabled( true );
4848

49-
connect( verticalHeader(), SIGNAL( sectionClicked( int ) ), SLOT( onVerticalHeaderSectionClicked( int ) ) );
49+
verticalHeader()->viewport()->installEventFilter( this );
5050
}
5151

5252
QgsAttributeTableView::~QgsAttributeTableView()
@@ -75,6 +75,30 @@ void QgsAttributeTableView::setCanvasAndLayerCache( QgsMapCanvas *canvas, QgsVec
7575
delete filterModel;
7676
}
7777

78+
bool QgsAttributeTableView::eventFilter(QObject *object, QEvent *event)
79+
{
80+
if ( object == verticalHeader()->viewport() )
81+
{
82+
83+
qDebug() << "Event " << event->type();
84+
85+
switch ( event->type() )
86+
{
87+
case QEvent::MouseButtonPress:
88+
mFilterModel->disableSelectionSync();
89+
break;
90+
91+
case QEvent::MouseButtonRelease:
92+
mFilterModel->enableSelectionSync();
93+
break;
94+
95+
default:
96+
break;
97+
}
98+
}
99+
return false;
100+
}
101+
78102
void QgsAttributeTableView::setModel( QgsAttributeTableFilterModel* filterModel )
79103
{
80104
if ( mFilterModel )
@@ -158,22 +182,6 @@ void QgsAttributeTableView::keyPressEvent( QKeyEvent *event )
158182
}
159183
}
160184

161-
void QgsAttributeTableView::onVerticalHeaderSectionClicked( int logicalIndex )
162-
{
163-
Q_UNUSED( logicalIndex )
164-
165-
QgsFeatureIds selectedFeatures;
166-
167-
QModelIndexList selectedRows = selectionModel()->selectedRows();
168-
169-
foreach ( QModelIndex row, selectedRows )
170-
{
171-
selectedFeatures.insert( mFilterModel->rowToId( row ) );
172-
}
173-
174-
emit selectionChangeFinished( selectedFeatures );
175-
}
176-
177185
void QgsAttributeTableView::onFilterAboutToBeInvalidated()
178186
{
179187
disconnect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SLOT( onSelectionChanged( QItemSelection, QItemSelection ) ) );

src/gui/attributetable/qgsattributetableview.h

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
6363
*/
6464
void setCanvasAndLayerCache( QgsMapCanvas *canvas, QgsVectorLayerCache *layerCache );
6565

66+
/**
67+
* This event filter is installed on the verticalHeader to intercept mouse press and release
68+
* events. These are used to disable / enable live synchronisation with the map canvas selection
69+
* which can be slow due to recurring canvas repaints. Updating the
70+
*
71+
* @param object The object which is the target of the event.
72+
* @param event The intercepted event
73+
*
74+
* @return Returns always false, so the event gets processed
75+
*/
76+
virtual bool eventFilter( QObject* object, QEvent* event );
77+
6678
protected:
6779
/**
6880
* Called for mouse press events on a table cell.
@@ -124,23 +136,7 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
124136

125137
void finished();
126138

127-
/**
128-
* @brief
129-
* Is emitted, after the selection has been changed.
130-
*
131-
* @param selectedFeatures A list of currently selected features.
132-
*/
133-
void selectionChangeFinished( const QgsFeatureIds &selectedFeatures );
134-
135139
public slots:
136-
/**
137-
* Is triggered after a mouse release event on the vertical header.
138-
* Emits a selectionChangeFinished() signal, so the underlying sort filter
139-
* can adapt to the current selection without disturbing the users current interaction.
140-
*
141-
* @param logicalIndex The section's logical index
142-
*/
143-
void onVerticalHeaderSectionClicked( int logicalIndex );
144140
void onFilterAboutToBeInvalidated();
145141
void onFilterInvalidated();
146142
void onSelectionChanged( const QItemSelection& selected, const QItemSelection& deselected );

src/gui/attributetable/qgsfeaturelistmodel.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,13 @@ int QgsFeatureListModel::rowCount( const QModelIndex& parent ) const
238238
Q_UNUSED( parent )
239239
return sourceModel()->rowCount();
240240
}
241+
242+
void QgsFeatureListModel::disableSelectionSync()
243+
{
244+
mFilterModel->disableSelectionSync();
245+
}
246+
247+
void QgsFeatureListModel::enableSelectionSync()
248+
{
249+
mFilterModel->enableSelectionSync();
250+
}

src/gui/attributetable/qgsfeaturelistmodel.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,21 @@ class QgsFeatureListModel : public QAbstractProxyModel
8585
virtual int columnCount( const QModelIndex&parent = QModelIndex() ) const;
8686
virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
8787

88+
/**
89+
* Disables selection synchronisation with the map canvas. Changes to the selection in the master
90+
* model are propagated to the layer, but no redraw is requested until @link{enableSelectionSync()}
91+
* is called.
92+
*/
93+
void disableSelectionSync();
94+
95+
/**
96+
* Enables selection synchronisation with the map canvas. Changes to the selection in the master
97+
* are propagated and upon every change, a redraw will be requested. This method will update the
98+
* selection to account for any cached selection change since @link{disableSelectionSync()} was
99+
* called.
100+
*/
101+
void enableSelectionSync();
102+
88103
public slots:
89104
void onBeginRemoveRows( const QModelIndex& parent, int first, int last );
90105
void onEndRemoveRows( const QModelIndex& parent, int first, int last );

src/gui/attributetable/qgsfeaturelistview.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,22 @@ void QgsFeatureListView::mousePressEvent( QMouseEvent *event )
115115
}
116116
else
117117
{
118+
mModel->disableSelectionSync();
118119
QListView::mousePressEvent( event );
119120
}
120121
}
121122

122123
void QgsFeatureListView::mouseReleaseEvent( QMouseEvent *event )
123124
{
124-
mEditSelectionDrag = false;
125-
126-
QListView::mouseReleaseEvent( event );
125+
if ( mEditSelectionDrag )
126+
{
127+
mEditSelectionDrag = false;
128+
}
129+
else
130+
{
131+
QListView::mouseReleaseEvent( event );
132+
mModel->enableSelectionSync();
133+
}
127134
}
128135

129136
void QgsFeatureListView::editSelectionChanged( QItemSelection deselected, QItemSelection selected )

0 commit comments

Comments
 (0)