Skip to content

Commit c07d26f

Browse files
author
jef
committedAug 28, 2010
[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
1 parent cf578ef commit c07d26f

File tree

8 files changed

+209
-35
lines changed

8 files changed

+209
-35
lines changed
 

‎python/core/qgsvectorfilewriter.sip

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ public:
2929
const QString& shapefileName,
3030
const QString& fileEncoding,
3131
const QgsCoordinateReferenceSystem*,
32-
bool onlySelected = FALSE);
32+
bool onlySelected = FALSE,
33+
QString *errorMessage = 0,
34+
const QStringList &datasourceOptions = QStringList(),
35+
const QStringList &layerOptions = QStringList() );
3336

3437
/** Write contents of vector layer to an (OGR supported) vector formt
3538
@note: this method was added in version 1.5*/
@@ -39,15 +42,19 @@ public:
3942
const QgsCoordinateReferenceSystem *destCRS,
4043
const QString& driverName = "ESRI Shapefile",
4144
bool onlySelected = FALSE,
42-
QString *errorMessage = 0 );
45+
QString *errorMessage = 0,
46+
const QStringList &datasourceOptions = QStringList(),
47+
const QStringList &layerOptions = QStringList() );
4348

4449
/** create shapefile and initialize it */
4550
QgsVectorFileWriter(const QString& vectorFileName,
4651
const QString& fileEncoding,
4752
const QMap<int, QgsField>& fields,
4853
QGis::WkbType geometryType,
4954
const QgsCoordinateReferenceSystem* srs,
50-
const QString& driverName = "ESRI Shapefile" );
55+
const QString& driverName = "ESRI Shapefile",
56+
const QStringList &datasourceOptions = QStringList(),
57+
const QStringList &layerOptions = QStringList() );
5158

5259
/**Returns map with format filter string as key and OGR format key as value*/
5360
static QMap< QString, QString> supportedFiltersAndFormats();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<h3>Save vector layer as...</h3>
2+
3+
<p>This dialog allows you to save vector data in various formats using GDAL/OGR.
4+
5+
<ul>
6+
<li>From the <label>Format</label> list you can select the destination format (as advertised by OGR).
7+
<li>At <label>Save as</label> you can enter a destination files name or select one using the <label>Browse</label> button.
8+
<li>In the <label>Encoding</label> list you can define in which encoding the data should be saved.
9+
<li>Using the <label>CRS</label> you can select a CRS into which the data about to be saved should be reprojected.
10+
<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).
11+
</ul>
12+
13+
See <a href="http://gdal.org/ogr/ogr_formats.html">OGR Vector formats</a> for a list of supported formats and the available options.

‎src/app/ogr/qgsvectorlayersaveasdialog.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,13 @@ long QgsVectorLayerSaveAsDialog::crs() const
137137
{
138138
return mCRS;
139139
}
140+
141+
QStringList QgsVectorLayerSaveAsDialog::datasourceOptions() const
142+
{
143+
return mOgrDatasourceOptions->toPlainText().split( "\n" );
144+
}
145+
146+
QStringList QgsVectorLayerSaveAsDialog::layerOptions() const
147+
{
148+
return mOgrLayerOptions->toPlainText().split( "\n" );
149+
}

‎src/app/ogr/qgsvectorlayersaveasdialog.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class QgsVectorLayerSaveAsDialog : public QDialog, private Ui::QgsVectorLayerSav
3737
QString format() const;
3838
QString encoding() const;
3939
QString filename() const;
40+
QStringList datasourceOptions() const;
41+
QStringList layerOptions() const;
4042
long crs() const;
4143

4244
private slots:

‎src/app/qgisapp.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4000,7 +4000,11 @@ void QgisApp::saveAsVectorFileGeneral( bool saveOnlySelection )
40004000

40014001
QgsVectorFileWriter::WriterError error;
40024002
QString errorMessage;
4003-
error = QgsVectorFileWriter::writeAsVectorFormat( vlayer, vectorFilename, encoding, &destCRS, format, saveOnlySelection, &errorMessage );
4003+
error = QgsVectorFileWriter::writeAsVectorFormat(
4004+
vlayer, vectorFilename, encoding, &destCRS, format,
4005+
saveOnlySelection,
4006+
&errorMessage,
4007+
dialog->datasourceOptions(), dialog->layerOptions() );
40044008

40054009
QApplication::restoreOverrideCursor();
40064010

@@ -4010,7 +4014,10 @@ void QgisApp::saveAsVectorFileGeneral( bool saveOnlySelection )
40104014
}
40114015
else
40124016
{
4013-
QMessageBox::warning( 0, tr( "Save error" ), tr( "Export to vector file failed.\nError: %1" ).arg( errorMessage ) );
4017+
QgsMessageViewer *m = new QgsMessageViewer( 0 );
4018+
m->setWindowTitle( tr( "Save error" ) );
4019+
m->setMessageAsPlainText( tr( "Export to vector file failed.\nError: %1" ).arg( errorMessage ) );
4020+
m->exec();
40144021
}
40154022
}
40164023

‎src/core/qgsvectorfilewriter.cpp

Lines changed: 109 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <ogr_api.h>
4141
#include <ogr_srs_api.h>
4242
#include <cpl_error.h>
43+
#include <cpl_conv.h>
4344

4445

4546
QgsVectorFileWriter::QgsVectorFileWriter(
@@ -48,7 +49,10 @@ QgsVectorFileWriter::QgsVectorFileWriter(
4849
const QgsFieldMap& fields,
4950
QGis::WkbType geometryType,
5051
const QgsCoordinateReferenceSystem* srs,
51-
const QString& driverName )
52+
const QString& driverName,
53+
const QStringList &datasourceOptions,
54+
const QStringList &layerOptions
55+
)
5256
: mDS( NULL )
5357
, mLayer( NULL )
5458
, mGeom( NULL )
@@ -116,8 +120,26 @@ QgsVectorFileWriter::QgsVectorFileWriter(
116120
QFile::remove( vectorFileName );
117121
}
118122

123+
char **options = NULL;
124+
if ( !datasourceOptions.isEmpty() )
125+
{
126+
options = new char *[ datasourceOptions.size()+1 ];
127+
for ( int i = 0; i < datasourceOptions.size(); i++ )
128+
{
129+
options[i] = CPLStrdup( datasourceOptions[i].toLocal8Bit().data() );
130+
}
131+
options[ datasourceOptions.size()] = NULL;
132+
}
133+
119134
// create the data source
120-
mDS = OGR_Dr_CreateDataSource( poDriver, vectorFileName.toLocal8Bit().data(), NULL );
135+
mDS = OGR_Dr_CreateDataSource( poDriver, vectorFileName.toLocal8Bit().data(), options );
136+
137+
if ( options )
138+
{
139+
for ( int i = 0; i < datasourceOptions.size(); i++ )
140+
CPLFree( options[i] );
141+
}
142+
121143
if ( mDS == NULL )
122144
{
123145
mError = ErrCreateDataSource;
@@ -155,7 +177,24 @@ QgsVectorFileWriter::QgsVectorFileWriter(
155177
// datasource created, now create the output layer
156178
QString layerName = QFileInfo( vectorFileName ).baseName();
157179
OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>( geometryType );
158-
mLayer = OGR_DS_CreateLayer( mDS, QFile::encodeName( layerName ).data(), ogrRef, wkbType, NULL );
180+
181+
if ( !layerOptions.isEmpty() )
182+
{
183+
options = new char *[ layerOptions.size()+1 ];
184+
for ( int i = 0; i < layerOptions.size(); i++ )
185+
{
186+
options[i] = CPLStrdup( layerOptions[i].toLocal8Bit().data() );
187+
}
188+
options[ layerOptions.size()] = NULL;
189+
}
190+
191+
mLayer = OGR_DS_CreateLayer( mDS, QFile::encodeName( layerName ).data(), ogrRef, wkbType, options );
192+
193+
if ( options )
194+
{
195+
for ( int i = 0; i < layerOptions.size(); i++ )
196+
CPLFree( options[i] );
197+
}
159198

160199
if ( srs )
161200
{
@@ -302,9 +341,6 @@ QString QgsVectorFileWriter::errorMessage()
302341

303342
bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
304343
{
305-
if ( hasError() != NoError )
306-
return false;
307-
308344
QgsAttributeMap::const_iterator it;
309345

310346
// create the feature
@@ -342,10 +378,13 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
342378
OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
343379
break;
344380
default:
345-
QgsDebugMsg( "Invalid variant type for field " + QString( fldIt.value().name() ) + " "
346-
+ QString::number( ogrField ) + ": Received Type " + QMetaType::typeName ( attrValue.type() )
347-
+ " : With Value : " + attrValue.toString()
348-
);
381+
mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
382+
.arg( fldIt.value().name() )
383+
.arg( ogrField )
384+
.arg( QMetaType::typeName( attrValue.type() ) )
385+
.arg( attrValue.toString() );
386+
QgsDebugMsg( mErrorMessage );
387+
mError = ErrFeatureWriteFailed;
349388
return false;
350389
}
351390
}
@@ -355,6 +394,8 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
355394
if ( !geom )
356395
{
357396
QgsDebugMsg( "invalid geometry" );
397+
mErrorMessage = QObject::tr( "Invalid feature geometry" );
398+
mError = ErrFeatureWriteFailed;
358399
OGR_F_Destroy( poFeature );
359400
return false;
360401
}
@@ -375,7 +416,10 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
375416
OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb(), geom->wkbSize() );
376417
if ( err != OGRERR_NONE )
377418
{
378-
QgsDebugMsg( "Failed to import geometry from WKB: " + QString::number( err ) );
419+
QgsDebugMsg( QString( "Failed to import geometry from WKB: %1 (OGR error: %2)" ).arg( err ).arg( CPLGetLastErrorMsg() ) );
420+
mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
421+
.arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
422+
mError = ErrFeatureWriteFailed;
379423
OGR_F_Destroy( poFeature );
380424
return false;
381425
}
@@ -388,7 +432,10 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
388432
OGRErr err = OGR_G_ImportFromWkb( mGeom, geom->asWkb(), geom->wkbSize() );
389433
if ( err != OGRERR_NONE )
390434
{
391-
QgsDebugMsg( "Failed to import geometry from WKB: " + QString::number( err ) );
435+
QgsDebugMsg( QString( "Failed to import geometry from WKB: %1 (OGR error: %2)" ).arg( err ).arg( CPLGetLastErrorMsg() ) );
436+
mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
437+
.arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
438+
mError = ErrFeatureWriteFailed;
392439
OGR_F_Destroy( poFeature );
393440
return false;
394441
}
@@ -400,7 +447,10 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
400447
// put the created feature to layer
401448
if ( OGR_L_CreateFeature( mLayer, poFeature ) != OGRERR_NONE )
402449
{
403-
QgsDebugMsg( "Failed to create feature in shapefile" );
450+
mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
451+
mError = ErrFeatureWriteFailed;
452+
453+
QgsDebugMsg( mErrorMessage );
404454
OGR_F_Destroy( poFeature );
405455
return false;
406456
}
@@ -432,9 +482,11 @@ QgsVectorFileWriter::writeAsShapefile( QgsVectorLayer* layer,
432482
const QString& fileEncoding,
433483
const QgsCoordinateReferenceSystem* destCRS,
434484
bool onlySelected,
435-
QString *errorMessage )
485+
QString *errorMessage,
486+
const QStringList &datasourceOptions,
487+
const QStringList &layerOptions )
436488
{
437-
return writeAsVectorFormat( layer, shapefileName, fileEncoding, destCRS, "ESRI Shapefile", onlySelected, errorMessage );
489+
return writeAsVectorFormat( layer, shapefileName, fileEncoding, destCRS, "ESRI Shapefile", onlySelected, errorMessage, datasourceOptions, layerOptions );
438490
}
439491

440492
QgsVectorFileWriter::WriterError
@@ -444,7 +496,9 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
444496
const QgsCoordinateReferenceSystem *destCRS,
445497
const QString& driverName,
446498
bool onlySelected,
447-
QString *errorMessage )
499+
QString *errorMessage,
500+
const QStringList &datasourceOptions,
501+
const QStringList &layerOptions )
448502
{
449503
const QgsCoordinateReferenceSystem* outputCRS;
450504
QgsCoordinateTransform* ct = 0;
@@ -462,7 +516,7 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
462516
outputCRS = &layer->srs();
463517
}
464518
QgsVectorFileWriter* writer =
465-
new QgsVectorFileWriter( fileName, fileEncoding, layer->pendingFields(), layer->wkbType(), outputCRS, driverName );
519+
new QgsVectorFileWriter( fileName, fileEncoding, layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions );
466520

467521
// check whether file creation was successful
468522
WriterError err = writer->hasError();
@@ -474,6 +528,11 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
474528
return err;
475529
}
476530

531+
if ( errorMessage )
532+
{
533+
errorMessage->clear();
534+
}
535+
477536
QgsAttributeList allAttr = layer->pendingAllAttributesList();
478537
QgsFeature fet;
479538

@@ -493,6 +552,8 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
493552
shallTransform = false;
494553
}
495554

555+
int n = 0, errors = 0;
556+
496557
// write all features
497558
while ( layer->nextFeature( fet ) )
498559
{
@@ -519,7 +580,31 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
519580
return ErrProjection;
520581
}
521582
}
522-
writer->addFeature( fet );
583+
if ( !writer->addFeature( fet ) )
584+
{
585+
WriterError err = writer->hasError();
586+
if ( err != NoError && errorMessage )
587+
{
588+
if ( errorMessage->isEmpty() )
589+
{
590+
*errorMessage = QObject::tr( "Feature write errors:" );
591+
}
592+
*errorMessage += "\n" + writer->errorMessage();
593+
}
594+
errors++;
595+
596+
if ( errors > 1000 )
597+
{
598+
if ( errorMessage )
599+
{
600+
*errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
601+
}
602+
603+
n = -1;
604+
break;
605+
}
606+
}
607+
n++;
523608
}
524609

525610
delete writer;
@@ -529,7 +614,12 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
529614
delete ct;
530615
}
531616

532-
return NoError;
617+
if ( errors > 0 && errorMessage && n > 0 )
618+
{
619+
*errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
620+
}
621+
622+
return errors == 0 ? NoError : ErrFeatureWriteFailed;
533623
}
534624

535625

‎src/core/qgsvectorfilewriter.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class CORE_EXPORT QgsVectorFileWriter
5252
ErrCreateLayer,
5353
ErrAttributeTypeUnsupported,
5454
ErrAttributeCreationFailed,
55-
ErrProjection // added in 1.5
55+
ErrProjection, // added in 1.5
56+
ErrFeatureWriteFailed, // added in 1.6
5657
};
5758

5859
/** Write contents of vector layer to a shapefile
@@ -62,7 +63,10 @@ class CORE_EXPORT QgsVectorFileWriter
6263
const QString& fileEncoding,
6364
const QgsCoordinateReferenceSystem *destCRS,
6465
bool onlySelected = false,
65-
QString *errorMessage = 0 );
66+
QString *errorMessage = 0,
67+
const QStringList &datasourceOptions = QStringList(), // added in 1.6
68+
const QStringList &layerOptions = QStringList() // added in 1.6
69+
);
6670

6771
/** Write contents of vector layer to an (OGR supported) vector formt
6872
@note: this method was added in version 1.5*/
@@ -72,15 +76,21 @@ class CORE_EXPORT QgsVectorFileWriter
7276
const QgsCoordinateReferenceSystem *destCRS,
7377
const QString& driverName = "ESRI Shapefile",
7478
bool onlySelected = false,
75-
QString *errorMessage = 0 );
79+
QString *errorMessage = 0,
80+
const QStringList &datasourceOptions = QStringList(), // added in 1.6
81+
const QStringList &layerOptions = QStringList() // added in 1.6
82+
);
7683

7784
/** create shapefile and initialize it */
7885
QgsVectorFileWriter( const QString& vectorFileName,
7986
const QString& fileEncoding,
8087
const QgsFieldMap& fields,
8188
QGis::WkbType geometryType,
8289
const QgsCoordinateReferenceSystem* srs,
83-
const QString& driverName = "ESRI Shapefile" );
90+
const QString& driverName = "ESRI Shapefile",
91+
const QStringList &datasourceOptions = QStringList(), // added in 1.6
92+
const QStringList &layerOptions = QStringList() // added in 1.6
93+
);
8494

8595
/**Returns map with format filter string as key and OGR format key as value*/
8696
static QMap< QString, QString> supportedFiltersAndFormats();

‎src/ui/qgsvectorlayersaveasdialogbase.ui

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>400</width>
10-
<height>203</height>
9+
<width>383</width>
10+
<height>348</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -38,7 +38,7 @@
3838
</property>
3939
</widget>
4040
</item>
41-
<item row="6" column="0" colspan="3">
41+
<item row="7" column="0" colspan="3">
4242
<widget class="QDialogButtonBox" name="buttonBox">
4343
<property name="orientation">
4444
<enum>Qt::Horizontal</enum>
@@ -101,6 +101,41 @@
101101
<item row="0" column="1" colspan="2">
102102
<widget class="QComboBox" name="mFormatComboBox"/>
103103
</item>
104+
<item row="6" column="0" colspan="3">
105+
<widget class="QGroupBox" name="groupBox">
106+
<property name="title">
107+
<string>OGR creation options</string>
108+
</property>
109+
<layout class="QGridLayout" name="gridLayout_2">
110+
<item row="0" column="1">
111+
<widget class="QTextEdit" name="mOgrDatasourceOptions"/>
112+
</item>
113+
<item row="1" column="1">
114+
<widget class="QTextEdit" name="mOgrLayerOptions"/>
115+
</item>
116+
<item row="0" column="0">
117+
<widget class="QLabel" name="label_5">
118+
<property name="text">
119+
<string>Data source</string>
120+
</property>
121+
<property name="buddy">
122+
<cstring>mOgrDatasourceOptions</cstring>
123+
</property>
124+
</widget>
125+
</item>
126+
<item row="1" column="0">
127+
<widget class="QLabel" name="label_6">
128+
<property name="text">
129+
<string>Layer</string>
130+
</property>
131+
<property name="buddy">
132+
<cstring>mOgrLayerOptions</cstring>
133+
</property>
134+
</widget>
135+
</item>
136+
</layout>
137+
</widget>
138+
</item>
104139
</layout>
105140
</widget>
106141
<tabstops>
@@ -121,8 +156,8 @@
121156
<slot>accept()</slot>
122157
<hints>
123158
<hint type="sourcelabel">
124-
<x>257</x>
125-
<y>181</y>
159+
<x>266</x>
160+
<y>268</y>
126161
</hint>
127162
<hint type="destinationlabel">
128163
<x>157</x>
@@ -137,8 +172,8 @@
137172
<slot>reject()</slot>
138173
<hints>
139174
<hint type="sourcelabel">
140-
<x>325</x>
141-
<y>181</y>
175+
<x>334</x>
176+
<y>268</y>
142177
</hint>
143178
<hint type="destinationlabel">
144179
<x>286</x>

0 commit comments

Comments
 (0)
Please sign in to comment.