QGIS API Documentation  2.99.0-Master (8ec3eaf)
qgsfeaturelistview.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 <QHeaderView>
17 #include <QKeyEvent>
18 #include <QMenu>
19 #include <QSet>
20 #include <QSettings>
21 
22 #include "qgsactionmenu.h"
25 #include "qgsattributetablemodel.h"
26 #include "qgsfeaturelistmodel.h"
28 #include "qgsfeaturelistview.h"
30 #include "qgslogger.h"
31 #include "qgsmapcanvas.h"
32 #include "qgsvectordataprovider.h"
33 #include "qgsvectorlayer.h"
35 
37  : QListView( parent )
38  , mModel( nullptr )
39  , mCurrentEditSelectionModel( nullptr )
40  , mFeatureSelectionModel( nullptr )
41  , mFeatureSelectionManager( nullptr )
42  , mItemDelegate( nullptr )
43  , mEditSelectionDrag( false )
44  , mRowAnchor( 0 )
45 {
46  setSelectionMode( QAbstractItemView::ExtendedSelection );
47 }
48 
50 {
51  return mModel->layerCache();
52 }
53 
55 {
56  QListView::setModel( featureListModel );
57  mModel = featureListModel;
58 
59  delete mFeatureSelectionModel;
60 
61  mCurrentEditSelectionModel = new QItemSelectionModel( mModel->masterModel(), this );
62  if ( !mFeatureSelectionManager )
63  {
64  mFeatureSelectionManager = new QgsVectorLayerSelectionManager( mModel->layerCache()->layer(), mModel );
65  }
66 
67  mFeatureSelectionModel = new QgsFeatureSelectionModel( featureListModel, featureListModel, mFeatureSelectionManager, this );
68  setSelectionModel( mFeatureSelectionModel );
69 
70  if ( mItemDelegate && mItemDelegate->parent() == this )
71  {
72  delete mItemDelegate;
73  }
74 
75  mItemDelegate = new QgsFeatureListViewDelegate( mModel, this );
76  mItemDelegate->setEditSelectionModel( mCurrentEditSelectionModel );
77  setItemDelegate( mItemDelegate );
78 
79  mItemDelegate->setFeatureSelectionModel( mFeatureSelectionModel );
80  connect( mFeatureSelectionModel, SIGNAL( requestRepaint( QModelIndexList ) ), this, SLOT( repaintRequested( QModelIndexList ) ) );
81  connect( mFeatureSelectionModel, SIGNAL( requestRepaint() ), this, SLOT( repaintRequested() ) );
82 
83  connect( mCurrentEditSelectionModel, SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), SLOT( editSelectionChanged( QItemSelection, QItemSelection ) ) );
84 
85  connect( mModel->layerCache()->layer(), SIGNAL( attributeValueChanged( QgsFeatureId, int, QVariant ) ), this, SLOT( repaintRequested() ) );
86 }
87 
88 bool QgsFeatureListView::setDisplayExpression( const QString& expression )
89 {
90  if ( mModel->setDisplayExpression( expression ) )
91  {
92  emit displayExpressionChanged( expression );
93  return true;
94  }
95  else
96  {
97  return false;
98  }
99 }
100 
102 {
103  return mModel->displayExpression();
104 }
105 
107 {
108  return mModel->parserErrorString();
109 }
110 
112 {
113  QgsFeatureIds selection;
114  Q_FOREACH ( const QModelIndex& idx, mCurrentEditSelectionModel->selectedIndexes() )
115  {
116  selection << idx.data( QgsAttributeTableModel::FeatureIdRole ).value<QgsFeatureId>();
117  }
118  return selection;
119 }
120 
122 {
123  mItemDelegate->setCurrentFeatureEdited( state );
124  viewport()->update( visualRegionForSelection( mCurrentEditSelectionModel->selection() ) );
125 }
126 
127 void QgsFeatureListView::mousePressEvent( QMouseEvent *event )
128 {
129  if ( mModel )
130  {
131  QPoint pos = event->pos();
132 
133  QModelIndex index = indexAt( pos );
134 
135  if ( QgsFeatureListViewDelegate::EditElement == mItemDelegate->positionToElement( event->pos() ) )
136  {
137  mEditSelectionDrag = true;
138  setEditSelection( mModel->mapToMaster( index ), QItemSelectionModel::ClearAndSelect );
139  }
140  else
141  {
142  mFeatureSelectionModel->enableSync( false );
143  selectRow( index, true );
145  }
146  }
147  else
148  {
149  QgsDebugMsg( "No model assigned to this view" );
150  }
151 }
152 
153 void QgsFeatureListView::editSelectionChanged( const QItemSelection& deselected, const QItemSelection& selected )
154 {
155  if ( isVisible() && updatesEnabled() )
156  {
157  QItemSelection localDeselected = mModel->mapSelectionFromMaster( deselected );
158  QItemSelection localSelected = mModel->mapSelectionFromMaster( selected );
159  viewport()->update( visualRegionForSelection( localDeselected ) | visualRegionForSelection( localSelected ) );
160  }
161 
162  QItemSelection currentSelection = mCurrentEditSelectionModel->selection();
163  if ( currentSelection.size() == 1 )
164  {
165  QModelIndexList indexList = currentSelection.indexes();
166  if ( !indexList.isEmpty() )
167  {
168  QgsFeature feat;
169  mModel->featureByIndex( mModel->mapFromMaster( indexList.first() ), feat );
170 
171  emit currentEditSelectionChanged( feat );
172  }
173  }
174 }
175 
177 {
178  QItemSelection selection;
179  selection.append( QItemSelectionRange( mModel->index( 0, 0 ), mModel->index( mModel->rowCount() - 1, 0 ) ) );
180 
181  mFeatureSelectionModel->selectFeatures( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
182 }
183 
185 {
186  QItemSelection selection;
187 
188  Q_FOREACH ( QgsFeatureId fid, fids )
189  {
190  selection.append( QItemSelectionRange( mModel->mapToMaster( mModel->fidToIdx( fid ) ) ) );
191  }
192 
193  bool ok = true;
194  emit aboutToChangeEditSelection( ok );
195 
196  if ( ok )
197  mCurrentEditSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect );
198 }
199 
200 void QgsFeatureListView::setEditSelection( const QModelIndex& index, QItemSelectionModel::SelectionFlags command )
201 {
202  bool ok = true;
203  emit aboutToChangeEditSelection( ok );
204 
205  if ( ok )
206  mCurrentEditSelectionModel->select( index, command );
207 }
208 
209 void QgsFeatureListView::repaintRequested( const QModelIndexList& indexes )
210 {
211  Q_FOREACH ( const QModelIndex& index, indexes )
212  {
213  update( index );
214  }
215 }
216 
218 {
219  setDirtyRegion( viewport()->rect() );
220 }
221 
228 void QgsFeatureListView::mouseMoveEvent( QMouseEvent *event )
229 {
230  QPoint pos = event->pos();
231 
232  QModelIndex index = indexAt( pos );
233 
234  if ( mEditSelectionDrag )
235  {
236  setEditSelection( mModel->mapToMaster( index ), QItemSelectionModel::ClearAndSelect );
237  }
238  else
239  {
240  selectRow( index, false );
241  }
242 }
243 
251 void QgsFeatureListView::mouseReleaseEvent( QMouseEvent *event )
252 {
253  Q_UNUSED( event );
254 
255  if ( mEditSelectionDrag )
256  {
257  mEditSelectionDrag = false;
258  }
259  else
260  {
261  if ( mFeatureSelectionModel )
262  mFeatureSelectionModel->enableSync( true );
263  }
264 }
265 
266 void QgsFeatureListView::keyPressEvent( QKeyEvent *event )
267 {
268  if ( Qt::Key_Up == event->key() || Qt::Key_Down == event->key() )
269  {
270  int currentRow = 0;
271  if ( 0 != mCurrentEditSelectionModel->selectedIndexes().count() )
272  {
273  QModelIndex localIndex = mModel->mapFromMaster( mCurrentEditSelectionModel->selectedIndexes().first() );
274  currentRow = localIndex.row();
275  }
276 
277  QModelIndex newLocalIndex;
278  QModelIndex newIndex;
279 
280  switch ( event->key() )
281  {
282  case Qt::Key_Up:
283  newLocalIndex = mModel->index( currentRow - 1, 0 );
284  newIndex = mModel->mapToMaster( newLocalIndex );
285  if ( newIndex.isValid() )
286  {
287  setEditSelection( newIndex, QItemSelectionModel::ClearAndSelect );
288  scrollTo( newLocalIndex );
289  }
290  break;
291 
292  case Qt::Key_Down:
293  newLocalIndex = mModel->index( currentRow + 1, 0 );
294  newIndex = mModel->mapToMaster( newLocalIndex );
295  if ( newIndex.isValid() )
296  {
297  setEditSelection( newIndex, QItemSelectionModel::ClearAndSelect );
298  scrollTo( newLocalIndex );
299  }
300  break;
301 
302  default:
303  break;
304  }
305  }
306  else
307  {
308  QListView::keyPressEvent( event );
309  }
310 }
311 
312 void QgsFeatureListView::contextMenuEvent( QContextMenuEvent *event )
313 {
314  QModelIndex index = indexAt( event->pos() );
315 
316  if ( index.isValid() )
317  {
318  QgsFeature feature = mModel->data( index, QgsFeatureListModel::FeatureRole ).value<QgsFeature>();
319 
320  QgsActionMenu* menu = new QgsActionMenu( mModel->layerCache()->layer(), feature, QStringLiteral( "AttributeTableRow" ), this );
321  menu->exec( event->globalPos() );
322  }
323 }
324 
325 void QgsFeatureListView::selectRow( const QModelIndex& index, bool anchor )
326 {
327  QItemSelectionModel::SelectionFlags command = selectionCommand( index );
328  int row = index.row();
329 
330  if ( anchor )
331  mRowAnchor = row;
332 
333  if ( selectionMode() != QListView::SingleSelection
334  && command.testFlag( QItemSelectionModel::Toggle ) )
335  {
336  if ( anchor )
337  mCtrlDragSelectionFlag = mFeatureSelectionModel->isSelected( index )
338  ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
339  command &= ~QItemSelectionModel::Toggle;
340  command |= mCtrlDragSelectionFlag;
341  if ( !anchor )
342  command |= QItemSelectionModel::Current;
343  }
344 
345  QModelIndex tl = model()->index( qMin( mRowAnchor, row ), 0 );
346  QModelIndex br = model()->index( qMax( mRowAnchor, row ), model()->columnCount() - 1 );
347 
348  mFeatureSelectionModel->selectFeatures( QItemSelection( tl, br ), command );
349 }
350 
352 {
353  delete mFeatureSelectionManager;
354 
355  mFeatureSelectionManager = featureSelectionManager;
356 
357  if ( mFeatureSelectionModel )
358  mFeatureSelectionModel->setFeatureSelectionManager( mFeatureSelectionManager );
359 }
static unsigned index
virtual bool isSelected(QgsFeatureId fid)
Returns the selection status of a given feature id.
void setCurrentFeatureEdited(bool state)
Sets if the currently shown form has received any edit events so far.
virtual void mouseReleaseEvent(QMouseEvent *event) override
bool setDisplayExpression(const QString &expression)
bool setDisplayExpression(const QString &displayExpression)
The display expression is an expression used to render the fields into a single string which is displ...
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:355
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool featureByIndex(const QModelIndex &index, QgsFeature &feat)
QgsVectorLayer * layer()
Returns the layer to which this cache belongs.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:135
void enableSync(bool enable)
Enables or disables synchronisation to the QgsVectorLayer When synchronisation is disabled...
QString parserErrorString()
Returns a detailed message about errors while parsing a QgsExpression.
virtual QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
Get the feature id of the feature in this row.
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QgsFeatureListModel * featureListModel()
Get the featureListModel used by this view.
void setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)
virtual QVariant data(const QModelIndex &index, int role) const override
void aboutToChangeEditSelection(bool &ok)
This class is a menu that is populated automatically with the actions defined for a given layer...
Definition: qgsactionmenu.h:34
virtual void selectFeatures(const QItemSelection &selection, SelectionFlags command)
Select features on this table.
QString parserErrorString()
Returns a detailed message about errors while parsing a QgsExpression.
virtual void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
void displayExpressionChanged(const QString &expression)
Is emitted, whenever the display expression is successfully changed.
QString displayExpression() const
QgsFeatureIds currentEditSelection()
Get the currentEditSelection.
virtual void mouseMoveEvent(QMouseEvent *event) override
QgsAttributeTableModel * masterModel()
virtual QModelIndex mapFromMaster(const QModelIndex &sourceIndex) const
This class caches features of a given QgsVectorLayer.
void setEditSelection(const QgsFeatureIds &fids)
Set the feature(s) to be edited.
const QString displayExpression() const
Returns the expression which is currently used to render the features.
virtual void selectAll() override
Select all currently visible features.
virtual void mousePressEvent(QMouseEvent *event) override
QModelIndex fidToIdx(const QgsFeatureId fid) const
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
setFeatureSelectionManager
virtual void contextMenuEvent(QContextMenuEvent *event) override
virtual void keyPressEvent(QKeyEvent *event) override
qint64 QgsFeatureId
Definition: qgsfeature.h:32
virtual QItemSelection mapSelectionFromMaster(const QItemSelection &selection) const
QgsFeatureListView(QWidget *parent=nullptr)
Creates a feature list view.
QgsVectorLayerCache * layerCache()
void setEditSelectionModel(QItemSelectionModel *editSelectionModel)
Is an interface class to abstract feature selection handling.
void currentEditSelectionChanged(QgsFeature &feat)
Is emitted, whenever the current edit selection has been changed.
virtual void setModel(QgsFeatureListModel *featureListModel)
Set the QgsFeatureListModel which is used to retrieve information.
QgsVectorLayerCache * layerCache()
Returns the layer cache.