16#include <QDesktopServices> 
   25#include "moc_qgsattributetableview.cpp" 
   43  restoreGeometry( settings.
value( QStringLiteral( 
"BetterAttributeTable/geometry" ) ).toByteArray() );
 
   46  horizontalHeader()->setHighlightSections( 
false );
 
   50  setItemDelegate( mTableDelegate );
 
   52  setEditTriggers( QAbstractItemView::AllEditTriggers );
 
   54  setSelectionBehavior( QAbstractItemView::SelectRows );
 
   55  setSelectionMode( QAbstractItemView::ExtendedSelection );
 
   56  setSortingEnabled( 
true );                          
 
   57  horizontalHeader()->setSortIndicatorShown( 
false ); 
 
   59  setHorizontalScrollMode( QAbstractItemView::ScrollPerPixel );
 
   61  verticalHeader()->viewport()->installEventFilter( 
this );
 
   63  connect( verticalHeader(), &QHeaderView::sectionPressed, 
this, [
this]( 
int row ) { 
selectRow( row, 
true ); } );
 
   65  connect( horizontalHeader(), &QHeaderView::sectionResized, 
this, &QgsAttributeTableView::columnSizeChanged );
 
   66  connect( horizontalHeader(), &QHeaderView::sortIndicatorChanged, 
this, &QgsAttributeTableView::showHorizontalSortIndicator );
 
 
   72  if ( 
object == verticalHeader()->viewport() )
 
   74    switch ( event->type() )
 
   76      case QEvent::MouseButtonPress:
 
   80      case QEvent::MouseButtonRelease:
 
   88  return QTableView::eventFilter( 
object, event );
 
 
   94  const auto constColumns = config.
columns();
 
   95  QMap<QString, int> columns;
 
   98    if ( columnConfig.hidden )
 
  101    if ( columnConfig.width >= 0 )
 
  103      setColumnWidth( i, columnConfig.width );
 
  107      setColumnWidth( i, horizontalHeader()->defaultSectionSize() );
 
  109    columns.insert( columnConfig.name, i );
 
  115    horizontalHeader()->setSortIndicatorShown( 
false );
 
  122      if ( sortExp.isField() )
 
  124        const QStringList refCols { sortExp.referencedColumns().values() };
 
  125        horizontalHeader()->setSortIndicatorShown( 
true );
 
  126        horizontalHeader()->setSortIndicator( columns.value( refCols.constFirst() ), config.
sortOrder() );
 
  130        horizontalHeader()->setSortIndicatorShown( 
false );
 
 
  143  QModelIndexList indexList;
 
  146    const QModelIndex index = mFilterModel->
fidToIndex( 
id );
 
  150  std::sort( indexList.begin(), indexList.end() );
 
  151  QList<QgsFeatureId> ids;
 
  152  for ( 
const QModelIndex &index : indexList )
 
 
  162  mFilterModel = filterModel;
 
  163  QTableView::setModel( mFilterModel );
 
  167    connect( mFilterModel, &QObject::destroyed, 
this, &QgsAttributeTableView::modelDeleted );
 
  171  delete mFeatureSelectionModel;
 
  172  mFeatureSelectionModel = 
nullptr;
 
  176    if ( !mFeatureSelectionManager )
 
  179      mFeatureSelectionManager = mOwnedFeatureSelectionManager;
 
  182    mFeatureSelectionModel = 
new QgsFeatureSelectionModel( mFilterModel, mFilterModel, mFeatureSelectionManager, mFilterModel );
 
  183    setSelectionModel( mFeatureSelectionModel );
 
 
  196  mFeatureSelectionManager = featureSelectionManager;
 
  198  if ( mFeatureSelectionModel )
 
  202  if ( mOwnedFeatureSelectionManager )
 
  204    mOwnedFeatureSelectionManager->deleteLater();
 
  205    mOwnedFeatureSelectionManager = 
nullptr;
 
 
  209QWidget *QgsAttributeTableView::createActionWidget( 
QgsFeatureId fid )
 
  213  QToolButton *toolButton = 
nullptr;
 
  214  QWidget *container = 
nullptr;
 
  218    toolButton = 
new QToolButton();
 
  219    toolButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
 
  220    toolButton->setPopupMode( QToolButton::MenuButtonPopup );
 
  221    container = toolButton;
 
  225    container = 
new QWidget();
 
  226    container->setLayout( 
new QHBoxLayout() );
 
  227    container->layout()->setContentsMargins( 0, 0, 0, 0 );
 
  230  QList<QAction *> actionList;
 
  231  QAction *defaultAction = 
nullptr;
 
  234  const QList<QgsAction> actions = mFilterModel->
layer()->
actions()->
actions( QStringLiteral( 
"Feature" ) );
 
  235  const auto constActions = actions;
 
  236  for ( 
const QgsAction &action : constActions )
 
  238    if ( !mFilterModel->
layer()->
isEditable() && action.isEnabledOnlyWhenEditable() )
 
  241    const QString actionTitle = !action.shortTitle().isEmpty() ? action.shortTitle() : action.icon().isNull() ? action.name()
 
  243    QAction *act = 
new QAction( action.icon(), actionTitle, container );
 
  244    act->setToolTip( action.name() );
 
  245    act->setData( 
"user_action" );
 
  246    act->setProperty( 
"fid", fid );
 
  247    act->setProperty( 
"action_id", action.id() );
 
  248    connect( act, &QAction::triggered, 
this, &QgsAttributeTableView::actionTriggered );
 
  260    QAction *action = 
new QAction( mapLayerAction->icon(), mapLayerAction->text(), container );
 
  261    action->setData( 
"map_layer_action" );
 
  262    action->setToolTip( mapLayerAction->text() );
 
  263    action->setProperty( 
"fid", fid );
 
  264    action->setProperty( 
"action", QVariant::fromValue( qobject_cast<QObject *>( mapLayerAction ) ) );
 
  265    connect( action, &QAction::triggered, 
this, &QgsAttributeTableView::actionTriggered );
 
  266    actionList << action;
 
  269      defaultAction = action;
 
  272  if ( !defaultAction && !actionList.isEmpty() )
 
  273    defaultAction = actionList.at( 0 );
 
  275  const auto constActionList = actionList;
 
  276  for ( QAction *act : constActionList )
 
  280      toolButton->addAction( act );
 
  282      if ( act == defaultAction )
 
  283        toolButton->setDefaultAction( act );
 
  285      container = toolButton;
 
  289      QToolButton *btn = 
new QToolButton;
 
  290      btn->setDefaultAction( act );
 
  291      container->layout()->addWidget( btn );
 
  297    static_cast<QHBoxLayout *
>( container->layout() )->addStretch();
 
  302  if ( toolButton && !toolButton->actions().isEmpty() && actions->defaultAction() == -1 )
 
  303    toolButton->setDefaultAction( toolButton->actions().at( 0 ) );
 
  313  settings.
setValue( QStringLiteral( 
"BetterAttributeTable/geometry" ), QVariant( saveGeometry() ) );
 
 
  318  setSelectionMode( QAbstractItemView::NoSelection );
 
  319  QTableView::mousePressEvent( event );
 
  320  setSelectionMode( QAbstractItemView::ExtendedSelection );
 
 
  325  setSelectionMode( QAbstractItemView::NoSelection );
 
  326  QTableView::mouseReleaseEvent( event );
 
  327  setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  328  if ( event->modifiers() == Qt::ControlModifier )
 
  330    const QModelIndex index = indexAt( event->pos() );
 
  331    const QVariant data = model()->data( index, Qt::DisplayRole );
 
  332    if ( data.userType() == QMetaType::Type::QString )
 
  334      const QString textVal = data.toString();
 
  337        QDesktopServices::openUrl( QUrl( textVal ) );
 
 
  345  setSelectionMode( QAbstractItemView::NoSelection );
 
  346  QTableView::mouseMoveEvent( event );
 
  347  setSelectionMode( QAbstractItemView::ExtendedSelection );
 
 
  352  switch ( event->key() )
 
  360      setSelectionMode( QAbstractItemView::NoSelection );
 
  361      QTableView::keyPressEvent( event );
 
  362      setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  366      QTableView::keyPressEvent( event );
 
 
  373  const auto constIndexes = indexes;
 
  374  for ( 
const QModelIndex &index : constIndexes )
 
 
  382  setDirtyRegion( viewport()->rect() );
 
 
  387  QItemSelection selection;
 
  388  selection.append( QItemSelectionRange( mFilterModel->index( 0, 0 ), mFilterModel->index( mFilterModel->rowCount() - 1, 0 ) ) );
 
  389  mFeatureSelectionModel->
selectFeatures( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
 
 
  395  mActionPopup = 
nullptr;
 
  397  const QModelIndex idx = mFilterModel->
mapToMaster( indexAt( event->pos() ) );
 
  398  if ( !idx.isValid() )
 
  407  mActionPopup = 
new QMenu( 
this );
 
  409  QAction *selectAllAction = mActionPopup->addAction( tr( 
"Select All" ) );
 
  410  selectAllAction->setShortcut( QKeySequence::SelectAll );
 
  416  if ( !mActionPopup->actions().isEmpty() )
 
  418    mActionPopup->popup( event->globalPos() );
 
 
  432void QgsAttributeTableView::modelDeleted()
 
  434  mFilterModel = 
nullptr;
 
  435  mFeatureSelectionManager = 
nullptr;
 
  436  mFeatureSelectionModel = 
nullptr;
 
  441  if ( selectionBehavior() == QTableView::SelectColumns
 
  442       || ( selectionMode() == QTableView::SingleSelection && selectionBehavior() == QTableView::SelectItems ) )
 
  445  if ( row >= 0 && row < model()->rowCount() )
 
  447    const int column = horizontalHeader()->logicalIndexAt( isRightToLeft() ? viewport()->width() : 0 );
 
  448    const QModelIndex index = model()->index( row, column );
 
  449    QItemSelectionModel::SelectionFlags command = selectionCommand( index );
 
  450    selectionModel()->setCurrentIndex( index, QItemSelectionModel::NoUpdate );
 
  451    if ( ( anchor && !( command & QItemSelectionModel::Current ) )
 
  452         || ( selectionMode() == QTableView::SingleSelection ) )
 
  453      mRowSectionAnchor = row;
 
  455    if ( selectionMode() != QTableView::SingleSelection
 
  456         && command.testFlag( QItemSelectionModel::Toggle ) )
 
  459        mCtrlDragSelectionFlag = mFeatureSelectionModel->
isSelected( index )
 
  460                                   ? QItemSelectionModel::Deselect
 
  461                                   : QItemSelectionModel::Select;
 
  462      command &= ~QItemSelectionModel::Toggle;
 
  463      command |= mCtrlDragSelectionFlag;
 
  465        command |= QItemSelectionModel::Current;
 
  468    const QModelIndex tl = model()->index( std::min( mRowSectionAnchor, row ), 0 );
 
  469    const QModelIndex br = model()->index( std::max( mRowSectionAnchor, row ), model()->columnCount() - 1 );
 
  470    if ( verticalHeader()->sectionsMoved() && tl.row() != br.row() )
 
  471      setSelection( visualRect( tl ) | visualRect( br ), command );
 
  473      mFeatureSelectionModel->
selectFeatures( QItemSelection( tl, br ), command );
 
  477void QgsAttributeTableView::showHorizontalSortIndicator()
 
  479  horizontalHeader()->setSortIndicatorShown( 
true );
 
  482void QgsAttributeTableView::actionTriggered()
 
  484  QAction *action = qobject_cast<QAction *>( sender() );
 
  485  const QgsFeatureId fid = action->property( 
"fid" ).toLongLong();
 
  490  if ( action->data().toString() == QLatin1String( 
"user_action" ) )
 
  494  else if ( action->data().toString() == QLatin1String( 
"map_layer_action" ) )
 
  496    QObject *
object = action->property( 
"action" ).value<QObject *>();
 
  502      layerAction->triggerForFeature( mFilterModel->
layer(), f );
 
  504      layerAction->triggerForFeature( mFilterModel->
layer(), f, context );
 
  509void QgsAttributeTableView::columnSizeChanged( 
int index, 
int oldWidth, 
int newWidth )
 
  515void QgsAttributeTableView::onActionColumnItemPainted( 
const QModelIndex &index )
 
  517  if ( !indexWidget( index ) )
 
  520    mActionWidgets.insert( index, widget );
 
  521    setIndexWidget( index, widget );
 
  525void QgsAttributeTableView::recreateActionWidgets()
 
  527  QMap<QModelIndex, QWidget *>::const_iterator it = mActionWidgets.constBegin();
 
  528  for ( ; it != mActionWidgets.constEnd(); ++it )
 
  533    setIndexWidget( it.key(), 
nullptr );
 
  535  mActionWidgets.clear();
 
  540  const QModelIndex index = mFilterModel->
fidToIndex( fid );
 
  542  if ( !index.isValid() )
 
  547  const QModelIndex selectionIndex = index.sibling( index.row(), col );
 
  549  if ( !selectionIndex.isValid() )
 
  552  selectionModel()->setCurrentIndex( index, QItemSelectionModel::SelectCurrent );
 
 
  557  QWidget *editor = indexWidget( currentIndex() );
 
  558  commitData( editor );
 
  559  closeEditor( editor, QAbstractItemDelegate::NoHint );
 
 
@ SingleFeature
Action targets a single feature from a layer.
 
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
 
void doAction(QUuid actionId, const QgsFeature &feature, int defaultValueIndex=0, const QgsExpressionContextScope &scope=QgsExpressionContextScope())
Does the given action.
 
QgsAction defaultAction(const QString &actionScope)
Each scope can have a default action.
 
Utility class that encapsulates an action based on vector attributes.
 
QUuid id() const
Returns a unique id for this action.
 
A container for configuration of the attribute table.
 
Qt::SortOrder sortOrder() const
Gets the sort order.
 
QVector< QgsAttributeTableConfig::ColumnConfig > columns() const
Gets the list with all columns and their configuration.
 
@ DropDown
A tool button with a drop-down to select the current action.
 
@ ButtonList
A list of buttons.
 
ActionWidgetStyle actionWidgetStyle() const
Gets the style of the action widget.
 
QString sortExpression() const
Gets the expression used for sorting.
 
A delegate item class for QgsAttributeTable (see Qt documentation for QItemDelegate).
 
void actionColumnItemPainted(const QModelIndex &index) const
Emitted when an action column item is painted.
 
void setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)
 
A proxy model for filtering an attribute table model.
 
QgsVectorLayerCache * layerCache() const
Returns the layerCache this filter acts on.
 
QModelIndex fidToIndex(QgsFeatureId fid) override
 
QVariant data(const QModelIndex &index, int role) const override
 
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
 
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
 
@ FeatureId
Get the feature id of the feature in this row.
 
Provides a table view of features of a QgsVectorLayer.
 
void willShowContextMenu(QMenu *menu, const QModelIndex &atIndex)
Emitted in order to provide a hook to add additional* menu entries to the context menu.
 
QList< QgsFeatureId > selectedFeaturesIds() const
Returns the selected features in the attribute table in table sorted order.
 
void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
setFeatureSelectionManager
 
void mouseMoveEvent(QMouseEvent *event) override
Called for mouse move events on a table cell.
 
virtual void selectRow(int row)
 
QgsAttributeTableView(QWidget *parent=nullptr)
Constructor for QgsAttributeTableView.
 
void selectAll() override
 
void scrollToFeature(const QgsFeatureId &fid, int column=-1)
Scroll to a feature with a given fid.
 
void mouseReleaseEvent(QMouseEvent *event) override
Called for mouse release events on a table cell.
 
void contextMenuEvent(QContextMenuEvent *event) override
Is called when the context menu will be shown.
 
virtual void _q_selectRow(int row)
 
void closeEvent(QCloseEvent *event) override
Saves geometry to the settings on close.
 
void mousePressEvent(QMouseEvent *event) override
Called for mouse press events on a table cell.
 
void closeCurrentEditor()
Closes the editor delegate for the current item, committing its changes to the model.
 
void keyPressEvent(QKeyEvent *event) override
Called for key press events Disables selection change by only pressing an arrow key.
 
void setAttributeTableConfig(const QgsAttributeTableConfig &config)
Set the attribute table config which should be used to control the appearance of the attribute table.
 
void columnResized(int column, int width)
Emitted when a column in the view has been resized.
 
bool eventFilter(QObject *object, QEvent *event) override
This event filter is installed on the verticalHeader to intercept mouse press and release events.
 
virtual void setModel(QgsAttributeTableFilterModel *filterModel)
 
Handles parsing and evaluation of expressions (formerly called "search strings").
 
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
 
Wraps a request for features to a vector layer (or directly its vector data provider).
 
Item selection model for selecting features.
 
void enableSync(bool enable)
Enables or disables synchronisation to the QgsVectorLayer When synchronisation is disabled,...
 
virtual void selectFeatures(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
Select features on this table.
 
virtual bool isSelected(QgsFeatureId fid)
Returns the selection status of a given feature id.
 
virtual void setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)
 
void requestRepaint()
Request a repaint of the visible items of connected views.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
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.
 
virtual const QgsFeatureIds & selectedFeatureIds() const =0
Returns reference to identifiers of selected features.
 
Encapsulates the context in which a QgsMapLayerAction action is executed.
 
void changed()
Triggered when an action is added or removed from the registry.
 
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 editingStopped()
Emitted when edited changes have been successfully written to the data provider.
 
void editingStarted()
Emitted when editing on this layer has started.
 
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 setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
 
static bool isUrl(const QString &string)
Returns whether the string is a URL (http,https,ftp,file)
 
A QTableView subclass with QGIS specific tweaks and improvements.
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
 
Manages vector layer selections.
 
Represents a vector layer which manages a vector based dataset.
 
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
 
QgsActionManager * actions()
Returns all layer actions defined on this layer.
 
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
 
#define Q_NOWARN_DEPRECATED_POP
 
#define Q_NOWARN_DEPRECATED_PUSH
 
QSet< QgsFeatureId > QgsFeatureIds
 
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
 
Defines the configuration of a column in the attribute table.