Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Value Relation Widget #600

Merged
merged 26 commits into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c2d8f24
add value relation widget
signedav Jun 25, 2019
b201241
add value relation widget to widget handling
signedav Jun 25, 2019
709ae2c
inherit from RelationWidget
signedav Jun 25, 2019
66a6dce
pass FeatureListModel and relation but not that nice
signedav Jun 25, 2019
bbd2cb9
value field of value relation
signedav Jun 25, 2019
3a7ef39
rename and rearrange editorwidget/RelationWidget.qml to RelationCombo…
signedav Jun 27, 2019
8c1489c
use QgsProject->mapLayer to get layer
signedav Jun 27, 2019
ebb9b8f
add mapLayer to qmlRegisterUncreatableType
signedav Jun 27, 2019
a104a38
AllowNull instead of AllowNULL (how it's called in relationreference)
signedav Jun 27, 2019
c83ac1f
add additional role to call displayString manually
signedav Jun 27, 2019
c415622
Basic gui implementation for multi value
signedav Jun 27, 2019
eaab3cd
indents
signedav Jun 27, 2019
cbf571e
Model for multiple selection in ValueRelation
signedav Jul 2, 2019
4388d25
fix the scope
signedav Jul 3, 2019
3415f9f
updating value on model change
signedav Jul 3, 2019
6635af6
beginResetModel / endResetModel and log that has to be removed later
signedav Jul 3, 2019
040c828
- keep index on list
signedav Jul 3, 2019
a5a7161
clear model on adding features
signedav Jul 3, 2019
16cf30e
remove wrong sign
signedav Jul 3, 2019
004d202
handle JSON and HSTORE regarding the field.type
signedav Jul 4, 2019
7a81a1c
Bump SDK
m-kuhn Jul 5, 2019
5c5f6aa
Fix builds with QGIS 3.9
m-kuhn Jul 7, 2019
8ba98ef
Bump SDK
m-kuhn Jul 26, 2019
35bb72b
use of QgsPostgresStringUtils
signedav Aug 11, 2019
e3f6cd0
exclude QgsPostgresStringUtils for android 5
signedav Sep 2, 2019
039d707
clean up
signedav Sep 2, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/core/featurelistmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "featurelistmodel.h"

#include "qgsvectorlayer.h"
#include <qgsproject.h>

FeatureListModel::FeatureListModel()
: mCurrentLayer( nullptr )
Expand Down Expand Up @@ -101,6 +102,17 @@ void FeatureListModel::setCurrentLayer( QgsVectorLayer *currentLayer )
emit currentLayerChanged();
}

QString FeatureListModel::currentLayerId() const
{
return mCurrentLayer->id();
}

void FeatureListModel::setCurrentLayerId( const QString &layerId )
{
QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( QgsProject::instance()->mapLayer( layerId ) );
setCurrentLayer( layer );
}
m-kuhn marked this conversation as resolved.
Show resolved Hide resolved

QString FeatureListModel::keyField() const
{
return mKeyField;
Expand All @@ -118,6 +130,23 @@ void FeatureListModel::setKeyField( const QString &keyField )
emit keyFieldChanged();
}

QString FeatureListModel::displayValueField() const
{
return mDisplayValueField;
}

void FeatureListModel::setDisplayValueField( const QString &displayValueField )
{
if ( mDisplayValueField == displayValueField )
return;

mDisplayValueField = displayValueField;

reloadLayer();

emit displayValueFieldChanged();
}

int FeatureListModel::findKey( const QVariant &key ) const
{
int idx = 0;
Expand Down Expand Up @@ -165,6 +194,7 @@ void FeatureListModel::processReloadLayer()
request.setSubsetOfAttributes( referencedColumns, fields );

int keyIndex = fields.indexOf( mKeyField );
int displayValueIndex = fields.indexOf( mDisplayValueField );

QgsFeatureIterator iterator = mCurrentLayer->getFeatures( request );

Expand All @@ -178,7 +208,10 @@ void FeatureListModel::processReloadLayer()
while ( iterator.nextFeature( feature ) )
{
context.setFeature( feature );
entries.append( Entry( expression.evaluate( &context ).toString(), feature.attribute( keyIndex ) ) );
if ( mDisplayValueField.isEmpty() )
entries.append( Entry( expression.evaluate( &context ).toString(), feature.attribute( keyIndex ) ) );
else
entries.append( Entry( feature.attribute( displayValueIndex ).toString(), feature.attribute( keyIndex ) ) );
}

if ( mOrderByValue )
Expand Down
18 changes: 18 additions & 0 deletions src/core/featurelistmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class QgsVectorLayer;
* Provides access to a list of features from a layer.
* For each feature, the display expression is exposed as DisplayRole
* and a keyField as KeyFieldRole for a unique identifier.
* If a displayValueField is set it replaces the display expression of the layer.
*/
class FeatureListModel : public QAbstractItemModel
{
Expand All @@ -34,10 +35,18 @@ class FeatureListModel : public QAbstractItemModel
* The vector layer to list
*/
Q_PROPERTY( QgsVectorLayer *currentLayer READ currentLayer WRITE setCurrentLayer NOTIFY currentLayerChanged )
/**
* The vector layer to list by id
*/
Q_PROPERTY( QString currentLayerId READ currentLayerId WRITE setCurrentLayerId NOTIFY currentLayerIdChanged )
/**
* The primary key field
*/
Q_PROPERTY( QString keyField READ keyField WRITE setKeyField NOTIFY keyFieldChanged )
/**
* The display value field
*/
Q_PROPERTY( QString displayValueField READ displayValueField WRITE setDisplayValueField NOTIFY displayValueFieldChanged )

Q_PROPERTY( bool orderByValue READ orderByValue WRITE setOrderByValue NOTIFY orderByValueChanged )

Expand All @@ -64,9 +73,15 @@ class FeatureListModel : public QAbstractItemModel
QgsVectorLayer *currentLayer() const;
void setCurrentLayer( QgsVectorLayer *currentLayer );

QString currentLayerId() const;
void setCurrentLayerId( const QString &layerId );

QString keyField() const;
void setKeyField( const QString &keyField );

QString displayValueField() const;
void setDisplayValueField( const QString &displayValueField );

/**
* Get the row for a given key value.
*/
Expand Down Expand Up @@ -94,7 +109,9 @@ class FeatureListModel : public QAbstractItemModel

signals:
void currentLayerChanged();
void currentLayerIdChanged();
m-kuhn marked this conversation as resolved.
Show resolved Hide resolved
void keyFieldChanged();
void displayValueFieldChanged();
void addNullChanged();
void orderByValueChanged();

Expand Down Expand Up @@ -134,6 +151,7 @@ class FeatureListModel : public QAbstractItemModel

QList<Entry> mEntries;
QString mKeyField;
QString mDisplayValueField;
bool mOrderByValue = false;
bool mAddNull = false;

Expand Down
191 changes: 9 additions & 182 deletions src/qml/editorwidgets/RelationReference.qml
Original file line number Diff line number Diff line change
Expand Up @@ -8,188 +8,15 @@ import "../js/style.js" as Style
import org.qfield 1.0
import org.qgis 1.0

Item {
RelationWidget {
id: relationReference
signal valueChanged(var value, bool isNull)
property var _relation

Component.onCompleted: {
_relation = qgisProject.relationManager.relation(config['Relation'])
featureListModel.currentLayer = _relation.referencedLayer
featureListModel.keyField = _relation.resolveReferencedField(field.name)
comboBox.currentIndex = featureListModel.findKey(comboBox.value)

comboBox.visible = _relation.isValid
addButton.visible = _relation.isValid
invalidWarning.visible = !(_relation.isValid)
}

anchors {
left: parent.left
right: parent.right
rightMargin: 10 * dp
}

height: childrenRect.height + 10 * dp

RowLayout {
anchors { left: parent.left; right: parent.right }

ComboBox {
id: comboBox

property var currentValue: value
property var _cachedCurrentValue

textRole: 'display'

Layout.fillWidth: true

model: FeatureListModel {
id: featureListModel
addNull: config['AllowNULL']
orderByValue: config['OrderByValue']
}

onCurrentIndexChanged: {
var idx = featureListModel.index(currentIndex, 0, undefined)
var newValue = featureListModel.data(idx, FeatureListModel.KeyFieldRole)
valueChanged(newValue, false)
}

// Workaround to get a signal when the value has changed
onCurrentValueChanged: {
currentIndex = featureListModel.findKey(currentValue)
}

Connections {
target: featureListModel

onModelAboutToBeReset: {
comboBox._cachedCurrentValue = comboBox.currentValue
}

onModelReset: {
comboBox.currentIndex = featureListModel.findKey(comboBox.currentValue)
}
}

MouseArea {
anchors.fill: parent
propagateComposedEvents: true

onClicked: mouse.accepted = false
onPressed: { forceActiveFocus(); mouse.accepted = false; }
onReleased: mouse.accepted = false;
onDoubleClicked: mouse.accepted = false;
onPositionChanged: mouse.accepted = false;
onPressAndHold: mouse.accepted = false;
}

// [hidpi fixes]
delegate: ItemDelegate {
width: comboBox.width
height: 36 * dp
text: comboBox.textRole ? (Array.isArray(comboBox.model) ? modelData[comboBox.textRole] : model[comboBox.textRole]) : modelData
font.weight: comboBox.currentIndex === index ? Font.DemiBold : Font.Normal
font.pointSize: 12
highlighted: comboBox.highlightedIndex == index
}

contentItem: Text {
height: 36 * dp
text: comboBox.displayText
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}

background: Item {
implicitWidth: 120 * dp
implicitHeight: 36 * dp

Rectangle {
anchors.fill: parent
id: backgroundRect
border.color: comboBox.pressed ? "#17a81a" : "#21be2b"
border.width: comboBox.visualFocus ? 2 : 1
color: "#dddddd"
radius: 2
}
}
// [/hidpi fixes]
}

Button {
id: addButton
iconSource: Style.getThemeIcon( "ic_add_black_48dp" )
bgcolor: "white"
onClicked: {
attributeFormModel.featureModel.resetAttributes()
addFeatureForm.active = true
}
}

Text {
id: invalidWarning
visible: false
text: qsTr( "Invalid relation")
color: "red"
}
}

AttributeFormModel {
id: attributeFormModel
featureModel: FeatureModel {
currentLayer: relationReference._relation.referencedLayer
}
}

Loader {
id: addFeatureForm
sourceComponent: addFeatureFormComponent
active: false
onLoaded: {
item.open()
}
}

Component {
id: addFeatureFormComponent
Popup {
id: popup
parent: ApplicationWindow.overlay

x: 24 * dp
y: 24 * dp
width: parent.width - 48 * dp
height: parent.height - 48 * dp
modal: true
focus: true
closePolicy: Popup.CloseOnEscape

FeatureForm {
model: attributeFormModel

anchors.fill: parent

state: "Add"
embedded: true

onSaved: {
var referencedValue = attributeFormModel.attribute(relationReference._relation.resolveReferencedField(field.name))
comboBox.currentValue = referencedValue
popup.close()
}

onCancelled: {
popup.close()
}
}

onClosed: {
addFeatureForm.active = false
}
}
property var _relation: qgisProject.relationManager.relation(config['Relation'])

FeatureListModel {
id: featureListModel
currentLayer: qgisProject.relationManager.relation(config['Relation']).referencedLayer
keyField: qgisProject.relationManager.relation(config['Relation']).resolveReferencedField(field.name)
addNull: config['AllowNULL']
orderByValue: config['OrderByValue']
}
}
Loading