QGIS API Documentation 3.41.0-Master (af5edcb665c)
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#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 QFile::remove( mTmpFileName );
639}
640
642{
643 return mValid;
644}
645
646QString QgsAuxiliaryStorage::fileName() const
647{
648 return mFileName;
649}
650
651bool QgsAuxiliaryStorage::save() const
652{
653 if ( mFileName.isEmpty() )
654 {
655 // only a saveAs is available on a new database
656 return false;
657 }
658 else if ( mCopy )
659 {
660 if ( QFile::exists( mFileName ) )
661 QFile::remove( mFileName );
662
663 return QFile::copy( mTmpFileName, mFileName );
664 }
665 else
666 {
667 // if the file is not empty the copy mode is not activated, then we're
668 // directly working on the database since the beginning (no savepoints
669 // /rollback for now)
670 return true;
671 }
672}
673
675{
676 QgsAuxiliaryLayer *alayer = nullptr;
677
678 if ( mValid && layer )
679 {
680 const QString table( layer->id() );
682 database = openDB( currentFileName() );
683
684 if ( !tableExists( table, database.get() ) )
685 {
686 if ( !createTable( field.typeName(), table, database.get(), mErrorString ) )
687 {
688 return alayer;
689 }
690 }
691
692 alayer = new QgsAuxiliaryLayer( field.name(), currentFileName(), table, layer );
693 alayer->startEditing();
694 }
695
696 return alayer;
697}
698
700{
701 bool rc = false;
702 const QgsDataSourceUri uri = parseOgrUri( ogrUri );
703
704 if ( !uri.database().isEmpty() && !uri.table().isEmpty() )
705 {
707 database = openDB( uri.database() );
708
709 if ( database )
710 {
711 QString sql = QStringLiteral( "DROP TABLE %1" ).arg( uri.table() );
712 rc = exec( sql, database.get() );
713
714 sql = QStringLiteral( "VACUUM" );
715 rc = exec( sql, database.get() );
716 }
717 }
718
719 return rc;
720}
721
722bool QgsAuxiliaryStorage::duplicateTable( const QgsDataSourceUri &ogrUri, const QString &newTable )
723{
724 const QgsDataSourceUri uri = parseOgrUri( ogrUri );
725 bool rc = false;
726
727 if ( !uri.table().isEmpty() && !uri.database().isEmpty() )
728 {
730 database = openDB( uri.database() );
731
732 if ( database )
733 {
734 const QString sql = QStringLiteral( "CREATE TABLE %1 AS SELECT * FROM %2" ).arg( newTable, uri.table() );
735 rc = exec( sql, database.get() );
736 }
737 }
738
739 return rc;
740}
741
743{
744 return mErrorString;
745}
746
747bool QgsAuxiliaryStorage::saveAs( const QString &filename )
748{
749 mErrorString.clear();
750
751 QFile dest( filename );
752 if ( dest.exists() && !dest.remove() )
753 {
754 mErrorString = dest.errorString();
755 return false;
756 }
757
758 QFile origin( currentFileName() );
759 if ( !origin.copy( filename ) )
760 {
761 mErrorString = origin.errorString();
762 return false;
763 }
764
765 return true;
766}
767
768bool QgsAuxiliaryStorage::saveAs( const QgsProject &project )
769{
770 return saveAs( filenameForProject( project ) );
771}
772
774{
775 return AS_EXTENSION;
776}
777
778bool QgsAuxiliaryStorage::exists( const QgsProject &project )
779{
780 const QFileInfo fileinfo( filenameForProject( project ) );
781 return fileinfo.exists() && fileinfo.isFile();
782}
783
784bool QgsAuxiliaryStorage::exec( const QString &sql, sqlite3 *handler )
785{
786 bool rc = false;
787
788 if ( handler )
789 {
790 const int err = sqlite3_exec( handler, sql.toStdString().c_str(), nullptr, nullptr, nullptr );
791
792 if ( err == SQLITE_OK )
793 rc = true;
794 else
795 debugMsg( sql, handler );
796 }
797
798 return rc;
799}
800
801QString QgsAuxiliaryStorage::debugMsg( const QString &sql, sqlite3 *handler )
802{
803 const QString err = QString::fromUtf8( sqlite3_errmsg( handler ) );
804 const QString msg = QObject::tr( "Unable to execute" );
805 const QString errMsg = QObject::tr( "%1 '%2': %3" ).arg( msg, sql, err );
806 QgsDebugError( errMsg );
807 return errMsg;
808}
809
810bool QgsAuxiliaryStorage::createTable( const QString &type, const QString &table, sqlite3 *handler, QString &errorMsg )
811{
812 const QString sql = QStringLiteral( "CREATE TABLE IF NOT EXISTS '%1' ( '%2' %3 )" ).arg( table, AS_JOINFIELD, type );
813
814 if ( !exec( sql, handler ) )
815 {
816 errorMsg = QgsAuxiliaryStorage::debugMsg( sql, handler );
817 return false;
818 }
819
820 return true;
821}
822
823sqlite3_database_unique_ptr QgsAuxiliaryStorage::createDB( const QString &filename )
824{
826
827 int rc;
828 rc = database.open_v2( filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr );
829 if ( rc )
830 {
831 debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
832 }
833 else
834 // activating Foreign Key constraints
835 exec( QStringLiteral( "PRAGMA foreign_keys = 1" ), database.get() );
836
837 return database;
838}
839
840sqlite3_database_unique_ptr QgsAuxiliaryStorage::openDB( const QString &filename )
841{
843 const int rc = database.open_v2( filename, SQLITE_OPEN_READWRITE, nullptr );
844
845 if ( rc )
846 {
847 debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
848 }
849
850 return database;
851}
852
853bool QgsAuxiliaryStorage::tableExists( const QString &table, sqlite3 *handler )
854{
855 const QString sql = QStringLiteral( "SELECT 1 FROM sqlite_master WHERE type='table' AND name='%1'" ).arg( table );
856 int rows = 0;
857 int columns = 0;
858 char **results = nullptr;
859 const int rc = sqlite3_get_table( handler, sql.toStdString().c_str(), &results, &rows, &columns, nullptr );
860 if ( rc != SQLITE_OK )
861 {
862 debugMsg( sql, handler );
863 return false;
864 }
865
866 sqlite3_free_table( results );
867 if ( rows >= 1 )
868 return true;
869
870 return false;
871}
872
873sqlite3_database_unique_ptr QgsAuxiliaryStorage::open( const QString &filename )
874{
876
877 if ( filename.isEmpty() )
878 {
879 if ( ( database = createDB( currentFileName() ) ) )
880 mValid = true;
881 }
882 else if ( QFile::exists( filename ) )
883 {
884 if ( mCopy )
885 QFile::copy( filename, mTmpFileName );
886
887 if ( ( database = openDB( currentFileName() ) ) )
888 mValid = true;
889 }
890 else
891 {
892 if ( ( database = createDB( currentFileName() ) ) )
893 mValid = true;
894 }
895
896 return database;
897}
898
899sqlite3_database_unique_ptr QgsAuxiliaryStorage::open( const QgsProject &project )
900{
901 return open( filenameForProject( project ) );
902}
903
904QString QgsAuxiliaryStorage::filenameForProject( const QgsProject &project )
905{
906 const QFileInfo info( project.absoluteFilePath() );
907 const QString path = info.path() + QDir::separator() + info.baseName();
908 return path + '.' + QgsAuxiliaryStorage::extension();
909}
910
911void QgsAuxiliaryStorage::initTmpFileName()
912{
913 QTemporaryFile tmpFile;
914 tmpFile.open();
915 tmpFile.close();
916 mTmpFileName = tmpFile.fileName();
917}
918
920{
921 if ( mCopy || mFileName.isEmpty() )
922 return mTmpFileName;
923 else
924 return mFileName;
925}
926
927QgsDataSourceUri QgsAuxiliaryStorage::parseOgrUri( const QgsDataSourceUri &uri )
928{
929 QgsDataSourceUri newUri;
930
931 // parsing for ogr style uri :
932 // " filePath|layername='tableName' table="" sql="
933 QStringList uriParts = uri.uri().split( '|' );
934 if ( uriParts.count() < 2 )
935 return newUri;
936
937 const QString databasePath = uriParts[0].replace( ' ', QString() );
938
939 const QString table = uriParts[1];
940 QStringList tableParts = table.split( ' ' );
941
942 if ( tableParts.count() < 1 )
943 return newUri;
944
945 const QString tableName = tableParts[0].replace( QLatin1String( "layername=" ), QString() );
946
947 newUri.setDataSource( QString(), tableName, QString() );
948 newUri.setDatabase( databasePath );
949
950 return newUri;
951}
@ Invalid
Invalid (not set) property.
@ Field
Field based property.
@ Expression
Expression based property.
virtual QStringList subProviders() const
Gets list of sub-providers within the layer's labeling.
virtual void setSettings(QgsPalLayerSettings *settings, const QString &providerId=QString())=0
Set pal settings for a specific provider (takes ownership).
virtual QgsPalLayerSettings settings(const QString &providerId=QString()) const =0
Gets associated label settings.
This is a container for configuration of the attribute table.
QVector< QgsAttributeTableConfig::ColumnConfig > columns() const
Gets the list with all columns and their configuration.
void update(const QgsFields &fields)
Update the configuration with the given fields.
void setColumns(const QVector< QgsAttributeTableConfig::ColumnConfig > &columns)
Set the list of columns visible in the attribute table.
Class allowing to manage the auxiliary storage for a vector layer.
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
static QgsField createAuxiliaryField(const QgsPropertyDefinition &definition)
Creates a new auxiliary field from a property definition.
static QgsPropertyDefinition propertyDefinitionFromField(const QgsField &field)
Returns the property definition from an auxiliary field.
bool clear()
Deletes all features from the layer.
bool addAuxiliaryField(const QgsPropertyDefinition &definition)
Adds an auxiliary field for the given property.
bool isHiddenProperty(int index) const
Returns true if the underlying field has to be hidden from editing tools like attribute table,...
QgsVectorLayer * toSpatialLayer() const
An auxiliary layer is not spatial.
bool deleteAttribute(int attr) override
Removes attribute from the layer and commits changes.
QgsFields auxiliaryFields() const
Returns a list of all auxiliary fields currently managed by the layer.
QgsAuxiliaryLayer(const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer)
Constructor.
bool save()
Commits changes and starts editing then.
int propertyFromIndex(int index) const
Returns the underlying property key for the field index.
QgsVectorLayerJoinInfo joinInfo() const
Returns information to use for joining with primary key and so on.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
QgsPropertyDefinition propertyDefinitionFromIndex(int index) const
Returns the property definition for the underlying field index.
bool exists(const QgsPropertyDefinition &definition) const
Returns true if the property is stored in the layer already, false otherwise.
static int createProperty(QgsPalLayerSettings::Property property, QgsVectorLayer *vlayer, bool overwriteExisting=true)
Creates if necessary a new auxiliary field for a PAL property and activates this property in settings...
int indexOfPropertyDefinition(const QgsPropertyDefinition &definition) const
Returns the index of the auxiliary field for a specific property definition.
static QString extension()
Returns the extension used for auxiliary databases.
QString errorString() const
Returns the underlying error string describing potential errors happening in saveAs().
bool save() const
Saves the current database.
static bool exists(const QgsProject &project)
Returns true if the auxiliary database yet exists for a project, false otherwise.
QgsAuxiliaryLayer * createAuxiliaryLayer(const QgsField &field, QgsVectorLayer *layer) const
Creates an auxiliary layer for a vector layer.
virtual ~QgsAuxiliaryStorage()
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
Class for storing the component parts of a RDBMS data source URI (e.g.
QString table() const
Returns the table name stored in the URI.
QString uri(bool expandAuthConfig=true) const
Returns the complete URI as a string.
void setDataSource(const QString &aSchema, const QString &aTable, const QString &aGeometryColumn, const QString &aSql=QString(), const QString &aKeyColumn=QString())
Sets all data source related members at once.
QString database() const
Returns the database name stored in the URI.
void setDatabase(const QString &database)
Sets the URI database name.
Stores the settings for rendering of all diagrams for a layer.
Property
Data definable properties.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the diagram property definitions.
Holder for the widget type and its configuration for a field.
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, 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.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h: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:161
QString name
Definition qgsfield.h:62
void setPrecision(int precision)
Set the field precision.
Definition qgsfield.cpp:261
void setName(const QString &name)
Set the field name.
Definition qgsfield.cpp:227
void setType(QMetaType::Type type)
Set variant type.
Definition qgsfield.cpp:232
void setLength(int len)
Set the field length.
Definition qgsfield.cpp:257
void setTypeName(const QString &typeName)
Set the field type.
Definition qgsfield.cpp:252
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:83
QString id
Definition qgsmaplayer.h:79
Qgis::LayerType type
Definition qgsmaplayer.h:86
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 a 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 data sets.
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:38
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
const QString & typeName
int precision