mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
Display generated field as read-only is editors
This commit is contained in:
parent
ce466a4726
commit
87f8e1514e
@ -371,6 +371,22 @@ Defaults may be set by the provider and can be overridden
|
||||
by manual field configuration.
|
||||
|
||||
:return: the value
|
||||
%End
|
||||
|
||||
void setReadOnly( bool readOnly );
|
||||
%Docstring
|
||||
Make field read-only if ``readOnly`` is set to true. This is the case for
|
||||
providers which support generated fields for instance.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
bool isReadOnly() const;
|
||||
%Docstring
|
||||
Returns ``True`` if this field is a read-only field. This is the case for
|
||||
providers which support generated fields for instance.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
SIP_PYOBJECT __repr__();
|
||||
|
@ -561,6 +561,17 @@ QgsEditorWidgetSetup QgsField::editorWidgetSetup() const
|
||||
return d->editorWidgetSetup;
|
||||
}
|
||||
|
||||
void QgsField::setReadOnly( bool readOnly )
|
||||
{
|
||||
d->isReadOnly = readOnly;
|
||||
}
|
||||
|
||||
bool QgsField::isReadOnly() const
|
||||
{
|
||||
return d->isReadOnly;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* This class is considered CRITICAL and any change MUST be accompanied with
|
||||
* full unit tests in testqgsfield.cpp.
|
||||
|
@ -433,6 +433,20 @@ class CORE_EXPORT QgsField
|
||||
*/
|
||||
QgsEditorWidgetSetup editorWidgetSetup() const;
|
||||
|
||||
/**
|
||||
* Make field read-only if \a readOnly is set to true. This is the case for
|
||||
* providers which support generated fields for instance.
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
void setReadOnly( bool readOnly );
|
||||
|
||||
/**
|
||||
* Returns TRUE if this field is a read-only field. This is the case for
|
||||
* providers which support generated fields for instance.
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
bool isReadOnly() const;
|
||||
|
||||
#ifdef SIP_RUN
|
||||
SIP_PYOBJECT __repr__();
|
||||
% MethodCode
|
||||
|
@ -78,6 +78,7 @@ class QgsFieldPrivate : public QSharedData
|
||||
, flags( other.flags )
|
||||
, defaultValueDefinition( other.defaultValueDefinition )
|
||||
, constraints( other.constraints )
|
||||
, isReadOnly( other.isReadOnly )
|
||||
{
|
||||
}
|
||||
|
||||
@ -88,7 +89,8 @@ class QgsFieldPrivate : public QSharedData
|
||||
return ( ( name == other.name ) && ( type == other.type ) && ( subType == other.subType )
|
||||
&& ( length == other.length ) && ( precision == other.precision )
|
||||
&& ( alias == other.alias ) && ( defaultValueDefinition == other.defaultValueDefinition )
|
||||
&& ( constraints == other.constraints ) && ( flags == other.flags ) );
|
||||
&& ( constraints == other.constraints ) && ( flags == other.flags )
|
||||
&& ( isReadOnly == other.isReadOnly ) );
|
||||
}
|
||||
|
||||
//! Name
|
||||
@ -126,6 +128,9 @@ class QgsFieldPrivate : public QSharedData
|
||||
|
||||
QgsEditorWidgetSetup editorWidgetSetup;
|
||||
|
||||
//! Read-only
|
||||
bool isReadOnly = false;
|
||||
|
||||
private:
|
||||
QgsFieldPrivate &operator=( const QgsFieldPrivate & ) = delete;
|
||||
};
|
||||
|
@ -863,7 +863,9 @@ bool _fieldIsEditable( const QgsVectorLayer *layer, int fieldIndex, const QgsFea
|
||||
{
|
||||
return layer->isEditable() &&
|
||||
!layer->editFormConfig().readOnly( fieldIndex ) &&
|
||||
( ( layer->dataProvider() && layer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) || FID_IS_NEW( feature.id() ) );
|
||||
layer->dataProvider() &&
|
||||
( ( layer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) || FID_IS_NEW( feature.id() ) ) &&
|
||||
!layer->fields().at( fieldIndex ).isReadOnly();
|
||||
}
|
||||
|
||||
bool QgsVectorLayerUtils::fieldIsEditable( const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature )
|
||||
|
@ -773,6 +773,7 @@ bool QgsOracleProvider::loadFields()
|
||||
|
||||
QVariant::Type type = field.type();
|
||||
QgsField newField( field.name(), type, types.value( field.name() ), field.length(), field.precision(), comments.value( field.name() ) );
|
||||
newField.setReadOnly( alwaysGenerated.value( field.name(), false ) );
|
||||
|
||||
QgsFieldConstraints constraints;
|
||||
if ( mPrimaryKeyAttrs.contains( i ) )
|
||||
@ -1221,7 +1222,6 @@ QString QgsOracleProvider::defaultValueClause( int fieldId ) const
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
bool QgsOracleProvider::skipConstraintCheck( int fieldIndex, QgsFieldConstraints::Constraint constraint, const QVariant &value ) const
|
||||
{
|
||||
Q_UNUSED( constraint );
|
||||
|
@ -898,7 +898,7 @@ bool QgsPostgresProvider::loadFields()
|
||||
notNullMap[attrelid][attnum] = attNotNull;
|
||||
uniqueMap[attrelid][attnum] = uniqueConstraint;
|
||||
identityMap[attrelid][attnum] = attIdentity.isEmpty() ? " " : attIdentity;
|
||||
generatedMap[attrelid][attnum] = attGenerated.isEmpty() ? "" : defVal;
|
||||
generatedMap[attrelid][attnum] = attGenerated.isEmpty() ? QString() : defVal;
|
||||
|
||||
// Also include atttype oid from pg_attribute, because PQnfields only returns basic type for for domains
|
||||
attroids.insert( attType );
|
||||
@ -1236,9 +1236,13 @@ bool QgsPostgresProvider::loadFields()
|
||||
}
|
||||
|
||||
mDefaultValues.insert( mAttributeFields.size(), defValMap[tableoid][attnum] );
|
||||
mGeneratedValues.insert( mAttributeFields.size(), generatedMap[tableoid][attnum] );
|
||||
|
||||
const QString generatedValue = generatedMap[tableoid][attnum];
|
||||
if ( !generatedValue.isNull() )
|
||||
mGeneratedValues.insert( mAttributeFields.size(), generatedValue );
|
||||
|
||||
QgsField newField = QgsField( fieldName, fieldType, fieldTypeName, fieldSize, fieldPrec, fieldComment, fieldSubType );
|
||||
newField.setReadOnly( !generatedValue.isNull() );
|
||||
|
||||
QgsFieldConstraints constraints;
|
||||
if ( notNullMap[tableoid][attnum] || ( mPrimaryKeyAttrs.size() == 1 && mPrimaryKeyAttrs[0] == i ) || identityMap[tableoid][attnum] != ' ' )
|
||||
@ -2115,7 +2119,6 @@ bool QgsPostgresProvider::isValid() const
|
||||
QString QgsPostgresProvider::defaultValueClause( int fieldId ) const
|
||||
{
|
||||
QString defVal = mDefaultValues.value( fieldId, QString() );
|
||||
QString genVal = mGeneratedValues.value( fieldId, QString() );
|
||||
|
||||
// with generated columns (PostgreSQL 12+), the provider will ALWAYS evaluate the default values.
|
||||
// The only acceptable value for such columns on INSERT or UPDATE clauses is the keyword "DEFAULT".
|
||||
@ -2124,7 +2127,7 @@ QString QgsPostgresProvider::defaultValueClause( int fieldId ) const
|
||||
// On inserting a new feature or updating a generated field, this is
|
||||
// omitted from the generated queries.
|
||||
// See https://www.postgresql.org/docs/12/ddl-generated-columns.html
|
||||
if ( !genVal.isEmpty() )
|
||||
if ( mGeneratedValues.contains( fieldId ) )
|
||||
{
|
||||
return defVal;
|
||||
}
|
||||
@ -2994,7 +2997,7 @@ bool QgsPostgresProvider::changeAttributeValues( const QgsChangedAttributesMap &
|
||||
|
||||
pkChanged = pkChanged || mPrimaryKeyAttrs.contains( siter.key() );
|
||||
|
||||
if ( mGeneratedValues.contains( siter.key() ) && !mGeneratedValues.value( siter.key(), QString() ).isEmpty() )
|
||||
if ( mGeneratedValues.contains( siter.key() ) )
|
||||
{
|
||||
QgsLogger::warning( tr( "Changing the value of GENERATED field %1 is not allowed." ).arg( fld.name() ) );
|
||||
continue;
|
||||
@ -3358,7 +3361,7 @@ bool QgsPostgresProvider::changeFeatures( const QgsChangedAttributesMap &attr_ma
|
||||
|
||||
pkChanged = pkChanged || mPrimaryKeyAttrs.contains( siter.key() );
|
||||
|
||||
if ( mGeneratedValues.contains( siter.key() ) && !mGeneratedValues.value( siter.key(), QString() ).isEmpty() )
|
||||
if ( mGeneratedValues.contains( siter.key() ) )
|
||||
{
|
||||
QgsLogger::warning( tr( "Changing the value of GENERATED field %1 is not allowed." ).arg( fld.name() ) );
|
||||
continue;
|
||||
|
@ -30,6 +30,7 @@ from qgis.core import (
|
||||
QgsTestUtils,
|
||||
QgsFeatureSource,
|
||||
QgsFieldConstraints,
|
||||
QgsVectorLayerUtils,
|
||||
NULL
|
||||
)
|
||||
from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant
|
||||
@ -1171,38 +1172,45 @@ class ProviderTestCase(FeatureSourceTestCase):
|
||||
vl.startEditing()
|
||||
|
||||
feature = next(vl.getFeatures())
|
||||
# to be fixed
|
||||
# self.assertEqual(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature), editable)
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature))
|
||||
self.assertTrue(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature))
|
||||
|
||||
# same test on a new inserted feature
|
||||
feature = QgsFeature(vl.fields())
|
||||
feature.setAttribute(0, 2)
|
||||
vl.addFeature(feature)
|
||||
self.assertTrue(feature.id() < 0)
|
||||
# to be fixed
|
||||
# self.assertEqual(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature), editable)
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature))
|
||||
self.assertTrue(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature))
|
||||
vl.commitChanges()
|
||||
|
||||
feature = vl.getFeature(2)
|
||||
self.assertTrue(feature.isValid())
|
||||
self.assertEqual(feature.attribute(1), "test:2")
|
||||
|
||||
# to be fixed
|
||||
# self.assertEqual(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature), editable)
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature))
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature))
|
||||
|
||||
# test update id and commit
|
||||
vl.startEditing()
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature))
|
||||
self.assertTrue(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature))
|
||||
self.assertTrue(vl.changeAttributeValue(2, 0, 10))
|
||||
self.assertTrue(vl.commitChanges())
|
||||
feature = vl.getFeature(10)
|
||||
self.assertTrue(feature.isValid())
|
||||
self.assertEqual(feature.attribute(0), 10)
|
||||
self.assertEqual(feature.attribute(1), "test:10")
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature))
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature))
|
||||
|
||||
# test update the_field and commit (the value is not changed because the field is generated)
|
||||
vl.startEditing()
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature))
|
||||
self.assertTrue(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature))
|
||||
self.assertTrue(vl.changeAttributeValue(10, 1, "new value"))
|
||||
self.assertTrue(vl.commitChanges())
|
||||
feature = vl.getFeature(10)
|
||||
self.assertTrue(feature.isValid())
|
||||
self.assertEqual(feature.attribute(1), "test:10")
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature))
|
||||
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature))
|
||||
|
Loading…
x
Reference in New Issue
Block a user