Branch data Line data Source code
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 : : 28 : 4017 : QgsFields::QgsFields() 29 : 4017 : { 30 : 4017 : d = new QgsFieldsPrivate(); 31 : 4017 : } 32 : : 33 : 2144 : QgsFields::QgsFields( const QgsFields &other ) //NOLINT 34 : 2144 : : d( other.d ) 35 : 2144 : { 36 : 2144 : } 37 : : 38 : 2566 : QgsFields &QgsFields::operator =( const QgsFields &other ) //NOLINT 39 : : { 40 : 2566 : d = other.d; 41 : 2566 : return *this; 42 : : } 43 : : 44 : 5620 : QgsFields::~QgsFields() //NOLINT 45 : 5620 : {} 46 : : 47 : 187 : void QgsFields::clear() 48 : : { 49 : 187 : d->fields.clear(); 50 : 187 : d->nameToIndex.clear(); 51 : 187 : } 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 : : 59 : 422 : bool QgsFields::append( const QgsField &field, FieldOrigin origin, int originIndex ) 60 : : { 61 : 422 : if ( d->nameToIndex.contains( field.name() ) ) 62 : 0 : return false; 63 : : 64 : 422 : if ( originIndex == -1 && origin == OriginProvider ) 65 : 422 : originIndex = d->fields.count(); 66 : 422 : d->fields.append( Field( field, origin, originIndex ) ); 67 : : 68 : 422 : d->nameToIndex.insert( field.name(), d->fields.count() - 1 ); 69 : 422 : return true; 70 : 422 : } 71 : : 72 : 0 : bool QgsFields::rename( int fieldIdx, const QString &name ) 73 : : { 74 : 0 : if ( !exists( fieldIdx ) ) 75 : 0 : return false; 76 : : 77 : 0 : if ( name.isEmpty() ) 78 : 0 : return false; 79 : : 80 : 0 : if ( d->nameToIndex.contains( name ) ) 81 : 0 : return false; 82 : : 83 : 0 : const QString oldName = d->fields[ fieldIdx ].field.name(); 84 : 0 : d->fields[ fieldIdx ].field.setName( name ); 85 : 0 : d->nameToIndex.remove( oldName ); 86 : 0 : d->nameToIndex.insert( name, fieldIdx ); 87 : 0 : return true; 88 : 0 : } 89 : : 90 : 0 : bool QgsFields::appendExpressionField( const QgsField &field, int originIndex ) 91 : : { 92 : 0 : if ( d->nameToIndex.contains( field.name() ) ) 93 : 0 : return false; 94 : : 95 : 0 : d->fields.append( Field( field, OriginExpression, originIndex ) ); 96 : : 97 : 0 : d->nameToIndex.insert( field.name(), d->fields.count() - 1 ); 98 : 0 : return true; 99 : 0 : } 100 : : 101 : 0 : void QgsFields::remove( int fieldIdx ) 102 : : { 103 : 0 : if ( !exists( fieldIdx ) ) 104 : 0 : return; 105 : : 106 : 0 : d->fields.remove( fieldIdx ); 107 : 0 : d->nameToIndex.clear(); 108 : 0 : for ( int idx = 0; idx < count(); ++idx ) 109 : : { 110 : 0 : d->nameToIndex.insert( d->fields.at( idx ).field.name(), idx ); 111 : 0 : } 112 : 0 : } 113 : : 114 : 0 : void QgsFields::extend( const QgsFields &other ) 115 : : { 116 : 0 : for ( int i = 0; i < other.count(); ++i ) 117 : : { 118 : 0 : append( other.at( i ), other.fieldOrigin( i ), other.fieldOriginIndex( i ) ); 119 : 0 : } 120 : 0 : } 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 : : 128 : 1 : bool QgsFields::isEmpty() const 129 : : { 130 : 1 : return d->fields.isEmpty(); 131 : : } 132 : : 133 : 3847 : int QgsFields::count() const 134 : : { 135 : 3847 : return d->fields.count(); 136 : : } 137 : : 138 : 457 : int QgsFields::size() const 139 : : { 140 : 457 : return d->fields.count(); 141 : : } 142 : : 143 : 0 : QStringList QgsFields::names() const 144 : : { 145 : 0 : QStringList lst; 146 : 0 : for ( int i = 0; i < d->fields.count(); ++i ) 147 : : { 148 : 0 : lst.append( d->fields[i].field.name() ); 149 : 0 : } 150 : 0 : return lst; 151 : 0 : } 152 : : 153 : 127 : bool QgsFields::exists( int i ) const 154 : : { 155 : 127 : return i >= 0 && i < d->fields.count(); 156 : : } 157 : : 158 : 0 : QgsField &QgsFields::operator[]( int i ) 159 : : { 160 : 0 : return d->fields[i].field; 161 : : } 162 : : 163 : 1824 : QgsField QgsFields::at( int i ) const 164 : : { 165 : 1824 : return d->fields[i].field; 166 : : } 167 : : 168 : 0 : QgsField QgsFields::field( int fieldIdx ) const 169 : : { 170 : 0 : return d->fields[fieldIdx].field; 171 : : } 172 : : 173 : 0 : QgsField QgsFields::field( const QString &name ) const 174 : : { 175 : 0 : 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 : : 184 : 0 : QgsField QgsFields::operator[]( int i ) const 185 : : { 186 : 0 : return d->fields[i].field; 187 : : } 188 : : 189 : 124 : QgsFields::FieldOrigin QgsFields::fieldOrigin( int fieldIdx ) const 190 : : { 191 : 124 : if ( !exists( fieldIdx ) ) 192 : 0 : return OriginUnknown; 193 : : 194 : 124 : return d->fields[fieldIdx].origin; 195 : 124 : } 196 : : 197 : 0 : int QgsFields::fieldOriginIndex( int fieldIdx ) const 198 : : { 199 : 0 : return d->fields[fieldIdx].originIndex; 200 : : } 201 : : 202 : 245 : int QgsFields::indexFromName( const QString &fieldName ) const 203 : : { 204 : 245 : return d->nameToIndex.value( fieldName, -1 ); 205 : : } 206 : : 207 : 0 : int QgsFields::indexOf( const QString &fieldName ) const 208 : : { 209 : 0 : return d->nameToIndex.value( fieldName, -1 ); 210 : : } 211 : : 212 : 0 : QList<QgsField> QgsFields::toList() const 213 : : { 214 : 0 : QList<QgsField> lst; 215 : 0 : for ( int i = 0; i < d->fields.count(); ++i ) 216 : 0 : lst.append( d->fields[i].field ); 217 : 0 : return lst; 218 : 0 : } 219 : : 220 : 79 : bool QgsFields::operator==( const QgsFields &other ) const 221 : : { 222 : 79 : return d->fields == other.d->fields; 223 : : } 224 : : 225 : 0 : QgsFields::const_iterator QgsFields::constBegin() const noexcept 226 : : { 227 : 0 : if ( d->fields.isEmpty() ) 228 : 0 : return const_iterator(); 229 : : 230 : 0 : return const_iterator( &d->fields.first() ); 231 : 0 : } 232 : : 233 : 0 : QgsFields::const_iterator QgsFields::constEnd() const noexcept 234 : : { 235 : 0 : if ( d->fields.isEmpty() ) 236 : 0 : return const_iterator(); 237 : : 238 : 0 : return const_iterator( &d->fields.last() + 1 ); 239 : 0 : } 240 : : 241 : 234 : QgsFields::const_iterator QgsFields::begin() const noexcept 242 : : { 243 : 234 : if ( d->fields.isEmpty() ) 244 : 42 : return const_iterator(); 245 : : 246 : 192 : return const_iterator( &d->fields.first() ); 247 : 234 : } 248 : : 249 : 234 : QgsFields::const_iterator QgsFields::end() const noexcept 250 : : { 251 : 234 : if ( d->fields.isEmpty() ) 252 : 42 : return const_iterator(); 253 : : 254 : 192 : return const_iterator( &d->fields.last() + 1 ); 255 : 234 : } 256 : : 257 : 0 : QgsFields::iterator QgsFields::begin() 258 : : { 259 : 0 : if ( d->fields.isEmpty() ) 260 : 0 : return iterator(); 261 : : 262 : 0 : d.detach(); 263 : 0 : return iterator( &d->fields.first() ); 264 : 0 : } 265 : : 266 : 0 : QgsFields::iterator QgsFields::end() 267 : : { 268 : 0 : if ( d->fields.isEmpty() ) 269 : 0 : return iterator(); 270 : : 271 : 0 : d.detach(); 272 : 0 : return iterator( &d->fields.last() + 1 ); 273 : 0 : } 274 : : 275 : 0 : QIcon QgsFields::iconForField( int fieldIdx, bool considerOrigin ) const 276 : : { 277 : 0 : if ( considerOrigin ) 278 : : { 279 : 0 : switch ( fieldOrigin( fieldIdx ) ) 280 : : { 281 : : case QgsFields::OriginExpression: 282 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) ); 283 : : break; 284 : : 285 : : case QgsFields::OriginJoin: 286 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/join.svg" ) ); 287 : : 288 : : default: 289 : 0 : return iconForFieldType( d->fields.at( fieldIdx ).field.type() ); 290 : : } 291 : : } 292 : 0 : return iconForFieldType( d->fields.at( fieldIdx ).field.type() ); 293 : 0 : } 294 : : 295 : 0 : QIcon QgsFields::iconForFieldType( const QVariant::Type &type ) 296 : : { 297 : 0 : switch ( type ) 298 : : { 299 : : case QVariant::Bool: 300 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldBool.svg" ); 301 : : 302 : : case QVariant::Int: 303 : : case QVariant::UInt: 304 : : case QVariant::LongLong: 305 : : case QVariant::ULongLong: 306 : : { 307 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldInteger.svg" ); 308 : : } 309 : : case QVariant::Double: 310 : : { 311 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldFloat.svg" ); 312 : : } 313 : : case QVariant::String: 314 : : { 315 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldText.svg" ); 316 : : } 317 : : case QVariant::Date: 318 : : { 319 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldDate.svg" ); 320 : : } 321 : : case QVariant::DateTime: 322 : : { 323 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldDateTime.svg" ); 324 : : } 325 : : case QVariant::Time: 326 : : { 327 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldTime.svg" ); 328 : : } 329 : : case QVariant::ByteArray: 330 : : { 331 : 0 : return QgsApplication::getThemeIcon( "/mIconFieldBinary.svg" ); 332 : : } 333 : : default: 334 : 0 : return QIcon(); 335 : : } 336 : 0 : } 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 : : 344 : 0 : int QgsFields::lookupField( const QString &fieldName ) const 345 : : { 346 : 0 : if ( fieldName.isEmpty() ) //shortcut 347 : 0 : return -1; 348 : : 349 : 0 : for ( int idx = 0; idx < count(); ++idx ) 350 : : { 351 : 0 : if ( d->fields[idx].field.name() == fieldName ) 352 : 0 : return idx; 353 : 0 : } 354 : : 355 : 0 : for ( int idx = 0; idx < count(); ++idx ) 356 : : { 357 : 0 : if ( QString::compare( d->fields[idx].field.name(), fieldName, Qt::CaseInsensitive ) == 0 ) 358 : 0 : return idx; 359 : 0 : } 360 : : 361 : 0 : for ( int idx = 0; idx < count(); ++idx ) 362 : : { 363 : 0 : QString alias = d->fields[idx].field.alias(); 364 : 0 : if ( !alias.isEmpty() && QString::compare( alias, fieldName, Qt::CaseInsensitive ) == 0 ) 365 : 0 : return idx; 366 : 0 : } 367 : : 368 : 0 : return -1; 369 : 0 : } 370 : : 371 : 208 : QgsAttributeList QgsFields::allAttributesList() const 372 : : { 373 : 208 : const int count = d->fields.count(); 374 : 208 : QgsAttributeList lst; 375 : 208 : lst.reserve( count ); 376 : 507 : for ( int i = 0; i < count; ++i ) 377 : 299 : lst.append( i ); 378 : 208 : return lst; 379 : 208 : } 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 : : 387 : 0 : QDataStream &operator<<( QDataStream &out, const QgsFields &fields ) 388 : : { 389 : 0 : out << static_cast< quint32 >( fields.size() ); 390 : 0 : for ( int i = 0; i < fields.size(); i++ ) 391 : : { 392 : 0 : out << fields.field( i ); 393 : 0 : } 394 : 0 : return out; 395 : 0 : } 396 : : 397 : 0 : QDataStream &operator>>( QDataStream &in, QgsFields &fields ) 398 : : { 399 : 0 : fields.clear(); 400 : : quint32 size; 401 : 0 : in >> size; 402 : 0 : for ( quint32 i = 0; i < size; i++ ) 403 : : { 404 : 0 : QgsField field; 405 : 0 : in >> field; 406 : 0 : fields.append( field ); 407 : 0 : } 408 : 0 : return in; 409 : 0 : }