the wxTreeItemData object will be destroyed only when it's attached to a FileTreeItem, 
but in the code here, the ftd is not attached to any FileTreeItem, so it will NOT freed automatically.
What do you think does "AddTreeNode(tree, foldername, m_ProjectNode, true, FileTreeData::ftdkVirtualFolder, true, vfldIdx, ftd);" do?
Let's see the AddTreeNode function:
wxTreeItemId cbProject::AddTreeNode(wxTreeCtrl*                    tree,
                                    const wxString&                text,
                                    const wxTreeItemId&            parent,
                                    bool                           useFolders,
                                    FileTreeData::FileTreeDataKind folders_kind,
                                    bool                           compiles,
                                    int                            image,
                                    FileTreeData*                  data)
{
    // see if the text contains any path info, e.g. plugins/compilergcc/compilergcc.cpp
    // in that case, take the first element (plugins in this example), create a sub-folder
    // with the same name and recurse with the result...
    wxTreeItemId ret;
    if (text.IsEmpty())
        return ret;
    wxString path = text;
    // special case for windows and files on a different drive
    if ( platform::windows && (path.Length() > 1) && (path.GetChar(1) == _T(':')) )
        path.Remove(1, 1);
    // avoid empty node names in case of UNC paths, then, at least the first two chars are slashes
    while ((path.Length() > 1) && (path.GetChar(0) == _T('\\') || path.GetChar(0) == _T('/')) )
        path.Remove(0, 1);
    if (path.IsEmpty())
        return ret;
    int pos = path.Find(_T('/'));
    if (pos == -1)
        pos = path.Find(_T('\\'));
    if (useFolders && pos >= 0)
    {
        // ok, we got it. now split it up and re-curse
        wxString folder = path.Left(pos);
        // avoid consecutive path separators
        while (path.GetChar(pos + 1) == _T('/') || path.GetChar(pos + 1) == _T('\\'))
            ++pos;
        path = path.Right(path.Length() - pos - 1);
        wxTreeItemIdValue cookie = 0;
        wxTreeItemId newparent = tree->GetFirstChild(parent, cookie);
        while (newparent)
        {
            wxString itemText = tree->GetItemText(newparent);
            if (itemText.Matches(folder))
                break;
            newparent = tree->GetNextChild(parent, cookie);
        }
        if (!newparent)
        {
            // in order not to override wxTreeCtrl to sort alphabetically but the
            // folders be always on top, we just search here where to put the new folder...
            int fldIdx  = Manager::Get()->GetProjectManager()->FolderIconIndex();
            int vfldIdx = Manager::Get()->GetProjectManager()->VirtualFolderIconIndex();
            newparent = FindNodeToInsertAfter(tree, folder, parent, true);
            FileTreeData* ftd = new FileTreeData(*data);
            ftd->SetKind(folders_kind);
            if (folders_kind != FileTreeData::ftdkVirtualFolder)
                ftd->SetFolder(m_CommonTopLevelPath + GetRelativeFolderPath(tree, parent) + folder + wxFILE_SEP_PATH);
            else
                ftd->SetFolder(GetRelativeFolderPath(tree, parent) + folder + wxFILE_SEP_PATH);
            ftd->SetProjectFile(0);
            int idx = folders_kind != FileTreeData::ftdkVirtualFolder ? fldIdx : vfldIdx;
            newparent = tree->InsertItem(parent, newparent, folder, idx, idx, ftd);
        }
        ret = AddTreeNode(tree, path, newparent, true, folders_kind, compiles, image, data);
    }
    else
    {
        ret = tree->AppendItem(parent, text, image, image, data);
        if (!compiles)
            tree->SetItemTextColour(ret, wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
    }
    return ret;
}
i created a virtual fold named 'test4', the first time called this function, the input parameter was:
   text = "test4\"
   useFolders = true
   data = a new allocated pointer
the following code will be executed:
            FileTreeData* ftd = new FileTreeData(*data);
            ftd->SetKind(folders_kind);
            if (folders_kind != FileTreeData::ftdkVirtualFolder)
                ftd->SetFolder(m_CommonTopLevelPath + GetRelativeFolderPath(tree, parent) + folder + wxFILE_SEP_PATH);
            else
                ftd->SetFolder(GetRelativeFolderPath(tree, parent) + folder + wxFILE_SEP_PATH);
            ftd->SetProjectFile(0);
            int idx = folders_kind != FileTreeData::ftdkVirtualFolder ? fldIdx : vfldIdx;
            newparent = tree->InsertItem(parent, newparent, folder, idx, idx, ftd);
the new ftd was attached to the tree, but data NOT            
then call AddTreeNode second time:
        ret = AddTreeNode(tree, path, newparent, true, folders_kind, compiles, image, data);
the input parameter was 
   text = ""
   useFolders = true
   data = a pointer that was passed at first time
then because text is a blank string, it will return quickly:
    if (text.IsEmpty())
        return ret;
you see, the data pointer input first time was NOT attached to any tree item, so this is the problem!