QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsrelationwidgetwrapper.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrelationwidgetwrapper.cpp
3 --------------------------------------
4 Date : 14.5.2014
5 Copyright : (C) 2014 Matthias Kuhn
6 Email : matthias at opengis dot 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
17
20#include "qgsproject.h"
21#include "qgsrelationmanager.h"
24#include "qgsgui.h"
25#include <QWidget>
26
27QgsRelationWidgetWrapper::QgsRelationWidgetWrapper( QgsVectorLayer *vl, const QgsRelation &relation, QWidget *editor, QWidget *parent )
28 : QgsRelationWidgetWrapper( QStringLiteral( "relation_editor" ), vl, relation, editor, parent )
29{
30}
31
32QgsRelationWidgetWrapper::QgsRelationWidgetWrapper( const QString &relationEditorName, QgsVectorLayer *vl, const QgsRelation &relation, QWidget *editor, QWidget *parent )
33 : QgsWidgetWrapper( vl, editor, parent )
34 , mRelation( relation )
35 , mRelationEditorId( relationEditorName )
36{
37}
38
39QWidget *QgsRelationWidgetWrapper::createWidget( QWidget *parent )
40{
41 QgsAttributeForm *form = qobject_cast<QgsAttributeForm *>( parent );
42 if ( form )
44
45 QgsAbstractRelationEditorWidget *relationEditorWidget = QgsGui::relationWidgetRegistry()->create( mRelationEditorId, widgetConfig(), parent );
46
47 if ( !relationEditorWidget )
48 {
49 QgsLogger::warning( QStringLiteral( "Failed to create relation widget \"%1\", fallback to \"basic\" relation widget" ).arg( mRelationEditorId ) );
50 relationEditorWidget = QgsGui::relationWidgetRegistry()->create( QStringLiteral( "relation_editor" ), widgetConfig(), parent );
51 }
52
54
55 return relationEditorWidget;
56}
57
59{
60 if ( mWidget && mRelation.isValid() )
61 mWidget->setFeature( feature );
62}
63
65{
66 if ( mWidget && mRelation.isValid() )
67 mWidget->setMultiEditFeatureIds( fids );
68}
69
71{
72 if ( mWidget )
73 mWidget->setVisible( visible );
74}
75
76void QgsRelationWidgetWrapper::aboutToSave()
77{
78 if ( !mRelation.isValid() || !widget() || !widget()->isVisible() || mRelation.referencingLayer() == mRelation.referencedLayer() || ( mNmRelation.isValid() && mNmRelation.referencedLayer() == mRelation.referencedLayer() ) )
79 return;
80
81 // If the layer is already saved before, return
82 const QgsAttributeEditorContext *ctx = &context();
83 do
84 {
85 if ( ctx->relation().isValid() && ( ctx->relation().referencedLayer() == mRelation.referencingLayer()
86 || ( mNmRelation.isValid() && ctx->relation().referencedLayer() == mNmRelation.referencedLayer() ) )
87 )
88 {
89 return;
90 }
91 ctx = ctx->parentContext();
92 }
93 while ( ctx );
94
95 // Calling isModified() will emit a beforeModifiedCheck()
96 // signal that will make the embedded form to send any
97 // outstanding widget changes to the edit buffer
98 mRelation.referencingLayer()->isModified();
99
100 if ( mNmRelation.isValid() )
101 mNmRelation.referencedLayer()->isModified();
102}
103
105{
106 return mRelation;
107}
108
109void QgsRelationWidgetWrapper::widgetValueChanged( const QString &attribute, const QVariant &newValue, bool attributeChanged )
110{
111 if ( mWidget && attributeChanged )
112 {
113 QgsFeature feature { mWidget->feature() };
114 if ( feature.attribute( attribute ) != newValue )
115 {
116 feature.setAttribute( attribute, newValue );
117 QgsAttributeEditorContext newContext { mWidget->editorContext() };
118 newContext.setParentFormFeature( feature );
119 mWidget->setEditorContext( newContext );
120 mWidget->setFeature( feature, false );
121 mWidget->parentFormValueChanged( attribute, newValue );
122 }
123 }
124}
125
127{
129 return visibleButtons().testFlag( QgsAttributeEditorRelation::Button::Unlink );
131}
132
134{
138}
139
140void QgsRelationWidgetWrapper::setShowSaveChildEditsButton( bool showSaveChildEditsButton )
141{
145}
146
148{
149 return false;
150}
151
153{
154 Q_UNUSED( showLabel )
155}
156
158{
159 QgsAbstractRelationEditorWidget *w = qobject_cast<QgsAbstractRelationEditorWidget *>( editor );
160
161 // if the editor cannot be cast to relation editor, insert a new one
162 if ( !w )
163 {
164 w = QgsGui::relationWidgetRegistry()->create( mRelationEditorId, widgetConfig(), editor );
165 if ( ! editor->layout() )
166 {
167 editor->setLayout( new QVBoxLayout( editor ) );
168 }
169 editor->layout()->addWidget( w );
170 }
171
173
174 // read the legacy config of force-suppress-popup to support settings made on autoconfigurated forms
175 // it will be overwritten on specific widget configuration
176 if ( config( QStringLiteral( "force-suppress-popup" ), false ).toBool() )
177 {
178 const_cast<QgsVectorLayerTools *>( myContext.vectorLayerTools() )->setForceSuppressFormPopup( true );
179 }
180
181 /* TODO: this seems to have no effect
182 if ( config( QStringLiteral( "hide-save-child-edits" ), false ).toBool() )
183 {
184 w->setShowSaveChildEditsButton( false );
185 }
186 */
187
188 // read the legacy config of nm-rel to support settings made on autoconfigurated forms
189 // it will be overwritten on specific widget configuration
190 mNmRelation = QgsProject::instance()->relationManager()->relation( config( QStringLiteral( "nm-rel" ) ).toString() );
191
192 // If this widget is already embedded by the same relation, reduce functionality
193 const QgsAttributeEditorContext *ctx = &context();
194 do
195 {
196 if ( ( ctx->relation().id() == mRelation.id() && ctx->formMode() == QgsAttributeEditorContext::Embed )
197 || ( mNmRelation.isValid() && ctx->relation().id() == mNmRelation.id() ) )
198 {
199 w->setVisible( false );
200 break;
201 }
202 ctx = ctx->parentContext();
203 }
204 while ( ctx );
205
206 w->setEditorContext( myContext );
207 w->setRelations( mRelation, mNmRelation );
208
209 mWidget = w;
210}
211
213{
214 return mWidget;
215}
216
218{
220 return visibleButtons().testFlag( QgsAttributeEditorRelation::Button::Link );
222}
223
225{
229}
230
232{
234 return visibleButtons().testFlag( QgsAttributeEditorRelation::Button::SaveChildEdits );
236}
237
238void QgsRelationWidgetWrapper::setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons )
239{
240 if ( ! mWidget )
241 return;
242 QVariantMap config = mWidget->config();
243 config.insert( "buttons", qgsFlagValueToKeys( buttons ) );
244
245 mWidget->setConfig( config );
246}
247
248QgsAttributeEditorRelation::Buttons QgsRelationWidgetWrapper::visibleButtons() const
249{
250 return qgsFlagKeysToValue( mWidget->config().value( QStringLiteral( "buttons" ) ).toString(), QgsAttributeEditorRelation::AllButtons );
251}
252
254{
255 if ( mWidget )
256 {
258 //it's set to true if one widget is configured like this but the setting is done generally (influencing all widgets).
260 }
261}
262
264{
265 if ( mWidget )
266 return mWidget->forceSuppressFormPopup();
267
268 return false;
269}
270
271void QgsRelationWidgetWrapper::setNmRelationId( const QVariant &nmRelationId )
272{
273 if ( mWidget )
274 {
275 mNmRelation = QgsProject::instance()->relationManager()->relation( nmRelationId.toString() );
276
277 // If this widget is already embedded by the same relation, reduce functionality
278 const QgsAttributeEditorContext *ctx = &context();
279 while ( ctx && ctx->relation().isValid() )
280 {
281 if ( ( ctx->relation().id() == mRelation.id() && ctx->formMode() == QgsAttributeEditorContext::Embed )
282 || ( mNmRelation.isValid() && ctx->relation().id() == mNmRelation.id() ) )
283 {
284 mWidget->setVisible( false );
285 break;
286 }
287 ctx = ctx->parentContext();
288 }
289
290 mWidget->setRelations( mRelation, mNmRelation );
291 }
292}
293
295{
296 if ( mWidget )
297 return mWidget->nmRelationId();
298 return QVariant();
299}
300
301
302void QgsRelationWidgetWrapper::setLabel( const QString &label )
303{
304 Q_UNUSED( label )
305}
306
308{
309 return QString();
310}
311
312void QgsRelationWidgetWrapper::setWidgetConfig( const QVariantMap &config )
313{
314 if ( mWidget )
315 mWidget->setConfig( config );
316}
317
319{
320 return mWidget ? mWidget->config() : QVariantMap();
321}
Base class to build new relation widgets.
void setMultiEditFeatureIds(const QgsFeatureIds &fids)
Set multiple feature to edit simultaneously.
virtual void setConfig(const QVariantMap &config)=0
Defines the widget configuration.
bool forceSuppressFormPopup() const
Determines the force suppress form popup status that is configured for this widget.
virtual void setEditorContext(const QgsAttributeEditorContext &context)
Sets the editor context.
void relatedFeaturesChanged()
Emit this signal, whenever the related features changed.
void setRelations(const QgsRelation &relation, const QgsRelation &nmrelation)
Sets the relation(s) for this widget If only one relation is set, it will act as a simple 1:N relatio...
QgsAttributeEditorContext editorContext() const
Returns the attribute editor context.
virtual QVariantMap config() const =0
Returns the widget configuration.
virtual void parentFormValueChanged(const QString &attribute, const QVariant &newValue)=0
Called when an attribute value in the parent widget has changed to newValue.
void setFeature(const QgsFeature &feature, bool update=true)
Sets the feature being edited and updates the UI unless update is set to false.
QgsFeature feature() const
Returns the widget's current feature If the widget is in multiedit mode only the first is returned.
QVariant nmRelationId() const
Determines the relation id of the second relation involved in an N:M relation.
void setForceSuppressFormPopup(bool forceSuppressFormPopup)
Sets force suppress form popup status with forceSuppressFormPopup configured for this widget.
This class contains context information for attribute editor widgets.
FormMode formMode() const
Returns the form mode.
@ Multiple
When showing a list of features (e.g. houses as an embedded form in a district form)
const QgsVectorLayerTools * vectorLayerTools() const
Returns the associated vector layer tools.
@ Embed
A form was embedded as a widget on another form.
void setParentFormFeature(const QgsFeature &feature)
Sets the feature of the currently edited parent form.
const QgsAttributeEditorContext * parentContext() const
const QgsRelation & relation() const
Returns the attribute relation.
@ SaveChildEdits
Save child edits button.
void widgetValueChanged(const QString &attribute, const QVariant &value, bool attributeChanged)
Notifies about changes of attributes.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
Definition: qgsfeature.cpp:265
static QgsRelationWidgetRegistry * relationWidgetRegistry()
Returns the global relation widget registry, used for managing all known relation widget factories.
Definition: qgsgui.cpp:88
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
QgsRelationManager * relationManager
Definition: qgsproject.h:114
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
QgsAbstractRelationEditorWidget * create(const QString &widgetType, const QVariantMap &config, QWidget *parent=nullptr) const
Create a relation widget of a given type for a given field.
void relatedFeaturesChanged()
Emit this signal, whenever the related features changed.
Q_DECL_DEPRECATED bool showLabel() const
Defines if a title label should be shown for this widget.
void setVisible(bool visible)
Sets the visibility of the wrapper's widget.
Q_DECL_DEPRECATED void setVisibleButtons(const QgsAttributeEditorRelation::Buttons &buttons)
Defines the buttons which are shown.
QgsRelation relation() const
The relation for which this wrapper is created.
QVariantMap widgetConfig() const
Returns the whole widget config.
Q_DECL_DEPRECATED void setShowLabel(bool showLabel)
Defines if a title label should be shown for this widget.
Q_DECL_DEPRECATED void setLabel(const QString &label=QString())
Sets label for this element If it's empty it takes the relation id as label.
void setWidgetConfig(const QVariantMap &config)
Will set the config of this widget wrapper to the specified config.
void widgetValueChanged(const QString &attribute, const QVariant &newValue, bool attributeChanged)
Will be called when a value in the current edited form or table row changes.
void setForceSuppressFormPopup(bool forceSuppressFormPopup)
Sets force suppress form popup status to forceSuppressFormPopup for this widget and for the vectorLay...
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
Q_DECL_DEPRECATED bool showLinkButton() const
Determines if the "link feature" button should be shown.
Q_DECL_DEPRECATED bool showUnlinkButton() const
Determines if the "unlink feature" button should be shown.
bool forceSuppressFormPopup() const
Determines the force suppress form popup status that is configured for this widget.
bool valid() const override
Returns true if the widget has been properly initialized.
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
void setMultiEditFeatureIds(const QgsFeatureIds &fids)
Set multiple feature to edit simultaneously.
Q_DECL_DEPRECATED void setShowUnlinkButton(bool showUnlinkButton)
Determines if the "unlink feature" button should be shown.
Q_DECL_DEPRECATED QgsAttributeEditorRelation::Buttons visibleButtons() const
Returns the buttons which are shown.
QgsRelationWidgetWrapper(QgsVectorLayer *vl, const QgsRelation &relation, QWidget *editor=nullptr, QWidget *parent=nullptr)
Constructor for QgsRelationWidgetWrapper.
Q_DECL_DEPRECATED QString label() const
Determines the label of this element.
void setNmRelationId(const QVariant &nmRelationId=QVariant())
Sets nmRelationId for the relation id of the second relation involved in an N:M relation.
QVariant nmRelationId() const
Determines the relation id of the second relation involved in an N:M relation.
Q_DECL_DEPRECATED bool showSaveChildEditsButton() const
Determines if the "Save child layer edits" button should be shown.
Q_DECL_DEPRECATED void setShowSaveChildEditsButton(bool showChildEdits)
Determines if the "Save child layer edits" button should be shown.
Q_DECL_DEPRECATED void setShowLinkButton(bool showLinkButton)
Determines if the "link feature" button should be shown.
void setFeature(const QgsFeature &feature) override
QgsVectorLayer * referencedLayer
Definition: qgsrelation.h:47
Q_GADGET QString id
Definition: qgsrelation.h:45
QgsVectorLayer * referencingLayer
Definition: qgsrelation.h:46
bool isValid
Definition: qgsrelation.h:49
Methods in this class are used to handle basic operations on vector layers.
Represents a vector layer which manages a vector based data sets.
bool isModified() const override
Returns true if the provider has been modified since the last commit.
Manages an editor widget Widget and wrapper share the same parent.
QWidget * widget()
Access the widget managed by this wrapper.
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
QVariantMap config() const
Returns the whole config.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:3061
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
Definition: qgis.h:2739
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given keys of a flag.
Definition: qgis.h:2761
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:3060
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37