-
-
Notifications
You must be signed in to change notification settings - Fork 3k
/
qgsauxiliarystorage.h
408 lines (356 loc) · 13.5 KB
/
qgsauxiliarystorage.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/***************************************************************************
qgsauxiliarystorage.h - description
-------------------
begin : Aug 28, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@oslandia.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSAUXILIARYSTORAGE_H
#define QGSAUXILIARYSTORAGE_H
#include "qgis_core.h"
#include "qgsdatasourceuri.h"
#include "qgspallabeling.h"
#include "qgsdiagramrenderer.h"
#include "qgsvectorlayerjoininfo.h"
#include "qgsproperty.h"
#include "qgsspatialiteutils.h"
#include <QString>
class QgsProject;
/**
* \class QgsAuxiliaryLayer
*
* \ingroup core
*
* Class allowing to manage the auxiliary storage for a vector layer.
*
* Such auxiliary data are data used mostly for the needs of QGIS (symbology)
* and have no real interest in being stored with the native raw geospatial
* data.
*
* The need arises from the restrictions existing in the manual placement of
* labels. Manual placement of labels are possible in QGIS by setting some
* labeling properties (X and Y position, and rotation angle optionally) as
* being "data-defined", meaning that values come from a column (or an
* expression). But setting this up on an existing layer requires either to
* add new columns to the source layer, while it is not always possible or
* desirable.
*
* This QgsAuxiliaryLayer provides the solution to this limitation. Actually
* it's an editable join to the original vector layer with some
* synchronisation mechanisms activated such as "Upsert On Edit" or "Delete
* Cascade". Thus, auxiliary fields are editable even if the
* source layer is not and edition of a joined field is also possible.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsAuxiliaryLayer : public QgsVectorLayer
{
Q_OBJECT
public:
/**
* Constructor
*
* \param pkField The primary key to use for joining
* \param filename The database path
* \param table The table name
* \param vlayer The target vector layer in join definition
*/
QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer );
/**
* Destructor
*/
virtual ~QgsAuxiliaryLayer() = default;
/**
* Copy constructor deactivated
*/
QgsAuxiliaryLayer( const QgsAuxiliaryLayer &rhs ) = delete;
QgsAuxiliaryLayer &operator=( QgsAuxiliaryLayer const &rhs ) = delete;
/**
* Returns a new instance equivalent to this one. The underlying table
* is duplicate for the layer given in parameter. Note that the current
* auxiliary layer should be saved to have a proper duplicated table.
*
* \param layer The layer for which the clone is made
*/
QgsAuxiliaryLayer *clone( QgsVectorLayer *layer ) const SIP_FACTORY;
/**
* An auxiliary layer is not spatial. This method returns a spatial
* representation of auxiliary data.
*
* \returns A new spatial vector layer
*/
QgsVectorLayer *toSpatialLayer() const;
/**
* Deletes all features from the layer. Changes are automatically committed
* and the layer remains editable.
*
* \returns true if changes are committed without error, false otherwise.
*/
bool clear();
/**
* Returns information to use for joining with primary key and so on.
*/
QgsVectorLayerJoinInfo joinInfo() const;
/**
* Returns true if the property is stored in the layer already, false
* otherwise.
*
* \param definition The property definition to check
*
* \returns true if the property is stored, false otherwise
*/
bool exists( const QgsPropertyDefinition &definition ) const;
/**
* Adds an auxiliary field for the given property. Setup for widget
* editors are updated in the target layer as well as the attribute
* table config to hide auxiliary fields by default.
*
* \param definition The definition of the property to add
*
* \returns true if the auxiliary field is well added, false otherwise
*/
bool addAuxiliaryField( const QgsPropertyDefinition &definition );
/**
* Returns a list of all auxiliary fields currently managed by the layer.
*/
QgsFields auxiliaryFields() const;
/**
* Commits changes and starts editing then.
*
* \returns true if commit step passed, false otherwise
*/
bool save();
/**
* Removes attribute from the layer and commits changes. The layer remains
* editable.
*
* \param attr The index of the attribute to remove
*
* \returns true if the attribute is well deleted, false otherwise
*/
virtual bool deleteAttribute( int attr ) override;
/**
* Returns true if the underlying field has to be hidden from editing
* tools like attribute table, false otherwise.
*
* \param index The index of the field for which visibility is checked
*/
bool isHiddenProperty( int index ) const;
/**
* Returns the index of the auxiliary field for a specific property
* definition.
*
* \param definition The property definition
*
* \returns The index of the field corresponding to the property or -1
*/
int indexOfPropertyDefinition( const QgsPropertyDefinition &definition ) const;
/**
* Returns the underlying property key for the field index. The key may be
* a PAL, diagram or symbology property according to the underlying
* property definition of the field. The key -1 is returned if an error
* happened.
*
* \param index The index of the field
*/
int propertyFromIndex( int index ) const;
/**
* Returns the property definition for the underlying field index.
*
* \param index The index of the field
*/
QgsPropertyDefinition propertyDefinitionFromIndex( int index ) const;
/**
* Creates if necessary a new auxiliary field for a PAL property and
* activates this property in settings.
*
* \param property The property to create
* \param vlayer The vector layer
*
* \returns The index of the auxiliary field or -1
*/
static int createProperty( QgsPalLayerSettings::Property property, QgsVectorLayer *vlayer );
/**
* Creates if necessary a new auxiliary field for a diagram's property and
* activates this property in settings.
*
* \param property The property to create
* \param vlayer The vector layer
*
* \returns The index of the auxiliary field or -1
*/
static int createProperty( QgsDiagramLayerSettings::Property property, QgsVectorLayer *vlayer );
/**
* Creates a new auxiliary field from a property definition.
*
* \param definition The property definition of the auxiliary field to create
*/
static QgsField createAuxiliaryField( const QgsPropertyDefinition &definition );
/**
* Creates a new auxiliary field from a field.
*
* \param field The field to use to create the auxiliary field
*/
static QgsField createAuxiliaryField( const QgsField &field );
/**
* Returns the name of the auxiliary field for a property definition.
*
* \param def The property definition
* \param joined The join prefix is taken into account if true
*/
static QString nameFromProperty( const QgsPropertyDefinition &def, bool joined = false );
/**
* Returns the property definition from an auxiliary field.
*
* \param field The auxiliary field
*/
static QgsPropertyDefinition propertyDefinitionFromField( const QgsField &field );
private:
QgsVectorLayerJoinInfo mJoinInfo;
QString mFileName;
QString mTable;
QgsVectorLayer *mLayer = nullptr;
};
/**
* \class QgsAuxiliaryStorage
*
* \ingroup core
*
* \brief Class providing some utility methods to manage auxiliary storage.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsAuxiliaryStorage
{
public:
/**
* Constructor.
*
* The project filename is used to build a database path at the same
* location, but with a different extension. Then, it's the same logic as
* described for \see QgsAuxiliaryStorage(const QString &, bool copy).
*
*
* \param project The project for which the auxiliary storage has to be used
* \param copy Parameter indicating if a copy of the database has to be used
*/
QgsAuxiliaryStorage( const QgsProject &project, bool copy = true );
/**
* Constructor.
*
* If a valid database path is given in parameter and copy mode is
* deactivated, then every changes is directly committed on the original
* database. But if the copy mode is activated, then changes are committed
* on a copy of the database (a temporary file) and a save action is
* therefore necessary to keep modifications in the original file.
*
* If an empty string for the database path is given in parameter, then
* a database is created in a temporary file whatever the copy mode.
*
* If the database path given in parameter is not empty but does not exist,
* then a database is created at this location when copy mode is
* deactivated. When copy mode is activated, a temporary database is used
* instead and a save action will be necessary to create the database at
* the original location given in parameter.
*
* \param filename The path of the database
* \param copy Parameter indicating if a copy of the database has to be used
*/
QgsAuxiliaryStorage( const QString &filename = QString(), bool copy = true );
/**
* Destructor.
*/
virtual ~QgsAuxiliaryStorage();
/**
* Returns the status of the auxiliary storage currently defined.
*
* \returns true if the auxiliary storage is valid, false otherwise
*/
bool isValid() const;
/**
* Returns the target filename of the database.
*/
QString fileName() const;
/**
* Returns the path of the current database used. It may be different from
* the target filename if the auxiliary storage is opened in copy mode.
*/
QString currentFileName() const;
/**
* Saves the current database to a new path.
*
* \returns true if everything is saved, false otherwise
*/
bool saveAs( const QString &filename ) const;
/**
* Saves the current database to a new path for a specific project.
* Actually, the current filename of the project is used to deduce the
* path of the database to save.
*
* \returns true if everything is saved, false otherwise
*/
bool saveAs( const QgsProject &project ) const;
/**
* Saves the current database.
*
* \returns true if everything is saved, false otherwise
*/
bool save() const;
/**
* Creates an auxiliary layer for a vector layer. A new table is created if
* necessary. The primary key to use to construct the auxiliary layer is
* given in parameter.
*
* \param field The primary key to join
* \param layer The vector layer for which the auxiliary layer has to be created
*
* \returns A new auxiliary layer or a nullptr if an error happened.
*/
QgsAuxiliaryLayer *createAuxiliaryLayer( const QgsField &field, QgsVectorLayer *layer ) const SIP_FACTORY;
/**
* Removes a table from the auxiliary storage.
*
* \param uri The uri of the table to remove
*
* \returns true if the table is well deleted, false otherwise
*/
static bool deleteTable( const QgsDataSourceUri &uri );
/**
* Duplicates a table and its content.
*
* \param uri The uri of the table to duplicate
* \param newTable The name of the new table
*
* \returns true if the table is well duplicated, false otherwise
*/
static bool duplicateTable( const QgsDataSourceUri &uri, const QString &newTable );
/**
* Returns the extension used for auxiliary databases.
*/
static QString extension();
private:
spatialite_database_unique_ptr open( const QString &filename = QString() );
spatialite_database_unique_ptr open( const QgsProject &project );
void initTmpFileName();
static QString filenameForProject( const QgsProject &project );
static spatialite_database_unique_ptr createDB( const QString &filename );
static spatialite_database_unique_ptr openDB( const QString &filename );
static bool tableExists( const QString &table, sqlite3 *handler );
static bool createTable( const QString &type, const QString &table, sqlite3 *handler );
static bool exec( const QString &sql, sqlite3 *handler );
static void debugMsg( const QString &sql, sqlite3 *handler );
static QgsDataSourceUri parseOgrUri( const QgsDataSourceUri &uri );
bool mValid = false;
QString mFileName; // original filename
QString mTmpFileName; // temporary filename used in copy mode
bool mCopy = false;
};
#endif