-
Notifications
You must be signed in to change notification settings - Fork 62
/
attributecontroller.h
240 lines (188 loc) 路 9.55 KB
/
attributecontroller.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/***************************************************************************
attributecontroller.h
--------------------------------------
Date : 20.4.2021
Copyright : (C) 2021 by Peter Petrik
Email : zilolv@gmail.com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef ATTRIBUTECONTROLLER_H
#define ATTRIBUTECONTROLLER_H
#include <QSortFilterProxyModel>
#include <QObject>
#include <QVariant>
#include <memory>
#include <QMap>
#include <QVector>
#include <QUuid>
#include "inputconfig.h"
#include "featurelayerpair.h"
#include "attributedata.h"
#include "attributeformproxymodel.h"
#include "attributetabproxymodel.h"
#include "rememberattributescontroller.h"
#include "qgsfeature.h"
#include "qgsproject.h"
#include "qgseditformconfig.h"
#include "qgsexpressioncontext.h"
#include "qgsattributeeditorcontainer.h"
#include "variablesmanager.h"
class AttributeFormModel;
class AttributeTabModel;
class QgsVectorLayer;
/**
* This is implementation of the controller between Attribute*Model
* and the QML's .FeatureForm. It is responsible for creation of the
* models, and CRUD management between QgsFeature and the form. It connects
* the QgsFeature Fields on the backend side and the QML widgets on the user side
*
* Remember values functionality is done by RememberAttributes controller.
*
* \note QML Type: AttributeController
*/
class AttributeController : public QObject
{
Q_OBJECT
/**
* FeatureLayerPair for the model. Input for attributes model.
*/
Q_PROPERTY( FeatureLayerPair featureLayerPair READ featureLayerPair WRITE setFeatureLayerPair NOTIFY featureLayerPairChanged )
// this is never nullptr (a form with no tabs will be parsed as having a single tab)
Q_PROPERTY( AttributeTabProxyModel *attributeTabProxyModel READ attributeTabProxyModel NOTIFY attributeTabProxyModelChanged )
//! Returns TRUE if form is in Drag&Drop mode and has any tabs
Q_PROPERTY( bool hasTabs READ hasTabs NOTIFY hasTabsChanged )
//! Returns TRUE if has any changes
Q_PROPERTY( bool hasAnyChanges READ hasAnyChanges NOTIFY hasAnyChangesChanged )
Q_PROPERTY( RememberAttributesController *rememberAttributesController READ rememberAttributesController WRITE setRememberAttributesController NOTIFY rememberAttributesChanged )
//! Returns extended expression context for attributes evaluation.
Q_PROPERTY( VariablesManager *variablesManager READ variablesManager WRITE setVariablesManager NOTIFY variablesManagerChanged )
//! Returns TRUE if any field do not pass necessary validation, false otherwise
Q_PROPERTY( bool hasValidationErrors READ hasValidationErrors NOTIFY hasValidationErrorsChanged )
/**
* If the featureLayerPair in this controller is a child feature in relation, it will have associated parent AttributeController saved in this property.
* parent together with linkedRelation is used to automatically prefill fields containing foreign key to parent table (relation reference fields)
*/
Q_PROPERTY( AttributeController *parentController READ parentController WRITE setParentController NOTIFY parentControllerChanged )
/**
* If featureLayerPair is a child feature in relation, it will have associated relation saved in this property
* see parentController documentation for more info
*/
Q_PROPERTY( QgsRelation linkedRelation READ linkedRelation WRITE setLinkedRelation NOTIFY linkedRelationChanged )
public:
AttributeController( QObject *parent = nullptr );
~AttributeController() override;
//! Restore clean/initial state: no layer, no feature!
Q_INVOKABLE void reset();
//! Gets current featureLayerPair
FeatureLayerPair featureLayerPair() const;
//! Sets current featureLayerPair
void setFeatureLayerPair( const FeatureLayerPair &pair );
bool constraintsHardValid() const;
bool constraintsSoftValid() const;
bool hasValidationErrors() const;
bool hasTabs() const;
bool hasAnyChanges() const;
AttributeTabProxyModel *attributeTabProxyModel() const;
AttributeFormProxyModel *attributeFormProxyModelForTab( int tabRow ) const;
Q_INVOKABLE bool deleteFeature();
Q_INVOKABLE bool rollback();
Q_INVOKABLE bool save();
Q_INVOKABLE void acquireId();
int tabCount() const;
// for data modification use setForm*Value() functions
const FormItem *formItem( const QUuid &id ) const;
// for data modification use setTab*Value() functions;
const TabItem *tabItem( int tabRow ) const;
// Returns true if successful; otherwise returns false.
bool setFormShouldRememberValue( const QUuid &id, bool shouldRememberValue );
bool formShouldRememberValue( int fieldIndex ) const;
// Returns true if successful; otherwise returns false.
bool setFormValue( const QUuid &id, QVariant value );
QVariant formValue( int fieldIndex ) const;
RememberAttributesController *rememberAttributesController() const;
void setRememberAttributesController( RememberAttributesController *rememberAttributes );
VariablesManager *variablesManager() const;
void setVariablesManager( VariablesManager *variablesManager );
AttributeController *parentController() const;
void setParentController( AttributeController *newParentController );
const QgsRelation &linkedRelation() const;
void setLinkedRelation( const QgsRelation &newLinkedRelation );
public slots:
void onFeatureAdded( QgsFeatureId newFeatureId );
signals:
void hasAnyChangesChanged();
void rememberAttributesChanged();
void featureLayerPairChanged();
void attributeTabProxyModelChanged();
void hasTabsChanged();
void variablesManagerChanged();
void hasValidationErrorsChanged();
void parentControllerChanged();
void linkedRelationChanged();
void formDataChanged( QUuid uuid, QVector<int> roles = QVector<int>() );
void tabDataChanged( int id );
void formRecalculated();
void featureIdChanged();
void changesCommited();
void commitFailed();
private:
void clearAll();
void setHasAnyChanges( bool hasChanges );
void setHasValidationErrors( bool hasErrors );
void discoverRelations( QgsAttributeEditorContainer *container );
bool isValidTabId( int id ) const;
bool isValidFormId( const QUuid &id ) const;
bool startEditing();
bool commit();
void updateOnLayerChange();
void updateOnFeatureChange();
bool isNewFeature() const;
/**
* Recalculates visibility & constrains & default values
* Note that reevaluate default values is needed only when an attribnute has changed.
* Evaluation of default values for a new feature is done in digitizing controller when a feature is created.
* @param isFormValueChange True if recalculation has to be done after an attribute has changed (called by setFormValue function).
*/
void recalculateDerivedItems( bool isFormValueChange = false, bool isFirstUpdateOfNewFeature = false );
bool recalculateDefaultValues( QSet<QUuid> &changedFormItems, QgsExpressionContext &context, bool isFormValueChange = false, bool isFirstUpdateOfNewFeature = false );
// generate tab
void createTab( QgsAttributeEditorContainer *container );
// flatten groups and tabs within tabs/groups
void flatten( QgsAttributeEditorContainer *container,
int parentTabRow,
const QString &parentVisibilityExpressions,
QVector<QUuid> &items );
// Generates fake root tab for auto-layout
QgsAttributeEditorContainer *autoLayoutTabContainer() const;
//! Returns editor widget setup according params. If is empty, returns a default setup according field's type.
QgsEditorWidgetSetup getEditorWidgetSetup( QgsVectorLayer *layer, int fieldIndex ) const;
//! Fills up relation reference (foreign key) field with parent id
void prefillRelationReferenceField();
/**
* Checks if tab layout is allowed for given container. Function is not recursive and checks only first level elements.
* @param container Suppose to be the root of attributeEditor container.
* @return True if there are only tabs and all other elements are within tabs, otherwise false.
*/
bool allowTabs( QgsAttributeEditorContainer *container );
bool mConstraintsHardValid = false;
bool mConstraintsSoftValid = false;
bool mHasValidationErrors = false;
bool mHasAnyChanges = false;
bool mHasTabs = false;
FeatureLayerPair mFeatureLayerPair;
std::unique_ptr<AttributeTabProxyModel> mAttributeTabProxyModel;
QVector<AttributeFormProxyModel *> mAttributeFormProxyModelForTabItem;
QMap<QUuid, std::shared_ptr<FormItem>> mFormItems; // order of fields in tab is in tab item
QVector<std::shared_ptr<TabItem>> mTabItems; // order of tabs by tab row number
RememberAttributesController *mRememberAttributesController = nullptr; // not owned
VariablesManager *mVariablesManager = nullptr; // not owned
AttributeController *mParentController = nullptr; // not owned
QgsRelation mLinkedRelation;
};
#endif // ATTRIBUTECONTROLLER_H