1 /*************************************************************************** 2 qgsfields.h - QgsFields 3 4 --------------------- 5 begin : 22.9.2016 6 copyright : (C) 2016 by Matthias Kuhn 7 email : matthias@opengis.ch 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 #ifndef QGSFIELDS_H 17 #define QGSFIELDS_H 18 19 20 #include "qgis_sip.h" 21 #include "qgis_core.h" 22 #include "qgsfield.h" 23 24 class QgsFieldsPrivate; 25 26 /*************************************************************************** 27 * This class is considered CRITICAL and any change MUST be accompanied with 28 * full unit tests in testqgsfields.cpp. 29 * See details in QEP #17 30 ****************************************************************************/ 31 32 /** 33 * \class QgsFields 34 * \ingroup core 35 * \brief Container of fields for a vector layer. 36 * 37 * In addition to storing a list of QgsField instances, it also: 38 * 39 * - allows quick lookups of field names to index in the list 40 * - keeps track of where the field definition comes from (vector data provider, joined layer or newly added from an editing operation) 41 * 42 * \note QgsFields objects are implicitly shared. 43 */ 44 class CORE_EXPORT QgsFields 45 { 46 public: 47 48 enum FieldOrigin 49 { 50 OriginUnknown, //!< It has not been specified where the field comes from 51 OriginProvider, //!< Field comes from the underlying data provider of the vector layer (originIndex = index in provider's fields) 52 OriginJoin, //!< Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index within the join) 53 OriginEdit, //!< Field has been temporarily added in editing mode (originIndex = index in the list of added attributes) 54 OriginExpression //!< Field is calculated from an expression 55 }; 56 57 #ifndef SIP_RUN 58 59 typedef struct Field 60 { FieldField61 Field() 62 {} 63 FieldField64 Field( const QgsField &f, FieldOrigin o, int oi ) 65 : field( f ) 66 , origin( o ) 67 , originIndex( oi ) 68 {} 69 70 //! \since QGIS 2.6 71 bool operator==( const Field &other ) const { return field == other.field && origin == other.origin && originIndex == other.originIndex; } 72 //! \since QGIS 2.6 73 bool operator!=( const Field &other ) const { return !( *this == other ); } 74 75 QgsField field; //!< Field 76 FieldOrigin origin = OriginUnknown ; //!< Origin of the field 77 int originIndex = -1 ; //!< Index specific to the origin 78 } Field; 79 80 #endif 81 82 /** 83 * Constructor for an empty field container 84 */ 85 QgsFields(); 86 87 /** 88 * Copy constructor 89 */ 90 QgsFields( const QgsFields &other ); 91 92 /** 93 * Assignment operator 94 */ 95 QgsFields &operator =( const QgsFields &other ) SIP_SKIP; 96 97 virtual ~QgsFields(); 98 99 //! Removes all fields 100 void clear(); 101 102 //! Appends a field. The field must have unique name, otherwise it is rejected (returns FALSE) 103 bool append( const QgsField &field, FieldOrigin origin = OriginProvider, int originIndex = -1 ); 104 105 /** 106 * Renames a name of field. The field must have unique name, otherwise change is rejected (returns FALSE) 107 * \since QGIS 3.6 108 */ 109 bool rename( int fieldIdx, const QString &name ); 110 111 //! Appends an expression field. The field must have unique name, otherwise it is rejected (returns FALSE) 112 bool appendExpressionField( const QgsField &field, int originIndex ); 113 114 //! Removes a field with the given index 115 void remove( int fieldIdx ); 116 #ifdef SIP_RUN 117 % MethodCode 118 if ( a0 < 0 || a0 >= sipCpp->count() ) 119 { 120 PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); 121 sipIsErr = 1; 122 } 123 else 124 { 125 sipCpp->remove( a0 ); 126 } 127 % End 128 #endif 129 130 //! Extends with fields from another QgsFields container 131 void extend( const QgsFields &other ); 132 133 //! Checks whether the container is empty 134 bool isEmpty() const; 135 136 //! Returns number of items 137 int count() const; 138 139 #ifdef SIP_RUN 140 int __len__() const; 141 % MethodCode 142 sipRes = sipCpp->count(); 143 % End 144 145 //! Ensures that bool(obj) returns TRUE (otherwise __len__() would be used) 146 int __bool__() const; 147 % MethodCode 148 sipRes = true; 149 % End 150 #endif 151 152 //! Returns number of items 153 int size() const; 154 155 /** 156 * Returns a list with field names 157 * \since QGIS 3.0 158 */ 159 QStringList names() const; 160 161 /** 162 * Returns if a field index is valid 163 * \param i Index of the field which needs to be checked 164 * \returns TRUE if the field exists 165 */ 166 bool exists( int i ) const; 167 168 #ifndef SIP_RUN 169 //! Gets field at particular index (must be in range 0..N-1) 170 QgsField operator[]( int i ) const; 171 #endif 172 173 //! Gets field at particular index (must be in range 0..N-1) 174 QgsField &operator[]( int i ) SIP_FACTORY; 175 #ifdef SIP_RUN 176 % MethodCode 177 SIP_SSIZE_T idx = sipConvertFromSequenceIndex( a0, sipCpp->count() ); 178 if ( idx < 0 ) 179 sipIsErr = 1; 180 else 181 sipRes = new QgsField( sipCpp->operator[]( idx ) ); 182 % End 183 #endif 184 185 //! Gets field at particular index (must be in range 0..N-1) 186 QgsField at( int i ) const SIP_FACTORY; 187 #ifdef SIP_RUN 188 % MethodCode 189 if ( a0 < 0 || a0 >= sipCpp->count() ) 190 { 191 PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); 192 sipIsErr = 1; 193 } 194 else 195 { 196 sipRes = new QgsField( sipCpp->at( a0 ) ); 197 } 198 % End 199 #endif 200 201 //! Gets field at particular index (must be in range 0..N-1) 202 QgsField field( int fieldIdx ) const SIP_FACTORY; 203 #ifdef SIP_RUN 204 % MethodCode 205 if ( a0 < 0 || a0 >= sipCpp->count() ) 206 { 207 PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); 208 sipIsErr = 1; 209 } 210 else 211 { 212 sipRes = new QgsField( sipCpp->field( a0 ) ); 213 } 214 % End 215 #endif 216 217 //! Gets field with matching name 218 QgsField field( const QString &name ) const SIP_FACTORY; 219 #ifdef SIP_RUN 220 % MethodCode 221 int fieldIdx = sipCpp->indexFromName( *a0 ); 222 if ( fieldIdx == -1 ) 223 { 224 PyErr_SetString( PyExc_KeyError, a0->toLatin1() ); 225 sipIsErr = 1; 226 } 227 else 228 { 229 sipRes = new QgsField( sipCpp->field( *a0 ) ); 230 } 231 % End 232 #endif 233 234 //! Gets field's origin (value from an enumeration) 235 FieldOrigin fieldOrigin( int fieldIdx ) const; 236 #ifdef SIP_RUN 237 % MethodCode 238 if ( a0 < 0 || a0 >= sipCpp->count() ) 239 { 240 PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); 241 sipIsErr = 1; 242 } 243 else 244 { 245 sipRes = sipCpp->fieldOrigin( a0 ); 246 } 247 % End 248 #endif 249 250 //! Gets field's origin index (its meaning is specific to each type of origin) 251 int fieldOriginIndex( int fieldIdx ) const; 252 #ifdef SIP_RUN 253 % MethodCode 254 if ( a0 < 0 || a0 >= sipCpp->count() ) 255 { 256 PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); 257 sipIsErr = 1; 258 } 259 else 260 { 261 sipRes = sipCpp->fieldOriginIndex( a0 ); 262 } 263 % End 264 #endif 265 266 /** 267 * Gets the field index from the field name. 268 * This method is case sensitive and only matches the data source 269 * name of the field. 270 * Alias for indexOf 271 * 272 * \param fieldName The name of the field. 273 * 274 * \returns The field index if found or -1 in case it cannot be found. 275 * \see lookupField For a more tolerant alternative. 276 */ 277 int indexFromName( const QString &fieldName ) const; 278 279 /** 280 * Gets the field index from the field name. 281 * This method is case sensitive and only matches the data source 282 * name of the field. 283 * 284 * \param fieldName The name of the field. 285 * 286 * \returns The field index if found or -1 in case it cannot be found. 287 * \see lookupField For a more tolerant alternative. 288 * \since QGIS 3.0 289 */ 290 int indexOf( const QString &fieldName ) const; 291 292 /** 293 * Looks up field's index from the field name. 294 * This method matches in the following order: 295 * 296 * 1. The exact field name taking case sensitivity into account 297 * 2. Looks for the field name by case insensitive comparison 298 * 3. The field alias (case insensitive) 299 * 300 * \param fieldName The name to look for. 301 * 302 * \returns The field index if found or -1 in case it cannot be found. 303 * \see indexFromName For a more performant and precise but less tolerant alternative. 304 * \since QGIS 2.4 305 */ 306 int lookupField( const QString &fieldName ) const; 307 308 /** 309 * Utility function to get list of attribute indexes 310 * \since QGIS 2.4 311 */ 312 QgsAttributeList allAttributesList() const; 313 314 //! Utility function to return a list of QgsField instances 315 QList<QgsField> toList() const; 316 317 //! \since QGIS 2.6 318 bool operator==( const QgsFields &other ) const; 319 //! \since QGIS 2.6 320 bool operator!=( const QgsFields &other ) const { return !( *this == other ); } 321 322 /** 323 * Returns an icon corresponding to a field index, based on the field's type and source 324 * \param fieldIdx the field index 325 * \param considerOrigin if TRUE the icon will the origin of the field 326 * \since QGIS 2.14 327 */ 328 QIcon iconForField( int fieldIdx, bool considerOrigin = false ) const SIP_FACTORY; 329 #ifdef SIP_RUN 330 % MethodCode 331 if ( a0 < 0 || a0 >= sipCpp->count() ) 332 { 333 PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); 334 sipIsErr = 1; 335 } 336 else 337 { 338 sipRes = new QIcon( sipCpp->iconForField( a0 ) ); 339 } 340 % End 341 #endif 342 343 344 /** 345 * Returns an icon corresponding to a field \a type 346 * \since QGIS 3.16 347 */ 348 static QIcon iconForFieldType( const QVariant::Type &type ) SIP_FACTORY; 349 350 //! Allows direct construction of QVariants from fields. QVariant()351 operator QVariant() const 352 { 353 return QVariant::fromValue( *this ); 354 } 355 356 #ifdef SIP_RUN 357 358 void __setitem__( int key, const QgsField &field ); 359 % MethodCode 360 int idx = ( int )sipConvertFromSequenceIndex( a0, sipCpp->count() ); 361 if ( idx < 0 ) 362 sipIsErr = 1; 363 else 364 ( *sipCpp )[idx] = *a1; 365 % End 366 367 #endif 368 369 #ifndef SIP_RUN 370 371 ///@cond PRIVATE 372 373 class const_iterator; 374 375 class iterator 376 { 377 public: 378 QgsFields::Field *d = nullptr; 379 typedef std::random_access_iterator_tag iterator_category; 380 typedef qptrdiff difference_type; 381 iterator()382 inline iterator() 383 {} 384 iterator(QgsFields::Field * n)385 inline iterator( QgsFields::Field *n ) 386 : d( n ) 387 {} 388 389 inline QgsField &operator*() const { return d->field; } 390 inline QgsField *operator->() const { return &d->field; } 391 inline QgsField &operator[]( difference_type j ) const { return d[j].field; } 392 inline bool operator==( const iterator &o ) const noexcept { return d == o.d; } // clazy:exclude=function-args-by-value 393 inline bool operator!=( const iterator &o ) const noexcept { return d != o.d; } // clazy:exclude=function-args-by-value 394 inline bool operator<( const iterator &other ) const noexcept { return d < other.d; } // clazy:exclude=function-args-by-value 395 inline bool operator<=( const iterator &other ) const noexcept { return d <= other.d; } // clazy:exclude=function-args-by-value 396 inline bool operator>( const iterator &other ) const noexcept { return d > other.d; } // clazy:exclude=function-args-by-value 397 inline bool operator>=( const iterator &other ) const noexcept { return d >= other.d; } // clazy:exclude=function-args-by-value 398 399 inline iterator &operator++() { ++d; return *this; } 400 inline iterator operator++( int ) { QgsFields::Field *n = d; ++d; return n; } 401 inline iterator &operator--() { d--; return *this; } 402 inline iterator operator--( int ) { QgsFields::Field *n = d; d--; return n; } 403 inline iterator &operator+=( difference_type j ) { d += j; return *this; } 404 inline iterator &operator-=( difference_type j ) { d -= j; return *this; } 405 inline iterator operator+( difference_type j ) const { return iterator( d + j ); } 406 inline iterator operator-( difference_type j ) const { return iterator( d - j ); } 407 inline int operator-( iterator j ) const { return int( d - j.d ); } 408 }; 409 friend class iterator; 410 411 class const_iterator // clazy:exclude=rule-of-three 412 { 413 public: 414 const QgsFields::Field *d = nullptr; 415 416 typedef std::random_access_iterator_tag iterator_category; 417 typedef qptrdiff difference_type; 418 const_iterator()419 inline const_iterator() 420 {} 421 const_iterator(const QgsFields::Field * f)422 inline const_iterator( const QgsFields::Field *f ) 423 : d( f ) {} const_iterator(const const_iterator & o)424 inline const_iterator( const const_iterator &o ) 425 : d( o.d ) {} const_iterator(const iterator & o)426 inline explicit const_iterator( const iterator &o ) // clazy:exclude=function-args-by-value 427 : d( o.d ) {} 428 inline const QgsField &operator*() const { return d->field; } 429 inline const QgsField *operator->() const { return &d->field; } 430 inline const QgsField &operator[]( difference_type j ) const noexcept { return d[j].field; } 431 inline bool operator==( const const_iterator &o ) const noexcept { return d == o.d; } 432 inline bool operator!=( const const_iterator &o ) const noexcept { return d != o.d; } 433 inline bool operator<( const const_iterator &other ) const noexcept { return d < other.d; } 434 inline bool operator<=( const const_iterator &other ) const noexcept { return d <= other.d; } 435 inline bool operator>( const const_iterator &other ) const noexcept { return d > other.d; } 436 inline bool operator>=( const const_iterator &other ) const noexcept { return d >= other.d; } 437 inline const_iterator &operator++() { ++d; return *this; } 438 inline const_iterator operator++( int ) { const QgsFields::Field *n = d; ++d; return n; } 439 inline const_iterator &operator--() { d--; return *this; } 440 inline const_iterator operator--( int ) { const QgsFields::Field *n = d; --d; return n; } 441 inline const_iterator &operator+=( difference_type j ) { d += j; return *this; } 442 inline const_iterator &operator-=( difference_type j ) { d -= j; return *this; } 443 inline const_iterator operator+( difference_type j ) const { return const_iterator( d + j ); } 444 inline const_iterator operator-( difference_type j ) const { return const_iterator( d - j ); } 445 inline int operator-( const_iterator j ) const { return int( d - j.d ); } // clazy:exclude=function-args-by-ref 446 private: 447 const_iterator &operator= ( const const_iterator & ) = delete; 448 }; 449 friend class const_iterator; 450 ///@endcond 451 452 453 /** 454 * Returns a const STL-style iterator pointing to the first item in the list. 455 * 456 * \note not available in Python bindings 457 * \since QGIS 2.16 458 */ 459 const_iterator constBegin() const noexcept; 460 461 /** 462 * Returns a const STL-style iterator pointing to the imaginary item after the last item in the list. 463 * 464 * \note not available in Python bindings 465 * \since QGIS 2.16 466 */ 467 const_iterator constEnd() const noexcept; 468 469 /** 470 * Returns a const STL-style iterator pointing to the first item in the list. 471 * 472 * \note not available in Python bindings 473 * \since QGIS 2.16 474 */ 475 const_iterator begin() const noexcept; 476 477 /** 478 * Returns a const STL-style iterator pointing to the imaginary item after the last item in the list. 479 * 480 * \note not available in Python bindings 481 * \since QGIS 2.16 482 */ 483 const_iterator end() const noexcept; 484 485 /** 486 * Returns an STL-style iterator pointing to the first item in the list. 487 * 488 * \note not available in Python bindings 489 * \since QGIS 2.16 490 */ 491 iterator begin(); 492 493 494 /** 495 * Returns an STL-style iterator pointing to the imaginary item after the last item in the list. 496 * 497 * \note not available in Python bindings 498 * \since QGIS 2.16 499 */ 500 iterator end(); 501 502 #endif 503 504 private: 505 506 QSharedDataPointer<QgsFieldsPrivate> d; 507 508 }; 509 510 Q_DECLARE_METATYPE( QgsFields ) 511 512 //! Writes the fields to stream out. QGIS version compatibility is not guaranteed. 513 CORE_EXPORT QDataStream &operator<<( QDataStream &out, const QgsFields &fields ); 514 //! Reads fields from stream in into fields. QGIS version compatibility is not guaranteed. 515 CORE_EXPORT QDataStream &operator>>( QDataStream &in, QgsFields &fields ); 516 517 #endif // QGSFIELDS_H 518