QGIS API Documentation 3.43.0-Master (ebb4087afc0)
Loading...
Searching...
No Matches
qgsattributes.h
Go to the documentation of this file.
1/***************************************************************************
2 qgsattributes.h - QgsAttributes
3
4 ---------------------
5 begin : 29.3.2017
6 copyright : (C) 2017 by Denis Rouzaud
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
18#ifndef QGSATTRIBUTES_H
19#define QGSATTRIBUTES_H
20
21#include "qgis_core.h"
22#include "qgis_sip.h"
23
24#include <QMap>
25#include <QString>
26#include <QVariant>
27#include <QList>
28#include <QVector>
29#include <QSet>
30#include <QExplicitlySharedDataPointer>
31
32
33#include "qgsfields.h"
35#include "qgsvariantutils.h"
36
37
38class QgsRectangle;
39class QgsFeature;
40class QgsFeaturePrivate;
41
42// key = field index, value = field value
43typedef QMap<int, QVariant> QgsAttributeMap;
44
45// key = field index, value = field name
46typedef QMap<int, QString> QgsFieldNameMap;
47
48#ifdef SIP_RUN
49typedef QMap<int, QgsField> QgsFieldMap;
50#endif
51
52
58#ifndef SIP_RUN
59class QgsAttributes : public QVector<QVariant>
60{
61 public:
62
63 QgsAttributes() = default;
64
70 QgsAttributes( int size )
71 : QVector<QVariant>( size )
72 {}
73
79 QgsAttributes( int size, const QVariant &v )
80 : QVector<QVariant>( size, v )
81 {}
82
87 QgsAttributes( const QVector<QVariant> &v )
88 : QVector<QVariant>( v )
89 {}
90
100 bool operator==( const QgsAttributes &v ) const
101 {
102 if ( size() != v.size() )
103 return false;
104 const QVariant *b = constData();
105 const QVariant *i = b + size();
106 const QVariant *j = v.constData() + size();
107
108 // note that for non-null values, we need to check that the type is equal too!
109 // QVariant == comparisons do some weird things, like reporting that a QDateTime(2021, 2, 10, 0, 0) variant is equal
110 // to a QString "2021-02-10 00:00" variant!
111 while ( i != b )
112 if ( !( QgsVariantUtils::isNull( *( --i ) ) == QgsVariantUtils::isNull( *( --j ) ) && ( QgsVariantUtils::isNull( *i ) || i->userType() == j->userType() ) && *i == *j ) )
113 return false;
114 return true;
115 }
116
122 CORE_EXPORT QgsAttributeMap toMap() const SIP_SKIP;
123
129 bool isUnsetValue( int index ) const
130 {
131 if ( index < 0 || index >= size() )
132 return false;
133
134 return at( index ).userType() == qMetaTypeId<QgsUnsetAttributeValue>();
135 }
136
137 inline bool operator!=( const QgsAttributes &v ) const { return !( *this == v ); }
138};
139
141CORE_EXPORT uint qHash( const QgsAttributes &attributes );
142
143#endif
144
145#ifdef SIP_PYQT5_RUN
146#ifdef SIP_RUN
147typedef QVector<QVariant> QgsAttributes;
148
149% MappedType QgsAttributes
150{
151 % TypeHeaderCode
152#include "qgsfeature.h"
153 % End
154
155 % ConvertFromTypeCode
156 // Create the list.
157 PyObject *l;
158
159 if ( ( l = PyList_New( sipCpp->size() ) ) == NULL )
160 return NULL;
161
162 // Set the list elements.
163 for ( int i = 0; i < sipCpp->size(); ++i )
164 {
165 const QVariant v = sipCpp->at( i );
166 PyObject *tobj = NULL;
167 if ( !v.isValid() )
168 {
169 Py_INCREF( Py_None );
170 tobj = Py_None;
171 }
172 // QByteArray null handling is "special"! See null_from_qvariant_converter in conversions.sip
173 else if ( QgsVariantUtils::isNull( v, true ) && v.userType() != QMetaType::Type::QByteArray )
174 {
175 PyObject *vartype = sipConvertFromEnum( v.type(), sipType_QVariant_Type );
176 PyObject *args = PyTuple_Pack( 1, vartype );
177 PyTypeObject *typeObj = sipTypeAsPyTypeObject( sipType_QVariant );
178 tobj = PyObject_Call( ( PyObject * )typeObj, args, nullptr );
179 Py_DECREF( args );
180 Py_DECREF( vartype );
181 }
182 else
183 {
184 switch ( v.userType() )
185 {
186 case QMetaType::Type::Int:
187 tobj = PyLong_FromLong( v.toInt() );
188 break;
189
190 case QMetaType::Type::UInt:
191 tobj = PyLong_FromUnsignedLong( v.toUInt() );
192 break;
193
194 case QMetaType::Type::Long:
195 case QMetaType::Type::LongLong:
196 tobj = PyLong_FromLongLong( v.toLongLong() );
197 break;
198
199 case QMetaType::Type::ULong:
200 case QMetaType::Type::ULongLong:
201 tobj = PyLong_FromUnsignedLongLong( v.toULongLong() );
202 break;
203
204 case QMetaType::Type::Bool:
205 tobj = PyBool_FromLong( v.toBool() ? 1 : 0 );
206 break;
207
208 case QMetaType::Type::Float:
209 case QMetaType::Type::Double:
210 tobj = PyFloat_FromDouble( v.toDouble() );
211 break;
212
213 case QMetaType::Type::QString:
214 tobj = PyUnicode_FromString( v.toString().toUtf8().constData() );
215 break;
216
217 default:
218 {
219 QVariant *newV = new QVariant( v );
220 tobj = sipConvertFromNewType( newV, sipType_QVariant, sipTransferObj );
221 break;
222 }
223 }
224 }
225 if ( tobj == NULL )
226 {
227 Py_DECREF( l );
228 return NULL;
229 }
230
231 PyList_SET_ITEM( l, i, tobj );
232 }
233
234 return l;
235 % End
236
237 % ConvertToTypeCode
238 // Check the type if that is all that is required.
239 if ( sipIsErr == NULL )
240 {
241 if ( !PyList_Check( sipPy ) )
242 return 0;
243
244 for ( SIP_SSIZE_T i = 0; i < PyList_GET_SIZE( sipPy ); ++i )
245 if ( !sipCanConvertToType( PyList_GET_ITEM( sipPy, i ), sipType_QVariant, SIP_NOT_NONE ) )
246 return 0;
247
248 return 1;
249 }
250
251 SIP_SSIZE_T listSize = PyList_GET_SIZE( sipPy );
252 // Initialize attributes to null. This has two motivations:
253 // 1. It speeds up the QVector construction, as otherwise we are creating n default QVariant objects (default QVariant constructor is not free!)
254 // 2. It lets us shortcut in the loop below when a Py_None is encountered in the list
255 const QVariant nullVariant( QVariant::Int );
256 QgsAttributes *qv = new QgsAttributes( listSize, nullVariant );
257 QVariant *outData = qv->data();
258
259 for ( SIP_SSIZE_T i = 0; i < listSize; ++i )
260 {
261 PyObject *obj = PyList_GET_ITEM( sipPy, i );
262 if ( obj == Py_None )
263 {
264 // outData was already initialized to null values
265 *outData++;
266 }
267 else if ( PyBool_Check( obj ) )
268 {
269 *outData++ = QVariant( PyObject_IsTrue( obj ) == 1 );
270 }
271 else if ( PyLong_Check( obj ) )
272 {
273 *outData++ = QVariant( PyLong_AsLongLong( obj ) );
274 }
275 else if ( PyFloat_Check( obj ) )
276 {
277 *outData++ = QVariant( PyFloat_AsDouble( obj ) );
278 }
279 else if ( PyUnicode_Check( obj ) )
280 {
281 *outData++ = QVariant( QString::fromUtf8( PyUnicode_AsUTF8( obj ) ) );
282 }
283 else
284 {
285 int state;
286 QVariant *t = reinterpret_cast<QVariant *>( sipConvertToType( obj, sipType_QVariant, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr ) );
287
288 if ( *sipIsErr )
289 {
290 sipReleaseType( t, sipType_QVariant, state );
291
292 delete qv;
293 return 0;
294 }
295
296 *outData++ = *t;
297 sipReleaseType( t, sipType_QVariant, state );
298 }
299 }
300
301 *sipCppPtr = qv;
302
303 return sipGetState( sipTransferObj );
304 % End
305};
306#endif
307#endif
308
309#ifdef SIP_PYQT6_RUN
310#ifdef SIP_RUN
311typedef QVector<QVariant> QgsAttributes;
312
313% MappedType QgsAttributes
314{
315 % TypeHeaderCode
316#include "qgsfeature.h"
317 % End
318
319 % ConvertFromTypeCode
320 // Create the list.
321 PyObject *l;
322
323 if ( ( l = PyList_New( sipCpp->size() ) ) == NULL )
324 return NULL;
325
326 // Set the list elements.
327 for ( int i = 0; i < sipCpp->size(); ++i )
328 {
329 const QVariant v = sipCpp->at( i );
330 PyObject *tobj = NULL;
331 // QByteArray null handling is "special"! See null_from_qvariant_converter in conversions.sip
332 if ( QgsVariantUtils::isNull( v, true ) && v.userType() != QMetaType::Type::QByteArray )
333 {
334 Py_INCREF( Py_None );
335 tobj = Py_None;
336 }
337 else
338 {
339 switch ( v.userType() )
340 {
341 case QMetaType::Type::Int:
342 tobj = PyLong_FromLong( v.toInt() );
343 break;
344
345 case QMetaType::Type::UInt:
346 tobj = PyLong_FromUnsignedLong( v.toUInt() );
347 break;
348
349 case QMetaType::Type::Long:
350 case QMetaType::Type::LongLong:
351 tobj = PyLong_FromLongLong( v.toLongLong() );
352 break;
353
354 case QMetaType::Type::ULong:
355 case QMetaType::Type::ULongLong:
356 tobj = PyLong_FromUnsignedLongLong( v.toULongLong() );
357 break;
358
359 case QMetaType::Type::Bool:
360 tobj = PyBool_FromLong( v.toBool() ? 1 : 0 );
361 break;
362
363 case QMetaType::Type::Float:
364 case QMetaType::Type::Double:
365 tobj = PyFloat_FromDouble( v.toDouble() );
366 break;
367
368 case QMetaType::Type::QString:
369 tobj = PyUnicode_FromString( v.toString().toUtf8().constData() );
370 break;
371
372 default:
373 {
374 QVariant *newV = new QVariant( v );
375 tobj = sipConvertFromNewType( newV, sipType_QVariant, sipTransferObj );
376 break;
377 }
378 }
379 }
380 if ( tobj == NULL )
381 {
382 Py_DECREF( l );
383 return NULL;
384 }
385
386 PyList_SET_ITEM( l, i, tobj );
387 }
388
389 return l;
390 % End
391
392 % ConvertToTypeCode
393 // Check the type if that is all that is required.
394 if ( sipIsErr == NULL )
395 {
396 if ( !PyList_Check( sipPy ) )
397 return 0;
398
399 for ( SIP_SSIZE_T i = 0; i < PyList_GET_SIZE( sipPy ); ++i )
400 if ( !sipCanConvertToType( PyList_GET_ITEM( sipPy, i ), sipType_QVariant, SIP_NOT_NONE ) )
401 return 0;
402
403 return 1;
404 }
405
406 SIP_SSIZE_T listSize = PyList_GET_SIZE( sipPy );
407 // Initialize attributes to null. This has two motivations:
408 // 1. It speeds up the QVector construction, as otherwise we are creating n default QVariant objects (default QVariant constructor is not free!)
409 // 2. It lets us shortcut in the loop below when a Py_None is encountered in the list
410 const QVariant nullVariant( QVariant::Int );
411 QgsAttributes *qv = new QgsAttributes( listSize, nullVariant );
412 QVariant *outData = qv->data();
413
414 for ( SIP_SSIZE_T i = 0; i < listSize; ++i )
415 {
416 PyObject *obj = PyList_GET_ITEM( sipPy, i );
417 if ( obj == Py_None )
418 {
419 // outData was already initialized to null values
420 *outData++;
421 }
422 else if ( PyBool_Check( obj ) )
423 {
424 *outData++ = QVariant( PyObject_IsTrue( obj ) == 1 );
425 }
426 else if ( PyLong_Check( obj ) )
427 {
428 *outData++ = QVariant( PyLong_AsLongLong( obj ) );
429 }
430 else if ( PyFloat_Check( obj ) )
431 {
432 *outData++ = QVariant( PyFloat_AsDouble( obj ) );
433 }
434 else if ( PyUnicode_Check( obj ) )
435 {
436 *outData++ = QVariant( QString::fromUtf8( PyUnicode_AsUTF8( obj ) ) );
437 }
438 else
439 {
440 int state;
441 QVariant *t = reinterpret_cast<QVariant *>( sipConvertToType( obj, sipType_QVariant, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr ) );
442
443 if ( *sipIsErr )
444 {
445 sipReleaseType( t, sipType_QVariant, state );
446
447 delete qv;
448 return 0;
449 }
450
451 *outData++ = *t;
452 sipReleaseType( t, sipType_QVariant, state );
453 }
454 }
455
456 *sipCppPtr = qv;
457
458 return sipGetState( sipTransferObj );
459 % End
460};
461#endif
462#endif
463#endif // QGSATTRIBUTES_H
A vector of attributes.
bool operator!=(const QgsAttributes &v) const
QgsAttributes(int size)
Create a new vector of attributes with the given size.
bool isUnsetValue(int index) const
Returns true if the attribute at the specified index is an unset value.
QgsAttributes(int size, const QVariant &v)
Constructs a vector with an initial size of size elements.
bool operator==(const QgsAttributes &v) const
Compares two vectors of attributes.
QgsAttributes()=default
QgsAttributes(const QVector< QVariant > &v)
Copies another vector of attributes.
CORE_EXPORT QgsAttributeMap toMap() const
Returns a QgsAttributeMap of the attribute values.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
A rectangle specified with double values.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
#define SIP_SKIP
Definition qgis_sip.h:126
CORE_EXPORT uint qHash(const QgsAttributes &attributes)
Hash for QgsAttributes.
QMap< int, QString > QgsFieldNameMap
QMap< int, QVariant > QgsAttributeMap