17 #include <QHeaderView> 
   19 #include <QToolButton> 
   20 #include <QHBoxLayout> 
   22 #include "qgssettings.h" 
   40   : QTableView( parent )
 
   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, [ = ]( 
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();
 
   97     if ( columnConfig.hidden )
 
  100     if ( columnConfig.width >= 0 )
 
  102       setColumnWidth( i, columnConfig.width );
 
  106       setColumnWidth( i, horizontalHeader()->defaultSectionSize() );
 
  112     horizontalHeader()->setSortIndicatorShown( 
false );
 
  121   QModelIndexList indexList;
 
  124     QModelIndex index = mFilterModel->
fidToIndex( 
id );
 
  128   std::sort( indexList.begin(), indexList.end() );
 
  129   QList<QgsFeatureId> ids;
 
  130   for ( 
const QModelIndex &index : indexList )
 
  140   mFilterModel = filterModel;
 
  141   QTableView::setModel( mFilterModel );
 
  145     connect( mFilterModel, &QObject::destroyed, 
this, &QgsAttributeTableView::modelDeleted );
 
  149   delete mFeatureSelectionModel;
 
  150   mFeatureSelectionModel = 
nullptr;
 
  154     if ( !mFeatureSelectionManager )
 
  157       mFeatureSelectionManager = mOwnedFeatureSelectionManager;
 
  160     mFeatureSelectionModel = 
new QgsFeatureSelectionModel( mFilterModel, mFilterModel, mFeatureSelectionManager, mFilterModel );
 
  161     setSelectionModel( mFeatureSelectionModel );
 
  176   mFeatureSelectionManager = featureSelectionManager;
 
  178   if ( mFeatureSelectionModel )
 
  182   if ( mOwnedFeatureSelectionManager )
 
  184     mOwnedFeatureSelectionManager->deleteLater();
 
  185     mOwnedFeatureSelectionManager = 
nullptr;
 
  189 QWidget *QgsAttributeTableView::createActionWidget( 
QgsFeatureId fid )
 
  193   QToolButton *toolButton = 
nullptr;
 
  194   QWidget *container = 
nullptr;
 
  198     toolButton  = 
new QToolButton();
 
  199     toolButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
 
  200     toolButton->setPopupMode( QToolButton::MenuButtonPopup );
 
  201     container = toolButton;
 
  205     container = 
new QWidget();
 
  206     container->setLayout( 
new QHBoxLayout() );
 
  207     container->layout()->setContentsMargins( 0, 0, 0, 0 );
 
  210   QList< QAction * > actionList;
 
  211   QAction *defaultAction = 
nullptr;
 
  214   QList<QgsAction> actions = mFilterModel->
layer()->
actions()->
actions( QStringLiteral( 
"Feature" ) );
 
  215   const auto constActions = actions;
 
  216   for ( 
const QgsAction &action : constActions )
 
  218     if ( !mFilterModel->
layer()->
isEditable() && action.isEnabledOnlyWhenEditable() )
 
  221     QString actionTitle = !action.shortTitle().isEmpty() ? action.shortTitle() : action.icon().isNull() ? action.name() : QString();
 
  222     QAction *act = 
new QAction( action.icon(), actionTitle, container );
 
  223     act->setToolTip( action.name() );
 
  224     act->setData( 
"user_action" );
 
  225     act->setProperty( 
"fid", fid );
 
  226     act->setProperty( 
"action_id", action.id() );
 
  227     connect( act, &QAction::triggered, 
this, &QgsAttributeTableView::actionTriggered );
 
  238     QAction *action = 
new QAction( mapLayerAction->icon(), mapLayerAction->text(), container );
 
  239     action->setData( 
"map_layer_action" );
 
  240     action->setToolTip( mapLayerAction->text() );
 
  241     action->setProperty( 
"fid", fid );
 
  242     action->setProperty( 
"action", QVariant::fromValue( qobject_cast<QObject *>( mapLayerAction ) ) );
 
  243     connect( action, &QAction::triggered, 
this, &QgsAttributeTableView::actionTriggered );
 
  244     actionList << action;
 
  246     if ( !defaultAction &&
 
  248       defaultAction = action;
 
  251   if ( !defaultAction && !actionList.isEmpty() )
 
  252     defaultAction = actionList.at( 0 );
 
  254   const auto constActionList = actionList;
 
  255   for ( QAction *act : constActionList )
 
  259       toolButton->addAction( act );
 
  261       if ( act == defaultAction )
 
  262         toolButton->setDefaultAction( act );
 
  264       container = toolButton;
 
  268       QToolButton *btn = 
new QToolButton;
 
  269       btn->setDefaultAction( act );
 
  270       container->layout()->addWidget( btn );
 
  276     static_cast< QHBoxLayout * 
>( container->layout() )->addStretch();
 
  281   if ( toolButton && !toolButton->actions().isEmpty() && actions->defaultAction() == -1 )
 
  282     toolButton->setDefaultAction( toolButton->actions().at( 0 ) );
 
  291   QgsSettings settings;
 
  292   settings.setValue( QStringLiteral( 
"BetterAttributeTable/geometry" ), QVariant( 
saveGeometry() ) );
 
  297   setSelectionMode( QAbstractItemView::NoSelection );
 
  298   QTableView::mousePressEvent( event );
 
  299   setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  304   setSelectionMode( QAbstractItemView::NoSelection );
 
  305   QTableView::mouseReleaseEvent( event );
 
  306   setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  311   setSelectionMode( QAbstractItemView::NoSelection );
 
  312   QTableView::mouseMoveEvent( event );
 
  313   setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  318   switch ( event->key() )
 
  327       setSelectionMode( QAbstractItemView::NoSelection );
 
  328       QTableView::keyPressEvent( event );
 
  329       setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  333       QTableView::keyPressEvent( event );
 
  340   const auto constIndexes = indexes;
 
  341   for ( 
const QModelIndex &index : constIndexes )
 
  349   setDirtyRegion( viewport()->rect() );
 
  354   QItemSelection selection;
 
  355   selection.append( QItemSelectionRange( mFilterModel->index( 0, 0 ), mFilterModel->index( mFilterModel->rowCount() - 1, 0 ) ) );
 
  356   mFeatureSelectionModel->
selectFeatures( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
 
  362   mActionPopup = 
nullptr;
 
  364   const QModelIndex idx = mFilterModel->
mapToMaster( indexAt( event->pos() ) );
 
  365   if ( !idx.isValid() )
 
  374   mActionPopup = 
new QMenu( 
this );
 
  376   QAction *selectAllAction = mActionPopup->addAction( tr( 
"Select All" ) );
 
  377   selectAllAction->setShortcut( QKeySequence::SelectAll );
 
  383   if ( !mActionPopup->actions().isEmpty() )
 
  385     mActionPopup->popup( event->globalPos() );
 
  399 void QgsAttributeTableView::modelDeleted()
 
  401   mFilterModel = 
nullptr;
 
  402   mFeatureSelectionManager = 
nullptr;
 
  403   mFeatureSelectionModel = 
nullptr;
 
  408   if ( selectionBehavior() == QTableView::SelectColumns
 
  409        || ( selectionMode() == QTableView::SingleSelection
 
  410             && selectionBehavior() == QTableView::SelectItems ) )
 
  413   if ( row >= 0 && row < model()->rowCount() )
 
  415     int column = horizontalHeader()->logicalIndexAt( isRightToLeft() ? viewport()->width() : 0 );
 
  416     QModelIndex index = model()->index( row, column );
 
  417     QItemSelectionModel::SelectionFlags command = selectionCommand( index );
 
  418     selectionModel()->setCurrentIndex( index, QItemSelectionModel::NoUpdate );
 
  419     if ( ( anchor && !( command & QItemSelectionModel::Current ) )
 
  420          || ( selectionMode() == QTableView::SingleSelection ) )
 
  421       mRowSectionAnchor = row;
 
  423     if ( selectionMode() != QTableView::SingleSelection
 
  424          && command.testFlag( QItemSelectionModel::Toggle ) )
 
  427         mCtrlDragSelectionFlag = mFeatureSelectionModel->
isSelected( index )
 
  428                                  ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
 
  429       command &= ~QItemSelectionModel::Toggle;
 
  430       command |= mCtrlDragSelectionFlag;
 
  432         command |= QItemSelectionModel::Current;
 
  435     QModelIndex tl = model()->index( std::min( mRowSectionAnchor, row ), 0 );
 
  436     QModelIndex br = model()->index( std::max( mRowSectionAnchor, row ), model()->columnCount() - 1 );
 
  437     if ( verticalHeader()->sectionsMoved() && tl.row() != br.row() )
 
  438       setSelection( visualRect( tl ) | visualRect( br ), command );
 
  440       mFeatureSelectionModel->
selectFeatures( QItemSelection( tl, br ), command );
 
  444 void QgsAttributeTableView::showHorizontalSortIndicator()
 
  446   horizontalHeader()->setSortIndicatorShown( 
true );
 
  449 void QgsAttributeTableView::actionTriggered()
 
  451   QAction *action = qobject_cast<QAction *>( sender() );
 
  452   QgsFeatureId fid = action->property( 
"fid" ).toLongLong();
 
  457   if ( action->data().toString() == QLatin1String( 
"user_action" ) )
 
  461   else if ( action->data().toString() == QLatin1String( 
"map_layer_action" ) )
 
  463     QObject *
object = action->property( 
"action" ).value<QObject *>();
 
  467       layerAction->triggerForFeature( mFilterModel->
layer(), f );
 
  472 void QgsAttributeTableView::columnSizeChanged( 
int index, 
int oldWidth, 
int newWidth )
 
  478 void QgsAttributeTableView::onActionColumnItemPainted( 
const QModelIndex &index )
 
  480   if ( !indexWidget( index ) )
 
  483     mActionWidgets.insert( index, widget );
 
  484     setIndexWidget( index, widget );
 
  488 void QgsAttributeTableView::recreateActionWidgets()
 
  490   QMap< QModelIndex, QWidget * >::const_iterator it = mActionWidgets.constBegin();
 
  491   for ( ; it != mActionWidgets.constEnd(); ++it )
 
  496     setIndexWidget( it.key(), 
nullptr );
 
  498   mActionWidgets.clear();
 
  503   QModelIndex index = mFilterModel->
fidToIndex( fid );
 
  505   if ( !index.isValid() )
 
  510   QModelIndex selectionIndex = index.sibling( index.row(), col );
 
  512   if ( !selectionIndex.isValid() )
 
  515   selectionModel()->setCurrentIndex( index, QItemSelectionModel::SelectCurrent );
 
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.
This is a container for configuration of the attribute table.
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)
QgsVectorLayer * layer() const
Returns the layer this filter acts on.
QModelIndex fidToIndex(QgsFeatureId fid) override
QVariant data(const QModelIndex &index, int role) const override
QModelIndex mapToMaster(const QModelIndex &proxyIndex) const
QgsVectorLayerCache * layerCache() const
Returns the layerCache this filter acts on.
@ FeatureIdRole
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 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)
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
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.
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
void changed()
Triggered when an action is added or removed from the registry.
An action which can run on map layers The class can be used in two manners:
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
Represents a vector layer which manages a vector based data sets.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
void editingStarted()
Emitted when editing on this layer has started.
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.
bool restoreGeometry(QWidget *widget, const QString &keyName)
Restore the wigget geometry from settings.
void saveGeometry(QWidget *widget, const QString &keyName)
Save the wigget geometry into settings.
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.