attributeformmodelbase.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. /***************************************************************************
  2. attributeformmodelbase.cpp - AttributeFormModelBase
  3. ---------------------
  4. begin : 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. #include "attributeformmodel.h"
  16. #include "attributeformmodelbase.h"
  17. #include <QRegularExpression>
  18. #include <qgsattributeeditorcontainer.h>
  19. #include <qgsattributeeditorelement.h>
  20. #include <qgsattributeeditorfield.h>
  21. #include <qgsattributeeditorhtmlelement.h>
  22. #include <qgsattributeeditorqmlelement.h>
  23. #include <qgsattributeeditorrelation.h>
  24. #include <qgsdatetimefieldformatter.h>
  25. #include <qgseditorwidgetsetup.h>
  26. #include <qgsmapthemecollection.h>
  27. #include <qgsproject.h>
  28. #include <qgsrelationmanager.h>
  29. #include <qgsvectorlayer.h>
  30. #include <qgsvectorlayerutils.h>
  31. AttributeFormModelBase::AttributeFormModelBase( QObject *parent )
  32. : QStandardItemModel( 0, 1, parent )
  33. {
  34. connect( QgsProject::instance(), &QgsProject::mapThemeCollectionChanged, this, &AttributeFormModelBase::onMapThemeCollectionChanged );
  35. if ( QgsProject::instance()->mapThemeCollection() )
  36. onMapThemeCollectionChanged();
  37. }
  38. AttributeFormModelBase::~AttributeFormModelBase()
  39. {
  40. delete mTemporaryContainer;
  41. }
  42. void AttributeFormModelBase::onMapThemeCollectionChanged()
  43. {
  44. connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeChanged, this, [ = ] { resetModel(); applyFeatureModel(); } );
  45. }
  46. QHash<int, QByteArray> AttributeFormModelBase::roleNames() const
  47. {
  48. QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
  49. roles[AttributeFormModel::ElementType] = "Type";
  50. roles[AttributeFormModel::Name] = "Name";
  51. roles[AttributeFormModel::AttributeValue] = "AttributeValue";
  52. roles[AttributeFormModel::AttributeEditable] = "AttributeEditable";
  53. roles[AttributeFormModel::EditorWidget] = "EditorWidget";
  54. roles[AttributeFormModel::EditorWidgetConfig] = "EditorWidgetConfig";
  55. roles[AttributeFormModel::RelationEditorWidget] = "RelationEditorWidget";
  56. roles[AttributeFormModel::RelationEditorWidgetConfig] = "RelationEditorWidgetConfig";
  57. roles[AttributeFormModel::RememberValue] = "RememberValue";
  58. roles[AttributeFormModel::Field] = "Field";
  59. roles[AttributeFormModel::RelationId] = "RelationId";
  60. roles[AttributeFormModel::NmRelationId] = "NmRelationId";
  61. roles[AttributeFormModel::Group] = "Group";
  62. roles[AttributeFormModel::ConstraintHardValid] = "ConstraintHardValid";
  63. roles[AttributeFormModel::ConstraintSoftValid] = "ConstraintSoftValid";
  64. roles[AttributeFormModel::ConstraintDescription] = "ConstraintDescription";
  65. roles[AttributeFormModel::AttributeAllowEdit] = "AttributeAllowEdit";
  66. roles[AttributeFormModel::EditorWidgetCode] = "EditorWidgetCode";
  67. roles[AttributeFormModel::TabIndex] = "TabIndex";
  68. roles[AttributeFormModel::Color] = "Color";
  69. return roles;
  70. }
  71. bool AttributeFormModelBase::setData( const QModelIndex &index, const QVariant &value, int role )
  72. {
  73. if ( !qgsVariantEqual( data( index, role ), value ) )
  74. {
  75. switch ( role )
  76. {
  77. case AttributeFormModel::AttributeAllowEdit:
  78. {
  79. QStandardItem *item = itemFromIndex( index );
  80. int fieldIndex = item->data( AttributeFormModel::FieldIndex ).toInt();
  81. mFeatureModel->setData( mFeatureModel->index( fieldIndex ), value, FeatureModel::AttributeAllowEdit );
  82. item->setData( value, AttributeFormModel::AttributeAllowEdit );
  83. updateVisibilityAndConstraints( fieldIndex );
  84. break;
  85. }
  86. case AttributeFormModel::RememberValue:
  87. {
  88. QStandardItem *item = itemFromIndex( index );
  89. int fieldIndex = item->data( AttributeFormModel::FieldIndex ).toInt();
  90. mFeatureModel->setData( mFeatureModel->index( fieldIndex ), value, FeatureModel::RememberAttribute );
  91. item->setData( value, AttributeFormModel::RememberValue );
  92. break;
  93. }
  94. case AttributeFormModel::AttributeValue:
  95. {
  96. QStandardItem *item = itemFromIndex( index );
  97. int fieldIndex = item->data( AttributeFormModel::FieldIndex ).toInt();
  98. bool changed = mFeatureModel->setData( mFeatureModel->index( fieldIndex ), value, FeatureModel::AttributeValue );
  99. if ( changed )
  100. {
  101. item->setData( value, AttributeFormModel::AttributeValue );
  102. emit dataChanged( index, index, QVector<int>() << role );
  103. }
  104. updateDefaultValues( fieldIndex );
  105. updateVisibilityAndConstraints( fieldIndex );
  106. return changed;
  107. }
  108. }
  109. }
  110. return false;
  111. }
  112. FeatureModel *AttributeFormModelBase::featureModel() const
  113. {
  114. return mFeatureModel;
  115. }
  116. void AttributeFormModelBase::setFeatureModel( FeatureModel *featureModel )
  117. {
  118. if ( mFeatureModel == featureModel )
  119. return;
  120. if ( mFeatureModel )
  121. {
  122. disconnect( mFeatureModel, &FeatureModel::currentLayerChanged, this, &AttributeFormModelBase::resetModel );
  123. disconnect( mFeatureModel, &FeatureModel::modelReset, this, &AttributeFormModelBase::applyFeatureModel );
  124. disconnect( mFeatureModel, &FeatureModel::featureUpdated, this, &AttributeFormModelBase::applyFeatureModel );
  125. }
  126. mFeatureModel = featureModel;
  127. connect( mFeatureModel, &FeatureModel::currentLayerChanged, this, &AttributeFormModelBase::resetModel );
  128. connect( mFeatureModel, &FeatureModel::modelReset, this, &AttributeFormModelBase::applyFeatureModel );
  129. connect( mFeatureModel, &FeatureModel::featureUpdated, this, &AttributeFormModelBase::applyFeatureModel );
  130. emit featureModelChanged();
  131. }
  132. void AttributeFormModelBase::resetModel()
  133. {
  134. clear();
  135. mVisibilityExpressions.clear();
  136. mConstraints.clear();
  137. if ( !mFeatureModel )
  138. return;
  139. mLayer = mFeatureModel->layer();
  140. if ( mLayer )
  141. {
  142. QgsAttributeEditorContainer *root;
  143. delete mTemporaryContainer;
  144. mTemporaryContainer = nullptr;
  145. if ( mLayer->editFormConfig().layout() == QgsEditFormConfig::TabLayout )
  146. {
  147. root = mLayer->editFormConfig().invisibleRootContainer();
  148. }
  149. else
  150. {
  151. root = generateRootContainer();
  152. mTemporaryContainer = root;
  153. }
  154. setHasTabs( !root->children().isEmpty() && QgsAttributeEditorElement::AeTypeContainer == root->children().first()->type() );
  155. invisibleRootItem()->setColumnCount( 1 );
  156. if ( mHasTabs )
  157. {
  158. const QList<QgsAttributeEditorElement *> children { root->children() };
  159. int currentTab = 0;
  160. for ( QgsAttributeEditorElement *element : children )
  161. {
  162. if ( element->type() == QgsAttributeEditorElement::AeTypeContainer )
  163. {
  164. QgsAttributeEditorContainer *container = static_cast<QgsAttributeEditorContainer *>( element );
  165. QStandardItem *item = new QStandardItem();
  166. item->setData( element->name(), AttributeFormModel::Name );
  167. item->setData( "container", AttributeFormModel::ElementType );
  168. item->setData( true, AttributeFormModel::CurrentlyVisible );
  169. item->setData( true, AttributeFormModel::ConstraintHardValid );
  170. item->setData( true, AttributeFormModel::ConstraintSoftValid );
  171. invisibleRootItem()->appendRow( item );
  172. if ( container->visibilityExpression().enabled() )
  173. {
  174. mVisibilityExpressions.append( qMakePair( container->visibilityExpression().data(), QVector<QStandardItem *>() << item ) );
  175. }
  176. QVector<QStandardItem *> dummy;
  177. flatten( container, item, QString(), dummy, currentTab, container->backgroundColor() );
  178. currentTab++;
  179. }
  180. }
  181. }
  182. else
  183. {
  184. QVector<QStandardItem *> dummy;
  185. flatten( invisibleRootContainer(), invisibleRootItem(), QString(), dummy );
  186. }
  187. mExpressionContext = mLayer->createExpressionContext();
  188. }
  189. }
  190. void AttributeFormModelBase::applyFeatureModel()
  191. {
  192. for ( int i = 0; i < invisibleRootItem()->rowCount(); ++i )
  193. {
  194. updateAttributeValue( invisibleRootItem()->child( i ) );
  195. }
  196. updateVisibilityAndConstraints();
  197. }
  198. QgsAttributeEditorContainer *AttributeFormModelBase::generateRootContainer() const
  199. {
  200. QgsAttributeEditorContainer *root = new QgsAttributeEditorContainer( QString(), nullptr );
  201. //get fields
  202. QgsFields fields = mLayer->fields();
  203. for ( int i = 0; i < fields.size(); ++i )
  204. {
  205. if ( fields.at( i ).editorWidgetSetup().type() != QStringLiteral( "Hidden" ) )
  206. {
  207. QgsAttributeEditorField *field = new QgsAttributeEditorField( fields.at( i ).name(), i, root );
  208. root->addChildElement( field );
  209. }
  210. }
  211. //get relations
  212. const QList<QgsRelation> referencingRelations = QgsProject::instance()->relationManager()->referencedRelations( mLayer );
  213. for ( const QgsRelation &referencingRelation : referencingRelations )
  214. {
  215. QgsAttributeEditorRelation *relation = new QgsAttributeEditorRelation( referencingRelation, root );
  216. root->addChildElement( relation );
  217. }
  218. return root;
  219. }
  220. QgsAttributeEditorContainer *AttributeFormModelBase::invisibleRootContainer() const
  221. {
  222. return mTemporaryContainer ? mTemporaryContainer : mLayer->editFormConfig().invisibleRootContainer();
  223. }
  224. void AttributeFormModelBase::updateAttributeValue( QStandardItem *item )
  225. {
  226. if ( item->data( AttributeFormModel::ElementType ) == QStringLiteral( "field" ) )
  227. {
  228. int fieldIndex = item->data( AttributeFormModel::FieldIndex ).toInt();
  229. QVariant attributeValue = mFeatureModel->data( mFeatureModel->index( fieldIndex ), FeatureModel::AttributeValue );
  230. item->setData( attributeValue.isNull() ? QVariant() : attributeValue, AttributeFormModel::AttributeValue );
  231. item->setData( mFeatureModel->data( mFeatureModel->index( fieldIndex ), FeatureModel::AttributeAllowEdit ), AttributeFormModel::AttributeAllowEdit );
  232. //set item visibility to false in case it's a linked attribute
  233. item->setData( !mFeatureModel->data( mFeatureModel->index( fieldIndex ), FeatureModel::LinkedAttribute ).toBool(), AttributeFormModel::CurrentlyVisible );
  234. }
  235. else if ( item->data( AttributeFormModel::ElementType ) == QStringLiteral( "qml" ) || item->data( AttributeFormModel::ElementType ) == QStringLiteral( "html" ) )
  236. {
  237. QString code = mEditorWidgetCodes[item];
  238. QRegularExpression re( "expression\\.evaluate\\(\\s*\\\"(.*?[^\\\\])\\\"\\s*\\)" );
  239. QRegularExpressionMatch match = re.match( code );
  240. while ( match.hasMatch() )
  241. {
  242. QString expression = match.captured( 1 );
  243. expression = expression.replace( QStringLiteral( "\\\"" ), QStringLiteral( "\"" ) );
  244. QgsExpressionContext expressionContext = mLayer->createExpressionContext();
  245. expressionContext.setFeature( mFeatureModel->feature() );
  246. QgsExpression exp = QgsExpression( expression );
  247. exp.prepare( &expressionContext );
  248. QVariant result = exp.evaluate( &expressionContext );
  249. QString resultString;
  250. switch ( static_cast<QMetaType::Type>( result.type() ) )
  251. {
  252. case QMetaType::Int:
  253. case QMetaType::UInt:
  254. case QMetaType::Double:
  255. case QMetaType::LongLong:
  256. case QMetaType::ULongLong:
  257. resultString = result.toString();
  258. break;
  259. case QMetaType::Bool:
  260. resultString = result.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" );
  261. break;
  262. default:
  263. resultString = QStringLiteral( "'%1'" ).arg( result.toString() );
  264. break;
  265. }
  266. code = code.mid( 0, match.capturedStart( 0 ) ) + resultString + code.mid( match.capturedEnd( 0 ) );
  267. match = re.match( code );
  268. }
  269. item->setData( code, AttributeFormModel::EditorWidgetCode );
  270. }
  271. else
  272. {
  273. for ( int i = 0; i < item->rowCount(); ++i )
  274. {
  275. updateAttributeValue( item->child( i ) );
  276. }
  277. }
  278. }
  279. void AttributeFormModelBase::flatten( QgsAttributeEditorContainer *container, QStandardItem *parent, const QString &parentVisibilityExpressions, QVector<QStandardItem *> &items, int currentTabIndex, const QColor &color )
  280. {
  281. const QList<QgsAttributeEditorElement *> children { container->children() };
  282. for ( QgsAttributeEditorElement *element : children )
  283. {
  284. switch ( element->type() )
  285. {
  286. case QgsAttributeEditorElement::AeTypeContainer:
  287. {
  288. QString visibilityExpression = parentVisibilityExpressions;
  289. QgsAttributeEditorContainer *innerContainer = static_cast<QgsAttributeEditorContainer *>( element );
  290. if ( innerContainer->visibilityExpression().enabled() )
  291. {
  292. if ( visibilityExpression.isNull() )
  293. visibilityExpression = innerContainer->visibilityExpression().data().expression();
  294. else
  295. visibilityExpression += " AND " + innerContainer->visibilityExpression().data().expression();
  296. }
  297. QVector<QStandardItem *> newItems;
  298. flatten( innerContainer, parent, visibilityExpression, newItems, 0, innerContainer->backgroundColor() );
  299. if ( !visibilityExpression.isEmpty() )
  300. mVisibilityExpressions.append( qMakePair( QgsExpression( visibilityExpression ), newItems ) );
  301. break;
  302. }
  303. case QgsAttributeEditorElement::AeTypeField:
  304. {
  305. QgsAttributeEditorField *editorField = static_cast<QgsAttributeEditorField *>( element );
  306. // editorField->idx() is not working on joined fields
  307. const QgsFields fields = mLayer->fields();
  308. int fieldIndex = fields.lookupField( editorField->name() );
  309. if ( fieldIndex < 0 || fieldIndex >= mLayer->fields().size() )
  310. continue;
  311. QgsField field = mLayer->fields().at( fieldIndex );
  312. QStandardItem *item = new QStandardItem();
  313. item->setData( currentTabIndex, AttributeFormModel::TabIndex );
  314. item->setData( mLayer->attributeDisplayName( fieldIndex ), AttributeFormModel::Name );
  315. item->setData( !mLayer->editFormConfig().readOnly( fieldIndex ) &&
  316. !( field.defaultValueDefinition().isValid() && field.defaultValueDefinition().applyOnUpdate() ), AttributeFormModel::AttributeEditable );
  317. const QgsEditorWidgetSetup setup = findBest( fieldIndex );
  318. item->setData( setup.type(), AttributeFormModel::EditorWidget );
  319. item->setData( setup.config(), AttributeFormModel::EditorWidgetConfig );
  320. item->setData( mFeatureModel->rememberedAttributes().at( fieldIndex ) ? Qt::Checked : Qt::Unchecked, AttributeFormModel::RememberValue );
  321. item->setData( QgsField( field ), AttributeFormModel::Field );
  322. item->setData( "field", AttributeFormModel::ElementType );
  323. item->setData( fieldIndex, AttributeFormModel::FieldIndex );
  324. item->setData( container->isGroupBox() ? container->name() : QString(), AttributeFormModel::Group );
  325. item->setData( true, AttributeFormModel::CurrentlyVisible );
  326. item->setData( true, AttributeFormModel::ConstraintHardValid );
  327. item->setData( true, AttributeFormModel::ConstraintSoftValid );
  328. item->setData( mFeatureModel->data( mFeatureModel->index( fieldIndex ), FeatureModel::AttributeAllowEdit ), AttributeFormModel::AttributeAllowEdit );
  329. if ( color.isValid() )
  330. item->setData( color, AttributeFormModel::Color );
  331. // create constraint description
  332. QStringList descriptions;
  333. if ( field.constraints().constraints() & QgsFieldConstraints::ConstraintExpression )
  334. {
  335. descriptions << ( !field.constraints().constraintDescription().isEmpty()
  336. ? field.constraints().constraintDescription()
  337. : tr( "Expression constraint" ) );
  338. }
  339. if ( field.constraints().constraints() & QgsFieldConstraints::ConstraintNotNull )
  340. {
  341. descriptions << tr( "Not NULL" );
  342. }
  343. if ( field.constraints().constraints() & QgsFieldConstraints::ConstraintUnique )
  344. {
  345. descriptions << tr( "Unique" );
  346. }
  347. item->setData( descriptions.join( ", " ), AttributeFormModel::ConstraintDescription );
  348. updateAttributeValue( item );
  349. mConstraints.insert( item, field.constraints() );
  350. items.append( item );
  351. parent->appendRow( item );
  352. break;
  353. }
  354. case QgsAttributeEditorElement::AeTypeRelation:
  355. {
  356. QgsAttributeEditorRelation *editorRelation = static_cast<QgsAttributeEditorRelation *>( element );
  357. QgsRelation relation = editorRelation->relation();
  358. QStandardItem *item = new QStandardItem();
  359. item->setData( currentTabIndex, AttributeFormModel::TabIndex );
  360. item->setData( relation.name(), AttributeFormModel::Name );
  361. item->setData( true, AttributeFormModel::AttributeEditable );
  362. item->setData( true, AttributeFormModel::CurrentlyVisible );
  363. item->setData( "relation", AttributeFormModel::ElementType );
  364. item->setData( "RelationEditor", AttributeFormModel::EditorWidget );
  365. item->setData( editorRelation->relationWidgetTypeId(), AttributeFormModel::RelationEditorWidget );
  366. item->setData( editorRelation->relationEditorConfiguration(), AttributeFormModel::RelationEditorWidgetConfig );
  367. item->setData( relation.id(), AttributeFormModel::RelationId );
  368. item->setData( mLayer->editFormConfig().widgetConfig( relation.id() )[QStringLiteral( "nm-rel" )].toString(), AttributeFormModel::NmRelationId );
  369. item->setData( container->isGroupBox() ? container->name() : QString(), AttributeFormModel::Group );
  370. item->setData( true, AttributeFormModel::CurrentlyVisible );
  371. item->setData( true, AttributeFormModel::ConstraintHardValid );
  372. item->setData( true, AttributeFormModel::ConstraintSoftValid );
  373. item->setData( true, AttributeFormModel::AttributeAllowEdit );
  374. items.append( item );
  375. parent->appendRow( item );
  376. break;
  377. }
  378. case QgsAttributeEditorElement::AeTypeQmlElement:
  379. {
  380. QgsAttributeEditorQmlElement *qmlElement = static_cast<QgsAttributeEditorQmlElement *>( element );
  381. QStandardItem *item = new QStandardItem();
  382. item->setData( currentTabIndex, AttributeFormModel::TabIndex );
  383. item->setData( "qml", AttributeFormModel::ElementType );
  384. item->setData( qmlElement->name(), AttributeFormModel::Name );
  385. item->setData( true, AttributeFormModel::CurrentlyVisible );
  386. item->setData( false, AttributeFormModel::AttributeEditable );
  387. item->setData( false, AttributeFormModel::AttributeAllowEdit );
  388. item->setData( container->isGroupBox() ? container->name() : QString(), AttributeFormModel::Group );
  389. mEditorWidgetCodes.insert( item, qmlElement->qmlCode() );
  390. updateAttributeValue( item );
  391. items.append( item );
  392. parent->appendRow( item );
  393. break;
  394. }
  395. case QgsAttributeEditorElement::AeTypeHtmlElement:
  396. {
  397. QgsAttributeEditorHtmlElement *htmlElement = static_cast<QgsAttributeEditorHtmlElement *>( element );
  398. QStandardItem *item = new QStandardItem();
  399. item->setData( currentTabIndex, AttributeFormModel::TabIndex );
  400. item->setData( "html", AttributeFormModel::ElementType );
  401. item->setData( htmlElement->name(), AttributeFormModel::Name );
  402. item->setData( true, AttributeFormModel::CurrentlyVisible );
  403. item->setData( false, AttributeFormModel::AttributeEditable );
  404. item->setData( false, AttributeFormModel::AttributeAllowEdit );
  405. item->setData( container->isGroupBox() ? container->name() : QString(), AttributeFormModel::Group );
  406. mEditorWidgetCodes.insert( item, htmlElement->htmlCode() );
  407. updateAttributeValue( item );
  408. items.append( item );
  409. parent->appendRow( item );
  410. break;
  411. }
  412. case QgsAttributeEditorElement::AeTypeInvalid:
  413. #if _QGIS_VERSION_INT >= 32100
  414. case QgsAttributeEditorElement::AeTypeAction:
  415. #endif
  416. // todo
  417. break;
  418. }
  419. }
  420. }
  421. void AttributeFormModelBase::updateDefaultValues( int fieldIndex )
  422. {
  423. const QgsFields fields = mFeatureModel->feature().fields();
  424. if ( fieldIndex < 0 || fieldIndex > fields.size() )
  425. return;
  426. const QString fieldName = fields.at( fieldIndex ).name();
  427. mExpressionContext.setFields( fields );
  428. mExpressionContext.setFeature( mFeatureModel->feature() );
  429. QMap<QStandardItem *, QgsFieldConstraints>::ConstIterator constraintIterator( mConstraints.constBegin() );
  430. for ( ; constraintIterator != mConstraints.constEnd(); ++constraintIterator )
  431. {
  432. QStandardItem *item = constraintIterator.key();
  433. int fidx = item->data( AttributeFormModel::FieldIndex ).toInt();
  434. if ( fidx == fieldIndex || !fields.at( fidx ).defaultValueDefinition().isValid() || !fields.at( fidx ).defaultValueDefinition().applyOnUpdate() )
  435. continue;
  436. QgsExpression exp( fields.at( fidx ).defaultValueDefinition().expression() );
  437. exp.prepare( &mExpressionContext );
  438. // avoid cost of value update if expression doesn't contain the field which triggered the default values update
  439. if ( !exp.referencedColumns().contains( fieldName ) )
  440. continue;
  441. QVariant defaultValue = exp.evaluate( &mExpressionContext );
  442. bool changed = mFeatureModel->setData( mFeatureModel->index( fidx ), defaultValue, FeatureModel::AttributeValue );
  443. if ( changed )
  444. {
  445. item->setData( defaultValue, AttributeFormModel::AttributeValue );
  446. updateDefaultValues( fidx );
  447. updateVisibilityAndConstraints( fidx );
  448. }
  449. }
  450. }
  451. void AttributeFormModelBase::updateVisibilityAndConstraints( int fieldIndex )
  452. {
  453. QgsFields fields = mFeatureModel->feature().fields();
  454. mExpressionContext.setFields( fields );
  455. mExpressionContext.setFeature( mFeatureModel->feature() );
  456. for ( const VisibilityExpression &it : std::as_const( mVisibilityExpressions ) )
  457. {
  458. if ( fieldIndex == -1 || it.first.referencedAttributeIndexes( fields ).contains( fieldIndex ) )
  459. {
  460. QgsExpression exp = it.first;
  461. exp.prepare( &mExpressionContext );
  462. bool visible = exp.evaluate( &mExpressionContext ).toInt();
  463. for ( QStandardItem *item : std::as_const( it.second ) )
  464. {
  465. if ( item->data( AttributeFormModel::CurrentlyVisible ).toBool() != visible )
  466. {
  467. item->setData( visible, AttributeFormModel::CurrentlyVisible );
  468. emit dataChanged( item->index(), item->index(), QVector<int>() << AttributeFormModel::CurrentlyVisible );
  469. }
  470. }
  471. }
  472. }
  473. // reset contrainsts status of containers
  474. if ( mHasTabs )
  475. {
  476. QStandardItem *root = invisibleRootItem();
  477. for ( int i = 0; i < root->rowCount(); i++ )
  478. {
  479. QStandardItem *item = root->child( i, 0 );
  480. item->setData( true, AttributeFormModel::ConstraintHardValid );
  481. item->setData( true, AttributeFormModel::ConstraintSoftValid );
  482. }
  483. }
  484. bool allConstraintsHardValid = true;
  485. bool allConstraintsSoftValid = true;
  486. QMap<QStandardItem *, QgsFieldConstraints>::ConstIterator constraintIterator( mConstraints.constBegin() );
  487. for ( ; constraintIterator != mConstraints.constEnd(); ++constraintIterator )
  488. {
  489. QStandardItem *item = constraintIterator.key();
  490. const bool isVisible = item->data( AttributeFormModel::CurrentlyVisible ).toBool();
  491. int fidx = item->data( AttributeFormModel::FieldIndex ).toInt();
  492. if ( isVisible && mFeatureModel->data( mFeatureModel->index( fidx ), FeatureModel::AttributeAllowEdit ) == true )
  493. {
  494. QStringList errors;
  495. QgsFeature feature = mFeatureModel->feature();
  496. QString defaultValueClause = mLayer->dataProvider()->defaultValueClause( fidx );
  497. QString attrValue = feature.attribute( fidx ).toString();
  498. // Providers will check for a literal "defaultValueClause" to autogenerate PKs.
  499. // For example, the gpkg provider will generate a fid if it is set to "Autogenerate".
  500. // On QField, if the user leaves the field empty, we will assume he wants to autogenerate it.
  501. // This makes sure, the NOT NULL constraint is skipped in this case.
  502. if ( attrValue.isEmpty() && !defaultValueClause.isEmpty() )
  503. {
  504. feature.setAttribute( fidx, defaultValueClause );
  505. }
  506. bool hardConstraintSatisfied = QgsVectorLayerUtils::validateAttribute( mLayer, feature, fidx, errors, QgsFieldConstraints::ConstraintStrengthHard );
  507. if ( hardConstraintSatisfied != item->data( AttributeFormModel::ConstraintHardValid ).toBool() )
  508. {
  509. item->setData( hardConstraintSatisfied, AttributeFormModel::ConstraintHardValid );
  510. }
  511. if ( !item->data( AttributeFormModel::ConstraintHardValid ).toBool() )
  512. {
  513. allConstraintsHardValid = false;
  514. if ( mHasTabs && item->parent() )
  515. item->parent()->setData( false, AttributeFormModel::ConstraintHardValid );
  516. }
  517. QStringList softErrors;
  518. bool softConstraintSatisfied = QgsVectorLayerUtils::validateAttribute( mLayer, mFeatureModel->feature(), fidx, softErrors, QgsFieldConstraints::ConstraintStrengthSoft );
  519. if ( softConstraintSatisfied != item->data( AttributeFormModel::ConstraintSoftValid ).toBool() )
  520. {
  521. item->setData( softConstraintSatisfied, AttributeFormModel::ConstraintSoftValid );
  522. }
  523. if ( !item->data( AttributeFormModel::ConstraintSoftValid ).toBool() )
  524. {
  525. allConstraintsSoftValid = false;
  526. if ( mHasTabs && item->parent() )
  527. item->parent()->setData( false, AttributeFormModel::ConstraintSoftValid );
  528. }
  529. }
  530. else
  531. {
  532. item->setData( true, AttributeFormModel::ConstraintHardValid );
  533. item->setData( true, AttributeFormModel::ConstraintSoftValid );
  534. }
  535. }
  536. setConstraintsHardValid( allConstraintsHardValid );
  537. setConstraintsSoftValid( allConstraintsSoftValid );
  538. }
  539. bool AttributeFormModelBase::constraintsHardValid() const
  540. {
  541. return mConstraintsHardValid;
  542. }
  543. bool AttributeFormModelBase::constraintsSoftValid() const
  544. {
  545. return mConstraintsSoftValid;
  546. }
  547. QVariant AttributeFormModelBase::attribute( const QString &name )
  548. {
  549. if ( !mLayer )
  550. return QVariant();
  551. int idx = mLayer->fields().indexOf( name );
  552. return mFeatureModel->data( mFeatureModel->index( idx ), FeatureModel::AttributeValue );
  553. }
  554. void AttributeFormModelBase::setConstraintsHardValid( bool constraintsHardValid )
  555. {
  556. if ( constraintsHardValid == mConstraintsHardValid )
  557. return;
  558. mConstraintsHardValid = constraintsHardValid;
  559. emit constraintsHardValidChanged();
  560. }
  561. void AttributeFormModelBase::setConstraintsSoftValid( bool constraintsSoftValid )
  562. {
  563. if ( constraintsSoftValid == mConstraintsSoftValid )
  564. return;
  565. mConstraintsSoftValid = constraintsSoftValid;
  566. emit constraintsSoftValidChanged();
  567. }
  568. QgsEditorWidgetSetup AttributeFormModelBase::findBest( const int fieldIndex )
  569. {
  570. QgsFields fields = mLayer->fields();
  571. //make the default one
  572. QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "TextEdit" ), QVariantMap() );
  573. if ( fieldIndex >= 0 && fieldIndex < fields.count() )
  574. {
  575. //when field has a configured setup, take it
  576. setup = mLayer->editorWidgetSetup( fieldIndex );
  577. if ( !setup.isNull() )
  578. return setup;
  579. //when it's a provider field with default value clause, take Textedit
  580. if ( fields.fieldOrigin( fieldIndex ) == QgsFields::OriginProvider )
  581. {
  582. int providerOrigin = fields.fieldOriginIndex( fieldIndex );
  583. if ( !mLayer->dataProvider()->defaultValueClause( providerOrigin ).isEmpty() )
  584. return setup;
  585. }
  586. //find the best one
  587. const QgsField field = fields.at( fieldIndex );
  588. //on a boolean type take "CheckBox"
  589. if ( field.type() == QVariant::Bool )
  590. setup = QgsEditorWidgetSetup( QStringLiteral( "CheckBox" ), QVariantMap() );
  591. //on a date or time type take "DateTime"
  592. if ( field.isDateOrTime() )
  593. {
  594. QVariantMap config;
  595. config.insert( QStringLiteral( "field_format" ), QgsDateTimeFieldFormatter::defaultFormat( field.type() ) );
  596. config.insert( QStringLiteral( "display_format" ), QgsDateTimeFieldFormatter::defaultFormat( field.type() ) );
  597. config.insert( QStringLiteral( "calendar_popup" ), true );
  598. config.insert( QStringLiteral( "allow_null" ), true );
  599. setup = QgsEditorWidgetSetup( QStringLiteral( "DateTime" ), config );
  600. }
  601. //on numeric types take "Range"
  602. if ( field.type() == QVariant::Int || field.type() == QVariant::Double || field.isNumeric() )
  603. setup = QgsEditorWidgetSetup( QStringLiteral( "Range" ), QVariantMap() );
  604. //if it's a foreign key configured in a relation take "RelationReference"
  605. if ( !mLayer->referencingRelations( fieldIndex ).isEmpty() )
  606. {
  607. QgsRelation relation = mLayer->referencingRelations( fieldIndex )[0];
  608. QVariantMap config;
  609. config.insert( QStringLiteral( "Relation" ), relation.id() );
  610. config.insert( QStringLiteral( "AllowAddFeatures" ), false );
  611. config.insert( QStringLiteral( "ShowOpenFormButton" ), true );
  612. setup = QgsEditorWidgetSetup( QStringLiteral( "RelationReference" ), config );
  613. }
  614. }
  615. return setup;
  616. }
  617. bool AttributeFormModelBase::hasTabs() const
  618. {
  619. return mHasTabs;
  620. }
  621. void AttributeFormModelBase::setHasTabs( bool hasTabs )
  622. {
  623. if ( hasTabs == mHasTabs )
  624. return;
  625. mHasTabs = hasTabs;
  626. emit hasTabsChanged();
  627. }
  628. bool AttributeFormModelBase::save()
  629. {
  630. return mFeatureModel->save();
  631. }
  632. bool AttributeFormModelBase::create()
  633. {
  634. return mFeatureModel->create();
  635. }
  636. bool AttributeFormModelBase::deleteFeature()
  637. {
  638. return mFeatureModel->deleteFeature();
  639. }