|
QGIS API Documentation
master-6164ace
|
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 return; 00382 } 00383 00384 int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( attrField.name() ) ); 00385 if ( ogrIdx < 0 ) 00386 { 00387 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700 00388 // if we didn't find our new column, assume it's name was truncated and 00389 // it was the last one added (like for shape files) 00390 int fieldCount = OGR_FD_GetFieldCount( defn ); 00391 00392 OGRFieldDefnH fdefn = OGR_FD_GetFieldDefn( defn, fieldCount - 1 ); 00393 if ( fdefn ) 00394 { 00395 const char *fieldName = OGR_Fld_GetNameRef( fdefn ); 00396 00397 if ( attrField.name().left( strlen( fieldName ) ) == fieldName ) 00398 { 00399 ogrIdx = fieldCount - 1; 00400 } 00401 } 00402 #else 00403 // GDAL 1.7 not just truncates, but launders more aggressivly. 00404 ogrIdx = OGR_FD_GetFieldCount( defn ) - 1; 00405 #endif 00406 00407 if ( ogrIdx < 0 ) 00408 { 00409 QgsDebugMsg( "error creating field " + attrField.name() ); 00410 mErrorMessage = QObject::tr( "created field %1 not found (OGR error: %2)" ) 00411 .arg( attrField.name() ) 00412 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00413 mError = ErrAttributeCreationFailed; 00414 return; 00415 } 00416 } 00417 00418 mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx ); 00419 } 00420 00421 QgsDebugMsg( "Done creating fields" ); 00422 00423 mWkbType = geometryType; 00424 if ( mWkbType != QGis::WKBNoGeometry ) 00425 { 00426 // create geometry which will be used for import 00427 mGeom = createEmptyGeometry( mWkbType ); 00428 } 00429 00430 if ( newFilename ) 00431 *newFilename = vectorFileName; 00432 } 00433 00434 OGRGeometryH QgsVectorFileWriter::createEmptyGeometry( QGis::WkbType wkbType ) 00435 { 00436 return OGR_G_CreateGeometry(( OGRwkbGeometryType ) wkbType ); 00437 } 00438 00439 00440 QgsVectorFileWriter::WriterError QgsVectorFileWriter::hasError() 00441 { 00442 return mError; 00443 } 00444 00445 QString QgsVectorFileWriter::errorMessage() 00446 { 00447 return mErrorMessage; 00448 } 00449 00450 bool QgsVectorFileWriter::addFeature( QgsFeature& feature, QgsFeatureRendererV2* renderer, QGis::UnitType outputUnit ) 00451 { 00452 // create the feature 00453 OGRFeatureH poFeature = createFeature( feature ); 00454 00455 //add OGR feature style type 00456 if ( mSymbologyExport != NoSymbology && renderer ) 00457 { 00458 //SymbolLayerSymbology: concatenate ogr styles of all symbollayers 00459 QgsSymbolV2List symbols = renderer->symbolsForFeature( feature ); 00460 QString styleString; 00461 QString currentStyle; 00462 00463 QgsSymbolV2List::const_iterator symbolIt = symbols.constBegin(); 00464 for ( ; symbolIt != symbols.constEnd(); ++symbolIt ) 00465 { 00466 int nSymbolLayers = ( *symbolIt )->symbolLayerCount(); 00467 for ( int i = 0; i < nSymbolLayers; ++i ) 00468 { 00469 #if 0 00470 QMap< QgsSymbolLayerV2*, QString >::const_iterator it = mSymbolLayerTable.find(( *symbolIt )->symbolLayer( i ) ); 00471 if ( it == mSymbolLayerTable.constEnd() ) 00472 { 00473 continue; 00474 } 00475 #endif 00476 double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit ); 00477 double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit ); 00478 00479 currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value(); 00480 00481 if ( mSymbologyExport == FeatureSymbology ) 00482 { 00483 if ( symbolIt != symbols.constBegin() || i != 0 ) 00484 { 00485 styleString.append( ";" ); 00486 } 00487 styleString.append( currentStyle ); 00488 } 00489 else if ( mSymbologyExport == SymbolLayerSymbology ) 00490 { 00491 OGR_F_SetStyleString( poFeature, currentStyle.toLocal8Bit().data() ); 00492 if ( !writeFeature( mLayer, poFeature ) ) 00493 { 00494 return false; 00495 } 00496 } 00497 } 00498 } 00499 OGR_F_SetStyleString( poFeature, styleString.toLocal8Bit().data() ); 00500 } 00501 00502 if ( mSymbologyExport == NoSymbology || mSymbologyExport == FeatureSymbology ) 00503 { 00504 if ( !writeFeature( mLayer, poFeature ) ) 00505 { 00506 return false; 00507 } 00508 } 00509 00510 OGR_F_Destroy( poFeature ); 00511 return true; 00512 } 00513 00514 OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature ) 00515 { 00516 OGRFeatureH poFeature = OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) ); 00517 00518 qint64 fid = FID_TO_NUMBER( feature.id() ); 00519 if ( fid > std::numeric_limits<int>::max() ) 00520 { 00521 QgsDebugMsg( QString( "feature id %1 too large." ).arg( fid ) ); 00522 OGRErr err = OGR_F_SetFID( poFeature, static_cast<long>( fid ) ); 00523 if ( err != OGRERR_NONE ) 00524 { 00525 QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" ) 00526 .arg( feature.id() ) 00527 .arg( err ).arg( CPLGetLastErrorMsg() ) 00528 ); 00529 } 00530 } 00531 00532 // attribute handling 00533 for ( int fldIdx = 0; fldIdx < mFields.count(); ++fldIdx ) 00534 { 00535 if ( !mAttrIdxToOgrIdx.contains( fldIdx ) ) 00536 { 00537 QgsDebugMsg( QString( "no ogr field for field %1" ).arg( fldIdx ) ); 00538 continue; 00539 } 00540 00541 const QVariant& attrValue = feature.attribute( fldIdx ); 00542 int ogrField = mAttrIdxToOgrIdx[ fldIdx ]; 00543 00544 if ( !attrValue.isValid() || attrValue.isNull() ) 00545 continue; 00546 00547 switch ( attrValue.type() ) 00548 { 00549 case QVariant::Int: 00550 OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() ); 00551 break; 00552 case QVariant::Double: 00553 OGR_F_SetFieldDouble( poFeature, ogrField, attrValue.toDouble() ); 00554 break; 00555 case QVariant::LongLong: 00556 case QVariant::String: 00557 OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() ); 00558 break; 00559 case QVariant::Date: 00560 OGR_F_SetFieldDateTime( poFeature, ogrField, 00561 attrValue.toDate().year(), 00562 attrValue.toDate().month(), 00563 attrValue.toDate().day(), 00564 0, 0, 0, 0 ); 00565 break; 00566 case QVariant::DateTime: 00567 OGR_F_SetFieldDateTime( poFeature, ogrField, 00568 attrValue.toDateTime().date().year(), 00569 attrValue.toDateTime().date().month(), 00570 attrValue.toDateTime().date().day(), 00571 attrValue.toDateTime().time().hour(), 00572 attrValue.toDateTime().time().minute(), 00573 attrValue.toDateTime().time().second(), 00574 0 ); 00575 break; 00576 case QVariant::Invalid: 00577 break; 00578 default: 00579 mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" ) 00580 .arg( mFields[fldIdx].name() ) 00581 .arg( ogrField ) 00582 .arg( QMetaType::typeName( attrValue.type() ) ) 00583 .arg( attrValue.toString() ); 00584 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00585 mError = ErrFeatureWriteFailed; 00586 return 0; 00587 } 00588 } 00589 00590 if ( mWkbType != QGis::WKBNoGeometry ) 00591 { 00592 // build geometry from WKB 00593 QgsGeometry *geom = feature.geometry(); 00594 00595 // turn single geoemetry to multi geometry if needed 00596 if ( geom && geom->wkbType() != mWkbType && geom->wkbType() == QGis::singleType( mWkbType ) ) 00597 { 00598 geom->convertToMultiType(); 00599 } 00600 00601 if ( geom && geom->wkbType() != mWkbType ) 00602 { 00603 // there's a problem when layer type is set as wkbtype Polygon 00604 // although there are also features of type MultiPolygon 00605 // (at least in OGR provider) 00606 // If the feature's wkbtype is different from the layer's wkbtype, 00607 // try to export it too. 00608 // 00609 // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive 00610 // i.e. Polygons can't be imported to OGRMultiPolygon 00611 00612 OGRGeometryH mGeom2 = createEmptyGeometry( geom->wkbType() ); 00613 00614 if ( !mGeom2 ) 00615 { 00616 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00617 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00618 mError = ErrFeatureWriteFailed; 00619 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00620 OGR_F_Destroy( poFeature ); 00621 return 0; 00622 } 00623 00624 OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb(), geom->wkbSize() ); 00625 if ( err != OGRERR_NONE ) 00626 { 00627 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00628 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00629 mError = ErrFeatureWriteFailed; 00630 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00631 OGR_F_Destroy( poFeature ); 00632 return 0; 00633 } 00634 00635 // pass ownership to geometry 00636 OGR_F_SetGeometryDirectly( poFeature, mGeom2 ); 00637 } 00638 else if ( geom ) 00639 { 00640 OGRErr err = OGR_G_ImportFromWkb( mGeom, geom->asWkb(), geom->wkbSize() ); 00641 if ( err != OGRERR_NONE ) 00642 { 00643 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00644 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00645 mError = ErrFeatureWriteFailed; 00646 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00647 OGR_F_Destroy( poFeature ); 00648 return 0; 00649 } 00650 00651 // set geometry (ownership is not passed to OGR) 00652 OGR_F_SetGeometry( poFeature, mGeom ); 00653 } 00654 } 00655 return poFeature; 00656 } 00657 00658 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature ) 00659 { 00660 if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE ) 00661 { 00662 mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00663 mError = ErrFeatureWriteFailed; 00664 QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) ); 00665 OGR_F_Destroy( feature ); 00666 return false; 00667 } 00668 return true; 00669 } 00670 00671 QgsVectorFileWriter::~QgsVectorFileWriter() 00672 { 00673 if ( mGeom ) 00674 { 00675 OGR_G_DestroyGeometry( mGeom ); 00676 } 00677 00678 if ( mDS ) 00679 { 00680 OGR_DS_Destroy( mDS ); 00681 } 00682 } 00683 00684 QgsVectorFileWriter::WriterError 00685 QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer, 00686 const QString& fileName, 00687 const QString& fileEncoding, 00688 const QgsCoordinateReferenceSystem *destCRS, 00689 const QString& driverName, 00690 bool onlySelected, 00691 QString *errorMessage, 00692 const QStringList &datasourceOptions, 00693 const QStringList &layerOptions, 00694 bool skipAttributeCreation, 00695 QString *newFilename, 00696 SymbologyExport symbologyExport, 00697 double symbologyScale ) 00698 { 00699 QgsDebugMsg( "fileName = " + fileName ); 00700 const QgsCoordinateReferenceSystem* outputCRS; 00701 QgsCoordinateTransform* ct = 0; 00702 int shallTransform = false; 00703 00704 if ( layer == NULL ) 00705 { 00706 return ErrInvalidLayer; 00707 } 00708 00709 if ( destCRS && destCRS->isValid() ) 00710 { 00711 // This means we should transform 00712 outputCRS = destCRS; 00713 shallTransform = true; 00714 } 00715 else 00716 { 00717 // This means we shouldn't transform, use source CRS as output (if defined) 00718 outputCRS = &layer->crs(); 00719 } 00720 QgsVectorFileWriter* writer = 00721 new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFields() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport ); 00722 writer->setSymbologyScaleDenominator( symbologyScale ); 00723 00724 if ( newFilename ) 00725 { 00726 QgsDebugMsg( "newFilename = " + *newFilename ); 00727 } 00728 00729 // check whether file creation was successful 00730 WriterError err = writer->hasError(); 00731 if ( err != NoError ) 00732 { 00733 if ( errorMessage ) 00734 *errorMessage = writer->errorMessage(); 00735 delete writer; 00736 return err; 00737 } 00738 00739 if ( errorMessage ) 00740 { 00741 errorMessage->clear(); 00742 } 00743 00744 QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList(); 00745 QgsFeature fet; 00746 00747 //add possible attributes needed by renderer 00748 writer->addRendererAttributes( layer, allAttr ); 00749 00750 QgsFeatureRequest req; 00751 if ( layer->wkbType() == QGis::WKBNoGeometry ) 00752 { 00753 req.setFlags( QgsFeatureRequest::NoGeometry ); 00754 } 00755 req.setSubsetOfAttributes( allAttr ); 00756 QgsFeatureIterator fit = layer->getFeatures( req ); 00757 00758 const QgsFeatureIds& ids = layer->selectedFeaturesIds(); 00759 00760 // Create our transform 00761 if ( destCRS ) 00762 { 00763 ct = new QgsCoordinateTransform( layer->crs(), *destCRS ); 00764 } 00765 00766 // Check for failure 00767 if ( ct == NULL ) 00768 { 00769 shallTransform = false; 00770 } 00771 00772 //create symbol table if needed 00773 if ( writer->symbologyExport() != NoSymbology ) 00774 { 00775 //writer->createSymbolLayerTable( layer, writer->mDS ); 00776 } 00777 00778 if ( writer->symbologyExport() == SymbolLayerSymbology ) 00779 { 00780 QgsFeatureRendererV2* r = layer->rendererV2(); 00781 if ( r->capabilities() & QgsFeatureRendererV2::SymbolLevels 00782 && r->usingSymbolLevels() ) 00783 { 00784 QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( layer, fit, ct, errorMessage ); 00785 delete writer; 00786 delete ct; 00787 return ( error == NoError ) ? NoError : ErrFeatureWriteFailed; 00788 } 00789 } 00790 00791 int n = 0, errors = 0; 00792 00793 //unit type 00794 QGis::UnitType mapUnits = layer->crs().mapUnits(); 00795 if ( ct ) 00796 { 00797 mapUnits = ct->destCRS().mapUnits(); 00798 } 00799 00800 writer->startRender( layer ); 00801 00802 // write all features 00803 while ( fit.nextFeature( fet ) ) 00804 { 00805 if ( onlySelected && !ids.contains( fet.id() ) ) 00806 continue; 00807 00808 if ( shallTransform ) 00809 { 00810 try 00811 { 00812 if ( fet.geometry() ) 00813 { 00814 fet.geometry()->transform( *ct ); 00815 } 00816 } 00817 catch ( QgsCsException &e ) 00818 { 00819 delete ct; 00820 delete writer; 00821 00822 QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" ) 00823 .arg( fet.id() ).arg( e.what() ); 00824 QgsLogger::warning( msg ); 00825 if ( errorMessage ) 00826 *errorMessage = msg; 00827 00828 return ErrProjection; 00829 } 00830 } 00831 if ( allAttr.size() < 1 && skipAttributeCreation ) 00832 { 00833 fet.initAttributes( 0 ); 00834 } 00835 00836 if ( !writer->addFeature( fet, layer->rendererV2(), mapUnits ) ) 00837 { 00838 WriterError err = writer->hasError(); 00839 if ( err != NoError && errorMessage ) 00840 { 00841 if ( errorMessage->isEmpty() ) 00842 { 00843 *errorMessage = QObject::tr( "Feature write errors:" ); 00844 } 00845 *errorMessage += "\n" + writer->errorMessage(); 00846 } 00847 errors++; 00848 00849 if ( errors > 1000 ) 00850 { 00851 if ( errorMessage ) 00852 { 00853 *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors ); 00854 } 00855 00856 n = -1; 00857 break; 00858 } 00859 } 00860 n++; 00861 } 00862 00863 writer->stopRender( layer ); 00864 delete writer; 00865 00866 if ( shallTransform ) 00867 { 00868 delete ct; 00869 } 00870 00871 if ( errors > 0 && errorMessage && n > 0 ) 00872 { 00873 *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n ); 00874 } 00875 00876 return errors == 0 ? NoError : ErrFeatureWriteFailed; 00877 } 00878 00879 00880 bool QgsVectorFileWriter::deleteShapeFile( QString theFileName ) 00881 { 00882 QFileInfo fi( theFileName ); 00883 QDir dir = fi.dir(); 00884 00885 QStringList filter; 00886 const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" }; 00887 for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ ) 00888 { 00889 filter << fi.completeBaseName() + suffixes[i]; 00890 } 00891 00892 bool ok = true; 00893 foreach ( QString file, dir.entryList( filter ) ) 00894 { 00895 if ( !QFile::remove( dir.canonicalPath() + "/" + file ) ) 00896 { 00897 QgsDebugMsg( "Removing file failed : " + file ); 00898 ok = false; 00899 } 00900 } 00901 00902 return ok; 00903 } 00904 00905 QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats() 00906 { 00907 QMap<QString, QString> resultMap; 00908 00909 QgsApplication::registerOgrDrivers(); 00910 int const drvCount = OGRGetDriverCount(); 00911 00912 for ( int i = 0; i < drvCount; ++i ) 00913 { 00914 OGRSFDriverH drv = OGRGetDriver( i ); 00915 if ( drv ) 00916 { 00917 QString drvName = OGR_Dr_GetName( drv ); 00918 if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 ) 00919 { 00920 QString filterString = filterForDriver( drvName ); 00921 if ( filterString.isEmpty() ) 00922 continue; 00923 00924 resultMap.insert( filterString, drvName ); 00925 } 00926 } 00927 } 00928 00929 return resultMap; 00930 } 00931 00932 QMap<QString, QString> QgsVectorFileWriter::ogrDriverList() 00933 { 00934 QMap<QString, QString> resultMap; 00935 00936 QgsApplication::registerOgrDrivers(); 00937 int const drvCount = OGRGetDriverCount(); 00938 00939 QStringList writableDrivers; 00940 for ( int i = 0; i < drvCount; ++i ) 00941 { 00942 OGRSFDriverH drv = OGRGetDriver( i ); 00943 if ( drv ) 00944 { 00945 QString drvName = OGR_Dr_GetName( drv ); 00946 if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 ) 00947 { 00948 // Add separate format for Mapinfo MIF (MITAB is OGR default) 00949 if ( drvName == "MapInfo File" ) 00950 { 00951 writableDrivers << "MapInfo MIF"; 00952 } 00953 else if ( drvName == "SQLite" ) 00954 { 00955 // Unfortunately it seems that there is no simple way to detect if 00956 // OGR SQLite driver is compiled with SpatiaLite support. 00957 // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR 00958 // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html 00959 // -> test if creation failes 00960 QString option = "SPATIALITE=YES"; 00961 char **options = new char *[2]; 00962 options[0] = CPLStrdup( option.toLocal8Bit().data() ); 00963 options[1] = NULL; 00964 OGRSFDriverH poDriver; 00965 QgsApplication::registerOgrDrivers(); 00966 poDriver = OGRGetDriverByName( drvName.toLocal8Bit().data() ); 00967 if ( poDriver ) 00968 { 00969 OGRDataSourceH ds = OGR_Dr_CreateDataSource( poDriver, TO8( QString( "/vsimem/spatialitetest.sqlite" ) ), options ); 00970 if ( ds ) 00971 { 00972 writableDrivers << "SpatiaLite"; 00973 OGR_DS_Destroy( ds ); 00974 } 00975 } 00976 CPLFree( options[0] ); 00977 delete [] options; 00978 } 00979 writableDrivers << drvName; 00980 } 00981 } 00982 } 00983 00984 foreach ( QString drvName, writableDrivers ) 00985 { 00986 QString longName; 00987 QString trLongName; 00988 QString glob; 00989 QString exts; 00990 if ( QgsVectorFileWriter::driverMetadata( drvName, longName, trLongName, glob, exts ) && !trLongName.isEmpty() ) 00991 { 00992 resultMap.insert( trLongName, drvName ); 00993 } 00994 } 00995 00996 return resultMap; 00997 } 00998 00999 QString QgsVectorFileWriter::fileFilterString() 01000 { 01001 QString filterString; 01002 QMap< QString, QString> driverFormatMap = supportedFiltersAndFormats(); 01003 QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin(); 01004 for ( ; it != driverFormatMap.constEnd(); ++it ) 01005 { 01006 if ( filterString.isEmpty() ) 01007 filterString += ";;"; 01008 01009 filterString += it.key(); 01010 } 01011 return filterString; 01012 } 01013 01014 QString QgsVectorFileWriter::filterForDriver( const QString& driverName ) 01015 { 01016 QString longName; 01017 QString trLongName; 01018 QString glob; 01019 QString exts; 01020 if ( !driverMetadata( driverName, longName, trLongName, glob, exts ) || trLongName.isEmpty() || glob.isEmpty() ) 01021 return ""; 01022 01023 return trLongName + " [OGR] (" + glob.toLower() + " " + glob.toUpper() + ")"; 01024 } 01025 01026 QString QgsVectorFileWriter::convertCodecNameForEncodingOption( const QString &codecName ) 01027 { 01028 if ( codecName == "System" ) 01029 return QString( "LDID/0" ); 01030 01031 QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive ); 01032 if ( re.exactMatch( codecName ) ) 01033 { 01034 QString c = re.cap( 2 ).replace( "-" , "" ); 01035 bool isNumber; 01036 c.toInt( &isNumber ); 01037 if ( isNumber ) 01038 return c; 01039 } 01040 return codecName; 01041 } 01042 01043 bool QgsVectorFileWriter::driverMetadata( QString driverName, QString &longName, QString &trLongName, QString &glob, QString &ext ) 01044 { 01045 if ( driverName.startsWith( "AVCE00" ) ) 01046 { 01047 longName = "Arc/Info ASCII Coverage"; 01048 trLongName = QObject::tr( "Arc/Info ASCII Coverage" ); 01049 glob = "*.e00"; 01050 ext = "e00"; 01051 } 01052 else if ( driverName.startsWith( "BNA" ) ) 01053 { 01054 longName = "Atlas BNA"; 01055 trLongName = QObject::tr( "Atlas BNA" ); 01056 glob = "*.bna"; 01057 ext = "bna"; 01058 } 01059 else if ( driverName.startsWith( "CSV" ) ) 01060 { 01061 longName = "Comma Separated Value"; 01062 trLongName = QObject::tr( "Comma Separated Value" ); 01063 glob = "*.csv"; 01064 ext = "csv"; 01065 } 01066 else if ( driverName.startsWith( "ESRI" ) ) 01067 { 01068 longName = "ESRI Shapefile"; 01069 trLongName = QObject::tr( "ESRI Shapefile" ); 01070 glob = "*.shp"; 01071 ext = "shp"; 01072 } 01073 else if ( driverName.startsWith( "FMEObjects Gateway" ) ) 01074 { 01075 longName = "FMEObjects Gateway"; 01076 trLongName = QObject::tr( "FMEObjects Gateway" ); 01077 glob = "*.fdd"; 01078 ext = "fdd"; 01079 } 01080 else if ( driverName.startsWith( "GeoJSON" ) ) 01081 { 01082 longName = "GeoJSON"; 01083 trLongName = QObject::tr( "GeoJSON" ); 01084 glob = "*.geojson"; 01085 ext = "geojson"; 01086 } 01087 else if ( driverName.startsWith( "GeoRSS" ) ) 01088 { 01089 longName = "GeoRSS"; 01090 trLongName = QObject::tr( "GeoRSS" ); 01091 glob = "*.xml"; 01092 ext = "xml"; 01093 } 01094 else if ( driverName.startsWith( "GML" ) ) 01095 { 01096 longName = "Geography Markup Language [GML]"; 01097 trLongName = QObject::tr( "Geography Markup Language [GML]" ); 01098 glob = "*.gml"; 01099 ext = "gml"; 01100 } 01101 else if ( driverName.startsWith( "GMT" ) ) 01102 { 01103 longName = "Generic Mapping Tools [GMT]"; 01104 trLongName = QObject::tr( "Generic Mapping Tools [GMT]" ); 01105 glob = "*.gmt"; 01106 ext = "gmt"; 01107 } 01108 else if ( driverName.startsWith( "GPX" ) ) 01109 { 01110 longName = "GPS eXchange Format [GPX]"; 01111 trLongName = QObject::tr( "GPS eXchange Format [GPX]" ); 01112 glob = "*.gpx"; 01113 ext = "gpx"; 01114 } 01115 else if ( driverName.startsWith( "Interlis 1" ) ) 01116 { 01117 longName = "INTERLIS 1"; 01118 trLongName = QObject::tr( "INTERLIS 1" ); 01119 glob = "*.itf *.xml *.ili"; 01120 ext = "ili"; 01121 } 01122 else if ( driverName.startsWith( "Interlis 2" ) ) 01123 { 01124 longName = "INTERLIS 2"; 01125 trLongName = QObject::tr( "INTERLIS 2" ); 01126 glob = "*.itf *.xml *.ili"; 01127 ext = "ili"; 01128 } 01129 else if ( driverName.startsWith( "KML" ) ) 01130 { 01131 longName = "Keyhole Markup Language [KML]"; 01132 trLongName = QObject::tr( "Keyhole Markup Language [KML]" ); 01133 glob = "*.kml" ; 01134 ext = "kml" ; 01135 } 01136 else if ( driverName.startsWith( "MapInfo File" ) ) 01137 { 01138 longName = "Mapinfo TAB"; 01139 trLongName = QObject::tr( "Mapinfo TAB" ); 01140 glob = "*.tab"; 01141 ext = "tab"; 01142 } 01143 // 'MapInfo MIF' is internal QGIS addition to distinguish between MITAB and MIF 01144 else if ( driverName.startsWith( "MapInfo MIF" ) ) 01145 { 01146 longName = "Mapinfo MIF"; 01147 trLongName = QObject::tr( "Mapinfo MIF" ); 01148 glob = "*.mif"; 01149 ext = "mif"; 01150 } 01151 else if ( driverName.startsWith( "DGN" ) ) 01152 { 01153 longName = "Microstation DGN"; 01154 trLongName = QObject::tr( "Microstation DGN" ); 01155 glob = "*.dgn"; 01156 ext = "dgn"; 01157 } 01158 else if ( driverName.startsWith( "S57" ) ) 01159 { 01160 longName = "S-57 Base file"; 01161 trLongName = QObject::tr( "S-57 Base file" ); 01162 glob = "*.000"; 01163 ext = "000"; 01164 } 01165 else if ( driverName.startsWith( "SDTS" ) ) 01166 { 01167 longName = "Spatial Data Transfer Standard [SDTS]"; 01168 trLongName = QObject::tr( "Spatial Data Transfer Standard [SDTS]" ); 01169 glob = "*catd.ddf"; 01170 ext = "ddf"; 01171 } 01172 else if ( driverName.startsWith( "SQLite" ) ) 01173 { 01174 longName = "SQLite"; 01175 trLongName = QObject::tr( "SQLite" ); 01176 glob = "*.sqlite"; 01177 ext = "sqlite"; 01178 } 01179 // QGIS internal addition for SpatialLite 01180 else if ( driverName.startsWith( "SpatiaLite" ) ) 01181 { 01182 longName = "SpatiaLite"; 01183 trLongName = QObject::tr( "SpatiaLite" ); 01184 glob = "*.sqlite"; 01185 ext = "sqlite"; 01186 } 01187 else if ( driverName.startsWith( "DXF" ) ) 01188 { 01189 longName = "AutoCAD DXF"; 01190 trLongName = QObject::tr( "AutoCAD DXF" ); 01191 glob = "*.dxf"; 01192 ext = "dxf"; 01193 } 01194 else if ( driverName.startsWith( "Geoconcept" ) ) 01195 { 01196 longName = "Geoconcept"; 01197 trLongName = QObject::tr( "Geoconcept" ); 01198 glob = "*.gxt *.txt"; 01199 ext = "gxt"; 01200 } 01201 else if ( driverName.startsWith( "FileGDB" ) ) 01202 { 01203 longName = "ESRI FileGDB"; 01204 trLongName = QObject::tr( "ESRI FileGDB" ); 01205 glob = "*.gdb"; 01206 ext = "gdb"; 01207 } 01208 else 01209 { 01210 return false; 01211 } 01212 01213 return true; 01214 } 01215 01216 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer* vl, const QgsCoordinateTransform* ct, OGRDataSourceH ds ) 01217 { 01218 if ( !vl || !ds ) 01219 { 01220 return; 01221 } 01222 01223 QgsFeatureRendererV2* renderer = vl->rendererV2(); 01224 if ( !renderer ) 01225 { 01226 return; 01227 } 01228 01229 //unit type 01230 QGis::UnitType mapUnits = vl->crs().mapUnits(); 01231 if ( ct ) 01232 { 01233 mapUnits = ct->destCRS().mapUnits(); 01234 } 01235 01236 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1700 01237 mSymbolLayerTable.clear(); 01238 OGRStyleTableH ogrStyleTable = OGR_STBL_Create(); 01239 OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable ); 01240 01241 //get symbols 01242 int nTotalLevels = 0; 01243 QgsSymbolV2List symbolList = renderer->symbols(); 01244 QgsSymbolV2List::iterator symbolIt = symbolList.begin(); 01245 for ( ; symbolIt != symbolList.end(); ++symbolIt ) 01246 { 01247 double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits ); 01248 double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits ); 01249 01250 int nLevels = ( *symbolIt )->symbolLayerCount(); 01251 for ( int i = 0; i < nLevels; ++i ) 01252 { 01253 mSymbolLayerTable.insert(( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) ); 01254 OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(), 01255 ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() ); 01256 ++nTotalLevels; 01257 } 01258 } 01259 OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable ); 01260 #endif 01261 } 01262 01263 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( QgsVectorLayer* layer, QgsFeatureIterator& fit, 01264 const QgsCoordinateTransform* ct, QString* errorMessage ) 01265 { 01266 if ( !layer ) 01267 { 01268 //return error 01269 } 01270 QgsFeatureRendererV2* renderer = layer->rendererV2(); 01271 if ( !renderer ) 01272 { 01273 //return error 01274 } 01275 QHash< QgsSymbolV2*, QList<QgsFeature> > features; 01276 01277 //unit type 01278 QGis::UnitType mapUnits = layer->crs().mapUnits(); 01279 if ( ct ) 01280 { 01281 mapUnits = ct->destCRS().mapUnits(); 01282 } 01283 01284 startRender( layer ); 01285 01286 //fetch features 01287 QgsFeature fet; 01288 QgsSymbolV2* featureSymbol = 0; 01289 while ( fit.nextFeature( fet ) ) 01290 { 01291 if ( ct ) 01292 { 01293 try 01294 { 01295 if ( fet.geometry() ) 01296 { 01297 fet.geometry()->transform( *ct ); 01298 } 01299 } 01300 catch ( QgsCsException &e ) 01301 { 01302 delete ct; 01303 01304 QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" ) 01305 .arg( e.what() ); 01306 QgsLogger::warning( msg ); 01307 if ( errorMessage ) 01308 *errorMessage = msg; 01309 01310 return ErrProjection; 01311 } 01312 } 01313 01314 featureSymbol = renderer->symbolForFeature( fet ); 01315 if ( !featureSymbol ) 01316 { 01317 continue; 01318 } 01319 01320 QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator it = features.find( featureSymbol ); 01321 if ( it == features.end() ) 01322 { 01323 it = features.insert( featureSymbol, QList<QgsFeature>() ); 01324 } 01325 it.value().append( fet ); 01326 } 01327 01328 //find out order 01329 QgsSymbolV2LevelOrder levels; 01330 QgsSymbolV2List symbols = renderer->symbols(); 01331 for ( int i = 0; i < symbols.count(); i++ ) 01332 { 01333 QgsSymbolV2* sym = symbols[i]; 01334 for ( int j = 0; j < sym->symbolLayerCount(); j++ ) 01335 { 01336 int level = sym->symbolLayer( j )->renderingPass(); 01337 if ( level < 0 || level >= 1000 ) // ignore invalid levels 01338 continue; 01339 QgsSymbolV2LevelItem item( sym, j ); 01340 while ( level >= levels.count() ) // append new empty levels 01341 levels.append( QgsSymbolV2Level() ); 01342 levels[level].append( item ); 01343 } 01344 } 01345 01346 int nErrors = 0; 01347 int nTotalFeatures = 0; 01348 01349 //export symbol layers and symbology 01350 for ( int l = 0; l < levels.count(); l++ ) 01351 { 01352 QgsSymbolV2Level& level = levels[l]; 01353 for ( int i = 0; i < level.count(); i++ ) 01354 { 01355 QgsSymbolV2LevelItem& item = level[i]; 01356 QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() ); 01357 if ( levelIt == features.end() ) 01358 { 01359 ++nErrors; 01360 continue; 01361 } 01362 01363 double mmsf = mmScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits ); 01364 double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits ); 01365 01366 int llayer = item.layer(); 01367 QList<QgsFeature>& featureList = levelIt.value(); 01368 QList<QgsFeature>::iterator featureIt = featureList.begin(); 01369 for ( ; featureIt != featureList.end(); ++featureIt ) 01370 { 01371 ++nTotalFeatures; 01372 OGRFeatureH ogrFeature = createFeature( *featureIt ); 01373 if ( !ogrFeature ) 01374 { 01375 ++nErrors; 01376 continue; 01377 } 01378 01379 QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf ); 01380 if ( !styleString.isEmpty() ) 01381 { 01382 OGR_F_SetStyleString( ogrFeature, styleString.toLocal8Bit().data() ); 01383 if ( ! writeFeature( mLayer, ogrFeature ) ) 01384 { 01385 ++nErrors; 01386 } 01387 } 01388 OGR_F_Destroy( ogrFeature ); 01389 } 01390 } 01391 } 01392 01393 stopRender( layer ); 01394 01395 if ( nErrors > 0 && errorMessage ) 01396 { 01397 *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures ); 01398 } 01399 01400 return ( nErrors > 0 ) ? QgsVectorFileWriter::ErrFeatureWriteFailed : QgsVectorFileWriter::NoError; 01401 } 01402 01403 double QgsVectorFileWriter::mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits ) 01404 { 01405 if ( symbolUnits == QgsSymbolV2::MM ) 01406 { 01407 return 1.0; 01408 } 01409 else 01410 { 01411 //conversion factor map units -> mm 01412 if ( mapUnits == QGis::Meters ) 01413 { 01414 return 1000 / scaleDenominator; 01415 } 01416 01417 } 01418 return 1.0; //todo: map units 01419 } 01420 01421 double QgsVectorFileWriter::mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits ) 01422 { 01423 if ( symbolUnits == QgsSymbolV2::MapUnit ) 01424 { 01425 return 1.0; 01426 } 01427 else 01428 { 01429 if ( symbolUnits == QgsSymbolV2::MM && mapUnits == QGis::Meters ) 01430 { 01431 return scaleDenominator / 1000; 01432 } 01433 } 01434 return 1.0; 01435 } 01436 01437 QgsRenderContext QgsVectorFileWriter::renderContext() const 01438 { 01439 QgsRenderContext context; 01440 context.setRendererScale( mSymbologyScaleDenominator ); 01441 return context; 01442 } 01443 01444 void QgsVectorFileWriter::startRender( QgsVectorLayer* vl ) const 01445 { 01446 QgsFeatureRendererV2* renderer = symbologyRenderer( vl ); 01447 if ( !renderer ) 01448 { 01449 return; 01450 } 01451 01452 QgsRenderContext ctx = renderContext(); 01453 renderer->startRender( ctx, vl ); 01454 } 01455 01456 void QgsVectorFileWriter::stopRender( QgsVectorLayer* vl ) const 01457 { 01458 QgsFeatureRendererV2* renderer = symbologyRenderer( vl ); 01459 if ( !renderer ) 01460 { 01461 return; 01462 } 01463 01464 QgsRenderContext ctx = renderContext(); 01465 renderer->stopRender( ctx ); 01466 } 01467 01468 QgsFeatureRendererV2* QgsVectorFileWriter::symbologyRenderer( QgsVectorLayer* vl ) const 01469 { 01470 if ( mSymbologyExport == NoSymbology ) 01471 { 01472 return 0; 01473 } 01474 if ( !vl ) 01475 { 01476 return 0; 01477 } 01478 01479 return vl->rendererV2(); 01480 } 01481 01482 void QgsVectorFileWriter::addRendererAttributes( QgsVectorLayer* vl, QgsAttributeList& attList ) 01483 { 01484 QgsFeatureRendererV2* renderer = symbologyRenderer( vl ); 01485 if ( renderer ) 01486 { 01487 QList<QString> rendererAttributes = renderer->usedAttributes(); 01488 for ( int i = 0; i < rendererAttributes.size(); ++i ) 01489 { 01490 int index = vl->fieldNameIndex( rendererAttributes.at( i ) ); 01491 if ( index != -1 ) 01492 { 01493 attList.push_back( vl->fieldNameIndex( rendererAttributes.at( i ) ) ); 01494 } 01495 } 01496 } 01497 }