QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 "qgsspatialiteutils.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
231  const QgsPropertyDefinition def = layer->labeling()->settings().propertyDefinitions()[property];
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 || overwriteExisting )
248  {
249  const QgsProperty prop = QgsProperty::fromField( fieldName );
250  c.setProperty( property, prop );
251  }
252  else
253  {
254  // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
255  const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
256  existingProperty.asExpression() ) );
257  c.setProperty( property, prop );
258  }
259  settings->setDataDefinedProperties( c );
260 
261  layer->labeling()->setSettings( settings, providerId );
262  }
263  }
264 
265  index = layer->fields().lookupField( fieldName );
266  }
267 
268  return index;
269 }
270 
272 {
273  int index = -1;
274 
275  if ( layer && layer->diagramLayerSettings() && layer->auxiliaryLayer() )
276  {
277  const QgsPropertyDefinition def = layer->diagramLayerSettings()->propertyDefinitions()[property];
278 
279  if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) )
280  {
281  const QString fieldName = nameFromProperty( def, true );
282 
283  QgsDiagramLayerSettings settings( *layer->diagramLayerSettings() );
284 
286  // is there an existing property?
287  const QgsProperty existingProperty = c.property( property );
288  if ( existingProperty.propertyType() == QgsProperty::InvalidProperty || overwriteExisting )
289  {
290  const QgsProperty prop = QgsProperty::fromField( fieldName );
291  c.setProperty( property, prop );
292  }
293  else
294  {
295  // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
296  const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
297  existingProperty.asExpression() ) );
298  c.setProperty( property, prop );
299  }
300  settings.setDataDefinedProperties( c );
301 
302  layer->setDiagramLayerSettings( settings );
303  index = layer->fields().lookupField( fieldName );
304  }
305  }
306 
307  return index;
308 }
309 
310 int QgsAuxiliaryLayer::createProperty( QgsCallout::Property property, QgsVectorLayer *layer, bool overwriteExisting )
311 {
312  int index = -1;
313 
314  if ( layer && layer->labeling() && layer->labeling()->settings().callout() && layer->auxiliaryLayer() )
315  {
316  // property definition are identical whatever the provider id
317  const QgsPropertyDefinition def = layer->labeling()->settings().callout()->propertyDefinitions()[property];
318  const QString fieldName = nameFromProperty( def, true );
319 
320  layer->auxiliaryLayer()->addAuxiliaryField( def );
321 
322  if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
323  {
324  const QStringList subProviderIds = layer->labeling()->subProviders();
325  for ( const QString &providerId : subProviderIds )
326  {
327  QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
328  if ( settings->callout() )
329  {
331  // is there an existing property?
332  const QgsProperty existingProperty = c.property( property );
333  if ( existingProperty.propertyType() == QgsProperty::InvalidProperty || overwriteExisting )
334  {
335  const QgsProperty prop = QgsProperty::fromField( fieldName );
336  c.setProperty( property, prop );
337  }
338  else
339  {
340  // build a new smart expression as coalesce("new aux field", 'the' || 'old' || 'expression')
341  const QgsProperty prop = QgsProperty::fromExpression( QStringLiteral( "coalesce(%1,%2)" ).arg( QgsExpression::quotedColumnRef( fieldName ),
342  existingProperty.asExpression() ) );
343  c.setProperty( property, prop );
344  }
345  settings->callout()->setDataDefinedProperties( c );
346  }
347  layer->labeling()->setSettings( settings, providerId );
348  }
349  }
350 
351  index = layer->fields().lookupField( fieldName );
352  }
353 
354  return index;
355 }
356 
357 bool QgsAuxiliaryLayer::isHiddenProperty( int index ) const
358 {
359  bool hidden = false;
361 
362  if ( def.origin().compare( QLatin1String( "labeling" ) ) == 0 )
363  {
364  const PalPropertyList &palProps = *palHiddenProperties();
365  for ( const QgsPalLayerSettings::Property &p : palProps )
366  {
367  const QString propName = QgsPalLayerSettings::propertyDefinitions()[ p ].name();
368  if ( propName.compare( def.name() ) == 0 )
369  {
370  hidden = true;
371  break;
372  }
373  }
374  }
375 
376  return hidden;
377 }
378 
380 {
381  int p = -1;
383 
384  if ( aDef.origin().compare( QLatin1String( "labeling" ) ) == 0 )
385  {
387  QgsPropertiesDefinition::const_iterator it = defs.constBegin();
388  for ( ; it != defs.constEnd(); ++it )
389  {
390  if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
391  {
392  p = it.key();
393  break;
394  }
395  }
396  }
397  else if ( aDef.origin().compare( QLatin1String( "symbol" ) ) == 0 )
398  {
400  QgsPropertiesDefinition::const_iterator it = defs.constBegin();
401  for ( ; it != defs.constEnd(); ++it )
402  {
403  if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
404  {
405  p = it.key();
406  break;
407  }
408  }
409  }
410  else if ( aDef.origin().compare( QLatin1String( "diagram" ) ) == 0 )
411  {
413  QgsPropertiesDefinition::const_iterator it = defs.constBegin();
414  for ( ; it != defs.constEnd(); ++it )
415  {
416  if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
417  {
418  p = it.key();
419  break;
420  }
421  }
422  }
423 
424  return p;
425 }
426 
428 {
429  return propertyDefinitionFromField( fields().field( index ) );
430 }
431 
433 {
434  return fields().indexOf( nameFromProperty( def ) );
435 }
436 
438 {
439  QString fieldName = def.origin();
440 
441  if ( !def.name().isEmpty() )
442  fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.name().toLower() );
443 
444  if ( !def.comment().isEmpty() )
445  fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.comment() );
446 
447  if ( joined )
448  fieldName = QStringLiteral( "%1%2" ).arg( AS_JOINPREFIX, fieldName );
449 
450  return fieldName;
451 }
452 
454 {
455  QgsField afield;
456 
457  if ( !def.name().isEmpty() || !def.comment().isEmpty() )
458  {
459  QVariant::Type type = QVariant::Invalid;
460  QString typeName;
461  int len( 0 ), precision( 0 );
462  switch ( def.dataType() )
463  {
465  type = QVariant::String;
466  len = 50;
467  typeName = QStringLiteral( "String" );
468  break;
470  type = QVariant::Double;
471  len = 0;
472  precision = 0;
473  typeName = QStringLiteral( "Real" );
474  break;
476  type = QVariant::Int; // sqlite does not have a bool type
477  typeName = QStringLiteral( "Integer" );
478  break;
479  }
480 
481  afield.setType( type );
482  afield.setName( nameFromProperty( def ) );
483  afield.setTypeName( typeName );
484  afield.setLength( len );
485  afield.setPrecision( precision );
486  }
487 
488  return afield;
489 }
490 
492 {
494  const QStringList parts = f.name().split( '_' );
495 
496  if ( parts.size() <= 1 )
497  return def;
498 
499  const QString origin = parts[0];
500  const QString propertyName = parts[1];
501 
502  if ( origin.compare( QLatin1String( "labeling" ), Qt::CaseInsensitive ) == 0 )
503  {
505  for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
506  {
507  if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
508  {
509  def = it.value();
510  if ( parts.size() >= 3 )
511  def.setComment( parts.mid( 2 ).join( '_' ) );
512  break;
513  }
514  }
515  }
516  else if ( origin.compare( QLatin1String( "symbol" ), Qt::CaseInsensitive ) == 0 )
517  {
519  for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
520  {
521  if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
522  {
523  def = it.value();
524  if ( parts.size() >= 3 )
525  def.setComment( parts.mid( 2 ).join( '_' ) );
526  break;
527  }
528  }
529  }
530  else if ( origin.compare( QLatin1String( "diagram" ), Qt::CaseInsensitive ) == 0 )
531  {
533  for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
534  {
535  if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
536  {
537  def = it.value();
538  if ( parts.size() >= 3 )
539  def.setComment( parts.mid( 2 ).join( '_' ) );
540  break;
541  }
542  }
543  }
544  else
545  {
546  def.setOrigin( origin );
547  def.setName( propertyName );
548  switch ( f.type() )
549  {
550  case QVariant::Double:
552  break;
553 
554  case QVariant::Bool:
556  break;
557 
558  case QVariant::String:
559  default:
561  break;
562  }
563 
564  if ( parts.size() >= 3 )
565  def.setComment( parts.mid( 2 ).join( '_' ) );
566  }
567 
568  return def;
569 }
570 
572 {
574  QgsField afield;
575 
576  if ( !def.name().isEmpty() || !def.comment().isEmpty() )
577  {
578  afield = createAuxiliaryField( def );
579  afield.setTypeName( field.typeName() );
580  }
581 
582  return afield;
583 }
584 
585 //
586 // QgsAuxiliaryStorage
587 //
588 
590  : mCopy( copy )
591 {
592  initTmpFileName();
593 
594  if ( !project.absoluteFilePath().isEmpty() )
595  {
596  mFileName = filenameForProject( project );
597  }
598 
599  open( mFileName );
600 }
601 
602 QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QString &filename, bool copy )
603  : mFileName( filename )
604  , mCopy( copy )
605 {
606  initTmpFileName();
607 
608  open( filename );
609 }
610 
612 {
613  QFile::remove( mTmpFileName );
614 }
615 
617 {
618  return mValid;
619 }
620 
622 {
623  return mFileName;
624 }
625 
627 {
628  if ( mFileName.isEmpty() )
629  {
630  // only a saveAs is available on a new database
631  return false;
632  }
633  else if ( mCopy )
634  {
635  if ( QFile::exists( mFileName ) )
636  QFile::remove( mFileName );
637 
638  return QFile::copy( mTmpFileName, mFileName );
639  }
640  else
641  {
642  // if the file is not empty the copy mode is not activated, then we're
643  // directly working on the database since the beginning (no savepoints
644  // /rollback for now)
645  return true;
646  }
647 }
648 
650 {
651  QgsAuxiliaryLayer *alayer = nullptr;
652 
653  if ( mValid && layer )
654  {
655  const QString table( layer->id() );
657  database = openDB( currentFileName() );
658 
659  if ( !tableExists( table, database.get() ) )
660  {
661  if ( !createTable( field.typeName(), table, database.get(), mErrorString ) )
662  {
663  return alayer;
664  }
665  }
666 
667  alayer = new QgsAuxiliaryLayer( field.name(), currentFileName(), table, layer );
668  alayer->startEditing();
669  }
670 
671  return alayer;
672 }
673 
675 {
676  bool rc = false;
677  const QgsDataSourceUri uri = parseOgrUri( ogrUri );
678 
679  if ( !uri.database().isEmpty() && !uri.table().isEmpty() )
680  {
682  database = openDB( uri.database() );
683 
684  if ( database )
685  {
686  QString sql = QStringLiteral( "DROP TABLE %1" ).arg( uri.table() );
687  rc = exec( sql, database.get() );
688 
689  sql = QStringLiteral( "VACUUM" );
690  rc = exec( sql, database.get() );
691  }
692  }
693 
694  return rc;
695 }
696 
697 bool QgsAuxiliaryStorage::duplicateTable( const QgsDataSourceUri &ogrUri, const QString &newTable )
698 {
699  const QgsDataSourceUri uri = parseOgrUri( ogrUri );
700  bool rc = false;
701 
702  if ( !uri.table().isEmpty() && !uri.database().isEmpty() )
703  {
705  database = openDB( uri.database() );
706 
707  if ( database )
708  {
709  const QString sql = QStringLiteral( "CREATE TABLE %1 AS SELECT * FROM %2" ).arg( newTable, uri.table() );
710  rc = exec( sql, database.get() );
711  }
712  }
713 
714  return rc;
715 }
716 
718 {
719  return mErrorString;
720 }
721 
722 bool QgsAuxiliaryStorage::saveAs( const QString &filename )
723 {
724  mErrorString.clear();
725 
726  QFile dest( filename );
727  if ( dest.exists() && !dest.remove() )
728  {
729  mErrorString = dest.errorString();
730  return false;
731  }
732 
733  QFile origin( currentFileName() );
734  if ( !origin.copy( filename ) )
735  {
736  mErrorString = origin.errorString();
737  return false;
738  }
739 
740  return true;
741 }
742 
744 {
745  return saveAs( filenameForProject( project ) );
746 }
747 
749 {
750  return AS_EXTENSION;
751 }
752 
754 {
755  const QFileInfo fileinfo( filenameForProject( project ) );
756  return fileinfo.exists() && fileinfo.isFile();
757 }
758 
759 bool QgsAuxiliaryStorage::exec( const QString &sql, sqlite3 *handler )
760 {
761  bool rc = false;
762 
763  if ( handler )
764  {
765  const int err = sqlite3_exec( handler, sql.toStdString().c_str(), nullptr, nullptr, nullptr );
766 
767  if ( err == SQLITE_OK )
768  rc = true;
769  else
770  debugMsg( sql, handler );
771  }
772 
773  return rc;
774 }
775 
776 QString QgsAuxiliaryStorage::debugMsg( const QString &sql, sqlite3 *handler )
777 {
778  const QString err = QString::fromUtf8( sqlite3_errmsg( handler ) );
779  const QString msg = QObject::tr( "Unable to execute" );
780  const QString errMsg = QObject::tr( "%1 '%2': %3" ).arg( msg, sql, err );
781  QgsDebugMsg( errMsg );
782  return errMsg;
783 }
784 
785 bool QgsAuxiliaryStorage::createTable( const QString &type, const QString &table, sqlite3 *handler, QString &errorMsg )
786 {
787  const QString sql = QStringLiteral( "CREATE TABLE IF NOT EXISTS '%1' ( '%2' %3 )" ).arg( table, AS_JOINFIELD, type );
788 
789  if ( !exec( sql, handler ) )
790  {
791  errorMsg = QgsAuxiliaryStorage::debugMsg( sql, handler );
792  return false;
793  }
794 
795  return true;
796 }
797 
798 spatialite_database_unique_ptr QgsAuxiliaryStorage::createDB( const QString &filename )
799 {
801 
802  int rc;
803  rc = database.open_v2( filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr );
804  if ( rc )
805  {
806  debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
807  }
808  else
809  // activating Foreign Key constraints
810  exec( QStringLiteral( "PRAGMA foreign_keys = 1" ), database.get() );
811 
812  return database;
813 }
814 
815 spatialite_database_unique_ptr QgsAuxiliaryStorage::openDB( const QString &filename )
816 {
818  const int rc = database.open_v2( filename, SQLITE_OPEN_READWRITE, nullptr );
819 
820  if ( rc )
821  {
822  debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
823  }
824 
825  return database;
826 }
827 
828 bool QgsAuxiliaryStorage::tableExists( const QString &table, sqlite3 *handler )
829 {
830  const QString sql = QStringLiteral( "SELECT 1 FROM sqlite_master WHERE type='table' AND name='%1'" ).arg( table );
831  int rows = 0;
832  int columns = 0;
833  char **results = nullptr;
834  const int rc = sqlite3_get_table( handler, sql.toStdString().c_str(), &results, &rows, &columns, nullptr );
835  if ( rc != SQLITE_OK )
836  {
837  debugMsg( sql, handler );
838  return false;
839  }
840 
841  sqlite3_free_table( results );
842  if ( rows >= 1 )
843  return true;
844 
845  return false;
846 }
847 
848 spatialite_database_unique_ptr QgsAuxiliaryStorage::open( const QString &filename )
849 {
851 
852  if ( filename.isEmpty() )
853  {
854  if ( ( database = createDB( currentFileName() ) ) )
855  mValid = true;
856  }
857  else if ( QFile::exists( filename ) )
858  {
859  if ( mCopy )
860  QFile::copy( filename, mTmpFileName );
861 
862  if ( ( database = openDB( currentFileName() ) ) )
863  mValid = true;
864  }
865  else
866  {
867  if ( ( database = createDB( currentFileName() ) ) )
868  mValid = true;
869  }
870 
871  return database;
872 }
873 
874 spatialite_database_unique_ptr QgsAuxiliaryStorage::open( const QgsProject &project )
875 {
876  return open( filenameForProject( project ) );
877 }
878 
879 QString QgsAuxiliaryStorage::filenameForProject( const QgsProject &project )
880 {
881  const QFileInfo info( project.absoluteFilePath() );
882  const QString path = info.path() + QDir::separator() + info.baseName();
883  return path + '.' + QgsAuxiliaryStorage::extension();
884 }
885 
886 void QgsAuxiliaryStorage::initTmpFileName()
887 {
888  QTemporaryFile tmpFile;
889  tmpFile.open();
890  tmpFile.close();
891  mTmpFileName = tmpFile.fileName();
892 }
893 
895 {
896  if ( mCopy || mFileName.isEmpty() )
897  return mTmpFileName;
898  else
899  return mFileName;
900 }
901 
902 QgsDataSourceUri QgsAuxiliaryStorage::parseOgrUri( const QgsDataSourceUri &uri )
903 {
904  QgsDataSourceUri newUri;
905 
906  // parsing for ogr style uri :
907  // " filePath|layername='tableName' table="" sql="
908  QStringList uriParts = uri.uri().split( '|' );
909  if ( uriParts.count() < 2 )
910  return newUri;
911 
912  const QString databasePath = uriParts[0].replace( ' ', QString() );
913 
914  const QString table = uriParts[1];
915  QStringList tableParts = table.split( ' ' );
916 
917  if ( tableParts.count() < 1 )
918  return newUri;
919 
920  const QString tableName = tableParts[0].replace( QLatin1String( "layername=" ), QString() );
921 
922  newUri.setDataSource( QString(), tableName, QString() );
923  newUri.setDatabase( databasePath );
924 
925  return newUri;
926 }
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)
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:138
QString name
Definition: qgsfield.h:60
void setPrecision(int precision)
Set the field precision.
Definition: qgsfield.cpp:198
void setName(const QString &name)
Set the field name.
Definition: qgsfield.cpp:174
void setLength(int len)
Set the field length.
Definition: qgsfield.cpp:194
QVariant::Type type
Definition: qgsfield.h:58
void setType(QVariant::Type type)
Set variant type.
Definition: qgsfield.cpp:179
void setTypeName(const QString &typeName)
Set the field type.
Definition: qgsfield.cpp:189
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:344
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:101
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:698
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Definition for a property.
Definition: qgsproperty.h:48
StandardPropertyTemplate standardTemplate() const
Returns the property's standard template, if applicable.
Definition: qgsproperty.h:195
QString comment() const
Returns the comment of the property.
Definition: qgsproperty.h:169
DataType dataType() const
Returns the allowable field/value data type for the property.
Definition: qgsproperty.h:189
void setOrigin(const QString &origin)
Sets the origin of the property.
Definition: qgsproperty.h:159
@ ColorNoAlpha
Color with no alpha channel.
Definition: qgsproperty.h:66
@ ColorWithAlpha
Color with alpha channel.
Definition: qgsproperty.h:65
QString name() const
Returns the name of the property.
Definition: qgsproperty.h:140
void setDataType(DataType type)
Sets the data type.
Definition: qgsproperty.h:184
void setName(const QString &name)
Sets the name of the property.
Definition: qgsproperty.h:145
QString origin() const
Returns the origin of the property.
Definition: qgsproperty.h:152
void setComment(const QString &comment)
Sets comment of the property.
Definition: qgsproperty.h:174
@ DataTypeString
Property requires a string value.
Definition: qgsproperty.h:93
@ DataTypeBoolean
Property requires a boolean value.
Definition: qgsproperty.h:107
@ DataTypeNumeric
Property requires a numeric value.
Definition: qgsproperty.h:100
A store for object properties.
Definition: qgsproperty.h:232
@ InvalidProperty
Invalid (not set) property.
Definition: qgsproperty.h:238
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
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 spatialite databases, which automatically closes the database when the pointer goe...
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