|
QGIS API Documentation
master-59fd5e0
|
00001 /*************************************************************************** 00002 qgsvectorfilewriter.cpp 00003 generic vector file writer 00004 ------------------- 00005 begin : Sat Jun 16 2004 00006 copyright : (C) 2004 by Tim Sutton 00007 email : tim at linfiniti.com 00008 ***************************************************************************/ 00009 00010 /*************************************************************************** 00011 * * 00012 * This program is free software; you can redistribute it and/or modify * 00013 * it under the terms of the GNU General Public License as published by * 00014 * the Free Software Foundation; either version 2 of the License, or * 00015 * (at your option) any later version. * 00016 * * 00017 ***************************************************************************/ 00018 00019 #include "qgsapplication.h" 00020 #include "qgsfield.h" 00021 #include "qgsfeature.h" 00022 #include "qgsgeometry.h" 00023 #include "qgslogger.h" 00024 #include "qgsmessagelog.h" 00025 #include "qgscoordinatereferencesystem.h" 00026 #include "qgsvectorfilewriter.h" 00027 #include "qgsrendererv2.h" 00028 #include "qgssymbollayerv2.h" 00029 00030 #include <QFile> 00031 #include <QSettings> 00032 #include <QFileInfo> 00033 #include <QDir> 00034 #include <QTextCodec> 00035 #include <QTextStream> 00036 #include <QSet> 00037 #include <QMetaType> 00038 00039 #include <cassert> 00040 #include <cstdlib> // size_t 00041 #include <limits> // std::numeric_limits 00042 00043 #include <ogr_srs_api.h> 00044 #include <cpl_error.h> 00045 #include <cpl_conv.h> 00046 00047 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 00048 #define TO8(x) (x).toUtf8().constData() 00049 #define TO8F(x) (x).toUtf8().constData() 00050 #else 00051 #define TO8(x) (x).toLocal8Bit().constData() 00052 #define TO8F(x) QFile::encodeName( x ).constData() 00053 #endif 00054 00055 00056 QgsVectorFileWriter::QgsVectorFileWriter( 00057 const QString &theVectorFileName, 00058 const QString &theFileEncoding, 00059 const QgsFields& fields, 00060 QGis::WkbType geometryType, 00061 const QgsCoordinateReferenceSystem* srs, 00062 const QString& driverName, 00063 const QStringList &datasourceOptions, 00064 const QStringList &layerOptions, 00065 QString *newFilename, 00066 SymbologyExport symbologyExport 00067 ) 00068 : mDS( NULL ) 00069 , mLayer( NULL ) 00070 , mGeom( NULL ) 00071 , mError( NoError ) 00072 , mSymbologyExport( symbologyExport ) 00073 { 00074 QString vectorFileName = theVectorFileName; 00075 QString fileEncoding = theFileEncoding; 00076 QStringList layOptions = layerOptions; 00077 QStringList dsOptions = datasourceOptions; 00078 00079 QString ogrDriverName; 00080 if ( driverName == "MapInfo MIF" ) 00081 { 00082 ogrDriverName = "MapInfo File"; 00083 } 00084 else if ( driverName == "SpatiaLite" ) 00085 { 00086 ogrDriverName = "SQLite"; 00087 if ( !dsOptions.contains( "SPATIALITE=YES" ) ) 00088 { 00089 dsOptions.append( "SPATIALITE=YES" ); 00090 } 00091 } 00092 else 00093 { 00094 ogrDriverName = driverName; 00095 } 00096 00097 // find driver in OGR 00098 OGRSFDriverH poDriver; 00099 QgsApplication::registerOgrDrivers(); 00100 00101 poDriver = OGRGetDriverByName( ogrDriverName.toLocal8Bit().data() ); 00102 00103 if ( poDriver == NULL ) 00104 { 00105 mErrorMessage = QObject::tr( "OGR driver for '%1' not found (OGR error: %2)" ) 00106 .arg( driverName ) 00107 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00108 mError = ErrDriverNotFound; 00109 return; 00110 } 00111 00112 if ( driverName == "ESRI Shapefile" ) 00113 { 00114 if ( layOptions.join( "" ).toUpper().indexOf( "ENCODING=" ) == -1 ) 00115 { 00116 layOptions.append( "ENCODING=" + convertCodecNameForEncodingOption( fileEncoding ) ); 00117 } 00118 00119 CPLSetConfigOption( "SHAPE_ENCODING", "" ); 00120 00121 if ( !vectorFileName.endsWith( ".shp", Qt::CaseInsensitive ) && 00122 !vectorFileName.endsWith( ".dbf", Qt::CaseInsensitive ) ) 00123 { 00124 vectorFileName += ".shp"; 00125 } 00126 00127 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700 00128 // check for unique fieldnames 00129 QSet<QString> fieldNames; 00130 for ( int i = 0; i < fields.count(); ++i ) 00131 { 00132 QString name = fields[i].name().left( 10 ); 00133 if ( fieldNames.contains( name ) ) 00134 { 00135 mErrorMessage = QObject::tr( "trimming attribute name '%1' to ten significant characters produces duplicate column name." ) 00136 .arg( fields[i].name() ); 00137 mError = ErrAttributeCreationFailed; 00138 return; 00139 } 00140 fieldNames << name; 00141 } 00142 #endif 00143 00144 deleteShapeFile( vectorFileName ); 00145 } 00146 else if ( driverName == "KML" ) 00147 { 00148 if ( !vectorFileName.endsWith( ".kml", Qt::CaseInsensitive ) ) 00149 { 00150 vectorFileName += ".kml"; 00151 } 00152 00153 if ( fileEncoding.compare( "UTF-8", Qt::CaseInsensitive ) != 0 ) 00154 { 00155 QgsDebugMsg( "forced UTF-8 encoding for KML" ); 00156 fileEncoding = "UTF-8"; 00157 } 00158 00159 QFile::remove( vectorFileName ); 00160 } 00161 else 00162 { 00163 QString longName; 00164 QString trLongName; 00165 QString glob; 00166 QString exts; 00167 if ( QgsVectorFileWriter::driverMetadata( driverName, longName, trLongName, glob, exts ) ) 00168 { 00169 QStringList allExts = exts.split( " ", QString::SkipEmptyParts ); 00170 bool found = false; 00171 foreach ( QString ext, allExts ) 00172 { 00173 if ( vectorFileName.endsWith( "." + ext, Qt::CaseInsensitive ) ) 00174 { 00175 found = true; 00176 break; 00177 } 00178 } 00179 00180 if ( !found ) 00181 { 00182 vectorFileName += "." + allExts[0]; 00183 } 00184 } 00185 00186 QFile::remove( vectorFileName ); 00187 } 00188 00189 char **options = NULL; 00190 if ( !dsOptions.isEmpty() ) 00191 { 00192 options = new char *[ dsOptions.size()+1 ]; 00193 for ( int i = 0; i < dsOptions.size(); i++ ) 00194 { 00195 options[i] = CPLStrdup( dsOptions[i].toLocal8Bit().data() ); 00196 } 00197 options[ dsOptions.size()] = NULL; 00198 } 00199 00200 // create the data source 00201 mDS = OGR_Dr_CreateDataSource( poDriver, TO8( vectorFileName ), options ); 00202 00203 if ( options ) 00204 { 00205 for ( int i = 0; i < dsOptions.size(); i++ ) 00206 CPLFree( options[i] ); 00207 delete [] options; 00208 options = NULL; 00209 } 00210 00211 if ( mDS == NULL ) 00212 { 00213 mError = ErrCreateDataSource; 00214 mErrorMessage = QObject::tr( "creation of data source failed (OGR error:%1)" ) 00215 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00216 return; 00217 } 00218 00219 QgsDebugMsg( "Created data source" ); 00220 00221 // use appropriate codec 00222 mCodec = QTextCodec::codecForName( fileEncoding.toLocal8Bit().constData() ); 00223 if ( !mCodec ) 00224 { 00225 QgsDebugMsg( "error finding QTextCodec for " + fileEncoding ); 00226 00227 QSettings settings; 00228 QString enc = settings.value( "/UI/encoding", "System" ).toString(); 00229 mCodec = QTextCodec::codecForName( enc.toLocal8Bit().constData() ); 00230 if ( !mCodec ) 00231 { 00232 QgsDebugMsg( "error finding QTextCodec for " + enc ); 00233 mCodec = QTextCodec::codecForLocale(); 00234 Q_ASSERT( mCodec ); 00235 } 00236 } 00237 00238 // consider spatial reference system of the layer 00239 OGRSpatialReferenceH ogrRef = NULL; 00240 if ( srs ) 00241 { 00242 QString srsWkt = srs->toWkt(); 00243 QgsDebugMsg( "WKT to save as is " + srsWkt ); 00244 ogrRef = OSRNewSpatialReference( srsWkt.toLocal8Bit().data() ); 00245 } 00246 00247 // datasource created, now create the output layer 00248 QString layerName = QFileInfo( vectorFileName ).baseName(); 00249 OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>( geometryType ); 00250 00251 if ( !layOptions.isEmpty() ) 00252 { 00253 options = new char *[ layOptions.size()+1 ]; 00254 for ( int i = 0; i < layOptions.size(); i++ ) 00255 { 00256 options[i] = CPLStrdup( layOptions[i].toLocal8Bit().data() ); 00257 } 00258 options[ layOptions.size()] = NULL; 00259 } 00260 00261 mLayer = OGR_DS_CreateLayer( mDS, TO8F( layerName ), ogrRef, wkbType, options ); 00262 00263 if ( options ) 00264 { 00265 for ( int i = 0; i < layOptions.size(); i++ ) 00266 CPLFree( options[i] ); 00267 delete [] options; 00268 options = NULL; 00269 } 00270 00271 if ( srs ) 00272 { 00273 if ( driverName == "ESRI Shapefile" ) 00274 { 00275 QString layerName = vectorFileName.left( vectorFileName.indexOf( ".shp", Qt::CaseInsensitive ) ); 00276 QFile prjFile( layerName + ".qpj" ); 00277 if ( prjFile.open( QIODevice::WriteOnly ) ) 00278 { 00279 QTextStream prjStream( &prjFile ); 00280 prjStream << srs->toWkt().toLocal8Bit().data() << endl; 00281 prjFile.close(); 00282 } 00283 else 00284 { 00285 QgsDebugMsg( "Couldn't open file " + layerName + ".qpj" ); 00286 } 00287 } 00288 00289 OSRDestroySpatialReference( ogrRef ); 00290 } 00291 00292 if ( mLayer == NULL ) 00293 { 00294 mErrorMessage = QObject::tr( "creation of layer failed (OGR error:%1)" ) 00295 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00296 mError = ErrCreateLayer; 00297 return; 00298 } 00299 00300 OGRFeatureDefnH defn = OGR_L_GetLayerDefn( mLayer ); 00301 00302 QgsDebugMsg( "created layer" ); 00303 00304 // create the fields 00305 QgsDebugMsg( "creating " + QString::number( fields.size() ) + " fields" ); 00306 00307 mFields = fields; 00308 mAttrIdxToOgrIdx.clear(); 00309 00310 for ( int fldIdx = 0; fldIdx < fields.count(); ++fldIdx ) 00311 { 00312 const QgsField& attrField = fields[fldIdx]; 00313 00314 OGRFieldType ogrType = OFTString; //default to string 00315 int ogrWidth = attrField.length(); 00316 int ogrPrecision = attrField.precision(); 00317 switch ( attrField.type() ) 00318 { 00319 case QVariant::LongLong: 00320 ogrType = OFTString; 00321 ogrWidth = ogrWidth > 0 && ogrWidth <= 21 ? ogrWidth : 21; 00322 ogrPrecision = -1; 00323 break; 00324 00325 case QVariant::String: 00326 ogrType = OFTString; 00327 if ( ogrWidth <= 0 || ogrWidth > 255 ) 00328 ogrWidth = 255; 00329 break; 00330 00331 case QVariant::Int: 00332 ogrType = OFTInteger; 00333 ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10; 00334 ogrPrecision = 0; 00335 break; 00336 00337 case QVariant::Double: 00338 ogrType = OFTReal; 00339 break; 00340 00341 case QVariant::Date: 00342 ogrType = OFTDate; 00343 break; 00344 00345 case QVariant::DateTime: 00346 ogrType = OFTDateTime; 00347 break; 00348 00349 default: 00350 //assert(0 && "invalid variant type!"); 00351 mErrorMessage = QObject::tr( "unsupported type for field %1" ) 00352 .arg( attrField.name() ); 00353 mError = ErrAttributeTypeUnsupported; 00354 return; 00355 } 00356 00357 // create field definition 00358 OGRFieldDefnH fld = OGR_Fld_Create( mCodec->fromUnicode( attrField.name() ), ogrType ); 00359 if ( ogrWidth > 0 ) 00360 { 00361 OGR_Fld_SetWidth( fld, ogrWidth ); 00362 } 00363 00364 if ( ogrPrecision >= 0 ) 00365 { 00366 OGR_Fld_SetPrecision( fld, ogrPrecision ); 00367 } 00368 00369 // create the field 00370 QgsDebugMsg( "creating field " + attrField.name() + 00371 " type " + QString( QVariant::typeToName( attrField.type() ) ) + 00372 " width " + QString::number( ogrWidth ) + 00373 " precision " + QString::number( ogrPrecision ) ); 00374 if ( OGR_L_CreateField( mLayer, fld, true ) != OGRERR_NONE ) 00375 { 00376 QgsDebugMsg( "error creating field " + attrField.name() ); 00377 mErrorMessage = QObject::tr( "creation of field %1 failed (OGR error: %2)" ) 00378 .arg( attrField.name() ) 00379 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00380 mError = ErrAttributeCreationFailed; 00381 OGR_Fld_Destroy( fld ); 00382 return; 00383 } 00384 OGR_Fld_Destroy( fld ); 00385 00386 int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( attrField.name() ) ); 00387 if ( ogrIdx < 0 ) 00388 { 00389 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700 00390 // if we didn't find our new column, assume it's name was truncated and 00391 // it was the last one added (like for shape files) 00392 int fieldCount = OGR_FD_GetFieldCount( defn ); 00393 00394 OGRFieldDefnH fdefn = OGR_FD_GetFieldDefn( defn, fieldCount - 1 ); 00395 if ( fdefn ) 00396 { 00397 const char *fieldName = OGR_Fld_GetNameRef( fdefn ); 00398 00399 if ( attrField.name().left( strlen( fieldName ) ) == fieldName ) 00400 { 00401 ogrIdx = fieldCount - 1; 00402 } 00403 } 00404 #else 00405 // GDAL 1.7 not just truncates, but launders more aggressivly. 00406 ogrIdx = OGR_FD_GetFieldCount( defn ) - 1; 00407 #endif 00408 00409 if ( ogrIdx < 0 ) 00410 { 00411 QgsDebugMsg( "error creating field " + attrField.name() ); 00412 mErrorMessage = QObject::tr( "created field %1 not found (OGR error: %2)" ) 00413 .arg( attrField.name() ) 00414 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00415 mError = ErrAttributeCreationFailed; 00416 return; 00417 } 00418 } 00419 00420 mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx ); 00421 } 00422 00423 QgsDebugMsg( "Done creating fields" ); 00424 00425 mWkbType = geometryType; 00426 if ( mWkbType != QGis::WKBNoGeometry ) 00427 { 00428 // create geometry which will be used for import 00429 mGeom = createEmptyGeometry( mWkbType ); 00430 } 00431 00432 if ( newFilename ) 00433 *newFilename = vectorFileName; 00434 } 00435 00436 OGRGeometryH QgsVectorFileWriter::createEmptyGeometry( QGis::WkbType wkbType ) 00437 { 00438 return OGR_G_CreateGeometry(( OGRwkbGeometryType ) wkbType ); 00439 } 00440 00441 00442 QgsVectorFileWriter::WriterError QgsVectorFileWriter::hasError() 00443 { 00444 return mError; 00445 } 00446 00447 QString QgsVectorFileWriter::errorMessage() 00448 { 00449 return mErrorMessage; 00450 } 00451 00452 bool QgsVectorFileWriter::addFeature( QgsFeature& feature, QgsFeatureRendererV2* renderer, QGis::UnitType outputUnit ) 00453 { 00454 // create the feature 00455 OGRFeatureH poFeature = createFeature( feature ); 00456 00457 //add OGR feature style type 00458 if ( mSymbologyExport != NoSymbology && renderer ) 00459 { 00460 //SymbolLayerSymbology: concatenate ogr styles of all symbollayers 00461 QgsSymbolV2List symbols = renderer->symbolsForFeature( feature ); 00462 QString styleString; 00463 QString currentStyle; 00464 00465 QgsSymbolV2List::const_iterator symbolIt = symbols.constBegin(); 00466 for ( ; symbolIt != symbols.constEnd(); ++symbolIt ) 00467 { 00468 int nSymbolLayers = ( *symbolIt )->symbolLayerCount(); 00469 for ( int i = 0; i < nSymbolLayers; ++i ) 00470 { 00471 #if 0 00472 QMap< QgsSymbolLayerV2*, QString >::const_iterator it = mSymbolLayerTable.find(( *symbolIt )->symbolLayer( i ) ); 00473 if ( it == mSymbolLayerTable.constEnd() ) 00474 { 00475 continue; 00476 } 00477 #endif 00478 double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit ); 00479 double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit ); 00480 00481 currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value(); 00482 00483 if ( mSymbologyExport == FeatureSymbology ) 00484 { 00485 if ( symbolIt != symbols.constBegin() || i != 0 ) 00486 { 00487 styleString.append( ";" ); 00488 } 00489 styleString.append( currentStyle ); 00490 } 00491 else if ( mSymbologyExport == SymbolLayerSymbology ) 00492 { 00493 OGR_F_SetStyleString( poFeature, currentStyle.toLocal8Bit().data() ); 00494 if ( !writeFeature( mLayer, poFeature ) ) 00495 { 00496 return false; 00497 } 00498 } 00499 } 00500 } 00501 OGR_F_SetStyleString( poFeature, styleString.toLocal8Bit().data() ); 00502 } 00503 00504 if ( mSymbologyExport == NoSymbology || mSymbologyExport == FeatureSymbology ) 00505 { 00506 if ( !writeFeature( mLayer, poFeature ) ) 00507 { 00508 return false; 00509 } 00510 } 00511 00512 OGR_F_Destroy( poFeature ); 00513 return true; 00514 } 00515 00516 OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature ) 00517 { 00518 OGRFeatureH poFeature = OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) ); 00519 00520 qint64 fid = FID_TO_NUMBER( feature.id() ); 00521 if ( fid > std::numeric_limits<int>::max() ) 00522 { 00523 QgsDebugMsg( QString( "feature id %1 too large." ).arg( fid ) ); 00524 OGRErr err = OGR_F_SetFID( poFeature, static_cast<long>( fid ) ); 00525 if ( err != OGRERR_NONE ) 00526 { 00527 QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" ) 00528 .arg( feature.id() ) 00529 .arg( err ).arg( CPLGetLastErrorMsg() ) 00530 ); 00531 } 00532 } 00533 00534 // attribute handling 00535 for ( int fldIdx = 0; fldIdx < mFields.count(); ++fldIdx ) 00536 { 00537 if ( !mAttrIdxToOgrIdx.contains( fldIdx ) ) 00538 { 00539 QgsDebugMsg( QString( "no ogr field for field %1" ).arg( fldIdx ) ); 00540 continue; 00541 } 00542 00543 const QVariant& attrValue = feature.attribute( fldIdx ); 00544 int ogrField = mAttrIdxToOgrIdx[ fldIdx ]; 00545 00546 if ( !attrValue.isValid() || attrValue.isNull() ) 00547 continue; 00548 00549 switch ( attrValue.type() ) 00550 { 00551 case QVariant::Int: 00552 OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() ); 00553 break; 00554 case QVariant::Double: 00555 OGR_F_SetFieldDouble( poFeature, ogrField, attrValue.toDouble() ); 00556 break; 00557 case QVariant::LongLong: 00558 case QVariant::String: 00559 OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() ); 00560 break; 00561 case QVariant::Date: 00562 OGR_F_SetFieldDateTime( poFeature, ogrField, 00563 attrValue.toDate().year(), 00564 attrValue.toDate().month(), 00565 attrValue.toDate().day(), 00566 0, 0, 0, 0 ); 00567 break; 00568 case QVariant::DateTime: 00569 OGR_F_SetFieldDateTime( poFeature, ogrField, 00570 attrValue.toDateTime().date().year(), 00571 attrValue.toDateTime().date().month(), 00572 attrValue.toDateTime().date().day(), 00573 attrValue.toDateTime().time().hour(), 00574 attrValue.toDateTime().time().minute(), 00575 attrValue.toDateTime().time().second(), 00576 0 ); 00577 break; 00578 case QVariant::Invalid: 00579 break; 00580 default: 00581 mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" ) 00582 .arg( mFields[fldIdx].name() ) 00583 .arg( ogrField ) 00584 .arg( QMetaType::typeName( attrValue.type() ) ) 00585 .arg( attrValue.toString() ); 00586 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00587 mError = ErrFeatureWriteFailed; 00588 return 0; 00589 } 00590 } 00591 00592 if ( mWkbType != QGis::WKBNoGeometry ) 00593 { 00594 // build geometry from WKB 00595 QgsGeometry *geom = feature.geometry(); 00596 00597 // turn single geoemetry to multi geometry if needed 00598 if ( geom && geom->wkbType() != mWkbType && geom->wkbType() == QGis::singleType( mWkbType ) ) 00599 { 00600 geom->convertToMultiType(); 00601 } 00602 00603 if ( geom && geom->wkbType() != mWkbType ) 00604 { 00605 // there's a problem when layer type is set as wkbtype Polygon 00606 // although there are also features of type MultiPolygon 00607 // (at least in OGR provider) 00608 // If the feature's wkbtype is different from the layer's wkbtype, 00609 // try to export it too. 00610 // 00611 // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive 00612 // i.e. Polygons can't be imported to OGRMultiPolygon 00613 00614 OGRGeometryH mGeom2 = createEmptyGeometry( geom->wkbType() ); 00615 00616 if ( !mGeom2 ) 00617 { 00618 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00619 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00620 mError = ErrFeatureWriteFailed; 00621 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00622 OGR_F_Destroy( poFeature ); 00623 return 0; 00624 } 00625 00626 OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb(), geom->wkbSize() ); 00627 if ( err != OGRERR_NONE ) 00628 { 00629 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00630 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00631 mError = ErrFeatureWriteFailed; 00632 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00633 OGR_F_Destroy( poFeature ); 00634 return 0; 00635 } 00636 00637 // pass ownership to geometry 00638 OGR_F_SetGeometryDirectly( poFeature, mGeom2 ); 00639 } 00640 else if ( geom ) 00641 { 00642 OGRErr err = OGR_G_ImportFromWkb( mGeom, geom->asWkb(), geom->wkbSize() ); 00643 if ( err != OGRERR_NONE ) 00644 { 00645 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00646 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00647 mError = ErrFeatureWriteFailed; 00648 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00649 OGR_F_Destroy( poFeature ); 00650 return 0; 00651 } 00652 00653 // set geometry (ownership is not passed to OGR) 00654 OGR_F_SetGeometry( poFeature, mGeom ); 00655 } 00656 } 00657 return poFeature; 00658 } 00659 00660 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature ) 00661 { 00662 if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE ) 00663 { 00664 mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00665 mError = ErrFeatureWriteFailed; 00666 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00667 OGR_F_Destroy( feature ); 00668 return false; 00669 } 00670 return true; 00671 } 00672 00673 QgsVectorFileWriter::~QgsVectorFileWriter() 00674 { 00675 if ( mGeom ) 00676 { 00677 OGR_G_DestroyGeometry( mGeom ); 00678 } 00679 00680 if ( mDS ) 00681 { 00682 OGR_DS_Destroy( mDS ); 00683 } 00684 } 00685 00686 QgsVectorFileWriter::WriterError 00687 QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer, 00688 const QString& fileName, 00689 const QString& fileEncoding, 00690 const QgsCoordinateReferenceSystem *destCRS, 00691 const QString& driverName, 00692 bool onlySelected, 00693 QString *errorMessage, 00694 const QStringList &datasourceOptions, 00695 const QStringList &layerOptions, 00696 bool skipAttributeCreation, 00697 QString *newFilename, 00698 SymbologyExport symbologyExport, 00699 double symbologyScale ) 00700 { 00701 QgsDebugMsg( "fileName = " + fileName ); 00702 const QgsCoordinateReferenceSystem* outputCRS; 00703 QgsCoordinateTransform* ct = 0; 00704 int shallTransform = false; 00705 00706 if ( layer == NULL ) 00707 { 00708 return ErrInvalidLayer; 00709 } 00710 00711 if ( destCRS && destCRS->isValid() ) 00712 { 00713 // This means we should transform 00714 outputCRS = destCRS; 00715 shallTransform = true; 00716 } 00717 else 00718 { 00719 // This means we shouldn't transform, use source CRS as output (if defined) 00720 outputCRS = &layer->crs(); 00721 } 00722 QgsVectorFileWriter* writer = 00723 new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFields() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport ); 00724 writer->setSymbologyScaleDenominator( symbologyScale ); 00725 00726 if ( newFilename ) 00727 { 00728 QgsDebugMsg( "newFilename = " + *newFilename ); 00729 } 00730 00731 // check whether file creation was successful 00732 WriterError err = writer->hasError(); 00733 if ( err != NoError ) 00734 { 00735 if ( errorMessage ) 00736 *errorMessage = writer->errorMessage(); 00737 delete writer; 00738 return err; 00739 } 00740 00741 if ( errorMessage ) 00742 { 00743 errorMessage->clear(); 00744 } 00745 00746 QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList(); 00747 QgsFeature fet; 00748 00749 //add possible attributes needed by renderer 00750 writer->addRendererAttributes( layer, allAttr ); 00751 00752 QgsFeatureRequest req; 00753 if ( layer->wkbType() == QGis::WKBNoGeometry ) 00754 { 00755 req.setFlags( QgsFeatureRequest::NoGeometry ); 00756 } 00757 req.setSubsetOfAttributes( allAttr ); 00758 QgsFeatureIterator fit = layer->getFeatures( req ); 00759 00760 const QgsFeatureIds& ids = layer->selectedFeaturesIds(); 00761 00762 // Create our transform 00763 if ( destCRS ) 00764 { 00765 ct = new QgsCoordinateTransform( layer->crs(), *destCRS ); 00766 } 00767 00768 // Check for failure 00769 if ( ct == NULL ) 00770 { 00771 shallTransform = false; 00772 } 00773 00774 //create symbol table if needed 00775 if ( writer->symbologyExport() != NoSymbology ) 00776 { 00777 //writer->createSymbolLayerTable( layer, writer->mDS ); 00778 } 00779 00780 if ( writer->symbologyExport() == SymbolLayerSymbology ) 00781 { 00782 QgsFeatureRendererV2* r = layer->rendererV2(); 00783 if ( r->capabilities() & QgsFeatureRendererV2::SymbolLevels 00784 && r->usingSymbolLevels() ) 00785 { 00786 QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( layer, fit, ct, errorMessage ); 00787 delete writer; 00788 delete ct; 00789 return ( error == NoError ) ? NoError : ErrFeatureWriteFailed; 00790 } 00791 } 00792 00793 int n = 0, errors = 0; 00794 00795 //unit type 00796 QGis::UnitType mapUnits = layer->crs().mapUnits(); 00797 if ( ct ) 00798 { 00799 mapUnits = ct->destCRS().mapUnits(); 00800 } 00801 00802 writer->startRender( layer ); 00803 00804 // write all features 00805 while ( fit.nextFeature( fet ) ) 00806 { 00807 if ( onlySelected && !ids.contains( fet.id() ) ) 00808 continue; 00809 00810 if ( shallTransform ) 00811 { 00812 try 00813 { 00814 if ( fet.geometry() ) 00815 { 00816 fet.geometry()->transform( *ct ); 00817 } 00818 } 00819 catch ( QgsCsException &e ) 00820 { 00821 delete ct; 00822 delete writer; 00823 00824 QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" ) 00825 .arg( fet.id() ).arg( e.what() ); 00826 QgsLogger::warning( msg ); 00827 if ( errorMessage ) 00828 *errorMessage = msg; 00829 00830 return ErrProjection; 00831 } 00832 } 00833 if ( allAttr.size() < 1 && skipAttributeCreation ) 00834 { 00835 fet.initAttributes( 0 ); 00836 } 00837 00838 if ( !writer->addFeature( fet, layer->rendererV2(), mapUnits ) ) 00839 { 00840 WriterError err = writer->hasError(); 00841 if ( err != NoError && errorMessage ) 00842 { 00843 if ( errorMessage->isEmpty() ) 00844 { 00845 *errorMessage = QObject::tr( "Feature write errors:" ); 00846 } 00847 *errorMessage += "\n" + writer->errorMessage(); 00848 } 00849 errors++; 00850 00851 if ( errors > 1000 ) 00852 { 00853 if ( errorMessage ) 00854 { 00855 *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors ); 00856 } 00857 00858 n = -1; 00859 break; 00860 } 00861 } 00862 n++; 00863 } 00864 00865 writer->stopRender( layer ); 00866 delete writer; 00867 00868 if ( shallTransform ) 00869 { 00870 delete ct; 00871 } 00872 00873 if ( errors > 0 && errorMessage && n > 0 ) 00874 { 00875 *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n ); 00876 } 00877 00878 return errors == 0 ? NoError : ErrFeatureWriteFailed; 00879 } 00880 00881 00882 bool QgsVectorFileWriter::deleteShapeFile( QString theFileName ) 00883 { 00884 QFileInfo fi( theFileName ); 00885 QDir dir = fi.dir(); 00886 00887 QStringList filter; 00888 const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" }; 00889 for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ ) 00890 { 00891 filter << fi.completeBaseName() + suffixes[i]; 00892 } 00893 00894 bool ok = true; 00895 foreach ( QString file, dir.entryList( filter ) ) 00896 { 00897 if ( !QFile::remove( dir.canonicalPath() + "/" + file ) ) 00898 { 00899 QgsDebugMsg( "Removing file failed : " + file ); 00900 ok = false; 00901 } 00902 } 00903 00904 return ok; 00905 } 00906 00907 QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats() 00908 { 00909 QMap<QString, QString> resultMap; 00910 00911 QgsApplication::registerOgrDrivers(); 00912 int const drvCount = OGRGetDriverCount(); 00913 00914 for ( int i = 0; i < drvCount; ++i ) 00915 { 00916 OGRSFDriverH drv = OGRGetDriver( i ); 00917 if ( drv ) 00918 { 00919 QString drvName = OGR_Dr_GetName( drv ); 00920 if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 ) 00921 { 00922 QString filterString = filterForDriver( drvName ); 00923 if ( filterString.isEmpty() ) 00924 continue; 00925 00926 resultMap.insert( filterString, drvName ); 00927 } 00928 } 00929 } 00930 00931 return resultMap; 00932 } 00933 00934 QMap<QString, QString> QgsVectorFileWriter::ogrDriverList() 00935 { 00936 QMap<QString, QString> resultMap; 00937 00938 QgsApplication::registerOgrDrivers(); 00939 int const drvCount = OGRGetDriverCount(); 00940 00941 QStringList writableDrivers; 00942 for ( int i = 0; i < drvCount; ++i ) 00943 { 00944 OGRSFDriverH drv = OGRGetDriver( i ); 00945 if ( drv ) 00946 { 00947 QString drvName = OGR_Dr_GetName( drv ); 00948 if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 ) 00949 { 00950 // Add separate format for Mapinfo MIF (MITAB is OGR default) 00951 if ( drvName == "MapInfo File" ) 00952 { 00953 writableDrivers << "MapInfo MIF"; 00954 } 00955 else if ( drvName == "SQLite" ) 00956 { 00957 // Unfortunately it seems that there is no simple way to detect if 00958 // OGR SQLite driver is compiled with SpatiaLite support. 00959 // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR 00960 // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html 00961 // -> test if creation failes 00962 QString option = "SPATIALITE=YES"; 00963 char **options = new char *[2]; 00964 options[0] = CPLStrdup( option.toLocal8Bit().data() ); 00965 options[1] = NULL; 00966 OGRSFDriverH poDriver; 00967 QgsApplication::registerOgrDrivers(); 00968 poDriver = OGRGetDriverByName( drvName.toLocal8Bit().data() ); 00969 if ( poDriver ) 00970 { 00971 OGRDataSourceH ds = OGR_Dr_CreateDataSource( poDriver, TO8( QString( "/vsimem/spatialitetest.sqlite" ) ), options ); 00972 if ( ds ) 00973 { 00974 writableDrivers << "SpatiaLite"; 00975 OGR_DS_Destroy( ds ); 00976 } 00977 } 00978 CPLFree( options[0] ); 00979 delete [] options; 00980 } 00981 writableDrivers << drvName; 00982 } 00983 } 00984 } 00985 00986 foreach ( QString drvName, writableDrivers ) 00987 { 00988 QString longName; 00989 QString trLongName; 00990 QString glob; 00991 QString exts; 00992 if ( QgsVectorFileWriter::driverMetadata( drvName, longName, trLongName, glob, exts ) && !trLongName.isEmpty() ) 00993 { 00994 resultMap.insert( trLongName, drvName ); 00995 } 00996 } 00997 00998 return resultMap; 00999 } 01000 01001 QString QgsVectorFileWriter::fileFilterString() 01002 { 01003 QString filterString; 01004 QMap< QString, QString> driverFormatMap = supportedFiltersAndFormats(); 01005 QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin(); 01006 for ( ; it != driverFormatMap.constEnd(); ++it ) 01007 { 01008 if ( filterString.isEmpty() ) 01009 filterString += ";;"; 01010 01011 filterString += it.key(); 01012 } 01013 return filterString; 01014 } 01015 01016 QString QgsVectorFileWriter::filterForDriver( const QString& driverName ) 01017 { 01018 QString longName; 01019 QString trLongName; 01020 QString glob; 01021 QString exts; 01022 if ( !driverMetadata( driverName, longName, trLongName, glob, exts ) || trLongName.isEmpty() || glob.isEmpty() ) 01023 return ""; 01024 01025 return trLongName + " [OGR] (" + glob.toLower() + " " + glob.toUpper() + ")"; 01026 } 01027 01028 QString QgsVectorFileWriter::convertCodecNameForEncodingOption( const QString &codecName ) 01029 { 01030 if ( codecName == "System" ) 01031 return QString( "LDID/0" ); 01032 01033 QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive ); 01034 if ( re.exactMatch( codecName ) ) 01035 { 01036 QString c = re.cap( 2 ).replace( "-" , "" ); 01037 bool isNumber; 01038 c.toInt( &isNumber ); 01039 if ( isNumber ) 01040 return c; 01041 } 01042 return codecName; 01043 } 01044 01045 bool QgsVectorFileWriter::driverMetadata( QString driverName, QString &longName, QString &trLongName, QString &glob, QString &ext ) 01046 { 01047 if ( driverName.startsWith( "AVCE00" ) ) 01048 { 01049 longName = "Arc/Info ASCII Coverage"; 01050 trLongName = QObject::tr( "Arc/Info ASCII Coverage" ); 01051 glob = "*.e00"; 01052 ext = "e00"; 01053 } 01054 else if ( driverName.startsWith( "BNA" ) ) 01055 { 01056 longName = "Atlas BNA"; 01057 trLongName = QObject::tr( "Atlas BNA" ); 01058 glob = "*.bna"; 01059 ext = "bna"; 01060 } 01061 else if ( driverName.startsWith( "CSV" ) ) 01062 { 01063 longName = "Comma Separated Value"; 01064 trLongName = QObject::tr( "Comma Separated Value" ); 01065 glob = "*.csv"; 01066 ext = "csv"; 01067 } 01068 else if ( driverName.startsWith( "ESRI" ) ) 01069 { 01070 longName = "ESRI Shapefile"; 01071 trLongName = QObject::tr( "ESRI Shapefile" ); 01072 glob = "*.shp"; 01073 ext = "shp"; 01074 } 01075 else if ( driverName.startsWith( "FMEObjects Gateway" ) ) 01076 { 01077 longName = "FMEObjects Gateway"; 01078 trLongName = QObject::tr( "FMEObjects Gateway" ); 01079 glob = "*.fdd"; 01080 ext = "fdd"; 01081 } 01082 else if ( driverName.startsWith( "GeoJSON" ) ) 01083 { 01084 longName = "GeoJSON"; 01085 trLongName = QObject::tr( "GeoJSON" ); 01086 glob = "*.geojson"; 01087 ext = "geojson"; 01088 } 01089 else if ( driverName.startsWith( "GeoRSS" ) ) 01090 { 01091 longName = "GeoRSS"; 01092 trLongName = QObject::tr( "GeoRSS" ); 01093 glob = "*.xml"; 01094 ext = "xml"; 01095 } 01096 else if ( driverName.startsWith( "GML" ) ) 01097 { 01098 longName = "Geography Markup Language [GML]"; 01099 trLongName = QObject::tr( "Geography Markup Language [GML]" ); 01100 glob = "*.gml"; 01101 ext = "gml"; 01102 } 01103 else if ( driverName.startsWith( "GMT" ) ) 01104 { 01105 longName = "Generic Mapping Tools [GMT]"; 01106 trLongName = QObject::tr( "Generic Mapping Tools [GMT]" ); 01107 glob = "*.gmt"; 01108 ext = "gmt"; 01109 } 01110 else if ( driverName.startsWith( "GPX" ) ) 01111 { 01112 longName = "GPS eXchange Format [GPX]"; 01113 trLongName = QObject::tr( "GPS eXchange Format [GPX]" ); 01114 glob = "*.gpx"; 01115 ext = "gpx"; 01116 } 01117 else if ( driverName.startsWith( "Interlis 1" ) ) 01118 { 01119 longName = "INTERLIS 1"; 01120 trLongName = QObject::tr( "INTERLIS 1" ); 01121 glob = "*.itf *.xml *.ili"; 01122 ext = "ili"; 01123 } 01124 else if ( driverName.startsWith( "Interlis 2" ) ) 01125 { 01126 longName = "INTERLIS 2"; 01127 trLongName = QObject::tr( "INTERLIS 2" ); 01128 glob = "*.itf *.xml *.ili"; 01129 ext = "ili"; 01130 } 01131 else if ( driverName.startsWith( "KML" ) ) 01132 { 01133 longName = "Keyhole Markup Language [KML]"; 01134 trLongName = QObject::tr( "Keyhole Markup Language [KML]" ); 01135 glob = "*.kml" ; 01136 ext = "kml" ; 01137 } 01138 else if ( driverName.startsWith( "MapInfo File" ) ) 01139 { 01140 longName = "Mapinfo TAB"; 01141 trLongName = QObject::tr( "Mapinfo TAB" ); 01142 glob = "*.tab"; 01143 ext = "tab"; 01144 } 01145 // 'MapInfo MIF' is internal QGIS addition to distinguish between MITAB and MIF 01146 else if ( driverName.startsWith( "MapInfo MIF" ) ) 01147 { 01148 longName = "Mapinfo MIF"; 01149 trLongName = QObject::tr( "Mapinfo MIF" ); 01150 glob = "*.mif"; 01151 ext = "mif"; 01152 } 01153 else if ( driverName.startsWith( "DGN" ) ) 01154 { 01155 longName = "Microstation DGN"; 01156 trLongName = QObject::tr( "Microstation DGN" ); 01157 glob = "*.dgn"; 01158 ext = "dgn"; 01159 } 01160 else if ( driverName.startsWith( "S57" ) ) 01161 { 01162 longName = "S-57 Base file"; 01163 trLongName = QObject::tr( "S-57 Base file" ); 01164 glob = "*.000"; 01165 ext = "000"; 01166 } 01167 else if ( driverName.startsWith( "SDTS" ) ) 01168 { 01169 longName = "Spatial Data Transfer Standard [SDTS]"; 01170 trLongName = QObject::tr( "Spatial Data Transfer Standard [SDTS]" ); 01171 glob = "*catd.ddf"; 01172 ext = "ddf"; 01173 } 01174 else if ( driverName.startsWith( "SQLite" ) ) 01175 { 01176 longName = "SQLite"; 01177 trLongName = QObject::tr( "SQLite" ); 01178 glob = "*.sqlite"; 01179 ext = "sqlite"; 01180 } 01181 // QGIS internal addition for SpatialLite 01182 else if ( driverName.startsWith( "SpatiaLite" ) ) 01183 { 01184 longName = "SpatiaLite"; 01185 trLongName = QObject::tr( "SpatiaLite" ); 01186 glob = "*.sqlite"; 01187 ext = "sqlite"; 01188 } 01189 else if ( driverName.startsWith( "DXF" ) ) 01190 { 01191 longName = "AutoCAD DXF"; 01192 trLongName = QObject::tr( "AutoCAD DXF" ); 01193 glob = "*.dxf"; 01194 ext = "dxf"; 01195 } 01196 else if ( driverName.startsWith( "Geoconcept" ) ) 01197 { 01198 longName = "Geoconcept"; 01199 trLongName = QObject::tr( "Geoconcept" ); 01200 glob = "*.gxt *.txt"; 01201 ext = "gxt"; 01202 } 01203 else if ( driverName.startsWith( "FileGDB" ) ) 01204 { 01205 longName = "ESRI FileGDB"; 01206 trLongName = QObject::tr( "ESRI FileGDB" ); 01207 glob = "*.gdb"; 01208 ext = "gdb"; 01209 } 01210 else 01211 { 01212 return false; 01213 } 01214 01215 return true; 01216 } 01217 01218 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer* vl, const QgsCoordinateTransform* ct, OGRDataSourceH ds ) 01219 { 01220 if ( !vl || !ds ) 01221 { 01222 return; 01223 } 01224 01225 QgsFeatureRendererV2* renderer = vl->rendererV2(); 01226 if ( !renderer ) 01227 { 01228 return; 01229 } 01230 01231 //unit type 01232 QGis::UnitType mapUnits = vl->crs().mapUnits(); 01233 if ( ct ) 01234 { 01235 mapUnits = ct->destCRS().mapUnits(); 01236 } 01237 01238 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1700 01239 mSymbolLayerTable.clear(); 01240 OGRStyleTableH ogrStyleTable = OGR_STBL_Create(); 01241 OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable ); 01242 01243 //get symbols 01244 int nTotalLevels = 0; 01245 QgsSymbolV2List symbolList = renderer->symbols(); 01246 QgsSymbolV2List::iterator symbolIt = symbolList.begin(); 01247 for ( ; symbolIt != symbolList.end(); ++symbolIt ) 01248 { 01249 double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits ); 01250 double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits ); 01251 01252 int nLevels = ( *symbolIt )->symbolLayerCount(); 01253 for ( int i = 0; i < nLevels; ++i ) 01254 { 01255 mSymbolLayerTable.insert(( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) ); 01256 OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(), 01257 ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() ); 01258 ++nTotalLevels; 01259 } 01260 } 01261 OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable ); 01262 #endif 01263 } 01264 01265 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( QgsVectorLayer* layer, QgsFeatureIterator& fit, 01266 const QgsCoordinateTransform* ct, QString* errorMessage ) 01267 { 01268 if ( !layer ) 01269 { 01270 //return error 01271 } 01272 QgsFeatureRendererV2* renderer = layer->rendererV2(); 01273 if ( !renderer ) 01274 { 01275 //return error 01276 } 01277 QHash< QgsSymbolV2*, QList<QgsFeature> > features; 01278 01279 //unit type 01280 QGis::UnitType mapUnits = layer->crs().mapUnits(); 01281 if ( ct ) 01282 { 01283 mapUnits = ct->destCRS().mapUnits(); 01284 } 01285 01286 startRender( layer ); 01287 01288 //fetch features 01289 QgsFeature fet; 01290 QgsSymbolV2* featureSymbol = 0; 01291 while ( fit.nextFeature( fet ) ) 01292 { 01293 if ( ct ) 01294 { 01295 try 01296 { 01297 if ( fet.geometry() ) 01298 { 01299 fet.geometry()->transform( *ct ); 01300 } 01301 } 01302 catch ( QgsCsException &e ) 01303 { 01304 delete ct; 01305 01306 QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" ) 01307 .arg( e.what() ); 01308 QgsLogger::warning( msg ); 01309 if ( errorMessage ) 01310 *errorMessage = msg; 01311 01312 return ErrProjection; 01313 } 01314 } 01315 01316 featureSymbol = renderer->symbolForFeature( fet ); 01317 if ( !featureSymbol ) 01318 { 01319 continue; 01320 } 01321 01322 QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator it = features.find( featureSymbol ); 01323 if ( it == features.end() ) 01324 { 01325 it = features.insert( featureSymbol, QList<QgsFeature>() ); 01326 } 01327 it.value().append( fet ); 01328 } 01329 01330 //find out order 01331 QgsSymbolV2LevelOrder levels; 01332 QgsSymbolV2List symbols = renderer->symbols(); 01333 for ( int i = 0; i < symbols.count(); i++ ) 01334 { 01335 QgsSymbolV2* sym = symbols[i]; 01336 for ( int j = 0; j < sym->symbolLayerCount(); j++ ) 01337 { 01338 int level = sym->symbolLayer( j )->renderingPass(); 01339 if ( level < 0 || level >= 1000 ) // ignore invalid levels 01340 continue; 01341 QgsSymbolV2LevelItem item( sym, j ); 01342 while ( level >= levels.count() ) // append new empty levels 01343 levels.append( QgsSymbolV2Level() ); 01344 levels[level].append( item ); 01345 } 01346 } 01347 01348 int nErrors = 0; 01349 int nTotalFeatures = 0; 01350 01351 //export symbol layers and symbology 01352 for ( int l = 0; l < levels.count(); l++ ) 01353 { 01354 QgsSymbolV2Level& level = levels[l]; 01355 for ( int i = 0; i < level.count(); i++ ) 01356 { 01357 QgsSymbolV2LevelItem& item = level[i]; 01358 QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() ); 01359 if ( levelIt == features.end() ) 01360 { 01361 ++nErrors; 01362 continue; 01363 } 01364 01365 double mmsf = mmScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits ); 01366 double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits ); 01367 01368 int llayer = item.layer(); 01369 QList<QgsFeature>& featureList = levelIt.value(); 01370 QList<QgsFeature>::iterator featureIt = featureList.begin(); 01371 for ( ; featureIt != featureList.end(); ++featureIt ) 01372 { 01373 ++nTotalFeatures; 01374 OGRFeatureH ogrFeature = createFeature( *featureIt ); 01375 if ( !ogrFeature ) 01376 { 01377 ++nErrors; 01378 continue; 01379 } 01380 01381 QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf ); 01382 if ( !styleString.isEmpty() ) 01383 { 01384 OGR_F_SetStyleString( ogrFeature, styleString.toLocal8Bit().data() ); 01385 if ( ! writeFeature( mLayer, ogrFeature ) ) 01386 { 01387 ++nErrors; 01388 } 01389 } 01390 OGR_F_Destroy( ogrFeature ); 01391 } 01392 } 01393 } 01394 01395 stopRender( layer ); 01396 01397 if ( nErrors > 0 && errorMessage ) 01398 { 01399 *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures ); 01400 } 01401 01402 return ( nErrors > 0 ) ? QgsVectorFileWriter::ErrFeatureWriteFailed : QgsVectorFileWriter::NoError; 01403 } 01404 01405 double QgsVectorFileWriter::mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits ) 01406 { 01407 if ( symbolUnits == QgsSymbolV2::MM ) 01408 { 01409 return 1.0; 01410 } 01411 else 01412 { 01413 //conversion factor map units -> mm 01414 if ( mapUnits == QGis::Meters ) 01415 { 01416 return 1000 / scaleDenominator; 01417 } 01418 01419 } 01420 return 1.0; //todo: map units 01421 } 01422 01423 double QgsVectorFileWriter::mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits ) 01424 { 01425 if ( symbolUnits == QgsSymbolV2::MapUnit ) 01426 { 01427 return 1.0; 01428 } 01429 else 01430 { 01431 if ( symbolUnits == QgsSymbolV2::MM && mapUnits == QGis::Meters ) 01432 { 01433 return scaleDenominator / 1000; 01434 } 01435 } 01436 return 1.0; 01437 } 01438 01439 QgsRenderContext QgsVectorFileWriter::renderContext() const 01440 { 01441 QgsRenderContext context; 01442 context.setRendererScale( mSymbologyScaleDenominator ); 01443 return context; 01444 } 01445 01446 void QgsVectorFileWriter::startRender( QgsVectorLayer* vl ) const 01447 { 01448 QgsFeatureRendererV2* renderer = symbologyRenderer( vl ); 01449 if ( !renderer ) 01450 { 01451 return; 01452 } 01453 01454 QgsRenderContext ctx = renderContext(); 01455 renderer->startRender( ctx, vl ); 01456 } 01457 01458 void QgsVectorFileWriter::stopRender( QgsVectorLayer* vl ) const 01459 { 01460 QgsFeatureRendererV2* renderer = symbologyRenderer( vl ); 01461 if ( !renderer ) 01462 { 01463 return; 01464 } 01465 01466 QgsRenderContext ctx = renderContext(); 01467 renderer->stopRender( ctx ); 01468 } 01469 01470 QgsFeatureRendererV2* QgsVectorFileWriter::symbologyRenderer( QgsVectorLayer* vl ) const 01471 { 01472 if ( mSymbologyExport == NoSymbology ) 01473 { 01474 return 0; 01475 } 01476 if ( !vl ) 01477 { 01478 return 0; 01479 } 01480 01481 return vl->rendererV2(); 01482 } 01483 01484 void QgsVectorFileWriter::addRendererAttributes( QgsVectorLayer* vl, QgsAttributeList& attList ) 01485 { 01486 QgsFeatureRendererV2* renderer = symbologyRenderer( vl ); 01487 if ( renderer ) 01488 { 01489 QList<QString> rendererAttributes = renderer->usedAttributes(); 01490 for ( int i = 0; i < rendererAttributes.size(); ++i ) 01491 { 01492 int index = vl->fieldNameIndex( rendererAttributes.at( i ) ); 01493 if ( index != -1 ) 01494 { 01495 attList.push_back( vl->fieldNameIndex( rendererAttributes.at( i ) ) ); 01496 } 01497 } 01498 } 01499 }