QGIS API Documentation  master-3f58142
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 "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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines