Game Development Community

Question about solving a bug found. in the GUI Tree Control.

by Antony K Jones · in Torque 3D Professional · 02/01/2015 (12:15 pm) · 4 replies

I think I found a bug.

Notice that when removeItem() is called it calls _destroyItem().
Imagine when this function is called you have 2 elements in mItems.
And this is called to delete the 2nd element in mItems.
You will notice that all _destroyItem does is set the 2nd element
in mItems to NULL. So that the tVector still thinks it has 2 elements
in it the second one being NULL.
There is a lot of places in the code not testing for NULL.
Am I right that somehow we should be resizing the array?
What is the best solution for this?



bool GuiTreeViewCtrl::removeItem( S32 itemId, bool deleteObjects )
{
if( isSelected( itemId ) )
removeSelection( itemId );

// tree?
if(itemId == 0)
{
//RD: this does not delete objects and thus isn't coherent with the semantics of this method

_destroyTree();
return(true);
}

Item * item = getItem(itemId);
if(!item)
{
//Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::removeItem: invalid item id!");
return false;
}

// root?
if(item == mRoot)
mRoot = item->mNext;

// Dispose of any children...
if (item->mChild)
_destroyChildren( item->mChild, item, deleteObjects );

// Kill the item...
--> _destroyItem( item, deleteObjects );

// Update the rendered tree...
mFlags.set(RebuildVisible);

return true;
}

void GuiTreeViewCtrl::_destroyItem( Item* item, bool deleteObject )
{
if(!item)
return;

if(item->isInspectorData())
{
// make sure the SimObjectPtr is clean!
SimObject *pObject = item->getObject();
if( pObject && pObject->isProperlyAdded() )
{
bool skipDelete = !deleteObject;

if( !skipDelete && isMethod( "onDeleteObject" ) )
skipDelete = onDeleteObject_callback( pObject );

if ( !skipDelete )
pObject->deleteObject();
}

item->setObject( NULL );
}

// Remove item from the selection
if (mSelectedItem == item->mId)
mSelectedItem = 0;
for ( S32 i = 0; i < mSelectedItems.size(); i++ )
{
if ( mSelectedItems[i] == item )
{
mSelectedItems.erase( i );
break;
}
}
item->mState.clear();

// unlink
if( item->mPrevious )
item->mPrevious->mNext = item->mNext;
if( item->mNext )
item->mNext->mPrevious = item->mPrevious;
if( item->mParent && ( item->mParent->mChild == item ) )
item->mParent->mChild = item->mNext;

// remove from vector
--> mItems[item->mId-1] = 0;

// set as root free item
item->mNext = mItemFreeList;
mItemFreeList = item;
mItemCount--;
}

#1
02/01/2015 (3:00 pm)
It seems like the intended behavior was keeping around the NULL elements otherwise. The item's ID's would get messed up. I chose for now to fix the crash by testing for NULL in the findItemByName function.

S32 GuiTreeViewCtrl::findItemByName(const char *name)
{
for (S32 i = 0; i < mItems.size(); i++)
{
-->if ( !mItems[i] )
--> continue;
if( mItems[i]->mState.test( Item::InspectorData ) )
continue;
if (mItems[i] && dStrcmp(mItems[i]->getText(),name) == 0)
return mItems[i]->mId;
}

return 0;
}
#2
02/01/2015 (7:23 pm)
What were you doing to cause it to crash, and why is it not more common? But either way, adding a NULL check is probably a good idea. Thanks for the catch :).
#3
02/01/2015 (8:26 pm)
np, thanks Dan. ill create a pull request.
#4
02/10/2015 (5:48 pm)
I was testing undo and redo for node creation in the shape editor.