mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-16 00:03:12 -04:00
[bugfix] Do not crash when layer is destroyed while loading
Fixes #17636 QGIS crashes when a layer is removed while loading the attribute table
This commit is contained in:
parent
53ebe050bd
commit
e479b71594
@ -208,6 +208,12 @@ class QgsDualView : QStackedWidget
|
|||||||
%Docstring
|
%Docstring
|
||||||
Copy the content of the selected cell in the clipboard.
|
Copy the content of the selected cell in the clipboard.
|
||||||
.. versionadded:: 1.16
|
.. versionadded:: 1.16
|
||||||
|
%End
|
||||||
|
|
||||||
|
void cancelProgress( );
|
||||||
|
%Docstring
|
||||||
|
Cancel the progress dialog (if any)
|
||||||
|
.. versionadded:: 3.0
|
||||||
%End
|
%End
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
@ -69,7 +69,7 @@ QgsExpressionContext QgsAttributeTableDialog::createExpressionContext() const
|
|||||||
|
|
||||||
void QgsAttributeTableDialog::updateMultiEditButtonState()
|
void QgsAttributeTableDialog::updateMultiEditButtonState()
|
||||||
{
|
{
|
||||||
if ( mLayer->editFormConfig().layout() == QgsEditFormConfig::UiFileLayout )
|
if ( ! mLayer || ( mLayer->editFormConfig().layout() == QgsEditFormConfig::UiFileLayout ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mActionToggleMultiEdit->setEnabled( mLayer->isEditable() );
|
mActionToggleMultiEdit->setEnabled( mLayer->isEditable() );
|
||||||
@ -199,7 +199,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttr
|
|||||||
// info from layer to table
|
// info from layer to table
|
||||||
connect( mLayer, &QgsVectorLayer::editingStarted, this, &QgsAttributeTableDialog::editingToggled );
|
connect( mLayer, &QgsVectorLayer::editingStarted, this, &QgsAttributeTableDialog::editingToggled );
|
||||||
connect( mLayer, &QgsVectorLayer::editingStopped, 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::selectionChanged, this, &QgsAttributeTableDialog::updateTitle );
|
||||||
connect( mLayer, &QgsVectorLayer::featureAdded, this, &QgsAttributeTableDialog::updateTitle );
|
connect( mLayer, &QgsVectorLayer::featureAdded, this, &QgsAttributeTableDialog::updateTitle );
|
||||||
connect( mLayer, &QgsVectorLayer::featuresDeleted, this, &QgsAttributeTableDialog::updateTitle );
|
connect( mLayer, &QgsVectorLayer::featuresDeleted, this, &QgsAttributeTableDialog::updateTitle );
|
||||||
@ -292,59 +292,69 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttr
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mUpdateExpressionText->registerExpressionContextGenerator( this );
|
// Layer might have been destroyed while loading!
|
||||||
mFieldCombo->setFilters( QgsFieldProxyModel::AllTypes | QgsFieldProxyModel::HideReadOnly );
|
if ( mLayer )
|
||||||
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();
|
mUpdateExpressionText->registerExpressionContextGenerator( this );
|
||||||
}
|
mFieldCombo->setFilters( QgsFieldProxyModel::AllTypes | QgsFieldProxyModel::HideReadOnly );
|
||||||
mMainView->setView( static_cast< QgsDualView::ViewMode >( initialView ) );
|
mFieldCombo->setLayer( mLayer );
|
||||||
mMainViewButtonGroup->button( initialView )->setChecked( true );
|
|
||||||
|
|
||||||
connect( mActionToggleMultiEdit, &QAction::toggled, mMainView, &QgsDualView::setMultiEditEnabled );
|
connect( mRunFieldCalc, &QAbstractButton::clicked, this, &QgsAttributeTableDialog::updateFieldFromExpression );
|
||||||
connect( mActionSearchForm, &QAction::toggled, mMainView, &QgsDualView::toggleSearchMode );
|
connect( mRunFieldCalcSelected, &QAbstractButton::clicked, this, &QgsAttributeTableDialog::updateFieldFromExpressionSelected );
|
||||||
updateMultiEditButtonState();
|
// 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 );
|
||||||
|
|
||||||
if ( mLayer->editFormConfig().layout() == QgsEditFormConfig::UiFileLayout )
|
int initialView = settings.value( QStringLiteral( "qgis/attributeTableView" ), -1 ).toInt();
|
||||||
{
|
if ( initialView < 0 )
|
||||||
//not supported with custom UI
|
{
|
||||||
mActionToggleMultiEdit->setEnabled( false );
|
initialView = settings.value( QStringLiteral( "qgis/attributeTableLastView" ), QgsDualView::AttributeTable ).toInt();
|
||||||
mActionToggleMultiEdit->setToolTip( tr( "Multiedit is not supported when using custom UI forms" ) );
|
}
|
||||||
mActionSearchForm->setEnabled( false );
|
mMainView->setView( static_cast< QgsDualView::ViewMode >( initialView ) );
|
||||||
mActionSearchForm->setToolTip( tr( "Search is not supported when using custom UI forms" ) );
|
mMainViewButtonGroup->button( initialView )->setChecked( true );
|
||||||
}
|
|
||||||
|
|
||||||
QList<QgsAction> actions = mLayer->actions()->actions( QStringLiteral( "Layer" ) );
|
connect( mActionToggleMultiEdit, &QAction::toggled, mMainView, &QgsDualView::setMultiEditEnabled );
|
||||||
|
connect( mActionSearchForm, &QAction::toggled, mMainView, &QgsDualView::toggleSearchMode );
|
||||||
|
updateMultiEditButtonState();
|
||||||
|
|
||||||
if ( actions.isEmpty() )
|
if ( mLayer->editFormConfig().layout() == QgsEditFormConfig::UiFileLayout )
|
||||||
{
|
{
|
||||||
mActionFeatureActions->setVisible( false );
|
//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" ) );
|
||||||
|
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
QMenu *actionMenu = new QMenu();
|
QWidget::close();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QgsAttributeTableDialog::~QgsAttributeTableDialog()
|
QgsAttributeTableDialog::~QgsAttributeTableDialog()
|
||||||
@ -354,6 +364,10 @@ QgsAttributeTableDialog::~QgsAttributeTableDialog()
|
|||||||
|
|
||||||
void QgsAttributeTableDialog::updateTitle()
|
void QgsAttributeTableDialog::updateTitle()
|
||||||
{
|
{
|
||||||
|
if ( ! mLayer )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
QWidget *w = mDock ? qobject_cast<QWidget *>( mDock ) : qobject_cast<QWidget *>( this );
|
QWidget *w = mDock ? qobject_cast<QWidget *>( mDock ) : qobject_cast<QWidget *>( this );
|
||||||
w->setWindowTitle( tr( " %1 :: Features Total: %2, Filtered: %3, Selected: %4" )
|
w->setWindowTitle( tr( " %1 :: Features Total: %2, Filtered: %3, Selected: %4" )
|
||||||
.arg( mLayer->name() )
|
.arg( mLayer->name() )
|
||||||
|
@ -230,7 +230,7 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
|
|||||||
QMenu *mFilterColumnsMenu = nullptr;
|
QMenu *mFilterColumnsMenu = nullptr;
|
||||||
QSignalMapper *mFilterActionMapper = nullptr;
|
QSignalMapper *mFilterActionMapper = nullptr;
|
||||||
|
|
||||||
QgsVectorLayer *mLayer = nullptr;
|
QPointer< QgsVectorLayer > mLayer = nullptr;
|
||||||
QgsSearchWidgetWrapper *mCurrentSearchWidgetWrapper = nullptr;
|
QgsSearchWidgetWrapper *mCurrentSearchWidgetWrapper = nullptr;
|
||||||
QStringList mVisibleFields;
|
QStringList mVisibleFields;
|
||||||
QgsAttributeEditorContext mEditorContext;
|
QgsAttributeEditorContext mEditorContext;
|
||||||
|
@ -318,6 +318,10 @@ void QgsDualView::restoreRecentDisplayExpressions()
|
|||||||
|
|
||||||
void QgsDualView::saveRecentDisplayExpressions() const
|
void QgsDualView::saveRecentDisplayExpressions() const
|
||||||
{
|
{
|
||||||
|
if ( ! mLayer )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
QList<QAction *> actions = mFeatureListPreviewButton->actions();
|
QList<QAction *> actions = mFeatureListPreviewButton->actions();
|
||||||
|
|
||||||
// Remove existing same action
|
// Remove existing same action
|
||||||
@ -397,6 +401,7 @@ void QgsDualView::insertRecentlyUsedDisplayExpression( const QString &expression
|
|||||||
mLastDisplayExpressionAction = previewAction;
|
mLastDisplayExpressionAction = previewAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void QgsDualView::mFeatureList_aboutToChangeEditSelection( bool &ok )
|
void QgsDualView::mFeatureList_aboutToChangeEditSelection( bool &ok )
|
||||||
{
|
{
|
||||||
if ( mLayer->isEditable() && !mAttributeForm->save() )
|
if ( mLayer->isEditable() && !mAttributeForm->save() )
|
||||||
@ -515,6 +520,12 @@ void QgsDualView::copyCellContent() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsDualView::cancelProgress()
|
||||||
|
{
|
||||||
|
if ( mProgressDlg )
|
||||||
|
mProgressDlg->cancel();
|
||||||
|
}
|
||||||
|
|
||||||
void QgsDualView::hideEvent( QHideEvent *event )
|
void QgsDualView::hideEvent( QHideEvent *event )
|
||||||
{
|
{
|
||||||
Q_UNUSED( event )
|
Q_UNUSED( event )
|
||||||
|
@ -236,6 +236,12 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
|
|||||||
*/
|
*/
|
||||||
void copyCellContent() const;
|
void copyCellContent() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel the progress dialog (if any)
|
||||||
|
* \since QGIS 3.0
|
||||||
|
*/
|
||||||
|
void cancelProgress( );
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -360,7 +366,7 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
|
|||||||
QAction *mLastDisplayExpressionAction = nullptr;
|
QAction *mLastDisplayExpressionAction = nullptr;
|
||||||
QMenu *mHorizontalHeaderMenu = nullptr;
|
QMenu *mHorizontalHeaderMenu = nullptr;
|
||||||
QgsVectorLayerCache *mLayerCache = nullptr;
|
QgsVectorLayerCache *mLayerCache = nullptr;
|
||||||
QgsVectorLayer *mLayer = nullptr;
|
QPointer< QgsVectorLayer > mLayer = nullptr;
|
||||||
QProgressDialog *mProgressDlg = nullptr;
|
QProgressDialog *mProgressDlg = nullptr;
|
||||||
QgsIFeatureSelectionManager *mFeatureSelectionManager = nullptr;
|
QgsIFeatureSelectionManager *mFeatureSelectionManager = nullptr;
|
||||||
QgsDistanceArea mDistanceArea;
|
QgsDistanceArea mDistanceArea;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user