QGIS API Documentation 3.99.0-Master (d270888f95f)
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 <QString>
34#include <QToolBar>
35
36#include "moc_qgsrasterattributetablewidget.cpp"
37
38using namespace Qt::StringLiterals;
39
40QgsRasterAttributeTableWidget::QgsRasterAttributeTableWidget( QWidget *parent, QgsRasterLayer *rasterLayer, const int bandNumber )
41 : QgsPanelWidget( parent )
42 , mRasterLayer( rasterLayer )
43{
44 setupUi( this );
45
46 // Create the toolbar
47 QToolBar *editToolBar = new QToolBar( this );
48 editToolBar->setIconSize( QgsGuiUtils::iconSize( true ) );
49
50 mActionToggleEditing = new QAction( QgsApplication::getThemeIcon( "/mActionEditTable.svg" ), tr( "&Edit Attribute Table" ), editToolBar );
51 mActionToggleEditing->setCheckable( true );
52 connect( mActionToggleEditing, &QAction::triggered, this, [this]( bool editable ) {
53 setEditable( editable );
54 } );
55
56 editToolBar->addAction( mActionToggleEditing );
57
58 mActionAddColumn = new QAction( QgsApplication::getThemeIcon( "/mActionNewAttribute.svg" ), tr( "Add &Column…" ), editToolBar );
59 connect( mActionAddColumn, &QAction::triggered, this, &QgsRasterAttributeTableWidget::addColumn );
60 editToolBar->addAction( mActionAddColumn );
61
62 mActionAddRow = new QAction( QgsApplication::getThemeIcon( "/mActionNewTableRow.svg" ), tr( "&Add Row…" ), editToolBar );
63 connect( mActionAddRow, &QAction::triggered, this, &QgsRasterAttributeTableWidget::addRow );
64 editToolBar->addAction( mActionAddRow );
65
66 mActionRemoveRow = new QAction( QgsApplication::getThemeIcon( "/mActionRemoveSelectedFeature.svg" ), tr( "Remove Row" ), editToolBar );
67 connect( mActionRemoveRow, &QAction::triggered, this, &QgsRasterAttributeTableWidget::removeRow );
68 editToolBar->addAction( mActionRemoveRow );
69
70 mActionRemoveColumn = new QAction( QgsApplication::getThemeIcon( "/mActionDeleteAttribute.svg" ), tr( "Remove Column" ), editToolBar );
71 connect( mActionRemoveColumn, &QAction::triggered, this, &QgsRasterAttributeTableWidget::removeColumn );
72 editToolBar->addAction( mActionRemoveColumn );
73
74 mActionSaveChanges = new QAction( QgsApplication::getThemeIcon( "/mActionSaveAllEdits.svg" ), tr( "&Save Changes" ), editToolBar );
75 connect( mActionSaveChanges, &QAction::triggered, this, &QgsRasterAttributeTableWidget::saveChanges );
76 editToolBar->addAction( mActionSaveChanges );
77
78 layout()->setMenuBar( editToolBar );
79
80 connect( mClassifyButton, &QPushButton::clicked, this, &QgsRasterAttributeTableWidget::classify );
81
82 mProxyModel = new QSortFilterProxyModel( this );
83
84 mRATView->setModel( mProxyModel );
85
86 connect( mRATView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsRasterAttributeTableWidget::updateButtons );
87
88 if ( rasterLayer )
89 {
90 init( bandNumber );
91 }
92}
93
94void QgsRasterAttributeTableWidget::setRasterLayer( QgsRasterLayer *rasterLayer, const int bandNumber )
95{
96 mRasterLayer = rasterLayer;
97 init( bandNumber );
98}
99
100bool QgsRasterAttributeTableWidget::isDirty() const
101{
102 return mAttributeTableBuffer && mAttributeTableBuffer->isDirty();
103}
104
105void QgsRasterAttributeTableWidget::init( int bandNumber )
106{
107 disconnect( mRasterBandsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterAttributeTableWidget::bandChanged );
108 mAttributeTableBuffer = nullptr;
109 mCurrentBand = 0;
110 mRasterBandsComboBox->clear();
111
112 QList<int> availableRats;
113
114 if ( mRasterLayer )
115 {
116 for ( int checkBandNumber = 1; checkBandNumber <= mRasterLayer->bandCount(); ++checkBandNumber )
117 {
118 // Search for RATs
119 if ( mRasterLayer->attributeTable( checkBandNumber ) )
120 {
121 mRasterBandsComboBox->addItem( mRasterLayer->bandName( checkBandNumber ), checkBandNumber );
122 availableRats.push_back( checkBandNumber );
123 }
124 }
125
126 if ( !availableRats.isEmpty() )
127 {
128 if ( availableRats.contains( bandNumber ) )
129 {
130 mCurrentBand = bandNumber;
131 }
132 else if ( !availableRats.isEmpty() )
133 {
134 mCurrentBand = availableRats.first();
135 }
136
137 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
138 mRasterBandsComboBox->setCurrentIndex( availableRats.indexOf( mCurrentBand ) );
139 }
140 }
141
142 if ( mAttributeTableBuffer )
143 {
144 mModel = std::make_unique<QgsRasterAttributeTableModel>( mAttributeTableBuffer.get() );
145 mModel->setEditable( mEditable );
146
147 connect( mModel.get(), &QgsRasterAttributeTableModel::dataChanged, this, [this]( const QModelIndex &, const QModelIndex &, const QVector<int> & ) {
148 updateButtons();
149 } );
150
151 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsInserted, this, [this]( const QModelIndex &, int, int ) {
152 setDelegates();
153 } );
154
155 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsRemoved, this, [this]( const QModelIndex &, int, int ) {
156 setDelegates();
157 } );
158
159 static_cast<QSortFilterProxyModel *>( mRATView->model() )->setSourceModel( mModel.get() );
160 setDelegates();
161 }
162 else
163 {
164 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 );
165 }
166
167 connect( mRasterBandsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterAttributeTableWidget::bandChanged );
168
169 updateButtons();
170}
171
172void QgsRasterAttributeTableWidget::updateButtons()
173{
174 const bool enableEditingButtons( static_cast<bool>( mAttributeTableBuffer ) && mEditable && mRATView->selectionModel()->currentIndex().isValid() );
175 mActionToggleEditing->setChecked( mEditable );
176 mActionToggleEditing->setEnabled( mAttributeTableBuffer && mRasterLayer );
177 mActionAddColumn->setEnabled( mEditable );
178 mActionRemoveColumn->setEnabled( enableEditingButtons );
179 mActionAddRow->setEnabled( enableEditingButtons );
180 mActionRemoveRow->setEnabled( enableEditingButtons );
181 mActionSaveChanges->setEnabled( mAttributeTableBuffer && mAttributeTableBuffer->isDirty() );
182 mClassifyButton->setEnabled( mAttributeTableBuffer && mRasterLayer );
183 mClassifyComboBox->setEnabled( mAttributeTableBuffer && mRasterLayer );
184}
185
186void QgsRasterAttributeTableWidget::setDockMode( bool dockMode )
187{
189 static_cast<QToolBar *>( layout()->menuBar() )->setIconSize( QgsGuiUtils::iconSize( dockMode ) );
190}
191
192void QgsRasterAttributeTableWidget::setMessageBar( QgsMessageBar *bar )
193{
194 mMessageBar = bar;
195}
196
197bool QgsRasterAttributeTableWidget::setEditable( bool editable, bool allowCancel )
198{
199 const bool isDirty { mAttributeTableBuffer && mAttributeTableBuffer->isDirty() && mCurrentBand > 0 && mRasterLayer->attributeTable( mCurrentBand ) };
200 bool retVal { true };
201 // Switch to read-only
202 if ( !editable && isDirty )
203 {
204 QMessageBox::StandardButtons buttons { QMessageBox::Button::Yes | QMessageBox::Button::No };
205
206 if ( allowCancel )
207 {
208 buttons |= QMessageBox::Button::Cancel;
209 }
210
211 switch ( QMessageBox::question( nullptr, tr( "Save Attribute Table" ), tr( "Attribute table contains unsaved changes, do you want to save the changes?" ), buttons ) )
212 {
213 case QMessageBox::Button::Cancel:
214 {
215 retVal = false;
216 break;
217 }
218 case QMessageBox::Button::Yes:
219 {
220 saveChanges();
221 retVal = true;
222 break;
223 }
224 case QMessageBox::Button::No:
225 default:
226 {
227 // Reset to its original state
228 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
229 init( mCurrentBand );
230 retVal = true;
231 break;
232 }
233 }
234 }
235
236 if ( retVal )
237 {
238 mEditable = editable;
239 mModel->setEditable( editable );
240 }
241
242 updateButtons();
243
244 return retVal;
245}
246
247void QgsRasterAttributeTableWidget::saveChanges()
248{
249 if ( mRasterLayer && mAttributeTableBuffer && mAttributeTableBuffer->isDirty() && mCurrentBand > 0 )
250 {
251 QgsRasterAttributeTable *attributeTable { mRasterLayer->dataProvider()->attributeTable( mCurrentBand ) };
252 if ( !attributeTable )
253 {
254 QgsDebugError( u"Error saving RAT: RAT for band %1 is unexpectedly gone!"_s.arg( mCurrentBand ) );
255 }
256 else
257 {
258 *attributeTable = *mAttributeTableBuffer;
259 QString errorMessage;
260 QString newPath { attributeTable->filePath() };
261 const bool nativeRatSupported = mRasterLayer->dataProvider()->providerCapabilities().testFlag( Qgis::RasterProviderCapability::NativeRasterAttributeTable );
262 bool saveToNative { false };
263
264 if ( newPath.isEmpty() && !nativeRatSupported )
265 {
266 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(), u"VAT DBF Files (*.vat.dbf)"_s );
267 if ( newPath.isEmpty() )
268 {
269 // Aborted by user
270 return;
271 }
272 }
273 else if ( newPath.isEmpty() )
274 {
275 saveToNative = true;
276 }
277
278 bool writeSuccess { false };
279
280 // Save to file
281 if ( !saveToNative && !newPath.isEmpty() )
282 {
283 writeSuccess = attributeTable->writeToFile( attributeTable->filePath(), &errorMessage );
284 }
285 else if ( saveToNative )
286 {
287 writeSuccess = mRasterLayer->dataProvider()->writeNativeAttributeTable( &errorMessage ); //#spellok
288 }
289
290 if ( writeSuccess )
291 {
292 mAttributeTableBuffer->setDirty( false );
293 notify( tr( "Attribute Table Write Success" ), tr( "The raster attribute table has been successfully saved." ), Qgis::MessageLevel::Success );
294 }
295 else
296 {
297 notify( tr( "Attribute Table Write Error" ), errorMessage, Qgis::MessageLevel::Critical );
298 }
299
300 // Save to native saves RATs for all bands, no need to loop further.
301 if ( saveToNative )
302 {
303 return;
304 }
305 }
306 }
307
308 updateButtons();
309}
310
311void QgsRasterAttributeTableWidget::classify()
312{
313 if ( !mAttributeTableBuffer )
314 {
315 notify( tr( "Classification Error" ), tr( "The raster attribute table is not set." ), Qgis::MessageLevel::Critical );
316 return;
317 }
318
319 if ( !mRasterLayer )
320 {
321 notify( tr( "Classification Error" ), tr( "The raster layer is not set." ), Qgis::MessageLevel::Critical );
322 return;
323 }
324
325 QString confirmMessage;
326 QString errorMessage;
327
328 if ( !mAttributeTableBuffer->isValid( &errorMessage ) )
329 {
330 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 );
331 }
332
333 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 )
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).
411 QgsRasterAttributeTableAddRowDialog dlg;
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( QgsVariantUtils::createNullVariant( 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 {
488 {
489 QMessageBox::information( nullptr, title, message );
490 break;
491 }
493 {
494 QMessageBox::warning( nullptr, title, message );
495 break;
496 }
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 == QMetaType::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 )
637 precision = 0;
638 else
639 precision = s.length() - dotPosition - 1;
640
641 if ( -1 < value.toDouble() && value.toDouble() < 1 )
642 {
643 return QLocale().toString( value.toDouble(), 'g', precision );
644 }
645 else
646 {
647 return QLocale().toString( value.toDouble(), 'f', precision );
648 }
649 }
650}
651
@ NativeRasterAttributeTable
Indicates that the provider supports native raster attribute table.
Definition qgis.h:4966
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:159
@ NoLevel
No level.
Definition qgis.h:164
@ Warning
Warning message.
Definition qgis.h:161
@ Critical
Critical/error message.
Definition qgis.h:162
@ Info
Information message.
Definition qgis.h:160
@ Success
Used for reporting a successful operation.
Definition qgis.h:163
@ Alpha
Field usage Alpha.
Definition qgis.h:1655
@ AlphaMin
Field usage AlphaMin.
Definition qgis.h:1659
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:59