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