QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 "qgsfeatureiterator.h"
20#include "qgsexpression.h"
21#include "qgsfeature.h"
22#include "qgsiconutils.h"
23#include "qgsrelation.h"
24#include "qgslogger.h"
25#include "qgsvectorlayerutils.h"
26#include "qgsmapcanvas.h"
29#include "qgsmessagebar.h"
30#include "qgsmessagebaritem.h"
31#include "qgsactionmenu.h"
32
33#include <QHBoxLayout>
34#include <QLabel>
35#include <QMessageBox>
36#include <QPushButton>
37#include <QTreeWidget>
38
41QgsFilteredSelectionManager::QgsFilteredSelectionManager( QgsVectorLayer *layer, const QgsFeatureRequest &request, QObject *parent )
42 : QgsVectorLayerSelectionManager( layer, parent )
43 , mRequest( request )
44{
45 if ( ! layer )
46 return;
47
48 for ( const auto fid : layer->selectedFeatureIds() )
49 if ( mRequest.acceptFeature( layer->getFeature( fid ) ) )
50 mSelectedFeatureIds << fid;
51
52 connect( layer, &QgsVectorLayer::selectionChanged, this, &QgsFilteredSelectionManager::onSelectionChanged );
53}
54
55const QgsFeatureIds &QgsFilteredSelectionManager::selectedFeatureIds() const
56
57
58{
59 return mSelectedFeatureIds;
60}
61
62int QgsFilteredSelectionManager::selectedFeatureCount()
63{
64 return mSelectedFeatureIds.count();
65}
66
67void 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 ( const auto fid : deselected )
77 mSelectedFeatureIds.remove( fid );
78 }
79
80 for ( const 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
91QgsRelationEditorWidget::QgsRelationEditorWidget( const QVariantMap &config, QWidget *parent )
92 : QgsAbstractRelationEditorWidget( config, parent )
93 , mButtonsVisibility( qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsRelationEditorWidget::Button::AllButtons ) )
94 , mShowFirstFeature( config.value( QStringLiteral( "show_first_feature" ), true ).toBool() )
95 , mAllowAddChildFeatureWithNoGeometry( config.value( QStringLiteral( "allow_add_child_feature_with_no_geometry" ), false ).toBool() )
96{
97 QVBoxLayout *rootLayout = new QVBoxLayout( this );
98 rootLayout->setContentsMargins( 0, 9, 0, 0 );
99
100 // buttons
101 QHBoxLayout *buttonLayout = new QHBoxLayout();
102 buttonLayout->setContentsMargins( 0, 0, 0, 0 );
103 // toggle editing
104 mToggleEditingButton = new QToolButton( this );
105 mToggleEditingButton->setObjectName( QStringLiteral( "mToggleEditingButton" ) );
106 mToggleEditingButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) ) );
107 mToggleEditingButton->setText( tr( "Toggle Editing" ) );
108 mToggleEditingButton->setEnabled( false );
109 mToggleEditingButton->setCheckable( true );
110 mToggleEditingButton->setToolTip( tr( "Toggle editing mode for child layer" ) );
111 buttonLayout->addWidget( mToggleEditingButton );
112 // save Edits
113 mSaveEditsButton = new QToolButton( this );
114 mSaveEditsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSaveEdits.svg" ) ) );
115 mSaveEditsButton->setText( tr( "Save Child Layer Edits" ) );
116 mSaveEditsButton->setToolTip( tr( "Save child layer edits" ) );
117 mSaveEditsButton->setEnabled( true );
118 buttonLayout->addWidget( mSaveEditsButton );
119 // add feature with geometry
120 mAddFeatureGeometryButton = new QToolButton( this );
121 mAddFeatureGeometryButton->setObjectName( QStringLiteral( "mAddFeatureGeometryButton" ) );
122 buttonLayout->addWidget( mAddFeatureGeometryButton );
123 // add feature
124 mAddFeatureButton = new QToolButton( this );
125 mAddFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionNewTableRow.svg" ) ) );
126 mAddFeatureButton->setText( tr( "Add Child Feature" ) );
127 mAddFeatureButton->setToolTip( tr( "Add child feature" ) );
128 mAddFeatureButton->setObjectName( QStringLiteral( "mAddFeatureButton" ) );
129 buttonLayout->addWidget( mAddFeatureButton );
130 // duplicate feature
131 mDuplicateFeatureButton = new QToolButton( this );
132 mDuplicateFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDuplicateFeature.svg" ) ) );
133 mDuplicateFeatureButton->setText( tr( "Duplicate Child Feature(s)" ) );
134 mDuplicateFeatureButton->setToolTip( tr( "Duplicate selected child feature(s)" ) );
135 mDuplicateFeatureButton->setObjectName( QStringLiteral( "mDuplicateFeatureButton" ) );
136 buttonLayout->addWidget( mDuplicateFeatureButton );
137 // delete feature
138 mDeleteFeatureButton = new QToolButton( this );
139 mDeleteFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelectedFeatures.svg" ) ) );
140 mDeleteFeatureButton->setText( tr( "Delete Child Feature(s)" ) );
141 mDeleteFeatureButton->setToolTip( tr( "Delete selected child feature(s)" ) );
142 mDeleteFeatureButton->setObjectName( QStringLiteral( "mDeleteFeatureButton" ) );
143 buttonLayout->addWidget( mDeleteFeatureButton );
144 // link feature
145 mLinkFeatureButton = new QToolButton( this );
146 mLinkFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionLink.svg" ) ) );
147 mLinkFeatureButton->setText( tr( "Link Existing Feature(s)" ) );
148 mLinkFeatureButton->setToolTip( tr( "Link existing child feature(s)" ) );
149 mLinkFeatureButton->setObjectName( QStringLiteral( "mLinkFeatureButton" ) );
150 buttonLayout->addWidget( mLinkFeatureButton );
151 // unlink feature
152 mUnlinkFeatureButton = new QToolButton( this );
153 mUnlinkFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ) );
154 mUnlinkFeatureButton->setText( tr( "Unlink Feature(s)" ) );
155 mUnlinkFeatureButton->setToolTip( tr( "Unlink selected child feature(s)" ) );
156 mUnlinkFeatureButton->setObjectName( QStringLiteral( "mUnlinkFeatureButton" ) );
157 buttonLayout->addWidget( mUnlinkFeatureButton );
158 // zoom to linked feature
159 mZoomToFeatureButton = new QToolButton( this );
160 mZoomToFeatureButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToSelected.svg" ) ) );
161 mZoomToFeatureButton->setText( tr( "Zoom To Feature(s)" ) );
162 mZoomToFeatureButton->setToolTip( tr( "Zoom to selected child feature(s)" ) );
163 mZoomToFeatureButton->setObjectName( QStringLiteral( "mZoomToFeatureButton" ) );
164 buttonLayout->addWidget( mZoomToFeatureButton );
165 // spacer
166 buttonLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding ) );
167 // form view
168 mFormViewButton = new QToolButton( this );
169 mFormViewButton->setText( tr( "Form View" ) );
170 mFormViewButton->setToolTip( tr( "Switch to form view" ) );
171 mFormViewButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPropertyItem.svg" ) ) );
172 mFormViewButton->setCheckable( true );
173 mFormViewButton->setChecked( mViewMode == QgsDualView::AttributeEditor );
174 buttonLayout->addWidget( mFormViewButton );
175 // table view
176 mTableViewButton = new QToolButton( this );
177 mTableViewButton->setText( tr( "Table View" ) );
178 mTableViewButton->setToolTip( tr( "Switch to table view" ) );
179 mTableViewButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ) );
180 mTableViewButton->setCheckable( true );
181 mTableViewButton->setChecked( mViewMode == QgsDualView::AttributeTable );
182 buttonLayout->addWidget( mTableViewButton );
183 // button group
184 mViewModeButtonGroup = new QButtonGroup( this );
185 mViewModeButtonGroup->addButton( mFormViewButton, QgsDualView::AttributeEditor );
186 mViewModeButtonGroup->addButton( mTableViewButton, QgsDualView::AttributeTable );
187 // multiedit info label
188 mMultiEditInfoLabel = new QLabel( this );
189 buttonLayout->addWidget( mMultiEditInfoLabel );
190
191 // add buttons layout
192 rootLayout->addLayout( buttonLayout );
193
194 // add stacked widget
195 mStackedWidget = new QStackedWidget( this );
196
197 // add dual view (single feature content)
198 mDualView = new QgsDualView( this );
199 mDualView->setView( mViewMode );
200 connect( mDualView, &QgsDualView::showContextMenuExternally, this, &QgsRelationEditorWidget::showContextMenu );
201
202 // add multi feature editing page
203 mMultiEditStackedWidgetPage = new QWidget( this );
204 {
205 QVBoxLayout *vBoxLayout = new QVBoxLayout();
206 vBoxLayout->setContentsMargins( 0, 0, 0, 0 );
207
208 mMultiEditTreeWidget = new QTreeWidget( this );
209 mMultiEditTreeWidget->setHeaderHidden( true );
210 mMultiEditTreeWidget->setSelectionMode( QTreeWidget::ExtendedSelection );
211 vBoxLayout->addWidget( mMultiEditTreeWidget );
212
213 mMultiEditStackedWidgetPage->setLayout( vBoxLayout );
214 }
215 mStackedWidget->addWidget( mMultiEditStackedWidgetPage );
216
217 mStackedWidget->addWidget( mDualView );
218
219 rootLayout->addWidget( mStackedWidget );
220
221 connect( mViewModeButtonGroup, &QButtonGroup::idClicked,
222 this, static_cast<void ( QgsRelationEditorWidget::* )( int )>( &QgsRelationEditorWidget::setViewMode ) );
223 connect( mToggleEditingButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::toggleEditing );
224 connect( mSaveEditsButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::saveEdits );
225 connect( mAddFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::addFeature );
226 connect( mAddFeatureGeometryButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::addFeatureGeometry );
227 connect( mDuplicateFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::duplicateSelectedFeatures );
228 connect( mDeleteFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::deleteSelectedFeatures );
229 connect( mLinkFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::linkFeature );
230 connect( mUnlinkFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::unlinkSelectedFeatures );
231 connect( mZoomToFeatureButton, &QAbstractButton::clicked, this, &QgsRelationEditorWidget::zoomToSelectedFeatures );
232 connect( mMultiEditTreeWidget, &QTreeWidget::itemSelectionChanged, this, &QgsRelationEditorWidget::multiEditItemSelectionChanged );
233
234 // Set initial state for add/remove etc. buttons
235 updateButtons();
236
237 setLayout( rootLayout );
238}
239
240void QgsRelationEditorWidget::initDualView( QgsVectorLayer *layer, const QgsFeatureRequest &request )
241{
242 if ( multiEditModeActive() )
243 {
244 QgsLogger::warning( tr( "Dual view should not be used in multiple edit mode" ) );
245 return;
246 }
247
249 ctx.setParentFormFeature( mFeatureList.first() );
250 mDualView->init( layer, mEditorContext.mapCanvas(), request, ctx, true, mShowFirstFeature );
251 mFeatureSelectionMgr = new QgsFilteredSelectionManager( layer, request, mDualView );
252 mDualView->setFeatureSelectionManager( mFeatureSelectionMgr );
253
254 connect( mFeatureSelectionMgr, &QgsIFeatureSelectionManager::selectionChanged, this, &QgsRelationEditorWidget::updateButtons );
255
256 QIcon icon;
257 QString text;
258 if ( layer->geometryType() == Qgis::GeometryType::Point )
259 {
260 icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePoint.svg" ) );
261 text = tr( "Add Point Child Feature" );
262 }
263 else if ( layer->geometryType() == Qgis::GeometryType::Line )
264 {
265 icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCaptureLine.svg" ) );
266 text = tr( "Add Line Child Feature" );
267 }
268 else if ( layer->geometryType() == Qgis::GeometryType::Polygon )
269 {
270 icon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePolygon.svg" ) );
271 text = tr( "Add Polygon Child Feature" );
272 }
273
274 mAddFeatureGeometryButton->setIcon( icon );
275 mAddFeatureGeometryButton->setText( text );
276 mAddFeatureGeometryButton->setToolTip( text );
277
278 updateButtons();
279}
280
282{
283 mEditorContext = context;
284
285 if ( context.mapCanvas() && context.cadDockWidget() )
286 {
287 mMapToolDigitize.reset( new QgsMapToolDigitizeFeature( context.mapCanvas(), context.cadDockWidget() ) );
288 mMapToolDigitize->setButton( mAddFeatureGeometryButton );
289 }
290
291 updateButtons();
292}
293
295{
296 mDualView->setView( mode );
297 mViewMode = mode;
298}
299
300void QgsRelationEditorWidget::updateButtons()
301{
302 bool toggleEditingButtonEnabled = false;
303 bool canAdd = false;
304 bool canAddGeometry = false;
305 bool canRemove = false;
306 bool canEdit = false;
307 bool canLink = false;
308 bool canUnlink = false;
309 bool spatial = false;
310
311 if ( mRelation.isValid() )
312 {
313 toggleEditingButtonEnabled = mRelation.referencingLayer()->supportsEditing();
315 canAddGeometry = mRelation.referencingLayer()->isEditable();
316 canRemove = mRelation.referencingLayer()->isEditable();
319 canUnlink = mRelation.referencingLayer()->isEditable();
320 spatial = mRelation.referencingLayer()->isSpatial();
321 }
322
323 if ( mNmRelation.isValid() )
324 {
325 toggleEditingButtonEnabled |= mNmRelation.referencedLayer()->supportsEditing();
327 canAddGeometry = mNmRelation.referencedLayer()->isEditable();
328 canRemove = mNmRelation.referencedLayer()->isEditable();
331 }
332
333 const bool selectionNotEmpty = mFeatureSelectionMgr ? mFeatureSelectionMgr->selectedFeatureCount() : false;
334 if ( multiEditModeActive() )
335 {
336 const bool multieditLinkedChildSelected = ! selectedChildFeatureIds().isEmpty();
337
338 canAddGeometry = false;
339
340 canRemove = canRemove && multieditLinkedChildSelected;
341
342 // In 1:n relations an element can be linked only to 1 feature
343 canLink = canLink && mNmRelation.isValid();
344 canUnlink = canUnlink && multieditLinkedChildSelected;
345 }
346 else
347 {
348 canRemove = canRemove && selectionNotEmpty;
349 canUnlink = canUnlink && selectionNotEmpty;
350 }
351
352 mToggleEditingButton->setEnabled( toggleEditingButtonEnabled );
353 mAddFeatureButton->setEnabled( canAdd );
354 mAddFeatureGeometryButton->setEnabled( canAddGeometry );
355 mDuplicateFeatureButton->setEnabled( canEdit && selectionNotEmpty );
356 mLinkFeatureButton->setEnabled( canLink );
357 mDeleteFeatureButton->setEnabled( canRemove );
358 mUnlinkFeatureButton->setEnabled( canUnlink );
359 mZoomToFeatureButton->setEnabled( selectionNotEmpty );
360 mToggleEditingButton->setChecked( canEdit );
361 mSaveEditsButton->setEnabled( canEdit || canLink || canUnlink );
362
363 mToggleEditingButton->setVisible( !mLayerInSameTransactionGroup );
364
365 mLinkFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::Link ) );
366 mUnlinkFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::Unlink ) );
367 mSaveEditsButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::SaveChildEdits ) && !mLayerInSameTransactionGroup );
368 mAddFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::AddChildFeature ) && !( spatial && !mAllowAddChildFeatureWithNoGeometry ) );
369 mAddFeatureGeometryButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::AddChildFeature ) && mEditorContext.mapCanvas() && mEditorContext.cadDockWidget() && spatial );
370 mDuplicateFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::DuplicateChildFeature ) );
371 mDeleteFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::DeleteChildFeature ) );
372 mZoomToFeatureButton->setVisible( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::ZoomToChildFeature ) && mEditorContext.mapCanvas() && spatial );
373}
374
375void QgsRelationEditorWidget::addFeature()
376{
378
379 if ( !multiEditModeActive() )
380 return;
381
382 mMultiEditTreeWidget->blockSignals( true );
383 mMultiEdit1NJustAddedIds = addedFeatures;
384 QTreeWidgetItemIterator treeWidgetItemIterator( mMultiEditTreeWidget );
385 while ( *treeWidgetItemIterator )
386 {
387 if ( ( *treeWidgetItemIterator )->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ) ).toInt() != static_cast<int>( MultiEditFeatureType::Child ) )
388 {
389 ++treeWidgetItemIterator;
390 continue;
391 }
392
393 if ( addedFeatures.contains( ( *treeWidgetItemIterator )->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toInt() ) )
394 ( *treeWidgetItemIterator )->setSelected( true );
395
396 ++treeWidgetItemIterator;
397 }
398 mMultiEditTreeWidget->blockSignals( false );
399
400 updateUi();
401 updateButtons();
402}
403
404void QgsRelationEditorWidget::addFeatureGeometry()
405{
406 if ( multiEditModeActive() )
407 {
408 QgsLogger::warning( tr( "Adding a geometry feature is not supported in multiple edit mode" ) );
409 return;
410 }
411
412 QgsVectorLayer *layer = nullptr;
413 if ( mNmRelation.isValid() )
415 else
416 layer = mRelation.referencingLayer();
417
418 mMapToolDigitize->setLayer( layer );
419
420 // window is always on top, so we hide it to digitize without seeing it
421 if ( window()->objectName() != QLatin1String( "QgisApp" ) )
422 {
423 window()->setVisible( false );
424 }
425 setMapTool( mMapToolDigitize );
426
427 connect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
428
429 connect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCanceled, this, &QgsRelationEditorWidget::onDigitizingCanceled );
430
431 if ( auto *lMainMessageBar = mEditorContext.mainMessageBar() )
432 {
433 const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( layer, mFeatureList.first() );
434
435 const QString title = tr( "Create child feature for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString );
436 const QString msg = tr( "Digitize the geometry for the new feature on layer %1. Press &lt;ESC&gt; to cancel." )
437 .arg( layer->name() );
438 mMessageBarItem = QgsMessageBar::createMessage( title, msg, this );
439 lMainMessageBar->pushItem( mMessageBarItem );
440 }
441}
442
443void QgsRelationEditorWidget::onDigitizingCompleted( const QgsFeature &feature )
444{
446 digitizingFinished();
447}
448
449void QgsRelationEditorWidget::multiEditItemSelectionChanged()
450{
451 const QList<QTreeWidgetItem *> selectedItems = mMultiEditTreeWidget->selectedItems();
452
453 // Select all items pointing to the same feature
454 // but only if we are not deselecting.
455 if ( selectedItems.size() == 1
456 && mMultiEditPreviousSelectedItems.size() <= 1 )
457 {
458 if ( selectedItems.first()->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ) ).toInt() == static_cast<int>( MultiEditFeatureType::Child ) )
459 {
460 mMultiEditTreeWidget->blockSignals( true );
461
462 const QgsFeatureId featureIdSelectedItem = selectedItems.first()->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toInt();
463
464 QTreeWidgetItemIterator treeWidgetItemIterator( mMultiEditTreeWidget );
465 while ( *treeWidgetItemIterator )
466 {
467 if ( ( *treeWidgetItemIterator )->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ) ).toInt() != static_cast<int>( MultiEditFeatureType::Child ) )
468 {
469 ++treeWidgetItemIterator;
470 continue;
471 }
472
473 const QgsFeatureId featureIdCurrentItem = ( *treeWidgetItemIterator )->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toInt();
474 if ( mNmRelation.isValid() )
475 {
476 if ( featureIdSelectedItem == featureIdCurrentItem )
477 ( *treeWidgetItemIterator )->setSelected( true );
478 }
479 else
480 {
481 if ( ! mMultiEdit1NJustAddedIds.contains( featureIdSelectedItem ) )
482 break;
483
484 if ( mMultiEdit1NJustAddedIds.contains( featureIdCurrentItem ) )
485 ( *treeWidgetItemIterator )->setSelected( true );
486 }
487
488 ++treeWidgetItemIterator;
489 }
490 mMultiEditTreeWidget->blockSignals( false );
491 }
492 }
493 mMultiEditPreviousSelectedItems = selectedItems;
494 updateButtons();
495}
496
497void QgsRelationEditorWidget::toggleEditing( bool state )
498{
500
501 updateButtons();
502}
503
505{
506 if ( !mRelation.isValid() || mFeatureList.isEmpty() || !mFeatureList.first().isValid() )
507 return;
508
509 if ( !isVisible() )
510 return;
511
512 if ( multiEditModeActive() )
513 updateUiMultiEdit();
514 else
515 updateUiSingleEdit();
516}
517
519{
520 mButtonsVisibility = buttons;
521 updateButtons();
522}
523
525{
526 Buttons buttons;
527 if ( mLinkFeatureButton->isVisible() )
528 buttons |= Button::Link;
529 if ( mUnlinkFeatureButton->isVisible() )
530 buttons |= Button::Unlink;
531 if ( mSaveEditsButton->isVisible() )
532 buttons |= Button::SaveChildEdits;
533 if ( mAddFeatureButton->isVisible() )
534 buttons |= Button::AddChildFeature;
535 if ( mDuplicateFeatureButton->isVisible() )
536 buttons |= Button::DuplicateChildFeature;
537 if ( mDeleteFeatureButton->isVisible() )
538 buttons |= Button::DeleteChildFeature;
539 if ( mZoomToFeatureButton->isVisible() )
540 buttons |= Button::ZoomToChildFeature;
541 return buttons;
542}
543
544void QgsRelationEditorWidget::parentFormValueChanged( const QString &attribute, const QVariant &newValue )
545{
546 mDualView->parentFormValueChanged( attribute, newValue );
547}
548
549void QgsRelationEditorWidget::showContextMenu( QgsActionMenu *menu, const QgsFeatureId fid )
550{
552 {
553 QAction *qAction = nullptr;
554
555 if ( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::DeleteChildFeature ) )
556 {
557 qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ), tr( "Delete Feature" ) );
558 connect( qAction, &QAction::triggered, this, [this, fid]() { deleteFeature( fid ); } );
559 }
560
561 if ( mButtonsVisibility.testFlag( QgsRelationEditorWidget::Button::Unlink ) )
562 {
563 qAction = menu->addAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUnlink.svg" ) ), tr( "Unlink Feature" ) );
564 connect( qAction, &QAction::triggered, this, [this, fid]() { unlinkFeature( fid ); } );
565 }
566 }
567}
568
569void QgsRelationEditorWidget::setMapTool( QgsMapTool *mapTool )
570{
572
573 mapCanvas->setMapTool( mapTool );
574 mapCanvas->window()->raise();
575 mapCanvas->activateWindow();
576 mapCanvas->setFocus();
577 connect( mapTool, &QgsMapTool::deactivated, this, &QgsRelationEditorWidget::mapToolDeactivated );
578}
579
580void QgsRelationEditorWidget::unsetMapTool()
581{
583
584 // this will call mapToolDeactivated
585 mapCanvas->unsetMapTool( mMapToolDigitize );
586
587 disconnect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationEditorWidget::onDigitizingCompleted );
588}
589
590QgsFeatureIds QgsRelationEditorWidget::selectedChildFeatureIds() const
591{
592 if ( multiEditModeActive() )
593 {
594 QgsFeatureIds featureIds;
595 for ( QTreeWidgetItem *treeWidgetItem : mMultiEditTreeWidget->selectedItems() )
596 {
597 if ( static_cast<MultiEditFeatureType>( treeWidgetItem->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ) ).toInt() ) != MultiEditFeatureType::Child )
598 continue;
599
600 featureIds.insert( treeWidgetItem->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toLongLong() );
601 }
602 return featureIds;
603 }
604 else
605 return mFeatureSelectionMgr->selectedFeatureIds();
606}
607
608void QgsRelationEditorWidget::updateUiSingleEdit()
609{
610 mFormViewButton->setVisible( true );
611 mTableViewButton->setVisible( true );
612 mMultiEditInfoLabel->setVisible( false );
613
614 mStackedWidget->setCurrentWidget( mDualView );
615
617 QgsVectorLayer *layer = nullptr;
618 if ( mNmRelation.isValid() )
619 {
621 QgsFeature fet;
622 QStringList filters;
623
624 while ( it.nextFeature( fet ) )
625 {
627 filters << filter.prepend( '(' ).append( ')' );
628 }
629
630 QgsFeatureRequest nmRequest;
631 nmRequest.setFilterExpression( filters.join( QLatin1String( " OR " ) ) );
632
633 request = nmRequest;
635 }
636 else if ( mRelation.referencingLayer() )
637 {
638 layer = mRelation.referencingLayer();
639 }
640
641 if ( !layer )
642 return;
643
644 // don't recreate all the widget from scratch if only the request has changed
645 if ( !mDualView->masterModel() || layer != mDualView->masterModel()->layer() )
646 {
647 initDualView( layer, request );
648 }
649 else
650 {
651 mFeatureSelectionMgr = new QgsFilteredSelectionManager( layer, request, mDualView );
652 mDualView->setFeatureSelectionManager( mFeatureSelectionMgr );
653 connect( mFeatureSelectionMgr, &QgsIFeatureSelectionManager::selectionChanged, this, &QgsRelationEditorWidget::updateButtons );
654
655 mDualView->setRequest( request );
656 mDualView->masterModel()->loadLayer();
657
658 updateButtons();
659 }
660}
661
662void QgsRelationEditorWidget::updateUiMultiEdit()
663{
664 mFormViewButton->setVisible( false );
665 mTableViewButton->setVisible( false );
666 mMultiEditInfoLabel->setVisible( true );
667
668 mStackedWidget->setCurrentWidget( mMultiEditStackedWidgetPage ) ;
669
670 QList<QTreeWidgetItem *> parentTreeWidgetItems;
671
672 QgsFeatureIds featureIdsMixedValues;
673 QMultiMap<QTreeWidgetItem *, QgsFeatureId> multimapChildFeatures;
674
675 mMultiEditTreeWidget->clear();
676 for ( const QgsFeature &featureParent : std::as_const( mFeatureList ) )
677 {
678 QTreeWidgetItem *treeWidgetItem = createMultiEditTreeWidgetItem( featureParent, mRelation.referencedLayer(), MultiEditFeatureType::Parent );
679
680 // Parent feature items are not selectable
681 treeWidgetItem->setFlags( Qt::ItemIsEnabled );
682
683 parentTreeWidgetItems.append( treeWidgetItem );
684
685 // Get child features
686 const QgsFeatureRequest request = relation().getRelatedFeaturesRequest( featureParent );
687 QgsFeatureIterator featureIterator = mRelation.referencingLayer()->getFeatures( request );
688 QgsFeature featureChild;
689 while ( featureIterator.nextFeature( featureChild ) )
690 {
691 if ( mNmRelation.isValid() )
692 {
693 const QgsFeatureRequest requestFinalChild = mNmRelation.getReferencedFeatureRequest( featureChild );
694 QgsFeatureIterator featureIteratorFinalChild = mNmRelation.referencedLayer()->getFeatures( requestFinalChild );
695 QgsFeature featureChildChild;
696 while ( featureIteratorFinalChild.nextFeature( featureChildChild ) )
697 {
698 QTreeWidgetItem *treeWidgetItemChild = createMultiEditTreeWidgetItem( featureChildChild, mNmRelation.referencedLayer(), MultiEditFeatureType::Child );
699
700 treeWidgetItem->addChild( treeWidgetItemChild );
701
702 featureIdsMixedValues.insert( featureChildChild.id() );
703 multimapChildFeatures.insert( treeWidgetItem, featureChildChild.id() );
704 }
705 }
706 else
707 {
708 QTreeWidgetItem *treeWidgetItemChild = createMultiEditTreeWidgetItem( featureChild, mRelation.referencingLayer(), MultiEditFeatureType::Child );
709 treeWidgetItem->addChild( treeWidgetItemChild );
710
711 featureIdsMixedValues.insert( featureChild.id() );
712 }
713 }
714
715 mMultiEditTreeWidget->addTopLevelItem( treeWidgetItem );
716 treeWidgetItem->setExpanded( true );
717 }
718
719 // Set mixed values indicator (Green or Orange)
720 //
721 // Green:
722 // n:m and 1:n: 0 child features available
723 // n:m with no mixed values
724 // Orange:
725 // n:m with mixed values
726 // 1:n always, including when we pseudo know that feature are related (just added feature)
727 //
728 // See https://github.com/qgis/QGIS/pull/45703
729 //
730 if ( mNmRelation.isValid() )
731 {
732 QgsFeatureIds::iterator iterator = featureIdsMixedValues.begin();
733 while ( iterator != featureIdsMixedValues.end() )
734 {
735 bool mixedValues = false;
736 for ( QTreeWidgetItem *parentTreeWidgetItem : parentTreeWidgetItems )
737 {
738 if ( ! multimapChildFeatures.values( parentTreeWidgetItem ).contains( *iterator ) )
739 {
740 mixedValues = true;
741 break;
742 }
743 }
744
745 if ( !mixedValues )
746 {
747 iterator = featureIdsMixedValues.erase( iterator );
748 continue;
749 }
750
751 ++iterator;
752 }
753 }
754
755 // Set multiedit info label
756 if ( featureIdsMixedValues.isEmpty() )
757 {
758 QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/multieditSameValues.svg" ) );
759 mMultiEditInfoLabel->setPixmap( icon.pixmap( mMultiEditInfoLabel->height(),
760 mMultiEditInfoLabel->height() ) );
761 mMultiEditInfoLabel->setToolTip( tr( "All features in selection have equal relations" ) );
762 }
763 else
764 {
765 QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "/multieditMixedValues.svg" ) );
766 mMultiEditInfoLabel->setPixmap( icon.pixmap( mMultiEditInfoLabel->height(),
767 mMultiEditInfoLabel->height() ) );
768 mMultiEditInfoLabel->setToolTip( tr( "Some features in selection have different relations" ) );
769
770 // Set italic font for mixed values
771 QFont fontItalic = mMultiEditTreeWidget->font();
772 fontItalic.setItalic( true );
773 for ( QTreeWidgetItem *parentTreeWidgetItem : parentTreeWidgetItems )
774 {
775 for ( int childIndex = 0; childIndex < parentTreeWidgetItem->childCount(); ++childIndex )
776 {
777 QTreeWidgetItem *childItem = parentTreeWidgetItem->child( childIndex );
778 const QgsFeatureId featureIdCurrentItem = childItem->data( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ) ).toInt();
779 if ( featureIdsMixedValues.contains( featureIdCurrentItem ) )
780 childItem->setFont( 0, fontItalic );
781 }
782 }
783 }
784}
785
786QTreeWidgetItem *QgsRelationEditorWidget::createMultiEditTreeWidgetItem( const QgsFeature &feature, QgsVectorLayer *layer, MultiEditFeatureType type )
787{
788 QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem();
789 treeWidgetItem->setText( 0, QgsVectorLayerUtils::getFeatureDisplayString( layer, feature ) );
790 treeWidgetItem->setIcon( 0, QgsIconUtils::iconForLayer( layer ) );
791 treeWidgetItem->setData( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureType ), static_cast<int>( type ) );
792 treeWidgetItem->setData( 0, static_cast<int>( MultiEditTreeWidgetRole::FeatureId ), feature.id() );
793 return treeWidgetItem;
794}
795
796void QgsRelationEditorWidget::onDigitizingCanceled( )
797{
798 digitizingFinished();
799}
800
801void QgsRelationEditorWidget::digitizingFinished( )
802{
803 window()->setVisible( true );
804 window()->raise();
805 window()->activateWindow();
806 unsetMapTool();
807}
808
809void QgsRelationEditorWidget::mapToolDeactivated()
810{
811 if ( mEditorContext.mainMessageBar() && mMessageBarItem )
812 {
813 mEditorContext.mainMessageBar()->popWidget( mMessageBarItem );
814 }
815 mMessageBarItem = nullptr;
816}
817
819{
820 return QVariantMap( {{"buttons", qgsFlagValueToKeys( visibleButtons() )},
821 {"show_first_feature", mShowFirstFeature},
822 {"allow_add_child_feature_with_no_geometry", mAllowAddChildFeatureWithNoGeometry }
823 } );
824}
825
826void QgsRelationEditorWidget::setConfig( const QVariantMap &config )
827{
828 mButtonsVisibility = qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsRelationEditorWidget::Button::AllButtons );
829 mShowFirstFeature = config.value( QStringLiteral( "show_first_feature" ), true ).toBool();
830 mAllowAddChildFeatureWithNoGeometry = config.value( QStringLiteral( "allow_add_child_feature_with_no_geometry" ), false ).toBool();
831 updateButtons();
832}
833
835{
836 Q_UNUSED( newRelation );
837 Q_UNUSED( newFeature );
838
839 if ( ! mRelation.isValid() )
840 return;
841
842 disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
843 disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
844}
845
847{
848 if ( ! mRelation.isValid()
849 || mFeatureList.isEmpty() )
850 {
851 updateButtons();
852 return;
853 }
854
855 connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
856 connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
857
858 updateButtons();
859
861 initDualView( mRelation.referencingLayer(), myRequest );
862}
863
864void QgsRelationEditorWidget::beforeSetRelations( const QgsRelation &newRelation, const QgsRelation &newNmRelation )
865{
866 Q_UNUSED( newRelation );
867 Q_UNUSED( newNmRelation );
868
869 if ( mRelation.isValid() )
870 {
871 disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
872 disconnect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
873 }
874
875 if ( mNmRelation.isValid() )
876 {
877 disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
878 disconnect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
879 }
880}
881
883{
884 if ( !mRelation.isValid() )
885 return;
886
887 connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
888 connect( mRelation.referencingLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
889
890 if ( mNmRelation.isValid() )
891 {
892 connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStarted, this, &QgsRelationEditorWidget::updateButtons );
893 connect( mNmRelation.referencedLayer(), &QgsVectorLayer::editingStopped, this, &QgsRelationEditorWidget::updateButtons );
894 }
895
896 updateButtons();
897}
898
900{
901 return mFeatureSelectionMgr;
902}
903
905{
906 const QgsFeatureIds selectedFids = selectedChildFeatureIds();
907 unlinkFeatures( selectedFids );
908}
909
911{
912 duplicateFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
913}
914
916{
917 duplicateFeatures( mFeatureSelectionMgr->selectedFeatureIds() );
918}
919
921{
922 const QgsFeatureIds selectedFids = selectedChildFeatureIds();
923 deleteFeatures( selectedFids );
924}
925
927{
929 if ( !c )
930 return;
931
932 c->zoomToFeatureIds(
934 mFeatureSelectionMgr->selectedFeatureIds()
935 );
936}
937
939
940
942 : QgsAbstractRelationEditorConfigWidget( relation, parent )
943{
944 setupUi( this );
945}
946
948{
950 buttons.setFlag( QgsRelationEditorWidget::Button::Link, mRelationShowLinkCheckBox->isChecked() );
951 buttons.setFlag( QgsRelationEditorWidget::Button::Unlink, mRelationShowUnlinkCheckBox->isChecked() );
952 buttons.setFlag( QgsRelationEditorWidget::Button::AddChildFeature, mRelationShowAddChildCheckBox->isChecked() );
953 buttons.setFlag( QgsRelationEditorWidget::Button::DuplicateChildFeature, mRelationShowDuplicateChildFeatureCheckBox->isChecked() );
954 buttons.setFlag( QgsRelationEditorWidget::Button::ZoomToChildFeature, mRelationShowZoomToFeatureCheckBox->isChecked() );
955 buttons.setFlag( QgsRelationEditorWidget::Button::DeleteChildFeature, mRelationDeleteChildFeatureCheckBox->isChecked() );
956 buttons.setFlag( QgsRelationEditorWidget::Button::SaveChildEdits, mRelationShowSaveChildEditsCheckBox->isChecked() );
957
958 return QVariantMap(
959 {
960 {"buttons", qgsFlagValueToKeys( buttons )},
961 {"show_first_feature", mShowFirstFeature->isChecked()},
962 {"allow_add_child_feature_with_no_geometry", mAllowAddChildFeatureWithNoGeometry->isChecked()}
963 } );
964}
965
966void QgsRelationEditorConfigWidget::setConfig( const QVariantMap &config )
967{
968 const QgsRelationEditorWidget::Buttons buttons = qgsFlagKeysToValue( config.value( QStringLiteral( "buttons" ) ).toString(), QgsRelationEditorWidget::Button::AllButtons );
969
970 mRelationShowLinkCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::Link ) );
971 mRelationShowUnlinkCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::Unlink ) );
972 mRelationShowAddChildCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::AddChildFeature ) );
973 mRelationShowDuplicateChildFeatureCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::DuplicateChildFeature ) );
974 mRelationShowZoomToFeatureCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::ZoomToChildFeature ) );
975 mRelationDeleteChildFeatureCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::DeleteChildFeature ) );
976 mRelationShowSaveChildEditsCheckBox->setChecked( buttons.testFlag( QgsRelationEditorWidget::Button::SaveChildEdits ) );
977 mShowFirstFeature->setChecked( config.value( QStringLiteral( "show_first_feature" ), true ).toBool() );
978 mAllowAddChildFeatureWithNoGeometry->setChecked( config.value( QStringLiteral( "allow_add_child_feature_with_no_geometry" ), false ).toBool() );
979}
980
981
983
984
985#ifndef SIP_RUN
987{
988
989}
990
992{
993 return QStringLiteral( "relation_editor" );
994}
995
997{
998 return QObject::tr( "Relation Editor" );
999}
1000
1001QgsAbstractRelationEditorWidget *QgsRelationEditorWidgetFactory::create( const QVariantMap &config, QWidget *parent ) const
1002{
1003 return new QgsRelationEditorWidget( config, parent );
1004}
1005
1007{
1008 return static_cast<QgsAbstractRelationEditorConfigWidget *>( new QgsRelationEditorConfigWidget( relation, parent ) );
1009}
1010#endif
void reset(T *p=nullptr)
Will reset the managed pointer to p.
@ Polygon
Polygons.
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:39
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.
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
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 setRequest(const QgsFeatureRequest &request)
Set the request.
void parentFormValueChanged(const QString &attribute, const QVariant &value)
Called in embedded forms when an attribute value in the parent form has changed.
QgsAttributeTableModel * masterModel() const
Returns the model which has the information about all features (not only filtered)
Definition: qgsdualview.h:185
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)
Fetch next feature and stores in f, returns true on success.
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:131
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:93
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:78
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:156
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.
QVariantMap config() override
Create a configuration from the current GUI state.
void setConfig(const QVariantMap &config) override
Update the configuration widget to represent the given configuration.
QgsRelationEditorConfigWidget(const QgsRelation &relation, QWidget *parent)
Create a new configuration widget.
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.
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.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
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:5456
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:5478
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