QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsattributetablefiltermodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  QgsAttributeTableFilterModel.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 <QItemSelectionModel>
17 
19 #include "qgsattributetablemodel.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsfeature.h"
22 #include "qgsmapcanvas.h"
23 #include "qgslogger.h"
24 #include "qgsrendererv2.h"
27 // Filter Model //
29 
31  : QSortFilterProxyModel( parent )
32  , mCanvas( canvas )
33  , mFilterMode( ShowAll )
34  , mSelectedOnTop( false )
35 {
36  setSourceModel( sourceModel );
37  setDynamicSortFilter( true );
38  setSortRole( QgsAttributeTableModel::SortRole );
39  connect( layer(), SIGNAL( selectionChanged() ), SLOT( selectionChanged() ) );
40 }
41 
42 bool QgsAttributeTableFilterModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
43 {
44  if ( mSelectedOnTop )
45  {
46  bool leftSelected = layer()->selectedFeaturesIds().contains( masterModel()->rowToId( left.row() ) );
47  bool rightSelected = layer()->selectedFeaturesIds().contains( masterModel()->rowToId( right.row() ) );
48 
49  if ( leftSelected && !rightSelected )
50  {
51  return true;
52  }
53  else if ( rightSelected && !leftSelected )
54  {
55  return false;
56  }
57  }
58 
59 
60  QVariant leftData = left.data( QgsAttributeTableModel::SortRole );
61  QVariant rightData = right.data( QgsAttributeTableModel::SortRole );
62 
63  if ( leftData.isNull() )
64  return true;
65 
66  if ( rightData.isNull() )
67  return false;
68 
69  switch ( leftData.type() )
70  {
71  case QVariant::Int:
72  case QVariant::UInt:
73  case QVariant::LongLong:
74  case QVariant::ULongLong:
75  return leftData.toLongLong() < rightData.toLongLong();
76 
77  case QVariant::Double:
78  return leftData.toDouble() < rightData.toDouble();
79 
80  case QVariant::Date:
81  return leftData.toDate() < rightData.toDate();
82 
83  case QVariant::DateTime:
84  return leftData.toDateTime() < rightData.toDateTime();
85 
86  default:
87  return leftData.toString().localeAwareCompare( rightData.toString() ) < 0;
88  }
89 
90  // Avoid warning. Will never reach this
91  return false;
92 }
93 
94 void QgsAttributeTableFilterModel::sort( int column, Qt::SortOrder order )
95 {
96  masterModel()->prefetchColumnData( column );
97  QSortFilterProxyModel::sort( column, order );
98 }
99 
101 {
102  if ( mSelectedOnTop != selectedOnTop )
103  {
104  mSelectedOnTop = selectedOnTop;
105 
106  if ( sortColumn() == -1 )
107  {
108  sort( 0 );
109  }
110  invalidate();
111  }
112 }
113 
115 {
116  mTableModel = sourceModel;
117 
119 }
120 
122 {
123  return mSelectedOnTop;
124 }
125 
127 {
128  mFilteredFeatures = ids;
130  invalidateFilter();
131 }
132 
134 {
135  QgsFeatureIds ids;
136  for ( int i = 0; i < rowCount(); ++i )
137  {
138  QModelIndex row = index( i, 0 );
139  ids << rowToId( row );
140  }
141  return ids;
142 }
143 
145 {
146  if ( filterMode != mFilterMode )
147  {
148  if ( filterMode == ShowVisible )
149  {
150  connect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( extentsChanged() ) );
152  }
153  else
154  {
155  disconnect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( extentsChanged() ) );
156  }
157 
158  if ( filterMode == ShowSelected )
159  {
161  }
162 
163  mFilterMode = filterMode;
164  invalidateFilter();
165  }
166 }
167 
168 bool QgsAttributeTableFilterModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
169 {
170  Q_UNUSED( sourceParent );
171  switch ( mFilterMode )
172  {
173  case ShowAll:
174  return true;
175 
176  case ShowFilteredList:
177  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
178 
179  case ShowSelected:
180  return layer()->selectedFeaturesIds().isEmpty() || layer()->selectedFeaturesIds().contains( masterModel()->rowToId( sourceRow ) );
181 
182  case ShowVisible:
183  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
184 
185  case ShowEdited:
186  {
187  QgsVectorLayerEditBuffer* editBuffer = layer()->editBuffer();
188  if ( editBuffer )
189  {
190  const QList<QgsFeatureId> addedFeatures = editBuffer->addedFeatures().keys();
191  const QList<QgsFeatureId> changedFeatures = editBuffer->changedAttributeValues().keys();
192  const QgsFeatureId fid = masterModel()->rowToId( sourceRow );
193  return addedFeatures.contains( fid ) || changedFeatures.contains( fid );
194  }
195  return false;
196  }
197 
198  default:
199  Q_ASSERT( false ); // In debug mode complain
200  return true; // In release mode accept row
201  }
202  // returns are handled in their respective case statement above
203 }
204 
206 {
208  invalidateFilter();
209 }
210 
211 void QgsAttributeTableFilterModel::selectionChanged()
212 {
213  if ( ShowSelected == mFilterMode )
214  {
216  invalidateFilter();
217  }
218  else if ( mSelectedOnTop )
219  {
220  sort( sortColumn(), sortOrder() );
221  invalidate();
222  }
223 }
224 
226 {
227  if ( !layer() )
228  return;
229 
230  bool filter = false;
231  QgsRectangle rect = mCanvas->mapSettings().mapToLayerCoordinates( layer(), mCanvas->extent() );
232  QgsRenderContext renderContext;
233  QgsFeatureRendererV2* renderer = layer()->rendererV2();
234 
235  mFilteredFeatures.clear();
236 
237  if ( !renderer )
238  {
239  QgsDebugMsg( "Cannot get renderer" );
240  return;
241  }
242 
243  const QgsMapSettings& ms = mCanvas->mapSettings();
244  if ( layer()->hasScaleBasedVisibility() &&
245  ( layer()->minimumScale() > ms.scale() ||
246  layer()->maximumScale() <= ms.scale() ) )
247  {
248  QgsDebugMsg( "Out of scale limits" );
249  }
250  else
251  {
252  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
253  {
254  // setup scale
255  // mapRenderer()->renderContext()->scale is not automaticaly updated when
256  // render extent changes (because it's scale is used to identify if changed
257  // since last render) -> use local context
258  renderContext.setExtent( ms.visibleExtent() );
259  renderContext.setMapToPixel( ms.mapToPixel() );
260  renderContext.setRendererScale( ms.scale() );
261  }
262 
263  filter = renderer && renderer->capabilities() & QgsFeatureRendererV2::Filter;
264  }
265 
266  renderer->startRender( renderContext, layer()->pendingFields() );
267 
268  QgsFeatureRequest r( masterModel()->request() );
270  {
271  r.setFilterRect( r.filterRect().intersect( &rect ) );
272  }
273  else
274  {
275  r.setFilterRect( rect );
276  }
278 
279  QgsFeature f;
280 
281  while ( features.nextFeature( f ) )
282  {
283  if ( !filter || renderer->willRenderFeature( f ) )
284  {
285  mFilteredFeatures << f.id();
286  }
287 #if 0
288  if ( t.elapsed() > 5000 )
289  {
290  bool cancel = false;
291  emit progress( i, cancel );
292  if ( cancel )
293  break;
294 
295  t.restart();
296  }
297 #endif
298  }
299 
300  features.close();
301 
302  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
303  {
304  renderer->stopRender( renderContext );
305  }
306 }
307 
309 {
310  return masterModel()->rowToId( mapToSource( row ).row() );
311 }
312 
314 {
315  return mapFromMaster( masterModel()->idToIndex( fid ) );
316 }
317 
319 {
320  QModelIndexList indexes;
321  foreach ( QModelIndex idx, masterModel()->idToIndexList( fid ) )
322  {
323  indexes.append( mapFromMaster( idx ) );
324  }
325 
326  return indexes;
327 }
328 
329 QModelIndex QgsAttributeTableFilterModel::mapToMaster( const QModelIndex &proxyIndex ) const
330 {
331  // Master is source
332  return mapToSource( proxyIndex );
333 }
334 
335 QModelIndex QgsAttributeTableFilterModel::mapFromMaster( const QModelIndex &sourceIndex ) const
336 {
337  // Master is source
338  return mapFromSource( sourceIndex );
339 }