QGIS API Documentation  3.27.0-Master (0e23467727)
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 }
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
void setLayer(QgsMapLayer *layer)
Sets the layer for which fields are listed in the combobox.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString name
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
QgsJoinDialog(QgsVectorLayer *layer, QList< QgsMapLayer * > alreadyJoinedLayers, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
QgsVectorLayerJoinInfo joinInfo() const
Returns the join info.
bool createAttributeIndex() const
Returns true if user wants to create an attribute index on the join field.
void setJoinInfo(const QgsVectorLayerJoinInfo &joinInfo)
Configure the dialog for an existing join.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
bool isValid
Definition: qgsmaplayer.h:81
This is the base class for vector data providers.
@ CreateAttributeIndex
Can create indexes on provider's fields.
virtual Q_INVOKABLE QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
Defines left outer join from our vector layer to some other vector layer.
void setDynamicFormEnabled(bool enabled)
Sets whether the form has to be dynamically updated with joined fields when a feature is being create...
bool hasCascadedDelete() const
Returns whether a feature deleted on the target layer has to impact the joined layer by deleting the ...
void setUsingMemoryCache(bool enabled)
Sets whether values from the joined layer should be cached in memory to speed up lookups.
bool isDynamicFormEnabled() const
Returns whether the form has to be dynamically updated with joined fields when a feature is being cre...
bool hasUpsertOnEdit() const
Returns whether a feature created on the target layer has to impact the joined layer by creating a ne...
void setEditable(bool enabled)
Sets whether the form of the target layer allows editing joined fields.
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
void setCascadedDelete(bool enabled)
Sets whether a feature deleted on the target layer has to impact the joined layer by deleting the cor...
void setJoinFieldName(const QString &fieldName)
Sets name of the field of joined layer that will be used for join.
bool isUsingMemoryCache() const
Returns whether values from the joined layer should be cached in memory to speed up lookups.
QString prefix() const
Returns prefix of fields from the joined layer. If nullptr, joined layer's name will be used.
static QStringList joinFieldNamesSubset(const QgsVectorLayerJoinInfo &info, bool blocklisted=true)
Returns the list of field names to use for joining considering blocklisted fields and subset.
void setTargetFieldName(const QString &fieldName)
Sets name of the field of our layer that will be used for join.
QString joinFieldName() const
Returns name of the field of joined layer that will be used for join.
void setUpsertOnEdit(bool enabled)
Sets whether a feature created on the target layer has to impact the joined layer by creating a new f...
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet)
void setPrefix(const QString &prefix)
Sets prefix of fields from the joined layer. If nullptr, joined layer's name will be used.
void setJoinLayer(QgsVectorLayer *layer)
Sets weak reference to the joined layer.
void setJoinFieldNamesSubset(QStringList *fieldNamesSubset)
Sets the subset of fields to be used from joined layer.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
const QgsField & field
Definition: qgsfield.h:463