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() )
 
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.
 
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
 
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.
 
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.