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