Fix crash when deleting item being edited in wxOSX wxDataViewCtrl
Avoid touching the model while updating the control due to the items being deleted from it, as doing this can easily result in dereferencing pointers to the already deleted objects and crashing. This is rather ugly, but the original code seems to have been written with this approach in mind (see preexisting comments in ItemDeleted()) and, to be fair, there doesn't seem any other solution with the existing API, as it allows (or maybe even requires?) deleting the items _before_ notifying the control about their removal and so not giving it any opportunity to stop editing the item while it's still alive. Closes #18337.
This commit is contained in:
@@ -568,6 +568,14 @@ outlineView:(NSOutlineView*)outlineView
|
|||||||
{
|
{
|
||||||
wxUnusedVar(outlineView);
|
wxUnusedVar(outlineView);
|
||||||
|
|
||||||
|
if ( implementation->GetDataViewCtrl()->IsDeleting() )
|
||||||
|
{
|
||||||
|
// Note that returning "NO" here would result in currently expanded
|
||||||
|
// branches not being expanded any more, while returning "YES" doesn't
|
||||||
|
// seem to have any ill effects, even though this is clearly bogus.
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
wxCHECK_MSG( model, 0, "Valid model in data source does not exist." );
|
wxCHECK_MSG( model, 0, "Valid model in data source does not exist." );
|
||||||
return model->IsContainer(wxDataViewItemFromItem(item));
|
return model->IsContainer(wxDataViewItemFromItem(item));
|
||||||
}
|
}
|
||||||
@@ -597,6 +605,15 @@ outlineView:(NSOutlineView*)outlineView
|
|||||||
{
|
{
|
||||||
wxUnusedVar(outlineView);
|
wxUnusedVar(outlineView);
|
||||||
|
|
||||||
|
// We ignore any calls to this function happening while items are being
|
||||||
|
// deleted, as they can (only?) come from -[NSTableView textDidEndEditing:]
|
||||||
|
// called from our own textDidEndEditing, which is called by
|
||||||
|
// -[NSOutlineView reloadItem:reloadChildren:], and if the item being
|
||||||
|
// edited is one of the items being deleted, then trying to use it would
|
||||||
|
// attempt to use already freed memory and crash.
|
||||||
|
if ( implementation->GetDataViewCtrl()->IsDeleting() )
|
||||||
|
return nil;
|
||||||
|
|
||||||
wxCHECK_MSG( model, nil, "Valid model in data source does not exist." );
|
wxCHECK_MSG( model, nil, "Valid model in data source does not exist." );
|
||||||
|
|
||||||
wxDataViewColumn* const
|
wxDataViewColumn* const
|
||||||
@@ -623,6 +640,11 @@ outlineView:(NSOutlineView*)outlineView
|
|||||||
{
|
{
|
||||||
wxUnusedVar(outlineView);
|
wxUnusedVar(outlineView);
|
||||||
|
|
||||||
|
// See the comment in outlineView:objectValueForTableColumn:byItem: above:
|
||||||
|
// this function can also be called in the same circumstances.
|
||||||
|
if ( implementation->GetDataViewCtrl()->IsDeleting() )
|
||||||
|
return;
|
||||||
|
|
||||||
wxDataViewColumn* const
|
wxDataViewColumn* const
|
||||||
col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
|
col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
|
||||||
|
|
||||||
@@ -1937,6 +1959,10 @@ outlineView:(NSOutlineView*)outlineView
|
|||||||
{
|
{
|
||||||
// call method of superclass (otherwise editing does not work correctly -
|
// call method of superclass (otherwise editing does not work correctly -
|
||||||
// the outline data source class is not informed about a change of data):
|
// the outline data source class is not informed about a change of data):
|
||||||
|
//
|
||||||
|
// Note that we really, really need to do this, as otherwise we would be
|
||||||
|
// left with an orphan text control -- even though doing this forces us to
|
||||||
|
// have the checks for IsDeleting() in several other methods of this class.
|
||||||
[super textDidEndEditing:notification];
|
[super textDidEndEditing:notification];
|
||||||
|
|
||||||
// under OSX an event indicating the end of an editing session can be sent
|
// under OSX an event indicating the end of an editing session can be sent
|
||||||
|
Reference in New Issue
Block a user