QGIS API Documentation  2.2.0-Valmiera
 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  {
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  if ( filterMode != mFilterMode )
136  {
137  if ( filterMode == ShowVisible )
138  {
139  connect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( extentsChanged() ) );
141  }
142  else
143  {
144  disconnect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( extentsChanged() ) );
145  }
146 
147  if ( filterMode == ShowSelected )
148  {
150  }
151 
152  mFilterMode = filterMode;
153  invalidateFilter();
154  }
155 }
156 
157 bool QgsAttributeTableFilterModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
158 {
159  Q_UNUSED( sourceParent );
160  switch ( mFilterMode )
161  {
162  case ShowAll:
163  return true;
164  break;
165 
166  case ShowFilteredList:
167  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
168  break;
169 
170  case ShowSelected:
171  return layer()->selectedFeaturesIds().contains( masterModel()->rowToId( sourceRow ) );
172  break;
173 
174  case ShowVisible:
175  return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
176  break;
177 
178  case ShowEdited:
179  {
180  QgsVectorLayerEditBuffer* editBuffer = layer()->editBuffer();
181  if ( editBuffer )
182  {
183  const QList<QgsFeatureId> addedFeatures = editBuffer->addedFeatures().keys();
184  const QList<QgsFeatureId> changedFeatures = editBuffer->changedAttributeValues().keys();
185  const QgsFeatureId fid = masterModel()->rowToId( sourceRow );
186  return addedFeatures.contains( fid ) || changedFeatures.contains( fid );
187  }
188  return false;
189  break;
190  }
191 
192  default:
193  Q_ASSERT( false ); // In debug mode complain
194  return true; // In release mode accept row
195  break;
196  }
197  // returns are handled in their respective case statement above
198 }
199 
201 {
203  invalidateFilter();
204 }
205 
207 {
208  if ( ShowSelected == mFilterMode )
209  {
211  invalidateFilter();
212  }
213  else if ( mSelectedOnTop )
214  {
215  sort( sortColumn(), sortOrder() );
216  invalidate();
217  }
218 }
219 
221 {
222  if ( !layer() )
223  return;
224 
225  bool filter = false;
227  QgsRenderContext renderContext;
228  QgsFeatureRendererV2* renderer = layer()->rendererV2();
229 
230  mFilteredFeatures.clear();
231 
232  if ( !renderer )
233  {
234  QgsDebugMsg( "Cannot get renderer" );
235  return;
236  }
237 
238  if ( layer()->hasScaleBasedVisibility() &&
239  ( layer()->minimumScale() > mCanvas->mapRenderer()->scale() ||
240  layer()->maximumScale() <= mCanvas->mapRenderer()->scale() ) )
241  {
242  QgsDebugMsg( "Out of scale limits" );
243  }
244  else
245  {
246  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
247  {
248  // setup scale
249  // mapRenderer()->renderContext()->scale is not automaticaly updated when
250  // render extent changes (because it's scale is used to identify if changed
251  // since last render) -> use local context
252  renderContext.setExtent( mCanvas->mapRenderer()->rendererContext()->extent() );
253  renderContext.setMapToPixel( mCanvas->mapRenderer()->rendererContext()->mapToPixel() );
254  renderContext.setRendererScale( mCanvas->mapRenderer()->scale() );
255  }
256 
257  filter = renderer && renderer->capabilities() & QgsFeatureRendererV2::Filter;
258  }
259 
260  renderer->startRender( renderContext, layer() );
261 
262  QgsFeatureIterator features = masterModel()->layerCache()->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setFilterRect( rect ) );
263 
264  QgsFeature f;
265 
266  while ( features.nextFeature( f ) )
267  {
268  if ( !filter || renderer->willRenderFeature( f ) )
269  {
270  mFilteredFeatures << f.id();
271  }
272 #if 0
273  if ( t.elapsed() > 5000 )
274  {
275  bool cancel = false;
276  emit progress( i, cancel );
277  if ( cancel )
278  break;
279 
280  t.restart();
281  }
282 #endif
283  }
284 
285  features.close();
286 
287  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
288  {
289  renderer->stopRender( renderContext );
290  }
291 }
292 
294 {
295  return masterModel()->rowToId( mapToSource( row ).row() );
296 }
297 
299 {
300  return mapFromMaster( masterModel()->idToIndex( fid ) );
301 }
302 
304 {
305  QModelIndexList indexes;
306  foreach ( QModelIndex idx, masterModel()->idToIndexList( fid ) )
307  {
308  indexes.append( mapFromMaster( idx ) );
309  }
310 
311  return indexes;
312 }
313 
314 QModelIndex QgsAttributeTableFilterModel::mapToMaster( const QModelIndex &proxyIndex ) const
315 {
316  // Master is source
317  return mapToSource( proxyIndex );
318 }
319 
320 QModelIndex QgsAttributeTableFilterModel::mapFromMaster( const QModelIndex &sourceIndex ) const
321 {
322  // Master is source
323  return mapFromSource( sourceIndex );
324 }