|
QGIS API Documentation
master-3f58142
|
00001 /*************************************************************************** 00002 QgsAttributeTableModel.cpp 00003 -------------------------------------- 00004 Date : Feb 2009 00005 Copyright : (C) 2009 Vita Cizek 00006 Email : weetya (at) gmail.com 00007 *************************************************************************** 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 ***************************************************************************/ 00015 00016 #include "qgsapplication.h" 00017 #include "qgsattributetablemodel.h" 00018 #include "qgsattributetablefiltermodel.h" 00019 00020 #include "qgsfield.h" 00021 #include "qgsvectorlayer.h" 00022 #include "qgslogger.h" 00023 #include "qgsattributeaction.h" 00024 #include "qgsmapcanvas.h" 00025 #include "qgsrendererv2.h" 00026 #include "qgsmaplayerregistry.h" 00027 #include "qgsexpression.h" 00028 00029 #include <QtGui> 00030 #include <QVariant> 00031 00032 #include <limits> 00033 00034 QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayerCache *layerCache, QObject *parent ) 00035 : QAbstractTableModel( parent ) 00036 , mLayerCache( layerCache ) 00037 , mCachedField( -1 ) 00038 { 00039 QgsDebugMsg( "entered." ); 00040 00041 if ( layerCache->layer()->geometryType() == QGis::NoGeometry ) 00042 { 00043 mFeatureRequest.setFlags( QgsFeatureRequest::NoGeometry ); 00044 } 00045 00046 mFeat.setFeatureId( std::numeric_limits<int>::min() ); 00047 00048 if ( !layer()->hasGeometryType() ) 00049 mFeatureRequest.setFlags( QgsFeatureRequest::NoGeometry ); 00050 00051 loadAttributes(); 00052 00053 connect( layer(), SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) ); 00054 connect( layer(), SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) ); 00055 connect( layer(), SIGNAL( featureDeleted( QgsFeatureId ) ), this, SLOT( featureDeleted( QgsFeatureId ) ) ); 00056 connect( layer(), SIGNAL( updatedFields() ), this, SLOT( updatedFields() ) ); 00057 connect( mLayerCache, SIGNAL( cachedLayerDeleted() ), this, SLOT( layerDeleted() ) ); 00058 } 00059 00060 QgsAttributeTableModel::~QgsAttributeTableModel() 00061 { 00062 qDeleteAll( mValueMaps ); 00063 } 00064 00065 bool QgsAttributeTableModel::loadFeatureAtId( QgsFeatureId fid ) const 00066 { 00067 QgsDebugMsgLevel( QString( "loading feature %1" ).arg( fid ), 3 ); 00068 00069 if ( fid == std::numeric_limits<int>::min() ) 00070 { 00071 return false; 00072 } 00073 00074 return mLayerCache->featureAtId( fid, mFeat ); 00075 } 00076 00077 void QgsAttributeTableModel::featureDeleted( QgsFeatureId fid ) 00078 { 00079 prefetchColumnData( -1 ); // Invalidate cached column data 00080 00081 int row = idToRow( fid ); 00082 00083 beginRemoveRows( QModelIndex(), row, row ); 00084 removeRow( row ); 00085 endRemoveRows(); 00086 } 00087 00088 bool QgsAttributeTableModel::removeRows( int row, int count, const QModelIndex &parent ) 00089 { 00090 Q_UNUSED( parent ); 00091 QgsDebugMsgLevel( QString( "remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 ); 00092 00093 // clean old references 00094 for ( int i = row; i < row + count; i++ ) 00095 { 00096 mIdRowMap.remove( mRowIdMap[ i ] ); 00097 mRowIdMap.remove( i ); 00098 } 00099 00100 // update maps 00101 int n = mRowIdMap.size() + count; 00102 for ( int i = row + count; i < n; i++ ) 00103 { 00104 QgsFeatureId id = mRowIdMap[i]; 00105 mIdRowMap[ id ] -= count; 00106 mRowIdMap[ i-count ] = id; 00107 mRowIdMap.remove( i ); 00108 } 00109 00110 #ifdef QGISDEBUG 00111 QgsDebugMsgLevel( QString( "after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 ); 00112 QgsDebugMsgLevel( "id->row", 4 ); 00113 for ( QHash<QgsFeatureId, int>::iterator it = mIdRowMap.begin(); it != mIdRowMap.end(); ++it ) 00114 QgsDebugMsgLevel( QString( "%1->%2" ).arg( FID_TO_STRING( it.key() ) ).arg( *it ), 4 ); 00115 00116 QHash<QgsFeatureId, int>::iterator idit; 00117 00118 QgsDebugMsgLevel( "row->id", 4 ); 00119 for ( QHash<int, QgsFeatureId>::iterator it = mRowIdMap.begin(); it != mRowIdMap.end(); ++it ) 00120 QgsDebugMsgLevel( QString( "%1->%2" ).arg( it.key() ).arg( FID_TO_STRING( *it ) ), 4 ); 00121 #endif 00122 00123 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() ); 00124 00125 return true; 00126 } 00127 00128 void QgsAttributeTableModel::featureAdded( QgsFeatureId fid, bool newOperation ) 00129 { 00130 prefetchColumnData( -1 ); // Invalidate cached column data 00131 int n = mRowIdMap.size(); 00132 if ( newOperation ) 00133 beginInsertRows( QModelIndex(), n, n ); 00134 00135 mIdRowMap.insert( fid, n ); 00136 mRowIdMap.insert( n, fid ); 00137 00138 if ( newOperation ) 00139 endInsertRows(); 00140 00141 reload( index( rowCount() - 1, 0 ), index( rowCount() - 1, columnCount() ) ); 00142 } 00143 00144 void QgsAttributeTableModel::updatedFields() 00145 { 00146 QgsDebugMsg( "entered." ); 00147 loadAttributes(); 00148 emit modelChanged(); 00149 } 00150 00151 void QgsAttributeTableModel::layerDeleted() 00152 { 00153 QgsDebugMsg( "entered." ); 00154 00155 beginRemoveRows( QModelIndex(), 0, rowCount() - 1 ); 00156 removeRows( 0, rowCount() ); 00157 endRemoveRows(); 00158 00159 const QMap<QString, QVariant> *item; 00160 foreach ( item, mValueMaps ) 00161 { 00162 delete item; 00163 } 00164 00165 mValueMaps.clear(); 00166 } 00167 00168 void QgsAttributeTableModel::attributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value ) 00169 { 00170 if ( mCachedField == idx ) 00171 mFieldCache[ fid ] = value; 00172 00173 if ( fid == mFeat.id() ) 00174 { 00175 mFeat.setValid( false ); 00176 } 00177 setData( index( idToRow( fid ), fieldCol( idx ) ), value, Qt::EditRole ); 00178 } 00179 00180 void QgsAttributeTableModel::loadAttributes() 00181 { 00182 if ( !layer() ) 00183 { 00184 return; 00185 } 00186 00187 bool ins = false, rm = false; 00188 00189 QgsAttributeList attributes; 00190 const QgsFields& fields = layer()->pendingFields(); 00191 for ( int idx = 0; idx < fields.count(); ++idx ) 00192 { 00193 switch ( layer()->editType( idx ) ) 00194 { 00195 case QgsVectorLayer::Hidden: 00196 continue; 00197 00198 case QgsVectorLayer::ValueMap: 00199 mValueMaps.insert( idx, new QMap< QString, QVariant >( layer()->valueMap( idx ) ) ); 00200 break; 00201 00202 case QgsVectorLayer::ValueRelation: 00203 { 00204 const QgsVectorLayer::ValueRelationData &data = layer()->valueRelation( idx ); 00205 00206 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( data.mLayer ) ); 00207 if ( !layer ) 00208 continue; 00209 00210 int ki = layer->fieldNameIndex( data.mKey ); 00211 int vi = layer->fieldNameIndex( data.mValue ); 00212 00213 QgsExpression *e = 0; 00214 if ( !data.mFilterExpression.isEmpty() ) 00215 { 00216 e = new QgsExpression( data.mFilterExpression ); 00217 if ( e->hasParserError() || !e->prepare( layer->pendingFields() ) ) 00218 continue; 00219 } 00220 00221 if ( ki >= 0 && vi >= 0 ) 00222 { 00223 QSet<int> attributes; 00224 attributes << ki << vi; 00225 00226 QgsFeatureRequest::Flag flags = QgsFeatureRequest::NoGeometry; 00227 00228 if ( e ) 00229 { 00230 if ( e->needsGeometry() ) 00231 flags = QgsFeatureRequest::NoFlags; 00232 00233 foreach ( const QString &field, e->referencedColumns() ) 00234 { 00235 int idx = layer->fieldNameIndex( field ); 00236 if ( idx < 0 ) 00237 continue; 00238 attributes << idx; 00239 } 00240 } 00241 00242 QMap< QString, QVariant > *map = new QMap< QString, QVariant >(); 00243 00244 QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFlags( flags ).setSubsetOfAttributes( attributes.toList() ) ); 00245 QgsFeature f; 00246 while ( fit.nextFeature( f ) ) 00247 { 00248 if ( e && !e->evaluate( &f ).toBool() ) 00249 continue; 00250 00251 map->insert( f.attribute( vi ).toString(), f.attribute( ki ) ); 00252 } 00253 00254 mValueMaps.insert( idx, map ); 00255 } 00256 } 00257 break; 00258 00259 default: 00260 break; 00261 } 00262 00263 attributes << idx; 00264 } 00265 00266 if ( mFieldCount < attributes.size() ) 00267 { 00268 ins = true; 00269 beginInsertColumns( QModelIndex(), mFieldCount, attributes.size() - 1 ); 00270 } 00271 else if ( attributes.size() < mFieldCount ) 00272 { 00273 rm = true; 00274 beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount - 1 ); 00275 } 00276 00277 mFieldCount = attributes.size(); 00278 mAttributes = attributes; 00279 00280 if ( ins ) 00281 { 00282 endInsertColumns(); 00283 } 00284 else if ( rm ) 00285 { 00286 endRemoveColumns(); 00287 } 00288 } 00289 00290 void QgsAttributeTableModel::loadLayer() 00291 { 00292 QgsDebugMsg( "entered." ); 00293 00294 beginRemoveRows( QModelIndex(), 0, rowCount() - 1 ); 00295 removeRows( 0, rowCount() ); 00296 endRemoveRows(); 00297 00298 QgsFeatureIterator features = mLayerCache->getFeatures( mFeatureRequest ); 00299 00300 int i = 0; 00301 00302 QTime t; 00303 t.start(); 00304 00305 QgsFeature feat; 00306 while ( features.nextFeature( feat ) ) 00307 { 00308 ++i; 00309 00310 if ( t.elapsed() > 1000 ) 00311 { 00312 bool cancel = false; 00313 emit( progress( i, cancel ) ); 00314 if ( cancel ) 00315 break; 00316 00317 t.restart(); 00318 } 00319 featureAdded( feat.id() ); 00320 } 00321 00322 emit finished(); 00323 00324 mFieldCount = mAttributes.size(); 00325 } 00326 00327 void QgsAttributeTableModel::swapRows( QgsFeatureId a, QgsFeatureId b ) 00328 { 00329 if ( a == b ) 00330 return; 00331 00332 int rowA = idToRow( a ); 00333 int rowB = idToRow( b ); 00334 00335 //emit layoutAboutToBeChanged(); 00336 00337 mRowIdMap.remove( rowA ); 00338 mRowIdMap.remove( rowB ); 00339 mRowIdMap.insert( rowA, b ); 00340 mRowIdMap.insert( rowB, a ); 00341 00342 mIdRowMap.remove( a ); 00343 mIdRowMap.remove( b ); 00344 mIdRowMap.insert( a, rowB ); 00345 mIdRowMap.insert( b, rowA ); 00346 00347 //emit layoutChanged(); 00348 } 00349 00350 int QgsAttributeTableModel::idToRow( QgsFeatureId id ) const 00351 { 00352 if ( !mIdRowMap.contains( id ) ) 00353 { 00354 QgsDebugMsg( QString( "idToRow: id %1 not in the map" ).arg( id ) ); 00355 return -1; 00356 } 00357 00358 return mIdRowMap[id]; 00359 } 00360 00361 QModelIndex QgsAttributeTableModel::idToIndex( QgsFeatureId id ) const 00362 { 00363 return index( idToRow( id ), 0 ); 00364 } 00365 00366 QModelIndexList QgsAttributeTableModel::idToIndexList( QgsFeatureId id ) const 00367 { 00368 QModelIndexList indexes; 00369 00370 int row = idToRow( id ); 00371 for ( int column = 0; column < columnCount(); ++column ) 00372 { 00373 indexes.append( index( row, column ) ); 00374 } 00375 00376 return indexes; 00377 } 00378 00379 QgsFeatureId QgsAttributeTableModel::rowToId( const int row ) const 00380 { 00381 if ( !mRowIdMap.contains( row ) ) 00382 { 00383 QgsDebugMsg( QString( "rowToId: row %1 not in the map" ).arg( row ) ); 00384 // return negative infinite (to avoid collision with newly added features) 00385 return std::numeric_limits<int>::min(); 00386 } 00387 00388 return mRowIdMap[row]; 00389 } 00390 00391 int QgsAttributeTableModel::fieldIdx( int col ) const 00392 { 00393 return mAttributes[ col ]; 00394 } 00395 00396 int QgsAttributeTableModel::fieldCol( int idx ) const 00397 { 00398 return mAttributes.indexOf( idx ); 00399 } 00400 00401 int QgsAttributeTableModel::rowCount( const QModelIndex &parent ) const 00402 { 00403 Q_UNUSED( parent ); 00404 return mRowIdMap.size(); 00405 } 00406 00407 int QgsAttributeTableModel::columnCount( const QModelIndex &parent ) const 00408 { 00409 Q_UNUSED( parent ); 00410 return qMax( 1, mFieldCount ); // if there are zero columns all model indices will be considered invalid 00411 } 00412 00413 QVariant QgsAttributeTableModel::headerData( int section, Qt::Orientation orientation, int role ) const 00414 { 00415 if ( !layer() ) 00416 return QVariant(); 00417 00418 if ( role == Qt::DisplayRole ) 00419 { 00420 if ( orientation == Qt::Vertical ) //row 00421 { 00422 return QVariant( section ); 00423 } 00424 else if ( section >= 0 && section < mFieldCount ) 00425 { 00426 QString attributeName = layer()->attributeAlias( mAttributes[section] ); 00427 if ( attributeName.isEmpty() ) 00428 { 00429 QgsField field = layer()->pendingFields()[ mAttributes[section] ]; 00430 attributeName = field.name(); 00431 } 00432 return QVariant( attributeName ); 00433 } 00434 else 00435 { 00436 return tr( "feature id" ); 00437 } 00438 } 00439 else 00440 { 00441 return QVariant(); 00442 } 00443 } 00444 00445 QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) const 00446 { 00447 if ( !index.isValid() || 00448 ( role != Qt::TextAlignmentRole 00449 && role != Qt::DisplayRole 00450 && role != Qt::EditRole 00451 && role != SortRole 00452 && role != FeatureIdRole 00453 && role != FieldIndexRole 00454 ) 00455 ) 00456 return QVariant(); 00457 00458 QgsFeatureId rowId = rowToId( index.row() ); 00459 00460 if ( role == FeatureIdRole ) 00461 return rowId; 00462 00463 if ( index.column() >= mFieldCount ) 00464 return role == Qt::DisplayRole ? rowId : QVariant(); 00465 00466 int fieldId = mAttributes[ index.column()]; 00467 00468 if ( role == FieldIndexRole ) 00469 return fieldId; 00470 00471 const QgsField& field = layer()->pendingFields()[ fieldId ]; 00472 00473 QVariant::Type fldType = field.type(); 00474 bool fldNumeric = ( fldType == QVariant::Int || fldType == QVariant::Double ); 00475 00476 if ( role == Qt::TextAlignmentRole ) 00477 { 00478 if ( fldNumeric ) 00479 return QVariant( Qt::AlignRight ); 00480 else 00481 return QVariant( Qt::AlignLeft ); 00482 } 00483 00484 QVariant val; 00485 00486 // if we don't have the row in current cache, load it from layer first 00487 if ( mCachedField == fieldId ) 00488 { 00489 val = mFieldCache[ rowId ]; 00490 } 00491 else 00492 { 00493 if ( mFeat.id() != rowId || !mFeat.isValid() ) 00494 { 00495 if ( !loadFeatureAtId( rowId ) ) 00496 return QVariant( "ERROR" ); 00497 00498 if ( mFeat.id() != rowId ) 00499 return QVariant( "ERROR" ); 00500 } 00501 00502 val = mFeat.attribute( fieldId ); 00503 } 00504 00505 // For sorting return unprocessed value 00506 if ( SortRole == role ) 00507 { 00508 return val; 00509 } 00510 00511 if ( val.isNull() ) 00512 { 00513 // if the value is NULL, show that in table, but don't show "NULL" text in editor 00514 if ( role == Qt::EditRole ) 00515 { 00516 return QVariant( fldType ); 00517 } 00518 else 00519 { 00520 QSettings settings; 00521 return settings.value( "qgis/nullValue", "NULL" ); 00522 } 00523 } 00524 00525 if ( role == Qt::DisplayRole ) 00526 { 00527 if ( mValueMaps.contains( fieldId ) ) 00528 { 00529 return mValueMaps[ fieldId ]->key( val.toString(), QString( "(%1)" ).arg( val.toString() ) ); 00530 } 00531 00532 if ( layer()->editType( fieldId ) == QgsVectorLayer::Calendar && val.canConvert( QVariant::Date ) ) 00533 { 00534 return val.toDate().toString( layer()->dateFormat( fieldId ) ); 00535 } 00536 } 00537 00538 00539 return field.displayString( val ); 00540 } 00541 00542 bool QgsAttributeTableModel::setData( const QModelIndex &index, const QVariant &value, int role ) 00543 { 00544 Q_UNUSED( value ) 00545 00546 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !layer()->isEditable() ) 00547 return false; 00548 00549 if ( !layer()->isModified() ) 00550 return false; 00551 00552 emit dataChanged( index, index ); 00553 00554 return true; 00555 } 00556 00557 Qt::ItemFlags QgsAttributeTableModel::flags( const QModelIndex &index ) const 00558 { 00559 if ( !index.isValid() ) 00560 return Qt::ItemIsEnabled; 00561 00562 if ( index.column() >= mFieldCount ) 00563 return Qt::NoItemFlags; 00564 00565 Qt::ItemFlags flags = QAbstractItemModel::flags( index ); 00566 00567 if ( layer()->isEditable() && 00568 layer()->editType( mAttributes[ index.column()] ) != QgsVectorLayer::Immutable ) 00569 flags |= Qt::ItemIsEditable; 00570 00571 return flags; 00572 } 00573 00574 void QgsAttributeTableModel::reload( const QModelIndex &index1, const QModelIndex &index2 ) 00575 { 00576 for ( int row = index1.row(); row <= index2.row(); row++ ) 00577 { 00578 QgsFeatureId fid = rowToId( row ); 00579 mLayerCache->removeCachedFeature( fid ); 00580 } 00581 00582 mFeat.setFeatureId( std::numeric_limits<int>::min() ); 00583 emit dataChanged( index1, index2 ); 00584 } 00585 00586 void QgsAttributeTableModel::resetModel() 00587 { 00588 reset(); 00589 } 00590 00591 void QgsAttributeTableModel::executeAction( int action, const QModelIndex &idx ) const 00592 { 00593 QgsFeature f = feature( idx ); 00594 layer()->actions()->doAction( action, f, fieldIdx( idx.column() ) ); 00595 } 00596 00597 QgsFeature QgsAttributeTableModel::feature( const QModelIndex &idx ) const 00598 { 00599 QgsFeature f; 00600 f.initAttributes( mAttributes.size() ); 00601 f.setFeatureId( rowToId( idx.row() ) ); 00602 for ( int i = 0; i < mAttributes.size(); i++ ) 00603 { 00604 f.setAttribute( mAttributes[i], data( index( idx.row(), i ), Qt::EditRole ) ); 00605 } 00606 00607 return f; 00608 } 00609 00610 void QgsAttributeTableModel::prefetchColumnData( int column ) 00611 { 00612 mFieldCache.clear(); 00613 00614 if ( column == -1 ) 00615 { 00616 mCachedField = -1; 00617 } 00618 else 00619 { 00620 int fieldId = mAttributes[ column ]; 00621 const QgsFields& fields = layer()->pendingFields(); 00622 QStringList fldNames; 00623 fldNames << fields[ fieldId ].name(); 00624 00625 QgsFeatureIterator it = mLayerCache->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( fldNames, fields ) ); 00626 00627 QgsFeature f; 00628 while ( it.nextFeature( f ) ) 00629 { 00630 mFieldCache.insert( f.id(), f.attribute( fieldId ) ); 00631 } 00632 00633 mCachedField = fieldId; 00634 } 00635 }