QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsrelationeditorwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrelationeditorwidget.cpp
3  --------------------------------------
4  Date : 17.5.2013
5  Copyright : (C) 2013 Matthias Kuhn
6  Email : matthias at opengis dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
18 #include "qgsapplication.h"
19 #include "qgsdistancearea.h"
20 #include "qgsfeatureiterator.h"
21 #include "qgsvectordataprovider.h"
22 #include "qgsexpression.h"
23 #include "qgsfeature.h"
24 #include "qgsfeatureselectiondlg.h"
26 #include "qgsiconutils.h"
27 #include "qgsrelation.h"
28 #include "qgsvectorlayertools.h"
29 #include "qgsproject.h"
30 #include "qgstransactiongroup.h"
31 #include "qgslogger.h"
32 #include "qgsvectorlayerutils.h"
33 #include "qgsmapcanvas.h"
37 #include "qgsmessagebar.h"
38 #include "qgsmessagebaritem.h"
39 #include "qgscollapsiblegroupbox.h"
40 
41 #include <QHBoxLayout>
42 #include <QLabel>
43 #include <QMessageBox>
44 #include <QPushButton>
45 #include <QTreeWidget>
46 
49 QgsFilteredSelectionManager::QgsFilteredSelectionManager( QgsVectorLayer *layer, const QgsFeatureRequest &request, QObject *parent )
50  : QgsVectorLayerSelectionManager( layer, parent )
51  , mRequest( request )
52 {
53  if ( ! layer )
54  return;
55 
56  for ( const auto fid : layer->selectedFeatureIds() )
57  if ( mRequest.acceptFeature( layer->getFeature( fid ) ) )
58  mSelectedFeatureIds << fid;
59 
60  connect( layer, &QgsVectorLayer::selectionChanged, this, &QgsFilteredSelectionManager::onSelectionChanged );
61 }
62 
63 const QgsFeatureIds &QgsFilteredSelectionManager::selectedFeatureIds() const
64 
65 
66 {
67  return mSelectedFeatureIds;
68 }
69 
70 int QgsFilteredSelectionManager::selectedFeatureCount()
71 {
72  return mSelectedFeatureIds.count();
73 }
74 
75 void QgsFilteredSelectionManager::onSelectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect )
76 {
77  QgsFeatureIds lselected = selected;
78  if ( clearAndSelect )
79  {
80  mSelectedFeatureIds.clear();
81  }
82  else
83  {
84  for ( const auto fid : deselected )
85  mSelectedFeatureIds.remove( fid );
86  }
87 
88  for ( const auto fid : selected )
89  if ( mRequest.acceptFeature( layer()->getFeature( fid ) ) )
90  mSelectedFeatureIds << fid;
91  else
92  lselected.remove( fid );
93 
94  emit selectionChanged( lselected, deselected, clearAndSelect );
95 }
96 
98 
99 QgsRelationEditorWidget::QgsRelationEditorWidget( const QVariantMap &config, QWidget *parent )
100  : QgsAbstractRelationEditorWidget( config, parent )
101  , mButtonsVisibility( qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsRelationEditorWidget::Button::AllButtons ) )
102  , mShowFirstFeature( config.value( QStringLiteral( "show_first_feature" ), true ).toBool() )
103 {
104  QVBoxLayout *rootLayout = new QVBoxLayout( this );
105  rootLayout->setContentsMargins( 0, 9, 0, 0 );
106 
107  // buttons
108  QHBoxLayout *buttonLayout = new QHBoxLayout();
109  buttonLayout->setContentsMargins( 0, 0, 0, 0 );
110  // toggle editing
111  mToggleEditingButton = new QToolButton( this );
112  mToggleEditingButton->setObjectName( QStringLiteral( "mToggleEditingButton" ) );
113  mToggleEditingButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) ) );
114  mToggleEditingButton->setText( tr( "Toggle Editing" ) );
115  mToggleEditingButton->setEnabled( false );
116  mToggleEditingButton->setCheckable( true );
117  mToggleEditingButton->setToolTip( tr( "Toggle editing mode for child layer" ) );
118  buttonLayout->addWidget( mToggleEditingButton );
119  // save Edits
120  mSaveEditsButton = new QToolButton( this );
121  mSaveEditsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSaveEdits.svg" ) ) );
122  mSaveEditsButton->setText( tr( "Save Child Layer Edits" ) );
123  mSaveEditsButton->setToolTip( tr( "Save child layer edits" ) );
124  mSaveEditsButton->setEnabled( true );
125  buttonLayout->addWidget( mSaveEditsButton );
126  // add feature with geometry
127  mAddFeatureGeometryButton = new QToolButton( this );
128  mAddFeatureGeometryButton->setObjectName( QStringLiteral( "mAddFeatureGeometryButton" ) );
129  buttonLayout->addWidget( mAddFeatureGeometryButton );
130  // add feature
131  mAddFeatureButton = new QToolButton( this );
132  mAddFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionNewTableRow.svg" ) ) );
133  mAddFeatureButton->setText( tr( "Add Child Feature" ) );
134  mAddFeatureButton->setToolTip( tr( "Add child feature" ) );
135  mAddFeatureButton->setObjectName( QStringLiteral( "mAddFeatureButton" ) );
136  buttonLayout->addWidget( mAddFeatureButton );
137  // duplicate feature
138  mDuplicateFeatureButton = new QToolButton( this );
139  mDuplicateFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDuplicateFeature.svg" ) ) );
140  mDuplicateFeatureButton->setText( tr( "Duplicate Child Feature(s)" ) );
141  mDuplicateFeatureButton->setToolTip( tr( "Duplicate selected child feature(s)" ) );
142  mDuplicateFeatureButton->setObjectName( QStringLiteral( "mDuplicateFeatureButton" ) );
143  buttonLayout->addWidget( mDuplicateFeatureButton );
144  // delete feature
145  mDeleteFeatureButton = new QToolButton( this );
146  mDeleteFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelectedFeatures.svg" ) ) );
147  mDeleteFeatureButton->setText( tr( "Delete Child Feature(s)" ) );
148  mDeleteFeatureButton->setToolTip( tr( "Delete selected child feature(s)" ) );
149  mDeleteFeatureButton->setObjectName( QStringLiteral( "mDeleteFeatureButton" ) );
150  buttonLayout->addWidget( mDeleteFeatureButton );
151  // link feature
152  mLinkFeatureButton = new QToolButton( this );
153  mLinkFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionLink.svg" ) ) );
154  mLinkFeatureButton->setText( tr( "Link Existing Feature(s)" ) );
155  mLinkFeatureButton->setToolTip( tr( "Link existing child feature(s)" ) );
156  mLinkFeatureButton->setObjectName( QStringLiteral( "mLinkFeatureButton" ) );
157  buttonLayout->addWidget( mLinkFeatureButton );
158  // unlink feature
159  mUnlinkFeatureButton = new QToolButton( this );
160  mUnlinkFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ) );
161  mUnlinkFeatureButton->setText( tr( "Unlink Feature(s)" ) );
162  mUnlinkFeatureButton->setToolTip( tr( "Unlink selected child feature(s)" ) );
163  mUnlinkFeatureButton->setObjectName( QStringLiteral( "mUnlinkFeatureButton" ) );
164  buttonLayout->addWidget( mUnlinkFeatureButton );
165  // zoom to linked feature
166  mZoomToFeatureButton = new QToolButton( this );
167  mZoomToFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToSelected.svg" ) ) );
168  mZoomToFeatureButton->setText( tr( "Zoom To Feature(s)" ) );
169  mZoomToFeatureButton->setToolTip( tr( "Zoom to selected child feature(s)" ) );
170  mZoomToFeatureButton->setObjectName( QStringLiteral( "mZoomToFeatureButton" ) );
171  buttonLayout->addWidget( mZoomToFeatureButton );
172  // spacer
173  buttonLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding ) );
174  // form view
175  mFormViewButton = new QToolButton( this );
176  mFormViewButton->setText( tr( "Form View" ) );
177  mFormViewButton->setToolTip( tr( "Switch to form view" ) );
178  mFormViewButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPropertyItem.svg" ) ) );
179  mFormViewButton->setCheckable( true );
180  mFormViewButton->setChecked( mViewMode == QgsDualView::AttributeEditor );
181  buttonLayout->addWidget( mFormViewButton );
182  // table view
183  mTableViewButton = new QToolButton( this );
184  mTableViewButton->setText( tr( "Table View" ) );
185  mTableViewButton->setToolTip( tr( "Switch to table view" ) );
186  mTableViewButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ) );
187  mTableViewButton->setCheckable( true );
188  mTableViewButton->setChecked( mViewMode == QgsDualView::AttributeTable );
189  buttonLayout->addWidget( mTableViewButton );
190  // button group
191  mViewModeButtonGroup = new QButtonGroup( this );
192  mViewModeButtonGroup->addButton( mFormViewButton, QgsDualView::AttributeEditor );
193  mViewModeButtonGroup->addButton( mTableViewButton, QgsDualView::AttributeTable );
194  // multiedit info label
195  mMultiEditInfoLabel = new QLabel( this );
196  buttonLayout->addWidget( mMultiEditInfoLabel );
197 
198  // add buttons layout
199  rootLayout->addLayout( buttonLayout );
200 
201  // add stacked widget
202  mStackedWidget = new QStackedWidget( this );
203 
204  // add dual view (single feature content)
205  mDualView = new QgsDualView( this );
206  mDualView->setView( mViewMode );
207  connect( mDualView, &QgsDualView::showContextMenuExternally, this, &QgsRelationEditorWidget::showContextMenu );
208 
209  // add multi feature editing page
210  mMultiEditStackedWidgetPage = new QWidget( this );
211  {
212  QVBoxLayout *vBoxLayout = new QVBoxLayout();
213  vBoxLayout->setContentsMargins( 0, 0, 0, 0 );
214 
215  mMultiEditTreeWidget = new QTreeWidget( this );
216  mMultiEditTreeWidget->setHeaderHidden( true );
217  mMultiEditTreeWidget->setSelectionMode( QTreeWidget::ExtendedSelection );
218  vBoxLayout->addWidget( mMultiEditTreeWidget );
219 
220  mMultiEditStackedWidgetPage->setLayout( vBoxLayout );
221  }
222  mStackedWidget->addWidget( mMultiEditStackedWidgetPage );
223 
224  mStackedWidget->addWidget( mDualView );
225 
226  rootLayout->addWidget( mStackedWidget );
227 
228 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
229  connect( mViewModeButtonGroup, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ),
230  this, static_cast<void ( QgsRelationEditorWidget::* )( int )>( &QgsRelationEditorWidget::setViewMode ) );
231 #else
232  connect( mViewModeButtonGroup, &QButtonGroup::idClicked,
233  this, static_cast<void ( QgsRelationEditorWidget::* )( int )>( &QgsRelationEditorWidget::setViewMode ) );
234 #endif
235  connect( mToggleEditingButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::toggleEditing );
236  connect( mSaveEditsButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::saveEdits );
237  connect( mAddFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::addFeature );
238  connect( mAddFeatureGeometryButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::addFeatureGeometry );
239  connect( mDuplicateFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::duplicateSelectedFeatures );
240  connect( mDeleteFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::deleteSelectedFeatures );
241  connect( mLinkFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::linkFeature );
242  connect( mUnlinkFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::unlinkSelectedFeatures );
243  connect( mZoomToFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::zoomToSelectedFeatures );
244  connect( mMultiEditTreeWidget, &QTreeWidget::itemSelectionChanged, this, &QgsRelationEditorWidget::multiEditItemSelectionChanged );
245 
246  // Set initial state for add/remove etc. buttons
247  updateButtons();
248 
249  setLayout( rootLayout );
250 }
251 
252 void QgsRelationEditorWidget::initDualView( QgsVectorLayer *layer, const QgsFeatureRequest &request )
253 {
254  if ( multiEditModeActive() )
255  {
256  QgsLogger::warning( tr( "Dual view should not be used in multiple edit mode" ) );
257  return;
258  }
259 
261  ctx.setParentFormFeature( mFeatureList.first() );
262  mDualView->init( layer, mEditorContext.mapCanvas(), request, ctx, true, mShowFirstFeature );
263  mFeatureSelectionMgr = new QgsFilteredSelectionManager( layer, request, mDualView );
264  mDualView->setFeatureSelectionManager( mFeatureSelectionMgr );
265 
266  connect( mFeatureSelectionMgr, &QgsIFeatureSelectionManager::selectionChanged, this, &QgsRelationEditorWidget::updateButtons );
267 
268  QIcon icon;
269  QString text;
270  if ( layer->geometryType() == QgsWkbTypes::PointGeometry )
271  {
272  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePoint.svg" ) );
273  text = tr( "Add Point Child Feature" );
274  }
275  else if ( layer->geometryType() == QgsWkbTypes::LineGeometry )
276  {
277  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCaptureLine.svg" ) );
278  text = tr( "Add Line Child Feature" );
279  }
280  else if ( layer->geometryType() == QgsWkbTypes::PolygonGeometry )
281  {
282  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePolygon.svg" ) );
283  text = tr( "Add Polygon Child Feature" );
284  }
285 
286  mAddFeatureGeometryButton->setIcon( icon );
287  mAddFeatureGeometryButton->setText( text );
288  mAddFeatureGeometryButton->setToolTip( text );
289 
290  updateButtons();
291 }
292 
294 {
295  mEditorContext = context;
296 
297  if ( context.mapCanvas() && context.cadDockWidget() )
298  {
299  mMapToolDigitize.reset( new QgsMapToolDigitizeFeature( context.mapCanvas(), context.cadDockWidget() ) );
300  mMapToolDigitize->setButton( mAddFeatureGeometryButton );
301  }
302 
303  updateButtons();
304 }
305 
307 {
308  mDualView->setView( mode );
309  mViewMode = mode;
310 }
311 
312 void QgsRelationEditorWidget::updateButtons()
313 {
314  bool toggleEditingButtonEnabled = false;
315  bool canAdd = false;
316  bool canAddGeometry = false;
317  bool canRemove = false;
318  bool canEdit = false;
319  bool canLink = false;
320  bool canUnlink = false;
321  bool spatial = false;
322 
323  if ( mRelation.isValid() )
324  {
325  toggleEditingButtonEnabled = mRelation.referencingLayer()->supportsEditing();
326  canAdd = mRelation.referencingLayer()->isEditable();
327  canAddGeometry = mRelation.referencingLayer()->isEditable();
328  canRemove = mRelation.referencingLayer()->isEditable();
329  canEdit = mRelation.referencingLayer()->isEditable();
330  canLink = mRelation.referencingLayer()->isEditable();
331  canUnlink = mRelation.referencingLayer()->isEditable();
332  spatial = mRelation.referencingLayer()->isSpatial();
333  }
334 
335  if ( mNmRelation.isValid() )
336  {
337  toggleEditingButtonEnabled |= mNmRelation.referencedLayer()->supportsEditing();
338  canAdd = mNmRelation.referencedLayer()->isEditable();
339  canAddGeometry = mNmRelation.referencedLayer()->isEditable();
340  canRemove = mNmRelation.referencedLayer()->isEditable();
341  canEdit = mNmRelation.referencedLayer()->isEditable();
342  spatial = mNmRelation.referencedLayer()->isSpatial();
343  }
344 
345  const bool selectionNotEmpty = mFeatureSelectionMgr ? mFeatureSelectionMgr->selectedFeatureCount() : false;
346  if ( multiEditModeActive() )
347  {
348  const bool multieditLinkedChildSelected = ! selectedChildFeatureIds().isEmpty();
349 
350  canAddGeometry = false;
351 
352  canRemove = canRemove && multieditLinkedChildSelected;
353 
354  // In 1:n relations an element can be linked only to 1 feature
355  canLink = canLink && mNmRelation.isValid();
356  canUnlink = canUnlink && multieditLinkedChildSelected;
357  }
358  else
359  {
360  canRemove = canRemove && selectionNotEmpty;
361  canUnlink = canUnlink && selectionNotEmpty;
362  }
363 
364  mToggleEditingButton->setEnabled( toggleEditingButtonEnabled );
365  mAddFeatureButton->setEnabled( canAdd );
366  mAddFeatureGeometryButton->setEnabled( canAddGeometry );
367  mDuplicateFeatureButton->setEnabled( canEdit && selectionNotEmpty );
368  mLinkFeatureButton->setEnabled( canLink );
369  mDeleteFeatureButton->setEnabled( canRemove );
370  mUnlinkFeatureButton->setEnabled( canUnlink );
371  mZoomToFeatureButton->setEnabled( selectionNotEmpty );
372  mToggleEditingButton->setChecked( canEdit );
373  mSaveEditsButton->setEnabled( canEdit || canLink || canUnlink );
374 
375  mToggleEditingButton->setVisible( !mLayerInSameTransactionGroup );
376 
377  mLinkFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::Link ) );
378  mUnlinkFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::Unlink ) );
379  mSaveEditsButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::SaveChildEdits ) && !mLayerInSameTransactionGroup );
380  mAddFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::AddChildFeature ) );
381  mAddFeatureGeometryButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::AddChildFeature ) && mEditorContext.mapCanvas() && mEditorContext.cadDockWidget() && spatial );
382  mDuplicateFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::DuplicateChildFeature ) );
383  mDeleteFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::DeleteChildFeature ) );
384  mZoomToFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::ZoomToChildFeature ) && mEditorContext.mapCanvas() && spatial );
385 }
386 
387 void QgsRelationEditorWidget::addFeature()
388 {
390 
391  if ( !multiEditModeActive() )
392  return;
393 
394  mMultiEditTreeWidget->blockSignals( true );
395  mMultiEdit1NJustAddedIds = addedFeatures;
396  QTreeWidgetItemIterator treeWidgetItemIterator( mMultiEditTreeWidget );
397  while ( *treeWidgetItemIterator )
398  {
399  if ( ( *treeWidgetItemIterator )->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ) ).toInt() != static_cast<int>( MultiEditFeatureType::Child ) )
400  {
401  ++treeWidgetItemIterator;
402  continue;
403  }
404 
405  if ( addedFeatures.contains( ( *treeWidgetItemIterator )->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toInt() ) )
406  ( *treeWidgetItemIterator )->setSelected( true );
407 
408  ++treeWidgetItemIterator;
409  }
410  mMultiEditTreeWidget->blockSignals( false );
411 
412  updateUi();
413  updateButtons();
414 }
415 
416 void QgsRelationEditorWidget::addFeatureGeometry()
417 {
418  if ( multiEditModeActive() )
419  {
420  QgsLogger::warning( tr( "Adding a geometry feature is not supported in multiple edit mode" ) );
421  return;
422  }
423 
424  QgsVectorLayer *layer = nullptr;
425  if ( mNmRelation.isValid() )
426  layer = mNmRelation.referencedLayer();
427  else
428  layer = mRelation.referencingLayer();
429 
430  mMapToolDigitize->setLayer( layer );
431 
432  // window is always on top, so we hide it to digitize without seeing it
433  if ( window()->objectName() != QLatin1String( "QgisApp" ) )
434  {
435  window()->setVisible( false );
436  }
437  setMapTool( mMapToolDigitize );
438 
439  connect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
440  connect( mEditorContext.mapCanvas(), &QgsMapCanvas::keyPressed, this, &QgsRelationEditorWidget::onKeyPressed );
441 
442  if ( auto *lMainMessageBar = mEditorContext.mainMessageBar() )
443  {
444  const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( layer, mFeatureList.first() );
445 
446  const QString title = tr( "Create child feature for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString );
447  const QString msg = tr( "Digitize the geometry for the new feature on layer %1. Press &lt;ESC&gt; to cancel." )
448  .arg( layer->name() );
449  mMessageBarItem = QgsMessageBar::createMessage( title, msg, this );
450  lMainMessageBar->pushItem( mMessageBarItem );
451  }
452 }
453 
454 void QgsRelationEditorWidget::onDigitizingCompleted( const QgsFeature &feature )
455 {
457 
458  unsetMapTool();
459 }
460 
461 void QgsRelationEditorWidget::multiEditItemSelectionChanged()
462 {
463  const QList<QTreeWidgetItem *> selectedItems = mMultiEditTreeWidget->selectedItems();
464 
465  // Select all items pointing to the same feature
466  // but only if we are not deselecting.
467  if ( selectedItems.size() == 1
468  && mMultiEditPreviousSelectedItems.size() <= 1 )
469  {
470  if ( selectedItems.first()->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ) ).toInt() == static_cast<int>( MultiEditFeatureType::Child ) )
471  {
472  mMultiEditTreeWidget->blockSignals( true );
473 
474  const QgsFeatureId featureIdSelectedItem = selectedItems.first()->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toInt();
475 
476  QTreeWidgetItemIterator treeWidgetItemIterator( mMultiEditTreeWidget );
477  while ( *treeWidgetItemIterator )
478  {
479  if ( ( *treeWidgetItemIterator )->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ) ).toInt() != static_cast<int>( MultiEditFeatureType::Child ) )
480  {
481  ++treeWidgetItemIterator;
482  continue;
483  }
484 
485  const QgsFeatureId featureIdCurrentItem = ( *treeWidgetItemIterator )->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toInt();
486  if ( mNmRelation.isValid() )
487  {
488  if ( featureIdSelectedItem == featureIdCurrentItem )
489  ( *treeWidgetItemIterator )->setSelected( true );
490  }
491  else
492  {
493  if ( ! mMultiEdit1NJustAddedIds.contains( featureIdSelectedItem ) )
494  break;
495 
496  if ( mMultiEdit1NJustAddedIds.contains( featureIdCurrentItem ) )
497  ( *treeWidgetItemIterator )->setSelected( true );
498  }
499 
500  ++treeWidgetItemIterator;
501  }
502  mMultiEditTreeWidget->blockSignals( false );
503  }
504  }
505  mMultiEditPreviousSelectedItems = selectedItems;
506  updateButtons();
507 }
508 
509 void QgsRelationEditorWidget::toggleEditing( bool state )
510 {
512 
513  updateButtons();
514 }
515 
517 {
518  if ( !mRelation.isValid() || mFeatureList.isEmpty() || !mFeatureList.first().isValid() )
519  return;
520 
521  if ( !isVisible() )
522  return;
523 
524  if ( multiEditModeActive() )
525  updateUiMultiEdit();
526  else
527  updateUiSingleEdit();
528 }
529 
530 void QgsRelationEditorWidget::setVisibleButtons( const Buttons &buttons )
531 {
532  mButtonsVisibility = buttons;
533  updateButtons();
534 }
535 
536 QgsRelationEditorWidget::Buttons QgsRelationEditorWidget::visibleButtons() const
537 {
538  Buttons buttons;
539  if ( mLinkFeatureButton->isVisible() )
540  buttons |= Button::Link;
541  if ( mUnlinkFeatureButton->isVisible() )
542  buttons |= Button::Unlink;
543  if ( mSaveEditsButton->isVisible() )
544  buttons |= Button::SaveChildEdits;
545  if ( mAddFeatureButton->isVisible() )
546  buttons |= Button::AddChildFeature;
547  if ( mDuplicateFeatureButton->isVisible() )
548  buttons |= Button::DuplicateChildFeature;
549  if ( mDeleteFeatureButton->isVisible() )
550  buttons |= Button::DeleteChildFeature;
551  if ( mZoomToFeatureButton->isVisible() )
552  buttons |= Button::ZoomToChildFeature;
553  return buttons;
554 }
555 
556 void QgsRelationEditorWidget::parentFormValueChanged( const QString &attribute, const QVariant &newValue )
557 {
558  mDualView->parentFormValueChanged( attribute, newValue );
559 }
560 
561 void QgsRelationEditorWidget::showContextMenu( QgsActionMenu *menu, const QgsFeatureId fid )
562 {
564  {
565  QAction *qAction = nullptr;
566 
567  qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ), tr( "Delete Feature" ) );
568  connect( qAction, &QAction::triggered, this, [this, fid]() { deleteFeature( fid ); } );
569 
570  qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ), tr( "Unlink Feature" ) );
571  connect( qAction, &QAction::triggered, this, [this, fid]() { unlinkFeature( fid ); } );
572  }
573 }
574 
575 void QgsRelationEditorWidget::setMapTool( QgsMapTool *mapTool )
576 {
577  QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
578 
579  mapCanvas->setMapTool( mapTool );
580  mapCanvas->window()->raise();
581  mapCanvas->activateWindow();
582  mapCanvas->setFocus();
583  connect( mapTool, &QgsMapTool::deactivated, this, &QgsRelationEditorWidget::mapToolDeactivated );
584 }
585 
586 void QgsRelationEditorWidget::unsetMapTool()
587 {
588  QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
589 
590  // this will call mapToolDeactivated
591  mapCanvas->unsetMapTool( mMapToolDigitize );
592 
593  disconnect( mapCanvas, &QgsMapCanvas::keyPressed, this, &QgsRelationEditorWidget::onKeyPressed );
594  disconnect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
595 }
596 
597 QgsFeatureIds QgsRelationEditorWidget::selectedChildFeatureIds() const
598 {
599  if ( multiEditModeActive() )
600  {
601  QgsFeatureIds featureIds;
602  for ( QTreeWidgetItem *treeWidgetItem : mMultiEditTreeWidget->selectedItems() )
603  {
604  if ( static_cast<MultiEditFeatureType>( treeWidgetItem->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ) ).toInt() ) != MultiEditFeatureType::Child )
605  continue;
606 
607  featureIds.insert( treeWidgetItem->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toLongLong() );
608  }
609  return featureIds;
610  }
611  else
612  return mFeatureSelectionMgr->selectedFeatureIds();
613 }
614 
615 void QgsRelationEditorWidget::updateUiSingleEdit()
616 {
617  mFormViewButton->setVisible( true );
618  mTableViewButton->setVisible( true );
619  mMultiEditInfoLabel->setVisible( false );
620 
621  mStackedWidget->setCurrentWidget( mDualView );
622 
624 
625  if ( mNmRelation.isValid() )
626  {
628  QgsFeature fet;
629  QStringList filters;
630 
631  while ( it.nextFeature( fet ) )
632  {
634  filters << filter.prepend( '(' ).append( ')' );
635  }
636 
637  QgsFeatureRequest nmRequest;
638  nmRequest.setFilterExpression( filters.join( QLatin1String( " OR " ) ) );
639 
640  initDualView( mNmRelation.referencedLayer(), nmRequest );
641  }
642  else if ( mRelation.referencingLayer() )
643  {
644  initDualView( mRelation.referencingLayer(), request );
645  }
646 }
647 
648 void QgsRelationEditorWidget::updateUiMultiEdit()
649 {
650  mFormViewButton->setVisible( false );
651  mTableViewButton->setVisible( false );
652  mMultiEditInfoLabel->setVisible( true );
653 
654  mStackedWidget->setCurrentWidget( mMultiEditStackedWidgetPage ) ;
655 
656  QList<QTreeWidgetItem *> parentTreeWidgetItems;
657 
658  QgsFeatureIds featureIdsMixedValues;
659  QMultiMap<QTreeWidgetItem *, QgsFeatureId> multimapChildFeatures;
660 
661  mMultiEditTreeWidget->clear();
662  for ( const QgsFeature &featureParent : std::as_const( mFeatureList ) )
663  {
664  QTreeWidgetItem *treeWidgetItem = createMultiEditTreeWidgetItem( featureParent, mRelation.referencedLayer(), MultiEditFeatureType::Parent );
665 
666  // Parent feature items are not selectable
667  treeWidgetItem->setFlags( Qt::ItemIsEnabled );
668 
669  parentTreeWidgetItems.append( treeWidgetItem );
670 
671  // Get child features
672  const QgsFeatureRequest request = relation().getRelatedFeaturesRequest( featureParent );
673  QgsFeatureIterator featureIterator = mRelation.referencingLayer()->getFeatures( request );
674  QgsFeature featureChild;
675  while ( featureIterator.nextFeature( featureChild ) )
676  {
677  if ( mNmRelation.isValid() )
678  {
679  const QgsFeatureRequest requestFinalChild = mNmRelation.getReferencedFeatureRequest( featureChild );
680  QgsFeatureIterator featureIteratorFinalChild = mNmRelation.referencedLayer()->getFeatures( requestFinalChild );
681  QgsFeature featureChildChild;
682  while ( featureIteratorFinalChild.nextFeature( featureChildChild ) )
683  {
684  QTreeWidgetItem *treeWidgetItemChild = createMultiEditTreeWidgetItem( featureChildChild, mNmRelation.referencedLayer(), MultiEditFeatureType::Child );
685 
686  treeWidgetItem->addChild( treeWidgetItemChild );
687 
688  featureIdsMixedValues.insert( featureChildChild.id() );
689  multimapChildFeatures.insert( treeWidgetItem, featureChildChild.id() );
690  }
691  }
692  else
693  {
694  QTreeWidgetItem *treeWidgetItemChild = createMultiEditTreeWidgetItem( featureChild, mRelation.referencingLayer(), MultiEditFeatureType::Child );
695  treeWidgetItem->addChild( treeWidgetItemChild );
696 
697  featureIdsMixedValues.insert( featureChild.id() );
698  }
699  }
700 
701  mMultiEditTreeWidget->addTopLevelItem( treeWidgetItem );
702  treeWidgetItem->setExpanded( true );
703  }
704 
705  // Set mixed values indicator (Green or Orange)
706  //
707  // Green:
708  // n:m and 1:n: 0 child features available
709  // n:m with no mixed values
710  // Orange:
711  // n:m with mixed values
712  // 1:n always, including when we pseudo know that feature are related (just added feature)
713  //
714  // See https://github.com/qgis/QGIS/pull/45703
715  //
716  if ( mNmRelation.isValid() )
717  {
718  QgsFeatureIds::iterator iterator = featureIdsMixedValues.begin();
719  while ( iterator != featureIdsMixedValues.end() )
720  {
721  bool mixedValues = false;
722  for ( QTreeWidgetItem *parentTreeWidgetItem : parentTreeWidgetItems )
723  {
724  if ( ! multimapChildFeatures.values( parentTreeWidgetItem ).contains( *iterator ) )
725  {
726  mixedValues = true;
727  break;
728  }
729  }
730 
731  if ( !mixedValues )
732  {
733  iterator = featureIdsMixedValues.erase( iterator );
734  continue;
735  }
736 
737  ++iterator;
738  }
739  }
740 
741  // Set multiedit info label
742  if ( featureIdsMixedValues.isEmpty() )
743  {
744  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/multieditSameValues.svg" ) );
745  mMultiEditInfoLabel->setPixmap( icon.pixmap( mMultiEditInfoLabel->height(),
746  mMultiEditInfoLabel->height() ) );
747  mMultiEditInfoLabel->setToolTip( tr( "All features in selection have equal relations" ) );
748  }
749  else
750  {
751  QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/multieditMixedValues.svg" ) );
752  mMultiEditInfoLabel->setPixmap( icon.pixmap( mMultiEditInfoLabel->height(),
753  mMultiEditInfoLabel->height() ) );
754  mMultiEditInfoLabel->setToolTip( tr( "Some features in selection have different relations" ) );
755 
756  // Set italic font for mixed values
757  QFont fontItalic = mMultiEditTreeWidget->font();
758  fontItalic.setItalic( true );
759  for ( QTreeWidgetItem *parentTreeWidgetItem : parentTreeWidgetItems )
760  {
761  for ( int childIndex = 0; childIndex < parentTreeWidgetItem->childCount(); ++childIndex )
762  {
763  QTreeWidgetItem *childItem = parentTreeWidgetItem->child( childIndex );
764  const QgsFeatureId featureIdCurrentItem = childItem->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toInt();
765  if ( featureIdsMixedValues.contains( featureIdCurrentItem ) )
766  childItem->setFont( 0, fontItalic );
767  }
768  }
769  }
770 }
771 
772 QTreeWidgetItem *QgsRelationEditorWidget::createMultiEditTreeWidgetItem( const QgsFeature &feature, QgsVectorLayer *layer, MultiEditFeatureType type )
773 {
774  QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem();
775  treeWidgetItem->setText( 0, QgsVectorLayerUtils::getFeatureDisplayString( layer, feature ) );
776  treeWidgetItem->setIcon( 0, QgsIconUtils::iconForLayer( layer ) );
777  treeWidgetItem->setData( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ), static_cast<int>( type ) );
778  treeWidgetItem->setData( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ), feature.id() );
779  return treeWidgetItem;
780 }
781 
782 void QgsRelationEditorWidget::onKeyPressed( QKeyEvent *e )
783 {
784  if ( e->key() == Qt::Key_Escape )
785  {
786  window()->setVisible( true );
787  window()->raise();
788  window()->activateWindow();
789  unsetMapTool();
790  }
791 }
792 
793 void QgsRelationEditorWidget::mapToolDeactivated()
794 {
795  if ( mEditorContext.mainMessageBar() && mMessageBarItem )
796  {
797  mEditorContext.mainMessageBar()->popWidget( mMessageBarItem );
798  }
799  mMessageBarItem = nullptr;
800 }
801 
803 {
804  return QVariantMap( {{"buttons", qgsFlagValueToKeys( visibleButtons() )},
805  {"show_first_feature", mShowFirstFeature}} );
806 }
807 
808 void QgsRelationEditorWidget::setConfig( const QVariantMap &config )
809 {
810  mButtonsVisibility = qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsRelationEditorWidget::Button::AllButtons );
811  mShowFirstFeature = config.value( QStringLiteral( "show_first_feature" ), true ).toBool();
812  updateButtons();
813 }
814 
815 void QgsRelationEditorWidget::beforeSetRelationFeature( const QgsRelation &newRelation, const QgsFeature &newFeature )
816 {
817  Q_UNUSED( newRelation );
818  Q_UNUSED( newFeature );
819 
820  if ( ! mRelation.isValid() )
821  return;
822 
823  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
824  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
825 }
826 
828 {
829  if ( ! mRelation.isValid()
830  || mFeatureList.isEmpty() )
831  {
832  updateButtons();
833  return;
834  }
835 
836  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
837  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
838 
839  updateButtons();
840 
842  initDualView( mRelation.referencingLayer(), myRequest );
843 }
844 
845 void QgsRelationEditorWidget::beforeSetRelations( const QgsRelation &newRelation, const QgsRelation &newNmRelation )
846 {
847  Q_UNUSED( newRelation );
848  Q_UNUSED( newNmRelation );
849 
850  if ( mRelation.isValid() )
851  {
852  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
853  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
854  }
855 
856  if ( mNmRelation.isValid() )
857  {
858  disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
859  disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
860  }
861 }
862 
864 {
865  if ( !mRelation.isValid() )
866  return;
867 
868  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
869  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
870 
871  if ( mNmRelation.isValid() )
872  {
873  connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
874  connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
875  }
876 
877  updateButtons();
878 }
879 
881 {
882  return mFeatureSelectionMgr;
883 }
884 
886 {
887  const QgsFeatureIds selectedFids = selectedChildFeatureIds();
888  unlinkFeatures( selectedFids );
889 }
890 
892 {
893  duplicateFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
894 }
895 
897 {
898  duplicateFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
899 }
900 
902 {
903  const QgsFeatureIds selectedFids = selectedChildFeatureIds();
904  deleteFeatures( selectedFids );
905 }
906 
908 {
910  if ( !c )
911  return;
912 
913  c->zoomToFeatureIds(
915  mFeatureSelectionMgr->selectedFeatureIds()
916  );
917 }
918 
920 
921 
923  : QgsAbstractRelationEditorConfigWidget( relation, parent )
924 {
925  setupUi( this );
926 }
927 
929 {
930  QgsRelationEditorWidget::Buttons buttons;
931  buttons.setFlag( QgsRelationEditorWidget::Button::Link, mRelationShowLinkCheckBox->isChecked() );
932  buttons.setFlag( QgsRelationEditorWidget::Button::Unlink, mRelationShowUnlinkCheckBox->isChecked() );
933  buttons.setFlag( QgsRelationEditorWidget::Button::AddChildFeature, mRelationShowAddChildCheckBox->isChecked() );
934  buttons.setFlag( QgsRelationEditorWidget::Button::DuplicateChildFeature, mRelationShowDuplicateChildFeatureCheckBox->isChecked() );
935  buttons.setFlag( QgsRelationEditorWidget::Button::ZoomToChildFeature, mRelationShowZoomToFeatureCheckBox->isChecked() );
936  buttons.setFlag( QgsRelationEditorWidget::Button::DeleteChildFeature, mRelationDeleteChildFeatureCheckBox->isChecked() );
937  buttons.setFlag( QgsRelationEditorWidget::Button::SaveChildEdits, mRelationShowSaveChildEditsCheckBox->isChecked() );
938 
939  return QVariantMap(
940  {
941  {"buttons", qgsFlagValueToKeys( buttons )},
942  {"show_first_feature", mShowFirstFeature->isChecked()}
943  } );
944 }
945 
946 void QgsRelationEditorConfigWidget::setConfig( const QVariantMap &config )
947 {
948  const QgsRelationEditorWidget::Buttons buttons = qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsRelationEditorWidget::Button::AllButtons );
949 
950  mRelationShowLinkCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::Link ) );
951  mRelationShowUnlinkCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::Unlink ) );
952  mRelationShowAddChildCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::AddChildFeature ) );
953  mRelationShowDuplicateChildFeatureCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::DuplicateChildFeature ) );
954  mRelationShowZoomToFeatureCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::ZoomToChildFeature ) );
955  mRelationDeleteChildFeatureCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::DeleteChildFeature ) );
956  mRelationShowSaveChildEditsCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::SaveChildEdits ) );
957  mShowFirstFeature->setChecked( config.value( QStringLiteral( "show_first_feature" ), true ).toBool() );
958 }
959 
960 
962 
963 
964 #ifndef SIP_RUN
966 {
967 
968 }
969 
971 {
972  return QStringLiteral( "relation_editor" );
973 }
974 
976 {
977  return QObject::tr( "Relation Editor" );
978 }
979 
980 QgsAbstractRelationEditorWidget *QgsRelationEditorWidgetFactory::create( const QVariantMap &config, QWidget *parent ) const
981 {
982  return new QgsRelationEditorWidget( config, parent );
983 }
984 
986 {
987  return static_cast<QgsAbstractRelationEditorConfigWidget *>( new QgsRelationEditorConfigWidget( relation, parent ) );
988 }
989 #endif
QgsAttributeEditorContext::mapCanvas
QgsMapCanvas * mapCanvas() const
Returns the associated map canvas (e.g.
Definition: qgsattributeeditorcontext.h:140
QgsRelationEditorWidgetFactory::QgsRelationEditorWidgetFactory
QgsRelationEditorWidgetFactory()
Definition: qgsrelationeditorwidget.cpp:965
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:1052
QgsAttributeEditorContext::setParentFormFeature
void setParentFormFeature(const QgsFeature &feature)
Sets the feature of the currently edited parent form.
Definition: qgsattributeeditorcontext.h:258
qgsexpressioncontextutils.h
QgsAbstractRelationEditorWidget::addFeature
QgsFeatureIds addFeature(const QgsGeometry &geometry=QgsGeometry())
Adds new features with given geometry Returns the Id of added features.
Definition: qgsabstractrelationeditorwidget.cpp:218
QgsAbstractRelationEditorWidget::mLayerInSameTransactionGroup
bool mLayerInSameTransactionGroup
Definition: qgsabstractrelationeditorwidget.h:267
QgsAbstractRelationEditorWidget::relation
QgsRelation relation() const
Returns the relation.
Definition: qgsabstractrelationeditorwidget.h:87
QObjectUniquePtr::reset
void reset(T *p=nullptr)
Will reset the managed pointer to p.
Definition: qobjectuniqueptr.h:179
QgsRelationEditorWidget::Button
Button
Possible buttons shown in the relation editor.
Definition: qgsrelationeditorwidget.h:102
qgscollapsiblegroupbox.h
QgsAttributeEditorContext::cadDockWidget
QgsAdvancedDigitizingDockWidget * cadDockWidget() const
Returns the associated CAD dock widget (e.g.
Definition: qgsattributeeditorcontext.h:156
QgsRelationEditorConfigWidget::QgsRelationEditorConfigWidget
QgsRelationEditorConfigWidget(const QgsRelation &relation, QWidget *parent)
Create a new configuration widget.
Definition: qgsrelationeditorwidget.cpp:922
qgsmessagebaritem.h
QgsMapLayer::editingStopped
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
QgsRelationEditorWidgetFactory::configWidget
QgsAbstractRelationEditorConfigWidget * configWidget(const QgsRelation &relation, QWidget *parent) const override
Override this in your implementation.
Definition: qgsrelationeditorwidget.cpp:985
QgsRelationEditorWidgetFactory::type
QString type() const override
Returns the machine readable identifier name of this widget type.
Definition: qgsrelationeditorwidget.cpp:970
qgsmapcanvas.h
QgsVectorLayer::supportsEditing
bool supportsEditing
Definition: qgsvectorlayer.h:400
QgsAbstractRelationEditorConfigWidget
This class should be subclassed for every configurable relation widget type.
Definition: qgsabstractrelationeditorwidget.h:343
qgsexpression.h
QgsRelationEditorWidget::afterSetRelationFeature
void afterSetRelationFeature() override
A hook called right after setRelationFeature() is executed, but before updateUi() is called.
Definition: qgsrelationeditorwidget.cpp:827
QgsAbstractRelationEditorWidget::unlinkFeature
void unlinkFeature(QgsFeatureId fid=QgsFeatureId())
Unlinks a feature with given fid.
Definition: qgsabstractrelationeditorwidget.cpp:579
QgsRelationEditorWidget::unlinkSelectedFeatures
void unlinkSelectedFeatures()
Unlinks the selected features from the relation.
Definition: qgsrelationeditorwidget.cpp:885
QgsIconUtils::iconForLayer
static QIcon iconForLayer(const QgsMapLayer *layer)
Returns the icon corresponding to a specified map layer.
Definition: qgsiconutils.cpp:94
QgsAbstractRelationEditorWidget::deleteFeature
void deleteFeature(QgsFeatureId fid=QgsFeatureId())
Delete a feature with given fid.
Definition: qgsabstractrelationeditorwidget.cpp:310
QgsDualView::setView
void setView(ViewMode view)
Change the current view mode.
Definition: qgsdualview.cpp:290
QgsRelationEditorWidget::config
QVariantMap config() const override
Returns the current configuration.
Definition: qgsrelationeditorwidget.cpp:802
qgsfeatureiterator.h
qgsFlagKeysToValue
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given keys of a flag.
Definition: qgis.h:2520
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
qgsfeature.h
QgsRelationEditorWidget
The default relation widget in QGIS.
Definition: qgsrelationeditorwidget.h:89
QgsRelationEditorWidget::setEditorContext
void setEditorContext(const QgsAttributeEditorContext &context) override
Sets the editor context.
Definition: qgsrelationeditorwidget.cpp:293
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsRelationEditorWidget::duplicateSelectedFeatures
void duplicateSelectedFeatures()
Duplicates the selected features.
Definition: qgsrelationeditorwidget.cpp:896
QgsVectorLayer::isSpatial
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
Definition: qgsvectorlayer.cpp:3733
QgsRelationEditorWidget::visibleButtons
Buttons visibleButtons
Definition: qgsrelationeditorwidget.h:94
QgsMapLayer::editingStarted
void editingStarted()
Emitted when editing on this layer has started.
QgsDualView
This widget is used to show the attributes of a set of features of a QgsVectorLayer....
Definition: qgsdualview.h:44
QgsDualView::AttributeTable
@ AttributeTable
Shows the features and attributes in a table layout.
Definition: qgsdualview.h:61
QgsRelationEditorWidget::beforeSetRelationFeature
void beforeSetRelationFeature(const QgsRelation &newRelation, const QgsFeature &newFeature) override
A hook called right before setRelationFeature() is executed.
Definition: qgsrelationeditorwidget.cpp:815
QgsRelationEditorWidget::afterSetRelations
void afterSetRelations() override
A hook called right after setRelations() is executed, but before updateUi() is called.
Definition: qgsrelationeditorwidget.cpp:863
QgsMessageBar::popWidget
bool popWidget(QgsMessageBarItem *item)
Remove the specified item from the bar, and display the next most recent one in the stack.
Definition: qgsmessagebar.cpp:161
QgsRelationEditorWidget::QgsRelationEditorWidget
QgsRelationEditorWidget(const QVariantMap &config, QWidget *parent=nullptr)
Constructor.
Definition: qgsrelationeditorwidget.cpp:99
QgsAbstractRelationEditorWidget::unlinkFeatures
void unlinkFeatures(const QgsFeatureIds &fids)
Unlinks the features with fids.
Definition: qgsabstractrelationeditorwidget.cpp:584
qgsrelationeditorwidget.h
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsRelationEditorWidget::updateUi
virtual void updateUi() override
A hook called every time the state of the relation editor widget has changed via calling its set* met...
Definition: qgsrelationeditorwidget.cpp:516
QgsVectorLayer::isEditable
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
Definition: qgsvectorlayer.cpp:3728
QgsRelation::referencingLayer
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:47
QgsFeatureRequest::setFilterExpression
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Definition: qgsfeaturerequest.cpp:167
qgsapplication.h
QgsAbstractRelationEditorWidget::linkFeature
void linkFeature()
Links a new feature to the relation.
Definition: qgsabstractrelationeditorwidget.cpp:436
QgsDualView::init
void init(QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request=QgsFeatureRequest(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), bool loadFeatures=true, bool showFirstFeature=true)
Has to be called to initialize the dual view.
Definition: qgsdualview.cpp:121
QgsMapTool
Abstract base class for all map tools. Map tools are user interactive tools for manipulating the map ...
Definition: qgsmaptool.h:70
qgsmaptooldigitizefeature.h
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
qgsFlagValueToKeys
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
Definition: qgis.h:2498
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
QgsRelationEditorConfigWidget::setConfig
void setConfig(const QVariantMap &config)
Update the configuration widget to represent the given configuration.
Definition: qgsrelationeditorwidget.cpp:946
QgsMapToolDigitizeFeature::digitizingCompleted
void digitizingCompleted(const QgsFeature &feature)
Emitted whenever the digitizing has been successfully completed.
qgsvectorlayertools.h
QgsRelationEditorWidget::beforeSetRelations
void beforeSetRelations(const QgsRelation &newRelation, const QgsRelation &newNmRelation) override
A hook called right before setRelations() is executed.
Definition: qgsrelationeditorwidget.cpp:845
qgsvectorlayerselectionmanager.h
QgsRelationEditorWidget::setViewMode
void setViewMode(QgsDualView::ViewMode mode)
Define the view mode for the dual view.
Definition: qgsrelationeditorwidget.cpp:306
QgsAbstractRelationEditorWidget::mFeatureList
QgsFeatureList mFeatureList
Definition: qgsabstractrelationeditorwidget.h:265
QgsVectorLayer::selectionChanged
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
QgsIFeatureSelectionManager::selectionChanged
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
QgsMapToolDigitizeFeature::setLayer
void setLayer(QgsMapLayer *vl)
Change the layer edited by the map tool.
Definition: qgsmaptooldigitizefeature.cpp:204
QgsRelation::referencedLayer
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:48
QgsRelationEditorWidget::duplicateFeature
Q_DECL_DEPRECATED void duplicateFeature()
Duplicates a feature.
Definition: qgsrelationeditorwidget.cpp:891
QgsVectorLayer::selectedFeatureIds
const Q_INVOKABLE QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Definition: qgsvectorlayer.cpp:3621
QgsFeatureRequest::filterExpression
QgsExpression * filterExpression() const
Returns the filter expression (if set).
Definition: qgsfeaturerequest.h:562
QgsAbstractRelationEditorWidget::deleteFeatures
void deleteFeatures(const QgsFeatureIds &fids)
Deletes the features with fids.
Definition: qgsabstractrelationeditorwidget.cpp:317
qgstransactiongroup.h
QgsDualView::AttributeEditor
@ AttributeEditor
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
Definition: qgsdualview.h:68
qgsvectordataprovider.h
qgsvectorlayerutils.h
QgsActionMenu
This class is a menu that is populated automatically with the actions defined for a given layer.
Definition: qgsactionmenu.h:37
QgsMapToolDigitizeFeature
This tool digitizes geometry of new point/line/polygon features on already existing vector layers Onc...
Definition: qgsmaptooldigitizefeature.h:31
QgsLogger::warning
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
QgsAbstractRelationEditorWidget::feature
QgsFeature feature() const
Returns the widget's current feature If the widget is in multiedit mode only the first is returned.
Definition: qgsabstractrelationeditorwidget.cpp:182
QgsRelationEditorWidget::zoomToSelectedFeatures
void zoomToSelectedFeatures()
Zooms to the selected features.
Definition: qgsrelationeditorwidget.cpp:907
QgsRelation::getReferencedFeatureRequest
QgsFeatureRequest getReferencedFeatureRequest(const QgsAttributes &attributes) const
Creates a request to return the feature on the referenced (parent) layer which is referenced by the p...
Definition: qgsrelation.cpp:239
qgsmessagebar.h
QgsVectorLayerSelectionManager
Definition: qgsvectorlayerselectionmanager.h:32
QgsMapTool::setButton
void setButton(QAbstractButton *button)
Use this to associate a button to this maptool.
Definition: qgsmaptool.cpp:150
qgsrelation.h
QgsRelationEditorWidget::setVisibleButtons
void setVisibleButtons(const Buttons &buttons)
Defines the buttons which are shown.
Definition: qgsrelationeditorwidget.cpp:530
QgsMapCanvas::setMapTool
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
Definition: qgsmapcanvas.cpp:2475
QgsRelationEditorWidgetFactory::name
QString name() const override
Returns the human readable identifier name of this widget type.
Definition: qgsrelationeditorwidget.cpp:975
QgsFeatureIds
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
QgsAbstractRelationEditorWidget::toggleEditing
void toggleEditing(bool state)
Toggles editing state of the widget.
Definition: qgsabstractrelationeditorwidget.cpp:195
QgsAbstractRelationEditorWidget::duplicateFeatures
void duplicateFeatures(const QgsFeatureIds &fids)
Duplicates features.
Definition: qgsabstractrelationeditorwidget.cpp:707
QgsDualView::ViewMode
ViewMode
The view modes, in which this widget can present information.
Definition: qgsdualview.h:55
QgsRelationEditorWidget::setConfig
void setConfig(const QVariantMap &config) override
Defines the current configuration.
Definition: qgsrelationeditorwidget.cpp:808
QgsRelationEditorWidget::deleteSelectedFeatures
void deleteSelectedFeatures()
Deletes the currently selected features.
Definition: qgsrelationeditorwidget.cpp:901
QgsAbstractRelationEditorWidget::mEditorContext
QgsAttributeEditorContext mEditorContext
Definition: qgsabstractrelationeditorwidget.h:262
QgsVectorLayerSelectionManager::selectedFeatureCount
int selectedFeatureCount() override
Returns the number of features that are selected in this layer.
Definition: qgsvectorlayerselectionmanager.cpp:27
QgsRelationEditorWidgetFactory::create
QgsAbstractRelationEditorWidget * create(const QVariantMap &config, QWidget *parent=nullptr) const override
Override this in your implementation.
Definition: qgsrelationeditorwidget.cpp:980
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
QgsRelation::getRelatedFeaturesRequest
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
Definition: qgsrelation.cpp:193
QgsAbstractRelationEditorWidget::mRelation
QgsRelation mRelation
Definition: qgsabstractrelationeditorwidget.h:263
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
c
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
Definition: porting_processing.dox:1
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsDualView::parentFormValueChanged
void parentFormValueChanged(const QString &attribute, const QVariant &value)
Called in embedded forms when an attribute value in the parent form has changed.
Definition: qgsdualview.cpp:797
QgsRelation::isValid
bool isValid
Definition: qgsrelation.h:50
QgsRelationEditorWidget::parentFormValueChanged
void parentFormValueChanged(const QString &attribute, const QVariant &newValue) override
Definition: qgsrelationeditorwidget.cpp:556
QgsDualView::setFeatureSelectionManager
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
Set the feature selection model.
Definition: qgsdualview.cpp:1254
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:76
QgsMapCanvas::keyPressed
void keyPressed(QKeyEvent *e)
Emit key press event.
qgsiconutils.h
QgsRelationEditorWidget::featureSelectionManager
QgsIFeatureSelectionManager * featureSelectionManager()
The feature selection manager is responsible for the selected features which are currently being edit...
Definition: qgsrelationeditorwidget.cpp:880
QgsMapCanvas::unsetMapTool
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
Definition: qgsmapcanvas.cpp:2515
QgsRelationEditorConfigWidget
Creates a new configuration widget for the relation editor widget.
Definition: qgsrelationeditorwidget.h:276
QgsRelation
Definition: qgsrelation.h:42
QgsRelationEditorConfigWidget::config
QVariantMap config()
Create a configuration from the current GUI state.
Definition: qgsrelationeditorwidget.cpp:928
qgsdistancearea.h
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsDualView::showContextMenuExternally
void showContextMenuExternally(QgsActionMenu *menu, QgsFeatureId fid)
Emitted when selecting context menu on the feature list to create the context menu individually.
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
qgsfeatureselectiondlg.h
QgsVectorLayer::getFeature
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
Definition: qgsvectorlayer.h:1187
QgsIFeatureSelectionManager
Is an interface class to abstract feature selection handling.
Definition: qgsifeatureselectionmanager.h:31
QgsMessageBar::createMessage
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
Creates message bar item widget containing a message text to be displayed on the bar.
Definition: qgsmessagebar.cpp:389
qgslogger.h
QgsAttributeEditorContext
This class contains context information for attribute editor widgets. It will be passed to embedded w...
Definition: qgsattributeeditorcontext.h:40
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
QgsVectorLayer::geometryType
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Definition: qgsvectorlayer.cpp:720
QgsAbstractRelationEditorWidget::mNmRelation
QgsRelation mNmRelation
Definition: qgsabstractrelationeditorwidget.h:264
QgsAttributeEditorContext::mainMessageBar
QgsMessageBar * mainMessageBar()
Returns the main message bar.
Definition: qgsattributeeditorcontext.h:292
QgsExpression::expression
QString expression() const
Returns the original, unmodified expression string.
Definition: qgsexpression.cpp:60
QgsVectorLayerSelectionManager::selectedFeatureIds
const QgsFeatureIds & selectedFeatureIds() const override
Returns reference to identifiers of selected features.
Definition: qgsvectorlayerselectionmanager.cpp:47
QgsAbstractRelationEditorWidget
Base class to build new relation widgets.
Definition: qgsabstractrelationeditorwidget.h:45
qgsproject.h
qgsgenericfeatureselectionmanager.h
QgsMapTool::deactivated
void deactivated()
signal emitted once the map tool is deactivated
QgsAbstractRelationEditorWidget::multiEditModeActive
bool multiEditModeActive() const
Returns true if editing multiple features at a time.
Definition: qgsabstractrelationeditorwidget.cpp:177
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QgsVectorLayerUtils::getFeatureDisplayString
static QString getFeatureDisplayString(const QgsVectorLayer *layer, const QgsFeature &feature)
Definition: qgsvectorlayerutils.cpp:1053
QgsAbstractRelationEditorWidget::saveEdits
void saveEdits()
Saves the current modifications in the relation.
Definition: qgsabstractrelationeditorwidget.cpp:211