Skip to content

Commit d14a5e6

Browse files
author
mhugent
committedMar 18, 2010
Apply patch #2452 (save as vector)
git-svn-id: http://svn.osgeo.org/qgis/trunk@13072 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 116dfc8 commit d14a5e6

File tree

5 files changed

+391
-12
lines changed

5 files changed

+391
-12
lines changed
 

‎python/core/qgsvectorfilewriter.sip

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,32 @@ public:
3131
const QgsCoordinateReferenceSystem*,
3232
bool onlySelected = FALSE);
3333

34+
/** Write contents of vector layer to an (OGR supported) vector formt
35+
@note: this method was added in version 1.5*/
36+
static WriterError writeAsVectorFormat( QgsVectorLayer* layer,
37+
const QString& fileName,
38+
const QString& fileEncoding,
39+
const QgsCoordinateReferenceSystem *destCRS,
40+
const QString& driverName = "ESRI Shapefile",
41+
bool onlySelected = FALSE,
42+
QString *errorMessage = 0 );
43+
3444
/** create shapefile and initialize it */
35-
QgsVectorFileWriter(const QString& shapefileName,
45+
QgsVectorFileWriter(const QString& vectorFileName,
3646
const QString& fileEncoding,
3747
const QMap<int, QgsField>& fields,
3848
QGis::WkbType geometryType,
3949
const QgsCoordinateReferenceSystem* srs,
4050
const QString& driverName = "ESRI Shapefile" );
51+
52+
/**Returns map with format filter string as key and OGR format key as value*/
53+
static QMap< QString, QString> supportedFiltersAndFormats();
54+
55+
/**Returns filter string that can be used for dialogs*/
56+
static QString fileFilterString();
57+
58+
/**Creates a filter for an OGR driver key*/
59+
static QString filterForDriver( const QString& driverName );
4160

4261
/** checks whether there were any errors in constructor */
4362
WriterError hasError();

‎src/app/legend/qgslegendlayer.cpp

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -423,14 +423,14 @@ void QgsLegendLayer::addToPopupMenu( QMenu& theMenu, QAction* toggleEditingActio
423423
}
424424
}
425425

426-
// save as shapefile
427-
theMenu.addAction( tr( "Save as shapefile..." ), this, SLOT( saveAsShapefile() ) );
426+
// save as vector file
427+
theMenu.addAction( tr( "Save as..." ), this, SLOT( saveAsVectorFile() ) );
428428

429-
// save selection as shapefile
430-
QAction* saveSelectionAction = theMenu.addAction( tr( "Save selection as shapefile..." ), this, SLOT( saveSelectionAsShapefile() ) );
429+
// save selection as vector file
430+
QAction* saveSelectionAsAction = theMenu.addAction( tr( "Save selection as..." ), this, SLOT( saveSelectionAsVectorFile() ) );
431431
if ( vlayer->selectedFeatureCount() == 0 )
432432
{
433-
saveSelectionAction->setEnabled( false );
433+
saveSelectionAsAction->setEnabled( false );
434434
}
435435

436436
theMenu.addSeparator();
@@ -460,6 +460,16 @@ void QgsLegendLayer::saveSelectionAsShapefile()
460460
saveAsShapefileGeneral( TRUE );
461461
}
462462

463+
void QgsLegendLayer::saveAsVectorFile()
464+
{
465+
saveAsVectorFileGeneral( false );
466+
}
467+
468+
void QgsLegendLayer::saveSelectionAsVectorFile()
469+
{
470+
saveAsVectorFileGeneral( true );
471+
}
472+
463473
//////////
464474

465475
void QgsLegendLayer::setVisible( bool visible )
@@ -492,7 +502,81 @@ void QgsLegendLayer::showInOverview()
492502
legend()->updateOverview();
493503
}
494504

505+
void QgsLegendLayer::saveAsVectorFileGeneral( bool saveOnlySelection )
506+
{
507+
if ( mLyr.layer()->type() != QgsMapLayer::VectorLayer )
508+
return;
509+
510+
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( mLyr.layer() );
495511

512+
//get output name and format
513+
QSettings settings;
514+
QString filter = QString( "Shapefiles (*.shp)" );
515+
QString dirName = settings.value( "/UI/lastVectorfileDir", "." ).toString();
516+
QString filterString = QgsVectorFileWriter::fileFilterString();
517+
QString selectedFilter = settings.value( "/UI/lastVectorFilter", "[OGR] ESRI Shapefiles (*.shp *.SHP)" ).toString();
518+
QString outputFile = QFileDialog::getSaveFileName( 0, tr( "Save layer as..." ), dirName, filterString, &selectedFilter );
519+
if ( outputFile.isNull() )
520+
{
521+
return; //cancelled
522+
}
523+
524+
settings.setValue( "/UI/lastVectorfileDir", QFileInfo( outputFile ).absolutePath() );
525+
settings.setValue( "/UI/lastVectorFilter", selectedFilter );
526+
527+
QMap< QString, QString> filterDriverMap = QgsVectorFileWriter::supportedFiltersAndFormats();
528+
QMap< QString, QString>::const_iterator it = filterDriverMap.find( selectedFilter + ";;" );
529+
if ( it == filterDriverMap.constEnd() )
530+
{
531+
return; //unknown format
532+
}
533+
534+
QString driverKey = *it;
535+
536+
//output CRS
537+
QgsCoordinateReferenceSystem destCRS = vlayer->srs();
538+
// Find out if we have projections enabled or not
539+
if ( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() )
540+
{
541+
destCRS = QgisApp::instance()->mapCanvas()->mapRenderer()->destinationSrs();
542+
}
543+
544+
QgsGenericProjectionSelector * mySelector = new QgsGenericProjectionSelector();
545+
mySelector->setSelectedCrsId( destCRS.srsid() );
546+
mySelector->setMessage( tr( "Select the coordinate reference system for the saved shapefile. "
547+
"The data points will be transformed from the layer coordinate reference system." ) );
548+
549+
if ( mySelector->exec() )
550+
{
551+
QgsCoordinateReferenceSystem srs( mySelector->selectedCrsId(), QgsCoordinateReferenceSystem::InternalCrsId );
552+
destCRS = srs;
553+
// destCRS->createFromId(mySelector->selectedCrsId(), QgsCoordinateReferenceSystem::InternalCrsId)
554+
}
555+
else
556+
{
557+
// Aborted CS selection, don't save.
558+
delete mySelector;
559+
return;
560+
}
561+
delete mySelector;
562+
563+
// overwrite the file - user will already have been prompted
564+
// to verify they want to overwrite by the file dialog above
565+
// might not even exists in the given case.
566+
if ( driverKey == "ESRI Shapefile" )
567+
{
568+
// add the extension if not present
569+
if ( !outputFile.endsWith( ".shp", Qt::CaseInsensitive ) )
570+
{
571+
outputFile += ".shp";
572+
}
573+
QgsVectorFileWriter::deleteShapeFile( outputFile );
574+
}
575+
576+
QString errorMessage;
577+
QgsVectorFileWriter::WriterError error;
578+
error = QgsVectorFileWriter::writeAsVectorFormat( vlayer, outputFile, "utf-8", &destCRS, driverKey, saveOnlySelection, &errorMessage );
579+
}
496580

497581

498582
void QgsLegendLayer::saveAsShapefileGeneral( bool saveOnlySelection )

‎src/app/legend/qgslegendlayer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ class QgsLegendLayer : public QgsLegendItem
8787
void saveAsShapefile();
8888
void saveSelectionAsShapefile();
8989

90+
void saveAsVectorFile();
91+
void saveSelectionAsVectorFile();
92+
9093
/**update the layer's icon to show whether is in editing mode or in overview */
9194
void updateIcon();
9295

@@ -111,6 +114,8 @@ class QgsLegendLayer : public QgsLegendItem
111114
/**Save as shapefile (called from saveAsShapefile and saveSelectionAsShapefile)*/
112115
void saveAsShapefileGeneral( bool saveOnlySelection );
113116

117+
void saveAsVectorFileGeneral( bool saveOnlySelection );
118+
114119
private:
115120
/** Helper method to make the font bold from all ctors.
116121
* Not to be confused with setFont() which is inherited

‎src/core/qgsvectorfilewriter.cpp

Lines changed: 255 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
#include <cpl_error.h>
4242

4343

44-
QgsVectorFileWriter::QgsVectorFileWriter( const QString& shapefileName,
44+
QgsVectorFileWriter::QgsVectorFileWriter( const QString& vectorFileName,
4545
const QString& fileEncoding,
4646
const QgsFieldMap& fields,
4747
QGis::WkbType geometryType,
@@ -85,7 +85,7 @@ QgsVectorFileWriter::QgsVectorFileWriter( const QString& shapefileName,
8585
}
8686

8787
// create the data source
88-
mDS = OGR_Dr_CreateDataSource( poDriver, shapefileName.toLocal8Bit().data(), NULL );
88+
mDS = OGR_Dr_CreateDataSource( poDriver, vectorFileName.toLocal8Bit().data(), NULL );
8989
if ( mDS == NULL )
9090
{
9191
mError = ErrCreateDataSource;
@@ -121,7 +121,7 @@ QgsVectorFileWriter::QgsVectorFileWriter( const QString& shapefileName,
121121
}
122122

123123
// datasource created, now create the output layer
124-
QString layerName = shapefileName.left( shapefileName.indexOf( ".shp", Qt::CaseInsensitive ) );
124+
QString layerName = QFileInfo( vectorFileName ).baseName();
125125
OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>( geometryType );
126126
mLayer = OGR_DS_CreateLayer( mDS, QFile::encodeName( layerName ).data(), ogrRef, wkbType, NULL );
127127

@@ -386,7 +386,8 @@ QgsVectorFileWriter::writeAsShapefile( QgsVectorLayer* layer,
386386
bool onlySelected,
387387
QString *errorMessage )
388388
{
389-
389+
return writeAsVectorFormat( layer, shapefileName, fileEncoding, destCRS, "ESRI Shapefile", onlySelected, errorMessage );
390+
#if 0
390391
const QgsCoordinateReferenceSystem* outputCRS;
391392
QgsCoordinateTransform* ct = 0;
392393
int shallTransform = false;
@@ -470,6 +471,102 @@ QgsVectorFileWriter::writeAsShapefile( QgsVectorLayer* layer,
470471
delete ct;
471472
}
472473

474+
return NoError;
475+
#endif //0
476+
}
477+
478+
QgsVectorFileWriter::WriterError
479+
QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
480+
const QString& fileName,
481+
const QString& fileEncoding,
482+
const QgsCoordinateReferenceSystem *destCRS,
483+
const QString& driverName,
484+
bool onlySelected,
485+
QString *errorMessage )
486+
{
487+
const QgsCoordinateReferenceSystem* outputCRS;
488+
QgsCoordinateTransform* ct = 0;
489+
int shallTransform = false;
490+
491+
if ( destCRS && destCRS->isValid() )
492+
{
493+
// This means we should transform
494+
outputCRS = destCRS;
495+
shallTransform = true;
496+
}
497+
else
498+
{
499+
// This means we shouldn't transform, use source CRS as output (if defined)
500+
outputCRS = &layer->srs();
501+
}
502+
QgsVectorFileWriter* writer =
503+
new QgsVectorFileWriter( fileName, fileEncoding, layer->pendingFields(), layer->wkbType(), outputCRS, driverName );
504+
505+
// check whether file creation was successful
506+
WriterError err = writer->hasError();
507+
if ( err != NoError )
508+
{
509+
if ( errorMessage )
510+
*errorMessage = writer->errorMessage();
511+
delete writer;
512+
return err;
513+
}
514+
515+
QgsAttributeList allAttr = layer->pendingAllAttributesList();
516+
QgsFeature fet;
517+
518+
layer->select( allAttr, QgsRectangle(), true );
519+
520+
const QgsFeatureIds& ids = layer->selectedFeaturesIds();
521+
522+
// Create our transform
523+
if ( destCRS )
524+
{
525+
ct = new QgsCoordinateTransform( layer->srs(), *destCRS );
526+
}
527+
528+
// Check for failure
529+
if ( ct == NULL )
530+
{
531+
shallTransform = false;
532+
}
533+
534+
// write all features
535+
while ( layer->nextFeature( fet ) )
536+
{
537+
if ( onlySelected && !ids.contains( fet.id() ) )
538+
continue;
539+
540+
if ( shallTransform )
541+
{
542+
try
543+
{
544+
fet.geometry()->transform( *ct );
545+
}
546+
catch ( QgsCsException &e )
547+
{
548+
delete ct;
549+
delete writer;
550+
551+
QString msg = QObject::tr( "Failed to transform a point while drawing a feature of type '%1'. Writing stopped. (Exception: %2)" )
552+
.arg( fet.typeName() ).arg( e.what() );
553+
QgsLogger::warning( msg );
554+
if ( errorMessage )
555+
*errorMessage = msg;
556+
557+
return ErrProjection;
558+
}
559+
}
560+
writer->addFeature( fet );
561+
}
562+
563+
delete writer;
564+
565+
if ( shallTransform )
566+
{
567+
delete ct;
568+
}
569+
473570
return NoError;
474571
}
475572

@@ -498,3 +595,157 @@ bool QgsVectorFileWriter::deleteShapeFile( QString theFileName )
498595

499596
return ok;
500597
}
598+
599+
QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats()
600+
{
601+
QMap<QString, QString> resultMap;
602+
603+
QgsApplication::registerOgrDrivers();
604+
int const drvCount = OGRGetDriverCount();
605+
606+
QString drvName;
607+
QString filterString;
608+
for ( int i = 0; i < drvCount; ++i )
609+
{
610+
OGRSFDriverH drv = OGRGetDriver( i );
611+
if ( drv )
612+
{
613+
drvName = OGR_Dr_GetName( drv );
614+
if ( OGR_Dr_TestCapability( drv, ODrCCreateDataSource ) != 0 )
615+
{
616+
//add driver name and filter to map
617+
filterString = QgsVectorFileWriter::filterForDriver( drvName );
618+
if ( !filterString.isEmpty() )
619+
{
620+
resultMap.insert( filterString, drvName );
621+
}
622+
}
623+
}
624+
}
625+
626+
return resultMap;
627+
}
628+
629+
QString QgsVectorFileWriter::fileFilterString()
630+
{
631+
QString filterString;
632+
QMap< QString, QString> driverFormatMap = QgsVectorFileWriter::supportedFiltersAndFormats();
633+
QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin();
634+
for ( ; it != driverFormatMap.constEnd(); ++it )
635+
{
636+
filterString += it.key();
637+
}
638+
return filterString;
639+
}
640+
641+
QString QgsVectorFileWriter::filterForDriver( const QString& driverName )
642+
{
643+
QString longName;
644+
QString glob;
645+
646+
if ( driverName.startsWith( "AVCE00" ) )
647+
{
648+
longName = "Arc/Info ASCII Coverage";
649+
glob = "*.e00";
650+
}
651+
else if ( driverName.startsWith( "BNA" ) )
652+
{
653+
longName = "Atlas BNA";
654+
glob = "*.bna";
655+
}
656+
else if ( driverName.startsWith( "CSV" ) )
657+
{
658+
longName = "Comma Separated Value";
659+
glob = "*.csv";
660+
}
661+
else if ( driverName.startsWith( "ESRI" ) )
662+
{
663+
longName = "ESRI Shapefiles";
664+
glob = "*.shp";
665+
}
666+
else if ( driverName.startsWith( "FMEObjects Gateway" ) )
667+
{
668+
longName = "FMEObjects Gateway";
669+
glob = "*.fdd";
670+
}
671+
else if ( driverName.startsWith( "GeoJSON" ) )
672+
{
673+
longName = "GeoJSON";
674+
glob = "*.geojson";
675+
}
676+
else if ( driverName.startsWith( "GeoRSS" ) )
677+
{
678+
longName = "GeoRSS";
679+
glob = "*.xml";
680+
}
681+
else if ( driverName.startsWith( "GML" ) )
682+
{
683+
longName = "Geography Markup Language";
684+
glob = "*.gml";
685+
}
686+
else if ( driverName.startsWith( "GMT" ) )
687+
{
688+
longName = "GMT";
689+
glob = "*.gmt";
690+
}
691+
else if ( driverName.startsWith( "GPX" ) )
692+
{
693+
longName = "GPX";
694+
glob = "*.gpx";
695+
}
696+
else if ( driverName.startsWith( "Interlis 1" ) )
697+
{
698+
longName = "INTERLIS 1";
699+
glob = "*.itf *.xml *.ili";
700+
}
701+
else if ( driverName.startsWith( "Interlis 2" ) )
702+
{
703+
longName = "INTERLIS 2";
704+
glob = "*.itf *.xml *.ili";
705+
}
706+
else if ( driverName.startsWith( "KML" ) )
707+
{
708+
longName = "KML";
709+
glob = "*.kml" ;
710+
}
711+
else if ( driverName.startsWith( "MapInfo File" ) )
712+
{
713+
longName = "Mapinfo File";
714+
glob = "*.mif *.tab";
715+
}
716+
else if ( driverName.startsWith( "DGN" ) )
717+
{
718+
longName = "Microstation DGN";
719+
glob = "*.dgn";
720+
}
721+
else if ( driverName.startsWith( "S57" ) )
722+
{
723+
longName = "S-57 Base file";
724+
glob = "*.000";
725+
}
726+
else if ( driverName.startsWith( "SDTS" ) )
727+
{
728+
longName = "Spatial Data Transfer Standard";
729+
glob = "*catd.ddf";
730+
}
731+
else if ( driverName.startsWith( "SQLite" ) )
732+
{
733+
longName = "SQLite";
734+
glob = "*.sqlite";
735+
}
736+
else if ( driverName.startsWith( "VRT" ) )
737+
{
738+
longName = "VRT - Virtual Datasource ";
739+
glob = "*.vrt";
740+
}
741+
else if ( driverName.startsWith( "XPlane" ) )
742+
{
743+
longName = "X-Plane/Flighgear";
744+
glob = "apt.dat nav.dat fix.dat awy.dat";
745+
}
746+
else
747+
{
748+
return QString();
749+
}
750+
return "[OGR] " + longName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
751+
}

‎src/core/qgsvectorfilewriter.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,42 @@ class CORE_EXPORT QgsVectorFileWriter
5353
ErrProjection // added in 1.5
5454
};
5555

56-
/** Write contents of vector layer to a shapefile */
56+
/** Write contents of vector layer to a shapefile
57+
@note: deprecated. Use writeAsVectorFormat instead*/
5758
static WriterError writeAsShapefile( QgsVectorLayer* layer,
5859
const QString& shapefileName,
5960
const QString& fileEncoding,
6061
const QgsCoordinateReferenceSystem *destCRS,
6162
bool onlySelected = FALSE,
6263
QString *errorMessage = 0 );
6364

65+
/** Write contents of vector layer to an (OGR supported) vector formt
66+
@note: this method was added in version 1.5*/
67+
static WriterError writeAsVectorFormat( QgsVectorLayer* layer,
68+
const QString& fileName,
69+
const QString& fileEncoding,
70+
const QgsCoordinateReferenceSystem *destCRS,
71+
const QString& driverName = "ESRI Shapefile",
72+
bool onlySelected = FALSE,
73+
QString *errorMessage = 0 );
74+
6475
/** create shapefile and initialize it */
65-
QgsVectorFileWriter( const QString& shapefileName,
76+
QgsVectorFileWriter( const QString& vectorFileName,
6677
const QString& fileEncoding,
6778
const QgsFieldMap& fields,
6879
QGis::WkbType geometryType,
6980
const QgsCoordinateReferenceSystem* srs,
7081
const QString& driverName = "ESRI Shapefile" );
7182

83+
/**Returns map with format filter string as key and OGR format key as value*/
84+
static QMap< QString, QString> supportedFiltersAndFormats();
85+
86+
/**Returns filter string that can be used for dialogs*/
87+
static QString fileFilterString();
88+
89+
/**Creates a filter for an OGR driver key*/
90+
static QString filterForDriver( const QString& driverName );
91+
7292
/** checks whether there were any errors in constructor */
7393
WriterError hasError();
7494

0 commit comments

Comments
 (0)
Please sign in to comment.