Skip to content

Commit 39e4c16

Browse files
committed
[FEATURE] make loading attributes interruptable
- also show progress - fix tracking of canvas extent (OTFR wasn't considered)
1 parent 7b85948 commit 39e4c16

9 files changed

+111
-64
lines changed

src/app/qgsattributetabledialog.cpp

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,23 @@ class QgsAttributeTableDock : public QDockWidget
5454

5555

5656
QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWidget *parent, Qt::WindowFlags flags )
57-
: QDialog( parent, flags ), mDock( NULL )
57+
: QDialog( parent, flags ), mDock( 0 ), mLayer( theLayer ), mProgress( 0 ), mWorkaround( false )
5858
{
59-
mLayer = theLayer;
60-
6159
setupUi( this );
6260

6361
setAttribute( Qt::WA_DeleteOnClose );
6462

6563
QSettings settings;
6664
restoreGeometry( settings.value( "/Windows/BetterAttributeTable/geometry" ).toByteArray() );
6765

68-
// extent has to be set before the model is created
69-
QgsAttributeTableModel::setCurrentExtent( QgisApp::instance()->mapCanvas()->extent() );
70-
connect( QgisApp::instance()->mapCanvas(), SIGNAL( extentsChanged() ), this, SLOT( updateExtent() ) );
66+
mView->setCanvasAndLayer( QgisApp::instance()->mapCanvas(), mLayer );
7167

72-
mView->setLayer( mLayer );
7368
mFilterModel = ( QgsAttributeTableFilterModel * ) mView->model();
74-
mModel = ( QgsAttributeTableModel * )(( QgsAttributeTableFilterModel * )mView->model() )->sourceModel();
69+
mModel = qobject_cast<QgsAttributeTableModel * >( dynamic_cast<QgsAttributeTableFilterModel *>( mView->model() )->sourceModel() );
70+
71+
connect( mModel, SIGNAL( progress( int, bool & ) ), this, SLOT( progress( int, bool & ) ) );
72+
mModel->loadLayer();
73+
delete mProgress;
7574

7675
mQuery = query;
7776
mColumnBox = columnBox;
@@ -127,20 +126,21 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
127126
// info from layer to table
128127
connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) );
129128
connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
129+
connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
130+
connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( close() ) );
130131

131132
connect( searchButton, SIGNAL( clicked() ), this, SLOT( search() ) );
132133
connect( mAddFeature, SIGNAL( clicked() ), this, SLOT( addFeature() ) );
133134

134-
connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
135-
connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( close() ) );
136135
connect( mView->verticalHeader(), SIGNAL( sectionClicked( int ) ), this, SLOT( updateRowSelection( int ) ) );
137136
connect( mView->verticalHeader(), SIGNAL( sectionPressed( int ) ), this, SLOT( updateRowPressed( int ) ) );
137+
138138
connect( mModel, SIGNAL( modelChanged() ), this, SLOT( updateSelection() ) );
139139

140140
connect( mView, SIGNAL( willShowContextMenu( QMenu*, QModelIndex ) ), this, SLOT( viewWillShowContextMenu( QMenu*, QModelIndex ) ) );
141141

142142
mLastClickedHeaderIndex = 0;
143-
mSelectionModel = new QItemSelectionModel( mFilterModel );
143+
mSelectionModel = new QItemSelectionModel( mFilterModel, this );
144144
updateSelectionFromLayer();
145145

146146
//make sure to show all recs on first load
@@ -149,7 +149,6 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
149149

150150
QgsAttributeTableDialog::~QgsAttributeTableDialog()
151151
{
152-
delete mSelectionModel;
153152
}
154153

155154
void QgsAttributeTableDialog::updateTitle()
@@ -797,12 +796,6 @@ void QgsAttributeTableDialog::addFeature()
797796
}
798797
}
799798

800-
void QgsAttributeTableDialog::updateExtent()
801-
{
802-
// let the model know about the new extent (we may be showing only features from current extent)
803-
QgsAttributeTableModel::setCurrentExtent( QgisApp::instance()->mapCanvas()->extent() );
804-
}
805-
806799
void QgsAttributeTableDialog::viewWillShowContextMenu( QMenu* menu, QModelIndex atIndex )
807800
{
808801
QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
@@ -829,6 +822,38 @@ void QgsAttributeTableDialog::viewWillShowContextMenu( QMenu* menu, QModelIndex
829822
menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
830823
}
831824

825+
void QgsAttributeTableDialog::progress( int i, bool &cancel )
826+
{
827+
if ( !mProgress )
828+
{
829+
mProgress = new QProgressDialog( tr( "Loading feature attributes..." ), tr( "Abort" ), 0, 0, this );
830+
mProgress->setWindowTitle( tr( "Attribute table" ) );
831+
mProgress->setWindowModality( Qt::WindowModal );
832+
mStarted.start();
833+
}
834+
835+
mProgress->setValue( i );
836+
837+
if ( i > 0 && i % 1000 == 0 )
838+
{
839+
mProgress->setLabelText( tr( "%1 features loaded." ).arg( i ) );
840+
}
841+
842+
if ( !mProgress->isVisible() && mStarted.elapsed() > mProgress->minimumDuration()*5 / 4 )
843+
{
844+
// for some reason this is sometimes necessary
845+
mProgress->show();
846+
mWorkaround = true;
847+
}
848+
849+
if ( mWorkaround )
850+
{
851+
QCoreApplication::processEvents();
852+
}
853+
854+
cancel = mProgress->wasCanceled();
855+
}
856+
832857
void QgsAttributeTableAction::execute()
833858
{
834859
mModel->executeAction( mAction, mFieldIdx );

src/app/qgsattributetabledialog.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
#include <QDialog>
2121
#include <QModelIndex>
2222
#include <QItemSelectionModel>
23-
#include <QMutex>
23+
24+
#include <time.h>
2425

2526
#include "ui_qgsattributetabledialog.h"
2627
#include "qgscontexthelp.h"
@@ -33,6 +34,7 @@ class QLineEdit;
3334
class QComboBox;
3435
class QMenu;
3536
class QDockWidget;
37+
class QProgressDialog;
3638

3739
class QgsAttributeTableModel;
3840
class QgsAttributeTableFilterModel;
@@ -58,10 +60,10 @@ class QgsAttributeTableDialog : public QDialog, private Ui::QgsAttributeTableDia
5860
*/
5961
void editingToggled();
6062

61-
void updateExtent();
62-
6363
void viewWillShowContextMenu( QMenu* menu, QModelIndex atIndex );
6464

65+
void progress( int i, bool &cancel );
66+
6567
private slots:
6668
/**
6769
* submits the data
@@ -208,21 +210,22 @@ class QgsAttributeTableDialog : public QDialog, private Ui::QgsAttributeTableDia
208210

209211
QLineEdit *mQuery;
210212
QComboBox *mColumnBox;
211-
QComboBox *mShowBox;
212213

213214
QMenu* mMenuActions;
214215
QAction* mActionToggleEditing;
215216

216217
QgsAttributeTableModel *mModel;
217218
QgsAttributeTableFilterModel *mFilterModel;
219+
QDockWidget *mDock;
218220
QgsVectorLayer *mLayer;
221+
QProgressDialog *mProgress;
222+
QTime mStarted;
223+
bool mWorkaround;
219224
QgsFeatureIds mSelectedFeatures;
220225
int mIndexPressed;
221226

222227
QItemSelectionModel* mSelectionModel;
223228
int mLastClickedHeaderIndex;
224-
225-
QDockWidget *mDock;
226229
};
227230

228231

src/browser/qgsbrowser.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
#include "qgsvectorlayer.h"
3232
#include "qgsrasterlayer.h"
3333
#include "qgsnewvectorlayerdialog.h"
34-
34+
#include "qgsattributetablemodel.h"
35+
#include "qgsattributetablefiltermodel.h"
3536

3637
QgsBrowser::QgsBrowser( QWidget *parent, Qt::WFlags flags )
3738
: QMainWindow( parent, flags )
@@ -114,7 +115,8 @@ void QgsBrowser::itemClicked( const QModelIndex& index )
114115
mDirtyAttributes = true;
115116

116117
// clear the previous stuff
117-
attributeTable->setLayer( NULL );
118+
attributeTable->setCanvasAndLayer( 0, 0 );
119+
118120
QList<QgsMapCanvasLayer> nolayers;
119121
mapCanvas->setLayerSet( nolayers );
120122
metaTextBrowser->clear();
@@ -478,12 +480,13 @@ void QgsBrowser::updateCurrentTab()
478480
{
479481
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( mLayer );
480482
QApplication::setOverrideCursor( Qt::WaitCursor );
481-
attributeTable->setLayer( vlayer );
483+
attributeTable->setCanvasAndLayer( mapCanvas, vlayer );
484+
qobject_cast<QgsAttributeTableModel * >( dynamic_cast<QgsAttributeTableFilterModel *>( attributeTable->model() )->sourceModel() )->loadLayer();
482485
QApplication::restoreOverrideCursor();
483486
}
484487
else
485488
{
486-
attributeTable->setLayer( NULL );
489+
attributeTable->setCanvasAndLayer( 0, 0 );
487490
}
488491
mDirtyAttributes = false;
489492
}

src/gui/attributetable/qgsattributetablememorymodel.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
// In-Memory model //
2828
/////////////////////
2929

30-
QgsAttributeTableMemoryModel::QgsAttributeTableMemoryModel( QgsVectorLayer *theLayer )
31-
: QgsAttributeTableModel( theLayer )
30+
QgsAttributeTableMemoryModel::QgsAttributeTableMemoryModel( QgsMapCanvas *theCanvas, QgsVectorLayer *theLayer )
31+
: QgsAttributeTableModel( theCanvas, theLayer )
3232
{
3333
QgsDebugMsg( "entered." );
3434
}

src/gui/attributetable/qgsattributetablememorymodel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class QgsAttributeTableMemoryModel : public QgsAttributeTableModel
3737
* Constructor
3838
* @param theLayer layer pointer
3939
*/
40-
QgsAttributeTableMemoryModel( QgsVectorLayer *theLayer );
40+
QgsAttributeTableMemoryModel( QgsMapCanvas *theCanvas, QgsVectorLayer *theLayer );
4141

4242
/**
4343
* Returns the number of rows

src/gui/attributetable/qgsattributetablemodel.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,28 @@
2424

2525
#include <QtGui>
2626
#include <QVariant>
27-
#include <limits>
28-
29-
QgsRectangle QgsAttributeTableModel::mCurrentExtent; // static member
3027

28+
#include <limits>
3129

32-
QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayer *theLayer, QObject *parent )
33-
: QAbstractTableModel( parent )
30+
QgsAttributeTableModel::QgsAttributeTableModel( QgsMapCanvas *canvas, QgsVectorLayer *theLayer, QObject *parent )
31+
: QAbstractTableModel( parent ), mCanvas( canvas ), mLayer( theLayer )
3432
{
3533
QgsDebugMsg( "entered." );
3634

3735
mFeat.setFeatureId( std::numeric_limits<int>::min() );
3836
mFeatureMap.clear();
3937
mFeatureQueue.clear();
4038

41-
mLayer = theLayer;
4239
loadAttributes();
4340

4441
connect( mLayer, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
4542
connect( mLayer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) );
4643
connect( mLayer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SLOT( featureDeleted( QgsFeatureId ) ) );
4744
connect( mLayer, SIGNAL( attributeAdded( int ) ), this, SLOT( attributeAdded( int ) ) );
4845
connect( mLayer, SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );
46+
47+
connect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( extentsChanged() ) );
48+
extentsChanged();
4949
}
5050

5151
bool QgsAttributeTableModel::featureAtId( QgsFeatureId fid ) const
@@ -245,13 +245,19 @@ void QgsAttributeTableModel::loadLayer()
245245

246246
QSettings settings;
247247
int behaviour = settings.value( "/qgis/attributeTableBehaviour", 0 ).toInt();
248+
int i = 0;
248249

249250
if ( behaviour == 1 )
250251
{
251252
beginInsertRows( QModelIndex(), 0, mLayer->selectedFeatureCount() - 1 );
252253
foreach( QgsFeatureId fid, mLayer->selectedFeaturesIds() )
253254
{
254255
featureAdded( fid, false );
256+
257+
bool cancel = false;
258+
emit progress( i++, cancel );
259+
if ( cancel )
260+
break;
255261
}
256262
endInsertRows();
257263
}
@@ -267,9 +273,14 @@ void QgsAttributeTableModel::loadLayer()
267273
mLayer->select( QgsAttributeList(), rect, false );
268274

269275
QgsFeature f;
270-
for ( int i = 0; mLayer->nextFeature( f ); ++i )
276+
for ( i = 0; mLayer->nextFeature( f ); ++i )
271277
{
272278
featureAdded( f.id() );
279+
280+
bool cancel = false;
281+
emit progress( i, cancel );
282+
if ( cancel )
283+
break;
273284
}
274285
}
275286

@@ -567,3 +578,8 @@ QgsFeature QgsAttributeTableModel::feature( QModelIndex &idx )
567578

568579
return f;
569580
}
581+
582+
void QgsAttributeTableModel::extentsChanged()
583+
{
584+
mCurrentExtent = mCanvas->mapRenderer()->mapToLayerCoordinates( mLayer, mCanvas->extent() );
585+
}

src/gui/attributetable/qgsattributetablemodel.h

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "qgsvectorlayer.h" // QgsAttributeList
2828
#include "qgsattributetableidcolumnpair.h"
2929

30+
class QgsMapCanvas;
31+
3032
class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
3133
{
3234
Q_OBJECT
@@ -37,7 +39,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
3739
* @param theLayer layer pointer
3840
* @param parent parent pointer
3941
*/
40-
QgsAttributeTableModel( QgsVectorLayer *theLayer, QObject *parent = 0 );
42+
QgsAttributeTableModel( QgsMapCanvas *canvas, QgsVectorLayer *theLayer, QObject *parent = 0 );
4143
/**
4244
* Returns the number of rows
4345
* @param parent parent index
@@ -138,22 +140,16 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
138140
/** return feature attributes at given index */
139141
QgsFeature feature( QModelIndex &idx );
140142

141-
/** In case the table's behaviour is to show only features from current extent,
142-
this is a method how to let the model know what extent to use without having
143-
to explicitly ask any canvas */
144-
static void setCurrentExtent( const QgsRectangle& extent ) { mCurrentExtent = extent; }
145-
146143
signals:
147144
/**
148145
* Model has been changed
149146
*/
150147
void modelChanged();
151-
/**
152-
* Sets new number of rows
153-
* @param oldNum old row number
154-
* @param newNum new row number
155-
*/
156-
void setNumRows( int oldNum, int newNum );
148+
149+
void progress( int i, bool &cancel );
150+
151+
public slots:
152+
void extentsChanged();
157153

158154
private slots:
159155
/**
@@ -166,6 +162,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
166162
* @param idx attribute index
167163
*/
168164
virtual void attributeDeleted( int idx );
165+
169166
protected slots:
170167
/**
171168
* Launched when attribute value has been changed
@@ -191,6 +188,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
191188
virtual void layerDeleted();
192189

193190
protected:
191+
QgsMapCanvas *mCanvas;
194192
QgsVectorLayer *mLayer;
195193
int mFieldCount;
196194

@@ -205,7 +203,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
205203
QHash<int, QgsFeatureId> mRowIdMap;
206204

207205
//! useful when showing only features from a particular extent
208-
static QgsRectangle mCurrentExtent;
206+
QgsRectangle mCurrentExtent;
209207

210208
/**
211209
* Initializes id <-> row maps

0 commit comments

Comments
 (0)