QGIS API Documentation 4.3.0-Master (0de80482b60)
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 "qgsgui.h"
24#include "qgsmessagebar.h"
28#include "qgsrasterlayer.h"
29#include "qgsrasterrenderer.h"
30
31#include <QAction>
32#include <QFileDialog>
33#include <QMessageBox>
34#include <QSortFilterProxyModel>
35#include <QString>
36#include <QToolBar>
37
38#include "moc_qgsrasterattributetablewidget.cpp"
39
40using namespace Qt::StringLiterals;
41
42QgsRasterAttributeTableWidget::QgsRasterAttributeTableWidget( QWidget *parent, QgsRasterLayer *rasterLayer, const int bandNumber )
43 : QgsPanelWidget( parent )
44 , mRasterLayer( rasterLayer )
45{
46 setupUi( this );
47
48 // Create the toolbar
49 QToolBar *editToolBar = new QToolBar( this );
51
52 mActionToggleEditing = new QAction( QgsApplication::getThemeIcon( "/mActionEditTable.svg" ), tr( "&Edit Attribute Table" ), editToolBar );
53 mActionToggleEditing->setCheckable( true );
54 connect( mActionToggleEditing, &QAction::triggered, this, [this]( bool editable ) { setEditable( editable ); } );
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> & ) { updateButtons(); } );
148
149 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsInserted, this, [this]( const QModelIndex &, int, int ) { setDelegates(); } );
150
151 connect( mModel.get(), &QgsRasterAttributeTableModel::columnsRemoved, this, [this]( const QModelIndex &, int, int ) { setDelegates(); } );
152
153 static_cast<QSortFilterProxyModel *>( mRATView->model() )->setSourceModel( mModel.get() );
154 setDelegates();
155 }
156 else
157 {
158 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 );
159 }
160
161 connect( mRasterBandsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRasterAttributeTableWidget::bandChanged );
162
163 updateButtons();
164}
165
166void QgsRasterAttributeTableWidget::updateButtons()
167{
168 const bool enableEditingButtons( static_cast<bool>( mAttributeTableBuffer ) && mEditable && mRATView->selectionModel()->currentIndex().isValid() );
169 mActionToggleEditing->setChecked( mEditable );
170 mActionToggleEditing->setEnabled( mAttributeTableBuffer && mRasterLayer );
171 mActionAddColumn->setEnabled( mEditable );
172 mActionRemoveColumn->setEnabled( enableEditingButtons );
173 mActionAddRow->setEnabled( enableEditingButtons );
174 mActionRemoveRow->setEnabled( enableEditingButtons );
175 mActionSaveChanges->setEnabled( mAttributeTableBuffer && mAttributeTableBuffer->isDirty() );
176 mClassifyButton->setEnabled( mAttributeTableBuffer && mRasterLayer );
177 mClassifyComboBox->setEnabled( mAttributeTableBuffer && mRasterLayer );
178}
179
180void QgsRasterAttributeTableWidget::setDockMode( bool dockMode )
181{
183 static_cast<QToolBar *>( layout()->menuBar() )->setIconSize( QgsGui::iconSize( dockMode ? Qgis::UserInterfaceIconType::DockedToolbar : Qgis::UserInterfaceIconType::MainWindowToolbar ) );
184}
185
186void QgsRasterAttributeTableWidget::setMessageBar( QgsMessageBar *bar )
187{
188 mMessageBar = bar;
189}
190
191bool QgsRasterAttributeTableWidget::setEditable( bool editable, bool allowCancel )
192{
193 const bool isDirty { mAttributeTableBuffer && mAttributeTableBuffer->isDirty() && mCurrentBand > 0 && mRasterLayer->attributeTable( mCurrentBand ) };
194 bool retVal { true };
195 // Switch to read-only
196 if ( !editable && isDirty )
197 {
198 QMessageBox::StandardButtons buttons { QMessageBox::Button::Yes | QMessageBox::Button::No };
199
200 if ( allowCancel )
201 {
202 buttons |= QMessageBox::Button::Cancel;
203 }
204
205 switch ( QMessageBox::question( nullptr, tr( "Save Attribute Table" ), tr( "Attribute table contains unsaved changes, do you want to save the changes?" ), buttons ) )
206 {
207 case QMessageBox::Button::Cancel:
208 {
209 retVal = false;
210 break;
211 }
212 case QMessageBox::Button::Yes:
213 {
214 saveChanges();
215 retVal = true;
216 break;
217 }
218 case QMessageBox::Button::No:
219 default:
220 {
221 // Reset to its original state
222 mAttributeTableBuffer = std::make_unique<QgsRasterAttributeTable>( *mRasterLayer->attributeTable( mCurrentBand ) );
223 init( mCurrentBand );
224 retVal = true;
225 break;
226 }
227 }
228 }
229
230 if ( retVal )
231 {
232 mEditable = editable;
233 mModel->setEditable( editable );
234 }
235
236 updateButtons();
237
238 return retVal;
239}
240
241void QgsRasterAttributeTableWidget::saveChanges()
242{
243 if ( mRasterLayer && mAttributeTableBuffer && mAttributeTableBuffer->isDirty() && mCurrentBand > 0 )
244 {
245 QgsRasterAttributeTable *attributeTable { mRasterLayer->dataProvider()->attributeTable( mCurrentBand ) };
246 if ( !attributeTable )
247 {
248 QgsDebugError( u"Error saving RAT: RAT for band %1 is unexpectedly gone!"_s.arg( mCurrentBand ) );
249 }
250 else
251 {
252 *attributeTable = *mAttributeTableBuffer;
253 QString errorMessage;
254 QString newPath { attributeTable->filePath() };
255 const bool nativeRatSupported = mRasterLayer->dataProvider()->providerCapabilities().testFlag( Qgis::RasterProviderCapability::NativeRasterAttributeTable );
256 bool saveToNative { false };
257
258 if ( newPath.isEmpty() && !nativeRatSupported )
259 {
260 newPath = QFileDialog::getOpenFileName(
261 nullptr,
262 tr( "Save Raster Attribute Table (band %1) To File" ).arg( mCurrentBand ),
263 QFile::exists( mRasterLayer->dataProvider()->dataSourceUri() ) ? mRasterLayer->dataProvider()->dataSourceUri() + ".vat.dbf" : QString(),
264 u"VAT DBF Files (*.vat.dbf)"_s
265 );
266 if ( newPath.isEmpty() )
267 {
268 // Aborted by user
269 return;
270 }
271 }
272 else if ( newPath.isEmpty() )
273 {
274 saveToNative = true;
275 }
276
277 bool writeSuccess { false };
278
279 // Save to file
280 if ( !saveToNative && !newPath.isEmpty() )
281 {
282 writeSuccess = attributeTable->writeToFile( attributeTable->filePath(), &errorMessage );
283 }
284 else if ( saveToNative )
285 {
286 writeSuccess = mRasterLayer->dataProvider()->writeNativeAttributeTable( &errorMessage ); //#spellok
287 }
288
289 if ( writeSuccess )
290 {
291 mAttributeTableBuffer->setDirty( false );
292 notify( tr( "Attribute Table Write Success" ), tr( "The raster attribute table has been successfully saved." ), Qgis::MessageLevel::Success );
293 }
294 else
295 {
296 notify( tr( "Attribute Table Write Error" ), errorMessage, Qgis::MessageLevel::Critical );
297 }
298
299 // Save to native saves RATs for all bands, no need to loop further.
300 if ( saveToNative )
301 {
302 return;
303 }
304 }
305 }
306
307 updateButtons();
308}
309
310void QgsRasterAttributeTableWidget::classify()
311{
312 if ( !mAttributeTableBuffer )
313 {
314 notify( tr( "Classification Error" ), tr( "The raster attribute table is not set." ), Qgis::MessageLevel::Critical );
315 return;
316 }
317
318 if ( !mRasterLayer )
319 {
320 notify( tr( "Classification Error" ), tr( "The raster layer is not set." ), Qgis::MessageLevel::Critical );
321 return;
322 }
323
324 QString confirmMessage;
325 QString errorMessage;
326
327 if ( !mAttributeTableBuffer->isValid( &errorMessage ) )
328 {
329 confirmMessage = tr( "The attribute table does not seem to be valid and it may produce an unusable symbology, validation errors:<br>%1<br>" ).arg( errorMessage );
330 }
331
332 if ( QMessageBox::question( nullptr, tr( "Apply Style From Attribute Table" ), confirmMessage.append( tr( "The existing symbology for the raster will be replaced by a new symbology from the attribute table and any unsaved changes to the current symbology will be lost, do you want to proceed?" ) ) )
333 == QMessageBox::Yes )
334 {
335 if ( std::unique_ptr<QgsRasterRenderer> renderer = mAttributeTableBuffer->createRenderer( mRasterLayer->dataProvider(), mCurrentBand, mClassifyComboBox->currentData().toInt() ) )
336 {
337 mRasterLayer->setRenderer( renderer.release() );
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
@ MainWindowToolbar
Main window toolbar icons.
Definition qgis.h:7084
@ DockedToolbar
Toolbars for docked windows.
Definition qgis.h:7085
@ NativeRasterAttributeTable
Indicates that the provider supports native raster attribute table.
Definition qgis.h:5393
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:160
@ NoLevel
No level.
Definition qgis.h:165
@ Warning
Warning message.
Definition qgis.h:162
@ Critical
Critical/error message.
Definition qgis.h:163
@ Info
Information message.
Definition qgis.h:161
@ Success
Used for reporting a successful operation.
Definition qgis.h:164
@ Alpha
Field usage Alpha.
Definition qgis.h:1747
@ AlphaMin
Field usage AlphaMin.
Definition qgis.h:1751
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.
static QSize iconSize(Qgis::UserInterfaceIconType iconType=Qgis::UserInterfaceIconType::MainWindowToolbar)
Returns the desired size for user interface icons.
Definition qgsgui.cpp:509
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.
#define QgsDebugError(str)
Definition qgslogger.h:71