QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsrasterattributetablewidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrasterattributetablewidget.cpp - QgsRasterAttributeTableWidget
3
4 ---------------------
5 begin : 6.10.2022
6 copyright : (C) 2022 by Alessandro Pasotti
7 email : elpaso at itopen dot it
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
18#include "qgsrasterlayer.h"
19#include "qgsapplication.h"
20#include "qgsmessagebar.h"
23#include "qgscolorbutton.h"
25
26#include <QToolBar>
27#include <QAction>
28#include <QSortFilterProxyModel>
29#include <QMessageBox>
30#include <QFileDialog>
31
32QgsRasterAttributeTableWidget::QgsRasterAttributeTableWidget( QWidget *parent, QgsRasterLayer *rasterLayer, const int bandNumber )
33 : QgsPanelWidget( parent )
34 , mRasterLayer( rasterLayer )
35{
36 setupUi( this );
37
38 // Create the toolbar
39 QToolBar *editToolBar = new QToolBar( this );
40 editToolBar->setIconSize( QgsGuiUtils::iconSize( true ) );
41
42 mActionToggleEditing = new QAction( QgsApplication::getThemeIcon( "/mActionEditTable.svg" ), tr( "&Edit Attribute Table" ), editToolBar );
43 mActionToggleEditing->setCheckable( true );
44 connect( mActionToggleEditing, &QAction::triggered, this, [ = ]( bool editable )
45 {
46 setEditable( editable );
47 } );
48
49 editToolBar->addAction( mActionToggleEditing );
50
51 mActionAddColumn = new QAction( QgsApplication::getThemeIcon( "/mActionNewAttribute.svg" ), tr( "Add &Column…" ), editToolBar );
52 connect( mActionAddColumn, &QAction::triggered, this, &QgsRasterAttributeTableWidget::addColumn );
53 editToolBar->addAction( mActionAddColumn );
54
55 mActionAddRow = new QAction( QgsApplication::getThemeIcon( "/mActionNewTableRow.svg" ), tr( "&Add Row…" ), editToolBar );
56 connect( mActionAddRow, &QAction::triggered, this, &QgsRasterAttributeTableWidget::addRow );
57 editToolBar->addAction( mActionAddRow );
58
59 mActionRemoveRow = new QAction( QgsApplication::getThemeIcon( "/mActionRemoveSelectedFeature.svg" ), tr( "Remove Row" ), editToolBar );
60 connect( mActionRemoveRow, &QAction::triggered, this, &QgsRasterAttributeTableWidget::removeRow );
61 editToolBar->addAction( mActionRemoveRow );
62
63 mActionRemoveColumn = new QAction( QgsApplication::getThemeIcon( "/mActionDeleteAttribute.svg" ), tr( "Remove Column" ), editToolBar );
64 connect( mActionRemoveColumn, &QAction::triggered, this, &QgsRasterAttributeTableWidget::removeColumn );
65 editToolBar->addAction( mActionRemoveColumn );
66
67 mActionSaveChanges = new QAction( QgsApplication::getThemeIcon( "/mActionSaveAllEdits.svg" ), tr( "&Save Changes" ), editToolBar );
68 connect( mActionSaveChanges, &QAction::triggered, this, &QgsRasterAttributeTableWidget::saveChanges );
69 editToolBar->addAction( mActionSaveChanges );
70
71 layout()->setMenuBar( editToolBar );
72
73 connect( mClassifyButton, &QPushButton::clicked, this, &QgsRasterAttributeTableWidget::classify );
74
75 mProxyModel = new QSortFilterProxyModel( this );
76
77 mRATView->setModel( mProxyModel );
78
79 connect( mRATView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsRasterAttributeTableWidget::updateButtons );
80
81 if ( rasterLayer )
82 {
83 init( bandNumber );
84 }
85}
86
87void QgsRasterAttributeTableWidget::setRasterLayer( QgsRasterLayer *rasterLayer, const int bandNumber )
88{
89 mRasterLayer = rasterLayer;
90 init( bandNumber );
91}
92
94{
95 return mAttributeTableBuffer && mAttributeTableBuffer->isDirty();
96}
97
98void QgsRasterAttributeTableWidget::init( int bandNumber )
99{
100
101 disconnect( mRasterBandsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterAttributeTableWidget::bandChanged );
102 mAttributeTableBuffer = nullptr;
103 mCurrentBand = 0;
104 mRasterBandsComboBox->clear();
105
106 QList<int> availableRats;
107
108 if ( mRasterLayer )
109 {
110 for ( int checkBandNumber = 1; checkBandNumber <= mRasterLayer->bandCount(); ++checkBandNumber )
111 {
112 // Search for RATs
113 if ( mRasterLayer->attributeTable( checkBandNumber ) )
114 {
115 mRasterBandsComboBox->addItem( mRasterLayer->bandName( checkBandNumber ), checkBandNumber );
116 availableRats.push_back( checkBandNumber );
117 }
118 }
119
120 if ( !availableRats.isEmpty() )
121 {
122 if ( availableRats.contains( bandNumber ) )
123 {
124 mCurrentBand = bandNumber;
125 }
126 else if ( ! availableRats.isEmpty() )
127 {
128 mCurrentBand = availableRats.first();
129 }
130
131 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
132 mRasterBandsComboBox->setCurrentIndex( availableRats.indexOf( mCurrentBand ) );
133 }
134 }
135
136 if ( mAttributeTableBuffer )
137 {
138 mModel.reset( new QgsRasterAttributeTableModel( mAttributeTableBuffer.get() ) );
139 mModel->setEditable( mEditable );
140
141 connect( mModel.get(), &QgsRasterAttributeTableModel::dataChanged, this, [ = ]( const QModelIndex &, const QModelIndex &, const QVector<int> & )
142 {
143 updateButtons();
144 } );
145
146 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsInserted, this, [ = ]( const QModelIndex &, int, int )
147 {
148 setDelegates();
149 } );
150
151 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsRemoved, this, [ = ]( const QModelIndex &, int, int )
152 {
153 setDelegates();
154 } );
155
156 static_cast<QSortFilterProxyModel *>( mRATView->model() )->setSourceModel( mModel.get() );
157 setDelegates();
158 }
159 else
160 {
161 notify( tr( "No Attribute Tables Available" ), tr( "The raster layer has no associated attribute tables, you can create a new attribute table or load one from a VAT.DBF file." ), Qgis::Warning );
162 }
163
164 connect( mRasterBandsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterAttributeTableWidget::bandChanged );
165
166 updateButtons();
167}
168
169void QgsRasterAttributeTableWidget::updateButtons()
170{
171 const bool enableEditingButtons( static_cast<bool>( mAttributeTableBuffer ) && mEditable && mRATView->selectionModel()->currentIndex().isValid() );
172 mActionToggleEditing->setChecked( mEditable );
173 mActionToggleEditing->setEnabled( enableEditingButtons );
174 mActionAddColumn->setEnabled( mEditable );
175 mActionRemoveColumn->setEnabled( enableEditingButtons );
176 mActionAddRow->setEnabled( enableEditingButtons );
177 mActionRemoveRow->setEnabled( enableEditingButtons );
178 mActionSaveChanges->setEnabled( mAttributeTableBuffer && mAttributeTableBuffer->isDirty() );
179 mClassifyButton->setEnabled( mAttributeTableBuffer && mRasterLayer );
180 mClassifyComboBox->setEnabled( mAttributeTableBuffer && mRasterLayer );
181}
182
184{
186 static_cast<QToolBar *>( layout()->menuBar() )->setIconSize( QgsGuiUtils::iconSize( dockMode ) );
187}
188
190{
191 mMessageBar = bar;
192}
193
194bool QgsRasterAttributeTableWidget::setEditable( bool editable, bool allowCancel )
195{
196 const bool isDirty { mAttributeTableBuffer &&mAttributeTableBuffer->isDirty() &&mCurrentBand > 0 && mRasterLayer->attributeTable( mCurrentBand ) };
197 bool retVal { true };
198 // Switch to read-only
199 if ( ! editable && isDirty )
200 {
201 QMessageBox::StandardButtons buttons { QMessageBox::Button::Yes | QMessageBox::Button::No };
202
203 if ( allowCancel )
204 {
205 buttons |= QMessageBox::Button::Cancel;
206 }
207
208 switch ( QMessageBox::question( nullptr, tr( "Save Attribute Table" ), tr( "Attribute table contains unsaved changes, do you want to save the changes?" ), buttons ) )
209 {
210 case QMessageBox::Button::Cancel:
211 {
212 retVal = false;
213 break;
214 }
215 case QMessageBox::Button::Yes:
216 {
217 saveChanges();
218 retVal = true;
219 break;
220 }
221 case QMessageBox::Button::No:
222 default:
223 {
224 // Reset to its original state
225 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
226 init( mCurrentBand );
227 retVal = true;
228 break;
229 }
230 }
231 }
232
233 if ( retVal )
234 {
235 mEditable = editable;
236 mModel->setEditable( editable );
237 }
238
239 updateButtons();
240
241 return retVal;
242}
243
245{
246 if ( mRasterLayer && mAttributeTableBuffer && mAttributeTableBuffer->isDirty() && mCurrentBand > 0 )
247 {
248 QgsRasterAttributeTable *attributeTable { mRasterLayer->dataProvider()->attributeTable( mCurrentBand ) };
249 if ( ! attributeTable )
250 {
251 QgsDebugError( QStringLiteral( "Error saving RAT: RAT for band %1 is unexpectedly gone!" ).arg( mCurrentBand ) );
252 }
253 else
254 {
255 *attributeTable = *mAttributeTableBuffer;
256 QString errorMessage;
257 QString newPath { attributeTable->filePath() };
258 const bool nativeRatSupported = mRasterLayer->dataProvider()->providerCapabilities().testFlag( QgsRasterDataProvider::ProviderCapability::NativeRasterAttributeTable );
259 bool saveToNative { false };
260
261 if ( newPath.isEmpty() && ! nativeRatSupported )
262 {
263 newPath = QFileDialog::getOpenFileName( nullptr, tr( "Save Raster Attribute Table (band %1) To File" ).arg( mCurrentBand ), QFile::exists( mRasterLayer->dataProvider()->dataSourceUri( ) ) ? mRasterLayer->dataProvider()->dataSourceUri( ) + ".vat.dbf" : QString(), QStringLiteral( "VAT DBF Files (*.vat.dbf)" ) );
264 if ( newPath.isEmpty() )
265 {
266 // Aborted by user
267 return;
268 }
269 }
270 else if ( newPath.isEmpty() )
271 {
272 saveToNative = true;
273 }
274
275 bool writeSuccess { false };
276
277 // Save to file
278 if ( ! saveToNative && ! newPath.isEmpty() )
279 {
280 writeSuccess = attributeTable->writeToFile( attributeTable->filePath(), &errorMessage );
281 }
282 else if ( saveToNative )
283 {
284 writeSuccess = mRasterLayer->dataProvider()->writeNativeAttributeTable( &errorMessage ); //#spellok
285 }
286
287 if ( writeSuccess )
288 {
289 mAttributeTableBuffer->setDirty( false );
290 notify( tr( "Attribute Table Write Success" ), tr( "The raster attribute table has been successfully saved." ), Qgis::MessageLevel::Success );
291 }
292 else
293 {
294 notify( tr( "Attribute Table Write Error" ), errorMessage, Qgis::MessageLevel::Critical );
295 }
296
297 // Save to native saves RATs for all bands, no need to loop further.
298 if ( saveToNative )
299 {
300 return;
301 }
302
303 }
304 }
305
306 updateButtons();
307}
308
309void QgsRasterAttributeTableWidget::classify()
310{
311
312 if ( ! mAttributeTableBuffer )
313 {
314 notify( tr( "Classification Error" ), tr( "The raster attribute table is not set." ), Qgis::MessageLevel::Critical );
315 return;
316 }
317
318 if ( ! mRasterLayer )
319 {
320 notify( tr( "Classification Error" ), tr( "The raster layer is not set." ), Qgis::MessageLevel::Critical );
321 return;
322 }
323
324 QString confirmMessage;
325 QString errorMessage;
326
327 if ( ! mAttributeTableBuffer->isValid( &errorMessage ) )
328 {
329 confirmMessage = tr( "The attribute table does not seem to be valid and it may produce an unusable symbology, validation errors:<br>%1<br>" ).arg( errorMessage );
330 }
331
332 if ( QMessageBox::question( nullptr, tr( "Apply Style From Attribute Table" ), confirmMessage.append( tr( "The existing symbology for the raster will be replaced by a new symbology from the attribute table and any unsaved changes to the current symbology will be lost, do you want to proceed?" ) ) ) == QMessageBox::Yes )
333 {
334
335 if ( QgsRasterRenderer *renderer = mAttributeTableBuffer->createRenderer( mRasterLayer->dataProvider(), mCurrentBand, mClassifyComboBox->currentData().toInt() ) )
336 {
337 mRasterLayer->setRenderer( renderer );
338 mRasterLayer->triggerRepaint( );
339 emit rendererChanged();
340 }
341 else
342 {
343 notify( tr( "Classification Error" ), tr( "The classification returned no classes." ), Qgis::MessageLevel::Critical );
344 }
345 }
346}
347
348void QgsRasterAttributeTableWidget::addColumn()
349{
350 if ( mAttributeTableBuffer )
351 {
352 QgsRasterAttributeTableAddColumnDialog dlg { mAttributeTableBuffer.get() };
353 if ( dlg.exec() == QDialog::Accepted )
354 {
355 QString errorMessage;
356 if ( dlg.isColor() )
357 {
358 if ( ! mModel->insertColor( dlg.position(), &errorMessage ) )
359 {
360 notify( tr( "Error adding color column" ), errorMessage, Qgis::MessageLevel::Critical );
361 }
362 }
363 else if ( dlg.isRamp() )
364 {
365 if ( ! mModel->insertRamp( dlg.position(), &errorMessage ) )
366 {
367 notify( tr( "Error adding color ramp column" ), errorMessage, Qgis::MessageLevel::Critical );
368 }
369 }
370 else
371 {
372 if ( ! mModel->insertField( dlg.position(), dlg.name(), dlg.usage(), dlg.type(), &errorMessage ) )
373 {
374 notify( tr( "Error adding new column" ), errorMessage, Qgis::MessageLevel::Critical );
375 }
376 }
377 }
378 setDelegates();
379 }
380}
381
382void QgsRasterAttributeTableWidget::removeColumn()
383{
384 const QModelIndex currentIndex { mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ) };
385 if ( mAttributeTableBuffer && currentIndex.isValid() && currentIndex.column() < mAttributeTableBuffer->fields().count() )
386 {
387 if ( QMessageBox::question( nullptr, tr( "Remove Column" ), tr( "Do you want to remove the selected column? This action cannot be undone." ) ) == QMessageBox::Yes )
388 {
389 QString errorMessage;
390 if ( ! mModel->removeField( currentIndex.column(), &errorMessage ) )
391 {
392 notify( tr( "Error removing column" ), errorMessage, Qgis::MessageLevel::Critical );
393 }
394 }
395 }
396}
397
398void QgsRasterAttributeTableWidget::addRow()
399{
400 if ( mAttributeTableBuffer )
401 {
402 // Default to append
403 int position { mModel->rowCount( QModelIndex() ) };
404 const QModelIndex currentIndex { mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ) };
405
406 // If there is a selected row, ask if before of after.
407 if ( currentIndex.isValid() )
408 {
409 // Ask the user where to insert the new row (before or after the currently
410 // selected row).
412 if ( dlg.exec() != QDialog::DialogCode::Accepted )
413 {
414 return;
415 }
416 else
417 {
418 position = currentIndex.row() + ( dlg.insertAfter() ? 1 : 0 );
419 }
420 }
421
422 bool result { true };
423 QString errorMessage;
424
425 QVariantList rowData;
426
427 QList<QgsRasterAttributeTable::Field> fields { mAttributeTableBuffer->fields() };
428 for ( const QgsRasterAttributeTable::Field &field : std::as_const( fields ) )
429 {
430 rowData.push_back( QVariant( field.type ) );
431 }
432
433 result = mModel->insertRow( position, rowData, &errorMessage );
434
435 if ( ! result )
436 {
437 notify( tr( "Error adding row" ), errorMessage, Qgis::MessageLevel::Critical );
438 }
439 else
440 {
441 mRATView->scrollTo( mRATView->model()->index( position, 0 ) );
442 }
443 }
444}
445
446void QgsRasterAttributeTableWidget::removeRow()
447{
448 if ( mAttributeTableBuffer && mRATView->selectionModel()->currentIndex().isValid() )
449 {
450 if ( QMessageBox::question( nullptr, tr( "Remove Row" ), tr( "Do you want to remove the selected row? This action cannot be undone." ) ) == QMessageBox::Yes )
451 {
452 QString errorMessage;
453 if ( ! mModel->removeRow( mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ).row(), &errorMessage ) )
454 {
455 notify( tr( "Error removing row" ), errorMessage, Qgis::MessageLevel::Critical );
456 }
457 }
458 }
459}
460
461void QgsRasterAttributeTableWidget::bandChanged( const int index )
462{
463 const QVariant itemData = mRasterBandsComboBox->itemData( index );
464
465 if ( itemData.isValid() )
466 {
467 if ( mEditable )
468 {
469 setEditable( false );
470 }
471 init( itemData.toInt( ) );
472 }
473}
474
475void QgsRasterAttributeTableWidget::notify( const QString &title, const QString &message, Qgis::MessageLevel level )
476{
477 if ( mMessageBar )
478 {
479 mMessageBar->pushMessage( message, level );
480 }
481 else
482 {
483 switch ( level )
484 {
485 case Qgis::MessageLevel::Info:
486 case Qgis::MessageLevel::Success:
487 case Qgis::MessageLevel::NoLevel:
488 {
489 QMessageBox::information( nullptr, title, message );
490 break;
491 }
492 case Qgis::MessageLevel::Warning:
493 {
494 QMessageBox::warning( nullptr, title, message );
495 break;
496 }
497 case Qgis::MessageLevel::Critical:
498 {
499 QMessageBox::critical( nullptr, title, message );
500 break;
501 }
502 }
503 }
504}
505
506void QgsRasterAttributeTableWidget::setDelegates()
507{
508 mClassifyComboBox->clear();
509 if ( mAttributeTableBuffer )
510 {
511 const QList<QgsRasterAttributeTable::Field> tableFields { mAttributeTableBuffer->fields() };
512 int fieldIdx { 0 };
513 const QHash<Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation> usageInfo { QgsRasterAttributeTable::usageInformation() };
514
515 for ( const QgsRasterAttributeTable::Field &f : std::as_const( tableFields ) )
516 {
517 // Clear all delegates.
518 mRATView->setItemDelegateForColumn( fieldIdx, nullptr );
519
520 if ( usageInfo[f.usage].maybeClass )
521 {
522 mClassifyComboBox->addItem( QgsFields::iconForFieldType( f.type ), f.name, QVariant( fieldIdx ) );
523 }
524
525 // Set delegates for doubles
526 if ( ( ! f.isColor() && ! f.isRamp() ) && f.type == QVariant::Type::Double )
527 {
528 mRATView->setItemDelegateForColumn( fieldIdx, new LocalizedDoubleDelegate( mRATView ) );
529 }
530 fieldIdx++;
531 }
532
533 // Set delegates for color and ramp
534 if ( mAttributeTableBuffer->hasColor() )
535 {
536 if ( mAttributeTableBuffer->usages().contains( Qgis::RasterAttributeTableFieldUsage::Alpha ) )
537 {
538 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorAlphaDelegate( mRATView ) );
539 }
540 else
541 {
542 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorDelegate( mRATView ) );
543 }
544 }
545 else if ( mAttributeTableBuffer->hasRamp() )
546 {
547 if ( mAttributeTableBuffer->usages().contains( Qgis::RasterAttributeTableFieldUsage::AlphaMin ) )
548 {
549 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorRampAlphaDelegate( mRATView ) );
550 }
551 else
552 {
553 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorRampDelegate( mRATView ) );
554 }
555 }
556 }
557}
558
559
561
562QWidget *ColorDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
563{
564 return new QgsColorButton( parent, tr( "Select Color" ) );
565}
566
567void ColorDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
568{
569 const QColor color { index.data( Qt::ItemDataRole::EditRole ).value<QColor>() };
570 static_cast<QgsColorButton *>( editor )->setColor( color );
571}
572
573void ColorDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
574{
575 const QColor color { static_cast<QgsColorButton *>( editor )->color( ) };
576 model->setData( index, color );
577}
578
579QWidget *ColorAlphaDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
580{
581 QWidget *editor { ColorDelegate::createEditor( parent, option, index ) };
582 static_cast<QgsColorButton *>( editor )->setAllowOpacity( true );
583 return editor;
584}
585
586QWidget *ColorRampDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
587{
589 return editor;
590}
591
592void ColorRampDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
593{
594 const QgsGradientColorRamp ramp { qvariant_cast<QgsGradientColorRamp>( index.data( Qt::ItemDataRole::EditRole ) ) };
595 static_cast<QgsGradientColorRampDialog *>( editor )->setRamp( ramp );
596}
597
598void ColorRampDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
599{
600 model->setData( index, QVariant::fromValue( static_cast<QgsGradientColorRampDialog *>( editor )->ramp() ) );
601}
602
603void ColorRampDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
604{
605 const QgsGradientColorRamp ramp { qvariant_cast<QgsGradientColorRamp>( index.data( Qt::ItemDataRole::EditRole ) ) };
606 QLinearGradient gradient( QPointF( 0, 0 ), QPointF( 1, 0 ) );
607 gradient.setCoordinateMode( QGradient::CoordinateMode::ObjectBoundingMode );
608 gradient.setColorAt( 0, ramp.color1() );
609 gradient.setColorAt( 1, ramp.color2() );
610 const QRect r = option.rect.adjusted( 1, 1, -1, -1 );
611 const QgsScopedQPainterState painterState( painter );
612 painter->fillRect( r, QBrush{ gradient } );
613}
614
615QWidget *ColorRampAlphaDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
616{
617 QWidget *editor { ColorRampDelegate::createEditor( parent, option, index ) };
618 // No opacity setting for ramps?
619 return editor;
620}
621
622
623QString LocalizedDoubleDelegate::displayText( const QVariant &value, const QLocale &locale ) const
624{
625 Q_UNUSED( locale );
626 const QString s( value.toString() );
627 const int dotPosition( s.indexOf( '.' ) );
628 int precision;
629 if ( dotPosition < 0 && s.indexOf( 'e' ) < 0 )
630 {
631 precision = 0;
632 return QLocale().toString( value.toDouble(), 'f', precision );
633 }
634 else
635 {
636 if ( dotPosition < 0 ) precision = 0;
637 else precision = s.length() - dotPosition - 1;
638
639 if ( -1 < value.toDouble() && value.toDouble() < 1 )
640 {
641 return QLocale().toString( value.toDouble(), 'g', precision );
642 }
643 else
644 {
645 return QLocale().toString( value.toDouble(), 'f', precision );
646 }
647 }
648 return QLocale().toString( value.toDouble( ), 'f' );
649}
650
652
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:99
@ Warning
Warning message.
Definition: qgis.h:101
@ AlphaMin
Field usage AlphaMin.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A cross platform button subclass for selecting colors.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
static QIcon iconForFieldType(QVariant::Type type, QVariant::Type subType=QVariant::Type::Invalid, const QString &typeString=QString())
Returns an icon corresponding to a field type.
Definition: qgsfields.cpp:294
A dialog which allows users to modify the properties of a QgsGradientColorRamp.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
Base class for any widget that can be shown as a inline panel.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
bool dockMode()
Returns the dock mode state.
The QgsRasterAttributeTableAddColumnDialog class collects options to add a new column to a raster att...
The QgsRasterAttributeTableAddColumnDialog class collects options to add a new row to a raster attrib...
bool insertAfter() const
Returns true if the desired insertion position for the new row is after the currently selected row,...
The QgsRasterAttributeTableModel class manages a QgsRasterAttributeTable.
void rendererChanged()
This signal is emitted after a successful classify operation which changed the raster renderer.
bool isDirty() const
Returns true if the associated raster attribute table is dirty.
bool setEditable(bool editable, bool allowCancel=true)
Set the editable state, it may trigger save changes if the attribute table has unsave changes.
void setRasterLayer(QgsRasterLayer *rasterLayer, const int bandNumber=0)
Sets the raster layer and an optional band number.
void saveChanges()
Save the changes in the raster attribute table.
QgsRasterAttributeTableWidget(QWidget *parent=nullptr, QgsRasterLayer *rasterLayer=nullptr, const int bandNumber=0)
Creates a new QgsRasterAttributeTableWidget.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
The Field class represents a Raster Attribute Table field, including its name, usage and type.
The QgsRasterAttributeTable class represents a Raster Attribute Table (RAT).
static QHash< Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation > usageInformation()
Returns information about supported Raster Attribute Table usages.
virtual bool writeNativeAttributeTable(QString *errorMessage=nullptr)
Writes the native attribute table, optionally reporting any error in errorMessage,...
QgsRasterAttributeTable * attributeTable(int bandNumber) const
Returns the (possibly NULL) attribute table for the specified bandNumber.
virtual QgsRasterDataProvider::ProviderCapabilities providerCapabilities() const
Returns flags containing the supported capabilities of the data provider.
Represents a raster layer.
QgsRasterAttributeTable * attributeTable(int bandNumber) const
Returns the (possibly NULL) raster attribute table for the given band bandNumber.
int bandCount() const
Returns the number of bands in this layer.
QString bandName(int bandNoInt) const
Returns the name of a band given its number.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
void setRenderer(QgsRasterRenderer *renderer)
Sets the raster's renderer.
Raster renderer pipe that applies colors to a raster.
Scoped object for saving and restoring a QPainter object's state.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
#define QgsDebugError(str)
Definition: qgslogger.h:38
int precision