QGIS API Documentation  3.13.0-Master (788156190c)
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  if ( mShowLabel )
232  setTitle( relation.name() );
233 
234  QgsVectorLayer *lyr = relation.referencingLayer();
235 
236  bool canChangeAttributes = lyr->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
237  if ( canChangeAttributes && !lyr->readOnly() )
238  {
239  mToggleEditingButton->setEnabled( true );
240  updateButtons();
241  }
242  else
243  {
244  mToggleEditingButton->setEnabled( false );
245  }
246 
247  setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
248 
249  // If not yet initialized, it is not (yet) visible, so we don't load it to be faster (lazy loading)
250  // If it is already initialized, it has been set visible before and the currently shown feature is changing
251  // and the widget needs updating
252 
253  if ( mVisible )
254  {
255  QgsFeatureRequest myRequest = mRelation.getRelatedFeaturesRequest( mFeature );
256  initDualView( mRelation.referencingLayer(), myRequest );
257  }
258 }
259 
260 void QgsRelationEditorWidget::initDualView( QgsVectorLayer *layer, const QgsFeatureRequest &request )
261 {
262  QgsAttributeEditorContext ctx { mEditorContext };
263  ctx.setParentFormFeature( mFeature );
264  mDualView->init( layer, mEditorContext.mapCanvas(), request, ctx );
265  mFeatureSelectionMgr = new QgsFilteredSelectionManager( layer, request, mDualView );
266  mDualView->setFeatureSelectionManager( mFeatureSelectionMgr );
267 
268  connect( mFeatureSelectionMgr, &QgsIFeatureSelectionManager::selectionChanged, this, &QgsRelationEditorWidget::updateButtons );
269 
270  QIcon icon;
271  QString text;
272  if ( layer->geometryType() == QgsWkbTypes::PointGeometry )
273  {
274  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePoint.svg" ) );
275  text = tr( "Add Point child Feature" );
276  }
277  else if ( layer->geometryType() == QgsWkbTypes::LineGeometry )
278  {
279  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCaptureLine.svg" ) );
280  text = tr( "Add Line child Feature" );
281  }
282  else if ( layer->geometryType() == QgsWkbTypes::PolygonGeometry )
283  {
284  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePolygon.svg" ) );
285  text = tr( "Add Polygon Feature" );
286  }
287 
288  if ( text.isEmpty() || !mEditorContext.mapCanvas() || !mEditorContext.cadDockWidget() )
289  {
290  mAddFeatureGeometryButton->setVisible( false );
291  }
292  else
293  {
294  mAddFeatureGeometryButton->setIcon( icon );
295  mAddFeatureGeometryButton->setText( text );
296  mAddFeatureGeometryButton->setToolTip( text );
297  }
298 
299  updateButtons();
300 }
301 
302 void QgsRelationEditorWidget::setRelations( const QgsRelation &relation, const QgsRelation &nmrelation )
303 {
304  if ( mRelation.isValid() )
305  {
306  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
307  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
308  }
309 
310  if ( mNmRelation.isValid() )
311  {
312  disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
313  disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
314  }
315 
316  mRelation = relation;
317  mNmRelation = nmrelation;
318 
319  if ( !mRelation.isValid() )
320  return;
321 
322  mToggleEditingButton->setVisible( true );
323 
324  const auto transactionGroups = QgsProject::instance()->transactionGroups();
325  for ( auto it = transactionGroups.constBegin(); it != transactionGroups.constEnd(); ++it )
326  {
327  if ( it.value()->layers().contains( mRelation.referencingLayer() ) )
328  {
329  mToggleEditingButton->setVisible( false );
330  mSaveEditsButton->setVisible( false );
331  }
332  }
333 
334  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
335  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
336 
337  if ( mNmRelation.isValid() )
338  {
339  connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
340  connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
341  }
342 
343  setTitle( relation.name() );
344 
345  QgsVectorLayer *lyr = relation.referencingLayer();
346 
347  bool canChangeAttributes = lyr->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
348  if ( canChangeAttributes && !lyr->readOnly() )
349  {
350  mToggleEditingButton->setEnabled( true );
351  updateButtons();
352  }
353  else
354  {
355  mToggleEditingButton->setEnabled( false );
356  }
357 
358  if ( mNmRelation.isValid() )
359  mZoomToFeatureButton->setVisible( mNmRelation.referencedLayer()->isSpatial() );
360  else
361  mZoomToFeatureButton->setVisible( mRelation.referencingLayer()->isSpatial() );
362 
363  setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
364 
365  updateUi();
366 }
367 
369 {
370  mEditorContext = context;
371 
372  if ( context.mapCanvas() && context.cadDockWidget() )
373  {
374  mMapToolDigitize.reset( new QgsMapToolDigitizeFeature( context.mapCanvas(), context.cadDockWidget() ) );
375  mMapToolDigitize->setButton( mAddFeatureGeometryButton );
376  }
377 }
378 
380 {
381  return mFeatureSelectionMgr;
382 }
383 
385 {
386  mDualView->setView( mode );
387  mViewMode = mode;
388 }
389 
390 void QgsRelationEditorWidget::setFeature( const QgsFeature &feature, bool update )
391 {
392  mFeature = feature;
393 
394  mEditorContext.setFormFeature( feature );
395 
396  if ( update )
397  updateUi();
398 }
399 
400 void QgsRelationEditorWidget::updateButtons()
401 {
402  bool editable = false;
403  bool linkable = false;
404  bool selectionNotEmpty = mFeatureSelectionMgr ? mFeatureSelectionMgr->selectedFeatureCount() : false;
405 
406  if ( mRelation.isValid() )
407  {
408  editable = mRelation.referencingLayer()->isEditable();
409  linkable = mRelation.referencingLayer()->isEditable();
410  }
411 
412  if ( mNmRelation.isValid() )
413  {
414  editable = mNmRelation.referencedLayer()->isEditable();
415  }
416 
417  mAddFeatureButton->setEnabled( editable );
418  mAddFeatureGeometryButton->setEnabled( editable );
419  mDuplicateFeatureButton->setEnabled( editable && selectionNotEmpty );
420  mLinkFeatureButton->setEnabled( linkable );
421  mDeleteFeatureButton->setEnabled( editable && selectionNotEmpty );
422  mUnlinkFeatureButton->setEnabled( linkable && selectionNotEmpty );
423 
424  mZoomToFeatureButton->setVisible(
425  mEditorContext.mapCanvas() && (
426  (
427  mNmRelation.isValid() &&
430  )
431  ||
432  (
433  mRelation.isValid() &&
436  )
437  )
438  );
439 
440  mZoomToFeatureButton->setEnabled( selectionNotEmpty );
441 
442  mToggleEditingButton->setChecked( editable );
443  mSaveEditsButton->setEnabled( editable );
444 }
445 
446 void QgsRelationEditorWidget::addFeatureGeometry()
447 {
448  QgsVectorLayer *layer = nullptr;
449  if ( mNmRelation.isValid() )
450  layer = mNmRelation.referencedLayer();
451  else
452  layer = mRelation.referencingLayer();
453 
454  mMapToolDigitize->setLayer( layer );
455 
456  // window is always on top, so we hide it to digitize without seeing it
457  window()->setVisible( false );
458  setMapTool( mMapToolDigitize );
459 
460  connect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
461  connect( mEditorContext.mapCanvas(), &QgsMapCanvas::keyPressed, this, &QgsRelationEditorWidget::onKeyPressed );
462 
463  if ( mEditorContext.mainMessageBar() )
464  {
465  QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( layer, mFeature );
466 
467  QString title = tr( "Create child feature for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString );
468  QString msg = tr( "Digitize the geometry for the new feature on layer %1. Press &lt;ESC&gt; to cancel." )
469  .arg( layer->name() );
470  mMessageBarItem = QgsMessageBar::createMessage( title, msg, this );
471  mEditorContext.mainMessageBar()->pushItem( mMessageBarItem );
472  }
473 
474 }
475 
476 void QgsRelationEditorWidget::addFeature( const QgsGeometry &geometry )
477 {
478  QgsAttributeMap keyAttrs;
479 
480  const QgsVectorLayerTools *vlTools = mEditorContext.vectorLayerTools();
481 
482  if ( mNmRelation.isValid() )
483  {
484  // n:m Relation: first let the user create a new feature on the other table
485  // and autocreate a new linking feature.
486  QgsFeature f;
487  if ( vlTools->addFeature( mNmRelation.referencedLayer(), QgsAttributeMap(), geometry, &f ) )
488  {
489  // Fields of the linking table
490  const QgsFields fields = mRelation.referencingLayer()->fields();
491 
492  // Expression context for the linking table
494 
495  QgsAttributeMap linkAttributes;
496  const auto constFieldPairs = mRelation.fieldPairs();
497  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
498  {
499  int index = fields.indexOf( fieldPair.first );
500  linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
501  }
502 
503  const auto constNmFieldPairs = mNmRelation.fieldPairs();
504  for ( const QgsRelation::FieldPair &fieldPair : constNmFieldPairs )
505  {
506  int index = fields.indexOf( fieldPair.first );
507  linkAttributes.insert( index, f.attribute( fieldPair.second ) );
508  }
509  QgsFeature linkFeature = QgsVectorLayerUtils::createFeature( mRelation.referencingLayer(), QgsGeometry(), linkAttributes, &context );
510 
511  mRelation.referencingLayer()->addFeature( linkFeature );
512 
513  updateUi();
514  }
515  }
516  else
517  {
518  QgsFields fields = mRelation.referencingLayer()->fields();
519 
520  const auto constFieldPairs = mRelation.fieldPairs();
521  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
522  {
523  keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeature.attribute( fieldPair.referencedField() ) );
524  }
525 
526  vlTools->addFeature( mDualView->masterModel()->layer(), keyAttrs, geometry );
527  }
528 }
529 
530 void QgsRelationEditorWidget::onDigitizingCompleted( const QgsFeature &feature )
531 {
532  addFeature( feature.geometry() );
533 
534  unsetMapTool();
535 }
536 
537 void QgsRelationEditorWidget::linkFeature()
538 {
539  QgsVectorLayer *layer = nullptr;
540 
541  if ( mNmRelation.isValid() )
542  layer = mNmRelation.referencedLayer();
543  else
544  layer = mRelation.referencingLayer();
545 
546  QgsFeatureSelectionDlg *selectionDlg = new QgsFeatureSelectionDlg( layer, mEditorContext, this );
547  selectionDlg->setAttribute( Qt::WA_DeleteOnClose );
548 
549  const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( mRelation.referencedLayer(), mFeature );
550  selectionDlg->setWindowTitle( tr( "Link existing child features for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString ) );
551 
552  connect( selectionDlg, &QDialog::accepted, this, &QgsRelationEditorWidget::onLinkFeatureDlgAccepted );
553  selectionDlg->show();
554 }
555 
556 void QgsRelationEditorWidget::onLinkFeatureDlgAccepted()
557 {
558  QgsFeatureSelectionDlg *selectionDlg = qobject_cast<QgsFeatureSelectionDlg *>( sender() );
559  if ( mNmRelation.isValid() )
560  {
561  QgsFeatureIterator it = mNmRelation.referencedLayer()->getFeatures(
563  .setFilterFids( selectionDlg->selectedFeatures() )
564  .setSubsetOfAttributes( mNmRelation.referencedFields() ) );
565 
566  QgsFeature relatedFeature;
567 
568  QgsFeatureList newFeatures;
569 
570  // Fields of the linking table
571  const QgsFields fields = mRelation.referencingLayer()->fields();
572 
573  // Expression context for the linking table
575 
576  QgsAttributeMap linkAttributes;
577  const auto constFieldPairs = mRelation.fieldPairs();
578  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
579  {
580  int index = fields.indexOf( fieldPair.first );
581  linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
582  }
583 
584  while ( it.nextFeature( relatedFeature ) )
585  {
586  const auto constFieldPairs = mNmRelation.fieldPairs();
587  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
588  {
589  int index = fields.indexOf( fieldPair.first );
590  linkAttributes.insert( index, relatedFeature.attribute( fieldPair.second ) );
591  }
592  const QgsFeature linkFeature = QgsVectorLayerUtils::createFeature( mRelation.referencingLayer(), QgsGeometry(), linkAttributes, &context );
593 
594  newFeatures << linkFeature;
595  }
596 
597  mRelation.referencingLayer()->addFeatures( newFeatures );
598  QgsFeatureIds ids;
599  const auto constNewFeatures = newFeatures;
600  for ( const QgsFeature &f : constNewFeatures )
601  ids << f.id();
602  mRelation.referencingLayer()->selectByIds( ids );
603  }
604  else
605  {
606  QMap<int, QVariant> keys;
607  const auto constFieldPairs = mRelation.fieldPairs();
608  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
609  {
610  int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
611  QVariant val = mFeature.attribute( fieldPair.referencedField() );
612  keys.insert( idx, val );
613  }
614 
615  const auto constSelectedFeatures = selectionDlg->selectedFeatures();
616  for ( QgsFeatureId fid : constSelectedFeatures )
617  {
618  QMapIterator<int, QVariant> it( keys );
619  while ( it.hasNext() )
620  {
621  it.next();
622  mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), it.value() );
623  }
624  }
625  }
626 
627  updateUi();
628 }
629 
630 void QgsRelationEditorWidget::duplicateFeature()
631 {
632  QgsVectorLayer *layer = mRelation.referencingLayer();
633 
634  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterFids( mFeatureSelectionMgr->selectedFeatureIds() ) );
635  QgsFeature f;
636  while ( fit.nextFeature( f ) )
637  {
638  QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicatedFeatureContext;
639  QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), 0, duplicatedFeatureContext );
640  }
641 }
642 
643 void QgsRelationEditorWidget::deleteFeature( const QgsFeatureId featureid )
644 {
645  deleteFeatures( QgsFeatureIds() << featureid );
646 }
647 
648 void QgsRelationEditorWidget::deleteSelectedFeatures()
649 {
650  deleteFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
651 }
652 
653 void QgsRelationEditorWidget::deleteFeatures( const QgsFeatureIds &featureids )
654 {
655  bool deleteFeatures = true;
656 
657  QgsVectorLayer *layer;
658  if ( mNmRelation.isValid() )
659  {
660  layer = mNmRelation.referencedLayer();
661 
662  // When deleting a linked feature within an N:M relation,
663  // check if the feature is linked to more than just one feature.
664  // In case it is linked more than just once, ask the user for confirmation
665  // as it is likely he was not aware of the implications and might either
666  // leave the dataset in a corrupted state (referential integrity) or if
667  // the fk constraint is ON CASCADE DELETE, there may be several linking
668  // entries deleted along.
669 
670  QgsFeatureRequest deletedFeaturesRequest;
671  deletedFeaturesRequest.setFilterFids( featureids );
672  deletedFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
673  deletedFeaturesRequest.setSubsetOfAttributes( QgsAttributeList() << mNmRelation.referencedFields().first() );
674 
675  QgsFeatureIterator deletedFeatures = layer->getFeatures( deletedFeaturesRequest );
676  QStringList deletedFeaturesPks;
678  while ( deletedFeatures.nextFeature( feature ) )
679  {
680  deletedFeaturesPks.append( QgsExpression::quotedValue( feature.attribute( mNmRelation.referencedFields().first() ) ) );
681  }
682 
683  QgsFeatureRequest linkingFeaturesRequest;
684  linkingFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
685  linkingFeaturesRequest.setNoAttributes();
686 
687  QString linkingFeaturesRequestExpression;
688  if ( !deletedFeaturesPks.empty() )
689  {
690  linkingFeaturesRequestExpression = QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( mNmRelation.fieldPairs().first().first ), deletedFeaturesPks.join( ',' ) );
691  linkingFeaturesRequest.setFilterExpression( linkingFeaturesRequestExpression );
692 
693  QgsFeatureIterator relatedLinkingFeatures = mNmRelation.referencingLayer()->getFeatures( linkingFeaturesRequest );
694 
695  int relatedLinkingFeaturesCount = 0;
696  while ( relatedLinkingFeatures.nextFeature( feature ) )
697  {
698  relatedLinkingFeaturesCount++;
699  }
700 
701  if ( deletedFeaturesPks.size() == 1 && relatedLinkingFeaturesCount > 1 )
702  {
703  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 );
704  messageBox.addButton( QMessageBox::Cancel );
705  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
706 
707  messageBox.exec();
708  if ( messageBox.clickedButton() != deleteButton )
709  deleteFeatures = false;
710  }
711  else if ( deletedFeaturesPks.size() > 1 && relatedLinkingFeaturesCount > deletedFeaturesPks.size() )
712  {
713  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 );
714  messageBox.addButton( QMessageBox::Cancel );
715  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
716 
717  messageBox.exec();
718  if ( messageBox.clickedButton() != deleteButton )
719  deleteFeatures = false;
720  }
721  }
722  }
723  else
724  {
725  layer = mRelation.referencingLayer();
726  }
727 
728  if ( deleteFeatures )
729  {
730  layer->deleteFeatures( featureids );
731  updateUi();
732  }
733 }
734 
735 void QgsRelationEditorWidget::unlinkFeature( const QgsFeatureId featureid )
736 {
737  unlinkFeatures( QgsFeatureIds() << featureid );
738 }
739 
740 void QgsRelationEditorWidget::unlinkSelectedFeatures()
741 {
742  unlinkFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
743 }
744 
745 void QgsRelationEditorWidget::zoomToSelectedFeatures()
746 {
747  QgsMapCanvas *c = mEditorContext.mapCanvas();
748  if ( !c )
749  return;
750 
751  c->zoomToFeatureIds(
752  mNmRelation.isValid() ? mNmRelation.referencedLayer() : mRelation.referencingLayer(),
753  mFeatureSelectionMgr->selectedFeatureIds()
754  );
755 }
756 
757 void QgsRelationEditorWidget::unlinkFeatures( const QgsFeatureIds &featureids )
758 {
759  if ( mNmRelation.isValid() )
760  {
761  QgsFeatureIterator selectedIterator = mNmRelation.referencedLayer()->getFeatures(
763  .setFilterFids( featureids )
764  .setSubsetOfAttributes( mNmRelation.referencedFields() ) );
765 
766  QgsFeature f;
767 
768  QStringList filters;
769 
770  while ( selectedIterator.nextFeature( f ) )
771  {
772  filters << '(' + mNmRelation.getRelatedFeaturesRequest( f ).filterExpression()->expression() + ')';
773  }
774 
775  QString filter = QStringLiteral( "(%1) AND (%2)" ).arg(
776  mRelation.getRelatedFeaturesRequest( mFeature ).filterExpression()->expression(),
777  filters.join( QStringLiteral( " OR " ) ) );
778 
779  QgsFeatureIterator linkedIterator = mRelation.referencingLayer()->getFeatures( QgsFeatureRequest()
780  .setNoAttributes()
781  .setFilterExpression( filter ) );
782 
783  QgsFeatureIds fids;
784 
785  while ( linkedIterator.nextFeature( f ) )
786  {
787  fids << f.id();
788  QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 );
789  }
790 
791  mRelation.referencingLayer()->deleteFeatures( fids );
792 
793  updateUi();
794  }
795  else
796  {
797  QMap<int, QgsField> keyFields;
798  const auto constFieldPairs = mRelation.fieldPairs();
799  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
800  {
801  int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
802  if ( idx < 0 )
803  {
804  QgsDebugMsg( QStringLiteral( "referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
805  return;
806  }
807  QgsField fld = mRelation.referencingLayer()->fields().at( idx );
808  keyFields.insert( idx, fld );
809  }
810 
811  const auto constFeatureids = featureids;
812  for ( QgsFeatureId fid : constFeatureids )
813  {
814  QMapIterator<int, QgsField> it( keyFields );
815  while ( it.hasNext() )
816  {
817  it.next();
818  mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QVariant( it.value().type() ) );
819  }
820  }
821  }
822 }
823 
824 void QgsRelationEditorWidget::toggleEditing( bool state )
825 {
826  if ( state )
827  {
828  mEditorContext.vectorLayerTools()->startEditing( mRelation.referencingLayer() );
829  if ( mNmRelation.isValid() )
830  mEditorContext.vectorLayerTools()->startEditing( mNmRelation.referencedLayer() );
831  }
832  else
833  {
834  mEditorContext.vectorLayerTools()->stopEditing( mRelation.referencingLayer() );
835  if ( mNmRelation.isValid() )
836  mEditorContext.vectorLayerTools()->stopEditing( mNmRelation.referencedLayer() );
837  }
838 }
839 
840 void QgsRelationEditorWidget::saveEdits()
841 {
842  mEditorContext.vectorLayerTools()->saveEdits( mRelation.referencingLayer() );
843  if ( mNmRelation.isValid() )
844  mEditorContext.vectorLayerTools()->saveEdits( mNmRelation.referencedLayer() );
845 }
846 
847 void QgsRelationEditorWidget::onCollapsedStateChanged( bool collapsed )
848 {
849  if ( !collapsed )
850  {
851  mVisible = true;
852  updateUi();
853  }
854 }
855 
856 void QgsRelationEditorWidget::updateUi()
857 {
858  // If not yet initialized, it is not (yet) visible, so we don't load it to be faster (lazy loading)
859  // If it is already initialized, it has been set visible before and the currently shown feature is changing
860  // and the widget needs updating
861 
862  if ( mVisible )
863  {
864  QgsFeatureRequest myRequest = mRelation.getRelatedFeaturesRequest( mFeature );
865 
866  if ( mNmRelation.isValid() )
867  {
868  QgsFeatureIterator it = mRelation.referencingLayer()->getFeatures( myRequest );
869 
870  QgsFeature fet;
871 
872  QStringList filters;
873 
874  while ( it.nextFeature( fet ) )
875  {
876  QString filter = mNmRelation.getReferencedFeatureRequest( fet ).filterExpression()->expression();
877  filters << filter.prepend( '(' ).append( ')' );
878  }
879 
880  QgsFeatureRequest nmRequest;
881 
882  nmRequest.setFilterExpression( filters.join( QStringLiteral( " OR " ) ) );
883 
884  initDualView( mNmRelation.referencedLayer(), nmRequest );
885  }
886  else
887  {
888  initDualView( mRelation.referencingLayer(), myRequest );
889  }
890  }
891 }
892 
894 {
895  return mLinkFeatureButton->isVisible();
896 }
897 
899 {
900  mLinkFeatureButton->setVisible( showLinkButton );
901 }
902 
904 {
905  return mUnlinkFeatureButton->isVisible();
906 }
907 
909 {
910  mSaveEditsButton->setVisible( showChildEdits );
911 }
912 
914 {
915  return mSaveEditsButton->isVisible();
916 }
917 
918 void QgsRelationEditorWidget::setShowUnlinkButton( bool showUnlinkButton )
919 {
920  mUnlinkFeatureButton->setVisible( showUnlinkButton );
921 }
922 
923 void QgsRelationEditorWidget::parentFormValueChanged( const QString &attribute, const QVariant &newValue )
924 {
925  mDualView->parentFormValueChanged( attribute, newValue );
926 }
927 
929 {
930  return mShowLabel;
931 }
932 
934 {
935  mShowLabel = showLabel;
936 
937  if ( mShowLabel && mRelation.isValid() )
938  setTitle( mRelation.name() );
939  else
940  setTitle( QString() );
941 }
942 
943 void QgsRelationEditorWidget::showContextMenu( QgsActionMenu *menu, const QgsFeatureId fid )
944 {
945  if ( mRelation.referencingLayer()->isEditable() )
946  {
947  QAction *qAction = nullptr;
948 
949  qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ), tr( "Delete Feature" ) );
950  connect( qAction, &QAction::triggered, this, [this, fid]() { deleteFeature( fid ); } );
951 
952  qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ), tr( "Unlink Feature" ) );
953  connect( qAction, &QAction::triggered, this, [this, fid]() { unlinkFeature( fid ); } );
954  }
955 }
956 
957 void QgsRelationEditorWidget::setMapTool( QgsMapTool *mapTool )
958 {
959  QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
960 
961  mapCanvas->setMapTool( mapTool );
962  mapCanvas->window()->raise();
963  mapCanvas->activateWindow();
964  mapCanvas->setFocus();
965  connect( mapTool, &QgsMapTool::deactivated, this, &QgsRelationEditorWidget::mapToolDeactivated );
966 }
967 
968 void QgsRelationEditorWidget::unsetMapTool()
969 {
970  QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
971 
972  // this will call mapToolDeactivated
973  mapCanvas->unsetMapTool( mMapToolDigitize );
974 
975  disconnect( mapCanvas, &QgsMapCanvas::keyPressed, this, &QgsRelationEditorWidget::onKeyPressed );
976  disconnect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
977 }
978 
980 {
981  return mFeature;
982 }
983 
984 void QgsRelationEditorWidget::onKeyPressed( QKeyEvent *e )
985 {
986  if ( e->key() == Qt::Key_Escape )
987  {
988  unsetMapTool();
989  }
990 }
991 
992 void QgsRelationEditorWidget::mapToolDeactivated()
993 {
994  window()->setVisible( true );
995  window()->raise();
996  window()->activateWindow();
997 
998  if ( mEditorContext.mainMessageBar() && mMessageBarItem )
999  {
1000  mEditorContext.mainMessageBar()->popWidget( mMessageBarItem );
1001  }
1002  mMessageBarItem = nullptr;
1003 }
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:104
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:971
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:371
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:394
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:589
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:390
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:610
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:923
QgsRelationEditorWidget::feature
QgsFeature feature() const
Returns the widget's current feature.
Definition: qgsrelationeditorwidget.cpp:979
qgsmapcanvas.h
QgsWkbTypes::NullGeometry
@ NullGeometry
Definition: qgswkbtypes.h:145
QgsVectorLayer::addFeature
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
Definition: qgsvectorlayer.cpp:989
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:588
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsexpression.h
QgsRelation::name
QString name
Definition: qgsrelation.h:48
QgsDualView::setView
void setView(ViewMode view)
Change the current view mode.
Definition: qgsdualview.cpp:234
qgsfeatureiterator.h
QgsFields
Definition: qgsfields.h:42
QgsProject::transactionGroups
QMap< QPair< QString, QString >, QgsTransactionGroup * > transactionGroups()
Map of transaction groups.
Definition: qgsproject.cpp:3027
QgsRelationEditorWidget::showLinkButton
bool showLinkButton() const
Determines if the "link feature" button should be shown.
Definition: qgsrelationeditorwidget.cpp:893
QgsMapCanvas
Definition: qgsmapcanvas.h:78
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:457
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:3514
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:118
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:506
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:187
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 passed widget from the bar (if previously added), then display the next one in the stack i...
Definition: qgsmessagebar.cpp:159
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:2940
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:3509
QgsRelation::referencingLayer
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:46
QgsFeatureRequest::setFilterExpression
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Definition: qgsfeaturerequest.cpp:126
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:62
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:3203
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
QgsFeatureRequest
Definition: qgsfeaturerequest.h:72
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.
QgsVectorLayer::deleteFeatures
bool deleteFeatures(const QgsFeatureIds &fids)
Deletes a set of features from the layer (but does not commit it)
Definition: qgsvectorlayer.cpp:3181
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:384
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:345
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:918
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:269
QgsVectorLayer::selectedFeatureIds
const Q_INVOKABLE QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Definition: qgsvectorlayer.cpp:3356
QgsFeatureRequest::filterExpression
QgsExpression * filterExpression() const
Returns the filter expression if set.
Definition: qgsfeaturerequest.h:422
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:571
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:898
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:908
QgsFeatureRequest::setFilterFids
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
Definition: qgsfeaturerequest.cpp:107
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:1786
QgsFeatureRequest::setNoAttributes
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
Definition: qgsfeaturerequest.cpp:194
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:913
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:448
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
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:302
QgsRelationEditorWidget::setShowLabel
void setShowLabel(bool showLabel)
Defines if a title label should be shown for this widget.
Definition: qgsrelationeditorwidget.cpp:933
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
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:386
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:690
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:1088
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:84
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:379
QgsMapCanvas::unsetMapTool
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
Definition: qgsmapcanvas.cpp:1826
QgsRelation
Definition: qgsrelation.h:41
QgsRelationEditorWidget::setEditorContext
void setEditorContext(const QgsAttributeEditorContext &context)
Sets the editor context.
Definition: qgsrelationeditorwidget.cpp:368
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:1159
QgsIFeatureSelectionManager
Definition: qgsifeatureselectionmanager.h:31
QgsVectorLayer::addFeatures
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a list of features to the sink.
Definition: qgsvectorlayer.cpp:3407
QgsMessageBar::createMessage
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
make out a widget containing a message to be displayed on the bar
Definition: qgsmessagebar.cpp:352
qgslogger.h
QgsRelationEditorWidget::showUnlinkButton
bool showUnlinkButton() const
Determines if the "unlink feature" button should be shown.
Definition: qgsrelationeditorwidget.cpp:903
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:4845
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:637
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:181
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
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:1033
QgsField
Definition: qgsfield.h:49