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