QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsrelationeditorwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrelationeditor.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 "qgsrelation.h"
27 #include "qgsvectorlayertools.h"
28 #include "qgsproject.h"
29 #include "qgstransactiongroup.h"
30 #include "qgslogger.h"
31 #include "qgsvectorlayerutils.h"
32 #include "qgsmapcanvas.h"
36 #include "qgsmessagebar.h"
37 #include "qgsmessagebaritem.h"
38 
39 #include <QHBoxLayout>
40 #include <QLabel>
41 #include <QMessageBox>
42 #include <QPushButton>
43 
46 QgsFilteredSelectionManager::QgsFilteredSelectionManager( QgsVectorLayer *layer, const QgsFeatureRequest &request, QObject *parent )
47  : QgsVectorLayerSelectionManager( layer, parent )
48  , mRequest( request )
49 {
50  for ( auto fid : layer->selectedFeatureIds() )
51  if ( mRequest.acceptFeature( layer->getFeature( fid ) ) )
52  mSelectedFeatureIds << fid;
53 
54  connect( layer, &QgsVectorLayer::selectionChanged, this, &QgsFilteredSelectionManager::onSelectionChanged );
55 }
56 
57 const QgsFeatureIds &QgsFilteredSelectionManager::selectedFeatureIds() const
58 {
59  return mSelectedFeatureIds;
60 }
61 
62 int QgsFilteredSelectionManager::selectedFeatureCount()
63 {
64  return mSelectedFeatureIds.count();
65 }
66 
67 void QgsFilteredSelectionManager::onSelectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect )
68 {
69  QgsFeatureIds lselected = selected;
70  if ( clearAndSelect )
71  {
72  mSelectedFeatureIds.clear();
73  }
74  else
75  {
76  for ( auto fid : deselected )
77  mSelectedFeatureIds.remove( fid );
78  }
79 
80  for ( auto fid : selected )
81  if ( mRequest.acceptFeature( layer()->getFeature( fid ) ) )
82  mSelectedFeatureIds << fid;
83  else
84  lselected.remove( fid );
85 
86  emit selectionChanged( lselected, deselected, clearAndSelect );
87 }
88 
90 
92  : QgsCollapsibleGroupBox( parent )
93 {
94  QVBoxLayout *topLayout = new QVBoxLayout( this );
95  topLayout->setContentsMargins( 0, 9, 0, 0 );
96  setLayout( topLayout );
97 
98  // buttons
99  QHBoxLayout *buttonLayout = new QHBoxLayout();
100  buttonLayout->setContentsMargins( 0, 0, 0, 0 );
101  // toggle editing
102  mToggleEditingButton = new QToolButton( this );
103  mToggleEditingButton->setObjectName( QStringLiteral( "mToggleEditingButton" ) );
104  mToggleEditingButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) ) );
105  mToggleEditingButton->setText( tr( "Toggle Editing" ) );
106  mToggleEditingButton->setEnabled( false );
107  mToggleEditingButton->setCheckable( true );
108  mToggleEditingButton->setToolTip( tr( "Toggle editing mode for child layer" ) );
109  buttonLayout->addWidget( mToggleEditingButton );
110  // save Edits
111  mSaveEditsButton = new QToolButton( this );
112  mSaveEditsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSaveEdits.svg" ) ) );
113  mSaveEditsButton->setText( tr( "Save Child Layer Edits" ) );
114  mSaveEditsButton->setToolTip( tr( "Save child layer edits" ) );
115  mSaveEditsButton->setEnabled( true );
116  buttonLayout->addWidget( mSaveEditsButton );
117  // add feature with geometry
118  mAddFeatureGeometryButton = new QToolButton( this );
119  mAddFeatureGeometryButton->setObjectName( QStringLiteral( "mAddFeatureGeometryButton" ) );
120  buttonLayout->addWidget( mAddFeatureGeometryButton );
121  // add feature
122  mAddFeatureButton = new QToolButton( this );
123  mAddFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionNewTableRow.svg" ) ) );
124  mAddFeatureButton->setText( tr( "Add Child Feature" ) );
125  mAddFeatureButton->setToolTip( tr( "Add child feature" ) );
126  mAddFeatureButton->setObjectName( QStringLiteral( "mAddFeatureButton" ) );
127  buttonLayout->addWidget( mAddFeatureButton );
128  // duplicate feature
129  mDuplicateFeatureButton = new QToolButton( this );
130  mDuplicateFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDuplicateFeature.svg" ) ) );
131  mDuplicateFeatureButton->setText( tr( "Duplicate Child Feature" ) );
132  mDuplicateFeatureButton->setToolTip( tr( "Duplicate child feature" ) );
133  mDuplicateFeatureButton->setObjectName( QStringLiteral( "mDuplicateFeatureButton" ) );
134  buttonLayout->addWidget( mDuplicateFeatureButton );
135  // delete feature
136  mDeleteFeatureButton = new QToolButton( this );
137  mDeleteFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ) );
138  mDeleteFeatureButton->setText( tr( "Delete Child Feature" ) );
139  mDeleteFeatureButton->setToolTip( tr( "Delete child feature" ) );
140  mDeleteFeatureButton->setObjectName( QStringLiteral( "mDeleteFeatureButton" ) );
141  buttonLayout->addWidget( mDeleteFeatureButton );
142  // link feature
143  mLinkFeatureButton = new QToolButton( this );
144  mLinkFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionLink.svg" ) ) );
145  mLinkFeatureButton->setText( tr( "Link Existing Features" ) );
146  mLinkFeatureButton->setToolTip( tr( "Link existing child features" ) );
147  mLinkFeatureButton->setObjectName( QStringLiteral( "mLinkFeatureButton" ) );
148  buttonLayout->addWidget( mLinkFeatureButton );
149  // unlink feature
150  mUnlinkFeatureButton = new QToolButton( this );
151  mUnlinkFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ) );
152  mUnlinkFeatureButton->setText( tr( "Unlink Feature" ) );
153  mUnlinkFeatureButton->setToolTip( tr( "Unlink child feature" ) );
154  mUnlinkFeatureButton->setObjectName( QStringLiteral( "mUnlinkFeatureButton" ) );
155  buttonLayout->addWidget( mUnlinkFeatureButton );
156  // zoom to linked feature
157  mZoomToFeatureButton = new QToolButton( this );
158  mZoomToFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToSelected.svg" ) ) );
159  mZoomToFeatureButton->setText( tr( "Zoom To Feature" ) );
160  mZoomToFeatureButton->setToolTip( tr( "Zoom to child feature" ) );
161  mZoomToFeatureButton->setObjectName( QStringLiteral( "mZoomToFeatureButton" ) );
162  buttonLayout->addWidget( mZoomToFeatureButton );
163  // spacer
164  buttonLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding ) );
165  // form view
166  mFormViewButton = new QToolButton( this );
167  mFormViewButton->setText( tr( "Form View" ) );
168  mFormViewButton->setToolTip( tr( "Switch to form view" ) );
169  mFormViewButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPropertyItem.svg" ) ) );
170  mFormViewButton->setCheckable( true );
171  mFormViewButton->setChecked( mViewMode == QgsDualView::AttributeEditor );
172  buttonLayout->addWidget( mFormViewButton );
173  // table view
174  mTableViewButton = new QToolButton( this );
175  mTableViewButton->setText( tr( "Table View" ) );
176  mTableViewButton->setToolTip( tr( "Switch to table view" ) );
177  mTableViewButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ) );
178  mTableViewButton->setCheckable( true );
179  mTableViewButton->setChecked( mViewMode == QgsDualView::AttributeTable );
180  buttonLayout->addWidget( mTableViewButton );
181  // button group
182  mViewModeButtonGroup = new QButtonGroup( this );
183  mViewModeButtonGroup->addButton( mFormViewButton, QgsDualView::AttributeEditor );
184  mViewModeButtonGroup->addButton( mTableViewButton, QgsDualView::AttributeTable );
185 
186  // add buttons layout
187  topLayout->addLayout( buttonLayout );
188 
189  mRelationLayout = new QGridLayout();
190  mRelationLayout->setContentsMargins( 0, 0, 0, 0 );
191  topLayout->addLayout( mRelationLayout );
192 
193  mDualView = new QgsDualView( this );
194  mDualView->setView( mViewMode );
195 
196  mRelationLayout->addWidget( mDualView );
197 
198  connect( this, &QgsCollapsibleGroupBoxBasic::collapsedStateChanged, this, &QgsRelationEditorWidget::onCollapsedStateChanged );
199  connect( mViewModeButtonGroup, static_cast<void ( QButtonGroup::* )( int )>( &QButtonGroup::buttonClicked ),
200  this, static_cast<void ( QgsRelationEditorWidget::* )( int )>( &QgsRelationEditorWidget::setViewMode ) );
201  connect( mToggleEditingButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::toggleEditing );
202  connect( mSaveEditsButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::saveEdits );
203  connect( mAddFeatureButton, &QAbstractButton::clicked, this, [this]() { addFeature(); } );
204  connect( mAddFeatureGeometryButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::addFeatureGeometry );
205  connect( mDuplicateFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::duplicateFeature );
206  connect( mDeleteFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::deleteSelectedFeatures );
207  connect( mLinkFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::linkFeature );
208  connect( mUnlinkFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::unlinkSelectedFeatures );
209  connect( mZoomToFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::zoomToSelectedFeatures );
210 
211  connect( mDualView, &QgsDualView::showContextMenuExternally, this, &QgsRelationEditorWidget::showContextMenu );
212 
213  // Set initial state for add/remove etc. buttons
214  updateButtons();
215 }
216 
218 {
219  if ( mRelation.isValid() )
220  {
221  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
222  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
223  }
224 
225  mRelation = relation;
226  mFeature = feature;
227 
228  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
229  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
230 
231  updateTitle();
232 
233  QgsVectorLayer *lyr = relation.referencingLayer();
234 
235  bool canChangeAttributes = lyr->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
236  if ( canChangeAttributes && !lyr->readOnly() )
237  {
238  mToggleEditingButton->setEnabled( true );
239  updateButtons();
240  }
241  else
242  {
243  mToggleEditingButton->setEnabled( false );
244  }
245 
246  setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
247 
248  // If not yet initialized, it is not (yet) visible, so we don't load it to be faster (lazy loading)
249  // If it is already initialized, it has been set visible before and the currently shown feature is changing
250  // and the widget needs updating
251 
252  if ( mVisible )
253  {
254  QgsFeatureRequest myRequest = mRelation.getRelatedFeaturesRequest( mFeature );
255  initDualView( mRelation.referencingLayer(), myRequest );
256  }
257 }
258 
259 void QgsRelationEditorWidget::initDualView( QgsVectorLayer *layer, const QgsFeatureRequest &request )
260 {
261  QgsAttributeEditorContext ctx { mEditorContext };
262  ctx.setParentFormFeature( mFeature );
263  mDualView->init( layer, mEditorContext.mapCanvas(), request, ctx );
264  mFeatureSelectionMgr = new QgsFilteredSelectionManager( layer, request, mDualView );
265  mDualView->setFeatureSelectionManager( mFeatureSelectionMgr );
266 
267  connect( mFeatureSelectionMgr, &QgsIFeatureSelectionManager::selectionChanged, this, &QgsRelationEditorWidget::updateButtons );
268 
269  QIcon icon;
270  QString text;
271  if ( layer->geometryType() == QgsWkbTypes::PointGeometry )
272  {
273  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePoint.svg" ) );
274  text = tr( "Add Point child Feature" );
275  }
276  else if ( layer->geometryType() == QgsWkbTypes::LineGeometry )
277  {
278  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCaptureLine.svg" ) );
279  text = tr( "Add Line child Feature" );
280  }
281  else if ( layer->geometryType() == QgsWkbTypes::PolygonGeometry )
282  {
283  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePolygon.svg" ) );
284  text = tr( "Add Polygon Feature" );
285  }
286 
287  if ( text.isEmpty() || !mEditorContext.mapCanvas() || !mEditorContext.cadDockWidget() )
288  {
289  mAddFeatureGeometryButton->setVisible( false );
290  }
291  else
292  {
293  mAddFeatureGeometryButton->setIcon( icon );
294  mAddFeatureGeometryButton->setText( text );
295  mAddFeatureGeometryButton->setToolTip( text );
296  }
297 
298  updateButtons();
299 }
300 
301 void QgsRelationEditorWidget::setRelations( const QgsRelation &relation, const QgsRelation &nmrelation )
302 {
303  if ( mRelation.isValid() )
304  {
305  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
306  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
307  }
308 
309  if ( mNmRelation.isValid() )
310  {
311  disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
312  disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
313  }
314 
315  mRelation = relation;
316  mNmRelation = nmrelation;
317 
318  if ( !mRelation.isValid() )
319  return;
320 
321  mToggleEditingButton->setVisible( true );
322 
323  const auto transactionGroups = QgsProject::instance()->transactionGroups();
324  for ( auto it = transactionGroups.constBegin(); it != transactionGroups.constEnd(); ++it )
325  {
326  if ( it.value()->layers().contains( mRelation.referencingLayer() ) )
327  {
328  mToggleEditingButton->setVisible( false );
329  mSaveEditsButton->setVisible( false );
330  }
331  }
332 
333  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
334  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
335 
336  if ( mNmRelation.isValid() )
337  {
338  connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
339  connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
340  }
341 
342  updateTitle();
343 
344  QgsVectorLayer *lyr = relation.referencingLayer();
345 
346  bool canChangeAttributes = lyr->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
347  if ( canChangeAttributes && !lyr->readOnly() )
348  {
349  mToggleEditingButton->setEnabled( true );
350  updateButtons();
351  }
352  else
353  {
354  mToggleEditingButton->setEnabled( false );
355  }
356 
357  if ( mNmRelation.isValid() )
358  mZoomToFeatureButton->setVisible( mNmRelation.referencedLayer()->isSpatial() );
359  else
360  mZoomToFeatureButton->setVisible( mRelation.referencingLayer()->isSpatial() );
361 
362  setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
363 
364  updateUi();
365 }
366 
368 {
369  mEditorContext = context;
370 
371  if ( context.mapCanvas() && context.cadDockWidget() )
372  {
373  mMapToolDigitize.reset( new QgsMapToolDigitizeFeature( context.mapCanvas(), context.cadDockWidget() ) );
374  mMapToolDigitize->setButton( mAddFeatureGeometryButton );
375  }
376 }
377 
379 {
380  return mEditorContext;
381 }
382 
384 {
385  return mFeatureSelectionMgr;
386 }
387 
389 {
390  mDualView->setView( mode );
391  mViewMode = mode;
392 }
393 
394 void QgsRelationEditorWidget::setFeature( const QgsFeature &feature, bool update )
395 {
396  mFeature = feature;
397 
398  mEditorContext.setFormFeature( feature );
399 
400  if ( update )
401  updateUi();
402 }
403 
404 void QgsRelationEditorWidget::updateButtons()
405 {
406  bool editable = false;
407  bool linkable = false;
408  bool selectionNotEmpty = mFeatureSelectionMgr ? mFeatureSelectionMgr->selectedFeatureCount() : false;
409 
410  if ( mRelation.isValid() )
411  {
412  editable = mRelation.referencingLayer()->isEditable();
413  linkable = mRelation.referencingLayer()->isEditable();
414  }
415 
416  if ( mNmRelation.isValid() )
417  {
418  editable = mNmRelation.referencedLayer()->isEditable();
419  }
420 
421  mAddFeatureButton->setEnabled( editable );
422  mAddFeatureGeometryButton->setEnabled( editable );
423  mDuplicateFeatureButton->setEnabled( editable && selectionNotEmpty );
424  mLinkFeatureButton->setEnabled( linkable );
425  mDeleteFeatureButton->setEnabled( editable && selectionNotEmpty );
426  mUnlinkFeatureButton->setEnabled( linkable && selectionNotEmpty );
427 
428  mZoomToFeatureButton->setVisible(
429  mEditorContext.mapCanvas() && (
430  (
431  mNmRelation.isValid() &&
434  )
435  ||
436  (
437  mRelation.isValid() &&
440  )
441  )
442  );
443 
444  mZoomToFeatureButton->setEnabled( selectionNotEmpty );
445 
446  mToggleEditingButton->setChecked( editable );
447  mSaveEditsButton->setEnabled( editable );
448 }
449 
450 void QgsRelationEditorWidget::addFeatureGeometry()
451 {
452  QgsVectorLayer *layer = nullptr;
453  if ( mNmRelation.isValid() )
454  layer = mNmRelation.referencedLayer();
455  else
456  layer = mRelation.referencingLayer();
457 
458  mMapToolDigitize->setLayer( layer );
459 
460  // window is always on top, so we hide it to digitize without seeing it
461  window()->setVisible( false );
462  setMapTool( mMapToolDigitize );
463 
464  connect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
465  connect( mEditorContext.mapCanvas(), &QgsMapCanvas::keyPressed, this, &QgsRelationEditorWidget::onKeyPressed );
466 
467  if ( mEditorContext.mainMessageBar() )
468  {
469  QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( layer, mFeature );
470 
471  QString title = tr( "Create child feature for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString );
472  QString msg = tr( "Digitize the geometry for the new feature on layer %1. Press &lt;ESC&gt; to cancel." )
473  .arg( layer->name() );
474  mMessageBarItem = QgsMessageBar::createMessage( title, msg, this );
475  mEditorContext.mainMessageBar()->pushItem( mMessageBarItem );
476  }
477 
478 }
479 
480 void QgsRelationEditorWidget::addFeature( const QgsGeometry &geometry )
481 {
482  QgsAttributeMap keyAttrs;
483 
484  const QgsVectorLayerTools *vlTools = mEditorContext.vectorLayerTools();
485 
486  if ( mNmRelation.isValid() )
487  {
488  // n:m Relation: first let the user create a new feature on the other table
489  // and autocreate a new linking feature.
490  QgsFeature f;
491  if ( vlTools->addFeature( mNmRelation.referencedLayer(), QgsAttributeMap(), geometry, &f ) )
492  {
493  // Fields of the linking table
494  const QgsFields fields = mRelation.referencingLayer()->fields();
495 
496  // Expression context for the linking table
498 
499  QgsAttributeMap linkAttributes;
500  const auto constFieldPairs = mRelation.fieldPairs();
501  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
502  {
503  int index = fields.indexOf( fieldPair.first );
504  linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
505  }
506 
507  const auto constNmFieldPairs = mNmRelation.fieldPairs();
508  for ( const QgsRelation::FieldPair &fieldPair : constNmFieldPairs )
509  {
510  int index = fields.indexOf( fieldPair.first );
511  linkAttributes.insert( index, f.attribute( fieldPair.second ) );
512  }
513  QgsFeature linkFeature = QgsVectorLayerUtils::createFeature( mRelation.referencingLayer(), QgsGeometry(), linkAttributes, &context );
514 
515  mRelation.referencingLayer()->addFeature( linkFeature );
516 
517  updateUi();
518  }
519  }
520  else
521  {
522  QgsFields fields = mRelation.referencingLayer()->fields();
523 
524  const auto constFieldPairs = mRelation.fieldPairs();
525  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
526  {
527  keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeature.attribute( fieldPair.referencedField() ) );
528  }
529 
530  vlTools->addFeature( mDualView->masterModel()->layer(), keyAttrs, geometry );
531  }
532 }
533 
534 void QgsRelationEditorWidget::onDigitizingCompleted( const QgsFeature &feature )
535 {
536  addFeature( feature.geometry() );
537 
538  unsetMapTool();
539 }
540 
541 void QgsRelationEditorWidget::linkFeature()
542 {
543  QgsVectorLayer *layer = nullptr;
544 
545  if ( mNmRelation.isValid() )
546  layer = mNmRelation.referencedLayer();
547  else
548  layer = mRelation.referencingLayer();
549 
550  QgsFeatureSelectionDlg *selectionDlg = new QgsFeatureSelectionDlg( layer, mEditorContext, this );
551  selectionDlg->setAttribute( Qt::WA_DeleteOnClose );
552 
553  const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( mRelation.referencedLayer(), mFeature );
554  selectionDlg->setWindowTitle( tr( "Link existing child features for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString ) );
555 
556  connect( selectionDlg, &QDialog::accepted, this, &QgsRelationEditorWidget::onLinkFeatureDlgAccepted );
557  selectionDlg->show();
558 }
559 
560 void QgsRelationEditorWidget::onLinkFeatureDlgAccepted()
561 {
562  QgsFeatureSelectionDlg *selectionDlg = qobject_cast<QgsFeatureSelectionDlg *>( sender() );
563  if ( mNmRelation.isValid() )
564  {
565  QgsFeatureIterator it = mNmRelation.referencedLayer()->getFeatures(
567  .setFilterFids( selectionDlg->selectedFeatures() )
568  .setSubsetOfAttributes( mNmRelation.referencedFields() ) );
569 
570  QgsFeature relatedFeature;
571 
572  QgsFeatureList newFeatures;
573 
574  // Fields of the linking table
575  const QgsFields fields = mRelation.referencingLayer()->fields();
576 
577  // Expression context for the linking table
579 
580  QgsAttributeMap linkAttributes;
581  const auto constFieldPairs = mRelation.fieldPairs();
582  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
583  {
584  int index = fields.indexOf( fieldPair.first );
585  linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
586  }
587 
588  while ( it.nextFeature( relatedFeature ) )
589  {
590  const auto constFieldPairs = mNmRelation.fieldPairs();
591  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
592  {
593  int index = fields.indexOf( fieldPair.first );
594  linkAttributes.insert( index, relatedFeature.attribute( fieldPair.second ) );
595  }
596  const QgsFeature linkFeature = QgsVectorLayerUtils::createFeature( mRelation.referencingLayer(), QgsGeometry(), linkAttributes, &context );
597 
598  newFeatures << linkFeature;
599  }
600 
601  mRelation.referencingLayer()->addFeatures( newFeatures );
602  QgsFeatureIds ids;
603  const auto constNewFeatures = newFeatures;
604  for ( const QgsFeature &f : constNewFeatures )
605  ids << f.id();
606  mRelation.referencingLayer()->selectByIds( ids );
607  }
608  else
609  {
610  QMap<int, QVariant> keys;
611  const auto constFieldPairs = mRelation.fieldPairs();
612  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
613  {
614  int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
615  QVariant val = mFeature.attribute( fieldPair.referencedField() );
616  keys.insert( idx, val );
617  }
618 
619  const auto constSelectedFeatures = selectionDlg->selectedFeatures();
620  for ( QgsFeatureId fid : constSelectedFeatures )
621  {
622  QMapIterator<int, QVariant> it( keys );
623  while ( it.hasNext() )
624  {
625  it.next();
626  mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), it.value() );
627  }
628  }
629  }
630 
631  updateUi();
632 }
633 
634 void QgsRelationEditorWidget::duplicateFeature()
635 {
636  QgsVectorLayer *layer = mRelation.referencingLayer();
637 
638  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterFids( mFeatureSelectionMgr->selectedFeatureIds() ) );
639  QgsFeature f;
640  while ( fit.nextFeature( f ) )
641  {
642  QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicatedFeatureContext;
643  QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), 0, duplicatedFeatureContext );
644  }
645 }
646 
647 void QgsRelationEditorWidget::deleteFeature( const QgsFeatureId featureid )
648 {
649  deleteFeatures( QgsFeatureIds() << featureid );
650 }
651 
652 void QgsRelationEditorWidget::deleteSelectedFeatures()
653 {
654  QgsFeatureIds selectedFids = mFeatureSelectionMgr->selectedFeatureIds();
655  deleteFeatures( selectedFids );
656 }
657 
658 void QgsRelationEditorWidget::deleteFeatures( const QgsFeatureIds &featureids )
659 {
660  bool deleteFeatures = true;
661 
662  QgsVectorLayer *layer;
663  if ( mNmRelation.isValid() )
664  {
665  layer = mNmRelation.referencedLayer();
666 
667  // When deleting a linked feature within an N:M relation,
668  // check if the feature is linked to more than just one feature.
669  // In case it is linked more than just once, ask the user for confirmation
670  // as it is likely he was not aware of the implications and might delete
671  // there may be several linking entries deleted along.
672 
673  QgsFeatureRequest deletedFeaturesRequest;
674  deletedFeaturesRequest.setFilterFids( featureids );
675  deletedFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
676  deletedFeaturesRequest.setSubsetOfAttributes( QgsAttributeList() << mNmRelation.referencedFields().first() );
677 
678  QgsFeatureIterator deletedFeatures = layer->getFeatures( deletedFeaturesRequest );
679  QStringList deletedFeaturesPks;
681  while ( deletedFeatures.nextFeature( feature ) )
682  {
683  deletedFeaturesPks.append( QgsExpression::quotedValue( feature.attribute( mNmRelation.referencedFields().first() ) ) );
684  }
685 
686  QgsFeatureRequest linkingFeaturesRequest;
687  linkingFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
688  linkingFeaturesRequest.setNoAttributes();
689 
690  QString linkingFeaturesRequestExpression;
691  if ( !deletedFeaturesPks.empty() )
692  {
693  linkingFeaturesRequestExpression = QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( mNmRelation.fieldPairs().first().first ), deletedFeaturesPks.join( ',' ) );
694  linkingFeaturesRequest.setFilterExpression( linkingFeaturesRequestExpression );
695 
696  QgsFeatureIterator relatedLinkingFeatures = mNmRelation.referencingLayer()->getFeatures( linkingFeaturesRequest );
697 
698  int relatedLinkingFeaturesCount = 0;
699  while ( relatedLinkingFeatures.nextFeature( feature ) )
700  {
701  relatedLinkingFeaturesCount++;
702  }
703 
704  if ( deletedFeaturesPks.size() == 1 && relatedLinkingFeaturesCount > 1 )
705  {
706  QMessageBox messageBox( QMessageBox::Question, tr( "Really delete entry?" ), tr( "The entry on %1 is still linked to %2 features on %3. Do you want to delete it?" ).arg( mNmRelation.referencedLayer()->name(), QString::number( relatedLinkingFeaturesCount ), mRelation.referencedLayer()->name() ), QMessageBox::NoButton, this );
707  messageBox.addButton( QMessageBox::Cancel );
708  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
709 
710  messageBox.exec();
711  if ( messageBox.clickedButton() != deleteButton )
712  deleteFeatures = false;
713  }
714  else if ( deletedFeaturesPks.size() > 1 && relatedLinkingFeaturesCount > deletedFeaturesPks.size() )
715  {
716  QMessageBox messageBox( QMessageBox::Question, tr( "Really delete entries?" ), tr( "The %1 entries on %2 are still linked to %3 features on %4. Do you want to delete them?" ).arg( QString::number( deletedFeaturesPks.size() ), mNmRelation.referencedLayer()->name(), QString::number( relatedLinkingFeaturesCount ), mRelation.referencedLayer()->name() ), QMessageBox::NoButton, this );
717  messageBox.addButton( QMessageBox::Cancel );
718  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
719 
720  messageBox.exec();
721  if ( messageBox.clickedButton() != deleteButton )
722  deleteFeatures = false;
723  }
724  }
725  }
726  else
727  {
728  layer = mRelation.referencingLayer();
729  }
730 
732  if ( QgsVectorLayerUtils::impactsCascadeFeatures( layer, featureids, QgsProject::instance(), infoContext ) )
733  {
734  QString childrenInfo;
735  int childrenCount = 0;
736  const auto infoContextLayers = infoContext.layers();
737  for ( QgsVectorLayer *chl : infoContextLayers )
738  {
739  childrenCount += infoContext.duplicatedFeatures( chl ).size();
740  childrenInfo += ( tr( "%1 feature(s) on layer \"%2\", " ).arg( infoContext.duplicatedFeatures( chl ).size() ).arg( chl->name() ) );
741  }
742 
743  // for extra safety to make sure we know that the delete can have impact on children and joins
744  int res = QMessageBox::question( this, tr( "Delete at least %1 feature(s) on other layer(s)" ).arg( childrenCount ),
745  tr( "Delete %1 feature(s) on layer \"%2\", %3 as well\nand all of its other descendants.\nDelete these features?" ).arg( featureids.count() ).arg( layer->name() ).arg( childrenInfo ),
746  QMessageBox::Yes | QMessageBox::No );
747  if ( res != QMessageBox::Yes )
748  deleteFeatures = false;
749  }
750 
751  if ( deleteFeatures )
752  {
754  layer->deleteFeatures( featureids, &context );
755  const auto contextLayers = context.handledLayers();
756  if ( contextLayers.size() > 1 )
757  {
758  int deletedCount = 0;
759  QString feedbackMessage;
760  for ( QgsVectorLayer *contextLayer : contextLayers )
761  {
762  feedbackMessage += tr( "%1 on layer %2. " ).arg( context.handledFeatures( contextLayer ).size() ).arg( contextLayer->name() );
763  deletedCount += context.handledFeatures( contextLayer ).size();
764  }
765  mEditorContext.mainMessageBar()->pushMessage( tr( "%1 features deleted: %2" ).arg( deletedCount ).arg( feedbackMessage ), Qgis::Success );
766  }
767 
768  updateUi();
769  }
770 }
771 
772 void QgsRelationEditorWidget::unlinkFeature( const QgsFeatureId featureid )
773 {
774  unlinkFeatures( QgsFeatureIds() << featureid );
775 }
776 
777 void QgsRelationEditorWidget::unlinkSelectedFeatures()
778 {
779  unlinkFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
780 }
781 
782 void QgsRelationEditorWidget::zoomToSelectedFeatures()
783 {
784  QgsMapCanvas *c = mEditorContext.mapCanvas();
785  if ( !c )
786  return;
787 
788  c->zoomToFeatureIds(
789  mNmRelation.isValid() ? mNmRelation.referencedLayer() : mRelation.referencingLayer(),
790  mFeatureSelectionMgr->selectedFeatureIds()
791  );
792 }
793 
794 void QgsRelationEditorWidget::unlinkFeatures( const QgsFeatureIds &featureids )
795 {
796  if ( mNmRelation.isValid() )
797  {
798  QgsFeatureIterator selectedIterator = mNmRelation.referencedLayer()->getFeatures(
800  .setFilterFids( featureids )
801  .setSubsetOfAttributes( mNmRelation.referencedFields() ) );
802 
803  QgsFeature f;
804 
805  QStringList filters;
806 
807  while ( selectedIterator.nextFeature( f ) )
808  {
809  filters << '(' + mNmRelation.getRelatedFeaturesRequest( f ).filterExpression()->expression() + ')';
810  }
811 
812  QString filter = QStringLiteral( "(%1) AND (%2)" ).arg(
813  mRelation.getRelatedFeaturesRequest( mFeature ).filterExpression()->expression(),
814  filters.join( QStringLiteral( " OR " ) ) );
815 
816  QgsFeatureIterator linkedIterator = mRelation.referencingLayer()->getFeatures( QgsFeatureRequest()
817  .setNoAttributes()
818  .setFilterExpression( filter ) );
819 
820  QgsFeatureIds fids;
821 
822  while ( linkedIterator.nextFeature( f ) )
823  {
824  fids << f.id();
825  QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 );
826  }
827 
828  mRelation.referencingLayer()->deleteFeatures( fids );
829 
830  updateUi();
831  }
832  else
833  {
834  QMap<int, QgsField> keyFields;
835  const auto constFieldPairs = mRelation.fieldPairs();
836  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
837  {
838  int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
839  if ( idx < 0 )
840  {
841  QgsDebugMsg( QStringLiteral( "referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
842  return;
843  }
844  QgsField fld = mRelation.referencingLayer()->fields().at( idx );
845  keyFields.insert( idx, fld );
846  }
847 
848  const auto constFeatureids = featureids;
849  for ( QgsFeatureId fid : constFeatureids )
850  {
851  QMapIterator<int, QgsField> it( keyFields );
852  while ( it.hasNext() )
853  {
854  it.next();
855  mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QVariant( it.value().type() ) );
856  }
857  }
858  }
859 }
860 
861 void QgsRelationEditorWidget::toggleEditing( bool state )
862 {
863  if ( state )
864  {
865  mEditorContext.vectorLayerTools()->startEditing( mRelation.referencingLayer() );
866  if ( mNmRelation.isValid() )
867  mEditorContext.vectorLayerTools()->startEditing( mNmRelation.referencedLayer() );
868  }
869  else
870  {
871  mEditorContext.vectorLayerTools()->stopEditing( mRelation.referencingLayer() );
872  if ( mNmRelation.isValid() )
873  mEditorContext.vectorLayerTools()->stopEditing( mNmRelation.referencedLayer() );
874  }
875 }
876 
877 void QgsRelationEditorWidget::saveEdits()
878 {
879  mEditorContext.vectorLayerTools()->saveEdits( mRelation.referencingLayer() );
880  if ( mNmRelation.isValid() )
881  mEditorContext.vectorLayerTools()->saveEdits( mNmRelation.referencedLayer() );
882 }
883 
884 void QgsRelationEditorWidget::onCollapsedStateChanged( bool collapsed )
885 {
886  if ( !collapsed )
887  {
888  mVisible = true;
889  updateUi();
890  }
891 }
892 
893 void QgsRelationEditorWidget::updateUi()
894 {
895  // If not yet initialized, it is not (yet) visible, so we don't load it to be faster (lazy loading)
896  // If it is already initialized, it has been set visible before and the currently shown feature is changing
897  // and the widget needs updating
898 
899  if ( mVisible )
900  {
901  QgsFeatureRequest myRequest = mRelation.getRelatedFeaturesRequest( mFeature );
902 
903  if ( mNmRelation.isValid() )
904  {
905  QgsFeatureIterator it = mRelation.referencingLayer()->getFeatures( myRequest );
906 
907  QgsFeature fet;
908 
909  QStringList filters;
910 
911  while ( it.nextFeature( fet ) )
912  {
913  QString filter = mNmRelation.getReferencedFeatureRequest( fet ).filterExpression()->expression();
914  filters << filter.prepend( '(' ).append( ')' );
915  }
916 
917  QgsFeatureRequest nmRequest;
918 
919  nmRequest.setFilterExpression( filters.join( QStringLiteral( " OR " ) ) );
920 
921  initDualView( mNmRelation.referencedLayer(), nmRequest );
922  }
923  else
924  {
925  initDualView( mRelation.referencingLayer(), myRequest );
926  }
927  }
928 }
929 
931 {
932  return mLinkFeatureButton->isVisible();
933 }
934 
936 {
937  mLinkFeatureButton->setVisible( showLinkButton );
938 }
939 
941 {
942  return mUnlinkFeatureButton->isVisible();
943 }
944 
946 {
947  mSaveEditsButton->setVisible( showChildEdits );
948 }
949 
951 {
952  return mSaveEditsButton->isVisible();
953 }
954 
955 void QgsRelationEditorWidget::setShowUnlinkButton( bool showUnlinkButton )
956 {
957  mUnlinkFeatureButton->setVisible( showUnlinkButton );
958 }
959 
960 void QgsRelationEditorWidget::parentFormValueChanged( const QString &attribute, const QVariant &newValue )
961 {
962  mDualView->parentFormValueChanged( attribute, newValue );
963 }
964 
966 {
967  return mShowLabel;
968 }
969 
971 {
972  mShowLabel = showLabel;
973 
974  updateTitle();
975 }
976 
977 void QgsRelationEditorWidget::showContextMenu( QgsActionMenu *menu, const QgsFeatureId fid )
978 {
979  if ( mRelation.referencingLayer()->isEditable() )
980  {
981  QAction *qAction = nullptr;
982 
983  qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ), tr( "Delete Feature" ) );
984  connect( qAction, &QAction::triggered, this, [this, fid]() { deleteFeature( fid ); } );
985 
986  qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ), tr( "Unlink Feature" ) );
987  connect( qAction, &QAction::triggered, this, [this, fid]() { unlinkFeature( fid ); } );
988  }
989 }
990 
991 void QgsRelationEditorWidget::setMapTool( QgsMapTool *mapTool )
992 {
993  QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
994 
995  mapCanvas->setMapTool( mapTool );
996  mapCanvas->window()->raise();
997  mapCanvas->activateWindow();
998  mapCanvas->setFocus();
999  connect( mapTool, &QgsMapTool::deactivated, this, &QgsRelationEditorWidget::mapToolDeactivated );
1000 }
1001 
1002 void QgsRelationEditorWidget::unsetMapTool()
1003 {
1004  QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
1005 
1006  // this will call mapToolDeactivated
1007  mapCanvas->unsetMapTool( mMapToolDigitize );
1008 
1009  disconnect( mapCanvas, &QgsMapCanvas::keyPressed, this, &QgsRelationEditorWidget::onKeyPressed );
1010  disconnect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
1011 }
1012 
1013 void QgsRelationEditorWidget::updateTitle()
1014 {
1015  if ( mShowLabel && mRelation.isValid() )
1016  setTitle( mRelation.name() );
1017  else
1018  setTitle( QString() );
1019 }
1020 
1022 {
1023  return mFeature;
1024 }
1025 
1026 void QgsRelationEditorWidget::onKeyPressed( QKeyEvent *e )
1027 {
1028  if ( e->key() == Qt::Key_Escape )
1029  {
1030  unsetMapTool();
1031  }
1032 }
1033 
1034 void QgsRelationEditorWidget::mapToolDeactivated()
1035 {
1036  window()->setVisible( true );
1037  window()->raise();
1038  window()->activateWindow();
1039 
1040  if ( mEditorContext.mainMessageBar() && mMessageBarItem )
1041  {
1042  mEditorContext.mainMessageBar()->popWidget( mMessageBarItem );
1043  }
1044  mMessageBarItem = nullptr;
1045 }
QgsAttributeEditorContext::mapCanvas
QgsMapCanvas * mapCanvas() const
Returns the associated map canvas (e.g.
Definition: qgsattributeeditorcontext.h:139
QgsFeatureRequest::NoGeometry
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition: qgsfeaturerequest.h:107
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:993
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:369
QgsVectorLayer::addFeatures
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a list of features to the sink.
Definition: qgsvectorlayer.cpp:3484
QgsAttributeEditorContext::setParentFormFeature
void setParentFormFeature(const QgsFeature &feature)
Sets the feature of the currently edited parent form.
Definition: qgsattributeeditorcontext.h:257
qgsexpressioncontextutils.h
QgsVectorLayerTools::addFeature
virtual bool addFeature(QgsVectorLayer *layer, const QgsAttributeMap &defaultValues=QgsAttributeMap(), const QgsGeometry &defaultGeometry=QgsGeometry(), QgsFeature *feature=nullptr) const =0
This method should/will be called, whenever a new feature will be added to the layer.
QObjectUniquePtr::reset
void reset(T *p=nullptr)
Will reset the managed pointer to p.
Definition: qobjectuniqueptr.h:176
QgsVectorLayer::readOnly
bool readOnly
Definition: qgsvectorlayer.h:393
QgsAttributeEditorContext::cadDockWidget
QgsAdvancedDigitizingDockWidget * cadDockWidget() const
Returns the associated CAD dock widget (e.g.
Definition: qgsattributeeditorcontext.h:155
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
qgsmessagebaritem.h
QgsRelationEditorWidget::setFeature
void setFeature(const QgsFeature &feature, bool update=true)
Sets the feature being edited and updates the UI unless update is set to false.
Definition: qgsrelationeditorwidget.cpp:394
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:627
QgsRelationEditorWidget::parentFormValueChanged
void parentFormValueChanged(const QString &attribute, const QVariant &newValue)
Called when an attribute value in the parent widget has changed to newValue.
Definition: qgsrelationeditorwidget.cpp:960
QgsRelationEditorWidget::feature
QgsFeature feature() const
Returns the widget's current feature.
Definition: qgsrelationeditorwidget.cpp:1021
QgsVectorLayerUtils::impactsCascadeFeatures
static bool impactsCascadeFeatures(const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context)
Definition: qgsvectorlayerutils.cpp:973
qgsmapcanvas.h
QgsWkbTypes::NullGeometry
@ NullGeometry
Definition: qgswkbtypes.h:145
QgsVectorLayerUtils::duplicateFeature
static QgsFeature duplicateFeature(QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext)
Duplicates a feature and it's children (one level deep).
Definition: qgsvectorlayerutils.cpp:623
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsexpression.h
QgsVectorLayer::DeleteContext
Context for cascade delete features.
Definition: qgsvectorlayer.h:510
QgsRelation::name
QString name
Definition: qgsrelation.h:48
QgsDualView::setView
void setView(ViewMode view)
Change the current view mode.
Definition: qgsdualview.cpp:272
qgsfeatureiterator.h
QgsFields
Definition: qgsfields.h:44
QgsProject::transactionGroups
QMap< QPair< QString, QString >, QgsTransactionGroup * > transactionGroups()
Map of transaction groups.
Definition: qgsproject.cpp:3103
QgsRelationEditorWidget::showLinkButton
bool showLinkButton() const
Determines if the "link feature" button should be shown.
Definition: qgsrelationeditorwidget.cpp:930
QgsMapCanvas
Definition: qgsmapcanvas.h:83
qgsfeature.h
QgsRelationEditorWidget
Definition: qgsrelationeditorwidget.h:83
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsVectorLayerTools
Definition: qgsvectorlayertools.h:39
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
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:3591
QgsDualView::init
void init(QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request=QgsFeatureRequest(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), bool loadFeatures=true)
Has to be called to initialize the dual view.
Definition: qgsdualview.cpp:119
Qgis::Success
@ Success
Definition: qgis.h:106
QgsRelation::referencedFields
QgsAttributeList referencedFields() const
Returns a list of attributes used to form the referenced fields (most likely primary key) on the refe...
Definition: qgsrelation.cpp:311
QgsVectorLayer::selectByIds
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, QgsVectorLayer::SelectBehavior behavior=QgsVectorLayer::SetSelection)
Selects matching features using a list of feature IDs.
Definition: qgsvectorlayer.cpp:523
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:190
QgsDualView
Definition: qgsdualview.h:41
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
FID_TO_STRING
#define FID_TO_STRING(fid)
Definition: qgsfeatureid.h:30
QgsDualView::AttributeTable
@ AttributeTable
Shows the features and attributes in a table layout.
Definition: qgsdualview.h:58
QgsAttributeList
QList< int > QgsAttributeList
Definition: qgsfield.h:26
QgsCollapsibleGroupBox
Definition: qgscollapsiblegroupbox.h:178
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:160
qgsrelationeditorwidget.h
QgsVectorLayer::changeAttributeValue
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
Definition: qgsvectorlayer.cpp:2965
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:143
QgsVectorLayer::isEditable
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
Definition: qgsvectorlayer.cpp:3586
QgsRelation::referencingLayer
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:46
QgsFeatureRequest::setFilterExpression
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Definition: qgsfeaturerequest.cpp:129
qgsapplication.h
QgsDualView::masterModel
QgsAttributeTableModel * masterModel() const
Returns the model which has the information about all features (not only filtered)
Definition: qgsdualview.h:182
QgsMapTool
Definition: qgsmaptool.h:63
QgsExpression::quotedValue
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
Definition: qgsexpression.cpp:79
qgsmaptooldigitizefeature.h
QgsRelationEditorWidget::QgsRelationEditorWidget
QgsRelationEditorWidget(QWidget *parent=nullptr)
Definition: qgsrelationeditorwidget.cpp:91
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3280
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
QgsVectorDataProvider::capabilities
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
Definition: qgsvectordataprovider.cpp:191
QgsVectorLayer::editingStarted
void editingStarted()
Emitted when editing on this layer has started.
QgsVectorLayerUtils::QgsDuplicateFeatureContext::layers
QList< QgsVectorLayer * > layers() const
Returns all the layers on which features have been duplicated.
Definition: qgsvectorlayerutils.cpp:800
QgsMapToolDigitizeFeature::digitizingCompleted
void digitizingCompleted(const QgsFeature &feature)
Emitted whenever the digitizing has been successfully completed.
qgsvectorlayertools.h
qgsvectorlayerselectionmanager.h
QgsRelationEditorWidget::setViewMode
void setViewMode(QgsDualView::ViewMode mode)
Define the view mode for the dual view.
Definition: qgsrelationeditorwidget.cpp:388
QgsVectorLayer::selectionChanged
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
QgsRelationEditorWidget::showLabel
bool showLabel
Definition: qgsrelationeditorwidget.h:99
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:365
QgsVectorLayerTools::saveEdits
virtual bool saveEdits(QgsVectorLayer *layer) const =0
Should be called, when the features should be committed but the editing session is not ended.
QgsRelation::referencedLayer
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:47
QgsRelationEditorWidget::setShowUnlinkButton
void setShowUnlinkButton(bool showUnlinkButton)
Determines if the "unlink feature" button should be shown.
Definition: qgsrelationeditorwidget.cpp:955
QgsMessageBar::pushItem
void pushItem(QgsMessageBarItem *item)
Display a message item on the bar, after hiding the currently visible one and putting it in a stack.
Definition: qgsmessagebar.cpp:274
QgsVectorLayer::selectedFeatureIds
const Q_INVOKABLE QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Definition: qgsvectorlayer.cpp:3433
QgsFeatureRequest::filterExpression
QgsExpression * filterExpression() const
Returns the filter expression if set.
Definition: qgsfeaturerequest.h:425
QgsVectorLayerUtils::QgsDuplicateFeatureContext
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds do list all the duplicated features.
Definition: qgsvectorlayerutils.h:46
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:65
qgsvectordataprovider.h
QgsFeatureList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:572
QgsAttributeMap
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QgsRelationEditorWidget::setShowLinkButton
void setShowLinkButton(bool showLinkButton)
Determines if the "link feature" button should be shown.
Definition: qgsrelationeditorwidget.cpp:935
qgsvectorlayerutils.h
QgsActionMenu
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
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QgsRelationEditorWidget::setShowSaveChildEditsButton
void setShowSaveChildEditsButton(bool showChildEdits)
Determines if the "Save child layer edits" button should be shown.
Definition: qgsrelationeditorwidget.cpp:945
QgsFeatureRequest::setFilterFids
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
Definition: qgsfeaturerequest.cpp:110
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:228
qgsmessagebar.h
QgsAttributeTableModel::layer
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
Definition: qgsattributetablemodel.h:168
QgsVectorLayerSelectionManager
Definition: qgsvectorlayerselectionmanager.h:32
QgsMapTool::setButton
void setButton(QAbstractButton *button)
Use this to associate a button to this maptool.
Definition: qgsmaptool.cpp:139
qgsrelation.h
QgsMapCanvas::setMapTool
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
Definition: qgsmapcanvas.cpp:1975
QgsFeatureRequest::setNoAttributes
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
Definition: qgsfeaturerequest.cpp:197
QgsFeatureIds
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
QgsRelation::FieldPair
Definition: qgsrelation.h:74
QgsRelationEditorWidget::showSaveChildEditsButton
bool showSaveChildEditsButton() const
Determines if the "Save child layer edits" button should be shown.
Definition: qgsrelationeditorwidget.cpp:950
QgsDualView::ViewMode
ViewMode
The view modes, in which this widget can present information.
Definition: qgsdualview.h:52
QgsVectorLayerUtils::createFeature
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
Definition: qgsvectorlayerutils.cpp:475
QgsRelation::fieldPairs
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
Definition: qgsrelation.cpp:306
QgsVectorLayerSelectionManager::selectedFeatureCount
int selectedFeatureCount() override
Returns the number of features that are selected in this layer.
Definition: qgsvectorlayerselectionmanager.cpp:27
QgsRelationEditorWidget::editorContext
QgsAttributeEditorContext editorContext() const
Returns the attribute editor context.
Definition: qgsrelationeditorwidget.cpp:378
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:142
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:141
QgsVectorLayer::editingStopped
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
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:205
QgsRelationEditorWidget::setRelations
void setRelations(const QgsRelation &relation, const QgsRelation &nmrelation)
Set the relation(s) for this widget If only one relation is set, it will act as a simple 1:N relation...
Definition: qgsrelationeditorwidget.cpp:301
QgsRelationEditorWidget::setShowLabel
void setShowLabel(bool showLabel)
Defines if a title label should be shown for this widget.
Definition: qgsrelationeditorwidget.cpp:970
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
QgsVectorLayer::deleteFeatures
bool deleteFeatures(const QgsFeatureIds &fids, DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it)
Definition: qgsvectorlayer.cpp:3264
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
QgsGeometry
Definition: qgsgeometry.h:122
QgsRelationEditorWidget::setRelationFeature
void setRelationFeature(const QgsRelation &relation, const QgsFeature &feature)
Sets the relation and the feature.
Definition: qgsrelationeditorwidget.cpp:217
QgsVectorDataProvider::ChangeAttributeValues
@ ChangeAttributeValues
Allows modification of attribute values.
Definition: qgsvectordataprovider.h:77
QgsVectorLayer
Definition: qgsvectorlayer.h:385
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:739
QgsVectorLayerTools::stopEditing
virtual bool stopEditing(QgsVectorLayer *layer, bool allowCancel=true) const =0
Will be called, when an editing session is ended and the features should be committed.
QgsRelation::isValid
bool isValid
Definition: qgsrelation.h:49
QgsCollapsibleGroupBoxBasic::collapsedStateChanged
void collapsedStateChanged(bool collapsed)
Signal emitted when groupbox collapsed/expanded state is changed, and when first shown.
QgsDualView::setFeatureSelectionManager
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
Set the feature selection model.
Definition: qgsdualview.cpp:1138
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:85
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:144
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:65
QgsMapCanvas::keyPressed
void keyPressed(QKeyEvent *e)
Emit key press event.
QgsRelationEditorWidget::featureSelectionManager
QgsIFeatureSelectionManager * featureSelectionManager()
The feature selection manager is responsible for the selected features which are currently being edit...
Definition: qgsrelationeditorwidget.cpp:383
QgsMapCanvas::unsetMapTool
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
Definition: qgsmapcanvas.cpp:2015
QgsRelation
Definition: qgsrelation.h:41
QgsRelationEditorWidget::setEditorContext
void setEditorContext(const QgsAttributeEditorContext &context)
Sets the editor context.
Definition: qgsrelationeditorwidget.cpp:367
qgsdistancearea.h
QgsFeature
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.
qgsfeatureselectiondlg.h
QgsVectorLayer::getFeature
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
Definition: qgsvectorlayer.h:1183
QgsIFeatureSelectionManager
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:363
qgslogger.h
QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicatedFeatures
QgsFeatureIds duplicatedFeatures(QgsVectorLayer *layer) const
Returns the duplicated features in the given layer.
Definition: qgsvectorlayerutils.cpp:809
QgsRelationEditorWidget::showUnlinkButton
bool showUnlinkButton() const
Determines if the "unlink feature" button should be shown.
Definition: qgsrelationeditorwidget.cpp:940
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:324
QgsVectorLayer::createExpressionContext
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgsvectorlayer.cpp:4933
QgsFields::at
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
QgsAttributeEditorContext
Definition: qgsattributeeditorcontext.h:40
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
QgsVectorLayer::geometryType
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Definition: qgsvectorlayer.cpp:659
QgsVectorLayer::addFeature
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
Definition: qgsvectorlayer.cpp:1011
QgsCollapsibleGroupBoxBasic::collapsed
bool collapsed
The collapsed state of this group box.
Definition: qgscollapsiblegroupbox.h:79
QgsAttributeEditorContext::mainMessageBar
QgsMessageBar * mainMessageBar()
Returns the main message bar.
Definition: qgsattributeeditorcontext.h:291
QgsVectorLayerTools::startEditing
virtual bool startEditing(QgsVectorLayer *layer) const =0
This will be called, whenever a vector layer should be switched to edit mode.
QgsFeatureRequest::setFlags
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Definition: qgsfeaturerequest.cpp:184
QgsExpression::expression
QString expression() const
Returns the original, unmodified expression string.
Definition: qgsexpression.cpp:57
QgsVectorLayerSelectionManager::selectedFeatureIds
const QgsFeatureIds & selectedFeatureIds() const override
Returns reference to identifiers of selected features.
Definition: qgsvectorlayerselectionmanager.cpp:47
qgsproject.h
QgsFields::indexFromName
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
QgsAttributeEditorContext::vectorLayerTools
const QgsVectorLayerTools * vectorLayerTools() const
Returns the associated vector layer tools.
Definition: qgsattributeeditorcontext.h:171
QgsMessageBar::pushMessage
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::Info, int duration=5)
A convenience method for pushing a message with the specified text to the bar.
Definition: qgsmessagebar.cpp:379
qgsgenericfeatureselectionmanager.h
QgsAttributeEditorContext::setFormFeature
void setFormFeature(const QgsFeature &feature)
Set current feature for the currently edited form or table row.
Definition: qgsattributeeditorcontext.h:243
QgsMapTool::deactivated
void deactivated()
signal emitted once the map tool is deactivated
QgsFields::indexOf
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
QgsFeatureId
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
QgsVectorLayerUtils::getFeatureDisplayString
static QString getFeatureDisplayString(const QgsVectorLayer *layer, const QgsFeature &feature)
Definition: qgsvectorlayerutils.cpp:961
QgsField
Definition: qgsfield.h:49