QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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.
Qt::AlignmentFlag hAlignment() const
Returns the horizontal alignment for a column, which controls the alignment used for drawing column v...
Qt::AlignmentFlag vAlignment() const
Returns the vertical alignment for a column, which controls the alignment used for drawing column val...
int length() const
void removeAt(int i)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
T value() const
T takeAt(int i)
static bool columnsBySortRank(QgsComposerTableColumn *a, QgsComposerTableColumn *b)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
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
int sortByRank() const
Returns the sort rank for the column.
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
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.
double width() const
Returns the width for a column.
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
QString heading() const
Returns the heading for a column, which is the value displayed in the columns header cell...
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.
QgsComposerTableColumn * columnFromIndex(const QModelIndex &index) const
Returns the QgsComposerTableColumn corresponding to an index in the proxy model.
ColumnFilterType
Controls whether the proxy model shows sorted or unsorted columns.
QgsComposerTableColumn * columnFromSourceIndex(const QModelIndex &sourceIndex) const
Returns the QgsComposerTableColumn corresponding to an index from the source QgsComposerAttributeTabl...
QAbstractItemModel * sourceModel() const
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
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.
void setVAlignment(Qt::AlignmentFlag alignment)
Sets the vertical alignment for a column, which controls the alignment used for drawing column values...
int column() const
QString attribute() const
Returns the attribute name or expression used for the column&#39;s values.
QgsComposerTableColumns * columns()
Returns a pointer to the list of QgsComposerTableColumns shown in the table.
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.
Qt::SortOrder sortOrder() const
Returns the sort order for the column.
void setSortByRank(int sortByRank)
Sets the sort rank for the column.
QgsComposerTableColumn * columnFromIndex(const QModelIndex &index) const
Returns the QgsComposerTableColumn corresponding to an index in the model.
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
typedef ItemFlags
virtual QVariant data(const QModelIndex &index, int role) const override