Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #4795 from pblottiere/dynamicform
[FEATURE] Dynamic form for joined fields
  • Loading branch information
m-kuhn committed Jul 7, 2017
2 parents 0036f27 + df5551a commit 632eca6
Show file tree
Hide file tree
Showing 20 changed files with 438 additions and 26 deletions.
18 changes: 18 additions & 0 deletions python/core/qgsvectorlayerjoinbuffer.sip
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions python/core/qgsvectorlayerjoininfo.sip
Expand Up @@ -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/ );
Expand All @@ -108,6 +132,7 @@ Returns whether values from the joined layer should be cached in memory to speed




};


Expand Down
7 changes: 7 additions & 0 deletions python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip
Expand Up @@ -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 );
Expand Down
2 changes: 1 addition & 1 deletion python/gui/qgsattributeform.sip
Expand Up @@ -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.

Expand Down
4 changes: 4 additions & 0 deletions src/app/qgsjoindialog.cpp
Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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() );
Expand Down
13 changes: 9 additions & 4 deletions src/app/qgsvectorlayerproperties.cpp
Expand Up @@ -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 )
Expand All @@ -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 );
}
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -286,6 +286,7 @@ SET(QGIS_CORE_SRCS
qgsvectorlayerfeatureiterator.cpp
qgsvectorlayerexporter.cpp
qgsvectorlayerjoinbuffer.cpp
qgsvectorlayerjoininfo.cpp
qgsvectorlayerlabeling.cpp
qgsvectorlayerlabelprovider.cpp
qgsvectorlayerrenderer.cpp
Expand Down
40 changes: 40 additions & 0 deletions src/core/qgsvectorlayerjoinbuffer.cpp
Expand Up @@ -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() )
{
Expand Down Expand Up @@ -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() )
Expand Down Expand Up @@ -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 );
Expand Down
14 changes: 14 additions & 0 deletions src/core/qgsvectorlayerjoinbuffer.h
Expand Up @@ -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;
Expand Down
35 changes: 35 additions & 0 deletions src/core/qgsvectorlayerjoininfo.cpp
@@ -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;
}
21 changes: 21 additions & 0 deletions src/core/qgsvectorlayerjoininfo.h
Expand Up @@ -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 &&
Expand Down Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp
Expand Up @@ -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 );
}
7 changes: 7 additions & 0 deletions src/gui/editorwidgets/core/qgseditorwidgetwrapper.h
Expand Up @@ -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:

/**
Expand Down
13 changes: 13 additions & 0 deletions src/gui/editorwidgets/qgstexteditwrapper.cpp
Expand Up @@ -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 );
}
8 changes: 8 additions & 0 deletions src/gui/editorwidgets/qgstexteditwrapper.h
Expand Up @@ -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;
Expand All @@ -66,6 +73,7 @@ class GUI_EXPORT QgsTextEditWrapper : public QgsEditorWidgetWrapper
QPalette mReadOnlyPalette;
QPalette mWritablePalette;
QString mPlaceholderText;
QString mPlaceholderTextBackup;

void setWidgetValue( const QVariant &value );
};
Expand Down

0 comments on commit 632eca6

Please sign in to comment.