QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposerattributetablemodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerattributetablemodel.cpp
3  --------------------
4  begin : April 2014
5  copyright : (C) 2014 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
20 #include "qgscomposertable.h"
21 #include "qgscomposertablecolumn.h"
22 
23 
24 //QgsComposerAttributeTableColumnModel
25 
26 QgsComposerAttributeTableColumnModel::QgsComposerAttributeTableColumnModel( QgsComposerAttributeTable *composerTable, QObject *parent ) : QAbstractTableModel( parent )
27  , mComposerTable( composerTable )
28 {
29 
30 }
31 
33 {
34 
35 }
36 
37 QModelIndex QgsComposerAttributeTableColumnModel::index( int row, int column, const QModelIndex &parent ) const
38 {
39  if ( hasIndex( row, column, parent ) )
40  {
41  if (( *mComposerTable->columns() )[row] )
42  {
43  return createIndex( row, column, ( *mComposerTable->columns() )[row] );
44  }
45  }
46  return QModelIndex();
47 }
48 
49 QModelIndex QgsComposerAttributeTableColumnModel::parent( const QModelIndex &child ) const
50 {
51  Q_UNUSED( child );
52  return QModelIndex();
53 }
54 
55 int QgsComposerAttributeTableColumnModel::rowCount( const QModelIndex &parent ) const
56 {
57  if ( parent.isValid() )
58  return 0;
59 
60  return mComposerTable->columns()->length();
61 }
62 
63 int QgsComposerAttributeTableColumnModel::columnCount( const QModelIndex &parent ) const
64 {
65  Q_UNUSED( parent );
66  return 3;
67 }
68 
69 QVariant QgsComposerAttributeTableColumnModel::data( const QModelIndex &index, int role ) const
70 {
71  if ( !index.isValid() ||
72  ( role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::UserRole ) )
73  {
74  return QVariant();
75  }
76 
77  if ( index.row() >= mComposerTable->columns()->length() )
78  {
79  return QVariant();
80  }
81 
82  //get column for index
83  QgsComposerTableColumn* column = columnFromIndex( index );
84  if ( !column )
85  {
86  return QVariant();
87  }
88 
89  if ( role == Qt::UserRole )
90  {
91  //user role stores reference in column object
92  return qVariantFromValue( qobject_cast<QObject *>( column ) );
93  }
94 
95  switch ( index.column() )
96  {
97  case 0:
98  return column->attribute();
99  case 1:
100  return column->heading();
101  case 2:
102  {
103  if ( role == Qt::DisplayRole )
104  {
105  switch ( column->hAlignment() )
106  {
107  case Qt::AlignHCenter:
108  return tr( "Center" );
109  case Qt::AlignRight:
110  return tr( "Right" );
111  case Qt::AlignLeft:
112  default:
113  return tr( "Left" );
114  }
115  }
116  else
117  {
118  //edit role
119  return column->hAlignment();
120  }
121  }
122 
123  default:
124  return QVariant();
125  }
126 
127 }
128 
129 QVariant QgsComposerAttributeTableColumnModel::headerData( int section, Qt::Orientation orientation, int role ) const
130 {
131  if ( !mComposerTable )
132  {
133  return QVariant();
134  }
135 
136  if ( role == Qt::DisplayRole )
137  {
138  if ( orientation == Qt::Vertical ) //row
139  {
140  return QVariant( section );
141  }
142  else
143  {
144  switch ( section )
145  {
146  case 0:
147  return QVariant( tr( "Attribute" ) );
148 
149  case 1:
150  return QVariant( tr( "Heading" ) );
151 
152  case 2:
153  return QVariant( tr( "Alignment" ) );
154 
155  default:
156  return QVariant();
157  }
158  }
159  }
160  else
161  {
162  return QVariant();
163  }
164 }
165 
166 bool QgsComposerAttributeTableColumnModel::setData( const QModelIndex& index, const QVariant& value, int role )
167 {
168  if ( !index.isValid() || role != Qt::EditRole || !mComposerTable )
169  {
170  return false;
171  }
172  if ( index.row() >= mComposerTable->columns()->length() )
173  {
174  return false;
175  }
176 
177  //get column for index
178  QgsComposerTableColumn* column = columnFromIndex( index );
179  if ( !column )
180  {
181  return false;
182  }
183 
184  switch ( index.column() )
185  {
186  case 0:
187  // also update column's heading, if it hasn't been customised
188  if ( column->heading().isEmpty() || ( column->heading() == column->attribute() ) )
189  {
190  column->setHeading( value.toString() );
191  emit dataChanged( createIndex( index.row(), 1, 0 ), createIndex( index.row(), 1, 0 ) );
192  }
193  column->setAttribute( value.toString() );
194  emit dataChanged( index, index );
195  return true;
196  case 1:
197  column->setHeading( value.toString() );
198  emit dataChanged( index, index );
199  return true;
200  case 2:
201  column->setHAlignment(( Qt::AlignmentFlag )value.toInt() );
202  emit dataChanged( index, index );
203  return true;
204  default:
205  break;
206  }
207 
208  return false;
209 }
210 
211 Qt::ItemFlags QgsComposerAttributeTableColumnModel::flags( const QModelIndex& index ) const
212 {
213  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
214 
215  if ( index.isValid() )
216  {
217  return flags | Qt::ItemIsEditable;
218  }
219  else
220  {
221  return flags;
222  }
223 }
224 
225 bool QgsComposerAttributeTableColumnModel::removeRows( int row, int count, const QModelIndex& parent )
226 {
227  Q_UNUSED( parent );
228 
229  int maxRow = qMin( row + count - 1, mComposerTable->columns()->length() - 1 );
230  beginRemoveRows( QModelIndex(), row, maxRow );
231  //move backwards through rows, removing each corresponding QgsComposerTableColumn
232  for ( int i = maxRow; i >= row; --i )
233  {
234  delete( *mComposerTable->columns() )[i];
235  mComposerTable->columns()->removeAt( i );
236  }
237  endRemoveRows();
238  return true;
239 }
240 
241 bool QgsComposerAttributeTableColumnModel::insertRows( int row, int count, const QModelIndex& parent )
242 {
243  Q_UNUSED( parent );
244  beginInsertRows( QModelIndex(), row, row + count - 1 );
245  //create new QgsComposerTableColumns for each inserted row
246  for ( int i = row; i < row + count; ++i )
247  {
249  mComposerTable->columns()->insert( i, col );
250  }
251  endInsertRows();
252  return true;
253 }
254 
256 {
257  if (( direction == ShiftUp && row <= 0 ) ||
258  ( direction == ShiftDown && row >= rowCount() - 1 ) )
259  {
260  //row is already at top/bottom
261  return false;
262  }
263 
264  //we shift a row by removing the next row up/down, then reinserting it before/after the target row
265  int swapWithRow = direction == ShiftUp ? row - 1 : row + 1;
266 
267  //remove row
268  beginRemoveRows( QModelIndex(), swapWithRow, swapWithRow );
269  QgsComposerTableColumn* temp = mComposerTable->columns()->takeAt( swapWithRow );
270  endRemoveRows();
271 
272  //insert row
273  beginInsertRows( QModelIndex(), row, row );
274  mComposerTable->columns()->insert( row, temp );
275  endInsertRows();
276 
277  return true;
278 }
279 
281 {
282  beginResetModel();
284  endResetModel();
285 }
286 
288 {
289  QgsComposerTableColumn* column = static_cast<QgsComposerTableColumn*>( index.internalPointer() );
290  return column;
291 }
292 
294 {
295  if ( !mComposerTable )
296  {
297  return QModelIndex();
298  }
299 
300  int r = mComposerTable->columns()->indexOf( column );
301 
302  QModelIndex idx = index( r, 0, QModelIndex() );
303  if ( idx.isValid() )
304  {
305  return idx;
306  }
307 
308  return QModelIndex();
309 }
310 
312 {
313  if ( !column || !mComposerTable )
314  {
315  return;
316  }
317 
318  //find current highest sort by rank
319  int highestRank = 0;
320  QList<QgsComposerTableColumn*>::const_iterator columnIt = mComposerTable->columns()->constBegin();
321  for ( ; columnIt != mComposerTable->columns()->constEnd(); ++columnIt )
322  {
323  highestRank = qMax( highestRank, ( *columnIt )->sortByRank() );
324  }
325 
326  column->setSortByRank( highestRank + 1 );
327  column->setSortOrder( order );
328 
329  QModelIndex idx = indexFromColumn( column );
330  emit dataChanged( idx, idx );
331 }
332 
334 {
335  if ( !mComposerTable || !column )
336  {
337  return;
338  }
339 
340  column->setSortByRank( 0 );
341  QModelIndex idx = indexFromColumn( column );
342  emit dataChanged( idx, idx );
343 }
344 
346 {
347  return a->sortByRank() < b->sortByRank();
348 }
349 
351 {
352  if ( !mComposerTable || !column )
353  {
354  return false;
355  }
356  if (( direction == ShiftUp && column->sortByRank() <= 1 )
357  || ( direction == ShiftDown && column->sortByRank() <= 0 ) )
358  {
359  //already at start/end of list or not being used for sort
360  return false;
361  }
362 
363  //find column before this one in sort order
364  QList<QgsComposerTableColumn*> sortedColumns;
365  QList<QgsComposerTableColumn*>::iterator columnIt = mComposerTable->columns()->begin();
366  for ( ; columnIt != mComposerTable->columns()->end(); ++columnIt )
367  {
368  if (( *columnIt )->sortByRank() > 0 )
369  {
370  sortedColumns.append( *columnIt );
371  }
372  }
373  qStableSort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );
374  int columnPos = sortedColumns.indexOf( column );
375 
376  if (( columnPos == 0 && direction == ShiftUp )
377  || (( columnPos == sortedColumns.length() - 1 ) && direction == ShiftDown ) )
378  {
379  //column already at start/end
380  return false;
381  }
382 
383  QgsComposerTableColumn* swapColumn = direction == ShiftUp ?
384  sortedColumns[ columnPos - 1]
385  : sortedColumns[ columnPos + 1];
386  QModelIndex idx = indexFromColumn( column );
387  QModelIndex idxSwap = indexFromColumn( swapColumn );
388 
389  //now swap sort ranks
390  int oldSortRank = column->sortByRank();
391  column->setSortByRank( swapColumn->sortByRank() );
392  emit dataChanged( idx, idx );
393 
394  swapColumn->setSortByRank( oldSortRank );
395  emit dataChanged( idxSwap, idxSwap );
396 
397  return true;
398 }
399 
400 
401 
402 //QgsComposerTableSortColumnsProxyModel
403 
405  : QSortFilterProxyModel( parent )
406  , mComposerTable( composerTable )
407  , mFilterType( filterType )
408 {
409  setDynamicSortFilter( true );
410 }
411 
413 {
414 
415 }
416 
417 bool QgsComposerTableSortColumnsProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
418 {
419  //get QgsComposerTableColumn corresponding to row
420  QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
422 
423  if ( !column )
424  {
425  return false;
426  }
427 
428  if (( column->sortByRank() > 0 && mFilterType == ShowSortedColumns )
429  || ( column->sortByRank() <= 0 && mFilterType == ShowUnsortedColumns ) )
430  {
431  //column matches filter type
432  return true;
433  }
434  else
435  {
436  return false;
437  }
438 }
439 
441 {
442  //get column corresponding to an index from the proxy
443  QModelIndex sourceIndex = mapToSource( index );
444  return columnFromSourceIndex( sourceIndex );
445 }
446 
448 {
449  //get column corresponding to an index from the source model
450  QVariant columnAsVariant = sourceModel()->data( sourceIndex, Qt::UserRole );
451  QgsComposerTableColumn* column = qobject_cast<QgsComposerTableColumn *>( columnAsVariant.value<QObject *>() );
452  return column;
453 }
454 
455 bool QgsComposerTableSortColumnsProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
456 {
458  QgsComposerTableColumn* column2 = columnFromSourceIndex( right );
459  if ( !column1 )
460  {
461  return false;
462  }
463  if ( !column2 )
464  {
465  return true;
466  }
467  return column1->sortByRank() < column2->sortByRank();
468 }
469 
470 int QgsComposerTableSortColumnsProxyModel::columnCount( const QModelIndex &parent ) const
471 {
472  Q_UNUSED( parent );
473  return 2;
474 }
475 
476 QVariant QgsComposerTableSortColumnsProxyModel::data( const QModelIndex &index, int role ) const
477 {
478  if (( role != Qt::DisplayRole && role != Qt::EditRole ) || !index.isValid() )
479  {
480  return QVariant();
481  }
482 
483  QgsComposerTableColumn* column = columnFromIndex( index );
484  if ( !column )
485  {
486  return QVariant();
487  }
488 
489  switch ( index.column() )
490  {
491  case 0:
492  return column->attribute();
493  case 1:
494  if ( role == Qt::DisplayRole )
495  {
496  switch ( column->sortOrder() )
497  {
498  case Qt::DescendingOrder:
499  return tr( "Descending" );
500  case Qt::AscendingOrder:
501  default:
502  return tr( "Ascending" );
503  }
504  }
505  else
506  {
507  //edit role
508  return column->sortOrder();
509  }
510 
511  default:
512  return QVariant();
513  }
514 }
515 
516 QVariant QgsComposerTableSortColumnsProxyModel::headerData( int section, Qt::Orientation orientation, int role ) const
517 {
518  if ( !mComposerTable )
519  {
520  return QVariant();
521  }
522 
523  if ( role == Qt::DisplayRole )
524  {
525  if ( orientation == Qt::Vertical ) //row
526  {
527  return QVariant( section );
528  }
529  else
530  {
531  switch ( section )
532  {
533  case 0:
534  return QVariant( tr( "Attribute" ) );
535 
536  case 1:
537  return QVariant( tr( "Sort Order" ) );
538 
539  default:
540  return QVariant();
541  }
542  }
543  }
544  else
545  {
546  return QVariant();
547  }
548 }
549 
550 Qt::ItemFlags QgsComposerTableSortColumnsProxyModel::flags( const QModelIndex& index ) const
551 {
552  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
553 
554  if ( index.column() == 1 )
555  {
556  //only sort order is editable
557  flags |= Qt::ItemIsEditable;
558  }
559 
560  return flags;
561 }
562 
563 bool QgsComposerTableSortColumnsProxyModel::setData( const QModelIndex& index, const QVariant& value, int role )
564 {
565  if ( !index.isValid() || role != Qt::EditRole )
566  return false;
567 
568  if ( !mComposerTable )
569  {
570  return false;
571  }
572 
573  QgsComposerTableColumn* column = columnFromIndex( index );
574  if ( !column )
575  {
576  return false;
577  }
578 
579  if ( index.column() == 1 )
580  {
581  column->setSortOrder(( Qt::SortOrder )value.toInt() );
582  emit dataChanged( index, index );
583  return true;
584  }
585 
586  return false;
587 }
588 
590 {
591  QModelIndex proxyIndex = index( row, 0 );
592  return columnFromIndex( proxyIndex );
593 }
594 
596 {
597  invalidate();
598 }
static unsigned index
bool lessThan(const QModelIndex &left, const QModelIndex &right) const
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
QgsComposerTableColumn * columnFromRow(int row)
Returns the QgsComposerTableColumn corresponding to a row in the proxy model.
void setAttribute(QString attribute)
Sets the attribute name or expression used for the column's values.
virtual QVariant data(const QModelIndex &index, int role) const
QModelIndex index(int row, int column, const QModelIndex &parent) const
int sortByRank() const
Returns the sort rank for the column.
QgsComposerAttributeTableColumnModel(QgsComposerAttributeTable *composerTable, QObject *parent=0)
Constructor for QgsComposerAttributeTableColumnModel.
void setColumnAsSorted(QgsComposerTableColumn *column, Qt::SortOrder order)
Sets a specified column as a sorted column in the QgsComposerAttributeTable.
Qt::SortOrder sortOrder() const
Returns the sort order for the column.
QList< QgsComposerTableColumn * > * columns()
Returns a pointer to the list of QgsComposerTableColumns shown in the table.
void setHeading(QString heading)
Sets the heading for a column, which is the value displayed in the columns header cell...
void setHAlignment(Qt::AlignmentFlag alignment)
Sets the horizontal alignment for a column, which controls the alignment used for drawing column valu...
bool moveRow(int row, ShiftDirection direction)
Moves the specified row up or down in the model.
QgsComposerTableColumn * columnFromSourceIndex(const QModelIndex &sourceIndex) const
Returns the QgsComposerTableColumn corresponding to an index from the source QgsComposerAttributeTabl...
Qt::ItemFlags flags(const QModelIndex &index) const
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
int columnCount(const QModelIndex &parent=QModelIndex()) const
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
QModelIndex parent(const QModelIndex &child) const
static bool columnsBySortRank(QgsComposerTableColumn *a, QgsComposerTableColumn *b)
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
Qt::ItemFlags flags(const QModelIndex &index) const
QgsComposerTableColumn * columnFromIndex(const QModelIndex &index) const
Returns the QgsComposerTableColumn corresponding to an index in the model.
virtual QVariant data(const QModelIndex &index, int role) const
QgsComposerTableColumn * columnFromIndex(const QModelIndex &index) const
Returns the QgsComposerTableColumn corresponding to an index in the proxy model.
Stores properties of a column in a QgsComposerTable.
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
void resetColumns()
Resets the attribute table's columns to match the vector layer's fields.
void resetToLayer()
Resets the attribute table's columns to match the source layer's fields.
QModelIndex indexFromColumn(QgsComposerTableColumn *column)
Returns a QModelIndex corresponding to a QgsComposerTableColumn in the model.
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
int columnCount(const QModelIndex &parent=QModelIndex()) const
A table class that displays a vector attribute table.
bool moveColumnInSortRank(QgsComposerTableColumn *column, ShiftDirection direction)
Moves a column up or down in the sort rank for the QgsComposerAttributeTable.
QString heading() const
Returns the heading for a column, which is the value displayed in the columns header cell...
void setSortOrder(Qt::SortOrder sortOrder)
Sets the sort order for the column.
Qt::AlignmentFlag hAlignment() const
Returns the horizontal alignment for a column, which controls the alignment used for drawing column v...
QString attribute() const
Returns the attribute name or expression used for the column's values.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
QgsComposerTableSortColumnsProxyModel(QgsComposerAttributeTable *composerTable, ColumnFilterType filterType, QObject *parent=0)
Constructor for QgsComposerTableSortColumnsProxyModel.
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex())
void setColumnAsUnsorted(QgsComposerTableColumn *column)
Sets a specified column as an unsorted column in the QgsComposerAttributeTable.
void setSortByRank(int sortByRank)
Sets the sort rank for the column.
void resetFilter()
Invalidates the current filter used by the proxy model.
#define tr(sourceText)