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