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 conditional 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.
 
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
 
A QAction subclass for map layer actions shown in an attribute table.
 
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.
 
A proxy model for filtering an attribute table model.
 
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 QAction for attribute table map layer actions.
 
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...
 
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.
 
A proxy model for feature lists.
 
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
 
@ 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...
 
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.
 
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
 
Stores settings for use within QGIS.
 
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.
 
Caches features for 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 dataset.
 
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.