QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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 mActionAddColumn->setEnabled( mEditable );
174 mActionRemoveColumn->setEnabled( enableEditingButtons );
175 mActionAddRow->setEnabled( enableEditingButtons );
176 mActionRemoveRow->setEnabled( enableEditingButtons );
177 mActionSaveChanges->setEnabled( mAttributeTableBuffer && mAttributeTableBuffer->isDirty() );
178 mClassifyButton->setEnabled( mAttributeTableBuffer && mRasterLayer );
179 mClassifyComboBox->setEnabled( mAttributeTableBuffer && mRasterLayer );
180}
181
183{
185 static_cast<QToolBar *>( layout()->menuBar() )->setIconSize( QgsGuiUtils::iconSize( dockMode ) );
186}
187
189{
190 mMessageBar = bar;
191}
192
193bool QgsRasterAttributeTableWidget::setEditable( bool editable, bool allowCancel )
194{
195 const bool isDirty { mAttributeTableBuffer &&mAttributeTableBuffer->isDirty() &&mCurrentBand > 0 && mRasterLayer->attributeTable( mCurrentBand ) };
196 bool retVal { true };
197 // Switch to read-only
198 if ( ! editable && isDirty )
199 {
200 QMessageBox::StandardButtons buttons { QMessageBox::Button::Yes | QMessageBox::Button::No };
201
202 if ( allowCancel )
203 {
204 buttons |= QMessageBox::Button::Cancel;
205 }
206
207 switch ( QMessageBox::question( nullptr, tr( "Save Attribute Table" ), tr( "Attribute table contains unsaved changes, do you want to save the changes?" ), buttons ) )
208 {
209 case QMessageBox::Button::Cancel:
210 {
211 retVal = false;
212 break;
213 }
214 case QMessageBox::Button::Yes:
215 {
216 saveChanges();
217 retVal = true;
218 break;
219 }
220 case QMessageBox::Button::No:
221 default:
222 {
223 // Reset to its original state
224 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
225 init( mCurrentBand );
226 retVal = true;
227 break;
228 }
229 }
230 }
231
232 if ( retVal )
233 {
234 mEditable = editable;
235 mModel->setEditable( editable );
236 }
237
238 updateButtons();
239
240 return retVal;
241}
242
244{
245 if ( mRasterLayer && mAttributeTableBuffer && mAttributeTableBuffer->isDirty() && mCurrentBand > 0 )
246 {
247 QgsRasterAttributeTable *attributeTable { mRasterLayer->dataProvider()->attributeTable( mCurrentBand ) };
248 if ( ! attributeTable )
249 {
250 QgsDebugMsg( QStringLiteral( "Error saving RAT: RAT for band %1 is unexpectedly gone!" ).arg( mCurrentBand ) );
251 }
252 else
253 {
254 *attributeTable = *mAttributeTableBuffer;
255 QString errorMessage;
256 QString newPath { attributeTable->filePath() };
257 const bool nativeRatSupported = mRasterLayer->dataProvider()->providerCapabilities().testFlag( QgsRasterDataProvider::ProviderCapability::NativeRasterAttributeTable );
258 bool saveToNative { false };
259
260 if ( newPath.isEmpty() && ! nativeRatSupported )
261 {
262 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)" ) );
263 if ( newPath.isEmpty() )
264 {
265 // Aborted by user
266 return;
267 }
268 }
269 else if ( newPath.isEmpty() )
270 {
271 saveToNative = true;
272 }
273
274 bool writeSuccess { false };
275
276 // Save to file
277 if ( ! saveToNative && ! newPath.isEmpty() )
278 {
279 writeSuccess = attributeTable->writeToFile( attributeTable->filePath(), &errorMessage );
280 }
281 else if ( saveToNative )
282 {
283 writeSuccess = mRasterLayer->dataProvider()->writeNativeAttributeTable( &errorMessage ); //#spellok
284 }
285
286 if ( writeSuccess )
287 {
288 mAttributeTableBuffer->setDirty( false );
289 notify( tr( "Attribute Table Write Success" ), tr( "The raster attribute table has been successfully saved." ), Qgis::MessageLevel::Success );
290 }
291 else
292 {
293 notify( tr( "Attribute Table Write Error" ), errorMessage, Qgis::MessageLevel::Critical );
294 }
295
296 // Save to native saves RATs for all bands, no need to loop further.
297 if ( saveToNative )
298 {
299 return;
300 }
301
302 }
303 }
304
305 updateButtons();
306}
307
308void QgsRasterAttributeTableWidget::classify()
309{
310
311 if ( ! mAttributeTableBuffer )
312 {
313 notify( tr( "Classification Error" ), tr( "The raster attribute table is not set." ), Qgis::MessageLevel::Critical );
314 return;
315 }
316
317 if ( ! mRasterLayer )
318 {
319 notify( tr( "Classification Error" ), tr( "The raster layer is not set." ), Qgis::MessageLevel::Critical );
320 return;
321 }
322
323 QString confirmMessage;
324 QString errorMessage;
325
326 if ( ! mAttributeTableBuffer->isValid( &errorMessage ) )
327 {
328 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 );
329 }
330
331 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 )
332 {
333
334 if ( QgsRasterRenderer *renderer = mAttributeTableBuffer->createRenderer( mRasterLayer->dataProvider(), mCurrentBand, mClassifyComboBox->currentData().toInt() ) )
335 {
336 mRasterLayer->setRenderer( renderer );
337 mRasterLayer->triggerRepaint( );
338 emit rendererChanged();
339 }
340 else
341 {
342 notify( tr( "Classification Error" ), tr( "The classification returned no classes." ), Qgis::MessageLevel::Critical );
343 }
344 }
345}
346
347void QgsRasterAttributeTableWidget::addColumn()
348{
349 if ( mAttributeTableBuffer )
350 {
351 QgsRasterAttributeTableAddColumnDialog dlg { mAttributeTableBuffer.get() };
352 if ( dlg.exec() == QDialog::Accepted )
353 {
354 QString errorMessage;
355 if ( dlg.isColor() )
356 {
357 if ( ! mModel->insertColor( dlg.position(), &errorMessage ) )
358 {
359 notify( tr( "Error adding color column" ), errorMessage, Qgis::MessageLevel::Critical );
360 }
361 }
362 else if ( dlg.isRamp() )
363 {
364 if ( ! mModel->insertRamp( dlg.position(), &errorMessage ) )
365 {
366 notify( tr( "Error adding color ramp column" ), errorMessage, Qgis::MessageLevel::Critical );
367 }
368 }
369 else
370 {
371 if ( ! mModel->insertField( dlg.position(), dlg.name(), dlg.usage(), dlg.type(), &errorMessage ) )
372 {
373 notify( tr( "Error adding new column" ), errorMessage, Qgis::MessageLevel::Critical );
374 }
375 }
376 }
377 setDelegates();
378 }
379}
380
381void QgsRasterAttributeTableWidget::removeColumn()
382{
383 const QModelIndex currentIndex { mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ) };
384 if ( mAttributeTableBuffer && currentIndex.isValid() && currentIndex.column() < mAttributeTableBuffer->fields().count() )
385 {
386 if ( QMessageBox::question( nullptr, tr( "Remove Column" ), tr( "Do you want to remove the selected column? This action cannot be undone." ) ) == QMessageBox::Yes )
387 {
388 QString errorMessage;
389 if ( ! mModel->removeField( currentIndex.column(), &errorMessage ) )
390 {
391 notify( tr( "Error removing column" ), errorMessage, Qgis::MessageLevel::Critical );
392 }
393 }
394 }
395}
396
397void QgsRasterAttributeTableWidget::addRow()
398{
399 if ( mAttributeTableBuffer )
400 {
401 // Default to append
402 int position { mModel->rowCount( QModelIndex() ) };
403 const QModelIndex currentIndex { mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ) };
404
405 // If there is a selected row, ask if before of after.
406 if ( currentIndex.isValid() )
407 {
408 // Ask the user where to insert the new row (before or after the currently
409 // selected row).
411 if ( dlg.exec() != QDialog::DialogCode::Accepted )
412 {
413 return;
414 }
415 else
416 {
417 position = currentIndex.row() + ( dlg.insertAfter() ? 1 : 0 );
418 }
419 }
420
421 bool result { true };
422 QString errorMessage;
423
424 QVariantList rowData;
425
426 QList<QgsRasterAttributeTable::Field> fields { mAttributeTableBuffer->fields() };
427 for ( const QgsRasterAttributeTable::Field &field : std::as_const( fields ) )
428 {
429 rowData.push_back( QVariant( field.type ) );
430 }
431
432 result = mModel->insertRow( position, rowData, &errorMessage );
433
434 if ( ! result )
435 {
436 notify( tr( "Error adding row" ), errorMessage, Qgis::MessageLevel::Critical );
437 }
438 else
439 {
440 mRATView->scrollTo( mRATView->model()->index( position, 0 ) );
441 }
442 }
443}
444
445void QgsRasterAttributeTableWidget::removeRow()
446{
447 if ( mAttributeTableBuffer && mRATView->selectionModel()->currentIndex().isValid() )
448 {
449 if ( QMessageBox::question( nullptr, tr( "Remove Row" ), tr( "Do you want to remove the selected row? This action cannot be undone." ) ) == QMessageBox::Yes )
450 {
451 QString errorMessage;
452 if ( ! mModel->removeRow( mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ).row(), &errorMessage ) )
453 {
454 notify( tr( "Error removing row" ), errorMessage, Qgis::MessageLevel::Critical );
455 }
456 }
457 }
458}
459
460void QgsRasterAttributeTableWidget::bandChanged( const int index )
461{
462 const QVariant itemData = mRasterBandsComboBox->itemData( index );
463
464 if ( itemData.isValid() )
465 {
466 if ( mEditable )
467 {
468 setEditable( false );
469 }
470 init( itemData.toInt( ) );
471 }
472}
473
474void QgsRasterAttributeTableWidget::notify( const QString &title, const QString &message, Qgis::MessageLevel level )
475{
476 if ( mMessageBar )
477 {
478 mMessageBar->pushMessage( message, level );
479 }
480 else
481 {
482 switch ( level )
483 {
484 case Qgis::MessageLevel::Info:
485 case Qgis::MessageLevel::Success:
486 case Qgis::MessageLevel::NoLevel:
487 {
488 QMessageBox::information( nullptr, title, message );
489 break;
490 }
491 case Qgis::MessageLevel::Warning:
492 {
493 QMessageBox::warning( nullptr, title, message );
494 break;
495 }
496 case Qgis::MessageLevel::Critical:
497 {
498 QMessageBox::critical( nullptr, title, message );
499 break;
500 }
501 }
502 }
503}
504
505void QgsRasterAttributeTableWidget::setDelegates()
506{
507 mClassifyComboBox->clear();
508 if ( mAttributeTableBuffer )
509 {
510 const QList<QgsRasterAttributeTable::Field> tableFields { mAttributeTableBuffer->fields() };
511 int fieldIdx { 0 };
512 const QHash<Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation> usageInfo { QgsRasterAttributeTable::usageInformation() };
513
514 for ( const QgsRasterAttributeTable::Field &f : std::as_const( tableFields ) )
515 {
516 // Clear all delegates.
517 mRATView->setItemDelegateForColumn( fieldIdx, nullptr );
518
519 if ( usageInfo[f.usage].maybeClass )
520 {
521 mClassifyComboBox->addItem( QgsFields::iconForFieldType( f.type ), f.name, QVariant( fieldIdx ) );
522 }
523
524 // Set delegates for doubles
525 if ( ( ! f.isColor() && ! f.isRamp() ) && f.type == QVariant::Type::Double )
526 {
527 mRATView->setItemDelegateForColumn( fieldIdx, new LocalizedDoubleDelegate( mRATView ) );
528 }
529 fieldIdx++;
530 }
531
532 // Set delegates for color and ramp
533 if ( mAttributeTableBuffer->hasColor() )
534 {
535 if ( mAttributeTableBuffer->usages().contains( Qgis::RasterAttributeTableFieldUsage::Alpha ) )
536 {
537 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorAlphaDelegate( mRATView ) );
538 }
539 else
540 {
541 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorDelegate( mRATView ) );
542 }
543 }
544 else if ( mAttributeTableBuffer->hasRamp() )
545 {
546 if ( mAttributeTableBuffer->usages().contains( Qgis::RasterAttributeTableFieldUsage::AlphaMin ) )
547 {
548 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorRampAlphaDelegate( mRATView ) );
549 }
550 else
551 {
552 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorRampDelegate( mRATView ) );
553 }
554 }
555 }
556}
557
558
560
561QWidget *ColorDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
562{
563 return new QgsColorButton( parent, tr( "Select Color" ) );
564}
565
566void ColorDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
567{
568 const QColor color { index.data( Qt::ItemDataRole::EditRole ).value<QColor>() };
569 static_cast<QgsColorButton *>( editor )->setColor( color );
570}
571
572void ColorDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
573{
574 const QColor color { static_cast<QgsColorButton *>( editor )->color( ) };
575 model->setData( index, color );
576}
577
578QWidget *ColorAlphaDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
579{
580 QWidget *editor { ColorDelegate::createEditor( parent, option, index ) };
581 static_cast<QgsColorButton *>( editor )->setAllowOpacity( true );
582 return editor;
583}
584
585QWidget *ColorRampDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
586{
588 return editor;
589}
590
591void ColorRampDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
592{
593 const QgsGradientColorRamp ramp { qvariant_cast<QgsGradientColorRamp>( index.data( Qt::ItemDataRole::EditRole ) ) };
594 static_cast<QgsGradientColorRampDialog *>( editor )->setRamp( ramp );
595}
596
597void ColorRampDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
598{
599 model->setData( index, QVariant::fromValue( static_cast<QgsGradientColorRampDialog *>( editor )->ramp() ) );
600}
601
602void ColorRampDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
603{
604 const QgsGradientColorRamp ramp { qvariant_cast<QgsGradientColorRamp>( index.data( Qt::ItemDataRole::EditRole ) ) };
605 QLinearGradient gradient( QPointF( 0, 0 ), QPointF( 1, 0 ) );
606 gradient.setCoordinateMode( QGradient::CoordinateMode::ObjectBoundingMode );
607 gradient.setColorAt( 0, ramp.color1() );
608 gradient.setColorAt( 1, ramp.color2() );
609 const QRect r = option.rect.adjusted( 1, 1, -1, -1 );
610 const QgsScopedQPainterState painterState( painter );
611 painter->fillRect( r, QBrush{ gradient } );
612}
613
614QWidget *ColorRampAlphaDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
615{
616 QWidget *editor { ColorRampDelegate::createEditor( parent, option, index ) };
617 // No opacity setting for ramps?
618 return editor;
619}
620
621
622QString LocalizedDoubleDelegate::displayText( const QVariant &value, const QLocale &locale ) const
623{
624 Q_UNUSED( locale );
625 const QString s( value.toString() );
626 const int dotPosition( s.indexOf( '.' ) );
627 int precision;
628 if ( dotPosition < 0 && s.indexOf( 'e' ) < 0 )
629 {
630 precision = 0;
631 return QLocale().toString( value.toDouble(), 'f', precision );
632 }
633 else
634 {
635 if ( dotPosition < 0 ) precision = 0;
636 else precision = s.length() - dotPosition - 1;
637
638 if ( -1 < value.toDouble() && value.toDouble() < 1 )
639 {
640 return QLocale().toString( value.toDouble(), 'g', precision );
641 }
642 else
643 {
644 return QLocale().toString( value.toDouble(), 'f', precision );
645 }
646 }
647 return QLocale().toString( value.toDouble( ), 'f' );
648}
649
651
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:100
@ Warning
Warning message.
Definition: qgis.h:102
@ 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.
QVariant::Type type
Definition: qgsfield.h:59
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.
const QgsField & field
Definition: qgsfield.h:501
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
int precision