QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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  mDualView->init( layer, mEditorContext.mapCanvas(), request, mEditorContext );
263  mFeatureSelectionMgr = new QgsFilteredSelectionManager( layer, request, mDualView );
264  mDualView->setFeatureSelectionManager( mFeatureSelectionMgr );
265  connect( mFeatureSelectionMgr, &QgsIFeatureSelectionManager::selectionChanged, this, &QgsRelationEditorWidget::updateButtons );
266 
267  QIcon icon;
268  QString text;
269  if ( layer->geometryType() == QgsWkbTypes::PointGeometry )
270  {
271  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePoint.svg" ) );
272  text = tr( "Add Point child Feature" );
273  }
274  else if ( layer->geometryType() == QgsWkbTypes::LineGeometry )
275  {
276  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCaptureLine.svg" ) );
277  text = tr( "Add Line child Feature" );
278  }
279  else if ( layer->geometryType() == QgsWkbTypes::PolygonGeometry )
280  {
281  icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePolygon.svg" ) );
282  text = tr( "Add Polygon Feature" );
283  }
284 
285  if ( text.isEmpty() || !mEditorContext.mapCanvas() || !mEditorContext.cadDockWidget() )
286  {
287  mAddFeatureGeometryButton->setVisible( false );
288  }
289  else
290  {
291  mAddFeatureGeometryButton->setIcon( icon );
292  mAddFeatureGeometryButton->setText( text );
293  mAddFeatureGeometryButton->setToolTip( text );
294  }
295 
296  updateButtons();
297 }
298 
299 void QgsRelationEditorWidget::setRelations( const QgsRelation &relation, const QgsRelation &nmrelation )
300 {
301  if ( mRelation.isValid() )
302  {
303  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
304  disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
305  }
306 
307  if ( mNmRelation.isValid() )
308  {
309  disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
310  disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
311  }
312 
313  mRelation = relation;
314  mNmRelation = nmrelation;
315 
316  if ( !mRelation.isValid() )
317  return;
318 
319  mToggleEditingButton->setVisible( true );
320 
321  const auto transactionGroups = QgsProject::instance()->transactionGroups();
322  for ( auto it = transactionGroups.constBegin(); it != transactionGroups.constEnd(); ++it )
323  {
324  if ( it.value()->layers().contains( mRelation.referencingLayer() ) )
325  {
326  mToggleEditingButton->setVisible( false );
327  mSaveEditsButton->setVisible( false );
328  }
329  }
330 
331  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
332  connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
333 
334  if ( mNmRelation.isValid() )
335  {
336  connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
337  connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
338  }
339 
340  setTitle( relation.name() );
341 
342  QgsVectorLayer *lyr = relation.referencingLayer();
343 
344  bool canChangeAttributes = lyr->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues;
345  if ( canChangeAttributes && !lyr->readOnly() )
346  {
347  mToggleEditingButton->setEnabled( true );
348  updateButtons();
349  }
350  else
351  {
352  mToggleEditingButton->setEnabled( false );
353  }
354 
355  if ( mNmRelation.isValid() )
356  mZoomToFeatureButton->setVisible( mNmRelation.referencedLayer()->isSpatial() );
357  else
358  mZoomToFeatureButton->setVisible( mRelation.referencingLayer()->isSpatial() );
359 
360  setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
361 
362  updateUi();
363 }
364 
366 {
367  mEditorContext = context;
368 
369  if ( context.mapCanvas() && context.cadDockWidget() )
370  {
371  mMapToolDigitize.reset( new QgsMapToolDigitizeFeature( context.mapCanvas(), context.cadDockWidget() ) );
372  mMapToolDigitize->setButton( mAddFeatureGeometryButton );
373  }
374 }
375 
377 {
378  return mFeatureSelectionMgr;
379 }
380 
382 {
383  mDualView->setView( mode );
384  mViewMode = mode;
385 }
386 
388 {
389  mFeature = feature;
390 
391  updateUi();
392 }
393 
394 void QgsRelationEditorWidget::updateButtons()
395 {
396  bool editable = false;
397  bool linkable = false;
398  bool selectionNotEmpty = mFeatureSelectionMgr ? mFeatureSelectionMgr->selectedFeatureCount() : false;
399 
400  if ( mRelation.isValid() )
401  {
402  editable = mRelation.referencingLayer()->isEditable();
403  linkable = mRelation.referencingLayer()->isEditable();
404  }
405 
406  if ( mNmRelation.isValid() )
407  {
408  editable = mNmRelation.referencedLayer()->isEditable();
409  }
410 
411  mAddFeatureButton->setEnabled( editable );
412  mAddFeatureGeometryButton->setEnabled( editable );
413  mDuplicateFeatureButton->setEnabled( editable && selectionNotEmpty );
414  mLinkFeatureButton->setEnabled( linkable );
415  mDeleteFeatureButton->setEnabled( editable && selectionNotEmpty );
416  mUnlinkFeatureButton->setEnabled( linkable && selectionNotEmpty );
417 
418  mZoomToFeatureButton->setVisible(
419  mEditorContext.mapCanvas() && (
420  (
421  mNmRelation.isValid() &&
424  )
425  ||
426  (
427  mRelation.isValid() &&
430  )
431  )
432  );
433 
434  mZoomToFeatureButton->setEnabled( selectionNotEmpty );
435 
436  mToggleEditingButton->setChecked( editable );
437  mSaveEditsButton->setEnabled( editable );
438 }
439 
440 void QgsRelationEditorWidget::addFeatureGeometry()
441 {
442  QgsVectorLayer *layer = nullptr;
443  if ( mNmRelation.isValid() )
444  layer = mNmRelation.referencedLayer();
445  else
446  layer = mRelation.referencingLayer();
447 
448  mMapToolDigitize->setLayer( layer );
449 
450  // window is always on top, so we hide it to digitize without seeing it
451  window()->setVisible( false );
452  setMapTool( mMapToolDigitize );
453 
454  connect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
455  connect( mEditorContext.mapCanvas(), &QgsMapCanvas::keyPressed, this, &QgsRelationEditorWidget::onKeyPressed );
456 
457  if ( mEditorContext.mainMessageBar() )
458  {
459  QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( layer, mFeature );
460 
461  QString title = tr( "Create child feature for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString );
462  QString msg = tr( "Digitize the geometry for the new feature on layer %1. Press &lt;ESC&gt; to cancel." )
463  .arg( layer->name() );
464  mMessageBarItem = QgsMessageBar::createMessage( title, msg, this );
465  mEditorContext.mainMessageBar()->pushItem( mMessageBarItem );
466  }
467 
468 }
469 
470 void QgsRelationEditorWidget::addFeature( const QgsGeometry &geometry )
471 {
472  QgsAttributeMap keyAttrs;
473 
474  const QgsVectorLayerTools *vlTools = mEditorContext.vectorLayerTools();
475 
476  if ( mNmRelation.isValid() )
477  {
478  // n:m Relation: first let the user create a new feature on the other table
479  // and autocreate a new linking feature.
480  QgsFeature f;
481  if ( vlTools->addFeature( mNmRelation.referencedLayer(), QgsAttributeMap(), geometry, &f ) )
482  {
483  // Fields of the linking table
484  const QgsFields fields = mRelation.referencingLayer()->fields();
485 
486  // Expression context for the linking table
488 
489  QgsAttributeMap linkAttributes;
490  const auto constFieldPairs = mRelation.fieldPairs();
491  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
492  {
493  int index = fields.indexOf( fieldPair.first );
494  linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
495  }
496 
497  const auto constNmFieldPairs = mNmRelation.fieldPairs();
498  for ( const QgsRelation::FieldPair &fieldPair : constNmFieldPairs )
499  {
500  int index = fields.indexOf( fieldPair.first );
501  linkAttributes.insert( index, f.attribute( fieldPair.second ) );
502  }
503  QgsFeature linkFeature = QgsVectorLayerUtils::createFeature( mRelation.referencingLayer(), QgsGeometry(), linkAttributes, &context );
504 
505  mRelation.referencingLayer()->addFeature( linkFeature );
506 
507  updateUi();
508  }
509  }
510  else
511  {
512  QgsFields fields = mRelation.referencingLayer()->fields();
513 
514  const auto constFieldPairs = mRelation.fieldPairs();
515  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
516  {
517  keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeature.attribute( fieldPair.referencedField() ) );
518  }
519 
520  vlTools->addFeature( mDualView->masterModel()->layer(), keyAttrs, geometry );
521  }
522 }
523 
524 void QgsRelationEditorWidget::onDigitizingCompleted( const QgsFeature &feature )
525 {
526  addFeature( feature.geometry() );
527 
528  unsetMapTool();
529 }
530 
531 void QgsRelationEditorWidget::linkFeature()
532 {
533  QgsVectorLayer *layer = nullptr;
534 
535  if ( mNmRelation.isValid() )
536  layer = mNmRelation.referencedLayer();
537  else
538  layer = mRelation.referencingLayer();
539 
540  QgsFeatureSelectionDlg *selectionDlg = new QgsFeatureSelectionDlg( layer, mEditorContext, this );
541  selectionDlg->setAttribute( Qt::WA_DeleteOnClose );
542 
543  const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( mRelation.referencedLayer(), mFeature );
544  selectionDlg->setWindowTitle( tr( "Link existing child features for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString ) );
545 
546  connect( selectionDlg, &QDialog::accepted, this, &QgsRelationEditorWidget::onLinkFeatureDlgAccepted );
547  selectionDlg->show();
548 }
549 
550 void QgsRelationEditorWidget::onLinkFeatureDlgAccepted()
551 {
552  QgsFeatureSelectionDlg *selectionDlg = qobject_cast<QgsFeatureSelectionDlg *>( sender() );
553  if ( mNmRelation.isValid() )
554  {
555  QgsFeatureIterator it = mNmRelation.referencedLayer()->getFeatures(
557  .setFilterFids( selectionDlg->selectedFeatures() )
558  .setSubsetOfAttributes( mNmRelation.referencedFields() ) );
559 
560  QgsFeature relatedFeature;
561 
562  QgsFeatureList newFeatures;
563 
564  // Fields of the linking table
565  const QgsFields fields = mRelation.referencingLayer()->fields();
566 
567  // Expression context for the linking table
569 
570  QgsAttributeMap linkAttributes;
571  const auto constFieldPairs = mRelation.fieldPairs();
572  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
573  {
574  int index = fields.indexOf( fieldPair.first );
575  linkAttributes.insert( index, mFeature.attribute( fieldPair.second ) );
576  }
577 
578  while ( it.nextFeature( relatedFeature ) )
579  {
580  const auto constFieldPairs = mNmRelation.fieldPairs();
581  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
582  {
583  int index = fields.indexOf( fieldPair.first );
584  linkAttributes.insert( index, relatedFeature.attribute( fieldPair.second ) );
585  }
586  const QgsFeature linkFeature = QgsVectorLayerUtils::createFeature( mRelation.referencingLayer(), QgsGeometry(), linkAttributes, &context );
587 
588  newFeatures << linkFeature;
589  }
590 
591  mRelation.referencingLayer()->addFeatures( newFeatures );
592  QgsFeatureIds ids;
593  const auto constNewFeatures = newFeatures;
594  for ( const QgsFeature &f : constNewFeatures )
595  ids << f.id();
596  mRelation.referencingLayer()->selectByIds( ids );
597  }
598  else
599  {
600  QMap<int, QVariant> keys;
601  const auto constFieldPairs = mRelation.fieldPairs();
602  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
603  {
604  int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
605  QVariant val = mFeature.attribute( fieldPair.referencedField() );
606  keys.insert( idx, val );
607  }
608 
609  const auto constSelectedFeatures = selectionDlg->selectedFeatures();
610  for ( QgsFeatureId fid : constSelectedFeatures )
611  {
612  QMapIterator<int, QVariant> it( keys );
613  while ( it.hasNext() )
614  {
615  it.next();
616  mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), it.value() );
617  }
618  }
619  }
620 
621  updateUi();
622 }
623 
624 void QgsRelationEditorWidget::duplicateFeature()
625 {
626  QgsVectorLayer *layer = mRelation.referencingLayer();
627 
628  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterFids( mFeatureSelectionMgr->selectedFeatureIds() ) );
629  QgsFeature f;
630  while ( fit.nextFeature( f ) )
631  {
632  QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicatedFeatureContext;
633  QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), 0, duplicatedFeatureContext );
634  }
635 }
636 
637 void QgsRelationEditorWidget::deleteFeature( const QgsFeatureId featureid )
638 {
639  deleteFeatures( QgsFeatureIds() << featureid );
640 }
641 
642 void QgsRelationEditorWidget::deleteSelectedFeatures()
643 {
644  deleteFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
645 }
646 
647 void QgsRelationEditorWidget::deleteFeatures( const QgsFeatureIds &featureids )
648 {
649  bool deleteFeatures = true;
650 
651  QgsVectorLayer *layer;
652  if ( mNmRelation.isValid() )
653  {
654  layer = mNmRelation.referencedLayer();
655 
656  // When deleting a linked feature within an N:M relation,
657  // check if the feature is linked to more than just one feature.
658  // In case it is linked more than just once, ask the user for confirmation
659  // as it is likely he was not aware of the implications and might either
660  // leave the dataset in a corrupted state (referential integrity) or if
661  // the fk constraint is ON CASCADE DELETE, there may be several linking
662  // entries deleted along.
663 
664  QgsFeatureRequest deletedFeaturesRequest;
665  deletedFeaturesRequest.setFilterFids( featureids );
666  deletedFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
667  deletedFeaturesRequest.setSubsetOfAttributes( QgsAttributeList() << mNmRelation.referencedFields().first() );
668 
669  QgsFeatureIterator deletedFeatures = layer->getFeatures( deletedFeaturesRequest );
670  QStringList deletedFeaturesPks;
671  QgsFeature feature;
672  while ( deletedFeatures.nextFeature( feature ) )
673  {
674  deletedFeaturesPks.append( QgsExpression::quotedValue( feature.attribute( mNmRelation.referencedFields().first() ) ) );
675  }
676 
677  QgsFeatureRequest linkingFeaturesRequest;
678  linkingFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
679  linkingFeaturesRequest.setNoAttributes();
680 
681  QString linkingFeaturesRequestExpression;
682  if ( !deletedFeaturesPks.empty() )
683  {
684  linkingFeaturesRequestExpression = QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( mNmRelation.fieldPairs().first().first ), deletedFeaturesPks.join( ',' ) );
685  linkingFeaturesRequest.setFilterExpression( linkingFeaturesRequestExpression );
686 
687  QgsFeatureIterator relatedLinkingFeatures = mNmRelation.referencingLayer()->getFeatures( linkingFeaturesRequest );
688 
689  int relatedLinkingFeaturesCount = 0;
690  while ( relatedLinkingFeatures.nextFeature( feature ) )
691  {
692  relatedLinkingFeaturesCount++;
693  }
694 
695  if ( deletedFeaturesPks.size() == 1 && relatedLinkingFeaturesCount > 1 )
696  {
697  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 );
698  messageBox.addButton( QMessageBox::Cancel );
699  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
700 
701  messageBox.exec();
702  if ( messageBox.clickedButton() != deleteButton )
703  deleteFeatures = false;
704  }
705  else if ( deletedFeaturesPks.size() > 1 && relatedLinkingFeaturesCount > deletedFeaturesPks.size() )
706  {
707  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 );
708  messageBox.addButton( QMessageBox::Cancel );
709  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
710 
711  messageBox.exec();
712  if ( messageBox.clickedButton() != deleteButton )
713  deleteFeatures = false;
714  }
715  }
716  }
717  else
718  {
719  layer = mRelation.referencingLayer();
720  }
721 
722  if ( deleteFeatures )
723  {
724  layer->deleteFeatures( featureids );
725  updateUi();
726  }
727 }
728 
729 void QgsRelationEditorWidget::unlinkFeature( const QgsFeatureId featureid )
730 {
731  unlinkFeatures( QgsFeatureIds() << featureid );
732 }
733 
734 void QgsRelationEditorWidget::unlinkSelectedFeatures()
735 {
736  unlinkFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
737 }
738 
739 void QgsRelationEditorWidget::zoomToSelectedFeatures()
740 {
741  QgsMapCanvas *c = mEditorContext.mapCanvas();
742  if ( !c )
743  return;
744 
745  c->zoomToFeatureIds(
746  mNmRelation.isValid() ? mNmRelation.referencedLayer() : mRelation.referencingLayer(),
747  mFeatureSelectionMgr->selectedFeatureIds()
748  );
749 }
750 
751 void QgsRelationEditorWidget::unlinkFeatures( const QgsFeatureIds &featureids )
752 {
753  if ( mNmRelation.isValid() )
754  {
755  QgsFeatureIterator selectedIterator = mNmRelation.referencedLayer()->getFeatures(
757  .setFilterFids( featureids )
758  .setSubsetOfAttributes( mNmRelation.referencedFields() ) );
759 
760  QgsFeature f;
761 
762  QStringList filters;
763 
764  while ( selectedIterator.nextFeature( f ) )
765  {
766  filters << '(' + mNmRelation.getRelatedFeaturesRequest( f ).filterExpression()->expression() + ')';
767  }
768 
769  QString filter = QStringLiteral( "(%1) AND (%2)" ).arg(
770  mRelation.getRelatedFeaturesRequest( mFeature ).filterExpression()->expression(),
771  filters.join( QStringLiteral( " OR " ) ) );
772 
773  QgsFeatureIterator linkedIterator = mRelation.referencingLayer()->getFeatures( QgsFeatureRequest()
774  .setNoAttributes()
775  .setFilterExpression( filter ) );
776 
777  QgsFeatureIds fids;
778 
779  while ( linkedIterator.nextFeature( f ) )
780  {
781  fids << f.id();
782  QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 );
783  }
784 
785  mRelation.referencingLayer()->deleteFeatures( fids );
786 
787  updateUi();
788  }
789  else
790  {
791  QMap<int, QgsField> keyFields;
792  const auto constFieldPairs = mRelation.fieldPairs();
793  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
794  {
795  int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
796  if ( idx < 0 )
797  {
798  QgsDebugMsg( QStringLiteral( "referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
799  return;
800  }
801  QgsField fld = mRelation.referencingLayer()->fields().at( idx );
802  keyFields.insert( idx, fld );
803  }
804 
805  const auto constFeatureids = featureids;
806  for ( QgsFeatureId fid : constFeatureids )
807  {
808  QMapIterator<int, QgsField> it( keyFields );
809  while ( it.hasNext() )
810  {
811  it.next();
812  mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QVariant( it.value().type() ) );
813  }
814  }
815  }
816 }
817 
818 void QgsRelationEditorWidget::toggleEditing( bool state )
819 {
820  if ( state )
821  {
822  mEditorContext.vectorLayerTools()->startEditing( mRelation.referencingLayer() );
823  if ( mNmRelation.isValid() )
824  mEditorContext.vectorLayerTools()->startEditing( mNmRelation.referencedLayer() );
825  }
826  else
827  {
828  mEditorContext.vectorLayerTools()->stopEditing( mRelation.referencingLayer() );
829  if ( mNmRelation.isValid() )
830  mEditorContext.vectorLayerTools()->stopEditing( mNmRelation.referencedLayer() );
831  }
832 }
833 
834 void QgsRelationEditorWidget::saveEdits()
835 {
836  mEditorContext.vectorLayerTools()->saveEdits( mRelation.referencingLayer() );
837  if ( mNmRelation.isValid() )
838  mEditorContext.vectorLayerTools()->saveEdits( mNmRelation.referencedLayer() );
839 }
840 
841 void QgsRelationEditorWidget::onCollapsedStateChanged( bool collapsed )
842 {
843  if ( !collapsed )
844  {
845  mVisible = true;
846  updateUi();
847  }
848 }
849 
850 void QgsRelationEditorWidget::updateUi()
851 {
852  // If not yet initialized, it is not (yet) visible, so we don't load it to be faster (lazy loading)
853  // If it is already initialized, it has been set visible before and the currently shown feature is changing
854  // and the widget needs updating
855 
856  if ( mVisible )
857  {
858  QgsFeatureRequest myRequest = mRelation.getRelatedFeaturesRequest( mFeature );
859 
860  if ( mNmRelation.isValid() )
861  {
862  QgsFeatureIterator it = mRelation.referencingLayer()->getFeatures( myRequest );
863 
864  QgsFeature fet;
865 
866  QStringList filters;
867 
868  while ( it.nextFeature( fet ) )
869  {
870  QString filter = mNmRelation.getReferencedFeatureRequest( fet ).filterExpression()->expression();
871  filters << filter.prepend( '(' ).append( ')' );
872  }
873 
874  QgsFeatureRequest nmRequest;
875 
876  nmRequest.setFilterExpression( filters.join( QStringLiteral( " OR " ) ) );
877 
878  initDualView( mNmRelation.referencedLayer(), nmRequest );
879  }
880  else
881  {
882  initDualView( mRelation.referencingLayer(), myRequest );
883  }
884  }
885 }
886 
888 {
889  return mLinkFeatureButton->isVisible();
890 }
891 
893 {
894  mLinkFeatureButton->setVisible( showLinkButton );
895 }
896 
898 {
899  return mUnlinkFeatureButton->isVisible();
900 }
901 
903 {
904  mUnlinkFeatureButton->setVisible( showUnlinkButton );
905 }
906 
908 {
909  return mShowLabel;
910 }
911 
913 {
914  mShowLabel = showLabel;
915 
916  if ( mShowLabel && mRelation.isValid() )
917  setTitle( mRelation.name() );
918  else
919  setTitle( QString() );
920 }
921 
922 void QgsRelationEditorWidget::showContextMenu( QgsActionMenu *menu, const QgsFeatureId fid )
923 {
924  if ( mRelation.referencingLayer()->isEditable() )
925  {
926  QAction *qAction = nullptr;
927 
928  qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ), tr( "Delete Feature" ) );
929  connect( qAction, &QAction::triggered, this, [this, fid]() { deleteFeature( fid ); } );
930 
931  qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ), tr( "Unlink Feature" ) );
932  connect( qAction, &QAction::triggered, this, [this, fid]() { unlinkFeature( fid ); } );
933  }
934 }
935 
936 void QgsRelationEditorWidget::setMapTool( QgsMapTool *mapTool )
937 {
938  QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
939 
940  mapCanvas->setMapTool( mapTool );
941  mapCanvas->window()->raise();
942  mapCanvas->activateWindow();
943  mapCanvas->setFocus();
944  connect( mapTool, &QgsMapTool::deactivated, this, &QgsRelationEditorWidget::mapToolDeactivated );
945 }
946 
947 void QgsRelationEditorWidget::unsetMapTool()
948 {
949  QgsMapCanvas *mapCanvas = mEditorContext.mapCanvas();
950 
951  // this will call mapToolDeactivated
952  mapCanvas->unsetMapTool( mMapToolDigitize );
953 
954  disconnect( mapCanvas, &QgsMapCanvas::keyPressed, this, &QgsRelationEditorWidget::onKeyPressed );
955  disconnect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
956 }
957 
958 void QgsRelationEditorWidget::onKeyPressed( QKeyEvent *e )
959 {
960  if ( e->key() == Qt::Key_Escape )
961  {
962  unsetMapTool();
963  }
964 }
965 
966 void QgsRelationEditorWidget::mapToolDeactivated()
967 {
968  window()->setVisible( true );
969  window()->raise();
970  window()->activateWindow();
971 
972  if ( mEditorContext.mainMessageBar() && mMessageBarItem )
973  {
974  mEditorContext.mainMessageBar()->popWidget( mMessageBarItem );
975  }
976  mMessageBarItem = nullptr;
977 }
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
Methods in this class are used to handle basic operations on vector layers.
const QgsVectorLayerTools * vectorLayerTools() const
Returns the associated vector layer tools.
QString name
Definition: qgsrelation.h:48
QgsFeatureId id
Definition: qgsfeature.h:64
bool showUnlinkButton() const
Determines if the "unlink feature" button should be shown.
Wrapper for iterator of features from vector data provider or vector layer.
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
virtual bool saveEdits(QgsVectorLayer *layer) const =0
Should be called, when the features should be committed but the editing session is not ended...
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
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.
bool collapsed
The collapsed state of this group box.
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
virtual bool startEditing(QgsVectorLayer *layer) const =0
This will be called, whenever a vector layer should be switched to edit mode.
QgsAttributeTableModel * masterModel() const
Returns the model which has the information about all features (not only filtered) ...
Definition: qgsdualview.h:173
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
Set the feature selection model.
A groupbox that collapses/expands when toggled and can save its collapsed and checked states...
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds do list all the duplicated features...
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
This class contains context information for attribute editor widgets.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:46
void digitizingCompleted(const QgsFeature &feature)
Emitted whenever the digitizing has been successfully completed.
ViewMode
The view modes, in which this widget can present information.
Definition: qgsdualview.h:52
void collapsedStateChanged(bool collapsed)
Signal emitted when groupbox collapsed/expanded state is changed, and when first shown.
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool deleteFeatures(const QgsFeatureIds &fids)
Deletes a set of features from the layer (but does not commit it)
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
bool showLinkButton() const
Determines if the "link feature" button should be shown.
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.
QgsMessageBar * mainMessageBar()
Returns the main message bar.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
const QgsFeatureIds & selectedFeatureIds() const override
Returns reference to identifiers of selected features.
void setViewMode(QgsDualView::ViewMode mode)
Define the view mode for the dual view.
static QString getFeatureDisplayString(const QgsVectorLayer *layer, const QgsFeature &feature)
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:75
void reset(T *p=nullptr)
Will reset the managed pointer to p.
void setView(ViewMode view)
Change the current view mode.
void setButton(QAbstractButton *button)
Use this to associate a button to this maptool.
Definition: qgsmaptool.cpp:139
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
QgsExpression * filterExpression() const
Returns the filter expression if set.
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
Definition: qgsdualview.h:65
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
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
make out a widget containing a message to be displayed on the bar
void setShowLinkButton(bool showLinkButton)
Determines if the "link feature" button should be shown.
QgsAttributeList referencedFields() const
Returns a list of attributes used to form the referenced fields (most likely primary key) on the refe...
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
QgsFeatureRequest getReferencedFeatureRequest(const QgsAttributes &attributes) const
Creates a request to return the feature on the referenced (parent) layer which is referenced by the p...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void setLayer(QgsMapLayer *vl)
Change the layer edited by the map tool.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:74
Shows the features and attributes in a table layout.
Definition: qgsdualview.h:58
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
void setShowUnlinkButton(bool showUnlinkButton)
Determines if the "unlink feature" button should be shown.
bool popWidget(QgsMessageBarItem *item)
Remove the passed widget from the bar (if previously added), then display the next one in the stack i...
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
This class is a menu that is populated automatically with the actions defined for a given layer...
Definition: qgsactionmenu.h:37
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a list of features to the sink.
QgsRelationEditorWidget(QWidget *parent=nullptr)
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:47
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:49
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
void editingStarted()
Emitted when editing on this layer has started.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void keyPressed(QKeyEvent *e)
Emit key press event.
QgsAdvancedDigitizingDockWidget * cadDockWidget() const
Returns the associated CAD dock widget (e.g.
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
QString expression() const
Returns the original, unmodified expression string.
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...
Abstract base class for all map tools.
Definition: qgsmaptool.h:62
void setRelationFeature(const QgsRelation &relation, const QgsFeature &feature)
void showContextMenuExternally(QgsActionMenu *menu, QgsFeatureId fid)
Emitted when selecting context menu on the feature list to create the context menu individually...
void zoomToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Set canvas extent to the bounding box of a set of features.
void deactivated()
signal emitted once the map tool is deactivated
void pushItem(QgsMessageBarItem *item)
Display a message item on the bar after hiding the currently visible one and putting it in a stack...
bool isValid
Definition: qgsrelation.h:49
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
#define FID_TO_STRING(fid)
Definition: qgsfeatureid.h:30
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
int selectedFeatureCount() override
Returns the number of features that are selected in this layer.
QMap< QPair< QString, QString >, QgsTransactionGroup * > transactionGroups()
Map of transaction groups.
QgsIFeatureSelectionManager * featureSelectionManager()
The feature selection manager is responsible for the selected features which are currently being edit...
static QgsFeature duplicateFeature(QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext)
Duplicates a feature and it&#39;s children (one level deep).
void setShowLabel(bool showLabel)
Defines if a title label should be shown for this widget.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:450
void setEditorContext(const QgsAttributeEditorContext &context)
Sets the editor context.
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, QgsVectorLayer::SelectBehavior behavior=QgsVectorLayer::SetSelection)
Selects matching features using a list of feature IDs.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
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.
This tool digitizes geometry of new point/line/polygon features on already existing vector layers Onc...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QString name
Definition: qgsmaplayer.h:83
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).
QgsGeometry geometry
Definition: qgsfeature.h:67
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be nullptr.
QList< int > QgsAttributeList
Definition: qgsfield.h:26
bool nextFeature(QgsFeature &f)
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Is an interface class to abstract feature selection handling.
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QgsMapCanvas * mapCanvas() const
Returns the associated map canvas (e.g.
Allows modification of attribute values.
void setFeature(const QgsFeature &feature)
This widget is used to show the attributes of a set of features of a QgsVectorLayer.
Definition: qgsdualview.h:41
bool showLabel() const
Defines if a title label should be shown for this widget.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.