LCOV - code coverage report
Current view: top level - core - qgsauxiliarystorage.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 47 511 9.2 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                           qgsauxiliarystorage.cpp  -  description
       3                 :            :                             -------------------
       4                 :            :     begin                : Aug 28, 2017
       5                 :            :     copyright            : (C) 2017 by Paul Blottiere
       6                 :            :     email                : paul.blottiere@oslandia.com
       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;
      34                 :          0 : Q_GLOBAL_STATIC_WITH_ARGS( PalPropertyList, palHiddenProperties, (
      35                 :            : {
      36                 :            :   QgsPalLayerSettings::PositionX,
      37                 :            :   QgsPalLayerSettings::PositionY,
      38                 :            :   QgsPalLayerSettings::Show,
      39                 :            :   QgsPalLayerSettings::LabelRotation,
      40                 :            :   QgsPalLayerSettings::Family,
      41                 :            :   QgsPalLayerSettings::FontStyle,
      42                 :            :   QgsPalLayerSettings::Size,
      43                 :            :   QgsPalLayerSettings::Bold,
      44                 :            :   QgsPalLayerSettings::Italic,
      45                 :            :   QgsPalLayerSettings::Underline,
      46                 :            :   QgsPalLayerSettings::Color,
      47                 :            :   QgsPalLayerSettings::Strikeout,
      48                 :            :   QgsPalLayerSettings::MultiLineAlignment,
      49                 :            :   QgsPalLayerSettings::BufferSize,
      50                 :            :   QgsPalLayerSettings::BufferDraw,
      51                 :            :   QgsPalLayerSettings::BufferColor,
      52                 :            :   QgsPalLayerSettings::LabelDistance,
      53                 :            :   QgsPalLayerSettings::Hali,
      54                 :            :   QgsPalLayerSettings::Vali,
      55                 :            :   QgsPalLayerSettings::ScaleVisibility,
      56                 :            :   QgsPalLayerSettings::MinScale,
      57                 :            :   QgsPalLayerSettings::MaxScale,
      58                 :            :   QgsPalLayerSettings::AlwaysShow,
      59                 :            :   QgsPalLayerSettings::CalloutDraw,
      60                 :            :   QgsPalLayerSettings::LabelAllParts
      61                 :            : } ) )
      62                 :            : 
      63                 :            : //
      64                 :            : // QgsAuxiliaryLayer
      65                 :            : //
      66                 :            : 
      67                 :          0 : QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer )
      68                 :          0 :   : QgsVectorLayer( QStringLiteral( "%1|layername=%2" ).arg( filename, table ),
      69                 :          0 :                     QStringLiteral( "%1_auxiliarystorage" ).arg( table ), QStringLiteral( "ogr" ) )
      70                 :          0 :   , mFileName( filename )
      71                 :          0 :   , mTable( table )
      72                 :          0 :   , mLayer( vlayer )
      73                 :          0 : {
      74                 :            :   // init join info
      75                 :          0 :   mJoinInfo.setPrefix( AS_JOINPREFIX );
      76                 :          0 :   mJoinInfo.setJoinLayer( this );
      77                 :          0 :   mJoinInfo.setJoinFieldName( AS_JOINFIELD );
      78                 :          0 :   mJoinInfo.setTargetFieldName( pkField );
      79                 :          0 :   mJoinInfo.setEditable( true );
      80                 :          0 :   mJoinInfo.setUpsertOnEdit( true );
      81                 :          0 :   mJoinInfo.setCascadedDelete( true );
      82                 :          0 :   mJoinInfo.setJoinFieldNamesBlockList( QStringList() << QStringLiteral( "rowid" ) ); // introduced by ogr provider
      83                 :          0 : }
      84                 :            : 
      85                 :          0 : QgsAuxiliaryLayer *QgsAuxiliaryLayer::clone( QgsVectorLayer *target ) const
      86                 :            : {
      87                 :          0 :   QgsAuxiliaryStorage::duplicateTable( source(), target->id() );
      88                 :          0 :   return new QgsAuxiliaryLayer( mJoinInfo.targetFieldName(), mFileName, target->id(), target );
      89                 :          0 : }
      90                 :            : 
      91                 :          0 : bool QgsAuxiliaryLayer::clear()
      92                 :            : {
      93                 :          0 :   bool rc = deleteFeatures( allFeatureIds() );
      94                 :          0 :   commitChanges();
      95                 :          0 :   startEditing();
      96                 :          0 :   return rc;
      97                 :          0 : }
      98                 :            : 
      99                 :          0 : QgsVectorLayer *QgsAuxiliaryLayer::toSpatialLayer() const
     100                 :            : {
     101                 :          0 :   QgsVectorLayer *layer = QgsMemoryProviderUtils::createMemoryLayer( QStringLiteral( "auxiliary_layer" ), fields(), mLayer->wkbType(), mLayer->crs() );
     102                 :            : 
     103                 :          0 :   QString pkField = mJoinInfo.targetFieldName();
     104                 :          0 :   QgsFeature joinFeature;
     105                 :          0 :   QgsFeature targetFeature;
     106                 :          0 :   QgsFeatureIterator it = getFeatures();
     107                 :            : 
     108                 :          0 :   layer->startEditing();
     109                 :          0 :   while ( it.nextFeature( joinFeature ) )
     110                 :            :   {
     111                 :          0 :     QString filter = QgsExpression::createFieldEqualityExpression( pkField, joinFeature.attribute( AS_JOINFIELD ) );
     112                 :            : 
     113                 :          0 :     QgsFeatureRequest request;
     114                 :          0 :     request.setFilterExpression( filter );
     115                 :            : 
     116                 :          0 :     mLayer->getFeatures( request ).nextFeature( targetFeature );
     117                 :            : 
     118                 :          0 :     if ( targetFeature.isValid() )
     119                 :            :     {
     120                 :          0 :       QgsFeature newFeature( joinFeature );
     121                 :          0 :       newFeature.setGeometry( targetFeature.geometry() );
     122                 :          0 :       layer->addFeature( newFeature );
     123                 :          0 :     }
     124                 :          0 :   }
     125                 :          0 :   layer->commitChanges();
     126                 :            : 
     127                 :          0 :   return layer;
     128                 :          0 : }
     129                 :            : 
     130                 :          0 : QgsVectorLayerJoinInfo QgsAuxiliaryLayer::joinInfo() const
     131                 :            : {
     132                 :          0 :   return mJoinInfo;
     133                 :            : }
     134                 :            : 
     135                 :          0 : bool QgsAuxiliaryLayer::exists( const QgsPropertyDefinition &definition ) const
     136                 :            : {
     137                 :          0 :   return ( indexOfPropertyDefinition( definition ) >= 0 );
     138                 :            : }
     139                 :            : 
     140                 :          0 : bool QgsAuxiliaryLayer::addAuxiliaryField( const QgsPropertyDefinition &definition )
     141                 :            : {
     142                 :          0 :   if ( ( definition.name().isEmpty() && definition.comment().isEmpty() ) || exists( definition ) )
     143                 :          0 :     return false;
     144                 :            : 
     145                 :          0 :   const QgsField af = createAuxiliaryField( definition );
     146                 :          0 :   const bool rc = addAttribute( af );
     147                 :          0 :   updateFields();
     148                 :          0 :   mLayer->updateFields();
     149                 :            : 
     150                 :          0 :   if ( rc )
     151                 :            :   {
     152                 :          0 :     int auxIndex = indexOfPropertyDefinition( definition );
     153                 :          0 :     int index = mLayer->fields().indexOf( nameFromProperty( definition, true ) );
     154                 :            : 
     155                 :          0 :     if ( index >= 0 && auxIndex >= 0 )
     156                 :            :     {
     157                 :          0 :       if ( isHiddenProperty( auxIndex ) )
     158                 :            :       {
     159                 :            :         // update editor widget
     160                 :          0 :         QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Hidden" ), QVariantMap() );
     161                 :          0 :         setEditorWidgetSetup( auxIndex, setup );
     162                 :            : 
     163                 :            :         // column is hidden
     164                 :          0 :         QgsAttributeTableConfig attrCfg = mLayer->attributeTableConfig();
     165                 :          0 :         attrCfg.update( mLayer->fields() );
     166                 :          0 :         QVector<QgsAttributeTableConfig::ColumnConfig> columns = attrCfg.columns();
     167                 :            :         QVector<QgsAttributeTableConfig::ColumnConfig>::iterator it;
     168                 :            : 
     169                 :          0 :         for ( it = columns.begin(); it != columns.end(); ++it )
     170                 :            :         {
     171                 :          0 :           if ( it->name.compare( mLayer->fields().field( index ).name() ) == 0 )
     172                 :          0 :             it->hidden = true;
     173                 :          0 :         }
     174                 :            : 
     175                 :          0 :         attrCfg.setColumns( columns );
     176                 :          0 :         mLayer->setAttributeTableConfig( attrCfg );
     177                 :          0 :       }
     178                 :          0 :       else if ( definition.standardTemplate() == QgsPropertyDefinition::ColorNoAlpha
     179                 :          0 :                 || definition.standardTemplate() == QgsPropertyDefinition::ColorWithAlpha )
     180                 :            :       {
     181                 :          0 :         QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Color" ), QVariantMap() );
     182                 :          0 :         setEditorWidgetSetup( auxIndex, setup );
     183                 :          0 :       }
     184                 :            : 
     185                 :          0 :       mLayer->setEditorWidgetSetup( index, editorWidgetSetup( auxIndex ) );
     186                 :          0 :     }
     187                 :          0 :   }
     188                 :            : 
     189                 :          0 :   return rc;
     190                 :          0 : }
     191                 :            : 
     192                 :          0 : QgsFields QgsAuxiliaryLayer::auxiliaryFields() const
     193                 :            : {
     194                 :          0 :   QgsFields afields;
     195                 :            : 
     196                 :          0 :   for ( int i = 2; i < fields().count(); i++ ) // ignore rowid and PK field
     197                 :          0 :     afields.append( createAuxiliaryField( fields().field( i ) ) );
     198                 :            : 
     199                 :          0 :   return afields;
     200                 :          0 : }
     201                 :            : 
     202                 :          0 : bool QgsAuxiliaryLayer::deleteAttribute( int attr )
     203                 :            : {
     204                 :          0 :   QgsVectorLayer::deleteAttribute( attr );
     205                 :          0 :   bool rc = commitChanges();
     206                 :          0 :   startEditing();
     207                 :          0 :   return rc;
     208                 :            : }
     209                 :            : 
     210                 :          0 : bool QgsAuxiliaryLayer::save()
     211                 :            : {
     212                 :          0 :   bool rc = false;
     213                 :            : 
     214                 :          0 :   if ( isEditable() )
     215                 :            :   {
     216                 :          0 :     rc = commitChanges();
     217                 :          0 :   }
     218                 :            : 
     219                 :          0 :   startEditing();
     220                 :            : 
     221                 :          0 :   return rc;
     222                 :            : }
     223                 :            : 
     224                 :          0 : int QgsAuxiliaryLayer::createProperty( QgsPalLayerSettings::Property property, QgsVectorLayer *layer )
     225                 :            : {
     226                 :          0 :   int index = -1;
     227                 :            : 
     228                 :          0 :   if ( layer && layer->labeling() && layer->auxiliaryLayer() )
     229                 :            :   {
     230                 :            :     // property definition are identical whatever the provider id
     231                 :          0 :     const QgsPropertyDefinition def = layer->labeling()->settings().propertyDefinitions()[property];
     232                 :          0 :     const QString fieldName = nameFromProperty( def, true );
     233                 :            : 
     234                 :          0 :     layer->auxiliaryLayer()->addAuxiliaryField( def );
     235                 :            : 
     236                 :          0 :     if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
     237                 :            :     {
     238                 :          0 :       const QgsProperty prop = QgsProperty::fromField( fieldName );
     239                 :            : 
     240                 :          0 :       const QStringList subProviderIds = layer->labeling()->subProviders();
     241                 :          0 :       for ( const QString &providerId : subProviderIds )
     242                 :            :       {
     243                 :          0 :         QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
     244                 :            : 
     245                 :          0 :         QgsPropertyCollection c = settings->dataDefinedProperties();
     246                 :          0 :         c.setProperty( property, prop );
     247                 :          0 :         settings->setDataDefinedProperties( c );
     248                 :            : 
     249                 :          0 :         layer->labeling()->setSettings( settings, providerId );
     250                 :          0 :       }
     251                 :          0 :     }
     252                 :            : 
     253                 :          0 :     index = layer->fields().lookupField( fieldName );
     254                 :          0 :   }
     255                 :            : 
     256                 :          0 :   return index;
     257                 :          0 : }
     258                 :            : 
     259                 :          0 : int QgsAuxiliaryLayer::createProperty( QgsDiagramLayerSettings::Property property, QgsVectorLayer *layer )
     260                 :            : {
     261                 :          0 :   int index = -1;
     262                 :            : 
     263                 :          0 :   if ( layer && layer->diagramLayerSettings() && layer->auxiliaryLayer() )
     264                 :            :   {
     265                 :          0 :     const QgsPropertyDefinition def = layer->diagramLayerSettings()->propertyDefinitions()[property];
     266                 :            : 
     267                 :          0 :     if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) )
     268                 :            :     {
     269                 :          0 :       const QString fieldName = nameFromProperty( def, true );
     270                 :          0 :       const QgsProperty prop = QgsProperty::fromField( fieldName );
     271                 :            : 
     272                 :          0 :       QgsDiagramLayerSettings settings( *layer->diagramLayerSettings() );
     273                 :            : 
     274                 :          0 :       QgsPropertyCollection c = settings.dataDefinedProperties();
     275                 :          0 :       c.setProperty( property, prop );
     276                 :          0 :       settings.setDataDefinedProperties( c );
     277                 :            : 
     278                 :          0 :       layer->setDiagramLayerSettings( settings );
     279                 :          0 :       index = layer->fields().lookupField( fieldName );
     280                 :          0 :     }
     281                 :          0 :   }
     282                 :            : 
     283                 :          0 :   return index;
     284                 :          0 : }
     285                 :            : 
     286                 :          0 : int QgsAuxiliaryLayer::createProperty( QgsCallout::Property property, QgsVectorLayer *layer )
     287                 :            : {
     288                 :          0 :   int index = -1;
     289                 :            : 
     290                 :          0 :   if ( layer && layer->labeling() && layer->labeling()->settings().callout() && layer->auxiliaryLayer() )
     291                 :            :   {
     292                 :            :     // property definition are identical whatever the provider id
     293                 :          0 :     const QgsPropertyDefinition def = layer->labeling()->settings().callout()->propertyDefinitions()[property];
     294                 :          0 :     const QString fieldName = nameFromProperty( def, true );
     295                 :            : 
     296                 :          0 :     layer->auxiliaryLayer()->addAuxiliaryField( def );
     297                 :            : 
     298                 :          0 :     if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
     299                 :            :     {
     300                 :          0 :       const QgsProperty prop = QgsProperty::fromField( fieldName );
     301                 :            : 
     302                 :          0 :       const QStringList subProviderIds = layer->labeling()->subProviders();
     303                 :          0 :       for ( const QString &providerId : subProviderIds )
     304                 :            :       {
     305                 :          0 :         QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
     306                 :          0 :         if ( settings->callout() )
     307                 :            :         {
     308                 :          0 :           QgsPropertyCollection c = settings->callout()->dataDefinedProperties();
     309                 :          0 :           c.setProperty( property, prop );
     310                 :          0 :           settings->callout()->setDataDefinedProperties( c );
     311                 :          0 :         }
     312                 :          0 :         layer->labeling()->setSettings( settings, providerId );
     313                 :            :       }
     314                 :          0 :     }
     315                 :            : 
     316                 :          0 :     index = layer->fields().lookupField( fieldName );
     317                 :          0 :   }
     318                 :            : 
     319                 :          0 :   return index;
     320                 :          0 : }
     321                 :            : 
     322                 :          0 : bool QgsAuxiliaryLayer::isHiddenProperty( int index ) const
     323                 :            : {
     324                 :          0 :   bool hidden = false;
     325                 :          0 :   QgsPropertyDefinition def = propertyDefinitionFromIndex( index );
     326                 :            : 
     327                 :          0 :   if ( def.origin().compare( QLatin1String( "labeling" ) ) == 0 )
     328                 :            :   {
     329                 :          0 :     const PalPropertyList &palProps = *palHiddenProperties();
     330                 :          0 :     for ( const QgsPalLayerSettings::Property &p : palProps )
     331                 :            :     {
     332                 :          0 :       const QString propName = QgsPalLayerSettings::propertyDefinitions()[ p ].name();
     333                 :          0 :       if ( propName.compare( def.name() ) == 0 )
     334                 :            :       {
     335                 :          0 :         hidden = true;
     336                 :          0 :         break;
     337                 :            :       }
     338                 :          0 :     }
     339                 :          0 :   }
     340                 :            : 
     341                 :          0 :   return hidden;
     342                 :          0 : }
     343                 :            : 
     344                 :          0 : int QgsAuxiliaryLayer::propertyFromIndex( int index ) const
     345                 :            : {
     346                 :          0 :   int p = -1;
     347                 :          0 :   QgsPropertyDefinition aDef = propertyDefinitionFromIndex( index );
     348                 :            : 
     349                 :          0 :   if ( aDef.origin().compare( QLatin1String( "labeling" ) ) == 0 )
     350                 :            :   {
     351                 :          0 :     const QgsPropertiesDefinition defs = QgsPalLayerSettings::propertyDefinitions();
     352                 :          0 :     QgsPropertiesDefinition::const_iterator it = defs.constBegin();
     353                 :          0 :     for ( ; it != defs.constEnd(); ++it )
     354                 :            :     {
     355                 :          0 :       if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
     356                 :            :       {
     357                 :          0 :         p = it.key();
     358                 :          0 :         break;
     359                 :            :       }
     360                 :          0 :     }
     361                 :          0 :   }
     362                 :          0 :   else if ( aDef.origin().compare( QLatin1String( "symbol" ) ) == 0 )
     363                 :            :   {
     364                 :          0 :     const QgsPropertiesDefinition defs = QgsSymbolLayer::propertyDefinitions();
     365                 :          0 :     QgsPropertiesDefinition::const_iterator it = defs.constBegin();
     366                 :          0 :     for ( ; it != defs.constEnd(); ++it )
     367                 :            :     {
     368                 :          0 :       if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
     369                 :            :       {
     370                 :          0 :         p = it.key();
     371                 :          0 :         break;
     372                 :            :       }
     373                 :          0 :     }
     374                 :          0 :   }
     375                 :          0 :   else if ( aDef.origin().compare( QLatin1String( "diagram" ) ) == 0 )
     376                 :            :   {
     377                 :          0 :     const QgsPropertiesDefinition defs = QgsDiagramLayerSettings::propertyDefinitions();
     378                 :          0 :     QgsPropertiesDefinition::const_iterator it = defs.constBegin();
     379                 :          0 :     for ( ; it != defs.constEnd(); ++it )
     380                 :            :     {
     381                 :          0 :       if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
     382                 :            :       {
     383                 :          0 :         p = it.key();
     384                 :          0 :         break;
     385                 :            :       }
     386                 :          0 :     }
     387                 :          0 :   }
     388                 :            : 
     389                 :          0 :   return p;
     390                 :          0 : }
     391                 :            : 
     392                 :          0 : QgsPropertyDefinition QgsAuxiliaryLayer::propertyDefinitionFromIndex( int index ) const
     393                 :            : {
     394                 :          0 :   return propertyDefinitionFromField( fields().field( index ) );
     395                 :          0 : }
     396                 :            : 
     397                 :          0 : int QgsAuxiliaryLayer::indexOfPropertyDefinition( const QgsPropertyDefinition &def ) const
     398                 :            : {
     399                 :          0 :   return fields().indexOf( nameFromProperty( def ) );
     400                 :          0 : }
     401                 :            : 
     402                 :          0 : QString QgsAuxiliaryLayer::nameFromProperty( const QgsPropertyDefinition &def, bool joined )
     403                 :            : {
     404                 :          0 :   QString fieldName = def.origin();
     405                 :            : 
     406                 :          0 :   if ( !def.name().isEmpty() )
     407                 :          0 :     fieldName =  QStringLiteral( "%1_%2" ).arg( fieldName, def.name().toLower() );
     408                 :            : 
     409                 :          0 :   if ( !def.comment().isEmpty() )
     410                 :          0 :     fieldName = QStringLiteral( "%1_%2" ).arg( fieldName, def.comment() );
     411                 :            : 
     412                 :          0 :   if ( joined )
     413                 :          0 :     fieldName = QStringLiteral( "%1%2" ).arg( AS_JOINPREFIX, fieldName );
     414                 :            : 
     415                 :          0 :   return fieldName;
     416                 :          0 : }
     417                 :            : 
     418                 :          0 : QgsField QgsAuxiliaryLayer::createAuxiliaryField( const QgsPropertyDefinition &def )
     419                 :            : {
     420                 :          0 :   QgsField afield;
     421                 :            : 
     422                 :          0 :   if ( !def.name().isEmpty() || !def.comment().isEmpty() )
     423                 :            :   {
     424                 :          0 :     QVariant::Type type = QVariant::Invalid;
     425                 :          0 :     QString typeName;
     426                 :          0 :     int len( 0 ), precision( 0 );
     427                 :          0 :     switch ( def.dataType() )
     428                 :            :     {
     429                 :            :       case QgsPropertyDefinition::DataTypeString:
     430                 :          0 :         type = QVariant::String;
     431                 :          0 :         len = 50;
     432                 :          0 :         typeName = QStringLiteral( "String" );
     433                 :          0 :         break;
     434                 :            :       case QgsPropertyDefinition::DataTypeNumeric:
     435                 :          0 :         type = QVariant::Double;
     436                 :         13 :         len = 0;
     437                 :          0 :         precision = 0;
     438                 :          0 :         typeName = QStringLiteral( "Real" );
     439                 :          0 :         break;
     440                 :            :       case QgsPropertyDefinition::DataTypeBoolean:
     441                 :          0 :         type = QVariant::Int; // sqlite does not have a bool type
     442                 :          0 :         typeName = QStringLiteral( "Integer" );
     443                 :          0 :         break;
     444                 :            :     }
     445                 :            : 
     446                 :          0 :     afield.setType( type );
     447                 :          0 :     afield.setName( nameFromProperty( def ) );
     448                 :          0 :     afield.setTypeName( typeName );
     449                 :          0 :     afield.setLength( len );
     450                 :          0 :     afield.setPrecision( precision );
     451                 :          0 :   }
     452                 :            : 
     453                 :          0 :   return afield;
     454                 :          0 : }
     455                 :            : 
     456                 :          0 : QgsPropertyDefinition QgsAuxiliaryLayer::propertyDefinitionFromField( const QgsField &f )
     457                 :            : {
     458                 :          0 :   QgsPropertyDefinition def;
     459                 :          0 :   const QStringList parts = f.name().split( '_' );
     460                 :            : 
     461                 :          0 :   if ( parts.size() <= 1 )
     462                 :          0 :     return def;
     463                 :            : 
     464                 :          0 :   const QString origin = parts[0];
     465                 :          0 :   const QString propertyName = parts[1];
     466                 :            : 
     467                 :          0 :   if ( origin.compare( QLatin1String( "labeling" ), Qt::CaseInsensitive ) == 0 )
     468                 :            :   {
     469                 :          0 :     const QgsPropertiesDefinition props = QgsPalLayerSettings::propertyDefinitions();
     470                 :          0 :     for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
     471                 :            :     {
     472                 :          0 :       if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
     473                 :            :       {
     474                 :          0 :         def = it.value();
     475                 :          0 :         if ( parts.size() >= 3 )
     476                 :          0 :           def.setComment( parts.mid( 2 ).join( '_' ) );
     477                 :          0 :         break;
     478                 :            :       }
     479                 :          0 :     }
     480                 :          0 :   }
     481                 :          0 :   else if ( origin.compare( QLatin1String( "symbol" ), Qt::CaseInsensitive ) == 0 )
     482                 :            :   {
     483                 :          0 :     const QgsPropertiesDefinition props = QgsSymbolLayer::propertyDefinitions();
     484                 :          0 :     for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
     485                 :            :     {
     486                 :          0 :       if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
     487                 :            :       {
     488                 :          0 :         def = it.value();
     489                 :          0 :         if ( parts.size() >= 3 )
     490                 :          0 :           def.setComment( parts.mid( 2 ).join( '_' ) );
     491                 :          0 :         break;
     492                 :            :       }
     493                 :          0 :     }
     494                 :          0 :   }
     495                 :          0 :   else if ( origin.compare( QLatin1String( "diagram" ), Qt::CaseInsensitive ) == 0 )
     496                 :            :   {
     497                 :          0 :     const QgsPropertiesDefinition props = QgsDiagramLayerSettings::propertyDefinitions();
     498                 :          0 :     for ( auto it = props.constBegin(); it != props.constEnd(); ++it )
     499                 :            :     {
     500                 :          0 :       if ( it.value().name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
     501                 :            :       {
     502                 :          0 :         def = it.value();
     503                 :          0 :         if ( parts.size() >= 3 )
     504                 :          0 :           def.setComment( parts.mid( 2 ).join( '_' ) );
     505                 :          0 :         break;
     506                 :            :       }
     507                 :          0 :     }
     508                 :          0 :   }
     509                 :            :   else
     510                 :            :   {
     511                 :          0 :     def.setOrigin( origin );
     512                 :          0 :     def.setName( propertyName );
     513                 :          0 :     switch ( f.type() )
     514                 :            :     {
     515                 :            :       case QVariant::Double:
     516                 :          0 :         def.setDataType( QgsPropertyDefinition::DataTypeNumeric );
     517                 :          0 :         break;
     518                 :            : 
     519                 :            :       case QVariant::Bool:
     520                 :          0 :         def.setDataType( QgsPropertyDefinition::DataTypeBoolean );
     521                 :          0 :         break;
     522                 :            : 
     523                 :            :       case QVariant::String:
     524                 :            :       default:
     525                 :          0 :         def.setDataType( QgsPropertyDefinition::DataTypeString );
     526                 :          0 :         break;
     527                 :            :     }
     528                 :            : 
     529                 :          0 :     if ( parts.size() >= 3 )
     530                 :          0 :       def.setComment( parts.mid( 2 ).join( '_' ) );
     531                 :            :   }
     532                 :            : 
     533                 :          0 :   return def;
     534                 :          0 : }
     535                 :            : 
     536                 :          0 : QgsField QgsAuxiliaryLayer::createAuxiliaryField( const QgsField &field )
     537                 :            : {
     538                 :          0 :   QgsPropertyDefinition def = propertyDefinitionFromField( field );
     539                 :          0 :   QgsField afield;
     540                 :            : 
     541                 :          0 :   if ( !def.name().isEmpty() || !def.comment().isEmpty() )
     542                 :            :   {
     543                 :          0 :     afield = createAuxiliaryField( def );
     544                 :          0 :     afield.setTypeName( field.typeName() );
     545                 :          0 :   }
     546                 :            : 
     547                 :          0 :   return afield;
     548                 :          0 : }
     549                 :            : 
     550                 :            : //
     551                 :            : // QgsAuxiliaryStorage
     552                 :            : //
     553                 :            : 
     554                 :          0 : QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QgsProject &project, bool copy )
     555                 :          0 :   : mCopy( copy )
     556                 :          0 : {
     557                 :          0 :   initTmpFileName();
     558                 :            : 
     559                 :          0 :   if ( !project.absoluteFilePath().isEmpty() )
     560                 :            :   {
     561                 :          0 :     mFileName = filenameForProject( project );
     562                 :          0 :   }
     563                 :            : 
     564                 :          0 :   open( mFileName );
     565                 :          0 : }
     566                 :            : 
     567                 :         13 : QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QString &filename, bool copy )
     568                 :         13 :   : mFileName( filename )
     569                 :         13 :   , mCopy( copy )
     570                 :         13 : {
     571                 :         13 :   initTmpFileName();
     572                 :            : 
     573                 :         13 :   open( filename );
     574                 :         13 : }
     575                 :            : 
     576                 :         22 : QgsAuxiliaryStorage::~QgsAuxiliaryStorage()
     577                 :         22 : {
     578                 :         11 :   QFile::remove( mTmpFileName );
     579                 :         22 : }
     580                 :            : 
     581                 :          1 : bool QgsAuxiliaryStorage::isValid() const
     582                 :            : {
     583                 :          1 :   return mValid;
     584                 :            : }
     585                 :            : 
     586                 :          0 : QString QgsAuxiliaryStorage::fileName() const
     587                 :            : {
     588                 :          0 :   return mFileName;
     589                 :            : }
     590                 :            : 
     591                 :          0 : bool QgsAuxiliaryStorage::save() const
     592                 :            : {
     593                 :          0 :   if ( mFileName.isEmpty() )
     594                 :            :   {
     595                 :            :     // only a saveAs is available on a new database
     596                 :          0 :     return false;
     597                 :            :   }
     598                 :          0 :   else if ( mCopy )
     599                 :            :   {
     600                 :          0 :     if ( QFile::exists( mFileName ) )
     601                 :          0 :       QFile::remove( mFileName );
     602                 :            : 
     603                 :          0 :     return QFile::copy( mTmpFileName, mFileName );
     604                 :            :   }
     605                 :            :   else
     606                 :            :   {
     607                 :            :     // if the file is not empty the copy mode is not activated, then we're
     608                 :            :     // directly working on the database since the beginning (no savepoints
     609                 :            :     // /rollback for now)
     610                 :          0 :     return true;
     611                 :            :   }
     612                 :          0 : }
     613                 :            : 
     614                 :          0 : QgsAuxiliaryLayer *QgsAuxiliaryStorage::createAuxiliaryLayer( const QgsField &field, QgsVectorLayer *layer ) const
     615                 :            : {
     616                 :          0 :   QgsAuxiliaryLayer *alayer = nullptr;
     617                 :            : 
     618                 :          0 :   if ( mValid && layer )
     619                 :            :   {
     620                 :          0 :     const QString table( layer->id() );
     621                 :          0 :     spatialite_database_unique_ptr database;
     622                 :          0 :     database = openDB( currentFileName() );
     623                 :            : 
     624                 :          0 :     if ( !tableExists( table, database.get() ) )
     625                 :            :     {
     626                 :          0 :       if ( !createTable( field.typeName(), table, database.get() ) )
     627                 :            :       {
     628                 :          0 :         return alayer;
     629                 :            :       }
     630                 :          0 :     }
     631                 :            : 
     632                 :          0 :     alayer = new QgsAuxiliaryLayer( field.name(), currentFileName(), table, layer );
     633                 :          0 :     alayer->startEditing();
     634                 :          0 :   }
     635                 :            : 
     636                 :          0 :   return alayer;
     637                 :          0 : }
     638                 :            : 
     639                 :          0 : bool QgsAuxiliaryStorage::deleteTable( const QgsDataSourceUri &ogrUri )
     640                 :            : {
     641                 :          0 :   bool rc = false;
     642                 :          0 :   QgsDataSourceUri uri = parseOgrUri( ogrUri );
     643                 :            : 
     644                 :          0 :   if ( !uri.database().isEmpty() && !uri.table().isEmpty() )
     645                 :            :   {
     646                 :          0 :     spatialite_database_unique_ptr database;
     647                 :          0 :     database = openDB( uri.database() );
     648                 :            : 
     649                 :          0 :     if ( database )
     650                 :            :     {
     651                 :          0 :       QString sql = QStringLiteral( "DROP TABLE %1" ).arg( uri.table() );
     652                 :          0 :       rc = exec( sql, database.get() );
     653                 :            : 
     654                 :          0 :       sql = QStringLiteral( "VACUUM" );
     655                 :          0 :       rc = exec( sql, database.get() );
     656                 :          0 :     }
     657                 :          0 :   }
     658                 :            : 
     659                 :          0 :   return rc;
     660                 :          0 : }
     661                 :            : 
     662                 :          0 : bool QgsAuxiliaryStorage::duplicateTable( const QgsDataSourceUri &ogrUri, const QString &newTable )
     663                 :            : {
     664                 :          0 :   QgsDataSourceUri uri = parseOgrUri( ogrUri );
     665                 :          0 :   bool rc = false;
     666                 :            : 
     667                 :          0 :   if ( !uri.table().isEmpty() && !uri.database().isEmpty() )
     668                 :            :   {
     669                 :          0 :     spatialite_database_unique_ptr database;
     670                 :          0 :     database = openDB( uri.database() );
     671                 :            : 
     672                 :          0 :     if ( database )
     673                 :            :     {
     674                 :          0 :       QString sql = QStringLiteral( "CREATE TABLE %1 AS SELECT * FROM %2" ).arg( newTable, uri.table() );
     675                 :          0 :       rc = exec( sql, database.get() );
     676                 :          0 :     }
     677                 :          0 :   }
     678                 :            : 
     679                 :          0 :   return rc;
     680                 :          0 : }
     681                 :            : 
     682                 :          0 : QString QgsAuxiliaryStorage::errorString() const
     683                 :            : {
     684                 :          0 :   return mErrorString;
     685                 :            : }
     686                 :            : 
     687                 :          0 : bool QgsAuxiliaryStorage::saveAs( const QString &filename )
     688                 :            : {
     689                 :          0 :   mErrorString.clear();
     690                 :            : 
     691                 :          0 :   QFile dest( filename );
     692                 :          0 :   if ( dest.exists() && !dest.remove() )
     693                 :            :   {
     694                 :          0 :     mErrorString = dest.errorString();
     695                 :          0 :     return false;
     696                 :            :   }
     697                 :            : 
     698                 :          0 :   QFile origin( currentFileName() );
     699                 :          0 :   if ( !origin.copy( filename ) )
     700                 :            :   {
     701                 :          0 :     mErrorString = origin.errorString();
     702                 :          0 :     return false;
     703                 :            :   }
     704                 :            : 
     705                 :          0 :   return true;
     706                 :          0 : }
     707                 :            : 
     708                 :          0 : bool QgsAuxiliaryStorage::saveAs( const QgsProject &project )
     709                 :            : {
     710                 :          0 :   return saveAs( filenameForProject( project ) );
     711                 :          0 : }
     712                 :            : 
     713                 :          0 : QString QgsAuxiliaryStorage::extension()
     714                 :            : {
     715                 :          0 :   return AS_EXTENSION;
     716                 :            : }
     717                 :            : 
     718                 :          0 : bool QgsAuxiliaryStorage::exists( const QgsProject &project )
     719                 :            : {
     720                 :          0 :   const QFileInfo fileinfo( filenameForProject( project ) );
     721                 :          0 :   return fileinfo.exists() && fileinfo.isFile();
     722                 :          0 : }
     723                 :            : 
     724                 :         13 : bool QgsAuxiliaryStorage::exec( const QString &sql, sqlite3 *handler )
     725                 :            : {
     726                 :         13 :   bool rc = false;
     727                 :            : 
     728                 :         13 :   if ( handler )
     729                 :            :   {
     730                 :         13 :     const int err = sqlite3_exec( handler, sql.toStdString().c_str(), nullptr, nullptr, nullptr );
     731                 :            : 
     732                 :         13 :     if ( err == SQLITE_OK )
     733                 :         13 :       rc = true;
     734                 :            :     else
     735                 :          0 :       debugMsg( sql, handler );
     736                 :         13 :   }
     737                 :            : 
     738                 :         13 :   return rc;
     739                 :          0 : }
     740                 :            : 
     741                 :          0 : void QgsAuxiliaryStorage::debugMsg( const QString &sql, sqlite3 *handler )
     742                 :            : {
     743                 :            : #ifdef QGISDEBUG
     744                 :            :   const QString err = QString::fromUtf8( sqlite3_errmsg( handler ) );
     745                 :            :   const QString msg = QObject::tr( "Unable to execute" );
     746                 :            :   const QString errMsg = QObject::tr( "%1 '%2': %3" ).arg( msg, sql, err );
     747                 :            :   QgsDebugMsg( errMsg );
     748                 :            : #else
     749                 :          0 :   Q_UNUSED( sql )
     750                 :            :   Q_UNUSED( handler )
     751                 :            : #endif
     752                 :          0 : }
     753                 :            : 
     754                 :          0 : bool QgsAuxiliaryStorage::createTable( const QString &type, const QString &table, sqlite3 *handler )
     755                 :            : {
     756                 :          0 :   const QString sql = QStringLiteral( "CREATE TABLE IF NOT EXISTS '%1' ( '%2' %3  )" ).arg( table, AS_JOINFIELD, type );
     757                 :            : 
     758                 :          0 :   if ( !exec( sql, handler ) )
     759                 :          0 :     return false;
     760                 :            : 
     761                 :          0 :   return true;
     762                 :          0 : }
     763                 :            : 
     764                 :         13 : spatialite_database_unique_ptr QgsAuxiliaryStorage::createDB( const QString &filename )
     765                 :            : {
     766                 :         13 :   spatialite_database_unique_ptr database;
     767                 :            : 
     768                 :            :   int rc;
     769                 :         13 :   rc = database.open_v2( filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr );
     770                 :         13 :   if ( rc )
     771                 :            :   {
     772                 :          0 :     debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
     773                 :          0 :   }
     774                 :            :   else
     775                 :            :     // activating Foreign Key constraints
     776                 :         26 :     exec( QStringLiteral( "PRAGMA foreign_keys = 1" ), database.get() );
     777                 :            : 
     778                 :         13 :   return database;
     779                 :         13 : }
     780                 :            : 
     781                 :          0 : spatialite_database_unique_ptr QgsAuxiliaryStorage::openDB( const QString &filename )
     782                 :            : {
     783                 :          0 :   spatialite_database_unique_ptr database;
     784                 :          0 :   int rc = database.open_v2( filename, SQLITE_OPEN_READWRITE, nullptr );
     785                 :            : 
     786                 :          0 :   if ( rc )
     787                 :            :   {
     788                 :          0 :     debugMsg( QStringLiteral( "sqlite3_open_v2" ), database.get() );
     789                 :          0 :   }
     790                 :            : 
     791                 :          0 :   return database;
     792                 :          0 : }
     793                 :            : 
     794                 :          0 : bool QgsAuxiliaryStorage::tableExists( const QString &table, sqlite3 *handler )
     795                 :            : {
     796                 :          0 :   const QString sql = QStringLiteral( "SELECT 1 FROM sqlite_master WHERE type='table' AND name='%1'" ).arg( table );
     797                 :          0 :   int rows = 0;
     798                 :          0 :   int columns = 0;
     799                 :          0 :   char **results = nullptr;
     800                 :          0 :   const int rc = sqlite3_get_table( handler, sql.toStdString().c_str(), &results, &rows, &columns, nullptr );
     801                 :          0 :   if ( rc != SQLITE_OK )
     802                 :            :   {
     803                 :          0 :     debugMsg( sql, handler );
     804                 :          0 :     return false;
     805                 :            :   }
     806                 :            : 
     807                 :          0 :   sqlite3_free_table( results );
     808                 :          0 :   if ( rows >= 1 )
     809                 :          0 :     return true;
     810                 :            : 
     811                 :          0 :   return false;
     812                 :          0 : }
     813                 :            : 
     814                 :         13 : spatialite_database_unique_ptr QgsAuxiliaryStorage::open( const QString &filename )
     815                 :            : {
     816                 :         13 :   spatialite_database_unique_ptr database;
     817                 :            : 
     818                 :         13 :   if ( filename.isEmpty() )
     819                 :            :   {
     820                 :         13 :     if ( ( database = createDB( currentFileName() ) ) )
     821                 :         13 :       mValid = true;
     822                 :         13 :   }
     823                 :          0 :   else if ( QFile::exists( filename ) )
     824                 :            :   {
     825                 :          0 :     if ( mCopy )
     826                 :          0 :       QFile::copy( filename, mTmpFileName );
     827                 :            : 
     828                 :          0 :     if ( ( database = openDB( currentFileName() ) ) )
     829                 :          0 :       mValid = true;
     830                 :          0 :   }
     831                 :            :   else
     832                 :            :   {
     833                 :          0 :     if ( ( database = createDB( currentFileName() ) ) )
     834                 :          0 :       mValid = true;
     835                 :            :   }
     836                 :            : 
     837                 :         13 :   return database;
     838                 :         13 : }
     839                 :            : 
     840                 :          0 : spatialite_database_unique_ptr QgsAuxiliaryStorage::open( const QgsProject &project )
     841                 :            : {
     842                 :          0 :   return open( filenameForProject( project ) );
     843                 :          0 : }
     844                 :            : 
     845                 :          0 : QString QgsAuxiliaryStorage::filenameForProject( const QgsProject &project )
     846                 :            : {
     847                 :          0 :   const QFileInfo info( project.absoluteFilePath() );
     848                 :          0 :   const QString path = info.path() + QDir::separator() + info.baseName();
     849                 :          0 :   return path + '.' + QgsAuxiliaryStorage::extension();
     850                 :          0 : }
     851                 :            : 
     852                 :         13 : void QgsAuxiliaryStorage::initTmpFileName()
     853                 :            : {
     854                 :         13 :   QTemporaryFile tmpFile;
     855                 :         13 :   tmpFile.open();
     856                 :         13 :   tmpFile.close();
     857                 :         13 :   mTmpFileName = tmpFile.fileName();
     858                 :         13 : }
     859                 :            : 
     860                 :         13 : QString QgsAuxiliaryStorage::currentFileName() const
     861                 :            : {
     862                 :         13 :   if ( mCopy || mFileName.isEmpty() )
     863                 :         13 :     return mTmpFileName;
     864                 :            :   else
     865                 :          0 :     return mFileName;
     866                 :         13 : }
     867                 :            : 
     868                 :          0 : QgsDataSourceUri QgsAuxiliaryStorage::parseOgrUri( const QgsDataSourceUri &uri )
     869                 :            : {
     870                 :          0 :   QgsDataSourceUri newUri;
     871                 :            : 
     872                 :            :   // parsing for ogr style uri :
     873                 :            :   // " filePath|layername='tableName' table="" sql="
     874                 :          0 :   QStringList uriParts = uri.uri().split( '|' );
     875                 :          0 :   if ( uriParts.count() < 2 )
     876                 :          0 :     return newUri;
     877                 :            : 
     878                 :          0 :   const QString databasePath = uriParts[0].replace( ' ', QString() );
     879                 :            : 
     880                 :          0 :   const QString table = uriParts[1];
     881                 :          0 :   QStringList tableParts = table.split( ' ' );
     882                 :            : 
     883                 :          0 :   if ( tableParts.count() < 1 )
     884                 :          0 :     return newUri;
     885                 :            : 
     886                 :          0 :   const QString tableName = tableParts[0].replace( QLatin1String( "layername=" ), QString() );
     887                 :            : 
     888                 :          0 :   newUri.setDataSource( QString(), tableName, QString() );
     889                 :          0 :   newUri.setDatabase( databasePath );
     890                 :            : 
     891                 :          0 :   return newUri;
     892                 :          0 : }

Generated by: LCOV version 1.14