mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -04:00
[FEATURE] add support for OGR creation options to and improve error handling of file writer
git-svn-id: http://svn.osgeo.org/qgis/trunk@14166 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
parent
cf578ef78e
commit
c07d26fbf6
@ -29,7 +29,10 @@ public:
|
||||
const QString& shapefileName,
|
||||
const QString& fileEncoding,
|
||||
const QgsCoordinateReferenceSystem*,
|
||||
bool onlySelected = FALSE);
|
||||
bool onlySelected = FALSE,
|
||||
QString *errorMessage = 0,
|
||||
const QStringList &datasourceOptions = QStringList(),
|
||||
const QStringList &layerOptions = QStringList() );
|
||||
|
||||
/** Write contents of vector layer to an (OGR supported) vector formt
|
||||
@note: this method was added in version 1.5*/
|
||||
@ -39,7 +42,9 @@ public:
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
const QString& driverName = "ESRI Shapefile",
|
||||
bool onlySelected = FALSE,
|
||||
QString *errorMessage = 0 );
|
||||
QString *errorMessage = 0,
|
||||
const QStringList &datasourceOptions = QStringList(),
|
||||
const QStringList &layerOptions = QStringList() );
|
||||
|
||||
/** create shapefile and initialize it */
|
||||
QgsVectorFileWriter(const QString& vectorFileName,
|
||||
@ -47,7 +52,9 @@ public:
|
||||
const QMap<int, QgsField>& fields,
|
||||
QGis::WkbType geometryType,
|
||||
const QgsCoordinateReferenceSystem* srs,
|
||||
const QString& driverName = "ESRI Shapefile" );
|
||||
const QString& driverName = "ESRI Shapefile",
|
||||
const QStringList &datasourceOptions = QStringList(),
|
||||
const QStringList &layerOptions = QStringList() );
|
||||
|
||||
/**Returns map with format filter string as key and OGR format key as value*/
|
||||
static QMap< QString, QString> supportedFiltersAndFormats();
|
||||
|
13
resources/context_help/QgsVectorLayerSaveAsDialog-en_US
Normal file
13
resources/context_help/QgsVectorLayerSaveAsDialog-en_US
Normal file
@ -0,0 +1,13 @@
|
||||
<h3>Save vector layer as...</h3>
|
||||
|
||||
<p>This dialog allows you to save vector data in various formats using GDAL/OGR.
|
||||
|
||||
<ul>
|
||||
<li>From the <label>Format</label> list you can select the destination format (as advertised by OGR).
|
||||
<li>At <label>Save as</label> you can enter a destination files name or select one using the <label>Browse</label> button.
|
||||
<li>In the <label>Encoding</label> list you can define in which encoding the data should be saved.
|
||||
<li>Using the <label>CRS</label> you can select a CRS into which the data about to be saved should be reprojected.
|
||||
<li>OGR also has various options for the different formats it supports. Use the <label>datasource</label> creation field to set the datasource options and the <label>layer</label> creation options. Enter one options per line (e.g. <code>SPATIALITE=yes</code> in the <label>datasource</label> to create a spatialite database using the SQLite driver).
|
||||
</ul>
|
||||
|
||||
See <a href="http://gdal.org/ogr/ogr_formats.html">OGR Vector formats</a> for a list of supported formats and the available options.
|
@ -137,3 +137,13 @@ long QgsVectorLayerSaveAsDialog::crs() const
|
||||
{
|
||||
return mCRS;
|
||||
}
|
||||
|
||||
QStringList QgsVectorLayerSaveAsDialog::datasourceOptions() const
|
||||
{
|
||||
return mOgrDatasourceOptions->toPlainText().split( "\n" );
|
||||
}
|
||||
|
||||
QStringList QgsVectorLayerSaveAsDialog::layerOptions() const
|
||||
{
|
||||
return mOgrLayerOptions->toPlainText().split( "\n" );
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ class QgsVectorLayerSaveAsDialog : public QDialog, private Ui::QgsVectorLayerSav
|
||||
QString format() const;
|
||||
QString encoding() const;
|
||||
QString filename() const;
|
||||
QStringList datasourceOptions() const;
|
||||
QStringList layerOptions() const;
|
||||
long crs() const;
|
||||
|
||||
private slots:
|
||||
|
@ -4000,7 +4000,11 @@ void QgisApp::saveAsVectorFileGeneral( bool saveOnlySelection )
|
||||
|
||||
QgsVectorFileWriter::WriterError error;
|
||||
QString errorMessage;
|
||||
error = QgsVectorFileWriter::writeAsVectorFormat( vlayer, vectorFilename, encoding, &destCRS, format, saveOnlySelection, &errorMessage );
|
||||
error = QgsVectorFileWriter::writeAsVectorFormat(
|
||||
vlayer, vectorFilename, encoding, &destCRS, format,
|
||||
saveOnlySelection,
|
||||
&errorMessage,
|
||||
dialog->datasourceOptions(), dialog->layerOptions() );
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
@ -4010,7 +4014,10 @@ void QgisApp::saveAsVectorFileGeneral( bool saveOnlySelection )
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning( 0, tr( "Save error" ), tr( "Export to vector file failed.\nError: %1" ).arg( errorMessage ) );
|
||||
QgsMessageViewer *m = new QgsMessageViewer( 0 );
|
||||
m->setWindowTitle( tr( "Save error" ) );
|
||||
m->setMessageAsPlainText( tr( "Export to vector file failed.\nError: %1" ).arg( errorMessage ) );
|
||||
m->exec();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <ogr_api.h>
|
||||
#include <ogr_srs_api.h>
|
||||
#include <cpl_error.h>
|
||||
#include <cpl_conv.h>
|
||||
|
||||
|
||||
QgsVectorFileWriter::QgsVectorFileWriter(
|
||||
@ -48,7 +49,10 @@ QgsVectorFileWriter::QgsVectorFileWriter(
|
||||
const QgsFieldMap& fields,
|
||||
QGis::WkbType geometryType,
|
||||
const QgsCoordinateReferenceSystem* srs,
|
||||
const QString& driverName )
|
||||
const QString& driverName,
|
||||
const QStringList &datasourceOptions,
|
||||
const QStringList &layerOptions
|
||||
)
|
||||
: mDS( NULL )
|
||||
, mLayer( NULL )
|
||||
, mGeom( NULL )
|
||||
@ -116,8 +120,26 @@ QgsVectorFileWriter::QgsVectorFileWriter(
|
||||
QFile::remove( vectorFileName );
|
||||
}
|
||||
|
||||
char **options = NULL;
|
||||
if ( !datasourceOptions.isEmpty() )
|
||||
{
|
||||
options = new char *[ datasourceOptions.size()+1 ];
|
||||
for ( int i = 0; i < datasourceOptions.size(); i++ )
|
||||
{
|
||||
options[i] = CPLStrdup( datasourceOptions[i].toLocal8Bit().data() );
|
||||
}
|
||||
options[ datasourceOptions.size()] = NULL;
|
||||
}
|
||||
|
||||
// create the data source
|
||||
mDS = OGR_Dr_CreateDataSource( poDriver, vectorFileName.toLocal8Bit().data(), NULL );
|
||||
mDS = OGR_Dr_CreateDataSource( poDriver, vectorFileName.toLocal8Bit().data(), options );
|
||||
|
||||
if ( options )
|
||||
{
|
||||
for ( int i = 0; i < datasourceOptions.size(); i++ )
|
||||
CPLFree( options[i] );
|
||||
}
|
||||
|
||||
if ( mDS == NULL )
|
||||
{
|
||||
mError = ErrCreateDataSource;
|
||||
@ -155,7 +177,24 @@ QgsVectorFileWriter::QgsVectorFileWriter(
|
||||
// datasource created, now create the output layer
|
||||
QString layerName = QFileInfo( vectorFileName ).baseName();
|
||||
OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>( geometryType );
|
||||
mLayer = OGR_DS_CreateLayer( mDS, QFile::encodeName( layerName ).data(), ogrRef, wkbType, NULL );
|
||||
|
||||
if ( !layerOptions.isEmpty() )
|
||||
{
|
||||
options = new char *[ layerOptions.size()+1 ];
|
||||
for ( int i = 0; i < layerOptions.size(); i++ )
|
||||
{
|
||||
options[i] = CPLStrdup( layerOptions[i].toLocal8Bit().data() );
|
||||
}
|
||||
options[ layerOptions.size()] = NULL;
|
||||
}
|
||||
|
||||
mLayer = OGR_DS_CreateLayer( mDS, QFile::encodeName( layerName ).data(), ogrRef, wkbType, options );
|
||||
|
||||
if ( options )
|
||||
{
|
||||
for ( int i = 0; i < layerOptions.size(); i++ )
|
||||
CPLFree( options[i] );
|
||||
}
|
||||
|
||||
if ( srs )
|
||||
{
|
||||
@ -302,9 +341,6 @@ QString QgsVectorFileWriter::errorMessage()
|
||||
|
||||
bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
|
||||
{
|
||||
if ( hasError() != NoError )
|
||||
return false;
|
||||
|
||||
QgsAttributeMap::const_iterator it;
|
||||
|
||||
// create the feature
|
||||
@ -342,10 +378,13 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
|
||||
OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
|
||||
break;
|
||||
default:
|
||||
QgsDebugMsg( "Invalid variant type for field " + QString( fldIt.value().name() ) + " "
|
||||
+ QString::number( ogrField ) + ": Received Type " + QMetaType::typeName ( attrValue.type() )
|
||||
+ " : With Value : " + attrValue.toString()
|
||||
);
|
||||
mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
|
||||
.arg( fldIt.value().name() )
|
||||
.arg( ogrField )
|
||||
.arg( QMetaType::typeName( attrValue.type() ) )
|
||||
.arg( attrValue.toString() );
|
||||
QgsDebugMsg( mErrorMessage );
|
||||
mError = ErrFeatureWriteFailed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -355,6 +394,8 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
|
||||
if ( !geom )
|
||||
{
|
||||
QgsDebugMsg( "invalid geometry" );
|
||||
mErrorMessage = QObject::tr( "Invalid feature geometry" );
|
||||
mError = ErrFeatureWriteFailed;
|
||||
OGR_F_Destroy( poFeature );
|
||||
return false;
|
||||
}
|
||||
@ -375,7 +416,10 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
|
||||
OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb(), geom->wkbSize() );
|
||||
if ( err != OGRERR_NONE )
|
||||
{
|
||||
QgsDebugMsg( "Failed to import geometry from WKB: " + QString::number( err ) );
|
||||
QgsDebugMsg( QString( "Failed to import geometry from WKB: %1 (OGR error: %2)" ).arg( err ).arg( CPLGetLastErrorMsg() ) );
|
||||
mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
|
||||
.arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
|
||||
mError = ErrFeatureWriteFailed;
|
||||
OGR_F_Destroy( poFeature );
|
||||
return false;
|
||||
}
|
||||
@ -388,7 +432,10 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
|
||||
OGRErr err = OGR_G_ImportFromWkb( mGeom, geom->asWkb(), geom->wkbSize() );
|
||||
if ( err != OGRERR_NONE )
|
||||
{
|
||||
QgsDebugMsg( "Failed to import geometry from WKB: " + QString::number( err ) );
|
||||
QgsDebugMsg( QString( "Failed to import geometry from WKB: %1 (OGR error: %2)" ).arg( err ).arg( CPLGetLastErrorMsg() ) );
|
||||
mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
|
||||
.arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
|
||||
mError = ErrFeatureWriteFailed;
|
||||
OGR_F_Destroy( poFeature );
|
||||
return false;
|
||||
}
|
||||
@ -400,7 +447,10 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
|
||||
// put the created feature to layer
|
||||
if ( OGR_L_CreateFeature( mLayer, poFeature ) != OGRERR_NONE )
|
||||
{
|
||||
QgsDebugMsg( "Failed to create feature in shapefile" );
|
||||
mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
|
||||
mError = ErrFeatureWriteFailed;
|
||||
|
||||
QgsDebugMsg( mErrorMessage );
|
||||
OGR_F_Destroy( poFeature );
|
||||
return false;
|
||||
}
|
||||
@ -432,9 +482,11 @@ QgsVectorFileWriter::writeAsShapefile( QgsVectorLayer* layer,
|
||||
const QString& fileEncoding,
|
||||
const QgsCoordinateReferenceSystem* destCRS,
|
||||
bool onlySelected,
|
||||
QString *errorMessage )
|
||||
QString *errorMessage,
|
||||
const QStringList &datasourceOptions,
|
||||
const QStringList &layerOptions )
|
||||
{
|
||||
return writeAsVectorFormat( layer, shapefileName, fileEncoding, destCRS, "ESRI Shapefile", onlySelected, errorMessage );
|
||||
return writeAsVectorFormat( layer, shapefileName, fileEncoding, destCRS, "ESRI Shapefile", onlySelected, errorMessage, datasourceOptions, layerOptions );
|
||||
}
|
||||
|
||||
QgsVectorFileWriter::WriterError
|
||||
@ -444,7 +496,9 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
const QString& driverName,
|
||||
bool onlySelected,
|
||||
QString *errorMessage )
|
||||
QString *errorMessage,
|
||||
const QStringList &datasourceOptions,
|
||||
const QStringList &layerOptions )
|
||||
{
|
||||
const QgsCoordinateReferenceSystem* outputCRS;
|
||||
QgsCoordinateTransform* ct = 0;
|
||||
@ -462,7 +516,7 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
|
||||
outputCRS = &layer->srs();
|
||||
}
|
||||
QgsVectorFileWriter* writer =
|
||||
new QgsVectorFileWriter( fileName, fileEncoding, layer->pendingFields(), layer->wkbType(), outputCRS, driverName );
|
||||
new QgsVectorFileWriter( fileName, fileEncoding, layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions );
|
||||
|
||||
// check whether file creation was successful
|
||||
WriterError err = writer->hasError();
|
||||
@ -474,6 +528,11 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
|
||||
return err;
|
||||
}
|
||||
|
||||
if ( errorMessage )
|
||||
{
|
||||
errorMessage->clear();
|
||||
}
|
||||
|
||||
QgsAttributeList allAttr = layer->pendingAllAttributesList();
|
||||
QgsFeature fet;
|
||||
|
||||
@ -493,6 +552,8 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
|
||||
shallTransform = false;
|
||||
}
|
||||
|
||||
int n = 0, errors = 0;
|
||||
|
||||
// write all features
|
||||
while ( layer->nextFeature( fet ) )
|
||||
{
|
||||
@ -519,7 +580,31 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
|
||||
return ErrProjection;
|
||||
}
|
||||
}
|
||||
writer->addFeature( fet );
|
||||
if ( !writer->addFeature( fet ) )
|
||||
{
|
||||
WriterError err = writer->hasError();
|
||||
if ( err != NoError && errorMessage )
|
||||
{
|
||||
if ( errorMessage->isEmpty() )
|
||||
{
|
||||
*errorMessage = QObject::tr( "Feature write errors:" );
|
||||
}
|
||||
*errorMessage += "\n" + writer->errorMessage();
|
||||
}
|
||||
errors++;
|
||||
|
||||
if ( errors > 1000 )
|
||||
{
|
||||
if ( errorMessage )
|
||||
{
|
||||
*errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
|
||||
}
|
||||
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
delete writer;
|
||||
@ -529,7 +614,12 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
|
||||
delete ct;
|
||||
}
|
||||
|
||||
return NoError;
|
||||
if ( errors > 0 && errorMessage && n > 0 )
|
||||
{
|
||||
*errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
|
||||
}
|
||||
|
||||
return errors == 0 ? NoError : ErrFeatureWriteFailed;
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,7 +52,8 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
ErrCreateLayer,
|
||||
ErrAttributeTypeUnsupported,
|
||||
ErrAttributeCreationFailed,
|
||||
ErrProjection // added in 1.5
|
||||
ErrProjection, // added in 1.5
|
||||
ErrFeatureWriteFailed, // added in 1.6
|
||||
};
|
||||
|
||||
/** Write contents of vector layer to a shapefile
|
||||
@ -62,7 +63,10 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
const QString& fileEncoding,
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
bool onlySelected = false,
|
||||
QString *errorMessage = 0 );
|
||||
QString *errorMessage = 0,
|
||||
const QStringList &datasourceOptions = QStringList(), // added in 1.6
|
||||
const QStringList &layerOptions = QStringList() // added in 1.6
|
||||
);
|
||||
|
||||
/** Write contents of vector layer to an (OGR supported) vector formt
|
||||
@note: this method was added in version 1.5*/
|
||||
@ -72,7 +76,10 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
const QgsCoordinateReferenceSystem *destCRS,
|
||||
const QString& driverName = "ESRI Shapefile",
|
||||
bool onlySelected = false,
|
||||
QString *errorMessage = 0 );
|
||||
QString *errorMessage = 0,
|
||||
const QStringList &datasourceOptions = QStringList(), // added in 1.6
|
||||
const QStringList &layerOptions = QStringList() // added in 1.6
|
||||
);
|
||||
|
||||
/** create shapefile and initialize it */
|
||||
QgsVectorFileWriter( const QString& vectorFileName,
|
||||
@ -80,7 +87,10 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
const QgsFieldMap& fields,
|
||||
QGis::WkbType geometryType,
|
||||
const QgsCoordinateReferenceSystem* srs,
|
||||
const QString& driverName = "ESRI Shapefile" );
|
||||
const QString& driverName = "ESRI Shapefile",
|
||||
const QStringList &datasourceOptions = QStringList(), // added in 1.6
|
||||
const QStringList &layerOptions = QStringList() // added in 1.6
|
||||
);
|
||||
|
||||
/**Returns map with format filter string as key and OGR format key as value*/
|
||||
static QMap< QString, QString> supportedFiltersAndFormats();
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>203</height>
|
||||
<width>383</width>
|
||||
<height>348</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -38,7 +38,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="3">
|
||||
<item row="7" column="0" colspan="3">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@ -101,6 +101,41 @@
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="mFormatComboBox"/>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="3">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>OGR creation options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QTextEdit" name="mOgrDatasourceOptions"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QTextEdit" name="mOgrLayerOptions"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Data source</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>mOgrDatasourceOptions</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Layer</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>mOgrLayerOptions</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
@ -121,8 +156,8 @@
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>257</x>
|
||||
<y>181</y>
|
||||
<x>266</x>
|
||||
<y>268</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
@ -137,8 +172,8 @@
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>325</x>
|
||||
<y>181</y>
|
||||
<x>334</x>
|
||||
<y>268</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
|
Loading…
x
Reference in New Issue
Block a user