16 #include <QMessageBox>
54 connect( mNewFieldGroupBox, &QGroupBox::toggled,
this, &QgsFieldCalculator::mNewFieldGroupBox_toggled );
55 connect( mUpdateExistingGroupBox, &QGroupBox::toggled,
this, &QgsFieldCalculator::mUpdateExistingGroupBox_toggled );
56 connect( mCreateVirtualFieldCheckbox, &QCheckBox::stateChanged,
this, &QgsFieldCalculator::mCreateVirtualFieldCheckbox_stateChanged );
57 connect( mOutputFieldNameLineEdit, &QLineEdit::textChanged,
this, &QgsFieldCalculator::mOutputFieldNameLineEdit_textChanged );
58 connect( mOutputFieldTypeComboBox,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::activated ),
this, &QgsFieldCalculator::mOutputFieldTypeComboBox_activated );
68 const QgsVectorDataProvider::Capabilities caps = dataProvider->
capabilities();
78 populateOutputFieldTypes();
81 connect( mOutputFieldWidthSpinBox, &QAbstractSpinBox::editingFinished,
this, &QgsFieldCalculator::setPrecisionMinMax );
82 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsFieldCalculator::showHelp );
87 builder->setGeomCalculator( myDa );
90 mOutputFieldWidthSpinBox->setValue( 10 );
91 mOutputFieldWidthSpinBox->setClearValue( 10 );
92 mOutputFieldPrecisionSpinBox->setValue( 3 );
93 mOutputFieldPrecisionSpinBox->setClearValue( 3 );
98 mOutputFieldNameLineEdit->setMaxLength( 10 );
101 if ( !mCanAddAttribute )
103 mCreateVirtualFieldCheckbox->setChecked(
true );
104 mCreateVirtualFieldCheckbox->setEnabled(
false );
105 mOnlyVirtualFieldsInfoLabel->setVisible(
true );
106 mInfoIcon->setVisible(
true );
110 mOnlyVirtualFieldsInfoLabel->setVisible(
false );
111 mInfoIcon->setVisible(
false );
114 if ( !mCanChangeAttributeValue )
116 mUpdateExistingGroupBox->setEnabled(
false );
117 mCreateVirtualFieldCheckbox->setChecked(
true );
118 mCreateVirtualFieldCheckbox->setEnabled(
false );
121 Q_ASSERT( mNewFieldGroupBox->isEnabled() || mUpdateExistingGroupBox->isEnabled() );
123 if ( mNewFieldGroupBox->isEnabled() )
125 mNewFieldGroupBox->setChecked(
true );
129 mNewFieldGroupBox->setToolTip( tr(
"Not available for layer" ) );
130 mUpdateExistingGroupBox->setChecked(
true );
131 mUpdateExistingGroupBox->setCheckable(
false );
134 if ( mUpdateExistingGroupBox->isEnabled() )
136 mUpdateExistingGroupBox->setChecked( !mNewFieldGroupBox->isEnabled() );
140 mUpdateExistingGroupBox->setToolTip( tr(
"Not available for layer" ) );
141 mNewFieldGroupBox->setChecked(
true );
142 mNewFieldGroupBox->setCheckable(
false );
145 if ( ( mNewFieldGroupBox->isChecked() && mCreateVirtualFieldCheckbox->isChecked() ) || mVectorLayer->
isEditable() )
147 mEditModeAutoTurnOnLabel->setVisible(
false );
148 mInfoIcon->setVisible(
false );
152 mInfoIcon->setVisible(
true );
156 mOnlyUpdateSelectedCheckBox->setChecked( mCanChangeAttributeValue && hasselection );
157 mOnlyUpdateSelectedCheckBox->setEnabled( mCanChangeAttributeValue && hasselection );
158 mOnlyUpdateSelectedCheckBox->setText( tr(
"Only update %n selected feature(s)",
nullptr, vl->
selectedFeatureCount() ) );
160 builder->initWithLayer( vl, expContext, QStringLiteral(
"fieldcalc" ) );
162 mInfoIcon->setPixmap( style()->standardPixmap( QStyle::SP_MessageBoxInformation ) );
164 setWindowTitle( tr(
"%1 — Field Calculator" ).arg( mVectorLayer->
name() ) );
171 builder->expressionTree()->saveToRecent( builder->expressionText(), QStringLiteral(
"fieldcalc" ) );
182 const QString calcString = builder->expressionText();
190 if ( !exp.
prepare( &expContext ) )
192 QMessageBox::critical(
nullptr, tr(
"Evaluation Error" ), exp.
evalErrorString() );
196 bool updatingGeom =
false;
202 if ( ! mUpdateExistingGroupBox->isChecked() && mCreateVirtualFieldCheckbox->isChecked() )
216 if ( mUpdateExistingGroupBox->isChecked() || !mNewFieldGroupBox->isEnabled() )
218 if ( mExistingFieldComboBox->currentData().toString() == QLatin1String(
"geom" ) )
227 const int id = mExistingFieldComboBox->currentData().toInt( &ok );
235 const QgsField newField = fieldDefinition();
240 QMessageBox::critical(
nullptr, tr(
"Create New Field" ), tr(
"Could not add the new field to the provider." ) );
248 for (
int idx = 0; idx < fields.
count(); ++idx )
250 if ( fields.
at( idx ).
name() == mOutputFieldNameLineEdit->text() )
259 if ( ! exp.
prepare( &expContext ) )
262 QMessageBox::critical(
nullptr, tr(
"Evaluation Error" ), exp.
evalErrorString() );
267 if ( mAttributeId == -1 && !updatingGeom )
275 bool calculationSuccess =
true;
283 const bool newField = !mUpdateExistingGroupBox->isChecked();
284 QVariant emptyAttribute;
286 emptyAttribute = QVariant(
field.
type() );
290 referencedColumns.insert(
field.
name() );
292 if ( mOnlyUpdateSelectedCheckBox->isChecked() )
298 std::unique_ptr< QgsScopedProxyProgressTask > task = std::make_unique< QgsScopedProxyProgressTask >( tr(
"Calculating field" ) );
304 task->setProgress( i /
static_cast< double >( count ) * 100 );
309 QVariant value = exp.
evaluate( &expContext );
312 calculationSuccess =
false;
316 else if ( updatingGeom )
333 if ( !calculationSuccess )
337 QMessageBox::critical(
nullptr, tr(
"Evaluation Error" ), tr(
"An error occurred while evaluating the calculation string:\n%1" ).arg( error ) );
347 void QgsFieldCalculator::populateOutputFieldTypes()
360 const int oldDataType = mOutputFieldTypeComboBox->currentData( Qt::UserRole +
FTC_TYPE_ROLE_IDX ).toInt();
362 mOutputFieldTypeComboBox->blockSignals(
true );
365 const QList< QgsVectorDataProvider::NativeType > &typelist = mCreateVirtualFieldCheckbox->isChecked() ?
366 ( QList< QgsVectorDataProvider::NativeType >()
382 mOutputFieldTypeComboBox->clear();
383 for (
int i = 0; i < typelist.size(); i++ )
385 mOutputFieldTypeComboBox->addItem(
QgsFields::iconForFieldType( typelist[i].mType, typelist[i].mSubType ), typelist[i].mTypeDesc );
386 mOutputFieldTypeComboBox->setItemData( i,
static_cast<int>( typelist[i].mType ), Qt::UserRole +
FTC_TYPE_ROLE_IDX );
387 mOutputFieldTypeComboBox->setItemData( i, typelist[i].mTypeName, Qt::UserRole +
FTC_TYPE_NAME_IDX );
388 mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMinLen, Qt::UserRole +
FTC_MINLEN_IDX );
389 mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMaxLen, Qt::UserRole +
FTC_MAXLEN_IDX );
390 mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMinPrec, Qt::UserRole +
FTC_MINPREC_IDX );
391 mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMaxPrec, Qt::UserRole +
FTC_MAXPREC_IDX );
392 mOutputFieldTypeComboBox->setItemData( i,
static_cast<int>( typelist[i].mSubType ), Qt::UserRole +
FTC_SUBTYPE_IDX );
394 mOutputFieldTypeComboBox->blockSignals(
false );
396 const int idx = mOutputFieldTypeComboBox->findData( oldDataType, Qt::UserRole +
FTC_TYPE_ROLE_IDX );
399 mOutputFieldTypeComboBox->setCurrentIndex( idx );
400 mOutputFieldTypeComboBox_activated( idx );
404 mOutputFieldTypeComboBox->setCurrentIndex( 0 );
405 mOutputFieldTypeComboBox_activated( 0 );
409 void QgsFieldCalculator::mNewFieldGroupBox_toggled(
bool on )
411 mUpdateExistingGroupBox->setChecked( !on );
412 if ( on && !mCanAddAttribute )
414 mOnlyVirtualFieldsInfoLabel->setVisible(
true );
418 mOnlyVirtualFieldsInfoLabel->setVisible(
false );
421 if ( ( mNewFieldGroupBox->isChecked() && mCreateVirtualFieldCheckbox->isChecked() ) || mVectorLayer->
isEditable() )
423 mEditModeAutoTurnOnLabel->setVisible(
false );
427 mEditModeAutoTurnOnLabel->setVisible(
true );
430 mInfoIcon->setVisible( mOnlyVirtualFieldsInfoLabel->isVisible() || mEditModeAutoTurnOnLabel->isVisible() );
433 void QgsFieldCalculator::mUpdateExistingGroupBox_toggled(
bool on )
435 mNewFieldGroupBox->setChecked( !on );
444 mCreateVirtualFieldCheckbox_stateChanged( mCreateVirtualFieldCheckbox->checkState() );
448 void QgsFieldCalculator::mCreateVirtualFieldCheckbox_stateChanged(
int state )
450 mOnlyUpdateSelectedCheckBox->setChecked(
false );
451 mOnlyUpdateSelectedCheckBox->setEnabled( state != Qt::Checked && mVectorLayer->
selectedFeatureCount() > 0 );
453 if ( ( mNewFieldGroupBox->isChecked() && mCreateVirtualFieldCheckbox->isChecked() ) || mVectorLayer->
isEditable() )
455 mEditModeAutoTurnOnLabel->setVisible(
false );
459 mEditModeAutoTurnOnLabel->setVisible(
true );
461 populateOutputFieldTypes();
462 mInfoIcon->setVisible( mOnlyVirtualFieldsInfoLabel->isVisible() || mEditModeAutoTurnOnLabel->isVisible() );
466 void QgsFieldCalculator::mOutputFieldNameLineEdit_textChanged(
const QString &text )
473 void QgsFieldCalculator::mOutputFieldTypeComboBox_activated(
int index )
475 mOutputFieldWidthSpinBox->setMinimum( mOutputFieldTypeComboBox->itemData( index, Qt::UserRole +
FTC_MINLEN_IDX ).toInt() );
476 mOutputFieldWidthSpinBox->setMaximum( mOutputFieldTypeComboBox->itemData( index, Qt::UserRole +
FTC_MAXLEN_IDX ).toInt() );
477 mOutputFieldWidthSpinBox->setEnabled( mOutputFieldWidthSpinBox->minimum() < mOutputFieldWidthSpinBox->maximum() );
478 if ( mOutputFieldWidthSpinBox->value() < mOutputFieldWidthSpinBox->minimum() )
479 mOutputFieldWidthSpinBox->setValue( mOutputFieldWidthSpinBox->minimum() );
480 if ( mOutputFieldWidthSpinBox->value() > mOutputFieldWidthSpinBox->maximum() )
481 mOutputFieldWidthSpinBox->setValue( mOutputFieldWidthSpinBox->maximum() );
483 setPrecisionMinMax();
486 void QgsFieldCalculator::populateFields()
492 for (
int idx = 0; idx < fields.
count(); ++idx )
524 const QString fieldName = fields.
at( idx ).
name();
527 mExistingFieldComboBox->addItem( fields.
iconForField( idx ), fieldName, idx );
532 mExistingFieldComboBox->addItem( tr(
"<geometry>" ),
"geom" );
534 QFont font = mExistingFieldComboBox->itemData( mExistingFieldComboBox->count() - 1, Qt::FontRole ).value<QFont>();
535 font.setItalic(
true );
536 mExistingFieldComboBox->setItemData( mExistingFieldComboBox->count() - 1, font, Qt::FontRole );
538 mExistingFieldComboBox->setCurrentIndex( -1 );
541 void QgsFieldCalculator::setOkButtonState()
543 QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
545 if ( ( mNewFieldGroupBox->isChecked() || !mUpdateExistingGroupBox->isEnabled() )
546 && mOutputFieldNameLineEdit->text().isEmpty() )
548 okButton->setToolTip( tr(
"Please enter a field name" ) );
549 okButton->setEnabled(
false );
553 if ( !builder->isExpressionValid() )
555 okButton->setToolTip( okButton->toolTip() + tr(
"\n The expression is invalid see (more info) for details" ) );
556 okButton->setEnabled(
false );
560 okButton->setToolTip( QString() );
561 okButton->setEnabled(
true );
564 void QgsFieldCalculator::setPrecisionMinMax()
566 const int idx = mOutputFieldTypeComboBox->currentIndex();
567 const int minPrecType = mOutputFieldTypeComboBox->itemData( idx, Qt::UserRole +
FTC_MINPREC_IDX ).toInt();
568 const int maxPrecType = mOutputFieldTypeComboBox->itemData( idx, Qt::UserRole +
FTC_MAXPREC_IDX ).toInt();
569 const bool precisionIsEnabled = minPrecType < maxPrecType;
570 mOutputFieldPrecisionSpinBox->setEnabled( precisionIsEnabled );
574 if ( precisionIsEnabled )
576 mOutputFieldPrecisionSpinBox->setMinimum( minPrecType );
577 mOutputFieldPrecisionSpinBox->setMaximum( std::max( minPrecType, std::min( maxPrecType, mOutputFieldWidthSpinBox->value() ) ) );
581 void QgsFieldCalculator::showHelp()
583 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/attribute_table.html#editing-attribute-values" ) );
586 QgsField QgsFieldCalculator::fieldDefinition()
588 return QgsField( mOutputFieldNameLineEdit->text(),
589 static_cast< QVariant::Type
>( mOutputFieldTypeComboBox->currentData( Qt::UserRole +
FTC_TYPE_ROLE_IDX ).toInt() ),
590 mOutputFieldTypeComboBox->currentData( Qt::UserRole +
FTC_TYPE_NAME_IDX ).toString(),
591 mOutputFieldWidthSpinBox->value(),
592 mOutputFieldPrecisionSpinBox->isEnabled() ? mOutputFieldPrecisionSpinBox->value() : 0,
594 static_cast< QVariant::Type
>( mOutputFieldTypeComboBox->currentData( Qt::UserRole +
FTC_SUBTYPE_IDX ).toInt() )