Navigation Menu

Skip to content

Commit

Permalink
allow to manually add relations with composite keys
Browse files Browse the repository at this point in the history
  • Loading branch information
3nids committed Aug 9, 2019
1 parent 4a1c42d commit 1b563c0
Show file tree
Hide file tree
Showing 3 changed files with 277 additions and 188 deletions.
243 changes: 212 additions & 31 deletions src/app/qgsrelationadddlg.cpp
Expand Up @@ -14,79 +14,260 @@
* *
***************************************************************************/

#include <QDialogButtonBox>
#include <QLabel>
#include <QToolButton>
#include <QPushButton>
#include <QComboBox>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>

#include "qgsrelationadddlg.h"
#include "qgsvectorlayer.h"
#include "qgsmaplayercombobox.h"
#include "qgsfieldcombobox.h"
#include "qgsmaplayerproxymodel.h"
#include "qgsapplication.h"

#include <QPushButton>


QgsFieldPairWidget::QgsFieldPairWidget( int index, QWidget *parent )
: QWidget( parent )
, mIndex( index )
, mEnabled( index == 0 )
{
mLayout = new QHBoxLayout();
mLayout->setMargin( 0 );

mAddButton = new QToolButton( this );
mAddButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
mAddButton->setMinimumWidth( 30 );
mLayout->addWidget( mAddButton, 0, Qt::AlignLeft );

mRemoveButton = new QToolButton( this );
mRemoveButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyRemove.svg" ) ) );
mRemoveButton->setMinimumWidth( 30 );
mLayout->addWidget( mRemoveButton, 0, Qt::AlignLeft );

mSpacerItem = new QSpacerItem( 30, 30, QSizePolicy::Minimum, QSizePolicy::Maximum );
mLayout->addSpacerItem( mSpacerItem );

mReferencedFieldCombobox = new QgsFieldComboBox( this );
connect( mReferencedFieldCombobox, &QgsFieldComboBox::fieldChanged, this, &QgsFieldPairWidget::configChanged );
mLayout->addWidget( mReferencedFieldCombobox, 1 );

mReferencingFieldCombobox = new QgsFieldComboBox( this );
connect( mReferencingFieldCombobox, &QgsFieldComboBox::fieldChanged, this, &QgsFieldPairWidget::configChanged );
mLayout->addWidget( mReferencingFieldCombobox, 1 );

setLayout( mLayout );
updateWidgetVisibility();

connect( mAddButton, &QToolButton::clicked, this, &QgsFieldPairWidget::changeEnable );
connect( mRemoveButton, &QToolButton::clicked, this, &QgsFieldPairWidget::changeEnable );
connect( mAddButton, &QToolButton::clicked, this, &QgsFieldPairWidget::pairEnabled );
connect( mRemoveButton, &QToolButton::clicked, this, &QgsFieldPairWidget::pairDisabled );
}

void QgsFieldPairWidget::setReferencingLayer( QgsMapLayer *layer )
{
mReferencingFieldCombobox->setLayer( layer );
}

void QgsFieldPairWidget::setReferencedLayer( QgsMapLayer *layer )
{
mReferencedFieldCombobox->setLayer( layer );
}

QString QgsFieldPairWidget::referencingField() const
{
return mReferencingFieldCombobox->currentField();
}

QString QgsFieldPairWidget::referencedField() const
{
return mReferencedFieldCombobox->currentField();
}

bool QgsFieldPairWidget::isPairEnabled() const
{
return mEnabled;
}

void QgsFieldPairWidget::updateWidgetVisibility()
{
mAddButton->setVisible( !mEnabled );
mRemoveButton->setVisible( mIndex > 0 && mEnabled );
mReferencingFieldCombobox->setVisible( mEnabled );
mReferencedFieldCombobox->setVisible( mEnabled );
int spacerSize = 0;
if ( !mRemoveButton->isVisible() && !mAddButton->isVisible() )
spacerSize = mRemoveButton->minimumWidth() + mLayout->spacing();
mSpacerItem->changeSize( spacerSize, spacerSize );
}

void QgsFieldPairWidget::changeEnable()
{
mEnabled = !mEnabled || ( mIndex == 0 );
updateWidgetVisibility();
emit configChanged();
}

////////////////////
// QgsRelationAddDlg

QgsRelationAddDlg::QgsRelationAddDlg( QWidget *parent )
: QDialog( parent )
{
setupUi( this );
QGridLayout *layout = new QGridLayout(); // column 0 is kept free for alignmenent purpose

// row 0: name
// col 1
QLabel *nameLabel = new QLabel( tr( "Name" ), this );
layout->addWidget( nameLabel, 0, 1 );
// col 2
mNameLineEdit = new QLineEdit( this );
layout->addWidget( mNameLineEdit, 0, 2 );

// row 1: labels
// col 1
QLabel *referencedLabel = new QLabel( tr( "Referenced layer (parent)" ), this );
layout->addWidget( referencedLabel, 1, 1 );
// col 2
QLabel *referencingLabel = new QLabel( tr( "Referencing layer (parent)" ), this );
layout->addWidget( referencingLabel, 1, 2 );

// row 2: layer comboboxes
// col 1
mReferencedLayerCombobox = new QgsMapLayerComboBox( this );
mReferencedLayerCombobox->setFilters( QgsMapLayerProxyModel::VectorLayer );
layout->addWidget( mReferencedLayerCombobox, 2, 1 );
// col 2
mReferencingLayerCombobox = new QgsMapLayerComboBox( this );
mReferencingLayerCombobox->setFilters( QgsMapLayerProxyModel::VectorLayer );
layout->addWidget( mReferencingLayerCombobox, 2, 2 );

connect( mCbxReferencingLayer, &QgsMapLayerComboBox::layerChanged, mCbxReferencingField, &QgsFieldComboBox::setLayer );
connect( mCbxReferencedLayer, &QgsMapLayerComboBox::layerChanged, mCbxReferencedField, &QgsFieldComboBox::setLayer );
// row 3: field pairs layout
mFieldPairsLayout = new QVBoxLayout();
layout->addLayout( mFieldPairsLayout, 3, 0, 1, 3 );

mCbxReferencingLayer->setFilters( QgsMapLayerProxyModel::VectorLayer );
mCbxReferencingField->setLayer( mCbxReferencingLayer->currentLayer() );
mCbxReferencedLayer->setFilters( QgsMapLayerProxyModel::VectorLayer );
mCbxReferencedField->setLayer( mCbxReferencedLayer->currentLayer() );
// row 4: id
// row 1
QLabel *idLabel = new QLabel( tr( "Id" ), this );
layout->addWidget( idLabel, 4, 1 );
// col 2
mIdLineEdit = new QLineEdit( this );
mIdLineEdit->setPlaceholderText( tr( "[Generated automatically]" ) );
layout->addWidget( mIdLineEdit, 4, 2 );

mCbxRelationStrength->addItem( "Association", QVariant::fromValue( QgsRelation::RelationStrength::Association ) );
mCbxRelationStrength->addItem( "Composition", QVariant::fromValue( QgsRelation::RelationStrength::Composition ) );
mCbxRelationStrength->setToolTip( QStringLiteral( "On composition, the child features will be duplicated too.\nDuplications are made by the feature duplication action.\nThe default actions are activated in the Action section of the layer properties." ) );
// row 5: strength
QLabel *strengthLabel = new QLabel( tr( "Relationship strength" ), this );
layout->addWidget( strengthLabel, 5, 1 );
// col 2
mStrengthCombobox = new QComboBox( this );
mStrengthCombobox->addItem( "Association", QVariant::fromValue( QgsRelation::RelationStrength::Association ) );
mStrengthCombobox->addItem( "Composition", QVariant::fromValue( QgsRelation::RelationStrength::Composition ) );
mStrengthCombobox->setToolTip( QStringLiteral( "On composition, the child features will be duplicated too.\n"
"Duplications are made by the feature duplication action.\n"
"The default actions are activated in the Action section of the layer properties." ) );
layout->addWidget( mStrengthCombobox, 5, 2 );

// row 6: button box
mButtonBox = new QDialogButtonBox( this );
mButtonBox->setOrientation( Qt::Horizontal );
mButtonBox->setStandardButtons( QDialogButtonBox::Cancel | QDialogButtonBox::Ok );
connect( mButtonBox, &QDialogButtonBox::accepted, this, &QgsRelationAddDlg::accept );
connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsRelationAddDlg::reject );
layout->addWidget( mButtonBox, 7, 1, 1, 2 );

// set layout
layout->setColumnMinimumWidth( 0, 30 );
layout->setColumnStretch( 1, 1 );
layout->setColumnStretch( 2, 1 );
layout->setRowStretch( 6, 2 );
setLayout( layout );

addFieldPairWidget();
addFieldPairWidget();

mTxtRelationId->setPlaceholderText( tr( "[Generated automatically]" ) );
checkDefinitionValid();

connect( mCbxReferencingLayer, &QgsMapLayerComboBox::layerChanged, this, &QgsRelationAddDlg::checkDefinitionValid );
connect( mCbxReferencingField, &QgsFieldComboBox::fieldChanged, this, &QgsRelationAddDlg::checkDefinitionValid );
connect( mCbxReferencedLayer, &QgsMapLayerComboBox::layerChanged, this, &QgsRelationAddDlg::checkDefinitionValid );
connect( mCbxReferencedField, &QgsFieldComboBox::fieldChanged, this, &QgsRelationAddDlg::checkDefinitionValid );
connect( mReferencingLayerCombobox, &QgsMapLayerComboBox::layerChanged, this, &QgsRelationAddDlg::checkDefinitionValid );
connect( mReferencedLayerCombobox, &QgsMapLayerComboBox::layerChanged, this, &QgsRelationAddDlg::checkDefinitionValid );
}

void QgsRelationAddDlg::addFieldPairWidget()
{
int index = mFieldPairWidgets.count();
QgsFieldPairWidget *w = new QgsFieldPairWidget( index, this );
w->setReferencingLayer( mReferencingLayerCombobox->currentLayer() );
w->setReferencedLayer( mReferencedLayerCombobox->currentLayer() );
mFieldPairsLayout->addWidget( w );
mFieldPairWidgets << w;

connect( w, &QgsFieldPairWidget::configChanged, this, &QgsRelationAddDlg::checkDefinitionValid );
connect( w, &QgsFieldPairWidget::pairDisabled, this, [ = ]() {emit fieldPairRemoved( w );} );
connect( w, &QgsFieldPairWidget::pairEnabled, this, &QgsRelationAddDlg::addFieldPairWidget );
connect( mReferencingLayerCombobox, &QgsMapLayerComboBox::layerChanged, w, &QgsFieldPairWidget::setReferencingLayer );
connect( mReferencedLayerCombobox, &QgsMapLayerComboBox::layerChanged, w, &QgsFieldPairWidget::setReferencedLayer );
}

void QgsRelationAddDlg::fieldPairRemoved( QgsFieldPairWidget *fieldPairWidget )
{
// remove widget only if not the first one, last one should always be disabled
int index = mFieldPairWidgets.indexOf( fieldPairWidget );
if ( index > 0 && index < mFieldPairWidgets.count() )
{
mFieldPairWidgets.removeAt( index );
fieldPairWidget->deleteLater();
}
}

QString QgsRelationAddDlg::referencingLayerId()
{
return mCbxReferencingLayer->currentLayer()->id();
return mReferencingLayerCombobox->currentLayer()->id();
}

QString QgsRelationAddDlg::referencedLayerId()
{
return mCbxReferencedLayer->currentLayer()->id();
return mReferencedLayerCombobox->currentLayer()->id();
}

QList< QPair< QString, QString > > QgsRelationAddDlg::references()
{
QList< QPair< QString, QString > > references;

QString referencingField = mCbxReferencingField->currentField();
QString referencedField = mCbxReferencedField->currentField();

references.append( QPair<QString, QString> ( referencingField, referencedField ) );

for ( int i = 0; i < mFieldPairWidgets.count(); i++ )
{
QString referencingField = mFieldPairWidgets.at( i )->referencingField();
QString referencedField = mFieldPairWidgets.at( i )->referencedField();
references << qMakePair( referencingField, referencedField );
}
return references;
}

QString QgsRelationAddDlg::relationId()
{
return mTxtRelationId->text();
return mIdLineEdit->text();
}

QString QgsRelationAddDlg::relationName()
{
return mTxtRelationName->text();
return mNameLineEdit->text();
}

QgsRelation::RelationStrength QgsRelationAddDlg::relationStrength()
{
return mCbxRelationStrength->currentData().value<QgsRelation::RelationStrength>();
return mStrengthCombobox->currentData().value<QgsRelation::RelationStrength>();
}

void QgsRelationAddDlg::checkDefinitionValid()
{
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( mCbxReferencedLayer->currentIndex() != -1
&& mCbxReferencedField->currentIndex() != -1
&& mCbxReferencingLayer->currentIndex() != -1
&& mCbxReferencingField->currentIndex() != -1 );
bool valid = mReferencingLayerCombobox->currentLayer() && mReferencedLayerCombobox->currentLayer();
for ( int i = 0; i < mFieldPairWidgets.count(); i++ )
{
valid &= mFieldPairWidgets.at( i )->isPairEnabled() || !mFieldPairWidgets.at( i )->referencingField().isNull();
valid &= mFieldPairWidgets.at( i )->isPairEnabled() || !mFieldPairWidgets.at( i )->referencedField().isNull();
}
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( valid );
}
68 changes: 65 additions & 3 deletions src/app/qgsrelationadddlg.h
Expand Up @@ -16,13 +16,63 @@
#define QGSRELATIONADDDLG_H

#include <QDialog>
#include "ui_qgsrelationadddlgbase.h"
#include "qgis_app.h"
#include "qgsrelation.h"

class QDialogButtonBox;
class QComboBox;
class QLineEdit;
class QSpacerItem;
class QToolButton;
class QVBoxLayout;
class QHBoxLayout;

class QgsVectorLayer;
class QgsMapLayerComboBox;
class QgsFieldComboBox;

class APP_EXPORT QgsRelationAddDlg : public QDialog, private Ui::QgsRelationAddDlgBase
/**
* QgsFieldPairWidget is horizontal widget with a field pair and buttons to enable/disable it
*/
class APP_EXPORT QgsFieldPairWidget : public QWidget
{
Q_OBJECT
public:
explicit QgsFieldPairWidget( int index, QWidget *parent = nullptr );
QString referencingField() const;
QString referencedField() const;
bool isPairEnabled() const;

signals:
void configChanged();
void pairDisabled( int index );
void pairEnabled();

public slots:
void setReferencingLayer( QgsMapLayer *layer );
void setReferencedLayer( QgsMapLayer *layer );

private:
void updateWidgetVisibility();
void changeEnable();

int mIndex;
bool mEnabled;
QToolButton *mAddButton;
QToolButton *mRemoveButton;
QgsFieldComboBox *mReferencingFieldCombobox;
QgsFieldComboBox *mReferencedFieldCombobox;
QSpacerItem *mSpacerItem;
QHBoxLayout *mLayout;

};


/**
* QgsRelationAddDlg allows to configure a new relation.
* Multiple field pairs can be set.
*/
class APP_EXPORT QgsRelationAddDlg : public QDialog
{
Q_OBJECT

Expand All @@ -37,8 +87,20 @@ class APP_EXPORT QgsRelationAddDlg : public QDialog, private Ui::QgsRelationAddD
QgsRelation::RelationStrength relationStrength();

private slots:

void checkDefinitionValid();
void fieldPairRemoved( QgsFieldPairWidget *fieldPairWidget );
void addFieldPairWidget();

private:
QList<QgsFieldPairWidget *> mFieldPairWidgets;

QDialogButtonBox *mButtonBox = nullptr;
QVBoxLayout *mFieldPairsLayout = nullptr;
QLineEdit *mNameLineEdit = nullptr;
QLineEdit *mIdLineEdit = nullptr;
QComboBox *mStrengthCombobox = nullptr;
QgsMapLayerComboBox *mReferencedLayerCombobox = nullptr;
QgsMapLayerComboBox *mReferencingLayerCombobox = nullptr;

};

Expand Down

0 comments on commit 1b563c0

Please sign in to comment.