src/app/qgsattributetable.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           qgsattributetable.cpp  -  description
00003                              -------------------
00004     begin                : Sat Nov 23 2002
00005     copyright            : (C) 2002 by Gary E.Sherman
00006     email                : sherman at mrcc dot com
00007        Romans 3:23=>Romans 6:23=>Romans 5:8=>Romans 10:9,10=>Romans 12
00008  ***************************************************************************/
00009 
00010 /***************************************************************************
00011  *                                                                         *
00012  *   This program is free software; you can redistribute it and/or modify  *
00013  *   it under the terms of the GNU General Public License as published by  *
00014  *   the Free Software Foundation; either version 2 of the License, or     *
00015  *   (at your option) any later version.                                   *
00016  *                                                                         *
00017  ***************************************************************************/
00018 /* $Id: qgsattributetable.cpp 9506 2008-10-20 21:44:15Z timlinux $ */
00019 #include <QLineEdit>
00020 #include <QValidator>
00021 
00022 #include "qgsattributetable.h"
00023 #include "qgsfield.h"
00024 #include "qgslogger.h"
00025 #include "qgsvectordataprovider.h"
00026 #include "qgsvectorlayer.h"
00027 
00028 #include <QApplication>
00029 #include <QClipboard>
00030 #include <QHeaderView>
00031 #include <QKeyEvent>
00032 #include <QMenu>
00033 
00034 
00035 QgsAttributeTableItemDelegate::QgsAttributeTableItemDelegate( QgsAttributeTable *table, QObject *parent )
00036     : QItemDelegate( parent ), mTable( table )
00037 {
00038 }
00039 
00040 QWidget *QgsAttributeTableItemDelegate::createEditor(
00041   QWidget *parent,
00042   const QStyleOptionViewItem &option,
00043   const QModelIndex &index ) const
00044 {
00045   QWidget *editor = QItemDelegate::createEditor( parent, option, index );
00046   QLineEdit *le = dynamic_cast<QLineEdit*>( editor );
00047   if ( !le )
00048     return editor;
00049 
00050   int col = index.column();
00051   QTableWidgetItem *twi = mTable->horizontalHeaderItem( col );
00052   if ( !twi )
00053   {
00054     QgsDebugMsg( QString( "horizontalHeaderItem %1 not found" ).arg( col ) );
00055     return editor;
00056   }
00057 
00058   int type = twi->data( QgsAttributeTable::AttributeType ).toInt();
00059   if ( type == QVariant::Int )
00060   {
00061     le->setValidator( new QIntValidator( le ) );
00062   }
00063   else if ( type == QVariant::Double )
00064   {
00065     le->setValidator( new QDoubleValidator( le ) );
00066   }
00067 
00068   return editor;
00069 }
00070 
00071 
00072 QgsAttributeTable::QgsAttributeTable( QWidget * parent ) :
00073     QTableWidget( parent ),
00074     lockKeyPressed( false ),
00075     mEditable( false ),
00076     mEdited( false ),
00077     mActionPopup( 0 ),
00078     mPreviousSortIndicatorColumn( -1 )
00079 {
00080   QFont f( font() );
00081 #ifdef Q_WS_MAC
00082   // The default application font for OS X is Lucida Grande 13 point; for small, use 11 point
00083   f.setPointSize( 11 );
00084 #else
00085   f.setFamily( "Helvetica" );
00086   f.setPointSize( 9 );
00087 #endif
00088   setFont( f );
00089   mDelegate = new QgsAttributeTableItemDelegate( this );
00090   setItemDelegate( mDelegate );
00091   setSelectionBehavior( QAbstractItemView::SelectRows );
00092   connect( this, SIGNAL( itemSelectionChanged() ), this, SLOT( handleChangedSelections() ) );
00093   connect( horizontalHeader(), SIGNAL( sectionClicked( int ) ), this, SLOT( columnClicked( int ) ) );
00094   connect( verticalHeader(), SIGNAL( sectionClicked( int ) ), this, SLOT( rowClicked( int ) ) );
00095   setFocus();
00096 }
00097 
00098 QgsAttributeTable::~QgsAttributeTable()
00099 {
00100   delete mActionPopup;
00101   delete mDelegate;
00102 }
00103 
00104 void QgsAttributeTable::setReadOnly( bool b )
00105 {
00106   blockSignals( true );
00107 
00108   setEditTriggers( b ? QAbstractItemView::NoEditTriggers :
00109                    QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed );
00110   if ( !b )
00111   {
00112     setColumnReadOnly( 0, true );
00113   }
00114 
00115   blockSignals( false );
00116 }
00117 
00118 void QgsAttributeTable::setColumnReadOnly( int col, bool ro )
00119 {
00120   for ( int i = 0; i < rowCount(); ++i )
00121   {
00122     QTableWidgetItem *twi = item( i, col );
00123     twi->setFlags( ro ? twi->flags() & ~Qt::ItemIsEditable : twi->flags() | Qt::ItemIsEditable );
00124   }
00125 }
00126 
00127 void QgsAttributeTable::columnClicked( int col )
00128 {
00129   QApplication::setOverrideCursor( Qt::WaitCursor );
00130 
00131   //store the ids of the selected rows in a list
00132   QList<int> idsOfSelected;
00133   QList<QTableWidgetSelectionRange> selection = selectedRanges();
00134   for ( int i = 0; i < selection.count(); i++ )
00135   {
00136     for ( int j = selection.at( i ).topRow(); j <= selection.at( i ).bottomRow(); j++ )
00137     {
00138       idsOfSelected.append( item( j, 0 )->text().toInt() );
00139     }
00140   }
00141 
00142   QHeaderView *header = horizontalHeader();
00143   if ( !header->isSortIndicatorShown() )
00144   {
00145     header->setSortIndicatorShown( true );
00146     header->setSortIndicator( col, Qt::AscendingOrder );
00147   }
00148   if ( col != mPreviousSortIndicatorColumn )
00149   {
00150     // Workaround for QTableView sortIndicator displayed in wrong direction
00151     header->setSortIndicator( col, header->sortIndicatorOrder() == Qt::AscendingOrder ?
00152                               Qt::DescendingOrder : Qt::AscendingOrder );
00153   }
00154   mPreviousSortIndicatorColumn = col;
00155   sortColumn( col, header->sortIndicatorOrder() == Qt::DescendingOrder );
00156 
00157   //clear and rebuild rowIdMap. Overwrite sortColumn later and sort rowIdMap there
00158   rowIdMap.clear();
00159   int id;
00160   for ( int i = 0; i < rowCount(); i++ )
00161   {
00162     id = item( i, 0 )->text().toInt();
00163     rowIdMap.insert( id, i );
00164   }
00165 
00166   disconnect( this, SIGNAL( itemSelectionChanged() ), this, SLOT( handleChangedSelections() ) );
00167   clearSelection();
00168 
00169   //select the rows again after sorting
00170 
00171   QList < int >::iterator it;
00172   for ( it = idsOfSelected.begin(); it != idsOfSelected.end(); ++it )
00173   {
00174     selectRowWithId(( *it ) );
00175   }
00176   connect( this, SIGNAL( itemSelectionChanged() ), this, SLOT( handleChangedSelections() ) );
00177 
00178   QApplication::restoreOverrideCursor();
00179 }
00180 
00181 void QgsAttributeTable::keyPressEvent( QKeyEvent * ev )
00182 {
00183   if ( ev->key() == Qt::Key_Control || ev->key() == Qt::Key_Shift )
00184   {
00185     lockKeyPressed = true;
00186   }
00187 }
00188 
00189 void QgsAttributeTable::keyReleaseEvent( QKeyEvent * ev )
00190 {
00191   if ( ev->key() == Qt::Key_Control || ev->key() == Qt::Key_Shift )
00192   {
00193     lockKeyPressed = false;
00194   }
00195 }
00196 
00197 void QgsAttributeTable::handleChangedSelections()
00198 {
00199   emit selectionRemoved( false );
00200 
00201   QList<QTableWidgetSelectionRange> selectedItemRanges = selectedRanges();
00202   QList<QTableWidgetSelectionRange>::const_iterator range_it = selectedItemRanges.constBegin();
00203   for ( ; range_it != selectedItemRanges.constEnd(); ++range_it )
00204   {
00205     for ( int index = range_it->topRow(); index <= range_it->bottomRow(); index++ )
00206     {
00207       emit selected( item( index, 0 )->text().toInt(), false );
00208     }
00209   }
00210 
00211   //don't send the signal repaintRequested() from here
00212   //but in mouseReleaseEvent() and rowClicked(int)
00213   //todo: don't repaint in case of double clicks
00214 }
00215 
00216 void QgsAttributeTable::insertFeatureId( int id, int row )
00217 {
00218   rowIdMap.insert( id, row );
00219 }
00220 
00221 void QgsAttributeTable::selectRowWithId( int id )
00222 {
00223   QMap < int, int >::iterator it = rowIdMap.find( id );
00224   setRangeSelected( QTableWidgetSelectionRange( it.value(), 0, it.value(), columnCount() - 1 ), true );
00225 }
00226 
00227 void QgsAttributeTable::sortColumn( int col, bool ascending )
00228 {
00229   int type = horizontalHeaderItem( col )->data( QgsAttributeTable::AttributeType ).toInt();
00230   qsort( 0, rowCount() - 1, col, ascending, type != QVariant::Int && type != QVariant::Double );
00231 }
00232 
00233 
00237 int QgsAttributeTable::compareItems( QString s1, QString s2, bool ascending, bool alphanumeric )
00238 {
00239   if ( alphanumeric )
00240   {
00241     if ( s1 > s2 )
00242     {
00243       if ( ascending )
00244       {
00245         return 1;
00246       }
00247       else
00248       {
00249         return -1;
00250       }
00251     }
00252     else if ( s1 < s2 )
00253     {
00254       if ( ascending )
00255       {
00256         return -1;
00257       }
00258       else
00259       {
00260         return 1;
00261       }
00262     }
00263     else if ( s1 == s2 )
00264     {
00265       return 0;
00266     }
00267   }
00268   else                        //numeric
00269   {
00270     double d1 = s1.toDouble();
00271     double d2 = s2.toDouble();
00272     if ( d1 > d2 )
00273     {
00274       if ( ascending )
00275       {
00276         return 1;
00277       }
00278       else
00279       {
00280         return -1;
00281       }
00282     }
00283     else if ( d1 < d2 )
00284     {
00285       if ( ascending )
00286       {
00287         return -1;
00288       }
00289       else
00290       {
00291         return 1;
00292       }
00293     }
00294     else if ( d1 == d2 )
00295     {
00296       return 0;
00297     }
00298   }
00299 
00300   return 0;                     // XXX has to return something; is this reasonable?
00301 }
00302 
00303 void QgsAttributeTable::qsort( int lower, int upper, int col, bool ascending, bool alphanumeric )
00304 {
00305   int i, j;
00306   QString v;
00307   if ( upper > lower )
00308   {
00309     //chose a random element (this avoids n^2 worst case)
00310     int element = int (( double )rand() / ( double )RAND_MAX * ( upper - lower ) + lower );
00311     swapRows( element, upper );
00312     v = item( upper, col )->text();
00313     i = lower - 1;
00314     j = upper;
00315     for ( ;; )
00316     {
00317       while ( compareItems( item( ++i, col )->text(), v, ascending, alphanumeric ) == -1 )
00318         ;
00319       while ( compareItems( item( --j, col )->text(), v, ascending, alphanumeric ) == 1 && j > 0 ); //make sure that j does not get negative
00320       if ( i >= j )
00321       {
00322         break;
00323       }
00324       swapRows( i, j );
00325     }
00326     swapRows( i, upper );
00327     qsort( lower, i - 1, col, ascending, alphanumeric );
00328     qsort( i + 1, upper, col, ascending, alphanumeric );
00329   }
00330 }
00331 
00332 void QgsAttributeTable::swapRows( int row1, int row2 )
00333 {
00334   for ( int col = 0; col < columnCount(); col++ )
00335   {
00336     QTableWidgetItem *item = takeItem( row1, col );
00337     setItem( row1, col, takeItem( row2, col ) );
00338     setItem( row2, col, item );
00339   }
00340 }
00341 
00342 void QgsAttributeTable::contextMenuEvent( QContextMenuEvent *event )
00343 {
00344   const QPoint& pos = event->globalPos();
00345   int row = rowAt( pos.x() );
00346   int col = columnAt( pos.y() );
00347 
00348   // Duplication of code in qgsidentufyresults.cpp. Consider placing
00349   // in a seperate class
00350   if ( mActionPopup == 0 )
00351   {
00352     mActionPopup = new QMenu();
00353     mActionPopup->addAction( tr( "Run action" ) );
00354     mActionPopup->addSeparator();
00355 
00356     QgsAttributeAction::aIter iter = mActions.begin();
00357     for ( int j = 0; iter != mActions.end(); ++iter, ++j )
00358     {
00359       QAction* a = mActionPopup->addAction( iter->name() );
00360       // The menu action stores an integer that is used later on to
00361       // associate an menu action with an actual qgis action.
00362       a->setData( QVariant::fromValue( j ) );
00363     }
00364     connect( mActionPopup, SIGNAL( triggered( QAction* ) ),
00365              this, SLOT( popupItemSelected( QAction* ) ) );
00366   }
00367 
00368   // Get and store the attribute values and their column names are
00369   // these are needed for substituting into the actions if the user
00370   // chooses one.
00371   mActionValues.clear();
00372 
00373   for ( int i = 0; i < columnCount(); ++i )
00374   {
00375     if ( row >= 0 ) //prevent crash if row is negative, see ticket #1149
00376     {
00377       mActionValues.push_back(
00378         std::make_pair(
00379           horizontalHeaderItem( i )->text(),
00380           item( row, i )->text() ) );
00381     }
00382   }
00383   // The item that was clicked on, stored as an index into the
00384   // mActionValues vector.
00385   mClickedOnValue = col;
00386 
00387   if ( mActions.size() > 0 )
00388     mActionPopup->popup( pos );
00389 }
00390 
00391 void QgsAttributeTable::popupItemSelected( QAction* menuAction )
00392 {
00393   int id = menuAction->data().toInt();
00394   mActions.doAction( id, mActionValues, mClickedOnValue );
00395 }
00396 
00397 /* Deprecated: See QgisApp::editCopy() instead */
00398 void QgsAttributeTable::copySelectedRows()
00399 {
00400   // Copy selected rows to the clipboard
00401 
00402   QString toClipboard;
00403   const char fieldSep = '\t';
00404 
00405   // Pick up the headers first
00406   for ( int i = 0; i < columnCount(); ++i )
00407     toClipboard += horizontalHeaderItem( i )->text() + fieldSep;
00408   toClipboard += '\n';
00409 
00410   QList<QTableWidgetSelectionRange> selection = selectedRanges();
00411   // Then populate with the cell contents
00412   for ( int i = 0; i < selection.count(); ++i )
00413   {
00414     QTableWidgetSelectionRange sel = selection.at( i );
00415     for ( int row = sel.topRow(); row < sel.topRow() + sel.rowCount(); ++row )
00416     {
00417       for ( int column = 0; column < columnCount(); ++column )
00418         toClipboard += item( row, column )->text() + fieldSep;
00419       toClipboard += '\n';
00420     }
00421   }
00422 #ifdef QGISDEBUG
00423   std::cerr << "Selected data in table is:\n" << toClipboard.data(); // OK
00424 #endif
00425   // And then copy to the clipboard
00426   QClipboard* clipboard = QApplication::clipboard();
00427 
00428   // With qgis running under Linux, but with a Windows based X
00429   // server (Xwin32), ::Selection was necessary to get the data into
00430   // the Windows clipboard (which seems contrary to the Qt
00431   // docs). With a Linux X server, ::Clipboard was required.
00432   // The simple solution was to put the text into both clipboards.
00433 
00434   // The ::Selection setText() below one may need placing inside so
00435   // #ifdef so that it doesn't get compiled under Windows.
00436   clipboard->setText( toClipboard, QClipboard::Selection );
00437   clipboard->setText( toClipboard, QClipboard::Clipboard );
00438 }
00439 
00440 void QgsAttributeTable::fillTable( QgsVectorLayer *layer )
00441 {
00442   blockSignals( true );
00443 
00444   const QgsFieldMap &fields = layer->pendingFields();
00445 
00446   // set up the column headers
00447   setColumnCount( fields.size() + 1 );
00448 
00449   setHorizontalHeaderItem( 0, new QTableWidgetItem( "id" ) ); //label for the id-column
00450 
00451   int h = 1;
00452   for ( QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt != fields.end(); fldIt++, h++ )
00453   {
00454     QgsDebugMsg( QString( "%1: field %2: %3 | %4" )
00455                  .arg( h ).arg( fldIt.key() ).arg( fldIt->name() ).arg( QVariant::typeToName( fldIt->type() ) ) );
00456 
00457     QTableWidgetItem *twi = new QTableWidgetItem( fldIt->name() );
00458     twi->setData( AttributeIndex, fldIt.key() );
00459     twi->setData( AttributeName, fldIt->name() );
00460     twi->setData( AttributeType, fldIt->type() );
00461     setHorizontalHeaderItem( h, twi );
00462 
00463     mAttrIdxMap.insert( fldIt.key(), h );
00464   }
00465 
00466   QgsFeatureList features;
00467   if ( layer->selectedFeatureCount() == 0 )
00468   {
00469     layer->select( layer->pendingAllAttributesList(), QgsRect(), false );
00470 
00471     QgsFeature f;
00472     while ( layer->nextFeature( f ) )
00473       features << f;
00474   }
00475   else
00476   {
00477     features = layer->selectedFeatures();
00478   }
00479 
00480   setRowCount( features.size() );
00481 
00482   for ( int i = 0; i < features.size(); i++ )
00483     putFeatureInTable( i, features[i] );
00484 
00485   // Default row height is too tall
00486   resizeRowsToContents();
00487 
00488   // Make each column wide enough to show all the contents
00489   for ( int i = 0; i < columnCount(); i++ )
00490     resizeColumnToContents( i );
00491 
00492   blockSignals( false );
00493 }
00494 
00495 void QgsAttributeTable::putFeatureInTable( int row, const QgsFeature& fet )
00496 {
00497   // Prevent a crash if a provider doesn't update the feature count properly
00498   if ( row >= rowCount() )
00499   {
00500     setRowCount( row + 1 );
00501   }
00502 
00503   //id-field
00504   int id = fet.id();
00505   QTableWidgetItem *twi = new QTableWidgetItem( QString::number( id ) );
00506   twi->setTextAlignment( Qt::AlignRight | Qt::AlignVCenter );
00507   setItem( row, 0, twi );
00508   insertFeatureId( id, row );  //insert the id into the search tree of qgsattributetable
00509 
00510   const QgsAttributeMap& attr = fet.attributeMap();
00511 
00512   for ( QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it )
00513   {
00514     if ( !mAttrIdxMap.contains( it.key() ) )
00515       continue;
00516 
00517     int h = mAttrIdxMap[ it.key()];
00518 
00519     twi = horizontalHeaderItem( h );
00520     if ( !twi )
00521     {
00522       QgsDebugMsg( "header item not found." );
00523       continue;
00524     }
00525 
00526     int type = twi->data( AttributeType ).toInt();
00527     bool isNum = ( type == QVariant::Double || type == QVariant::Int );
00528 
00529     QString value;
00530     // get the field values
00531     if ( it->isNull() )
00532     {
00533       if ( isNum )
00534         value = "";
00535       else
00536         value = "NULL";
00537     }
00538     else
00539     {
00540       value = it->toString();
00541     }
00542 
00543     twi = new QTableWidgetItem( value );
00544     if ( isNum )
00545       twi->setTextAlignment( Qt::AlignRight | Qt::AlignVCenter );
00546     setItem( row, h, twi );
00547   }
00548 }
00549 
00550 void QgsAttributeTable::bringSelectedToTop()
00551 {
00552   blockSignals( true );
00553   horizontalHeader()->setSortIndicatorShown( false );
00554   mPreviousSortIndicatorColumn = -1;
00555   int swaptorow = 0;
00556   QList<QTableWidgetSelectionRange> selections = selectedRanges();
00557   bool removeselection;
00558 
00559   for ( QList<QTableWidgetSelectionRange>::iterator iter = selections.begin();iter != selections.end();++iter )
00560   {
00561     removeselection = true;
00562     while ( swaptorow < rowCount() && item( swaptorow, 0 )->isSelected() )//selections are not necessary stored in ascending order
00563     {
00564       ++swaptorow;
00565     }
00566 
00567     for ( int j = iter->topRow();j <= iter->bottomRow();++j )
00568     {
00569       if ( j > swaptorow )//selections are not necessary stored in ascending order
00570       {
00571         swapRows( j, swaptorow );
00572         setRangeSelected( QTableWidgetSelectionRange( swaptorow, 0, swaptorow, columnCount() - 1 ), true );
00573         ++swaptorow;
00574 
00575       }
00576       else
00577       {
00578         removeselection = false;//keep selection
00579       }
00580     }
00581     if ( removeselection )
00582     {
00583       setRangeSelected( *iter, false );
00584     }
00585   }
00586 
00587   //clear and rebuild rowIdMap.
00588   rowIdMap.clear();
00589   int id;
00590   for ( int i = 0; i < rowCount(); i++ )
00591   {
00592     id = item( i, 0 )->text().toInt();
00593     rowIdMap.insert( id, i );
00594   }
00595 
00596   blockSignals( false );
00597 }
00598 
00599 void QgsAttributeTable::selectRowsWithId( const QgsFeatureIds& ids )
00600 {
00601   /*
00602   // if selecting rows takes too much time we can use progress dialog
00603   QProgressDialog progress( tr("Updating selection..."), tr("Abort"), 0, mSelected.size(), tabledisplay);
00604   int i=0;
00605   for(std::set<int>::iterator iter=mSelected.begin();iter!=mSelected.end();++iter)
00606   {
00607     ++i;
00608     progress.setValue(i);
00609     qApp->processEvents();
00610     if(progress.wasCanceled())
00611     {
00612       //deselect the remaining features if action was canceled
00613       mSelected.erase(iter,--mSelected.end());
00614       break;
00615       }
00616     selectRowWithId(*iter);//todo: avoid that the table gets repainted during each selection
00617   }
00618   */
00619 
00620 
00621   // to select more rows at once effectively, we stop sending signals to handleChangedSelections()
00622   // otherwise it will repaint map everytime row is selected
00623 
00624   disconnect( this, SIGNAL( itemSelectionChanged() ), this, SLOT( handleChangedSelections() ) );
00625 
00626   clearSelection();
00627   QgsFeatureIds::const_iterator it;
00628   for ( it = ids.begin(); it != ids.end(); it++ )
00629   {
00630     selectRowWithId( *it );
00631   }
00632 
00633   connect( this, SIGNAL( itemSelectionChanged() ), this, SLOT( handleChangedSelections() ) );
00634   emit repaintRequested();
00635 }
00636 
00637 void QgsAttributeTable::showRowsWithId( const QgsFeatureIds& ids )
00638 {
00639   setUpdatesEnabled( false );
00640 
00641   // hide all rows first
00642   for ( int i = 0; i < rowCount(); i++ )
00643     hideRow( i );
00644 
00645   // show only matching rows
00646   QgsFeatureIds::const_iterator it;
00647   for ( it = ids.begin(); it != ids.end(); it++ )
00648   {
00649     showRow( rowIdMap[*it] );
00650   }
00651 
00652   clearSelection(); // deselect all
00653   setUpdatesEnabled( true );
00654 }
00655 
00656 void QgsAttributeTable::showAllRows()
00657 {
00658   for ( int i = 0; i < rowCount(); i++ )
00659     showRow( i );
00660 }
00661 
00662 void QgsAttributeTable::rowClicked( int row )
00663 {
00664   if ( checkSelectionChanges() )//only repaint the canvas if the selection has changed
00665   {
00666     emit repaintRequested();
00667   }
00668 }
00669 
00670 void QgsAttributeTable::mouseReleaseEvent( QMouseEvent* e )
00671 {
00672   QTableWidget::mouseReleaseEvent( e );
00673   if ( checkSelectionChanges() )//only repaint the canvas if the selection has changed
00674   {
00675     emit repaintRequested();
00676   }
00677 }
00678 
00679 bool QgsAttributeTable::checkSelectionChanges()
00680 {
00681   std::set<int> theCurrentSelection;
00682   QList<QTableWidgetSelectionRange> selectedItemRanges = selectedRanges();
00683   QList<QTableWidgetSelectionRange>::const_iterator range_it = selectedItemRanges.constBegin();
00684   for ( ; range_it != selectedItemRanges.constEnd(); ++range_it )
00685   {
00686     for ( int index = range_it->topRow(); index <= range_it->bottomRow(); index++ )
00687     {
00688       theCurrentSelection.insert( index );
00689     }
00690   }
00691 
00692   if ( theCurrentSelection == mLastSelectedRows )
00693   {
00694     return false;
00695   }
00696   else
00697   {
00698     mLastSelectedRows = theCurrentSelection;
00699     return true;
00700   }
00701 }
00702 
00703 void QgsAttributeTable::attributeValueChanged( int fid, int idx, const QVariant &value )
00704 {
00705   if ( !rowIdMap.contains( fid ) )
00706     return;
00707 
00708   if ( !mAttrIdxMap.contains( idx ) )
00709     return;
00710 
00711   QTableWidgetItem *twi = horizontalHeaderItem( mAttrIdxMap[ idx ] );
00712   if ( !twi )
00713   {
00714     QgsDebugMsg( "header item not found." );
00715     return;
00716   }
00717 
00718   int type = twi->data( AttributeType ).toInt();
00719   bool isNum = ( type == QVariant::Double || type == QVariant::Int );
00720 
00721   QString v;
00722   // get the field values
00723   if ( value.isNull() )
00724   {
00725     if ( isNum )
00726       v = "";
00727     else
00728       v = "NULL";
00729   }
00730   else
00731   {
00732     v = value.toString();
00733   }
00734 
00735   item( rowIdMap[fid], mAttrIdxMap[idx] )->setText( v );
00736 }
00737 
00738 void QgsAttributeTable::featureDeleted( int fid )
00739 {
00740   if ( !rowIdMap.contains( fid ) )
00741     return;
00742 
00743   int row = rowIdMap[fid];
00744 
00745   removeRow( row );
00746 
00747   for ( QMap<int, int>::iterator it = rowIdMap.begin(); it != rowIdMap.end(); it++ )
00748     if ( it.value() > row )
00749       rowIdMap[ it.key()]--;
00750 }
00751 
00752 void QgsAttributeTable::addAttribute( int attr, const QgsField &fld )
00753 {
00754   QTableWidgetItem *twi = new QTableWidgetItem( fld.name() );
00755   twi->setData( AttributeIndex, attr );
00756   twi->setData( AttributeName, fld.name() );
00757   twi->setData( AttributeType, fld.type() );
00758 
00759   insertColumn( columnCount() );
00760   setHorizontalHeaderItem( columnCount() - 1, twi );
00761 
00762   mAttrIdxMap.insert( attr, columnCount() - 1 );
00763 }
00764 
00765 void QgsAttributeTable::deleteAttribute( int attr )
00766 {
00767   int column = mAttrIdxMap[attr];
00768 
00769   removeColumn( column );
00770   mAttrIdxMap.remove( attr );
00771   for ( QMap<int, int>::iterator it = mAttrIdxMap.begin(); it != mAttrIdxMap.end(); it++ )
00772   {
00773     if ( it.value() > column )
00774       mAttrIdxMap[ it.key()]--;
00775   }
00776 }

Generated on Tue Oct 28 16:51:25 2008 for Quantum GIS API Documentation by  doxygen 1.5.1