QGIS API Documentation  2.14.0-Essen
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 
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 
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 
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  Q_FOREACH ( QgsComposerTableColumn* currentColumn, *mComposerTable->columns() )
391  {
392  if ( currentColumn->sortByRank() > 0 )
393  {
394  sortedColumns.append( currentColumn );
395  }
396  }
397  qStableSort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );
398  int columnPos = sortedColumns.indexOf( column );
399 
400  if (( columnPos == 0 && direction == ShiftUp )
401  || (( columnPos == sortedColumns.length() - 1 ) && direction == ShiftDown ) )
402  {
403  //column already at start/end
404  return false;
405  }
406 
407  QgsComposerTableColumn* swapColumn = direction == ShiftUp ?
408  sortedColumns[ columnPos - 1]
409  : sortedColumns[ columnPos + 1];
410  QModelIndex idx = indexFromColumn( column );
411  QModelIndex idxSwap = indexFromColumn( swapColumn );
412 
413  //now swap sort ranks
414  int oldSortRank = column->sortByRank();
415  column->setSortByRank( swapColumn->sortByRank() );
416  emit dataChanged( idx, idx );
417 
418  swapColumn->setSortByRank( oldSortRank );
419  emit dataChanged( idxSwap, idxSwap );
420 
421  return true;
422 }
423 
424 
425 
426 //QgsComposerTableSortColumnsProxyModel
427 
429  : QSortFilterProxyModel( parent )
430  , mComposerTable( composerTable )
431  , mFilterType( filterType )
432 {
433  setDynamicSortFilter( true );
434 }
435 
437 {
438 
439 }
440 
441 bool QgsComposerTableSortColumnsProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
442 {
443  //get QgsComposerTableColumn corresponding to row
444  QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
446 
447  if ( !column )
448  {
449  return false;
450  }
451 
452  if (( column->sortByRank() > 0 && mFilterType == ShowSortedColumns )
453  || ( column->sortByRank() <= 0 && mFilterType == ShowUnsortedColumns ) )
454  {
455  //column matches filter type
456  return true;
457  }
458  else
459  {
460  return false;
461  }
462 }
463 
465 {
466  //get column corresponding to an index from the proxy
467  QModelIndex sourceIndex = mapToSource( index );
468  return columnFromSourceIndex( sourceIndex );
469 }
470 
472 {
473  //get column corresponding to an index from the source model
474  QVariant columnAsVariant = sourceModel()->data( sourceIndex, Qt::UserRole );
475  QgsComposerTableColumn* column = qobject_cast<QgsComposerTableColumn *>( columnAsVariant.value<QObject *>() );
476  return column;
477 }
478 
480 {
482  QgsComposerTableColumn* column2 = columnFromSourceIndex( right );
483  if ( !column1 )
484  {
485  return false;
486  }
487  if ( !column2 )
488  {
489  return true;
490  }
491  return column1->sortByRank() < column2->sortByRank();
492 }
493 
495 {
496  Q_UNUSED( parent );
497  return 2;
498 }
499 
501 {
502  if (( role != Qt::DisplayRole && role != Qt::EditRole ) || !index.isValid() )
503  {
504  return QVariant();
505  }
506 
507  QgsComposerTableColumn* column = columnFromIndex( index );
508  if ( !column )
509  {
510  return QVariant();
511  }
512 
513  switch ( index.column() )
514  {
515  case 0:
516  return column->attribute();
517  case 1:
518  if ( role == Qt::DisplayRole )
519  {
520  switch ( column->sortOrder() )
521  {
522  case Qt::DescendingOrder:
523  return tr( "Descending" );
524  case Qt::AscendingOrder:
525  default:
526  return tr( "Ascending" );
527  }
528  }
529  else
530  {
531  //edit role
532  return column->sortOrder();
533  }
534 
535  default:
536  return QVariant();
537  }
538 }
539 
540 QVariant QgsComposerTableSortColumnsProxyModel::headerData( int section, Qt::Orientation orientation, int role ) const
541 {
542  if ( !mComposerTable )
543  {
544  return QVariant();
545  }
546 
547  if ( role == Qt::DisplayRole )
548  {
549  if ( orientation == Qt::Vertical ) //row
550  {
551  return QVariant( section );
552  }
553  else
554  {
555  switch ( section )
556  {
557  case 0:
558  return QVariant( tr( "Attribute" ) );
559 
560  case 1:
561  return QVariant( tr( "Sort Order" ) );
562 
563  default:
564  return QVariant();
565  }
566  }
567  }
568  else
569  {
570  return QVariant();
571  }
572 }
573 
575 {
577 
578  if ( index.column() == 1 )
579  {
580  //only sort order is editable
581  flags |= Qt::ItemIsEditable;
582  }
583 
584  return flags;
585 }
586 
588 {
589  if ( !index.isValid() || role != Qt::EditRole )
590  return false;
591 
592  if ( !mComposerTable )
593  {
594  return false;
595  }
596 
597  QgsComposerTableColumn* column = columnFromIndex( index );
598  if ( !column )
599  {
600  return false;
601  }
602 
603  if ( index.column() == 1 )
604  {
605  column->setSortOrder( static_cast< Qt::SortOrder >( value.toInt() ) );
606  emit dataChanged( index, index );
607  return true;
608  }
609 
610  return false;
611 }
612 
614 {
615  QModelIndex proxyIndex = index( row, 0 );
616  return columnFromIndex( proxyIndex );
617 }
618 
620 {
621  invalidate();
622 }
bool hasIndex(int row, int column, const QModelIndex &parent) const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) 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&#39;s values.
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.
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)
QgsComposerAttributeTableColumnModel(QgsComposerAttributeTable *composerTable, QObject *parent=nullptr)
Constructor for QgsComposerAttributeTableColumnModel.
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&#39;s columns to match the vector layer&#39;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&#39;s columns to match the source layer&#39;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&#39;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
QString toString() const
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QgsComposerTableSortColumnsProxyModel(QgsComposerAttributeTable *composerTable, ColumnFilterType filterType, QObject *parent=nullptr)
Constructor for QgsComposerTableSortColumnsProxyModel.
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