34 #include <QHBoxLayout> 36 #include <QMessageBox> 41 QVBoxLayout *topLayout =
new QVBoxLayout(
this );
42 topLayout->setContentsMargins( 0, 9, 0, 0 );
43 setLayout( topLayout );
46 QHBoxLayout *buttonLayout =
new QHBoxLayout();
47 buttonLayout->setContentsMargins( 0, 0, 0, 0 );
49 mToggleEditingButton =
new QToolButton(
this );
50 mToggleEditingButton->setObjectName( QStringLiteral(
"mToggleEditingButton" ) );
52 mToggleEditingButton->setText( tr(
"Toggle Editing" ) );
53 mToggleEditingButton->setEnabled(
false );
54 mToggleEditingButton->setCheckable(
true );
55 mToggleEditingButton->setToolTip( tr(
"Toggle editing mode for child layer" ) );
56 buttonLayout->addWidget( mToggleEditingButton );
58 mSaveEditsButton =
new QToolButton(
this );
60 mSaveEditsButton->setText( tr(
"Save Child Layer Edits" ) );
61 mSaveEditsButton->setToolTip( tr(
"Save child layer edits" ) );
62 mSaveEditsButton->setEnabled(
true );
63 buttonLayout->addWidget( mSaveEditsButton );
65 mAddFeatureButton =
new QToolButton(
this );
67 mAddFeatureButton->setText( tr(
"Add Child Feature" ) );
68 mAddFeatureButton->setToolTip( tr(
"Add child feature" ) );
69 mAddFeatureButton->setObjectName( QStringLiteral(
"mAddFeatureButton" ) );
70 buttonLayout->addWidget( mAddFeatureButton );
72 mDuplicateFeatureButton =
new QToolButton(
this );
74 mDuplicateFeatureButton->setText( tr(
"Duplicate Child Feature" ) );
75 mDuplicateFeatureButton->setToolTip( tr(
"Duplicate child feature" ) );
76 mDuplicateFeatureButton->setObjectName( QStringLiteral(
"mDuplicateFeatureButton" ) );
77 buttonLayout->addWidget( mDuplicateFeatureButton );
79 mDeleteFeatureButton =
new QToolButton(
this );
81 mDeleteFeatureButton->setText( tr(
"Delete Child Feature" ) );
82 mDeleteFeatureButton->setToolTip( tr(
"Delete child feature" ) );
83 mDeleteFeatureButton->setObjectName( QStringLiteral(
"mDeleteFeatureButton" ) );
84 buttonLayout->addWidget( mDeleteFeatureButton );
86 mLinkFeatureButton =
new QToolButton(
this );
88 mLinkFeatureButton->setText( tr(
"Link Existing Features" ) );
89 mLinkFeatureButton->setToolTip( tr(
"Link existing child features" ) );
90 mLinkFeatureButton->setObjectName( QStringLiteral(
"mLinkFeatureButton" ) );
91 buttonLayout->addWidget( mLinkFeatureButton );
93 mUnlinkFeatureButton =
new QToolButton(
this );
95 mUnlinkFeatureButton->setText( tr(
"Unlink Feature" ) );
96 mUnlinkFeatureButton->setToolTip( tr(
"Unlink child feature" ) );
97 mUnlinkFeatureButton->setObjectName( QStringLiteral(
"mUnlinkFeatureButton" ) );
98 buttonLayout->addWidget( mUnlinkFeatureButton );
100 mZoomToFeatureButton =
new QToolButton(
this );
102 mZoomToFeatureButton->setText( tr(
"Zoom To Feature" ) );
103 mZoomToFeatureButton->setToolTip( tr(
"Zoom to child feature" ) );
104 mZoomToFeatureButton->setObjectName( QStringLiteral(
"mZoomToFeatureButton" ) );
105 buttonLayout->addWidget( mZoomToFeatureButton );
107 buttonLayout->addItem(
new QSpacerItem( 0, 0, QSizePolicy::Expanding ) );
109 mFormViewButton =
new QToolButton(
this );
110 mFormViewButton->setText( tr(
"Form View" ) );
111 mFormViewButton->setToolTip( tr(
"Switch to form view" ) );
113 mFormViewButton->setCheckable(
true );
115 buttonLayout->addWidget( mFormViewButton );
117 mTableViewButton =
new QToolButton(
this );
118 mTableViewButton->setText( tr(
"Table View" ) );
119 mTableViewButton->setToolTip( tr(
"Switch to table view" ) );
121 mTableViewButton->setCheckable(
true );
123 buttonLayout->addWidget( mTableViewButton );
125 mViewModeButtonGroup =
new QButtonGroup(
this );
130 topLayout->addLayout( buttonLayout );
132 mRelationLayout =
new QGridLayout();
133 mRelationLayout->setContentsMargins( 0, 0, 0, 0 );
134 topLayout->addLayout( mRelationLayout );
137 mDualView->
setView( mViewMode );
141 mRelationLayout->addWidget( mDualView );
144 connect( mViewModeButtonGroup,
static_cast<void ( QButtonGroup::* )(
int )
>( &QButtonGroup::buttonClicked ),
146 connect( mToggleEditingButton, &QAbstractButton::clicked,
this, &QgsRelationEditorWidget::toggleEditing );
147 connect( mSaveEditsButton, &QAbstractButton::clicked,
this, &QgsRelationEditorWidget::saveEdits );
148 connect( mAddFeatureButton, &QAbstractButton::clicked,
this, &QgsRelationEditorWidget::addFeature );
149 connect( mDuplicateFeatureButton, &QAbstractButton::clicked,
this, &QgsRelationEditorWidget::duplicateFeature );
150 connect( mDeleteFeatureButton, &QAbstractButton::clicked,
this, &QgsRelationEditorWidget::deleteSelectedFeatures );
151 connect( mLinkFeatureButton, &QAbstractButton::clicked,
this, &QgsRelationEditorWidget::linkFeature );
152 connect( mUnlinkFeatureButton, &QAbstractButton::clicked,
this, &QgsRelationEditorWidget::unlinkSelectedFeatures );
153 connect( mZoomToFeatureButton, &QAbstractButton::clicked,
this, &QgsRelationEditorWidget::zoomToSelectedFeatures );
170 mRelation = relation;
177 setTitle( relation.
name() );
182 if ( canChangeAttributes && !lyr->readOnly() )
184 mToggleEditingButton->setEnabled(
true );
189 mToggleEditingButton->setEnabled(
false );
192 setObjectName( QStringLiteral(
"referenced/" ) + mRelation.name() );
201 mDualView->
init( mRelation.referencingLayer(),
nullptr, myRequest, mEditorContext );
219 mRelation = relation;
220 mNmRelation = nmrelation;
222 if ( !mRelation.isValid() )
225 mToggleEditingButton->setVisible(
true );
228 for (
auto it = transactionGroups.constBegin(); it != transactionGroups.constEnd(); ++it )
230 if ( it.value()->layers().contains( mRelation.referencingLayer() ) )
232 mToggleEditingButton->setVisible(
false );
233 mSaveEditsButton->setVisible(
false );
246 setTitle( relation.
name() );
251 if ( canChangeAttributes && !lyr->readOnly() )
253 mToggleEditingButton->setEnabled(
true );
258 mToggleEditingButton->setEnabled(
false );
264 mZoomToFeatureButton->setVisible( mRelation.referencingLayer()->isSpatial() );
266 setObjectName( QStringLiteral(
"referenced/" ) + mRelation.name() );
273 mEditorContext = context;
278 return mFeatureSelectionMgr;
294 void QgsRelationEditorWidget::updateButtons()
296 bool editable =
false;
297 bool linkable =
false;
311 mAddFeatureButton->setEnabled( editable );
312 mDuplicateFeatureButton->setEnabled( editable && selectionNotEmpty );
313 mLinkFeatureButton->setEnabled( linkable );
314 mDeleteFeatureButton->setEnabled( editable && selectionNotEmpty );
315 mUnlinkFeatureButton->setEnabled( linkable && selectionNotEmpty );
317 mZoomToFeatureButton->setVisible(
333 mZoomToFeatureButton->setEnabled( selectionNotEmpty );
335 mToggleEditingButton->setChecked( editable );
336 mSaveEditsButton->setEnabled( editable );
339 void QgsRelationEditorWidget::addFeature()
359 const auto constFieldPairs = mRelation.
fieldPairs();
362 int index = fields.
indexOf( fieldPair.first );
363 linkAttributes.insert( index, mFeature.
attribute( fieldPair.second ) );
366 const auto constNmFieldPairs = mNmRelation.
fieldPairs();
369 int index = fields.
indexOf( fieldPair.first );
370 linkAttributes.insert( index, f.
attribute( fieldPair.second ) );
383 const auto constFieldPairs = mRelation.
fieldPairs();
386 keyAttrs.insert( fields.
indexFromName( fieldPair.referencingField() ), mFeature.
attribute( fieldPair.referencedField() ) );
393 void QgsRelationEditorWidget::linkFeature()
404 if ( selectionDlg.exec() )
424 const auto constFieldPairs = mRelation.
fieldPairs();
427 int index = fields.
indexOf( fieldPair.first );
428 linkAttributes.insert( index, mFeature.
attribute( fieldPair.second ) );
433 const auto constFieldPairs = mNmRelation.
fieldPairs();
436 int index = fields.
indexOf( fieldPair.first );
437 linkAttributes.insert( index, relatedFeature.
attribute( fieldPair.second ) );
441 newFeatures << linkFeature;
446 const auto constNewFeatures = newFeatures;
447 for (
const QgsFeature &f : constNewFeatures )
456 QMap<int, QVariant> keys;
457 const auto constFieldPairs = mRelation.
fieldPairs();
461 QVariant val = mFeature.
attribute( fieldPair.referencedField() );
462 keys.insert( idx, val );
468 QMapIterator<int, QVariant> it( keys );
469 while ( it.hasNext() )
479 void QgsRelationEditorWidget::duplicateFeature()
492 void QgsRelationEditorWidget::deleteFeature(
const QgsFeatureId featureid )
497 void QgsRelationEditorWidget::deleteSelectedFeatures()
502 void QgsRelationEditorWidget::deleteFeatures(
const QgsFeatureIds &featureids )
504 bool deleteFeatures =
true;
525 QStringList deletedFeaturesPks;
536 QString linkingFeaturesRequestExpression;
537 if ( !deletedFeaturesPks.empty() )
544 int relatedLinkingFeaturesCount = 0;
545 while ( relatedLinkingFeatures.
nextFeature( feature ) )
547 relatedLinkingFeaturesCount++;
550 if ( deletedFeaturesPks.size() == 1 && relatedLinkingFeaturesCount > 1 )
552 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 );
553 messageBox.addButton( QMessageBox::Cancel );
554 QAbstractButton *deleteButton = messageBox.addButton( tr(
"Delete" ), QMessageBox::AcceptRole );
557 if ( messageBox.clickedButton() != deleteButton )
558 deleteFeatures =
false;
560 else if ( deletedFeaturesPks.size() > 1 && relatedLinkingFeaturesCount > deletedFeaturesPks.size() )
562 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 );
563 messageBox.addButton( QMessageBox::Cancel );
564 QAbstractButton *deleteButton = messageBox.addButton( tr(
"Delete" ), QMessageBox::AcceptRole );
567 if ( messageBox.clickedButton() != deleteButton )
568 deleteFeatures =
false;
577 if ( deleteFeatures )
584 void QgsRelationEditorWidget::unlinkFeature(
const QgsFeatureId featureid )
589 void QgsRelationEditorWidget::unlinkSelectedFeatures()
594 void QgsRelationEditorWidget::zoomToSelectedFeatures()
606 void QgsRelationEditorWidget::unlinkFeatures(
const QgsFeatureIds &featureids )
612 .setFilterFids( featureids )
624 QString filter = QStringLiteral(
"(%1) AND (%2)" ).arg(
626 filters.join( QStringLiteral(
" OR " ) ) );
630 .setFilterExpression( filter ) );
646 QMap<int, QgsField> keyFields;
647 const auto constFieldPairs = mRelation.
fieldPairs();
653 QgsDebugMsg( QStringLiteral(
"referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
657 keyFields.insert( idx, fld );
660 const auto constFeatureids = featureids;
663 QMapIterator<int, QgsField> it( keyFields );
664 while ( it.hasNext() )
673 void QgsRelationEditorWidget::toggleEditing(
bool state )
689 void QgsRelationEditorWidget::saveEdits()
696 void QgsRelationEditorWidget::onCollapsedStateChanged(
bool collapsed )
705 void QgsRelationEditorWidget::updateUi()
726 filters << filter.prepend(
'(' ).append(
')' );
744 return mLinkFeatureButton->isVisible();
749 mLinkFeatureButton->setVisible( showLinkButton );
754 return mUnlinkFeatureButton->isVisible();
759 mUnlinkFeatureButton->setVisible( showUnlinkButton );
771 if ( mShowLabel && mRelation.
isValid() )
772 setTitle( mRelation.
name() );
774 setTitle( QString() );
781 QAction *qAction =
nullptr;
784 connect( qAction, &QAction::triggered,
this, [
this, fid]() { deleteFeature( fid ); } );
787 connect( qAction, &QAction::triggered,
this, [
this, fid]() { unlinkFeature( fid ); } );
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
const QgsVectorLayerTools * vectorLayerTools() const
Returns the associated vector layer tools.
Wrapper for iterator of features from vector data provider or vector layer.
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
QSet< QgsFeatureId > QgsFeatureIds
void init(QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request=QgsFeatureRequest(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), bool loadFeatures=true)
Has to be called to initialize the dual view.
bool collapsed
The collapsed state of this group box.
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
QgsAttributeTableModel * masterModel() const
Returns the model which has the information about all features (not only filtered) ...
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
Set the feature selection model.
A groupbox that collapses/expands when toggled and can save its collapsed and checked states...
int selectedFeatureCount() override
Returns the number of features that are selected in this layer.
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds do list all the duplicated features...
This class contains context information for attribute editor widgets.
QList< QgsFeature > QgsFeatureList
QgsVectorLayer referencingLayer
ViewMode
The view modes, in which this widget can present information.
void collapsedStateChanged(bool collapsed)
Signal emitted when groupbox collapsed/expanded state is changed, and when first shown.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool deleteFeatures(const QgsFeatureIds &fids)
Deletes a set of features from the layer (but does not commit it)
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void selectByIds(const QgsFeatureIds &ids, SelectBehavior behavior=SetSelection)
Selects matching features using a list of feature IDs.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
Map canvas is a class for displaying all GIS data types on a canvas.
void setView(ViewMode view)
Change the current view mode.
const QgsFeatureIds & selectedFeatures()
Gets the selected features.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
QgsExpression * filterExpression() const
Returns the filter expression if set.
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QgsAttributeList referencedFields() const
Returns a list of attributes used to form the referenced fields (most likely primary key) on the refe...
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
QgsFeatureRequest getReferencedFeatureRequest(const QgsAttributes &attributes) const
Creates a request to return the feature on the referenced (parent) layer which is referenced by the p...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Defines a relation between matching fields of the two involved tables of a relation.
Shows the features and attributes in a table layout.
#define QgsDebugMsgLevel(str, level)
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
QMap< int, QVariant > QgsAttributeMap
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a list of features to the sink.
QgsVectorLayer referencedLayer
Encapsulate a field in an attribute table or data source.
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
void editingStarted()
Emitted when editing on this layer has started.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
QString expression() const
Returns the original, unmodified expression string.
This selection manager synchronizes a local set of selected features with an attribute table...
void showContextMenuExternally(QgsActionMenu *menu, QgsFeatureId fid)
Emitted when selecting context menu on the feature list to create the context menu individually...
void zoomToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Set canvas extent to the bounding box of a set of features.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
#define FID_TO_STRING(fid)
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QMap< QPair< QString, QString >, QgsTransactionGroup * > transactionGroups()
Map of transaction groups.
static QgsFeature duplicateFeature(QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext)
Duplicates a feature and it's children (one level deep).
static QgsProject * instance()
Returns the QgsProject singleton instance.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
QList< int > QgsAttributeList
bool nextFeature(QgsFeature &f)
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Is an interface class to abstract feature selection handling.
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
QgsMapCanvas * mapCanvas() const
Returns the associated map canvas (e.g.
Allows modification of attribute values.
const QgsFeatureIds & selectedFeatureIds() const override
Returns reference to identifiers of selected features.
This widget is used to show the attributes of a set of features of a QgsVectorLayer.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.