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
QgsJoinDialog(QgsVectorLayer * layer,QList<QgsMapLayer * > alreadyJoinedLayers,QWidget * parent,Qt::WindowFlags f)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
setJoinInfo(const QgsVectorLayerJoinInfo & joinInfo)79 void QgsJoinDialog::setJoinInfo( const QgsVectorLayerJoinInfo &joinInfo )
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
joinInfo() const125 QgsVectorLayerJoinInfo QgsJoinDialog::joinInfo() const
126 {
127 QgsVectorLayerJoinInfo info;
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
createAttributeIndex() const165 bool QgsJoinDialog::createAttributeIndex() const
166 {
167 return mCreateIndexCheckBox->isChecked();
168 }
169
joinedLayerChanged(QgsMapLayer * layer)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
checkDefinitionValid()210 void QgsJoinDialog::checkDefinitionValid()
211 {
212 buttonBox->button( QDialogButtonBox::Ok )->setEnabled( mJoinLayerComboBox->currentIndex() != -1
213 && mJoinFieldComboBox->currentIndex() != -1
214 && mTargetFieldComboBox->currentIndex() != -1 );
215 }
216
editableJoinLayerChanged()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 }
233