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