QGIS API Documentation  3.27.0-Master (e113457133)
qgsauxiliarystorage.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsauxiliarystorage.cpp - description
3  -------------------
4  begin : Aug 28, 2017
5  copyright : (C) 2017 by Paul Blottiere
6  email : [email protected]
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsauxiliarystorage.h"
19 #include "qgslogger.h"
20 #include "qgssqliteutils.h"
21 #include "qgsproject.h"
22 #include "qgsvectorlayerlabeling.h"
23 #include "qgsdiagramrenderer.h"
24 #include "qgsmemoryproviderutils.h"
25 #include "qgssymbollayer.h"
26 
27 #include <sqlite3.h>
28 #include <QFile>
29 
30 #define AS_JOINFIELD QStringLiteral( "ASPK" )
31 #define AS_EXTENSION QStringLiteral( "qgd" )
32 #define AS_JOINPREFIX QStringLiteral( "auxiliary_storage_" )
33 typedef QVector<QgsPalLayerSettings::Property> PalPropertyList;
35 {
61 } ) )
62 
63 //
64 // QgsAuxiliaryLayer
65 //
66 
67 QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer )
68  : QgsVectorLayer( QStringLiteral( "%1|layername=%2" ).arg( filename, table ),
69  QStringLiteral( "%1_auxiliarystorage" ).arg( table ), QStringLiteral( "ogr" ) )
70  , mFileName( filename )
71  , mTable( table )
72  , mLayer( vlayer )
73 {
74  // init join info
75  mJoinInfo.setPrefix( AS_JOINPREFIX );
76  mJoinInfo.setJoinLayer( this );
77  mJoinInfo.setJoinFieldName( AS_JOINFIELD );
78  mJoinInfo.setTargetFieldName( pkField );
79  mJoinInfo.setEditable( true );
80  mJoinInfo.setUpsertOnEdit( true );
81  mJoinInfo.setCascadedDelete( true );
82  mJoinInfo.setJoinFieldNamesBlockList( QStringList() << QStringLiteral( "rowid" ) ); // introduced by ogr provider
83 }
84 
86 {
88  return new QgsAuxiliaryLayer( mJoinInfo.targetFieldName(), mFileName, target->id(), target );
89 }
90 
92 {
93  const bool rc = deleteFeatures( allFeatureIds() );
94  commitChanges();
95  startEditing();
96  return rc;
97 }
98 
100 {
101  QgsVectorLayer *layer = QgsMemoryProviderUtils::createMemoryLayer( QStringLiteral( "auxiliary_layer" ), fields(), mLayer->wkbType(), mLayer->crs() );
102 
103  const QString pkField = mJoinInfo.targetFieldName();
104  QgsFeature joinFeature;
105  QgsFeature targetFeature;
107 
108  layer->startEditing();
109  while ( it.nextFeature( joinFeature ) )
110  {
111  const QString filter = QgsExpression::createFieldEqualityExpression( pkField, joinFeature.attribute( AS_JOINFIELD ) );
112 
113  QgsFeatureRequest request;
114  request.setFilterExpression( filter );
115 
116  mLayer->getFeatures( request ).nextFeature( targetFeature );
117 
118  if ( targetFeature.isValid() )
119  {
120  QgsFeature newFeature( joinFeature );
121  newFeature.setGeometry( targetFeature.geometry() );
122  layer->addFeature( newFeature );
123  }
124  }
125  layer->commitChanges();
126 
127  return layer;
128 }
129 
131 {
132  return mJoinInfo;
133 }
134 
135 bool QgsAuxiliaryLayer::exists( const QgsPropertyDefinition &definition ) const
136 {
137  return ( indexOfPropertyDefinition( definition ) >= 0 );
138 }
139 
141 {
142  if ( ( definition.name().isEmpty() && definition.comment().isEmpty() ) || exists( definition ) )
143  return false;
144 
145  const QgsField af = createAuxiliaryField( definition );
146  const bool rc = addAttribute( af );
147  updateFields();
148  mLayer->updateFields();
149 
150  if ( rc )
151  {
152  const int auxIndex = indexOfPropertyDefinition( definition );
153  const int index = mLayer->fields().indexOf( nameFromProperty( definition, true ) );
154 
155  if ( index >= 0 && auxIndex >= 0 )
156  {
157  if ( isHiddenProperty( auxIndex ) )
158  {
159  // update editor widget
160  const QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Hidden" ), QVariantMap() );
161  setEditorWidgetSetup( auxIndex, setup );
162 
163  // column is hidden
164  QgsAttributeTableConfig attrCfg = mLayer->attributeTableConfig();
165  attrCfg.update( mLayer->fields() );
166  QVector<QgsAttributeTableConfig::ColumnConfig> columns = attrCfg.columns();
167  QVector<QgsAttributeTableConfig::ColumnConfig>::iterator it;
168 
169  for ( it = columns.begin(); it != columns.end(); ++it )
170  {
171  if ( it->name.compare( mLayer->fields().field( index ).name() ) == 0 )
172  it->hidden = true;
173  }
174 
175  attrCfg.setColumns( columns );
176  mLayer->setAttributeTableConfig( attrCfg );
177  }
178  else if ( definition.standardTemplate() == QgsPropertyDefinition::ColorNoAlpha
180  {
181  const QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Color" ), QVariantMap() );
182  setEditorWidgetSetup( auxIndex, setup );
183  }
184 
185  mLayer->setEditorWidgetSetup( index, editorWidgetSetup( auxIndex ) );
186  }
187  }
188 
189  return rc;
190 }
191 
193 {
194  QgsFields afields;
195 
196  for ( int i = 2; i < fields().count(); i++ ) // ignore rowid and PK field
197  afields.append( createAuxiliaryField( fields().field( i ) ) );
198 
199  return afields;
200 }
201 
203 {
205  const bool rc = commitChanges();
206  startEditing();
207  return rc;
208 }
209 
211 {
212  bool rc = false;
213 
214  if ( isEditable() )
215  {
216  rc = commitChanges();
217  }
218 
219  startEditing();
220 
221  return rc;
222 }
223 
225 {
226  int index = -1;
227 
228  if ( layer && layer->labeling() && layer->auxiliaryLayer() )
229  {
230  // property definition are identical whatever the provider id
232  const QString fieldName = nameFromProperty( def, true );
233 
234  layer->auxiliaryLayer()->addAuxiliaryField( def );
235 
236  if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
237  {
238  const QStringList subProviderIds = layer->labeling()->subProviders();
239  for ( const QString &providerId : subProviderIds )
240  {
241  QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
242 
244 
245  // is there an existing property?
246  const QgsProperty existingProperty = c.property( property );
247  if ( existingProperty.propertyType() == QgsProperty::InvalidProperty
248  || ( existingProperty.propertyType() == QgsProperty::FieldBasedProperty && existingProperty.field().isEmpty() )
249  || ( existingProperty.propertyType() == QgsProperty::ExpressionBasedProperty && existingProperty.expressionString().isEmpty() )
250  || overwriteExisting )
251  {
252  const QgsProperty prop = QgsProperty::fromField( fieldName );
253  c.setProperty( property, prop );
254  }
255  else
256  {
257  // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
258  const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
259  existingProperty.asExpression() ) );
260  c.setProperty( property, prop );
261  }
262  settings->setDataDefinedProperties( c );
263 
264  layer->labeling()->setSettings( settings, providerId );
265  }
266  }
267 
268  index = layer->fields().lookupField( fieldName );
269  }
270 
271  return index;
272 }
273 
275 {
276  int index = -1;
277 
278  if ( layer && layer->diagramLayerSettings() && layer->auxiliaryLayer() )
279  {
281 
282  if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) )
283  {
284  const QString fieldName = nameFromProperty( def, true );
285 
286  QgsDiagramLayerSettings settings( *layer->diagramLayerSettings() );
287 
289  // is there an existing property?
290  const QgsProperty existingProperty = c.property( property );
291  if ( existingProperty.propertyType() == QgsProperty::InvalidProperty || overwriteExisting )
292  {
293  const QgsProperty prop = QgsProperty::fromField( fieldName );
294  c.setProperty( property, prop );
295  }
296  else
297  {
298  // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
299  const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
300  existingProperty.asExpression() ) );
301  c.setProperty( property, prop );
302  }
303  settings.setDataDefinedProperties( c );
304 
305  layer->setDiagramLayerSettings( settings );
306  index = layer->fields().lookupField( fieldName );
307  }
308  }
309 
310  return index;
311 }
312 
313 int QgsAuxiliaryLayer::createProperty( QgsCallout::Property property, QgsVectorLayer *layer, bool overwriteExisting )
314 {
315  int index = -1;
316 
317  if ( layer && layer->labeling() && layer->labeling()->settings().callout() && layer->auxiliaryLayer() )
318  {
319  // property definition are identical whatever the provider id
321  const QString fieldName = nameFromProperty( def, true );
322 
323  layer->auxiliaryLayer()->addAuxiliaryField( def );
324 
325  if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
326  {
327  const QStringList subProviderIds = layer->labeling()->subProviders();
328  for ( const QString &providerId : subProviderIds )
329  {
330  QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
331  if ( settings->callout() )
332  {
334  // is there an existing property?
335  const QgsProperty existingProperty = c.property( property );
336  if ( existingProperty.propertyType() == QgsProperty::InvalidProperty || overwriteExisting )
337  {
338  const QgsProperty prop = QgsProperty::fromField( fieldName );
339  c.setProperty( property, prop );
340  }
341  else
342  {
343  // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
344  const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
345  existingProperty.asExpression() ) );
346  c.setProperty( property, prop );
347  }
348  settings->callout()->setDataDefinedProperties( c );
349  }
350  layer->labeling()->setSettings( settings, providerId );
351  }
352  }
353 
354  index = layer->fields().lookupField( fieldName );
355  }
356 
357  return index;
358 }
359 
360 bool QgsAuxiliaryLayer::isHiddenProperty( int index ) const
361 {
362  bool hidden = false;
364 
365  if ( def.origin().compare( QLatin1String( "labeling" ) ) == 0 )
366  {
367  const PalPropertyList &palProps = *palHiddenProperties();
368  for ( const QgsPalLayerSettings::Property &p : palProps )
369  {
370  const QString propName = QgsPalLayerSettings::propertyDefinitions()[ p ].name();
371  if ( propName.compare( def.name() ) == 0 )
372  {
373  hidden = true;
374  break;
375  }
376  }
377  }
378 
379  return hidden;
380 }
381 
383 {
384  int p = -1;
386 
387  if ( aDef.origin().compare( QLatin1String( "labeling" ) ) == 0 )
388  {
390  QgsPropertiesDefinition::const_iterator it = defs.constBegin();
391  for ( ; it != defs.constEnd(); ++it )
392  {
393  if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
394  {
395  p = it.key();
396  break;
397  }
398  }
399  }
400  else if ( aDef.origin().compare( QLatin1String( "symbol" ) ) == 0 )
401  {
403  QgsPropertiesDefinition::const_iterator it = defs.constBegin();
404  for ( ; it != defs.constEnd(); ++it )
405  {
406  if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
407  {
408  p = it.key();
409  break;
410  }
411  }
412  }
413  else if ( aDef.origin().compare( QLatin1String( "diagram" ) ) == 0 )
414  {
416  QgsPropertiesDefinition::const_iterator it = defs.constBegin();
417  for ( ; it != defs.constEnd(); ++it )
418  {
419  if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
420  {
421  p = it.key();
422  break;
423  }
424  }
425  }
426 
427  return p;
428 }
429 
431 {
432  return propertyDefinitionFromField( fields().field( index ) );
433 }
434 
436 {
437  return fields().indexOf( nameFromProperty( def ) );
438 }
439 
441 {
442  QString fieldName = def.origin();
443 
444  if ( !def.name().isEmpty() )
445  fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.name().toLower() );
446 
447  if ( !def.comment().isEmpty() )
448  fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.comment() );
449 
450  if ( joined )
451  fieldName = QStringLiteral( "%1%2" ).arg( AS_JOINPREFIX, fieldName );
452 
453  return fieldName;
454 }
455 
457 {
458  QgsField afield;
459 
460  if ( !def.name().isEmpty() || !def.comment().isEmpty() )
461  {
462  QVariant::Type type = QVariant::Invalid;
463  QString typeName;
464  int len( 0 ), precision( 0 );
465  switch ( def.dataType() )
466  {
468  type = QVariant::String;
469  len = 50;
470  typeName = QStringLiteral( "String" );
471  break;
473  type = QVariant::Double;
474  len = 0;
475  precision = 0;
476  typeName = QStringLiteral( "Real" );
477  break;
479  type = QVariant::Int; // sqlite does not have a bool type
480  typeName = QStringLiteral( "Integer" );
481  break;
482  }
483 
484  afield.setType( type );
485  afield.setName( nameFromProperty( def ) );
486  afield.setTypeName( typeName );
487  afield.setLength( len );
488  afield.setPrecision( precision );
489  }
490 
491  return afield;
492 }
493 
495 {
497  const QStringList parts = f.name().split( '_' );
498 
499  if ( parts.size() <= 1 )
500  return def;
501 
502  const QString origin = parts[0];
503  const QString propertyName = parts[1];
504 
505  if ( origin.compare( QLatin1String( "labeling" ), Qt::CaseInsensitive ) == 0 )
506  {
508  for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
509  {
510  if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
511  {
512  def = it.value();
513  if ( parts.size() >= 3 )
514  def.setComment( parts.mid( 2 ).join( '_' ) );
515  break;
516  }
517  }
518  }
519  else if ( origin.compare( QLatin1String( "symbol" ), Qt::CaseInsensitive ) == 0 )
520  {
522  for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
523  {
524  if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
525  {
526  def = it.value();
527  if ( parts.size() >= 3 )
528  def.setComment( parts.mid( 2 ).join( '_' ) );
529  break;
530  }
531  }
532  }
533  else if ( origin.compare( QLatin1String( "diagram" ), 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
548  {
549  def.setOrigin( origin );
550  def.setName( propertyName );
551  switch ( f.type() )
552  {
553  case QVariant::Double:
555  break;
556 
557  case QVariant::Bool:
559  break;
560 
561  case QVariant::String:
562  default:
564  break;
565  }
566 
567  if ( parts.size() >= 3 )
568  def.setComment( parts.mid( 2 ).join( '_' ) );
569  }
570 
571  return def;
572 }
573 
575 {
577  QgsField afield;
578 
579  if ( !def.name().isEmpty() || !def.comment().isEmpty() )
580  {
581  afield = createAuxiliaryField( def );
582  afield.setTypeName( field.typeName() );
583  }
584 
585  return afield;
586 }
587 
588 //
589 // QgsAuxiliaryStorage
590 //
591 
593  : mCopy( copy )
594 {
595  initTmpFileName();
596 
597  if ( !project.absoluteFilePath().isEmpty() )
598  {
599  mFileName = filenameForProject( project );
600  }
601 
602  open( mFileName );
603 }
604 
605 QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QString &filename, bool copy )
606  : mFileName( filename )
607  , mCopy( copy )
608 {
609  initTmpFileName();
610 
611  open( filename );
612 }
613 
615 {
616  QFile::remove( mTmpFileName );
617 }
618 
620 {
621  return mValid;
622 }
623 
625 {
626  return mFileName;
627 }
628 
630 {
631  if ( mFileName.isEmpty() )
632  {
633  // only a saveAs is available on a new database
634  return false;
635  }
636  else if ( mCopy )
637  {
638  if ( QFile::exists( mFileName ) )
639  QFile::remove( mFileName );
640 
641  return QFile::copy( mTmpFileName, mFileName );
642  }
643  else
644  {
645  // if the file is not empty the copy mode is not activated, then we're
646  // directly working on the database since the beginning (no savepoints
647  // /rollback for now)
648  return true;
649  }
650 }
651 
653 {
654  QgsAuxiliaryLayer *alayer = nullptr;
655 
656  if ( mValid && layer )
657  {
658  const QString table( layer->id() );
660  database = openDB( currentFileName() );
661 
662  if ( !tableExists( table, database.get() ) )
663  {
664  if ( !createTable( field.typeName(), table, database.get(), mErrorString ) )
665  {
666  return alayer;
667  }
668  }
669 
670  alayer = new QgsAuxiliaryLayer( field.name(), currentFileName(), table, layer );
671  alayer->startEditing();
672  }
673 
674  return alayer;
675 }
676 
678 {
679  bool rc = false;
680  const QgsDataSourceUri uri = parseOgrUri( ogrUri );
681 
682  if ( !uri.database().isEmpty() && !uri.table().isEmpty() )
683  {
685  database = openDB( uri.database() );
686 
687  if ( database )
688  {
689  QString sql = QStringLiteral( "DROP TABLE %1" ).arg( uri.table() );
690  rc = exec( sql, database.get() );
691 
692  sql = QStringLiteral( "VACUUM" );
693  rc = exec( sql, database.get() );
694  }
695  }
696 
697  return rc;
698 }
699 
700 bool QgsAuxiliaryStorage::duplicateTable( const QgsDataSourceUri &ogrUri, const QString &newTable )
701 {
702  const QgsDataSourceUri uri = parseOgrUri( ogrUri );
703  bool rc = false;
704 
705  if ( !uri.table().isEmpty() && !uri.database().isEmpty() )
706  {
708  database = openDB( uri.database() );
709 
710  if ( database )
711  {
712  const QString sql = QStringLiteral( "CREATE TABLE %1 AS SELECT * FROM %2" ).arg( newTable, uri.table() );
713  rc = exec( sql, database.get() );
714  }
715  }
716 
717  return rc;
718 }
719 
721 {
722  return mErrorString;
723 }
724 
725 bool QgsAuxiliaryStorage::saveAs( const QString &filename )
726 {
727  mErrorString.clear();
728 
729  QFile dest( filename );
730  if ( dest.exists() && !dest.remove() )
731  {
732  mErrorString = dest.errorString();
733  return false;
734  }
735 
736  QFile origin( currentFileName() );
737  if ( !origin.copy( filename ) )
738  {
739  mErrorString = origin.errorString();
740  return false;
741  }
742 
743  return true;
744 }
745 
747 {
748  return saveAs( filenameForProject( project ) );
749 }
750 
752 {
753  return AS_EXTENSION;
754 }
755 
757 {
758  const QFileInfo fileinfo( filenameForProject( project ) );
759  return fileinfo.exists() && fileinfo.isFile();
760 }
761 
762 bool QgsAuxiliaryStorage::exec( const QString &sql, sqlite3 *handler )
763 {
764  bool rc = false;
765 
766  if ( handler )
767  {
768  const int err = sqlite3_exec( handler, sql.toStdString().c_str(), nullptr, nullptr, nullptr );
769 
770  if ( err == SQLITE_OK )
771  rc = true;
772  else
773  debugMsg( sql, handler );
774  }
775 
776  return rc;
777 }
778 
779 QString QgsAuxiliaryStorage::debugMsg( const QString &sql, sqlite3 *handler )
780 {
781  const QString err = QString::fromUtf8( sqlite3_errmsg( handler ) );
782  const QString msg = QObject::tr( "Unable to execute" );
783  const QString errMsg = QObject::tr( "%1 '%2': %3" ).arg( msg, sql, err );
784  QgsDebugMsg( errMsg );
785  return errMsg;
786 }
787 
788 bool QgsAuxiliaryStorage::createTable( const QString &type, const QString &table, sqlite3 *handler, QString &errorMsg )
789 {
790  const QString sql = QStringLiteral( "CREATE TABLE IF NOT EXISTS '%1' ( '%2' %3 )" ).arg( table, AS_JOINFIELD, type );
791 
792  if ( !exec( sql, handler ) )
793  {
794  errorMsg = QgsAuxiliaryStorage::debugMsg( sql, handler );
795  return false;
796  }
797 
798  return true;
799 }
800 
801 sqlite3_database_unique_ptr QgsAuxiliaryStorage::createDB( const QString &filename )
802 {
804 
805  int rc;
806  rc = database.open_v2( filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr );
807  if ( rc )
808  {
809  debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
810  }
811  else
812  // activating Foreign Key constraints
813  exec( QStringLiteral( "PRAGMA foreign_keys = 1" ), database.get() );
814 
815  return database;
816 }
817 
818 sqlite3_database_unique_ptr QgsAuxiliaryStorage::openDB( const QString &filename )
819 {
821  const int rc = database.open_v2( filename, SQLITE_OPEN_READWRITE, nullptr );
822 
823  if ( rc )
824  {
825  debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
826  }
827 
828  return database;
829 }
830 
831 bool QgsAuxiliaryStorage::tableExists( const QString &table, sqlite3 *handler )
832 {
833  const QString sql = QStringLiteral( "SELECT 1 FROM sqlite_master WHERE type='table' AND name='%1'" ).arg( table );
834  int rows = 0;
835  int columns = 0;
836  char **results = nullptr;
837  const int rc = sqlite3_get_table( handler, sql.toStdString().c_str(), &results, &rows, &columns, nullptr );
838  if ( rc != SQLITE_OK )
839  {
840  debugMsg( sql, handler );
841  return false;
842  }
843 
844  sqlite3_free_table( results );
845  if ( rows >= 1 )
846  return true;
847 
848  return false;
849 }
850 
851 sqlite3_database_unique_ptr QgsAuxiliaryStorage::open( const QString &filename )
852 {
854 
855  if ( filename.isEmpty() )
856  {
857  if ( ( database = createDB( currentFileName() ) ) )
858  mValid = true;
859  }
860  else if ( QFile::exists( filename ) )
861  {
862  if ( mCopy )
863  QFile::copy( filename, mTmpFileName );
864 
865  if ( ( database = openDB( currentFileName() ) ) )
866  mValid = true;
867  }
868  else
869  {
870  if ( ( database = createDB( currentFileName() ) ) )
871  mValid = true;
872  }
873 
874  return database;
875 }
876 
877 sqlite3_database_unique_ptr QgsAuxiliaryStorage::open( const QgsProject &project )
878 {
879  return open( filenameForProject( project ) );
880 }
881 
882 QString QgsAuxiliaryStorage::filenameForProject( const QgsProject &project )
883 {
884  const QFileInfo info( project.absoluteFilePath() );
885  const QString path = info.path() + QDir::separator() + info.baseName();
886  return path + '.' + QgsAuxiliaryStorage::extension();
887 }
888 
889 void QgsAuxiliaryStorage::initTmpFileName()
890 {
891  QTemporaryFile tmpFile;
892  tmpFile.open();
893  tmpFile.close();
894  mTmpFileName = tmpFile.fileName();
895 }
896 
898 {
899  if ( mCopy || mFileName.isEmpty() )
900  return mTmpFileName;
901  else
902  return mFileName;
903 }
904 
905 QgsDataSourceUri QgsAuxiliaryStorage::parseOgrUri( const QgsDataSourceUri &uri )
906 {
907  QgsDataSourceUri newUri;
908 
909  // parsing for ogr style uri :
910  // " filePath|layername='tableName' table="" sql="
911  QStringList uriParts = uri.uri().split( '|' );
912  if ( uriParts.count() < 2 )
913  return newUri;
914 
915  const QString databasePath = uriParts[0].replace( ' ', QString() );
916 
917  const QString table = uriParts[1];
918  QStringList tableParts = table.split( ' ' );
919 
920  if ( tableParts.count() < 1 )
921  return newUri;
922 
923  const QString tableName = tableParts[0].replace( QLatin1String( "layername=" ), QString() );
924 
925  newUri.setDataSource( QString(), tableName, QString() );
926  newUri.setDatabase( databasePath );
927 
928  return newUri;
929 }
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 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.
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...
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.
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
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.
int indexOfPropertyDefinition(const QgsPropertyDefinition &definition) const
Returns the index of the auxiliary field for a specific property definition.
static QgsField createAuxiliaryField(const QgsPropertyDefinition &definition)
Creates a new auxiliary field from a property definition.
virtual ~QgsAuxiliaryStorage()
Destructor.
static bool duplicateTable(const QgsDataSourceUri &uri, const QString &newTable)
Duplicates a table and its content.
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.
static bool deleteTable(const QgsDataSourceUri &uri)
Removes a table from the auxiliary storage.
QgsAuxiliaryLayer * createAuxiliaryLayer(const QgsField &field, QgsVectorLayer *layer) const
Creates an auxiliary layer for a vector layer.
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 QString extension()
Returns the extension used for auxiliary databases.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the callout's property collection, used for data defined overrides.
Definition: qgscallout.h:349
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in callouts.
Definition: qgscallout.cpp:192
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the callout's property collection, used for data defined overrides.
Definition: qgscallout.h:331
Property
Data definable properties.
Definition: qgscallout.h:84
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.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the diagram's property collection, used for data defined overrides.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the diagram's property collection, used for data defined overrides.
Holder for the widget type and its configuration for a field.
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QVariant::Type fieldType=QVariant::Type::Invalid)
Create an expression allowing to evaluate if a field is equal to a value.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:209
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:320
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:163
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:139
QString name
Definition: qgsfield.h:60
void setPrecision(int precision)
Set the field precision.
Definition: qgsfield.cpp:199
void setName(const QString &name)
Set the field name.
Definition: qgsfield.cpp:175
void setLength(int len)
Set the field length.
Definition: qgsfield.cpp:195
QVariant::Type type
Definition: qgsfield.h:58
void setType(QVariant::Type type)
Set variant type.
Definition: qgsfield.cpp:180
void setTypeName(const QString &typeName)
Set the field type.
Definition: qgsfield.cpp:190
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:168
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
QString source() const
Returns the source for the layer.
QgsMapLayerType type
Definition: qgsmaplayer.h:80
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
static QgsVectorLayer * createMemoryLayer(const QString &name, const QgsFields &fields, QgsWkbTypes::Type geometryType=QgsWkbTypes::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem()) 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.
Property
Data definable properties.
@ LabelRotation
Label rotation.
@ PositionY
Y-coordinate data defined label position.
@ Strikeout
Use strikeout.
@ FontStyle
Font style name.
@ PositionX
X-coordinate data defined label position.
@ CalloutDraw
Show callout.
@ Underline
Use underline.
@ Bold
Use bold style.
@ MaxScale
Max scale (deprecated, for old project compatibility only)
@ Hali
Horizontal alignment for data defined label position (Left, Center, Right)
@ LabelAllParts
Whether all parts of multi-part features should be labeled.
@ Italic
Use italic style.
@ MinScale
Min scale (deprecated, for old project compatibility only)
@ Family
Font family.
@ Vali
Vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top)
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the label's property collection, used for data defined overrides.
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:104
QString absoluteFilePath() const
Returns full absolute path to the project file if the project is stored in a file system - derived fr...
Definition: qgsproject.cpp:822
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Definition for a property.
Definition: qgsproperty.h:47
StandardPropertyTemplate standardTemplate() const
Returns the property's standard template, if applicable.
Definition: qgsproperty.h:194
QString comment() const
Returns the comment of the property.
Definition: qgsproperty.h:168
DataType dataType() const
Returns the allowable field/value data type for the property.
Definition: qgsproperty.h:188
void setOrigin(const QString &origin)
Sets the origin of the property.
Definition: qgsproperty.h:158
@ 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.
Definition: qgsproperty.h:139
void setDataType(DataType type)
Sets the data type.
Definition: qgsproperty.h:183
void setName(const QString &name)
Sets the name of the property.
Definition: qgsproperty.h:144
QString origin() const
Returns the origin of the property.
Definition: qgsproperty.h:151
void setComment(const QString &comment)
Sets comment of the property.
Definition: qgsproperty.h:173
@ DataTypeString
Property requires a string value.
Definition: qgsproperty.h:92
@ DataTypeBoolean
Property requires a boolean value.
Definition: qgsproperty.h:106
@ DataTypeNumeric
Property requires a numeric value.
Definition: qgsproperty.h:99
A store for object properties.
Definition: qgsproperty.h:231
@ ExpressionBasedProperty
Expression based property (QgsExpressionBasedProperty)
Definition: qgsproperty.h:240
@ FieldBasedProperty
Field based property (QgsFieldBasedProperty)
Definition: qgsproperty.h:239
@ InvalidProperty
Invalid (not set) property.
Definition: qgsproperty.h:237
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.
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.
Type propertyType() const
Returns the property type.
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.
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 QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
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,...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool deleteFeatures(const QgsFeatureIds &fids, DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it)
const QgsDiagramLayerSettings * diagramLayerSettings() const
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
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.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
Q_INVOKABLE bool commitChanges(bool stopEditing=true)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
QgsEditorWidgetSetup editorWidgetSetup(int index) const
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
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)
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
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
#define AS_JOINFIELD
Q_GLOBAL_STATIC_WITH_ARGS(PalPropertyList, palHiddenProperties,({ QgsPalLayerSettings::PositionX, QgsPalLayerSettings::PositionY, QgsPalLayerSettings::Show, QgsPalLayerSettings::LabelRotation, QgsPalLayerSettings::Family, QgsPalLayerSettings::FontStyle, QgsPalLayerSettings::Size, QgsPalLayerSettings::Bold, QgsPalLayerSettings::Italic, QgsPalLayerSettings::Underline, QgsPalLayerSettings::Color, QgsPalLayerSettings::Strikeout, QgsPalLayerSettings::MultiLineAlignment, QgsPalLayerSettings::BufferSize, QgsPalLayerSettings::BufferDraw, QgsPalLayerSettings::BufferColor, QgsPalLayerSettings::LabelDistance, QgsPalLayerSettings::Hali, QgsPalLayerSettings::Vali, QgsPalLayerSettings::ScaleVisibility, QgsPalLayerSettings::MinScale, QgsPalLayerSettings::MaxScale, QgsPalLayerSettings::AlwaysShow, QgsPalLayerSettings::CalloutDraw, QgsPalLayerSettings::LabelAllParts })) QgsAuxiliaryLayer
QVector< QgsPalLayerSettings::Property > PalPropertyList
#define AS_JOINPREFIX
#define AS_EXTENSION
struct sqlite3 sqlite3
const QgsField & field
Definition: qgsfield.h:463
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
const QString & typeName
int precision