Skip to content

Commit

Permalink
Fix action column widget rendering artifacts
Browse files Browse the repository at this point in the history
This creates an action column widget when the widget is rendered for the
first time.
The original approach was to create an image and render the buffered
image onto the cell until the first mouse action triggered the creation
of the real widget. This led to several rendering problems and triggered
some strange ownership issues with crashes under certain situations.

Followup a05b2ad
  • Loading branch information
m-kuhn committed Jun 14, 2016
1 parent 6d1e554 commit 3fcabc9
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 44 deletions.
10 changes: 8 additions & 2 deletions python/gui/attributetable/qgsattributetabledelegate.sip
Expand Up @@ -40,8 +40,14 @@ class QgsAttributeTableDelegate : QItemDelegate

void setFeatureSelectionModel( QgsFeatureSelectionModel* featureSelectionModel );

signals:
/**
* Set an image that represents an action widget
* Is emitted when an action column item is painted.
* The consumer of this signal can initialize the index widget.
*
* @note This signal is emitted repeatedly whenever the item is being painted.
* It is the consumers responsibility to check if initialization has already
* happened before.
*/
void setActionWidgetImage( const QImage& image );
void actionColumnItemPainted( const QModelIndex& index ) const;
};
9 changes: 1 addition & 8 deletions src/gui/attributetable/qgsattributetabledelegate.cpp
Expand Up @@ -118,20 +118,13 @@ void QgsAttributeTableDelegate::setFeatureSelectionModel( QgsFeatureSelectionMod
mFeatureSelectionModel = featureSelectionModel;
}

void QgsAttributeTableDelegate::setActionWidgetImage( const QImage& image )
{
mActionWidgetImage = image;
}


void QgsAttributeTableDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
QgsAttributeTableFilterModel::ColumnType columnType = static_cast<QgsAttributeTableFilterModel::ColumnType>( index.model()->data( index, QgsAttributeTableFilterModel::TypeRole ).toInt() );

if ( columnType == QgsAttributeTableFilterModel::ColumnTypeActionButton )
{
QRect r = option.rect.adjusted( -1, 0, 0, 0 );
painter->drawImage( r.x(), r.y(), mActionWidgetImage );
emit actionColumnItemPainted( index );
}
else
{
Expand Down
11 changes: 8 additions & 3 deletions src/gui/attributetable/qgsattributetabledelegate.h
Expand Up @@ -77,15 +77,20 @@ class GUI_EXPORT QgsAttributeTableDelegate : public QItemDelegate

void setFeatureSelectionModel( QgsFeatureSelectionModel* featureSelectionModel );

signals:
/**
* Set an image that represents an action widget
* Is emitted when an action column item is painted.
* The consumer of this signal can initialize the index widget.
*
* @note This signal is emitted repeatedly whenever the item is being painted.
* It is the consumers responsibility to check if initialization has already
* happened before.
*/
void setActionWidgetImage( const QImage& image );
void actionColumnItemPainted( const QModelIndex& index ) const;

private:
QgsVectorLayer* mLayer;
QgsFeatureSelectionModel* mFeatureSelectionModel;
QImage mActionWidgetImage;
};

#endif //QGSATTRIBUTETABLEDELEGATE_H
34 changes: 6 additions & 28 deletions src/gui/attributetable/qgsattributetableview.cpp
Expand Up @@ -35,15 +35,12 @@

QgsAttributeTableView::QgsAttributeTableView( QWidget *parent )
: QTableView( parent )
, mMasterModel( nullptr )
, mFilterModel( nullptr )
, mFeatureSelectionModel( nullptr )
, mFeatureSelectionManager( nullptr )
, mModel( nullptr )
, mActionPopup( nullptr )
, mRowSectionAnchor( 0 )
, mCtrlDragSelectionFlag( QItemSelectionModel::Select )
, mActionWidget( nullptr )
{
QSettings settings;
restoreGeometry( settings.value( "/BetterAttributeTable/geometry" ).toByteArray() );
Expand All @@ -52,8 +49,6 @@ QgsAttributeTableView::QgsAttributeTableView( QWidget *parent )
horizontalHeader()->setHighlightSections( false );

// We need mouse move events to create the action button on hover
setMouseTracking( true );

mTableDelegate = new QgsAttributeTableDelegate( this );
setItemDelegate( mTableDelegate );

Expand Down Expand Up @@ -121,6 +116,7 @@ void QgsAttributeTableView::setModel( QgsAttributeTableFilterModel* filterModel
if ( mFilterModel )
{
connect( mFilterModel, SIGNAL( destroyed() ), this, SLOT( modelDeleted() ) );
connect( mTableDelegate, SIGNAL( actionColumnItemPainted( QModelIndex ) ), this, SLOT( onActionColumnItemPainted( QModelIndex ) ) );
}

delete mFeatureSelectionModel;
Expand All @@ -138,10 +134,6 @@ void QgsAttributeTableView::setModel( QgsAttributeTableFilterModel* filterModel
mTableDelegate->setFeatureSelectionModel( mFeatureSelectionModel );
connect( mFeatureSelectionModel, SIGNAL( requestRepaint( QModelIndexList ) ), this, SLOT( repaintRequested( QModelIndexList ) ) );
connect( mFeatureSelectionModel, SIGNAL( requestRepaint() ), this, SLOT( repaintRequested() ) );

mActionWidget.reset( createActionWidget( 0 ) );
mActionWidget->setVisible( false );
updateActionImage( mActionWidget.data() );
}
}

Expand Down Expand Up @@ -238,15 +230,6 @@ void QgsAttributeTableView::mouseReleaseEvent( QMouseEvent *event )

void QgsAttributeTableView::mouseMoveEvent( QMouseEvent *event )
{
QModelIndex index = indexAt( event->pos() );
if ( index.data( QgsAttributeTableFilterModel::TypeRole ) == QgsAttributeTableFilterModel::ColumnTypeActionButton )
{
Q_ASSERT( index.isValid() );

if ( !indexWidget( index ) )
setIndexWidget( index, createActionWidget( mFilterModel->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong() ) );
}

setSelectionMode( QAbstractItemView::NoSelection );
QTableView::mouseMoveEvent( event );
setSelectionMode( QAbstractItemView::ExtendedSelection );
Expand Down Expand Up @@ -396,18 +379,13 @@ void QgsAttributeTableView::actionTriggered()
void QgsAttributeTableView::columnSizeChanged( int index, int oldWidth, int newWidth )
{
Q_UNUSED( oldWidth )
if ( mFilterModel->actionColumnIndex() == index )
{
mActionWidget->resize( newWidth, mActionWidget->height() );
updateActionImage( mActionWidget.data() );
}
emit columnResized( index, newWidth );
}

void QgsAttributeTableView::updateActionImage( QWidget* widget )
void QgsAttributeTableView::onActionColumnItemPainted( const QModelIndex& index )
{
QImage image( widget->size(), QImage::Format_ARGB32_Premultiplied );
QPainter painter( &image );
widget->render( &painter );
mTableDelegate->setActionWidgetImage( image );
if ( !indexWidget( index ) )
{
setIndexWidget( index, createActionWidget( mFilterModel->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong() ) );
}
}
4 changes: 1 addition & 3 deletions src/gui/attributetable/qgsattributetableview.h
Expand Up @@ -155,22 +155,20 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
void showHorizontalSortIndicator();
void actionTriggered();
void columnSizeChanged( int index, int oldWidth, int newWidth );
void onActionColumnItemPainted( const QModelIndex& index );

private:
void updateActionImage( QWidget* widget );
QWidget* createActionWidget( QgsFeatureId fid );

void selectRow( int row, bool anchor );
QgsAttributeTableModel* mMasterModel;
QgsAttributeTableFilterModel* mFilterModel;
QgsFeatureSelectionModel* mFeatureSelectionModel;
QgsIFeatureSelectionManager* mFeatureSelectionManager;
QgsAttributeTableDelegate* mTableDelegate;
QAbstractItemModel* mModel; // Most likely the filter model
QMenu *mActionPopup;
int mRowSectionAnchor;
QItemSelectionModel::SelectionFlag mCtrlDragSelectionFlag;
QScopedPointer<QWidget> mActionWidget;
};

#endif

0 comments on commit 3fcabc9

Please sign in to comment.