mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-09 00:05:52 -04:00
624 lines
23 KiB
C++
624 lines
23 KiB
C++
/***************************************************************************
|
|
qgsrelationeditor.cpp
|
|
--------------------------------------
|
|
Date : 17.5.2013
|
|
Copyright : (C) 2013 Matthias Kuhn
|
|
Email : matthias at opengis dot 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 "qgsrelationeditorwidget.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 <QHBoxLayout>
|
|
#include <QLabel>
|
|
|
|
QgsRelationEditorWidget::QgsRelationEditorWidget( QWidget *parent )
|
|
: QgsCollapsibleGroupBox( parent )
|
|
{
|
|
QVBoxLayout *topLayout = new QVBoxLayout( this );
|
|
topLayout->setContentsMargins( 0, 9, 0, 0 );
|
|
setLayout( topLayout );
|
|
|
|
// buttons
|
|
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
|
buttonLayout->setContentsMargins( 0, 0, 0, 0 );
|
|
// toogle 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
|
|
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 );
|
|
// 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 );
|
|
mFeatureSelectionMgr = new QgsGenericFeatureSelectionManager( mDualView );
|
|
mDualView->setFeatureSelectionManager( mFeatureSelectionMgr );
|
|
|
|
mRelationLayout->addWidget( mDualView );
|
|
|
|
connect( this, &QgsCollapsibleGroupBoxBasic::collapsedStateChanged, this, &QgsRelationEditorWidget::onCollapsedStateChanged );
|
|
connect( mViewModeButtonGroup, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ),
|
|
this, static_cast<void ( QgsRelationEditorWidget::* )( int )>( &QgsRelationEditorWidget::setViewMode ) );
|
|
connect( mToggleEditingButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::toggleEditing );
|
|
connect( mSaveEditsButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::saveEdits );
|
|
connect( mAddFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::addFeature );
|
|
connect( mDuplicateFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::duplicateFeature );
|
|
connect( mDeleteFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::deleteFeature );
|
|
connect( mLinkFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::linkFeature );
|
|
connect( mUnlinkFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::unlinkFeature );
|
|
connect( mFeatureSelectionMgr, &QgsIFeatureSelectionManager::selectionChanged, this, &QgsRelationEditorWidget::updateButtons );
|
|
|
|
// Set initial state for add/remove etc. buttons
|
|
updateButtons();
|
|
}
|
|
|
|
void QgsRelationEditorWidget::setRelationFeature( const QgsRelation &relation, const QgsFeature &feature )
|
|
{
|
|
if ( mRelation.isValid() )
|
|
{
|
|
disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
|
|
disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
|
|
}
|
|
|
|
mRelation = relation;
|
|
mFeature = feature;
|
|
|
|
connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
|
|
connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
|
|
|
|
if ( mShowLabel )
|
|
setTitle( relation.name() );
|
|
|
|
QgsVectorLayer *lyr = relation.referencingLayer();
|
|
|
|
bool canChangeAttributes = lyr->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
|
|
if ( canChangeAttributes && !lyr->readOnly() )
|
|
{
|
|
mToggleEditingButton->setEnabled( true );
|
|
updateButtons();
|
|
}
|
|
else
|
|
{
|
|
mToggleEditingButton->setEnabled( false );
|
|
}
|
|
|
|
setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
|
|
|
|
// 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 );
|
|
|
|
mDualView->init( mRelation.referencingLayer(), nullptr, myRequest, mEditorContext );
|
|
}
|
|
}
|
|
|
|
void QgsRelationEditorWidget::setRelations( const QgsRelation &relation, const QgsRelation &nmrelation )
|
|
{
|
|
if ( mRelation.isValid() )
|
|
{
|
|
disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
|
|
disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
|
|
}
|
|
|
|
if ( mNmRelation.isValid() )
|
|
{
|
|
disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
|
|
disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
|
|
}
|
|
|
|
mRelation = relation;
|
|
mNmRelation = nmrelation;
|
|
|
|
if ( !mRelation.isValid() )
|
|
return;
|
|
|
|
mToggleEditingButton->setVisible( true );
|
|
|
|
const auto transactionGroups = QgsProject::instance()->transactionGroups();
|
|
for ( auto it = transactionGroups.constBegin(); it != transactionGroups.constEnd(); ++it )
|
|
{
|
|
if ( it.value()->layers().contains( mRelation.referencingLayer() ) )
|
|
{
|
|
mToggleEditingButton->setVisible( false );
|
|
mSaveEditsButton->setVisible( false );
|
|
}
|
|
}
|
|
|
|
connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
|
|
connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
|
|
|
|
if ( mNmRelation.isValid() )
|
|
{
|
|
connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
|
|
connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
|
|
}
|
|
|
|
setTitle( relation.name() );
|
|
|
|
QgsVectorLayer *lyr = relation.referencingLayer();
|
|
|
|
bool canChangeAttributes = lyr->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
|
|
if ( canChangeAttributes && !lyr->readOnly() )
|
|
{
|
|
mToggleEditingButton->setEnabled( true );
|
|
updateButtons();
|
|
}
|
|
else
|
|
{
|
|
mToggleEditingButton->setEnabled( false );
|
|
}
|
|
|
|
setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
|
|
|
|
updateUi();
|
|
}
|
|
|
|
void QgsRelationEditorWidget::setEditorContext( const QgsAttributeEditorContext &context )
|
|
{
|
|
mEditorContext = context;
|
|
}
|
|
|
|
QgsIFeatureSelectionManager *QgsRelationEditorWidget::featureSelectionManager()
|
|
{
|
|
return mFeatureSelectionMgr;
|
|
}
|
|
|
|
void QgsRelationEditorWidget::setViewMode( QgsDualView::ViewMode mode )
|
|
{
|
|
mDualView->setView( mode );
|
|
mViewMode = mode;
|
|
}
|
|
|
|
|
|
void QgsRelationEditorWidget::setFeature( const QgsFeature &feature )
|
|
{
|
|
mFeature = feature;
|
|
|
|
updateUi();
|
|
}
|
|
|
|
void QgsRelationEditorWidget::updateButtons()
|
|
{
|
|
bool editable = false;
|
|
bool linkable = false;
|
|
bool selectionNotEmpty = mFeatureSelectionMgr->selectedFeatureCount();
|
|
|
|
if ( mRelation.isValid() )
|
|
{
|
|
editable = mRelation.referencingLayer()->isEditable();
|
|
linkable = mRelation.referencingLayer()->isEditable();
|
|
}
|
|
|
|
if ( mNmRelation.isValid() )
|
|
{
|
|
editable = mNmRelation.referencedLayer()->isEditable();
|
|
}
|
|
|
|
mAddFeatureButton->setEnabled( editable );
|
|
mDuplicateFeatureButton->setEnabled( editable && selectionNotEmpty );
|
|
mLinkFeatureButton->setEnabled( linkable );
|
|
mDeleteFeatureButton->setEnabled( editable && selectionNotEmpty );
|
|
mUnlinkFeatureButton->setEnabled( linkable && selectionNotEmpty );
|
|
mToggleEditingButton->setChecked( editable );
|
|
mSaveEditsButton->setEnabled( editable );
|
|
}
|
|
|
|
void QgsRelationEditorWidget::addFeature()
|
|
{
|
|
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(), QgsGeometry(), &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;
|
|
Q_FOREACH ( const QgsRelation::FieldPair &fieldPair, mRelation.fieldPairs() )
|
|
{
|
|
int index = fields.indexOf( fieldPair.first );
|
|
linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
|
|
}
|
|
|
|
Q_FOREACH ( const QgsRelation::FieldPair &fieldPair, mNmRelation.fieldPairs() )
|
|
{
|
|
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();
|
|
|
|
Q_FOREACH ( const QgsRelation::FieldPair &fieldPair, mRelation.fieldPairs() )
|
|
{
|
|
keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeature.attribute( fieldPair.referencedField() ) );
|
|
}
|
|
|
|
vlTools->addFeature( mDualView->masterModel()->layer(), keyAttrs );
|
|
}
|
|
}
|
|
|
|
void QgsRelationEditorWidget::linkFeature()
|
|
{
|
|
QgsVectorLayer *layer = nullptr;
|
|
|
|
if ( mNmRelation.isValid() )
|
|
layer = mNmRelation.referencedLayer();
|
|
else
|
|
layer = mRelation.referencingLayer();
|
|
|
|
QgsFeatureSelectionDlg selectionDlg( layer, mEditorContext, this );
|
|
|
|
if ( selectionDlg.exec() )
|
|
{
|
|
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;
|
|
Q_FOREACH ( const QgsRelation::FieldPair &fieldPair, mRelation.fieldPairs() )
|
|
{
|
|
int index = fields.indexOf( fieldPair.first );
|
|
linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
|
|
}
|
|
|
|
while ( it.nextFeature( relatedFeature ) )
|
|
{
|
|
Q_FOREACH ( const QgsRelation::FieldPair &fieldPair, mNmRelation.fieldPairs() )
|
|
{
|
|
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;
|
|
Q_FOREACH ( const QgsFeature &f, newFeatures )
|
|
ids << f.id();
|
|
mRelation.referencingLayer()->selectByIds( ids );
|
|
|
|
|
|
updateUi();
|
|
}
|
|
else
|
|
{
|
|
QMap<int, QVariant> keys;
|
|
Q_FOREACH ( const QgsRelation::FieldPair &fieldPair, mRelation.fieldPairs() )
|
|
{
|
|
int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
|
|
QVariant val = mFeature.attribute( fieldPair.referencedField() );
|
|
keys.insert( idx, val );
|
|
}
|
|
|
|
Q_FOREACH ( QgsFeatureId fid, selectionDlg.selectedFeatures() )
|
|
{
|
|
QMapIterator<int, QVariant> it( keys );
|
|
while ( it.hasNext() )
|
|
{
|
|
it.next();
|
|
mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), it.value() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void QgsRelationEditorWidget::duplicateFeature()
|
|
{
|
|
}
|
|
|
|
void QgsRelationEditorWidget::deleteFeature()
|
|
{
|
|
QgsVectorLayer *layer = nullptr;
|
|
|
|
if ( mNmRelation.isValid() )
|
|
// So far we expect the database to take care of cleaning up the linking table or restricting
|
|
// TODO: add more options for the behavior here
|
|
layer = mNmRelation.referencedLayer();
|
|
else
|
|
layer = mRelation.referencingLayer();
|
|
QgsDebugMsg( QString( "Delete %1" ).arg( mFeatureSelectionMgr->selectedFeatureIds().size() ) );
|
|
layer->deleteFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
|
|
}
|
|
|
|
void QgsRelationEditorWidget::unlinkFeature()
|
|
{
|
|
if ( mNmRelation.isValid() )
|
|
{
|
|
QgsFeatureIterator selectedIterator = mNmRelation.referencedLayer()->getFeatures(
|
|
QgsFeatureRequest()
|
|
.setFilterFids( mFeatureSelectionMgr->selectedFeatureIds() )
|
|
.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( QStringLiteral( " OR " ) ) );
|
|
|
|
QgsFeatureIterator linkedIterator = mRelation.referencingLayer()->getFeatures( QgsFeatureRequest()
|
|
.setSubsetOfAttributes( QgsAttributeList() )
|
|
.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;
|
|
Q_FOREACH ( const QgsRelation::FieldPair &fieldPair, mRelation.fieldPairs() )
|
|
{
|
|
int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
|
|
if ( idx < 0 )
|
|
{
|
|
QgsDebugMsg( QString( "referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
|
|
return;
|
|
}
|
|
QgsField fld = mRelation.referencingLayer()->fields().at( idx );
|
|
keyFields.insert( idx, fld );
|
|
}
|
|
|
|
Q_FOREACH ( QgsFeatureId fid, mFeatureSelectionMgr->selectedFeatureIds() )
|
|
{
|
|
QMapIterator<int, QgsField> it( keyFields );
|
|
while ( it.hasNext() )
|
|
{
|
|
it.next();
|
|
mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QVariant( it.value().type() ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void QgsRelationEditorWidget::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 QgsRelationEditorWidget::saveEdits()
|
|
{
|
|
mEditorContext.vectorLayerTools()->saveEdits( mRelation.referencingLayer() );
|
|
if ( mNmRelation.isValid() )
|
|
mEditorContext.vectorLayerTools()->saveEdits( mNmRelation.referencedLayer() );
|
|
}
|
|
|
|
void QgsRelationEditorWidget::onCollapsedStateChanged( bool collapsed )
|
|
{
|
|
|
|
if ( !collapsed )
|
|
{
|
|
mVisible = true;
|
|
updateUi();
|
|
}
|
|
}
|
|
|
|
void QgsRelationEditorWidget::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( QStringLiteral( " OR " ) ) );
|
|
|
|
mDualView->init( mNmRelation.referencedLayer(), nullptr, nmRequest, mEditorContext );
|
|
}
|
|
else
|
|
{
|
|
mDualView->init( mRelation.referencingLayer(), nullptr, myRequest, mEditorContext );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool QgsRelationEditorWidget::showLinkButton() const
|
|
{
|
|
return mLinkFeatureButton->isVisible();
|
|
}
|
|
|
|
void QgsRelationEditorWidget::setShowLinkButton( bool showLinkButton )
|
|
{
|
|
mLinkFeatureButton->setVisible( showLinkButton );
|
|
}
|
|
|
|
bool QgsRelationEditorWidget::showUnlinkButton() const
|
|
{
|
|
return mUnlinkFeatureButton->isVisible();
|
|
}
|
|
|
|
void QgsRelationEditorWidget::setShowUnlinkButton( bool showUnlinkButton )
|
|
{
|
|
mUnlinkFeatureButton->setVisible( showUnlinkButton );
|
|
}
|
|
|
|
bool QgsRelationEditorWidget::showLabel() const
|
|
{
|
|
return mShowLabel;
|
|
}
|
|
|
|
void QgsRelationEditorWidget::setShowLabel( bool showLabel )
|
|
{
|
|
mShowLabel = showLabel;
|
|
|
|
if ( mShowLabel && mRelation.isValid() )
|
|
setTitle( mRelation.name() );
|
|
else
|
|
setTitle( QString() );
|
|
}
|