mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-15 00:07:25 -05:00
Add relation widget registry
This commit is contained in:
parent
112aaf06f8
commit
51cd712c76
@ -113,6 +113,20 @@ Controls if this element should be labeled with a title (field, relation or grou
|
||||
Controls if this element should be labeled with a title (field, relation or groupname).
|
||||
|
||||
.. versionadded:: 2.18
|
||||
%End
|
||||
|
||||
QVariantMap config() const;
|
||||
%Docstring
|
||||
Returns the editor configuration
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
void setConfig( const QVariantMap &config );
|
||||
%Docstring
|
||||
Sets the editor configuration
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
protected:
|
||||
@ -411,18 +425,24 @@ Determines if the "Save child layer edits" button should be shown
|
||||
use visibleButtons() instead
|
||||
%End
|
||||
|
||||
void setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons );
|
||||
void setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons );
|
||||
%Docstring
|
||||
Defines the buttons which are shown
|
||||
|
||||
.. versionadded:: 3.16
|
||||
|
||||
.. deprecated:: QGIS 3.18
|
||||
use setConfig() instead
|
||||
%End
|
||||
|
||||
QgsAttributeEditorRelation::Buttons visibleButtons() const;
|
||||
QgsAttributeEditorRelation::Buttons visibleButtons() const;
|
||||
%Docstring
|
||||
Returns the buttons which are shown
|
||||
|
||||
.. versionadded:: 3.16
|
||||
|
||||
.. deprecated:: QGIS 3.18
|
||||
use setConfig() instead
|
||||
%End
|
||||
|
||||
bool forceSuppressFormPopup() const;
|
||||
@ -469,6 +489,16 @@ Sets ``label`` for this element
|
||||
If it's empty it takes the relation id as label
|
||||
|
||||
.. versionadded:: 3.16
|
||||
%End
|
||||
|
||||
QString relationWidgetTypeId() const;
|
||||
%Docstring
|
||||
Returns the current relation widget type id
|
||||
%End
|
||||
|
||||
void setRelationWidgetTypeId( const QString &relationWidgetTypeId );
|
||||
%Docstring
|
||||
Sets the relation widget type
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
4
python/gui/auto_additions/qgsbasicrelationwidget.py
Normal file
4
python/gui/auto_additions/qgsbasicrelationwidget.py
Normal file
@ -0,0 +1,4 @@
|
||||
# The following has been generated automatically from src/gui/qgsbasicrelationwidget.h
|
||||
QgsBasicRelationWidget.Button.baseClass = QgsBasicRelationWidget
|
||||
QgsBasicRelationWidget.Buttons.baseClass = QgsBasicRelationWidget
|
||||
Buttons = QgsBasicRelationWidget # dirty hack since SIP seems to introduce the flags in module
|
||||
@ -18,7 +18,23 @@ class QgsRelationWidgetWrapper : QgsWidgetWrapper
|
||||
%End
|
||||
public:
|
||||
|
||||
explicit QgsRelationWidgetWrapper( QgsVectorLayer *vl, const QgsRelation &relation, QWidget *editor = 0, QWidget *parent /TransferThis/ = 0 );
|
||||
QgsRelationWidgetWrapper(
|
||||
QgsVectorLayer *vl,
|
||||
const QgsRelation &relation,
|
||||
QWidget *editor /Constrained/ = 0,
|
||||
QWidget *parent /TransferThis,Constrained/ = 0
|
||||
);
|
||||
%Docstring
|
||||
Constructor for QgsRelationWidgetWrapper
|
||||
%End
|
||||
|
||||
QgsRelationWidgetWrapper(
|
||||
const QString &relationEditorName,
|
||||
QgsVectorLayer *vl,
|
||||
const QgsRelation &relation,
|
||||
QWidget *editor = 0,
|
||||
QWidget *parent /TransferThis/ = 0
|
||||
);
|
||||
%Docstring
|
||||
Constructor for QgsRelationWidgetWrapper
|
||||
%End
|
||||
@ -99,18 +115,35 @@ Determines if the "Save child layer edits" button should be shown
|
||||
use visibleButtons() instead
|
||||
%End
|
||||
|
||||
void setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons );
|
||||
void setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons );
|
||||
%Docstring
|
||||
Defines the buttons which are shown
|
||||
|
||||
.. versionadded:: 3.16
|
||||
|
||||
.. deprecated:: QGIS 3.18
|
||||
%End
|
||||
|
||||
QgsAttributeEditorRelation::Buttons visibleButtons() const;
|
||||
QgsAttributeEditorRelation::Buttons visibleButtons() const;
|
||||
%Docstring
|
||||
Returns the buttons which are shown
|
||||
|
||||
.. versionadded:: 3.16
|
||||
|
||||
.. deprecated:: QGIS 3.18
|
||||
%End
|
||||
|
||||
|
||||
void setWidgetConfig( const QVariantMap &config );
|
||||
%Docstring
|
||||
Will set the config of this widget wrapper to the specified config.
|
||||
|
||||
:param config: The config for this wrapper
|
||||
%End
|
||||
|
||||
QVariantMap widgetConfig() const;
|
||||
%Docstring
|
||||
Returns the whole widget config
|
||||
%End
|
||||
|
||||
bool forceSuppressFormPopup() const;
|
||||
|
||||
110
python/gui/auto_generated/qgsbasicrelationwidget.sip.in
Normal file
110
python/gui/auto_generated/qgsbasicrelationwidget.sip.in
Normal file
@ -0,0 +1,110 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsbasicrelationwidget.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsBasicRelationWidget : QgsRelationWidget
|
||||
{
|
||||
%Docstring
|
||||
The default relation widget in QGIS. Successor of the now deprecated {:py:class:`QgsRelationEditorWidget`}.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsbasicrelationwidget.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum Button
|
||||
{
|
||||
Link,
|
||||
Unlink,
|
||||
SaveChildEdits,
|
||||
AddChildFeature,
|
||||
DuplicateChildFeature,
|
||||
DeleteChildFeature,
|
||||
ZoomToChildFeature,
|
||||
AllButtons
|
||||
};
|
||||
typedef QFlags<QgsBasicRelationWidget::Button> Buttons;
|
||||
|
||||
|
||||
QgsBasicRelationWidget( const QVariantMap &config, QWidget *parent /TransferThis/ = 0 );
|
||||
%Docstring
|
||||
Constructor
|
||||
|
||||
:param config: widget configuration
|
||||
:param parent: parent widget
|
||||
%End
|
||||
|
||||
void setViewMode( QgsDualView::ViewMode mode );
|
||||
%Docstring
|
||||
Define the view mode for the dual view
|
||||
%End
|
||||
|
||||
QgsDualView::ViewMode viewMode();
|
||||
%Docstring
|
||||
Gets the view mode for the dual view
|
||||
%End
|
||||
|
||||
void setEditorContext( const QgsAttributeEditorContext &context );
|
||||
%Docstring
|
||||
Sets the editor ``context``
|
||||
|
||||
.. note::
|
||||
|
||||
if context cadDockWidget is null, it won't be possible to digitize
|
||||
the geometry of a referencing feature from this widget
|
||||
%End
|
||||
|
||||
void setVisibleButtons( const Buttons &buttons );
|
||||
%Docstring
|
||||
Defines the buttons which are shown
|
||||
%End
|
||||
|
||||
Buttons visibleButtons() const;
|
||||
%Docstring
|
||||
Returns the buttons which are shown
|
||||
%End
|
||||
|
||||
virtual QVariantMap config() const;
|
||||
|
||||
%Docstring
|
||||
Returns the current configuration
|
||||
%End
|
||||
|
||||
virtual void setConfig( const QVariantMap &config );
|
||||
|
||||
%Docstring
|
||||
Defines the current configuration
|
||||
%End
|
||||
|
||||
virtual void setTitle( const QString &title );
|
||||
|
||||
%Docstring
|
||||
Sets the title of the root groupbox
|
||||
%End
|
||||
|
||||
public slots:
|
||||
virtual void parentFormValueChanged( const QString &attribute, const QVariant &newValue );
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsbasicrelationwidget.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
@ -129,6 +129,13 @@ Returns the registry of subset string editors of data providers
|
||||
%Docstring
|
||||
Returns the registry of provider source widget providers.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
static QgsRelationWidgetRegistry *relationWidgetRegistry() /KeepReference/;
|
||||
%Docstring
|
||||
Returns the global relation widget registry, used for managing all known relation widget factories.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
|
||||
77
python/gui/auto_generated/qgsrelationconfigwidget.sip.in
Normal file
77
python/gui/auto_generated/qgsrelationconfigwidget.sip.in
Normal file
@ -0,0 +1,77 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsrelationconfigwidget.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsRelationConfigWidget : QWidget
|
||||
{
|
||||
%Docstring
|
||||
This class should be subclassed for every configurable relation widget type.
|
||||
|
||||
It implements the GUI configuration widget and transforms this to/from a configuration.
|
||||
|
||||
It will only be instantiated by {:py:class:`QgsRelationWidgetFactory`}
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsrelationconfigwidget.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
explicit QgsRelationConfigWidget( const QgsRelation &relation, QWidget *parent /TransferThis/ );
|
||||
%Docstring
|
||||
Create a new configuration widget
|
||||
|
||||
:param relation: The relation for which the configuration dialog will be created
|
||||
:param parent: A parent widget
|
||||
%End
|
||||
|
||||
virtual QVariantMap config() = 0;
|
||||
%Docstring
|
||||
Create a configuration from the current GUI state
|
||||
|
||||
:return: A widget configuration
|
||||
%End
|
||||
|
||||
virtual void setConfig( const QVariantMap &config ) = 0;
|
||||
%Docstring
|
||||
Update the configuration widget to represent the given configuration.
|
||||
|
||||
:param config: The configuration which should be represented by this widget
|
||||
%End
|
||||
|
||||
QgsVectorLayer *layer();
|
||||
%Docstring
|
||||
Returns the layer for which this configuration widget applies
|
||||
|
||||
:return: The layer
|
||||
%End
|
||||
|
||||
QgsRelation relation() const;
|
||||
%Docstring
|
||||
Returns the relation for which this configuration widget applies
|
||||
|
||||
:return: The relation
|
||||
%End
|
||||
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsrelationconfigwidget.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
226
python/gui/auto_generated/qgsrelationwidget.sip.in
Normal file
226
python/gui/auto_generated/qgsrelationwidget.sip.in
Normal file
@ -0,0 +1,226 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsrelationwidget.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsRelationWidget : QWidget
|
||||
{
|
||||
%Docstring
|
||||
Base class to build new relation widgets.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsrelationwidget.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
|
||||
QgsRelationWidget( const QVariantMap &config, QWidget *parent /TransferThis/ = 0 );
|
||||
%Docstring
|
||||
Constructor
|
||||
%End
|
||||
|
||||
void setRelationFeature( const QgsRelation &relation, const QgsFeature &feature );
|
||||
%Docstring
|
||||
Sets the ``relation`` and the ``feature``
|
||||
%End
|
||||
|
||||
void setRelations( const QgsRelation &relation, const QgsRelation &nmrelation );
|
||||
%Docstring
|
||||
Set the relation(s) for this widget
|
||||
If only one relation is set, it will act as a simple 1:N relation widget
|
||||
If both relations are set, it will act as an N:M relation widget
|
||||
inserting and deleting entries on the intermediate table as required.
|
||||
|
||||
:param relation: Relation referencing the edited table
|
||||
:param nmrelation: Optional reference from the referencing table to a 3rd N:M table
|
||||
%End
|
||||
|
||||
void setFeature( const QgsFeature &feature, bool update = true );
|
||||
%Docstring
|
||||
Sets the ``feature`` being edited and updates the UI unless ``update`` is set to ``False``
|
||||
%End
|
||||
|
||||
void setEditorContext( const QgsAttributeEditorContext &context );
|
||||
%Docstring
|
||||
Sets the editor ``context``
|
||||
|
||||
.. note::
|
||||
|
||||
if context cadDockWidget is null, it won't be possible to digitize
|
||||
the geometry of a referencing feature from this widget
|
||||
%End
|
||||
|
||||
QgsAttributeEditorContext editorContext( ) const;
|
||||
%Docstring
|
||||
Returns the attribute editor context.
|
||||
%End
|
||||
|
||||
QgsIFeatureSelectionManager *featureSelectionManager();
|
||||
%Docstring
|
||||
The feature selection manager is responsible for the selected features
|
||||
which are currently being edited.
|
||||
%End
|
||||
|
||||
bool showLabel() const;
|
||||
%Docstring
|
||||
Defines if a title label should be shown for this widget.
|
||||
%End
|
||||
|
||||
void setShowLabel( bool showLabel );
|
||||
%Docstring
|
||||
Defines if a title label should be shown for this widget.
|
||||
%End
|
||||
|
||||
QVariant nmRelationId() const;
|
||||
%Docstring
|
||||
Determines the relation id of the second relation involved in an N:M relation.
|
||||
%End
|
||||
|
||||
void setNmRelationId( const QVariant &nmRelationId = QVariant() );
|
||||
%Docstring
|
||||
Sets ``nmRelationId`` for the relation id of the second relation involved in an N:M relation.
|
||||
If it's empty, then it's considered as a 1:M relationship.
|
||||
%End
|
||||
|
||||
QString label() const;
|
||||
%Docstring
|
||||
Determines the label of this element
|
||||
%End
|
||||
|
||||
void setLabel( const QString &label = QString() );
|
||||
%Docstring
|
||||
Sets ``label`` for this element
|
||||
If it's empty it takes the relation id as label
|
||||
%End
|
||||
|
||||
QgsFeature feature() const;
|
||||
%Docstring
|
||||
Returns the widget's current feature
|
||||
%End
|
||||
|
||||
bool forceSuppressFormPopup() const;
|
||||
%Docstring
|
||||
Determines the force suppress form popup status that is configured for this widget
|
||||
%End
|
||||
|
||||
void setForceSuppressFormPopup( bool forceSuppressFormPopup );
|
||||
%Docstring
|
||||
Sets force suppress form popup status with ``forceSuppressFormPopup``
|
||||
configured for this widget
|
||||
%End
|
||||
|
||||
virtual QVariantMap config() const = 0;
|
||||
%Docstring
|
||||
Returns the widget configuration
|
||||
%End
|
||||
|
||||
virtual void setConfig( const QVariantMap &config ) = 0;
|
||||
%Docstring
|
||||
Defines the widget configuration
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void parentFormValueChanged( const QString &attribute, const QVariant &newValue ) = 0;
|
||||
%Docstring
|
||||
Called when an ``attribute`` value in the parent widget has changed to ``newValue``
|
||||
%End
|
||||
|
||||
protected slots:
|
||||
|
||||
void toggleEditing( bool state );
|
||||
%Docstring
|
||||
Toggles editing state of the widget
|
||||
%End
|
||||
|
||||
void saveEdits();
|
||||
%Docstring
|
||||
Saves the current modifications in the relation
|
||||
%End
|
||||
|
||||
void addFeature( const QgsGeometry &geometry = QgsGeometry() );
|
||||
%Docstring
|
||||
Adds a new feature with given ``geometry``
|
||||
%End
|
||||
|
||||
void deleteFeature( QgsFeatureId fid = QgsFeatureId() );
|
||||
%Docstring
|
||||
Delete a feature with given ``fid``
|
||||
%End
|
||||
|
||||
void deleteSelectedFeatures();
|
||||
%Docstring
|
||||
Deletes the currently selected features
|
||||
%End
|
||||
|
||||
void linkFeature();
|
||||
%Docstring
|
||||
Links a new feature to the relation
|
||||
%End
|
||||
|
||||
void onLinkFeatureDlgAccepted();
|
||||
%Docstring
|
||||
Called when the link feature dialog is confirmed by the user
|
||||
%End
|
||||
|
||||
void unlinkFeature( QgsFeatureId fid = QgsFeatureId() );
|
||||
%Docstring
|
||||
Unlinks a feature with given ``fid``
|
||||
%End
|
||||
|
||||
void unlinkSelectedFeatures();
|
||||
%Docstring
|
||||
Unlinks the selected features from the relation
|
||||
%End
|
||||
|
||||
void duplicateFeature();
|
||||
%Docstring
|
||||
Duplicates a feature
|
||||
%End
|
||||
|
||||
void zoomToSelectedFeatures();
|
||||
%Docstring
|
||||
Zooms to the selected features
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
|
||||
|
||||
void updateTitle();
|
||||
%Docstring
|
||||
Updates the title contents to reflect the current state of the widget
|
||||
%End
|
||||
|
||||
void deleteFeatures( const QgsFeatureIds &fids );
|
||||
%Docstring
|
||||
Deletes the features with ``fids``
|
||||
%End
|
||||
|
||||
void unlinkFeatures( const QgsFeatureIds &fids );
|
||||
%Docstring
|
||||
Unlinks the features with ``fids``
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsrelationwidget.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
75
python/gui/auto_generated/qgsrelationwidgetfactory.sip.in
Normal file
75
python/gui/auto_generated/qgsrelationwidgetfactory.sip.in
Normal file
@ -0,0 +1,75 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsrelationwidgetfactory.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsRelationWidgetFactory
|
||||
{
|
||||
%Docstring
|
||||
Factory class for creating relation widgets and their corresponding config widgets
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsrelationwidgetfactory.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsRelationWidgetFactory();
|
||||
%Docstring
|
||||
Creates a new relation widget factory with given ``name``
|
||||
%End
|
||||
|
||||
virtual ~QgsRelationWidgetFactory();
|
||||
|
||||
virtual QString type() const = 0;
|
||||
%Docstring
|
||||
Returns the machine readable identifier name of this widget type
|
||||
%End
|
||||
|
||||
virtual QString name() const = 0;
|
||||
%Docstring
|
||||
Returns the human readable identifier name of this widget type
|
||||
%End
|
||||
|
||||
virtual QgsRelationWidget *create( const QVariantMap &config, QWidget *parent = 0 ) const = 0 /Factory/;
|
||||
%Docstring
|
||||
Override this in your implementation.
|
||||
Create a new relation widget. Call :py:func:`QgsEditorWidgetRegistry.create()`
|
||||
instead of calling this method directly.
|
||||
|
||||
:param config: The widget configuration to build the widget with
|
||||
:param parent: The parent for the wrapper class and any created widget.
|
||||
|
||||
:return: A new widget wrapper
|
||||
%End
|
||||
|
||||
virtual QgsRelationConfigWidget *configWidget( const QgsRelation &relation, QWidget *parent ) const = 0 /Factory/;
|
||||
%Docstring
|
||||
Override this in your implementation.
|
||||
Create a new configuration widget for this widget type.
|
||||
|
||||
:param relation: The relation for which the widget will be created
|
||||
:param parent: The parent widget of the created config widget
|
||||
|
||||
:return: A configuration widget
|
||||
%End
|
||||
};
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsrelationwidgetfactory.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
81
python/gui/auto_generated/qgsrelationwidgetregistry.sip.in
Normal file
81
python/gui/auto_generated/qgsrelationwidgetregistry.sip.in
Normal file
@ -0,0 +1,81 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsrelationwidgetregistry.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsRelationWidgetRegistry
|
||||
{
|
||||
%Docstring
|
||||
Keeps track of the registered relations widgets. New widgets can be registered, old ones deleted.
|
||||
The default {:py:class:`QgsBasicRelationWidget`} is protected from removing.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsrelationwidgetregistry.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsRelationWidgetRegistry();
|
||||
%Docstring
|
||||
Constructor
|
||||
%End
|
||||
|
||||
~QgsRelationWidgetRegistry();
|
||||
|
||||
void addRelationWidget( QgsRelationWidgetFactory *widgetFactory /Transfer/ );
|
||||
%Docstring
|
||||
Adds a new registered relation ``widgetFactory``
|
||||
%End
|
||||
|
||||
void removeRelationWidget( const QString &widgetType );
|
||||
%Docstring
|
||||
Removes a registered relation widget with given ``widgetType``
|
||||
%End
|
||||
|
||||
QStringList relationWidgetNames();
|
||||
%Docstring
|
||||
Returns a list of names of registered relation widgets
|
||||
%End
|
||||
|
||||
QMap<QString, QgsRelationWidgetFactory *> factories() const;
|
||||
%Docstring
|
||||
Gets access to all registered factories
|
||||
%End
|
||||
|
||||
QgsRelationWidget *create( const QString &widgetType, const QVariantMap &config, QWidget *parent = 0 ) const /TransferBack/;
|
||||
%Docstring
|
||||
Create a relation widget of a given type for a given field.
|
||||
|
||||
:param widgetType: The widget type to create a relation editor for
|
||||
:param config: The configuration of the widget
|
||||
:param parent:
|
||||
%End
|
||||
|
||||
QgsRelationConfigWidget *createConfigWidget( const QString &widgetType, const QgsRelation &relation, QWidget *parent = 0 ) const /TransferBack/;
|
||||
%Docstring
|
||||
Creates a configuration widget
|
||||
|
||||
:param widgetType: The widget type to create a configuration widget for
|
||||
:param relation: The relation for which this widget will be created
|
||||
:param parent: The parent widget for the created widget
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsrelationwidgetregistry.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
@ -181,6 +181,11 @@
|
||||
%Include auto_generated/qgsrasterpyramidsoptionswidget.sip
|
||||
%Include auto_generated/qgsratiolockbutton.sip
|
||||
%Include auto_generated/qgsrelationeditorwidget.sip
|
||||
%Include auto_generated/qgsrelationconfigwidget.sip
|
||||
%Include auto_generated/qgsbasicrelationwidget.sip
|
||||
%Include auto_generated/qgsrelationwidget.sip
|
||||
%Include auto_generated/qgsrelationwidgetfactory.sip
|
||||
%Include auto_generated/qgsrelationwidgetregistry.sip
|
||||
%Include auto_generated/qgsrubberband.sip
|
||||
%Include auto_generated/qgsscalecombobox.sip
|
||||
%Include auto_generated/qgsscalerangewidget.sip
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
***************************************************************************/
|
||||
#include "qgsattributeeditorelement.h"
|
||||
#include "qgsrelationmanager.h"
|
||||
#include "qgsxmlutils.h"
|
||||
|
||||
|
||||
void QgsAttributeEditorContainer::addChildElement( QgsAttributeEditorElement *widget )
|
||||
@ -118,6 +119,11 @@ QDomElement QgsAttributeEditorElement::toDomElement( QDomDocument &doc ) const
|
||||
QDomElement elem = doc.createElement( typeIdentifier() );
|
||||
elem.setAttribute( QStringLiteral( "name" ), mName );
|
||||
elem.setAttribute( QStringLiteral( "showLabel" ), mShowLabel );
|
||||
|
||||
QDomElement elemConfig = QgsXmlUtils::writeVariant( mConfig, doc );
|
||||
elemConfig.setTagName( QStringLiteral( "config" ) );
|
||||
elem.appendChild( elemConfig );
|
||||
|
||||
saveConfiguration( elem );
|
||||
return elem;
|
||||
}
|
||||
@ -132,13 +138,24 @@ void QgsAttributeEditorElement::setShowLabel( bool showLabel )
|
||||
mShowLabel = showLabel;
|
||||
}
|
||||
|
||||
QVariantMap QgsAttributeEditorElement::config() const
|
||||
{
|
||||
return mConfig;
|
||||
}
|
||||
|
||||
void QgsAttributeEditorElement::setConfig( const QVariantMap &config )
|
||||
{
|
||||
mConfig = config;
|
||||
}
|
||||
|
||||
void QgsAttributeEditorRelation::saveConfiguration( QDomElement &elem ) const
|
||||
{
|
||||
elem.setAttribute( QStringLiteral( "relation" ), mRelation.id() );
|
||||
elem.setAttribute( QStringLiteral( "buttons" ), qgsFlagValueToKeys( mButtons ) );
|
||||
elem.setAttribute( QStringLiteral( "buttons" ), mConfig.value( QStringLiteral( "buttons" ) ).toString() );
|
||||
elem.setAttribute( QStringLiteral( "forceSuppressFormPopup" ), mForceSuppressFormPopup );
|
||||
elem.setAttribute( QStringLiteral( "nmRelationId" ), mNmRelationId.toString() );
|
||||
elem.setAttribute( QStringLiteral( "label" ), mLabel );
|
||||
elem.setAttribute( QStringLiteral( "relationWidgetTypeId" ), mRelationWidgetTypeId );
|
||||
}
|
||||
|
||||
QString QgsAttributeEditorRelation::typeIdentifier() const
|
||||
@ -211,6 +228,16 @@ QString QgsAttributeEditorRelation::label() const
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
QString QgsAttributeEditorRelation::relationWidgetTypeId() const
|
||||
{
|
||||
return mRelationWidgetTypeId;
|
||||
}
|
||||
|
||||
void QgsAttributeEditorRelation::setRelationWidgetTypeId( const QString &relationWidgetTypeId )
|
||||
{
|
||||
mRelationWidgetTypeId = relationWidgetTypeId;
|
||||
}
|
||||
|
||||
QgsAttributeEditorElement *QgsAttributeEditorQmlElement::clone( QgsAttributeEditorElement *parent ) const
|
||||
{
|
||||
QgsAttributeEditorQmlElement *element = new QgsAttributeEditorQmlElement( name(), parent );
|
||||
|
||||
@ -135,12 +135,27 @@ class CORE_EXPORT QgsAttributeEditorElement SIP_ABSTRACT
|
||||
*/
|
||||
void setShowLabel( bool showLabel );
|
||||
|
||||
/**
|
||||
* Returns the editor configuration
|
||||
*
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
QVariantMap config() const;
|
||||
|
||||
/**
|
||||
* Sets the editor configuration
|
||||
*
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
void setConfig( const QVariantMap &config );
|
||||
|
||||
protected:
|
||||
#ifndef SIP_RUN
|
||||
AttributeEditorType mType;
|
||||
QString mName;
|
||||
QgsAttributeEditorElement *mParent = nullptr;
|
||||
bool mShowLabel;
|
||||
QVariantMap mConfig;
|
||||
#endif
|
||||
|
||||
private:
|
||||
@ -458,14 +473,16 @@ class CORE_EXPORT QgsAttributeEditorRelation : public QgsAttributeEditorElement
|
||||
/**
|
||||
* Defines the buttons which are shown
|
||||
* \since QGIS 3.16
|
||||
* \deprecated since QGIS 3.18 use setConfig() instead
|
||||
*/
|
||||
void setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons );
|
||||
Q_DECL_DEPRECATED void setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons );
|
||||
|
||||
/**
|
||||
* Returns the buttons which are shown
|
||||
* \since QGIS 3.16
|
||||
* \deprecated since QGIS 3.18 use setConfig() instead
|
||||
*/
|
||||
QgsAttributeEditorRelation::Buttons visibleButtons() const {return mButtons;}
|
||||
Q_DECL_DEPRECATED QgsAttributeEditorRelation::Buttons visibleButtons() const {return mButtons;}
|
||||
|
||||
/**
|
||||
* Determines the force suppress form popup status.
|
||||
@ -507,6 +524,16 @@ class CORE_EXPORT QgsAttributeEditorRelation : public QgsAttributeEditorElement
|
||||
*/
|
||||
void setLabel( const QString &label = QString() );
|
||||
|
||||
/**
|
||||
* Returns the current relation widget type id
|
||||
*/
|
||||
QString relationWidgetTypeId() const;
|
||||
|
||||
/**
|
||||
* Sets the relation widget type
|
||||
*/
|
||||
void setRelationWidgetTypeId( const QString &relationWidgetTypeId );
|
||||
|
||||
private:
|
||||
void saveConfiguration( QDomElement &elem ) const override;
|
||||
QString typeIdentifier() const override;
|
||||
@ -516,6 +543,7 @@ class CORE_EXPORT QgsAttributeEditorRelation : public QgsAttributeEditorElement
|
||||
bool mForceSuppressFormPopup = false;
|
||||
QVariant mNmRelationId;
|
||||
QString mLabel;
|
||||
QString mRelationWidgetTypeId;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsAttributeEditorRelation::Buttons )
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsmessagelog.h"
|
||||
|
||||
|
||||
QgsAttributeEditorContainer::~QgsAttributeEditorContainer()
|
||||
{
|
||||
qDeleteAll( mChildren );
|
||||
@ -660,20 +661,36 @@ QgsAttributeEditorElement *QgsEditFormConfig::attributeEditorElementFromDomEleme
|
||||
// At this time, the relations are not loaded
|
||||
// So we only grab the id and delegate the rest to onRelationsLoaded()
|
||||
QgsAttributeEditorRelation *relElement = new QgsAttributeEditorRelation( elem.attribute( QStringLiteral( "relation" ), QStringLiteral( "[None]" ) ), parent );
|
||||
if ( elem.hasAttribute( "buttons" ) )
|
||||
QVariantMap config = QgsXmlUtils::readVariant( elem.firstChildElement( "config" ) ).toMap();
|
||||
|
||||
// load defaults
|
||||
if ( config.isEmpty() )
|
||||
config = relElement->config();
|
||||
|
||||
// pre QGIS 3.18 compatibility
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
if ( ! config.contains( QStringLiteral( "buttons" ) ) )
|
||||
{
|
||||
QString buttonString = elem.attribute( QStringLiteral( "buttons" ), qgsFlagValueToKeys( QgsAttributeEditorRelation::Button::AllButtons ) );
|
||||
relElement->setVisibleButtons( qgsFlagKeysToValue( buttonString, QgsAttributeEditorRelation::Button::AllButtons ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// pre QGIS 3.16 compatibility
|
||||
QgsAttributeEditorRelation::Buttons buttons = QgsAttributeEditorRelation::Button::AllButtons;
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::Link, elem.attribute( QStringLiteral( "showLinkButton" ), QStringLiteral( "1" ) ).toInt() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::Unlink, elem.attribute( QStringLiteral( "showUnlinkButton" ), QStringLiteral( "1" ) ).toInt() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::SaveChildEdits, elem.attribute( QStringLiteral( "showSaveChildEditsButton" ), QStringLiteral( "1" ) ).toInt() );
|
||||
relElement->setVisibleButtons( buttons );
|
||||
if ( elem.hasAttribute( "buttons" ) )
|
||||
{
|
||||
QString buttonString = elem.attribute( QStringLiteral( "buttons" ), qgsFlagValueToKeys( QgsAttributeEditorRelation::Button::AllButtons ) );
|
||||
relElement->setVisibleButtons( qgsFlagKeysToValue( buttonString, QgsAttributeEditorRelation::Button::AllButtons ) );
|
||||
config.insert( "buttons", qgsFlagValueToKeys( relElement->visibleButtons() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// pre QGIS 3.16 compatibility
|
||||
QgsAttributeEditorRelation::Buttons buttons = QgsAttributeEditorRelation::Button::AllButtons;
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::Link, elem.attribute( QStringLiteral( "showLinkButton" ), QStringLiteral( "1" ) ).toInt() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::Unlink, elem.attribute( QStringLiteral( "showUnlinkButton" ), QStringLiteral( "1" ) ).toInt() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::SaveChildEdits, elem.attribute( QStringLiteral( "showSaveChildEditsButton" ), QStringLiteral( "1" ) ).toInt() );
|
||||
config.insert( "buttons", qgsFlagValueToKeys( relElement->visibleButtons() ) );
|
||||
}
|
||||
}
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
|
||||
relElement->setConfig( config );
|
||||
|
||||
if ( elem.hasAttribute( QStringLiteral( "forceSuppressFormPopup" ) ) )
|
||||
{
|
||||
relElement->setForceSuppressFormPopup( elem.attribute( QStringLiteral( "forceSuppressFormPopup" ) ).toInt() );
|
||||
@ -698,6 +715,11 @@ QgsAttributeEditorElement *QgsEditFormConfig::attributeEditorElementFromDomEleme
|
||||
QString label = elem.attribute( QStringLiteral( "label" ) );
|
||||
relElement->setLabel( label );
|
||||
}
|
||||
if ( elem.hasAttribute( "relationWidgetTypeId" ) )
|
||||
{
|
||||
QString relationWidgetTypeId = elem.attribute( QStringLiteral( "relationWidgetTypeId" ) );
|
||||
relElement->setRelationWidgetTypeId( relationWidgetTypeId );
|
||||
}
|
||||
newElement = relElement;
|
||||
}
|
||||
else if ( elem.tagName() == QLatin1String( "attributeEditorQmlElement" ) )
|
||||
|
||||
@ -566,6 +566,13 @@ set(QGIS_GUI_SRCS
|
||||
qgsrasterlayersaveasdialog.cpp
|
||||
qgsrasterpyramidsoptionswidget.cpp
|
||||
qgsrelationeditorwidget.cpp
|
||||
qgsrelationconfigwidget.cpp
|
||||
qgsbasicrelationwidget.cpp
|
||||
qgsbasicrelationconfigwidget.cpp
|
||||
qgsbasicrelationwidgetfactory.cpp
|
||||
qgsrelationwidget.cpp
|
||||
qgsrelationwidgetfactory.cpp
|
||||
qgsrelationwidgetregistry.cpp
|
||||
qgsrubberband.cpp
|
||||
qgsscalecombobox.cpp
|
||||
qgsscalerangewidget.cpp
|
||||
@ -812,6 +819,13 @@ set(QGIS_GUI_HDRS
|
||||
qgsrasterpyramidsoptionswidget.h
|
||||
qgsratiolockbutton.h
|
||||
qgsrelationeditorwidget.h
|
||||
qgsrelationconfigwidget.h
|
||||
qgsbasicrelationwidget.h
|
||||
qgsbasicrelationconfigwidget.h
|
||||
qgsbasicrelationwidgetfactory.h
|
||||
qgsrelationwidget.h
|
||||
qgsrelationwidgetfactory.h
|
||||
qgsrelationwidgetregistry.h
|
||||
qgsrubberband.h
|
||||
qgsscalecombobox.h
|
||||
qgsscalerangewidget.h
|
||||
|
||||
@ -15,6 +15,8 @@
|
||||
|
||||
#include "qgsattributewidgetedit.h"
|
||||
#include "qgsattributesformproperties.h"
|
||||
#include "qgsrelationwidgetregistry.h"
|
||||
#include "qgsrelationconfigwidget.h"
|
||||
|
||||
|
||||
QgsAttributeWidgetEdit::QgsAttributeWidgetEdit( QTreeWidgetItem *item, QWidget *parent )
|
||||
@ -29,7 +31,6 @@ QgsAttributeWidgetEdit::QgsAttributeWidgetEdit( QTreeWidgetItem *item, QWidget *
|
||||
// common configs
|
||||
mShowLabelCheckBox->setChecked( itemData.showLabel() );
|
||||
|
||||
|
||||
switch ( itemData.type() )
|
||||
{
|
||||
case QgsAttributesFormProperties::DnDTreeItemData::Relation:
|
||||
@ -92,18 +93,18 @@ QgsAttributeWidgetRelationEditWidget::QgsAttributeWidgetRelationEditWidget( QWid
|
||||
: QWidget( parent )
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
QMapIterator<QString, QgsRelationWidgetFactory *> it( QgsGui::relationWidgetRegistry()->factories() );
|
||||
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
it.next();
|
||||
mWidgetTypeComboBox->addItem( it.value()->name(), it.key() );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeWidgetRelationEditWidget::setRelationEditorConfiguration( const QgsAttributesFormProperties::RelationEditorConfiguration &config, const QString &relationId )
|
||||
{
|
||||
mRelationShowLinkCheckBox->setChecked( config.buttons.testFlag( QgsAttributeEditorRelation::Button::Link ) );
|
||||
mRelationShowUnlinkCheckBox->setChecked( config.buttons.testFlag( QgsAttributeEditorRelation::Button::Unlink ) );
|
||||
mRelationShowAddChildCheckBox->setChecked( config.buttons.testFlag( QgsAttributeEditorRelation::Button::AddChildFeature ) );
|
||||
mRelationShowDuplicateChildFeatureCheckBox->setChecked( config.buttons.testFlag( QgsAttributeEditorRelation::Button::DuplicateChildFeature ) );
|
||||
mRelationShowZoomToFeatureCheckBox->setChecked( config.buttons.testFlag( QgsAttributeEditorRelation::Button::ZoomToChildFeature ) );
|
||||
mRelationDeleteChildFeatureCheckBox->setChecked( config.buttons.testFlag( QgsAttributeEditorRelation::Button::DeleteChildFeature ) );
|
||||
mRelationShowSaveChildEditsCheckBox->setChecked( config.buttons.testFlag( QgsAttributeEditorRelation::Button::SaveChildEdits ) );
|
||||
|
||||
//load the combo mRelationCardinalityCombo
|
||||
setCardinalityCombo( tr( "Many to one relation" ) );
|
||||
|
||||
@ -115,7 +116,30 @@ void QgsAttributeWidgetRelationEditWidget::setRelationEditorConfiguration( const
|
||||
setCardinalityCombo( QStringLiteral( "%1 (%2)" ).arg( nmrel.referencedLayer()->name(), nmrel.fieldPairs().at( 0 ).referencedField() ), nmrel.id() );
|
||||
}
|
||||
|
||||
mRelationCardinalityCombo->setToolTip( tr( "For a many to many (N:M) relation, the direct link has to be selected. The in-between table will be hidden." ) );
|
||||
int widgetTypeIdx = mWidgetTypeComboBox->findText( config.mRelationWidgetType );
|
||||
mWidgetTypeComboBox->setCurrentIndex( widgetTypeIdx >= 0 ? widgetTypeIdx : 0 );
|
||||
|
||||
const QString widgetType = mWidgetTypeComboBox->currentData().toString();
|
||||
mConfigWidget = QgsGui::relationWidgetRegistry()->createConfigWidget( widgetType, relation, this );
|
||||
mConfigWidget->setConfig( config.mRelationWidgetConfig );
|
||||
mWidgetTypePlaceholderLayout->addWidget( mConfigWidget );
|
||||
|
||||
disconnect( mWidgetTypeComboBoxConnection );
|
||||
|
||||
mWidgetTypeComboBoxConnection = connect( mWidgetTypeComboBox, &QComboBox::currentTextChanged, this, [ = ]()
|
||||
{
|
||||
const QString widgetId = mWidgetTypeComboBox->currentData().toString();
|
||||
|
||||
mConfigWidget->deleteLater();
|
||||
mConfigWidget = QgsGui::relationWidgetRegistry()->createConfigWidget( widgetId, relation, this );
|
||||
mConfigWidget->setConfig( config.mRelationWidgetConfig );
|
||||
mWidgetTypePlaceholderLayout->addWidget( mConfigWidget );
|
||||
update();
|
||||
} );
|
||||
|
||||
mRelationCardinalityCombo->setToolTip( tr( "This is being changed" ) );
|
||||
mRelationCardinalityCombo->addItem( "CHECKED" );
|
||||
|
||||
setNmRelationId( config.nmRelationId );
|
||||
|
||||
mRelationLabelEdit->setText( config.label );
|
||||
@ -126,15 +150,8 @@ void QgsAttributeWidgetRelationEditWidget::setRelationEditorConfiguration( const
|
||||
QgsAttributesFormProperties::RelationEditorConfiguration QgsAttributeWidgetRelationEditWidget::relationEditorConfiguration() const
|
||||
{
|
||||
QgsAttributesFormProperties::RelationEditorConfiguration relEdCfg;
|
||||
QgsAttributeEditorRelation::Buttons buttons;
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::Link, mRelationShowLinkCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::Unlink, mRelationShowUnlinkCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::AddChildFeature, mRelationShowAddChildCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::DuplicateChildFeature, mRelationShowDuplicateChildFeatureCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::ZoomToChildFeature, mRelationShowZoomToFeatureCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::DeleteChildFeature, mRelationDeleteChildFeatureCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsAttributeEditorRelation::Button::SaveChildEdits, mRelationShowSaveChildEditsCheckBox->isChecked() );
|
||||
relEdCfg.buttons = buttons;
|
||||
relEdCfg.mRelationWidgetType = mWidgetTypeComboBox->currentData().toString();
|
||||
relEdCfg.mRelationWidgetConfig = mConfigWidget->config();
|
||||
relEdCfg.nmRelationId = mRelationCardinalityCombo->currentData();
|
||||
relEdCfg.forceSuppressFormPopup = mRelationForceSuppressFormPopupCheckBox->isChecked();
|
||||
relEdCfg.label = mRelationLabelEdit->text();
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QTreeWidgetItem;
|
||||
class QgsRelationConfigWidget;
|
||||
|
||||
/**
|
||||
* Widget to edit the configuration (tab or group box, any field or relation, QML, …) of a form item
|
||||
@ -72,6 +73,9 @@ class GUI_EXPORT QgsAttributeWidgetRelationEditWidget : public QWidget, private
|
||||
private:
|
||||
void setCardinalityCombo( const QString &cardinalityComboItem, const QVariant &auserData = QVariant() );
|
||||
void setNmRelationId( const QVariant &auserData = QVariant() );
|
||||
|
||||
QMetaObject::Connection mWidgetTypeComboBoxConnection;
|
||||
QgsRelationConfigWidget *mConfigWidget = nullptr;
|
||||
};
|
||||
|
||||
#endif // QGSATTRIBUTEWIDGETEDIT_H
|
||||
|
||||
@ -19,12 +19,19 @@
|
||||
#include "qgsattributeeditorcontext.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsrelationmanager.h"
|
||||
#include "qgsrelationwidgetregistry.h"
|
||||
#include "qgsgui.h"
|
||||
#include <QWidget>
|
||||
|
||||
QgsRelationWidgetWrapper::QgsRelationWidgetWrapper( QgsVectorLayer *vl, const QgsRelation &relation, QWidget *editor, QWidget *parent )
|
||||
: QgsRelationWidgetWrapper( QStringLiteral( "basic" ), vl, relation, editor, parent )
|
||||
{
|
||||
}
|
||||
|
||||
QgsRelationWidgetWrapper::QgsRelationWidgetWrapper( const QString &relationEditorName, QgsVectorLayer *vl, const QgsRelation &relation, QWidget *editor, QWidget *parent )
|
||||
: QgsWidgetWrapper( vl, editor, parent )
|
||||
, mRelation( relation )
|
||||
|
||||
, mRelationEditorName( relationEditorName )
|
||||
{
|
||||
}
|
||||
|
||||
@ -34,7 +41,15 @@ QWidget *QgsRelationWidgetWrapper::createWidget( QWidget *parent )
|
||||
if ( form )
|
||||
connect( form, &QgsAttributeForm::widgetValueChanged, this, &QgsRelationWidgetWrapper::widgetValueChanged );
|
||||
|
||||
return new QgsRelationEditorWidget( parent );
|
||||
QWidget *widget = QgsGui::instance()->relationWidgetRegistry()->create( mRelationEditorName, widgetConfig(), parent );
|
||||
|
||||
if ( !widget )
|
||||
{
|
||||
QgsLogger::warning( QStringLiteral( "Failed to create relation widget \"%1\", fallback to \"basic\" relation widget" ).arg( mRelationEditorName ) );
|
||||
widget = QgsGui::instance()->relationWidgetRegistry()->create( QStringLiteral( "basic" ), widgetConfig(), parent );
|
||||
}
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
void QgsRelationWidgetWrapper::setFeature( const QgsFeature &feature )
|
||||
@ -101,25 +116,17 @@ void QgsRelationWidgetWrapper::widgetValueChanged( const QString &attribute, con
|
||||
|
||||
bool QgsRelationWidgetWrapper::showUnlinkButton() const
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
return mWidget->showUnlinkButton();
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
return visibleButtons().testFlag( QgsAttributeEditorRelation::Button::Unlink );
|
||||
}
|
||||
|
||||
void QgsRelationWidgetWrapper::setShowUnlinkButton( bool showUnlinkButton )
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
if ( mWidget )
|
||||
mWidget->setShowUnlinkButton( showUnlinkButton );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
setVisibleButtons( visibleButtons().setFlag( QgsAttributeEditorRelation::Unlink, showUnlinkButton ) );
|
||||
}
|
||||
|
||||
void QgsRelationWidgetWrapper::setShowSaveChildEditsButton( bool showSaveChildEditsButton )
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
if ( mWidget )
|
||||
mWidget->setShowSaveChildEditsButton( showSaveChildEditsButton );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
setVisibleButtons( visibleButtons().setFlag( QgsAttributeEditorRelation::SaveChildEdits, showSaveChildEditsButton ) );
|
||||
}
|
||||
|
||||
bool QgsRelationWidgetWrapper::showLabel() const
|
||||
@ -139,17 +146,12 @@ void QgsRelationWidgetWrapper::setShowLabel( bool showLabel )
|
||||
|
||||
void QgsRelationWidgetWrapper::initWidget( QWidget *editor )
|
||||
{
|
||||
QgsRelationEditorWidget *w = qobject_cast<QgsRelationEditorWidget *>( editor );
|
||||
QgsRelationWidget *w = qobject_cast<QgsRelationWidget *>( editor );
|
||||
|
||||
// if the editor cannot be cast to relation editor, insert a new one
|
||||
if ( !w )
|
||||
{
|
||||
w = new QgsRelationEditorWidget( editor );
|
||||
w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||
if ( ! editor->layout() )
|
||||
{
|
||||
editor->setLayout( new QGridLayout() );
|
||||
}
|
||||
w = QgsGui::instance()->relationWidgetRegistry()->create( mRelationEditorName, widgetConfig(), editor );
|
||||
editor->layout()->addWidget( w );
|
||||
}
|
||||
|
||||
@ -206,10 +208,7 @@ bool QgsRelationWidgetWrapper::showLinkButton() const
|
||||
|
||||
void QgsRelationWidgetWrapper::setShowLinkButton( bool showLinkButton )
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
if ( mWidget )
|
||||
mWidget->setShowLinkButton( showLinkButton );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
setVisibleButtons( visibleButtons().setFlag( QgsAttributeEditorRelation::Link, showLinkButton ) );
|
||||
}
|
||||
|
||||
bool QgsRelationWidgetWrapper::showSaveChildEditsButton() const
|
||||
@ -219,13 +218,17 @@ bool QgsRelationWidgetWrapper::showSaveChildEditsButton() const
|
||||
|
||||
void QgsRelationWidgetWrapper::setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons )
|
||||
{
|
||||
if ( mWidget )
|
||||
mWidget->setVisibleButtons( buttons );
|
||||
if ( ! mWidget )
|
||||
return;
|
||||
QVariantMap config = mWidget->config();
|
||||
config.insert( "buttons", qgsFlagValueToKeys( buttons ) );
|
||||
|
||||
mWidget->setConfig( config );
|
||||
}
|
||||
|
||||
QgsAttributeEditorRelation::Buttons QgsRelationWidgetWrapper::visibleButtons() const
|
||||
{
|
||||
return mWidget->visibleButtons();
|
||||
return qgsFlagKeysToValue( mWidget->config().value( QStringLiteral( "buttons" ) ).toString(), QgsAttributeEditorRelation::AllButtons );
|
||||
}
|
||||
|
||||
void QgsRelationWidgetWrapper::setForceSuppressFormPopup( bool forceSuppressFormPopup )
|
||||
@ -245,6 +248,7 @@ bool QgsRelationWidgetWrapper::forceSuppressFormPopup() const
|
||||
{
|
||||
if ( mWidget )
|
||||
return mWidget->forceSuppressFormPopup();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -294,3 +298,14 @@ QString QgsRelationWidgetWrapper::label() const
|
||||
return mWidget->label();
|
||||
return QString();
|
||||
}
|
||||
|
||||
void QgsRelationWidgetWrapper::setWidgetConfig( const QVariantMap &config )
|
||||
{
|
||||
if ( mWidget )
|
||||
mWidget->setConfig( config );
|
||||
}
|
||||
|
||||
QVariantMap QgsRelationWidgetWrapper::widgetConfig() const
|
||||
{
|
||||
return mWidget ? mWidget->config() : QVariantMap();
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
#include "qgis_sip.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QgsRelationEditorWidget;
|
||||
class QgsRelationWidget;
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
@ -34,7 +34,21 @@ class GUI_EXPORT QgsRelationWidgetWrapper : public QgsWidgetWrapper
|
||||
public:
|
||||
|
||||
//! Constructor for QgsRelationWidgetWrapper
|
||||
explicit QgsRelationWidgetWrapper( QgsVectorLayer *vl, const QgsRelation &relation, QWidget *editor = nullptr, QWidget *parent SIP_TRANSFERTHIS = nullptr );
|
||||
QgsRelationWidgetWrapper(
|
||||
QgsVectorLayer *vl,
|
||||
const QgsRelation &relation,
|
||||
QWidget *editor SIP_CONSTRAINED = nullptr,
|
||||
QWidget *parent SIP_TRANSFERTHIS SIP_CONSTRAINED = nullptr
|
||||
);
|
||||
|
||||
//! Constructor for QgsRelationWidgetWrapper
|
||||
QgsRelationWidgetWrapper(
|
||||
const QString &relationEditorName,
|
||||
QgsVectorLayer *vl,
|
||||
const QgsRelation &relation,
|
||||
QWidget *editor = nullptr,
|
||||
QWidget *parent SIP_TRANSFERTHIS = nullptr
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines if a title label should be shown for this widget.
|
||||
@ -97,14 +111,29 @@ class GUI_EXPORT QgsRelationWidgetWrapper : public QgsWidgetWrapper
|
||||
/**
|
||||
* Defines the buttons which are shown
|
||||
* \since QGIS 3.16
|
||||
* \deprecated since QGIS 3.18
|
||||
*/
|
||||
void setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons );
|
||||
Q_DECL_DEPRECATED void setVisibleButtons( const QgsAttributeEditorRelation::Buttons &buttons );
|
||||
|
||||
/**
|
||||
* Returns the buttons which are shown
|
||||
* \since QGIS 3.16
|
||||
* \deprecated since QGIS 3.18
|
||||
*/
|
||||
QgsAttributeEditorRelation::Buttons visibleButtons() const;
|
||||
Q_DECL_DEPRECATED QgsAttributeEditorRelation::Buttons visibleButtons() const;
|
||||
|
||||
|
||||
/**
|
||||
* Will set the config of this widget wrapper to the specified config.
|
||||
*
|
||||
* \param config The config for this wrapper
|
||||
*/
|
||||
void setWidgetConfig( const QVariantMap &config );
|
||||
|
||||
/**
|
||||
* Returns the whole widget config
|
||||
*/
|
||||
QVariantMap widgetConfig() const;
|
||||
|
||||
/**
|
||||
* Determines the force suppress form popup status that is configured for this widget
|
||||
@ -187,7 +216,8 @@ class GUI_EXPORT QgsRelationWidgetWrapper : public QgsWidgetWrapper
|
||||
void aboutToSave() override;
|
||||
QgsRelation mRelation;
|
||||
QgsRelation mNmRelation;
|
||||
QgsRelationEditorWidget *mWidget = nullptr;
|
||||
QString mRelationEditorName;
|
||||
QgsRelationWidget *mWidget = nullptr;
|
||||
};
|
||||
|
||||
#endif // QGSRELATIONWIDGETWRAPPER_H
|
||||
|
||||
@ -1254,7 +1254,12 @@ QList<QgsEditorWidgetWrapper *> QgsAttributeForm::constraintDependencies( QgsEdi
|
||||
|
||||
QgsRelationWidgetWrapper *QgsAttributeForm::setupRelationWidgetWrapper( const QgsRelation &rel, const QgsAttributeEditorContext &context )
|
||||
{
|
||||
QgsRelationWidgetWrapper *rww = new QgsRelationWidgetWrapper( mLayer, rel, nullptr, this );
|
||||
return setupRelationWidgetWrapper( QString(), rel, context );
|
||||
}
|
||||
|
||||
QgsRelationWidgetWrapper *QgsAttributeForm::setupRelationWidgetWrapper( const QString &relationWidgetTypeId, const QgsRelation &rel, const QgsAttributeEditorContext &context )
|
||||
{
|
||||
QgsRelationWidgetWrapper *rww = new QgsRelationWidgetWrapper( relationWidgetTypeId, mLayer, rel, nullptr, this );
|
||||
const QVariantMap config = mLayer->editFormConfig().widgetConfig( rel.id() );
|
||||
rww->setConfig( config );
|
||||
rww->setContext( context );
|
||||
@ -1943,7 +1948,7 @@ QgsAttributeForm::WidgetInfo QgsAttributeForm::createWidgetFromDef( const QgsAtt
|
||||
{
|
||||
const QgsAttributeEditorRelation *relDef = static_cast<const QgsAttributeEditorRelation *>( widgetDef );
|
||||
|
||||
QgsRelationWidgetWrapper *rww = setupRelationWidgetWrapper( relDef->relation(), context );
|
||||
QgsRelationWidgetWrapper *rww = setupRelationWidgetWrapper( relDef->relationWidgetTypeId(), relDef->relation(), context );
|
||||
|
||||
QgsAttributeFormRelationEditorWidget *formWidget = new QgsAttributeFormRelationEditorWidget( rww, this );
|
||||
formWidget->createSearchWidgetWrappers( mContext );
|
||||
@ -1951,7 +1956,7 @@ QgsAttributeForm::WidgetInfo QgsAttributeForm::createWidgetFromDef( const QgsAtt
|
||||
// This needs to be after QgsAttributeFormRelationEditorWidget creation, because the widget
|
||||
// does not exists yet until QgsAttributeFormRelationEditorWidget is created and the setters
|
||||
// below directly alter the widget and check for it.
|
||||
rww->setVisibleButtons( relDef->visibleButtons() );
|
||||
rww->setWidgetConfig( relDef->config() );
|
||||
rww->setShowLabel( relDef->showLabel() );
|
||||
rww->setNmRelationId( relDef->nmRelationId() );
|
||||
rww->setForceSuppressFormPopup( relDef->forceSuppressFormPopup() );
|
||||
|
||||
@ -415,6 +415,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
|
||||
QList<QgsEditorWidgetWrapper *> constraintDependencies( QgsEditorWidgetWrapper *w );
|
||||
|
||||
QgsRelationWidgetWrapper *setupRelationWidgetWrapper( const QgsRelation &rel, const QgsAttributeEditorContext &context );
|
||||
QgsRelationWidgetWrapper *setupRelationWidgetWrapper( const QString &relationWidgetTypeId, const QgsRelation &rel, const QgsAttributeEditorContext &context );
|
||||
|
||||
QgsVectorLayer *mLayer = nullptr;
|
||||
QgsFeature mFeature;
|
||||
|
||||
57
src/gui/qgsbasicrelationconfigwidget.cpp
Normal file
57
src/gui/qgsbasicrelationconfigwidget.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
qgsbasicrelationconfigwidget.cpp
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "qgsbasicrelationconfigwidget.h"
|
||||
#include "qgsbasicrelationwidget.h"
|
||||
|
||||
|
||||
QgsBasicRelationConfigWidget::QgsBasicRelationConfigWidget( const QgsRelation &relation, QWidget *parent )
|
||||
: QgsRelationConfigWidget( relation, parent )
|
||||
{
|
||||
setupUi( this );
|
||||
}
|
||||
|
||||
QVariantMap QgsBasicRelationConfigWidget::config()
|
||||
{
|
||||
QgsBasicRelationWidget::Buttons buttons;
|
||||
buttons.setFlag( QgsBasicRelationWidget::Button::Link, mRelationShowLinkCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsBasicRelationWidget::Button::Unlink, mRelationShowUnlinkCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsBasicRelationWidget::Button::AddChildFeature, mRelationShowAddChildCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsBasicRelationWidget::Button::DuplicateChildFeature, mRelationShowDuplicateChildFeatureCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsBasicRelationWidget::Button::ZoomToChildFeature, mRelationShowZoomToFeatureCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsBasicRelationWidget::Button::DeleteChildFeature, mRelationDeleteChildFeatureCheckBox->isChecked() );
|
||||
buttons.setFlag( QgsBasicRelationWidget::Button::SaveChildEdits, mRelationShowSaveChildEditsCheckBox->isChecked() );
|
||||
|
||||
return QVariantMap(
|
||||
{
|
||||
{"buttons", qgsFlagValueToKeys( buttons )},
|
||||
} );
|
||||
}
|
||||
|
||||
void QgsBasicRelationConfigWidget::setConfig( const QVariantMap &config )
|
||||
{
|
||||
const QgsBasicRelationWidget::Buttons buttons = qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsBasicRelationWidget::Button::AllButtons );
|
||||
|
||||
mRelationShowLinkCheckBox->setChecked( buttons.testFlag( QgsBasicRelationWidget::Button::Link ) );
|
||||
mRelationShowUnlinkCheckBox->setChecked( buttons.testFlag( QgsBasicRelationWidget::Button::Unlink ) );
|
||||
mRelationShowAddChildCheckBox->setChecked( buttons.testFlag( QgsBasicRelationWidget::Button::AddChildFeature ) );
|
||||
mRelationShowDuplicateChildFeatureCheckBox->setChecked( buttons.testFlag( QgsBasicRelationWidget::Button::DuplicateChildFeature ) );
|
||||
mRelationShowZoomToFeatureCheckBox->setChecked( buttons.testFlag( QgsBasicRelationWidget::Button::ZoomToChildFeature ) );
|
||||
mRelationDeleteChildFeatureCheckBox->setChecked( buttons.testFlag( QgsBasicRelationWidget::Button::DeleteChildFeature ) );
|
||||
mRelationShowSaveChildEditsCheckBox->setChecked( buttons.testFlag( QgsBasicRelationWidget::Button::SaveChildEdits ) );
|
||||
}
|
||||
62
src/gui/qgsbasicrelationconfigwidget.h
Normal file
62
src/gui/qgsbasicrelationconfigwidget.h
Normal file
@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
qgsbasicrelationconfigwidget.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 QGSBASICRELATIONCONFIGWIDGET_H
|
||||
#define QGSBASICRELATIONCONFIGWIDGET_H
|
||||
|
||||
|
||||
#include "ui_qgsrelationeditorconfigwidgetbase.h"
|
||||
#include "qgsrelationconfigwidget.h"
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* \class QgsBasicRelationConfigWidget
|
||||
* Creates a new configuration widget for the basic relation widget
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class QgsBasicRelationConfigWidget : public QgsRelationConfigWidget, private Ui::QgsRelationEditorConfigWidgetBase
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a new configuration widget
|
||||
*
|
||||
* \param relation The relation for which the configuration dialog will be created
|
||||
* \param parent A parent widget
|
||||
*/
|
||||
explicit QgsBasicRelationConfigWidget( const QgsRelation &relation, QWidget *parent SIP_TRANSFERTHIS );
|
||||
|
||||
/**
|
||||
* \brief Create a configuration from the current GUI state
|
||||
*
|
||||
* \returns A widget configuration
|
||||
*/
|
||||
QVariantMap config();
|
||||
|
||||
/**
|
||||
* \brief Update the configuration widget to represent the given configuration.
|
||||
*
|
||||
* \param config The configuration which should be represented by this widget
|
||||
*/
|
||||
void setConfig( const QVariantMap &config );
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSBASICRELATIONCONFIGWIDGET_H
|
||||
558
src/gui/qgsbasicrelationwidget.cpp
Normal file
558
src/gui/qgsbasicrelationwidget.cpp
Normal file
@ -0,0 +1,558 @@
|
||||
/***************************************************************************
|
||||
qgsbasicrelationwidget.cpp
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsbasicrelationwidget.h"
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsdistancearea.h"
|
||||
#include "qgsfeatureiterator.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsexpression.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsfeatureselectiondlg.h"
|
||||
#include "qgsgenericfeatureselectionmanager.h"
|
||||
#include "qgsrelation.h"
|
||||
#include "qgsvectorlayertools.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgstransactiongroup.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsvectorlayerutils.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsvectorlayerselectionmanager.h"
|
||||
#include "qgsmaptooldigitizefeature.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
#include "qgsmessagebar.h"
|
||||
#include "qgsmessagebaritem.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
QgsBasicRelationWidget::QgsBasicRelationWidget( const QVariantMap &config, QWidget *parent )
|
||||
: QgsRelationWidget( config, parent )
|
||||
, mButtonsVisibility( qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsBasicRelationWidget::Button::AllButtons ) )
|
||||
{
|
||||
QVBoxLayout *rootLayout = new QVBoxLayout( this );
|
||||
rootLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
|
||||
mRootCollapsibleGroupBox = new QgsCollapsibleGroupBox( QString(), this );
|
||||
rootLayout->addWidget( mRootCollapsibleGroupBox );
|
||||
|
||||
QVBoxLayout *topLayout = new QVBoxLayout( mRootCollapsibleGroupBox );
|
||||
topLayout->setContentsMargins( 0, 9, 0, 0 );
|
||||
|
||||
// buttons
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
buttonLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
// toggle editing
|
||||
mToggleEditingButton = new QToolButton( this );
|
||||
mToggleEditingButton->setObjectName( QStringLiteral( "mToggleEditingButton" ) );
|
||||
mToggleEditingButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) ) );
|
||||
mToggleEditingButton->setText( tr( "Toggle Editing" ) );
|
||||
mToggleEditingButton->setEnabled( false );
|
||||
mToggleEditingButton->setCheckable( true );
|
||||
mToggleEditingButton->setToolTip( tr( "Toggle editing mode for child layer" ) );
|
||||
buttonLayout->addWidget( mToggleEditingButton );
|
||||
// save Edits
|
||||
mSaveEditsButton = new QToolButton( this );
|
||||
mSaveEditsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSaveEdits.svg" ) ) );
|
||||
mSaveEditsButton->setText( tr( "Save Child Layer Edits" ) );
|
||||
mSaveEditsButton->setToolTip( tr( "Save child layer edits" ) );
|
||||
mSaveEditsButton->setEnabled( true );
|
||||
buttonLayout->addWidget( mSaveEditsButton );
|
||||
// add feature with geometry
|
||||
mAddFeatureGeometryButton = new QToolButton( this );
|
||||
mAddFeatureGeometryButton->setObjectName( QStringLiteral( "mAddFeatureGeometryButton" ) );
|
||||
buttonLayout->addWidget( mAddFeatureGeometryButton );
|
||||
// add feature
|
||||
mAddFeatureButton = new QToolButton( this );
|
||||
mAddFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionNewTableRow.svg" ) ) );
|
||||
mAddFeatureButton->setText( tr( "Add Child Feature" ) );
|
||||
mAddFeatureButton->setToolTip( tr( "Add child feature" ) );
|
||||
mAddFeatureButton->setObjectName( QStringLiteral( "mAddFeatureButton" ) );
|
||||
buttonLayout->addWidget( mAddFeatureButton );
|
||||
// duplicate feature
|
||||
mDuplicateFeatureButton = new QToolButton( this );
|
||||
mDuplicateFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDuplicateFeature.svg" ) ) );
|
||||
mDuplicateFeatureButton->setText( tr( "Duplicate Child Feature" ) );
|
||||
mDuplicateFeatureButton->setToolTip( tr( "Duplicate child feature" ) );
|
||||
mDuplicateFeatureButton->setObjectName( QStringLiteral( "mDuplicateFeatureButton" ) );
|
||||
buttonLayout->addWidget( mDuplicateFeatureButton );
|
||||
// delete feature
|
||||
mDeleteFeatureButton = new QToolButton( this );
|
||||
mDeleteFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ) );
|
||||
mDeleteFeatureButton->setText( tr( "Delete Child Feature" ) );
|
||||
mDeleteFeatureButton->setToolTip( tr( "Delete child feature" ) );
|
||||
mDeleteFeatureButton->setObjectName( QStringLiteral( "mDeleteFeatureButton" ) );
|
||||
buttonLayout->addWidget( mDeleteFeatureButton );
|
||||
// link feature
|
||||
mLinkFeatureButton = new QToolButton( this );
|
||||
mLinkFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionLink.svg" ) ) );
|
||||
mLinkFeatureButton->setText( tr( "Link Existing Features" ) );
|
||||
mLinkFeatureButton->setToolTip( tr( "Link existing child features" ) );
|
||||
mLinkFeatureButton->setObjectName( QStringLiteral( "mLinkFeatureButton" ) );
|
||||
buttonLayout->addWidget( mLinkFeatureButton );
|
||||
// unlink feature
|
||||
mUnlinkFeatureButton = new QToolButton( this );
|
||||
mUnlinkFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ) );
|
||||
mUnlinkFeatureButton->setText( tr( "Unlink Feature" ) );
|
||||
mUnlinkFeatureButton->setToolTip( tr( "Unlink child feature" ) );
|
||||
mUnlinkFeatureButton->setObjectName( QStringLiteral( "mUnlinkFeatureButton" ) );
|
||||
buttonLayout->addWidget( mUnlinkFeatureButton );
|
||||
// zoom to linked feature
|
||||
mZoomToFeatureButton = new QToolButton( this );
|
||||
mZoomToFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToSelected.svg" ) ) );
|
||||
mZoomToFeatureButton->setText( tr( "Zoom To Feature" ) );
|
||||
mZoomToFeatureButton->setToolTip( tr( "Zoom to child feature" ) );
|
||||
mZoomToFeatureButton->setObjectName( QStringLiteral( "mZoomToFeatureButton" ) );
|
||||
buttonLayout->addWidget( mZoomToFeatureButton );
|
||||
// spacer
|
||||
buttonLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding ) );
|
||||
// form view
|
||||
mFormViewButton = new QToolButton( this );
|
||||
mFormViewButton->setText( tr( "Form View" ) );
|
||||
mFormViewButton->setToolTip( tr( "Switch to form view" ) );
|
||||
mFormViewButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPropertyItem.svg" ) ) );
|
||||
mFormViewButton->setCheckable( true );
|
||||
mFormViewButton->setChecked( mViewMode == QgsDualView::AttributeEditor );
|
||||
buttonLayout->addWidget( mFormViewButton );
|
||||
// table view
|
||||
mTableViewButton = new QToolButton( this );
|
||||
mTableViewButton->setText( tr( "Table View" ) );
|
||||
mTableViewButton->setToolTip( tr( "Switch to table view" ) );
|
||||
mTableViewButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ) );
|
||||
mTableViewButton->setCheckable( true );
|
||||
mTableViewButton->setChecked( mViewMode == QgsDualView::AttributeTable );
|
||||
buttonLayout->addWidget( mTableViewButton );
|
||||
// button group
|
||||
mViewModeButtonGroup = new QButtonGroup( this );
|
||||
mViewModeButtonGroup->addButton( mFormViewButton, QgsDualView::AttributeEditor );
|
||||
mViewModeButtonGroup->addButton( mTableViewButton, QgsDualView::AttributeTable );
|
||||
|
||||
// add buttons layout
|
||||
topLayout->addLayout( buttonLayout );
|
||||
|
||||
mRelationLayout = new QGridLayout();
|
||||
mRelationLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
topLayout->addLayout( mRelationLayout );
|
||||
|
||||
mDualView = new QgsDualView( this );
|
||||
mDualView->setView( mViewMode );
|
||||
|
||||
mRelationLayout->addWidget( mDualView );
|
||||
|
||||
// connect( this, &QgsCollapsibleGroupBoxBasic::collapsedStateChanged, this, &QgsRelationEditorWidget2::onCollapsedStateChanged );
|
||||
connect( mViewModeButtonGroup, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ),
|
||||
this, static_cast<void ( QgsBasicRelationWidget::* )( int )>( &QgsBasicRelationWidget::setViewMode ) );
|
||||
connect( mToggleEditingButton, &QAbstractButton::clicked, this, &QgsBasicRelationWidget::toggleEditing );
|
||||
connect( mSaveEditsButton, &QAbstractButton::clicked, this, &QgsBasicRelationWidget::saveEdits );
|
||||
connect( mAddFeatureButton, &QAbstractButton::clicked, this, [this]() { addFeature(); } );
|
||||
connect( mAddFeatureGeometryButton, &QAbstractButton::clicked, this, &QgsBasicRelationWidget::addFeatureGeometry );
|
||||
connect( mDuplicateFeatureButton, &QAbstractButton::clicked, this, &QgsBasicRelationWidget::duplicateFeature );
|
||||
connect( mDeleteFeatureButton, &QAbstractButton::clicked, this, &QgsBasicRelationWidget::deleteSelectedFeatures );
|
||||
connect( mLinkFeatureButton, &QAbstractButton::clicked, this, &QgsBasicRelationWidget::linkFeature );
|
||||
connect( mUnlinkFeatureButton, &QAbstractButton::clicked, this, &QgsBasicRelationWidget::unlinkSelectedFeatures );
|
||||
connect( mZoomToFeatureButton, &QAbstractButton::clicked, this, &QgsBasicRelationWidget::zoomToSelectedFeatures );
|
||||
|
||||
connect( mDualView, &QgsDualView::showContextMenuExternally, this, &QgsBasicRelationWidget::showContextMenu );
|
||||
|
||||
// Set initial state for add/remove etc. buttons
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::initDualView( QgsVectorLayer *layer, const QgsFeatureRequest &request )
|
||||
{
|
||||
QgsAttributeEditorContext ctx { mEditorContext };
|
||||
ctx.setParentFormFeature( mFeature );
|
||||
mDualView->init( layer, mEditorContext.mapCanvas(), request, ctx );
|
||||
mFeatureSelectionMgr = new QgsFilteredSelectionManager( layer, request, mDualView );
|
||||
mDualView->setFeatureSelectionManager( mFeatureSelectionMgr );
|
||||
|
||||
connect( mFeatureSelectionMgr, &QgsIFeatureSelectionManager::selectionChanged, this, &QgsBasicRelationWidget::updateButtons );
|
||||
|
||||
QIcon icon;
|
||||
QString text;
|
||||
if ( layer->geometryType() == QgsWkbTypes::PointGeometry )
|
||||
{
|
||||
icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePoint.svg" ) );
|
||||
text = tr( "Add Point child Feature" );
|
||||
}
|
||||
else if ( layer->geometryType() == QgsWkbTypes::LineGeometry )
|
||||
{
|
||||
icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCaptureLine.svg" ) );
|
||||
text = tr( "Add Line child Feature" );
|
||||
}
|
||||
else if ( layer->geometryType() == QgsWkbTypes::PolygonGeometry )
|
||||
{
|
||||
icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePolygon.svg" ) );
|
||||
text = tr( "Add Polygon Feature" );
|
||||
}
|
||||
|
||||
mAddFeatureGeometryButton->setIcon( icon );
|
||||
mAddFeatureGeometryButton->setText( text );
|
||||
mAddFeatureGeometryButton->setToolTip( text );
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::setEditorContext( const QgsAttributeEditorContext &context )
|
||||
{
|
||||
mEditorContext = context;
|
||||
|
||||
if ( context.mapCanvas() && context.cadDockWidget() )
|
||||
{
|
||||
mMapToolDigitize.reset( new QgsMapToolDigitizeFeature( context.mapCanvas(), context.cadDockWidget() ) );
|
||||
mMapToolDigitize->setButton( mAddFeatureGeometryButton );
|
||||
}
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::setViewMode( QgsDualView::ViewMode mode )
|
||||
{
|
||||
mDualView->setView( mode );
|
||||
mViewMode = mode;
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::updateButtons()
|
||||
{
|
||||
bool editable = false;
|
||||
bool linkable = false;
|
||||
bool spatial = false;
|
||||
bool selectionNotEmpty = mFeatureSelectionMgr ? mFeatureSelectionMgr->selectedFeatureCount() : false;
|
||||
|
||||
if ( mRelation.isValid() )
|
||||
{
|
||||
editable = mRelation.referencingLayer()->isEditable();
|
||||
linkable = mRelation.referencingLayer()->isEditable();
|
||||
spatial = mRelation.referencingLayer()->isSpatial();
|
||||
}
|
||||
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
editable = mNmRelation.referencedLayer()->isEditable();
|
||||
spatial = mNmRelation.referencedLayer()->isSpatial();
|
||||
}
|
||||
|
||||
mAddFeatureButton->setEnabled( editable );
|
||||
mAddFeatureGeometryButton->setEnabled( editable );
|
||||
mDuplicateFeatureButton->setEnabled( editable && selectionNotEmpty );
|
||||
mLinkFeatureButton->setEnabled( linkable );
|
||||
mDeleteFeatureButton->setEnabled( editable && selectionNotEmpty );
|
||||
mUnlinkFeatureButton->setEnabled( linkable && selectionNotEmpty );
|
||||
mZoomToFeatureButton->setEnabled( selectionNotEmpty );
|
||||
mToggleEditingButton->setChecked( editable );
|
||||
mSaveEditsButton->setEnabled( editable );
|
||||
|
||||
mToggleEditingButton->setVisible( !mLayerInSameTransactionGroup );
|
||||
|
||||
mLinkFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsBasicRelationWidget::Button::Link ) );
|
||||
mUnlinkFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsBasicRelationWidget::Button::Unlink ) );
|
||||
mSaveEditsButton->setVisible( mButtonsVisibility.testFlag( QgsBasicRelationWidget::Button::SaveChildEdits ) && !mLayerInSameTransactionGroup );
|
||||
mAddFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsBasicRelationWidget::Button::AddChildFeature ) );
|
||||
mAddFeatureGeometryButton->setVisible( mButtonsVisibility.testFlag( QgsBasicRelationWidget::Button::AddChildFeature ) && mEditorContext.mapCanvas() && mEditorContext.cadDockWidget() && spatial );
|
||||
mDuplicateFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsBasicRelationWidget::Button::DuplicateChildFeature ) );
|
||||
mDeleteFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsBasicRelationWidget::Button::DeleteChildFeature ) );
|
||||
mZoomToFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsBasicRelationWidget::Button::ZoomToChildFeature ) && mEditorContext.mapCanvas() && spatial );
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::addFeatureGeometry()
|
||||
{
|
||||
QgsVectorLayer *layer = nullptr;
|
||||
if ( mNmRelation.isValid() )
|
||||
layer = mNmRelation.referencedLayer();
|
||||
else
|
||||
layer = mRelation.referencingLayer();
|
||||
|
||||
mMapToolDigitize->setLayer( layer );
|
||||
|
||||
// window is always on top, so we hide it to digitize without seeing it
|
||||
window()->setVisible( false );
|
||||
setMapTool( mMapToolDigitize );
|
||||
|
||||
connect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsBasicRelationWidget::onDigitizingCompleted );
|
||||
connect( mEditorContext.mapCanvas(), &QgsMapCanvas::keyPressed, this, &QgsBasicRelationWidget::onKeyPressed );
|
||||
|
||||
if ( auto *lMainMessageBar = mEditorContext.mainMessageBar() )
|
||||
{
|
||||
QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( layer, mFeature );
|
||||
|
||||
QString title = tr( "Create child feature for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString );
|
||||
QString msg = tr( "Digitize the geometry for the new feature on layer %1. Press <ESC> to cancel." )
|
||||
.arg( layer->name() );
|
||||
mMessageBarItem = QgsMessageBar::createMessage( title, msg, this );
|
||||
lMainMessageBar->pushItem( mMessageBarItem );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::onDigitizingCompleted( const QgsFeature &feature )
|
||||
{
|
||||
addFeature( feature.geometry() );
|
||||
|
||||
unsetMapTool();
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::toggleEditing( bool state )
|
||||
{
|
||||
QgsRelationWidget::toggleEditing( state );
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::onCollapsedStateChanged( bool collapsed )
|
||||
{
|
||||
if ( !collapsed )
|
||||
{
|
||||
mVisible = true;
|
||||
updateUi();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::updateUi()
|
||||
{
|
||||
// If not yet initialized, it is not (yet) visible, so we don't load it to be faster (lazy loading)
|
||||
// If it is already initialized, it has been set visible before and the currently shown feature is changing
|
||||
// and the widget needs updating
|
||||
|
||||
if ( mVisible )
|
||||
{
|
||||
QgsFeatureRequest myRequest = mRelation.getRelatedFeaturesRequest( mFeature );
|
||||
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
QgsFeatureIterator it = mRelation.referencingLayer()->getFeatures( myRequest );
|
||||
|
||||
QgsFeature fet;
|
||||
|
||||
QStringList filters;
|
||||
|
||||
while ( it.nextFeature( fet ) )
|
||||
{
|
||||
QString filter = mNmRelation.getReferencedFeatureRequest( fet ).filterExpression()->expression();
|
||||
filters << filter.prepend( '(' ).append( ')' );
|
||||
}
|
||||
|
||||
QgsFeatureRequest nmRequest;
|
||||
|
||||
nmRequest.setFilterExpression( filters.join( QLatin1String( " OR " ) ) );
|
||||
|
||||
initDualView( mNmRelation.referencedLayer(), nmRequest );
|
||||
}
|
||||
else if ( mRelation.referencingLayer() )
|
||||
{
|
||||
initDualView( mRelation.referencingLayer(), myRequest );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::setVisibleButtons( const Buttons &buttons )
|
||||
{
|
||||
mButtonsVisibility = buttons;
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
QgsBasicRelationWidget::Buttons QgsBasicRelationWidget::visibleButtons() const
|
||||
{
|
||||
Buttons buttons;
|
||||
if ( mLinkFeatureButton->isVisible() )
|
||||
buttons |= Button::Link;
|
||||
if ( mUnlinkFeatureButton->isVisible() )
|
||||
buttons |= Button::Unlink;
|
||||
if ( mSaveEditsButton->isVisible() )
|
||||
buttons |= Button::SaveChildEdits;
|
||||
if ( mAddFeatureButton->isVisible() )
|
||||
buttons |= Button::AddChildFeature;
|
||||
if ( mDuplicateFeatureButton->isVisible() )
|
||||
buttons |= Button::DuplicateChildFeature;
|
||||
if ( mDeleteFeatureButton->isVisible() )
|
||||
buttons |= Button::DeleteChildFeature;
|
||||
if ( mZoomToFeatureButton->isVisible() )
|
||||
buttons |= Button::ZoomToChildFeature;
|
||||
return buttons;
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::parentFormValueChanged( const QString &attribute, const QVariant &newValue )
|
||||
{
|
||||
mDualView->parentFormValueChanged( attribute, newValue );
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::showContextMenu( QgsActionMenu *menu, const QgsFeatureId fid )
|
||||
{
|
||||
if ( mRelation.referencingLayer()->isEditable() )
|
||||
{
|
||||
QAction *qAction = nullptr;
|
||||
|
||||
qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ), tr( "Delete Feature" ) );
|
||||
connect( qAction, &QAction::triggered, this, [this, fid]() { deleteFeature( fid ); } );
|
||||
|
||||
qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ), tr( "Unlink Feature" ) );
|
||||
connect( qAction, &QAction::triggered, this, [this, fid]() { unlinkFeature( fid ); } );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::setMapTool( QgsMapTool *mapTool )
|
||||
{
|
||||
QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
|
||||
|
||||
mapCanvas->setMapTool( mapTool );
|
||||
mapCanvas->window()->raise();
|
||||
mapCanvas->activateWindow();
|
||||
mapCanvas->setFocus();
|
||||
connect( mapTool, &QgsMapTool::deactivated, this, &QgsBasicRelationWidget::mapToolDeactivated );
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::unsetMapTool()
|
||||
{
|
||||
QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
|
||||
|
||||
// this will call mapToolDeactivated
|
||||
mapCanvas->unsetMapTool( mMapToolDigitize );
|
||||
|
||||
disconnect( mapCanvas, &QgsMapCanvas::keyPressed, this, &QgsBasicRelationWidget::onKeyPressed );
|
||||
disconnect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsBasicRelationWidget::onDigitizingCompleted );
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::onKeyPressed( QKeyEvent *e )
|
||||
{
|
||||
if ( e->key() == Qt::Key_Escape )
|
||||
{
|
||||
unsetMapTool();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::mapToolDeactivated()
|
||||
{
|
||||
window()->setVisible( true );
|
||||
window()->raise();
|
||||
window()->activateWindow();
|
||||
|
||||
if ( mEditorContext.mainMessageBar() && mMessageBarItem )
|
||||
{
|
||||
mEditorContext.mainMessageBar()->popWidget( mMessageBarItem );
|
||||
}
|
||||
mMessageBarItem = nullptr;
|
||||
}
|
||||
|
||||
QVariantMap QgsBasicRelationWidget::config() const
|
||||
{
|
||||
return QVariantMap( {{"buttons", qgsFlagValueToKeys( visibleButtons() )}} );
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::setConfig( const QVariantMap &config )
|
||||
{
|
||||
mButtonsVisibility = qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsBasicRelationWidget::Button::AllButtons );
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::setTitle( const QString &title )
|
||||
{
|
||||
mRootCollapsibleGroupBox->setTitle( title );
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::beforeSetRelationFeature( const QgsRelation &newRelation, const QgsFeature &newFeature )
|
||||
{
|
||||
Q_UNUSED( newRelation );
|
||||
Q_UNUSED( newFeature );
|
||||
|
||||
if ( ! mRelation.isValid() )
|
||||
return;
|
||||
|
||||
disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsBasicRelationWidget::updateButtons );
|
||||
disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsBasicRelationWidget::updateButtons );
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::afterSetRelationFeature()
|
||||
{
|
||||
mToggleEditingButton->setEnabled( false );
|
||||
|
||||
if ( ! mRelation.isValid() )
|
||||
return;
|
||||
|
||||
connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsBasicRelationWidget::updateButtons );
|
||||
connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsBasicRelationWidget::updateButtons );
|
||||
|
||||
QgsVectorLayer *vl = mRelation.referencingLayer();
|
||||
bool canChangeAttributes = vl->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
|
||||
if ( canChangeAttributes && !vl->readOnly() )
|
||||
{
|
||||
mToggleEditingButton->setEnabled( true );
|
||||
updateButtons();
|
||||
}
|
||||
else
|
||||
{
|
||||
mToggleEditingButton->setEnabled( false );
|
||||
}
|
||||
|
||||
// If not yet initialized, it is not (yet) visible, so we don't load it to be faster (lazy loading)
|
||||
// If it is already initialized, it has been set visible before and the currently shown feature is changing
|
||||
// and the widget needs updating
|
||||
|
||||
if ( mVisible )
|
||||
{
|
||||
QgsFeatureRequest myRequest = mRelation.getRelatedFeaturesRequest( mFeature );
|
||||
initDualView( mRelation.referencingLayer(), myRequest );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::beforeSetRelations( const QgsRelation &newRelation, const QgsRelation &newNmRelation )
|
||||
{
|
||||
Q_UNUSED( newRelation );
|
||||
Q_UNUSED( newNmRelation );
|
||||
|
||||
if ( mRelation.isValid() )
|
||||
{
|
||||
disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsBasicRelationWidget::updateButtons );
|
||||
disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsBasicRelationWidget::updateButtons );
|
||||
}
|
||||
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsBasicRelationWidget::updateButtons );
|
||||
disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsBasicRelationWidget::updateButtons );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBasicRelationWidget::afterSetRelations()
|
||||
{
|
||||
if ( !mRelation.isValid() )
|
||||
return;
|
||||
|
||||
connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsBasicRelationWidget::updateButtons );
|
||||
connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsBasicRelationWidget::updateButtons );
|
||||
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsBasicRelationWidget::updateButtons );
|
||||
connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsBasicRelationWidget::updateButtons );
|
||||
}
|
||||
|
||||
QgsVectorLayer *vl = mRelation.referencingLayer();
|
||||
bool canChangeAttributes = vl->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
|
||||
if ( canChangeAttributes && !vl->readOnly() )
|
||||
{
|
||||
mToggleEditingButton->setEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
mToggleEditingButton->setEnabled( false );
|
||||
}
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
172
src/gui/qgsbasicrelationwidget.h
Normal file
172
src/gui/qgsbasicrelationwidget.h
Normal file
@ -0,0 +1,172 @@
|
||||
/***************************************************************************
|
||||
qgsbasicrelationwidget.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 QGSBASICRELATIONWIDGET_H
|
||||
#define QGSBASICRELATIONWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QToolButton>
|
||||
#include <QButtonGroup>
|
||||
#include <QGridLayout>
|
||||
#include "qobjectuniqueptr.h"
|
||||
|
||||
#include "qgsrelationeditorwidget.h"
|
||||
#include "qgsrelationwidget.h"
|
||||
#include "qobjectuniqueptr.h"
|
||||
#include "qgsattributeeditorcontext.h"
|
||||
#include "qgscollapsiblegroupbox.h"
|
||||
#include "qgsdualview.h"
|
||||
#include "qgsrelation.h"
|
||||
#include "qgsvectorlayerselectionmanager.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QgsFeature;
|
||||
class QgsVectorLayer;
|
||||
class QgsVectorLayerTools;
|
||||
class QgsMapTool;
|
||||
class QgsMapToolDigitizeFeature;
|
||||
|
||||
/**
|
||||
* The default relation widget in QGIS. Successor of the now deprecated {\see QgsRelationEditorWidget}.
|
||||
* \ingroup gui
|
||||
* \class QgsBasicRelationWidget
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class GUI_EXPORT QgsBasicRelationWidget : public QgsRelationWidget
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QgsDualView::ViewMode viewMode READ viewMode WRITE setViewMode )
|
||||
Q_PROPERTY( Buttons visibleButtons READ visibleButtons WRITE setVisibleButtons )
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Possible buttons shown in the relation editor
|
||||
*/
|
||||
enum Button
|
||||
{
|
||||
Link = 1 << 1, //!< Link button
|
||||
Unlink = 1 << 2, //!< Unlink button
|
||||
SaveChildEdits = 1 << 3, //!< Save child edits button
|
||||
AddChildFeature = 1 << 4, //!< Add child feature (as in some projects we only want to allow linking/unlinking existing features)
|
||||
DuplicateChildFeature = 1 << 5, //!< Duplicate child feature
|
||||
DeleteChildFeature = 1 << 6, //!< Delete child feature button
|
||||
ZoomToChildFeature = 1 << 7, //!< Zoom to child feature
|
||||
AllButtons = Link | Unlink | SaveChildEdits | AddChildFeature | DuplicateChildFeature | DeleteChildFeature | ZoomToChildFeature //!< All buttons
|
||||
};
|
||||
Q_ENUM( Button )
|
||||
Q_DECLARE_FLAGS( Buttons, Button )
|
||||
Q_FLAG( Buttons )
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* \param config widget configuration
|
||||
* \param parent parent widget
|
||||
*/
|
||||
QgsBasicRelationWidget( const QVariantMap &config, QWidget *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
//! Define the view mode for the dual view
|
||||
void setViewMode( QgsDualView::ViewMode mode );
|
||||
|
||||
//! Gets the view mode for the dual view
|
||||
QgsDualView::ViewMode viewMode() {return mViewMode;}
|
||||
|
||||
/**
|
||||
* Sets the editor \a context
|
||||
* \note if context cadDockWidget is null, it won't be possible to digitize
|
||||
* the geometry of a referencing feature from this widget
|
||||
*/
|
||||
void setEditorContext( const QgsAttributeEditorContext &context );
|
||||
|
||||
/**
|
||||
* Defines the buttons which are shown
|
||||
*/
|
||||
void setVisibleButtons( const Buttons &buttons );
|
||||
|
||||
/**
|
||||
* Returns the buttons which are shown
|
||||
*/
|
||||
Buttons visibleButtons() const;
|
||||
|
||||
/**
|
||||
* Returns the current configuration
|
||||
*/
|
||||
QVariantMap config() const override;
|
||||
|
||||
/**
|
||||
* Defines the current configuration
|
||||
*/
|
||||
void setConfig( const QVariantMap &config ) override;
|
||||
|
||||
/**
|
||||
* Sets the title of the root groupbox
|
||||
*/
|
||||
void setTitle( const QString &title ) override;
|
||||
|
||||
public slots:
|
||||
void parentFormValueChanged( const QString &attribute, const QVariant &newValue ) override;
|
||||
|
||||
private slots:
|
||||
void setViewMode( int mode ) {setViewMode( static_cast<QgsDualView::ViewMode>( mode ) );}
|
||||
void updateButtons();
|
||||
|
||||
void addFeatureGeometry();
|
||||
void toggleEditing( bool state );
|
||||
void onCollapsedStateChanged( bool collapsed );
|
||||
void showContextMenu( QgsActionMenu *menu, QgsFeatureId fid );
|
||||
void mapToolDeactivated();
|
||||
void onKeyPressed( QKeyEvent *e );
|
||||
void onDigitizingCompleted( const QgsFeature &feature );
|
||||
|
||||
private:
|
||||
void updateUi() override;
|
||||
void initDualView( QgsVectorLayer *layer, const QgsFeatureRequest &request );
|
||||
void setMapTool( QgsMapTool *mapTool );
|
||||
void unsetMapTool();
|
||||
|
||||
QgsCollapsibleGroupBox *mRootCollapsibleGroupBox = nullptr;
|
||||
QgsDualView *mDualView = nullptr;
|
||||
QPointer<QgsMessageBarItem> mMessageBarItem;
|
||||
QgsDualView::ViewMode mViewMode = QgsDualView::AttributeEditor;
|
||||
|
||||
QToolButton *mToggleEditingButton = nullptr;
|
||||
QToolButton *mSaveEditsButton = nullptr;
|
||||
QToolButton *mAddFeatureButton = nullptr;
|
||||
QToolButton *mDuplicateFeatureButton = nullptr;
|
||||
QToolButton *mDeleteFeatureButton = nullptr;
|
||||
QToolButton *mLinkFeatureButton = nullptr;
|
||||
QToolButton *mUnlinkFeatureButton = nullptr;
|
||||
QToolButton *mZoomToFeatureButton = nullptr;
|
||||
QToolButton *mFormViewButton = nullptr;
|
||||
QToolButton *mTableViewButton = nullptr;
|
||||
QToolButton *mAddFeatureGeometryButton = nullptr;
|
||||
QGridLayout *mRelationLayout = nullptr;
|
||||
QObjectUniquePtr<QgsMapToolDigitizeFeature> mMapToolDigitize;
|
||||
QButtonGroup *mViewModeButtonGroup = nullptr;
|
||||
|
||||
Buttons mButtonsVisibility = Button::AllButtons;
|
||||
bool mVisible = true;
|
||||
|
||||
void beforeSetRelationFeature( const QgsRelation &newRelation, const QgsFeature &newFeature ) override;
|
||||
void afterSetRelationFeature() override;
|
||||
void beforeSetRelations( const QgsRelation &newRelation, const QgsRelation &newNmRelation ) override;
|
||||
void afterSetRelations() override;
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSBASICRELATIONWIDGET_H
|
||||
46
src/gui/qgsbasicrelationwidgetfactory.cpp
Normal file
46
src/gui/qgsbasicrelationwidgetfactory.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/***************************************************************************
|
||||
qgsbasicrelationwidgetfactory.cpp
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsbasicrelationwidgetfactory.h"
|
||||
#include "qgsbasicrelationconfigwidget.h"
|
||||
|
||||
QgsBasicRelationWidgetFactory::QgsBasicRelationWidgetFactory()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString QgsBasicRelationWidgetFactory::type() const
|
||||
{
|
||||
return QStringLiteral( "basic" );
|
||||
}
|
||||
|
||||
QString QgsBasicRelationWidgetFactory::name() const
|
||||
{
|
||||
return QStringLiteral( "Relation Editor" );
|
||||
}
|
||||
|
||||
QgsRelationWidget *QgsBasicRelationWidgetFactory::create( const QVariantMap &config, QWidget *parent ) const
|
||||
{
|
||||
return new QgsBasicRelationWidget( config, parent );
|
||||
}
|
||||
|
||||
|
||||
QgsRelationConfigWidget *QgsBasicRelationWidgetFactory::configWidget( const QgsRelation &relation, QWidget *parent ) const
|
||||
{
|
||||
return static_cast<QgsRelationConfigWidget *>( new QgsBasicRelationConfigWidget( relation, parent ) );
|
||||
}
|
||||
|
||||
48
src/gui/qgsbasicrelationwidgetfactory.h
Normal file
48
src/gui/qgsbasicrelationwidgetfactory.h
Normal file
@ -0,0 +1,48 @@
|
||||
/***************************************************************************
|
||||
qgsbasicrelationwidgetfactory.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 QGSBASICRELATIONWIDGETFACTORY_H
|
||||
#define QGSBASICRELATIONWIDGETFACTORY_H
|
||||
|
||||
#include "qgsrelationwidgetfactory.h"
|
||||
#include "qgsbasicrelationwidget.h"
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
/**
|
||||
* Factory class for creating a basic relation widget and the respective config widget.
|
||||
* \ingroup gui
|
||||
* \class QgsBasicRelationWidgetFactory
|
||||
* \note not available in Python bindings
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class GUI_EXPORT QgsBasicRelationWidgetFactory : public QgsRelationWidgetFactory
|
||||
{
|
||||
public:
|
||||
QgsBasicRelationWidgetFactory();
|
||||
|
||||
QString type() const override;
|
||||
|
||||
QString name() const override;
|
||||
|
||||
QgsRelationWidget *create( const QVariantMap &config, QWidget *parent = nullptr ) const override;
|
||||
|
||||
QgsRelationConfigWidget *configWidget( const QgsRelation &relation, QWidget *parent ) const override;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSBASICRELATIONWIDGETFACTORY_H
|
||||
@ -60,6 +60,7 @@
|
||||
#include "qgscodeeditorcolorschemeregistry.h"
|
||||
#include "qgssubsetstringeditorproviderregistry.h"
|
||||
#include "qgsprovidersourcewidgetproviderregistry.h"
|
||||
#include "qgsrelationwidgetregistry.h"
|
||||
|
||||
QgsGui *QgsGui::instance()
|
||||
{
|
||||
@ -77,6 +78,11 @@ QgsEditorWidgetRegistry *QgsGui::editorWidgetRegistry()
|
||||
return instance()->mEditorWidgetRegistry;
|
||||
}
|
||||
|
||||
QgsRelationWidgetRegistry *QgsGui::relationWidgetRegistry()
|
||||
{
|
||||
return instance()->mRelationEditorRegistry;
|
||||
}
|
||||
|
||||
QgsSourceSelectProviderRegistry *QgsGui::sourceSelectProviderRegistry()
|
||||
{
|
||||
return instance()->mSourceSelectProviderRegistry;
|
||||
@ -198,6 +204,7 @@ QgsGui::~QgsGui()
|
||||
delete mCodeEditorColorSchemeRegistry;
|
||||
delete mSubsetStringEditorProviderRegistry;
|
||||
delete mProviderSourceWidgetProviderRegistry;
|
||||
delete mRelationEditorRegistry;
|
||||
}
|
||||
|
||||
QColor QgsGui::sampleColor( QPoint point )
|
||||
@ -261,6 +268,7 @@ QgsGui::QgsGui()
|
||||
mProviderSourceWidgetProviderRegistry->initializeFromProviderGuiRegistry( mProviderGuiRegistry );
|
||||
|
||||
mEditorWidgetRegistry = new QgsEditorWidgetRegistry();
|
||||
mRelationEditorRegistry = new QgsRelationWidgetRegistry();
|
||||
mShortcutsManager = new QgsShortcutsManager();
|
||||
mLayerTreeEmbeddedWidgetRegistry = new QgsLayerTreeEmbeddedWidgetRegistry();
|
||||
mMapLayerActionRegistry = new QgsMapLayerActionRegistry();
|
||||
|
||||
@ -42,6 +42,7 @@ class QgsCodeEditorColorSchemeRegistry;
|
||||
class QgsMessageBar;
|
||||
class QgsSubsetStringEditorProviderRegistry;
|
||||
class QgsProviderSourceWidgetProviderRegistry;
|
||||
class QgsRelationWidgetRegistry;
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
@ -168,6 +169,12 @@ class GUI_EXPORT QgsGui : public QObject
|
||||
*/
|
||||
static QgsProviderSourceWidgetProviderRegistry *sourceWidgetProviderRegistry() SIP_KEEPREFERENCE;
|
||||
|
||||
/**
|
||||
* Returns the global relation widget registry, used for managing all known relation widget factories.
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
static QgsRelationWidgetRegistry *relationWidgetRegistry() SIP_KEEPREFERENCE;
|
||||
|
||||
/**
|
||||
* Register the widget to allow its position to be automatically saved and restored when open and closed.
|
||||
* Use this to avoid needing to call saveGeometry() and restoreGeometry() on your widget.
|
||||
@ -271,6 +278,7 @@ class GUI_EXPORT QgsGui : public QObject
|
||||
QgsProjectStorageGuiRegistry *mProjectStorageGuiRegistry = nullptr;
|
||||
QgsSubsetStringEditorProviderRegistry *mSubsetStringEditorProviderRegistry = nullptr;
|
||||
QgsProviderSourceWidgetProviderRegistry *mProviderSourceWidgetProviderRegistry = nullptr;
|
||||
QgsRelationWidgetRegistry *mRelationEditorRegistry = nullptr;
|
||||
std::unique_ptr< QgsWindowManagerInterface > mWindowManager;
|
||||
|
||||
#ifdef SIP_RUN
|
||||
|
||||
37
src/gui/qgsrelationconfigwidget.cpp
Normal file
37
src/gui/qgsrelationconfigwidget.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/***************************************************************************
|
||||
qgsrelationconfigbasewidget.cpp
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsrelationconfigwidget.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
|
||||
QgsRelationConfigWidget::QgsRelationConfigWidget( const QgsRelation &relation, QWidget *parent )
|
||||
: QWidget( parent )
|
||||
, mRelation( relation )
|
||||
{
|
||||
}
|
||||
|
||||
QgsVectorLayer *QgsRelationConfigWidget::layer()
|
||||
{
|
||||
return mLayer;
|
||||
}
|
||||
|
||||
QgsRelation QgsRelationConfigWidget::relation() const
|
||||
{
|
||||
return mRelation;
|
||||
}
|
||||
|
||||
|
||||
87
src/gui/qgsrelationconfigwidget.h
Normal file
87
src/gui/qgsrelationconfigwidget.h
Normal file
@ -0,0 +1,87 @@
|
||||
/***************************************************************************
|
||||
qgsrelationconfigwidget.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 QGSRELATIONCONFIGBASEWIDGET_H
|
||||
#define QGSRELATIONCONFIGBASEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "qgis_sip.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
#include "qgseditorwidgetwrapper.h"
|
||||
|
||||
class QgsRelation;
|
||||
class QgsPropertyOverrideButton;
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* This class should be subclassed for every configurable relation widget type.
|
||||
*
|
||||
* It implements the GUI configuration widget and transforms this to/from a configuration.
|
||||
*
|
||||
* It will only be instantiated by {\see QgsRelationWidgetFactory}
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
|
||||
class GUI_EXPORT QgsRelationConfigWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a new configuration widget
|
||||
*
|
||||
* \param relation The relation for which the configuration dialog will be created
|
||||
* \param parent A parent widget
|
||||
*/
|
||||
explicit QgsRelationConfigWidget( const QgsRelation &relation, QWidget *parent SIP_TRANSFERTHIS );
|
||||
|
||||
/**
|
||||
* \brief Create a configuration from the current GUI state
|
||||
*
|
||||
* \returns A widget configuration
|
||||
*/
|
||||
virtual QVariantMap config() = 0;
|
||||
|
||||
/**
|
||||
* \brief Update the configuration widget to represent the given configuration.
|
||||
*
|
||||
* \param config The configuration which should be represented by this widget
|
||||
*/
|
||||
virtual void setConfig( const QVariantMap &config ) = 0;
|
||||
|
||||
/**
|
||||
* Returns the layer for which this configuration widget applies
|
||||
*
|
||||
* \returns The layer
|
||||
*/
|
||||
QgsVectorLayer *layer();
|
||||
|
||||
/**
|
||||
* Returns the relation for which this configuration widget applies
|
||||
*
|
||||
* \returns The relation
|
||||
*/
|
||||
QgsRelation relation() const;
|
||||
|
||||
|
||||
private:
|
||||
QgsVectorLayer *mLayer = nullptr;
|
||||
QgsRelation mRelation;
|
||||
};
|
||||
|
||||
#endif // QGSRELATIONCONFIGBASEWIDGET_H
|
||||
595
src/gui/qgsrelationwidget.cpp
Normal file
595
src/gui/qgsrelationwidget.cpp
Normal file
@ -0,0 +1,595 @@
|
||||
/***************************************************************************
|
||||
qgsrelationwidget.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsrelationwidget.h"
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsdistancearea.h"
|
||||
#include "qgsfeatureiterator.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsexpression.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsfeatureselectiondlg.h"
|
||||
#include "qgsgenericfeatureselectionmanager.h"
|
||||
#include "qgsrelation.h"
|
||||
#include "qgsvectorlayertools.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgstransactiongroup.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsvectorlayerutils.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsvectorlayerselectionmanager.h"
|
||||
#include "qgsmaptooldigitizefeature.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
#include "qgsmessagebar.h"
|
||||
#include "qgsmessagebaritem.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
QgsRelationWidget::QgsRelationWidget( const QVariantMap &config, QWidget *parent )
|
||||
: QWidget( parent )
|
||||
{
|
||||
Q_UNUSED( config );
|
||||
}
|
||||
|
||||
void QgsRelationWidget::setRelationFeature( const QgsRelation &relation, const QgsFeature &feature )
|
||||
{
|
||||
beforeSetRelationFeature( relation, feature );
|
||||
|
||||
mRelation = relation;
|
||||
mFeature = feature;
|
||||
|
||||
setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
|
||||
|
||||
updateTitle();
|
||||
afterSetRelationFeature();
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void QgsRelationWidget::setRelations( const QgsRelation &relation, const QgsRelation &nmrelation )
|
||||
{
|
||||
|
||||
beforeSetRelations( relation, nmrelation );
|
||||
|
||||
mRelation = relation;
|
||||
mNmRelation = nmrelation;
|
||||
|
||||
if ( !mRelation.isValid() )
|
||||
{
|
||||
afterSetRelations();
|
||||
return;
|
||||
}
|
||||
|
||||
mLayerInSameTransactionGroup = false;
|
||||
|
||||
const auto transactionGroups = QgsProject::instance()->transactionGroups();
|
||||
for ( auto it = transactionGroups.constBegin(); it != transactionGroups.constEnd(); ++it )
|
||||
{
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
if ( it.value()->layers().contains( mRelation.referencedLayer() ) &&
|
||||
it.value()->layers().contains( mRelation.referencingLayer() ) &&
|
||||
it.value()->layers().contains( mNmRelation.referencedLayer() ) )
|
||||
mLayerInSameTransactionGroup = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( it.value()->layers().contains( mRelation.referencedLayer() ) &&
|
||||
it.value()->layers().contains( mRelation.referencingLayer() ) )
|
||||
mLayerInSameTransactionGroup = true;
|
||||
}
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
|
||||
setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
|
||||
|
||||
afterSetRelations();
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void QgsRelationWidget::setEditorContext( const QgsAttributeEditorContext &context )
|
||||
{
|
||||
mEditorContext = context;
|
||||
}
|
||||
|
||||
QgsAttributeEditorContext QgsRelationWidget::editorContext() const
|
||||
{
|
||||
return mEditorContext;
|
||||
}
|
||||
|
||||
QgsIFeatureSelectionManager *QgsRelationWidget::featureSelectionManager()
|
||||
{
|
||||
return mFeatureSelectionMgr;
|
||||
}
|
||||
|
||||
void QgsRelationWidget::setFeature( const QgsFeature &feature, bool update )
|
||||
{
|
||||
mFeature = feature;
|
||||
|
||||
mEditorContext.setFormFeature( feature );
|
||||
|
||||
if ( update )
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void QgsRelationWidget::setNmRelationId( const QVariant &nmRelationId )
|
||||
{
|
||||
mNmRelationId = nmRelationId;
|
||||
}
|
||||
|
||||
QVariant QgsRelationWidget::nmRelationId() const
|
||||
{
|
||||
return mNmRelationId;
|
||||
}
|
||||
|
||||
QString QgsRelationWidget::label() const
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
void QgsRelationWidget::setLabel( const QString &label )
|
||||
{
|
||||
mLabel = label;
|
||||
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
bool QgsRelationWidget::showLabel() const
|
||||
{
|
||||
return mShowLabel;
|
||||
}
|
||||
|
||||
void QgsRelationWidget::setShowLabel( bool showLabel )
|
||||
{
|
||||
mShowLabel = showLabel;
|
||||
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void QgsRelationWidget::setForceSuppressFormPopup( bool forceSuppressFormPopup )
|
||||
{
|
||||
mForceSuppressFormPopup = forceSuppressFormPopup;
|
||||
}
|
||||
|
||||
bool QgsRelationWidget::forceSuppressFormPopup() const
|
||||
{
|
||||
return mForceSuppressFormPopup;
|
||||
}
|
||||
|
||||
void QgsRelationWidget::updateTitle()
|
||||
{
|
||||
if ( mShowLabel && !mLabel.isEmpty() )
|
||||
{
|
||||
setTitle( mLabel );
|
||||
}
|
||||
else if ( mShowLabel && mRelation.isValid() )
|
||||
{
|
||||
setTitle( mRelation.name() );
|
||||
}
|
||||
else
|
||||
{
|
||||
setTitle( QString() );
|
||||
}
|
||||
}
|
||||
|
||||
QgsFeature QgsRelationWidget::feature() const
|
||||
{
|
||||
return mFeature;
|
||||
}
|
||||
|
||||
void QgsRelationWidget::toggleEditing( bool state )
|
||||
{
|
||||
if ( state )
|
||||
{
|
||||
mEditorContext.vectorLayerTools()->startEditing( mRelation.referencingLayer() );
|
||||
if ( mNmRelation.isValid() )
|
||||
mEditorContext.vectorLayerTools()->startEditing( mNmRelation.referencedLayer() );
|
||||
}
|
||||
else
|
||||
{
|
||||
mEditorContext.vectorLayerTools()->stopEditing( mRelation.referencingLayer() );
|
||||
if ( mNmRelation.isValid() )
|
||||
mEditorContext.vectorLayerTools()->stopEditing( mNmRelation.referencedLayer() );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRelationWidget::saveEdits()
|
||||
{
|
||||
mEditorContext.vectorLayerTools()->saveEdits( mRelation.referencingLayer() );
|
||||
if ( mNmRelation.isValid() )
|
||||
mEditorContext.vectorLayerTools()->saveEdits( mNmRelation.referencedLayer() );
|
||||
}
|
||||
|
||||
void QgsRelationWidget::addFeature( const QgsGeometry &geometry )
|
||||
{
|
||||
QgsAttributeMap keyAttrs;
|
||||
|
||||
const QgsVectorLayerTools *vlTools = mEditorContext.vectorLayerTools();
|
||||
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
// n:m Relation: first let the user create a new feature on the other table
|
||||
// and autocreate a new linking feature.
|
||||
QgsFeature f;
|
||||
if ( vlTools->addFeature( mNmRelation.referencedLayer(), QgsAttributeMap(), geometry, &f ) )
|
||||
{
|
||||
// Fields of the linking table
|
||||
const QgsFields fields = mRelation.referencingLayer()->fields();
|
||||
|
||||
// Expression context for the linking table
|
||||
QgsExpressionContext context = mRelation.referencingLayer()->createExpressionContext();
|
||||
|
||||
QgsAttributeMap linkAttributes;
|
||||
const auto constFieldPairs = mRelation.fieldPairs();
|
||||
for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
|
||||
{
|
||||
int index = fields.indexOf( fieldPair.first );
|
||||
linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
|
||||
}
|
||||
|
||||
const auto constNmFieldPairs = mNmRelation.fieldPairs();
|
||||
for ( const QgsRelation::FieldPair &fieldPair : constNmFieldPairs )
|
||||
{
|
||||
int index = fields.indexOf( fieldPair.first );
|
||||
linkAttributes.insert( index, f.attribute( fieldPair.second ) );
|
||||
}
|
||||
QgsFeature linkFeature = QgsVectorLayerUtils::createFeature( mRelation.referencingLayer(), QgsGeometry(), linkAttributes, &context );
|
||||
|
||||
mRelation.referencingLayer()->addFeature( linkFeature );
|
||||
|
||||
updateUi();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsFields fields = mRelation.referencingLayer()->fields();
|
||||
|
||||
const auto constFieldPairs = mRelation.fieldPairs();
|
||||
for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
|
||||
{
|
||||
keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeature.attribute( fieldPair.referencedField() ) );
|
||||
|
||||
// TODO FINISH!!!!
|
||||
// vlTools->addFeature( mDualView->masterModel()->layer(), keyAttrs, geometry );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRelationWidget::deleteFeature( const QgsFeatureId fid )
|
||||
{
|
||||
deleteFeatures( QgsFeatureIds() << fid );
|
||||
}
|
||||
|
||||
void QgsRelationWidget::deleteSelectedFeatures()
|
||||
{
|
||||
QgsFeatureIds selectedFids = mFeatureSelectionMgr->selectedFeatureIds();
|
||||
deleteFeatures( selectedFids );
|
||||
}
|
||||
|
||||
void QgsRelationWidget::deleteFeatures( const QgsFeatureIds &fids )
|
||||
{
|
||||
bool deleteFeatures = true;
|
||||
|
||||
QgsVectorLayer *layer;
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
layer = mNmRelation.referencedLayer();
|
||||
|
||||
// When deleting a linked feature within an N:M relation,
|
||||
// check if the feature is linked to more than just one feature.
|
||||
// In case it is linked more than just once, ask the user for confirmation
|
||||
// as it is likely he was not aware of the implications and might delete
|
||||
// there may be several linking entries deleted along.
|
||||
|
||||
QgsFeatureRequest deletedFeaturesRequest;
|
||||
deletedFeaturesRequest.setFilterFids( fids );
|
||||
deletedFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
|
||||
deletedFeaturesRequest.setSubsetOfAttributes( QgsAttributeList() << mNmRelation.referencedFields().first() );
|
||||
|
||||
QgsFeatureIterator deletedFeatures = layer->getFeatures( deletedFeaturesRequest );
|
||||
QStringList deletedFeaturesPks;
|
||||
QgsFeature feature;
|
||||
while ( deletedFeatures.nextFeature( feature ) )
|
||||
{
|
||||
deletedFeaturesPks.append( QgsExpression::quotedValue( feature.attribute( mNmRelation.referencedFields().first() ) ) );
|
||||
}
|
||||
|
||||
QgsFeatureRequest linkingFeaturesRequest;
|
||||
linkingFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
|
||||
linkingFeaturesRequest.setNoAttributes();
|
||||
|
||||
QString linkingFeaturesRequestExpression;
|
||||
if ( !deletedFeaturesPks.empty() )
|
||||
{
|
||||
linkingFeaturesRequestExpression = QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( mNmRelation.fieldPairs().first().first ), deletedFeaturesPks.join( ',' ) );
|
||||
linkingFeaturesRequest.setFilterExpression( linkingFeaturesRequestExpression );
|
||||
|
||||
QgsFeatureIterator relatedLinkingFeatures = mNmRelation.referencingLayer()->getFeatures( linkingFeaturesRequest );
|
||||
|
||||
int relatedLinkingFeaturesCount = 0;
|
||||
while ( relatedLinkingFeatures.nextFeature( feature ) )
|
||||
{
|
||||
relatedLinkingFeaturesCount++;
|
||||
}
|
||||
|
||||
if ( deletedFeaturesPks.size() == 1 && relatedLinkingFeaturesCount > 1 )
|
||||
{
|
||||
QMessageBox messageBox( QMessageBox::Question, tr( "Really delete entry?" ), tr( "The entry on %1 is still linked to %2 features on %3. Do you want to delete it?" ).arg( mNmRelation.referencedLayer()->name(), QString::number( relatedLinkingFeaturesCount ), mRelation.referencedLayer()->name() ), QMessageBox::NoButton, this );
|
||||
messageBox.addButton( QMessageBox::Cancel );
|
||||
QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
|
||||
|
||||
messageBox.exec();
|
||||
if ( messageBox.clickedButton() != deleteButton )
|
||||
deleteFeatures = false;
|
||||
}
|
||||
else if ( deletedFeaturesPks.size() > 1 && relatedLinkingFeaturesCount > deletedFeaturesPks.size() )
|
||||
{
|
||||
QMessageBox messageBox( QMessageBox::Question, tr( "Really delete entries?" ), tr( "The %1 entries on %2 are still linked to %3 features on %4. Do you want to delete them?" ).arg( QString::number( deletedFeaturesPks.size() ), mNmRelation.referencedLayer()->name(), QString::number( relatedLinkingFeaturesCount ), mRelation.referencedLayer()->name() ), QMessageBox::NoButton, this );
|
||||
messageBox.addButton( QMessageBox::Cancel );
|
||||
QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
|
||||
|
||||
messageBox.exec();
|
||||
if ( messageBox.clickedButton() != deleteButton )
|
||||
deleteFeatures = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
layer = mRelation.referencingLayer();
|
||||
}
|
||||
|
||||
QgsVectorLayerUtils::QgsDuplicateFeatureContext infoContext;
|
||||
if ( QgsVectorLayerUtils::impactsCascadeFeatures( layer, fids, QgsProject::instance(), infoContext ) )
|
||||
{
|
||||
QString childrenInfo;
|
||||
int childrenCount = 0;
|
||||
const auto infoContextLayers = infoContext.layers();
|
||||
for ( QgsVectorLayer *chl : infoContextLayers )
|
||||
{
|
||||
childrenCount += infoContext.duplicatedFeatures( chl ).size();
|
||||
childrenInfo += ( tr( "%1 feature(s) on layer \"%2\", " ).arg( infoContext.duplicatedFeatures( chl ).size() ).arg( chl->name() ) );
|
||||
}
|
||||
|
||||
// for extra safety to make sure we know that the delete can have impact on children and joins
|
||||
int res = QMessageBox::question( this, tr( "Delete at least %1 feature(s) on other layer(s)" ).arg( childrenCount ),
|
||||
tr( "Delete %1 feature(s) on layer \"%2\", %3 as well\nand all of its other descendants.\nDelete these features?" ).arg( fids.count() ).arg( layer->name() ).arg( childrenInfo ),
|
||||
QMessageBox::Yes | QMessageBox::No );
|
||||
if ( res != QMessageBox::Yes )
|
||||
deleteFeatures = false;
|
||||
}
|
||||
|
||||
if ( deleteFeatures )
|
||||
{
|
||||
QgsVectorLayer::DeleteContext context( true, QgsProject::instance() );
|
||||
layer->deleteFeatures( fids, &context );
|
||||
const auto contextLayers = context.handledLayers();
|
||||
if ( contextLayers.size() > 1 )
|
||||
{
|
||||
int deletedCount = 0;
|
||||
QString feedbackMessage;
|
||||
for ( QgsVectorLayer *contextLayer : contextLayers )
|
||||
{
|
||||
feedbackMessage += tr( "%1 on layer %2. " ).arg( context.handledFeatures( contextLayer ).size() ).arg( contextLayer->name() );
|
||||
deletedCount += context.handledFeatures( contextLayer ).size();
|
||||
}
|
||||
mEditorContext.mainMessageBar()->pushMessage( tr( "%1 features deleted: %2" ).arg( deletedCount ).arg( feedbackMessage ), Qgis::Success );
|
||||
}
|
||||
|
||||
updateUi();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRelationWidget::linkFeature()
|
||||
{
|
||||
QgsVectorLayer *layer = nullptr;
|
||||
|
||||
if ( mNmRelation.isValid() )
|
||||
layer = mNmRelation.referencedLayer();
|
||||
else
|
||||
layer = mRelation.referencingLayer();
|
||||
|
||||
QgsFeatureSelectionDlg *selectionDlg = new QgsFeatureSelectionDlg( layer, mEditorContext, this );
|
||||
selectionDlg->setAttribute( Qt::WA_DeleteOnClose );
|
||||
|
||||
const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( mRelation.referencedLayer(), mFeature );
|
||||
selectionDlg->setWindowTitle( tr( "Link existing child features for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString ) );
|
||||
|
||||
connect( selectionDlg, &QDialog::accepted, this, &QgsRelationWidget::onLinkFeatureDlgAccepted );
|
||||
selectionDlg->show();
|
||||
}
|
||||
|
||||
void QgsRelationWidget::onLinkFeatureDlgAccepted()
|
||||
{
|
||||
QgsFeatureSelectionDlg *selectionDlg = qobject_cast<QgsFeatureSelectionDlg *>( sender() );
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
QgsFeatureIterator it = mNmRelation.referencedLayer()->getFeatures(
|
||||
QgsFeatureRequest()
|
||||
.setFilterFids( selectionDlg->selectedFeatures() )
|
||||
.setSubsetOfAttributes( mNmRelation.referencedFields() ) );
|
||||
|
||||
QgsFeature relatedFeature;
|
||||
|
||||
QgsFeatureList newFeatures;
|
||||
|
||||
// Fields of the linking table
|
||||
const QgsFields fields = mRelation.referencingLayer()->fields();
|
||||
|
||||
// Expression context for the linking table
|
||||
QgsExpressionContext context = mRelation.referencingLayer()->createExpressionContext();
|
||||
|
||||
QgsAttributeMap linkAttributes;
|
||||
const auto constFieldPairs = mRelation.fieldPairs();
|
||||
for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
|
||||
{
|
||||
int index = fields.indexOf( fieldPair.first );
|
||||
linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
|
||||
}
|
||||
|
||||
while ( it.nextFeature( relatedFeature ) )
|
||||
{
|
||||
const auto constFieldPairs = mNmRelation.fieldPairs();
|
||||
for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
|
||||
{
|
||||
int index = fields.indexOf( fieldPair.first );
|
||||
linkAttributes.insert( index, relatedFeature.attribute( fieldPair.second ) );
|
||||
}
|
||||
const QgsFeature linkFeature = QgsVectorLayerUtils::createFeature( mRelation.referencingLayer(), QgsGeometry(), linkAttributes, &context );
|
||||
|
||||
newFeatures << linkFeature;
|
||||
}
|
||||
|
||||
mRelation.referencingLayer()->addFeatures( newFeatures );
|
||||
QgsFeatureIds ids;
|
||||
const auto constNewFeatures = newFeatures;
|
||||
for ( const QgsFeature &f : constNewFeatures )
|
||||
ids << f.id();
|
||||
mRelation.referencingLayer()->selectByIds( ids );
|
||||
}
|
||||
else
|
||||
{
|
||||
QMap<int, QVariant> keys;
|
||||
const auto constFieldPairs = mRelation.fieldPairs();
|
||||
for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
|
||||
{
|
||||
int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
|
||||
QVariant val = mFeature.attribute( fieldPair.referencedField() );
|
||||
keys.insert( idx, val );
|
||||
}
|
||||
|
||||
const auto constSelectedFeatures = selectionDlg->selectedFeatures();
|
||||
for ( QgsFeatureId fid : constSelectedFeatures )
|
||||
{
|
||||
QMapIterator<int, QVariant> it( keys );
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
it.next();
|
||||
mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), it.value() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void QgsRelationWidget::unlinkFeature( const QgsFeatureId fid )
|
||||
{
|
||||
unlinkFeatures( QgsFeatureIds() << fid );
|
||||
}
|
||||
|
||||
void QgsRelationWidget::unlinkSelectedFeatures()
|
||||
{
|
||||
unlinkFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
|
||||
}
|
||||
|
||||
void QgsRelationWidget::unlinkFeatures( const QgsFeatureIds &fids )
|
||||
{
|
||||
if ( mNmRelation.isValid() )
|
||||
{
|
||||
QgsFeatureIterator selectedIterator = mNmRelation.referencedLayer()->getFeatures(
|
||||
QgsFeatureRequest()
|
||||
.setFilterFids( fids )
|
||||
.setSubsetOfAttributes( mNmRelation.referencedFields() ) );
|
||||
|
||||
QgsFeature f;
|
||||
|
||||
QStringList filters;
|
||||
|
||||
while ( selectedIterator.nextFeature( f ) )
|
||||
{
|
||||
filters << '(' + mNmRelation.getRelatedFeaturesRequest( f ).filterExpression()->expression() + ')';
|
||||
}
|
||||
|
||||
QString filter = QStringLiteral( "(%1) AND (%2)" ).arg(
|
||||
mRelation.getRelatedFeaturesRequest( mFeature ).filterExpression()->expression(),
|
||||
filters.join( QLatin1String( " OR " ) ) );
|
||||
|
||||
QgsFeatureIterator linkedIterator = mRelation.referencingLayer()->getFeatures( QgsFeatureRequest()
|
||||
.setNoAttributes()
|
||||
.setFilterExpression( filter ) );
|
||||
|
||||
QgsFeatureIds fids;
|
||||
|
||||
while ( linkedIterator.nextFeature( f ) )
|
||||
{
|
||||
fids << f.id();
|
||||
QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 );
|
||||
}
|
||||
|
||||
mRelation.referencingLayer()->deleteFeatures( fids );
|
||||
|
||||
updateUi();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMap<int, QgsField> keyFields;
|
||||
const auto constFieldPairs = mRelation.fieldPairs();
|
||||
for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
|
||||
{
|
||||
int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
|
||||
if ( idx < 0 )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
|
||||
return;
|
||||
}
|
||||
QgsField fld = mRelation.referencingLayer()->fields().at( idx );
|
||||
keyFields.insert( idx, fld );
|
||||
}
|
||||
|
||||
const auto constFeatureids = fids;
|
||||
for ( QgsFeatureId fid : constFeatureids )
|
||||
{
|
||||
QMapIterator<int, QgsField> it( keyFields );
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
it.next();
|
||||
mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QVariant( it.value().type() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRelationWidget::duplicateFeature()
|
||||
{
|
||||
QgsVectorLayer *layer = mRelation.referencingLayer();
|
||||
|
||||
QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterFids( mFeatureSelectionMgr->selectedFeatureIds() ) );
|
||||
QgsFeature f;
|
||||
while ( fit.nextFeature( f ) )
|
||||
{
|
||||
QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicatedFeatureContext;
|
||||
QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), duplicatedFeatureContext );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRelationWidget::zoomToSelectedFeatures()
|
||||
{
|
||||
QgsMapCanvas *c = mEditorContext.mapCanvas();
|
||||
if ( !c )
|
||||
return;
|
||||
|
||||
c->zoomToFeatureIds(
|
||||
mNmRelation.isValid() ? mNmRelation.referencedLayer() : mRelation.referencingLayer(),
|
||||
mFeatureSelectionMgr->selectedFeatureIds()
|
||||
);
|
||||
}
|
||||
260
src/gui/qgsrelationwidget.h
Normal file
260
src/gui/qgsrelationwidget.h
Normal file
@ -0,0 +1,260 @@
|
||||
/***************************************************************************
|
||||
qgsrelationwidget.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 QGSRELATIONWIDGET_H
|
||||
#define QGSRELATIONWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QToolButton>
|
||||
#include <QButtonGroup>
|
||||
#include <QGridLayout>
|
||||
#include "qobjectuniqueptr.h"
|
||||
|
||||
#include "qobjectuniqueptr.h"
|
||||
#include "qgsattributeeditorcontext.h"
|
||||
#include "qgscollapsiblegroupbox.h"
|
||||
#include "qgsdualview.h"
|
||||
#include "qgsrelation.h"
|
||||
#include "qgsvectorlayerselectionmanager.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QgsFeature;
|
||||
class QgsVectorLayer;
|
||||
class QgsVectorLayerTools;
|
||||
class QgsMapTool;
|
||||
class QgsMapToolDigitizeFeature;
|
||||
|
||||
|
||||
/**
|
||||
* Base class to build new relation widgets.
|
||||
* \ingroup gui
|
||||
* \class QgsRelationWidget
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class GUI_EXPORT QgsRelationWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
QgsRelationWidget( const QVariantMap &config, QWidget *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
/**
|
||||
* Sets the \a relation and the \a feature
|
||||
*/
|
||||
void setRelationFeature( const QgsRelation &relation, const QgsFeature &feature );
|
||||
|
||||
/**
|
||||
* Set the relation(s) for this widget
|
||||
* If only one relation is set, it will act as a simple 1:N relation widget
|
||||
* If both relations are set, it will act as an N:M relation widget
|
||||
* inserting and deleting entries on the intermediate table as required.
|
||||
*
|
||||
* \param relation Relation referencing the edited table
|
||||
* \param nmrelation Optional reference from the referencing table to a 3rd N:M table
|
||||
*/
|
||||
void setRelations( const QgsRelation &relation, const QgsRelation &nmrelation );
|
||||
|
||||
/**
|
||||
* Sets the \a feature being edited and updates the UI unless \a update is set to FALSE
|
||||
*/
|
||||
void setFeature( const QgsFeature &feature, bool update = true );
|
||||
|
||||
/**
|
||||
* Sets the editor \a context
|
||||
* \note if context cadDockWidget is null, it won't be possible to digitize
|
||||
* the geometry of a referencing feature from this widget
|
||||
*/
|
||||
void setEditorContext( const QgsAttributeEditorContext &context );
|
||||
|
||||
/**
|
||||
* Returns the attribute editor context.
|
||||
*/
|
||||
QgsAttributeEditorContext editorContext( ) const;
|
||||
|
||||
/**
|
||||
* The feature selection manager is responsible for the selected features
|
||||
* which are currently being edited.
|
||||
*/
|
||||
QgsIFeatureSelectionManager *featureSelectionManager();
|
||||
|
||||
/**
|
||||
* Defines if a title label should be shown for this widget.
|
||||
*/
|
||||
bool showLabel() const;
|
||||
|
||||
/**
|
||||
* Defines if a title label should be shown for this widget.
|
||||
*/
|
||||
void setShowLabel( bool showLabel );
|
||||
|
||||
/**
|
||||
* Determines the relation id of the second relation involved in an N:M relation.
|
||||
*/
|
||||
QVariant nmRelationId() const;
|
||||
|
||||
/**
|
||||
* Sets \a nmRelationId for the relation id of the second relation involved in an N:M relation.
|
||||
* If it's empty, then it's considered as a 1:M relationship.
|
||||
*/
|
||||
void setNmRelationId( const QVariant &nmRelationId = QVariant() );
|
||||
|
||||
/**
|
||||
* Determines the label of this element
|
||||
*/
|
||||
QString label() const;
|
||||
|
||||
/**
|
||||
* Sets \a label for this element
|
||||
* If it's empty it takes the relation id as label
|
||||
*/
|
||||
void setLabel( const QString &label = QString() );
|
||||
|
||||
/**
|
||||
* Returns the widget's current feature
|
||||
*/
|
||||
QgsFeature feature() const;
|
||||
|
||||
/**
|
||||
* Determines the force suppress form popup status that is configured for this widget
|
||||
*/
|
||||
bool forceSuppressFormPopup() const;
|
||||
|
||||
/**
|
||||
* Sets force suppress form popup status with \a forceSuppressFormPopup
|
||||
* configured for this widget
|
||||
*/
|
||||
void setForceSuppressFormPopup( bool forceSuppressFormPopup );
|
||||
|
||||
/**
|
||||
* Returns the widget configuration
|
||||
*/
|
||||
virtual QVariantMap config() const = 0;
|
||||
|
||||
/**
|
||||
* Defines the widget configuration
|
||||
*/
|
||||
virtual void setConfig( const QVariantMap &config ) = 0;
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Called when an \a attribute value in the parent widget has changed to \a newValue
|
||||
*/
|
||||
virtual void parentFormValueChanged( const QString &attribute, const QVariant &newValue ) = 0;
|
||||
|
||||
protected slots:
|
||||
|
||||
/**
|
||||
* Toggles editing state of the widget
|
||||
*/
|
||||
void toggleEditing( bool state );
|
||||
|
||||
/**
|
||||
* Saves the current modifications in the relation
|
||||
*/
|
||||
void saveEdits();
|
||||
|
||||
/**
|
||||
* Adds a new feature with given \a geometry
|
||||
*/
|
||||
void addFeature( const QgsGeometry &geometry = QgsGeometry() );
|
||||
|
||||
/**
|
||||
* Delete a feature with given \a fid
|
||||
*/
|
||||
void deleteFeature( QgsFeatureId fid = QgsFeatureId() );
|
||||
|
||||
/**
|
||||
* Deletes the currently selected features
|
||||
*/
|
||||
void deleteSelectedFeatures();
|
||||
|
||||
/**
|
||||
* Links a new feature to the relation
|
||||
*/
|
||||
void linkFeature();
|
||||
|
||||
/**
|
||||
* Called when the link feature dialog is confirmed by the user
|
||||
*/
|
||||
void onLinkFeatureDlgAccepted();
|
||||
|
||||
/**
|
||||
* Unlinks a feature with given \a fid
|
||||
*/
|
||||
void unlinkFeature( QgsFeatureId fid = QgsFeatureId() );
|
||||
|
||||
/**
|
||||
* Unlinks the selected features from the relation
|
||||
*/
|
||||
void unlinkSelectedFeatures();
|
||||
|
||||
/**
|
||||
* Duplicates a feature
|
||||
*/
|
||||
void duplicateFeature();
|
||||
|
||||
/**
|
||||
* Zooms to the selected features
|
||||
*/
|
||||
void zoomToSelectedFeatures();
|
||||
|
||||
protected:
|
||||
|
||||
QgsVectorLayerSelectionManager *mFeatureSelectionMgr = nullptr;
|
||||
QgsAttributeEditorContext mEditorContext;
|
||||
QgsRelation mRelation;
|
||||
QgsRelation mNmRelation;
|
||||
QgsFeature mFeature;
|
||||
|
||||
bool mShowLabel = true;
|
||||
bool mLayerInSameTransactionGroup = false;
|
||||
|
||||
bool mForceSuppressFormPopup = false;
|
||||
QVariant mNmRelationId;
|
||||
QString mLabel;
|
||||
|
||||
/**
|
||||
* Updates the title contents to reflect the current state of the widget
|
||||
*/
|
||||
void updateTitle();
|
||||
|
||||
/**
|
||||
* Deletes the features with \a fids
|
||||
*/
|
||||
void deleteFeatures( const QgsFeatureIds &fids );
|
||||
|
||||
/**
|
||||
* Unlinks the features with \a fids
|
||||
*/
|
||||
void unlinkFeatures( const QgsFeatureIds &fids );
|
||||
|
||||
private:
|
||||
virtual void updateUi() {};
|
||||
virtual void setTitle( const QString &title ) { Q_UNUSED( title ); };
|
||||
virtual void beforeSetRelationFeature( const QgsRelation &newRelation, const QgsFeature &newFeature ) { Q_UNUSED( newRelation ); Q_UNUSED( newFeature ); };
|
||||
virtual void afterSetRelationFeature() {};
|
||||
virtual void beforeSetRelations( const QgsRelation &newRelation, const QgsRelation &newNmRelation ) { Q_UNUSED( newRelation ); Q_UNUSED( newNmRelation ); };
|
||||
virtual void afterSetRelations() {};
|
||||
};
|
||||
|
||||
#endif // QGSRELATIONWIDGET_H
|
||||
24
src/gui/qgsrelationwidgetfactory.cpp
Normal file
24
src/gui/qgsrelationwidgetfactory.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
/***************************************************************************
|
||||
qgsrelationwidgetfactory.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsrelationwidgetfactory.h"
|
||||
|
||||
|
||||
QgsRelationWidgetFactory::QgsRelationWidgetFactory()
|
||||
{
|
||||
}
|
||||
|
||||
80
src/gui/qgsrelationwidgetfactory.h
Normal file
80
src/gui/qgsrelationwidgetfactory.h
Normal file
@ -0,0 +1,80 @@
|
||||
/***************************************************************************
|
||||
qgsrelationwidgetfactory.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 QGSRELATIONEDITORBASEWIDGETFACTORY_H
|
||||
#define QGSRELATIONEDITORBASEWIDGETFACTORY_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "qgsrelationwidget.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QgsRelationConfigWidget;
|
||||
|
||||
/**
|
||||
* Factory class for creating relation widgets and their corresponding config widgets
|
||||
* \ingroup gui
|
||||
* \class QgsRelationWidgetFactory
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class GUI_EXPORT QgsRelationWidgetFactory
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new relation widget factory with given \a name
|
||||
*/
|
||||
QgsRelationWidgetFactory();
|
||||
|
||||
virtual ~QgsRelationWidgetFactory() = default;
|
||||
|
||||
/**
|
||||
* Returns the machine readable identifier name of this widget type
|
||||
*/
|
||||
virtual QString type() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the human readable identifier name of this widget type
|
||||
*/
|
||||
virtual QString name() const = 0;
|
||||
|
||||
/**
|
||||
* Override this in your implementation.
|
||||
* Create a new relation widget. Call QgsEditorWidgetRegistry::create()
|
||||
* instead of calling this method directly.
|
||||
*
|
||||
* \param config The widget configuration to build the widget with
|
||||
* \param parent The parent for the wrapper class and any created widget.
|
||||
*
|
||||
* \returns A new widget wrapper
|
||||
*/
|
||||
virtual QgsRelationWidget *create( const QVariantMap &config, QWidget *parent = nullptr ) const = 0 SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Override this in your implementation.
|
||||
* Create a new configuration widget for this widget type.
|
||||
*
|
||||
* \param relation The relation for which the widget will be created
|
||||
* \param parent The parent widget of the created config widget
|
||||
*
|
||||
* \returns A configuration widget
|
||||
*/
|
||||
virtual QgsRelationConfigWidget *configWidget( const QgsRelation &relation, QWidget *parent ) const = 0 SIP_FACTORY;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // QGSRELATIONEDITORBASEWIDGETFACTORY_H
|
||||
78
src/gui/qgsrelationwidgetregistry.cpp
Normal file
78
src/gui/qgsrelationwidgetregistry.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
/***************************************************************************
|
||||
qgsrelationwidgetregistry.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsrelationwidgetregistry.h"
|
||||
#include "qgsrelationwidget.h"
|
||||
#include "qgsrelationconfigwidget.h"
|
||||
#include "qgsbasicrelationwidgetfactory.h"
|
||||
|
||||
QgsRelationWidgetRegistry::QgsRelationWidgetRegistry()
|
||||
{
|
||||
addRelationWidget( new QgsBasicRelationWidgetFactory() );
|
||||
}
|
||||
|
||||
QgsRelationWidgetRegistry::~QgsRelationWidgetRegistry()
|
||||
{
|
||||
qDeleteAll( mRelationWidgetFactories );
|
||||
mRelationWidgetFactories.clear();
|
||||
}
|
||||
|
||||
void QgsRelationWidgetRegistry::addRelationWidget( QgsRelationWidgetFactory *widgetFactory )
|
||||
{
|
||||
if ( !widgetFactory )
|
||||
return;
|
||||
|
||||
if ( mRelationWidgetFactories.contains( widgetFactory->type() ) )
|
||||
return;
|
||||
|
||||
mRelationWidgetFactories.insert( widgetFactory->type(), widgetFactory );
|
||||
}
|
||||
|
||||
void QgsRelationWidgetRegistry::removeRelationWidget( const QString &widgetType )
|
||||
{
|
||||
// protect the basic widget from removing, so the user has at least one relation widget type
|
||||
if ( dynamic_cast<QgsBasicRelationWidgetFactory *>( mRelationWidgetFactories.value( widgetType ) ) )
|
||||
return;
|
||||
|
||||
mRelationWidgetFactories.remove( widgetType );
|
||||
}
|
||||
|
||||
QStringList QgsRelationWidgetRegistry::relationWidgetNames()
|
||||
{
|
||||
return mRelationWidgetFactories.keys();
|
||||
}
|
||||
|
||||
QMap<QString, QgsRelationWidgetFactory *> QgsRelationWidgetRegistry::factories() const
|
||||
{
|
||||
return mRelationWidgetFactories;
|
||||
}
|
||||
|
||||
QgsRelationWidget *QgsRelationWidgetRegistry::create( const QString &widgetType, const QVariantMap &config, QWidget *parent ) const
|
||||
{
|
||||
if ( ! mRelationWidgetFactories.contains( widgetType ) )
|
||||
return nullptr;
|
||||
|
||||
return mRelationWidgetFactories.value( widgetType )->create( config, parent );
|
||||
}
|
||||
|
||||
QgsRelationConfigWidget *QgsRelationWidgetRegistry::createConfigWidget( const QString &widgetType, const QgsRelation &relation, QWidget *parent ) const
|
||||
{
|
||||
if ( ! mRelationWidgetFactories.contains( widgetType ) )
|
||||
return nullptr;
|
||||
|
||||
return mRelationWidgetFactories.value( widgetType )->configWidget( relation, parent );
|
||||
}
|
||||
90
src/gui/qgsrelationwidgetregistry.h
Normal file
90
src/gui/qgsrelationwidgetregistry.h
Normal file
@ -0,0 +1,90 @@
|
||||
/***************************************************************************
|
||||
qgsrelationwidgetregistry.h
|
||||
----------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgseditorconfigwidget.h"
|
||||
#include "qgsrelationwidget.h"
|
||||
#include "qgsrelationwidgetfactory.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
|
||||
#ifndef QGSRELATIONWIDGETREGISTRY_H
|
||||
#define QGSRELATIONWIDGETREGISTRY_H
|
||||
|
||||
class QgsRelationConfigWidget;
|
||||
|
||||
/**
|
||||
* Keeps track of the registered relations widgets. New widgets can be registered, old ones deleted.
|
||||
* The default {\see QgsBasicRelationWidget} is protected from removing.
|
||||
* \ingroup gui
|
||||
* \class QgsRelationWidgetRegistry
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class GUI_EXPORT QgsRelationWidgetRegistry
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
QgsRelationWidgetRegistry();
|
||||
|
||||
~QgsRelationWidgetRegistry();
|
||||
|
||||
/**
|
||||
* Adds a new registered relation \a widgetFactory
|
||||
*/
|
||||
void addRelationWidget( QgsRelationWidgetFactory *widgetFactory SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Removes a registered relation widget with given \a widgetType
|
||||
*/
|
||||
void removeRelationWidget( const QString &widgetType );
|
||||
|
||||
/**
|
||||
* Returns a list of names of registered relation widgets
|
||||
*/
|
||||
QStringList relationWidgetNames();
|
||||
|
||||
/**
|
||||
* Gets access to all registered factories
|
||||
*/
|
||||
QMap<QString, QgsRelationWidgetFactory *> factories() const;
|
||||
|
||||
/**
|
||||
* Create a relation widget of a given type for a given field.
|
||||
*
|
||||
* \param widgetType The widget type to create a relation editor for
|
||||
* \param config The configuration of the widget
|
||||
* \param parent
|
||||
*/
|
||||
QgsRelationWidget *create( const QString &widgetType, const QVariantMap &config, QWidget *parent = nullptr ) const SIP_TRANSFERBACK;
|
||||
|
||||
/**
|
||||
* Creates a configuration widget
|
||||
*
|
||||
* \param widgetType The widget type to create a configuration widget for
|
||||
* \param relation The relation for which this widget will be created
|
||||
* \param parent The parent widget for the created widget
|
||||
*/
|
||||
QgsRelationConfigWidget *createConfigWidget( const QString &widgetType, const QgsRelation &relation, QWidget *parent = nullptr ) const SIP_TRANSFERBACK;
|
||||
|
||||
private:
|
||||
|
||||
QMap<QString, QgsRelationWidgetFactory *> mRelationWidgetFactories;
|
||||
};
|
||||
|
||||
#endif // QGSRELATIONWIDGETREGISTRY_H
|
||||
@ -409,8 +409,11 @@ QTreeWidgetItem *QgsAttributesFormProperties::loadAttributeEditorTreeItem( QgsAt
|
||||
const QgsAttributeEditorRelation *relationEditor = static_cast<const QgsAttributeEditorRelation *>( widgetDef );
|
||||
DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Relation, relationEditor->relation().id(), relationEditor->relation().name() );
|
||||
itemData.setShowLabel( widgetDef->showLabel() );
|
||||
|
||||
RelationEditorConfiguration relEdConfig;
|
||||
relEdConfig.buttons = relationEditor->visibleButtons();
|
||||
// relEdConfig.buttons = relationEditor->visibleButtons();
|
||||
relEdConfig.mRelationWidgetType = relationEditor->relationWidgetTypeId();
|
||||
relEdConfig.mRelationWidgetConfig = relationEditor->config();
|
||||
relEdConfig.nmRelationId = relationEditor->nmRelationId();
|
||||
relEdConfig.forceSuppressFormPopup = relationEditor->forceSuppressFormPopup();
|
||||
relEdConfig.label = relationEditor->label();
|
||||
@ -657,10 +660,12 @@ QgsAttributeEditorElement *QgsAttributesFormProperties::createAttributeEditorWid
|
||||
{
|
||||
QgsRelation relation = QgsProject::instance()->relationManager()->relation( itemData.name() );
|
||||
QgsAttributeEditorRelation *relDef = new QgsAttributeEditorRelation( relation, parent );
|
||||
relDef->setVisibleButtons( itemData.relationEditorConfiguration().buttons );
|
||||
relDef->setNmRelationId( itemData.relationEditorConfiguration().nmRelationId );
|
||||
relDef->setForceSuppressFormPopup( itemData.relationEditorConfiguration().forceSuppressFormPopup );
|
||||
relDef->setLabel( itemData.relationEditorConfiguration().label );
|
||||
QgsAttributesFormProperties::RelationEditorConfiguration relationEditorConfig = itemData.relationEditorConfiguration();
|
||||
relDef->setRelationWidgetTypeId( relationEditorConfig.mRelationWidgetType );
|
||||
relDef->setConfig( relationEditorConfig.mRelationWidgetConfig );
|
||||
relDef->setNmRelationId( relationEditorConfig.nmRelationId );
|
||||
relDef->setForceSuppressFormPopup( relationEditorConfig.forceSuppressFormPopup );
|
||||
relDef->setLabel( relationEditorConfig.label );
|
||||
widgetDef = relDef;
|
||||
break;
|
||||
}
|
||||
@ -892,7 +897,6 @@ void QgsAttributesFormProperties::apply()
|
||||
/*
|
||||
* FieldConfig implementation
|
||||
*/
|
||||
|
||||
QgsAttributesFormProperties::FieldConfig::FieldConfig( QgsVectorLayer *layer, int idx )
|
||||
{
|
||||
mAlias = layer->fields().at( idx ).alias();
|
||||
@ -913,6 +917,15 @@ QgsAttributesFormProperties::FieldConfig::operator QVariant()
|
||||
return QVariant::fromValue<QgsAttributesFormProperties::FieldConfig>( *this );
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationEditorConfiguration implementation
|
||||
*/
|
||||
|
||||
QgsAttributesFormProperties::RelationEditorConfiguration::operator QVariant()
|
||||
{
|
||||
return QVariant::fromValue<QgsAttributesFormProperties::RelationEditorConfiguration>( *this );
|
||||
}
|
||||
|
||||
/*
|
||||
* DnDTree implementation
|
||||
*/
|
||||
|
||||
@ -62,12 +62,16 @@ class GUI_EXPORT QgsAttributesFormProperties : public QWidget, public QgsExpress
|
||||
{
|
||||
DnDTreeRole = Qt::UserRole,
|
||||
FieldConfigRole,
|
||||
FieldNameRole
|
||||
FieldNameRole,
|
||||
};
|
||||
|
||||
struct RelationEditorConfiguration
|
||||
{
|
||||
operator QVariant();
|
||||
|
||||
QgsAttributeEditorRelation::Buttons buttons = QgsAttributeEditorRelation::Button::AllButtons;
|
||||
QString mRelationWidgetType;
|
||||
QVariantMap mRelationWidgetConfig;
|
||||
QVariant nmRelationId;
|
||||
bool forceSuppressFormPopup = false;
|
||||
QString label;
|
||||
@ -310,6 +314,7 @@ class GUI_EXPORT QgsAttributesDnDTree : public QTreeWidget
|
||||
};
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE( QgsAttributesFormProperties::RelationEditorConfiguration )
|
||||
Q_DECLARE_METATYPE( QgsAttributesFormProperties::FieldConfig )
|
||||
Q_DECLARE_METATYPE( QgsAttributesFormProperties::DnDTreeItemData )
|
||||
|
||||
|
||||
@ -7,101 +7,41 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>340</width>
|
||||
<height>361</height>
|
||||
<height>316</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Attribute Widget Relation Edit Widget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelLabel">
|
||||
<property name="text">
|
||||
<string>Label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="mRelationLabelEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowLinkCheckBox">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mLabelLabel">
|
||||
<property name="text">
|
||||
<string>Show link button</string>
|
||||
<string>Label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowUnlinkCheckBox">
|
||||
<property name="text">
|
||||
<string>Show unlink button</string>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="mRelationLabelEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowSaveChildEditsCheckBox">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="mCardinalityLabel">
|
||||
<property name="text">
|
||||
<string>Show save child layer edits button</string>
|
||||
<string>Cardinality</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowAddChildCheckBox">
|
||||
<property name="text">
|
||||
<string>Add child feature</string>
|
||||
</property>
|
||||
</widget>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="mRelationCardinalityCombo"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowDuplicateChildFeatureCheckBox">
|
||||
<property name="text">
|
||||
<string>Duplicate child feature</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationDeleteChildFeatureCheckBox">
|
||||
<property name="text">
|
||||
<string>Delete child feature</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowZoomToFeatureCheckBox">
|
||||
<property name="text">
|
||||
<string>Zoom to child feature</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="cardinalityLabel">
|
||||
<property name="text">
|
||||
<string>Cardinality</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="mRelationCardinalityCombo"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="mRelationForceSuppressFormPopupCheckBox">
|
||||
<property name="statusTip">
|
||||
<string>Do not open a new attribute form after digitizing a new feature, overrides all other options</string>
|
||||
@ -111,8 +51,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QgsCollapsibleGroupBox" name="mWidgetTypeGroupBox">
|
||||
<property name="title">
|
||||
<string>Widget Configuration</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="mWidgetTypePlaceholderLayout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<spacer name="mVerticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
@ -124,8 +76,26 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="mWidgetTypeComboBox"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="mCardinalityLabel_2">
|
||||
<property name="text">
|
||||
<string>Widget Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsCollapsibleGroupBox</class>
|
||||
<extends>QGroupBox</extends>
|
||||
<header>qgscollapsiblegroupbox.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
70
src/ui/qgsrelationeditorconfigwidgetbase.ui
Normal file
70
src/ui/qgsrelationeditorconfigwidgetbase.ui
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsRelationEditorConfigWidgetBase</class>
|
||||
<widget class="QWidget" name="QgsRelationEditorConfigWidgetBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>274</width>
|
||||
<height>215</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Attribute Widget Relation Edit Widget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowLinkCheckBox">
|
||||
<property name="text">
|
||||
<string>Show link button</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowUnlinkCheckBox">
|
||||
<property name="text">
|
||||
<string>Show unlink button</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowSaveChildEditsCheckBox">
|
||||
<property name="text">
|
||||
<string>Show save child layer edits button</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowAddChildCheckBox">
|
||||
<property name="text">
|
||||
<string>Add child feature</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowDuplicateChildFeatureCheckBox">
|
||||
<property name="text">
|
||||
<string>Duplicate child feature</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationDeleteChildFeatureCheckBox">
|
||||
<property name="text">
|
||||
<string>Delete child feature</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mRelationShowZoomToFeatureCheckBox">
|
||||
<property name="text">
|
||||
<string>Zoom to child feature</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Loading…
x
Reference in New Issue
Block a user