QGIS API Documentation  2.12.0-Lyon
qgscomposerattributetablemodelv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerattributetablemodelv2.cpp
3  --------------------
4  begin : September 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 "qgscomposertablev2.h"
21 #include "qgscomposertablecolumn.h"
22 
23 
24 //QgsComposerAttributeTableColumnModelV2V2
25 
27  , mComposerTable( composerTable )
28 {
29 
30 }
31 
33 {
34 
35 }
36 
37 QModelIndex QgsComposerAttributeTableColumnModelV2::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 4;
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  case 3:
147  {
148  if ( role == Qt::DisplayRole )
149  {
150  return column->width() <= 0 ? tr( "Automatic" ) : QString( tr( "%1 mm" ) ).arg( column->width(), 0, 'f', 2 );
151  }
152  else
153  {
154  //edit role
155  return column->width();
156  }
157  }
158  default:
159  return QVariant();
160  }
161 
162 }
163 
164 QVariant QgsComposerAttributeTableColumnModelV2::headerData( int section, Qt::Orientation orientation, int role ) const
165 {
166  if ( !mComposerTable )
167  {
168  return QVariant();
169  }
170 
171  if ( role == Qt::DisplayRole )
172  {
173  if ( orientation == Qt::Vertical ) //row
174  {
175  return QVariant( section );
176  }
177  else
178  {
179  switch ( section )
180  {
181  case 0:
182  return QVariant( tr( "Attribute" ) );
183 
184  case 1:
185  return QVariant( tr( "Heading" ) );
186 
187  case 2:
188  return QVariant( tr( "Alignment" ) );
189 
190  case 3:
191  return QVariant( tr( "Width" ) );
192 
193  default:
194  return QVariant();
195  }
196  }
197  }
198  else
199  {
200  return QVariant();
201  }
202 }
203 
205 {
206  if ( !index.isValid() || role != Qt::EditRole || !mComposerTable )
207  {
208  return false;
209  }
210  if ( index.row() >= mComposerTable->columns()->length() )
211  {
212  return false;
213  }
214 
215  //get column for index
216  QgsComposerTableColumn* column = columnFromIndex( index );
217  if ( !column )
218  {
219  return false;
220  }
221 
222  switch ( index.column() )
223  {
224  case 0:
225  // also update column's heading, if it hasn't been customised
226  if ( column->heading().isEmpty() || ( column->heading() == column->attribute() ) )
227  {
228  column->setHeading( value.toString() );
229  emit dataChanged( createIndex( index.row(), 1 ), createIndex( index.row(), 1 ) );
230  }
231  column->setAttribute( value.toString() );
232  emit dataChanged( index, index );
233  return true;
234  case 1:
235  column->setHeading( value.toString() );
236  emit dataChanged( index, index );
237  return true;
238  case 2:
239  column->setHAlignment( Qt::AlignmentFlag( value.toInt() & Qt::AlignHorizontal_Mask ) );
240  column->setVAlignment( Qt::AlignmentFlag( value.toInt() & Qt::AlignVertical_Mask ) );
241  emit dataChanged( index, index );
242  return true;
243  case 3:
244  column->setWidth( value.toDouble() );
245  emit dataChanged( index, index );
246  return true;
247  default:
248  break;
249  }
250 
251  return false;
252 }
253 
255 {
257 
258  if ( index.isValid() )
259  {
260  return flags | Qt::ItemIsEditable;
261  }
262  else
263  {
264  return flags;
265  }
266 }
267 
268 bool QgsComposerAttributeTableColumnModelV2::removeRows( int row, int count, const QModelIndex& parent )
269 {
270  Q_UNUSED( parent );
271 
272  int maxRow = qMin( row + count - 1, mComposerTable->columns()->length() - 1 );
273  beginRemoveRows( QModelIndex(), row, maxRow );
274  //move backwards through rows, removing each corresponding QgsComposerTableColumn
275  for ( int i = maxRow; i >= row; --i )
276  {
277  delete( *mComposerTable->columns() )[i];
278  mComposerTable->columns()->removeAt( i );
279  }
280  endRemoveRows();
281  return true;
282 }
283 
284 bool QgsComposerAttributeTableColumnModelV2::insertRows( int row, int count, const QModelIndex& parent )
285 {
286  Q_UNUSED( parent );
287  beginInsertRows( QModelIndex(), row, row + count - 1 );
288  //create new QgsComposerTableColumns for each inserted row
289  for ( int i = row; i < row + count; ++i )
290  {
292  mComposerTable->columns()->insert( i, col );
293  }
294  endInsertRows();
295  return true;
296 }
297 
299 {
300  if (( direction == ShiftUp && row <= 0 ) ||
301  ( direction == ShiftDown && row >= rowCount() - 1 ) )
302  {
303  //row is already at top/bottom
304  return false;
305  }
306 
307  //we shift a row by removing the next row up/down, then reinserting it before/after the target row
308  int swapWithRow = direction == ShiftUp ? row - 1 : row + 1;
309 
310  //remove row
311  beginRemoveRows( QModelIndex(), swapWithRow, swapWithRow );
312  QgsComposerTableColumn* temp = mComposerTable->columns()->takeAt( swapWithRow );
313  endRemoveRows();
314 
315  //insert row
316  beginInsertRows( QModelIndex(), row, row );
317  mComposerTable->columns()->insert( row, temp );
318  endInsertRows();
319 
320  return true;
321 }
322 
324 {
325  beginResetModel();
326  mComposerTable->resetColumns();
327  endResetModel();
328 }
329 
331 {
332  QgsComposerTableColumn* column = static_cast<QgsComposerTableColumn*>( index.internalPointer() );
333  return column;
334 }
335 
337 {
338  if ( !mComposerTable )
339  {
340  return QModelIndex();
341  }
342 
343  int r = mComposerTable->columns()->indexOf( column );
344 
345  QModelIndex idx = index( r, 0, QModelIndex() );
346  if ( idx.isValid() )
347  {
348  return idx;
349  }
350 
351  return QModelIndex();
352 }
353 
355 {
356  if ( !column || !mComposerTable )
357  {
358  return;
359  }
360 
361  //find current highest sort by rank
362  int highestRank = 0;
363  QList<QgsComposerTableColumn*>::const_iterator columnIt = mComposerTable->columns()->constBegin();
364  for ( ; columnIt != mComposerTable->columns()->constEnd(); ++columnIt )
365  {
366  highestRank = qMax( highestRank, ( *columnIt )->sortByRank() );
367  }
368 
369  column->setSortByRank( highestRank + 1 );
370  column->setSortOrder( order );
371 
372  QModelIndex idx = indexFromColumn( column );
373  emit dataChanged( idx, idx );
374 }
375 
377 {
378  if ( !mComposerTable || !column )
379  {
380  return;
381  }
382 
383  column->setSortByRank( 0 );
384  QModelIndex idx = indexFromColumn( column );
385  emit dataChanged( idx, idx );
386 }
387 
389 {
390  return a->sortByRank() < b->sortByRank();
391 }
392 
394 {
395  if ( !mComposerTable || !column )
396  {
397  return false;
398  }
399  if (( direction == ShiftUp && column->sortByRank() <= 1 )
400  || ( direction == ShiftDown && column->sortByRank() <= 0 ) )
401  {
402  //already at start/end of list or not being used for sort
403  return false;
404  }
405 
406  //find column before this one in sort order
407  QList<QgsComposerTableColumn*> sortedColumns;
408  QList<QgsComposerTableColumn*>::iterator columnIt = mComposerTable->columns()->begin();
409  for ( ; columnIt != mComposerTable->columns()->end(); ++columnIt )
410  {
411  if (( *columnIt )->sortByRank() > 0 )
412  {
413  sortedColumns.append( *columnIt );
414  }
415  }
416  qStableSort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );
417  int columnPos = sortedColumns.indexOf( column );
418 
419  if (( columnPos == 0 && direction == ShiftUp )
420  || (( columnPos == sortedColumns.length() - 1 ) && direction == ShiftDown ) )
421  {
422  //column already at start/end
423  return false;
424  }
425 
426  QgsComposerTableColumn* swapColumn = direction == ShiftUp ?
427  sortedColumns[ columnPos - 1]
428  : sortedColumns[ columnPos + 1];
429  QModelIndex idx = indexFromColumn( column );
430  QModelIndex idxSwap = indexFromColumn( swapColumn );
431 
432  //now swap sort ranks
433  int oldSortRank = column->sortByRank();
434  column->setSortByRank( swapColumn->sortByRank() );
435  emit dataChanged( idx, idx );
436 
437  swapColumn->setSortByRank( oldSortRank );
438  emit dataChanged( idxSwap, idxSwap );
439 
440  return true;
441 }
442 
443 
444 
445 //QgsComposerTableSortColumnsProxyModelV2V2
446 
448  : QSortFilterProxyModel( parent )
449  , mComposerTable( composerTable )
450  , mFilterType( filterType )
451 {
452  setDynamicSortFilter( true );
453 }
454 
456 {
457 
458 }
459 
460 bool QgsComposerTableSortColumnsProxyModelV2::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
461 {
462  //get QgsComposerTableColumn corresponding to row
463  QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
465 
466  if ( !column )
467  {
468  return false;
469  }
470 
471  if (( column->sortByRank() > 0 && mFilterType == ShowSortedColumns )
472  || ( column->sortByRank() <= 0 && mFilterType == ShowUnsortedColumns ) )
473  {
474  //column matches filter type
475  return true;
476  }
477  else
478  {
479  return false;
480  }
481 }
482 
484 {
485  //get column corresponding to an index from the proxy
486  QModelIndex sourceIndex = mapToSource( index );
487  return columnFromSourceIndex( sourceIndex );
488 }
489 
491 {
492  //get column corresponding to an index from the source model
493  QVariant columnAsVariant = sourceModel()->data( sourceIndex, Qt::UserRole );
494  QgsComposerTableColumn* column = qobject_cast<QgsComposerTableColumn *>( columnAsVariant.value<QObject *>() );
495  return column;
496 }
497 
499 {
501  QgsComposerTableColumn* column2 = columnFromSourceIndex( right );
502  if ( !column1 )
503  {
504  return false;
505  }
506  if ( !column2 )
507  {
508  return true;
509  }
510  return column1->sortByRank() < column2->sortByRank();
511 }
512 
514 {
515  Q_UNUSED( parent );
516  return 2;
517 }
518 
520 {
521  if (( role != Qt::DisplayRole && role != Qt::EditRole ) || !index.isValid() )
522  {
523  return QVariant();
524  }
525 
526  QgsComposerTableColumn* column = columnFromIndex( index );
527  if ( !column )
528  {
529  return QVariant();
530  }
531 
532  switch ( index.column() )
533  {
534  case 0:
535  return column->attribute();
536  case 1:
537  if ( role == Qt::DisplayRole )
538  {
539  switch ( column->sortOrder() )
540  {
541  case Qt::DescendingOrder:
542  return tr( "Descending" );
543  case Qt::AscendingOrder:
544  default:
545  return tr( "Ascending" );
546  }
547  }
548  else
549  {
550  //edit role
551  return column->sortOrder();
552  }
553 
554  default:
555  return QVariant();
556  }
557 }
558 
559 QVariant QgsComposerTableSortColumnsProxyModelV2::headerData( int section, Qt::Orientation orientation, int role ) const
560 {
561  if ( !mComposerTable )
562  {
563  return QVariant();
564  }
565 
566  if ( role == Qt::DisplayRole )
567  {
568  if ( orientation == Qt::Vertical ) //row
569  {
570  return QVariant( section );
571  }
572  else
573  {
574  switch ( section )
575  {
576  case 0:
577  return QVariant( tr( "Attribute" ) );
578 
579  case 1:
580  return QVariant( tr( "Sort Order" ) );
581 
582  default:
583  return QVariant();
584  }
585  }
586  }
587  else
588  {
589  return QVariant();
590  }
591 }
592 
594 {
596 
597  if ( index.column() == 1 )
598  {
599  //only sort order is editable
600  flags |= Qt::ItemIsEditable;
601  }
602 
603  return flags;
604 }
605 
607 {
608  if ( !index.isValid() || role != Qt::EditRole )
609  return false;
610 
611  if ( !mComposerTable )
612  {
613  return false;
614  }
615 
616  QgsComposerTableColumn* column = columnFromIndex( index );
617  if ( !column )
618  {
619  return false;
620  }
621 
622  if ( index.column() == 1 )
623  {
624  column->setSortOrder(( Qt::SortOrder )value.toInt() );
625  emit dataChanged( index, index );
626  return true;
627  }
628 
629  return false;
630 }
631 
633 {
634  QModelIndex proxyIndex = index( row, 0 );
635  return columnFromIndex( proxyIndex );
636 }
637 
639 {
640  invalidate();
641 }
bool hasIndex(int row, int column, const QModelIndex &parent) const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
QgsComposerTableColumn * columnFromRow(int row)
Returns the QgsComposerTableColumn corresponding to a row in the proxy model.
void setAttribute(const QString &attribute)
Sets the attribute name or expression used for the column's values.
bool moveColumnInSortRank(QgsComposerTableColumn *column, ShiftDirection direction)
Moves a column up or down in the sort rank for the QgsComposerAttributeTable.
static unsigned index
ShiftDirection
Controls whether a row/column is shifted up or down.
virtual QVariant data(const QModelIndex &index, int role) const override
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
void setColumnAsUnsorted(QgsComposerTableColumn *column)
Sets a specified column as an unsorted column in the QgsComposerAttributeTable.
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.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
T value() const
T takeAt(int i)
static bool columnsBySortRank(QgsComposerTableColumn *a, QgsComposerTableColumn *b)
double width() const
Returns the width for a column.
Qt::SortOrder sortOrder() const
Returns the sort order for the column.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QgsComposerTableColumn * columnFromIndex(const QModelIndex &index) const
Returns the QgsComposerTableColumn corresponding to an index in the model.
void setHAlignment(Qt::AlignmentFlag alignment)
Sets the horizontal alignment for a column, which controls the alignment used for drawing column valu...
QString tr(const char *sourceText, const char *disambiguation, int n)
QgsComposerTableSortColumnsProxyModelV2(QgsComposerAttributeTableV2 *composerTable, ColumnFilterType filterType, QObject *parent=0)
Constructor for QgsComposerTableSortColumnsProxyModel.
A table that displays attributes from a vector layer.
int indexOf(const T &value, int from) const
bool isValid() const
void append(const T &value)
void resetToLayer()
Resets the attribute table's columns to match the source layer's fields.
int toInt(bool *ok) const
QModelIndex indexFromColumn(QgsComposerTableColumn *column)
Returns a QModelIndex corresponding to a QgsComposerTableColumn in the model.
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...
bool isEmpty() const
void setColumnAsSorted(QgsComposerTableColumn *column, Qt::SortOrder order)
Sets a specified column as a sorted column in the QgsComposerAttributeTable.
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 proxy model.
void setDynamicSortFilter(bool enable)
void * internalPointer() const
virtual QVariant data(const QModelIndex &index, int role) const =0
Stores properties of a column in a QgsComposerTable.
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QModelIndex index(int row, int column, const QModelIndex &parent) const override
QModelIndex createIndex(int row, int column, void *ptr) const
iterator end()
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
void beginInsertRows(const QModelIndex &parent, int first, int last)
QgsComposerAttributeTableColumnModelV2(QgsComposerAttributeTableV2 *composerTable, QObject *parent=0)
Constructor for QgsComposerAttributeTableColumnModel.
Qt::ItemFlags flags(const QModelIndex &index) const override
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
bool moveRow(int row, ShiftDirection direction)
Moves the specified row up or down in the model.
ColumnFilterType
Controls whether the proxy model shows sorted or unsorted columns.
QAbstractItemModel * sourceModel() const
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
QString heading() const
Returns the heading for a column, which is the value displayed in the columns header cell...
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
void resetColumns()
Resets the attribute table's columns to match the vector layer's fields.
void insert(int i, const T &value)
void setSortOrder(Qt::SortOrder sortOrder)
Sets the sort order for the column.
QgsComposerTableColumn * columnFromSourceIndex(const QModelIndex &sourceIndex) const
Returns the QgsComposerTableColumn corresponding to an index from the source QgsComposerAttributeTabl...
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
QgsComposerTableColumns * columns()
Returns a pointer to the list of QgsComposerTableColumns shown in the table.
QString attribute() const
Returns the attribute name or expression used for the column's values.
virtual Qt::ItemFlags flags(const QModelIndex &index) const
double toDouble(bool *ok) const
void setWidth(const double width)
Sets the width for a column.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Qt::ItemFlags flags(const QModelIndex &index) const override
const_iterator constEnd() const
const_iterator constBegin() const
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QObject * parent() const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
iterator begin()
void resetFilter()
Invalidates the current filter used by the proxy model.
void setSortByRank(int sortByRank)
Sets the sort rank for the column.
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
typedef ItemFlags
virtual QVariant data(const QModelIndex &index, int role) const override