34 #include <QPushButton>    35 #include <QInputDialog>    36 #include <QFileDialog>    38 #include <QMessageBox>    39 #include <QTextStream>    48   mLoadFromBandButton->setVisible( 
false ); 
    50   connect( mAddEntryButton, &QPushButton::clicked, 
this, &QgsColorRampShaderWidget::mAddEntryButton_clicked );
    51   connect( mDeleteEntryButton, &QPushButton::clicked, 
this, &QgsColorRampShaderWidget::mDeleteEntryButton_clicked );
    52   connect( mLoadFromBandButton, &QPushButton::clicked, 
this, &QgsColorRampShaderWidget::mLoadFromBandButton_clicked );
    53   connect( mLoadFromFileButton, &QPushButton::clicked, 
this, &QgsColorRampShaderWidget::mLoadFromFileButton_clicked );
    54   connect( mExportToFileButton, &QPushButton::clicked, 
this, &QgsColorRampShaderWidget::mExportToFileButton_clicked );
    55   connect( mUnitLineEdit, &QLineEdit::textEdited, 
this, &QgsColorRampShaderWidget::mUnitLineEdit_textEdited );
    56   connect( mColormapTreeWidget, &QTreeWidget::itemDoubleClicked, 
this, &QgsColorRampShaderWidget::mColormapTreeWidget_itemDoubleClicked );
    57   connect( mColorInterpolationComboBox, 
static_cast<void ( QComboBox::* )( 
int )
>( &QComboBox::currentIndexChanged ), 
this, &QgsColorRampShaderWidget::mColorInterpolationComboBox_currentIndexChanged );
    58   connect( mClassificationModeComboBox, 
static_cast<void ( QComboBox::* )( 
int )
>( &QComboBox::currentIndexChanged ), 
this, &QgsColorRampShaderWidget::mClassificationModeComboBox_currentIndexChanged );
    60   contextMenu = 
new QMenu( tr( 
"Options" ), 
this );
    61   contextMenu->addAction( tr( 
"Change Color…" ), 
this, SLOT( changeColor() ) );
    62   contextMenu->addAction( tr( 
"Change Opacity…" ), 
this, SLOT( changeOpacity() ) );
    65   mColormapTreeWidget->setItemDelegateForColumn( ColorColumn, mSwatchDelegate );
    66   mColormapTreeWidget->setColumnWidth( ColorColumn, 
Qgis::UI_SCALE_FACTOR * fontMetrics().width( 
'X' ) * 6.6 );
    67   mColormapTreeWidget->setContextMenuPolicy( Qt::CustomContextMenu );
    68   mColormapTreeWidget->setSelectionMode( QAbstractItemView::ExtendedSelection );
    69   connect( mColormapTreeWidget, &QTreeView::customContextMenuRequested, 
this, [ = ]( QPoint ) { contextMenu->exec( QCursor::pos() ); }
    72   QString defaultPalette = settings.
value( QStringLiteral( 
"Raster/defaultPalette" ), 
"" ).toString();
    73   btnColorRamp->setColorRampFromName( defaultPalette );
    85   mNumberOfEntriesSpinBox->setValue( 5 ); 
    87   mClassificationModeComboBox_currentIndexChanged( 0 );
    89   resetClassifyButton();
    92   connect( mClassifyButton, &QPushButton::clicked, 
this, &QgsColorRampShaderWidget::applyColorRamp );
   106   mRasterDataProvider = dp;
   107   mLoadFromBandButton->setVisible( 
bool( mRasterDataProvider ) ); 
   123   colorRampShader.
setColorRampType( static_cast< QgsColorRampShader::Type >( mColorInterpolationComboBox->currentData().toInt() ) );
   124   colorRampShader.
setClassificationMode( static_cast< QgsColorRampShader::ClassificationMode >( mClassificationModeComboBox->currentData().toInt() ) );
   125   colorRampShader.
setClip( mClipCheckBox->isChecked() );
   128   QList<QgsColorRampShader::ColorRampItem> colorRampItems;
   129   int topLevelItemCount = mColormapTreeWidget->topLevelItemCount();
   130   QTreeWidgetItem *currentItem = 
nullptr;
   131   for ( 
int i = 0; i < topLevelItemCount; ++i )
   133     currentItem = mColormapTreeWidget->topLevelItem( i );
   139     newColorRampItem.
value = currentItem->text( ValueColumn ).toDouble();
   140     newColorRampItem.
color = currentItem->data( ColorColumn, Qt::EditRole ).value<QColor>();
   141     newColorRampItem.
label = currentItem->text( LabelColumn );
   142     colorRampItems.append( newColorRampItem );
   145   std::sort( colorRampItems.begin(), colorRampItems.end() );
   148   if ( !btnColorRamp->isNull() )
   152   return colorRampShader;
   155 void QgsColorRampShaderWidget::autoLabel()
   159   QString unit = mUnitLineEdit->text();
   161   int topLevelItemCount = mColormapTreeWidget->topLevelItemCount();
   162   QTreeWidgetItem *currentItem = 
nullptr;
   163   for ( 
int i = 0; i < topLevelItemCount; ++i )
   165     currentItem = mColormapTreeWidget->topLevelItem( i );
   167     if ( !currentItem || currentItem->text( ValueColumn ).isEmpty() )
   176         label = 
"<= " + currentItem->text( ValueColumn ) + unit;
   178       else if ( currentItem->text( ValueColumn ).toDouble() == std::numeric_limits<double>::infinity() )
   180         label = 
"> " + mColormapTreeWidget->topLevelItem( i - 1 )->text( ValueColumn ) + unit;
   184         label = mColormapTreeWidget->topLevelItem( i - 1 )->text( ValueColumn ) + 
" - " + currentItem->text( ValueColumn ) + unit;
   189       label = currentItem->text( ValueColumn ) + unit;
   192     if ( currentItem->text( LabelColumn ).isEmpty() || currentItem->text( LabelColumn ) == label || currentItem->foreground( LabelColumn ).color() == QColor( Qt::gray ) )
   194       currentItem->setText( LabelColumn, label );
   195       currentItem->setForeground( LabelColumn, QBrush( QColor( Qt::gray ) ) );
   200 void QgsColorRampShaderWidget::setUnitFromLabels()
   204   QStringList allSuffixes;
   206   int topLevelItemCount = mColormapTreeWidget->topLevelItemCount();
   207   QTreeWidgetItem *currentItem = 
nullptr;
   208   for ( 
int i = 0; i < topLevelItemCount; ++i )
   210     currentItem = mColormapTreeWidget->topLevelItem( i );
   212     if ( !currentItem || currentItem->text( ValueColumn ).isEmpty() )
   221         label = 
"<= " + currentItem->text( ValueColumn );
   223       else if ( currentItem->text( ValueColumn ).toDouble() == std::numeric_limits<double>::infinity() )
   225         label = 
"> " + mColormapTreeWidget->topLevelItem( i - 1 )->text( ValueColumn );
   229         label = mColormapTreeWidget->topLevelItem( i - 1 )->text( ValueColumn ) + 
" - " + currentItem->text( ValueColumn );
   234       label = currentItem->text( ValueColumn );
   237     if ( currentItem->text( LabelColumn ).startsWith( label ) )
   239       allSuffixes.append( currentItem->text( LabelColumn ).mid( label.length() ) );
   243   QStringList suffixes = QStringList( allSuffixes );
   244   suffixes.removeDuplicates();
   247   for ( 
int i = 0; i < suffixes.count(); ++i )
   249     int n = allSuffixes.count( suffixes[i] );
   259     mUnitLineEdit->setText( unit );
   265 void QgsColorRampShaderWidget::mAddEntryButton_clicked()
   268   newItem->setText( ValueColumn, QStringLiteral( 
"0" ) );
   269   newItem->
setData( ColorColumn, Qt::EditRole, QColor( Qt::magenta ) );
   270   newItem->setText( LabelColumn, QString() );
   271   newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable );
   273            this, &QgsColorRampShaderWidget::mColormapTreeWidget_itemEdited );
   274   mColormapTreeWidget->sortItems( ValueColumn, Qt::AscendingOrder );
   281 void QgsColorRampShaderWidget::mDeleteEntryButton_clicked()
   283   QList<QTreeWidgetItem *> itemList;
   284   itemList = mColormapTreeWidget->selectedItems();
   285   if ( itemList.isEmpty() )
   290   Q_FOREACH ( QTreeWidgetItem *item, itemList )
   301   std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
   302   if ( !ramp || std::isnan( mMin ) || std::isnan( mMax ) )
   311         static_cast< QgsColorRampShader::ClassificationMode >( mClassificationModeComboBox->currentData().toInt() ) )
   315   colorRampShader->classifyColorRamp( mNumberOfEntriesSpinBox->value(),
   318                                       mRasterDataProvider );
   319   colorRampShader->setClip( mClipCheckBox->isChecked() );
   322   mColormapTreeWidget->clear();
   324   const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader->colorRampItemList();
   325   QList<QgsColorRampShader::ColorRampItem>::const_iterator it = colorRampItemList.constBegin();
   326   for ( ; it != colorRampItemList.end(); ++it )
   329     newItem->setText( ValueColumn, QString::number( it->value, 
'g', 15 ) );
   330     newItem->
setData( ColorColumn, Qt::EditRole, it->color );
   331     newItem->setText( LabelColumn, it->label );
   332     newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable );
   334              this, &QgsColorRampShaderWidget::mColormapTreeWidget_itemEdited );
   336   mClipCheckBox->setChecked( colorRampShader->clip() );
   343 void QgsColorRampShaderWidget::mClassificationModeComboBox_currentIndexChanged( 
int index )
   351 void QgsColorRampShaderWidget::applyColorRamp()
   353   std::unique_ptr< QgsColorRamp > ramp( btnColorRamp->colorRamp() );
   359   if ( !btnColorRamp->colorRampName().isEmpty() )
   363     settings.
setValue( QStringLiteral( 
"Raster/defaultPalette" ), btnColorRamp->colorRampName() );
   366   bool enableContinuous = ( ramp->count() > 0 );
   367   mClassificationModeComboBox->setEnabled( enableContinuous );
   368   if ( !enableContinuous )
   378   mColormapTreeWidget->clear();
   379   QList<QgsColorRampShader::ColorRampItem>::const_iterator it = colorRampItems.constBegin();
   380   for ( ; it != colorRampItems.constEnd(); ++it )
   383     newItem->setText( ValueColumn, QString::number( it->value, 
'g', 15 ) );
   384     newItem->
setData( ColorColumn, Qt::EditRole, it->color );
   385     newItem->setText( LabelColumn, it->label );
   386     newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable );
   388              this, &QgsColorRampShaderWidget::mColormapTreeWidget_itemEdited );
   396 void QgsColorRampShaderWidget::mLoadFromBandButton_clicked()
   398   if ( !mRasterDataProvider )
   401   QList<QgsColorRampShader::ColorRampItem> colorRampList = mRasterDataProvider->
colorTable( mBand );
   402   if ( !colorRampList.isEmpty() )
   409     QMessageBox::warning( 
this, tr( 
"Load Color Map" ), tr( 
"The color map for band %1 has no entries." ).arg( mBand ) );
   416 void QgsColorRampShaderWidget::mLoadFromFileButton_clicked()
   419   bool importError = 
false;
   422   QString lastDir = settings.
value( QStringLiteral( 
"lastColorMapDir" ), QDir::homePath() ).toString();
   423   QString fileName = QFileDialog::getOpenFileName( 
this, tr( 
"Load Color Map from File" ), lastDir, tr( 
"Textfile (*.txt)" ) );
   424   QFile inputFile( fileName );
   425   if ( inputFile.open( QFile::ReadOnly ) )
   428     mColormapTreeWidget->clear();
   430     QTextStream inputStream( &inputFile );
   432     QStringList inputStringComponents;
   433     QList<QgsColorRampShader::ColorRampItem> colorRampItems;
   436     while ( !inputStream.atEnd() )
   439       inputLine = inputStream.readLine();
   440       if ( !inputLine.isEmpty() )
   442         if ( !inputLine.simplified().startsWith( 
'#' ) )
   444           if ( inputLine.contains( QLatin1String( 
"INTERPOLATION" ), Qt::CaseInsensitive ) )
   446             inputStringComponents = inputLine.split( 
':' );
   447             if ( inputStringComponents.size() == 2 )
   449               if ( inputStringComponents[1].trimmed().toUpper().compare( QLatin1String( 
"INTERPOLATED" ), Qt::CaseInsensitive ) == 0 )
   453               else if ( inputStringComponents[1].trimmed().toUpper().compare( QLatin1String( 
"DISCRETE" ), Qt::CaseInsensitive ) == 0 )
   465               badLines = badLines + QString::number( lineCounter ) + 
":\t[" + inputLine + 
"]\n";
   470             inputStringComponents = inputLine.split( 
',' );
   471             if ( inputStringComponents.size() == 6 )
   474                   QColor::fromRgb( inputStringComponents[1].toInt(), inputStringComponents[2].toInt(),
   475                                    inputStringComponents[3].toInt(), inputStringComponents[4].toInt() ),
   476                   inputStringComponents[5] );
   477               colorRampItems.push_back( currentItem );
   482               badLines = badLines + QString::number( lineCounter ) + 
":\t[" + inputLine + 
"]\n";
   491     QFileInfo fileInfo( fileName );
   492     settings.
setValue( QStringLiteral( 
"lastColorMapDir" ), fileInfo.absoluteDir().absolutePath() );
   496       QMessageBox::warning( 
this, tr( 
"Load Color Map from File" ), tr( 
"The following lines contained errors\n\n" ) + badLines );
   499   else if ( !fileName.isEmpty() )
   501     QMessageBox::warning( 
this, tr( 
"Load Color Map from File" ), tr( 
"Read access denied. Adjust the file permissions and try again.\n\n" ) );
   508 void QgsColorRampShaderWidget::mExportToFileButton_clicked()
   511   QString lastDir = settings.
value( QStringLiteral( 
"lastColorMapDir" ), QDir::homePath() ).toString();
   512   QString fileName = QFileDialog::getSaveFileName( 
this, tr( 
"Save Color Map as File" ), lastDir, tr( 
"Textfile (*.txt)" ) );
   513   if ( !fileName.isEmpty() )
   515     if ( !fileName.endsWith( QLatin1String( 
".txt" ), Qt::CaseInsensitive ) )
   517       fileName = fileName + 
".txt";
   520     QFile outputFile( fileName );
   521     if ( outputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
   523       QTextStream outputStream( &outputFile );
   524       outputStream << 
"# " << tr( 
"QGIS Generated Color Map Export File" ) << 
'\n';
   525       outputStream << 
"INTERPOLATION:";
   527       switch ( interpolation )
   530           outputStream << 
"INTERPOLATED\n";
   533           outputStream << 
"DISCRETE\n";
   536           outputStream << 
"EXACT\n";
   540       int topLevelItemCount = mColormapTreeWidget->topLevelItemCount();
   541       QTreeWidgetItem *currentItem = 
nullptr;
   543       for ( 
int i = 0; i < topLevelItemCount; ++i )
   545         currentItem = mColormapTreeWidget->topLevelItem( i );
   550         color = currentItem->data( ColorColumn, Qt::EditRole ).value<QColor>();
   551         outputStream << currentItem->text( ValueColumn ).toDouble() << 
',';
   552         outputStream << color.red() << 
',' << color.green() << 
',' << color.blue() << 
',' << color.alpha() << 
',';
   553         if ( currentItem->text( LabelColumn ).isEmpty() )
   555           outputStream << 
"Color entry " << i + 1 << 
'\n';
   559           outputStream << currentItem->text( LabelColumn ) << 
'\n';
   562       outputStream.flush();
   565       QFileInfo fileInfo( fileName );
   566       settings.
setValue( QStringLiteral( 
"lastColorMapDir" ), fileInfo.absoluteDir().absolutePath() );
   570       QMessageBox::warning( 
this, tr( 
"Save Color Map as File" ), tr( 
"Write access denied. Adjust the file permissions and try again.\n\n" ) );
   575 void QgsColorRampShaderWidget::mColormapTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, 
int column )
   582   if ( column == ColorColumn )
   584     item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
   585     QColor newColor = 
QgsColorDialog::getColor( item->data( column, Qt::EditRole ).value<QColor>(), 
this, QStringLiteral( 
"Change Color" ), true );
   586     if ( newColor.isValid() )
   588       item->setData( ColorColumn, Qt::EditRole, newColor );
   595     if ( column == LabelColumn )
   598       item->setForeground( LabelColumn, QBrush() );
   600     item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable );
   604 void QgsColorRampShaderWidget::mColormapTreeWidget_itemEdited( QTreeWidgetItem *item, 
int column )
   608   if ( column == ValueColumn )
   610     mColormapTreeWidget->sortItems( ValueColumn, Qt::AscendingOrder );
   617   else if ( column == LabelColumn )
   634     QString defaultPalette = settings.
value( QStringLiteral( 
"/Raster/defaultPalette" ), 
"Spectral" ).toString();
   635     btnColorRamp->setColorRampFromName( defaultPalette );
   638   mColorInterpolationComboBox->setCurrentIndex( mColorInterpolationComboBox->findData( colorRampShader.
colorRampType() ) );
   640   mColormapTreeWidget->clear();
   641   const QList<QgsColorRampShader::ColorRampItem> colorRampItemList = colorRampShader.
colorRampItemList();
   642   QList<QgsColorRampShader::ColorRampItem>::const_iterator it = colorRampItemList.constBegin();
   643   for ( ; it != colorRampItemList.end(); ++it )
   646     newItem->setText( ValueColumn, QString::number( it->value, 
'g', 15 ) );
   647     newItem->
setData( ColorColumn, Qt::EditRole, it->color );
   648     newItem->setText( LabelColumn, it->label );
   649     newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable );
   651              this, &QgsColorRampShaderWidget::mColormapTreeWidget_itemEdited );
   654   mClipCheckBox->setChecked( colorRampShader.
clip() );
   655   mClassificationModeComboBox->setCurrentIndex( mClassificationModeComboBox->findData( colorRampShader.
classificationMode() ) );
   656   mNumberOfEntriesSpinBox->setValue( colorRampShader.
colorRampItemList().count() ); 
   659 void QgsColorRampShaderWidget::mColorInterpolationComboBox_currentIndexChanged( 
int index )
   666   QString valueToolTip;
   667   switch ( interpolation )
   670       valueLabel = tr( 
"Value" );
   671       valueToolTip = tr( 
"Value for color stop" );
   674       valueLabel = tr( 
"Value <=" );
   675       valueToolTip = tr( 
"Maximum value for class" );
   678       valueLabel = tr( 
"Value =" );
   679       valueToolTip = tr( 
"Value for color" );
   683   QTreeWidgetItem *header = mColormapTreeWidget->headerItem();
   684   header->setText( ValueColumn, valueLabel );
   685   header->setToolTip( ValueColumn, valueToolTip );
   704   resetClassifyButton();
   721   QTreeWidgetItem *item = mColormapTreeWidget->topLevelItem( 0 );
   727   double min = item->text( ValueColumn ).toDouble();
   728   item = mColormapTreeWidget->topLevelItem( mColormapTreeWidget->topLevelItemCount() - 1 );
   729   double max = item->text( ValueColumn ).toDouble();
   739 void QgsColorRampShaderWidget::resetClassifyButton()
   741   mClassifyButton->setEnabled( 
true );
   742   if ( std::isnan( mMin ) || std::isnan( mMax ) || mMin >= mMax )
   744     mClassifyButton->setEnabled( 
false );
   748 void QgsColorRampShaderWidget::changeColor()
   750   QList<QTreeWidgetItem *> itemList;
   751   itemList = mColormapTreeWidget->selectedItems();
   752   if ( itemList.isEmpty() )
   756   QTreeWidgetItem *firstItem = itemList.first();
   758   QColor newColor = 
QgsColorDialog::getColor( firstItem->data( ColorColumn, Qt::EditRole ).value<QColor>(), 
this, QStringLiteral( 
"Change Color" ), true );
   759   if ( newColor.isValid() )
   761     Q_FOREACH ( QTreeWidgetItem *item, itemList )
   763       item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
   764       item->setData( ColorColumn, Qt::EditRole, newColor );
   772 void QgsColorRampShaderWidget::changeOpacity()
   774   QList<QTreeWidgetItem *> itemList;
   775   itemList = mColormapTreeWidget->selectedItems();
   776   if ( itemList.isEmpty() )
   780   QTreeWidgetItem *firstItem = itemList.first();
   783   double oldOpacity = firstItem->data( ColorColumn, Qt::EditRole ).value<QColor>().alpha() / 255 * 100;
   784   double opacity = QInputDialog::getDouble( 
this, tr( 
"Opacity" ), tr( 
"Change color opacity [%]" ), oldOpacity, 0.0, 100.0, 0, &ok );
   787     int newOpacity = 
static_cast<int>( opacity / 100 * 255 );
   788     Q_FOREACH ( QTreeWidgetItem *item, itemList )
   790       QColor newColor = item->data( ColorColumn, Qt::EditRole ).value<QColor>();
   791       newColor.setAlpha( newOpacity );
   792       item->setData( ColorColumn, Qt::EditRole, newColor );
 
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), bool allowOpacity=false)
Returns a color selection from a color dialog. 
 
A rectangle specified with double values. 
 
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom colormap. 
 
Uses quantile (i.e. equal pixel) count. 
 
static const double UI_SCALE_FACTOR
UI scaling factor. 
 
This class is a composition of two QSettings instances: 
 
A ramp shader will color a raster pixel based on a list of values ranges in a ramp. 
 
virtual QList< QgsColorRampShader::ColorRampItem > colorTable(int bandNo) const
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key. 
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference) 
 
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom colormap. 
 
void setClip(bool clip)
Sets whether the shader should not render values out of range. 
 
Type
Supported methods for color interpolation. 
 
void setColorRampType(QgsColorRampShader::Type colorRampType)
Sets the color ramp type. 
 
void setSourceColorRamp(QgsColorRamp *colorramp)
Set the source color ramp. 
 
Type colorRampType() const
Returns the color ramp type. 
 
Assigns the color of the exact matching value in the color ramp item list. 
 
Uses breaks from color palette. 
 
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value. 
 
void setClassificationMode(ClassificationMode classificationMode)
Sets classification mode. 
 
bool clip() const
Returns whether the shader will clip values which are out of range. 
 
Interpolates the color between two class breaks linearly. 
 
ClassificationMode
Classification modes used to create the color ramp shader. 
 
Assigns the color of the higher class for every pixel between two class breaks. 
 
ClassificationMode classificationMode() const
Returns the classification mode. 
 
QgsColorRamp * sourceColorRamp() const
Gets the source color ramp. 
 
A delegate for showing a color swatch in a list. 
 
Base class for raster data providers.