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