48#include <QInputDialog>
51#include <QProgressDialog>
56#include "moc_qgsdualview.cpp"
58using namespace Qt::StringLiterals;
66const std::unique_ptr<QgsSettingsEntryVariant> QgsDualView::conditionalFormattingSplitterState = std::make_unique<
68const std::unique_ptr<QgsSettingsEntryVariant> QgsDualView::attributeEditorSplitterState = std::make_unique<
72 : QStackedWidget( parent )
81 mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
82 connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested,
this, &QgsDualView::showViewHeaderMenu );
85 mConditionalFormatWidgetStack->hide();
87 mConditionalFormatWidgetStack->setMainPanel( mConditionalFormatWidget );
88 mConditionalFormatWidget->setDockMode(
true );
92 conditionalFormattingSplitterState->copyValueFromKey( u
"/qgis/attributeTable/splitterState"_s,
true );
93 mConditionalSplitter->restoreState( conditionalFormattingSplitterState->value().toByteArray() );
94 mAttributeEditorViewSplitter->restoreState( attributeEditorSplitterState->value().toByteArray() );
96 mPreviewColumnsMenu =
new QMenu(
this );
97 mActionPreviewColumnsMenu->setMenu( mPreviewColumnsMenu );
101 mActionExpressionPreview->setText( tr(
"Expression" ) );
104 connect( mActionExpressionPreview, &QAction::triggered,
this, &QgsDualView::previewExpressionBuilder );
113 auto createShortcuts = [
this](
const QString &objectName, void (
QgsFeatureListView::*slot )() ) {
118 connect( sc, &QShortcut::activated, mFeatureListView, slot );
125 QButtonGroup *buttonGroup =
new QButtonGroup(
this );
126 buttonGroup->setExclusive(
false );
130 QAbstractButton *bt = buttonGroup->button(
static_cast<int>( action ) );
132 bt->setChecked(
true );
133 connect( buttonGroup, qOverload<QAbstractButton *, bool>( &QButtonGroup::buttonToggled ),
this, &QgsDualView::panZoomGroupButtonToggled );
135 connect( mFlashButton, &QToolButton::clicked,
this, &QgsDualView::flashButtonClicked );
146 delete mAttributeForm;
147 mAttributeForm =
nullptr;
154 mConfig.update( mLayer->fields() );
158 mEditorContext = context;
165 const bool needsGeometry = mLayer->conditionalStyles()->rulesNeedGeometry()
171 initLayerCache( needsGeometry );
172 initModels( mapCanvas, request, loadFeatures );
174 mConditionalFormatWidget->setLayer( mLayer );
176 mTableView->setModel( mFilterModel );
177 mFeatureListView->setModel( mFeatureListModel );
182 if ( mFeatureListPreviewButton->defaultAction() )
184 mFeatureListView->setDisplayExpression( mDisplayExpression );
194 if ( showFirstFeature && mFeatureListModel->rowCount() > 0 )
205void QgsDualView::initAttributeForm(
const QgsFeature &feature )
207 Q_ASSERT( !mAttributeForm );
213 mAttributeEditorScrollArea->setWidgetResizable(
true );
214 mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
215 mAttributeEditorScrollArea->setWidget( mAttributeForm );
219 mAttributeEditor->layout()->addWidget( mAttributeForm );
224 mAttributeForm->setMinimumWidth( 200 );
232 if ( QgsMapCanvas *canvas = mFilterModel->mapCanvas() )
238 if ( QgsMapCanvas *canvas = mFilterModel->mapCanvas() )
247void QgsDualView::columnBoxInit()
250 const QList<QgsField> fields = mLayer->fields().toList();
251 const QString displayExpression = mLayer->displayExpression();
253 mFeatureListPreviewButton->addAction( mActionExpressionPreview );
254 mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
256 QAction *defaultFieldAction =
nullptr;
257 const auto constFields = fields;
258 for (
const QgsField &field : constFields )
260 const int fieldIndex = mLayer->fields().lookupField( field.name() );
261 if ( fieldIndex == -1 )
264 const QString fieldName = field.name();
267 const QIcon fieldIcon = mLayer->fields().iconForField( fieldIndex );
268 const QString fieldDisplayName = mLayer->attributeDisplayName( fieldIndex );
271 QAction *previewAction =
new QAction( fieldIcon, fieldDisplayName, mFeatureListPreviewButton );
272 connect( previewAction, &QAction::triggered,
this, [
this, previewAction, fieldName] { previewColumnChanged( previewAction, fieldName ); } );
273 mPreviewColumnsMenu->addAction( previewAction );
275 if ( fieldDisplayName == displayExpression
276 || u
"COALESCE( \"%1\", '<NULL>' )"_s.arg( fieldDisplayName ) == displayExpression
277 || u
"\"%1\""_s.arg( fieldDisplayName ) == displayExpression
278 || fieldName == displayExpression
279 || u
"COALESCE( \"%1\", '<NULL>' )"_s.arg( fieldName ) == displayExpression
280 || u
"\"%1\""_s.arg( fieldName ) == displayExpression )
282 defaultFieldAction = previewAction;
287 QMenu *sortMenu =
new QMenu(
this );
289 sortMenuAction->setMenu( sortMenu );
291 QAction *sortByPreviewExpressionAsc =
new QAction(
QgsApplication::getThemeIcon( u
"sort.svg"_s ), tr(
"By Display Name (Ascending)" ),
this );
292 connect( sortByPreviewExpressionAsc, &QAction::triggered,
this, [
this]() { mFeatureListModel->setSortByDisplayExpression(
true, Qt::AscendingOrder ); } );
293 sortMenu->addAction( sortByPreviewExpressionAsc );
294 QAction *sortByPreviewExpressionDesc =
new QAction(
QgsApplication::getThemeIcon( u
"sort-reverse.svg"_s ), tr(
"By Display Name (Descending)" ),
this );
295 connect( sortByPreviewExpressionDesc, &QAction::triggered,
this, [
this]() { mFeatureListModel->setSortByDisplayExpression(
true, Qt::DescendingOrder ); } );
296 sortMenu->addAction( sortByPreviewExpressionDesc );
297 QAction *sortByPreviewExpressionCustom =
new QAction(
QgsApplication::getThemeIcon( u
"mIconExpressionPreview.svg"_s ), tr(
"By Custom Expression" ),
this );
298 connect( sortByPreviewExpressionCustom, &QAction::triggered,
this, [
this]() {
300 mFeatureListModel->setSortByDisplayExpression(
false );
302 sortMenu->addAction( sortByPreviewExpressionCustom );
304 mFeatureListPreviewButton->addAction( sortMenuAction );
306 QAction *separator =
new QAction( mFeatureListPreviewButton );
307 separator->setSeparator(
true );
308 mFeatureListPreviewButton->addAction( separator );
309 restoreRecentDisplayExpressions();
311 if ( defaultFieldAction )
313 mFeatureListPreviewButton->setDefaultAction( defaultFieldAction );
314 mFeatureListPreviewButton->defaultAction()->trigger();
318 mActionExpressionPreview->setToolTip( displayExpression );
319 mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
321 mFeatureListView->setDisplayExpression( displayExpression );
322 setDisplayExpression( displayExpression.isEmpty() ? tr(
"'[Please define preview text]'" ) : displayExpression );
328 setCurrentIndex(
view );
339 switch ( mFilterModel->filterMode() )
363 mMasterModel->setShowValidityState(
false );
373 const bool requiresTableReload = ( request.
filterType() != Qgis::Qgis::FeatureRequestFilterType::NoFilter
376 || ( mMasterModel->rowCount() == 0 );
388 if ( mFilterModel->mapCanvas() )
390 const QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
405 mMasterModel->setShowValidityState(
true );
417 if ( !filterExpression.isEmpty() )
434 setBrowsingAutoPanScaleAllowed(
false );
442 setBrowsingAutoPanScaleAllowed(
true );
446 if ( requiresTableReload )
449 mFilterModel->disconnectFilterModeConnections();
451 mMasterModel->setRequest( request );
452 whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry );
453 mMasterModel->loadLayer();
463 mFilterModel->setSelectedOnTop( selectedOnTop );
466void QgsDualView::initLayerCache(
bool cacheGeometry )
476 rebuildFullLayerCache();
482 delete mFeatureListModel;
486 mMasterModel =
new QgsAttributeTableModel( mLayerCache,
this );
487 mMasterModel->setRequest( request );
488 mMasterModel->setEditorContext( mEditorContext );
489 mMasterModel->setExtraColumns( 1 );
497 mMasterModel->loadLayer();
499 mFilterModel =
new QgsAttributeTableFilterModel( mapCanvas, mMasterModel, mMasterModel );
503 connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
504 connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
508 mFeatureListModel =
new QgsFeatureListModel( mFilterModel, mFilterModel );
511void QgsDualView::restoreRecentDisplayExpressions()
513 const QVariantList previewExpressions = mLayer->customProperty( u
"dualview/previewExpressions"_s ).toList();
515 for (
const QVariant &previewExpression : previewExpressions )
517 insertRecentlyUsedDisplayExpression( previewExpression.toString() );
521void QgsDualView::saveRecentDisplayExpressions()
const
527 const QList<QAction *> actions = mFeatureListPreviewButton->actions();
530 int index = actions.indexOf( mLastDisplayExpressionAction );
533 QVariantList previewExpressions;
534 for ( ; index < actions.length(); ++index )
536 QAction *action = actions.at( index );
537 previewExpressions << action->property(
"previewExpression" );
540 mLayer->setCustomProperty( u
"dualview/previewExpressions"_s, previewExpressions );
544void QgsDualView::setDisplayExpression(
const QString &expression )
546 mDisplayExpression = expression;
547 insertRecentlyUsedDisplayExpression( expression );
550void QgsDualView::insertRecentlyUsedDisplayExpression(
const QString &expression )
552 const QList<QAction *> actions = mFeatureListPreviewButton->actions();
555 const int index = actions.indexOf( mLastDisplayExpressionAction );
558 for (
int i = 0; index + i < actions.length(); ++i )
560 QAction *action = actions.at( index );
561 if ( action->text() == expression || i >= 9 )
563 if ( action == mLastDisplayExpressionAction )
565 mLastDisplayExpressionAction =
nullptr;
567 mFeatureListPreviewButton->removeAction( action );
571 if ( !mLastDisplayExpressionAction )
573 mLastDisplayExpressionAction = action;
579 QString name = expression;
581 if ( expression.startsWith(
"COALESCE( \""_L1 ) && expression.endsWith(
", '<NULL>' )"_L1 ) )
583 name = expression.mid( 11, expression.length() - 24 );
585 const int fieldIndex = mLayer->fields().indexOf( name );
586 if ( fieldIndex != -1 )
588 name = mLayer->attributeDisplayName( fieldIndex );
589 icon = mLayer->fields().iconForField( fieldIndex );
597 QAction *previewAction =
new QAction( icon, name, mFeatureListPreviewButton );
598 previewAction->setProperty(
"previewExpression", expression );
599 connect( previewAction, &QAction::triggered,
this, [expression,
this](
bool ) {
600 setDisplayExpression( expression );
601 mFeatureListPreviewButton->setText( tr(
"Expression" ) );
602 mFeatureListPreviewButton->setToolTip( expression );
605 mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
606 mLastDisplayExpressionAction = previewAction;
609void QgsDualView::updateEditSelectionProgress(
int progress,
int count )
611 mProgressCount->setText( u
"%1 / %2"_s.arg( progress + 1 ).arg( count ) );
612 mPreviousFeatureButton->setEnabled( progress > 0 );
613 mNextFeatureButton->setEnabled( progress + 1 < count );
614 mFirstFeatureButton->setEnabled( progress > 0 );
615 mLastFeatureButton->setEnabled( progress + 1 < count );
616 if ( mAttributeForm )
618 mAttributeForm->setVisible( count > 0 );
622void QgsDualView::panOrZoomToFeature(
const QgsFeatureIds &featureset )
624 QgsMapCanvas *canvas = mFilterModel->mapCanvas();
627 if ( mBrowsingAutoPanScaleAllowed )
629 if ( mAutoPanButton->isChecked() )
630 QTimer::singleShot( 0,
this, [
this, featureset, canvas]() { canvas->
panToFeatureIds( mLayer, featureset,
false ); } );
631 else if ( mAutoZoomButton->isChecked() )
632 QTimer::singleShot( 0,
this, [
this, featureset, canvas]() { canvas->
zoomToFeatureIds( mLayer, featureset ); } );
634 if ( mFlashButton->isChecked() )
635 QTimer::singleShot( 0,
this, [
this, featureset, canvas]() { canvas->
flashFeatureIds( mLayer, featureset ); } );
636 mLastFeatureSet = featureset;
640void QgsDualView::setBrowsingAutoPanScaleAllowed(
bool allowed )
642 if ( mBrowsingAutoPanScaleAllowed == allowed )
645 mBrowsingAutoPanScaleAllowed = allowed;
647 mAutoPanButton->setEnabled( allowed );
648 mAutoZoomButton->setEnabled( allowed );
650 const QString disabledHint = tr(
"(disabled when attribute table only shows features visible in the current map canvas extent)" );
652 mAutoPanButton->setToolTip( tr(
"Automatically pan to the current feature" ) + ( allowed ? QString() : QString(
' ' ) + disabledHint ) );
653 mAutoZoomButton->setToolTip( tr(
"Automatically zoom to the current feature" ) + ( allowed ? QString() : QString(
' ' ) + disabledHint ) );
656void QgsDualView::panZoomGroupButtonToggled( QAbstractButton *button,
bool checked )
658 if ( button == mAutoPanButton && checked )
660 QgsSettings().setEnumValue( u
"/qgis/attributeTable/featureListBrowsingAction"_s,
PanToFeature );
661 mAutoZoomButton->setChecked(
false );
663 else if ( button == mAutoZoomButton && checked )
665 QgsSettings().setEnumValue( u
"/qgis/attributeTable/featureListBrowsingAction"_s,
ZoomToFeature );
666 mAutoPanButton->setChecked(
false );
670 QgsSettings().setEnumValue( u
"/qgis/attributeTable/featureListBrowsingAction"_s,
NoAction );
673 if ( checked && mLayer->isSpatial() )
674 panOrZoomToFeature( mFeatureListView->currentEditSelection() );
677void QgsDualView::flashButtonClicked(
bool clicked )
683 QgsMapCanvas *canvas = mFilterModel->mapCanvas();
686 canvas->
flashFeatureIds( mLayer, mFeatureListView->currentEditSelection() );
689void QgsDualView::filterError(
const QString &errorMessage )
691 if ( mEditorContext.mainMessageBar() )
693 mEditorContext.mainMessageBar()->pushWarning( tr(
"An error occurred while filtering features" ), errorMessage );
697void QgsDualView::featureListAboutToChangeEditSelection(
bool &ok )
699 if ( !mAttributeForm )
702 if ( mLayer->isEditable() && !mAttributeForm->save() )
706void QgsDualView::featureListCurrentEditSelectionChanged(
const QgsFeature &feat )
708 if ( !mAttributeForm )
710 initAttributeForm( feat );
712 else if ( !mLayer->isEditable() || mAttributeForm->save() )
714 mAttributeForm->setFeature( feat );
716 featureset << feat.
id();
719 if ( mLayer->isSpatial() )
720 panOrZoomToFeature( featureset );
730 mFeatureListView->setCurrentFeatureEdited(
false );
731 mFeatureListView->setEditSelection( fids );
736 return mAttributeForm ? mAttributeForm->save() :
false;
741 mConditionalFormatWidgetStack->setVisible( !mConditionalFormatWidgetStack->isVisible() );
746 if ( !mAttributeForm )
751 mPreviousView =
view();
764 if ( !mAttributeForm )
771 mAttributeForm->setVisible(
true );
776 mAttributeForm->setVisible( mFilterModel->rowCount() > 0 );
780void QgsDualView::previewExpressionBuilder()
786 dlg.setWindowTitle( tr(
"Expression Based Preview" ) );
787 dlg.setExpressionText( mFeatureListView->displayExpression() );
789 if ( dlg.exec() == QDialog::Accepted )
791 mFeatureListView->setDisplayExpression( dlg.expressionText() );
792 mActionExpressionPreview->setToolTip( dlg.expressionText() );
794 mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
795 mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
798 setDisplayExpression( mFeatureListView->displayExpression() );
801void QgsDualView::previewColumnChanged( QAction *previewAction,
const QString &expression )
803 if ( !mFeatureListView->setDisplayExpression( u
"COALESCE( \"%1\", '<NULL>' )"_s.arg( expression ) ) )
805 QMessageBox::warning(
this, tr(
"Column Display Name" ), tr(
"Could not set column '%1' as display name.\nParser error:\n%2" ).arg( previewAction->text(), mFeatureListView->parserErrorString() ) );
809 mFeatureListPreviewButton->setText( previewAction->text() );
810 mFeatureListPreviewButton->setIcon( previewAction->icon() );
811 mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
814 setDisplayExpression( mFeatureListView->displayExpression() );
819 return mMasterModel->rowCount();
824 return mFilterModel->rowCount();
829 const QModelIndex currentIndex = mTableView->currentIndex();
830 if ( !currentIndex.isValid() )
835 const QVariant var = mMasterModel->data( currentIndex, Qt::DisplayRole );
836 QApplication::clipboard()->setText( var.toString() );
842 mProgressDlg->cancel();
847 if ( mAttributeForm )
849 mAttributeForm->parentFormValueChanged( attribute, newValue );
856 saveRecentDisplayExpressions();
863 conditionalFormattingSplitterState->setValue( mConditionalSplitter->saveState() );
864 attributeEditorSplitterState->setValue( mAttributeEditorViewSplitter->saveState() );
867void QgsDualView::viewWillShowContextMenu( QMenu *menu,
const QModelIndex &masterIndex )
874 const QVariant displayValue = mMasterModel->data( masterIndex, Qt::DisplayRole );
876 if ( displayValue.isValid() )
879 QString previewDisplayValue = displayValue.toString();
880 if ( previewDisplayValue.length() > 12 )
882 previewDisplayValue.truncate( 12 );
883 previewDisplayValue.append( u
"…"_s );
887 QAction *copyContentAction = menu->addAction( tr(
"Copy Cell Content (%1)" ).arg( previewDisplayValue ) );
888 menu->addAction( copyContentAction );
889 connect( copyContentAction, &QAction::triggered,
this, [displayValue] { QApplication::clipboard()->setText( displayValue.toString() ); } );
892 const QVariant rawValue = mMasterModel->data( masterIndex, Qt::EditRole );
893 if ( rawValue.isValid() )
896 QString previewRawValue = rawValue.toString();
897 if ( previewRawValue.length() > 12 )
899 previewRawValue.truncate( 12 );
900 previewRawValue.append( u
"…"_s );
903 QAction *copyRawContentAction = menu->addAction( tr(
"Copy Raw Value (%1)" ).arg( previewRawValue ) );
904 menu->addAction( copyRawContentAction );
905 connect( copyRawContentAction, &QAction::triggered,
this, [rawValue] { QApplication::clipboard()->setText( rawValue.toString() ); } );
908 QgsVectorLayer *vl = mFilterModel->layer();
909 QgsMapCanvas *canvas = mFilterModel->mapCanvas();
912 QAction *zoomToFeatureAction = menu->addAction( tr(
"Zoom to Feature" ) );
913 connect( zoomToFeatureAction, &QAction::triggered,
this, &QgsDualView::zoomToCurrentFeature );
915 QAction *panToFeatureAction = menu->addAction( tr(
"Pan to Feature" ) );
916 connect( panToFeatureAction, &QAction::triggered,
this, &QgsDualView::panToCurrentFeature );
918 QAction *flashFeatureAction = menu->addAction( tr(
"Flash Feature" ) );
919 connect( flashFeatureAction, &QAction::triggered,
this, &QgsDualView::flashCurrentFeature );
923 const QList<QgsAction> actions = mLayer->actions()->actions( u
"Field"_s );
924 if ( !actions.isEmpty() )
926 QAction *a = menu->addAction( tr(
"Run Layer Action" ) );
927 a->setEnabled(
false );
929 for (
const QgsAction &action : actions )
931 if ( !action.runable() )
934 if ( vl && !vl->
isEditable() && action.isEnabledOnlyWhenEditable() )
937 QgsAttributeTableAction *a =
new QgsAttributeTableAction( action.name(),
this, action.id(), masterIndex );
941 const QModelIndex rowSourceIndex = mMasterModel->index( masterIndex.row(), 0 );
942 if ( !rowSourceIndex.isValid() )
948 QgsMapLayerActionContext context;
950 if ( !registeredActions.isEmpty() )
953 menu->addSeparator();
955 for ( QgsMapLayerAction *action : registeredActions )
957 QgsAttributeTableMapLayerAction *a =
new QgsAttributeTableMapLayerAction( action->text(),
this, action, rowSourceIndex );
964 const QgsFeatureId currentFid = mMasterModel->rowToId( masterIndex.row() );
965 if ( mLayer->selectedFeatureCount() > 1 && mLayer->selectedFeatureIds().contains( currentFid ) )
968 if ( !registeredActions.isEmpty() )
970 menu->addSeparator();
971 QAction *action = menu->addAction( tr(
"Actions on Selection (%1)" ).arg( mLayer->selectedFeatureCount() ) );
972 action->setEnabled(
false );
974 QgsMapLayerActionContext context;
975 for ( QgsMapLayerAction *action : registeredActions )
977 menu->addAction( action->text(), action, [
this, action, context]() {
978 Q_NOWARN_DEPRECATED_PUSH
979 action->triggerForFeatures( mLayer, mLayer->selectedFeatures() );
980 Q_NOWARN_DEPRECATED_POP
981 action->triggerForFeatures( mLayer, mLayer->selectedFeatures(), context );
987 menu->addSeparator();
988 QgsAttributeTableAction *a =
new QgsAttributeTableAction( tr(
"Open Form" ),
this, QUuid(), rowSourceIndex );
993void QgsDualView::widgetWillShowContextMenu(
QgsActionMenu *menu,
const QModelIndex &atIndex )
999void QgsDualView::showViewHeaderMenu( QPoint point )
1001 const int col = mTableView->columnAt( point.x() );
1003 delete mHorizontalHeaderMenu;
1004 mHorizontalHeaderMenu =
new QMenu(
this );
1006 QAction *hide =
new QAction( tr(
"&Hide Column" ), mHorizontalHeaderMenu );
1007 connect( hide, &QAction::triggered,
this, &QgsDualView::hideColumn );
1008 hide->setData( col );
1009 mHorizontalHeaderMenu->addAction( hide );
1010 QAction *setWidth =
new QAction( tr(
"&Set Width…" ), mHorizontalHeaderMenu );
1011 connect( setWidth, &QAction::triggered,
this, &QgsDualView::resizeColumn );
1012 setWidth->setData( col );
1013 mHorizontalHeaderMenu->addAction( setWidth );
1015 QAction *setWidthAllColumns =
new QAction( tr(
"&Set All Column Widths…" ), mHorizontalHeaderMenu );
1016 connect( setWidthAllColumns, &QAction::triggered,
this, &QgsDualView::resizeAllColumns );
1017 setWidthAllColumns->setData( col );
1018 mHorizontalHeaderMenu->addAction( setWidthAllColumns );
1020 QAction *optimizeWidth =
new QAction( tr(
"&Autosize" ), mHorizontalHeaderMenu );
1021 connect( optimizeWidth, &QAction::triggered,
this, &QgsDualView::autosizeColumn );
1022 optimizeWidth->setData( col );
1023 mHorizontalHeaderMenu->addAction( optimizeWidth );
1025 QAction *optimizeWidthAllColumns =
new QAction( tr(
"&Autosize All Columns" ), mHorizontalHeaderMenu );
1026 connect( optimizeWidthAllColumns, &QAction::triggered,
this, &QgsDualView::autosizeAllColumns );
1027 mHorizontalHeaderMenu->addAction( optimizeWidthAllColumns );
1030 mHorizontalHeaderMenu->addSeparator();
1031 QAction *organize =
new QAction( tr(
"&Organize Columns…" ), mHorizontalHeaderMenu );
1032 connect( organize, &QAction::triggered,
this, &QgsDualView::organizeColumns );
1033 mHorizontalHeaderMenu->addAction( organize );
1034 QAction *sort =
new QAction( tr(
"&Sort…" ), mHorizontalHeaderMenu );
1035 connect( sort, &QAction::triggered,
this, [
this]() { modifySort(); } );
1036 mHorizontalHeaderMenu->addAction( sort );
1038 mConfig.update( mLayer->fields() );
1040 int fieldIndex = -1;
1042 fieldIndex = mLayer->fields().indexFromName( mConfig.columns().at( mConfig.mapVisibleColumnToIndex( col ) ).name );
1043 const Qgis::FieldOrigin fieldOrigin = mLayer->fields().fieldOrigin( fieldIndex );
1045 mHorizontalHeaderMenu->addSeparator();
1047 const QgsVectorLayer *vl = mFilterModel->layer();
1048 const QgsVectorDataProvider *dataProvider = vl->
dataProvider();
1050 const bool layerIsReadOnly { vl->
readOnly() };
1053 bool fieldCalculatorEnabled =
false;
1055 switch ( fieldOrigin )
1059 fieldCalculatorEnabled = canChangeAttributeValue;
1064 const QgsVectorLayerJoinInfo *info = mLayer->joinBuffer()->joinForFieldIndex( fieldIndex, mLayer->fields(), srcFieldIndex );
1065 const QgsVectorLayer *joinedLayer = info->
joinLayer();
1066 const QgsVectorDataProvider *joinedDataProvider = joinedLayer->
dataProvider();
1068 const bool joinedLayerIsReadOnly { joinedLayer->
readOnly() };
1071 fieldCalculatorEnabled = joinedLayerCanChangeAttributeValue;
1081 QAction *fieldCalculator =
new QAction( tr(
"Open &Field Calculator…" ), mHorizontalHeaderMenu );
1082 connect( fieldCalculator, &QAction::triggered,
this, &QgsDualView::fieldCalculator );
1083 fieldCalculator->setData( fieldIndex );
1084 mHorizontalHeaderMenu->addAction( fieldCalculator );
1086 fieldCalculator->setEnabled( fieldCalculatorEnabled );
1088 mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
1091void QgsDualView::organizeColumns()
1099 if ( dialog.exec() == QDialog::Accepted )
1101 const QgsAttributeTableConfig config = dialog.config();
1106void QgsDualView::tableColumnResized(
int column,
int width )
1108 QgsAttributeTableConfig config = mConfig;
1110 if ( sourceCol >= 0 && config.
columnWidth( sourceCol ) != width )
1117void QgsDualView::hideColumn()
1119 QAction *action = qobject_cast<QAction *>( sender() );
1120 const int col = action->data().toInt();
1121 QgsAttributeTableConfig config = mConfig;
1123 if ( sourceCol >= 0 )
1130void QgsDualView::fieldCalculator()
1132 QAction *action = qobject_cast<QAction *>( sender() );
1133 const int fieldIndex = action->data().toInt();
1134 mConfig.update( mLayer->fields() );
1135 QgsFieldCalculator calc( mLayer,
this, fieldIndex );
1136 if ( calc.exec() == QDialog::Accepted )
1138 int col = mMasterModel->fieldCol( calc.changedAttributeId() );
1141 mMasterModel->reload( mMasterModel->index( 0, col ), mMasterModel->index( mMasterModel->rowCount() - 1, col ) );
1145void QgsDualView::resizeColumn()
1147 QAction *action = qobject_cast<QAction *>( sender() );
1148 const int col = action->data().toInt();
1152 QgsAttributeTableConfig config = mConfig;
1154 if ( sourceCol >= 0 )
1157 const int width = QInputDialog::getInt(
this, tr(
"Set column width" ), tr(
"Enter column width" ), mTableView->columnWidth( col ), 0, 1000, 10, &ok );
1166void QgsDualView::resizeAllColumns()
1168 QAction *action = qobject_cast<QAction *>( sender() );
1169 const int col = action->data().toInt();
1173 QgsAttributeTableConfig config = mConfig;
1176 const int width = QInputDialog::getInt(
this, tr(
"Set Column Width" ), tr(
"Enter column width" ), mTableView->columnWidth( col ), 1, 1000, 10, &ok );
1179 const int colCount = mTableView->model()->columnCount();
1182 for (
int i = 0; i < colCount; i++ )
1191void QgsDualView::autosizeColumn()
1193 QAction *action = qobject_cast<QAction *>( sender() );
1194 const int col = action->data().toInt();
1195 mTableView->resizeColumnToContents( col );
1198void QgsDualView::autosizeAllColumns()
1200 mTableView->resizeColumnsToContents();
1203bool QgsDualView::modifySort()
1208 QgsAttributeTableConfig config = mConfig;
1211 orderByDlg.setWindowTitle( tr(
"Configure Attribute Table Sort Order" ) );
1212 QDialogButtonBox *dialogButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1213 QGridLayout *layout =
new QGridLayout();
1214 connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
1215 connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
1216 orderByDlg.setLayout( layout );
1218 QGroupBox *sortingGroupBox =
new QGroupBox();
1219 sortingGroupBox->setTitle( tr(
"Defined sort order in attribute table" ) );
1220 sortingGroupBox->setCheckable(
true );
1222 layout->addWidget( sortingGroupBox );
1223 sortingGroupBox->setLayout(
new QGridLayout() );
1225 QgsExpressionBuilderWidget *expressionBuilder =
new QgsExpressionBuilderWidget();
1228 expressionBuilder->
initWithLayer( mLayer, context, u
"generic"_s );
1231 sortingGroupBox->layout()->addWidget( expressionBuilder );
1233 QCheckBox *cbxSortAscending =
new QCheckBox( tr(
"Sort ascending" ) );
1234 cbxSortAscending->setChecked( config.
sortOrder() == Qt::AscendingOrder );
1235 sortingGroupBox->layout()->addWidget( cbxSortAscending );
1237 layout->addWidget( dialogButtonBox );
1238 if ( orderByDlg.exec() )
1240 const Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
1241 if ( sortingGroupBox->isChecked() )
1263 QSet<int> attributes;
1267 const QVector<QgsAttributeTableConfig::ColumnConfig> constColumnconfigs { config.
columns() };
1276 const QSet<int> colAttrs { attributes };
1277 for (
const int attrIdx : std::as_const( colAttrs ) )
1286 std::sort( attrs.begin(), attrs.end() );
1290void QgsDualView::zoomToCurrentFeature()
1292 const QModelIndex currentIndex = mTableView->currentIndex();
1293 if ( !currentIndex.isValid() )
1299 ids.insert( mFilterModel->rowToId( currentIndex ) );
1300 QgsMapCanvas *canvas = mFilterModel->mapCanvas();
1307void QgsDualView::panToCurrentFeature()
1309 const QModelIndex currentIndex = mTableView->currentIndex();
1310 if ( !currentIndex.isValid() )
1316 ids.insert( mFilterModel->rowToId( currentIndex ) );
1317 QgsMapCanvas *canvas = mFilterModel->mapCanvas();
1324void QgsDualView::flashCurrentFeature()
1326 const QModelIndex currentIndex = mTableView->currentIndex();
1327 if ( !currentIndex.isValid() )
1333 ids.insert( mFilterModel->rowToId( currentIndex ) );
1334 QgsMapCanvas *canvas = mFilterModel->mapCanvas();
1341void QgsDualView::rebuildFullLayerCache()
1346 mLayerCache->setFullCache(
true );
1349void QgsDualView::previewExpressionChanged(
const QString &expression )
1351 mLayer->setDisplayExpression( expression );
1354void QgsDualView::onSortColumnChanged()
1365void QgsDualView::updateSelectedFeatures()
1367 QgsFeatureRequest r = mMasterModel->request();
1372 mMasterModel->setRequest( r );
1373 mMasterModel->loadLayer();
1377void QgsDualView::updateEditedAddedFeatures()
1379 QgsFeatureRequest r = mMasterModel->request();
1384 mMasterModel->setRequest( r );
1385 mMasterModel->loadLayer();
1389void QgsDualView::extentChanged()
1391 QgsFeatureRequest r = mMasterModel->request();
1394 const QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() );
1396 mMasterModel->setRequest( r );
1397 mMasterModel->loadLayer();
1402void QgsDualView::featureFormAttributeChanged(
const QString &attribute,
const QVariant &value,
bool attributeChanged )
1404 Q_UNUSED( attribute )
1406 if ( attributeChanged )
1408 mFeatureListView->setCurrentFeatureEdited(
true );
1409 mAttributeForm->save();
1420 mFilterModel->setFilterExpression( filterExpression, context );
1421 mFilterModel->filterFeatures();
1427 mMasterModel->setRequest( request );
1432 mTableView->setFeatureSelectionManager( featureSelectionManager );
1433 mFeatureListView->setFeatureSelectionManager( featureSelectionManager );
1435 if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() ==
this )
1436 delete mFeatureSelectionManager;
1438 mFeatureSelectionManager = featureSelectionManager;
1444 mConfig.
update( mLayer->fields() );
1445 mLayer->setAttributeTableConfig( mConfig );
1446 mFilterModel->setAttributeTableConfig( mConfig );
1447 mTableView->setAttributeTableConfig( mConfig );
1453 mLayerCache->setCacheGeometry(
true );
1457 mMasterModel->setRequest( request );
1458 mLayerCache->setCacheSubsetOfAttributes( attributes );
1464 mFilterModel->sort( -1 );
1469 mConfig.setSortOrder( sortOrder );
1475 return mFilterModel->sortExpression();
1483void QgsDualView::progress(
int i,
bool &cancel )
1485 if ( !mProgressDlg )
1487 mProgressDlg =
new QProgressDialog( tr(
"Loading features…" ), tr(
"Abort" ), 0, 0,
this );
1488 mProgressDlg->setWindowTitle( tr(
"Attribute Table" ) );
1489 mProgressDlg->setWindowModality( Qt::WindowModal );
1490 mProgressDlg->show();
1493 mProgressDlg->setLabelText( tr(
"%L1 features loaded." ).arg( i ) );
1494 QCoreApplication::processEvents();
1496 cancel = mProgressDlg && mProgressDlg->wasCanceled();
1499void QgsDualView::finished()
1501 delete mProgressDlg;
1502 mProgressDlg =
nullptr;
1511 mDualView->masterModel()->executeAction( mAction, mFieldIdx );
1517 editedIds << mDualView->masterModel()->rowToId( mFieldIdx.row() );
1518 mDualView->setCurrentEditSelection( editedIds );
1529 mDualView->masterModel()->executeMapLayerAction( mAction, mFieldIdx, context );
@ SelectAtId
Fast access to features using their ID.
@ ChangeAttributeValues
Allows modification of attribute values.
@ NoFilter
No filter is applied.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ NoFilter
No spatial filtering of features.
@ MultipleFeatures
Action targets multiple features from a layer.
@ Layer
Action targets a complete layer.
@ SingleFeature
Action targets a single feature from a layer.
QFlags< VectorProviderCapability > VectorProviderCapabilities
Vector data provider capabilities.
@ Provider
Field originates from the underlying data provider of the vector layer.
@ Edit
Field has been temporarily added in editing mode.
@ Unknown
The field origin has not been specified.
@ Expression
Field is calculated from an expression.
@ Join
Field originates from a joined layer.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Contains context information for attribute editor widgets.
@ SearchMode
Form values are used for searching/filtering the layer.
@ SingleEditMode
Single edit mode, for editing a single feature.
@ MultiEditMode
Multi edit mode, for editing fields of multiple features at once.
const QgsAttributeEditorContext * parentContext() const
A container for configuration of the attribute table.
void setSortExpression(const QString &sortExpression)
Set the sort expression used for sorting.
@ Field
This column represents a field.
Qt::SortOrder sortOrder() const
Gets the sort order.
QVector< QgsAttributeTableConfig::ColumnConfig > columns() const
Gets the list with all columns and their configuration.
int mapVisibleColumnToIndex(int visibleColumn) const
Maps a visible column index to its original column index.
void update(const QgsFields &fields)
Update the configuration with the given fields.
void setSortOrder(Qt::SortOrder sortOrder)
Set the sort order.
int columnWidth(int column) const
Returns the width of a column, or -1 if column should use default width.
void setColumnHidden(int column, bool hidden)
Sets whether the specified column should be hidden.
QString sortExpression() const
Gets the expression used for sorting.
void setColumnWidth(int column, int width)
Sets the width of a column.
FilterMode
The filter mode defines how the rows should be filtered.
@ ShowFilteredList
Show only features whose ids are on the filter list. {.
@ ShowVisible
Show only visible features (depends on the map canvas).
@ ShowSelected
Show only selected features.
@ ShowInvalid
Show only features not respecting constraints.
@ ShowEdited
Show only features which have unsaved changes.
@ ShowAll
Show all features.
void filterError(const QString &errorMessage)
Emitted when an error occurred while filtering features.
void featuresFiltered()
Emitted when the filtering of the features has been done.
void visibleReloaded()
Emitted when the the visible features on extend are reloaded (the list is created).
void sortColumnChanged(int column, Qt::SortOrder order)
Emitted whenever the sort column is changed.
void fieldConditionalStyleChanged(const QString &fieldName)
Handles updating the model when the conditional style for a field changes.
void modelChanged()
Emitted when the model has been changed.
void progress(int i, bool &cancel)
void finished()
Emitted when the model has completely loaded all features.
void willShowContextMenu(QMenu *menu, const QModelIndex &atIndex)
Emitted in order to provide a hook to add additional* menu entries to the context menu.
void columnResized(int column, int width)
Emitted when a column in the view has been resized.
void showContextMenuExternally(QgsActionMenu *menu, QgsFeatureId fid)
Emitted when selecting context menu on the feature list to create the context menu individually.
void copyCellContent() const
Copy the content of the selected cell in the clipboard.
ViewMode
The view modes, in which this widget can present information.
@ AttributeEditor
Show a list of the features, where one can be chosen and the according attribute dialog will be prese...
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
Set the feature selection model.
static QgsAttributeList requiredAttributes(const QgsVectorLayer *layer)
Returns the list of required attributes according to the attribute table configuration of the layer,...
QgsAttributeTableFilterModel::FilterMode filterMode()
Gets the filter mode.
void setMultiEditEnabled(bool enabled)
Sets whether multi edit mode is enabled.
QgsFeatureIds filteredFeatures()
Gets a list of currently visible feature ids.
void cancelProgress()
Cancel the progress dialog (if any).
void filterChanged()
Emitted whenever the filter changes.
static const QgsSettingsEntryBool * settingsFeatureListHighlightFeature
static const QgsSettingsEntryInteger * settingsAttributeTableRowCache
QgsDualView(QWidget *parent=nullptr)
Constructor.
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table config which should be used to control the appearance of the attribute table.
ViewMode view() const
Returns the current view mode.
int featureCount()
Returns the number of features on the layer.
Q_DECL_DEPRECATED void setFilteredFeatures(const QgsFeatureIds &filteredFeatures)
Set a list of currently visible features.
void formModeChanged(QgsAttributeEditorContext::Mode mode)
Emitted when the form changes mode.
FeatureListBrowsingAction
Action on the map canvas when browsing the list of features.
@ NoAction
No action is done.
@ PanToFeature
The map is panned to the center of the feature bounding-box.
@ ZoomToFeature
The map is zoomed to contained the feature bounding-box.
void hideEvent(QHideEvent *event) override
QgsAttributeTableConfig attributeTableConfig() const
The config used for the attribute table.
void filterExpressionSet(const QString &expression, QgsAttributeForm::FilterType type)
Emitted when a filter expression is set using the view.
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.
bool saveEditChanges()
saveEditChanges
void openConditionalStyles()
void toggleSearchMode(bool enabled)
Toggles whether search mode should be enabled in the form.
void displayExpressionChanged(const QString &expression)
Emitted whenever the display expression is successfully changed.
void setSortExpression(const QString &sortExpression, Qt::SortOrder sortOrder=Qt::AscendingOrder)
Set the expression used for sorting the table and feature list.
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).
void setCurrentEditSelection(const QgsFeatureIds &fids)
Set the current edit selection in the AttributeEditor mode.
int filteredFeatureCount()
Returns the number of features which are currently visible, according to the filter restrictions.
QString sortExpression() const
Gets the expression used for sorting the table and feature list.
void setFilterMode(QgsAttributeTableFilterModel::FilterMode filterMode)
Set the filter mode.
void setView(ViewMode view)
Change the current view mode.
void setSelectedOnTop(bool selectedOnTop)
Toggle the selectedOnTop flag.
void filterFeatures(const QgsExpression &filterExpression, const QgsExpressionContext &context)
Sets the expression and Updates the filtered features in the filter model.
A generic dialog for building expression strings.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Handles parsing and evaluation of expressions (formerly called "search strings").
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
@ FeatureRole
Feature with all attributes and no geometry.
Shows a list of features and renders an edit button next to each feature.
void currentEditSelectionProgressChanged(int progress, int count)
Emitted whenever the current edit selection has been changed.
void editNextFeature()
editNextFeature will try to edit next feature of the list
void editLastFeature()
editLastFeature will try to edit the last feature of the list
void editFirstFeature()
editFirstFeature will try to edit the first feature of the list
void displayExpressionChanged(const QString &expression)
Emitted whenever the display expression is successfully changed.
void editPreviousFeature()
editPreviousFeature will try to edit previous feature of the list
void willShowContextMenu(QgsActionMenu *menu, const QModelIndex &atIndex)
Emitted when the context menu is created to add the specific actions to it.
void currentEditSelectionChanged(QgsFeature &feat)
Emitted whenever the current edit selection has been changed.
void aboutToChangeEditSelection(bool &ok)
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsRectangle filterRect() const
Returns the rectangle from which features will be taken.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
Qgis::FeatureRequestFilterType filterType() const
Returns the attribute/ID filter type which is currently set on this request.
Qgis::FeatureRequestFlags flags() const
Returns the flags which affect how features are fetched.
QgsFeatureRequest & disableFilter()
Disables any attribute/ID filtering.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Qgis::SpatialFilterType spatialFilterType() const
Returns the spatial filter type which is currently set on this request.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Qgis::FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
static QgsShortcutsManager * shortcutsManager()
Returns the global shortcuts manager, used for managing a QAction and QShortcut sequences.
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Is an interface class to abstract feature selection handling.
static long zoomToMatchingFeatures(QgsMapCanvas *canvas, QgsVectorLayer *layer, const QString &filter)
Zooms a map canvas to features from the specified layer which match the given filter expression strin...
static long flashMatchingFeatures(QgsMapCanvas *canvas, QgsVectorLayer *layer, const QString &filter)
Flashes features from the specified layer which match the given filter expression string with a map c...
Map canvas is a class for displaying all GIS data types on a canvas.
void extentsChanged()
Emitted when the extents of the map change.
void panToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids, bool alwaysRecenter=true)
Centers canvas extent to feature ids.
void flashFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids, const QColor &startColor=QColor(255, 0, 0, 255), const QColor &endColor=QColor(255, 0, 0, 0), int flashes=3, int duration=500)
Causes a set of features with matching ids from a vector layer to flash within the canvas.
void zoomToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Set canvas extent to the bounding box of a set of features.
Encapsulates the context in which a QgsMapLayerAction action is executed.
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, Qgis::MapLayerActionTargets targets=Qgis::MapLayerActionTarget::AllActions, const QgsMapLayerActionContext &context=QgsMapLayerActionContext())
Returns the map layer actions which can run on the specified layer.
void layerModified()
Emitted when modifications has been done on layer.
A rectangle specified with double values.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
A boolean settings entry.
An integer settings entry.
A variant settings entry.
static QgsSettingsTreeNode * sTreeAttributeTable
static QgsSettingsTreeNode * sTreeWindowState
Stores settings for use within QGIS.
T enumValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on an enum.
QShortcut * shortcutByName(const QString &name) const
Returns a shortcut by its name, or nullptr if nothing found.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
virtual Q_INVOKABLE Qgis::VectorProviderCapabilities capabilities() const
Returns flags containing the supported capabilities.
Caches features for a given QgsVectorLayer.
void finished()
When filling the cache, this signal gets emitted once the cache is fully initialized.
void invalidated()
The cache has been invalidated and cleared.
void setCacheSubsetOfAttributes(const QgsAttributeList &attributes)
Set the list (possibly a subset) of attributes to be cached.
void progress(int i, bool &cancel)
When filling the cache, this signal gets emitted periodically to notify about the progress and to be ...
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet).
Represents a vector layer which manages a vector based dataset.
bool isEditable() const final
Returns true if the provider is in editing mode.
bool isSpatial() const final
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QString expressionField(int index) const
Returns the expression used for a given expression field.
void afterCommitChanges()
Emitted after changes are committed to the data provider.
QgsAttributeTableConfig attributeTableConfig() const
Returns the attribute table configuration object.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
Defines the configuration of a column in the attribute table.