QGIS API Documentation  2.9.0-Master
qgsattributetableview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  QgsAttributeTableView.cpp
3  --------------------------------------
4  Date : Feb 2009
5  Copyright : (C) 2009 Vita Cizek
6  Email : weetya (at) gmail.com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QKeyEvent>
17 #include <QSettings>
18 #include <QHeaderView>
19 #include <QMenu>
20 
21 #include "qgsattributetableview.h"
22 #include "qgsattributetablemodel.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsvectorlayercache.h"
28 #include "qgsvectordataprovider.h"
29 #include "qgslogger.h"
30 #include "qgsmapcanvas.h"
32 
34  : QTableView( parent )
35  , mMasterModel( NULL )
36  , mFilterModel( NULL )
37  , mFeatureSelectionModel( NULL )
38  , mFeatureSelectionManager( NULL )
39  , mModel( NULL )
40  , mActionPopup( NULL )
41  , mLayerCache( NULL )
42  , mRowSectionAnchor( 0 )
43  , mCtrlDragSelectionFlag( QItemSelectionModel::Select )
44 {
45  QSettings settings;
46  restoreGeometry( settings.value( "/BetterAttributeTable/geometry" ).toByteArray() );
47 
48  //verticalHeader()->setDefaultSectionSize( 20 );
49  horizontalHeader()->setHighlightSections( false );
50 
51  mTableDelegate = new QgsAttributeTableDelegate( this );
52  setItemDelegate( mTableDelegate );
53 
54  setSelectionBehavior( QAbstractItemView::SelectRows );
55  setSelectionMode( QAbstractItemView::ExtendedSelection );
56  setSortingEnabled( true );
57 
58  verticalHeader()->viewport()->installEventFilter( this );
59 
60  connect( verticalHeader(), SIGNAL( sectionPressed( int ) ), this, SLOT( selectRow( int ) ) );
61  connect( verticalHeader(), SIGNAL( sectionEntered( int ) ), this, SLOT( _q_selectRow( int ) ) );
62 }
63 
65 {
66  delete mActionPopup;
67 }
68 #if 0
69 void QgsAttributeTableView::setCanvasAndLayerCache( QgsMapCanvas *canvas, QgsVectorLayerCache *layerCache )
70 {
71  QgsAttributeTableModel* oldModel = mMasterModel;
72  QgsAttributeTableFilterModel* filterModel = mFilterModel;
73 
74  mMasterModel = new QgsAttributeTableModel( layerCache, this );
75 
76  mLayerCache = layerCache;
77 
78  mMasterModel->loadLayer();
79 
80  mFilterModel = new QgsAttributeTableFilterModel( canvas, mMasterModel, mMasterModel );
81  setModel( mFilterModel );
82  delete mFeatureSelectionModel;
83  mFeatureSelectionModel = new QgsFeatureSelectionModel( mFilterModel, mFilterModel, new QgsVectorLayerSelectionManager( layerCache->layer(), mFilterModel ), mFilterModel );
84  connect( mFeatureSelectionModel, SIGNAL( requestRepaint( QModelIndexList ) ), this, SLOT( repaintRequested( QModelIndexList ) ) );
85  connect( mFeatureSelectionModel, SIGNAL( requestRepaint() ), this, SLOT( repaintRequested() ) );
86  setSelectionModel( mFeatureSelectionModel );
87 
88  delete oldModel;
89  delete filterModel;
90 }
91 #endif
92 bool QgsAttributeTableView::eventFilter( QObject *object, QEvent *event )
93 {
94  if ( object == verticalHeader()->viewport() )
95  {
96  switch ( event->type() )
97  {
98  case QEvent::MouseButtonPress:
99  mFeatureSelectionModel->enableSync( false );
100  break;
101 
102  case QEvent::MouseButtonRelease:
103  mFeatureSelectionModel->enableSync( true );
104  break;
105 
106  default:
107  break;
108  }
109  }
110  return false;
111 }
112 
114 {
115  if ( mFilterModel )
116  {
117  // Cleanup old model stuff if present
118  disconnect( mFilterModel, SIGNAL( filterAboutToBeInvalidated() ), this, SLOT( onFilterAboutToBeInvalidated() ) );
119  disconnect( mFilterModel, SIGNAL( filterInvalidated() ), this, SLOT( onFilterInvalidated() ) );
120  }
121 
122  mFilterModel = filterModel;
123  QTableView::setModel( filterModel );
124 
125  connect( mFilterModel, SIGNAL( destroyed() ), this, SLOT( modelDeleted() ) );
126 
127  delete mFeatureSelectionModel;
128  mFeatureSelectionModel = 0;
129 
130  if ( filterModel )
131  {
132  if ( !mFeatureSelectionManager )
133  {
134  mFeatureSelectionManager = new QgsVectorLayerSelectionManager( mFilterModel->layer(), mFilterModel );
135  }
136 
137  mFeatureSelectionModel = new QgsFeatureSelectionModel( mFilterModel, mFilterModel, mFeatureSelectionManager, mFilterModel );
138  setSelectionModel( mFeatureSelectionModel );
139  mTableDelegate->setFeatureSelectionModel( mFeatureSelectionModel );
140  connect( mFeatureSelectionModel, SIGNAL( requestRepaint( QModelIndexList ) ), this, SLOT( repaintRequested( QModelIndexList ) ) );
141  connect( mFeatureSelectionModel, SIGNAL( requestRepaint() ), this, SLOT( repaintRequested() ) );
142  }
143 }
144 
146 {
147  if ( mFeatureSelectionManager )
148  delete mFeatureSelectionManager;
149 
150  mFeatureSelectionManager = featureSelectionManager;
151 
152  if ( mFeatureSelectionModel )
153  mFeatureSelectionModel->setFeatureSelectionManager( mFeatureSelectionManager );
154 }
155 
156 void QgsAttributeTableView::closeEvent( QCloseEvent *e )
157 {
158  Q_UNUSED( e );
159  QSettings settings;
160  settings.setValue( "/BetterAttributeTable/geometry", QVariant( saveGeometry() ) );
161 }
162 
163 void QgsAttributeTableView::mousePressEvent( QMouseEvent *event )
164 {
165  setSelectionMode( QAbstractItemView::NoSelection );
166  QTableView::mousePressEvent( event );
167  setSelectionMode( QAbstractItemView::ExtendedSelection );
168 }
169 
171 {
172  setSelectionMode( QAbstractItemView::NoSelection );
173  QTableView::mouseReleaseEvent( event );
174  setSelectionMode( QAbstractItemView::ExtendedSelection );
175 }
176 
177 void QgsAttributeTableView::mouseMoveEvent( QMouseEvent *event )
178 {
179  setSelectionMode( QAbstractItemView::NoSelection );
180  QTableView::mouseMoveEvent( event );
181  setSelectionMode( QAbstractItemView::ExtendedSelection );
182 }
183 
184 void QgsAttributeTableView::keyPressEvent( QKeyEvent *event )
185 {
186  switch ( event->key() )
187  {
188 
189  // Default Qt behavior would be to change the selection.
190  // We don't make it that easy for the user to trash his selection.
191  case Qt::Key_Up:
192  case Qt::Key_Down:
193  case Qt::Key_Left:
194  case Qt::Key_Right:
195  setSelectionMode( QAbstractItemView::NoSelection );
196  QTableView::keyPressEvent( event );
197  setSelectionMode( QAbstractItemView::ExtendedSelection );
198  break;
199 
200  default:
201  QTableView::keyPressEvent( event );
202  break;
203  }
204 }
205 
206 void QgsAttributeTableView::repaintRequested( QModelIndexList indexes )
207 {
208  foreach ( const QModelIndex index, indexes )
209  {
210  update( index );
211  }
212 }
213 
215 {
216  setDirtyRegion( viewport()->rect() );
217 }
218 
220 {
221  QItemSelection selection;
222  selection.append( QItemSelectionRange( mFilterModel->index( 0, 0 ), mFilterModel->index( mFilterModel->rowCount() - 1, 0 ) ) );
223  mFeatureSelectionModel->selectFeatures( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
224 }
225 
226 void QgsAttributeTableView::contextMenuEvent( QContextMenuEvent* event )
227 {
228  delete mActionPopup;
229  mActionPopup = 0;
230 
231  QModelIndex idx = indexAt( event->pos() );
232  if ( !idx.isValid() )
233  {
234  return;
235  }
236 
237  QgsVectorLayer *vlayer = mFilterModel->layer();
238  if ( !vlayer )
239  return;
240 
241  mActionPopup = new QMenu();
242 
243  mActionPopup->addAction( tr( "Select All" ), this, SLOT( selectAll() ), QKeySequence::SelectAll );
244 
245  // let some other parts of the application add some actions
246  emit willShowContextMenu( mActionPopup, idx );
247 
248  if ( mActionPopup->actions().count() > 0 )
249  {
250  mActionPopup->popup( event->globalPos() );
251  }
252 }
253 
255 {
256  selectRow( row, true );
257 }
258 
260 {
261  selectRow( row, false );
262 }
263 
264 void QgsAttributeTableView::modelDeleted()
265 {
266  mFilterModel = 0;
267  mFeatureSelectionManager = 0;
268  mFeatureSelectionModel = 0;
269 }
270 
271 void QgsAttributeTableView::selectRow( int row, bool anchor )
272 {
273  if ( selectionBehavior() == QTableView::SelectColumns
274  || ( selectionMode() == QTableView::SingleSelection
275  && selectionBehavior() == QTableView::SelectItems ) )
276  return;
277 
278  if ( row >= 0 && row < model()->rowCount() )
279  {
280  int column = horizontalHeader()->logicalIndexAt( isRightToLeft() ? viewport()->width() : 0 );
281  QModelIndex index = model()->index( row, column );
282  QItemSelectionModel::SelectionFlags command = selectionCommand( index );
283  selectionModel()->setCurrentIndex( index, QItemSelectionModel::NoUpdate );
284  if (( anchor && !( command & QItemSelectionModel::Current ) )
285  || ( selectionMode() == QTableView::SingleSelection ) )
286  mRowSectionAnchor = row;
287 
288  if ( selectionMode() != QTableView::SingleSelection
289  && command.testFlag( QItemSelectionModel::Toggle ) )
290  {
291  if ( anchor )
292  mCtrlDragSelectionFlag = mFeatureSelectionModel->isSelected( index )
293  ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
294  command &= ~QItemSelectionModel::Toggle;
295  command |= mCtrlDragSelectionFlag;
296  if ( !anchor )
297  command |= QItemSelectionModel::Current;
298  }
299 
300  QModelIndex tl = model()->index( qMin( mRowSectionAnchor, row ), 0 );
301  QModelIndex br = model()->index( qMax( mRowSectionAnchor, row ), model()->columnCount() - 1 );
302  if ( verticalHeader()->sectionsMoved() && tl.row() != br.row() )
303  setSelection( visualRect( tl ) | visualRect( br ), command );
304  else
305  mFeatureSelectionModel->selectFeatures( QItemSelection( tl, br ), command );
306  }
307 }
static unsigned index
virtual bool isSelected(QgsFeatureId fid)
Returns the selection status of a given feature id.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before basing any other models on this model...
QgsVectorLayer * layer()
Returns the layer to which this cache belongs.
virtual bool eventFilter(QObject *object, QEvent *event) override
This event filter is installed on the verticalHeader to intercept mouse press and release events...
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
virtual void selectAll() override
void enableSync(bool enable)
Enables or disables synchronisation to the QgsVectorLayer When synchronisation is disabled...
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:105
void setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)
void mouseReleaseEvent(QMouseEvent *event) override
Called for mouse release events on a table cell.
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
QgsAttributeTableView(QWidget *parent=0)
virtual void selectFeatures(const QItemSelection &selection, SelectionFlags command)
Select features on this table.
void mousePressEvent(QMouseEvent *event) override
Called for mouse press events on a table cell.
virtual void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
virtual void setModel(QgsAttributeTableFilterModel *filterModel)
void willShowContextMenu(QMenu *menu, QModelIndex atIndex)
Is emitted, in order to provide a hook to add aditional menu entries to the context menu...
This class caches features of a given QgsVectorLayer.
void mouseMoveEvent(QMouseEvent *event) override
Called for mouse move events on a table cell.
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
setFeatureSelectionManager
A delegate item class for QgsAttributeTable (see Qt documentation for QItemDelegate).
virtual void selectRow(int row)
virtual void _q_selectRow(int row)
Is an interface class to abstract feature selection handling.
void closeEvent(QCloseEvent *event) override
Saves geometry to the settings on close.
Represents a vector layer which manages a vector based data sets.
void keyPressEvent(QKeyEvent *event) override
Called for key press events Disables selection change by only pressing an arrow key.
void contextMenuEvent(QContextMenuEvent *event) override
Is called when the context menu will be shown.
#define tr(sourceText)