QGIS API Documentation  2.99.0-Master (7705179)
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  , mEditSelectionDrag( false )
39  , mRowAnchor( 0 )
40 {
41  setSelectionMode( QAbstractItemView::ExtendedSelection );
42 }
43 
45 {
46  return mModel->layerCache();
47 }
48 
50 {
51  QListView::setModel( featureListModel );
52  mModel = featureListModel;
53 
54  delete mFeatureSelectionModel;
55 
56  mCurrentEditSelectionModel = new QItemSelectionModel( mModel->masterModel(), this );
57  if ( !mFeatureSelectionManager )
58  {
59  mFeatureSelectionManager = new QgsVectorLayerSelectionManager( mModel->layerCache()->layer(), mModel );
60  }
61 
62  mFeatureSelectionModel = new QgsFeatureSelectionModel( featureListModel, featureListModel, mFeatureSelectionManager, this );
63  setSelectionModel( mFeatureSelectionModel );
64 
65  if ( mItemDelegate && mItemDelegate->parent() == this )
66  {
67  delete mItemDelegate;
68  }
69 
70  mItemDelegate = new QgsFeatureListViewDelegate( mModel, this );
71  mItemDelegate->setEditSelectionModel( mCurrentEditSelectionModel );
72  setItemDelegate( mItemDelegate );
73 
74  mItemDelegate->setFeatureSelectionModel( mFeatureSelectionModel );
75  connect( mFeatureSelectionModel, static_cast<void ( QgsFeatureSelectionModel::* )( const QModelIndexList &indexes )>( &QgsFeatureSelectionModel::requestRepaint ),
76  this, static_cast<void ( QgsFeatureListView::* )( const QModelIndexList &indexes )>( &QgsFeatureListView::repaintRequested ) );
77  connect( mFeatureSelectionModel, static_cast<void ( QgsFeatureSelectionModel::* )()>( &QgsFeatureSelectionModel::requestRepaint ),
78  this, static_cast<void ( QgsFeatureListView::* )()>( &QgsFeatureListView::repaintRequested ) );
79  connect( mCurrentEditSelectionModel, &QItemSelectionModel::selectionChanged, this, &QgsFeatureListView::editSelectionChanged );
80  connect( mModel->layerCache()->layer(), &QgsVectorLayer::attributeValueChanged, this, [ = ] { repaintRequested(); } );
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  Q_FOREACH ( const QModelIndex &idx, mCurrentEditSelectionModel->selectedIndexes() )
110  {
111  selection << idx.data( QgsAttributeTableModel::FeatureIdRole ).value<QgsFeatureId>();
112  }
113  return selection;
114 }
115 
117 {
118  mItemDelegate->setCurrentFeatureEdited( state );
119  viewport()->update( visualRegionForSelection( mCurrentEditSelectionModel->selection() ) );
120 }
121 
122 void QgsFeatureListView::mousePressEvent( QMouseEvent *event )
123 {
124  if ( mModel )
125  {
126  QPoint pos = event->pos();
127 
128  QModelIndex index = indexAt( pos );
129 
130  if ( QgsFeatureListViewDelegate::EditElement == mItemDelegate->positionToElement( event->pos() ) )
131  {
132  mEditSelectionDrag = true;
133  setEditSelection( mModel->mapToMaster( index ), QItemSelectionModel::ClearAndSelect );
134  }
135  else
136  {
137  mFeatureSelectionModel->enableSync( false );
138  selectRow( index, true );
140  }
141  }
142  else
143  {
144  QgsDebugMsg( "No model assigned to this view" );
145  }
146 }
147 
148 void QgsFeatureListView::editSelectionChanged( const QItemSelection &deselected, const QItemSelection &selected )
149 {
150  if ( isVisible() && updatesEnabled() )
151  {
152  QItemSelection localDeselected = mModel->mapSelectionFromMaster( deselected );
153  QItemSelection localSelected = mModel->mapSelectionFromMaster( selected );
154  viewport()->update( visualRegionForSelection( localDeselected ) | visualRegionForSelection( localSelected ) );
155  }
156 
157  QItemSelection currentSelection = mCurrentEditSelectionModel->selection();
158  if ( currentSelection.size() == 1 )
159  {
160  QModelIndexList indexList = currentSelection.indexes();
161  if ( !indexList.isEmpty() )
162  {
163  QgsFeature feat;
164  mModel->featureByIndex( mModel->mapFromMaster( indexList.first() ), feat );
165 
166  emit currentEditSelectionChanged( feat );
167  }
168  }
169 }
170 
172 {
173  QItemSelection selection;
174  selection.append( QItemSelectionRange( mModel->index( 0, 0 ), mModel->index( mModel->rowCount() - 1, 0 ) ) );
175 
176  mFeatureSelectionModel->selectFeatures( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
177 }
178 
180 {
181  QItemSelection selection;
182 
183  Q_FOREACH ( QgsFeatureId fid, fids )
184  {
185  selection.append( QItemSelectionRange( mModel->mapToMaster( mModel->fidToIdx( fid ) ) ) );
186  }
187 
188  bool ok = true;
189  emit aboutToChangeEditSelection( ok );
190 
191  if ( ok )
192  mCurrentEditSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect );
193 }
194 
195 void QgsFeatureListView::setEditSelection( const QModelIndex &index, QItemSelectionModel::SelectionFlags command )
196 {
197  bool ok = true;
198  emit aboutToChangeEditSelection( ok );
199 
200  if ( ok )
201  mCurrentEditSelectionModel->select( index, command );
202 }
203 
204 void QgsFeatureListView::repaintRequested( const QModelIndexList &indexes )
205 {
206  Q_FOREACH ( const QModelIndex &index, indexes )
207  {
208  update( index );
209  }
210 }
211 
213 {
214  setDirtyRegion( viewport()->rect() );
215 }
216 
217 void QgsFeatureListView::mouseMoveEvent( QMouseEvent *event )
218 {
219  QPoint pos = event->pos();
220 
221  QModelIndex index = indexAt( pos );
222 
223  if ( mEditSelectionDrag )
224  {
225  setEditSelection( mModel->mapToMaster( index ), QItemSelectionModel::ClearAndSelect );
226  }
227  else
228  {
229  selectRow( index, false );
230  }
231 }
232 
233 void QgsFeatureListView::mouseReleaseEvent( QMouseEvent *event )
234 {
235  Q_UNUSED( event );
236 
237  if ( mEditSelectionDrag )
238  {
239  mEditSelectionDrag = false;
240  }
241  else
242  {
243  if ( mFeatureSelectionModel )
244  mFeatureSelectionModel->enableSync( true );
245  }
246 }
247 
248 void QgsFeatureListView::keyPressEvent( QKeyEvent *event )
249 {
250  if ( Qt::Key_Up == event->key() || Qt::Key_Down == event->key() )
251  {
252  int currentRow = 0;
253  if ( 0 != mCurrentEditSelectionModel->selectedIndexes().count() )
254  {
255  QModelIndex localIndex = mModel->mapFromMaster( mCurrentEditSelectionModel->selectedIndexes().first() );
256  currentRow = localIndex.row();
257  }
258 
259  QModelIndex newLocalIndex;
260  QModelIndex newIndex;
261 
262  switch ( event->key() )
263  {
264  case Qt::Key_Up:
265  newLocalIndex = mModel->index( currentRow - 1, 0 );
266  newIndex = mModel->mapToMaster( newLocalIndex );
267  if ( newIndex.isValid() )
268  {
269  setEditSelection( newIndex, QItemSelectionModel::ClearAndSelect );
270  scrollTo( newLocalIndex );
271  }
272  break;
273 
274  case Qt::Key_Down:
275  newLocalIndex = mModel->index( currentRow + 1, 0 );
276  newIndex = mModel->mapToMaster( newLocalIndex );
277  if ( newIndex.isValid() )
278  {
279  setEditSelection( newIndex, QItemSelectionModel::ClearAndSelect );
280  scrollTo( newLocalIndex );
281  }
282  break;
283 
284  default:
285  break;
286  }
287  }
288  else
289  {
290  QListView::keyPressEvent( event );
291  }
292 }
293 
294 void QgsFeatureListView::contextMenuEvent( QContextMenuEvent *event )
295 {
296  QModelIndex index = indexAt( event->pos() );
297 
298  if ( index.isValid() )
299  {
300  QgsFeature feature = mModel->data( index, QgsFeatureListModel::FeatureRole ).value<QgsFeature>();
301 
302  QgsActionMenu *menu = new QgsActionMenu( mModel->layerCache()->layer(), feature, QStringLiteral( "AttributeTableRow" ), this );
303  menu->exec( event->globalPos() );
304  }
305 }
306 
307 void QgsFeatureListView::selectRow( const QModelIndex &index, bool anchor )
308 {
309  QItemSelectionModel::SelectionFlags command = selectionCommand( index );
310  int row = index.row();
311 
312  if ( anchor )
313  mRowAnchor = row;
314 
315  if ( selectionMode() != QListView::SingleSelection
316  && command.testFlag( QItemSelectionModel::Toggle ) )
317  {
318  if ( anchor )
319  mCtrlDragSelectionFlag = mFeatureSelectionModel->isSelected( index )
320  ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
321  command &= ~QItemSelectionModel::Toggle;
322  command |= mCtrlDragSelectionFlag;
323  if ( !anchor )
324  command |= QItemSelectionModel::Current;
325  }
326 
327  QModelIndex tl = model()->index( std::min( mRowAnchor, row ), 0 );
328  QModelIndex br = model()->index( std::max( mRowAnchor, row ), model()->columnCount() - 1 );
329 
330  mFeatureSelectionModel->selectFeatures( QItemSelection( tl, br ), command );
331 }
332 
334 {
335  delete mFeatureSelectionManager;
336 
337  mFeatureSelectionManager = featureSelectionManager;
338 
339  if ( mFeatureSelectionModel )
340  mFeatureSelectionModel->setFeatureSelectionManager( mFeatureSelectionManager );
341 }
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.