1 /***************************************************************************
2                           qgsvectorlayerexporter.h
3                              -------------------
4     begin                : Thu Aug 25 2011
5     copyright            : (C) 2011 by Giuseppe Sucameli
6     email                : brush.tyler at gmail.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #ifndef QGSVECTORLAYEREXPORTER_H
19 #define QGSVECTORLAYEREXPORTER_H
20 
21 #include "qgis_core.h"
22 #include "qgis_sip.h"
23 #include "qgsfeature.h"
24 #include "qgsfeaturesink.h"
25 #include "qgstaskmanager.h"
26 #include "qgsfeedback.h"
27 #include "qgsvectorlayer.h"
28 
29 class QProgressDialog;
30 class QgsVectorDataProvider;
31 class QgsFields;
32 
33 /**
34  * \class QgsVectorLayerExporter
35  * \ingroup core
36  * \brief A convenience class for exporting vector layers to a destination data provider.
37  *
38  * QgsVectorLayerExporter can be used in two ways:
39  *
40  * # Using a static call to QgsVectorLayerExporter::exportLayer(...) which exports the
41  *   entire layer to the destination provider.
42  * # Create an instance of the class and issue calls to addFeature(...)
43  *
44  * \since QGIS 3.0
45  */
46 class CORE_EXPORT QgsVectorLayerExporter : public QgsFeatureSink
47 {
48   public:
49 
50     //! Error codes
51     enum ExportError
52     {
53       NoError = 0, //!< No errors were encountered
54       ErrCreateDataSource, //!< Could not create the destination data source
55       ErrCreateLayer, //!< Could not create destination layer
56       ErrAttributeTypeUnsupported, //!< Source layer has an attribute type which could not be handled by destination
57       ErrAttributeCreationFailed, //!< Destination provider was unable to create an attribute
58       ErrProjection, //!< An error occurred while reprojecting features to destination CRS
59       ErrFeatureWriteFailed, //!< An error occurred while writing a feature to the destination
60       ErrInvalidLayer, //!< Could not access newly created destination layer
61       ErrInvalidProvider, //!< Could not find a matching provider key
62       ErrProviderUnsupportedFeature, //!< Provider does not support creation of empty layers
63       ErrConnectionFailed, //!< Could not connect to destination
64       ErrUserCanceled, //!< User canceled the export
65     };
66 
67     /**
68      * Writes the contents of vector layer to a different datasource.
69      * \param layer source layer
70      * \param uri URI for destination data source
71      * \param providerKey string key for destination data provider
72      * \param destCRS destination CRS, or an invalid (default constructed) CRS if
73      * not available
74      * \param onlySelected set to TRUE to export only selected features
75      * \param errorMessage if non-null, will be set to any error messages
76      * \param options optional provider dataset options
77      * \param feedback optional feedback object to show progress and cancellation of export
78      * \returns NoError for a successful export, or encountered error
79      */
80     static ExportError exportLayer( QgsVectorLayer *layer,
81                                     const QString &uri,
82                                     const QString &providerKey,
83                                     const QgsCoordinateReferenceSystem &destCRS,
84                                     bool onlySelected = false,
85                                     QString *errorMessage SIP_OUT = nullptr,
86                                     const QMap<QString, QVariant> &options = QMap<QString, QVariant>(),
87                                     QgsFeedback *feedback = nullptr
88                                   );
89 
90     /**
91      * Constructor for QgsVectorLayerExporter.
92      * \param uri URI for destination data source
93      * \param provider string key for destination data provider
94      * \param fields fields to include in created layer
95      * \param geometryType destination geometry type
96      * \param crs desired CRS, or an invalid (default constructed) CRS if
97      * not available
98      * \param overwrite set to TRUE to overwrite any existing data source
99      * \param options optional provider dataset options
100      * \param sinkFlags for how to add features
101      */
102     QgsVectorLayerExporter( const QString &uri,
103                             const QString &provider,
104                             const QgsFields &fields,
105                             QgsWkbTypes::Type geometryType,
106                             const QgsCoordinateReferenceSystem &crs,
107                             bool overwrite = false,
108                             const QMap<QString, QVariant> &options = QMap<QString, QVariant>(),
109                             QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags() );
110 
111     //! QgsVectorLayerExporter cannot be copied
112     QgsVectorLayerExporter( const QgsVectorLayerExporter &rh ) = delete;
113     //! QgsVectorLayerExporter cannot be copied
114     QgsVectorLayerExporter &operator=( const QgsVectorLayerExporter &rh ) = delete;
115 
116     /**
117      * Returns any encountered error code, or FALSE if no error was encountered.
118      * \see errorMessage()
119      * \see errorCount()
120      */
121     ExportError errorCode() const;
122 
123     /**
124      * Returns any error message encountered during the export.
125      * \see errorCount()
126      * \see errorCode()
127      */
128     QString errorMessage() const;
129 
130     /**
131      * Returns the number of error messages encountered during the export.
132      * \see errorMessage()
133      * \see errorCode()
134      */
errorCount()135     int errorCount() const { return mErrorCount; }
136 
137     bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override;
138     bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override;
139     QString lastError() const override;
140 
141     /**
142      * Finalizes the export and closes the new created layer.
143      */
144     ~QgsVectorLayerExporter() override;
145 
146     bool flushBuffer() override;
147 
148   private:
149 
150     //! Create index
151     bool createSpatialIndex();
152 
153     //! Contains error value
154     ExportError mError;
155     QString mErrorMessage;
156 
157     int mErrorCount;
158 
159     QgsVectorDataProvider *mProvider = nullptr;
160 
161     //! Map attribute indexes to new field indexes
162     QMap<int, int> mOldToNewAttrIdx;
163     int mAttributeCount;
164 
165     QgsFeatureList mFeatureBuffer;
166     int mFeatureBufferMemoryUsage = 0;
167 
168     bool mCreateSpatialIndex = true;
169 
170 #ifdef SIP_RUN
171     QgsVectorLayerExporter( const QgsVectorLayerExporter &rh );
172 #endif
173 
174 };
175 
176 
177 /**
178  * \class QgsVectorLayerExporterTask
179  * \ingroup core
180  * \brief QgsTask task which performs a QgsVectorLayerExporter layer export operation as a background
181  * task. This can be used to export a vector layer out to a provider without blocking the
182  * QGIS interface.
183  * \see QgsVectorFileWriterTask
184  * \see QgsRasterFileWriterTask
185  * \since QGIS 3.0
186  */
187 class CORE_EXPORT QgsVectorLayerExporterTask : public QgsTask
188 {
189     Q_OBJECT
190 
191   public:
192 
193     /**
194      * Constructor for QgsVectorLayerExporterTask. Takes a source \a layer, destination \a uri
195      * and \a providerKey, and various export related parameters such as destination CRS
196      * and export \a options. \a ownsLayer has to be set to TRUE if the task should take ownership
197      * of the layer and delete it after export.
198     */
199     QgsVectorLayerExporterTask( QgsVectorLayer *layer,
200                                 const QString &uri,
201                                 const QString &providerKey,
202                                 const QgsCoordinateReferenceSystem &destinationCrs,
203                                 const QMap<QString, QVariant> &options = QMap<QString, QVariant>(),
204                                 bool ownsLayer = false );
205 
206     /**
207      * Creates a new QgsVectorLayerExporterTask which has ownership over a source \a layer.
208      * When the export task has completed (successfully or otherwise) \a layer will be
209      * deleted. The destination \a uri and \a providerKey, and various export related parameters such as destination CRS
210      * and export \a options must be specified.
211     */
212     static QgsVectorLayerExporterTask *withLayerOwnership( QgsVectorLayer *layer SIP_TRANSFER,
213         const QString &uri,
214         const QString &providerKey,
215         const QgsCoordinateReferenceSystem &destinationCrs,
216         const QMap<QString, QVariant> &options = QMap<QString, QVariant>() ) SIP_FACTORY;
217 
218     void cancel() override;
219 
220   signals:
221 
222     /**
223      * Emitted when exporting the layer is successfully completed.
224      */
225     void exportComplete();
226 
227     /**
228      * Emitted when an error occurs which prevented the layer being exported (or if
229      * the task is canceled). The export \a error and \a errorMessage will be reported.
230      */
231     void errorOccurred( int error, const QString &errorMessage );
232 
233   protected:
234 
235     bool run() override;
236     void finished( bool result ) override;
237 
238   private:
239 
240     QPointer< QgsVectorLayer > mLayer = nullptr;
241     bool mOwnsLayer = false;
242 
243     QString mDestUri;
244     QString mDestProviderKey;
245     QgsCoordinateReferenceSystem mDestCrs;
246     QMap<QString, QVariant> mOptions;
247 
248     std::unique_ptr< QgsFeedback > mOwnedFeedback;
249 
250     QgsVectorLayerExporter::ExportError mError = QgsVectorLayerExporter::NoError;
251     QString mErrorMessage;
252 
253 };
254 
255 #endif // QGSVECTORLAYEREXPORTER_H
256