|
| 1 | +/*************************************************************************** |
| 2 | + qgsrelationeditor.cpp |
| 3 | + -------------------------------------- |
| 4 | + Date : 17.5.2013 |
| 5 | + Copyright : (C) 2013 Matthias Kuhn |
| 6 | + Email : matthias dot kuhn at gmx dot ch |
| 7 | + *************************************************************************** |
| 8 | + * * |
| 9 | + * This program is free software; you can redistribute it and/or modify * |
| 10 | + * it under the terms of the GNU General Public License as published by * |
| 11 | + * the Free Software Foundation; either version 2 of the License, or * |
| 12 | + * (at your option) any later version. * |
| 13 | + * * |
| 14 | + ***************************************************************************/ |
| 15 | + |
| 16 | +#include "qgsrelationeditorwidget.h" |
| 17 | + |
| 18 | +#include "qgsapplication.h" |
| 19 | +#include "qgsdistancearea.h" |
| 20 | +#include "qgsvectordataprovider.h" |
| 21 | +#include "qgsexpression.h" |
| 22 | +#include "qgsfeature.h" |
| 23 | +#include "qgsfeatureselectiondlg.h" |
| 24 | +#include "qgsgenericfeatureselectionmanager.h" |
| 25 | +#include "qgsrelation.h" |
| 26 | +#include "qgsvectorlayertools.h" |
| 27 | + |
| 28 | +#include <QHBoxLayout> |
| 29 | +#include <QLabel> |
| 30 | + |
| 31 | +QgsRelationEditorWidget::QgsRelationEditorWidget( QWidget* parent ) |
| 32 | + : QgsCollapsibleGroupBox( parent ) |
| 33 | + , mViewMode( QgsDualView::AttributeEditor ) |
| 34 | + , mEditorContext( QgsAttributeEditorContext() ) |
| 35 | + , mRelation( QgsRelation() ) |
| 36 | + , mFeature( QgsFeature() ) |
| 37 | +{ |
| 38 | + QVBoxLayout* topLayout = new QVBoxLayout( this ); |
| 39 | + topLayout->setContentsMargins( 0, 9, 0, 0 ); |
| 40 | + setLayout( topLayout ); |
| 41 | + |
| 42 | + // buttons |
| 43 | + QHBoxLayout* buttonLayout = new QHBoxLayout(); |
| 44 | + buttonLayout->setContentsMargins( 0, 0, 0, 0 ); |
| 45 | + // toogle editing |
| 46 | + mToggleEditingButton = new QToolButton( this ); |
| 47 | + QAction* toggleEditingAction = new QAction( QgsApplication::getThemeIcon( "/mActionToggleEditing.svg" ), tr( "Toggle editing" ), this ); |
| 48 | + mToggleEditingButton->addAction( toggleEditingAction ); |
| 49 | + mToggleEditingButton->setDefaultAction( toggleEditingAction ); |
| 50 | + buttonLayout->addWidget( mToggleEditingButton ); |
| 51 | + // add feature |
| 52 | + mAddFeatureButton = new QToolButton( this ); |
| 53 | + QAction* addFeatureAction = new QAction( QgsApplication::getThemeIcon( "/mActionAdd.svg" ), tr( "Add feature" ), this ); |
| 54 | + mAddFeatureButton->addAction( addFeatureAction ); |
| 55 | + mAddFeatureButton->setDefaultAction( addFeatureAction ); |
| 56 | + buttonLayout->addWidget( mAddFeatureButton ); |
| 57 | + // delete feature |
| 58 | + mDeleteFeatureButton = new QToolButton( this ); |
| 59 | + QAction* deleteFeatureAction = new QAction( QgsApplication::getThemeIcon( "/mActionRemove.svg" ), tr( "Delete feature" ), this ); |
| 60 | + mDeleteFeatureButton->addAction( deleteFeatureAction ); |
| 61 | + mDeleteFeatureButton->setDefaultAction( deleteFeatureAction ); |
| 62 | + buttonLayout->addWidget( mDeleteFeatureButton ); |
| 63 | + // link feature |
| 64 | + mLinkFeatureButton = new QToolButton( this ); |
| 65 | + QAction* linkFeatureAction = new QAction( QgsApplication::getThemeIcon( "/mActionLink.svg" ), tr( "Link feature" ), this ); |
| 66 | + mLinkFeatureButton->addAction( linkFeatureAction ); |
| 67 | + mLinkFeatureButton->setDefaultAction( linkFeatureAction ); |
| 68 | + buttonLayout->addWidget( mLinkFeatureButton ); |
| 69 | + // unlink feature |
| 70 | + mUnlinkFeatureButton = new QToolButton( this ); |
| 71 | + QAction* unlinkFeatureAction = new QAction( QgsApplication::getThemeIcon( "/mActionUnlink.svg" ), tr( "Unlink feature" ), this ); |
| 72 | + mUnlinkFeatureButton->addAction( unlinkFeatureAction ); |
| 73 | + mUnlinkFeatureButton->setDefaultAction( unlinkFeatureAction ); |
| 74 | + buttonLayout->addWidget( mUnlinkFeatureButton ); |
| 75 | + // spacer |
| 76 | + buttonLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding ) ); |
| 77 | + // form view |
| 78 | + mFormViewButton = new QToolButton( this ); |
| 79 | + QAction* formViewAction = new QAction( QgsApplication::getThemeIcon( "/mActionPropertyItem.png" ), tr( "Form view" ), this ); |
| 80 | + mFormViewButton->addAction( formViewAction ); |
| 81 | + mFormViewButton->setDefaultAction( formViewAction ); |
| 82 | + mFormViewButton->setCheckable( true ); |
| 83 | + mFormViewButton->setChecked( mViewMode == QgsDualView::AttributeEditor ); |
| 84 | + buttonLayout->addWidget( mFormViewButton ); |
| 85 | + // table view |
| 86 | + mTableViewButton = new QToolButton( this ); |
| 87 | + QAction* tableViewAction = new QAction( QgsApplication::getThemeIcon( "/mActionOpenTable.png" ), tr( "Table view" ), this ); |
| 88 | + mTableViewButton->addAction( tableViewAction ); |
| 89 | + mTableViewButton->setDefaultAction( tableViewAction ); |
| 90 | + mTableViewButton->setCheckable( true ); |
| 91 | + mTableViewButton->setChecked( mViewMode == QgsDualView::AttributeTable ); |
| 92 | + buttonLayout->addWidget( mTableViewButton ); |
| 93 | + // button group |
| 94 | + mViewModeButtonGroup = new QButtonGroup( this ); |
| 95 | + mViewModeButtonGroup->addButton( mFormViewButton ); |
| 96 | + mViewModeButtonGroup->addButton( mTableViewButton ); |
| 97 | + mViewModeButtonGroup->setId( mTableViewButton, QgsDualView::AttributeTable ); |
| 98 | + mViewModeButtonGroup->setId( mFormViewButton, QgsDualView::AttributeEditor ); |
| 99 | + |
| 100 | + // add buttons layout |
| 101 | + topLayout->addLayout( buttonLayout ); |
| 102 | + |
| 103 | + // Set initial state for add/remove etc. buttons |
| 104 | + referencingLayerEditingToggled(); |
| 105 | + |
| 106 | + mRelationLayout = new QGridLayout(); |
| 107 | + mRelationLayout->setContentsMargins( 0, 0, 0, 0 ); |
| 108 | + topLayout->addLayout( mRelationLayout ); |
| 109 | + |
| 110 | + mDualView = new QgsDualView( this ); |
| 111 | + mDualView->setView( mViewMode ); |
| 112 | + mFeatureSelectionMgr = new QgsGenericFeatureSelectionManager( mDualView ); |
| 113 | + mRelationLayout->addWidget( mDualView ); |
| 114 | + |
| 115 | + connect( this, SIGNAL( collapsedStateChanged( bool ) ), this, SLOT( onCollapsedStateChanged( bool ) ) ); |
| 116 | + connect( mViewModeButtonGroup, SIGNAL( buttonClicked( int ) ), this, SLOT( setViewMode( int ) ) ); |
| 117 | +} |
| 118 | + |
| 119 | +void QgsRelationEditorWidget::setRelationFeature( const QgsRelation& relation, const QgsFeature& feature, const QgsAttributeEditorContext& context ) |
| 120 | +{ |
| 121 | + if ( mRelation.isValid() ) |
| 122 | + { |
| 123 | + disconnect( mRelation.referencingLayer(), SIGNAL( editingStarted() ), this, SLOT( referencingLayerEditingToggled() ) ); |
| 124 | + disconnect( mRelation.referencingLayer(), SIGNAL( editingStopped() ), this, SLOT( referencingLayerEditingToggled() ) ); |
| 125 | + } |
| 126 | + |
| 127 | + mRelation = relation; |
| 128 | + mFeature = feature; |
| 129 | + mEditorContext = context; |
| 130 | + |
| 131 | + connect( mRelation.referencingLayer(), SIGNAL( editingStarted() ), this, SLOT( referencingLayerEditingToggled() ) ); |
| 132 | + connect( mRelation.referencingLayer(), SIGNAL( editingStopped() ), this, SLOT( referencingLayerEditingToggled() ) ); |
| 133 | + |
| 134 | + setTitle( relation.name() ); |
| 135 | + |
| 136 | + QgsVectorLayer* lyr = relation.referencingLayer(); |
| 137 | + |
| 138 | + bool canChangeAttributes = lyr->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues; |
| 139 | + mToggleEditingButton->setEnabled( canChangeAttributes && !lyr->isReadOnly() ); |
| 140 | + |
| 141 | + |
| 142 | + mDualView->setFeatureSelectionManager( mFeatureSelectionMgr ); |
| 143 | + |
| 144 | + QgsFeatureRequest myRequest = relation.getRelatedFeaturesRequest( feature ); |
| 145 | + |
| 146 | + mDualView->init( relation.referencingLayer(), NULL, myRequest, context ); |
| 147 | +} |
| 148 | + |
| 149 | +void QgsRelationEditorWidget::setViewMode( QgsDualView::ViewMode mode ) |
| 150 | +{ |
| 151 | + mDualView->setView( mode ); |
| 152 | + mViewMode = mode; |
| 153 | + mTableViewButton->setChecked( mViewMode == QgsDualView::AttributeTable ); |
| 154 | + mFormViewButton->setChecked( mViewMode == QgsDualView::AttributeEditor ); |
| 155 | +} |
| 156 | + |
| 157 | +void QgsRelationEditorWidget::onCollapsedStateChanged( bool state ) |
| 158 | +{ |
| 159 | + if ( state && !mDualView->masterModel() ) |
| 160 | + { |
| 161 | + // TODO: Lazy init dual view if collapsed on init |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | +void QgsRelationEditorWidget::referencingLayerEditingToggled() |
| 166 | +{ |
| 167 | + bool editable = false; |
| 168 | + if ( mRelation.isValid() ) |
| 169 | + { |
| 170 | + editable = mRelation.referencingLayer()->isEditable(); |
| 171 | + } |
| 172 | + |
| 173 | + mAddFeatureButton->setEnabled( editable ); |
| 174 | + mLinkFeatureButton->setEnabled( editable ); |
| 175 | + mDeleteFeatureButton->setEnabled( editable ); |
| 176 | + mUnlinkFeatureButton->setEnabled( editable ); |
| 177 | + mToggleEditingButton->setChecked( editable ); |
| 178 | +} |
| 179 | + |
| 180 | +void QgsRelationEditorWidget::on_mAddFeatureButton_clicked() |
| 181 | +{ |
| 182 | + QgsAttributeMap keyAttrs; |
| 183 | + |
| 184 | + QgsFields fields = mRelation.referencingLayer()->pendingFields(); |
| 185 | + |
| 186 | + foreach ( QgsRelation::FieldPair fieldPair, mRelation.fieldPairs() ) |
| 187 | + { |
| 188 | + keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeature.attribute( fieldPair.referencedField() ) ); |
| 189 | + } |
| 190 | + |
| 191 | + mEditorContext.vectorLayerTools()->addFeature( mDualView->masterModel()->layer(), keyAttrs ); |
| 192 | +} |
| 193 | + |
| 194 | +void QgsRelationEditorWidget::on_mLinkFeatureButton_clicked() |
| 195 | +{ |
| 196 | + QgsFeatureSelectionDlg selectionDlg( mRelation.referencingLayer(), this ); |
| 197 | + |
| 198 | + if ( selectionDlg.exec() ) |
| 199 | + { |
| 200 | + QMap<int, QVariant> keys; |
| 201 | + foreach ( const QgsRelation::FieldPair fieldPair, mRelation.fieldPairs() ) |
| 202 | + { |
| 203 | + int idx = mRelation.referencingLayer()->fieldNameIndex( fieldPair.referencingField() ); |
| 204 | + QVariant val = mFeature.attribute( fieldPair.referencedField() ); |
| 205 | + keys.insert( idx, val ); |
| 206 | + } |
| 207 | + |
| 208 | + foreach ( QgsFeatureId fid, selectionDlg.selectedFeatures() ) |
| 209 | + { |
| 210 | + QMapIterator<int, QVariant> it( keys ); |
| 211 | + while ( it.hasNext() ) |
| 212 | + { |
| 213 | + it.next(); |
| 214 | + mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), it.value() ); |
| 215 | + } |
| 216 | + } |
| 217 | + } |
| 218 | +} |
| 219 | + |
| 220 | +void QgsRelationEditorWidget::on_mDeleteFeatureButton_clicked() |
| 221 | +{ |
| 222 | + foreach ( QgsFeatureId fid, mFeatureSelectionMgr->selectedFeaturesIds() ) |
| 223 | + { |
| 224 | + mRelation.referencingLayer()->deleteFeature( fid ); |
| 225 | + } |
| 226 | +} |
| 227 | + |
| 228 | +void QgsRelationEditorWidget::on_mUnlinkFeatureButton_clicked() |
| 229 | +{ |
| 230 | + QMap<int, QgsField> keyFields; |
| 231 | + foreach ( const QgsRelation::FieldPair fieldPair, mRelation.fieldPairs() ) |
| 232 | + { |
| 233 | + int idx = mRelation.referencingLayer()->fieldNameIndex( fieldPair.referencingField() ); |
| 234 | + QgsField fld = mRelation.referencingLayer()->pendingFields().at( idx ); |
| 235 | + keyFields.insert( idx, fld ); |
| 236 | + } |
| 237 | + |
| 238 | + foreach ( QgsFeatureId fid, mFeatureSelectionMgr->selectedFeaturesIds() ) |
| 239 | + { |
| 240 | + QMapIterator<int, QgsField> it( keyFields ); |
| 241 | + while ( it.hasNext() ) |
| 242 | + { |
| 243 | + it.next(); |
| 244 | + mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QVariant( it.value().type() ) ); |
| 245 | + } |
| 246 | + } |
| 247 | +} |
| 248 | + |
| 249 | +void QgsRelationEditorWidget::on_mToggleEditingButton_toggled( bool state ) |
| 250 | +{ |
| 251 | + if ( state ) |
| 252 | + { |
| 253 | + mEditorContext.vectorLayerTools()->startEditing( mRelation.referencingLayer() ); |
| 254 | + } |
| 255 | + else |
| 256 | + { |
| 257 | + mEditorContext.vectorLayerTools()->stopEditing( mRelation.referencingLayer() ); |
| 258 | + } |
| 259 | +} |
0 commit comments