1 /***************************************************************************
2 qgsquickattributemodelbase.cpp
3 --------------------------------------
4 Date : 16.8.2016
5 Copyright : (C) 2016 by Matthias Kuhn
6 Email : matthias@opengis.ch
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
16 #include "qgseditorwidgetsetup.h"
17 #include "qgsvectorlayer.h"
18
19 #include "qgsquickattributeformmodelbase.h"
20 #include "qgsquickattributeformmodel.h"
21
22 /// @cond PRIVATE
23
QgsQuickAttributeFormModelBase(QObject * parent)24 QgsQuickAttributeFormModelBase::QgsQuickAttributeFormModelBase( QObject *parent )
25 : QStandardItemModel( 0, 1, parent )
26 {
27 }
28
29
roleNames() const30 QHash<int, QByteArray> QgsQuickAttributeFormModelBase::roleNames() const
31 {
32 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
33
34 roles[QgsQuickAttributeFormModel::ElementType] = QByteArray( "Type" );
35 roles[QgsQuickAttributeFormModel::Name] = QByteArray( "Name" );
36 roles[QgsQuickAttributeFormModel::AttributeValue] = QByteArray( "AttributeValue" );
37 roles[QgsQuickAttributeFormModel::AttributeEditable] = QByteArray( "AttributeEditable" );
38 roles[QgsQuickAttributeFormModel::EditorWidget] = QByteArray( "EditorWidget" );
39 roles[QgsQuickAttributeFormModel::EditorWidgetConfig] = QByteArray( "EditorWidgetConfig" );
40 roles[QgsQuickAttributeFormModel::RememberValue] = QByteArray( "RememberValue" );
41 roles[QgsQuickAttributeFormModel::Field] = QByteArray( "Field" );
42 roles[QgsQuickAttributeFormModel::Group] = QByteArray( "Group" );
43 roles[QgsQuickAttributeFormModel::ConstraintValid] = QByteArray( "ConstraintValid" );
44 roles[QgsQuickAttributeFormModel::ConstraintDescription] = QByteArray( "ConstraintDescription" );
45
46 return roles;
47 }
48
setData(const QModelIndex & index,const QVariant & value,int role)49 bool QgsQuickAttributeFormModelBase::setData( const QModelIndex &index, const QVariant &value, int role )
50 {
51 if ( data( index, role ) != value )
52 {
53 switch ( role )
54 {
55 case QgsQuickAttributeFormModel::RememberValue:
56 {
57 QStandardItem *item = itemFromIndex( index );
58 int fieldIndex = item->data( QgsQuickAttributeFormModel::FieldIndex ).toInt();
59 mAttributeModel->setData( mAttributeModel->index( fieldIndex ), value, QgsQuickAttributeModel::RememberAttribute );
60 item->setData( value, QgsQuickAttributeFormModel::RememberValue );
61 break;
62 }
63
64 case QgsQuickAttributeFormModel::AttributeValue:
65 {
66 QStandardItem *item = itemFromIndex( index );
67 int fieldIndex = item->data( QgsQuickAttributeFormModel::FieldIndex ).toInt();
68 bool changed = mAttributeModel->setData( mAttributeModel->index( fieldIndex ), value, QgsQuickAttributeModel::AttributeValue );
69 if ( changed )
70 {
71 item->setData( value, QgsQuickAttributeFormModel::AttributeValue );
72 emit dataChanged( index, index, QVector<int>() << role );
73 }
74 updateVisibility( fieldIndex );
75 return changed;
76 break;
77 }
78 }
79 }
80 return false;
81 }
82
attributeModel() const83 QgsQuickAttributeModel *QgsQuickAttributeFormModelBase::attributeModel() const
84 {
85 return mAttributeModel;
86 }
87
setAttributeModel(QgsQuickAttributeModel * attributeModel)88 void QgsQuickAttributeFormModelBase::setAttributeModel( QgsQuickAttributeModel *attributeModel )
89 {
90 if ( mAttributeModel == attributeModel )
91 return;
92
93 if ( mAttributeModel )
94 {
95 disconnect( mAttributeModel, &QgsQuickAttributeModel::layerChanged, this, &QgsQuickAttributeFormModelBase::onLayerChanged );
96 disconnect( mAttributeModel, &QgsQuickAttributeModel::featureChanged, this, &QgsQuickAttributeFormModelBase::onFeatureChanged );
97 disconnect( mAttributeModel, &QgsQuickAttributeModel::modelReset, this, &QgsQuickAttributeFormModelBase::onFeatureChanged );
98 }
99
100 mAttributeModel = attributeModel;
101
102 if ( mAttributeModel )
103 {
104 connect( mAttributeModel, &QgsQuickAttributeModel::layerChanged, this, &QgsQuickAttributeFormModelBase::onLayerChanged );
105 connect( mAttributeModel, &QgsQuickAttributeModel::featureChanged, this, &QgsQuickAttributeFormModelBase::onFeatureChanged );
106 connect( mAttributeModel, &QgsQuickAttributeModel::modelReset, this, &QgsQuickAttributeFormModelBase::onFeatureChanged );
107 }
108
109 emit attributeModelChanged();
110 }
111
onLayerChanged()112 void QgsQuickAttributeFormModelBase::onLayerChanged()
113 {
114 clear();
115
116 mLayer = mAttributeModel->featureLayerPair().layer();
117 mVisibilityExpressions.clear();
118 mConstraints.clear();
119
120 if ( mLayer )
121 {
122 QgsAttributeEditorContainer *root = nullptr;
123 mTemporaryContainer = nullptr;
124
125 if ( mLayer->editFormConfig().layout() == QgsEditFormConfig::TabLayout )
126 {
127 root = mLayer->editFormConfig().invisibleRootContainer();
128 }
129 else
130 {
131 root = generateRootContainer(); //#spellok
132 mTemporaryContainer.reset( root );
133 }
134
135 setHasTabs( !root->children().isEmpty() && QgsAttributeEditorElement::AeTypeContainer == root->children().first()->type() );
136
137 invisibleRootItem()->setColumnCount( 1 );
138 if ( mHasTabs )
139 {
140 for ( QgsAttributeEditorElement *element : root->children() )
141 {
142 if ( element->type() == QgsAttributeEditorElement::AeTypeContainer )
143 {
144 QgsAttributeEditorContainer *container = static_cast<QgsAttributeEditorContainer *>( element );
145
146 QStandardItem *item = new QStandardItem();
147 item->setData( element->name(), QgsQuickAttributeFormModel::Name );
148 item->setData( QStringLiteral( "container" ), QgsQuickAttributeFormModel::ElementType );
149 item->setData( true, QgsQuickAttributeFormModel::CurrentlyVisible );
150 invisibleRootItem()->appendRow( item );
151
152 if ( container->visibilityExpression().enabled() )
153 {
154 mVisibilityExpressions.append( qMakePair( container->visibilityExpression().data(), QVector<QStandardItem *>() << item ) );
155 }
156
157 QVector<QStandardItem *> dummy;
158 flatten( container, item, QString(), dummy );
159 }
160 }
161 }
162 else
163 {
164 QVector<QStandardItem *> dummy;
165 flatten( invisibleRootContainer(), invisibleRootItem(), QString(), dummy );
166 }
167
168 mExpressionContext = mLayer->createExpressionContext();
169 }
170 }
171
onFeatureChanged()172 void QgsQuickAttributeFormModelBase::onFeatureChanged()
173 {
174 for ( int i = 0 ; i < invisibleRootItem()->rowCount(); ++i )
175 {
176 updateAttributeValue( invisibleRootItem()->child( i ) );
177 }
178
179 updateVisibility();
180 }
181
generateRootContainer() const182 QgsAttributeEditorContainer *QgsQuickAttributeFormModelBase::generateRootContainer() const //#spellok
183 {
184 QgsAttributeEditorContainer *root = new QgsAttributeEditorContainer( QString(), nullptr );
185 QgsFields fields = mLayer->fields();
186 for ( int i = 0; i < fields.size(); ++i )
187 {
188 if ( fields.at( i ).editorWidgetSetup().type() != QLatin1String( "Hidden" ) )
189 {
190 QgsAttributeEditorField *field = new QgsAttributeEditorField( fields.at( i ).name(), i, root );
191 root->addChildElement( field );
192 }
193 }
194 return root;
195 }
196
invisibleRootContainer() const197 QgsAttributeEditorContainer *QgsQuickAttributeFormModelBase::invisibleRootContainer() const
198 {
199 return mTemporaryContainer ? mTemporaryContainer.get() : mLayer->editFormConfig().invisibleRootContainer();
200 }
201
updateAttributeValue(QStandardItem * item)202 void QgsQuickAttributeFormModelBase::updateAttributeValue( QStandardItem *item )
203 {
204 if ( item->data( QgsQuickAttributeFormModel::ElementType ) == QLatin1String( "field" ) )
205 {
206 item->setData( mAttributeModel->featureLayerPair().feature().attribute( item->data( QgsQuickAttributeFormModel::FieldIndex ).toInt() ), QgsQuickAttributeFormModel::AttributeValue );
207 }
208 else
209 {
210 for ( int i = 0; i < item->rowCount(); ++i )
211 {
212 updateAttributeValue( item->child( i ) );
213 }
214 }
215 }
216
flatten(QgsAttributeEditorContainer * container,QStandardItem * parent,const QString & parentVisibilityExpressions,QVector<QStandardItem * > & items)217 void QgsQuickAttributeFormModelBase::flatten( QgsAttributeEditorContainer *container, QStandardItem *parent, const QString &parentVisibilityExpressions, QVector<QStandardItem *> &items )
218 {
219 for ( QgsAttributeEditorElement *element : container->children() )
220 {
221 switch ( element->type() )
222 {
223 case QgsAttributeEditorElement::AeTypeContainer:
224 {
225 QString visibilityExpression = parentVisibilityExpressions;
226 QgsAttributeEditorContainer *container = static_cast<QgsAttributeEditorContainer *>( element );
227 if ( container->visibilityExpression().enabled() )
228 {
229 if ( visibilityExpression.isNull() )
230 visibilityExpression = container->visibilityExpression().data().expression();
231 else
232 visibilityExpression += " AND " + container->visibilityExpression().data().expression();
233 }
234
235 QVector<QStandardItem *> newItems;
236 flatten( container, parent, visibilityExpression, newItems );
237 if ( !visibilityExpression.isEmpty() )
238 mVisibilityExpressions.append( qMakePair( QgsExpression( visibilityExpression ), newItems ) );
239 break;
240 }
241
242 case QgsAttributeEditorElement::AeTypeField:
243 {
244 QgsAttributeEditorField *editorField = static_cast<QgsAttributeEditorField *>( element );
245 int fieldIndex = editorField->idx();
246 if ( fieldIndex < 0 || fieldIndex >= mLayer->fields().size() )
247 continue;
248
249 QgsField field = mLayer->fields().at( fieldIndex );
250
251 QStandardItem *item = new QStandardItem();
252 item->setData( mLayer->attributeDisplayName( fieldIndex ), QgsQuickAttributeFormModel::Name );
253 item->setData( mAttributeModel->featureLayerPair().feature().attribute( fieldIndex ), QgsQuickAttributeFormModel::AttributeValue );
254 item->setData( !mLayer->editFormConfig().readOnly( fieldIndex ), QgsQuickAttributeFormModel::AttributeEditable );
255 QgsEditorWidgetSetup setup = mLayer->editorWidgetSetup( fieldIndex );
256 item->setData( setup.type(), QgsQuickAttributeFormModel::EditorWidget );
257 item->setData( setup.config(), QgsQuickAttributeFormModel::EditorWidgetConfig );
258 item->setData( mAttributeModel->rememberedAttributes().at( fieldIndex ) ? Qt::Checked : Qt::Unchecked, QgsQuickAttributeFormModel::RememberValue );
259 item->setData( mLayer->fields().at( fieldIndex ), QgsQuickAttributeFormModel::Field );
260 item->setData( QStringLiteral( "field" ), QgsQuickAttributeFormModel::ElementType );
261 item->setData( fieldIndex, QgsQuickAttributeFormModel::FieldIndex );
262 item->setData( container->isGroupBox() ? container->name() : QString(), QgsQuickAttributeFormModel::Group );
263 item->setData( true, QgsQuickAttributeFormModel::CurrentlyVisible );
264 item->setData( true, QgsQuickAttributeFormModel::ConstraintValid );
265 item->setData( field.constraints().constraintDescription(), QgsQuickAttributeFormModel::ConstraintDescription );
266
267 if ( !field.constraints().constraintExpression().isEmpty() )
268 {
269 mConstraints.insert( item, field.constraints().constraintExpression() );
270 }
271
272 items.append( item );
273
274 parent->appendRow( item );
275 break;
276 }
277
278 case QgsAttributeEditorElement::AeTypeRelation:
279 // todo
280 break;
281
282 case QgsAttributeEditorElement::AeTypeInvalid:
283 // todo
284 break;
285
286 case QgsAttributeEditorElement::AeTypeQmlElement:
287 // todo
288 break;
289
290 case QgsAttributeEditorElement::AeTypeHtmlElement:
291 // todo
292 break;
293 }
294 }
295 }
296
updateVisibility(int fieldIndex)297 void QgsQuickAttributeFormModelBase::updateVisibility( int fieldIndex )
298 {
299 QgsFields fields = mAttributeModel->featureLayerPair().feature().fields();
300 mExpressionContext.setFields( fields );
301 mExpressionContext.setFeature( mAttributeModel->featureLayerPair().feature() );
302
303 for ( const VisibilityExpression &it : mVisibilityExpressions )
304 {
305 if ( fieldIndex == -1 || it.first.referencedAttributeIndexes( fields ).contains( fieldIndex ) )
306 {
307 QgsExpression exp = it.first;
308 exp.prepare( &mExpressionContext );
309
310 bool visible = exp.evaluate( &mExpressionContext ).toInt();
311 for ( QStandardItem *item : it.second )
312 {
313 if ( item->data( QgsQuickAttributeFormModel::CurrentlyVisible ).toBool() != visible )
314 {
315 item->setData( visible, QgsQuickAttributeFormModel::CurrentlyVisible );
316 }
317 }
318 }
319 }
320
321 bool allConstraintsValid = true;
322 QMap<QStandardItem *, QgsExpression>::ConstIterator constraintIterator( mConstraints.constBegin() );
323 for ( ; constraintIterator != mConstraints.constEnd(); ++constraintIterator )
324 {
325 QStandardItem *item = constraintIterator.key();
326 QgsExpression exp = constraintIterator.value();
327 exp.prepare( &mExpressionContext );
328 bool constraintSatisfied = exp.evaluate( &mExpressionContext ).toBool();
329
330 if ( constraintSatisfied != item->data( QgsQuickAttributeFormModel::ConstraintValid ).toBool() )
331 {
332 item->setData( constraintSatisfied, QgsQuickAttributeFormModel::ConstraintValid );
333 }
334
335 if ( !item->data( QgsQuickAttributeFormModel::ConstraintValid ).toBool() )
336 {
337 allConstraintsValid = false;
338 }
339 }
340
341 setConstraintsValid( allConstraintsValid );
342 }
343
constraintsValid() const344 bool QgsQuickAttributeFormModelBase::constraintsValid() const
345 {
346 return mConstraintsValid;
347 }
348
attribute(const QString & name) const349 QVariant QgsQuickAttributeFormModelBase::attribute( const QString &name ) const
350 {
351 if ( !mLayer )
352 return QVariant();
353
354 int idx = mLayer->fields().indexOf( name );
355 return mAttributeModel->featureLayerPair().feature().attribute( idx );
356 }
357
setConstraintsValid(bool constraintsValid)358 void QgsQuickAttributeFormModelBase::setConstraintsValid( bool constraintsValid )
359 {
360 if ( constraintsValid == mConstraintsValid )
361 return;
362
363 mConstraintsValid = constraintsValid;
364 emit constraintsValidChanged();
365 }
366
hasTabs() const367 bool QgsQuickAttributeFormModelBase::hasTabs() const
368 {
369 return mHasTabs;
370 }
371
setHasTabs(bool hasTabs)372 void QgsQuickAttributeFormModelBase::setHasTabs( bool hasTabs )
373 {
374 if ( hasTabs == mHasTabs )
375 return;
376
377 mHasTabs = hasTabs;
378 emit hasTabsChanged();
379 }
380
save()381 void QgsQuickAttributeFormModelBase::save()
382 {
383 mAttributeModel->save();
384 }
385
create()386 void QgsQuickAttributeFormModelBase::create()
387 {
388 mAttributeModel->create();
389 }
390
391 /// @endcond
392