QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgsfield.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfield.cpp - Describes a field in a layer or table
3  --------------------------------------
4  Date : 01-Jan-2004
5  Copyright : (C) 2004 by Gary E.Sherman
6  email : sherman at mrcc.com
7 
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgsfields.h"
18 #include "qgsfield_p.h"
19 #include "qgis.h"
20 #include "qgsapplication.h"
21 #include "qgssettings.h"
22 
23 #include <QDataStream>
24 #include <QIcon>
25 #include <QLocale>
26 #include <QJsonDocument>
27 
28 /***************************************************************************
29  * This class is considered CRITICAL and any change MUST be accompanied with
30  * full unit tests in testqgsfield.cpp.
31  * See details in QEP #17
32  ****************************************************************************/
33 
34 #if 0
35 QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
36  QString comment )
37  : mName( nam ), mType( typ ), mLength( len ), mPrecision( prec ), mNumeric( num )
38  , mComment( comment )
39 {
40  // This function used to lower case the field name since some stores
41  // use upper case (e.g., shapefiles), but that caused problems with
42  // attribute actions getting confused between uppercase and
43  // lowercase versions of the attribute names, so just leave the
44  // names how they are now.
45 }
46 #endif
47 QgsField::QgsField( const QString &name, QVariant::Type type,
48  const QString &typeName, int len, int prec, const QString &comment,
49  QVariant::Type subType )
50 {
51  d = new QgsFieldPrivate( name, type, subType, typeName, len, prec, comment );
52 }
53 
54 QgsField::QgsField( const QgsField &other ) //NOLINT
55  : d( other.d )
56 {
57 
58 }
59 
60 QgsField::~QgsField() = default;
61 
62 /***************************************************************************
63  * This class is considered CRITICAL and any change MUST be accompanied with
64  * full unit tests in testqgsfield.cpp.
65  * See details in QEP #17
66  ****************************************************************************/
67 
68 QgsField &QgsField::operator =( const QgsField &other ) //NOLINT
69 {
70  d = other.d;
71  return *this;
72 }
73 
74 bool QgsField::operator==( const QgsField &other ) const
75 {
76  return *( other.d ) == *d;
77 }
78 
79 bool QgsField::operator!=( const QgsField &other ) const
80 {
81  return !( *this == other );
82 }
83 
84 QString QgsField::name() const
85 {
86  return d->name;
87 }
88 
89 QString QgsField::displayName() const
90 {
91  if ( !d->alias.isEmpty() )
92  return d->alias;
93  else
94  return d->name;
95 }
96 
98 {
99  if ( alias().isEmpty() )
100  {
101  return name();
102  }
103  return QStringLiteral( "%1 (%2)" ).arg( name() ).arg( alias() );
104 }
105 
106 QVariant::Type QgsField::type() const
107 {
108  return d->type;
109 }
110 
111 QVariant::Type QgsField::subType() const
112 {
113  return d->subType;
114 }
115 
116 QString QgsField::typeName() const
117 {
118  return d->typeName;
119 }
120 
121 int QgsField::length() const
122 {
123  return d->length;
124 }
125 
126 int QgsField::precision() const
127 {
128  return d->precision;
129 }
130 
131 QString QgsField::comment() const
132 {
133  return d->comment;
134 }
135 
136 bool QgsField::isNumeric() const
137 {
138  return d->type == QVariant::Double || d->type == QVariant::Int || d->type == QVariant::UInt || d->type == QVariant::LongLong || d->type == QVariant::ULongLong;
139 }
140 
141 bool QgsField::isDateOrTime() const
142 {
143  return d->type == QVariant::Date || d->type == QVariant::Time || d->type == QVariant::DateTime;
144 }
145 
146 /***************************************************************************
147  * This class is considered CRITICAL and any change MUST be accompanied with
148  * full unit tests in testqgsfield.cpp.
149  * See details in QEP #17
150  ****************************************************************************/
151 
152 void QgsField::setName( const QString &name )
153 {
154  d->name = name;
155 }
156 
157 void QgsField::setType( QVariant::Type type )
158 {
159  d->type = type;
160 }
161 
162 void QgsField::setSubType( QVariant::Type subType )
163 {
164  d->subType = subType;
165 }
166 
167 void QgsField::setTypeName( const QString &typeName )
168 {
169  d->typeName = typeName;
170 }
171 
172 void QgsField::setLength( int len )
173 {
174  d->length = len;
175 }
177 {
178  d->precision = precision;
179 }
180 
181 void QgsField::setComment( const QString &comment )
182 {
183  d->comment = comment;
184 }
185 
187 {
188  return d->defaultValueDefinition;
189 }
190 
192 {
193  d->defaultValueDefinition = defaultValueDefinition;
194 }
195 
197 {
198  d->constraints = constraints;
199 }
200 
202 {
203  return d->constraints;
204 }
205 
206 QString QgsField::alias() const
207 {
208  return d->alias;
209 }
210 
211 void QgsField::setAlias( const QString &alias )
212 {
213  d->alias = alias;
214 }
215 
216 /***************************************************************************
217  * This class is considered CRITICAL and any change MUST be accompanied with
218  * full unit tests in testqgsfield.cpp.
219  * See details in QEP #17
220  ****************************************************************************/
221 
222 QString QgsField::displayString( const QVariant &v ) const
223 {
224  if ( v.isNull() )
225  {
227  }
228 
229  // Special treatment for numeric types if group separator is set or decimalPoint is not a dot
230  if ( d->type == QVariant::Double )
231  {
232  // Locales with decimal point != '.' or that require group separator: use QLocale
233  if ( QLocale().decimalPoint() != '.' ||
234  !( QLocale().numberOptions() & QLocale::NumberOption::OmitGroupSeparator ) )
235  {
236  if ( d->precision > 0 )
237  {
238  if ( -1 < v.toDouble() && v.toDouble() < 1 )
239  {
240  return QLocale().toString( v.toDouble(), 'g', d->precision );
241  }
242  else
243  {
244  return QLocale().toString( v.toDouble(), 'f', d->precision );
245  }
246  }
247  else
248  {
249  // Precision is not set, let's guess it from the
250  // standard conversion to string
251  QString s( v.toString() );
252  int dotPosition( s.indexOf( '.' ) );
253  int precision;
254  if ( dotPosition < 0 && s.indexOf( 'e' ) < 0 )
255  {
256  precision = 0;
257  return QLocale().toString( v.toDouble(), 'f', precision );
258  }
259  else
260  {
261  if ( dotPosition < 0 ) precision = 0;
262  else precision = s.length() - dotPosition - 1;
263 
264  if ( -1 < v.toDouble() && v.toDouble() < 1 )
265  {
266  return QLocale().toString( v.toDouble(), 'g', precision );
267  }
268  else
269  {
270  return QLocale().toString( v.toDouble(), 'f', precision );
271  }
272  }
273  }
274  }
275  // Default for doubles with precision
276  else if ( d->type == QVariant::Double && d->precision > 0 )
277  {
278  if ( -1 < v.toDouble() && v.toDouble() < 1 )
279  {
280  return QString::number( v.toDouble(), 'g', d->precision );
281  }
282  else
283  {
284  return QString::number( v.toDouble(), 'f', d->precision );
285  }
286  }
287  }
288  // Other numeric types than doubles
289  else if ( isNumeric() &&
290  !( QLocale().numberOptions() & QLocale::NumberOption::OmitGroupSeparator ) )
291  {
292  bool ok;
293  qlonglong converted( v.toLongLong( &ok ) );
294  if ( ok )
295  return QLocale().toString( converted );
296  }
297  else if ( d->typeName.compare( QLatin1String( "json" ), Qt::CaseInsensitive ) == 0 || d->typeName == QLatin1String( "jsonb" ) )
298  {
299  QJsonDocument doc = QJsonDocument::fromVariant( v );
300  return QString::fromUtf8( doc.toJson().data() );
301  }
302  else if ( d->type == QVariant::ByteArray )
303  {
304  return QObject::tr( "BLOB" );
305  }
306  // Fallback if special rules do not apply
307  return v.toString();
308 }
309 
310 /***************************************************************************
311  * This class is considered CRITICAL and any change MUST be accompanied with
312  * full unit tests in testqgsfield.cpp.
313  * See details in QEP #17
314  ****************************************************************************/
315 
316 bool QgsField::convertCompatible( QVariant &v ) const
317 {
318  if ( v.isNull() )
319  {
320  v.convert( d->type );
321  return true;
322  }
323 
324  if ( d->type == QVariant::Int && v.toInt() != v.toLongLong() )
325  {
326  v = QVariant( d->type );
327  return false;
328  }
329 
330  // Give it a chance to convert to double since for not '.' locales
331  // we accept both comma and dot as decimal point
332  if ( d->type == QVariant::Double && v.type() == QVariant::String )
333  {
334  QVariant tmp( v );
335  if ( !tmp.convert( d->type ) )
336  {
337  // This might be a string with thousand separator: use locale to convert
338  bool ok = false;
339  double d = qgsPermissiveToDouble( v.toString(), ok );
340  if ( ok )
341  {
342  v = QVariant( d );
343  return true;
344  }
345  // For not 'dot' locales, we also want to accept '.'
346  if ( QLocale().decimalPoint() != '.' )
347  {
348  d = QLocale( QLocale::C ).toDouble( v.toString(), &ok );
349  if ( ok )
350  {
351  v = QVariant( d );
352  return true;
353  }
354  }
355  }
356  }
357 
358  // For string representation of an int we also might have thousand separator
359  if ( d->type == QVariant::Int && v.type() == QVariant::String )
360  {
361  QVariant tmp( v );
362  if ( !tmp.convert( d->type ) )
363  {
364  // This might be a string with thousand separator: use locale to convert
365  bool ok;
366  int i = qgsPermissiveToInt( v.toString(), ok );
367  if ( ok )
368  {
369  v = QVariant( i );
370  return true;
371  }
372  }
373  }
374 
375  // For string representation of a long we also might have thousand separator
376  if ( d->type == QVariant::LongLong && v.type() == QVariant::String )
377  {
378  QVariant tmp( v );
379  if ( !tmp.convert( d->type ) )
380  {
381  // This might be a string with thousand separator: use locale to convert
382  bool ok;
383  qlonglong l = qgsPermissiveToLongLong( v.toString(), ok );
384  if ( ok )
385  {
386  v = QVariant( l );
387  return true;
388  }
389  }
390  }
391 
392  //String representations of doubles in QVariant will return false to convert( QVariant::Int )
393  //work around this by first converting to double, and then checking whether the double is convertible to int
394  if ( d->type == QVariant::Int && v.canConvert( QVariant::Double ) )
395  {
396  bool ok = false;
397  double dbl = v.toDouble( &ok );
398  if ( !ok )
399  {
400  //couldn't convert to number
401  v = QVariant( d->type );
402  return false;
403  }
404 
405  double round = std::round( dbl );
406  if ( round > std::numeric_limits<int>::max() || round < -std::numeric_limits<int>::max() )
407  {
408  //double too large to fit in int
409  v = QVariant( d->type );
410  return false;
411  }
412  v = QVariant( static_cast< int >( std::round( dbl ) ) );
413  return true;
414  }
415 
416  //String representations of doubles in QVariant will return false to convert( QVariant::LongLong )
417  //work around this by first converting to double, and then checking whether the double is convertible to longlong
418  if ( d->type == QVariant::LongLong && v.canConvert( QVariant::Double ) )
419  {
420  //firstly test the conversion to longlong because conversion to double will rounded the value
421  QVariant tmp( v );
422  if ( !tmp.convert( d->type ) )
423  {
424  bool ok = false;
425  double dbl = v.toDouble( &ok );
426  if ( !ok )
427  {
428  //couldn't convert to number
429  v = QVariant( d->type );
430  return false;
431  }
432 
433  double round = std::round( dbl );
434  if ( round > std::numeric_limits<long long>::max() || round < -std::numeric_limits<long long>::max() )
435  {
436  //double too large to fit in longlong
437  v = QVariant( d->type );
438  return false;
439  }
440  v = QVariant( static_cast< long long >( std::round( dbl ) ) );
441  return true;
442  }
443  }
444 
445  if ( !v.convert( d->type ) )
446  {
447  v = QVariant( d->type );
448  return false;
449  }
450 
451  if ( d->type == QVariant::Double && d->precision > 0 )
452  {
453  double s = std::pow( 10, d->precision );
454  double d = v.toDouble() * s;
455  v = QVariant( ( d < 0 ? std::ceil( d - 0.5 ) : std::floor( d + 0.5 ) ) / s );
456  return true;
457  }
458 
459  if ( d->type == QVariant::String && d->length > 0 && v.toString().length() > d->length )
460  {
461  v = v.toString().left( d->length );
462  return false;
463  }
464 
465  return true;
466 }
467 
469 {
470  d->editorWidgetSetup = v;
471 }
472 
474 {
475  return d->editorWidgetSetup;
476 }
477 
478 /***************************************************************************
479  * This class is considered CRITICAL and any change MUST be accompanied with
480  * full unit tests in testqgsfield.cpp.
481  * See details in QEP #17
482  ****************************************************************************/
483 
484 QDataStream &operator<<( QDataStream &out, const QgsField &field )
485 {
486  out << field.name();
487  out << static_cast< quint32 >( field.type() );
488  out << field.typeName();
489  out << field.length();
490  out << field.precision();
491  out << field.comment();
492  out << field.alias();
493  out << field.defaultValueDefinition().expression();
494  out << field.defaultValueDefinition().applyOnUpdate();
495  out << field.constraints().constraints();
496  out << static_cast< quint32 >( field.constraints().constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) );
497  out << static_cast< quint32 >( field.constraints().constraintOrigin( QgsFieldConstraints::ConstraintUnique ) );
498  out << static_cast< quint32 >( field.constraints().constraintOrigin( QgsFieldConstraints::ConstraintExpression ) );
499  out << static_cast< quint32 >( field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
500  out << static_cast< quint32 >( field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
501  out << static_cast< quint32 >( field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
502  out << field.constraints().constraintExpression();
503  out << field.constraints().constraintDescription();
504  out << static_cast< quint32 >( field.subType() );
505  return out;
506 }
507 
508 QDataStream &operator>>( QDataStream &in, QgsField &field )
509 {
510  quint32 type;
511  quint32 subType;
512  quint32 length;
513  quint32 precision;
514  quint32 constraints;
515  quint32 originNotNull;
516  quint32 originUnique;
517  quint32 originExpression;
518  quint32 strengthNotNull;
519  quint32 strengthUnique;
520  quint32 strengthExpression;
521 
522  bool applyOnUpdate;
523 
524  QString name;
525  QString typeName;
526  QString comment;
527  QString alias;
528  QString defaultValueExpression;
529  QString constraintExpression;
530  QString constraintDescription;
531 
532  in >> name >> type >> typeName >> length >> precision >> comment >> alias
533  >> defaultValueExpression >> applyOnUpdate >> constraints >> originNotNull >> originUnique >> originExpression >> strengthNotNull >> strengthUnique >> strengthExpression >>
534  constraintExpression >> constraintDescription >> subType;
535  field.setName( name );
536  field.setType( static_cast< QVariant::Type >( type ) );
537  field.setTypeName( typeName );
538  field.setLength( static_cast< int >( length ) );
539  field.setPrecision( static_cast< int >( precision ) );
540  field.setComment( comment );
541  field.setAlias( alias );
542  field.setDefaultValueDefinition( QgsDefaultValue( defaultValueExpression, applyOnUpdate ) );
543  QgsFieldConstraints fieldConstraints;
544  if ( constraints & QgsFieldConstraints::ConstraintNotNull )
545  {
546  fieldConstraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, static_cast< QgsFieldConstraints::ConstraintOrigin>( originNotNull ) );
547  fieldConstraints.setConstraintStrength( QgsFieldConstraints::ConstraintNotNull, static_cast< QgsFieldConstraints::ConstraintStrength>( strengthNotNull ) );
548  }
549  else
550  fieldConstraints.removeConstraint( QgsFieldConstraints::ConstraintNotNull );
551  if ( constraints & QgsFieldConstraints::ConstraintUnique )
552  {
553  fieldConstraints.setConstraint( QgsFieldConstraints::ConstraintUnique, static_cast< QgsFieldConstraints::ConstraintOrigin>( originUnique ) );
554  fieldConstraints.setConstraintStrength( QgsFieldConstraints::ConstraintUnique, static_cast< QgsFieldConstraints::ConstraintStrength>( strengthUnique ) );
555  }
556  else
557  fieldConstraints.removeConstraint( QgsFieldConstraints::ConstraintUnique );
558  if ( constraints & QgsFieldConstraints::ConstraintExpression )
559  {
560  fieldConstraints.setConstraint( QgsFieldConstraints::ConstraintExpression, static_cast< QgsFieldConstraints::ConstraintOrigin>( originExpression ) );
561  fieldConstraints.setConstraintStrength( QgsFieldConstraints::ConstraintExpression, static_cast< QgsFieldConstraints::ConstraintStrength>( strengthExpression ) );
562  }
563  else
564  fieldConstraints.removeConstraint( QgsFieldConstraints::ConstraintExpression );
565  fieldConstraints.setConstraintExpression( constraintExpression, constraintDescription );
566  field.setConstraints( fieldConstraints );
567  field.setSubType( static_cast< QVariant::Type >( subType ) );
568  return in;
569 }
bool isNumeric() const
Returns if this field is numeric.
QgsField & operator=(const QgsField &other)
Assignment operator.
Definition: qgsfield.cpp:68
void setConstraintStrength(Constraint constraint, ConstraintStrength strength)
Sets the strength of a constraint.
QgsField(const QString &name=QString(), QVariant::Type type=QVariant::Invalid, const QString &typeName=QString(), int len=0, int prec=0, const QString &comment=QString(), QVariant::Type subType=QVariant::Invalid)
Constructor.
Definition: qgsfield.cpp:47
QString comment() const
Returns the field comment.
bool isDateOrTime() const
Returns if this field is a date and/or time type.
ConstraintStrength constraintStrength(Constraint constraint) const
Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint is not pres...
QString name
Definition: qgsfield.h:59
int precision
Definition: qgsfield.h:56
QString alias() const
Returns the alias for the field (the friendly displayed name of the field ), or an empty string if th...
virtual ~QgsField()
QString alias
Definition: qgsfield.h:60
The QgsDefaultValue class provides a container for managing client side default values for fields...
void setPrecision(int precision)
Set the field precision.
Definition: qgsfield.cpp:176
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
Definition: qgis.cpp:65
QString comment
Definition: qgsfield.h:58
QDataStream & operator>>(QDataStream &in, QgsField &field)
Reads a field from stream in into field. QGIS version compatibility is not guaranteed.
Definition: qgsfield.cpp:508
void setDefaultValueDefinition(const QgsDefaultValue &defaultValueDefinition)
Sets an expression to use when calculating the default value for the field.
Definition: qgsfield.cpp:191
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:316
void setName(const QString &name)
Set the field name.
Definition: qgsfield.cpp:152
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:473
int precision() const
Gets the precision of the field.
Stores information about constraints which may be present on a field.
int qgsPermissiveToInt(QString string, bool &ok)
Converts a string to an integer in a permissive way, e.g., allowing for incorrect numbers of digits b...
Definition: qgis.cpp:72
QString name() const
Returns the name of the field.
Field has an expression constraint set. See constraintExpression().
int length
Definition: qgsfield.h:55
void setLength(int len)
Set the field length.
Definition: qgsfield.cpp:172
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:116
QString displayName() const
Returns the name to use when displaying this field.
Definition: qgsfield.cpp:89
void setTypeName(const QString &typeName)
Set the field type.
Definition: qgsfield.cpp:167
const QString & typeName
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
qlonglong qgsPermissiveToLongLong(QString string, bool &ok)
Converts a string to an qlonglong in a permissive way, e.g., allowing for incorrect numbers of digits...
Definition: qgis.cpp:79
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
bool operator!=(const QgsField &other) const
Definition: qgsfield.cpp:79
QString displayString(const QVariant &v) const
Formats string for display.
Definition: qgsfield.cpp:222
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:49
void setConstraint(Constraint constraint, ConstraintOrigin origin=ConstraintOriginLayer)
Sets a constraint on the field.
void setSubType(QVariant::Type subType)
If the field is a collection, set its element&#39;s type.
Definition: qgsfield.cpp:162
QgsFieldConstraints constraints
Definition: qgsfield.h:62
void setType(QVariant::Type type)
Set variant type.
Definition: qgsfield.cpp:157
bool operator==(const QgsField &other) const
Definition: qgsfield.cpp:74
void setAlias(const QString &alias)
Sets the alias for the field (the friendly displayed name of the field ).
Definition: qgsfield.cpp:211
void setConstraintExpression(const QString &expression, const QString &description=QString())
Set the constraint expression for the field.
Holder for the widget type and its configuration for a field.
int length() const
Gets the length of the field.
QVariant::Type subType() const
If the field is a collection, gets its element&#39;s type.
Definition: qgsfield.cpp:111
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
const QgsFieldConstraints & constraints() const
Returns constraints which are present for the field.
QString constraintExpression() const
Returns the constraint expression for the field, if set.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
QString displayNameWithAlias() const
Returns the name to use when displaying this field and adds the alias in parenthesis if it is defined...
Definition: qgsfield.cpp:97
void setConstraints(const QgsFieldConstraints &constraints)
Sets constraints which are present for the field.
Definition: qgsfield.cpp:196
void setComment(const QString &comment)
Set the field comment.
Definition: qgsfield.cpp:181
QVariant::Type type
Definition: qgsfield.h:57
QDataStream & operator<<(QDataStream &out, const QgsField &field)
Writes the field to stream out. QGIS version compatibility is not guaranteed.
Definition: qgsfield.cpp:484
QgsDefaultValue defaultValueDefinition
Definition: qgsfield.h:61
void removeConstraint(Constraint constraint)
Removes a constraint from the field.
QgsDefaultValue defaultValueDefinition() const
Returns the expression used when calculating the default value for the field.
Field must have a unique value.
void setEditorWidgetSetup(const QgsEditorWidgetSetup &v)
Set the editor widget setup for the field.
Definition: qgsfield.cpp:468