Skip to content

Commit 31a1c23

Browse files
Patrick Valsecchipvalsecc
authored andcommitted
Add auto-discovery of relations for PostgresQL
Fixed the add relation functionnality: the table is sorted. When the code was setting the sorted column, the row was sorted and the other columns it was setting were set on the wrong row.
1 parent 9cf9938 commit 31a1c23

19 files changed

+495
-8
lines changed

python/core/qgsrelation.sip

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@ class QgsRelation
171171
*/
172172
QString id() const;
173173

174+
/**
175+
* Generate a (project-wide) unique id for this relation
176+
* @note added in QGIS 3.0
177+
*/
178+
void generateId();
179+
174180
/**
175181
* Access the referencing (child) layer's id
176182
* This is the layer which has the field(s) which point to another layer
@@ -241,6 +247,15 @@ class QgsRelation
241247
*/
242248
bool isValid() const;
243249

250+
/**
251+
* Compares the two QgsRelation, ignoring the name and the ID.
252+
*
253+
* @param other The other relation
254+
* @return true if they are similar
255+
* @note added in QGIS 3.0
256+
*/
257+
bool hasEqualDefinition( const QgsRelation& other ) const;
258+
244259
protected:
245260
/**
246261
* Updates the validity status of this relation.

python/core/qgsrelationmanager.sip

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ class QgsRelationManager : QObject
9090
*/
9191
QList<QgsRelation> referencedRelations( QgsVectorLayer *layer = 0 ) const;
9292

93+
/**
94+
* Discover all the relations available from the current layers.
95+
*
96+
* @param existingRelations the existing relations to filter them out
97+
* @param layers the current layers
98+
* @return the list of discovered relations
99+
* @note added in QGIS 3.0
100+
*/
101+
static QList<QgsRelation> discoverRelations( const QList<QgsRelation>& existingRelations, const QList<QgsVectorLayer*>& layers );
102+
93103
signals:
94104
/** This signal is emitted when the relations were loaded after reading a project */
95105
void relationsLoaded();

python/core/qgsvectordataprovider.sip

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,15 @@ class QgsVectorDataProvider : QgsDataProvider
371371
*/
372372
virtual QSet<QgsMapLayerDependency> dependencies() const;
373373

374+
/**
375+
* Discover the available relations with the given layers.
376+
* @param self the layer using this data provider.
377+
* @param layers the other layers.
378+
* @return the list of N-1 relations from this provider.
379+
* @note added in QGIS 3.0
380+
*/
381+
virtual QList<QgsRelation> discoverRelations( const QgsVectorLayer* self, const QList<QgsVectorLayer*>& layers ) const;
382+
374383
signals:
375384
/** Signals an error in this provider */
376385
void raiseError( const QString& msg );

src/app/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ SET(QGIS_APP_SRCS
2828
qgsdecorationscalebardialog.cpp
2929
qgsdecorationgrid.cpp
3030
qgsdecorationgriddialog.cpp
31+
qgsdiscoverrelationsdlg.cpp
3132
qgsdxfexportdialog.cpp
3233
qgsformannotationdialog.cpp
3334
qgsguivectorlayertools.cpp
@@ -207,6 +208,7 @@ SET (QGIS_APP_MOC_HDRS
207208
qgsdecorationgriddialog.h
208209
qgsdelattrdialog.h
209210
qgsdiagramproperties.h
211+
qgsdiscoverrelationsdlg.h
210212
qgsdisplayangle.h
211213
qgsdxfexportdialog.h
212214
qgsfeatureaction.h
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/***************************************************************************
2+
qgsdiscoverrelationsdlg.cpp
3+
---------------------
4+
begin : September 2016
5+
copyright : (C) 2016 by Patrick Valsecchi
6+
email : patrick dot valsecchi at camptocamp dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
#include "qgsdiscoverrelationsdlg.h"
16+
#include "qgsvectorlayer.h"
17+
#include "qgsrelationmanager.h"
18+
19+
#include <QPushButton>
20+
21+
QgsDiscoverRelationsDlg::QgsDiscoverRelationsDlg( const QList<QgsRelation>& existingRelations, const QList<QgsVectorLayer*>& layers, QWidget *parent )
22+
: QDialog( parent )
23+
, mLayers( layers )
24+
{
25+
setupUi( this );
26+
27+
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
28+
connect( mRelationsTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsDiscoverRelationsDlg::onSelectionChanged );
29+
30+
mFoundRelations = QgsRelationManager::discoverRelations( existingRelations, layers );
31+
Q_FOREACH ( const QgsRelation& relation, mFoundRelations ) addRelation( relation );
32+
33+
mRelationsTable->resizeColumnsToContents();
34+
35+
}
36+
37+
void QgsDiscoverRelationsDlg::addRelation( const QgsRelation &rel )
38+
{
39+
const int row = mRelationsTable->rowCount();
40+
mRelationsTable->insertRow( row );
41+
mRelationsTable->setItem( row, 0, new QTableWidgetItem( rel.name() ) );
42+
mRelationsTable->setItem( row, 1, new QTableWidgetItem( rel.referencingLayer()->name() ) );
43+
mRelationsTable->setItem( row, 2, new QTableWidgetItem( rel.fieldPairs().at( 0 ).referencingField() ) );
44+
mRelationsTable->setItem( row, 3, new QTableWidgetItem( rel.referencedLayer()->name() ) );
45+
mRelationsTable->setItem( row, 4, new QTableWidgetItem( rel.fieldPairs().at( 0 ).referencedField() ) );
46+
}
47+
48+
QList<QgsRelation> QgsDiscoverRelationsDlg::relations() const
49+
{
50+
QList<QgsRelation> result;
51+
Q_FOREACH ( const QModelIndex& row, mRelationsTable->selectionModel()->selectedRows() )
52+
{
53+
result.append( mFoundRelations.at( row.row() ) );
54+
}
55+
return result;
56+
}
57+
58+
void QgsDiscoverRelationsDlg::onSelectionChanged()
59+
{
60+
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( mRelationsTable->selectionModel()->hasSelection() );
61+
}

src/app/qgsdiscoverrelationsdlg.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/***************************************************************************
2+
qgsdiscoverrelationsdlg.h
3+
---------------------
4+
begin : September 2016
5+
copyright : (C) 2016 by Patrick Valsecchi
6+
email : patrick dot valsecchi at camptocamp dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
#ifndef QGSDISCOVERRELATIONSDLG_H
16+
#define QGSDISCOVERRELATIONSDLG_H
17+
18+
#include <QDialog>
19+
#include "ui_qgsdiscoverrelationsdlgbase.h"
20+
#include "qgsrelation.h"
21+
22+
class QgsRelationManager;
23+
class QgsVectorLayer;
24+
25+
/**
26+
* Shows the list of relations discovered from the providers.
27+
*
28+
* The user can select some of them to add them to his project.
29+
*/
30+
class APP_EXPORT QgsDiscoverRelationsDlg : public QDialog, private Ui::QgsDiscoverRelationsDlgBase
31+
{
32+
Q_OBJECT
33+
34+
public:
35+
explicit QgsDiscoverRelationsDlg( const QList<QgsRelation>& existingRelations, const QList<QgsVectorLayer*>& layers, QWidget *parent = nullptr );
36+
37+
/**
38+
* Get the selected relations.
39+
*/
40+
QList<QgsRelation> relations() const;
41+
42+
private slots:
43+
void onSelectionChanged();
44+
45+
private:
46+
QList<QgsVectorLayer*> mLayers;
47+
QList<QgsRelation> mFoundRelations;
48+
49+
void addRelation( const QgsRelation &rel );
50+
51+
};
52+
53+
#endif // QGSDISCOVERRELATIONSDLG_H

src/app/qgsrelationmanagerdialog.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* *
1414
***************************************************************************/
1515

16+
#include "qgsdiscoverrelationsdlg.h"
1617
#include "qgsrelationadddlg.h"
1718
#include "qgsrelationmanagerdialog.h"
1819
#include "qgsrelationmanager.h"
@@ -46,6 +47,7 @@ void QgsRelationManagerDialog::setLayers( const QList< QgsVectorLayer* >& layers
4647

4748
void QgsRelationManagerDialog::addRelation( const QgsRelation &rel )
4849
{
50+
mRelationsTable->setSortingEnabled( false );
4951
int row = mRelationsTable->rowCount();
5052
mRelationsTable->insertRow( row );
5153

@@ -54,7 +56,6 @@ void QgsRelationManagerDialog::addRelation( const QgsRelation &rel )
5456
item->setData( Qt::UserRole, QVariant::fromValue<QgsRelation>( rel ) );
5557
mRelationsTable->setItem( row, 0, item );
5658

57-
5859
item = new QTableWidgetItem( rel.referencingLayer()->name() );
5960
item->setFlags( Qt::ItemIsEditable );
6061
mRelationsTable->setItem( row, 1, item );
@@ -74,6 +75,7 @@ void QgsRelationManagerDialog::addRelation( const QgsRelation &rel )
7475
item = new QTableWidgetItem( rel.id() );
7576
item->setFlags( Qt::ItemIsEditable );
7677
mRelationsTable->setItem( row, 5, item );
78+
mRelationsTable->setSortingEnabled( true );
7779
}
7880

7981
void QgsRelationManagerDialog::on_mBtnAddRelation_clicked()
@@ -118,6 +120,18 @@ void QgsRelationManagerDialog::on_mBtnAddRelation_clicked()
118120
}
119121
}
120122

123+
void QgsRelationManagerDialog::on_mBtnDiscoverRelations_clicked()
124+
{
125+
QgsDiscoverRelationsDlg discoverDlg( relations(), mLayers, this );
126+
if ( discoverDlg.exec() )
127+
{
128+
Q_FOREACH ( const QgsRelation& relation, discoverDlg.relations() )
129+
{
130+
addRelation( relation );
131+
}
132+
}
133+
}
134+
121135
void QgsRelationManagerDialog::on_mBtnRemoveRelation_clicked()
122136
{
123137
if ( mRelationsTable->currentIndex().isValid() )

src/app/qgsrelationmanagerdialog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class APP_EXPORT QgsRelationManagerDialog : public QWidget, private Ui::QgsRelat
3939

4040
public slots:
4141
void on_mBtnAddRelation_clicked();
42+
void on_mBtnDiscoverRelations_clicked();
4243
void on_mBtnRemoveRelation_clicked();
4344

4445
private:

src/core/qgsrelation.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,16 @@ QString QgsRelation::id() const
248248
return mRelationId;
249249
}
250250

251+
void QgsRelation::generateId()
252+
{
253+
mRelationId = QString( "%1_%2_%3_%4" )
254+
.arg( referencingLayerId(),
255+
mFieldPairs.at( 0 ).referencingField(),
256+
referencedLayerId(),
257+
mFieldPairs.at( 0 ).referencedField() );
258+
updateRelationStatus();
259+
}
260+
251261
QString QgsRelation::referencingLayerId() const
252262
{
253263
return mReferencingLayerId;
@@ -301,6 +311,11 @@ bool QgsRelation::isValid() const
301311
return mValid;
302312
}
303313

314+
bool QgsRelation::hasEqualDefinition( const QgsRelation& other ) const
315+
{
316+
return mReferencedLayerId == other.mReferencedLayerId && mReferencingLayerId == other.mReferencingLayerId && mFieldPairs == other.mFieldPairs;
317+
}
318+
304319
void QgsRelation::updateRelationStatus()
305320
{
306321
const QMap<QString, QgsMapLayer*>& mapLayers = QgsMapLayerRegistry::instance()->mapLayers();

src/core/qgsrelation.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ class CORE_EXPORT QgsRelation
5757
QString referencingField() const { return first; }
5858
//! Get the name of the referenced (parent) field
5959
QString referencedField() const { return second; }
60+
61+
bool operator==( const FieldPair& other ) const { return first == other.first && second == other.second; }
6062
};
6163

6264
/**
@@ -210,6 +212,12 @@ class CORE_EXPORT QgsRelation
210212
*/
211213
QString id() const;
212214

215+
/**
216+
* Generate a (project-wide) unique id for this relation
217+
* @note added in QGIS 3.0
218+
*/
219+
void generateId();
220+
213221
/**
214222
* Access the referencing (child) layer's id
215223
* This is the layer which has the field(s) which point to another layer
@@ -272,6 +280,15 @@ class CORE_EXPORT QgsRelation
272280
*/
273281
bool isValid() const;
274282

283+
/**
284+
* Compares the two QgsRelation, ignoring the name and the ID.
285+
*
286+
* @param other The other relation
287+
* @return true if they are similar
288+
* @note added in QGIS 3.0
289+
*/
290+
bool hasEqualDefinition( const QgsRelation& other ) const;
291+
275292
protected:
276293
/**
277294
* Updates the validity status of this relation.

0 commit comments

Comments
 (0)