QGIS API Documentation  2.13.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( nullptr )
36  , mFilterModel( nullptr )
37  , mFeatureSelectionModel( nullptr )
38  , mFeatureSelectionManager( nullptr )
39  , mModel( nullptr )
40  , mActionPopup( nullptr )
41  , mLayerCache( nullptr )
42  , mRowSectionAnchor( 0 )
43  , mCtrlDragSelectionFlag( QItemSelectionModel::Select )
44 {
45  QSettings settings;
46  restoreGeometry( settings.value( "/BetterAttributeTable/geometry" ).toByteArray() );
47 
48  //verticalHeader()->setDefaultSectionSize( 20 );
50 
51  mTableDelegate = new QgsAttributeTableDelegate( this );
52  setItemDelegate( mTableDelegate );
53 
54  setSelectionBehavior( QAbstractItemView::SelectRows );
55  setSelectionMode( QAbstractItemView::ExtendedSelection );
56  setSortingEnabled( true ); // At this point no data is in the model yet, so actually nothing is sorted.
57  horizontalHeader()->setSortIndicatorShown( false ); // So hide the indicator to avoid confusion.
58 
60 
61  connect( verticalHeader(), SIGNAL( sectionPressed( int ) ), this, SLOT( selectRow( int ) ) );
62  connect( verticalHeader(), SIGNAL( sectionEntered( int ) ), this, SLOT( _q_selectRow( int ) ) );
63  connect( horizontalHeader(), SIGNAL( sortIndicatorChanged( int, Qt::SortOrder ) ), this, SLOT( showHorizontalSortIndicator() ) );
64 }
65 
67 {
68  delete mActionPopup;
69 }
70 
72 {
73  if ( object == verticalHeader()->viewport() )
74  {
75  switch ( event->type() )
76  {
77  case QEvent::MouseButtonPress:
78  mFeatureSelectionModel->enableSync( false );
79  break;
80 
81  case QEvent::MouseButtonRelease:
82  mFeatureSelectionModel->enableSync( true );
83  break;
84 
85  default:
86  break;
87  }
88  }
89  return false;
90 }
91 
93 {
94  if ( mFilterModel )
95  {
96  // Cleanup old model stuff if present
97  disconnect( mFilterModel, SIGNAL( filterAboutToBeInvalidated() ), this, SLOT( onFilterAboutToBeInvalidated() ) );
98  disconnect( mFilterModel, SIGNAL( filterInvalidated() ), this, SLOT( onFilterInvalidated() ) );
99  }
100 
101  mFilterModel = filterModel;
102  QTableView::setModel( filterModel );
103 
104  connect( mFilterModel, SIGNAL( destroyed() ), this, SLOT( modelDeleted() ) );
105 
106  delete mFeatureSelectionModel;
107  mFeatureSelectionModel = nullptr;
108 
109  if ( filterModel )
110  {
111  if ( !mFeatureSelectionManager )
112  {
113  mFeatureSelectionManager = new QgsVectorLayerSelectionManager( mFilterModel->layer(), mFilterModel );
114  }
115 
116  mFeatureSelectionModel = new QgsFeatureSelectionModel( mFilterModel, mFilterModel, mFeatureSelectionManager, mFilterModel );
117  setSelectionModel( mFeatureSelectionModel );
118  mTableDelegate->setFeatureSelectionModel( mFeatureSelectionModel );
119  connect( mFeatureSelectionModel, SIGNAL( requestRepaint( QModelIndexList ) ), this, SLOT( repaintRequested( QModelIndexList ) ) );
120  connect( mFeatureSelectionModel, SIGNAL( requestRepaint() ), this, SLOT( repaintRequested() ) );
121  }
122 }
123 
125 {
126  if ( mFeatureSelectionManager )
127  delete mFeatureSelectionManager;
128 
129  mFeatureSelectionManager = featureSelectionManager;
130 
131  if ( mFeatureSelectionModel )
132  mFeatureSelectionModel->setFeatureSelectionManager( mFeatureSelectionManager );
133 }
134 
136 {
137  Q_UNUSED( e );
138  QSettings settings;
139  settings.setValue( "/BetterAttributeTable/geometry", QVariant( saveGeometry() ) );
140 }
141 
143 {
144  setSelectionMode( QAbstractItemView::NoSelection );
146  setSelectionMode( QAbstractItemView::ExtendedSelection );
147 }
148 
150 {
151  setSelectionMode( QAbstractItemView::NoSelection );
153  setSelectionMode( QAbstractItemView::ExtendedSelection );
154 }
155 
157 {
158  setSelectionMode( QAbstractItemView::NoSelection );
160  setSelectionMode( QAbstractItemView::ExtendedSelection );
161 }
162 
164 {
165  switch ( event->key() )
166  {
167 
168  // Default Qt behavior would be to change the selection.
169  // We don't make it that easy for the user to trash his selection.
170  case Qt::Key_Up:
171  case Qt::Key_Down:
172  case Qt::Key_Left:
173  case Qt::Key_Right:
174  setSelectionMode( QAbstractItemView::NoSelection );
175  QTableView::keyPressEvent( event );
176  setSelectionMode( QAbstractItemView::ExtendedSelection );
177  break;
178 
179  default:
180  QTableView::keyPressEvent( event );
181  break;
182  }
183 }
184 
185 void QgsAttributeTableView::repaintRequested( const QModelIndexList& indexes )
186 {
187  Q_FOREACH ( const QModelIndex& index, indexes )
188  {
189  update( index );
190  }
191 }
192 
194 {
195  setDirtyRegion( viewport()->rect() );
196 }
197 
199 {
200  QItemSelection selection;
201  selection.append( QItemSelectionRange( mFilterModel->index( 0, 0 ), mFilterModel->index( mFilterModel->rowCount() - 1, 0 ) ) );
202  mFeatureSelectionModel->selectFeatures( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
203 }
204 
206 {
207  delete mActionPopup;
208  mActionPopup = nullptr;
209 
210  QModelIndex idx = indexAt( event->pos() );
211  if ( !idx.isValid() )
212  {
213  return;
214  }
215 
216  QgsVectorLayer *vlayer = mFilterModel->layer();
217  if ( !vlayer )
218  return;
219 
220  mActionPopup = new QMenu();
221 
222  mActionPopup->addAction( tr( "Select All" ), this, SLOT( selectAll() ), QKeySequence::SelectAll );
223 
224  // let some other parts of the application add some actions
225  emit willShowContextMenu( mActionPopup, idx );
226 
227  if ( !mActionPopup->actions().isEmpty() )
228  {
229  mActionPopup->popup( event->globalPos() );
230  }
231 }
232 
234 {
235  selectRow( row, true );
236 }
237 
239 {
240  selectRow( row, false );
241 }
242 
243 void QgsAttributeTableView::modelDeleted()
244 {
245  mFilterModel = nullptr;
246  mFeatureSelectionManager = nullptr;
247  mFeatureSelectionModel = nullptr;
248 }
249 
250 void QgsAttributeTableView::selectRow( int row, bool anchor )
251 {
252  if ( selectionBehavior() == QTableView::SelectColumns
253  || ( selectionMode() == QTableView::SingleSelection
254  && selectionBehavior() == QTableView::SelectItems ) )
255  return;
256 
257  if ( row >= 0 && row < model()->rowCount() )
258  {
259  int column = horizontalHeader()->logicalIndexAt( isRightToLeft() ? viewport()->width() : 0 );
260  QModelIndex index = model()->index( row, column );
262  selectionModel()->setCurrentIndex( index, QItemSelectionModel::NoUpdate );
263  if (( anchor && !( command & QItemSelectionModel::Current ) )
264  || ( selectionMode() == QTableView::SingleSelection ) )
265  mRowSectionAnchor = row;
266 
267  if ( selectionMode() != QTableView::SingleSelection
268  && command.testFlag( QItemSelectionModel::Toggle ) )
269  {
270  if ( anchor )
271  mCtrlDragSelectionFlag = mFeatureSelectionModel->isSelected( index )
272  ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
273  command &= ~QItemSelectionModel::Toggle;
274  command |= mCtrlDragSelectionFlag;
275  if ( !anchor )
276  command |= QItemSelectionModel::Current;
277  }
278 
279  QModelIndex tl = model()->index( qMin( mRowSectionAnchor, row ), 0 );
280  QModelIndex br = model()->index( qMax( mRowSectionAnchor, row ), model()->columnCount() - 1 );
281  if ( verticalHeader()->sectionsMoved() && tl.row() != br.row() )
282  setSelection( visualRect( tl ) | visualRect( br ), command );
283  else
284  mFeatureSelectionModel->selectFeatures( QItemSelection( tl, br ), command );
285  }
286 }
287 
288 void QgsAttributeTableView::showHorizontalSortIndicator()
289 {
291 }
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
void setDirtyRegion(const QRegion &region)
QByteArray toByteArray() const
static unsigned index
virtual bool isSelected(QgsFeatureId fid)
Returns the selection status of a given feature id.
Type type() const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
void willShowContextMenu(QMenu *menu, const QModelIndex &atIndex)
Is emitted, in order to provide a hook to add aditional menu entries to the context menu...
virtual void setSelection(const QRect &rect, QFlags< QItemSelectionModel::SelectionFlag > flags)
void setSelectionMode(QAbstractItemView::SelectionMode mode)
QgsAttributeTableView(QWidget *parent=nullptr)
QItemSelectionModel * selectionModel() const
void setHighlightSections(bool highlight)
void addAction(QAction *action)
void setSortingEnabled(bool enable)
QWidget * viewport() const
void setSortIndicatorShown(bool show)
QHeaderView * verticalHeader() const
virtual bool eventFilter(QObject *object, QEvent *event) override
This event filter is installed on the verticalHeader to intercept mouse press and release events...
void setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual void selectAll() override
const QPoint & globalPos() const
QString tr(const char *sourceText, const char *disambiguation, int n)
void enableSync(bool enable)
Enables or disables synchronisation to the QgsVectorLayer When synchronisation is disabled...
virtual void mouseReleaseEvent(QMouseEvent *event)
void update()
virtual int rowCount(const QModelIndex &parent) const
void setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)
void mouseReleaseEvent(QMouseEvent *event) override
Called for mouse release events on a table cell.
int width() const
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
void setValue(const QString &key, const QVariant &value)
bool isValid() const
virtual QModelIndex indexAt(const QPoint &pos) const
void append(const T &value)
virtual void setModel(QAbstractItemModel *model)
virtual void setSelectionModel(QItemSelectionModel *selectionModel)
void installEventFilter(QObject *filterObj)
void popup(const QPoint &p, QAction *atAction)
bool restoreGeometry(const QByteArray &geometry)
void setItemDelegate(QAbstractItemDelegate *delegate)
int row() const
void mousePressEvent(QMouseEvent *event) override
Called for mouse press events on a table cell.
virtual void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
virtual void setModel(QgsAttributeTableFilterModel *filterModel)
QRect rect() const
int key() const
void mouseMoveEvent(QMouseEvent *event) override
Called for mouse move events on a table cell.
virtual QRect visualRect(const QModelIndex &index) const =0
virtual void mouseMoveEvent(QMouseEvent *event)
virtual QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &index, const QEvent *event) const
int logicalIndexAt(int position) const
QVariant value(const QString &key, const QVariant &defaultValue) const
virtual bool event(QEvent *event)
virtual void selectFeatures(const QItemSelection &selection, const SelectionFlags &command)
Select features on this table.
const QPoint & pos() const
QByteArray saveGeometry() const
virtual void mousePressEvent(QMouseEvent *event)
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
setFeatureSelectionManager
A delegate item class for QgsAttributeTable (see Qt documentation for QItemDelegate).
virtual void selectRow(int row)
void setCurrentIndex(const QModelIndex &index, QFlags< QItemSelectionModel::SelectionFlag > command)
virtual void keyPressEvent(QKeyEvent *event)
virtual void _q_selectRow(int row)
QAbstractItemModel * model() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QList< QAction * > actions() const
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.
QHeaderView * horizontalHeader() const
void destroyed(QObject *obj)
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.