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