19 #include <QMessageBox> 
   20 #include <QProgressDialog> 
   22 #include <QInputDialog> 
   40 #include "qgssettings.h" 
   52   : QStackedWidget( parent )
 
   61   mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
 
   62   connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, 
this, &QgsDualView::showViewHeaderMenu );
 
   65   mConditionalFormatWidgetStack->hide();
 
   67   mConditionalFormatWidgetStack->setMainPanel( mConditionalFormatWidget );
 
   71   mConditionalSplitter->restoreState( settings.value( QStringLiteral( 
"/qgis/attributeTable/splitterState" ), QByteArray() ).toByteArray() );
 
   73   mPreviewColumnsMenu = 
new QMenu( 
this );
 
   74   mActionPreviewColumnsMenu->setMenu( mPreviewColumnsMenu );
 
   80   connect( mActionExpressionPreview, &QAction::triggered, 
this, &QgsDualView::previewExpressionBuilder );
 
   89   auto createShortcuts = [ = ]( 
const QString & objectName, void ( 
QgsFeatureListView::* slot )() )
 
   95       connect( sc, &QShortcut::activated, mFeatureListView, slot );
 
  102   QButtonGroup *buttonGroup = 
new QButtonGroup( 
this );
 
  103   buttonGroup->setExclusive( 
false );
 
  107   QAbstractButton *bt = buttonGroup->button( 
static_cast<int>( action ) );
 
  109     bt->setChecked( 
true );
 
  110   connect( buttonGroup, qOverload< QAbstractButton *, bool >( &QButtonGroup::buttonToggled ), 
this, &QgsDualView::panZoomGroupButtonToggled );
 
  111   mFlashButton->setChecked( QgsSettings().value( QStringLiteral( 
"/qgis/attributeTable/featureListHighlightFeature" ), 
true ).toBool() );
 
  112   connect( mFlashButton, &QToolButton::clicked, 
this, &QgsDualView::flashButtonClicked );
 
  117   QgsSettings settings;
 
  118   settings.setValue( QStringLiteral( 
"/qgis/attributeTable/splitterState" ), mConditionalSplitter->saveState() );
 
  127   delete mAttributeForm;
 
  128   mAttributeForm = 
nullptr;
 
  131   mEditorContext = context;
 
  134   initModels( mapCanvas, request, loadFeatures );
 
  136   mConditionalFormatWidget->
setLayer( mLayer );
 
  138   mTableView->setModel( mFilterModel );
 
  139   mFeatureListView->setModel( mFeatureListModel );
 
  143   if ( mFeatureListPreviewButton->defaultAction() )
 
  144     mFeatureListView->setDisplayExpression( mDisplayExpression );
 
  151   if ( mFeatureListModel->
rowCount( ) > 0 )
 
  152     mFeatureListView->setEditSelection( 
QgsFeatureIds() << mFeatureListModel->
data( mFeatureListModel->index( 0, 0 ), QgsFeatureListModel::Role::FeatureRole ).value<
QgsFeature>().
id() );
 
  156 void QgsDualView::initAttributeForm( 
const QgsFeature &feature )
 
  158   Q_ASSERT( !mAttributeForm );
 
  164     mAttributeEditorScrollArea->setWidgetResizable( 
true );
 
  165     mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea );
 
  166     mAttributeEditorScrollArea->setWidget( mAttributeForm );
 
  170     mAttributeEditor->layout()->addWidget( mAttributeForm );
 
  182       QgsMapCanvasUtils::flashMatchingFeatures( canvas, mLayer, filter );
 
  189       QgsMapCanvasUtils::zoomToMatchingFeatures( canvas, mLayer, filter );
 
  196 void QgsDualView::columnBoxInit()
 
  199   QList<QgsField> fields = mLayer->fields().toList();
 
  201   QString defaultField;
 
  204   QString displayExpression = mLayer->displayExpression();
 
  206   if ( displayExpression.isEmpty() )
 
  209     displayExpression = QStringLiteral( 
"'[Please define preview text]'" );
 
  212   mFeatureListPreviewButton->addAction( mActionExpressionPreview );
 
  213   mFeatureListPreviewButton->addAction( mActionPreviewColumnsMenu );
 
  215   const auto constFields = fields;
 
  218     int fieldIndex = mLayer->fields().lookupField( 
field.
name() );
 
  219     if ( fieldIndex == -1 )
 
  225       QIcon icon = mLayer->fields().iconForField( fieldIndex );
 
  226       QString text = mLayer->attributeDisplayName( fieldIndex );
 
  229       QAction *previewAction = 
new QAction( icon, text, mFeatureListPreviewButton );
 
  230       connect( previewAction, &QAction::triggered, 
this, [ = ] { previewColumnChanged( previewAction, fieldName ); } );
 
  231       mPreviewColumnsMenu->addAction( previewAction );
 
  233       if ( text == defaultField )
 
  235         mFeatureListPreviewButton->setDefaultAction( previewAction );
 
  240   QMenu *sortMenu = 
new QMenu( 
this );
 
  242   sortMenuAction->setMenu( sortMenu );
 
  244   QAction *sortByPreviewExpressionAsc = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"sort.svg" ) ), tr( 
"By Preview Expression (ascending)" ), 
this );
 
  245   connect( sortByPreviewExpressionAsc, &QAction::triggered, 
this, [ = ]()
 
  249   sortMenu->addAction( sortByPreviewExpressionAsc );
 
  250   QAction *sortByPreviewExpressionDesc = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"sort-reverse.svg" ) ), tr( 
"By Preview Expression (descending)" ), 
this );
 
  251   connect( sortByPreviewExpressionDesc, &QAction::triggered, 
this, [ = ]()
 
  255   sortMenu->addAction( sortByPreviewExpressionDesc );
 
  256   QAction *sortByPreviewExpressionCustom = 
new QAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"mIconExpressionPreview.svg" ) ), tr( 
"By Custom Expression" ), 
this );
 
  257   connect( sortByPreviewExpressionCustom, &QAction::triggered, 
this, [ = ]()
 
  262   sortMenu->addAction( sortByPreviewExpressionCustom );
 
  264   mFeatureListPreviewButton->addAction( sortMenuAction );
 
  266   QAction *separator = 
new QAction( mFeatureListPreviewButton );
 
  267   separator->setSeparator( 
true );
 
  268   mFeatureListPreviewButton->addAction( separator );
 
  269   restoreRecentDisplayExpressions();
 
  272   if ( !mFeatureListPreviewButton->defaultAction() )
 
  274     mFeatureListView->setDisplayExpression( displayExpression );
 
  275     mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
 
  276     setDisplayExpression( mFeatureListView->displayExpression() );
 
  280     mFeatureListPreviewButton->defaultAction()->trigger();
 
  286   setCurrentIndex( 
view );
 
  326                              || ( mMasterModel->
rowCount() == 0 ); 
 
  328   if ( !needsGeometry )
 
  372       setBrowsingAutoPanScaleAllowed( 
false );
 
  379       setBrowsingAutoPanScaleAllowed( 
true );
 
  383   if ( requiresTableReload )
 
  389     whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry );
 
  403 void QgsDualView::initLayerCache( 
bool cacheGeometry )
 
  406   QgsSettings settings;
 
  407   int cacheSize = settings.value( QStringLiteral( 
"qgis/attributeTableRowCache" ), 
"10000" ).toInt();
 
  413     rebuildFullLayerCache();
 
  419   delete mFeatureListModel;
 
  440   connect( mMasterModel, &QgsAttributeTableModel::rowsRemoved, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
 
  441   connect( mMasterModel, &QgsAttributeTableModel::rowsInserted, mFilterModel, &QgsAttributeTableFilterModel::invalidate );
 
  449 void QgsDualView::restoreRecentDisplayExpressions()
 
  451   const QVariantList previewExpressions = mLayer->customProperty( QStringLiteral( 
"dualview/previewExpressions" ) ).toList();
 
  453   for ( 
const QVariant &previewExpression : previewExpressions )
 
  454     insertRecentlyUsedDisplayExpression( previewExpression.toString() );
 
  457 void QgsDualView::saveRecentDisplayExpressions()
 const 
  463   QList<QAction *> actions = mFeatureListPreviewButton->actions();
 
  466   int index = actions.indexOf( mLastDisplayExpressionAction );
 
  469     QVariantList previewExpressions;
 
  470     for ( ; index < actions.length(); ++index )
 
  472       QAction *action = actions.at( index );
 
  473       previewExpressions << action->property( 
"previewExpression" );
 
  476     mLayer->setCustomProperty( QStringLiteral( 
"dualview/previewExpressions" ), previewExpressions );
 
  480 void QgsDualView::setDisplayExpression( 
const QString &expression )
 
  482   mDisplayExpression = expression;
 
  483   insertRecentlyUsedDisplayExpression( expression );
 
  486 void QgsDualView::insertRecentlyUsedDisplayExpression( 
const QString &expression )
 
  488   QList<QAction *> actions = mFeatureListPreviewButton->actions();
 
  491   int index = actions.indexOf( mLastDisplayExpressionAction );
 
  494     for ( 
int i = 0; index + i < actions.length(); ++i )
 
  496       QAction *action = actions.at( index );
 
  497       if ( action->text() == expression || i >= 9 )
 
  499         if ( action == mLastDisplayExpressionAction )
 
  500           mLastDisplayExpressionAction = 
nullptr;
 
  501         mFeatureListPreviewButton->removeAction( action );
 
  505         if ( !mLastDisplayExpressionAction )
 
  506           mLastDisplayExpressionAction = action;
 
  511   QString name = expression;
 
  513   if ( expression.startsWith( QLatin1String( 
"COALESCE( \"" ) ) && expression.endsWith( QLatin1String( 
", '<NULL>' )" ) ) )
 
  515     name = expression.mid( 11, expression.length() - 24 ); 
 
  517     int fieldIndex = mLayer->fields().indexOf( name );
 
  518     if ( fieldIndex != -1 )
 
  520       name = mLayer->attributeDisplayName( fieldIndex );
 
  521       icon = mLayer->fields().iconForField( fieldIndex );
 
  529   QAction *previewAction = 
new QAction( icon, name, mFeatureListPreviewButton );
 
  530   previewAction->setProperty( 
"previewExpression", expression );
 
  531   connect( previewAction, &QAction::triggered, 
this, [expression, 
this]( 
bool )
 
  533     setDisplayExpression( expression );
 
  534     mFeatureListPreviewButton->setText( expression );
 
  538   mFeatureListPreviewButton->insertAction( mLastDisplayExpressionAction, previewAction );
 
  539   mLastDisplayExpressionAction = previewAction;
 
  542 void QgsDualView::updateEditSelectionProgress( 
int progress, 
int count )
 
  544   mProgressCount->setText( QStringLiteral( 
"%1 / %2" ).arg( progress + 1 ).arg( count ) );
 
  545   mPreviousFeatureButton->setEnabled( progress > 0 );
 
  546   mNextFeatureButton->setEnabled( progress + 1 < count );
 
  547   mFirstFeatureButton->setEnabled( progress > 0 );
 
  548   mLastFeatureButton->setEnabled( progress + 1 < count );
 
  549   if ( mAttributeForm )
 
  551     mAttributeForm->setVisible( count > 0 );
 
  555 void QgsDualView::panOrZoomToFeature( 
const QgsFeatureIds &featureset )
 
  560     if ( mBrowsingAutoPanScaleAllowed )
 
  562       if ( mAutoPanButton->isChecked() )
 
  563         QTimer::singleShot( 0, 
this, [ = ]()
 
  567       else if ( mAutoZoomButton->isChecked() )
 
  568         QTimer::singleShot( 0, 
this, [ = ]()
 
  573     if ( mFlashButton->isChecked() )
 
  574       QTimer::singleShot( 0, 
this, [ = ]()
 
  578     mLastFeatureSet = featureset;
 
  582 void QgsDualView::setBrowsingAutoPanScaleAllowed( 
bool allowed )
 
  584   if ( mBrowsingAutoPanScaleAllowed == allowed )
 
  587   mBrowsingAutoPanScaleAllowed = allowed;
 
  589   mAutoPanButton->setEnabled( allowed );
 
  590   mAutoZoomButton->setEnabled( allowed );
 
  592   QString disabledHint = tr( 
"(disabled when attribute table only shows features visible in the current map canvas extent)" );
 
  594   mAutoPanButton->setToolTip( tr( 
"Automatically pan to the current feature" ) + ( allowed ? QString() : QString( 
' ' ) + disabledHint ) );
 
  595   mAutoZoomButton->setToolTip( tr( 
"Automatically zoom to the current feature" ) + ( allowed ? QString() : QString( 
' ' ) + disabledHint ) );
 
  598 void QgsDualView::panZoomGroupButtonToggled( QAbstractButton *button, 
bool checked )
 
  600   if ( button == mAutoPanButton && checked )
 
  602     QgsSettings().setEnumValue( QStringLiteral( 
"/qgis/attributeTable/featureListBrowsingAction" ), 
PanToFeature );
 
  603     mAutoZoomButton->setChecked( 
false );
 
  605   else if ( button == mAutoZoomButton && checked )
 
  607     QgsSettings().setEnumValue( QStringLiteral( 
"/qgis/attributeTable/featureListBrowsingAction" ), 
ZoomToFeature );
 
  608     mAutoPanButton->setChecked( 
false );
 
  612     QgsSettings().setEnumValue( QStringLiteral( 
"/qgis/attributeTable/featureListBrowsingAction" ), 
NoAction );
 
  615   if ( checked && mLayer->isSpatial() )
 
  616     panOrZoomToFeature( mFeatureListView->currentEditSelection() );
 
  619 void QgsDualView::flashButtonClicked( 
bool clicked )
 
  621   QgsSettings().setValue( QStringLiteral( 
"/qgis/attributeTable/featureListHighlightFeature" ), clicked );
 
  628     canvas->
flashFeatureIds( mLayer, mFeatureListView->currentEditSelection() );
 
  631 void QgsDualView::filterError( 
const QString &errorMessage )
 
  639 void QgsDualView::featureListAboutToChangeEditSelection( 
bool &ok )
 
  641   if ( !mAttributeForm )
 
  644   if ( mLayer->isEditable() && !mAttributeForm->
save() )
 
  648 void QgsDualView::featureListCurrentEditSelectionChanged( 
const QgsFeature &feat )
 
  650   if ( !mAttributeForm )
 
  652     initAttributeForm( feat );
 
  654   else if ( !mLayer->isEditable() || mAttributeForm->
save() )
 
  658     featureset << feat.
id();
 
  661     if ( mLayer->isSpatial() )
 
  662       panOrZoomToFeature( featureset );
 
  673   mFeatureListView->setCurrentFeatureEdited( 
false );
 
  674   mFeatureListView->setEditSelection( fids );
 
  679   return mAttributeForm ? mAttributeForm->
save() : 
false;
 
  684   mConditionalFormatWidgetStack->setVisible( !mConditionalFormatWidgetStack->isVisible() );
 
  689   if ( !mAttributeForm )
 
  694     mPreviousView = 
view();
 
  707   if ( !mAttributeForm )
 
  714     mAttributeForm->setVisible( 
true );
 
  719     mAttributeForm->setVisible( mFilterModel->rowCount( ) > 0 );
 
  724 void QgsDualView::previewExpressionBuilder()
 
  730   dlg.setWindowTitle( tr( 
"Expression Based Preview" ) );
 
  731   dlg.setExpressionText( mFeatureListView->displayExpression() );
 
  733   if ( dlg.exec() == QDialog::Accepted )
 
  735     mFeatureListView->setDisplayExpression( dlg.expressionText() );
 
  736     mFeatureListPreviewButton->setDefaultAction( mActionExpressionPreview );
 
  737     mFeatureListPreviewButton->setPopupMode( QToolButton::MenuButtonPopup );
 
  740   setDisplayExpression( mFeatureListView->displayExpression() );
 
  743 void QgsDualView::previewColumnChanged( QAction *previewAction, 
const QString &expression )
 
  745   if ( !mFeatureListView->setDisplayExpression( QStringLiteral( 
"COALESCE( \"%1\", '<NULL>' )" ).arg( expression ) ) )
 
  747     QMessageBox::warning( 
this,
 
  748                           tr( 
"Column Preview" ),
 
  749                           tr( 
"Could not set column '%1' as preview column.\nParser error:\n%2" )
 
  750                           .arg( previewAction->text(), mFeatureListView->parserErrorString() )
 
  755     mFeatureListPreviewButton->setText( previewAction->text() );
 
  756     mFeatureListPreviewButton->setIcon( previewAction->icon() );
 
  757     mFeatureListPreviewButton->setPopupMode( QToolButton::InstantPopup );
 
  760   setDisplayExpression( mFeatureListView->displayExpression() );
 
  770   return mFilterModel->rowCount();
 
  775   const QModelIndex currentIndex = mTableView->currentIndex();
 
  776   if ( !currentIndex.isValid() )
 
  781   QVariant var = mMasterModel->
data( currentIndex, Qt::DisplayRole );
 
  782   QApplication::clipboard()->setText( var.toString() );
 
  788     mProgressDlg->cancel();
 
  793   if ( mAttributeForm )
 
  802   saveRecentDisplayExpressions();
 
  805 void QgsDualView::viewWillShowContextMenu( QMenu *menu, 
const QModelIndex &masterIndex )
 
  812   QAction *copyContentAction = menu->addAction( tr( 
"Copy Cell Content" ) );
 
  813   menu->addAction( copyContentAction );
 
  814   connect( copyContentAction, &QAction::triggered, 
this, [masterIndex, 
this]
 
  816     QVariant var = mMasterModel->
data( masterIndex, Qt::DisplayRole );
 
  817     QApplication::clipboard()->setText( var.toString() );
 
  824     QAction *zoomToFeatureAction = menu->addAction( tr( 
"Zoom to Feature" ) );
 
  825     connect( zoomToFeatureAction, &QAction::triggered, 
this, &QgsDualView::zoomToCurrentFeature );
 
  827     QAction *panToFeatureAction = menu->addAction( tr( 
"Pan to Feature" ) );
 
  828     connect( panToFeatureAction, &QAction::triggered, 
this, &QgsDualView::panToCurrentFeature );
 
  830     QAction *flashFeatureAction = menu->addAction( tr( 
"Flash Feature" ) );
 
  831     connect( flashFeatureAction, &QAction::triggered, 
this, &QgsDualView::flashCurrentFeature );
 
  835   const QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( 
"Field" ) );
 
  836   if ( !actions.isEmpty() )
 
  838     QAction *a = menu->addAction( tr( 
"Run Layer Action" ) );
 
  839     a->setEnabled( 
false );
 
  841     for ( 
const QgsAction &action : actions )
 
  843       if ( !action.runable() )
 
  846       if ( vl && !vl->isEditable() && action.isEnabledOnlyWhenEditable() )
 
  853   QModelIndex rowSourceIndex = mMasterModel->index( masterIndex.row(), 0 );
 
  854   if ( ! rowSourceIndex.isValid() )
 
  861   if ( !registeredActions.isEmpty() )
 
  864     menu->addSeparator();
 
  876   if ( mLayer->selectedFeatureCount() > 1 && mLayer->selectedFeatureIds().contains( currentFid ) )
 
  879     if ( !registeredActions.isEmpty() )
 
  881       menu->addSeparator();
 
  882       QAction *action = menu->addAction( tr( 
"Actions on Selection (%1)" ).arg( mLayer->selectedFeatureCount() ) );
 
  883       action->setEnabled( 
false );
 
  887         menu->addAction( action->text(), action, [ = ]() {action->triggerForFeatures( mLayer, mLayer->selectedFeatures() );} );
 
  892   menu->addSeparator();
 
  898 void QgsDualView::widgetWillShowContextMenu( 
QgsActionMenu *menu, 
const QModelIndex &atIndex )
 
  904 void QgsDualView::showViewHeaderMenu( QPoint point )
 
  906   int col = mTableView->columnAt( point.x() );
 
  908   delete mHorizontalHeaderMenu;
 
  909   mHorizontalHeaderMenu = 
new QMenu( 
this );
 
  911   QAction *hide = 
new QAction( tr( 
"&Hide Column" ), mHorizontalHeaderMenu );
 
  912   connect( hide, &QAction::triggered, 
this, &QgsDualView::hideColumn );
 
  913   hide->setData( col );
 
  914   mHorizontalHeaderMenu->addAction( hide );
 
  915   QAction *setWidth = 
new QAction( tr( 
"&Set Width…" ), mHorizontalHeaderMenu );
 
  916   connect( setWidth, &QAction::triggered, 
this, &QgsDualView::resizeColumn );
 
  917   setWidth->setData( col );
 
  918   mHorizontalHeaderMenu->addAction( setWidth );
 
  920   QAction *setWidthAllColumns = 
new QAction( tr( 
"&Set All Column Widths…" ), mHorizontalHeaderMenu );
 
  921   connect( setWidthAllColumns, &QAction::triggered, 
this, &QgsDualView::resizeAllColumns );
 
  922   setWidthAllColumns->setData( col );
 
  923   mHorizontalHeaderMenu->addAction( setWidthAllColumns );
 
  925   QAction *optimizeWidth = 
new QAction( tr( 
"&Autosize" ), mHorizontalHeaderMenu );
 
  926   connect( optimizeWidth, &QAction::triggered, 
this, &QgsDualView::autosizeColumn );
 
  927   optimizeWidth->setData( col );
 
  928   mHorizontalHeaderMenu->addAction( optimizeWidth );
 
  930   QAction *optimizeWidthAllColumns = 
new QAction( tr( 
"&Autosize All Columns" ), mHorizontalHeaderMenu );
 
  931   connect( optimizeWidthAllColumns, &QAction::triggered, 
this, &QgsDualView::autosizeAllColumns );
 
  932   mHorizontalHeaderMenu->addAction( optimizeWidthAllColumns );
 
  935   mHorizontalHeaderMenu->addSeparator();
 
  936   QAction *organize = 
new QAction( tr( 
"&Organize Columns…" ), mHorizontalHeaderMenu );
 
  937   connect( organize, &QAction::triggered, 
this, &QgsDualView::organizeColumns );
 
  938   mHorizontalHeaderMenu->addAction( organize );
 
  939   QAction *sort = 
new QAction( tr( 
"&Sort…" ), mHorizontalHeaderMenu );
 
  940   connect( sort, &QAction::triggered, 
this, [ = ]() {modifySort();} );
 
  941   mHorizontalHeaderMenu->addAction( sort );
 
  943   mHorizontalHeaderMenu->popup( mTableView->horizontalHeader()->mapToGlobal( point ) );
 
  946 void QgsDualView::organizeColumns()
 
  954   if ( dialog.exec() == QDialog::Accepted )
 
  961 void QgsDualView::tableColumnResized( 
int column, 
int width )
 
  965   if ( sourceCol >= 0 && config.
columnWidth( sourceCol ) != width )
 
  972 void QgsDualView::hideColumn()
 
  974   QAction *action = qobject_cast<QAction *>( sender() );
 
  975   int col = action->data().toInt();
 
  978   if ( sourceCol >= 0 )
 
  985 void QgsDualView::resizeColumn()
 
  987   QAction *action = qobject_cast<QAction *>( sender() );
 
  988   int col = action->data().toInt();
 
  994   if ( sourceCol >= 0 )
 
  997     int width = QInputDialog::getInt( 
this, tr( 
"Set column width" ), tr( 
"Enter column width" ),
 
  998                                       mTableView->columnWidth( col ),
 
 1008 void QgsDualView::resizeAllColumns()
 
 1010   QAction *action = qobject_cast<QAction *>( sender() );
 
 1011   int col = action->data().toInt();
 
 1018   int width = QInputDialog::getInt( 
this, tr( 
"Set Column Width" ), tr( 
"Enter column width" ),
 
 1019                                     mTableView->columnWidth( col ),
 
 1023     const int colCount = mTableView->model()->columnCount();
 
 1026       for ( 
int i = 0; i < colCount; i++ )
 
 1035 void QgsDualView::autosizeColumn()
 
 1037   QAction *action = qobject_cast<QAction *>( sender() );
 
 1038   int col = action->data().toInt();
 
 1039   mTableView->resizeColumnToContents( col );
 
 1042 void QgsDualView::autosizeAllColumns()
 
 1044   mTableView->resizeColumnsToContents();
 
 1047 bool QgsDualView::modifySort()
 
 1055   orderByDlg.setWindowTitle( tr( 
"Configure Attribute Table Sort Order" ) );
 
 1056   QDialogButtonBox *dialogButtonBox = 
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
 
 1057   QGridLayout *layout = 
new QGridLayout();
 
 1058   connect( dialogButtonBox, &QDialogButtonBox::accepted, &orderByDlg, &QDialog::accept );
 
 1059   connect( dialogButtonBox, &QDialogButtonBox::rejected, &orderByDlg, &QDialog::reject );
 
 1060   orderByDlg.setLayout( layout );
 
 1062   QGroupBox *sortingGroupBox = 
new QGroupBox();
 
 1063   sortingGroupBox->setTitle( tr( 
"Defined sort order in attribute table" ) );
 
 1064   sortingGroupBox->setCheckable( 
true );
 
 1066   layout->addWidget( sortingGroupBox );
 
 1067   sortingGroupBox->setLayout( 
new QGridLayout() );
 
 1072   expressionBuilder->
initWithLayer( mLayer, context, QStringLiteral( 
"generic" ) );
 
 1075   sortingGroupBox->layout()->addWidget( expressionBuilder );
 
 1077   QCheckBox *cbxSortAscending = 
new QCheckBox( tr( 
"Sort ascending" ) );
 
 1078   cbxSortAscending->setChecked( config.
sortOrder() == Qt::AscendingOrder );
 
 1079   sortingGroupBox->layout()->addWidget( cbxSortAscending );
 
 1081   layout->addWidget( dialogButtonBox );
 
 1082   if ( orderByDlg.exec() )
 
 1084     Qt::SortOrder sortOrder = cbxSortAscending->isChecked() ? Qt::AscendingOrder : Qt::DescendingOrder;
 
 1085     if ( sortingGroupBox->isChecked() )
 
 1107 void QgsDualView::zoomToCurrentFeature()
 
 1109   QModelIndex currentIndex = mTableView->currentIndex();
 
 1110   if ( !currentIndex.isValid() )
 
 1116   ids.insert( mFilterModel->
rowToId( currentIndex ) );
 
 1124 void QgsDualView::panToCurrentFeature()
 
 1126   QModelIndex currentIndex = mTableView->currentIndex();
 
 1127   if ( !currentIndex.isValid() )
 
 1133   ids.insert( mFilterModel->
rowToId( currentIndex ) );
 
 1141 void QgsDualView::flashCurrentFeature()
 
 1143   QModelIndex currentIndex = mTableView->currentIndex();
 
 1144   if ( !currentIndex.isValid() )
 
 1150   ids.insert( mFilterModel->
rowToId( currentIndex ) );
 
 1158 void QgsDualView::rebuildFullLayerCache()
 
 1166 void QgsDualView::previewExpressionChanged( 
const QString &expression )
 
 1168   mLayer->setDisplayExpression( expression );
 
 1171 void QgsDualView::onSortColumnChanged()
 
 1175        cfg.
sortOrder() != mFilterModel->sortOrder() )
 
 1183 void QgsDualView::updateSelectedFeatures()
 
 1195 void QgsDualView::updateEditedAddedFeatures()
 
 1207 void QgsDualView::extentChanged()
 
 1220 void QgsDualView::featureFormAttributeChanged( 
const QString &attribute, 
const QVariant &value, 
bool attributeChanged )
 
 1222   Q_UNUSED( attribute )
 
 1224   if ( attributeChanged )
 
 1225     mFeatureListView->setCurrentFeatureEdited( 
true );
 
 1247   mTableView->setFeatureSelectionManager( featureSelectionManager );
 
 1248   mFeatureListView->setFeatureSelectionManager( featureSelectionManager );
 
 1250   if ( mFeatureSelectionManager && mFeatureSelectionManager->parent() == 
this )
 
 1251     delete mFeatureSelectionManager;
 
 1253   mFeatureSelectionManager = featureSelectionManager;
 
 1259   mConfig.
update( mLayer->fields() );
 
 1260   mLayer->setAttributeTableConfig( mConfig );
 
 1262   mTableView->setAttributeTableConfig( mConfig );
 
 1268     mFilterModel->
sort( -1 );
 
 1287 void QgsDualView::progress( 
int i, 
bool &cancel )
 
 1289   if ( !mProgressDlg )
 
 1291     mProgressDlg = 
new QProgressDialog( tr( 
"Loading features…" ), tr( 
"Abort" ), 0, 0, 
this );
 
 1292     mProgressDlg->setWindowTitle( tr( 
"Attribute Table" ) );
 
 1293     mProgressDlg->setWindowModality( Qt::WindowModal );
 
 1294     mProgressDlg->show();
 
 1297   mProgressDlg->setLabelText( tr( 
"%1 features loaded." ).arg( i ) );
 
 1298   QCoreApplication::processEvents();
 
 1300   cancel = mProgressDlg && mProgressDlg->wasCanceled();
 
 1303 void QgsDualView::finished()
 
 1305   delete mProgressDlg;
 
 1306   mProgressDlg = 
nullptr;
 
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.
const QgsAttributeEditorContext * parentContext() const
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.
This is a container for configuration of the attribute table.
void setSortExpression(const QString &sortExpression)
Set the sort expression used for sorting.
Qt::SortOrder sortOrder() const
Gets the sort order.
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.
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
void setFilterMode(FilterMode filterMode)
Set the filter mode the filter will use.
QgsMapCanvas * mapCanvas() const
Returns the map canvas.
void disconnectFilterModeConnections()
Disconnect the connections set for the current filterMode.
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table configuration to control which fields are shown, in which order they are show...
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.
@ 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)
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()
Model has been changed.
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 executeMapLayerAction(QgsMapLayerAction *action, const QModelIndex &idx) const
Execute a QgsMapLayerAction.
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.
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.
QgsAttributeTableModel * masterModel() const
Returns the model which has the information about all features (not only filtered)
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.
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.
void init(QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request=QgsFeatureRequest(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), bool loadFeatures=true)
Has to be called to initialize the dual view.
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").
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 & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & disableFilter()
Disables filter conditions.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
FilterType filterType() const
Returns the filter type which is currently set on this request.
@ FilterNone
No filter is applied.
const Flags & flags() const
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.
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.
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
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:
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.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QShortcut * shortcutByName(const QString &name) const
Returns a shortcut by its name, or nullptr if nothing found.
@ SelectAtId
Fast access to features using their ID.
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 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.
void layerModified()
Emitted when modifications has been done on layer.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was 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