QGIS API Documentation  2.99.0-Master (716ff6c)
qgspalettedrendererwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspalettedrendererwidget.cpp
3  -----------------------------
4  begin : February 2012
5  copyright : (C) 2012 by Marco Hugentobler
6  email : marco at sourcepole dot ch
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 "qgsrasterdataprovider.h"
21 #include "qgsrasterlayer.h"
22 #include "qgscolordialog.h"
23 #include "qgssettings.h"
24 #include "qgsproject.h"
25 
26 #include <QColorDialog>
27 #include <QInputDialog>
28 #include <QFileDialog>
29 #include <QMessageBox>
30 #include <QMenu>
31 
32 #ifdef ENABLE_MODELTEST
33 #include "modeltest.h"
34 #endif
35 
37 {
38  setupUi( this );
39 
40  mCalculatingProgressBar->hide();
41  mCancelButton->hide();
42 
43  contextMenu = new QMenu( tr( "Options" ), this );
44  contextMenu->addAction( tr( "Change color" ), this, SLOT( changeColor() ) );
45  contextMenu->addAction( tr( "Change opacity" ), this, SLOT( changeOpacity() ) );
46  contextMenu->addAction( tr( "Change label" ), this, SLOT( changeLabel() ) );
47 
48  mModel = new QgsPalettedRendererModel( this );
49  mTreeView->setSortingEnabled( false );
50  mTreeView->setModel( mModel );
51 
52 #ifdef ENABLE_MODELTEST
53  new ModelTest( mModel, this );
54 #endif
55 
56  mSwatchDelegate = new QgsColorSwatchDelegate( this );
57  mTreeView->setItemDelegateForColumn( QgsPalettedRendererModel::ColorColumn, mSwatchDelegate );
58  mTreeView->setColumnWidth( QgsPalettedRendererModel::ColorColumn, 50 );
59  mTreeView->setContextMenuPolicy( Qt::CustomContextMenu );
60  mTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection );
61  mTreeView->setDragEnabled( true );
62  mTreeView->setAcceptDrops( true );
63  mTreeView->setDropIndicatorShown( true );
64  mTreeView->setDragDropMode( QAbstractItemView::InternalMove );
65  mTreeView->setSelectionBehavior( QAbstractItemView::SelectRows );
66  mTreeView->setDefaultDropAction( Qt::MoveAction );
67 
68  connect( mTreeView, &QTreeView::customContextMenuRequested, [ = ]( const QPoint & ) { contextMenu->exec( QCursor::pos() ); }
69  );
70 
71  btnColorRamp->setShowRandomColorRamp( true );
72 
73  connect( btnColorRamp, &QgsColorRampButton::colorRampChanged, this, &QgsPalettedRendererWidget::applyColorRamp );
74 
75  if ( mRasterLayer )
76  {
78  if ( !provider )
79  {
80  return;
81  }
82 
83  //fill available bands into combo box
84  int nBands = provider->bandCount();
85  for ( int i = 1; i <= nBands; ++i ) //band numbering seem to start at 1
86  {
87  mBandComboBox->addItem( displayBandName( i ), i );
88  }
89 
91  connect( mBandComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRasterRendererWidget::widgetChanged );
92  }
93 
94  connect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
95  connect( mDeleteEntryButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::deleteEntry );
96  connect( mAddEntryButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::addEntry );
97  connect( mLoadFromFileButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::loadColorTable );
98  connect( mExportToFileButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::saveColorTable );
99  connect( mClassifyButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::classify );
100  connect( mButtonLoadFromLayer, &QPushButton::clicked, this, &QgsPalettedRendererWidget::loadFromLayer );
101 
103  if ( provider )
104  {
105  mButtonLoadFromLayer->setEnabled( !provider->colorTable( mBandComboBox->currentData().toInt() ).isEmpty() );
106  }
107  else
108  {
109  mButtonLoadFromLayer->setEnabled( false );
110  }
111 
112  connect( QgsProject::instance(), static_cast < void ( QgsProject::* )( QgsMapLayer * ) >( &QgsProject::layerWillBeRemoved ), this, &QgsPalettedRendererWidget::layerWillBeRemoved );
113  connect( mBandComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPalettedRendererWidget::loadFromLayer );
114 }
115 
117 {
118  if ( mGatherer )
119  {
120  mGatherer->stop();
121  mGatherer->wait(); // mGatherer is deleted when wait completes
122  }
123 }
124 
126 {
127  QgsPalettedRasterRenderer::ClassData classes = mModel->classData();
128  int bandNumber = mBandComboBox->currentData().toInt();
129 
131  if ( !btnColorRamp->isNull() )
132  {
133  r->setSourceColorRamp( btnColorRamp->colorRamp() );
134  }
135  return r;
136 }
137 
139 {
140  const QgsPalettedRasterRenderer *pr = dynamic_cast<const QgsPalettedRasterRenderer *>( r );
141  if ( pr )
142  {
143  //read values and colors and fill into tree widget
144  mModel->setClassData( pr->classes() );
145 
146  if ( pr->sourceColorRamp() )
147  {
148  whileBlocking( btnColorRamp )->setColorRamp( pr->sourceColorRamp() );
149  }
150  else
151  {
152  std::unique_ptr< QgsColorRamp > ramp( new QgsRandomColorRamp() );
153  whileBlocking( btnColorRamp )->setColorRamp( ramp.get() );
154  }
155  }
156  else
157  {
158  loadFromLayer();
159  std::unique_ptr< QgsColorRamp > ramp( new QgsRandomColorRamp() );
160  whileBlocking( btnColorRamp )->setColorRamp( ramp.get() );
161  }
162 }
163 
164 void QgsPalettedRendererWidget::setSelectionColor( const QItemSelection &selection, const QColor &color )
165 {
166  // don't want to emit widgetChanged multiple times
167  disconnect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
168 
169  QModelIndex colorIndex;
170  Q_FOREACH ( const QItemSelectionRange &range, selection )
171  {
172  Q_FOREACH ( const QModelIndex &index, range.indexes() )
173  {
174  colorIndex = mModel->index( index.row(), QgsPalettedRendererModel::ColorColumn );
175  mModel->setData( colorIndex, color, Qt::EditRole );
176  }
177  }
178  connect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
179 
180  emit widgetChanged();
181 }
182 
183 void QgsPalettedRendererWidget::deleteEntry()
184 {
185  // don't want to emit widgetChanged multiple times
186  disconnect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
187 
188  QItemSelection sel = mTreeView->selectionModel()->selection();
189  Q_FOREACH ( const QItemSelectionRange &range, sel )
190  {
191  if ( range.isValid() )
192  mModel->removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() );
193  }
194 
195  connect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
196 
197  emit widgetChanged();
198 }
199 
200 void QgsPalettedRendererWidget::addEntry()
201 {
202  disconnect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
203 
204  QColor color( 150, 150, 150 );
205  std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
206  if ( ramp )
207  {
208  color = ramp->color( 1.0 );
209  }
210  mModel->addEntry( color );
211  connect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
212  emit widgetChanged();
213 }
214 
215 void QgsPalettedRendererWidget::changeColor()
216 {
217  QItemSelection sel = mTreeView->selectionModel()->selection();
218 
219  QModelIndex colorIndex = mModel->index( sel.first().top(), QgsPalettedRendererModel::ColorColumn );
220  QColor currentColor = mModel->data( colorIndex, Qt::DisplayRole ).value<QColor>();
221 
222  QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( qobject_cast< QWidget * >( parent() ) );
223  if ( panel && panel->dockMode() )
224  {
226  colorWidget->setPanelTitle( tr( "Select color" ) );
227  colorWidget->setAllowAlpha( true );
228  connect( colorWidget, &QgsCompoundColorWidget::currentColorChanged, this, [ = ]( const QColor & color ) { setSelectionColor( sel, color ); } );
229  panel->openPanel( colorWidget );
230  }
231  else
232  {
233  // modal dialog version... yuck
234  QColor newColor = QgsColorDialog::getColor( currentColor, this, QStringLiteral( "Change color" ), true );
235  if ( newColor.isValid() )
236  {
237  setSelectionColor( sel, newColor );
238  }
239  }
240 }
241 
242 void QgsPalettedRendererWidget::changeOpacity()
243 {
244  QItemSelection sel = mTreeView->selectionModel()->selection();
245 
246  QModelIndex colorIndex = mModel->index( sel.first().top(), QgsPalettedRendererModel::ColorColumn );
247  QColor currentColor = mModel->data( colorIndex, Qt::DisplayRole ).value<QColor>();
248 
249  bool ok;
250  double oldOpacity = ( currentColor.alpha() / 255.0 ) * 100.0;
251  double opacity = QInputDialog::getDouble( this, tr( "Opacity" ), tr( "Change color opacity [%]" ), oldOpacity, 0.0, 100.0, 0, &ok );
252  if ( ok )
253  {
254  int newOpacity = opacity / 100 * 255;
255 
256  // don't want to emit widgetChanged multiple times
257  disconnect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
258 
259  Q_FOREACH ( const QItemSelectionRange &range, sel )
260  {
261  Q_FOREACH ( const QModelIndex &index, range.indexes() )
262  {
263  colorIndex = mModel->index( index.row(), QgsPalettedRendererModel::ColorColumn );
264 
265  QColor newColor = mModel->data( colorIndex, Qt::DisplayRole ).value<QColor>();
266  newColor.setAlpha( newOpacity );
267  mModel->setData( colorIndex, newColor, Qt::EditRole );
268  }
269  }
270  connect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
271 
272  emit widgetChanged();
273  }
274 }
275 
276 void QgsPalettedRendererWidget::changeLabel()
277 {
278  QItemSelection sel = mTreeView->selectionModel()->selection();
279 
280  QModelIndex labelIndex = mModel->index( sel.first().top(), QgsPalettedRendererModel::LabelColumn );
281  QString currentLabel = mModel->data( labelIndex, Qt::DisplayRole ).toString();
282 
283  bool ok;
284  QString newLabel = QInputDialog::getText( this, tr( "Label" ), tr( "Change label" ), QLineEdit::Normal, currentLabel, &ok );
285  if ( ok )
286  {
287  // don't want to emit widgetChanged multiple times
288  disconnect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
289 
290  Q_FOREACH ( const QItemSelectionRange &range, sel )
291  {
292  Q_FOREACH ( const QModelIndex &index, range.indexes() )
293  {
294  labelIndex = mModel->index( index.row(), QgsPalettedRendererModel::LabelColumn );
295  mModel->setData( labelIndex, newLabel, Qt::EditRole );
296  }
297  }
298  connect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
299 
300  emit widgetChanged();
301  }
302 }
303 
304 void QgsPalettedRendererWidget::applyColorRamp()
305 {
306  std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
307  if ( !ramp )
308  {
309  return;
310  }
311 
312  disconnect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
313 
314  QgsPalettedRasterRenderer::ClassData data = mModel->classData();
315  QgsPalettedRasterRenderer::ClassData::iterator cIt = data.begin();
316 
317  double numberOfEntries = data.count();
318  int i = 0;
319 
320  if ( QgsRandomColorRamp *randomRamp = dynamic_cast<QgsRandomColorRamp *>( ramp.get() ) )
321  {
322  //ramp is a random colors ramp, so inform it of the total number of required colors
323  //this allows the ramp to pregenerate a set of visually distinctive colors
324  randomRamp->setTotalColorCount( numberOfEntries );
325  }
326 
327  if ( numberOfEntries > 1 )
328  numberOfEntries -= 1; //avoid duplicate first color
329 
330  for ( ; cIt != data.end(); ++cIt )
331  {
332  cIt->color = ramp->color( i / numberOfEntries );
333  i++;
334  }
335  mModel->setClassData( data );
336 
337  connect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
338  emit widgetChanged();
339 }
340 
341 void QgsPalettedRendererWidget::loadColorTable()
342 {
343  QgsSettings settings;
344  QString lastDir = settings.value( QStringLiteral( "lastColorMapDir" ), QDir::homePath() ).toString();
345  QString fileName = QFileDialog::getOpenFileName( this, tr( "Open file" ), lastDir );
346  if ( !fileName.isEmpty() )
347  {
349  if ( !classes.isEmpty() )
350  {
351  disconnect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
352  mModel->setClassData( classes );
353  emit widgetChanged();
354  connect( mModel, &QgsPalettedRendererModel::classesChanged, this, &QgsPalettedRendererWidget::widgetChanged );
355  }
356  else
357  {
358  QMessageBox::critical( nullptr, tr( "Invalid file" ), tr( "Could not interpret file as a raster color table." ) );
359  }
360  }
361 }
362 
363 void QgsPalettedRendererWidget::saveColorTable()
364 {
365  QgsSettings settings;
366  QString lastDir = settings.value( QStringLiteral( "lastColorMapDir" ), QDir::homePath() ).toString();
367  QString fileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), lastDir, tr( "Text (*.clr)" ) );
368  if ( !fileName.isEmpty() )
369  {
370  if ( !fileName.endsWith( QLatin1String( ".clr" ), Qt::CaseInsensitive ) )
371  {
372  fileName = fileName + ".clr";
373  }
374 
375  QFile outputFile( fileName );
376  if ( outputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
377  {
378  QTextStream outputStream( &outputFile );
379  outputStream << QgsPalettedRasterRenderer::classDataToString( mModel->classData() );
380  outputStream.flush();
381  outputFile.close();
382 
383  QFileInfo fileInfo( fileName );
384  settings.setValue( QStringLiteral( "lastColorMapDir" ), fileInfo.absoluteDir().absolutePath() );
385  }
386  else
387  {
388  QMessageBox::warning( this, tr( "Write access denied" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
389  }
390  }
391 }
392 
393 void QgsPalettedRendererWidget::classify()
394 {
395  if ( mRasterLayer )
396  {
398  if ( !provider )
399  {
400  return;
401  }
402 
403  if ( mGatherer )
404  {
405  mGatherer->stop();
406  return;
407  }
408 
409  mGatherer = new QgsPalettedRendererClassGatherer( mRasterLayer, mBandComboBox->currentData().toInt(), btnColorRamp->colorRamp() );
410 
411  connect( mGatherer, &QgsPalettedRendererClassGatherer::progressChanged, mCalculatingProgressBar, &QProgressBar::setValue );
412  mCalculatingProgressBar->show();
413  mCancelButton->show();
414  connect( mCancelButton, &QPushButton::clicked, mGatherer, &QgsPalettedRendererClassGatherer::stop );
415 
416  connect( mGatherer, &QgsPalettedRendererClassGatherer::collectedClasses, this, &QgsPalettedRendererWidget::gatheredClasses );
417  connect( mGatherer, &QgsPalettedRendererClassGatherer::finished, this, &QgsPalettedRendererWidget::gathererThreadFinished );
418  mClassifyButton->setText( tr( "Calculating..." ) );
419  mClassifyButton->setEnabled( false );
420  mGatherer->start();
421  }
422 }
423 
424 void QgsPalettedRendererWidget::loadFromLayer()
425 {
426  //read default palette settings from layer
428  if ( provider )
429  {
430  QList<QgsColorRampShader::ColorRampItem> table = provider->colorTable( mBandComboBox->currentData().toInt() );
431  if ( !table.isEmpty() )
432  {
433  QgsPalettedRasterRenderer::ClassData classes = QgsPalettedRasterRenderer::colorTableToClassData( provider->colorTable( mBandComboBox->currentData().toInt() ) );
434  mModel->setClassData( classes );
435  emit widgetChanged();
436  }
437  }
438 }
439 
440 void QgsPalettedRendererWidget::gatheredClasses()
441 {
442  if ( !mGatherer || mGatherer->wasCanceled() )
443  return;
444 
445  mModel->setClassData( mGatherer->classes() );
446  emit widgetChanged();
447 }
448 
449 void QgsPalettedRendererWidget::gathererThreadFinished()
450 {
451  mGatherer->deleteLater();
452  mGatherer = nullptr;
453  mClassifyButton->setText( tr( "Add Unique Values" ) );
454  mClassifyButton->setEnabled( true );
455  mCalculatingProgressBar->hide();
456  mCancelButton->hide();
457 }
458 
459 void QgsPalettedRendererWidget::layerWillBeRemoved( QgsMapLayer *layer )
460 {
461  if ( mGatherer && mRasterLayer == layer )
462  {
463  mGatherer->stop();
464  mGatherer->wait();
465  }
466 }
467 
468 //
469 // QgsPalettedRendererModel
470 //
471 
473 QgsPalettedRendererModel::QgsPalettedRendererModel( QObject *parent )
474  : QAbstractItemModel( parent )
475 {
476 
477 }
478 
479 void QgsPalettedRendererModel::setClassData( const QgsPalettedRasterRenderer::ClassData &data )
480 {
481  beginResetModel();
482  mData = data;
483  endResetModel();
484 }
485 
486 QModelIndex QgsPalettedRendererModel::index( int row, int column, const QModelIndex &parent ) const
487 {
488  if ( column < 0 || column >= columnCount() )
489  {
490  //column out of bounds
491  return QModelIndex();
492  }
493 
494  if ( !parent.isValid() && row >= 0 && row < mData.size() )
495  {
496  //return an index for the item at this position
497  return createIndex( row, column );
498  }
499 
500  //only top level supported
501  return QModelIndex();
502 }
503 
504 QModelIndex QgsPalettedRendererModel::parent( const QModelIndex &index ) const
505 {
506  Q_UNUSED( index );
507 
508  //all items are top level
509  return QModelIndex();
510 }
511 
512 int QgsPalettedRendererModel::columnCount( const QModelIndex &parent ) const
513 {
514  if ( parent.isValid() )
515  return 0;
516 
517  return 3;
518 }
519 
520 int QgsPalettedRendererModel::rowCount( const QModelIndex &parent ) const
521 {
522  if ( parent.isValid() )
523  return 0;
524 
525  return mData.count();
526 }
527 
528 QVariant QgsPalettedRendererModel::data( const QModelIndex &index, int role ) const
529 {
530  if ( !index.isValid() )
531  return QVariant();
532 
533  switch ( role )
534  {
535  case Qt::DisplayRole:
536  case Qt::EditRole:
537  {
538  switch ( index.column() )
539  {
540  case ValueColumn:
541  return mData.at( index.row() ).value;
542 
543  case ColorColumn:
544  return mData.at( index.row() ).color;
545 
546  case LabelColumn:
547  return mData.at( index.row() ).label;
548  }
549  }
550 
551  default:
552  return QVariant();
553  }
554 
555  return QVariant();
556 }
557 
558 QVariant QgsPalettedRendererModel::headerData( int section, Qt::Orientation orientation, int role ) const
559 {
560  switch ( orientation )
561  {
562  case Qt::Vertical:
563  return QVariant();
564 
565  case Qt::Horizontal:
566  {
567  switch ( role )
568  {
569  case Qt::DisplayRole:
570  {
571  switch ( section )
572  {
573  case ValueColumn:
574  return tr( "Value" );
575 
576  case ColorColumn:
577  return tr( "Color" );
578 
579  case LabelColumn:
580  return tr( "Label" );
581  }
582  }
583 
584  }
585  break;
586  }
587 
588  default:
589  return QAbstractItemModel::headerData( section, orientation, role );
590  }
591  return QAbstractItemModel::headerData( section, orientation, role );
592 }
593 
594 bool QgsPalettedRendererModel::setData( const QModelIndex &index, const QVariant &value, int )
595 {
596  if ( !index.isValid() )
597  return false;
598  if ( index.row() >= mData.length() )
599  return false;
600 
601  switch ( index.column() )
602  {
603  case ValueColumn:
604  {
605  bool ok = false;
606  int newValue = value.toInt( &ok );
607  if ( !ok )
608  return false;
609 
610  mData[ index.row() ].value = newValue;
611  emit dataChanged( index, index );
612  emit classesChanged();
613  return true;
614  }
615 
616  case ColorColumn:
617  {
618  mData[ index.row() ].color = value.value<QColor>();
619  emit dataChanged( index, index );
620  emit classesChanged();
621  return true;
622  }
623 
624  case LabelColumn:
625  {
626  mData[ index.row() ].label = value.toString();
627  emit dataChanged( index, index );
628  emit classesChanged();
629  return true;
630  }
631  }
632 
633  return false;
634 }
635 
636 Qt::ItemFlags QgsPalettedRendererModel::flags( const QModelIndex &index ) const
637 {
638  if ( !index.isValid() )
639  return QAbstractItemModel::flags( index ) | Qt::ItemIsDropEnabled;
640 
641  Qt::ItemFlags f = QAbstractItemModel::flags( index );
642  switch ( index.column() )
643  {
644  case ValueColumn:
645  case LabelColumn:
646  case ColorColumn:
647  f = f | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
648  break;
649  }
650  return f | Qt::ItemIsEnabled | Qt::ItemIsSelectable;;
651 }
652 
653 bool QgsPalettedRendererModel::removeRows( int row, int count, const QModelIndex &parent )
654 {
655  if ( row < 0 || row >= mData.count() )
656  return false;
657  if ( parent.isValid() )
658  return false;
659 
660  for ( int i = row + count - 1; i >= row; --i )
661  {
662  beginRemoveRows( parent, i, i );
663  mData.removeAt( i );
664  endRemoveRows();
665  }
666  emit classesChanged();
667  return true;
668 }
669 
670 bool QgsPalettedRendererModel::insertRows( int row, int count, const QModelIndex & )
671 {
672  QgsPalettedRasterRenderer::ClassData::const_iterator cIt = mData.constBegin();
673  int currentMaxValue = -INT_MAX;
674  for ( ; cIt != mData.constEnd(); ++cIt )
675  {
676  int value = cIt->value;
677  currentMaxValue = qMax( value, currentMaxValue );
678  }
679  int nextValue = qMax( 0, currentMaxValue + 1 );
680 
681  beginInsertRows( QModelIndex(), row, row + count - 1 );
682  for ( int i = row; i < row + count; ++i, ++nextValue )
683  {
684  mData.insert( i, QgsPalettedRasterRenderer::Class( nextValue, QColor( 200, 200, 200 ), QString::number( nextValue ) ) );
685  }
686  endInsertRows();
687  emit classesChanged();
688  return true;
689 }
690 
691 Qt::DropActions QgsPalettedRendererModel::supportedDropActions() const
692 {
693  return Qt::MoveAction;
694 }
695 
696 QStringList QgsPalettedRendererModel::mimeTypes() const
697 {
698  QStringList types;
699  types << QStringLiteral( "application/x-qgspalettedrenderermodel" );
700  return types;
701 }
702 
703 QMimeData *QgsPalettedRendererModel::mimeData( const QModelIndexList &indexes ) const
704 {
705  QMimeData *mimeData = new QMimeData();
706  QByteArray encodedData;
707 
708  QDataStream stream( &encodedData, QIODevice::WriteOnly );
709 
710  // Create list of rows
711  Q_FOREACH ( const QModelIndex &index, indexes )
712  {
713  if ( !index.isValid() || index.column() != 0 )
714  continue;
715 
716  stream << index.row();
717  }
718  mimeData->setData( QStringLiteral( "application/x-qgspalettedrenderermodel" ), encodedData );
719  return mimeData;
720 }
721 
722 bool QgsPalettedRendererModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex & )
723 {
724  Q_UNUSED( column );
725  if ( action != Qt::MoveAction ) return true;
726 
727  if ( !data->hasFormat( QStringLiteral( "application/x-qgspalettedrenderermodel" ) ) )
728  return false;
729 
730  QByteArray encodedData = data->data( QStringLiteral( "application/x-qgspalettedrenderermodel" ) );
731  QDataStream stream( &encodedData, QIODevice::ReadOnly );
732 
733  QVector<int> rows;
734  while ( !stream.atEnd() )
735  {
736  int r;
737  stream >> r;
738  rows.append( r );
739  }
740 
742  for ( int i = 0; i < rows.count(); ++i )
743  newData << mData.at( rows.at( i ) );
744 
745  if ( row < 0 )
746  row = mData.count();
747 
748  beginInsertRows( QModelIndex(), row, row + rows.count() - 1 );
749  for ( int i = 0; i < rows.count(); ++i )
750  mData.insert( row + i, newData.at( i ) );
751  endInsertRows();
752  emit classesChanged();
753  return true;
754 }
755 
756 void QgsPalettedRendererModel::addEntry( const QColor &color )
757 {
758  insertRow( rowCount() );
759  setData( index( mData.count() - 1, 1 ), color );
760 }
761 
763 
void setSourceColorRamp(QgsColorRamp *ramp)
Set the source color ramp.
QgsPalettedRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())
virtual int bandCount() const =0
Get number of bands.
static QString classDataToString(const QgsPalettedRasterRenderer::ClassData &classes)
Converts classes to a string representation, using the .clr/gdal color table file format...
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:38
Base class for all map layer types.
Definition: qgsmaplayer.h:53
Renderer for paletted raster images.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:54
virtual QList< QgsColorRampShader::ColorRampItem > colorTable(int bandNo) const
void colorRampChanged()
Emitted whenever a new color ramp is set for the button.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
ClassData classes() const
Returns a map of value to classes (colors) used by the renderer.
Properties of a single value class.
Base class for any widget that can be shown as a inline panel.
QgsRasterRenderer * renderer() const
QgsRasterDataProvider * dataProvider() override
void setFromRenderer(const QgsRasterRenderer *r)
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget...
A custom QGIS widget for selecting a color, including options for selecting colors via hue wheel...
QString displayBandName(int band) const
Returns a band name for display. First choice is color name, otherwise band number.
Reads and writes project states.
Definition: qgsproject.h:75
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), const bool allowAlpha=false)
Return a color selection from a color dialog.
void setAllowAlpha(const bool allowAlpha)
Sets whether alpha modification (transparency) is permitted for the color dialog. ...
Totally random color ramp.
Definition: qgscolorramp.h:382
QgsColorRamp * sourceColorRamp() const
Get the source color ramp.
QgsRasterRenderer * renderer() override
void layerWillBeRemoved(const QString &layerId)
Emitted when a layer is about to be removed from the registry.
static QgsPalettedRasterRenderer::ClassData classDataFromFile(const QString &path)
Opens a color table file and returns corresponding paletted renderer class data.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:178
void currentColorChanged(const QColor &color)
Emitted when the dialog&#39;s color changes.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:360
QList< Class > ClassData
Map of value to class properties.
void widgetChanged()
Emitted when something on the widget has changed.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
static QgsPalettedRasterRenderer::ClassData colorTableToClassData(const QList< QgsColorRampShader::ColorRampItem > &table)
Converts a raster color table to paletted renderer class data.
Raster renderer pipe that applies colors to a raster.
Use a narrower, vertically stacked layout.
A delegate for showing a color swatch in a list.
Base class for raster data providers.