QGIS API Documentation  2.14.0-Essen
qgsvectorlayerimport.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerimport.cpp
3  vector layer importer
4  -------------------
5  begin : Thu Aug 25 2011
6  copyright : (C) 2011 by Giuseppe Sucameli
7  email : brush.tyler at gmail.com
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "qgsfield.h"
20 #include "qgsfeature.h"
21 #include "qgsgeometry.h"
22 #include "qgslogger.h"
23 #include "qgsmessagelog.h"
25 #include "qgsvectorlayerimport.h"
26 #include "qgsproviderregistry.h"
27 #include "qgsdatasourceuri.h"
28 
29 #include <QProgressDialog>
30 
31 #define FEATURE_BUFFER_SIZE 200
32 
34  const QString &uri,
35  const QgsFields &fields,
36  QGis::WkbType geometryType,
37  const QgsCoordinateReferenceSystem *destCRS,
38  bool overwrite,
39  QMap<int, int> *oldToNewAttrIdx,
40  QString *errorMessage,
41  const QMap<QString, QVariant> *options
42 );
43 
44 
46  const QString &providerKey,
47  const QgsFields& fields,
48  QGis::WkbType geometryType,
50  bool overwrite,
51  const QMap<QString, QVariant> *options,
52  QProgressDialog *progress )
53  : mErrorCount( 0 )
54  , mAttributeCount( -1 )
55  , mProgress( progress )
56 
57 {
58  mProvider = nullptr;
59 
61 
62  QLibrary *myLib = pReg->providerLibrary( providerKey );
63  if ( !myLib )
64  {
66  mErrorMessage = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
67  return;
68  }
69 
70  createEmptyLayer_t * pCreateEmpty = reinterpret_cast< createEmptyLayer_t * >( cast_to_fptr( myLib->resolve( "createEmptyLayer" ) ) );
71  if ( !pCreateEmpty )
72  {
73  delete myLib;
75  mErrorMessage = QObject::tr( "Provider %1 has no %2 method" ).arg( providerKey, "createEmptyLayer" );
76  return;
77  }
78 
79  delete myLib;
80 
81  // create an empty layer
82  QString errMsg;
83  mError = pCreateEmpty( uri, fields, geometryType, crs, overwrite, &mOldToNewAttrIdx, &errMsg, options );
84  if ( hasError() )
85  {
86  mErrorMessage = errMsg;
87  return;
88  }
89 
90  Q_FOREACH ( int idx, mOldToNewAttrIdx )
91  {
92  if ( idx > mAttributeCount )
93  mAttributeCount = idx;
94  }
95 
97 
98  QgsDebugMsg( "Created empty layer" );
99 
100  QgsVectorDataProvider *vectorProvider = dynamic_cast< QgsVectorDataProvider* >( pReg->provider( providerKey, uri ) );
101  if ( !vectorProvider || !vectorProvider->isValid() || ( vectorProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) == 0 )
102  {
104  mErrorMessage = QObject::tr( "Loading of layer failed" );
105 
106  if ( vectorProvider )
107  delete vectorProvider;
108 
109  return;
110  }
111 
112  mProvider = vectorProvider;
113  mError = NoError;
114 }
115 
117 {
118  flushBuffer();
119 
120  if ( mProvider )
121  delete mProvider;
122 }
123 
125 {
126  return mError;
127 }
128 
130 {
131  return mErrorMessage;
132 }
133 
135 {
136  QgsAttributes attrs = feat.attributes();
137 
138  QgsFeature newFeat;
139  if ( feat.constGeometry() )
140  newFeat.setGeometry( *feat.constGeometry() );
141 
142  newFeat.initAttributes( mAttributeCount );
143 
144  for ( int i = 0; i < attrs.count(); ++i )
145  {
146  // add only mapped attributes (un-mapped ones will not be present in the
147  // destination layer)
148  int dstIdx = mOldToNewAttrIdx.value( i, -1 );
149  if ( dstIdx < 0 )
150  continue;
151 
152  QgsDebugMsgLevel( QString( "moving field from pos %1 to %2" ).arg( i ).arg( dstIdx ), 3 );
153  newFeat.setAttribute( dstIdx, attrs.at( i ) );
154  }
155 
156  mFeatureBuffer.append( newFeat );
157 
159  {
160  return flushBuffer();
161  }
162 
163  return true;
164 }
165 
167 {
168  if ( mFeatureBuffer.count() <= 0 )
169  return true;
170 
172  {
173  QStringList errors = mProvider->errors();
175 
176  mErrorMessage = QObject::tr( "Creation error for features from #%1 to #%2. Provider errors was: \n%3" )
177  .arg( mFeatureBuffer.first().id() )
178  .arg( mFeatureBuffer.last().id() )
179  .arg( errors.join( "\n" ) );
180 
183 
186  return false;
187  }
188 
190  return true;
191 }
192 
194 {
196  {
197  return mProvider->createSpatialIndex();
198  }
199  else
200  {
201  return true;
202  }
203 }
204 
207  const QString& uri,
208  const QString& providerKey,
209  const QgsCoordinateReferenceSystem *destCRS,
210  bool onlySelected,
212  bool skipAttributeCreation,
213  QMap<QString, QVariant> *options,
214  QProgressDialog *progress )
215 {
216  const QgsCoordinateReferenceSystem* outputCRS;
217  QgsCoordinateTransform* ct = nullptr;
218  bool shallTransform = false;
219 
220  if ( !layer )
221  return ErrInvalidLayer;
222 
223  if ( destCRS && destCRS->isValid() )
224  {
225  // This means we should transform
226  outputCRS = destCRS;
227  shallTransform = true;
228  }
229  else
230  {
231  // This means we shouldn't transform, use source CRS as output (if defined)
232  outputCRS = &layer->crs();
233  }
234 
235 
236  bool overwrite = false;
237  bool forceSinglePartGeom = false;
238  if ( options )
239  {
240  overwrite = options->take( "overwrite" ).toBool();
241  forceSinglePartGeom = options->take( "forceSinglePartGeometryType" ).toBool();
242  }
243 
244  QgsFields fields = skipAttributeCreation ? QgsFields() : layer->fields();
245  QGis::WkbType wkbType = layer->wkbType();
246 
247  // Special handling for Shapefiles
248  if ( layer->providerType() == "ogr" && layer->storageType() == "ESRI Shapefile" )
249  {
250  // convert field names to lowercase
251  for ( int fldIdx = 0; fldIdx < fields.count(); ++fldIdx )
252  {
253  fields[fldIdx].setName( fields.at( fldIdx ).name().toLower() );
254  }
255 
256  if ( !forceSinglePartGeom )
257  {
258  // convert wkbtype to multipart (see #5547)
259  switch ( wkbType )
260  {
261  case QGis::WKBPoint:
262  wkbType = QGis::WKBMultiPoint;
263  break;
264  case QGis::WKBLineString:
265  wkbType = QGis::WKBMultiLineString;
266  break;
267  case QGis::WKBPolygon:
268  wkbType = QGis::WKBMultiPolygon;
269  break;
270  case QGis::WKBPoint25D:
271  wkbType = QGis::WKBMultiPoint25D;
272  break;
274  wkbType = QGis::WKBMultiLineString25D;
275  break;
276  case QGis::WKBPolygon25D:
277  wkbType = QGis::WKBMultiPolygon25D;
278  break;
279  default:
280  break;
281  }
282  }
283  }
284 
285  QgsVectorLayerImport * writer =
286  new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options, progress );
287 
288  // check whether file creation was successful
289  ImportError err = writer->hasError();
290  if ( err != NoError )
291  {
292  if ( errorMessage )
293  *errorMessage = writer->errorMessage();
294  delete writer;
295  return err;
296  }
297 
298  if ( errorMessage )
299  {
300  errorMessage->clear();
301  }
302 
303  QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->attributeList();
304  QgsFeature fet;
305 
306  QgsFeatureRequest req;
307  if ( wkbType == QGis::WKBNoGeometry )
309  if ( skipAttributeCreation )
311 
312  QgsFeatureIterator fit = layer->getFeatures( req );
313 
314  const QgsFeatureIds& ids = layer->selectedFeaturesIds();
315 
316  // Create our transform
317  if ( destCRS )
318  ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
319 
320  // Check for failure
321  if ( !ct )
322  shallTransform = false;
323 
324  int n = 0;
325 
326  if ( errorMessage )
327  {
328  *errorMessage = QObject::tr( "Feature write errors:" );
329  }
330 
331  if ( progress )
332  {
333  progress->setRange( 0, layer->featureCount() );
334  }
335 
336  bool cancelled = false;
337 
338  // write all features
339  while ( fit.nextFeature( fet ) )
340  {
341  if ( progress && progress->wasCanceled() )
342  {
343  cancelled = true;
344  if ( errorMessage )
345  {
346  *errorMessage += '\n' + QObject::tr( "Import was canceled at %1 of %2" ).arg( progress->value() ).arg( progress->maximum() );
347  }
348  break;
349  }
350 
351  if ( writer->errorCount() > 1000 )
352  {
353  if ( errorMessage )
354  {
355  *errorMessage += '\n' + QObject::tr( "Stopping after %1 errors" ).arg( writer->errorCount() );
356  }
357  break;
358  }
359 
360  if ( onlySelected && !ids.contains( fet.id() ) )
361  continue;
362 
363  if ( shallTransform )
364  {
365  try
366  {
367  if ( fet.constGeometry() )
368  {
369  fet.geometry()->transform( *ct );
370  }
371  }
372  catch ( QgsCsException &e )
373  {
374  delete ct;
375  delete writer;
376 
377  QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
378  .arg( fet.id() ).arg( e.what() );
379  QgsMessageLog::logMessage( msg, QObject::tr( "Vector import" ) );
380  if ( errorMessage )
381  *errorMessage += '\n' + msg;
382 
383  return ErrProjection;
384  }
385  }
386  if ( skipAttributeCreation )
387  {
388  fet.initAttributes( 0 );
389  }
390  if ( !writer->addFeature( fet ) )
391  {
392  if ( writer->hasError() && errorMessage )
393  {
394  *errorMessage += '\n' + writer->errorMessage();
395  }
396  }
397  n++;
398 
399  if ( progress )
400  {
401  progress->setValue( n );
402  }
403  }
404 
405  // flush the buffer to be sure that all features are written
406  if ( !writer->flushBuffer() )
407  {
408  if ( writer->hasError() && errorMessage )
409  {
410  *errorMessage += '\n' + writer->errorMessage();
411  }
412  }
413  int errors = writer->errorCount();
414 
415  if ( !writer->createSpatialIndex() )
416  {
417  if ( writer->hasError() && errorMessage )
418  {
419  *errorMessage += '\n' + writer->errorMessage();
420  }
421  }
422 
423  delete writer;
424 
425  if ( shallTransform )
426  {
427  delete ct;
428  }
429 
430  if ( errorMessage )
431  {
432  if ( errors > 0 )
433  {
434  *errorMessage += '\n' + QObject::tr( "Only %1 of %2 features written." ).arg( n - errors ).arg( n );
435  }
436  else
437  {
438  errorMessage->clear();
439  }
440  }
441 
442  if ( cancelled )
443  return ErrUserCancelled;
444  else if ( errors > 0 )
445  return ErrFeatureWriteFailed;
446 
447  return NoError;
448 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
void clear()
Wrapper for iterator of features from vector data provider or vector layer.
static QgsProviderRegistry * instance(const QString &pluginPath=QString::null)
Means of accessing canonical single instance.
QgsAttributeList attributeList() const
Returns list of attribute indexes.
QMap< int, int > mOldToNewAttrIdx
Map attribute indexes to new field indexes.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsFields fields() const
Returns the list of fields of this layer.
#define FEATURE_BUFFER_SIZE
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
QgsVectorLayerImport(const QString &uri, const QString &provider, const QgsFields &fields, QGis::WkbType geometryType, const QgsCoordinateReferenceSystem *crs, bool overwrite=false, const QMap< QString, QVariant > *options=nullptr, QProgressDialog *progress=nullptr)
Create a empty layer and add fields to it.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
bool flushBuffer()
Flush the buffer writing the features to the new layer.
QgsVectorDataProvider * mProvider
Container of fields for a vector layer.
Definition: qgsfield.h:187
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:222
QStringList errors()
Get recorded errors.
WkbType
Used for symbology operations.
Definition: qgis.h:57
QgsVectorLayerImport::ImportError createEmptyLayer_t(const QString &uri, const QgsFields &fields, QGis::WkbType geometryType, const QgsCoordinateReferenceSystem *destCRS, bool overwrite, QMap< int, int > *oldToNewAttrIdx, QString *errorMessage, const QMap< QString, QVariant > *options)
QString join(const QString &separator) const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
virtual bool addFeatures(QgsFeatureList &flist)
Adds a list of features.
QString tr(const char *sourceText, const char *disambiguation, int n)
QGis::WkbType wkbType() const
Returns the WKBType or WKBUnknown in case of error.
void clear()
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
Allows creation of spatial index.
virtual bool createSpatialIndex()
Creates a spatial index on the datasource (if supported by the provider type).
void setGeometry(const QgsGeometry &geom)
Set this feature&#39;s geometry from another QgsGeometry object.
Definition: qgsfeature.cpp:124
int count(const T &value) const
void append(const T &value)
A convenience class for writing vector files to disk.
QgsDataProvider * provider(const QString &providerKey, const QString &dataSource)
Create an instance of the provider.
const QgsFeatureIds & selectedFeaturesIds() const
Return reference to identifiers of selected features.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
QgsAttributes attributes() const
Returns the feature&#39;s attributes.
Definition: qgsfeature.cpp:110
virtual int capabilities() const
Returns a bitmask containing the supported capabilities Note, some capabilities may change depending ...
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:213
QString name() const
Gets the name of the field.
Definition: qgsfield.cpp:84
QString errorMessage()
Retrieves error message.
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
~QgsVectorLayerImport()
Close the new created layer.
void clearErrors()
Clear recorded errors.
int count() const
Return number of items.
Definition: qgsfield.cpp:365
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
T & first()
void setRange(int minimum, int maximum)
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:385
ImportError mError
Contains error value.
static ImportError importLayer(QgsVectorLayer *layer, const QString &uri, const QString &providerKey, const QgsCoordinateReferenceSystem *destCRS, bool onlySelected=false, QString *errorMessage=nullptr, bool skipAttributeCreation=false, QMap< QString, QVariant > *options=nullptr, QProgressDialog *progress=nullptr)
Write contents of vector layer to a different datasource.
QString toLower() const
bool createSpatialIndex()
Create index.
A registry / canonical manager of data providers.
QgsGeometry * geometry()
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:76
bool contains(const T &value) const
bool addFeature(QgsFeature &feature)
Add feature to the new created layer.
QLibrary * providerLibrary(const QString &providerKey) const
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QString providerType() const
Return the provider type for this layer.
QString what() const
Definition: qgsexception.h:36
const T & at(int i) const
void * resolve(const char *symbol)
ImportError hasError()
Checks whether there were any errors.
virtual bool isValid()=0
Returns true if this is a valid layer.
T & last()
Class for storing a coordinate reference system (CRS)
int count(const T &value) const
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
Class for doing transforms between two map coordinate systems.
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
void(*)() cast_to_fptr(void *p)
Definition: qgis.h:258
Custom exception class for Coordinate Reference System related exceptions.
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
A vector of attributes.
Definition: qgsfeature.h:115
Represents a vector layer which manages a vector based data sets.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
T take(const Key &key)
const T value(const Key &key) const
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.