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, [=](
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.
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)
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)
Class for parsing and evaluation of expressions (formerly called "search strings").
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
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.
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 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)
A QTableView subclass with QGIS specific tweaks and improvements.
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.
#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.