Quantum GIS API Documentation  master-ce49b66
src/gui/attributetable/qgsattributetablemodel.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines