- [API] add optional progress dialog to QgsVectorLayerImport

- postgres/mssql: fix primary key generation on import (fixes #6907)
- fix crash on browser refresh after vector layer import
This commit is contained in:
Juergen E. Fischer 2013-01-07 00:30:30 +01:00
parent 4cffd07086
commit 460f578d93
7 changed files with 96 additions and 18 deletions

View File

@ -9,6 +9,7 @@ class QgsVectorLayerImport
%TypeHeaderCode
#include <qgsvectorlayerimport.h>
#include <qgsfield.h>
class QProgressDialog;
%End
public:
@ -37,7 +38,8 @@ class QgsVectorLayerImport
bool onlySelected = false,
QString *errorMessage /Out/ = 0,
bool skipAttributeCreation = false,
QMap<QString, QVariant> *options = 0
QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);
/** create a empty layer and add fields to it */
@ -47,7 +49,8 @@ class QgsVectorLayerImport
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* crs,
bool overwrite = false,
const QMap<QString, QVariant> *options = 0
const QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);
/** checks whether there were any errors */

View File

@ -25,6 +25,8 @@
#include "qgsvectorlayerimport.h"
#include "qgsproviderregistry.h"
#include <QProgressDialog>
#define FEATURE_BUFFER_SIZE 200
typedef QgsVectorLayerImport::ImportError createEmptyLayer_t(
@ -45,8 +47,10 @@ QgsVectorLayerImport::QgsVectorLayerImport( const QString &uri,
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* crs,
bool overwrite,
const QMap<QString, QVariant> *options )
const QMap<QString, QVariant> *options,
QProgressDialog *progress )
: mErrorCount( 0 )
, mProgress( progress )
{
mProvider = NULL;
@ -83,7 +87,7 @@ QgsVectorLayerImport::QgsVectorLayerImport( const QString &uri,
QgsDebugMsg( "Created empty layer" );
QgsVectorDataProvider *vectorProvider = ( QgsVectorDataProvider* ) pReg->provider( providerKey, uri );
if ( !vectorProvider || !vectorProvider->isValid() )
if ( !vectorProvider || !vectorProvider->isValid() || ( vectorProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) == 0 )
{
mError = ErrInvalidLayer;
mErrorMessage = QObject::tr( "Loading of layer failed" );
@ -181,7 +185,8 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
bool onlySelected,
QString *errorMessage,
bool skipAttributeCreation,
QMap<QString, QVariant> *options )
QMap<QString, QVariant> *options,
QProgressDialog *progress )
{
const QgsCoordinateReferenceSystem* outputCRS;
QgsCoordinateTransform* ct = 0;
@ -255,7 +260,7 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
}
QgsVectorLayerImport * writer =
new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options );
new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options, progress );
// check whether file creation was successful
ImportError err = writer->hasError();
@ -298,9 +303,23 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
*errorMessage = QObject::tr( "Feature write errors:" );
}
if ( progress )
{
progress->setRange( 0, layer->featureCount() );
}
// write all features
while ( layer->nextFeature( fet ) )
{
if ( progress && progress->wasCanceled() )
{
if ( errorMessage )
{
*errorMessage += "\n" + QObject::tr( "Import was canceled at %1 of %2" ).arg( progress->value() ).arg( progress->maximum() );
}
break;
}
if ( writer->errorCount() > 1000 )
{
if ( errorMessage )
@ -348,6 +367,11 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
}
}
n++;
if ( progress )
{
progress->setValue( n );
}
}
// flush the buffer to be sure that all features are written

View File

@ -22,6 +22,8 @@
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
class QProgressDialog;
/** \ingroup core
* A convenience class for writing vector files to disk.
There are two possibilities how to use this class:
@ -59,7 +61,8 @@ class CORE_EXPORT QgsVectorLayerImport
bool onlySelected = false,
QString *errorMessage = 0,
bool skipAttributeCreation = false,
QMap<QString, QVariant> *options = 0
QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);
/** create a empty layer and add fields to it */
@ -69,7 +72,8 @@ class CORE_EXPORT QgsVectorLayerImport
QGis::WkbType geometryType,
const QgsCoordinateReferenceSystem* crs,
bool overwrite = false,
const QMap<QString, QVariant> *options = 0
const QMap<QString, QVariant> *options = 0,
QProgressDialog *progress = 0
);
/** checks whether there were any errors */
@ -102,6 +106,7 @@ class CORE_EXPORT QgsVectorLayerImport
QMap<int, int> mOldToNewAttrIdx;
QgsFeatureList mFeatureBuffer;
QProgressDialog *mProgress;
};
#endif

View File

@ -1686,7 +1686,7 @@ QgsVectorLayerImport::ImportError QgsMssqlProvider::createEmptyLayer(
QString pk = primaryKey = "qgs_fid";
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
{
if ( fldIt.value().name() == pk )
if ( fldIt.value().name() == primaryKey )
{
// it already exists, try again with a new name
primaryKey = QString( "%1_%2" ).arg( pk ).arg( index++ );

View File

@ -22,18 +22,51 @@
#include "qgsapplication.h"
#include <QMessageBox>
#include <QProgressDialog>
QGISEXTERN bool deleteLayer( const QString& uri, QString& errCause );
// ---------------------------------------------------------------------------
QgsPGConnectionItem::QgsPGConnectionItem( QgsDataItem* parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
, mColumnTypeThread( 0 )
{
mIcon = QgsApplication::getThemeIcon( "mIconConnect.png" );
}
QgsPGConnectionItem::~QgsPGConnectionItem()
{
stop();
}
void QgsPGConnectionItem::stop()
{
if ( mColumnTypeThread )
{
mColumnTypeThread->stop();
mColumnTypeThread->wait();
delete mColumnTypeThread;
mColumnTypeThread = 0;
}
}
void QgsPGConnectionItem::refresh()
{
QApplication::setOverrideCursor( Qt::WaitCursor );
stop();
foreach ( QgsDataItem *child, mChildren )
{
deleteChildItem( child );
}
foreach ( QgsDataItem *item, createChildren() )
{
addChildItem( item, true );
}
QApplication::restoreOverrideCursor();
}
QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
@ -42,6 +75,8 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
QVector<QgsDataItem*> children;
QgsDataSourceURI uri = QgsPostgresConn::connUri( mName );
mSchemaMap.clear();
mConn = QgsPostgresConn::connectDb( uri.connectionInfo(), true );
if ( !mConn )
return children;
@ -62,7 +97,7 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
return children;
}
QgsGeomColumnTypeThread *columnTypeThread = 0;
stop();
foreach ( QgsPostgresLayerProperty layerProperty, layerProperties )
{
@ -76,17 +111,17 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
if ( QgsPostgresConn::wkbTypeFromPostgis( layerProperty.type ) == QGis::WKBUnknown )
{
if ( !columnTypeThread )
if ( !mColumnTypeThread )
{
QgsPostgresConn *conn = QgsPostgresConn::connectDb( uri.connectionInfo(), true /* readonly */ );
if ( conn )
{
columnTypeThread = new QgsGeomColumnTypeThread( conn, true /* use estimated metadata */ );
mColumnTypeThread = new QgsGeomColumnTypeThread( conn, true /* use estimated metadata */ );
connect( columnTypeThread, SIGNAL( setLayerType( QgsPostgresLayerProperty ) ),
connect( mColumnTypeThread, SIGNAL( setLayerType( QgsPostgresLayerProperty ) ),
this, SLOT( setLayerType( QgsPostgresLayerProperty ) ) );
connect( this, SIGNAL( addGeometryColumn( QgsPostgresLayerProperty ) ),
columnTypeThread, SLOT( addGeometryColumn( QgsPostgresLayerProperty ) ) );
mColumnTypeThread, SLOT( addGeometryColumn( QgsPostgresLayerProperty ) ) );
}
}
@ -98,8 +133,8 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
schemaItem->addLayer( layerProperty );
}
if ( columnTypeThread )
columnTypeThread->start();
if ( mColumnTypeThread )
mColumnTypeThread->start();
return children;
}
@ -186,6 +221,11 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData * data, Qt::DropAction )
qApp->setOverrideCursor( Qt::WaitCursor );
QProgressDialog *progress = new QProgressDialog( tr( "Copying features..." ), tr( "Abort" ), 0, 0, 0 );
progress->setWindowTitle( tr( "Import layer" ) );
progress->setWindowModality( Qt::WindowModal );
progress->show();
QStringList importResults;
bool hasError = false;
QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( data );
@ -207,7 +247,7 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData * data, Qt::DropAction )
QgsDebugMsg( "URI " + uri.uri() );
QgsVectorLayerImport::ImportError err;
QString importError;
err = QgsVectorLayerImport::importLayer( srcLayer, uri.uri(), "postgres", &srcLayer->crs(), false, &importError );
err = QgsVectorLayerImport::importLayer( srcLayer, uri.uri(), "postgres", &srcLayer->crs(), false, &importError, false, 0, progress );
if ( err == QgsVectorLayerImport::NoError )
importResults.append( tr( "%1: OK!" ).arg( u.name ) );
else
@ -225,6 +265,8 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData * data, Qt::DropAction )
delete srcLayer;
}
delete progress;
qApp->restoreOverrideCursor();
if ( hasError )

View File

@ -61,6 +61,8 @@ class QgsPGConnectionItem : public QgsDataCollectionItem
QgsPostgresConn *connection() const { return mConn; }
void refresh();
signals:
void addGeometryColumn( QgsPostgresLayerProperty );
@ -71,8 +73,10 @@ class QgsPGConnectionItem : public QgsDataCollectionItem
void setLayerType( QgsPostgresLayerProperty layerProperty );
private:
void stop();
QgsPostgresConn *mConn;
QMap<QString, QgsPGSchemaItem * > mSchemaMap;
QgsGeomColumnTypeThread *mColumnTypeThread;
};
class QgsPGSchemaItem : public QgsDataCollectionItem

View File

@ -3274,7 +3274,7 @@ QgsVectorLayerImport::ImportError QgsPostgresProvider::createEmptyLayer(
QString pk = primaryKey = "id";
for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); ++fldIt )
{
if ( fldIt.value().name() == pk )
if ( fldIt.value().name() == primaryKey )
{
// it already exists, try again with a new name
primaryKey = QString( "%1_%2" ).arg( pk ).arg( index++ );