QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsauxiliarystorage.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsauxiliarystorage.cpp - description
3 -------------------
4 begin : Aug 28, 2017
5 copyright : (C) 2017 by Paul Blottiere
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#include "qgsauxiliarystorage.h"
19#include "qgslogger.h"
20#include "qgssqliteutils.h"
21#include "qgsproject.h"
23#include "qgsdiagramrenderer.h"
25#include "qgssymbollayer.h"
26
27#include <sqlite3.h>
28#include <QFile>
29
30#define AS_JOINFIELD QStringLiteral( "ASPK" )
31#define AS_EXTENSION QStringLiteral( "qgd" )
32#define AS_JOINPREFIX QStringLiteral( "auxiliary_storage_" )
33
34typedef QVector<int> PalPropertyList;
35typedef QVector<int> SymbolPropertyList;
36
38{
39 static_cast< int >( QgsPalLayerSettings::Property::PositionX ),
40 static_cast< int >( QgsPalLayerSettings::Property::PositionY ),
41 static_cast< int >( QgsPalLayerSettings::Property::Show ),
43 static_cast< int >( QgsPalLayerSettings::Property::Family ),
44 static_cast< int >( QgsPalLayerSettings::Property::FontStyle ),
45 static_cast< int >( QgsPalLayerSettings::Property::Size ),
46 static_cast< int >( QgsPalLayerSettings::Property::Bold ),
47 static_cast< int >( QgsPalLayerSettings::Property::Italic ),
48 static_cast< int >( QgsPalLayerSettings::Property::Underline ),
49 static_cast< int >( QgsPalLayerSettings::Property::Color ),
50 static_cast< int >( QgsPalLayerSettings::Property::Strikeout ),
56 static_cast< int >( QgsPalLayerSettings::Property::Hali ),
57 static_cast< int >( QgsPalLayerSettings::Property::Vali ),
59 static_cast< int >( QgsPalLayerSettings::Property::MinScale ),
60 static_cast< int >( QgsPalLayerSettings::Property::MaxScale ),
64} ) )
66{
67 static_cast< int >( QgsSymbolLayer::Property::Angle ),
68 static_cast< int >( QgsSymbolLayer::Property::Offset )
69} ) )
70
71//
72// QgsAuxiliaryLayer
73//
74
75QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer )
76 : QgsVectorLayer( QStringLiteral( "%1|layername=%2" ).arg( filename, table ),
77 QStringLiteral( "%1_auxiliarystorage" ).arg( table ), QStringLiteral( "ogr" ) )
78 , mFileName( filename )
79 , mTable( table )
80 , mLayer( vlayer )
81{
82 // init join info
83 mJoinInfo.setPrefix( AS_JOINPREFIX );
84 mJoinInfo.setJoinLayer( this );
85 mJoinInfo.setJoinFieldName( AS_JOINFIELD );
86 mJoinInfo.setTargetFieldName( pkField );
87 mJoinInfo.setEditable( true );
88 mJoinInfo.setUpsertOnEdit( true );
89 mJoinInfo.setCascadedDelete( true );
90 mJoinInfo.setJoinFieldNamesBlockList( QStringList() << QStringLiteral( "rowid" ) ); // introduced by ogr provider
91}
92
94{
96 return new QgsAuxiliaryLayer( mJoinInfo.targetFieldName(), mFileName, target->id(), target );
97}
98
100{
101 const bool rc = deleteFeatures( allFeatureIds() );
103 startEditing();
104 return rc;
105}
106
108{
109 QgsVectorLayer *layer = QgsMemoryProviderUtils::createMemoryLayer( QStringLiteral( "auxiliary_layer" ), fields(), mLayer->wkbType(), mLayer->crs() );
110
111 const QString pkField = mJoinInfo.targetFieldName();
112 QgsFeature joinFeature;
113 QgsFeature targetFeature;
115
116 layer->startEditing();
117 while ( it.nextFeature( joinFeature ) )
118 {
119 const QString filter = QgsExpression::createFieldEqualityExpression( pkField, joinFeature.attribute( AS_JOINFIELD ) );
120
121 QgsFeatureRequest request;
122 request.setFilterExpression( filter );
123
124 mLayer->getFeatures( request ).nextFeature( targetFeature );
125
126 if ( targetFeature.isValid() )
127 {
128 QgsFeature newFeature( joinFeature );
129 newFeature.setGeometry( targetFeature.geometry() );
130 layer->addFeature( newFeature );
131 }
132 }
133 layer->commitChanges();
134
135 return layer;
136}
137
139{
140 return mJoinInfo;
141}
142
143bool QgsAuxiliaryLayer::exists( const QgsPropertyDefinition &definition ) const
144{
145 return ( indexOfPropertyDefinition( definition ) >= 0 );
146}
147
149{
150 if ( ( definition.name().isEmpty() && definition.comment().isEmpty() ) || exists( definition ) )
151 return false;
152
153 const QgsField af = createAuxiliaryField( definition );
154 const bool rc = addAttribute( af );
155 updateFields();
156 mLayer->updateFields();
157
158 if ( rc )
159 {
160 const int auxIndex = indexOfPropertyDefinition( definition );
161 const int index = mLayer->fields().indexOf( nameFromProperty( definition, true ) );
162
163 if ( index >= 0 && auxIndex >= 0 )
164 {
165 if ( isHiddenProperty( auxIndex ) )
166 {
167 // update editor widget
168 const QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Hidden" ), QVariantMap() );
169 setEditorWidgetSetup( auxIndex, setup );
170
171 // column is hidden
173 attrCfg.update( mLayer->fields() );
174 QVector<QgsAttributeTableConfig::ColumnConfig> columns = attrCfg.columns();
175 QVector<QgsAttributeTableConfig::ColumnConfig>::iterator it;
176
177 for ( it = columns.begin(); it != columns.end(); ++it )
178 {
179 if ( it->name.compare( mLayer->fields().field( index ).name() ) == 0 )
180 it->hidden = true;
181 }
182
183 attrCfg.setColumns( columns );
184 mLayer->setAttributeTableConfig( attrCfg );
185 }
188 {
189 const QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Color" ), QVariantMap() );
190 setEditorWidgetSetup( auxIndex, setup );
191 }
192
193 mLayer->setEditorWidgetSetup( index, editorWidgetSetup( auxIndex ) );
194 }
195 }
196
197 return rc;
198}
199
201{
202 QgsFields afields;
203
204 for ( int i = 2; i < fields().count(); i++ ) // ignore rowid and PK field
205 afields.append( createAuxiliaryField( fields().field( i ) ) );
206
207 return afields;
208}
209
211{
213 const bool rc = commitChanges();
214 startEditing();
215 return rc;
216}
217
219{
220 bool rc = false;
221
222 if ( isEditable() )
223 {
224 rc = commitChanges();
225 }
226
227 startEditing();
228
229 return rc;
230}
231
232int QgsAuxiliaryLayer::createProperty( QgsPalLayerSettings::Property property, QgsVectorLayer *layer, bool overwriteExisting )
233{
234 int index = -1;
235
236 if ( layer && layer->labeling() && layer->auxiliaryLayer() )
237 {
238 // property definition are identical whatever the provider id
239 const QgsPropertyDefinition def = QgsPalLayerSettings::propertyDefinitions()[static_cast< int >( property )];
240 const QString fieldName = nameFromProperty( def, true );
241
242 layer->auxiliaryLayer()->addAuxiliaryField( def );
243
244 if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
245 {
246 const QStringList subProviderIds = layer->labeling()->subProviders();
247 for ( const QString &providerId : subProviderIds )
248 {
249 QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
250
252
253 // is there an existing property?
254 const QgsProperty existingProperty = c.property( property );
255 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid
256 || ( existingProperty.propertyType() == Qgis::PropertyType::Field && existingProperty.field().isEmpty() )
257 || ( existingProperty.propertyType() == Qgis::PropertyType::Expression && existingProperty.expressionString().isEmpty() )
258 || overwriteExisting )
259 {
260 const QgsProperty prop = QgsProperty::fromField( fieldName );
261 c.setProperty( property, prop );
262 }
263 else
264 {
265 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
266 const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
267 existingProperty.asExpression() ) );
268 c.setProperty( property, prop );
269 }
270 settings->setDataDefinedProperties( c );
271
272 layer->labeling()->setSettings( settings, providerId );
273 }
274 }
275
276 index = layer->fields().lookupField( fieldName );
277 }
278
279 return index;
280}
281
282int QgsAuxiliaryLayer::createProperty( QgsDiagramLayerSettings::Property property, QgsVectorLayer *layer, bool overwriteExisting )
283{
284 int index = -1;
285
286 if ( layer && layer->diagramLayerSettings() && layer->auxiliaryLayer() )
287 {
288 const QgsPropertyDefinition def = QgsDiagramLayerSettings::propertyDefinitions()[static_cast<int>( property )];
289
290 if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) )
291 {
292 const QString fieldName = nameFromProperty( def, true );
293
294 QgsDiagramLayerSettings settings( *layer->diagramLayerSettings() );
295
297 // is there an existing property?
298 const QgsProperty existingProperty = c.property( property );
299 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid || overwriteExisting )
300 {
301 const QgsProperty prop = QgsProperty::fromField( fieldName );
302 c.setProperty( property, prop );
303 }
304 else
305 {
306 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
307 const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
308 existingProperty.asExpression() ) );
309 c.setProperty( property, prop );
310 }
311 settings.setDataDefinedProperties( c );
312
313 layer->setDiagramLayerSettings( settings );
314 index = layer->fields().lookupField( fieldName );
315 }
316 }
317
318 return index;
319}
320
321int QgsAuxiliaryLayer::createProperty( QgsCallout::Property property, QgsVectorLayer *layer, bool overwriteExisting )
322{
323 int index = -1;
324
325 if ( layer && layer->labeling() && layer->labeling()->settings().callout() && layer->auxiliaryLayer() )
326 {
327 // property definition are identical whatever the provider id
328 const QgsPropertyDefinition def = QgsCallout::propertyDefinitions()[static_cast< int >( property )];
329 const QString fieldName = nameFromProperty( def, true );
330
331 layer->auxiliaryLayer()->addAuxiliaryField( def );
332
333 if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
334 {
335 const QStringList subProviderIds = layer->labeling()->subProviders();
336 for ( const QString &providerId : subProviderIds )
337 {
338 QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
339 if ( settings->callout() )
340 {
342 // is there an existing property?
343 const QgsProperty existingProperty = c.property( property );
344 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid || overwriteExisting )
345 {
346 const QgsProperty prop = QgsProperty::fromField( fieldName );
347 c.setProperty( property, prop );
348 }
349 else
350 {
351 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
352 const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
353 existingProperty.asExpression() ) );
354 c.setProperty( property, prop );
355 }
356 settings->callout()->setDataDefinedProperties( c );
357 }
358 layer->labeling()->setSettings( settings, providerId );
359 }
360 }
361
362 index = layer->fields().lookupField( fieldName );
363 }
364
365 return index;
366}
367
368bool QgsAuxiliaryLayer::isHiddenProperty( int index ) const
369{
370 bool hidden = false;
372
373 if ( def.origin().compare( QLatin1String( "labeling" ) ) == 0 )
374 {
375 const PalPropertyList &palProps = *palHiddenProperties();
376 for ( const int p : palProps )
377 {
378 const QString propName = QgsPalLayerSettings::propertyDefinitions()[ p ].name();
379 if ( propName.compare( def.name() ) == 0 )
380 {
381 hidden = true;
382 break;
383 }
384 }
385 }
386 else if ( def.origin().compare( QLatin1String( "symbol" ) ) == 0 )
387 {
388 const SymbolPropertyList &symbolProps = *symbolHiddenProperties();
389 for ( int p : symbolProps )
390 {
391 const QString propName = QgsSymbolLayer::propertyDefinitions()[ p ].name();
392 if ( propName.compare( def.name() ) == 0 )
393 {
394 hidden = true;
395 break;
396 }
397 }
398 }
399
400 return hidden;
401}
402
403int QgsAuxiliaryLayer::propertyFromIndex( int index ) const
404{
405 int p = -1;
407
408 if ( aDef.origin().compare( QLatin1String( "labeling" ) ) == 0 )
409 {
411 QgsPropertiesDefinition::const_iterator it = defs.constBegin();
412 for ( ; it != defs.constEnd(); ++it )
413 {
414 if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
415 {
416 p = it.key();
417 break;
418 }
419 }
420 }
421 else if ( aDef.origin().compare( QLatin1String( "symbol" ) ) == 0 )
422 {
424 QgsPropertiesDefinition::const_iterator it = defs.constBegin();
425 for ( ; it != defs.constEnd(); ++it )
426 {
427 if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
428 {
429 p = it.key();
430 break;
431 }
432 }
433 }
434 else if ( aDef.origin().compare( QLatin1String( "diagram" ) ) == 0 )
435 {
437 QgsPropertiesDefinition::const_iterator it = defs.constBegin();
438 for ( ; it != defs.constEnd(); ++it )
439 {
440 if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
441 {
442 p = it.key();
443 break;
444 }
445 }
446 }
447
448 return p;
449}
450
452{
453 return propertyDefinitionFromField( fields().field( index ) );
454}
455
457{
458 return fields().indexOf( nameFromProperty( def ) );
459}
460
461QString QgsAuxiliaryLayer::nameFromProperty( const QgsPropertyDefinition &def, bool joined )
462{
463 QString fieldName = def.origin();
464
465 if ( !def.name().isEmpty() )
466 fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.name().toLower() );
467
468 if ( !def.comment().isEmpty() )
469 fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.comment() );
470
471 if ( joined )
472 fieldName = QStringLiteral( "%1%2" ).arg( AS_JOINPREFIX, fieldName );
473
474 return fieldName;
475}
476
478{
479 QgsField afield;
480
481 if ( !def.name().isEmpty() || !def.comment().isEmpty() )
482 {
483 QVariant::Type type = QVariant::Invalid;
484 QString typeName;
485 int len( 0 ), precision( 0 );
486 switch ( def.dataType() )
487 {
489 type = QVariant::String;
490 len = 50;
491 typeName = QStringLiteral( "String" );
492 break;
494 type = QVariant::Double;
495 len = 0;
496 precision = 0;
497 typeName = QStringLiteral( "Real" );
498 break;
500 type = QVariant::Int; // sqlite does not have a bool type
501 typeName = QStringLiteral( "Integer" );
502 break;
503 }
504
505 afield.setType( type );
506 afield.setName( nameFromProperty( def ) );
507 afield.setTypeName( typeName );
508 afield.setLength( len );
509 afield.setPrecision( precision );
510 }
511
512 return afield;
513}
514
516{
518 const QStringList parts = f.name().split( '_' );
519
520 if ( parts.size() <= 1 )
521 return def;
522
523 const QString origin = parts[0];
524 const QString propertyName = parts[1];
525
526 if ( origin.compare( QLatin1String( "labeling" ), Qt::CaseInsensitive ) == 0 )
527 {
529 for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
530 {
531 if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
532 {
533 def = it.value();
534 if ( parts.size() >= 3 )
535 def.setComment( parts.mid( 2 ).join( '_' ) );
536 break;
537 }
538 }
539 }
540 else if ( origin.compare( QLatin1String( "symbol" ), Qt::CaseInsensitive ) == 0 )
541 {
543 for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
544 {
545 if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
546 {
547 def = it.value();
548 if ( parts.size() >= 3 )
549 def.setComment( parts.mid( 2 ).join( '_' ) );
550 break;
551 }
552 }
553 }
554 else if ( origin.compare( QLatin1String( "diagram" ), Qt::CaseInsensitive ) == 0 )
555 {
557 for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
558 {
559 if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
560 {
561 def = it.value();
562 if ( parts.size() >= 3 )
563 def.setComment( parts.mid( 2 ).join( '_' ) );
564 break;
565 }
566 }
567 }
568 else
569 {
570 def.setOrigin( origin );
571 def.setName( propertyName );
572 switch ( f.type() )
573 {
574 case QVariant::Double:
576 break;
577
578 case QVariant::Bool:
580 break;
581
582 case QVariant::String:
583 default:
585 break;
586 }
587
588 if ( parts.size() >= 3 )
589 def.setComment( parts.mid( 2 ).join( '_' ) );
590 }
591
592 return def;
593}
594
596{
598 QgsField afield;
599
600 if ( !def.name().isEmpty() || !def.comment().isEmpty() )
601 {
602 afield = createAuxiliaryField( def );
603 afield.setTypeName( field.typeName() );
604 }
605
606 return afield;
607}
608
609//
610// QgsAuxiliaryStorage
611//
612
613QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QgsProject &project, bool copy )
614 : mCopy( copy )
615{
616 initTmpFileName();
617
618 if ( !project.absoluteFilePath().isEmpty() )
619 {
620 mFileName = filenameForProject( project );
621 }
622
623 open( mFileName );
624}
625
626QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QString &filename, bool copy )
627 : mFileName( filename )
628 , mCopy( copy )
629{
630 initTmpFileName();
631
632 open( filename );
633}
634
636{
637 QFile::remove( mTmpFileName );
638}
639
641{
642 return mValid;
643}
644
645QString QgsAuxiliaryStorage::fileName() const
646{
647 return mFileName;
648}
649
650bool QgsAuxiliaryStorage::save() const
651{
652 if ( mFileName.isEmpty() )
653 {
654 // only a saveAs is available on a new database
655 return false;
656 }
657 else if ( mCopy )
658 {
659 if ( QFile::exists( mFileName ) )
660 QFile::remove( mFileName );
661
662 return QFile::copy( mTmpFileName, mFileName );
663 }
664 else
665 {
666 // if the file is not empty the copy mode is not activated, then we're
667 // directly working on the database since the beginning (no savepoints
668 // /rollback for now)
669 return true;
670 }
671}
672
674{
675 QgsAuxiliaryLayer *alayer = nullptr;
676
677 if ( mValid && layer )
678 {
679 const QString table( layer->id() );
681 database = openDB( currentFileName() );
682
683 if ( !tableExists( table, database.get() ) )
684 {
685 if ( !createTable( field.typeName(), table, database.get(), mErrorString ) )
686 {
687 return alayer;
688 }
689 }
690
691 alayer = new QgsAuxiliaryLayer( field.name(), currentFileName(), table, layer );
692 alayer->startEditing();
693 }
694
695 return alayer;
696}
697
699{
700 bool rc = false;
701 const QgsDataSourceUri uri = parseOgrUri( ogrUri );
702
703 if ( !uri.database().isEmpty() && !uri.table().isEmpty() )
704 {
706 database = openDB( uri.database() );
707
708 if ( database )
709 {
710 QString sql = QStringLiteral( "DROP TABLE %1" ).arg( uri.table() );
711 rc = exec( sql, database.get() );
712
713 sql = QStringLiteral( "VACUUM" );
714 rc = exec( sql, database.get() );
715 }
716 }
717
718 return rc;
719}
720
721bool QgsAuxiliaryStorage::duplicateTable( const QgsDataSourceUri &ogrUri, const QString &newTable )
722{
723 const QgsDataSourceUri uri = parseOgrUri( ogrUri );
724 bool rc = false;
725
726 if ( !uri.table().isEmpty() && !uri.database().isEmpty() )
727 {
729 database = openDB( uri.database() );
730
731 if ( database )
732 {
733 const QString sql = QStringLiteral( "CREATE TABLE %1 AS SELECT * FROM %2" ).arg( newTable, uri.table() );
734 rc = exec( sql, database.get() );
735 }
736 }
737
738 return rc;
739}
740
742{
743 return mErrorString;
744}
745
746bool QgsAuxiliaryStorage::saveAs( const QString &filename )
747{
748 mErrorString.clear();
749
750 QFile dest( filename );
751 if ( dest.exists() && !dest.remove() )
752 {
753 mErrorString = dest.errorString();
754 return false;
755 }
756
757 QFile origin( currentFileName() );
758 if ( !origin.copy( filename ) )
759 {
760 mErrorString = origin.errorString();
761 return false;
762 }
763
764 return true;
765}
766
767bool QgsAuxiliaryStorage::saveAs( const QgsProject &project )
768{
769 return saveAs( filenameForProject( project ) );
770}
771
773{
774 return AS_EXTENSION;
775}
776
777bool QgsAuxiliaryStorage::exists( const QgsProject &project )
778{
779 const QFileInfo fileinfo( filenameForProject( project ) );
780 return fileinfo.exists() && fileinfo.isFile();
781}
782
783bool QgsAuxiliaryStorage::exec( const QString &sql, sqlite3 *handler )
784{
785 bool rc = false;
786
787 if ( handler )
788 {
789 const int err = sqlite3_exec( handler, sql.toStdString().c_str(), nullptr, nullptr, nullptr );
790
791 if ( err == SQLITE_OK )
792 rc = true;
793 else
794 debugMsg( sql, handler );
795 }
796
797 return rc;
798}
799
800QString QgsAuxiliaryStorage::debugMsg( const QString &sql, sqlite3 *handler )
801{
802 const QString err = QString::fromUtf8( sqlite3_errmsg( handler ) );
803 const QString msg = QObject::tr( "Unable to execute" );
804 const QString errMsg = QObject::tr( "%1 '%2': %3" ).arg( msg, sql, err );
805 QgsDebugError( errMsg );
806 return errMsg;
807}
808
809bool QgsAuxiliaryStorage::createTable( const QString &type, const QString &table, sqlite3 *handler, QString &errorMsg )
810{
811 const QString sql = QStringLiteral( "CREATE TABLE IF NOT EXISTS '%1' ( '%2' %3 )" ).arg( table, AS_JOINFIELD, type );
812
813 if ( !exec( sql, handler ) )
814 {
815 errorMsg = QgsAuxiliaryStorage::debugMsg( sql, handler );
816 return false;
817 }
818
819 return true;
820}
821
822sqlite3_database_unique_ptr QgsAuxiliaryStorage::createDB( const QString &filename )
823{
825
826 int rc;
827 rc = database.open_v2( filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr );
828 if ( rc )
829 {
830 debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
831 }
832 else
833 // activating Foreign Key constraints
834 exec( QStringLiteral( "PRAGMA foreign_keys = 1" ), database.get() );
835
836 return database;
837}
838
839sqlite3_database_unique_ptr QgsAuxiliaryStorage::openDB( const QString &filename )
840{
842 const int rc = database.open_v2( filename, SQLITE_OPEN_READWRITE, nullptr );
843
844 if ( rc )
845 {
846 debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
847 }
848
849 return database;
850}
851
852bool QgsAuxiliaryStorage::tableExists( const QString &table, sqlite3 *handler )
853{
854 const QString sql = QStringLiteral( "SELECT 1 FROM sqlite_master WHERE type='table' AND name='%1'" ).arg( table );
855 int rows = 0;
856 int columns = 0;
857 char **results = nullptr;
858 const int rc = sqlite3_get_table( handler, sql.toStdString().c_str(), &results, &rows, &columns, nullptr );
859 if ( rc != SQLITE_OK )
860 {
861 debugMsg( sql, handler );
862 return false;
863 }
864
865 sqlite3_free_table( results );
866 if ( rows >= 1 )
867 return true;
868
869 return false;
870}
871
872sqlite3_database_unique_ptr QgsAuxiliaryStorage::open( const QString &filename )
873{
875
876 if ( filename.isEmpty() )
877 {
878 if ( ( database = createDB( currentFileName() ) ) )
879 mValid = true;
880 }
881 else if ( QFile::exists( filename ) )
882 {
883 if ( mCopy )
884 QFile::copy( filename, mTmpFileName );
885
886 if ( ( database = openDB( currentFileName() ) ) )
887 mValid = true;
888 }
889 else
890 {
891 if ( ( database = createDB( currentFileName() ) ) )
892 mValid = true;
893 }
894
895 return database;
896}
897
898sqlite3_database_unique_ptr QgsAuxiliaryStorage::open( const QgsProject &project )
899{
900 return open( filenameForProject( project ) );
901}
902
903QString QgsAuxiliaryStorage::filenameForProject( const QgsProject &project )
904{
905 const QFileInfo info( project.absoluteFilePath() );
906 const QString path = info.path() + QDir::separator() + info.baseName();
907 return path + '.' + QgsAuxiliaryStorage::extension();
908}
909
910void QgsAuxiliaryStorage::initTmpFileName()
911{
912 QTemporaryFile tmpFile;
913 tmpFile.open();
914 tmpFile.close();
915 mTmpFileName = tmpFile.fileName();
916}
917
919{
920 if ( mCopy || mFileName.isEmpty() )
921 return mTmpFileName;
922 else
923 return mFileName;
924}
925
926QgsDataSourceUri QgsAuxiliaryStorage::parseOgrUri( const QgsDataSourceUri &uri )
927{
928 QgsDataSourceUri newUri;
929
930 // parsing for ogr style uri :
931 // " filePath|layername='tableName' table="" sql="
932 QStringList uriParts = uri.uri().split( '|' );
933 if ( uriParts.count() < 2 )
934 return newUri;
935
936 const QString databasePath = uriParts[0].replace( ' ', QString() );
937
938 const QString table = uriParts[1];
939 QStringList tableParts = table.split( ' ' );
940
941 if ( tableParts.count() < 1 )
942 return newUri;
943
944 const QString tableName = tableParts[0].replace( QLatin1String( "layername=" ), QString() );
945
946 newUri.setDataSource( QString(), tableName, QString() );
947 newUri.setDatabase( databasePath );
948
949 return newUri;
950}
@ Invalid
Invalid (not set) property.
@ Field
Field based property.
@ Expression
Expression based property.
virtual QStringList subProviders() const
Gets list of sub-providers within the layer's labeling.
virtual void setSettings(QgsPalLayerSettings *settings, const QString &providerId=QString())=0
Set pal settings for a specific provider (takes ownership).
virtual QgsPalLayerSettings settings(const QString &providerId=QString()) const =0
Gets associated label settings.
This is a container for configuration of the attribute table.
QVector< QgsAttributeTableConfig::ColumnConfig > columns() const
Gets the list with all columns and their configuration.
void update(const QgsFields &fields)
Update the configuration with the given fields.
void setColumns(const QVector< QgsAttributeTableConfig::ColumnConfig > &columns)
Set the list of columns visible in the attribute table.
Class allowing to manage the auxiliary storage for a vector layer.
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
static QgsField createAuxiliaryField(const QgsPropertyDefinition &definition)
Creates a new auxiliary field from a property definition.
static QgsPropertyDefinition propertyDefinitionFromField(const QgsField &field)
Returns the property definition from an auxiliary field.
bool clear()
Deletes all features from the layer.
bool addAuxiliaryField(const QgsPropertyDefinition &definition)
Adds an auxiliary field for the given property.
bool isHiddenProperty(int index) const
Returns true if the underlying field has to be hidden from editing tools like attribute table,...
QgsVectorLayer * toSpatialLayer() const
An auxiliary layer is not spatial.
bool deleteAttribute(int attr) override
Removes attribute from the layer and commits changes.
QgsFields auxiliaryFields() const
Returns a list of all auxiliary fields currently managed by the layer.
QgsAuxiliaryLayer(const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer)
Constructor.
bool save()
Commits changes and starts editing then.
int propertyFromIndex(int index) const
Returns the underlying property key for the field index.
QgsVectorLayerJoinInfo joinInfo() const
Returns information to use for joining with primary key and so on.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
QgsPropertyDefinition propertyDefinitionFromIndex(int index) const
Returns the property definition for the underlying field index.
bool exists(const QgsPropertyDefinition &definition) const
Returns true if the property is stored in the layer already, false otherwise.
static int createProperty(QgsPalLayerSettings::Property property, QgsVectorLayer *vlayer, bool overwriteExisting=true)
Creates if necessary a new auxiliary field for a PAL property and activates this property in settings...
int indexOfPropertyDefinition(const QgsPropertyDefinition &definition) const
Returns the index of the auxiliary field for a specific property definition.
static QString extension()
Returns the extension used for auxiliary databases.
QString errorString() const
Returns the underlying error string describing potential errors happening in saveAs().
bool save() const
Saves the current database.
static bool exists(const QgsProject &project)
Returns true if the auxiliary database yet exists for a project, false otherwise.
QgsAuxiliaryLayer * createAuxiliaryLayer(const QgsField &field, QgsVectorLayer *layer) const
Creates an auxiliary layer for a vector layer.
virtual ~QgsAuxiliaryStorage()
Destructor.
bool saveAs(const QString &filename)
Saves the current database to a new path.
bool isValid() const
Returns the status of the auxiliary storage currently defined.
QString currentFileName() const
Returns the path of the current database used.
QgsAuxiliaryStorage(const QgsProject &project, bool copy=true)
Constructor.
QString fileName() const
Returns the target filename of the database.
static bool deleteTable(const QgsDataSourceUri &uri)
Removes a table from the auxiliary storage.
static bool duplicateTable(const QgsDataSourceUri &uri, const QString &newTable)
Duplicates a table and its content.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the callout's property collection, used for data defined overrides.
Definition: qgscallout.h:351
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the callout's property collection, used for data defined overrides.
Definition: qgscallout.h:333
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in callouts.
Definition: qgscallout.cpp:193
Property
Data definable properties.
Definition: qgscallout.h:85
Class for storing the component parts of a RDBMS data source URI (e.g.
QString table() const
Returns the table name stored in the URI.
QString uri(bool expandAuthConfig=true) const
Returns the complete URI as a string.
void setDataSource(const QString &aSchema, const QString &aTable, const QString &aGeometryColumn, const QString &aSql=QString(), const QString &aKeyColumn=QString())
Sets all data source related members at once.
QString database() const
Returns the database name stored in the URI.
void setDatabase(const QString &database)
Sets the URI database name.
Stores the settings for rendering of all diagrams for a layer.
Property
Data definable properties.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the diagram property definitions.
Holder for the widget type and its configuration for a field.
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QVariant::Type fieldType=QVariant::Type::Invalid)
Create an expression allowing to evaluate if a field is equal to a value.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:216
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:335
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:53
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:150
QString name
Definition: qgsfield.h:62
void setPrecision(int precision)
Set the field precision.
Definition: qgsfield.cpp:240
void setName(const QString &name)
Set the field name.
Definition: qgsfield.cpp:216
void setLength(int len)
Set the field length.
Definition: qgsfield.cpp:236
QVariant::Type type
Definition: qgsfield.h:60
void setType(QVariant::Type type)
Set variant type.
Definition: qgsfield.cpp:221
void setTypeName(const QString &typeName)
Set the field type.
Definition: qgsfield.cpp:231
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:168
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
QString source() const
Returns the source for the layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:81
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Qgis::LayerType type
Definition: qgsmaplayer.h:82
static QgsVectorLayer * createMemoryLayer(const QString &name, const QgsFields &fields, Qgis::WkbType geometryType=Qgis::WkbType::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem(), bool loadDefaultStyle=true) SIP_FACTORY
Creates a new memory layer using the specified parameters.
Contains settings for how a map layer will be labeled.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the label's property collection, used for data defined overrides.
QgsCallout * callout() const
Returns the label callout renderer, responsible for drawing label callouts.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the label's property collection, used for data defined overrides.
Property
Data definable properties.
@ PositionX
X-coordinate data defined label position.
@ MinScale
Min scale (deprecated, for old project compatibility only)
@ LabelRotation
Label rotation.
@ FontStyle
Font style name.
@ Italic
Use italic style.
@ PositionY
Y-coordinate data defined label position.
@ Vali
Vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top)
@ MaxScale
Max scale (deprecated, for old project compatibility only)
@ LabelAllParts
Whether all parts of multi-part features should be labeled.
@ Hali
Horizontal alignment for data defined label position (Left, Center, Right)
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the labeling property definitions.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:107
QString absoluteFilePath() const
Returns full absolute path to the project file if the project is stored in a file system - derived fr...
Definition: qgsproject.cpp:882
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Definition for a property.
Definition: qgsproperty.h:45
StandardPropertyTemplate standardTemplate() const
Returns the property's standard template, if applicable.
Definition: qgsproperty.h:192
QString comment() const
Returns the comment of the property.
Definition: qgsproperty.h:166
DataType dataType() const
Returns the allowable field/value data type for the property.
Definition: qgsproperty.h:186
void setOrigin(const QString &origin)
Sets the origin of the property.
Definition: qgsproperty.h:156
@ ColorNoAlpha
Color with no alpha channel.
Definition: qgsproperty.h:63
@ ColorWithAlpha
Color with alpha channel.
Definition: qgsproperty.h:62
QString name() const
Returns the name of the property.
Definition: qgsproperty.h:137
void setDataType(DataType type)
Sets the data type.
Definition: qgsproperty.h:181
void setName(const QString &name)
Sets the name of the property.
Definition: qgsproperty.h:142
QString origin() const
Returns the origin of the property.
Definition: qgsproperty.h:149
void setComment(const QString &comment)
Sets comment of the property.
Definition: qgsproperty.h:171
@ DataTypeString
Property requires a string value.
Definition: qgsproperty.h:90
@ DataTypeBoolean
Property requires a boolean value.
Definition: qgsproperty.h:104
@ DataTypeNumeric
Property requires a numeric value.
Definition: qgsproperty.h:97
A store for object properties.
Definition: qgsproperty.h:228
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
QString expressionString() const
Returns the expression used for the property value.
Qgis::PropertyType propertyType() const
Returns the property type.
QString field() const
Returns the current field name the property references.
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
@ Offset
Symbol offset.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol layer property definitions.
Defines left outer join from our vector layer to some other vector layer.
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
bool addAttribute(const QgsField &field)
Add an attribute field (but does not commit it) returns true if the field was added.
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
const QgsDiagramLayerSettings * diagramLayerSettings() const
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool deleteFeatures(const QgsFeatureIds &fids, DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it)
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
virtual bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it).
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
Q_INVOKABLE bool commitChanges(bool stopEditing=true)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
QgsEditorWidgetSetup editorWidgetSetup(int index) const
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
QgsAttributeTableConfig attributeTableConfig() const
Returns the attribute table configuration object.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
void setAttributeTableConfig(const QgsAttributeTableConfig &attributeTableConfig)
Sets the attribute table configuration object.
void setDiagramLayerSettings(const QgsDiagramLayerSettings &s)
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Q_GLOBAL_STATIC_WITH_ARGS(PalPropertyList, palHiddenProperties,({ static_cast< int >(QgsPalLayerSettings::Property::PositionX), static_cast< int >(QgsPalLayerSettings::Property::PositionY), static_cast< int >(QgsPalLayerSettings::Property::Show), static_cast< int >(QgsPalLayerSettings::Property::LabelRotation), static_cast< int >(QgsPalLayerSettings::Property::Family), static_cast< int >(QgsPalLayerSettings::Property::FontStyle), static_cast< int >(QgsPalLayerSettings::Property::Size), static_cast< int >(QgsPalLayerSettings::Property::Bold), static_cast< int >(QgsPalLayerSettings::Property::Italic), static_cast< int >(QgsPalLayerSettings::Property::Underline), static_cast< int >(QgsPalLayerSettings::Property::Color), static_cast< int >(QgsPalLayerSettings::Property::Strikeout), static_cast< int >(QgsPalLayerSettings::Property::MultiLineAlignment), static_cast< int >(QgsPalLayerSettings::Property::BufferSize), static_cast< int >(QgsPalLayerSettings::Property::BufferDraw), static_cast< int >(QgsPalLayerSettings::Property::BufferColor), static_cast< int >(QgsPalLayerSettings::Property::LabelDistance), static_cast< int >(QgsPalLayerSettings::Property::Hali), static_cast< int >(QgsPalLayerSettings::Property::Vali), static_cast< int >(QgsPalLayerSettings::Property::ScaleVisibility), static_cast< int >(QgsPalLayerSettings::Property::MinScale), static_cast< int >(QgsPalLayerSettings::Property::MaxScale), static_cast< int >(QgsPalLayerSettings::Property::AlwaysShow), static_cast< int >(QgsPalLayerSettings::Property::CalloutDraw), static_cast< int >(QgsPalLayerSettings::Property::LabelAllParts) })) Q_GLOBAL_STATIC_WITH_ARGS(SymbolPropertyList
symbolHiddenProperties
QVector< int > SymbolPropertyList
#define AS_JOINFIELD
#define AS_JOINPREFIX
QVector< int > PalPropertyList
#define AS_EXTENSION
struct sqlite3 sqlite3
#define QgsDebugError(str)
Definition: qgslogger.h:38
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
const QString & typeName
int precision