QGIS API Documentation  2.99.0-Master (23ddace)
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, static_cast<void ( QgsFeatureSelectionModel::* )( const QModelIndexList &indexes )>( &QgsFeatureSelectionModel::requestRepaint ),
81  this, static_cast<void ( QgsFeatureListView::* )( const QModelIndexList &indexes )>( &QgsFeatureListView::repaintRequested ) );
82  connect( mFeatureSelectionModel, static_cast<void ( QgsFeatureSelectionModel::* )()>( &QgsFeatureSelectionModel::requestRepaint ),
83  this, static_cast<void ( QgsFeatureListView::* )()>( &QgsFeatureListView::repaintRequested ) );
84  connect( mCurrentEditSelectionModel, &QItemSelectionModel::selectionChanged, this, &QgsFeatureListView::editSelectionChanged );
85  connect( mModel->layerCache()->layer(), &QgsVectorLayer::attributeValueChanged, this, [ = ] { 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 
222 void QgsFeatureListView::mouseMoveEvent( QMouseEvent *event )
223 {
224  QPoint pos = event->pos();
225 
226  QModelIndex index = indexAt( pos );
227 
228  if ( mEditSelectionDrag )
229  {
230  setEditSelection( mModel->mapToMaster( index ), QItemSelectionModel::ClearAndSelect );
231  }
232  else
233  {
234  selectRow( index, false );
235  }
236 }
237 
238 void QgsFeatureListView::mouseReleaseEvent( QMouseEvent *event )
239 {
240  Q_UNUSED( event );
241 
242  if ( mEditSelectionDrag )
243  {
244  mEditSelectionDrag = false;
245  }
246  else
247  {
248  if ( mFeatureSelectionModel )
249  mFeatureSelectionModel->enableSync( true );
250  }
251 }
252 
253 void QgsFeatureListView::keyPressEvent( QKeyEvent *event )
254 {
255  if ( Qt::Key_Up == event->key() || Qt::Key_Down == event->key() )
256  {
257  int currentRow = 0;
258  if ( 0 != mCurrentEditSelectionModel->selectedIndexes().count() )
259  {
260  QModelIndex localIndex = mModel->mapFromMaster( mCurrentEditSelectionModel->selectedIndexes().first() );
261  currentRow = localIndex.row();
262  }
263 
264  QModelIndex newLocalIndex;
265  QModelIndex newIndex;
266 
267  switch ( event->key() )
268  {
269  case Qt::Key_Up:
270  newLocalIndex = mModel->index( currentRow - 1, 0 );
271  newIndex = mModel->mapToMaster( newLocalIndex );
272  if ( newIndex.isValid() )
273  {
274  setEditSelection( newIndex, QItemSelectionModel::ClearAndSelect );
275  scrollTo( newLocalIndex );
276  }
277  break;
278 
279  case Qt::Key_Down:
280  newLocalIndex = mModel->index( currentRow + 1, 0 );
281  newIndex = mModel->mapToMaster( newLocalIndex );
282  if ( newIndex.isValid() )
283  {
284  setEditSelection( newIndex, QItemSelectionModel::ClearAndSelect );
285  scrollTo( newLocalIndex );
286  }
287  break;
288 
289  default:
290  break;
291  }
292  }
293  else
294  {
295  QListView::keyPressEvent( event );
296  }
297 }
298 
299 void QgsFeatureListView::contextMenuEvent( QContextMenuEvent *event )
300 {
301  QModelIndex index = indexAt( event->pos() );
302 
303  if ( index.isValid() )
304  {
305  QgsFeature feature = mModel->data( index, QgsFeatureListModel::FeatureRole ).value<QgsFeature>();
306 
307  QgsActionMenu *menu = new QgsActionMenu( mModel->layerCache()->layer(), feature, QStringLiteral( "AttributeTableRow" ), this );
308  menu->exec( event->globalPos() );
309  }
310 }
311 
312 void QgsFeatureListView::selectRow( const QModelIndex &index, bool anchor )
313 {
314  QItemSelectionModel::SelectionFlags command = selectionCommand( index );
315  int row = index.row();
316 
317  if ( anchor )
318  mRowAnchor = row;
319 
320  if ( selectionMode() != QListView::SingleSelection
321  && command.testFlag( QItemSelectionModel::Toggle ) )
322  {
323  if ( anchor )
324  mCtrlDragSelectionFlag = mFeatureSelectionModel->isSelected( index )
325  ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
326  command &= ~QItemSelectionModel::Toggle;
327  command |= mCtrlDragSelectionFlag;
328  if ( !anchor )
329  command |= QItemSelectionModel::Current;
330  }
331 
332  QModelIndex tl = model()->index( qMin( mRowAnchor, row ), 0 );
333  QModelIndex br = model()->index( qMax( mRowAnchor, row ), model()->columnCount() - 1 );
334 
335  mFeatureSelectionModel->selectFeatures( QItemSelection( tl, br ), command );
336 }
337 
339 {
340  delete mFeatureSelectionManager;
341 
342  mFeatureSelectionManager = featureSelectionManager;
343 
344  if ( mFeatureSelectionModel )
345  mFeatureSelectionModel->setFeatureSelectionManager( mFeatureSelectionManager );
346 }
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:37
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:519
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:61
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
QgsFeatureListView(QWidget *parent=0)
Creates a feature list view.
Shows a list of features and renders a edit button next to each feature.
QgsFeatureListModel * featureListModel()
Get the featureListModel used by this view.
void requestRepaint()
Request a repaint of the visible items of connected views.
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:36
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
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Is emitted whenever an attribute value change is done in the edit buffer.
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:37
virtual QItemSelection mapSelectionFromMaster(const QItemSelection &selection) const
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.