16 #include <QDesktopServices>
18 #include <QHeaderView>
20 #include <QToolButton>
21 #include <QHBoxLayout>
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 );