Skip to content
Permalink
Browse files

[FEATURE] make loading attributes interruptable

- also show progress
- fix tracking of canvas extent (OTFR wasn't considered)
  • Loading branch information
jef-n committed Jan 8, 2012
1 parent 7b85948 commit 39e4c163c9bdeb8a7ee5df0a59bb5d37a2985540
@@ -54,24 +54,23 @@ class QgsAttributeTableDock : public QDockWidget


QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWidget *parent, Qt::WindowFlags flags )
: QDialog( parent, flags ), mDock( NULL )
: QDialog( parent, flags ), mDock( 0 ), mLayer( theLayer ), mProgress( 0 ), mWorkaround( false )
{
mLayer = theLayer;

setupUi( this );

setAttribute( Qt::WA_DeleteOnClose );

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

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

mView->setLayer( mLayer );
mFilterModel = ( QgsAttributeTableFilterModel * ) mView->model();
mModel = ( QgsAttributeTableModel * )(( QgsAttributeTableFilterModel * )mView->model() )->sourceModel();
mModel = qobject_cast<QgsAttributeTableModel * >( dynamic_cast<QgsAttributeTableFilterModel *>( mView->model() )->sourceModel() );

connect( mModel, SIGNAL( progress( int, bool & ) ), this, SLOT( progress( int, bool & ) ) );
mModel->loadLayer();
delete mProgress;

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

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

connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( close() ) );
connect( mView->verticalHeader(), SIGNAL( sectionClicked( int ) ), this, SLOT( updateRowSelection( int ) ) );
connect( mView->verticalHeader(), SIGNAL( sectionPressed( int ) ), this, SLOT( updateRowPressed( int ) ) );

connect( mModel, SIGNAL( modelChanged() ), this, SLOT( updateSelection() ) );

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

mLastClickedHeaderIndex = 0;
mSelectionModel = new QItemSelectionModel( mFilterModel );
mSelectionModel = new QItemSelectionModel( mFilterModel, this );
updateSelectionFromLayer();

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

QgsAttributeTableDialog::~QgsAttributeTableDialog()
{
delete mSelectionModel;
}

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

void QgsAttributeTableDialog::updateExtent()
{
// let the model know about the new extent (we may be showing only features from current extent)
QgsAttributeTableModel::setCurrentExtent( QgisApp::instance()->mapCanvas()->extent() );
}

void QgsAttributeTableDialog::viewWillShowContextMenu( QMenu* menu, QModelIndex atIndex )
{
QModelIndex sourceIndex = mFilterModel->mapToSource( atIndex );
@@ -829,6 +822,38 @@ void QgsAttributeTableDialog::viewWillShowContextMenu( QMenu* menu, QModelIndex
menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
}

void QgsAttributeTableDialog::progress( int i, bool &cancel )
{
if ( !mProgress )
{
mProgress = new QProgressDialog( tr( "Loading feature attributes..." ), tr( "Abort" ), 0, 0, this );
mProgress->setWindowTitle( tr( "Attribute table" ) );
mProgress->setWindowModality( Qt::WindowModal );
mStarted.start();
}

mProgress->setValue( i );

if ( i > 0 && i % 1000 == 0 )
{
mProgress->setLabelText( tr( "%1 features loaded." ).arg( i ) );
}

if ( !mProgress->isVisible() && mStarted.elapsed() > mProgress->minimumDuration()*5 / 4 )
{
// for some reason this is sometimes necessary
mProgress->show();
mWorkaround = true;
}

if ( mWorkaround )
{
QCoreApplication::processEvents();
}

cancel = mProgress->wasCanceled();
}

void QgsAttributeTableAction::execute()
{
mModel->executeAction( mAction, mFieldIdx );
@@ -20,7 +20,8 @@
#include <QDialog>
#include <QModelIndex>
#include <QItemSelectionModel>
#include <QMutex>

#include <time.h>

#include "ui_qgsattributetabledialog.h"
#include "qgscontexthelp.h"
@@ -33,6 +34,7 @@ class QLineEdit;
class QComboBox;
class QMenu;
class QDockWidget;
class QProgressDialog;

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

void updateExtent();

void viewWillShowContextMenu( QMenu* menu, QModelIndex atIndex );

void progress( int i, bool &cancel );

private slots:
/**
* submits the data
@@ -208,21 +210,22 @@ class QgsAttributeTableDialog : public QDialog, private Ui::QgsAttributeTableDia

QLineEdit *mQuery;
QComboBox *mColumnBox;
QComboBox *mShowBox;

QMenu* mMenuActions;
QAction* mActionToggleEditing;

QgsAttributeTableModel *mModel;
QgsAttributeTableFilterModel *mFilterModel;
QDockWidget *mDock;
QgsVectorLayer *mLayer;
QProgressDialog *mProgress;
QTime mStarted;
bool mWorkaround;
QgsFeatureIds mSelectedFeatures;
int mIndexPressed;

QItemSelectionModel* mSelectionModel;
int mLastClickedHeaderIndex;

QDockWidget *mDock;
};


@@ -31,7 +31,8 @@
#include "qgsvectorlayer.h"
#include "qgsrasterlayer.h"
#include "qgsnewvectorlayerdialog.h"

#include "qgsattributetablemodel.h"
#include "qgsattributetablefiltermodel.h"

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

// clear the previous stuff
attributeTable->setLayer( NULL );
attributeTable->setCanvasAndLayer( 0, 0 );

QList<QgsMapCanvasLayer> nolayers;
mapCanvas->setLayerSet( nolayers );
metaTextBrowser->clear();
@@ -478,12 +480,13 @@ void QgsBrowser::updateCurrentTab()
{
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( mLayer );
QApplication::setOverrideCursor( Qt::WaitCursor );
attributeTable->setLayer( vlayer );
attributeTable->setCanvasAndLayer( mapCanvas, vlayer );
qobject_cast<QgsAttributeTableModel * >( dynamic_cast<QgsAttributeTableFilterModel *>( attributeTable->model() )->sourceModel() )->loadLayer();
QApplication::restoreOverrideCursor();
}
else
{
attributeTable->setLayer( NULL );
attributeTable->setCanvasAndLayer( 0, 0 );
}
mDirtyAttributes = false;
}
@@ -27,8 +27,8 @@
// In-Memory model //
/////////////////////

QgsAttributeTableMemoryModel::QgsAttributeTableMemoryModel( QgsVectorLayer *theLayer )
: QgsAttributeTableModel( theLayer )
QgsAttributeTableMemoryModel::QgsAttributeTableMemoryModel( QgsMapCanvas *theCanvas, QgsVectorLayer *theLayer )
: QgsAttributeTableModel( theCanvas, theLayer )
{
QgsDebugMsg( "entered." );
}
@@ -37,7 +37,7 @@ class QgsAttributeTableMemoryModel : public QgsAttributeTableModel
* Constructor
* @param theLayer layer pointer
*/
QgsAttributeTableMemoryModel( QgsVectorLayer *theLayer );
QgsAttributeTableMemoryModel( QgsMapCanvas *theCanvas, QgsVectorLayer *theLayer );

/**
* Returns the number of rows
@@ -24,28 +24,28 @@

#include <QtGui>
#include <QVariant>
#include <limits>

QgsRectangle QgsAttributeTableModel::mCurrentExtent; // static member

#include <limits>

QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayer *theLayer, QObject *parent )
: QAbstractTableModel( parent )
QgsAttributeTableModel::QgsAttributeTableModel( QgsMapCanvas *canvas, QgsVectorLayer *theLayer, QObject *parent )
: QAbstractTableModel( parent ), mCanvas( canvas ), mLayer( theLayer )
{
QgsDebugMsg( "entered." );

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

mLayer = theLayer;
loadAttributes();

connect( mLayer, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
connect( mLayer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) );
connect( mLayer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SLOT( featureDeleted( QgsFeatureId ) ) );
connect( mLayer, SIGNAL( attributeAdded( int ) ), this, SLOT( attributeAdded( int ) ) );
connect( mLayer, SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );

connect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( extentsChanged() ) );
extentsChanged();
}

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

QSettings settings;
int behaviour = settings.value( "/qgis/attributeTableBehaviour", 0 ).toInt();
int i = 0;

if ( behaviour == 1 )
{
beginInsertRows( QModelIndex(), 0, mLayer->selectedFeatureCount() - 1 );
foreach( QgsFeatureId fid, mLayer->selectedFeaturesIds() )
{
featureAdded( fid, false );

bool cancel = false;
emit progress( i++, cancel );
if ( cancel )
break;
}
endInsertRows();
}
@@ -267,9 +273,14 @@ void QgsAttributeTableModel::loadLayer()
mLayer->select( QgsAttributeList(), rect, false );

QgsFeature f;
for ( int i = 0; mLayer->nextFeature( f ); ++i )
for ( i = 0; mLayer->nextFeature( f ); ++i )
{
featureAdded( f.id() );

bool cancel = false;
emit progress( i, cancel );
if ( cancel )
break;
}
}

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

return f;
}

void QgsAttributeTableModel::extentsChanged()
{
mCurrentExtent = mCanvas->mapRenderer()->mapToLayerCoordinates( mLayer, mCanvas->extent() );
}
@@ -27,6 +27,8 @@
#include "qgsvectorlayer.h" // QgsAttributeList
#include "qgsattributetableidcolumnpair.h"

class QgsMapCanvas;

class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
{
Q_OBJECT
@@ -37,7 +39,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
* @param theLayer layer pointer
* @param parent parent pointer
*/
QgsAttributeTableModel( QgsVectorLayer *theLayer, QObject *parent = 0 );
QgsAttributeTableModel( QgsMapCanvas *canvas, QgsVectorLayer *theLayer, QObject *parent = 0 );
/**
* Returns the number of rows
* @param parent parent index
@@ -138,22 +140,16 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
/** return feature attributes at given index */
QgsFeature feature( QModelIndex &idx );

/** In case the table's behaviour is to show only features from current extent,
this is a method how to let the model know what extent to use without having
to explicitly ask any canvas */
static void setCurrentExtent( const QgsRectangle& extent ) { mCurrentExtent = extent; }

signals:
/**
* Model has been changed
*/
void modelChanged();
/**
* Sets new number of rows
* @param oldNum old row number
* @param newNum new row number
*/
void setNumRows( int oldNum, int newNum );

void progress( int i, bool &cancel );

public slots:
void extentsChanged();

private slots:
/**
@@ -166,6 +162,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
* @param idx attribute index
*/
virtual void attributeDeleted( int idx );

protected slots:
/**
* Launched when attribute value has been changed
@@ -191,6 +188,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
virtual void layerDeleted();

protected:
QgsMapCanvas *mCanvas;
QgsVectorLayer *mLayer;
int mFieldCount;

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

//! useful when showing only features from a particular extent
static QgsRectangle mCurrentExtent;
QgsRectangle mCurrentExtent;

/**
* Initializes id <-> row maps

0 comments on commit 39e4c16

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