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