QGIS API Documentation  2.99.0-Master (585a4d3)
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 
24 #include "qgsattributetablemodel.h"
25 #include "qgsfeaturelistmodel.h"
27 #include "qgsfeaturelistview.h"
29 #include "qgslogger.h"
30 #include "qgsmapcanvas.h"
31 #include "qgsvectordataprovider.h"
32 #include "qgsvectorlayer.h"
34 
36  : QListView( parent )
37 {
38  setSelectionMode( QAbstractItemView::ExtendedSelection );
39 }
40 
42 {
43  return mModel->layerCache();
44 }
45 
47 {
48  QListView::setModel( featureListModel );
49  mModel = featureListModel;
50 
51  delete mFeatureSelectionModel;
52 
53  mCurrentEditSelectionModel = new QItemSelectionModel( mModel->masterModel(), this );
54  if ( !mFeatureSelectionManager )
55  {
56  mFeatureSelectionManager = new QgsVectorLayerSelectionManager( mModel->layerCache()->layer(), mModel );
57  }
58 
59  mFeatureSelectionModel = new QgsFeatureSelectionModel( featureListModel, featureListModel, mFeatureSelectionManager, this );
60  setSelectionModel( mFeatureSelectionModel );
61 
62  if ( mItemDelegate && mItemDelegate->parent() == this )
63  {
64  delete mItemDelegate;
65  }
66 
67  mItemDelegate = new QgsFeatureListViewDelegate( mModel, this );
68  mItemDelegate->setEditSelectionModel( mCurrentEditSelectionModel );
69  setItemDelegate( mItemDelegate );
70 
71  mItemDelegate->setFeatureSelectionModel( mFeatureSelectionModel );
72  connect( mFeatureSelectionModel, static_cast<void ( QgsFeatureSelectionModel::* )( const QModelIndexList &indexes )>( &QgsFeatureSelectionModel::requestRepaint ),
73  this, static_cast<void ( QgsFeatureListView::* )( const QModelIndexList &indexes )>( &QgsFeatureListView::repaintRequested ) );
74  connect( mFeatureSelectionModel, static_cast<void ( QgsFeatureSelectionModel::* )()>( &QgsFeatureSelectionModel::requestRepaint ),
75  this, static_cast<void ( QgsFeatureListView::* )()>( &QgsFeatureListView::repaintRequested ) );
76  connect( mCurrentEditSelectionModel, &QItemSelectionModel::selectionChanged, this, &QgsFeatureListView::editSelectionChanged );
77  connect( mModel->layerCache()->layer(), &QgsVectorLayer::attributeValueChanged, this, [ = ] { repaintRequested(); } );
78  connect( featureListModel, &QgsFeatureListModel::rowsRemoved, this, &QgsFeatureListView::ensureEditSelection );
79  connect( featureListModel, &QgsFeatureListModel::rowsInserted, this, &QgsFeatureListView::ensureEditSelection );
80  connect( featureListModel, &QgsFeatureListModel::modelReset, this, &QgsFeatureListView::ensureEditSelection );
81 }
82 
83 bool QgsFeatureListView::setDisplayExpression( const QString &expression )
84 {
85  if ( mModel->setDisplayExpression( expression ) )
86  {
87  emit displayExpressionChanged( expression );
88  return true;
89  }
90  else
91  {
92  return false;
93  }
94 }
95 
97 {
98  return mModel->displayExpression();
99 }
100 
102 {
103  return mModel->parserErrorString();
104 }
105 
107 {
108  QgsFeatureIds selection;
109  const QModelIndexList selectedIndexes = mCurrentEditSelectionModel->selectedIndexes();
110  for ( const QModelIndex &idx : selectedIndexes )
111  {
112  selection << idx.data( QgsAttributeTableModel::FeatureIdRole ).value<QgsFeatureId>();
113  }
114  return selection;
115 }
116 
118 {
119  mItemDelegate->setCurrentFeatureEdited( state );
120  viewport()->update( visualRegionForSelection( mCurrentEditSelectionModel->selection() ) );
121 }
122 
123 void QgsFeatureListView::mousePressEvent( QMouseEvent *event )
124 {
125  if ( mModel )
126  {
127  QPoint pos = event->pos();
128 
129  QModelIndex index = indexAt( pos );
130 
131  if ( QgsFeatureListViewDelegate::EditElement == mItemDelegate->positionToElement( event->pos() ) )
132  {
133  mEditSelectionDrag = true;
134  setEditSelection( mModel->mapToMaster( index ), QItemSelectionModel::ClearAndSelect );
135  }
136  else
137  {
138  mFeatureSelectionModel->enableSync( false );
139  selectRow( index, true );
141  }
142  }
143  else
144  {
145  QgsDebugMsg( "No model assigned to this view" );
146  }
147 }
148 
149 void QgsFeatureListView::editSelectionChanged( const QItemSelection &deselected, const QItemSelection &selected )
150 {
151  if ( isVisible() && updatesEnabled() )
152  {
153  QItemSelection localDeselected = mModel->mapSelectionFromMaster( deselected );
154  QItemSelection localSelected = mModel->mapSelectionFromMaster( selected );
155  viewport()->update( visualRegionForSelection( localDeselected ) | visualRegionForSelection( localSelected ) );
156  }
157 
158  QItemSelection currentSelection = mCurrentEditSelectionModel->selection();
159  if ( currentSelection.size() == 1 )
160  {
161  QModelIndexList indexList = currentSelection.indexes();
162  if ( !indexList.isEmpty() )
163  {
164  QgsFeature feat;
165  mModel->featureByIndex( mModel->mapFromMaster( indexList.first() ), feat );
166 
167  emit currentEditSelectionChanged( feat );
168  }
169  }
170 }
171 
173 {
174  QItemSelection selection;
175  selection.append( QItemSelectionRange( mModel->index( 0, 0 ), mModel->index( mModel->rowCount() - 1, 0 ) ) );
176 
177  mFeatureSelectionModel->selectFeatures( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
178 }
179 
181 {
182  QItemSelection selection;
183 
184  Q_FOREACH ( QgsFeatureId fid, fids )
185  {
186  selection.append( QItemSelectionRange( mModel->mapToMaster( mModel->fidToIdx( fid ) ) ) );
187  }
188 
189  bool ok = true;
190  emit aboutToChangeEditSelection( ok );
191 
192  if ( ok )
193  mCurrentEditSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect );
194 }
195 
196 void QgsFeatureListView::setEditSelection( const QModelIndex &index, QItemSelectionModel::SelectionFlags command )
197 {
198  bool ok = true;
199  emit aboutToChangeEditSelection( ok );
200 
201  if ( ok )
202  mCurrentEditSelectionModel->select( index, command );
203 }
204 
205 void QgsFeatureListView::repaintRequested( const QModelIndexList &indexes )
206 {
207  Q_FOREACH ( const QModelIndex &index, indexes )
208  {
209  update( index );
210  }
211 }
212 
214 {
215  setDirtyRegion( viewport()->rect() );
216 }
217 
218 void QgsFeatureListView::mouseMoveEvent( QMouseEvent *event )
219 {
220  QPoint pos = event->pos();
221 
222  QModelIndex index = indexAt( pos );
223 
224  if ( mEditSelectionDrag )
225  {
226  setEditSelection( mModel->mapToMaster( index ), QItemSelectionModel::ClearAndSelect );
227  }
228  else
229  {
230  selectRow( index, false );
231  }
232 }
233 
234 void QgsFeatureListView::mouseReleaseEvent( QMouseEvent *event )
235 {
236  Q_UNUSED( event );
237 
238  if ( mEditSelectionDrag )
239  {
240  mEditSelectionDrag = false;
241  }
242  else
243  {
244  if ( mFeatureSelectionModel )
245  mFeatureSelectionModel->enableSync( true );
246  }
247 }
248 
249 void QgsFeatureListView::keyPressEvent( QKeyEvent *event )
250 {
251  if ( Qt::Key_Up == event->key() || Qt::Key_Down == event->key() )
252  {
253  int currentRow = 0;
254  if ( 0 != mCurrentEditSelectionModel->selectedIndexes().count() )
255  {
256  QModelIndex localIndex = mModel->mapFromMaster( mCurrentEditSelectionModel->selectedIndexes().first() );
257  currentRow = localIndex.row();
258  }
259 
260  QModelIndex newLocalIndex;
261  QModelIndex newIndex;
262 
263  switch ( event->key() )
264  {
265  case Qt::Key_Up:
266  newLocalIndex = mModel->index( currentRow - 1, 0 );
267  newIndex = mModel->mapToMaster( newLocalIndex );
268  if ( newIndex.isValid() )
269  {
270  setEditSelection( newIndex, QItemSelectionModel::ClearAndSelect );
271  scrollTo( newLocalIndex );
272  }
273  break;
274 
275  case Qt::Key_Down:
276  newLocalIndex = mModel->index( currentRow + 1, 0 );
277  newIndex = mModel->mapToMaster( newLocalIndex );
278  if ( newIndex.isValid() )
279  {
280  setEditSelection( newIndex, QItemSelectionModel::ClearAndSelect );
281  scrollTo( newLocalIndex );
282  }
283  break;
284 
285  default:
286  break;
287  }
288  }
289  else
290  {
291  QListView::keyPressEvent( event );
292  }
293 }
294 
295 void QgsFeatureListView::contextMenuEvent( QContextMenuEvent *event )
296 {
297  QModelIndex index = indexAt( event->pos() );
298 
299  if ( index.isValid() )
300  {
301  QgsFeature feature = mModel->data( index, QgsFeatureListModel::FeatureRole ).value<QgsFeature>();
302 
303  QgsActionMenu *menu = new QgsActionMenu( mModel->layerCache()->layer(), feature, QStringLiteral( "Feature" ), this );
304 
305  emit willShowContextMenu( menu, index );
306 
307  menu->exec( event->globalPos() );
308  }
309 }
310 
311 void QgsFeatureListView::selectRow( const QModelIndex &index, bool anchor )
312 {
313  QItemSelectionModel::SelectionFlags command = selectionCommand( index );
314  int row = index.row();
315 
316  if ( anchor )
317  mRowAnchor = row;
318 
319  if ( selectionMode() != QListView::SingleSelection
320  && command.testFlag( QItemSelectionModel::Toggle ) )
321  {
322  if ( anchor )
323  mCtrlDragSelectionFlag = mFeatureSelectionModel->isSelected( index )
324  ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
325  command &= ~QItemSelectionModel::Toggle;
326  command |= mCtrlDragSelectionFlag;
327  if ( !anchor )
328  command |= QItemSelectionModel::Current;
329  }
330 
331  QModelIndex tl = model()->index( std::min( mRowAnchor, row ), 0 );
332  QModelIndex br = model()->index( std::max( mRowAnchor, row ), model()->columnCount() - 1 );
333 
334  mFeatureSelectionModel->selectFeatures( QItemSelection( tl, br ), command );
335 }
336 
337 void QgsFeatureListView::ensureEditSelection()
338 {
339  QModelIndexList selectedIndexes = mCurrentEditSelectionModel->selectedIndexes();
340  // If there is no selection or an invalid selection (and there would be something we could select) : select it
341  if ( ( selectedIndexes.isEmpty()
342  || mModel->mapFromMaster( selectedIndexes.first() ).row() == -1 )
343  && mModel->rowCount() )
344  {
345  mCurrentEditSelectionModel->select( mModel->mapToMaster( mModel->index( 0, 0 ) ), QItemSelectionModel::Select );
346  }
347 }
348 
350 {
351  delete mFeatureSelectionManager;
352 
353  mFeatureSelectionManager = featureSelectionManager;
354 
355  if ( mFeatureSelectionModel )
356  mFeatureSelectionModel->setFeatureSelectionManager( mFeatureSelectionManager );
357 }
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.
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:38
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:544
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void willShowContextMenu(QgsActionMenu *menu, const QModelIndex &atIndex)
Is emitted, when the context menu is created to add the specific actions to it.
bool featureByIndex(const QModelIndex &index, QgsFeature &feat)
virtual void selectFeatures(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
Select features on this table.
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:62
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.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
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)
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:37
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.
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.
void selectAll() override
Select all currently visible features.
void mousePressEvent(QMouseEvent *event) override
QModelIndex fidToIdx(const QgsFeatureId fid) const
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
setFeatureSelectionManager
void contextMenuEvent(QContextMenuEvent *event) override
void keyPressEvent(QKeyEvent *event) override
qint64 QgsFeatureId
Definition: qgsfeature.h:37
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.