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