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() );
110 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.