QGIS API Documentation 3.43.0-Master (a93bf8b6462)
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
6 email : paul.blottiere@oslandia.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#include "qgsauxiliarystorage.h"
19#include "moc_qgsauxiliarystorage.cpp"
20#include "qgslogger.h"
21#include "qgssqliteutils.h"
22#include "qgsproject.h"
24#include "qgsdiagramrenderer.h"
26#include "qgssymbollayer.h"
27
28#include <sqlite3.h>
29#include <QFile>
30
31#define AS_JOINFIELD QStringLiteral( "ASPK" )
32#define AS_EXTENSION QStringLiteral( "qgd" )
33#define AS_JOINPREFIX QStringLiteral( "auxiliary_storage_" )
34
35typedef QVector<int> PalPropertyList;
36typedef QVector<int> SymbolPropertyList;
37
39{
40 static_cast< int >( QgsPalLayerSettings::Property::PositionX ),
41 static_cast< int >( QgsPalLayerSettings::Property::PositionY ),
42 static_cast< int >( QgsPalLayerSettings::Property::Show ),
44 static_cast< int >( QgsPalLayerSettings::Property::Family ),
45 static_cast< int >( QgsPalLayerSettings::Property::FontStyle ),
46 static_cast< int >( QgsPalLayerSettings::Property::Size ),
47 static_cast< int >( QgsPalLayerSettings::Property::Bold ),
48 static_cast< int >( QgsPalLayerSettings::Property::Italic ),
49 static_cast< int >( QgsPalLayerSettings::Property::Underline ),
50 static_cast< int >( QgsPalLayerSettings::Property::Color ),
51 static_cast< int >( QgsPalLayerSettings::Property::Strikeout ),
57 static_cast< int >( QgsPalLayerSettings::Property::Hali ),
58 static_cast< int >( QgsPalLayerSettings::Property::Vali ),
60 static_cast< int >( QgsPalLayerSettings::Property::MinScale ),
61 static_cast< int >( QgsPalLayerSettings::Property::MaxScale ),
65} ) )
67{
68 static_cast< int >( QgsSymbolLayer::Property::Angle ),
69 static_cast< int >( QgsSymbolLayer::Property::Offset )
70} ) )
71
72//
73// QgsAuxiliaryLayer
74//
75
76QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer )
77 : QgsVectorLayer( QStringLiteral( "%1|layername=%2" ).arg( filename, table ),
78 QStringLiteral( "%1_auxiliarystorage" ).arg( table ), QStringLiteral( "ogr" ) )
79 , mFileName( filename )
80 , mTable( table )
81 , mLayer( vlayer )
82{
83 // init join info
84 mJoinInfo.setPrefix( AS_JOINPREFIX );
85 mJoinInfo.setJoinLayer( this );
86 mJoinInfo.setJoinFieldName( AS_JOINFIELD );
87 mJoinInfo.setTargetFieldName( pkField );
88 mJoinInfo.setEditable( true );
89 mJoinInfo.setUpsertOnEdit( true );
90 mJoinInfo.setCascadedDelete( true );
91 mJoinInfo.setJoinFieldNamesBlockList( QStringList() << QStringLiteral( "rowid" ) ); // introduced by ogr provider
92}
93
95{
97 return new QgsAuxiliaryLayer( mJoinInfo.targetFieldName(), mFileName, target->id(), target );
98}
99
101{
102 const bool rc = deleteFeatures( allFeatureIds() );
104 startEditing();
105 return rc;
106}
107
109{
110 QgsVectorLayer *layer = QgsMemoryProviderUtils::createMemoryLayer( QStringLiteral( "auxiliary_layer" ), fields(), mLayer->wkbType(), mLayer->crs() );
111
112 const QString pkField = mJoinInfo.targetFieldName();
113 QgsFeature joinFeature;
114 QgsFeature targetFeature;
116
117 layer->startEditing();
118 while ( it.nextFeature( joinFeature ) )
119 {
120 const QString filter = QgsExpression::createFieldEqualityExpression( pkField, joinFeature.attribute( AS_JOINFIELD ) );
121
122 QgsFeatureRequest request;
123 request.setFilterExpression( filter );
124
125 mLayer->getFeatures( request ).nextFeature( targetFeature );
126
127 if ( targetFeature.isValid() )
128 {
129 QgsFeature newFeature( joinFeature );
130 newFeature.setGeometry( targetFeature.geometry() );
131 layer->addFeature( newFeature );
132 }
133 }
134 layer->commitChanges();
135
136 return layer;
137}
138
140{
141 return mJoinInfo;
142}
143
144bool QgsAuxiliaryLayer::exists( const QgsPropertyDefinition &definition ) const
145{
146 return ( indexOfPropertyDefinition( definition ) >= 0 );
147}
148
150{
151 if ( ( definition.name().isEmpty() && definition.comment().isEmpty() ) || exists( definition ) )
152 return false;
153
154 const QgsField af = createAuxiliaryField( definition );
155 const bool rc = addAttribute( af );
156 updateFields();
157 mLayer->updateFields();
158
159 if ( rc )
160 {
161 const int auxIndex = indexOfPropertyDefinition( definition );
162 const int index = mLayer->fields().indexOf( nameFromProperty( definition, true ) );
163
164 if ( index >= 0 && auxIndex >= 0 )
165 {
166 if ( isHiddenProperty( auxIndex ) )
167 {
168 // update editor widget
169 const QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Hidden" ), QVariantMap() );
170 setEditorWidgetSetup( auxIndex, setup );
171
172 // column is hidden
174 attrCfg.update( mLayer->fields() );
175 QVector<QgsAttributeTableConfig::ColumnConfig> columns = attrCfg.columns();
176 QVector<QgsAttributeTableConfig::ColumnConfig>::iterator it;
177
178 for ( it = columns.begin(); it != columns.end(); ++it )
179 {
180 if ( it->name.compare( mLayer->fields().field( index ).name() ) == 0 )
181 it->hidden = true;
182 }
183
184 attrCfg.setColumns( columns );
185 mLayer->setAttributeTableConfig( attrCfg );
186 }
189 {
190 const QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Color" ), QVariantMap() );
191 setEditorWidgetSetup( auxIndex, setup );
192 }
193
194 mLayer->setEditorWidgetSetup( index, editorWidgetSetup( auxIndex ) );
195 }
196 }
197
198 return rc;
199}
200
202{
203 QgsFields afields;
204
205 for ( int i = 2; i < fields().count(); i++ ) // ignore rowid and PK field
206 afields.append( createAuxiliaryField( fields().field( i ) ) );
207
208 return afields;
209}
210
212{
214 const bool rc = commitChanges();
215 startEditing();
216 return rc;
217}
218
220{
221 bool rc = false;
222
223 if ( isEditable() )
224 {
225 rc = commitChanges();
226 }
227
228 startEditing();
229
230 return rc;
231}
232
233int QgsAuxiliaryLayer::createProperty( QgsPalLayerSettings::Property property, QgsVectorLayer *layer, bool overwriteExisting )
234{
235 int index = -1;
236
237 if ( layer && layer->labeling() && layer->auxiliaryLayer() )
238 {
239 // property definition are identical whatever the provider id
240 const QgsPropertyDefinition def = QgsPalLayerSettings::propertyDefinitions()[static_cast< int >( property )];
241 const QString fieldName = nameFromProperty( def, true );
242
243 layer->auxiliaryLayer()->addAuxiliaryField( def );
244
245 if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
246 {
247 const QStringList subProviderIds = layer->labeling()->subProviders();
248 for ( const QString &providerId : subProviderIds )
249 {
250 QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
251
253
254 // is there an existing property?
255 const QgsProperty existingProperty = c.property( property );
256 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid
257 || ( existingProperty.propertyType() == Qgis::PropertyType::Field && existingProperty.field().isEmpty() )
258 || ( existingProperty.propertyType() == Qgis::PropertyType::Expression && existingProperty.expressionString().isEmpty() )
259 || overwriteExisting )
260 {
261 const QgsProperty prop = QgsProperty::fromField( fieldName );
262 c.setProperty( property, prop );
263 }
264 else
265 {
266 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
267 const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
268 existingProperty.asExpression() ) );
269 c.setProperty( property, prop );
270 }
271 settings->setDataDefinedProperties( c );
272
273 layer->labeling()->setSettings( settings, providerId );
274 }
275 }
276
277 index = layer->fields().lookupField( fieldName );
278 }
279
280 return index;
281}
282
283int QgsAuxiliaryLayer::createProperty( QgsDiagramLayerSettings::Property property, QgsVectorLayer *layer, bool overwriteExisting )
284{
285 int index = -1;
286
287 if ( layer && layer->diagramLayerSettings() && layer->auxiliaryLayer() )
288 {
289 const QgsPropertyDefinition def = QgsDiagramLayerSettings::propertyDefinitions()[static_cast<int>( property )];
290
291 if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) )
292 {
293 const QString fieldName = nameFromProperty( def, true );
294
295 QgsDiagramLayerSettings settings( *layer->diagramLayerSettings() );
296
298 // is there an existing property?
299 const QgsProperty existingProperty = c.property( property );
300 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid || overwriteExisting )
301 {
302 const QgsProperty prop = QgsProperty::fromField( fieldName );
303 c.setProperty( property, prop );
304 }
305 else
306 {
307 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
308 const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
309 existingProperty.asExpression() ) );
310 c.setProperty( property, prop );
311 }
312 settings.setDataDefinedProperties( c );
313
314 layer->setDiagramLayerSettings( settings );
315 index = layer->fields().lookupField( fieldName );
316 }
317 }
318
319 return index;
320}
321
322int QgsAuxiliaryLayer::createProperty( QgsCallout::Property property, QgsVectorLayer *layer, bool overwriteExisting )
323{
324 int index = -1;
325
326 if ( layer && layer->labeling() && layer->labeling()->settings().callout() && layer->auxiliaryLayer() )
327 {
328 // property definition are identical whatever the provider id
329 const QgsPropertyDefinition def = QgsCallout::propertyDefinitions()[static_cast< int >( property )];
330 const QString fieldName = nameFromProperty( def, true );
331
332 layer->auxiliaryLayer()->addAuxiliaryField( def );
333
334 if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
335 {
336 const QStringList subProviderIds = layer->labeling()->subProviders();
337 for ( const QString &providerId : subProviderIds )
338 {
339 QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
340 if ( settings->callout() )
341 {
343 // is there an existing property?
344 const QgsProperty existingProperty = c.property( property );
345 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid || overwriteExisting )
346 {
347 const QgsProperty prop = QgsProperty::fromField( fieldName );
348 c.setProperty( property, prop );
349 }
350 else
351 {
352 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
353 const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
354 existingProperty.asExpression() ) );
355 c.setProperty( property, prop );
356 }
357 settings->callout()->setDataDefinedProperties( c );
358 }
359 layer->labeling()->setSettings( settings, providerId );
360 }
361 }
362
363 index = layer->fields().lookupField( fieldName );
364 }
365
366 return index;
367}
368
369bool QgsAuxiliaryLayer::isHiddenProperty( int index ) const
370{
371 bool hidden = false;
373
374 if ( def.origin().compare( QLatin1String( "labeling" ) ) == 0 )
375 {
376 const PalPropertyList &palProps = *palHiddenProperties();
377 for ( const int p : palProps )
378 {
379 const QString propName = QgsPalLayerSettings::propertyDefinitions()[ p ].name();
380 if ( propName.compare( def.name() ) == 0 )
381 {
382 hidden = true;
383 break;
384 }
385 }
386 }
387 else if ( def.origin().compare( QLatin1String( "symbol" ) ) == 0 )
388 {
389 const SymbolPropertyList &symbolProps = *symbolHiddenProperties();
390 for ( int p : symbolProps )
391 {
392 const QString propName = QgsSymbolLayer::propertyDefinitions()[ p ].name();
393 if ( propName.compare( def.name() ) == 0 )
394 {
395 hidden = true;
396 break;
397 }
398 }
399 }
400
401 return hidden;
402}
403
404int QgsAuxiliaryLayer::propertyFromIndex( int index ) const
405{
406 int p = -1;
408
409 if ( aDef.origin().compare( QLatin1String( "labeling" ) ) == 0 )
410 {
412 QgsPropertiesDefinition::const_iterator it = defs.constBegin();
413 for ( ; it != defs.constEnd(); ++it )
414 {
415 if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
416 {
417 p = it.key();
418 break;
419 }
420 }
421 }
422 else if ( aDef.origin().compare( QLatin1String( "symbol" ) ) == 0 )
423 {
425 QgsPropertiesDefinition::const_iterator it = defs.constBegin();
426 for ( ; it != defs.constEnd(); ++it )
427 {
428 if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
429 {
430 p = it.key();
431 break;
432 }
433 }
434 }
435 else if ( aDef.origin().compare( QLatin1String( "diagram" ) ) == 0 )
436 {
438 QgsPropertiesDefinition::const_iterator it = defs.constBegin();
439 for ( ; it != defs.constEnd(); ++it )
440 {
441 if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
442 {
443 p = it.key();
444 break;
445 }
446 }
447 }
448
449 return p;
450}
451
453{
454 return propertyDefinitionFromField( fields().field( index ) );
455}
456
458{
459 return fields().indexOf( nameFromProperty( def ) );
460}
461
462QString QgsAuxiliaryLayer::nameFromProperty( const QgsPropertyDefinition &def, bool joined )
463{
464 QString fieldName = def.origin();
465
466 if ( !def.name().isEmpty() )
467 fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.name().toLower() );
468
469 if ( !def.comment().isEmpty() )
470 fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.comment() );
471
472 if ( joined )
473 fieldName = QStringLiteral( "%1%2" ).arg( AS_JOINPREFIX, fieldName );
474
475 return fieldName;
476}
477
479{
480 QgsField afield;
481
482 if ( !def.name().isEmpty() || !def.comment().isEmpty() )
483 {
484 QMetaType::Type type = QMetaType::Type::UnknownType;
485 QString typeName;
486 int len( 0 ), precision( 0 );
487 switch ( def.dataType() )
488 {
490 type = QMetaType::Type::QString;
491 len = 50;
492 typeName = QStringLiteral( "String" );
493 break;
495 type = QMetaType::Type::Double;
496 len = 0;
497 precision = 0;
498 typeName = QStringLiteral( "Real" );
499 break;
501 type = QMetaType::Type::Int; // sqlite does not have a bool type
502 typeName = QStringLiteral( "Integer" );
503 break;
504 }
505
506 afield.setType( type );
507 afield.setName( nameFromProperty( def ) );
508 afield.setTypeName( typeName );
509 afield.setLength( len );
510 afield.setPrecision( precision );
511 }
512
513 return afield;
514}
515
517{
519 const QStringList parts = f.name().split( '_' );
520
521 if ( parts.size() <= 1 )
522 return def;
523
524 const QString origin = parts[0];
525 const QString propertyName = parts[1];
526
527 if ( origin.compare( QLatin1String( "labeling" ), Qt::CaseInsensitive ) == 0 )
528 {
530 for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
531 {
532 if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
533 {
534 def = it.value();
535 if ( parts.size() >= 3 )
536 def.setComment( parts.mid( 2 ).join( '_' ) );
537 break;
538 }
539 }
540 }
541 else if ( origin.compare( QLatin1String( "symbol" ), Qt::CaseInsensitive ) == 0 )
542 {
544 for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
545 {
546 if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
547 {
548 def = it.value();
549 if ( parts.size() >= 3 )
550 def.setComment( parts.mid( 2 ).join( '_' ) );
551 break;
552 }
553 }
554 }
555 else if ( origin.compare( QLatin1String( "diagram" ), Qt::CaseInsensitive ) == 0 )
556 {
558 for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
559 {
560 if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
561 {
562 def = it.value();
563 if ( parts.size() >= 3 )
564 def.setComment( parts.mid( 2 ).join( '_' ) );
565 break;
566 }
567 }
568 }
569 else
570 {
571 def.setOrigin( origin );
572 def.setName( propertyName );
573 switch ( f.type() )
574 {
575 case QMetaType::Type::Double:
577 break;
578
579 case QMetaType::Type::Bool:
581 break;
582
583 case QMetaType::Type::QString:
584 default:
586 break;
587 }
588
589 if ( parts.size() >= 3 )
590 def.setComment( parts.mid( 2 ).join( '_' ) );
591 }
592
593 return def;
594}
595
597{
599 QgsField afield;
600
601 if ( !def.name().isEmpty() || !def.comment().isEmpty() )
602 {
603 afield = createAuxiliaryField( def );
604 afield.setTypeName( field.typeName() );
605 }
606
607 return afield;
608}
609
610//
611// QgsAuxiliaryStorage
612//
613
614QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QgsProject &project, bool copy )
615 : mCopy( copy )
616{
617 initTmpFileName();
618
619 if ( !project.absoluteFilePath().isEmpty() )
620 {
621 mFileName = filenameForProject( project );
622 }
623
624 open( mFileName );
625}
626
627QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QString &filename, bool copy )
628 : mFileName( filename )
629 , mCopy( copy )
630{
631 initTmpFileName();
632
633 open( filename );
634}
635
637{
638 if ( QFile::exists( mTmpFileName ) )
639 QFile::remove( mTmpFileName );
640}
641
643{
644 return mValid;
645}
646
647QString QgsAuxiliaryStorage::fileName() const
648{
649 return mFileName;
650}
651
652bool QgsAuxiliaryStorage::save() const
653{
654 if ( mFileName.isEmpty() )
655 {
656 // only a saveAs is available on a new database
657 return false;
658 }
659 else if ( mCopy )
660 {
661 if ( QFile::exists( mFileName ) )
662 QFile::remove( mFileName );
663
664 return QFile::copy( mTmpFileName, mFileName );
665 }
666 else
667 {
668 // if the file is not empty the copy mode is not activated, then we're
669 // directly working on the database since the beginning (no savepoints
670 // /rollback for now)
671 return true;
672 }
673}
674
676{
677 QgsAuxiliaryLayer *alayer = nullptr;
678
679 if ( mValid && layer )
680 {
681 const QString table( layer->id() );
683 database = openDB( currentFileName() );
684
685 if ( !tableExists( table, database.get() ) )
686 {
687 if ( !createTable( field.typeName(), table, database.get(), mErrorString ) )
688 {
689 return alayer;
690 }
691 }
692
693 alayer = new QgsAuxiliaryLayer( field.name(), currentFileName(), table, layer );
694 alayer->startEditing();
695 }
696
697 return alayer;
698}
699
701{
702 bool rc = false;
703 const QgsDataSourceUri uri = parseOgrUri( ogrUri );
704
705 if ( !uri.database().isEmpty() && !uri.table().isEmpty() )
706 {
708 database = openDB( uri.database() );
709
710 if ( database )
711 {
712 QString sql = QStringLiteral( "DROP TABLE %1" ).arg( uri.table() );
713 rc = exec( sql, database.get() );
714
715 sql = QStringLiteral( "VACUUM" );
716 rc = exec( sql, database.get() );
717 }
718 }
719
720 return rc;
721}
722
723bool QgsAuxiliaryStorage::duplicateTable( const QgsDataSourceUri &ogrUri, const QString &newTable )
724{
725 const QgsDataSourceUri uri = parseOgrUri( ogrUri );
726 bool rc = false;
727
728 if ( !uri.table().isEmpty() && !uri.database().isEmpty() )
729 {
731 database = openDB( uri.database() );
732
733 if ( database )
734 {
735 const QString sql = QStringLiteral( "CREATE TABLE %1 AS SELECT * FROM %2" ).arg( newTable, uri.table() );
736 rc = exec( sql, database.get() );
737 }
738 }
739
740 return rc;
741}
742
744{
745 return mErrorString;
746}
747
748bool QgsAuxiliaryStorage::saveAs( const QString &filename )
749{
750 mErrorString.clear();
751
752 QFile dest( filename );
753 if ( dest.exists() && !dest.remove() )
754 {
755 mErrorString = dest.errorString();
756 return false;
757 }
758
759 QFile origin( currentFileName() );
760 if ( !origin.copy( filename ) )
761 {
762 mErrorString = origin.errorString();
763 return false;
764 }
765
766 return true;
767}
768
769bool QgsAuxiliaryStorage::saveAs( const QgsProject &project )
770{
771 return saveAs( filenameForProject( project ) );
772}
773
775{
776 return AS_EXTENSION;
777}
778
779bool QgsAuxiliaryStorage::exists( const QgsProject &project )
780{
781 const QFileInfo fileinfo( filenameForProject( project ) );
782 return fileinfo.exists() && fileinfo.isFile();
783}
784
785bool QgsAuxiliaryStorage::exec( const QString &sql, sqlite3 *handler )
786{
787 bool rc = false;
788
789 if ( handler )
790 {
791 const int err = sqlite3_exec( handler, sql.toStdString().c_str(), nullptr, nullptr, nullptr );
792
793 if ( err == SQLITE_OK )
794 rc = true;
795 else
796 debugMsg( sql, handler );
797 }
798
799 return rc;
800}
801
802QString QgsAuxiliaryStorage::debugMsg( const QString &sql, sqlite3 *handler )
803{
804 const QString err = QString::fromUtf8( sqlite3_errmsg( handler ) );
805 const QString msg = QObject::tr( "Unable to execute" );
806 const QString errMsg = QObject::tr( "%1 '%2': %3" ).arg( msg, sql, err );
807 QgsDebugError( errMsg );
808 return errMsg;
809}
810
811bool QgsAuxiliaryStorage::createTable( const QString &type, const QString &table, sqlite3 *handler, QString &errorMsg )
812{
813 const QString sql = QStringLiteral( "CREATE TABLE IF NOT EXISTS '%1' ( '%2' %3 )" ).arg( table, AS_JOINFIELD, type );
814
815 if ( !exec( sql, handler ) )
816 {
817 errorMsg = QgsAuxiliaryStorage::debugMsg( sql, handler );
818 return false;
819 }
820
821 return true;
822}
823
824sqlite3_database_unique_ptr QgsAuxiliaryStorage::createDB( const QString &filename )
825{
827
828 int rc;
829 rc = database.open_v2( filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr );
830 if ( rc )
831 {
832 debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
833 }
834 else
835 // activating Foreign Key constraints
836 exec( QStringLiteral( "PRAGMA foreign_keys = 1" ), database.get() );
837
838 return database;
839}
840
841sqlite3_database_unique_ptr QgsAuxiliaryStorage::openDB( const QString &filename )
842{
844 const int rc = database.open_v2( filename, SQLITE_OPEN_READWRITE, nullptr );
845
846 if ( rc )
847 {
848 debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
849 }
850
851 return database;
852}
853
854bool QgsAuxiliaryStorage::tableExists( const QString &table, sqlite3 *handler )
855{
856 const QString sql = QStringLiteral( "SELECT 1 FROM sqlite_master WHERE type='table' AND name='%1'" ).arg( table );
857 int rows = 0;
858 int columns = 0;
859 char **results = nullptr;
860 const int rc = sqlite3_get_table( handler, sql.toStdString().c_str(), &results, &rows, &columns, nullptr );
861 if ( rc != SQLITE_OK )
862 {
863 debugMsg( sql, handler );
864 return false;
865 }
866
867 sqlite3_free_table( results );
868 if ( rows >= 1 )
869 return true;
870
871 return false;
872}
873
874sqlite3_database_unique_ptr QgsAuxiliaryStorage::open( const QString &filename )
875{
877
878 if ( filename.isEmpty() )
879 {
880 if ( ( database = createDB( currentFileName() ) ) )
881 mValid = true;
882 }
883 else if ( QFile::exists( filename ) )
884 {
885 if ( mCopy )
886 QFile::copy( filename, mTmpFileName );
887
888 if ( ( database = openDB( currentFileName() ) ) )
889 mValid = true;
890 }
891 else
892 {
893 if ( ( database = createDB( currentFileName() ) ) )
894 mValid = true;
895 }
896
897 return database;
898}
899
900sqlite3_database_unique_ptr QgsAuxiliaryStorage::open( const QgsProject &project )
901{
902 return open( filenameForProject( project ) );
903}
904
905QString QgsAuxiliaryStorage::filenameForProject( const QgsProject &project )
906{
907 const QFileInfo info( project.absoluteFilePath() );
908 const QString path = info.path() + QDir::separator() + info.baseName();
909 return path + '.' + QgsAuxiliaryStorage::extension();
910}
911
912void QgsAuxiliaryStorage::initTmpFileName()
913{
914 QTemporaryFile tmpFile;
915 tmpFile.open();
916 tmpFile.close();
917 mTmpFileName = tmpFile.fileName();
918}
919
921{
922 if ( mCopy || mFileName.isEmpty() )
923 return mTmpFileName;
924 else
925 return mFileName;
926}
927
928QgsDataSourceUri QgsAuxiliaryStorage::parseOgrUri( const QgsDataSourceUri &uri )
929{
930 QgsDataSourceUri newUri;
931
932 // parsing for ogr style uri :
933 // " filePath|layername='tableName' table="" sql="
934 QStringList uriParts = uri.uri().split( '|' );
935 if ( uriParts.count() < 2 )
936 return newUri;
937
938 const QString databasePath = uriParts[0].replace( ' ', QString() );
939
940 const QString table = uriParts[1];
941 QStringList tableParts = table.split( ' ' );
942
943 if ( tableParts.count() < 1 )
944 return newUri;
945
946 const QString tableName = tableParts[0].replace( QLatin1String( "layername=" ), QString() );
947
948 newUri.setDataSource( QString(), tableName, QString() );
949 newUri.setDatabase( databasePath );
950
951 return newUri;
952}
@ 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.
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.
Allows managing 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()
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:352
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the callout's property collection, used for data defined overrides.
Definition qgscallout.h:334
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in callouts.
Property
Data definable properties.
Definition qgscallout.h:86
Stores the component parts of a 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, QMetaType::Type fieldType=QMetaType::Type::UnknownType)
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.
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:58
QgsGeometry geometry
Definition qgsfeature.h:69
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
QMetaType::Type type
Definition qgsfield.h:60
QString typeName() const
Gets the field type.
Definition qgsfield.cpp:162
QString name
Definition qgsfield.h:62
void setPrecision(int precision)
Set the field precision.
Definition qgsfield.cpp:262
void setName(const QString &name)
Set the field name.
Definition qgsfield.cpp:228
void setType(QMetaType::Type type)
Set variant type.
Definition qgsfield.cpp:233
void setLength(int len)
Set the field length.
Definition qgsfield.cpp:258
void setTypeName(const QString &typeName)
Set the field type.
Definition qgsfield.cpp:253
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:70
int count
Definition qgsfields.h:50
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
QString source() const
Returns the source for the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:84
QString id
Definition qgsmaplayer.h:80
Qgis::LayerType type
Definition qgsmaplayer.h:87
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...
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
Definition for a property.
Definition qgsproperty.h:45
StandardPropertyTemplate standardTemplate() const
Returns the property's standard template, if applicable.
QString comment() const
Returns the comment of the property.
DataType dataType() const
Returns the allowable field/value data type for the property.
void setOrigin(const QString &origin)
Sets the origin of the property.
@ 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.
void setDataType(DataType type)
Sets the data type.
void setName(const QString &name)
Sets the name of the property.
QString origin() const
Returns the origin of the property.
void setComment(const QString &comment)
Sets comment of the property.
@ DataTypeString
Property requires a string value.
Definition qgsproperty.h:90
@ DataTypeBoolean
Property requires a boolean value.
@ DataTypeNumeric
Property requires a numeric value.
Definition qgsproperty.h:97
A store for object properties.
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 dataset.
Q_INVOKABLE bool deleteFeatures(const QgsFeatureIds &fids, QgsVectorLayer::DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it)
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.
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)
Sets the editor widget setup for the field at the specified index.
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
Returns the editor widget setup for the field at the specified index.
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:40
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
const QString & typeName
int precision