QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules 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 
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 
50 {
51  Q_UNUSED( child );
52  return QModelIndex();
53 }
54 
56 {
57  if ( parent.isValid() )
58  return 0;
59 
60  return mComposerTable->columns()->length();
61 }
62 
64 {
65  Q_UNUSED( parent );
66  return 3;
67 }
68 
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 
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 ), createIndex( index.row(), 1 ) );
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 
212 {
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();
283  mComposerTable->resetColumns();
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 
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 
471 {
472  Q_UNUSED( parent );
473  return 2;
474 }
475 
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 
551 {
553 
554  if ( index.column() == 1 )
555  {
556  //only sort order is editable
557  flags |= Qt::ItemIsEditable;
558  }
559 
560  return flags;
561 }
562 
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 }
bool hasIndex(int row, int column, const QModelIndex &parent) const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
virtual QVariant data(const QModelIndex &index, int role) const override
static unsigned index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
QModelIndex index(int row, int column, const QModelIndex &parent) const override
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.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
int length() const
void removeAt(int i)
int sortByRank() const
Returns the sort rank for the column.
QgsComposerAttributeTableColumnModel(QgsComposerAttributeTable *composerTable, QObject *parent=0)
Constructor for QgsComposerAttributeTableColumnModel.
T value() const
void setColumnAsSorted(QgsComposerTableColumn *column, Qt::SortOrder order)
Sets a specified column as a sorted column in the QgsComposerAttributeTable.
T takeAt(int i)
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.
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QString tr(const char *sourceText, const char *disambiguation, int n)
QgsComposerTableColumn * columnFromSourceIndex(const QModelIndex &sourceIndex) const
Returns the QgsComposerTableColumn corresponding to an index from the source QgsComposerAttributeTabl...
int indexOf(const T &value, int from) const
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
bool isValid() const
void append(const T &value)
int toInt(bool *ok) const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
static bool columnsBySortRank(QgsComposerTableColumn *a, QgsComposerTableColumn *b)
bool isEmpty() const
void beginRemoveRows(const QModelIndex &parent, int first, int last)
int row() const
QgsComposerTableColumn * columnFromIndex(const QModelIndex &index) const
Returns the QgsComposerTableColumn corresponding to an index in the model.
void setDynamicSortFilter(bool enable)
void * internalPointer() const
virtual QVariant data(const QModelIndex &index, int role) const =0
QgsComposerTableColumn * columnFromIndex(const QModelIndex &index) const
Returns the QgsComposerTableColumn corresponding to an index in the proxy model.
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Stores properties of a column in a QgsComposerTable.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
void resetColumns()
Resets the attribute table's columns to match the vector layer's fields.
QModelIndex createIndex(int row, int column, void *ptr) const
virtual QVariant data(const QModelIndex &index, int role) const override
iterator end()
Qt::ItemFlags flags(const QModelIndex &index) const override
void beginInsertRows(const QModelIndex &parent, int first, int last)
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.
QAbstractItemModel * sourceModel() const
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) 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...
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void insert(int i, const T &value)
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
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...
int column() const
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Qt::ItemFlags flags(const QModelIndex &index) const override
QString attribute() const
Returns the attribute name or expression used for the column's values.
virtual Qt::ItemFlags flags(const QModelIndex &index) const
const_iterator constEnd() const
const_iterator constBegin() const
QObject * parent() const
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
QgsComposerTableSortColumnsProxyModel(QgsComposerAttributeTable *composerTable, ColumnFilterType filterType, QObject *parent=0)
Constructor for QgsComposerTableSortColumnsProxyModel.
QString toString() const
int columnCount(const QModelIndex &parent=QModelIndex()) const override
iterator begin()
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.
typedef ItemFlags