mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #4795 from pblottiere/dynamicform
[FEATURE] Dynamic form for joined fields
This commit is contained in:
commit
632eca6079
@ -99,6 +99,24 @@ Quick way to test if there is any join at all
|
||||
:rtype: list of int
|
||||
%End
|
||||
|
||||
QList<const QgsVectorLayerJoinInfo *> joinsWhereFieldIsId( const QgsField &field ) const;
|
||||
%Docstring
|
||||
Returns joins where the field of a target layer is considered as an id.
|
||||
\param field the field of a target layer
|
||||
:return: a list of vector joins
|
||||
.. versionadded:: 3.0
|
||||
:rtype: list of const QgsVectorLayerJoinInfo
|
||||
%End
|
||||
|
||||
QgsFeature joinedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const;
|
||||
%Docstring
|
||||
Returns the joined feature corresponding to the feature.
|
||||
\param info the vector join information
|
||||
\param feature the feature of the target layer
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsFeature
|
||||
%End
|
||||
|
||||
QgsVectorLayerJoinBuffer *clone() const /Factory/;
|
||||
%Docstring
|
||||
.. versionadded:: 2.6
|
||||
|
@ -84,6 +84,30 @@ Returns whether values from the joined layer should be cached in memory to speed
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
bool isDynamicFormEnabled() const;
|
||||
%Docstring
|
||||
Returns whether the form has to be dynamically updated with joined fields
|
||||
when a feature is being created in the target layer.
|
||||
.. versionadded:: 3.0
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void setDynamicFormEnabled( bool enabled );
|
||||
%Docstring
|
||||
Sets whether the form has to be dynamically updated with joined fields
|
||||
when a feature is being created in the target layer.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QString prefixedFieldName( const QgsField &field ) const;
|
||||
%Docstring
|
||||
Returns the prefixed name of the field.
|
||||
\param field the field
|
||||
:return: the prefixed name of the field
|
||||
.. versionadded:: 3.0
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
bool operator==( const QgsVectorLayerJoinInfo &other ) const;
|
||||
|
||||
void setJoinFieldNamesSubset( QStringList *fieldNamesSubset /Transfer/ );
|
||||
@ -108,6 +132,7 @@ Returns whether values from the joined layer should be cached in memory to speed
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -156,6 +156,13 @@ class QgsEditorWidgetWrapper : QgsWidgetWrapper
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
virtual void setHint( const QString &hintText );
|
||||
%Docstring
|
||||
Add a hint text on the widget
|
||||
\param hintText The hint text to display
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
signals:
|
||||
|
||||
void valueChanged( const QVariant &value );
|
||||
|
@ -167,7 +167,7 @@ class QgsAttributeForm : QWidget
|
||||
|
||||
public slots:
|
||||
|
||||
void changeAttribute( const QString &field, const QVariant &value );
|
||||
void changeAttribute( const QString &field, const QVariant &value, const QString &hintText = QString() );
|
||||
%Docstring
|
||||
Call this to change the content of a given attribute. Will update the editor(s) related to this field.
|
||||
|
||||
|
@ -42,6 +42,8 @@ QgsJoinDialog::QgsJoinDialog( QgsVectorLayer *layer, QList<QgsMapLayer *> alread
|
||||
|
||||
mTargetFieldComboBox->setLayer( mLayer );
|
||||
|
||||
mDynamicFormCheckBox->setToolTip( tr( "This option allows values of the joined fields to be automatically reloaded when the \"Target Field\" is changed" ) );
|
||||
|
||||
mJoinLayerComboBox->setFilters( QgsMapLayerProxyModel::VectorLayer );
|
||||
mJoinLayerComboBox->setExceptedLayerList( alreadyJoinedLayers );
|
||||
connect( mJoinLayerComboBox, &QgsMapLayerComboBox::layerChanged, mJoinFieldComboBox, &QgsFieldComboBox::setLayer );
|
||||
@ -73,6 +75,7 @@ void QgsJoinDialog::setJoinInfo( const QgsVectorLayerJoinInfo &joinInfo )
|
||||
mJoinFieldComboBox->setField( joinInfo.joinFieldName() );
|
||||
mTargetFieldComboBox->setField( joinInfo.targetFieldName() );
|
||||
mCacheInMemoryCheckBox->setChecked( joinInfo.isUsingMemoryCache() );
|
||||
mDynamicFormCheckBox->setChecked( joinInfo.isDynamicFormEnabled() );
|
||||
if ( joinInfo.prefix().isNull() )
|
||||
{
|
||||
mUseCustomPrefix->setChecked( false );
|
||||
@ -110,6 +113,7 @@ QgsVectorLayerJoinInfo QgsJoinDialog::joinInfo() const
|
||||
info.setJoinFieldName( mJoinFieldComboBox->currentField() );
|
||||
info.setTargetFieldName( mTargetFieldComboBox->currentField() );
|
||||
info.setUsingMemoryCache( mCacheInMemoryCheckBox->isChecked() );
|
||||
info.setDynamicFormEnabled( mDynamicFormCheckBox->isChecked() );
|
||||
|
||||
if ( mUseCustomPrefix->isChecked() )
|
||||
info.setPrefix( mCustomPrefix->text() );
|
||||
|
@ -1235,16 +1235,21 @@ void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo
|
||||
joinItem->setText( 3, QChar( 0x2714 ) );
|
||||
}
|
||||
|
||||
joinItem->setText( 4, join.prefix() );
|
||||
if ( join.isDynamicFormEnabled() )
|
||||
{
|
||||
joinItem->setText( 4, QChar( 0x2714 ) );
|
||||
}
|
||||
|
||||
joinItem->setText( 5, join.prefix() );
|
||||
|
||||
const QStringList *list = join.joinFieldNamesSubset();
|
||||
if ( list )
|
||||
{
|
||||
joinItem->setText( 5, QStringLiteral( "%1" ).arg( list->count() ) );
|
||||
joinItem->setText( 6, QStringLiteral( "%1" ).arg( list->count() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
joinItem->setText( 5, tr( "all" ) );
|
||||
joinItem->setText( 6, tr( "all" ) );
|
||||
}
|
||||
|
||||
if ( insertIndex >= 0 )
|
||||
@ -1255,7 +1260,7 @@ void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo
|
||||
{
|
||||
mJoinTreeWidget->addTopLevelItem( joinItem );
|
||||
}
|
||||
for ( int c = 0; c < 5; c++ )
|
||||
for ( int c = 0; c < 6; c++ )
|
||||
{
|
||||
mJoinTreeWidget->resizeColumnToContents( c );
|
||||
}
|
||||
|
@ -286,6 +286,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsvectorlayerfeatureiterator.cpp
|
||||
qgsvectorlayerexporter.cpp
|
||||
qgsvectorlayerjoinbuffer.cpp
|
||||
qgsvectorlayerjoininfo.cpp
|
||||
qgsvectorlayerlabeling.cpp
|
||||
qgsvectorlayerlabelprovider.cpp
|
||||
qgsvectorlayerrenderer.cpp
|
||||
|
@ -275,6 +275,7 @@ void QgsVectorLayerJoinBuffer::writeXml( QDomNode &layer_node, QDomDocument &doc
|
||||
joinElem.setAttribute( QStringLiteral( "joinFieldName" ), joinIt->joinFieldName() );
|
||||
|
||||
joinElem.setAttribute( QStringLiteral( "memoryCache" ), joinIt->isUsingMemoryCache() );
|
||||
joinElem.setAttribute( QStringLiteral( "dynamicForm" ), joinIt->isDynamicFormEnabled() );
|
||||
|
||||
if ( joinIt->joinFieldNamesSubset() )
|
||||
{
|
||||
@ -315,6 +316,7 @@ void QgsVectorLayerJoinBuffer::readXml( const QDomNode &layer_node )
|
||||
info.setJoinLayerId( infoElem.attribute( QStringLiteral( "joinLayerId" ) ) );
|
||||
info.setTargetFieldName( infoElem.attribute( QStringLiteral( "targetFieldName" ) ) );
|
||||
info.setUsingMemoryCache( infoElem.attribute( QStringLiteral( "memoryCache" ) ).toInt() );
|
||||
info.setDynamicFormEnabled( infoElem.attribute( QStringLiteral( "dynamicForm" ) ).toInt() );
|
||||
|
||||
QDomElement subsetElem = infoElem.firstChildElement( QStringLiteral( "joinFieldsSubset" ) );
|
||||
if ( !subsetElem.isNull() )
|
||||
@ -392,6 +394,44 @@ const QgsVectorLayerJoinInfo *QgsVectorLayerJoinBuffer::joinForFieldIndex( int i
|
||||
return &( mVectorJoins[sourceJoinIndex] );
|
||||
}
|
||||
|
||||
QList<const QgsVectorLayerJoinInfo *> QgsVectorLayerJoinBuffer::joinsWhereFieldIsId( const QgsField &field ) const
|
||||
{
|
||||
QList<const QgsVectorLayerJoinInfo *> infos;
|
||||
|
||||
Q_FOREACH ( const QgsVectorLayerJoinInfo &info, mVectorJoins )
|
||||
{
|
||||
if ( infos.contains( &info ) )
|
||||
continue;
|
||||
|
||||
if ( info.targetFieldName() == field.name() )
|
||||
infos.append( &info );
|
||||
}
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
QgsFeature QgsVectorLayerJoinBuffer::joinedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const
|
||||
{
|
||||
QgsFeature joinedFeature;
|
||||
|
||||
if ( info->joinLayer() )
|
||||
{
|
||||
const QVariant targetValue = feature.attribute( info->targetFieldName() );
|
||||
QString fieldRef = QgsExpression::quotedColumnRef( info->joinFieldName() );
|
||||
QString quotedVal = QgsExpression::quotedValue( targetValue.toString() );
|
||||
const QString filter = QStringLiteral( "%1 = %2" ).arg( fieldRef, quotedVal );
|
||||
|
||||
QgsFeatureRequest request;
|
||||
request.setFilterExpression( filter );
|
||||
request.setLimit( 1 );
|
||||
|
||||
QgsFeatureIterator it = info->joinLayer()->getFeatures( request );
|
||||
it.nextFeature( joinedFeature );
|
||||
}
|
||||
|
||||
return joinedFeature;
|
||||
}
|
||||
|
||||
QgsVectorLayerJoinBuffer *QgsVectorLayerJoinBuffer::clone() const
|
||||
{
|
||||
QgsVectorLayerJoinBuffer *cloned = new QgsVectorLayerJoinBuffer( mLayer );
|
||||
|
@ -84,6 +84,20 @@ class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject
|
||||
//! \since QGIS 2.6
|
||||
static QVector<int> joinSubsetIndices( QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset );
|
||||
|
||||
/** Returns joins where the field of a target layer is considered as an id.
|
||||
* \param field the field of a target layer
|
||||
* \returns a list of vector joins
|
||||
* \since QGIS3.0
|
||||
*/
|
||||
QList<const QgsVectorLayerJoinInfo *> joinsWhereFieldIsId( const QgsField &field ) const;
|
||||
|
||||
/** Returns the joined feature corresponding to the feature.
|
||||
* \param info the vector join information
|
||||
* \param feature the feature of the target layer
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsFeature joinedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const;
|
||||
|
||||
//! Create a copy of the join buffer
|
||||
//! \since QGIS 2.6
|
||||
QgsVectorLayerJoinBuffer *clone() const SIP_FACTORY;
|
||||
|
35
src/core/qgsvectorlayerjoininfo.cpp
Normal file
35
src/core/qgsvectorlayerjoininfo.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/***************************************************************************
|
||||
qgsvectorlayerjoininfo.cpp
|
||||
--------------------------
|
||||
begin : Jun 29, 2017
|
||||
copyright : (C) 2017 by Paul Blottiere
|
||||
email : paul.blottiere@oslandia.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsvectorlayerjoininfo.h"
|
||||
|
||||
QString QgsVectorLayerJoinInfo::prefixedFieldName( const QgsField &f ) const
|
||||
{
|
||||
QString name;
|
||||
|
||||
if ( joinLayer() )
|
||||
{
|
||||
if ( prefix().isNull() )
|
||||
name = joinLayer()->name() + '_';
|
||||
else
|
||||
name = prefix();
|
||||
|
||||
name += f.name();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
@ -68,6 +68,25 @@ class CORE_EXPORT QgsVectorLayerJoinInfo
|
||||
//! Returns whether values from the joined layer should be cached in memory to speed up lookups
|
||||
bool isUsingMemoryCache() const { return mMemoryCache; }
|
||||
|
||||
/** Returns whether the form has to be dynamically updated with joined fields
|
||||
* when a feature is being created in the target layer.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
bool isDynamicFormEnabled() const { return mDynamicForm; }
|
||||
|
||||
/** Sets whether the form has to be dynamically updated with joined fields
|
||||
* when a feature is being created in the target layer.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
void setDynamicFormEnabled( bool enabled ) { mDynamicForm = enabled; }
|
||||
|
||||
/** Returns the prefixed name of the field.
|
||||
* \param field the field
|
||||
* \returns the prefixed name of the field
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QString prefixedFieldName( const QgsField &field ) const;
|
||||
|
||||
bool operator==( const QgsVectorLayerJoinInfo &other ) const
|
||||
{
|
||||
return mTargetFieldName == other.mTargetFieldName &&
|
||||
@ -113,6 +132,8 @@ class CORE_EXPORT QgsVectorLayerJoinInfo
|
||||
//! True if the cached join attributes need to be updated
|
||||
bool cacheDirty;
|
||||
|
||||
bool mDynamicForm;
|
||||
|
||||
//! Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)
|
||||
QHash< QString, QgsAttributes> cachedAttributes;
|
||||
|
||||
|
@ -211,3 +211,8 @@ bool QgsEditorWidgetWrapper::isInTable( const QWidget *parent )
|
||||
if ( qobject_cast<const QTableView *>( parent ) ) return true;
|
||||
return isInTable( parent->parentWidget() );
|
||||
}
|
||||
|
||||
void QgsEditorWidgetWrapper::setHint( const QString &hintText )
|
||||
{
|
||||
widget()->setToolTip( hintText );
|
||||
}
|
||||
|
@ -164,6 +164,13 @@ class GUI_EXPORT QgsEditorWidgetWrapper : public QgsWidgetWrapper
|
||||
*/
|
||||
QString constraintFailureReason() const;
|
||||
|
||||
/**
|
||||
* Add a hint text on the widget
|
||||
* \param hintText The hint text to display
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual void setHint( const QString &hintText );
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
|
@ -240,3 +240,16 @@ void QgsTextEditWrapper::setWidgetValue( const QVariant &val )
|
||||
if ( mLineEdit )
|
||||
mLineEdit->setText( v );
|
||||
}
|
||||
|
||||
void QgsTextEditWrapper::setHint( const QString &hintText )
|
||||
{
|
||||
if ( hintText.isNull() )
|
||||
mPlaceholderText = mPlaceholderTextBackup;
|
||||
else
|
||||
{
|
||||
mPlaceholderTextBackup = mPlaceholderText;
|
||||
mPlaceholderText = hintText;
|
||||
}
|
||||
|
||||
mLineEdit->setPlaceholderText( mPlaceholderText );
|
||||
}
|
||||
|
@ -47,6 +47,13 @@ class GUI_EXPORT QgsTextEditWrapper : public QgsEditorWidgetWrapper
|
||||
QVariant value() const override;
|
||||
void showIndeterminateState() override;
|
||||
|
||||
/**
|
||||
* Add a hint text on the widget
|
||||
* \param hintText The hint text to display
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
void setHint( const QString &hintText ) override;
|
||||
|
||||
protected:
|
||||
QWidget *createWidget( QWidget *parent ) override;
|
||||
void initWidget( QWidget *editor ) override;
|
||||
@ -66,6 +73,7 @@ class GUI_EXPORT QgsTextEditWrapper : public QgsEditorWidgetWrapper
|
||||
QPalette mReadOnlyPalette;
|
||||
QPalette mWritablePalette;
|
||||
QString mPlaceholderText;
|
||||
QString mPlaceholderTextBackup;
|
||||
|
||||
void setWidgetValue( const QVariant &value );
|
||||
};
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include "qgssettings.h"
|
||||
#include "qgsscrollarea.h"
|
||||
#include "qgsgui.h"
|
||||
#include "qgsvectorlayerjoinbuffer.h"
|
||||
#include "qgsvectorlayerutils.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QTextStream>
|
||||
@ -221,7 +223,7 @@ void QgsAttributeForm::setMode( QgsAttributeForm::Mode mode )
|
||||
emit modeChanged( mMode );
|
||||
}
|
||||
|
||||
void QgsAttributeForm::changeAttribute( const QString &field, const QVariant &value )
|
||||
void QgsAttributeForm::changeAttribute( const QString &field, const QVariant &value, const QString &hintText )
|
||||
{
|
||||
Q_FOREACH ( QgsWidgetWrapper *ww, mWidgets )
|
||||
{
|
||||
@ -229,6 +231,7 @@ void QgsAttributeForm::changeAttribute( const QString &field, const QVariant &va
|
||||
if ( eww && eww->field().name() == field )
|
||||
{
|
||||
eww->setValue( value );
|
||||
eww->setHint( hintText );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -659,6 +662,9 @@ void QgsAttributeForm::onAttributeChanged( const QVariant &value )
|
||||
{
|
||||
emit attributeChanged( eww->field().name(), value );
|
||||
}
|
||||
|
||||
updateJoinedFields( *eww );
|
||||
|
||||
break;
|
||||
}
|
||||
case MultiEditMode:
|
||||
@ -1930,3 +1936,58 @@ void QgsAttributeForm::ContainerInformation::apply( QgsExpressionContext *expres
|
||||
isVisible = newVisibility;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeForm::updateJoinedFields( const QgsEditorWidgetWrapper &eww )
|
||||
{
|
||||
QgsFeature formFeature;
|
||||
QgsField field = eww.layer()->fields().field( eww.fieldIdx() );
|
||||
QList<const QgsVectorLayerJoinInfo *> infos = eww.layer()->joinBuffer()->joinsWhereFieldIsId( field );
|
||||
|
||||
if ( infos.count() == 0 || !currentFormFeature( formFeature ) )
|
||||
return;
|
||||
|
||||
const QString hint = tr( "No feature joined" );
|
||||
Q_FOREACH ( const QgsVectorLayerJoinInfo *info, infos )
|
||||
{
|
||||
if ( !info->isDynamicFormEnabled() )
|
||||
continue;
|
||||
|
||||
QgsFeature joinFeature = mLayer->joinBuffer()->joinedFeatureOf( info, formFeature );
|
||||
|
||||
QStringList *subsetFields = info->joinFieldNamesSubset();
|
||||
if ( subsetFields )
|
||||
{
|
||||
Q_FOREACH ( const QString &field, *subsetFields )
|
||||
{
|
||||
QString prefixedName = info->prefixedFieldName( field );
|
||||
QVariant val;
|
||||
QString hintText = hint;
|
||||
|
||||
if ( joinFeature.isValid() )
|
||||
{
|
||||
val = joinFeature.attribute( field );
|
||||
hintText.clear();
|
||||
}
|
||||
|
||||
changeAttribute( prefixedName, val, hintText );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_FOREACH ( const QgsField &field, joinFeature.fields() )
|
||||
{
|
||||
QString prefixedName = info->prefixedFieldName( field );
|
||||
QVariant val;
|
||||
QString hintText = hint;
|
||||
|
||||
if ( joinFeature.isValid() )
|
||||
{
|
||||
val = joinFeature.attribute( field.name() );
|
||||
hintText.clear();
|
||||
}
|
||||
|
||||
changeAttribute( prefixedName, val, hintText );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
|
||||
* \param field The field to change
|
||||
* \param value The new value
|
||||
*/
|
||||
void changeAttribute( const QString &field, const QVariant &value );
|
||||
void changeAttribute( const QString &field, const QVariant &value, const QString &hintText = QString() );
|
||||
|
||||
/**
|
||||
* Update all editors to correspond to a different feature.
|
||||
@ -273,6 +273,8 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
|
||||
|
||||
void initPython();
|
||||
|
||||
void updateJoinedFields( const QgsEditorWidgetWrapper &eww );
|
||||
|
||||
struct WidgetInfo
|
||||
{
|
||||
WidgetInfo()
|
||||
|
@ -44,10 +44,10 @@
|
||||
<item row="2" column="1">
|
||||
<widget class="QgsFieldComboBox" name="mTargetFieldComboBox"/>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QgsCollapsibleGroupBox" name="mUseJoinFieldsSubset">
|
||||
<property name="title">
|
||||
<string>Choose which fields are joined</string>
|
||||
<string>Choose which fields are &joined</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@ -65,10 +65,10 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<item row="7" column="0" colspan="2">
|
||||
<widget class="QgsCollapsibleGroupBox" name="mUseCustomPrefix">
|
||||
<property name="title">
|
||||
<string>Custom field name prefix</string>
|
||||
<string>Custom field &name prefix</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@ -86,7 +86,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="8" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@ -116,7 +116,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<item row="9" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@ -126,6 +126,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="mDynamicFormCheckBox">
|
||||
<property name="text">
|
||||
<string>Dynamic form</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
@ -303,7 +303,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>9</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="mOptsPage_Information">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
@ -379,8 +379,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>639</width>
|
||||
<height>592</height>
|
||||
<width>653</width>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
@ -831,7 +831,7 @@ border-radius: 2px;</string>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>653</width>
|
||||
<height>536</height>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
@ -1069,7 +1069,7 @@ border-radius: 2px;</string>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>653</width>
|
||||
<height>536</height>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_18">
|
||||
@ -1170,7 +1170,7 @@ border-radius: 2px;</string>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>653</width>
|
||||
<height>536</height>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_20">
|
||||
@ -1229,8 +1229,8 @@ border-radius: 2px;</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>671</width>
|
||||
<height>522</height>
|
||||
<width>653</width>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_32">
|
||||
@ -1249,7 +1249,7 @@ border-radius: 2px;</string>
|
||||
<item>
|
||||
<widget class="QgsCollapsibleGroupBox" name="mScaleVisibilityGroupBox">
|
||||
<property name="title">
|
||||
<string>Scale dependent visibility</string>
|
||||
<string>Scale dependen&t visibility</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@ -1268,7 +1268,7 @@ border-radius: 2px;</string>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="mSimplifyDrawingGroupBox">
|
||||
<property name="title">
|
||||
<string>Simplify geometry</string>
|
||||
<string>Simplify &geometry</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@ -1590,7 +1590,7 @@ border-radius: 2px;</string>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>653</width>
|
||||
<height>536</height>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_21">
|
||||
@ -1656,7 +1656,7 @@ border-radius: 2px;</string>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>653</width>
|
||||
<height>536</height>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_23">
|
||||
@ -1675,7 +1675,7 @@ border-radius: 2px;</string>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="mJoinTreeWidget">
|
||||
<property name="columnCount">
|
||||
<number>6</number>
|
||||
<number>7</number>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
@ -1697,6 +1697,11 @@ border-radius: 2px;</string>
|
||||
<string>Memory cache</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Dynamic form</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Prefix</string>
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <qgsvectorlayer.h>
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include <qgsfeature.h>
|
||||
#include <qgsvectorlayerjoininfo.h>
|
||||
#include "qgsgui.h"
|
||||
|
||||
class TestQgsAttributeForm : public QObject
|
||||
@ -41,6 +42,7 @@ class TestQgsAttributeForm : public QObject
|
||||
void testFieldConstraint();
|
||||
void testFieldMultiConstraints();
|
||||
void testOKButtonStatus();
|
||||
void testDynamicForm();
|
||||
};
|
||||
|
||||
void TestQgsAttributeForm::initTestCase()
|
||||
@ -306,5 +308,137 @@ void TestQgsAttributeForm::testOKButtonStatus()
|
||||
QVERIFY( !okButton->isEnabled() );
|
||||
}
|
||||
|
||||
void TestQgsAttributeForm::testDynamicForm()
|
||||
{
|
||||
// make temporary layers
|
||||
QString defA = QStringLiteral( "Point?field=id_a:integer" );
|
||||
QgsVectorLayer *layerA = new QgsVectorLayer( defA, QStringLiteral( "layerA" ), QStringLiteral( "memory" ) );
|
||||
|
||||
QString defB = QStringLiteral( "Point?field=id_b:integer&field=col0:integer" );
|
||||
QgsVectorLayer *layerB = new QgsVectorLayer( defB, QStringLiteral( "layerB" ), QStringLiteral( "memory" ) );
|
||||
|
||||
QString defC = QStringLiteral( "Point?field=id_c:integer&field=col0:integer" );
|
||||
QgsVectorLayer *layerC = new QgsVectorLayer( defC, QStringLiteral( "layerC" ), QStringLiteral( "memory" ) );
|
||||
|
||||
// join configuration
|
||||
QgsVectorLayerJoinInfo infoJoinAB;
|
||||
infoJoinAB.setTargetFieldName( "id_a" );
|
||||
infoJoinAB.setJoinLayer( layerB );
|
||||
infoJoinAB.setJoinFieldName( "id_b" );
|
||||
infoJoinAB.setDynamicFormEnabled( true );
|
||||
|
||||
layerA->addJoin( infoJoinAB );
|
||||
|
||||
QgsVectorLayerJoinInfo infoJoinAC;
|
||||
infoJoinAC.setTargetFieldName( "id_a" );
|
||||
infoJoinAC.setJoinLayer( layerC );
|
||||
infoJoinAC.setJoinFieldName( "id_c" );
|
||||
infoJoinAC.setDynamicFormEnabled( true );
|
||||
|
||||
layerA->addJoin( infoJoinAC );
|
||||
|
||||
// add features for main layer
|
||||
QgsFeature ftA( layerA->fields() );
|
||||
ftA.setAttribute( QStringLiteral( "id_a" ), 0 );
|
||||
layerA->startEditing();
|
||||
layerA->addFeature( ftA );
|
||||
layerA->commitChanges();
|
||||
|
||||
// add features for joined layers
|
||||
QgsFeature ft0B( layerB->fields() );
|
||||
ft0B.setAttribute( QStringLiteral( "id_b" ), 30 );
|
||||
ft0B.setAttribute( QStringLiteral( "col0" ), 10 );
|
||||
layerB->startEditing();
|
||||
layerB->addFeature( ft0B );
|
||||
layerB->commitChanges();
|
||||
|
||||
QgsFeature ft1B( layerB->fields() );
|
||||
ft1B.setAttribute( QStringLiteral( "id_b" ), 31 );
|
||||
ft1B.setAttribute( QStringLiteral( "col0" ), 11 );
|
||||
layerB->startEditing();
|
||||
layerB->addFeature( ft1B );
|
||||
layerB->commitChanges();
|
||||
|
||||
QgsFeature ft0C( layerC->fields() );
|
||||
ft0C.setAttribute( QStringLiteral( "id_c" ), 32 );
|
||||
ft0C.setAttribute( QStringLiteral( "col0" ), 12 );
|
||||
layerC->startEditing();
|
||||
layerC->addFeature( ft0C );
|
||||
layerC->commitChanges();
|
||||
|
||||
QgsFeature ft1C( layerC->fields() );
|
||||
ft1C.setAttribute( QStringLiteral( "id_c" ), 31 );
|
||||
ft1C.setAttribute( QStringLiteral( "col0" ), 13 );
|
||||
layerC->startEditing();
|
||||
layerC->addFeature( ft1C );
|
||||
layerC->commitChanges();
|
||||
|
||||
// build a form with feature A
|
||||
QgsAttributeForm form( layerA );
|
||||
form.setMode( QgsAttributeForm::AddFeatureMode );
|
||||
form.setFeature( ftA );
|
||||
|
||||
// test that there's no joined feature by default
|
||||
QgsEditorWidgetWrapper *ww = nullptr;
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[1] );
|
||||
QCOMPARE( ww->field().name(), QString( "layerB_col0" ) );
|
||||
QCOMPARE( ww->value(), QVariant( QVariant::Int ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[2] );
|
||||
QCOMPARE( ww->field().name(), QString( "layerC_col0" ) );
|
||||
QCOMPARE( ww->value(), QVariant( QVariant::Int ) );
|
||||
|
||||
// change layerA join id field to join with layerB
|
||||
form.changeAttribute( "id_a", QVariant( 30 ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[0] );
|
||||
QCOMPARE( ww->field().name(), QString( "id_a" ) );
|
||||
QCOMPARE( ww->value(), QVariant( 30 ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[1] );
|
||||
QCOMPARE( ww->field().name(), QString( "layerB_col0" ) );
|
||||
QCOMPARE( ww->value(), QVariant( 10 ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[2] );
|
||||
QCOMPARE( ww->field().name(), QString( "layerC_col0" ) );
|
||||
QCOMPARE( ww->value(), QVariant( QVariant::Int ) );
|
||||
|
||||
// change layerA join id field to join with layerC
|
||||
form.changeAttribute( "id_a", QVariant( 32 ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[0] );
|
||||
QCOMPARE( ww->field().name(), QString( "id_a" ) );
|
||||
QCOMPARE( ww->value(), QVariant( 32 ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[1] );
|
||||
QCOMPARE( ww->field().name(), QString( "layerB_col0" ) );
|
||||
QCOMPARE( ww->value(), QVariant( QVariant::Int ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[2] );
|
||||
QCOMPARE( ww->field().name(), QString( "layerC_col0" ) );
|
||||
QCOMPARE( ww->value(), QVariant( 12 ) );
|
||||
|
||||
// change layerA join id field to join with layerA and layerC
|
||||
form.changeAttribute( "id_a", QVariant( 31 ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[0] );
|
||||
QCOMPARE( ww->field().name(), QString( "id_a" ) );
|
||||
QCOMPARE( ww->value(), QVariant( 31 ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[1] );
|
||||
QCOMPARE( ww->field().name(), QString( "layerB_col0" ) );
|
||||
QCOMPARE( ww->value(), QVariant( 11 ) );
|
||||
|
||||
ww = qobject_cast<QgsEditorWidgetWrapper *>( form.mWidgets[2] );
|
||||
QCOMPARE( ww->field().name(), QString( "layerC_col0" ) );
|
||||
QCOMPARE( ww->value(), QVariant( 13 ) );
|
||||
|
||||
// clean
|
||||
delete layerA;
|
||||
delete layerB;
|
||||
delete layerC;
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsAttributeForm )
|
||||
#include "testqgsattributeform.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user