QGIS API Documentation 3.99.0-Master (752b475928d)
Loading...
Searching...
No Matches
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 ***************************************************************************/
17
18#include <memory>
19
20#include "qgsapplication.h"
21#include "qgscolorbutton.h"
23#include "qgsmessagebar.h"
27#include "qgsrasterlayer.h"
28
29#include <QAction>
30#include <QFileDialog>
31#include <QMessageBox>
32#include <QSortFilterProxyModel>
33#include <QToolBar>
34
35#include "moc_qgsrasterattributetablewidget.cpp"
36
37QgsRasterAttributeTableWidget::QgsRasterAttributeTableWidget( QWidget *parent, QgsRasterLayer *rasterLayer, const int bandNumber )
38 : QgsPanelWidget( parent )
39 , mRasterLayer( rasterLayer )
40{
41 setupUi( this );
42
43 // Create the toolbar
44 QToolBar *editToolBar = new QToolBar( this );
45 editToolBar->setIconSize( QgsGuiUtils::iconSize( true ) );
46
47 mActionToggleEditing = new QAction( QgsApplication::getThemeIcon( "/mActionEditTable.svg" ), tr( "&Edit Attribute Table" ), editToolBar );
48 mActionToggleEditing->setCheckable( true );
49 connect( mActionToggleEditing, &QAction::triggered, this, [this]( bool editable ) {
50 setEditable( editable );
51 } );
52
53 editToolBar->addAction( mActionToggleEditing );
54
55 mActionAddColumn = new QAction( QgsApplication::getThemeIcon( "/mActionNewAttribute.svg" ), tr( "Add &Column…" ), editToolBar );
56 connect( mActionAddColumn, &QAction::triggered, this, &QgsRasterAttributeTableWidget::addColumn );
57 editToolBar->addAction( mActionAddColumn );
58
59 mActionAddRow = new QAction( QgsApplication::getThemeIcon( "/mActionNewTableRow.svg" ), tr( "&Add Row…" ), editToolBar );
60 connect( mActionAddRow, &QAction::triggered, this, &QgsRasterAttributeTableWidget::addRow );
61 editToolBar->addAction( mActionAddRow );
62
63 mActionRemoveRow = new QAction( QgsApplication::getThemeIcon( "/mActionRemoveSelectedFeature.svg" ), tr( "Remove Row" ), editToolBar );
64 connect( mActionRemoveRow, &QAction::triggered, this, &QgsRasterAttributeTableWidget::removeRow );
65 editToolBar->addAction( mActionRemoveRow );
66
67 mActionRemoveColumn = new QAction( QgsApplication::getThemeIcon( "/mActionDeleteAttribute.svg" ), tr( "Remove Column" ), editToolBar );
68 connect( mActionRemoveColumn, &QAction::triggered, this, &QgsRasterAttributeTableWidget::removeColumn );
69 editToolBar->addAction( mActionRemoveColumn );
70
71 mActionSaveChanges = new QAction( QgsApplication::getThemeIcon( "/mActionSaveAllEdits.svg" ), tr( "&Save Changes" ), editToolBar );
72 connect( mActionSaveChanges, &QAction::triggered, this, &QgsRasterAttributeTableWidget::saveChanges );
73 editToolBar->addAction( mActionSaveChanges );
74
75 layout()->setMenuBar( editToolBar );
76
77 connect( mClassifyButton, &QPushButton::clicked, this, &QgsRasterAttributeTableWidget::classify );
78
79 mProxyModel = new QSortFilterProxyModel( this );
80
81 mRATView->setModel( mProxyModel );
82
83 connect( mRATView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsRasterAttributeTableWidget::updateButtons );
84
85 if ( rasterLayer )
86 {
87 init( bandNumber );
88 }
89}
90
91void QgsRasterAttributeTableWidget::setRasterLayer( QgsRasterLayer *rasterLayer, const int bandNumber )
92{
93 mRasterLayer = rasterLayer;
94 init( bandNumber );
95}
96
97bool QgsRasterAttributeTableWidget::isDirty() const
98{
99 return mAttributeTableBuffer && mAttributeTableBuffer->isDirty();
100}
101
102void QgsRasterAttributeTableWidget::init( int bandNumber )
103{
104 disconnect( mRasterBandsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterAttributeTableWidget::bandChanged );
105 mAttributeTableBuffer = nullptr;
106 mCurrentBand = 0;
107 mRasterBandsComboBox->clear();
108
109 QList<int> availableRats;
110
111 if ( mRasterLayer )
112 {
113 for ( int checkBandNumber = 1; checkBandNumber <= mRasterLayer->bandCount(); ++checkBandNumber )
114 {
115 // Search for RATs
116 if ( mRasterLayer->attributeTable( checkBandNumber ) )
117 {
118 mRasterBandsComboBox->addItem( mRasterLayer->bandName( checkBandNumber ), checkBandNumber );
119 availableRats.push_back( checkBandNumber );
120 }
121 }
122
123 if ( !availableRats.isEmpty() )
124 {
125 if ( availableRats.contains( bandNumber ) )
126 {
127 mCurrentBand = bandNumber;
128 }
129 else if ( !availableRats.isEmpty() )
130 {
131 mCurrentBand = availableRats.first();
132 }
133
134 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
135 mRasterBandsComboBox->setCurrentIndex( availableRats.indexOf( mCurrentBand ) );
136 }
137 }
138
139 if ( mAttributeTableBuffer )
140 {
141 mModel = std::make_unique<QgsRasterAttributeTableModel>( mAttributeTableBuffer.get() );
142 mModel->setEditable( mEditable );
143
144 connect( mModel.get(), &QgsRasterAttributeTableModel::dataChanged, this, [this]( const QModelIndex &, const QModelIndex &, const QVector<int> & ) {
145 updateButtons();
146 } );
147
148 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsInserted, this, [this]( const QModelIndex &, int, int ) {
149 setDelegates();
150 } );
151
152 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsRemoved, this, [this]( const QModelIndex &, int, int ) {
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( mAttributeTableBuffer && mRasterLayer );
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
183void QgsRasterAttributeTableWidget::setDockMode( bool dockMode )
184{
186 static_cast<QToolBar *>( layout()->menuBar() )->setIconSize( QgsGuiUtils::iconSize( dockMode ) );
187}
188
189void QgsRasterAttributeTableWidget::setMessageBar( QgsMessageBar *bar )
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
244void QgsRasterAttributeTableWidget::saveChanges()
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( Qgis::RasterProviderCapability::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 updateButtons();
306}
307
308void QgsRasterAttributeTableWidget::classify()
309{
310 if ( !mAttributeTableBuffer )
311 {
312 notify( tr( "Classification Error" ), tr( "The raster attribute table is not set." ), Qgis::MessageLevel::Critical );
313 return;
314 }
315
316 if ( !mRasterLayer )
317 {
318 notify( tr( "Classification Error" ), tr( "The raster layer is not set." ), Qgis::MessageLevel::Critical );
319 return;
320 }
321
322 QString confirmMessage;
323 QString errorMessage;
324
325 if ( !mAttributeTableBuffer->isValid( &errorMessage ) )
326 {
327 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 );
328 }
329
330 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 )
331 {
332 if ( QgsRasterRenderer *renderer = mAttributeTableBuffer->createRenderer( mRasterLayer->dataProvider(), mCurrentBand, mClassifyComboBox->currentData().toInt() ) )
333 {
334 mRasterLayer->setRenderer( renderer );
335 mRasterLayer->triggerRepaint();
336 emit rendererChanged();
337 }
338 else
339 {
340 notify( tr( "Classification Error" ), tr( "The classification returned no classes." ), Qgis::MessageLevel::Critical );
341 }
342 }
343}
344
345void QgsRasterAttributeTableWidget::addColumn()
346{
347 if ( mAttributeTableBuffer )
348 {
349 QgsRasterAttributeTableAddColumnDialog dlg { mAttributeTableBuffer.get() };
350 if ( dlg.exec() == QDialog::Accepted )
351 {
352 QString errorMessage;
353 if ( dlg.isColor() )
354 {
355 if ( !mModel->insertColor( dlg.position(), &errorMessage ) )
356 {
357 notify( tr( "Error adding color column" ), errorMessage, Qgis::MessageLevel::Critical );
358 }
359 }
360 else if ( dlg.isRamp() )
361 {
362 if ( !mModel->insertRamp( dlg.position(), &errorMessage ) )
363 {
364 notify( tr( "Error adding color ramp column" ), errorMessage, Qgis::MessageLevel::Critical );
365 }
366 }
367 else
368 {
369 if ( !mModel->insertField( dlg.position(), dlg.name(), dlg.usage(), dlg.type(), &errorMessage ) )
370 {
371 notify( tr( "Error adding new column" ), errorMessage, Qgis::MessageLevel::Critical );
372 }
373 }
374 }
375 setDelegates();
376 }
377}
378
379void QgsRasterAttributeTableWidget::removeColumn()
380{
381 const QModelIndex currentIndex { mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ) };
382 if ( mAttributeTableBuffer && currentIndex.isValid() && currentIndex.column() < mAttributeTableBuffer->fields().count() )
383 {
384 if ( QMessageBox::question( nullptr, tr( "Remove Column" ), tr( "Do you want to remove the selected column? This action cannot be undone." ) ) == QMessageBox::Yes )
385 {
386 QString errorMessage;
387 if ( !mModel->removeField( currentIndex.column(), &errorMessage ) )
388 {
389 notify( tr( "Error removing column" ), errorMessage, Qgis::MessageLevel::Critical );
390 }
391 }
392 }
393}
394
395void QgsRasterAttributeTableWidget::addRow()
396{
397 if ( mAttributeTableBuffer )
398 {
399 // Default to append
400 int position { mModel->rowCount( QModelIndex() ) };
401 const QModelIndex currentIndex { mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ) };
402
403 // If there is a selected row, ask if before of after.
404 if ( currentIndex.isValid() )
405 {
406 // Ask the user where to insert the new row (before or after the currently
407 // selected row).
408 QgsRasterAttributeTableAddRowDialog dlg;
409 if ( dlg.exec() != QDialog::DialogCode::Accepted )
410 {
411 return;
412 }
413 else
414 {
415 position = currentIndex.row() + ( dlg.insertAfter() ? 1 : 0 );
416 }
417 }
418
419 bool result { true };
420 QString errorMessage;
421
422 QVariantList rowData;
423
424 QList<QgsRasterAttributeTable::Field> fields { mAttributeTableBuffer->fields() };
425 for ( const QgsRasterAttributeTable::Field &field : std::as_const( fields ) )
426 {
427 rowData.push_back( QgsVariantUtils::createNullVariant( field.type ) );
428 }
429
430 result = mModel->insertRow( position, rowData, &errorMessage );
431
432 if ( !result )
433 {
434 notify( tr( "Error adding row" ), errorMessage, Qgis::MessageLevel::Critical );
435 }
436 else
437 {
438 mRATView->scrollTo( mRATView->model()->index( position, 0 ) );
439 }
440 }
441}
442
443void QgsRasterAttributeTableWidget::removeRow()
444{
445 if ( mAttributeTableBuffer && mRATView->selectionModel()->currentIndex().isValid() )
446 {
447 if ( QMessageBox::question( nullptr, tr( "Remove Row" ), tr( "Do you want to remove the selected row? This action cannot be undone." ) ) == QMessageBox::Yes )
448 {
449 QString errorMessage;
450 if ( !mModel->removeRow( mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ).row(), &errorMessage ) )
451 {
452 notify( tr( "Error removing row" ), errorMessage, Qgis::MessageLevel::Critical );
453 }
454 }
455 }
456}
457
458void QgsRasterAttributeTableWidget::bandChanged( const int index )
459{
460 const QVariant itemData = mRasterBandsComboBox->itemData( index );
461
462 if ( itemData.isValid() )
463 {
464 if ( mEditable )
465 {
466 setEditable( false );
467 }
468 init( itemData.toInt() );
469 }
470}
471
472void QgsRasterAttributeTableWidget::notify( const QString &title, const QString &message, Qgis::MessageLevel level )
473{
474 if ( mMessageBar )
475 {
476 mMessageBar->pushMessage( message, level );
477 }
478 else
479 {
480 switch ( level )
481 {
485 {
486 QMessageBox::information( nullptr, title, message );
487 break;
488 }
490 {
491 QMessageBox::warning( nullptr, title, message );
492 break;
493 }
495 {
496 QMessageBox::critical( nullptr, title, message );
497 break;
498 }
499 }
500 }
501}
502
503void QgsRasterAttributeTableWidget::setDelegates()
504{
505 mClassifyComboBox->clear();
506 if ( mAttributeTableBuffer )
507 {
508 const QList<QgsRasterAttributeTable::Field> tableFields { mAttributeTableBuffer->fields() };
509 int fieldIdx { 0 };
510 const QHash<Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation> usageInfo { QgsRasterAttributeTable::usageInformation() };
511
512 for ( const QgsRasterAttributeTable::Field &f : std::as_const( tableFields ) )
513 {
514 // Clear all delegates.
515 mRATView->setItemDelegateForColumn( fieldIdx, nullptr );
516
517 if ( usageInfo[f.usage].maybeClass )
518 {
519 mClassifyComboBox->addItem( QgsFields::iconForFieldType( f.type ), f.name, QVariant( fieldIdx ) );
520 }
521
522 // Set delegates for doubles
523 if ( ( !f.isColor() && !f.isRamp() ) && f.type == QMetaType::Type::Double )
524 {
525 mRATView->setItemDelegateForColumn( fieldIdx, new LocalizedDoubleDelegate( mRATView ) );
526 }
527 fieldIdx++;
528 }
529
530 // Set delegates for color and ramp
531 if ( mAttributeTableBuffer->hasColor() )
532 {
533 if ( mAttributeTableBuffer->usages().contains( Qgis::RasterAttributeTableFieldUsage::Alpha ) )
534 {
535 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count(), new ColorAlphaDelegate( mRATView ) );
536 }
537 else
538 {
539 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count(), new ColorDelegate( mRATView ) );
540 }
541 }
542 else if ( mAttributeTableBuffer->hasRamp() )
543 {
544 if ( mAttributeTableBuffer->usages().contains( Qgis::RasterAttributeTableFieldUsage::AlphaMin ) )
545 {
546 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count(), new ColorRampAlphaDelegate( mRATView ) );
547 }
548 else
549 {
550 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count(), new ColorRampDelegate( mRATView ) );
551 }
552 }
553 }
554}
555
556
558
559QWidget *ColorDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
560{
561 return new QgsColorButton( parent, tr( "Select Color" ) );
562}
563
564void ColorDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
565{
566 const QColor color { index.data( Qt::ItemDataRole::EditRole ).value<QColor>() };
567 static_cast<QgsColorButton *>( editor )->setColor( color );
568}
569
570void ColorDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
571{
572 const QColor color { static_cast<QgsColorButton *>( editor )->color() };
573 model->setData( index, color );
574}
575
576QWidget *ColorAlphaDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
577{
578 QWidget *editor { ColorDelegate::createEditor( parent, option, index ) };
579 static_cast<QgsColorButton *>( editor )->setAllowOpacity( true );
580 return editor;
581}
582
583QWidget *ColorRampDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
584{
586 return editor;
587}
588
589void ColorRampDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
590{
591 const QgsGradientColorRamp ramp { qvariant_cast<QgsGradientColorRamp>( index.data( Qt::ItemDataRole::EditRole ) ) };
592 static_cast<QgsGradientColorRampDialog *>( editor )->setRamp( ramp );
593}
594
595void ColorRampDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
596{
597 model->setData( index, QVariant::fromValue( static_cast<QgsGradientColorRampDialog *>( editor )->ramp() ) );
598}
599
600void ColorRampDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
601{
602 const QgsGradientColorRamp ramp { qvariant_cast<QgsGradientColorRamp>( index.data( Qt::ItemDataRole::EditRole ) ) };
603 QLinearGradient gradient( QPointF( 0, 0 ), QPointF( 1, 0 ) );
604 gradient.setCoordinateMode( QGradient::CoordinateMode::ObjectBoundingMode );
605 gradient.setColorAt( 0, ramp.color1() );
606 gradient.setColorAt( 1, ramp.color2() );
607 const QRect r = option.rect.adjusted( 1, 1, -1, -1 );
608 const QgsScopedQPainterState painterState( painter );
609 painter->fillRect( r, QBrush { gradient } );
610}
611
612QWidget *ColorRampAlphaDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
613{
614 QWidget *editor { ColorRampDelegate::createEditor( parent, option, index ) };
615 // No opacity setting for ramps?
616 return editor;
617}
618
619
620QString LocalizedDoubleDelegate::displayText( const QVariant &value, const QLocale &locale ) const
621{
622 Q_UNUSED( locale );
623 const QString s( value.toString() );
624 const int dotPosition( s.indexOf( '.' ) );
625 int precision;
626 if ( dotPosition < 0 && s.indexOf( 'e' ) < 0 )
627 {
628 precision = 0;
629 return QLocale().toString( value.toDouble(), 'f', precision );
630 }
631 else
632 {
633 if ( dotPosition < 0 )
634 precision = 0;
635 else
636 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}
648
@ NativeRasterAttributeTable
Indicates that the provider supports native raster attribute table.
Definition qgis.h:4894
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:156
@ NoLevel
No level.
Definition qgis.h:161
@ Warning
Warning message.
Definition qgis.h:158
@ Critical
Critical/error message.
Definition qgis.h:159
@ Info
Information message.
Definition qgis.h:157
@ Success
Used for reporting a successful operation.
Definition qgis.h:160
@ Alpha
Field usage Alpha.
Definition qgis.h:1597
@ AlphaMin
Field usage AlphaMin.
Definition qgis.h:1601
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.
static QIcon iconForFieldType(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType, const QString &typeString=QString())
Returns an icon corresponding to a field type.
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 ...
QColor color1() const
Returns the gradient start color.
QColor color2() const
Returns the gradient end color.
A bar for displaying non-blocking messages to the user.
Base class for any widget that can be shown as an inline panel.
bool dockMode() const
Returns the dock mode state.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
QMetaType::Type type() const
Returns the new column type.
bool isRamp() const
Returns true if the add color ramp column option was checked.
bool isColor() const
Returns true if the add color column option was checked.
int position() const
Returns the position where the new column (before) will be inserted.
Qgis::RasterAttributeTableFieldUsage usage() const
Returns the new column name.
bool insertAfter() const
Returns true if the desired insertion position for the new row is after the currently selected row,...
static QHash< Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation > usageInformation()
Returns information about supported Raster Attribute Table usages.
bool writeToFile(const QString &path, QString *errorMessage=nullptr)
Writes the Raster Attribute Table to a DBF file specified by path, optionally reporting any error in ...
QString filePath() const
Returns the (possibly empty) path of the file-based RAT, the path is set when a RAT is read or writte...
Represents a raster layer.
Scoped object for saving and restoring a QPainter object's state.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
#define QgsDebugError(str)
Definition qgslogger.h:57