1 /***************************************************************************
2 qgsfields.cpp - 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
17 #include "qgsfields.h"
18 #include "qgsfields_p.h"
19 #include "qgsapplication.h"
20 #include <QIcon>
21
22 /***************************************************************************
23 * This class is considered CRITICAL and any change MUST be accompanied with
24 * full unit tests in testqgsfields.cpp.
25 * See details in QEP #17
26 ****************************************************************************/
27
QgsFields()28 QgsFields::QgsFields()
29 {
30 d = new QgsFieldsPrivate();
31 }
32
QgsFields(const QgsFields & other)33 QgsFields::QgsFields( const QgsFields &other ) //NOLINT
34 : d( other.d )
35 {
36 }
37
operator =(const QgsFields & other)38 QgsFields &QgsFields::operator =( const QgsFields &other ) //NOLINT
39 {
40 d = other.d;
41 return *this;
42 }
43
~QgsFields()44 QgsFields::~QgsFields() //NOLINT
45 {}
46
clear()47 void QgsFields::clear()
48 {
49 d->fields.clear();
50 d->nameToIndex.clear();
51 }
52
53 /***************************************************************************
54 * This class is considered CRITICAL and any change MUST be accompanied with
55 * full unit tests in testqgsfields.cpp.
56 * See details in QEP #17
57 ****************************************************************************/
58
append(const QgsField & field,FieldOrigin origin,int originIndex)59 bool QgsFields::append( const QgsField &field, FieldOrigin origin, int originIndex )
60 {
61 if ( d->nameToIndex.contains( field.name() ) )
62 return false;
63
64 if ( originIndex == -1 && origin == OriginProvider )
65 originIndex = d->fields.count();
66 d->fields.append( Field( field, origin, originIndex ) );
67
68 d->nameToIndex.insert( field.name(), d->fields.count() - 1 );
69 return true;
70 }
71
rename(int fieldIdx,const QString & name)72 bool QgsFields::rename( int fieldIdx, const QString &name )
73 {
74 if ( !exists( fieldIdx ) )
75 return false;
76
77 if ( name.isEmpty() )
78 return false;
79
80 if ( d->nameToIndex.contains( name ) )
81 return false;
82
83 const QString oldName = d->fields[ fieldIdx ].field.name();
84 d->fields[ fieldIdx ].field.setName( name );
85 d->nameToIndex.remove( oldName );
86 d->nameToIndex.insert( name, fieldIdx );
87 return true;
88 }
89
appendExpressionField(const QgsField & field,int originIndex)90 bool QgsFields::appendExpressionField( const QgsField &field, int originIndex )
91 {
92 if ( d->nameToIndex.contains( field.name() ) )
93 return false;
94
95 d->fields.append( Field( field, OriginExpression, originIndex ) );
96
97 d->nameToIndex.insert( field.name(), d->fields.count() - 1 );
98 return true;
99 }
100
remove(int fieldIdx)101 void QgsFields::remove( int fieldIdx )
102 {
103 if ( !exists( fieldIdx ) )
104 return;
105
106 d->fields.remove( fieldIdx );
107 d->nameToIndex.clear();
108 for ( int idx = 0; idx < count(); ++idx )
109 {
110 d->nameToIndex.insert( d->fields.at( idx ).field.name(), idx );
111 }
112 }
113
extend(const QgsFields & other)114 void QgsFields::extend( const QgsFields &other )
115 {
116 for ( int i = 0; i < other.count(); ++i )
117 {
118 append( other.at( i ), other.fieldOrigin( i ), other.fieldOriginIndex( i ) );
119 }
120 }
121
122 /***************************************************************************
123 * This class is considered CRITICAL and any change MUST be accompanied with
124 * full unit tests in testqgsfields.cpp.
125 * See details in QEP #17
126 ****************************************************************************/
127
isEmpty() const128 bool QgsFields::isEmpty() const
129 {
130 return d->fields.isEmpty();
131 }
132
count() const133 int QgsFields::count() const
134 {
135 return d->fields.count();
136 }
137
size() const138 int QgsFields::size() const
139 {
140 return d->fields.count();
141 }
142
names() const143 QStringList QgsFields::names() const
144 {
145 QStringList lst;
146 for ( int i = 0; i < d->fields.count(); ++i )
147 {
148 lst.append( d->fields[i].field.name() );
149 }
150 return lst;
151 }
152
exists(int i) const153 bool QgsFields::exists( int i ) const
154 {
155 return i >= 0 && i < d->fields.count();
156 }
157
operator [](int i)158 QgsField &QgsFields::operator[]( int i )
159 {
160 return d->fields[i].field;
161 }
162
at(int i) const163 QgsField QgsFields::at( int i ) const
164 {
165 return d->fields[i].field;
166 }
167
field(int fieldIdx) const168 QgsField QgsFields::field( int fieldIdx ) const
169 {
170 return d->fields[fieldIdx].field;
171 }
172
field(const QString & name) const173 QgsField QgsFields::field( const QString &name ) const
174 {
175 return d->fields[ indexFromName( name )].field;
176 }
177
178 /***************************************************************************
179 * This class is considered CRITICAL and any change MUST be accompanied with
180 * full unit tests in testqgsfields.cpp.
181 * See details in QEP #17
182 ****************************************************************************/
183
operator [](int i) const184 QgsField QgsFields::operator[]( int i ) const
185 {
186 return d->fields[i].field;
187 }
188
fieldOrigin(int fieldIdx) const189 QgsFields::FieldOrigin QgsFields::fieldOrigin( int fieldIdx ) const
190 {
191 if ( !exists( fieldIdx ) )
192 return OriginUnknown;
193
194 return d->fields[fieldIdx].origin;
195 }
196
fieldOriginIndex(int fieldIdx) const197 int QgsFields::fieldOriginIndex( int fieldIdx ) const
198 {
199 return d->fields[fieldIdx].originIndex;
200 }
201
indexFromName(const QString & fieldName) const202 int QgsFields::indexFromName( const QString &fieldName ) const
203 {
204 return d->nameToIndex.value( fieldName, -1 );
205 }
206
indexOf(const QString & fieldName) const207 int QgsFields::indexOf( const QString &fieldName ) const
208 {
209 return d->nameToIndex.value( fieldName, -1 );
210 }
211
toList() const212 QList<QgsField> QgsFields::toList() const
213 {
214 QList<QgsField> lst;
215 for ( int i = 0; i < d->fields.count(); ++i )
216 lst.append( d->fields[i].field );
217 return lst;
218 }
219
operator ==(const QgsFields & other) const220 bool QgsFields::operator==( const QgsFields &other ) const
221 {
222 return d->fields == other.d->fields;
223 }
224
constBegin() const225 QgsFields::const_iterator QgsFields::constBegin() const noexcept
226 {
227 if ( d->fields.isEmpty() )
228 return const_iterator();
229
230 return const_iterator( &d->fields.first() );
231 }
232
constEnd() const233 QgsFields::const_iterator QgsFields::constEnd() const noexcept
234 {
235 if ( d->fields.isEmpty() )
236 return const_iterator();
237
238 return const_iterator( &d->fields.last() + 1 );
239 }
240
begin() const241 QgsFields::const_iterator QgsFields::begin() const noexcept
242 {
243 if ( d->fields.isEmpty() )
244 return const_iterator();
245
246 return const_iterator( &d->fields.first() );
247 }
248
end() const249 QgsFields::const_iterator QgsFields::end() const noexcept
250 {
251 if ( d->fields.isEmpty() )
252 return const_iterator();
253
254 return const_iterator( &d->fields.last() + 1 );
255 }
256
begin()257 QgsFields::iterator QgsFields::begin()
258 {
259 if ( d->fields.isEmpty() )
260 return iterator();
261
262 d.detach();
263 return iterator( &d->fields.first() );
264 }
265
end()266 QgsFields::iterator QgsFields::end()
267 {
268 if ( d->fields.isEmpty() )
269 return iterator();
270
271 d.detach();
272 return iterator( &d->fields.last() + 1 );
273 }
274
iconForField(int fieldIdx,bool considerOrigin) const275 QIcon QgsFields::iconForField( int fieldIdx, bool considerOrigin ) const
276 {
277 if ( considerOrigin )
278 {
279 switch ( fieldOrigin( fieldIdx ) )
280 {
281 case QgsFields::OriginExpression:
282 return QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) );
283 break;
284
285 case QgsFields::OriginJoin:
286 return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/join.svg" ) );
287
288 default:
289 return iconForFieldType( d->fields.at( fieldIdx ).field.type() );
290 }
291 }
292 return iconForFieldType( d->fields.at( fieldIdx ).field.type() );
293 }
294
iconForFieldType(const QVariant::Type & type)295 QIcon QgsFields::iconForFieldType( const QVariant::Type &type )
296 {
297 switch ( type )
298 {
299 case QVariant::Bool:
300 return QgsApplication::getThemeIcon( "/mIconFieldBool.svg" );
301
302 case QVariant::Int:
303 case QVariant::UInt:
304 case QVariant::LongLong:
305 case QVariant::ULongLong:
306 {
307 return QgsApplication::getThemeIcon( "/mIconFieldInteger.svg" );
308 }
309 case QVariant::Double:
310 {
311 return QgsApplication::getThemeIcon( "/mIconFieldFloat.svg" );
312 }
313 case QVariant::String:
314 {
315 return QgsApplication::getThemeIcon( "/mIconFieldText.svg" );
316 }
317 case QVariant::Date:
318 {
319 return QgsApplication::getThemeIcon( "/mIconFieldDate.svg" );
320 }
321 case QVariant::DateTime:
322 {
323 return QgsApplication::getThemeIcon( "/mIconFieldDateTime.svg" );
324 }
325 case QVariant::Time:
326 {
327 return QgsApplication::getThemeIcon( "/mIconFieldTime.svg" );
328 }
329 case QVariant::ByteArray:
330 {
331 return QgsApplication::getThemeIcon( "/mIconFieldBinary.svg" );
332 }
333 default:
334 return QIcon();
335 }
336 }
337
338 /***************************************************************************
339 * This class is considered CRITICAL and any change MUST be accompanied with
340 * full unit tests in testqgsfields.cpp.
341 * See details in QEP #17
342 ****************************************************************************/
343
lookupField(const QString & fieldName) const344 int QgsFields::lookupField( const QString &fieldName ) const
345 {
346 if ( fieldName.isEmpty() ) //shortcut
347 return -1;
348
349 for ( int idx = 0; idx < count(); ++idx )
350 {
351 if ( d->fields[idx].field.name() == fieldName )
352 return idx;
353 }
354
355 for ( int idx = 0; idx < count(); ++idx )
356 {
357 if ( QString::compare( d->fields[idx].field.name(), fieldName, Qt::CaseInsensitive ) == 0 )
358 return idx;
359 }
360
361 for ( int idx = 0; idx < count(); ++idx )
362 {
363 const QString alias = d->fields[idx].field.alias();
364 if ( !alias.isEmpty() && QString::compare( alias, fieldName, Qt::CaseInsensitive ) == 0 )
365 return idx;
366 }
367
368 return -1;
369 }
370
allAttributesList() const371 QgsAttributeList QgsFields::allAttributesList() const
372 {
373 const int count = d->fields.count();
374 QgsAttributeList lst;
375 lst.reserve( count );
376 for ( int i = 0; i < count; ++i )
377 lst.append( i );
378 return lst;
379 }
380
381 /***************************************************************************
382 * This class is considered CRITICAL and any change MUST be accompanied with
383 * full unit tests in testqgsfields.cpp.
384 * See details in QEP #17
385 ****************************************************************************/
386
operator <<(QDataStream & out,const QgsFields & fields)387 QDataStream &operator<<( QDataStream &out, const QgsFields &fields )
388 {
389 out << static_cast< quint32 >( fields.size() );
390 for ( int i = 0; i < fields.size(); i++ )
391 {
392 out << fields.field( i );
393 }
394 return out;
395 }
396
operator >>(QDataStream & in,QgsFields & fields)397 QDataStream &operator>>( QDataStream &in, QgsFields &fields )
398 {
399 fields.clear();
400 quint32 size;
401 in >> size;
402 for ( quint32 i = 0; i < size; i++ )
403 {
404 QgsField field;
405 in >> field;
406 fields.append( field );
407 }
408 return in;
409 }
410