20#include <QProgressDialog>
22#include <QInputDialog>
30#include "moc_qgsdualview.cpp"
51const std::unique_ptr<QgsSettingsEntryVariant> QgsDualView::conditionalFormattingSplitterState = std::make_unique<QgsSettingsEntryVariant>( QStringLiteral(
"attribute-table-splitter-state" ),
QgsSettingsTree::sTreeWindowState,
QgsVariantUtils::createNullVariant( QMetaType::Type::QByteArray ), QStringLiteral(
"State of conditionnal formatting splitter's layout so it could be restored when opening attribute table view." ) );
52const std::unique_ptr<QgsSettingsEntryVariant> QgsDualView::attributeEditorSplitterState = std::make_unique<QgsSettingsEntryVariant>( QStringLiteral(
"attribute-editor-splitter-state" ),
QgsSettingsTree::sTreeWindowState,
QgsVariantUtils::createNullVariant( QMetaType::Type::QByteArray ), QStringLiteral(
"State of attribute editor splitter's layout so it could be restored when opening attribute editor view." ) );
55 : QStackedWidget( parent )
64 mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
65 connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested,
this, &QgsDualView::showViewHeaderMenu );
68 mConditionalFormatWidgetStack->hide();
70 mConditionalFormatWidgetStack->setMainPanel( mConditionalFormatWidget );
75 conditionalFormattingSplitterState->copyValueFromKey( QStringLiteral(
"/qgis/attributeTable/splitterState" ),
true );
76 mConditionalSplitter->restoreState( conditionalFormattingSplitterState->value().toByteArray() );
77 mAttributeEditorViewSplitter->restoreState( attributeEditorSplitterState->value().toByteArray() );
79 mPreviewColumnsMenu =
new QMenu(
this );
80 mActionPreviewColumnsMenu->setMenu( mPreviewColumnsMenu );
86 connect( mActionExpressionPreview, &QAction::triggered,
this, &QgsDualView::previewExpressionBuilder );
95 auto createShortcuts = [
this](
const QString &objectName, void (
QgsFeatureListView::*slot )() ) {
100 connect( sc, &QShortcut::activated, mFeatureListView, slot );
107 QButtonGroup *buttonGroup =
new QButtonGroup(
this );
108 buttonGroup->setExclusive(
false );
112 QAbstractButton *bt = buttonGroup->button(
static_cast<int>( action ) );
114 bt->setChecked(
true );
115 connect( buttonGroup, qOverload<QAbstractButton *, bool>( &QButtonGroup::buttonToggled ),
this, &QgsDualView::panZoomGroupButtonToggled );
116 mFlashButton->setChecked(
QgsSettings().value( QStringLiteral(
"/qgis/attributeTable/featureListHighlightFeature" ),
true ).toBool() );
117 connect( mFlashButton, &QToolButton::clicked,
this, &QgsDualView::flashButtonClicked );
129 delete mAttributeForm;
130 mAttributeForm =
nullptr;
139 mEditorContext = context;
151 initLayerCache( needsGeometry );
152 initModels( mapCanvas, request, loadFeatures );
154 mConditionalFormatWidget->
setLayer( mLayer );
156 mTableView->setModel( mFilterModel );
157 mFeatureListView->setModel( mFeatureListModel );
162 if ( mFeatureListPreviewButton->defaultAction() )
163 mFeatureListView->setDisplayExpression( mDisplayExpression );
170 if ( showFirstFeature && mFeatureListModel->
rowCount() > 0 )
174void QgsDualView::initAttributeForm(
const QgsFeature &feature )
176 Q_ASSERT( !mAttributeForm );
182 mAttributeEditorScrollArea->setWidgetResizable(
true );
183 mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
184 mAttributeEditorScrollArea->setWidget( mAttributeForm );
188 mAttributeEditor->layout()->addWidget( mAttributeForm );
193 mAttributeForm->setMinimumWidth( 200 );
203 QgsMapCanvasUtils::flashMatchingFeatures( canvas, mLayer, filter );
209 QgsMapCanvasUtils::zoomToMatchingFeatures( canvas, mLayer, filter );
216void QgsDualView::columnBoxInit()
219 const QList<QgsField> fields = mLayer->fields().toList();
221 const QString defaultField;
223 mFeatureListPreviewButton->addAction( mActionExpressionPreview );
224 mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
226 const auto constFields = fields;
227 for (
const QgsField &field : constFields )
229 const int fieldIndex = mLayer->fields().lookupField( field.name() );
230 if ( fieldIndex == -1 )
233 const QString fieldName = field.name();
236 const QIcon icon = mLayer->fields().iconForField( fieldIndex );
237 const QString text = mLayer->attributeDisplayName( fieldIndex );
240 QAction *previewAction =
new QAction( icon, text, mFeatureListPreviewButton );
241 connect( previewAction, &QAction::triggered,
this, [
this, previewAction, fieldName] { previewColumnChanged( previewAction, fieldName ); } );
242 mPreviewColumnsMenu->addAction( previewAction );
244 if ( text == defaultField )
246 mFeatureListPreviewButton->setDefaultAction( previewAction );
251 QMenu *sortMenu =
new QMenu(
this );
253 sortMenuAction->setMenu( sortMenu );
255 QAction *sortByPreviewExpressionAsc =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"sort.svg" ) ), tr(
"By Preview Expression (ascending)" ),
this );
256 connect( sortByPreviewExpressionAsc, &QAction::triggered,
this, [
this]() {
259 sortMenu->addAction( sortByPreviewExpressionAsc );
260 QAction *sortByPreviewExpressionDesc =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"sort-reverse.svg" ) ), tr(
"By Preview Expression (descending)" ),
this );
261 connect( sortByPreviewExpressionDesc, &QAction::triggered,
this, [
this]() {
264 sortMenu->addAction( sortByPreviewExpressionDesc );
265 QAction *sortByPreviewExpressionCustom =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"mIconExpressionPreview.svg" ) ), tr(
"By Custom Expression" ),
this );
266 connect( sortByPreviewExpressionCustom, &QAction::triggered,
this, [
this]() {
270 sortMenu->addAction( sortByPreviewExpressionCustom );
272 mFeatureListPreviewButton->addAction( sortMenuAction );
274 QAction *separator =
new QAction( mFeatureListPreviewButton );
275 separator->setSeparator(
true );
276 mFeatureListPreviewButton->addAction( separator );
277 restoreRecentDisplayExpressions();
280 if ( !mFeatureListPreviewButton->defaultAction() )
282 mFeatureListView->setDisplayExpression( mLayer->displayExpression() );
283 mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
284 const QString displayExpression = mFeatureListView->displayExpression();
285 setDisplayExpression( displayExpression.isEmpty() ? tr(
"'[Please define preview text]'" ) : displayExpression );
289 mFeatureListPreviewButton->defaultAction()->trigger();
295 setCurrentIndex(
view );
342 || ( mMasterModel->
rowCount() == 0 );
373 filterFeatures( QStringLiteral(
"is_feature_valid() = false" ), context );
383 if ( !filterExpression.isEmpty() )
400 setBrowsingAutoPanScaleAllowed(
false );
408 setBrowsingAutoPanScaleAllowed(
true );
412 if ( requiresTableReload )
418 whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry );
432void QgsDualView::initLayerCache(
bool cacheGeometry )
436 const int cacheSize = settings.
value( QStringLiteral(
"qgis/attributeTableRowCache" ),
"10000" ).toInt();
443 rebuildFullLayerCache();
449 delete mFeatureListModel;
470 connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
471 connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
478void QgsDualView::restoreRecentDisplayExpressions()
480 const QVariantList previewExpressions = mLayer->customProperty( QStringLiteral(
"dualview/previewExpressions" ) ).toList();
482 for (
const QVariant &previewExpression : previewExpressions )
483 insertRecentlyUsedDisplayExpression( previewExpression.toString() );
486void QgsDualView::saveRecentDisplayExpressions()
const
492 const QList<QAction *> actions = mFeatureListPreviewButton->actions();
495 int index = actions.indexOf( mLastDisplayExpressionAction );
498 QVariantList previewExpressions;
499 for ( ; index < actions.length(); ++index )
501 QAction *action = actions.at( index );
502 previewExpressions << action->property(
"previewExpression" );
505 mLayer->setCustomProperty( QStringLiteral(
"dualview/previewExpressions" ), previewExpressions );
509void QgsDualView::setDisplayExpression(
const QString &expression )
511 mDisplayExpression = expression;
512 insertRecentlyUsedDisplayExpression( expression );
515void QgsDualView::insertRecentlyUsedDisplayExpression(
const QString &expression )
517 const QList<QAction *> actions = mFeatureListPreviewButton->actions();
520 const int index = actions.indexOf( mLastDisplayExpressionAction );
523 for (
int i = 0; index + i < actions.length(); ++i )
525 QAction *action = actions.at( index );
526 if ( action->text() == expression || i >= 9 )
528 if ( action == mLastDisplayExpressionAction )
529 mLastDisplayExpressionAction =
nullptr;
530 mFeatureListPreviewButton->removeAction( action );
534 if ( !mLastDisplayExpressionAction )
535 mLastDisplayExpressionAction = action;
540 QString name = expression;
542 if ( expression.startsWith( QLatin1String(
"COALESCE( \"" ) ) && expression.endsWith( QLatin1String(
", '<NULL>' )" ) ) )
544 name = expression.mid( 11, expression.length() - 24 );
546 const int fieldIndex = mLayer->fields().indexOf( name );
547 if ( fieldIndex != -1 )
549 name = mLayer->attributeDisplayName( fieldIndex );
550 icon = mLayer->fields().iconForField( fieldIndex );
558 QAction *previewAction =
new QAction( icon, name, mFeatureListPreviewButton );
559 previewAction->setProperty(
"previewExpression", expression );
560 connect( previewAction, &QAction::triggered,
this, [expression,
this](
bool ) {
561 setDisplayExpression( expression );
562 mFeatureListPreviewButton->setText( expression );
565 mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
566 mLastDisplayExpressionAction = previewAction;
569void QgsDualView::updateEditSelectionProgress(
int progress,
int count )
571 mProgressCount->setText( QStringLiteral(
"%1 / %2" ).arg( progress + 1 ).arg( count ) );
572 mPreviousFeatureButton->setEnabled( progress > 0 );
573 mNextFeatureButton->setEnabled( progress + 1 < count );
574 mFirstFeatureButton->setEnabled( progress > 0 );
575 mLastFeatureButton->setEnabled( progress + 1 < count );
576 if ( mAttributeForm )
578 mAttributeForm->setVisible( count > 0 );
582void QgsDualView::panOrZoomToFeature(
const QgsFeatureIds &featureset )
587 if ( mBrowsingAutoPanScaleAllowed )
589 if ( mAutoPanButton->isChecked() )
590 QTimer::singleShot( 0,
this, [
this, featureset, canvas]() {
593 else if ( mAutoZoomButton->isChecked() )
594 QTimer::singleShot( 0,
this, [
this, featureset, canvas]() {
598 if ( mFlashButton->isChecked() )
599 QTimer::singleShot( 0,
this, [
this, featureset, canvas]() {
602 mLastFeatureSet = featureset;
606void QgsDualView::setBrowsingAutoPanScaleAllowed(
bool allowed )
608 if ( mBrowsingAutoPanScaleAllowed == allowed )
611 mBrowsingAutoPanScaleAllowed = allowed;
613 mAutoPanButton->setEnabled( allowed );
614 mAutoZoomButton->setEnabled( allowed );
616 const QString disabledHint = tr(
"(disabled when attribute table only shows features visible in the current map canvas extent)" );
618 mAutoPanButton->setToolTip( tr(
"Automatically pan to the current feature" ) + ( allowed ? QString() : QString(
' ' ) + disabledHint ) );
619 mAutoZoomButton->setToolTip( tr(
"Automatically zoom to the current feature" ) + ( allowed ? QString() : QString(
' ' ) + disabledHint ) );
622void QgsDualView::panZoomGroupButtonToggled( QAbstractButton *button,
bool checked )
624 if ( button == mAutoPanButton && checked )
627 mAutoZoomButton->setChecked(
false );
629 else if ( button == mAutoZoomButton && checked )
632 mAutoPanButton->setChecked(
false );
639 if ( checked && mLayer->isSpatial() )
640 panOrZoomToFeature( mFeatureListView->currentEditSelection() );
643void QgsDualView::flashButtonClicked(
bool clicked )
645 QgsSettings().
setValue( QStringLiteral(
"/qgis/attributeTable/featureListHighlightFeature" ), clicked );
652 canvas->
flashFeatureIds( mLayer, mFeatureListView->currentEditSelection() );
655void QgsDualView::filterError(
const QString &errorMessage )
663void QgsDualView::featureListAboutToChangeEditSelection(
bool &ok )
665 if ( !mAttributeForm )
668 if ( mLayer->isEditable() && !mAttributeForm->
save() )
672void QgsDualView::featureListCurrentEditSelectionChanged(
const QgsFeature &feat )
674 if ( !mAttributeForm )
676 initAttributeForm( feat );
678 else if ( !mLayer->isEditable() || mAttributeForm->
save() )
682 featureset << feat.
id();
685 if ( mLayer->isSpatial() )
686 panOrZoomToFeature( featureset );
696 mFeatureListView->setCurrentFeatureEdited(
false );
697 mFeatureListView->setEditSelection( fids );
702 return mAttributeForm ? mAttributeForm->
save() :
false;
707 mConditionalFormatWidgetStack->setVisible( !mConditionalFormatWidgetStack->isVisible() );
712 if ( !mAttributeForm )
717 mPreviousView =
view();
730 if ( !mAttributeForm )
737 mAttributeForm->setVisible(
true );
742 mAttributeForm->setVisible( mFilterModel->rowCount() > 0 );
746void QgsDualView::previewExpressionBuilder()
752 dlg.setWindowTitle( tr(
"Expression Based Preview" ) );
753 dlg.setExpressionText( mFeatureListView->displayExpression() );
755 if ( dlg.exec() == QDialog::Accepted )
757 mFeatureListView->setDisplayExpression( dlg.expressionText() );
758 mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
759 mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
762 setDisplayExpression( mFeatureListView->displayExpression() );
765void QgsDualView::previewColumnChanged( QAction *previewAction,
const QString &expression )
767 if ( !mFeatureListView->setDisplayExpression( QStringLiteral(
"COALESCE( \"%1\", '<NULL>' )" ).arg( expression ) ) )
769 QMessageBox::warning(
this, tr(
"Column Preview" ), tr(
"Could not set column '%1' as preview column.\nParser error:\n%2" ).arg( previewAction->text(), mFeatureListView->parserErrorString() ) );
773 mFeatureListPreviewButton->setText( previewAction->text() );
774 mFeatureListPreviewButton->setIcon( previewAction->icon() );
775 mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
778 setDisplayExpression( mFeatureListView->displayExpression() );
788 return mFilterModel->rowCount();
793 const QModelIndex currentIndex = mTableView->currentIndex();
794 if ( !currentIndex.isValid() )
799 const QVariant var = mMasterModel->
data( currentIndex, Qt::DisplayRole );
800 QApplication::clipboard()->setText( var.toString() );
806 mProgressDlg->cancel();
811 if ( mAttributeForm )
820 saveRecentDisplayExpressions();
827 conditionalFormattingSplitterState->setValue( mConditionalSplitter->saveState() );
828 attributeEditorSplitterState->setValue( mAttributeEditorViewSplitter->saveState() );
831void QgsDualView::viewWillShowContextMenu( QMenu *menu,
const QModelIndex &masterIndex )
838 QAction *copyContentAction = menu->addAction( tr(
"Copy Cell Content" ) );
839 menu->addAction( copyContentAction );
840 connect( copyContentAction, &QAction::triggered,
this, [masterIndex,
this] {
841 const QVariant var = mMasterModel->
data( masterIndex, Qt::DisplayRole );
842 QApplication::clipboard()->setText( var.toString() );
847 if ( canvas && vl && vl->isSpatial() )
849 QAction *zoomToFeatureAction = menu->addAction( tr(
"Zoom to Feature" ) );
850 connect( zoomToFeatureAction, &QAction::triggered,
this, &QgsDualView::zoomToCurrentFeature );
852 QAction *panToFeatureAction = menu->addAction( tr(
"Pan to Feature" ) );
853 connect( panToFeatureAction, &QAction::triggered,
this, &QgsDualView::panToCurrentFeature );
855 QAction *flashFeatureAction = menu->addAction( tr(
"Flash Feature" ) );
856 connect( flashFeatureAction, &QAction::triggered,
this, &QgsDualView::flashCurrentFeature );
860 const QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral(
"Field" ) );
861 if ( !actions.isEmpty() )
863 QAction *a = menu->addAction( tr(
"Run Layer Action" ) );
864 a->setEnabled(
false );
866 for (
const QgsAction &action : actions )
868 if ( !action.runable() )
871 if ( vl && !vl->isEditable() && action.isEnabledOnlyWhenEditable() )
878 const QModelIndex rowSourceIndex = mMasterModel->index( masterIndex.row(), 0 );
879 if ( !rowSourceIndex.isValid() )
887 if ( !registeredActions.isEmpty() )
890 menu->addSeparator();
902 if ( mLayer->selectedFeatureCount() > 1 && mLayer->selectedFeatureIds().contains( currentFid ) )
905 if ( !registeredActions.isEmpty() )
907 menu->addSeparator();
908 QAction *action = menu->addAction( tr(
"Actions on Selection (%1)" ).arg( mLayer->selectedFeatureCount() ) );
909 action->setEnabled(
false );
914 menu->addAction( action->text(), action, [
this, action, context]() {
915 Q_NOWARN_DEPRECATED_PUSH
916 action->triggerForFeatures( mLayer, mLayer->selectedFeatures() );
917 Q_NOWARN_DEPRECATED_POP
918 action->triggerForFeatures( mLayer, mLayer->selectedFeatures(), context );
924 menu->addSeparator();
930void QgsDualView::widgetWillShowContextMenu(
QgsActionMenu *menu,
const QModelIndex &atIndex )
936void QgsDualView::showViewHeaderMenu( QPoint point )
938 const int col = mTableView->columnAt( point.x() );
940 delete mHorizontalHeaderMenu;
941 mHorizontalHeaderMenu =
new QMenu(
this );
943 QAction *hide =
new QAction( tr(
"&Hide Column" ), mHorizontalHeaderMenu );
944 connect( hide, &QAction::triggered,
this, &QgsDualView::hideColumn );
945 hide->setData( col );
946 mHorizontalHeaderMenu->addAction( hide );
947 QAction *setWidth =
new QAction( tr(
"&Set Width…" ), mHorizontalHeaderMenu );
948 connect( setWidth, &QAction::triggered,
this, &QgsDualView::resizeColumn );
949 setWidth->setData( col );
950 mHorizontalHeaderMenu->addAction( setWidth );
952 QAction *setWidthAllColumns =
new QAction( tr(
"&Set All Column Widths…" ), mHorizontalHeaderMenu );
953 connect( setWidthAllColumns, &QAction::triggered,
this, &QgsDualView::resizeAllColumns );
954 setWidthAllColumns->setData( col );
955 mHorizontalHeaderMenu->addAction( setWidthAllColumns );
957 QAction *optimizeWidth =
new QAction( tr(
"&Autosize" ), mHorizontalHeaderMenu );
958 connect( optimizeWidth, &QAction::triggered,
this, &QgsDualView::autosizeColumn );
959 optimizeWidth->setData( col );
960 mHorizontalHeaderMenu->addAction( optimizeWidth );
962 QAction *optimizeWidthAllColumns =
new QAction( tr(
"&Autosize All Columns" ), mHorizontalHeaderMenu );
963 connect( optimizeWidthAllColumns, &QAction::triggered,
this, &QgsDualView::autosizeAllColumns );
964 mHorizontalHeaderMenu->addAction( optimizeWidthAllColumns );
967 mHorizontalHeaderMenu->addSeparator();
968 QAction *organize =
new QAction( tr(
"&Organize Columns…" ), mHorizontalHeaderMenu );
969 connect( organize, &QAction::triggered,
this, &QgsDualView::organizeColumns );
970 mHorizontalHeaderMenu->addAction( organize );
971 QAction *sort =
new QAction( tr(
"&Sort…" ), mHorizontalHeaderMenu );
972 connect( sort, &QAction::triggered,
this, [
this]() { modifySort(); } );
973 mHorizontalHeaderMenu->addAction( sort );
975 mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
978void QgsDualView::organizeColumns()
986 if ( dialog.exec() == QDialog::Accepted )
993void QgsDualView::tableColumnResized(
int column,
int width )
997 if ( sourceCol >= 0 && config.
columnWidth( sourceCol ) != width )
1004void QgsDualView::hideColumn()
1006 QAction *action = qobject_cast<QAction *>( sender() );
1007 const int col = action->data().toInt();
1010 if ( sourceCol >= 0 )
1017void QgsDualView::resizeColumn()
1019 QAction *action = qobject_cast<QAction *>( sender() );
1020 const int col = action->data().toInt();
1026 if ( sourceCol >= 0 )
1029 const int width = QInputDialog::getInt(
this, tr(
"Set column width" ), tr(
"Enter column width" ), mTableView->columnWidth( col ), 0, 1000, 10, &ok );
1038void QgsDualView::resizeAllColumns()
1040 QAction *action = qobject_cast<QAction *>( sender() );
1041 const int col = action->data().toInt();
1048 const int width = QInputDialog::getInt(
this, tr(
"Set Column Width" ), tr(
"Enter column width" ), mTableView->columnWidth( col ), 1, 1000, 10, &ok );
1051 const int colCount = mTableView->model()->columnCount();
1054 for (
int i = 0; i < colCount; i++ )
1063void QgsDualView::autosizeColumn()
1065 QAction *action = qobject_cast<QAction *>( sender() );
1066 const int col = action->data().toInt();
1067 mTableView->resizeColumnToContents( col );
1070void QgsDualView::autosizeAllColumns()
1072 mTableView->resizeColumnsToContents();
1075bool QgsDualView::modifySort()
1083 orderByDlg.setWindowTitle( tr(
"Configure Attribute Table Sort Order" ) );
1084 QDialogButtonBox *dialogButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1085 QGridLayout *layout =
new QGridLayout();
1086 connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
1087 connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
1088 orderByDlg.setLayout( layout );
1090 QGroupBox *sortingGroupBox =
new QGroupBox();
1091 sortingGroupBox->setTitle( tr(
"Defined sort order in attribute table" ) );
1092 sortingGroupBox->setCheckable(
true );
1094 layout->addWidget( sortingGroupBox );
1095 sortingGroupBox->setLayout(
new QGridLayout() );
1100 expressionBuilder->
initWithLayer( mLayer, context, QStringLiteral(
"generic" ) );
1103 sortingGroupBox->layout()->addWidget( expressionBuilder );
1105 QCheckBox *cbxSortAscending =
new QCheckBox( tr(
"Sort ascending" ) );
1106 cbxSortAscending->setChecked( config.
sortOrder() == Qt::AscendingOrder );
1107 sortingGroupBox->layout()->addWidget( cbxSortAscending );
1109 layout->addWidget( dialogButtonBox );
1110 if ( orderByDlg.exec() )
1112 const Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
1113 if ( sortingGroupBox->isChecked() )
1135 QSet<int> attributes;
1139 const QVector<QgsAttributeTableConfig::ColumnConfig> constColumnconfigs { config.
columns() };
1148 const QSet<int> colAttrs { attributes };
1149 for (
const int attrIdx : std::as_const( colAttrs ) )
1158 std::sort( attrs.begin(), attrs.end() );
1162void QgsDualView::zoomToCurrentFeature()
1164 const QModelIndex currentIndex = mTableView->currentIndex();
1165 if ( !currentIndex.isValid() )
1171 ids.insert( mFilterModel->
rowToId( currentIndex ) );
1179void QgsDualView::panToCurrentFeature()
1181 const QModelIndex currentIndex = mTableView->currentIndex();
1182 if ( !currentIndex.isValid() )
1188 ids.insert( mFilterModel->
rowToId( currentIndex ) );
1196void QgsDualView::flashCurrentFeature()
1198 const QModelIndex currentIndex = mTableView->currentIndex();
1199 if ( !currentIndex.isValid() )
1205 ids.insert( mFilterModel->
rowToId( currentIndex ) );
1213void QgsDualView::rebuildFullLayerCache()
1221void QgsDualView::previewExpressionChanged(
const QString &expression )
1223 mLayer->setDisplayExpression( expression );
1226void QgsDualView::onSortColumnChanged()
1237void QgsDualView::updateSelectedFeatures()
1249void QgsDualView::updateEditedAddedFeatures()
1261void QgsDualView::extentChanged()
1274void QgsDualView::featureFormAttributeChanged(
const QString &attribute,
const QVariant &value,
bool attributeChanged )
1276 Q_UNUSED( attribute )
1278 if ( attributeChanged )
1280 mFeatureListView->setCurrentFeatureEdited(
true );
1281 mAttributeForm->
save();
1304 mTableView->setFeatureSelectionManager( featureSelectionManager );
1305 mFeatureListView->setFeatureSelectionManager( featureSelectionManager );
1307 if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() ==
this )
1308 delete mFeatureSelectionManager;
1310 mFeatureSelectionManager = featureSelectionManager;
1316 mConfig.
update( mLayer->fields() );
1317 mLayer->setAttributeTableConfig( mConfig );
1319 mTableView->setAttributeTableConfig( mConfig );
1336 mFilterModel->
sort( -1 );
1355void QgsDualView::progress(
int i,
bool &cancel )
1357 if ( !mProgressDlg )
1359 mProgressDlg =
new QProgressDialog( tr(
"Loading features…" ), tr(
"Abort" ), 0, 0,
this );
1360 mProgressDlg->setWindowTitle( tr(
"Attribute Table" ) );
1361 mProgressDlg->setWindowModality( Qt::WindowModal );
1362 mProgressDlg->show();
1365 mProgressDlg->setLabelText( tr(
"%L1 features loaded." ).arg( i ) );
1366 QCoreApplication::processEvents();
1368 cancel = mProgressDlg && mProgressDlg->wasCanceled();
1371void QgsDualView::finished()
1373 delete mProgressDlg;
1374 mProgressDlg =
nullptr;
@ SelectAtId
Fast access to features using their ID.
@ 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.
@ Expression
Field is calculated from an expression.
Utility class that encapsulates an action based on vector attributes.
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.
QgsMessageBar * mainMessageBar()
Returns the main message bar.
@ 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
This is 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.
QString sortExpression() const
The expression which is used to sort the attribute table.
FilterMode filterMode()
The current filterModel.
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Sort by the given column using the given order.
QgsMapCanvas * mapCanvas() const
Returns the map canvas.
void setFilterMode(FilterMode filterMode)
Set the filter mode the filter will use.
QString filterExpression() const
Returns the stored filter expression string.
void setAttributeTableConfig(const QgsAttributeTableConfig &config, bool force=false)
Set the attribute table configuration to control which fields are shown, in which order they are show...
void disconnectFilterModeConnections()
Disconnect the connections set for the current filterMode.
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 filterFeatures()
Updates the filtered features in the filter model.
void setFilterExpression(const QgsExpression &expression, const QgsExpressionContext &context)
Set the expression and the context to be stored in case of the features need to be filtered again (li...
virtual void setFilteredFeatures(const QgsFeatureIds &ids)
Specify a list of features, which the filter will accept.
QgsFeatureId rowToId(const QModelIndex &row)
Returns the feature id for a given model index.
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)
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
void setSelectedOnTop(bool selectedOnTop)
Changes the sort order of the features.
void sortColumnChanged(int column, Qt::SortOrder order)
Emitted whenever the sort column is changed.
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
const QgsFeatureRequest & request() const
Gets the the feature request.
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 executeMapLayerAction(QgsMapLayerAction *action, const QModelIndex &idx, const QgsMapLayerActionContext &context=QgsMapLayerActionContext()) const
Execute a QgsMapLayerAction.
void progress(int i, bool &cancel)
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
void setEditorContext(const QgsAttributeEditorContext &context)
Sets the context in which this table is shown.
void finished()
Emitted when the model has completely loaded all features.
void setShowValidityState(bool show)
Sets whether the attribute table will add a visual feedback to cells when an attribute constraint is ...
QgsFeatureId rowToId(int row) const
Maps row to feature id.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
void setExtraColumns(int extraColumns)
Empty extra columns to announce from this model.
void executeAction(QUuid action, const QModelIndex &idx) const
Execute an action.
QVariant data(const QModelIndex &index, int role) const override
Returns data on the given index.
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.
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...
Class for 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.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void setSortByDisplayExpression(bool sortByDisplayExpression, Qt::SortOrder order=Qt::AscendingOrder)
Sort this model by its display expression.
QVariant data(const QModelIndex &index, int role) const override
Shows a list of features and renders a 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)
This class 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...
Encapsulate a field in an attribute table or data source.
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.
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.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
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.
An action which can run on map layers The class can be used in two manners:
void layerModified()
Emitted when modifications has been done on layer.
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
void pushWarning(const QString &title, const QString &message)
Pushes a warning message that must be manually dismissed by the user.
Dialog for organising (hiding and reordering) columns in the attributes table.
A rectangle specified with double values.
static QgsSettingsTreeNode * sTreeWindowState
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setEnumValue(const QString &key, const T &value, const Section section=NoSection)
Set the value of a setting based on an enum.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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.
This class caches features of a given QgsVectorLayer.
void setFullCache(bool fullCache)
This enables or disables full caching.
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.
Represents a vector layer which manages a vector based data sets.
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.
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.