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