Skip to content

Commit 632eca6

Browse files
authoredJul 7, 2017
Merge pull request #4795 from pblottiere/dynamicform
[FEATURE] Dynamic form for joined fields
2 parents 0036f27 + df5551a commit 632eca6

20 files changed

+438
-26
lines changed
 

‎python/core/qgsvectorlayerjoinbuffer.sip

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,24 @@ Quick way to test if there is any join at all
9999
:rtype: list of int
100100
%End
101101

102+
QList<const QgsVectorLayerJoinInfo *> joinsWhereFieldIsId( const QgsField &field ) const;
103+
%Docstring
104+
Returns joins where the field of a target layer is considered as an id.
105+
\param field the field of a target layer
106+
:return: a list of vector joins
107+
.. versionadded:: 3.0
108+
:rtype: list of const QgsVectorLayerJoinInfo
109+
%End
110+
111+
QgsFeature joinedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const;
112+
%Docstring
113+
Returns the joined feature corresponding to the feature.
114+
\param info the vector join information
115+
\param feature the feature of the target layer
116+
.. versionadded:: 3.0
117+
:rtype: QgsFeature
118+
%End
119+
102120
QgsVectorLayerJoinBuffer *clone() const /Factory/;
103121
%Docstring
104122
.. versionadded:: 2.6

‎python/core/qgsvectorlayerjoininfo.sip

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,30 @@ Returns whether values from the joined layer should be cached in memory to speed
8484
:rtype: bool
8585
%End
8686

87+
bool isDynamicFormEnabled() const;
88+
%Docstring
89+
Returns whether the form has to be dynamically updated with joined fields
90+
when a feature is being created in the target layer.
91+
.. versionadded:: 3.0
92+
:rtype: bool
93+
%End
94+
95+
void setDynamicFormEnabled( bool enabled );
96+
%Docstring
97+
Sets whether the form has to be dynamically updated with joined fields
98+
when a feature is being created in the target layer.
99+
.. versionadded:: 3.0
100+
%End
101+
102+
QString prefixedFieldName( const QgsField &field ) const;
103+
%Docstring
104+
Returns the prefixed name of the field.
105+
\param field the field
106+
:return: the prefixed name of the field
107+
.. versionadded:: 3.0
108+
:rtype: str
109+
%End
110+
87111
bool operator==( const QgsVectorLayerJoinInfo &other ) const;
88112

89113
void setJoinFieldNamesSubset( QStringList *fieldNamesSubset /Transfer/ );
@@ -108,6 +132,7 @@ Returns whether values from the joined layer should be cached in memory to speed
108132

109133

110134

135+
111136
};
112137

113138

‎python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ class QgsEditorWidgetWrapper : QgsWidgetWrapper
156156
:rtype: str
157157
%End
158158

159+
virtual void setHint( const QString &hintText );
160+
%Docstring
161+
Add a hint text on the widget
162+
\param hintText The hint text to display
163+
.. versionadded:: 3.0
164+
%End
165+
159166
signals:
160167

161168
void valueChanged( const QVariant &value );

‎python/gui/qgsattributeform.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class QgsAttributeForm : QWidget
167167

168168
public slots:
169169

170-
void changeAttribute( const QString &field, const QVariant &value );
170+
void changeAttribute( const QString &field, const QVariant &value, const QString &hintText = QString() );
171171
%Docstring
172172
Call this to change the content of a given attribute. Will update the editor(s) related to this field.
173173

‎src/app/qgsjoindialog.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ QgsJoinDialog::QgsJoinDialog( QgsVectorLayer *layer, QList<QgsMapLayer *> alread
4242

4343
mTargetFieldComboBox->setLayer( mLayer );
4444

45+
mDynamicFormCheckBox->setToolTip( tr( "This option allows values of the joined fields to be automatically reloaded when the \"Target Field\" is changed" ) );
46+
4547
mJoinLayerComboBox->setFilters( QgsMapLayerProxyModel::VectorLayer );
4648
mJoinLayerComboBox->setExceptedLayerList( alreadyJoinedLayers );
4749
connect( mJoinLayerComboBox, &QgsMapLayerComboBox::layerChanged, mJoinFieldComboBox, &QgsFieldComboBox::setLayer );
@@ -73,6 +75,7 @@ void QgsJoinDialog::setJoinInfo( const QgsVectorLayerJoinInfo &joinInfo )
7375
mJoinFieldComboBox->setField( joinInfo.joinFieldName() );
7476
mTargetFieldComboBox->setField( joinInfo.targetFieldName() );
7577
mCacheInMemoryCheckBox->setChecked( joinInfo.isUsingMemoryCache() );
78+
mDynamicFormCheckBox->setChecked( joinInfo.isDynamicFormEnabled() );
7679
if ( joinInfo.prefix().isNull() )
7780
{
7881
mUseCustomPrefix->setChecked( false );
@@ -110,6 +113,7 @@ QgsVectorLayerJoinInfo QgsJoinDialog::joinInfo() const
110113
info.setJoinFieldName( mJoinFieldComboBox->currentField() );
111114
info.setTargetFieldName( mTargetFieldComboBox->currentField() );
112115
info.setUsingMemoryCache( mCacheInMemoryCheckBox->isChecked() );
116+
info.setDynamicFormEnabled( mDynamicFormCheckBox->isChecked() );
113117

114118
if ( mUseCustomPrefix->isChecked() )
115119
info.setPrefix( mCustomPrefix->text() );

‎src/app/qgsvectorlayerproperties.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,16 +1235,21 @@ void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo
12351235
joinItem->setText( 3, QChar( 0x2714 ) );
12361236
}
12371237

1238-
joinItem->setText( 4, join.prefix() );
1238+
if ( join.isDynamicFormEnabled() )
1239+
{
1240+
joinItem->setText( 4, QChar( 0x2714 ) );
1241+
}
1242+
1243+
joinItem->setText( 5, join.prefix() );
12391244

12401245
const QStringList *list = join.joinFieldNamesSubset();
12411246
if ( list )
12421247
{
1243-
joinItem->setText( 5, QStringLiteral( "%1" ).arg( list->count() ) );
1248+
joinItem->setText( 6, QStringLiteral( "%1" ).arg( list->count() ) );
12441249
}
12451250
else
12461251
{
1247-
joinItem->setText( 5, tr( "all" ) );
1252+
joinItem->setText( 6, tr( "all" ) );
12481253
}
12491254

12501255
if ( insertIndex >= 0 )
@@ -1255,7 +1260,7 @@ void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo
12551260
{
12561261
mJoinTreeWidget->addTopLevelItem( joinItem );
12571262
}
1258-
for ( int c = 0; c < 5; c++ )
1263+
for ( int c = 0; c < 6; c++ )
12591264
{
12601265
mJoinTreeWidget->resizeColumnToContents( c );
12611266
}

‎src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ SET(QGIS_CORE_SRCS
286286
qgsvectorlayerfeatureiterator.cpp
287287
qgsvectorlayerexporter.cpp
288288
qgsvectorlayerjoinbuffer.cpp
289+
qgsvectorlayerjoininfo.cpp
289290
qgsvectorlayerlabeling.cpp
290291
qgsvectorlayerlabelprovider.cpp
291292
qgsvectorlayerrenderer.cpp

‎src/core/qgsvectorlayerjoinbuffer.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ void QgsVectorLayerJoinBuffer::writeXml( QDomNode &layer_node, QDomDocument &doc
275275
joinElem.setAttribute( QStringLiteral( "joinFieldName" ), joinIt->joinFieldName() );
276276

277277
joinElem.setAttribute( QStringLiteral( "memoryCache" ), joinIt->isUsingMemoryCache() );
278+
joinElem.setAttribute( QStringLiteral( "dynamicForm" ), joinIt->isDynamicFormEnabled() );
278279

279280
if ( joinIt->joinFieldNamesSubset() )
280281
{
@@ -315,6 +316,7 @@ void QgsVectorLayerJoinBuffer::readXml( const QDomNode &layer_node )
315316
info.setJoinLayerId( infoElem.attribute( QStringLiteral( "joinLayerId" ) ) );
316317
info.setTargetFieldName( infoElem.attribute( QStringLiteral( "targetFieldName" ) ) );
317318
info.setUsingMemoryCache( infoElem.attribute( QStringLiteral( "memoryCache" ) ).toInt() );
319+
info.setDynamicFormEnabled( infoElem.attribute( QStringLiteral( "dynamicForm" ) ).toInt() );
318320

319321
QDomElement subsetElem = infoElem.firstChildElement( QStringLiteral( "joinFieldsSubset" ) );
320322
if ( !subsetElem.isNull() )
@@ -392,6 +394,44 @@ const QgsVectorLayerJoinInfo *QgsVectorLayerJoinBuffer::joinForFieldIndex( int i
392394
return &( mVectorJoins[sourceJoinIndex] );
393395
}
394396

397+
QList<const QgsVectorLayerJoinInfo *> QgsVectorLayerJoinBuffer::joinsWhereFieldIsId( const QgsField &field ) const
398+
{
399+
QList<const QgsVectorLayerJoinInfo *> infos;
400+
401+
Q_FOREACH ( const QgsVectorLayerJoinInfo &info, mVectorJoins )
402+
{
403+
if ( infos.contains( &info ) )
404+
continue;
405+
406+
if ( info.targetFieldName() == field.name() )
407+
infos.append( &info );
408+
}
409+
410+
return infos;
411+
}
412+
413+
QgsFeature QgsVectorLayerJoinBuffer::joinedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const
414+
{
415+
QgsFeature joinedFeature;
416+
417+
if ( info->joinLayer() )
418+
{
419+
const QVariant targetValue = feature.attribute( info->targetFieldName() );
420+
QString fieldRef = QgsExpression::quotedColumnRef( info->joinFieldName() );
421+
QString quotedVal = QgsExpression::quotedValue( targetValue.toString() );
422+
const QString filter = QStringLiteral( "%1 = %2" ).arg( fieldRef, quotedVal );
423+
424+
QgsFeatureRequest request;
425+
request.setFilterExpression( filter );
426+
request.setLimit( 1 );
427+
428+
QgsFeatureIterator it = info->joinLayer()->getFeatures( request );
429+
it.nextFeature( joinedFeature );
430+
}
431+
432+
return joinedFeature;
433+
}
434+
395435
QgsVectorLayerJoinBuffer *QgsVectorLayerJoinBuffer::clone() const
396436
{
397437
QgsVectorLayerJoinBuffer *cloned = new QgsVectorLayerJoinBuffer( mLayer );

‎src/core/qgsvectorlayerjoinbuffer.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject
8484
//! \since QGIS 2.6
8585
static QVector<int> joinSubsetIndices( QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset );
8686

87+
/** Returns joins where the field of a target layer is considered as an id.
88+
* \param field the field of a target layer
89+
* \returns a list of vector joins
90+
* \since QGIS3.0
91+
*/
92+
QList<const QgsVectorLayerJoinInfo *> joinsWhereFieldIsId( const QgsField &field ) const;
93+
94+
/** Returns the joined feature corresponding to the feature.
95+
* \param info the vector join information
96+
* \param feature the feature of the target layer
97+
* \since QGIS 3.0
98+
*/
99+
QgsFeature joinedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const;
100+
87101
//! Create a copy of the join buffer
88102
//! \since QGIS 2.6
89103
QgsVectorLayerJoinBuffer *clone() const SIP_FACTORY;

‎src/core/qgsvectorlayerjoininfo.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/***************************************************************************
2+
qgsvectorlayerjoininfo.cpp
3+
--------------------------
4+
begin : Jun 29, 2017
5+
copyright : (C) 2017 by Paul Blottiere
6+
email : paul.blottiere@oslandia.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsvectorlayerjoininfo.h"
19+
20+
QString QgsVectorLayerJoinInfo::prefixedFieldName( const QgsField &f ) const
21+
{
22+
QString name;
23+
24+
if ( joinLayer() )
25+
{
26+
if ( prefix().isNull() )
27+
name = joinLayer()->name() + '_';
28+
else
29+
name = prefix();
30+
31+
name += f.name();
32+
}
33+
34+
return name;
35+
}

‎src/core/qgsvectorlayerjoininfo.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,25 @@ class CORE_EXPORT QgsVectorLayerJoinInfo
6868
//! Returns whether values from the joined layer should be cached in memory to speed up lookups
6969
bool isUsingMemoryCache() const { return mMemoryCache; }
7070

71+
/** Returns whether the form has to be dynamically updated with joined fields
72+
* when a feature is being created in the target layer.
73+
* \since QGIS 3.0
74+
*/
75+
bool isDynamicFormEnabled() const { return mDynamicForm; }
76+
77+
/** Sets whether the form has to be dynamically updated with joined fields
78+
* when a feature is being created in the target layer.
79+
* \since QGIS 3.0
80+
*/
81+
void setDynamicFormEnabled( bool enabled ) { mDynamicForm = enabled; }
82+
83+
/** Returns the prefixed name of the field.
84+
* \param field the field
85+
* \returns the prefixed name of the field
86+
* \since QGIS 3.0
87+
*/
88+
QString prefixedFieldName( const QgsField &field ) const;
89+
7190
bool operator==( const QgsVectorLayerJoinInfo &other ) const
7291
{
7392
return mTargetFieldName == other.mTargetFieldName &&
@@ -113,6 +132,8 @@ class CORE_EXPORT QgsVectorLayerJoinInfo
113132
//! True if the cached join attributes need to be updated
114133
bool cacheDirty;
115134

135+
bool mDynamicForm;
136+
116137
//! Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)
117138
QHash< QString, QgsAttributes> cachedAttributes;
118139

‎src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,8 @@ bool QgsEditorWidgetWrapper::isInTable( const QWidget *parent )
211211
if ( qobject_cast<const QTableView *>( parent ) ) return true;
212212
return isInTable( parent->parentWidget() );
213213
}
214+
215+
void QgsEditorWidgetWrapper::setHint( const QString &hintText )
216+
{
217+
widget()->setToolTip( hintText );
218+
}

‎src/gui/editorwidgets/core/qgseditorwidgetwrapper.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ class GUI_EXPORT QgsEditorWidgetWrapper : public QgsWidgetWrapper
164164
*/
165165
QString constraintFailureReason() const;
166166

167+
/**
168+
* Add a hint text on the widget
169+
* \param hintText The hint text to display
170+
* \since QGIS 3.0
171+
*/
172+
virtual void setHint( const QString &hintText );
173+
167174
signals:
168175

169176
/**

‎src/gui/editorwidgets/qgstexteditwrapper.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,16 @@ void QgsTextEditWrapper::setWidgetValue( const QVariant &val )
240240
if ( mLineEdit )
241241
mLineEdit->setText( v );
242242
}
243+
244+
void QgsTextEditWrapper::setHint( const QString &hintText )
245+
{
246+
if ( hintText.isNull() )
247+
mPlaceholderText = mPlaceholderTextBackup;
248+
else
249+
{
250+
mPlaceholderTextBackup = mPlaceholderText;
251+
mPlaceholderText = hintText;
252+
}
253+
254+
mLineEdit->setPlaceholderText( mPlaceholderText );
255+
}

‎src/gui/editorwidgets/qgstexteditwrapper.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ class GUI_EXPORT QgsTextEditWrapper : public QgsEditorWidgetWrapper
4747
QVariant value() const override;
4848
void showIndeterminateState() override;
4949

50+
/**
51+
* Add a hint text on the widget
52+
* \param hintText The hint text to display
53+
* \since QGIS 3.0
54+
*/
55+
void setHint( const QString &hintText ) override;
56+
5057
protected:
5158
QWidget *createWidget( QWidget *parent ) override;
5259
void initWidget( QWidget *editor ) override;
@@ -66,6 +73,7 @@ class GUI_EXPORT QgsTextEditWrapper : public QgsEditorWidgetWrapper
6673
QPalette mReadOnlyPalette;
6774
QPalette mWritablePalette;
6875
QString mPlaceholderText;
76+
QString mPlaceholderTextBackup;
6977

7078
void setWidgetValue( const QVariant &value );
7179
};

0 commit comments

Comments
 (0)
Please sign in to comment.