[QGIS Commit] r14166 - in trunk/qgis: python/core resources/context_help src/app src/app/ogr src/core src/ui

svn_qgis at osgeo.org svn_qgis at osgeo.org
Sat Aug 28 19:14:16 EDT 2010


Author: jef
Date: 2010-08-28 23:14:16 +0000 (Sat, 28 Aug 2010)
New Revision: 14166

Added:
   trunk/qgis/resources/context_help/QgsVectorLayerSaveAsDialog-en_US
Modified:
   trunk/qgis/python/core/qgsvectorfilewriter.sip
   trunk/qgis/src/app/ogr/qgsvectorlayersaveasdialog.cpp
   trunk/qgis/src/app/ogr/qgsvectorlayersaveasdialog.h
   trunk/qgis/src/app/qgisapp.cpp
   trunk/qgis/src/core/qgsvectorfilewriter.cpp
   trunk/qgis/src/core/qgsvectorfilewriter.h
   trunk/qgis/src/ui/qgsvectorlayersaveasdialogbase.ui
Log:
[FEATURE] add support for OGR creation options to and improve error handling of file writer

Modified: trunk/qgis/python/core/qgsvectorfilewriter.sip
===================================================================
--- trunk/qgis/python/core/qgsvectorfilewriter.sip	2010-08-28 22:35:41 UTC (rev 14165)
+++ trunk/qgis/python/core/qgsvectorfilewriter.sip	2010-08-28 23:14:16 UTC (rev 14166)
@@ -29,7 +29,10 @@
                                         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 @@
                                             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 @@
                         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();

Added: trunk/qgis/resources/context_help/QgsVectorLayerSaveAsDialog-en_US
===================================================================
--- trunk/qgis/resources/context_help/QgsVectorLayerSaveAsDialog-en_US	                        (rev 0)
+++ trunk/qgis/resources/context_help/QgsVectorLayerSaveAsDialog-en_US	2010-08-28 23:14:16 UTC (rev 14166)
@@ -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.

Modified: trunk/qgis/src/app/ogr/qgsvectorlayersaveasdialog.cpp
===================================================================
--- trunk/qgis/src/app/ogr/qgsvectorlayersaveasdialog.cpp	2010-08-28 22:35:41 UTC (rev 14165)
+++ trunk/qgis/src/app/ogr/qgsvectorlayersaveasdialog.cpp	2010-08-28 23:14:16 UTC (rev 14166)
@@ -137,3 +137,13 @@
 {
   return mCRS;
 }
+
+QStringList QgsVectorLayerSaveAsDialog::datasourceOptions() const
+{
+  return mOgrDatasourceOptions->toPlainText().split( "\n" );
+}
+
+QStringList QgsVectorLayerSaveAsDialog::layerOptions() const
+{
+  return mOgrLayerOptions->toPlainText().split( "\n" );
+}

Modified: trunk/qgis/src/app/ogr/qgsvectorlayersaveasdialog.h
===================================================================
--- trunk/qgis/src/app/ogr/qgsvectorlayersaveasdialog.h	2010-08-28 22:35:41 UTC (rev 14165)
+++ trunk/qgis/src/app/ogr/qgsvectorlayersaveasdialog.h	2010-08-28 23:14:16 UTC (rev 14166)
@@ -37,6 +37,8 @@
     QString format() const;
     QString encoding() const;
     QString filename() const;
+    QStringList datasourceOptions() const;
+    QStringList layerOptions() const;
     long crs() const;
 
   private slots:

Modified: trunk/qgis/src/app/qgisapp.cpp
===================================================================
--- trunk/qgis/src/app/qgisapp.cpp	2010-08-28 22:35:41 UTC (rev 14165)
+++ trunk/qgis/src/app/qgisapp.cpp	2010-08-28 23:14:16 UTC (rev 14166)
@@ -4000,7 +4000,11 @@
 
     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 @@
     }
     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();
     }
   }
 

Modified: trunk/qgis/src/core/qgsvectorfilewriter.cpp
===================================================================
--- trunk/qgis/src/core/qgsvectorfilewriter.cpp	2010-08-28 22:35:41 UTC (rev 14165)
+++ trunk/qgis/src/core/qgsvectorfilewriter.cpp	2010-08-28 23:14:16 UTC (rev 14166)
@@ -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 @@
   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 @@
     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,8 +177,25 @@
   // 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 )
   {
     if ( driverName == "ESRI Shapefile" )
@@ -302,9 +341,6 @@
 
 bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
 {
-  if ( hasError() != NoError )
-    return false;
-
   QgsAttributeMap::const_iterator it;
 
   // create the feature
@@ -342,10 +378,13 @@
         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 @@
   if ( !geom )
   {
     QgsDebugMsg( "invalid geometry" );
+    mErrorMessage = QObject::tr( "Invalid feature geometry" );
+    mError = ErrFeatureWriteFailed;
     OGR_F_Destroy( poFeature );
     return false;
   }
@@ -375,7 +416,10 @@
     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 @@
     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 @@
   // 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 @@
                                        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 @@
     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 @@
     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 @@
     return err;
   }
 
+  if ( errorMessage )
+  {
+    errorMessage->clear();
+  }
+
   QgsAttributeList allAttr = layer->pendingAllAttributesList();
   QgsFeature fet;
 
@@ -493,6 +552,8 @@
     shallTransform = false;
   }
 
+  int n = 0, errors = 0;
+
   // write all features
   while ( layer->nextFeature( fet ) )
   {
@@ -519,7 +580,31 @@
         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 @@
     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;
 }
 
 

Modified: trunk/qgis/src/core/qgsvectorfilewriter.h
===================================================================
--- trunk/qgis/src/core/qgsvectorfilewriter.h	2010-08-28 22:35:41 UTC (rev 14165)
+++ trunk/qgis/src/core/qgsvectorfilewriter.h	2010-08-28 23:14:16 UTC (rev 14166)
@@ -52,7 +52,8 @@
       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 @@
                                          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 @@
                                             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 @@
                          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();

Modified: trunk/qgis/src/ui/qgsvectorlayersaveasdialogbase.ui
===================================================================
--- trunk/qgis/src/ui/qgsvectorlayersaveasdialogbase.ui	2010-08-28 22:35:41 UTC (rev 14165)
+++ trunk/qgis/src/ui/qgsvectorlayersaveasdialogbase.ui	2010-08-28 23:14:16 UTC (rev 14166)
@@ -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>



More information about the QGIS-commit mailing list