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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :      qgsproperty.cpp
       3                 :            :      ---------------
       4                 :            :     Date                 : January 2017
       5                 :            :     Copyright            : (C) 2017 by Nyall Dawson
       6                 :            :     Email                : nyall dot dawson at gmail dot com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : 
      16                 :            : #include "qgsproperty.h"
      17                 :            : #include "qgsproperty_p.h"
      18                 :            : 
      19                 :            : #include "qgslogger.h"
      20                 :            : #include "qgsexpression.h"
      21                 :            : #include "qgsfeature.h"
      22                 :            : #include "qgssymbollayerutils.h"
      23                 :            : #include "qgscolorramp.h"
      24                 :            : 
      25                 :            : #include <QRegularExpression>
      26                 :            : 
      27                 :        269 : QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, const QString &description, QgsPropertyDefinition::StandardPropertyTemplate type, const QString &origin, const QString &comment )
      28                 :        269 :   : mName( name )
      29                 :        269 :   , mDescription( description )
      30                 :        269 :   , mStandardType( type )
      31                 :        269 :   , mOrigin( origin )
      32                 :        269 :   , mComment( comment )
      33                 :            : {
      34                 :        269 :   switch ( mStandardType )
      35                 :            :   {
      36                 :            :     case Boolean:
      37                 :         35 :       mTypes = DataTypeBoolean;
      38                 :         35 :       mHelpText = QObject::tr( "bool [<b>1</b>=True|<b>0</b>=False]" );
      39                 :         35 :       break;
      40                 :            : 
      41                 :            :     case Integer:
      42                 :          0 :       mTypes = DataTypeNumeric;
      43                 :          0 :       mHelpText = QObject::tr( "int [≤ 0 ≥]" );
      44                 :          0 :       break;
      45                 :            : 
      46                 :            :     case IntegerPositive:
      47                 :          5 :       mTypes = DataTypeNumeric;
      48                 :          5 :       mHelpText = QObject::tr( "int [≥ 0]" );
      49                 :          5 :       break;
      50                 :            : 
      51                 :            :     case IntegerPositiveGreaterZero:
      52                 :          0 :       mTypes = DataTypeNumeric;
      53                 :          0 :       mHelpText = QObject::tr( "int [≥ 1]" );
      54                 :          0 :       break;
      55                 :            : 
      56                 :            :     case Double:
      57                 :         10 :       mTypes = DataTypeNumeric;
      58                 :         10 :       mHelpText = QObject::tr( "double [≤ 0.0 ≥]" );
      59                 :         10 :       break;
      60                 :            : 
      61                 :            :     case DoublePositive:
      62                 :         85 :       mTypes = DataTypeNumeric;
      63                 :         85 :       mHelpText = QObject::tr( "double [≥ 0.0]" );
      64                 :         85 :       break;
      65                 :            : 
      66                 :            :     case Double0To1:
      67                 :         20 :       mTypes = DataTypeNumeric;
      68                 :         20 :       mHelpText = QObject::tr( "double [0.0-1.0]" );
      69                 :         20 :       break;
      70                 :            : 
      71                 :            :     case Rotation:
      72                 :         10 :       mTypes = DataTypeNumeric;
      73                 :         10 :       mHelpText = QObject::tr( "double [0.0-360.0]" );
      74                 :         10 :       break;
      75                 :            : 
      76                 :            :     case String:
      77                 :         25 :       mTypes = DataTypeString;
      78                 :         25 :       mHelpText = QObject::tr( "string of variable length" );
      79                 :         25 :       break;
      80                 :            : 
      81                 :            :     case Opacity:
      82                 :          9 :       mTypes = DataTypeNumeric;
      83                 :          9 :       mHelpText = QObject::tr( "int [0-100]" );
      84                 :          9 :       break;
      85                 :            : 
      86                 :            :     case RenderUnits:
      87                 :          0 :       mTypes = DataTypeString;
      88                 :          0 :       mHelpText = trString() + QStringLiteral( "[<b>MM</b>|<b>MapUnit</b>|<b>Pixel</b>|<b>Point</b>]" );
      89                 :          0 :       break;
      90                 :            : 
      91                 :            :     case ColorWithAlpha:
      92                 :         15 :       mTypes = DataTypeString;
      93                 :         15 :       mHelpText = QObject::tr( "string [<b>r,g,b,a</b>] as int 0-255 or #<b>AARRGGBB</b> as hex or <b>color</b> as color's name" );
      94                 :         15 :       break;
      95                 :            : 
      96                 :            :     case ColorNoAlpha:
      97                 :          0 :       mTypes = DataTypeString;
      98                 :          0 :       mHelpText = QObject::tr( "string [<b>r,g,b</b>] as int 0-255 or #<b>RRGGBB</b> as hex or <b>color</b> as color's name" );
      99                 :          0 :       break;
     100                 :            : 
     101                 :            :     case PenJoinStyle:
     102                 :          5 :       mTypes = DataTypeString;
     103                 :         10 :       mHelpText = trString() + QStringLiteral( "[<b>bevel</b>|<b>miter</b>|<b>round</b>]" );
     104                 :          5 :       break;
     105                 :            : 
     106                 :            :     case BlendMode:
     107                 :          0 :       mTypes = DataTypeString;
     108                 :          0 :       mHelpText = trString() + QStringLiteral( "[<b>Normal</b>|<b>Lighten</b>|<b>Screen</b>|<b>Dodge</b>|<br>"
     109                 :            :                   "<b>Addition</b>|<b>Darken</b>|<b>Multiply</b>|<b>Burn</b>|<b>Overlay</b>|<br>"
     110                 :            :                   "<b>SoftLight</b>|<b>HardLight</b>|<b>Difference</b>|<b>Subtract</b>]" );
     111                 :          0 :       break;
     112                 :            : 
     113                 :            :     case Point:
     114                 :          0 :       mTypes = DataTypeString;
     115                 :          0 :       mHelpText = QObject::tr( "double coord [<b>X,Y</b>]" );
     116                 :          0 :       break;
     117                 :            : 
     118                 :            :     case Size:
     119                 :          5 :       mTypes = DataTypeNumeric;
     120                 :          5 :       mHelpText = QObject::tr( "double [≥ 0.0]" );
     121                 :          5 :       break;
     122                 :            : 
     123                 :            :     case Size2D:
     124                 :          0 :       mTypes = DataTypeString;
     125                 :          0 :       mHelpText = QObject::tr( "string of doubles '<b>width,height</b>' or array of doubles <b>[width, height]</b>" );
     126                 :          0 :       break;
     127                 :            : 
     128                 :            :     case LineStyle:
     129                 :          5 :       mTypes = DataTypeString;
     130                 :         10 :       mHelpText = trString() + QStringLiteral( "[<b>no</b>|<b>solid</b>|<b>dash</b>|<b>dot</b>|<b>dash dot</b>|<b>dash dot dot</b>]" );
     131                 :          5 :       break;
     132                 :            : 
     133                 :            :     case StrokeWidth:
     134                 :         15 :       mTypes = DataTypeNumeric;
     135                 :         15 :       mHelpText = QObject::tr( "double [≥ 0.0]" );
     136                 :         15 :       break;
     137                 :            : 
     138                 :            :     case FillStyle:
     139                 :          5 :       mTypes = DataTypeString;
     140                 :         10 :       mHelpText = trString() + QStringLiteral( "[<b>solid</b>|<b>horizontal</b>|<b>vertical</b>|<b>cross</b>|<b>b_diagonal</b>|<b>f_diagonal"
     141                 :            :                   "</b>|<b>diagonal_x</b>|<b>dense1</b>|<b>dense2</b>|<b>dense3</b>|<b>dense4</b>|<b>dense5"
     142                 :            :                   "</b>|<b>dense6</b>|<b>dense7</b>|<b>no]" );
     143                 :          5 :       break;
     144                 :            : 
     145                 :            :     case CapStyle:
     146                 :          5 :       mTypes = DataTypeString;
     147                 :         10 :       mHelpText = trString() + QStringLiteral( "[<b>square</b>|<b>flat</b>|<b>round</b>]" );
     148                 :          5 :       break;
     149                 :            : 
     150                 :            :     case HorizontalAnchor:
     151                 :          5 :       mTypes = DataTypeString;
     152                 :         10 :       mHelpText = trString() + QStringLiteral( "[<b>left</b>|<b>center</b>|<b>right</b>]" );
     153                 :          5 :       break;
     154                 :            : 
     155                 :            :     case VerticalAnchor:
     156                 :          5 :       mTypes = DataTypeString;
     157                 :         10 :       mHelpText = trString() + QStringLiteral( "[<b>top</b>|<b>center</b>|<b>bottom</b>]" );
     158                 :          5 :       break;
     159                 :            : 
     160                 :            :     case SvgPath:
     161                 :          0 :       mTypes = DataTypeString;
     162                 :          0 :       mHelpText = trString() + QStringLiteral( "[<b>filepath</b>] as<br>"
     163                 :            :                   "<b>''</b>=empty|absolute|search-paths-relative|<br>"
     164                 :            :                   "project-relative|URL" );
     165                 :          0 :       break;
     166                 :            : 
     167                 :            :     case Offset:
     168                 :          5 :       mTypes = DataTypeString;
     169                 :          5 :       mHelpText = QObject::tr( "string of doubles '<b>x,y</b>' or array of doubles <b>[x, y]</b>" );
     170                 :          5 :       break;
     171                 :            : 
     172                 :            :     case DateTime:
     173                 :          0 :       mTypes = DataTypeString;
     174                 :          0 :       mHelpText = QObject::tr( "DateTime or string representation of a DateTime" );
     175                 :          0 :       break;
     176                 :            : 
     177                 :            :     case Custom:
     178                 :          0 :       mTypes = DataTypeString;
     179                 :          0 :   }
     180                 :        269 : }
     181                 :            : 
     182                 :         45 : QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin, const QString &comment )
     183                 :         45 :   : mName( name )
     184                 :         45 :   , mDescription( description )
     185                 :         45 :   , mTypes( dataType )
     186                 :         45 :   , mHelpText( helpText )
     187                 :         45 :   , mOrigin( origin )
     188                 :         45 :   , mComment( comment )
     189                 :         45 : {}
     190                 :            : 
     191                 :          0 : bool QgsPropertyDefinition::supportsAssistant() const
     192                 :            : {
     193                 :          0 :   return mTypes == DataTypeNumeric || mStandardType == Size || mStandardType == StrokeWidth || mStandardType == ColorNoAlpha || mStandardType == ColorWithAlpha
     194                 :          0 :          || mStandardType == Rotation;
     195                 :            : }
     196                 :            : 
     197                 :         30 : QString QgsPropertyDefinition::trString()
     198                 :            : {
     199                 :            :   // just something to reduce translation redundancy
     200                 :         30 :   return QObject::tr( "string " );
     201                 :            : }
     202                 :            : 
     203                 :            : //
     204                 :            : // QgsProperty
     205                 :            : //
     206                 :            : 
     207                 :        269 : QgsProperty::QgsProperty()
     208                 :            : {
     209                 :         45 :   d = new QgsPropertyPrivate();
     210                 :          0 : }
     211                 :            : 
     212                 :          0 : QgsProperty::~QgsProperty() = default;
     213                 :            : 
     214                 :          0 : QgsProperty QgsProperty::fromExpression( const QString &expression, bool isActive )
     215                 :            : {
     216                 :          0 :   QgsProperty p;
     217                 :          0 :   p.setExpressionString( expression );
     218                 :          0 :   p.setActive( isActive );
     219                 :          0 :   return p;
     220                 :          0 : }
     221                 :            : 
     222                 :          0 : QgsProperty QgsProperty::fromField( const QString &fieldName, bool isActive )
     223                 :            : {
     224                 :          0 :   QgsProperty p;
     225                 :          0 :   p.setField( fieldName );
     226                 :          0 :   p.setActive( isActive );
     227                 :          0 :   return p;
     228                 :          0 : }
     229                 :            : 
     230                 :          0 : QgsProperty QgsProperty::fromValue( const QVariant &value, bool isActive )
     231                 :            : {
     232                 :          0 :   QgsProperty p;
     233                 :          0 :   p.setStaticValue( value );
     234                 :          0 :   p.setActive( isActive );
     235                 :          0 :   return p;
     236                 :          0 : }
     237                 :            : 
     238                 :          0 : QgsProperty::QgsProperty( const QgsProperty &other ) //NOLINT
     239                 :          0 :   : d( other.d )
     240                 :          0 : {}
     241                 :            : 
     242                 :          0 : QgsProperty &QgsProperty::operator=( const QgsProperty &other )  //NOLINT
     243                 :            : {
     244                 :          0 :   d = other.d;
     245                 :          0 :   return *this;
     246                 :            : }
     247                 :            : 
     248                 :          0 : bool QgsProperty::operator==( const QgsProperty &other ) const
     249                 :            : {
     250                 :          0 :   return d->active == other.d->active
     251                 :          0 :          && d->type == other.d->type
     252                 :          0 :          && ( d->type != StaticProperty || d->staticValue == other.d->staticValue )
     253                 :          0 :          && ( d->type != FieldBasedProperty || d->fieldName == other.d->fieldName )
     254                 :          0 :          && ( d->type != ExpressionBasedProperty || d->expressionString == other.d->expressionString )
     255                 :          0 :          && ( ( !d->transformer && !other.d->transformer ) || ( d->transformer && other.d->transformer && d->transformer->toExpression( QString() ) == other.d->transformer->toExpression( QString() ) ) );
     256                 :          0 : }
     257                 :            : 
     258                 :          0 : bool QgsProperty::operator!=( const QgsProperty &other ) const
     259                 :            : {
     260                 :          0 :   return ( !( ( *this ) == other ) );
     261                 :            : }
     262                 :            : 
     263                 :          0 : QgsProperty::Type QgsProperty::propertyType() const
     264                 :            : {
     265                 :          0 :   return static_cast< Type >( d->type );
     266                 :            : }
     267                 :            : 
     268                 :          0 : bool QgsProperty::isActive() const
     269                 :            : {
     270                 :          0 :   return d->type != InvalidProperty && d->active;
     271                 :            : }
     272                 :            : 
     273                 :          0 : void QgsProperty::setActive( bool active )
     274                 :            : {
     275                 :          0 :   d.detach();
     276                 :          0 :   d->active = active;
     277                 :          0 : }
     278                 :            : 
     279                 :          0 : void QgsProperty::setStaticValue( const QVariant &value )
     280                 :            : {
     281                 :          0 :   d.detach();
     282                 :          0 :   d->type = StaticProperty;
     283                 :          0 :   d->staticValue = value;
     284                 :          0 : }
     285                 :            : 
     286                 :          0 : QVariant QgsProperty::staticValue() const
     287                 :            : {
     288                 :          0 :   if ( d->type != StaticProperty )
     289                 :          0 :     return QVariant();
     290                 :            : 
     291                 :          0 :   return d->staticValue;
     292                 :          0 : }
     293                 :            : 
     294                 :          0 : void QgsProperty::setField( const QString &field )
     295                 :            : {
     296                 :          0 :   d.detach();
     297                 :          0 :   d->type = FieldBasedProperty;
     298                 :          0 :   d->fieldName = field;
     299                 :          0 :   d->cachedFieldIdx = -1;
     300                 :          0 : }
     301                 :            : 
     302                 :          0 : QString QgsProperty::field() const
     303                 :            : {
     304                 :          0 :   if ( d->type != FieldBasedProperty )
     305                 :          0 :     return QString();
     306                 :            : 
     307                 :          0 :   return d->fieldName;
     308                 :          0 : }
     309                 :            : 
     310                 :          0 : QgsProperty::operator bool() const
     311                 :            : {
     312                 :          0 :   return d->type != InvalidProperty;
     313                 :            : }
     314                 :            : 
     315                 :          0 : void QgsProperty::setExpressionString( const QString &expression )
     316                 :            : {
     317                 :          0 :   d.detach();
     318                 :          0 :   d->type = ExpressionBasedProperty;
     319                 :          0 :   d->expressionString = expression;
     320                 :          0 :   d->expression = QgsExpression( expression );
     321                 :          0 :   d->expressionPrepared = false;
     322                 :          0 :   d->expressionIsInvalid = false;
     323                 :          0 : }
     324                 :            : 
     325                 :          0 : QString QgsProperty::expressionString() const
     326                 :            : {
     327                 :          0 :   if ( d->type != ExpressionBasedProperty )
     328                 :          0 :     return QString();
     329                 :            : 
     330                 :          0 :   return d->expressionString;
     331                 :          0 : }
     332                 :            : 
     333                 :            : 
     334                 :          0 : QString QgsProperty::asExpression() const
     335                 :            : {
     336                 :          0 :   QString exp;
     337                 :          0 :   switch ( d->type )
     338                 :            :   {
     339                 :            :     case StaticProperty:
     340                 :          0 :       exp = QgsExpression::quotedValue( d->staticValue );
     341                 :          0 :       break;
     342                 :            : 
     343                 :            :     case FieldBasedProperty:
     344                 :          0 :       exp = QgsExpression::quotedColumnRef( d->fieldName );
     345                 :          0 :       break;
     346                 :            : 
     347                 :            :     case ExpressionBasedProperty:
     348                 :          0 :       exp = d->expressionString;
     349                 :          0 :       break;
     350                 :            : 
     351                 :            :     case InvalidProperty:
     352                 :          0 :       exp = QString();
     353                 :          0 :       break;
     354                 :            :   }
     355                 :          0 :   return d->transformer ? d->transformer->toExpression( exp ) : exp;
     356                 :          0 : }
     357                 :            : 
     358                 :          0 : bool QgsProperty::prepare( const QgsExpressionContext &context ) const
     359                 :            : {
     360                 :          0 :   if ( !d->active )
     361                 :          0 :     return true;
     362                 :            : 
     363                 :          0 :   switch ( d->type )
     364                 :            :   {
     365                 :            :     case StaticProperty:
     366                 :          0 :       return true;
     367                 :            : 
     368                 :            :     case FieldBasedProperty:
     369                 :            :     {
     370                 :          0 :       d.detach();
     371                 :            :       // cache field index to avoid subsequent lookups
     372                 :          0 :       QgsFields f = context.fields();
     373                 :          0 :       d->cachedFieldIdx = f.lookupField( d->fieldName );
     374                 :          0 :       return true;
     375                 :          0 :     }
     376                 :            : 
     377                 :            :     case ExpressionBasedProperty:
     378                 :            :     {
     379                 :          0 :       d.detach();
     380                 :          0 :       if ( !d->expression.prepare( &context ) )
     381                 :            :       {
     382                 :          0 :         d->expressionReferencedCols.clear();
     383                 :          0 :         d->expressionPrepared = false;
     384                 :          0 :         d->expressionIsInvalid = true;
     385                 :          0 :         return false;
     386                 :            :       }
     387                 :            : 
     388                 :          0 :       d->expressionPrepared = true;
     389                 :          0 :       d->expressionIsInvalid = false;
     390                 :          0 :       d->expressionReferencedCols = d->expression.referencedColumns();
     391                 :          0 :       return true;
     392                 :            :     }
     393                 :            : 
     394                 :            :     case InvalidProperty:
     395                 :          0 :       return true;
     396                 :            : 
     397                 :            :   }
     398                 :            : 
     399                 :          0 :   return false;
     400                 :          0 : }
     401                 :            : 
     402                 :          0 : QSet<QString> QgsProperty::referencedFields( const QgsExpressionContext &context, bool ignoreContext ) const
     403                 :            : {
     404                 :          0 :   if ( !d->active )
     405                 :          0 :     return QSet<QString>();
     406                 :            : 
     407                 :          0 :   switch ( d->type )
     408                 :            :   {
     409                 :            :     case StaticProperty:
     410                 :            :     case InvalidProperty:
     411                 :          0 :       return QSet<QString>();
     412                 :            : 
     413                 :            :     case FieldBasedProperty:
     414                 :            :     {
     415                 :          0 :       QSet< QString > fields;
     416                 :          0 :       if ( !d->fieldName.isEmpty() )
     417                 :          0 :         fields.insert( d->fieldName );
     418                 :          0 :       return fields;
     419                 :          0 :     }
     420                 :            : 
     421                 :            :     case ExpressionBasedProperty:
     422                 :            :     {
     423                 :          0 :       if ( ignoreContext )
     424                 :            :       {
     425                 :          0 :         return d->expression.referencedColumns();
     426                 :            :       }
     427                 :            : 
     428                 :          0 :       if ( d->expressionIsInvalid )
     429                 :          0 :         return QSet< QString >();
     430                 :            : 
     431                 :          0 :       d.detach();
     432                 :          0 :       if ( !d->expressionPrepared && !prepare( context ) )
     433                 :            :       {
     434                 :          0 :         d->expressionIsInvalid = true;
     435                 :          0 :         return QSet< QString >();
     436                 :            :       }
     437                 :            : 
     438                 :          0 :       return d->expressionReferencedCols;
     439                 :            :     }
     440                 :            : 
     441                 :            :   }
     442                 :          0 :   return QSet<QString>();
     443                 :          0 : }
     444                 :            : 
     445                 :          0 : bool QgsProperty::isProjectColor() const
     446                 :            : {
     447                 :          0 :   QRegularExpression rx( QStringLiteral( "^project_color\\('.*'\\)$" ) );
     448                 :          0 :   return d->type == QgsProperty::ExpressionBasedProperty && !d->expressionString.isEmpty()
     449                 :          0 :          && rx.match( d->expressionString ).hasMatch();
     450                 :          0 : }
     451                 :            : 
     452                 :          0 : QVariant QgsProperty::propertyValue( const QgsExpressionContext &context, const QVariant &defaultValue, bool *ok ) const
     453                 :            : {
     454                 :          0 :   if ( ok )
     455                 :          0 :     *ok = false;
     456                 :            : 
     457                 :          0 :   if ( !d->active )
     458                 :          0 :     return defaultValue;
     459                 :            : 
     460                 :          0 :   switch ( d->type )
     461                 :            :   {
     462                 :            :     case StaticProperty:
     463                 :            :     {
     464                 :          0 :       if ( ok )
     465                 :          0 :         *ok = true;
     466                 :          0 :       return d->staticValue;
     467                 :            :     }
     468                 :            : 
     469                 :            :     case FieldBasedProperty:
     470                 :            :     {
     471                 :          0 :       QgsFeature f = context.feature();
     472                 :          0 :       if ( !f.isValid() )
     473                 :          0 :         return defaultValue;
     474                 :            : 
     475                 :            :       //shortcut the field lookup
     476                 :          0 :       if ( d->cachedFieldIdx >= 0 )
     477                 :            :       {
     478                 :          0 :         if ( ok )
     479                 :          0 :           *ok = true;
     480                 :          0 :         return f.attribute( d->cachedFieldIdx );
     481                 :            :       }
     482                 :          0 :       prepare( context );
     483                 :          0 :       if ( d->cachedFieldIdx < 0 )
     484                 :          0 :         return defaultValue;
     485                 :            : 
     486                 :          0 :       if ( ok )
     487                 :          0 :         *ok = true;
     488                 :          0 :       return f.attribute( d->cachedFieldIdx );
     489                 :          0 :     }
     490                 :            : 
     491                 :            :     case ExpressionBasedProperty:
     492                 :            :     {
     493                 :          0 :       if ( d->expressionIsInvalid )
     494                 :          0 :         return defaultValue;
     495                 :            : 
     496                 :          0 :       if ( !d->expressionPrepared && !prepare( context ) )
     497                 :          0 :         return defaultValue;
     498                 :            : 
     499                 :          0 :       QVariant result = d->expression.evaluate( &context );
     500                 :          0 :       if ( !result.isNull() )
     501                 :            :       {
     502                 :          0 :         if ( ok )
     503                 :          0 :           *ok = true;
     504                 :          0 :         return result;
     505                 :            :       }
     506                 :            :       else
     507                 :            :       {
     508                 :          0 :         return defaultValue;
     509                 :            :       }
     510                 :          0 :     }
     511                 :            : 
     512                 :            :     case InvalidProperty:
     513                 :          0 :       return defaultValue;
     514                 :            : 
     515                 :            :   }
     516                 :            : 
     517                 :          0 :   return QVariant();
     518                 :          0 : }
     519                 :            : 
     520                 :            : 
     521                 :          0 : QVariant QgsProperty::value( const QgsExpressionContext &context, const QVariant &defaultValue, bool *ok ) const
     522                 :            : {
     523                 :          0 :   if ( ok )
     524                 :          0 :     *ok = false;
     525                 :            : 
     526                 :          0 :   bool valOk = false;
     527                 :          0 :   QVariant val = propertyValue( context, defaultValue, &valOk );
     528                 :          0 :   if ( !d->transformer && !valOk ) // if transformer present, let it handle null values
     529                 :          0 :     return defaultValue;
     530                 :            : 
     531                 :          0 :   if ( d->transformer )
     532                 :            :   {
     533                 :          0 :     if ( !valOk )
     534                 :          0 :       val = QVariant();
     535                 :          0 :     val = d->transformer->transform( context, val );
     536                 :          0 :   }
     537                 :            : 
     538                 :          0 :   if ( ok )
     539                 :          0 :     *ok = true;
     540                 :            : 
     541                 :          0 :   return val;
     542                 :          0 : }
     543                 :            : 
     544                 :          0 : QDateTime QgsProperty::valueAsDateTime( const QgsExpressionContext &context, const QDateTime &defaultDateTime, bool *ok ) const
     545                 :            : {
     546                 :          0 :   bool valOk = false;
     547                 :          0 :   QVariant val = value( context, defaultDateTime, &valOk );
     548                 :            : 
     549                 :          0 :   if ( !valOk || val.isNull() )
     550                 :            :   {
     551                 :          0 :     if ( ok )
     552                 :          0 :       *ok = false;
     553                 :          0 :     return defaultDateTime;
     554                 :            :   }
     555                 :            : 
     556                 :          0 :   QDateTime dateTime;
     557                 :          0 :   if ( val.type() == QVariant::DateTime )
     558                 :            :   {
     559                 :          0 :     dateTime = val.value<QDateTime>();
     560                 :          0 :   }
     561                 :            :   else
     562                 :            :   {
     563                 :          0 :     dateTime = val.toDateTime();
     564                 :            :   }
     565                 :            : 
     566                 :          0 :   if ( !dateTime.isValid() )
     567                 :          0 :     return defaultDateTime;
     568                 :            :   else
     569                 :            :   {
     570                 :          0 :     if ( ok )
     571                 :          0 :       *ok = true;
     572                 :          0 :     return dateTime;
     573                 :            :   }
     574                 :          0 : }
     575                 :            : 
     576                 :          0 : QString QgsProperty::valueAsString( const QgsExpressionContext &context, const QString &defaultString, bool *ok ) const
     577                 :            : {
     578                 :          0 :   bool valOk = false;
     579                 :          0 :   QVariant val = value( context, defaultString, &valOk );
     580                 :            : 
     581                 :          0 :   if ( !valOk || val.isNull() )
     582                 :            :   {
     583                 :          0 :     if ( ok )
     584                 :          0 :       *ok = false;
     585                 :          0 :     return defaultString;
     586                 :            :   }
     587                 :            :   else
     588                 :            :   {
     589                 :          0 :     if ( ok )
     590                 :          0 :       *ok = true;
     591                 :          0 :     return val.toString();
     592                 :            :   }
     593                 :          0 : }
     594                 :            : 
     595                 :          0 : QColor QgsProperty::valueAsColor( const QgsExpressionContext &context, const QColor &defaultColor, bool *ok ) const
     596                 :            : {
     597                 :          0 :   if ( ok )
     598                 :          0 :     *ok = false;
     599                 :            : 
     600                 :          0 :   bool valOk = false;
     601                 :          0 :   QVariant val = value( context, defaultColor, &valOk );
     602                 :            : 
     603                 :          0 :   if ( !valOk || val.isNull() )
     604                 :          0 :     return defaultColor;
     605                 :            : 
     606                 :          0 :   QColor color;
     607                 :          0 :   if ( val.type() == QVariant::Color )
     608                 :            :   {
     609                 :          0 :     color = val.value<QColor>();
     610                 :          0 :   }
     611                 :            :   else
     612                 :            :   {
     613                 :          0 :     color = QgsSymbolLayerUtils::decodeColor( val.toString() );
     614                 :            :   }
     615                 :            : 
     616                 :          0 :   if ( !color.isValid() )
     617                 :          0 :     return defaultColor;
     618                 :            :   else
     619                 :            :   {
     620                 :          0 :     if ( ok )
     621                 :          0 :       *ok = true;
     622                 :          0 :     return color;
     623                 :            :   }
     624                 :          0 : }
     625                 :            : 
     626                 :          0 : double QgsProperty::valueAsDouble( const QgsExpressionContext &context, double defaultValue, bool *ok ) const
     627                 :            : {
     628                 :          0 :   if ( ok )
     629                 :          0 :     *ok = false;
     630                 :            : 
     631                 :          0 :   bool valOk = false;
     632                 :          0 :   QVariant val = value( context, defaultValue, &valOk );
     633                 :            : 
     634                 :          0 :   if ( !valOk || val.isNull() )
     635                 :          0 :     return defaultValue;
     636                 :            : 
     637                 :          0 :   bool convertOk = false;
     638                 :          0 :   double dbl = val.toDouble( &convertOk );
     639                 :          0 :   if ( !convertOk )
     640                 :          0 :     return defaultValue;
     641                 :            :   else
     642                 :            :   {
     643                 :          0 :     if ( ok )
     644                 :          0 :       *ok = true;
     645                 :          0 :     return dbl;
     646                 :            :   }
     647                 :          0 : }
     648                 :            : 
     649                 :          0 : int QgsProperty::valueAsInt( const QgsExpressionContext &context, int defaultValue, bool *ok ) const
     650                 :            : {
     651                 :          0 :   if ( ok )
     652                 :          0 :     *ok = false;
     653                 :            : 
     654                 :          0 :   bool valOk = false;
     655                 :          0 :   QVariant val = value( context, defaultValue, &valOk );
     656                 :            : 
     657                 :          0 :   if ( !valOk || val.isNull() )
     658                 :          0 :     return defaultValue;
     659                 :            : 
     660                 :          0 :   bool convertOk = false;
     661                 :          0 :   int integer = val.toInt( &convertOk );
     662                 :          0 :   if ( !convertOk )
     663                 :            :   {
     664                 :            :     //one more option to try
     665                 :          0 :     double dbl = val.toDouble( &convertOk );
     666                 :          0 :     if ( convertOk )
     667                 :            :     {
     668                 :          0 :       if ( ok )
     669                 :          0 :         *ok = true;
     670                 :          0 :       return std::round( dbl );
     671                 :            :     }
     672                 :            :     else
     673                 :            :     {
     674                 :          0 :       return defaultValue;
     675                 :            :     }
     676                 :            :   }
     677                 :            :   else
     678                 :            :   {
     679                 :          0 :     if ( ok )
     680                 :          0 :       *ok = true;
     681                 :          0 :     return integer;
     682                 :            :   }
     683                 :          0 : }
     684                 :            : 
     685                 :          0 : bool QgsProperty::valueAsBool( const QgsExpressionContext &context, bool defaultValue, bool *ok ) const
     686                 :            : {
     687                 :          0 :   if ( ok )
     688                 :          0 :     *ok = false;
     689                 :            : 
     690                 :          0 :   bool valOk = false;
     691                 :          0 :   QVariant val = value( context, defaultValue, &valOk );
     692                 :            : 
     693                 :          0 :   if ( !valOk || val.isNull() )
     694                 :          0 :     return defaultValue;
     695                 :            : 
     696                 :          0 :   if ( ok )
     697                 :          0 :     *ok = true;
     698                 :          0 :   return val.toBool();
     699                 :          0 : }
     700                 :            : 
     701                 :          0 : QVariant QgsProperty::toVariant() const
     702                 :            : {
     703                 :          0 :   QVariantMap propertyMap;
     704                 :            : 
     705                 :          0 :   propertyMap.insert( QStringLiteral( "active" ), d->active );
     706                 :          0 :   propertyMap.insert( QStringLiteral( "type" ), d->type );
     707                 :            : 
     708                 :          0 :   switch ( d->type )
     709                 :            :   {
     710                 :            :     case StaticProperty:
     711                 :            :       // propertyMap.insert( QStringLiteral( "valType" ), d->staticValue.typeName() );
     712                 :          0 :       propertyMap.insert( QStringLiteral( "val" ), d->staticValue.toString() );
     713                 :          0 :       break;
     714                 :            : 
     715                 :            :     case FieldBasedProperty:
     716                 :          0 :       propertyMap.insert( QStringLiteral( "field" ), d->fieldName );
     717                 :          0 :       break;
     718                 :            : 
     719                 :            :     case ExpressionBasedProperty:
     720                 :          0 :       propertyMap.insert( QStringLiteral( "expression" ), d->expressionString );
     721                 :          0 :       break;
     722                 :            : 
     723                 :            :     case InvalidProperty:
     724                 :          0 :       break;
     725                 :            :   }
     726                 :            : 
     727                 :          0 :   if ( d->transformer )
     728                 :            :   {
     729                 :          0 :     QVariantMap transformer;
     730                 :          0 :     transformer.insert( QStringLiteral( "t" ), d->transformer->transformerType() );
     731                 :          0 :     transformer.insert( QStringLiteral( "d" ), d->transformer->toVariant() );
     732                 :            : 
     733                 :          0 :     propertyMap.insert( QStringLiteral( "transformer" ), transformer );
     734                 :          0 :   }
     735                 :            : 
     736                 :          0 :   return propertyMap;
     737                 :          0 : }
     738                 :            : 
     739                 :          0 : bool QgsProperty::loadVariant( const QVariant &property )
     740                 :            : {
     741                 :          0 :   QVariantMap propertyMap = property.toMap();
     742                 :            : 
     743                 :          0 :   d.detach();
     744                 :          0 :   d->active = propertyMap.value( QStringLiteral( "active" ) ).toBool();
     745                 :          0 :   d->type = static_cast< Type >( propertyMap.value( QStringLiteral( "type" ), InvalidProperty ).toInt() );
     746                 :            : 
     747                 :          0 :   switch ( d->type )
     748                 :            :   {
     749                 :            :     case StaticProperty:
     750                 :          0 :       d->staticValue = propertyMap.value( QStringLiteral( "val" ) );
     751                 :            :       // d->staticValue.convert( QVariant::nameToType( propertyElem.attribute( "valType", "QString" ).toLocal8Bit().constData() ) );
     752                 :          0 :       break;
     753                 :            : 
     754                 :            :     case FieldBasedProperty:
     755                 :          0 :       d->fieldName = propertyMap.value( QStringLiteral( "field" ) ).toString();
     756                 :          0 :       if ( d->fieldName.isEmpty() )
     757                 :          0 :         d->active = false;
     758                 :          0 :       break;
     759                 :            : 
     760                 :            :     case ExpressionBasedProperty:
     761                 :          0 :       d->expressionString = propertyMap.value( QStringLiteral( "expression" ) ).toString();
     762                 :          0 :       if ( d->expressionString.isEmpty() )
     763                 :          0 :         d->active = false;
     764                 :            : 
     765                 :          0 :       d->expression = QgsExpression( d->expressionString );
     766                 :          0 :       d->expressionPrepared = false;
     767                 :          0 :       d->expressionIsInvalid = false;
     768                 :          0 :       d->expressionReferencedCols.clear();
     769                 :          0 :       break;
     770                 :            : 
     771                 :            :     case InvalidProperty:
     772                 :          0 :       break;
     773                 :            : 
     774                 :            :   }
     775                 :            : 
     776                 :            :   //restore transformer if present
     777                 :          0 :   delete d->transformer;
     778                 :          0 :   d->transformer = nullptr;
     779                 :            : 
     780                 :            : 
     781                 :          0 :   QVariant transform = propertyMap.value( QStringLiteral( "transformer" ) );
     782                 :            : 
     783                 :          0 :   if ( transform.isValid() )
     784                 :            :   {
     785                 :          0 :     QVariantMap transformerMap = transform.toMap();
     786                 :            : 
     787                 :          0 :     QgsPropertyTransformer::Type type = static_cast< QgsPropertyTransformer::Type >( transformerMap.value( QStringLiteral( "t" ), QgsPropertyTransformer::GenericNumericTransformer ).toInt() );
     788                 :          0 :     std::unique_ptr< QgsPropertyTransformer > transformer( QgsPropertyTransformer::create( type ) );
     789                 :            : 
     790                 :          0 :     if ( transformer )
     791                 :            :     {
     792                 :          0 :       if ( transformer->loadVariant( transformerMap.value( QStringLiteral( "d" ) ) ) )
     793                 :          0 :         d->transformer = transformer.release();
     794                 :          0 :     }
     795                 :          0 :   }
     796                 :            : 
     797                 :            :   return true;
     798                 :          0 : }
     799                 :            : 
     800                 :            : 
     801                 :          0 : void QgsProperty::setTransformer( QgsPropertyTransformer *transformer )
     802                 :            : {
     803                 :          0 :   d.detach();
     804                 :          0 :   d->transformer = transformer;
     805                 :          0 : }
     806                 :            : 
     807                 :          0 : const QgsPropertyTransformer *QgsProperty::transformer() const
     808                 :            : {
     809                 :          0 :   return d->transformer;
     810                 :            : }
     811                 :            : 
     812                 :          0 : bool QgsProperty::convertToTransformer()
     813                 :            : {
     814                 :          0 :   if ( d->type != ExpressionBasedProperty )
     815                 :          0 :     return false;
     816                 :            : 
     817                 :          0 :   if ( d->transformer )
     818                 :          0 :     return false; // already a transformer
     819                 :            : 
     820                 :          0 :   QString baseExpression;
     821                 :          0 :   QString fieldName;
     822                 :          0 :   std::unique_ptr< QgsPropertyTransformer > transformer( QgsPropertyTransformer::fromExpression( d->expressionString, baseExpression, fieldName ) );
     823                 :          0 :   if ( !transformer )
     824                 :          0 :     return false;
     825                 :            : 
     826                 :          0 :   d.detach();
     827                 :          0 :   d->transformer = transformer.release();
     828                 :          0 :   if ( !fieldName.isEmpty() )
     829                 :          0 :     setField( fieldName );
     830                 :            :   else
     831                 :          0 :     setExpressionString( baseExpression );
     832                 :          0 :   return true;
     833                 :          0 : }
     834                 :            : 
     835                 :            : 
     836                 :            : 

Generated by: LCOV version 1.14