Apply same logic regarding joined fields as is used in field calculator

to QgsFieldProxyModel set to hiding read only fields

I.e. show editable joined fields, but only if they are set to a non-hidden
editor widget
This commit is contained in:
Nyall Dawson 2019-08-04 14:14:56 +10:00
parent 4a1115096b
commit 126ccb9736
5 changed files with 130 additions and 2 deletions

View File

@ -36,6 +36,8 @@ It can be associated with a QgsMapLayerModel to dynamically display a layer and
FieldTypeRole,
FieldOriginRole,
IsEmptyRole,
EditorWidgetType,
JoinedFieldIsEditable,
};
explicit QgsFieldModel( QObject *parent /TransferThis/ = 0 );

View File

@ -22,6 +22,7 @@
#include "qgslogger.h"
#include "qgsapplication.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayerjoinbuffer.h"
QgsFieldModel::QgsFieldModel( QObject *parent )
: QAbstractItemModel( parent )
@ -359,6 +360,33 @@ QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
return isEmpty;
}
case EditorWidgetType:
{
if ( exprIdx < 0 && !isEmpty )
{
return mFields.at( index.row() - fieldOffset ).editorWidgetSetup().type();
}
return QVariant();
}
case JoinedFieldIsEditable:
{
if ( exprIdx < 0 && !isEmpty )
{
if ( mLayer && mFields.fieldOrigin( index.row() - fieldOffset ) == QgsFields::OriginJoin )
{
int srcFieldIndex;
const QgsVectorLayerJoinInfo *info = mLayer->joinBuffer()->joinForFieldIndex( index.row() - fieldOffset, mLayer->fields(), srcFieldIndex );
if ( !info || !info->isEditable() )
return false;
return true;
}
}
return QVariant();
}
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::ToolTipRole:

View File

@ -55,6 +55,8 @@ class CORE_EXPORT QgsFieldModel : public QAbstractItemModel
FieldTypeRole = Qt::UserRole + 6, //!< Return the field type (if a field, return QVariant if expression)
FieldOriginRole = Qt::UserRole + 7, //!< Return the field origin (if a field, returns QVariant if expression)
IsEmptyRole = Qt::UserRole + 8, //!< Return if the index corresponds to the empty value
EditorWidgetType = Qt::UserRole + 9, //!< Editor widget type
JoinedFieldIsEditable = Qt::UserRole + 10, //!< TRUE if a joined field is editable (returns QVariant if not a joined field)
};
/**

View File

@ -44,8 +44,18 @@ bool QgsFieldProxyModel::isReadOnly( const QModelIndex &index ) const
QgsFields::FieldOrigin origin = static_cast< QgsFields::FieldOrigin >( originVariant.toInt() );
switch ( origin )
{
case QgsFields::OriginUnknown:
case QgsFields::OriginJoin:
{
// show joined fields (e.g. auxiliary fields) only if they have a non-hidden editor widget.
// This enables them to be bulk field-calculated when a user needs to, but hides them by default
// (since there's often MANY of these, e.g. after using the label properties tool on a layer)
if ( sourceModel()->data( index, QgsFieldModel::EditorWidgetType ).toString() == QLatin1String( "Hidden" ) )
return true;
return !sourceModel()->data( index, QgsFieldModel::JoinedFieldIsEditable ).toBool();
}
case QgsFields::OriginUnknown:
case QgsFields::OriginExpression:
//read only
return true;

View File

@ -15,7 +15,11 @@ import qgis # NOQA
from qgis.core import (QgsField,
QgsFields,
QgsVectorLayer,
QgsFieldModel)
QgsFieldModel,
QgsFieldProxyModel,
QgsEditorWidgetSetup,
QgsProject,
QgsVectorLayerJoinInfo)
from qgis.PyQt.QtCore import QVariant, Qt
from qgis.testing import start_app, unittest
@ -26,6 +30,8 @@ start_app()
def create_layer():
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
"addfeat", "memory")
layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup('Hidden', {}))
layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup('ValueMap', {}))
assert layer.isValid()
return layer
@ -245,6 +251,86 @@ class TestQgsFieldModel(unittest.TestCase):
m.setAllowEmptyFieldName(True)
self.assertFalse(m.data(m.indexFromName(None), Qt.DisplayRole))
def testEditorWidgetTypeRole(self):
l, m = create_model()
self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.EditorWidgetType), 'Hidden')
self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.EditorWidgetType), 'ValueMap')
self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.EditorWidgetType))
self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.EditorWidgetType))
m.setAllowExpression(True)
m.setExpression('an expression')
self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.EditorWidgetType))
m.setAllowEmptyFieldName(True)
self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.EditorWidgetType))
def testJoinedFieldIsEditableRole(self):
layer = QgsVectorLayer("Point?field=id_a:integer",
"addfeat", "memory")
layer2 = QgsVectorLayer("Point?field=id_b:integer&field=value_b",
"addfeat", "memory")
QgsProject.instance().addMapLayers([layer, layer2])
# editable join
join_info = QgsVectorLayerJoinInfo()
join_info.setTargetFieldName("id_a")
join_info.setJoinLayer(layer2)
join_info.setJoinFieldName("id_b")
join_info.setPrefix("B_")
join_info.setEditable(True)
join_info.setUpsertOnEdit(True)
layer.addJoin(join_info)
m = QgsFieldModel()
m.setLayer(layer)
self.assertIsNone(m.data(m.indexFromName('id_a'), QgsFieldModel.JoinedFieldIsEditable))
self.assertTrue(m.data(m.indexFromName('B_value_b'), QgsFieldModel.JoinedFieldIsEditable))
self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable))
self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable))
m.setAllowExpression(True)
m.setExpression('an expression')
self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable))
m.setAllowEmptyFieldName(True)
self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable))
proxy_m = QgsFieldProxyModel()
proxy_m.setFilters(QgsFieldProxyModel.AllTypes | QgsFieldProxyModel.HideReadOnly)
proxy_m.sourceFieldModel().setLayer(layer)
self.assertEqual(proxy_m.rowCount(), 2)
self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a')
self.assertEqual(proxy_m.data(proxy_m.index(1, 0)), 'B_value_b')
# not editable join
layer3 = QgsVectorLayer("Point?field=id_a:integer",
"addfeat", "memory")
QgsProject.instance().addMapLayers([layer3])
join_info = QgsVectorLayerJoinInfo()
join_info.setTargetFieldName("id_a")
join_info.setJoinLayer(layer2)
join_info.setJoinFieldName("id_b")
join_info.setPrefix("B_")
join_info.setEditable(False)
layer3.addJoin(join_info)
m = QgsFieldModel()
m.setLayer(layer3)
self.assertIsNone(m.data(m.indexFromName('id_a'), QgsFieldModel.JoinedFieldIsEditable))
self.assertFalse(m.data(m.indexFromName('B_value_b'), QgsFieldModel.JoinedFieldIsEditable))
self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable))
self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable))
m.setAllowExpression(True)
m.setExpression('an expression')
self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable))
m.setAllowEmptyFieldName(True)
self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable))
proxy_m = QgsFieldProxyModel()
proxy_m.sourceFieldModel().setLayer(layer3)
proxy_m.setFilters(QgsFieldProxyModel.AllTypes | QgsFieldProxyModel.HideReadOnly)
self.assertEqual(proxy_m.rowCount(), 1)
self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a')
def testFieldTooltip(self):
f = QgsField('my_string', QVariant.String, 'string')
self.assertEqual(QgsFieldModel.fieldToolTip(f), '<b>my_string</b><p>string</p>')