QGIS API Documentation  2.8.2-Wien
 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 
49 QModelIndex QgsComposerAttributeTableColumnModelV2::parent( const QModelIndex &child ) const
50 {
51  Q_UNUSED( child );
52  return QModelIndex();
53 }
54 
55 int QgsComposerAttributeTableColumnModelV2::rowCount( const QModelIndex &parent ) const
56 {
57  if ( parent.isValid() )
58  return 0;
59 
60  return mComposerTable->columns()->length();
61 }
62 
63 int QgsComposerAttributeTableColumnModelV2::columnCount( const QModelIndex &parent ) const
64 {
65  Q_UNUSED( parent );
66  return 4;
67 }
68 
69 QVariant QgsComposerAttributeTableColumnModelV2::data( const QModelIndex &index, int role ) const
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 
180 bool QgsComposerAttributeTableColumnModelV2::setData( const QModelIndex& index, const QVariant& value, int role )
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 
229 Qt::ItemFlags QgsComposerAttributeTableColumnModelV2::flags( const QModelIndex& index ) const
230 {
231  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
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 
473 bool QgsComposerTableSortColumnsProxyModelV2::lessThan( const QModelIndex &left, const QModelIndex &right ) const
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 
488 int QgsComposerTableSortColumnsProxyModelV2::columnCount( const QModelIndex &parent ) const
489 {
490  Q_UNUSED( parent );
491  return 2;
492 }
493 
494 QVariant QgsComposerTableSortColumnsProxyModelV2::data( const QModelIndex &index, int role ) const
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 
568 Qt::ItemFlags QgsComposerTableSortColumnsProxyModelV2::flags( const QModelIndex& index ) const
569 {
570  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
571 
572  if ( index.column() == 1 )
573  {
574  //only sort order is editable
575  flags |= Qt::ItemIsEditable;
576  }
577 
578  return flags;
579 }
580 
581 bool QgsComposerTableSortColumnsProxyModelV2::setData( const QModelIndex& index, const QVariant& value, int role )
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 }