QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsjoindialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsjoindialog.cpp
3  --------------------
4  begin : July 10, 2010
5  copyright : (C) 2010 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
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 "qgsjoindialog.h"
19 #include "qgsmaplayer.h"
20 #include "qgsproject.h"
21 #include "qgsvectordataprovider.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsvectorlayerjoininfo.h"
24 #include "qgsmaplayercombobox.h"
25 #include "qgsfieldcombobox.h"
26 #include "qgshelp.h"
27 
28 #include <QStandardItemModel>
29 #include <QPushButton>
30 
31 QgsJoinDialog::QgsJoinDialog( QgsVectorLayer *layer, QList<QgsMapLayer *> alreadyJoinedLayers, QWidget *parent, Qt::WindowFlags f )
32  : QDialog( parent, f )
33  , mLayer( layer )
34 {
35  setupUi( this );
36  connect( buttonBox, &QDialogButtonBox::helpRequested, this, [ = ]
37  {
38  QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#joins-properties" ) );
39  } );
40 
41  if ( !mLayer )
42  {
43  return;
44  }
45  // adds self layer to the joined layer (cannot join to itself)
46  alreadyJoinedLayers.append( layer );
47 
48  mTargetFieldComboBox->setLayer( mLayer );
49 
50  mDynamicFormCheckBox->setToolTip( tr( "This option allows values of the joined fields to be automatically reloaded when the \"Target Field\" is changed" ) );
51 
52  mEditableJoinLayer->setToolTip( tr( "This option allows values of the joined layers to be editable if they're themselves editable" ) );
53  mUpsertOnEditCheckBox->setToolTip( tr( "Automatically adds a matching row to the joined table, but if one already exists then update that matching row instead" ) );
54  mDeleteCascadeCheckBox->setToolTip( tr( "Automatically delete the corresponding feature of the linked layer if one exists" ) );
55 
56  mJoinLayerComboBox->setFilters( QgsMapLayerProxyModel::VectorLayer );
57  mJoinLayerComboBox->setExceptedLayerList( alreadyJoinedLayers );
58  connect( mJoinLayerComboBox, &QgsMapLayerComboBox::layerChanged, mJoinFieldComboBox, &QgsFieldComboBox::setLayer );
59  connect( mJoinLayerComboBox, &QgsMapLayerComboBox::layerChanged, this, &QgsJoinDialog::joinedLayerChanged );
60 
61  mCacheInMemoryCheckBox->setChecked( true );
62  mCacheEnabled = mCacheInMemoryCheckBox->isChecked();
63 
64  QgsMapLayer *joinLayer = mJoinLayerComboBox->currentLayer();
65  if ( joinLayer && joinLayer->isValid() )
66  {
67  mJoinFieldComboBox->setLayer( joinLayer );
68  joinedLayerChanged( joinLayer );
69  }
70 
71  connect( mJoinLayerComboBox, &QgsMapLayerComboBox::layerChanged, this, &QgsJoinDialog::checkDefinitionValid );
72  connect( mJoinFieldComboBox, &QgsFieldComboBox::fieldChanged, this, &QgsJoinDialog::checkDefinitionValid );
73  connect( mTargetFieldComboBox, &QgsFieldComboBox::fieldChanged, this, &QgsJoinDialog::checkDefinitionValid );
74  connect( mEditableJoinLayer, &QGroupBox::toggled, this, &QgsJoinDialog::editableJoinLayerChanged );
75 
76  checkDefinitionValid();
77 }
78 
80 {
81  mJoinLayerComboBox->setLayer( joinInfo.joinLayer() );
82  mJoinFieldComboBox->setField( joinInfo.joinFieldName() );
83  mTargetFieldComboBox->setField( joinInfo.targetFieldName() );
84 
85  mCacheEnabled = joinInfo.isUsingMemoryCache();
86  mCacheInMemoryCheckBox->setChecked( joinInfo.isUsingMemoryCache() );
87 
88  mDynamicFormCheckBox->setChecked( joinInfo.isDynamicFormEnabled() );
89  mEditableJoinLayer->setChecked( joinInfo.isEditable() );
90  mUpsertOnEditCheckBox->setChecked( joinInfo.hasUpsertOnEdit() );
91  mDeleteCascadeCheckBox->setChecked( joinInfo.hasCascadedDelete() );
92 
93  if ( joinInfo.prefix().isNull() )
94  {
95  mUseCustomPrefix->setChecked( false );
96  }
97  else
98  {
99  mUseCustomPrefix->setChecked( true );
100  mCustomPrefix->setText( joinInfo.prefix() );
101  }
102 
103  QStringList *lst = joinInfo.joinFieldNamesSubset();
104  mUseJoinFieldsSubset->setChecked( lst && !lst->isEmpty() );
105  QAbstractItemModel *model = mJoinFieldsSubsetView->model();
106  if ( model )
107  {
108  for ( int i = 0; i < model->rowCount(); ++i )
109  {
110  const QModelIndex index = model->index( i, 0 );
111  if ( lst && lst->contains( model->data( index, Qt::DisplayRole ).toString() ) )
112  {
113  model->setData( index, Qt::Checked, Qt::CheckStateRole );
114  }
115  else
116  {
117  model->setData( index, Qt::Unchecked, Qt::CheckStateRole );
118  }
119  }
120  }
121 
122  editableJoinLayerChanged();
123 }
124 
126 {
128  info.setJoinLayer( qobject_cast<QgsVectorLayer *>( mJoinLayerComboBox->currentLayer() ) );
129  info.setJoinFieldName( mJoinFieldComboBox->currentField() );
130  info.setTargetFieldName( mTargetFieldComboBox->currentField() );
131  info.setUsingMemoryCache( mCacheInMemoryCheckBox->isChecked() );
132  info.setDynamicFormEnabled( mDynamicFormCheckBox->isChecked() );
133 
134  info.setEditable( mEditableJoinLayer->isChecked() );
135  if ( info.isEditable() )
136  {
137  info.setUpsertOnEdit( mUpsertOnEditCheckBox->isChecked() );
138  info.setCascadedDelete( mDeleteCascadeCheckBox->isChecked() );
139  }
140 
141  if ( mUseCustomPrefix->isChecked() )
142  info.setPrefix( mCustomPrefix->text() );
143  else
144  info.setPrefix( QString() );
145 
146  if ( mUseJoinFieldsSubset->isChecked() )
147  {
148  QStringList lst;
149  QAbstractItemModel *model = mJoinFieldsSubsetView->model();
150  if ( model )
151  {
152  for ( int i = 0; i < model->rowCount(); ++i )
153  {
154  const QModelIndex index = model->index( i, 0 );
155  if ( model->data( index, Qt::CheckStateRole ).toInt() == Qt::Checked )
156  lst << model->data( index ).toString();
157  }
158  }
159  info.setJoinFieldNamesSubset( new QStringList( lst ) );
160  }
161 
162  return info;
163 }
164 
166 {
167  return mCreateIndexCheckBox->isChecked();
168 }
169 
170 void QgsJoinDialog::joinedLayerChanged( QgsMapLayer *layer )
171 {
172  mJoinFieldComboBox->clear();
173 
174  QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
175  if ( !vLayer )
176  {
177  return;
178  }
179 
180  mUseJoinFieldsSubset->setChecked( false );
181  QStandardItemModel *subsetModel = new QStandardItemModel( this );
182  const QgsFields layerFields = vLayer->fields();
183  for ( const QgsField &field : layerFields )
184  {
185  QStandardItem *subsetItem = new QStandardItem( field.name() );
186  subsetItem->setCheckable( true );
187  //subsetItem->setFlags( subsetItem->flags() | Qt::ItemIsUserCheckable );
188  subsetModel->appendRow( subsetItem );
189  }
190  mJoinFieldsSubsetView->setModel( subsetModel );
191 
192  QgsVectorDataProvider *dp = vLayer->dataProvider();
193  const bool canCreateAttrIndex = dp && ( dp->capabilities() & QgsVectorDataProvider::CreateAttributeIndex );
194  if ( canCreateAttrIndex )
195  {
196  mCreateIndexCheckBox->setEnabled( true );
197  }
198  else
199  {
200  mCreateIndexCheckBox->setEnabled( false );
201  mCreateIndexCheckBox->setChecked( false );
202  }
203 
204  if ( !mUseCustomPrefix->isChecked() )
205  {
206  mCustomPrefix->setText( layer->name() + '_' );
207  }
208 }
209 
210 void QgsJoinDialog::checkDefinitionValid()
211 {
212  buttonBox->button( QDialogButtonBox::Ok )->setEnabled( mJoinLayerComboBox->currentIndex() != -1
213  && mJoinFieldComboBox->currentIndex() != -1
214  && mTargetFieldComboBox->currentIndex() != -1 );
215 }
216 
217 void QgsJoinDialog::editableJoinLayerChanged()
218 {
219  if ( mEditableJoinLayer->isChecked() )
220  {
221  mCacheInMemoryCheckBox->setEnabled( false );
222  mCacheInMemoryCheckBox->setToolTip( tr( "Caching can not be enabled if editable join layer is enabled" ) );
223  mCacheEnabled = mCacheInMemoryCheckBox->isChecked();
224  mCacheInMemoryCheckBox->setChecked( false );
225  }
226  else
227  {
228  mCacheInMemoryCheckBox->setEnabled( true );
229  mCacheInMemoryCheckBox->setToolTip( QString() );
230  mCacheInMemoryCheckBox->setChecked( mCacheEnabled );
231  }
232 }
QgsVectorLayerJoinInfo::isDynamicFormEnabled
bool isDynamicFormEnabled() const
Returns whether the form has to be dynamically updated with joined fields when a feature is being cre...
Definition: qgsvectorlayerjoininfo.h:94
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:676
QgsVectorLayerJoinInfo::setEditable
void setEditable(bool enabled)
Sets whether the form of the target layer allows editing joined fields.
Definition: qgsvectorlayerjoininfo.cpp:51
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsVectorDataProvider::CreateAttributeIndex
@ CreateAttributeIndex
Can create indexes on provider's fields.
Definition: qgsvectordataprovider.h:84
qgsjoindialog.h
QgsVectorLayerJoinInfo::joinFieldNamesSubset
static QStringList joinFieldNamesSubset(const QgsVectorLayerJoinInfo &info, bool blocklisted=true)
Returns the list of field names to use for joining considering blocklisted fields and subset.
Definition: qgsvectorlayerjoininfo.cpp:86
QgsMapLayer::isValid
bool isValid
Definition: qgsmaplayer.h:81
QgsVectorLayerJoinInfo::setUpsertOnEdit
void setUpsertOnEdit(bool enabled)
Sets whether a feature created on the target layer has to impact the joined layer by creating a new f...
Definition: qgsvectorlayerjoininfo.h:128
field
const QgsField & field
Definition: qgsfield.h:463
QgsField::name
QString name
Definition: qgsfield.h:60
qgsvectorlayerjoininfo.h
QgsMapLayerProxyModel::VectorLayer
@ VectorLayer
Definition: qgsmaplayerproxymodel.h:51
QgsVectorLayerJoinInfo::targetFieldName
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
Definition: qgsvectorlayerjoininfo.h:68
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
qgsfieldcombobox.h
QgsVectorLayerJoinInfo::prefix
QString prefix() const
Returns prefix of fields from the joined layer. If nullptr, joined layer's name will be used.
Definition: qgsvectorlayerjoininfo.h:78
QgsVectorDataProvider::capabilities
virtual Q_INVOKABLE QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
Definition: qgsvectordataprovider.cpp:208
QgsJoinDialog::setJoinInfo
void setJoinInfo(const QgsVectorLayerJoinInfo &joinInfo)
Configure the dialog for an existing join.
Definition: qgsjoindialog.cpp:79
QgsVectorLayerJoinInfo::setDynamicFormEnabled
void setDynamicFormEnabled(bool enabled)
Sets whether the form has to be dynamically updated with joined fields when a feature is being create...
Definition: qgsvectorlayerjoininfo.h:101
QgsVectorLayerJoinInfo::hasUpsertOnEdit
bool hasUpsertOnEdit() const
Returns whether a feature created on the target layer has to impact the joined layer by creating a ne...
Definition: qgsvectorlayerjoininfo.h:121
qgsmaplayer.h
QgsJoinDialog::QgsJoinDialog
QgsJoinDialog(QgsVectorLayer *layer, QList< QgsMapLayer * > alreadyJoinedLayers, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
Definition: qgsjoindialog.cpp:31
qgsvectordataprovider.h
QgsVectorLayerJoinInfo::isEditable
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
Definition: qgsvectorlayerjoininfo.h:108
QgsVectorLayerJoinInfo::joinFieldName
QString joinFieldName() const
Returns name of the field of joined layer that will be used for join.
Definition: qgsvectorlayerjoininfo.h:73
QgsFieldComboBox::setLayer
void setLayer(QgsMapLayer *layer)
Sets the layer for which fields are listed in the combobox.
Definition: qgsfieldcombobox.cpp:46
QgsVectorLayerJoinInfo
Defines left outer join from our vector layer to some other vector layer. The join is done based on [...
Definition: qgsvectorlayerjoininfo.h:33
QgsVectorLayerJoinInfo::setUsingMemoryCache
void setUsingMemoryCache(bool enabled)
Sets whether values from the joined layer should be cached in memory to speed up lookups.
Definition: qgsvectorlayerjoininfo.cpp:38
qgsvectorlayer.h
QgsVectorLayerJoinInfo::setTargetFieldName
void setTargetFieldName(const QString &fieldName)
Sets name of the field of our layer that will be used for join.
Definition: qgsvectorlayerjoininfo.h:66
QgsVectorLayerJoinInfo::setJoinFieldName
void setJoinFieldName(const QString &fieldName)
Sets name of the field of joined layer that will be used for join.
Definition: qgsvectorlayerjoininfo.h:71
QgsVectorLayerJoinInfo::setJoinFieldNamesSubset
void setJoinFieldNamesSubset(QStringList *fieldNamesSubset)
Sets the subset of fields to be used from joined layer.
Definition: qgsvectorlayerjoininfo.h:225
QgsVectorLayerJoinInfo::setPrefix
void setPrefix(const QString &prefix)
Sets prefix of fields from the joined layer. If nullptr, joined layer's name will be used.
Definition: qgsvectorlayerjoininfo.h:76
qgsmaplayercombobox.h
QgsHelp::openHelp
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
QgsJoinDialog::joinInfo
QgsVectorLayerJoinInfo joinInfo() const
Returns the join info.
Definition: qgsjoindialog.cpp:125
QgsVectorLayerJoinInfo::joinLayer
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet)
Definition: qgsvectorlayerjoininfo.h:58
QgsVectorLayerJoinInfo::hasCascadedDelete
bool hasCascadedDelete() const
Returns whether a feature deleted on the target layer has to impact the joined layer by deleting the ...
Definition: qgsvectorlayerjoininfo.h:135
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:76
QgsVectorDataProvider
This is the base class for vector data providers.
Definition: qgsvectordataprovider.h:58
QgsVectorLayerJoinInfo::isUsingMemoryCache
bool isUsingMemoryCache() const
Returns whether values from the joined layer should be cached in memory to speed up lookups.
Definition: qgsvectorlayerjoininfo.cpp:43
QgsJoinDialog::createAttributeIndex
bool createAttributeIndex() const
Returns true if user wants to create an attribute index on the join field.
Definition: qgsjoindialog.cpp:165
QgsVectorLayerJoinInfo::setJoinLayer
void setJoinLayer(QgsVectorLayer *layer)
Sets weak reference to the joined layer.
Definition: qgsvectorlayerjoininfo.h:56
qgshelp.h
qgsproject.h
QgsMapLayerComboBox::layerChanged
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
QgsVectorLayerJoinInfo::setCascadedDelete
void setCascadedDelete(bool enabled)
Sets whether a feature deleted on the target layer has to impact the joined layer by deleting the cor...
Definition: qgsvectorlayerjoininfo.h:142
QgsFieldComboBox::fieldChanged
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50