QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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
46 palHiddenProperties,
47 (
48 { static_cast< int >( QgsPalLayerSettings::Property::PositionX ),
49 static_cast< int >( QgsPalLayerSettings::Property::PositionY ),
50 static_cast< int >( QgsPalLayerSettings::Property::Show ),
52 static_cast< int >( QgsPalLayerSettings::Property::Family ),
53 static_cast< int >( QgsPalLayerSettings::Property::FontStyle ),
54 static_cast< int >( QgsPalLayerSettings::Property::Size ),
55 static_cast< int >( QgsPalLayerSettings::Property::Bold ),
56 static_cast< int >( QgsPalLayerSettings::Property::Italic ),
57 static_cast< int >( QgsPalLayerSettings::Property::Underline ),
58 static_cast< int >( QgsPalLayerSettings::Property::Color ),
59 static_cast< int >( QgsPalLayerSettings::Property::Strikeout ),
65 static_cast< int >( QgsPalLayerSettings::Property::Hali ),
66 static_cast< int >( QgsPalLayerSettings::Property::Vali ),
68 static_cast< int >( QgsPalLayerSettings::Property::MinScale ),
69 static_cast< int >( QgsPalLayerSettings::Property::MaxScale ),
73 )
74)
76
77//
78// QgsAuxiliaryLayer
79//
80
81QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer )
82 : QgsVectorLayer( u"%1|layername=%2"_s.arg( filename, table ), u"%1_auxiliarystorage"_s.arg( table ), u"ogr"_s )
83 , mFileName( filename )
84 , mTable( table )
85 , mLayer( vlayer )
86{
87 // init join info
88 mJoinInfo.setPrefix( AS_JOINPREFIX );
89 mJoinInfo.setJoinLayer( this );
90 mJoinInfo.setJoinFieldName( AS_JOINFIELD );
91 mJoinInfo.setTargetFieldName( pkField );
92 mJoinInfo.setEditable( true );
93 mJoinInfo.setUpsertOnEdit( true );
94 mJoinInfo.setCascadedDelete( true );
95 mJoinInfo.setJoinFieldNamesBlockList( QStringList() << u"rowid"_s ); // introduced by ogr provider
96}
97
99{
101 return new QgsAuxiliaryLayer( mJoinInfo.targetFieldName(), mFileName, target->id(), target );
102}
103
105{
106 const bool rc = deleteFeatures( allFeatureIds() );
108 startEditing();
109 return rc;
110}
111
113{
114 QgsVectorLayer *layer = QgsMemoryProviderUtils::createMemoryLayer( u"auxiliary_layer"_s, fields(), mLayer->wkbType(), mLayer->crs() );
115
116 const QString pkField = mJoinInfo.targetFieldName();
117 QgsFeature joinFeature;
118 QgsFeature targetFeature;
119 QgsFeatureIterator it = getFeatures();
120
121 layer->startEditing();
122 while ( it.nextFeature( joinFeature ) )
123 {
124 const QString filter = QgsExpression::createFieldEqualityExpression( pkField, joinFeature.attribute( AS_JOINFIELD ) );
125
126 QgsFeatureRequest request;
127 request.setFilterExpression( filter );
128
129 mLayer->getFeatures( request ).nextFeature( targetFeature );
130
131 if ( targetFeature.isValid() )
132 {
133 QgsFeature newFeature( joinFeature );
134 newFeature.setGeometry( targetFeature.geometry() );
135 layer->addFeature( newFeature );
136 }
137 }
138 layer->commitChanges();
139
140 return layer;
141}
142
144{
145 return mJoinInfo;
146}
147
148bool QgsAuxiliaryLayer::exists( const QgsPropertyDefinition &definition ) const
149{
150 return ( indexOfPropertyDefinition( definition ) >= 0 );
151}
152
154{
155 if ( ( definition.name().isEmpty() && definition.comment().isEmpty() ) || exists( definition ) )
156 return false;
157
158 const QgsField af = createAuxiliaryField( definition );
159 const bool rc = addAttribute( af );
160 updateFields();
161 mLayer->updateFields();
162
163 if ( rc )
164 {
165 const int auxIndex = indexOfPropertyDefinition( definition );
166 const int index = mLayer->fields().indexOf( nameFromProperty( definition, true ) );
167
168 if ( index >= 0 && auxIndex >= 0 )
169 {
170 if ( isHiddenProperty( auxIndex ) )
171 {
172 // update editor widget
173 const QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( u"Hidden"_s, QVariantMap() );
174 setEditorWidgetSetup( auxIndex, setup );
175
176 // column is hidden
177 QgsAttributeTableConfig attrCfg = mLayer->attributeTableConfig();
178 attrCfg.update( mLayer->fields() );
179 QVector<QgsAttributeTableConfig::ColumnConfig> columns = attrCfg.columns();
180 QVector<QgsAttributeTableConfig::ColumnConfig>::iterator it;
181
182 for ( it = columns.begin(); it != columns.end(); ++it )
183 {
184 if ( it->name.compare( mLayer->fields().field( index ).name() ) == 0 )
185 it->hidden = true;
186 }
187
188 attrCfg.setColumns( columns );
189 mLayer->setAttributeTableConfig( attrCfg );
190 }
192 {
193 const QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( u"Color"_s, QVariantMap() );
194 setEditorWidgetSetup( auxIndex, setup );
195 }
196
197 mLayer->setEditorWidgetSetup( index, editorWidgetSetup( auxIndex ) );
198 }
199 }
200
201 return rc;
202}
203
205{
206 QgsFields afields;
207
208 for ( int i = 2; i < fields().count(); i++ ) // ignore rowid and PK field
209 afields.append( createAuxiliaryField( fields().field( i ) ) );
210
211 return afields;
212}
213
215{
217 const bool rc = commitChanges();
218 startEditing();
219 return rc;
220}
221
223{
224 bool rc = false;
225
226 if ( isEditable() )
227 {
228 rc = commitChanges();
229 }
230
231 startEditing();
232
233 return rc;
234}
235
236int QgsAuxiliaryLayer::createProperty( QgsPalLayerSettings::Property property, QgsVectorLayer *layer, bool overwriteExisting )
237{
238 int index = -1;
239
240 if ( layer && layer->labeling() && layer->auxiliaryLayer() )
241 {
242 // property definition are identical whatever the provider id
243 const QgsPropertyDefinition def = QgsPalLayerSettings::propertyDefinitions()[static_cast< int >( property )];
244 const QString fieldName = nameFromProperty( def, true );
245
246 layer->auxiliaryLayer()->addAuxiliaryField( def );
247
248 if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
249 {
250 const QStringList subProviderIds = layer->labeling()->subProviders();
251 for ( const QString &providerId : subProviderIds )
252 {
253 QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
254
255 QgsPropertyCollection c = settings->dataDefinedProperties();
256
257 // is there an existing property?
258 const QgsProperty existingProperty = c.property( property );
259 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid
260 || ( existingProperty.propertyType() == Qgis::PropertyType::Field && existingProperty.field().isEmpty() )
261 || ( existingProperty.propertyType() == Qgis::PropertyType::Expression && existingProperty.expressionString().isEmpty() )
262 || overwriteExisting )
263 {
264 const QgsProperty prop = QgsProperty::fromField( fieldName );
265 c.setProperty( property, prop );
266 }
267 else
268 {
269 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
270 const QgsProperty prop = QgsProperty::fromExpression( u"coalesce(%1,%2)"_s.arg( QgsExpression::quotedColumnRef( fieldName ), existingProperty.asExpression() ) );
271 c.setProperty( property, prop );
272 }
273 settings->setDataDefinedProperties( c );
274
275 layer->labeling()->setSettings( settings, providerId );
276 }
277 }
278
279 index = layer->fields().lookupField( fieldName );
280 }
281
282 return index;
283}
284
285int QgsAuxiliaryLayer::createProperty( QgsDiagramLayerSettings::Property property, QgsVectorLayer *layer, bool overwriteExisting )
286{
287 int index = -1;
288
289 if ( layer && layer->diagramLayerSettings() && layer->auxiliaryLayer() )
290 {
291 const QgsPropertyDefinition def = QgsDiagramLayerSettings::propertyDefinitions()[static_cast<int>( property )];
292
293 if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) )
294 {
295 const QString fieldName = nameFromProperty( def, true );
296
297 QgsDiagramLayerSettings settings( *layer->diagramLayerSettings() );
298
299 QgsPropertyCollection c = settings.dataDefinedProperties();
300 // is there an existing property?
301 const QgsProperty existingProperty = c.property( property );
302 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid || overwriteExisting )
303 {
304 const QgsProperty prop = QgsProperty::fromField( fieldName );
305 c.setProperty( property, prop );
306 }
307 else
308 {
309 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
310 const QgsProperty prop = QgsProperty::fromExpression( u"coalesce(%1,%2)"_s.arg( QgsExpression::quotedColumnRef( fieldName ), existingProperty.asExpression() ) );
311 c.setProperty( property, prop );
312 }
313 settings.setDataDefinedProperties( c );
314
315 layer->setDiagramLayerSettings( settings );
316 index = layer->fields().lookupField( fieldName );
317 }
318 }
319
320 return index;
321}
322
323int QgsAuxiliaryLayer::createProperty( QgsCallout::Property property, QgsVectorLayer *layer, bool overwriteExisting )
324{
325 int index = -1;
326
327 if ( layer && layer->labeling() && layer->labeling()->settings().callout() && layer->auxiliaryLayer() )
328 {
329 // property definition are identical whatever the provider id
330 const QgsPropertyDefinition def = QgsCallout::propertyDefinitions()[static_cast< int >( property )];
331 const QString fieldName = nameFromProperty( def, true );
332
333 layer->auxiliaryLayer()->addAuxiliaryField( def );
334
335 if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
336 {
337 const QStringList subProviderIds = layer->labeling()->subProviders();
338 for ( const QString &providerId : subProviderIds )
339 {
340 QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
341 if ( settings->callout() )
342 {
343 QgsPropertyCollection c = settings->callout()->dataDefinedProperties();
344 // is there an existing property?
345 const QgsProperty existingProperty = c.property( property );
346 if ( existingProperty.propertyType() == Qgis::PropertyType::Invalid || overwriteExisting )
347 {
348 const QgsProperty prop = QgsProperty::fromField( fieldName );
349 c.setProperty( property, prop );
350 }
351 else
352 {
353 // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
354 const QgsProperty prop = QgsProperty::fromExpression( u"coalesce(%1,%2)"_s.arg( QgsExpression::quotedColumnRef( fieldName ), 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;
372 const QgsPropertyDefinition def = propertyDefinitionFromIndex( index );
373
374 if ( def.origin().compare( "labeling"_L1 ) == 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( "symbol"_L1 ) == 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;
407 const QgsPropertyDefinition aDef = propertyDefinitionFromIndex( index );
408
409 if ( aDef.origin().compare( "labeling"_L1 ) == 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( "symbol"_L1 ) == 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( "diagram"_L1 ) == 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 = u"%1_%2"_s.arg( fieldName, def.name().toLower() );
468
469 if ( !def.comment().isEmpty() )
470 fieldName = u"%1_%2"_s.arg( fieldName, def.comment() );
471
472 if ( joined )
473 fieldName = u"%1%2"_s.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 = u"String"_s;
493 break;
495 type = QMetaType::Type::Double;
496 len = 0;
497 precision = 0;
498 typeName = u"Real"_s;
499 break;
501 type = QMetaType::Type::Int; // sqlite does not have a bool type
502 typeName = u"Integer"_s;
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{
518 QgsPropertyDefinition def;
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( "labeling"_L1, 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( "symbol"_L1, 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( "diagram"_L1, 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{
598 const QgsPropertyDefinition def = propertyDefinitionFromField( field );
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() );
682 sqlite3_database_unique_ptr database;
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 {
707 sqlite3_database_unique_ptr database;
708 database = openDB( uri.database() );
709
710 if ( database )
711 {
712 QString sql = u"DROP TABLE %1"_s.arg( uri.table() );
713 rc = exec( sql, database.get() );
714
715 sql = u"VACUUM"_s;
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 {
730 sqlite3_database_unique_ptr database;
731 database = openDB( uri.database() );
732
733 if ( database )
734 {
735 const QString sql = u"CREATE TABLE %1 AS SELECT * FROM %2"_s.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 = u"CREATE TABLE IF NOT EXISTS '%1' ( '%2' %3 )"_s.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{
826 sqlite3_database_unique_ptr database;
827
828 int rc;
829 rc = database.open_v2( filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr );
830 if ( rc )
831 {
832 debugMsg( u"sqlite3_open_v2"_s, database.get() );
833 }
834 else
835 // activating Foreign Key constraints
836 exec( u"PRAGMA foreign_keys = 1"_s, database.get() );
837
838 return database;
839}
840
841sqlite3_database_unique_ptr QgsAuxiliaryStorage::openDB( const QString &filename )
842{
843 sqlite3_database_unique_ptr database;
844 const int rc = database.open_v2( filename, SQLITE_OPEN_READWRITE, nullptr );
845
846 if ( rc )
847 {
848 debugMsg( u"sqlite3_open_v2"_s, database.get() );
849 }
850
851 return database;
852}
853
854bool QgsAuxiliaryStorage::tableExists( const QString &table, sqlite3 *handler )
855{
856 const QString sql = u"SELECT 1 FROM sqlite_master WHERE type='table' AND name='%1'"_s.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{
876 sqlite3_database_unique_ptr database;
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 if ( !tmpFile.open() )
916 {
917 QgsDebugError( u"Can't open temporary file"_s );
918 return;
919 }
920 tmpFile.close();
921 mTmpFileName = tmpFile.fileName();
922}
923
925{
926 if ( mCopy || mFileName.isEmpty() )
927 return mTmpFileName;
928 else
929 return mFileName;
930}
931
932QgsDataSourceUri QgsAuxiliaryStorage::parseOgrUri( const QgsDataSourceUri &uri )
933{
934 QgsDataSourceUri newUri;
935
936 // parsing for ogr style uri :
937 // " filePath|layername='tableName' table="" sql="
938 QStringList uriParts = uri.uri().split( '|' );
939 if ( uriParts.count() < 2 )
940 return newUri;
941
942 const QString databasePath = uriParts[0].replace( ' ', QString() );
943
944 const QString table = uriParts[1];
945 QStringList tableParts = table.split( ' ' );
946
947 if ( tableParts.count() < 1 )
948 return newUri;
949
950 const QString tableName = tableParts[0].replace( "layername="_L1, QString() );
951
952 newUri.setDataSource( QString(), tableName, QString() );
953 newUri.setDatabase( databasePath );
954
955 return newUri;
956}
@ Invalid
Invalid (not set) property.
Definition qgis.h:709
@ Field
Field based property.
Definition qgis.h:711
@ Expression
Expression based property.
Definition qgis.h:712
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: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.
Property
Data definable properties.
Definition qgscallout.h:85
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:158
QString name
Definition qgsfield.h:65
void setPrecision(int precision)
Set the field precision.
Definition qgsfield.cpp:258
void setName(const QString &name)
Set the field name.
Definition qgsfield.cpp:224
void setType(QMetaType::Type type)
Set variant type.
Definition qgsfield.cpp:229
void setLength(int len)
Set the field length.
Definition qgsfield.cpp:254
void setTypeName(const QString &typeName)
Set the field type.
Definition qgsfield.cpp:249
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:75
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:64
@ ColorWithAlpha
Color with alpha channel.
Definition qgsproperty.h:63
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:91
@ DataTypeBoolean
Property requires a boolean value.
@ DataTypeNumeric
Property requires a numeric value.
Definition qgsproperty.h:98
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.