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 )
318 if ( value.userType() == QMetaType::type(
"QgsGeometry" ) )
333 if ( !calculationSuccess )
337 QMessageBox::critical(
nullptr, tr(
"Evaluation Error" ), tr(
"An error occurred while evaluating the calculation string:\n%1" ).arg( error ) );
347void 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 );
409void 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() );
433void QgsFieldCalculator::mUpdateExistingGroupBox_toggled(
bool on )
435 mNewFieldGroupBox->setChecked( !on );
444 mCreateVirtualFieldCheckbox_stateChanged( mCreateVirtualFieldCheckbox->checkState() );
448void 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() );
466void QgsFieldCalculator::mOutputFieldNameLineEdit_textChanged(
const QString &text )
473void 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();
486void 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 );
541void 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 );
564void 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() ) ) );
581void QgsFieldCalculator::showHelp()
583 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/attribute_table.html#editing-attribute-values" ) );
586QgsField 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() )
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QString evalErrorString() const
Returns evaluation error.
void setDistanceUnits(QgsUnitTypes::DistanceUnit unit)
Sets the desired distance units for calculations involving geomCalculator(), e.g.,...
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
void setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
void setGeomCalculator(const QgsDistanceArea *calc)
Sets the geometry calculator used for distance and area calculations in expressions.
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
QgsFieldCalculator(QgsVectorLayer *vl, QWidget *parent=nullptr)
Encapsulate a field in an attribute table or data source.
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Container of fields for a vector layer.
static QIcon iconForFieldType(QVariant::Type type, QVariant::Type subType=QVariant::Type::Invalid)
Returns an icon corresponding to a field type.
@ OriginExpression
Field is calculated from an expression.
@ OriginEdit
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
@ OriginUnknown
It has not been specified where the field comes from.
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
@ OriginProvider
Field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
int count() const
Returns number of items.
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
QIcon iconForField(int fieldIdx, bool considerOrigin=false) const
Returns an icon corresponding to a field index, based on the field's type and source.
A geometry is the spatial representation of a feature.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
QString providerType() const
Returns the provider type (provider key) for this layer.
QgsCoordinateReferenceSystem crs
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsCoordinateTransformContext transformContext
Temporarily sets a cursor override for the QApplication for the lifetime of the object.
void release()
Releases the cursor override early (i.e.
static QString typeToDisplayString(QVariant::Type type, QVariant::Type subType=QVariant::Type::Invalid)
Returns a user-friendly translated string representing a QVariant type.
This is the base class for vector data providers.
@ AddAttributes
Allows addition of new attributes (fields)
@ ChangeAttributeValues
Allows modification of attribute values.
QList< QgsVectorDataProvider::NativeType > nativeTypes() const
Returns the names of the supported types.
virtual Q_INVOKABLE QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
Defines left outer join from our vector layer to some other vector layer.
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
Represents a vector layer which manages a vector based data sets.
int addExpressionField(const QString &exp, const QgsField &fld)
Add a new field which is calculated by the expression specified.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
bool addAttribute(const QgsField &field)
Add an attribute field (but does not commit it) returns true if the field was added.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
void endEditCommand()
Finish edit command and add it to undo/redo stack.
void destroyEditCommand()
Destroy active command and reverts all changes in it.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature's geometry within the layer's edit buffer (but does not immediately commit the chan...
constexpr int FTC_TYPE_NAME_IDX
constexpr int FTC_MINLEN_IDX
constexpr int FTC_TYPE_ROLE_IDX
constexpr int FTC_MAXLEN_IDX
constexpr int FTC_MAXPREC_IDX
constexpr int FTC_MINPREC_IDX
constexpr int FTC_SUBTYPE_IDX
Single variable definition for use within a QgsExpressionContextScope.