QGIS API Documentation 3.41.0-Master (3440c17df1d)
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#include "moc_qgsrasterattributetablewidget.cpp"
19#include "qgsrasterlayer.h"
20#include "qgsapplication.h"
21#include "qgsmessagebar.h"
24#include "qgscolorbutton.h"
26
27#include <QToolBar>
28#include <QAction>
29#include <QSortFilterProxyModel>
30#include <QMessageBox>
31#include <QFileDialog>
32
33QgsRasterAttributeTableWidget::QgsRasterAttributeTableWidget( QWidget *parent, QgsRasterLayer *rasterLayer, const int bandNumber )
34 : QgsPanelWidget( parent )
35 , mRasterLayer( rasterLayer )
36{
37 setupUi( this );
38
39 // Create the toolbar
40 QToolBar *editToolBar = new QToolBar( this );
41 editToolBar->setIconSize( QgsGuiUtils::iconSize( true ) );
42
43 mActionToggleEditing = new QAction( QgsApplication::getThemeIcon( "/mActionEditTable.svg" ), tr( "&Edit Attribute Table" ), editToolBar );
44 mActionToggleEditing->setCheckable( true );
45 connect( mActionToggleEditing, &QAction::triggered, this, [ = ]( bool editable )
46 {
47 setEditable( editable );
48 } );
49
50 editToolBar->addAction( mActionToggleEditing );
51
52 mActionAddColumn = new QAction( QgsApplication::getThemeIcon( "/mActionNewAttribute.svg" ), tr( "Add &Column…" ), editToolBar );
53 connect( mActionAddColumn, &QAction::triggered, this, &QgsRasterAttributeTableWidget::addColumn );
54 editToolBar->addAction( mActionAddColumn );
55
56 mActionAddRow = new QAction( QgsApplication::getThemeIcon( "/mActionNewTableRow.svg" ), tr( "&Add Row…" ), editToolBar );
57 connect( mActionAddRow, &QAction::triggered, this, &QgsRasterAttributeTableWidget::addRow );
58 editToolBar->addAction( mActionAddRow );
59
60 mActionRemoveRow = new QAction( QgsApplication::getThemeIcon( "/mActionRemoveSelectedFeature.svg" ), tr( "Remove Row" ), editToolBar );
61 connect( mActionRemoveRow, &QAction::triggered, this, &QgsRasterAttributeTableWidget::removeRow );
62 editToolBar->addAction( mActionRemoveRow );
63
64 mActionRemoveColumn = new QAction( QgsApplication::getThemeIcon( "/mActionDeleteAttribute.svg" ), tr( "Remove Column" ), editToolBar );
65 connect( mActionRemoveColumn, &QAction::triggered, this, &QgsRasterAttributeTableWidget::removeColumn );
66 editToolBar->addAction( mActionRemoveColumn );
67
68 mActionSaveChanges = new QAction( QgsApplication::getThemeIcon( "/mActionSaveAllEdits.svg" ), tr( "&Save Changes" ), editToolBar );
69 connect( mActionSaveChanges, &QAction::triggered, this, &QgsRasterAttributeTableWidget::saveChanges );
70 editToolBar->addAction( mActionSaveChanges );
71
72 layout()->setMenuBar( editToolBar );
73
74 connect( mClassifyButton, &QPushButton::clicked, this, &QgsRasterAttributeTableWidget::classify );
75
76 mProxyModel = new QSortFilterProxyModel( this );
77
78 mRATView->setModel( mProxyModel );
79
80 connect( mRATView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsRasterAttributeTableWidget::updateButtons );
81
82 if ( rasterLayer )
83 {
84 init( bandNumber );
85 }
86}
87
88void QgsRasterAttributeTableWidget::setRasterLayer( QgsRasterLayer *rasterLayer, const int bandNumber )
89{
90 mRasterLayer = rasterLayer;
91 init( bandNumber );
92}
93
94bool QgsRasterAttributeTableWidget::isDirty() const
95{
96 return mAttributeTableBuffer && mAttributeTableBuffer->isDirty();
97}
98
99void QgsRasterAttributeTableWidget::init( int bandNumber )
100{
101
102 disconnect( mRasterBandsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterAttributeTableWidget::bandChanged );
103 mAttributeTableBuffer = nullptr;
104 mCurrentBand = 0;
105 mRasterBandsComboBox->clear();
106
107 QList<int> availableRats;
108
109 if ( mRasterLayer )
110 {
111 for ( int checkBandNumber = 1; checkBandNumber <= mRasterLayer->bandCount(); ++checkBandNumber )
112 {
113 // Search for RATs
114 if ( mRasterLayer->attributeTable( checkBandNumber ) )
115 {
116 mRasterBandsComboBox->addItem( mRasterLayer->bandName( checkBandNumber ), checkBandNumber );
117 availableRats.push_back( checkBandNumber );
118 }
119 }
120
121 if ( !availableRats.isEmpty() )
122 {
123 if ( availableRats.contains( bandNumber ) )
124 {
125 mCurrentBand = bandNumber;
126 }
127 else if ( ! availableRats.isEmpty() )
128 {
129 mCurrentBand = availableRats.first();
130 }
131
132 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
133 mRasterBandsComboBox->setCurrentIndex( availableRats.indexOf( mCurrentBand ) );
134 }
135 }
136
137 if ( mAttributeTableBuffer )
138 {
139 mModel.reset( new QgsRasterAttributeTableModel( mAttributeTableBuffer.get() ) );
140 mModel->setEditable( mEditable );
141
142 connect( mModel.get(), &QgsRasterAttributeTableModel::dataChanged, this, [ = ]( const QModelIndex &, const QModelIndex &, const QVector<int> & )
143 {
144 updateButtons();
145 } );
146
147 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsInserted, this, [ = ]( const QModelIndex &, int, int )
148 {
149 setDelegates();
150 } );
151
152 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsRemoved, this, [ = ]( const QModelIndex &, int, int )
153 {
154 setDelegates();
155 } );
156
157 static_cast<QSortFilterProxyModel *>( mRATView->model() )->setSourceModel( mModel.get() );
158 setDelegates();
159 }
160 else
161 {
162 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 );
163 }
164
165 connect( mRasterBandsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterAttributeTableWidget::bandChanged );
166
167 updateButtons();
168}
169
170void QgsRasterAttributeTableWidget::updateButtons()
171{
172 const bool enableEditingButtons( static_cast<bool>( mAttributeTableBuffer ) && mEditable && mRATView->selectionModel()->currentIndex().isValid() );
173 mActionToggleEditing->setChecked( mEditable );
174 mActionToggleEditing->setEnabled( mAttributeTableBuffer && mRasterLayer );
175 mActionAddColumn->setEnabled( mEditable );
176 mActionRemoveColumn->setEnabled( enableEditingButtons );
177 mActionAddRow->setEnabled( enableEditingButtons );
178 mActionRemoveRow->setEnabled( enableEditingButtons );
179 mActionSaveChanges->setEnabled( mAttributeTableBuffer && mAttributeTableBuffer->isDirty() );
180 mClassifyButton->setEnabled( mAttributeTableBuffer && mRasterLayer );
181 mClassifyComboBox->setEnabled( mAttributeTableBuffer && mRasterLayer );
182}
183
184void QgsRasterAttributeTableWidget::setDockMode( bool dockMode )
185{
186 QgsPanelWidget::setDockMode( dockMode );
187 static_cast<QToolBar *>( layout()->menuBar() )->setIconSize( QgsGuiUtils::iconSize( dockMode ) );
188}
189
190void QgsRasterAttributeTableWidget::setMessageBar( QgsMessageBar *bar )
191{
192 mMessageBar = bar;
193}
194
195bool QgsRasterAttributeTableWidget::setEditable( bool editable, bool allowCancel )
196{
197 const bool isDirty { mAttributeTableBuffer &&mAttributeTableBuffer->isDirty() &&mCurrentBand > 0 && mRasterLayer->attributeTable( mCurrentBand ) };
198 bool retVal { true };
199 // Switch to read-only
200 if ( ! editable && isDirty )
201 {
202 QMessageBox::StandardButtons buttons { QMessageBox::Button::Yes | QMessageBox::Button::No };
203
204 if ( allowCancel )
205 {
206 buttons |= QMessageBox::Button::Cancel;
207 }
208
209 switch ( QMessageBox::question( nullptr, tr( "Save Attribute Table" ), tr( "Attribute table contains unsaved changes, do you want to save the changes?" ), buttons ) )
210 {
211 case QMessageBox::Button::Cancel:
212 {
213 retVal = false;
214 break;
215 }
216 case QMessageBox::Button::Yes:
217 {
218 saveChanges();
219 retVal = true;
220 break;
221 }
222 case QMessageBox::Button::No:
223 default:
224 {
225 // Reset to its original state
226 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
227 init( mCurrentBand );
228 retVal = true;
229 break;
230 }
231 }
232 }
233
234 if ( retVal )
235 {
236 mEditable = editable;
237 mModel->setEditable( editable );
238 }
239
240 updateButtons();
241
242 return retVal;
243}
244
245void QgsRasterAttributeTableWidget::saveChanges()
246{
247 if ( mRasterLayer && mAttributeTableBuffer && mAttributeTableBuffer->isDirty() && mCurrentBand > 0 )
248 {
249 QgsRasterAttributeTable *attributeTable { mRasterLayer->dataProvider()->attributeTable( mCurrentBand ) };
250 if ( ! attributeTable )
251 {
252 QgsDebugError( QStringLiteral( "Error saving RAT: RAT for band %1 is unexpectedly gone!" ).arg( mCurrentBand ) );
253 }
254 else
255 {
256 *attributeTable = *mAttributeTableBuffer;
257 QString errorMessage;
258 QString newPath { attributeTable->filePath() };
259 const bool nativeRatSupported = mRasterLayer->dataProvider()->providerCapabilities().testFlag( Qgis::RasterProviderCapability::NativeRasterAttributeTable );
260 bool saveToNative { false };
261
262 if ( newPath.isEmpty() && ! nativeRatSupported )
263 {
264 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)" ) );
265 if ( newPath.isEmpty() )
266 {
267 // Aborted by user
268 return;
269 }
270 }
271 else if ( newPath.isEmpty() )
272 {
273 saveToNative = true;
274 }
275
276 bool writeSuccess { false };
277
278 // Save to file
279 if ( ! saveToNative && ! newPath.isEmpty() )
280 {
281 writeSuccess = attributeTable->writeToFile( attributeTable->filePath(), &errorMessage );
282 }
283 else if ( saveToNative )
284 {
285 writeSuccess = mRasterLayer->dataProvider()->writeNativeAttributeTable( &errorMessage ); //#spellok
286 }
287
288 if ( writeSuccess )
289 {
290 mAttributeTableBuffer->setDirty( false );
291 notify( tr( "Attribute Table Write Success" ), tr( "The raster attribute table has been successfully saved." ), Qgis::MessageLevel::Success );
292 }
293 else
294 {
295 notify( tr( "Attribute Table Write Error" ), errorMessage, Qgis::MessageLevel::Critical );
296 }
297
298 // Save to native saves RATs for all bands, no need to loop further.
299 if ( saveToNative )
300 {
301 return;
302 }
303
304 }
305 }
306
307 updateButtons();
308}
309
310void QgsRasterAttributeTableWidget::classify()
311{
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
336 if ( QgsRasterRenderer *renderer = mAttributeTableBuffer->createRenderer( mRasterLayer->dataProvider(), mCurrentBand, mClassifyComboBox->currentData().toInt() ) )
337 {
338 mRasterLayer->setRenderer( renderer );
339 mRasterLayer->triggerRepaint( );
340 emit rendererChanged();
341 }
342 else
343 {
344 notify( tr( "Classification Error" ), tr( "The classification returned no classes." ), Qgis::MessageLevel::Critical );
345 }
346 }
347}
348
349void QgsRasterAttributeTableWidget::addColumn()
350{
351 if ( mAttributeTableBuffer )
352 {
353 QgsRasterAttributeTableAddColumnDialog dlg { mAttributeTableBuffer.get() };
354 if ( dlg.exec() == QDialog::Accepted )
355 {
356 QString errorMessage;
357 if ( dlg.isColor() )
358 {
359 if ( ! mModel->insertColor( dlg.position(), &errorMessage ) )
360 {
361 notify( tr( "Error adding color column" ), errorMessage, Qgis::MessageLevel::Critical );
362 }
363 }
364 else if ( dlg.isRamp() )
365 {
366 if ( ! mModel->insertRamp( dlg.position(), &errorMessage ) )
367 {
368 notify( tr( "Error adding color ramp column" ), errorMessage, Qgis::MessageLevel::Critical );
369 }
370 }
371 else
372 {
373 if ( ! mModel->insertField( dlg.position(), dlg.name(), dlg.usage(), dlg.type(), &errorMessage ) )
374 {
375 notify( tr( "Error adding new column" ), errorMessage, Qgis::MessageLevel::Critical );
376 }
377 }
378 }
379 setDelegates();
380 }
381}
382
383void QgsRasterAttributeTableWidget::removeColumn()
384{
385 const QModelIndex currentIndex { mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ) };
386 if ( mAttributeTableBuffer && currentIndex.isValid() && currentIndex.column() < mAttributeTableBuffer->fields().count() )
387 {
388 if ( QMessageBox::question( nullptr, tr( "Remove Column" ), tr( "Do you want to remove the selected column? This action cannot be undone." ) ) == QMessageBox::Yes )
389 {
390 QString errorMessage;
391 if ( ! mModel->removeField( currentIndex.column(), &errorMessage ) )
392 {
393 notify( tr( "Error removing column" ), errorMessage, Qgis::MessageLevel::Critical );
394 }
395 }
396 }
397}
398
399void QgsRasterAttributeTableWidget::addRow()
400{
401 if ( mAttributeTableBuffer )
402 {
403 // Default to append
404 int position { mModel->rowCount( QModelIndex() ) };
405 const QModelIndex currentIndex { mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ) };
406
407 // If there is a selected row, ask if before of after.
408 if ( currentIndex.isValid() )
409 {
410 // Ask the user where to insert the new row (before or after the currently
411 // selected row).
413 if ( dlg.exec() != QDialog::DialogCode::Accepted )
414 {
415 return;
416 }
417 else
418 {
419 position = currentIndex.row() + ( dlg.insertAfter() ? 1 : 0 );
420 }
421 }
422
423 bool result { true };
424 QString errorMessage;
425
426 QVariantList rowData;
427
428 QList<QgsRasterAttributeTable::Field> fields { mAttributeTableBuffer->fields() };
429 for ( const QgsRasterAttributeTable::Field &field : std::as_const( fields ) )
430 {
431 rowData.push_back( QgsVariantUtils::createNullVariant( field.type ) );
432 }
433
434 result = mModel->insertRow( position, rowData, &errorMessage );
435
436 if ( ! result )
437 {
438 notify( tr( "Error adding row" ), errorMessage, Qgis::MessageLevel::Critical );
439 }
440 else
441 {
442 mRATView->scrollTo( mRATView->model()->index( position, 0 ) );
443 }
444 }
445}
446
447void QgsRasterAttributeTableWidget::removeRow()
448{
449 if ( mAttributeTableBuffer && mRATView->selectionModel()->currentIndex().isValid() )
450 {
451 if ( QMessageBox::question( nullptr, tr( "Remove Row" ), tr( "Do you want to remove the selected row? This action cannot be undone." ) ) == QMessageBox::Yes )
452 {
453 QString errorMessage;
454 if ( ! mModel->removeRow( mProxyModel->mapToSource( mRATView->selectionModel()->currentIndex() ).row(), &errorMessage ) )
455 {
456 notify( tr( "Error removing row" ), errorMessage, Qgis::MessageLevel::Critical );
457 }
458 }
459 }
460}
461
462void QgsRasterAttributeTableWidget::bandChanged( const int index )
463{
464 const QVariant itemData = mRasterBandsComboBox->itemData( index );
465
466 if ( itemData.isValid() )
467 {
468 if ( mEditable )
469 {
470 setEditable( false );
471 }
472 init( itemData.toInt( ) );
473 }
474}
475
476void QgsRasterAttributeTableWidget::notify( const QString &title, const QString &message, Qgis::MessageLevel level )
477{
478 if ( mMessageBar )
479 {
480 mMessageBar->pushMessage( message, level );
481 }
482 else
483 {
484 switch ( level )
485 {
489 {
490 QMessageBox::information( nullptr, title, message );
491 break;
492 }
494 {
495 QMessageBox::warning( nullptr, title, message );
496 break;
497 }
499 {
500 QMessageBox::critical( nullptr, title, message );
501 break;
502 }
503 }
504 }
505}
506
507void QgsRasterAttributeTableWidget::setDelegates()
508{
509 mClassifyComboBox->clear();
510 if ( mAttributeTableBuffer )
511 {
512 const QList<QgsRasterAttributeTable::Field> tableFields { mAttributeTableBuffer->fields() };
513 int fieldIdx { 0 };
514 const QHash<Qgis::RasterAttributeTableFieldUsage, QgsRasterAttributeTable::UsageInformation> usageInfo { QgsRasterAttributeTable::usageInformation() };
515
516 for ( const QgsRasterAttributeTable::Field &f : std::as_const( tableFields ) )
517 {
518 // Clear all delegates.
519 mRATView->setItemDelegateForColumn( fieldIdx, nullptr );
520
521 if ( usageInfo[f.usage].maybeClass )
522 {
523 mClassifyComboBox->addItem( QgsFields::iconForFieldType( f.type ), f.name, QVariant( fieldIdx ) );
524 }
525
526 // Set delegates for doubles
527 if ( ( ! f.isColor() && ! f.isRamp() ) && f.type == QMetaType::Type::Double )
528 {
529 mRATView->setItemDelegateForColumn( fieldIdx, new LocalizedDoubleDelegate( mRATView ) );
530 }
531 fieldIdx++;
532 }
533
534 // Set delegates for color and ramp
535 if ( mAttributeTableBuffer->hasColor() )
536 {
537 if ( mAttributeTableBuffer->usages().contains( Qgis::RasterAttributeTableFieldUsage::Alpha ) )
538 {
539 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorAlphaDelegate( mRATView ) );
540 }
541 else
542 {
543 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorDelegate( mRATView ) );
544 }
545 }
546 else if ( mAttributeTableBuffer->hasRamp() )
547 {
548 if ( mAttributeTableBuffer->usages().contains( Qgis::RasterAttributeTableFieldUsage::AlphaMin ) )
549 {
550 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorRampAlphaDelegate( mRATView ) );
551 }
552 else
553 {
554 mRATView->setItemDelegateForColumn( mAttributeTableBuffer->fields().count( ), new ColorRampDelegate( mRATView ) );
555 }
556 }
557 }
558}
559
560
562
563QWidget *ColorDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
564{
565 return new QgsColorButton( parent, tr( "Select Color" ) );
566}
567
568void ColorDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
569{
570 const QColor color { index.data( Qt::ItemDataRole::EditRole ).value<QColor>() };
571 static_cast<QgsColorButton *>( editor )->setColor( color );
572}
573
574void ColorDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
575{
576 const QColor color { static_cast<QgsColorButton *>( editor )->color( ) };
577 model->setData( index, color );
578}
579
580QWidget *ColorAlphaDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
581{
582 QWidget *editor { ColorDelegate::createEditor( parent, option, index ) };
583 static_cast<QgsColorButton *>( editor )->setAllowOpacity( true );
584 return editor;
585}
586
587QWidget *ColorRampDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
588{
590 return editor;
591}
592
593void ColorRampDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
594{
595 const QgsGradientColorRamp ramp { qvariant_cast<QgsGradientColorRamp>( index.data( Qt::ItemDataRole::EditRole ) ) };
596 static_cast<QgsGradientColorRampDialog *>( editor )->setRamp( ramp );
597}
598
599void ColorRampDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
600{
601 model->setData( index, QVariant::fromValue( static_cast<QgsGradientColorRampDialog *>( editor )->ramp() ) );
602}
603
604void ColorRampDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
605{
606 const QgsGradientColorRamp ramp { qvariant_cast<QgsGradientColorRamp>( index.data( Qt::ItemDataRole::EditRole ) ) };
607 QLinearGradient gradient( QPointF( 0, 0 ), QPointF( 1, 0 ) );
608 gradient.setCoordinateMode( QGradient::CoordinateMode::ObjectBoundingMode );
609 gradient.setColorAt( 0, ramp.color1() );
610 gradient.setColorAt( 1, ramp.color2() );
611 const QRect r = option.rect.adjusted( 1, 1, -1, -1 );
612 const QgsScopedQPainterState painterState( painter );
613 painter->fillRect( r, QBrush{ gradient } );
614}
615
616QWidget *ColorRampAlphaDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
617{
618 QWidget *editor { ColorRampDelegate::createEditor( parent, option, index ) };
619 // No opacity setting for ramps?
620 return editor;
621}
622
623
624QString LocalizedDoubleDelegate::displayText( const QVariant &value, const QLocale &locale ) const
625{
626 Q_UNUSED( locale );
627 const QString s( value.toString() );
628 const int dotPosition( s.indexOf( '.' ) );
629 int precision;
630 if ( dotPosition < 0 && s.indexOf( 'e' ) < 0 )
631 {
632 precision = 0;
633 return QLocale().toString( value.toDouble(), 'f', precision );
634 }
635 else
636 {
637 if ( dotPosition < 0 ) precision = 0;
638 else precision = s.length() - dotPosition - 1;
639
640 if ( -1 < value.toDouble() && value.toDouble() < 1 )
641 {
642 return QLocale().toString( value.toDouble(), 'g', precision );
643 }
644 else
645 {
646 return QLocale().toString( value.toDouble(), 'f', precision );
647 }
648 }
649 return QLocale().toString( value.toDouble( ), 'f' );
650}
651
653
@ NativeRasterAttributeTable
Indicates that the provider supports native raster attribute table.
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:154
@ NoLevel
No level.
Definition qgis.h:159
@ Warning
Warning message.
Definition qgis.h:156
@ Critical
Critical/error message.
Definition qgis.h:157
@ Info
Information message.
Definition qgis.h:155
@ Success
Used for reporting a successful operation.
Definition qgis.h:158
@ 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.
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 ...
A bar for displaying non-blocking messages to the user.
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.
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.
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.
Represents a raster layer.
Raster renderer pipe that applies colors to a raster.
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:38
int precision