16 #include <QDesktopServices> 
   18 #include <QHeaderView> 
   20 #include <QToolButton> 
   21 #include <QHBoxLayout> 
   42   : QTableView( parent )
 
   45   restoreGeometry( settings.
value( QStringLiteral( 
"BetterAttributeTable/geometry" ) ).toByteArray() );
 
   48   horizontalHeader()->setHighlightSections( 
false );
 
   52   setItemDelegate( mTableDelegate );
 
   54   setEditTriggers( QAbstractItemView::AllEditTriggers );
 
   56   setSelectionBehavior( QAbstractItemView::SelectRows );
 
   57   setSelectionMode( QAbstractItemView::ExtendedSelection );
 
   58   setSortingEnabled( 
true ); 
 
   59   horizontalHeader()->setSortIndicatorShown( 
false ); 
 
   61   setHorizontalScrollMode( QAbstractItemView::ScrollPerPixel );
 
   63   verticalHeader()->viewport()->installEventFilter( 
this );
 
   65   connect( verticalHeader(), &QHeaderView::sectionPressed, 
this, [ = ]( 
int row ) { 
selectRow( row, 
true ); } );
 
   67   connect( horizontalHeader(), &QHeaderView::sectionResized, 
this, &QgsAttributeTableView::columnSizeChanged );
 
   68   connect( horizontalHeader(), &QHeaderView::sortIndicatorChanged, 
this, &QgsAttributeTableView::showHorizontalSortIndicator );
 
   74   if ( 
object == verticalHeader()->viewport() )
 
   76     switch ( event->type() )
 
   78       case QEvent::MouseButtonPress:
 
   82       case QEvent::MouseButtonRelease:
 
   90   return QTableView::eventFilter( 
object, event );
 
   96   const auto constColumns = config.
columns();
 
   97   QMap<QString, int> columns;
 
  100     if ( columnConfig.hidden )
 
  103     if ( columnConfig.width >= 0 )
 
  105       setColumnWidth( i, columnConfig.width );
 
  109       setColumnWidth( i, horizontalHeader()->defaultSectionSize() );
 
  111     columns.insert( columnConfig.name, i );
 
  117     horizontalHeader()->setSortIndicatorShown( 
false );
 
  124       if ( sortExp.isField() )
 
  126         const QStringList refCols { sortExp.referencedColumns().values() };
 
  127         horizontalHeader()->setSortIndicatorShown( 
true );
 
  128         horizontalHeader()->setSortIndicator( columns.value( refCols.constFirst() ), config.
sortOrder() );
 
  141   QModelIndexList indexList;
 
  144     const QModelIndex index = mFilterModel->
fidToIndex( 
id );
 
  148   std::sort( indexList.begin(), indexList.end() );
 
  149   QList<QgsFeatureId> ids;
 
  150   for ( 
const QModelIndex &index : indexList )
 
  160   mFilterModel = filterModel;
 
  161   QTableView::setModel( mFilterModel );
 
  165     connect( mFilterModel, &QObject::destroyed, 
this, &QgsAttributeTableView::modelDeleted );
 
  169   delete mFeatureSelectionModel;
 
  170   mFeatureSelectionModel = 
nullptr;
 
  174     if ( !mFeatureSelectionManager )
 
  177       mFeatureSelectionManager = mOwnedFeatureSelectionManager;
 
  180     mFeatureSelectionModel = 
new QgsFeatureSelectionModel( mFilterModel, mFilterModel, mFeatureSelectionManager, mFilterModel );
 
  181     setSelectionModel( mFeatureSelectionModel );
 
  196   mFeatureSelectionManager = featureSelectionManager;
 
  198   if ( mFeatureSelectionModel )
 
  202   if ( mOwnedFeatureSelectionManager )
 
  204     mOwnedFeatureSelectionManager->deleteLater();
 
  205     mOwnedFeatureSelectionManager = 
nullptr;
 
  209 QWidget *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() : QString();
 
  242     QAction *act = 
new QAction( action.icon(), actionTitle, container );
 
  243     act->setToolTip( action.name() );
 
  244     act->setData( 
"user_action" );
 
  245     act->setProperty( 
"fid", fid );
 
  246     act->setProperty( 
"action_id", action.id() );
 
  247     connect( act, &QAction::triggered, 
this, &QgsAttributeTableView::actionTriggered );
 
  258     QAction *action = 
new QAction( mapLayerAction->icon(), mapLayerAction->text(), container );
 
  259     action->setData( 
"map_layer_action" );
 
  260     action->setToolTip( mapLayerAction->text() );
 
  261     action->setProperty( 
"fid", fid );
 
  262     action->setProperty( 
"action", QVariant::fromValue( qobject_cast<QObject *>( mapLayerAction ) ) );
 
  263     connect( action, &QAction::triggered, 
this, &QgsAttributeTableView::actionTriggered );
 
  264     actionList << action;
 
  266     if ( !defaultAction &&
 
  268       defaultAction = action;
 
  271   if ( !defaultAction && !actionList.isEmpty() )
 
  272     defaultAction = actionList.at( 0 );
 
  274   const auto constActionList = actionList;
 
  275   for ( QAction *act : constActionList )
 
  279       toolButton->addAction( act );
 
  281       if ( act == defaultAction )
 
  282         toolButton->setDefaultAction( act );
 
  284       container = toolButton;
 
  288       QToolButton *btn = 
new QToolButton;
 
  289       btn->setDefaultAction( act );
 
  290       container->layout()->addWidget( btn );
 
  296     static_cast< QHBoxLayout * 
>( container->layout() )->addStretch();
 
  301   if ( toolButton && !toolButton->actions().isEmpty() && actions->defaultAction() == -1 )
 
  302     toolButton->setDefaultAction( toolButton->actions().at( 0 ) );
 
  312   settings.
setValue( QStringLiteral( 
"BetterAttributeTable/geometry" ), QVariant( 
saveGeometry() ) );
 
  317   setSelectionMode( QAbstractItemView::NoSelection );
 
  318   QTableView::mousePressEvent( event );
 
  319   setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  324   setSelectionMode( QAbstractItemView::NoSelection );
 
  325   QTableView::mouseReleaseEvent( event );
 
  326   setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  327   if ( event->modifiers() == Qt::ControlModifier )
 
  329     const QModelIndex index = indexAt( event->pos() );
 
  330     const QVariant data = model()->data( index, Qt::DisplayRole );
 
  331     if ( data.type() == QVariant::String )
 
  333       const QString textVal = data.toString();
 
  336         QDesktopServices::openUrl( QUrl( textVal ) );
 
  344   setSelectionMode( QAbstractItemView::NoSelection );
 
  345   QTableView::mouseMoveEvent( event );
 
  346   setSelectionMode( QAbstractItemView::ExtendedSelection );
 
  351   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() );
 
  432 void QgsAttributeTableView::modelDeleted()
 
  434   mFilterModel = 
nullptr;
 
  435   mFeatureSelectionManager = 
nullptr;
 
  436   mFeatureSelectionModel = 
nullptr;
 
  441   if ( selectionBehavior() == QTableView::SelectColumns
 
  442        || ( selectionMode() == QTableView::SingleSelection
 
  443             && selectionBehavior() == QTableView::SelectItems ) )
 
  446   if ( row >= 0 && row < model()->rowCount() )
 
  448     const int column = horizontalHeader()->logicalIndexAt( isRightToLeft() ? viewport()->width() : 0 );
 
  449     const QModelIndex index = model()->index( row, column );
 
  450     QItemSelectionModel::SelectionFlags command = selectionCommand( index );
 
  451     selectionModel()->setCurrentIndex( index, QItemSelectionModel::NoUpdate );
 
  452     if ( ( anchor && !( command & QItemSelectionModel::Current ) )
 
  453          || ( selectionMode() == QTableView::SingleSelection ) )
 
  454       mRowSectionAnchor = row;
 
  456     if ( selectionMode() != QTableView::SingleSelection
 
  457          && command.testFlag( QItemSelectionModel::Toggle ) )
 
  460         mCtrlDragSelectionFlag = mFeatureSelectionModel->
isSelected( index )
 
  461                                  ? QItemSelectionModel::Deselect : 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 );
 
  477 void QgsAttributeTableView::showHorizontalSortIndicator()
 
  479   horizontalHeader()->setSortIndicatorShown( 
true );
 
  482 void 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 *>();
 
  500       layerAction->triggerForFeature( mFilterModel->
layer(), f );
 
  505 void QgsAttributeTableView::columnSizeChanged( 
int index, 
int oldWidth, 
int newWidth )
 
  511 void QgsAttributeTableView::onActionColumnItemPainted( 
const QModelIndex &index )
 
  513   if ( !indexWidget( index ) )
 
  516     mActionWidgets.insert( index, widget );
 
  517     setIndexWidget( index, widget );
 
  521 void QgsAttributeTableView::recreateActionWidgets()
 
  523   QMap< QModelIndex, QWidget * >::const_iterator it = mActionWidgets.constBegin();
 
  524   for ( ; it != mActionWidgets.constEnd(); ++it )
 
  529     setIndexWidget( it.key(), 
nullptr );
 
  531   mActionWidgets.clear();
 
  536   const QModelIndex index = mFilterModel->
fidToIndex( fid );
 
  538   if ( !index.isValid() )
 
  543   const QModelIndex selectionIndex = index.sibling( index.row(), col );
 
  545   if ( !selectionIndex.isValid() )
 
  548   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.
 
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)
 
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)
 
Class for parsing and evaluation of expressions (formerly called "search strings").
 
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:
 
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
 
void editingStarted()
Emitted when editing on this layer has started.
 
This class is a composition of two QSettings instances:
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
 
void 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)
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
 
Represents a vector layer which manages a vector based data sets.
 
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.