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