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