QGIS API Documentation  2.12.0-Lyon
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  switch ( column->vAlignment() )
109  {
110  case Qt::AlignTop:
111  return tr( "Top center" );
112  case Qt::AlignBottom:
113  return tr( "Bottom center" );
114  default:
115  return tr( "Middle center" );
116  }
117  case Qt::AlignRight:
118  switch ( column->vAlignment() )
119  {
120  case Qt::AlignTop:
121  return tr( "Top right" );
122  case Qt::AlignBottom:
123  return tr( "Bottom right" );
124  default:
125  return tr( "Middle right" );
126  }
127  case Qt::AlignLeft:
128  default:
129  switch ( column->vAlignment() )
130  {
131  case Qt::AlignTop:
132  return tr( "Top left" );
133  case Qt::AlignBottom:
134  return tr( "Bottom left" );
135  default:
136  return tr( "Middle left" );
137  }
138  }
139  }
140  else
141  {
142  //edit role
143  return int( column->hAlignment() | column->vAlignment() );
144  }
145  }
146 
147  default:
148  return QVariant();
149  }
150 
151 }
152 
153 QVariant QgsComposerAttributeTableColumnModel::headerData( int section, Qt::Orientation orientation, int role ) const
154 {
155  if ( !mComposerTable )
156  {
157  return QVariant();
158  }
159 
160  if ( role == Qt::DisplayRole )
161  {
162  if ( orientation == Qt::Vertical ) //row
163  {
164  return QVariant( section );
165  }
166  else
167  {
168  switch ( section )
169  {
170  case 0:
171  return QVariant( tr( "Attribute" ) );
172 
173  case 1:
174  return QVariant( tr( "Heading" ) );
175 
176  case 2:
177  return QVariant( tr( "Alignment" ) );
178 
179  default:
180  return QVariant();
181  }
182  }
183  }
184  else
185  {
186  return QVariant();
187  }
188 }
189 
191 {
192  if ( !index.isValid() || role != Qt::EditRole || !mComposerTable )
193  {
194  return false;
195  }
196  if ( index.row() >= mComposerTable->columns()->length() )
197  {
198  return false;
199  }
200 
201  //get column for index
202  QgsComposerTableColumn* column = columnFromIndex( index );
203  if ( !column )
204  {
205  return false;
206  }
207 
208  switch ( index.column() )
209  {
210  case 0:
211  // also update column's heading, if it hasn't been customised
212  if ( column->heading().isEmpty() || ( column->heading() == column->attribute() ) )
213  {
214  column->setHeading( value.toString() );
215  emit dataChanged( createIndex( index.row(), 1 ), createIndex( index.row(), 1 ) );
216  }
217  column->setAttribute( value.toString() );
218  emit dataChanged( index, index );
219  return true;
220  case 1:
221  column->setHeading( value.toString() );
222  emit dataChanged( index, index );
223  return true;
224  case 2:
225  column->setHAlignment( Qt::AlignmentFlag( value.toInt() & Qt::AlignHorizontal_Mask ) );
226  column->setVAlignment( Qt::AlignmentFlag( value.toInt() & Qt::AlignVertical_Mask ) );
227  emit dataChanged( index, index );
228  return true;
229  default:
230  break;
231  }
232 
233  return false;
234 }
235 
237 {
239 
240  if ( index.isValid() )
241  {
242  return flags | Qt::ItemIsEditable;
243  }
244  else
245  {
246  return flags;
247  }
248 }
249 
250 bool QgsComposerAttributeTableColumnModel::removeRows( int row, int count, const QModelIndex& parent )
251 {
252  Q_UNUSED( parent );
253 
254  int maxRow = qMin( row + count - 1, mComposerTable->columns()->length() - 1 );
255  beginRemoveRows( QModelIndex(), row, maxRow );
256  //move backwards through rows, removing each corresponding QgsComposerTableColumn
257  for ( int i = maxRow; i >= row; --i )
258  {
259  delete( *mComposerTable->columns() )[i];
260  mComposerTable->columns()->removeAt( i );
261  }
262  endRemoveRows();
263  return true;
264 }
265 
266 bool QgsComposerAttributeTableColumnModel::insertRows( int row, int count, const QModelIndex& parent )
267 {
268  Q_UNUSED( parent );
269  beginInsertRows( QModelIndex(), row, row + count - 1 );
270  //create new QgsComposerTableColumns for each inserted row
271  for ( int i = row; i < row + count; ++i )
272  {
274  mComposerTable->columns()->insert( i, col );
275  }
276  endInsertRows();
277  return true;
278 }
279 
281 {
282  if (( direction == ShiftUp && row <= 0 ) ||
283  ( direction == ShiftDown && row >= rowCount() - 1 ) )
284  {
285  //row is already at top/bottom
286  return false;
287  }
288 
289  //we shift a row by removing the next row up/down, then reinserting it before/after the target row
290  int swapWithRow = direction == ShiftUp ? row - 1 : row + 1;
291 
292  //remove row
293  beginRemoveRows( QModelIndex(), swapWithRow, swapWithRow );
294  QgsComposerTableColumn* temp = mComposerTable->columns()->takeAt( swapWithRow );
295  endRemoveRows();
296 
297  //insert row
298  beginInsertRows( QModelIndex(), row, row );
299  mComposerTable->columns()->insert( row, temp );
300  endInsertRows();
301 
302  return true;
303 }
304 
306 {
307  beginResetModel();
308  mComposerTable->resetColumns();
309  endResetModel();
310 }
311 
313 {
314  QgsComposerTableColumn* column = static_cast<QgsComposerTableColumn*>( index.internalPointer() );
315  return column;
316 }
317 
319 {
320  if ( !mComposerTable )
321  {
322  return QModelIndex();
323  }
324 
325  int r = mComposerTable->columns()->indexOf( column );
326 
327  QModelIndex idx = index( r, 0, QModelIndex() );
328  if ( idx.isValid() )
329  {
330  return idx;
331  }
332 
333  return QModelIndex();
334 }
335 
337 {
338  if ( !column || !mComposerTable )
339  {
340  return;
341  }
342 
343  //find current highest sort by rank
344  int highestRank = 0;
345  QList<QgsComposerTableColumn*>::const_iterator columnIt = mComposerTable->columns()->constBegin();
346  for ( ; columnIt != mComposerTable->columns()->constEnd(); ++columnIt )
347  {
348  highestRank = qMax( highestRank, ( *columnIt )->sortByRank() );
349  }
350 
351  column->setSortByRank( highestRank + 1 );
352  column->setSortOrder( order );
353 
354  QModelIndex idx = indexFromColumn( column );
355  emit dataChanged( idx, idx );
356 }
357 
359 {
360  if ( !mComposerTable || !column )
361  {
362  return;
363  }
364 
365  column->setSortByRank( 0 );
366  QModelIndex idx = indexFromColumn( column );
367  emit dataChanged( idx, idx );
368 }
369 
371 {
372  return a->sortByRank() < b->sortByRank();
373 }
374 
376 {
377  if ( !mComposerTable || !column )
378  {
379  return false;
380  }
381  if (( direction == ShiftUp && column->sortByRank() <= 1 )
382  || ( direction == ShiftDown && column->sortByRank() <= 0 ) )
383  {
384  //already at start/end of list or not being used for sort
385  return false;
386  }
387 
388  //find column before this one in sort order
389  QList<QgsComposerTableColumn*> sortedColumns;
390  QList<QgsComposerTableColumn*>::iterator columnIt = mComposerTable->columns()->begin();
391  for ( ; columnIt != mComposerTable->columns()->end(); ++columnIt )
392  {
393  if (( *columnIt )->sortByRank() > 0 )
394  {
395  sortedColumns.append( *columnIt );
396  }
397  }
398  qStableSort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );
399  int columnPos = sortedColumns.indexOf( column );
400 
401  if (( columnPos == 0 && direction == ShiftUp )
402  || (( columnPos == sortedColumns.length() - 1 ) && direction == ShiftDown ) )
403  {
404  //column already at start/end
405  return false;
406  }
407 
408  QgsComposerTableColumn* swapColumn = direction == ShiftUp ?
409  sortedColumns[ columnPos - 1]
410  : sortedColumns[ columnPos + 1];
411  QModelIndex idx = indexFromColumn( column );
412  QModelIndex idxSwap = indexFromColumn( swapColumn );
413 
414  //now swap sort ranks
415  int oldSortRank = column->sortByRank();
416  column->setSortByRank( swapColumn->sortByRank() );
417  emit dataChanged( idx, idx );
418 
419  swapColumn->setSortByRank( oldSortRank );
420  emit dataChanged( idxSwap, idxSwap );
421 
422  return true;
423 }
424 
425 
426 
427 //QgsComposerTableSortColumnsProxyModel
428 
430  : QSortFilterProxyModel( parent )
431  , mComposerTable( composerTable )
432  , mFilterType( filterType )
433 {
434  setDynamicSortFilter( true );
435 }
436 
438 {
439 
440 }
441 
442 bool QgsComposerTableSortColumnsProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
443 {
444  //get QgsComposerTableColumn corresponding to row
445  QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
447 
448  if ( !column )
449  {
450  return false;
451  }
452 
453  if (( column->sortByRank() > 0 && mFilterType == ShowSortedColumns )
454  || ( column->sortByRank() <= 0 && mFilterType == ShowUnsortedColumns ) )
455  {
456  //column matches filter type
457  return true;
458  }
459  else
460  {
461  return false;
462  }
463 }
464 
466 {
467  //get column corresponding to an index from the proxy
468  QModelIndex sourceIndex = mapToSource( index );
469  return columnFromSourceIndex( sourceIndex );
470 }
471 
473 {
474  //get column corresponding to an index from the source model
475  QVariant columnAsVariant = sourceModel()->data( sourceIndex, Qt::UserRole );
476  QgsComposerTableColumn* column = qobject_cast<QgsComposerTableColumn *>( columnAsVariant.value<QObject *>() );
477  return column;
478 }
479 
481 {
483  QgsComposerTableColumn* column2 = columnFromSourceIndex( right );
484  if ( !column1 )
485  {
486  return false;
487  }
488  if ( !column2 )
489  {
490  return true;
491  }
492  return column1->sortByRank() < column2->sortByRank();
493 }
494 
496 {
497  Q_UNUSED( parent );
498  return 2;
499 }
500 
502 {
503  if (( role != Qt::DisplayRole && role != Qt::EditRole ) || !index.isValid() )
504  {
505  return QVariant();
506  }
507 
508  QgsComposerTableColumn* column = columnFromIndex( index );
509  if ( !column )
510  {
511  return QVariant();
512  }
513 
514  switch ( index.column() )
515  {
516  case 0:
517  return column->attribute();
518  case 1:
519  if ( role == Qt::DisplayRole )
520  {
521  switch ( column->sortOrder() )
522  {
523  case Qt::DescendingOrder:
524  return tr( "Descending" );
525  case Qt::AscendingOrder:
526  default:
527  return tr( "Ascending" );
528  }
529  }
530  else
531  {
532  //edit role
533  return column->sortOrder();
534  }
535 
536  default:
537  return QVariant();
538  }
539 }
540 
541 QVariant QgsComposerTableSortColumnsProxyModel::headerData( int section, Qt::Orientation orientation, int role ) const
542 {
543  if ( !mComposerTable )
544  {
545  return QVariant();
546  }
547 
548  if ( role == Qt::DisplayRole )
549  {
550  if ( orientation == Qt::Vertical ) //row
551  {
552  return QVariant( section );
553  }
554  else
555  {
556  switch ( section )
557  {
558  case 0:
559  return QVariant( tr( "Attribute" ) );
560 
561  case 1:
562  return QVariant( tr( "Sort Order" ) );
563 
564  default:
565  return QVariant();
566  }
567  }
568  }
569  else
570  {
571  return QVariant();
572  }
573 }
574 
576 {
578 
579  if ( index.column() == 1 )
580  {
581  //only sort order is editable
582  flags |= Qt::ItemIsEditable;
583  }
584 
585  return flags;
586 }
587 
589 {
590  if ( !index.isValid() || role != Qt::EditRole )
591  return false;
592 
593  if ( !mComposerTable )
594  {
595  return false;
596  }
597 
598  QgsComposerTableColumn* column = columnFromIndex( index );
599  if ( !column )
600  {
601  return false;
602  }
603 
604  if ( index.column() == 1 )
605  {
606  column->setSortOrder(( Qt::SortOrder )value.toInt() );
607  emit dataChanged( index, index );
608  return true;
609  }
610 
611  return false;
612 }
613 
615 {
616  QModelIndex proxyIndex = index( row, 0 );
617  return columnFromIndex( proxyIndex );
618 }
619 
621 {
622  invalidate();
623 }
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
void setAttribute(const QString &attribute)
Sets the attribute name or expression used for the column's values.
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.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
int length() const
Qt::AlignmentFlag vAlignment() const
Returns the vertical alignment for a column, which controls the alignment used for drawing column val...
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.
ShiftDirection
Controls whether a row/column is shifted up or down.
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)
void setHeading(const QString &heading)
Sets the heading for a column, which is the value displayed in the columns header cell...
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)
ColumnFilterType
Controls whether the proxy model shows sorted or unsorted columns.
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.
void setVAlignment(Qt::AlignmentFlag alignment)
Sets the vertical alignment for a column, which controls the alignment used for drawing column values...
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