Skip to content

Commit

Permalink
Merge pull request #5831 from elpaso/bugfix-17636-attrtable-progress
Browse files Browse the repository at this point in the history
[bugfix] Do not crash when layer is destroyed while loading
  • Loading branch information
elpaso committed Dec 11, 2017
2 parents 7037c29 + e479b71 commit 135ba69
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 48 deletions.
6 changes: 6 additions & 0 deletions python/gui/attributetable/qgsdualview.sip
Expand Up @@ -208,6 +208,12 @@ class QgsDualView : QStackedWidget
%Docstring
Copy the content of the selected cell in the clipboard.
.. versionadded:: 1.16
%End

void cancelProgress( );
%Docstring
Cancel the progress dialog (if any)
.. versionadded:: 3.0
%End

signals:
Expand Down
106 changes: 60 additions & 46 deletions src/app/qgsattributetabledialog.cpp
Expand Up @@ -69,7 +69,7 @@ QgsExpressionContext QgsAttributeTableDialog::createExpressionContext() const

void QgsAttributeTableDialog::updateMultiEditButtonState()
{
if ( mLayer->editFormConfig().layout() == QgsEditFormConfig::UiFileLayout )
if ( ! mLayer || ( mLayer->editFormConfig().layout() == QgsEditFormConfig::UiFileLayout ) )
return;

mActionToggleMultiEdit->setEnabled( mLayer->isEditable() );
Expand Down Expand Up @@ -199,7 +199,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttr
// info from layer to table
connect( mLayer, &QgsVectorLayer::editingStarted, this, &QgsAttributeTableDialog::editingToggled );
connect( mLayer, &QgsVectorLayer::editingStopped, this, &QgsAttributeTableDialog::editingToggled );
connect( mLayer, &QObject::destroyed, this, &QWidget::close );
connect( mLayer, &QObject::destroyed, mMainView, &QgsDualView::cancelProgress );
connect( mLayer, &QgsVectorLayer::selectionChanged, this, &QgsAttributeTableDialog::updateTitle );
connect( mLayer, &QgsVectorLayer::featureAdded, this, &QgsAttributeTableDialog::updateTitle );
connect( mLayer, &QgsVectorLayer::featuresDeleted, this, &QgsAttributeTableDialog::updateTitle );
Expand Down Expand Up @@ -292,59 +292,69 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttr
break;
}

mUpdateExpressionText->registerExpressionContextGenerator( this );
mFieldCombo->setFilters( QgsFieldProxyModel::AllTypes | QgsFieldProxyModel::HideReadOnly );
mFieldCombo->setLayer( mLayer );

connect( mRunFieldCalc, &QAbstractButton::clicked, this, &QgsAttributeTableDialog::updateFieldFromExpression );
connect( mRunFieldCalcSelected, &QAbstractButton::clicked, this, &QgsAttributeTableDialog::updateFieldFromExpressionSelected );
// NW TODO Fix in 2.6 - Doesn't work with field model for some reason.
// connect( mUpdateExpressionText, SIGNAL( returnPressed() ), this, SLOT( updateFieldFromExpression() ) );
connect( mUpdateExpressionText, static_cast < void ( QgsFieldExpressionWidget::* )( const QString &, bool ) > ( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsAttributeTableDialog::updateButtonStatus );
mUpdateExpressionText->setLayer( mLayer );
mUpdateExpressionText->setLeftHandButtonStyle( true );

int initialView = settings.value( QStringLiteral( "qgis/attributeTableView" ), -1 ).toInt();
if ( initialView < 0 )
// Layer might have been destroyed while loading!
if ( mLayer )
{
initialView = settings.value( QStringLiteral( "qgis/attributeTableLastView" ), QgsDualView::AttributeTable ).toInt();
}
mMainView->setView( static_cast< QgsDualView::ViewMode >( initialView ) );
mMainViewButtonGroup->button( initialView )->setChecked( true );
mUpdateExpressionText->registerExpressionContextGenerator( this );
mFieldCombo->setFilters( QgsFieldProxyModel::AllTypes | QgsFieldProxyModel::HideReadOnly );
mFieldCombo->setLayer( mLayer );

connect( mRunFieldCalc, &QAbstractButton::clicked, this, &QgsAttributeTableDialog::updateFieldFromExpression );
connect( mRunFieldCalcSelected, &QAbstractButton::clicked, this, &QgsAttributeTableDialog::updateFieldFromExpressionSelected );
// NW TODO Fix in 2.6 - Doesn't work with field model for some reason.
// connect( mUpdateExpressionText, SIGNAL( returnPressed() ), this, SLOT( updateFieldFromExpression() ) );
connect( mUpdateExpressionText, static_cast < void ( QgsFieldExpressionWidget::* )( const QString &, bool ) > ( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsAttributeTableDialog::updateButtonStatus );
mUpdateExpressionText->setLayer( mLayer );
mUpdateExpressionText->setLeftHandButtonStyle( true );

int initialView = settings.value( QStringLiteral( "qgis/attributeTableView" ), -1 ).toInt();
if ( initialView < 0 )
{
initialView = settings.value( QStringLiteral( "qgis/attributeTableLastView" ), QgsDualView::AttributeTable ).toInt();
}
mMainView->setView( static_cast< QgsDualView::ViewMode >( initialView ) );
mMainViewButtonGroup->button( initialView )->setChecked( true );

connect( mActionToggleMultiEdit, &QAction::toggled, mMainView, &QgsDualView::setMultiEditEnabled );
connect( mActionSearchForm, &QAction::toggled, mMainView, &QgsDualView::toggleSearchMode );
updateMultiEditButtonState();
connect( mActionToggleMultiEdit, &QAction::toggled, mMainView, &QgsDualView::setMultiEditEnabled );
connect( mActionSearchForm, &QAction::toggled, mMainView, &QgsDualView::toggleSearchMode );
updateMultiEditButtonState();

if ( mLayer->editFormConfig().layout() == QgsEditFormConfig::UiFileLayout )
{
//not supported with custom UI
mActionToggleMultiEdit->setEnabled( false );
mActionToggleMultiEdit->setToolTip( tr( "Multiedit is not supported when using custom UI forms" ) );
mActionSearchForm->setEnabled( false );
mActionSearchForm->setToolTip( tr( "Search is not supported when using custom UI forms" ) );
}
if ( mLayer->editFormConfig().layout() == QgsEditFormConfig::UiFileLayout )
{
//not supported with custom UI
mActionToggleMultiEdit->setEnabled( false );
mActionToggleMultiEdit->setToolTip( tr( "Multiedit is not supported when using custom UI forms" ) );
mActionSearchForm->setEnabled( false );
mActionSearchForm->setToolTip( tr( "Search is not supported when using custom UI forms" ) );
}

QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Layer" ) );
QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Layer" ) );

if ( actions.isEmpty() )
{
mActionFeatureActions->setVisible( false );
if ( actions.isEmpty() )
{
mActionFeatureActions->setVisible( false );
}
else
{
QMenu *actionMenu = new QMenu();
Q_FOREACH ( const QgsAction &action, actions )
{
QAction *qAction = actionMenu->addAction( action.icon(), action.shortTitle() );
qAction->setToolTip( action.name() );
qAction->setData( QVariant::fromValue<QgsAction>( action ) );
connect( qAction, &QAction::triggered, this, &QgsAttributeTableDialog::layerActionTriggered );
}
mActionFeatureActions->setMenu( actionMenu );
}

editingToggled();
// Close and delete if the layer has been destroyed
connect( mLayer, &QObject::destroyed, this, &QWidget::close );
}
else
{
QMenu *actionMenu = new QMenu();
Q_FOREACH ( const QgsAction &action, actions )
{
QAction *qAction = actionMenu->addAction( action.icon(), action.shortTitle() );
qAction->setToolTip( action.name() );
qAction->setData( QVariant::fromValue<QgsAction>( action ) );
connect( qAction, &QAction::triggered, this, &QgsAttributeTableDialog::layerActionTriggered );
}
mActionFeatureActions->setMenu( actionMenu );
QWidget::close();
}

editingToggled();
}

QgsAttributeTableDialog::~QgsAttributeTableDialog()
Expand All @@ -354,6 +364,10 @@ QgsAttributeTableDialog::~QgsAttributeTableDialog()

void QgsAttributeTableDialog::updateTitle()
{
if ( ! mLayer )
{
return;
}
QWidget *w = mDock ? qobject_cast<QWidget *>( mDock ) : qobject_cast<QWidget *>( this );
w->setWindowTitle( tr( " %1 :: Features Total: %2, Filtered: %3, Selected: %4" )
.arg( mLayer->name() )
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsattributetabledialog.h
Expand Up @@ -230,7 +230,7 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
QMenu *mFilterColumnsMenu = nullptr;
QSignalMapper *mFilterActionMapper = nullptr;

QgsVectorLayer *mLayer = nullptr;
QPointer< QgsVectorLayer > mLayer = nullptr;
QgsSearchWidgetWrapper *mCurrentSearchWidgetWrapper = nullptr;
QStringList mVisibleFields;
QgsAttributeEditorContext mEditorContext;
Expand Down
11 changes: 11 additions & 0 deletions src/gui/attributetable/qgsdualview.cpp
Expand Up @@ -318,6 +318,10 @@ void QgsDualView::restoreRecentDisplayExpressions()

void QgsDualView::saveRecentDisplayExpressions() const
{
if ( ! mLayer )
{
return;
}
QList<QAction *> actions = mFeatureListPreviewButton->actions();

// Remove existing same action
Expand Down Expand Up @@ -397,6 +401,7 @@ void QgsDualView::insertRecentlyUsedDisplayExpression( const QString &expression
mLastDisplayExpressionAction = previewAction;
}


void QgsDualView::mFeatureList_aboutToChangeEditSelection( bool &ok )
{
if ( mLayer->isEditable() && !mAttributeForm->save() )
Expand Down Expand Up @@ -515,6 +520,12 @@ void QgsDualView::copyCellContent() const
}
}

void QgsDualView::cancelProgress()
{
if ( mProgressDlg )
mProgressDlg->cancel();
}

void QgsDualView::hideEvent( QHideEvent *event )
{
Q_UNUSED( event )
Expand Down
8 changes: 7 additions & 1 deletion src/gui/attributetable/qgsdualview.h
Expand Up @@ -236,6 +236,12 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
*/
void copyCellContent() const;

/**
* Cancel the progress dialog (if any)
* \since QGIS 3.0
*/
void cancelProgress( );

signals:

/**
Expand Down Expand Up @@ -360,7 +366,7 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
QAction *mLastDisplayExpressionAction = nullptr;
QMenu *mHorizontalHeaderMenu = nullptr;
QgsVectorLayerCache *mLayerCache = nullptr;
QgsVectorLayer *mLayer = nullptr;
QPointer< QgsVectorLayer > mLayer = nullptr;
QProgressDialog *mProgressDlg = nullptr;
QgsIFeatureSelectionManager *mFeatureSelectionManager = nullptr;
QgsDistanceArea mDistanceArea;
Expand Down

0 comments on commit 135ba69

Please sign in to comment.