Save memory in wxDataViewTreeNode.
Put data that are meaningful only for non-leaf nodes into a separate struct that is only allocated for branch nodes. This makes branch nodes larger by sizeof(void*), but leaf nodes save >50% of memory. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68914 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
422aa8ecfe
commit
d0cfefc4e0
@ -285,30 +285,40 @@ public:
|
||||
wxDataViewTreeNode(wxDataViewTreeNode *parent, const wxDataViewItem& item)
|
||||
: m_item(item),
|
||||
m_parent(parent),
|
||||
m_hasChildren(false),
|
||||
m_open(false),
|
||||
m_subTreeCount(0)
|
||||
m_branchData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~wxDataViewTreeNode()
|
||||
{
|
||||
delete m_branchData;
|
||||
}
|
||||
|
||||
static wxDataViewTreeNode* CreateRootNode()
|
||||
{
|
||||
wxDataViewTreeNode *n = new wxDataViewTreeNode(NULL, wxDataViewItem());
|
||||
n->m_open = true;
|
||||
n->m_hasChildren = true;
|
||||
n->SetHasChildren(true);
|
||||
n->m_branchData->open = true;
|
||||
return n;
|
||||
}
|
||||
|
||||
wxDataViewTreeNode * GetParent() const { return m_parent; }
|
||||
|
||||
wxDataViewTreeNodes & GetNodes() { return m_nodes; }
|
||||
wxDataViewTreeNodes& GetNodes()
|
||||
{
|
||||
wxASSERT( m_branchData != NULL );
|
||||
return m_branchData->nodes;
|
||||
}
|
||||
|
||||
void AddNode( wxDataViewTreeNode * node )
|
||||
{
|
||||
m_nodes.Add( node );
|
||||
if ( !m_branchData )
|
||||
m_branchData = new BranchNodeData;
|
||||
|
||||
m_branchData->nodes.Add( node );
|
||||
// TODO: insert into sorted array directly in O(log n) instead of resorting in O(n log n)
|
||||
if (g_column >= -1)
|
||||
m_nodes.Sort( &wxGenericTreeModelNodeCmp );
|
||||
m_branchData->nodes.Sort( &wxGenericTreeModelNodeCmp );
|
||||
}
|
||||
|
||||
const wxDataViewItem & GetItem() const { return m_item; }
|
||||
@ -328,42 +338,65 @@ public:
|
||||
|
||||
bool IsOpen() const
|
||||
{
|
||||
return m_open;
|
||||
return m_branchData && m_branchData->open;
|
||||
}
|
||||
|
||||
void ToggleOpen()
|
||||
{
|
||||
wxCHECK_RET( m_branchData != NULL, "can't open leaf node" );
|
||||
|
||||
int sum = 0;
|
||||
|
||||
const int len = m_nodes.GetCount();
|
||||
const wxDataViewTreeNodes& nodes = m_branchData->nodes;
|
||||
const int len = nodes.GetCount();
|
||||
for ( int i = 0;i < len; i ++)
|
||||
sum += 1 + m_nodes[i]->GetSubTreeCount();
|
||||
sum += 1 + nodes[i]->GetSubTreeCount();
|
||||
|
||||
if (m_open)
|
||||
if (m_branchData->open)
|
||||
{
|
||||
ChangeSubTreeCount(-sum);
|
||||
m_open = !m_open;
|
||||
m_branchData->open = !m_branchData->open;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_open = !m_open;
|
||||
m_branchData->open = !m_branchData->open;
|
||||
ChangeSubTreeCount(+sum);
|
||||
}
|
||||
}
|
||||
|
||||
// "HasChildren" property corresponds to model's IsContainer(). Note that it may be true
|
||||
// even if GetNodes() is empty; see below.
|
||||
bool HasChildren() const { return m_hasChildren; }
|
||||
void SetHasChildren(bool has) { m_hasChildren = has; }
|
||||
bool HasChildren() const
|
||||
{
|
||||
return m_branchData != NULL;
|
||||
}
|
||||
|
||||
void SetHasChildren(bool has)
|
||||
{
|
||||
if ( !has )
|
||||
{
|
||||
wxDELETE(m_branchData);
|
||||
}
|
||||
else if ( m_branchData == NULL )
|
||||
{
|
||||
m_branchData = new BranchNodeData;
|
||||
}
|
||||
}
|
||||
|
||||
int GetSubTreeCount() const
|
||||
{
|
||||
return m_branchData ? m_branchData->subTreeCount : 0;
|
||||
}
|
||||
|
||||
int GetSubTreeCount() const { return m_subTreeCount; }
|
||||
void ChangeSubTreeCount( int num )
|
||||
{
|
||||
if( !m_open )
|
||||
wxASSERT( m_branchData != NULL );
|
||||
|
||||
if( !m_branchData->open )
|
||||
return;
|
||||
|
||||
m_subTreeCount += num;
|
||||
wxASSERT( m_subTreeCount >= 0 );
|
||||
m_branchData->subTreeCount += num;
|
||||
wxASSERT( m_branchData->subTreeCount >= 0 );
|
||||
|
||||
if( m_parent )
|
||||
m_parent->ChangeSubTreeCount(num);
|
||||
@ -371,39 +404,55 @@ public:
|
||||
|
||||
void Resort()
|
||||
{
|
||||
if ( !m_branchData )
|
||||
return;
|
||||
|
||||
if (g_column >= -1)
|
||||
{
|
||||
m_nodes.Sort( &wxGenericTreeModelNodeCmp );
|
||||
int len = m_nodes.GetCount();
|
||||
wxDataViewTreeNodes& nodes = m_branchData->nodes;
|
||||
|
||||
nodes.Sort( &wxGenericTreeModelNodeCmp );
|
||||
int len = nodes.GetCount();
|
||||
for (int i = 0; i < len; i ++)
|
||||
{
|
||||
if ( m_nodes[i]->HasChildren() )
|
||||
m_nodes[i]->Resort();
|
||||
if ( nodes[i]->HasChildren() )
|
||||
nodes[i]->Resort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
wxDataViewTreeNode *m_parent;
|
||||
|
||||
// Corresponding model item.
|
||||
wxDataViewItem m_item;
|
||||
|
||||
wxDataViewTreeNode *m_parent;
|
||||
// Data specific to non-leaf (branch, inner) nodes. They are kept in a
|
||||
// separate struct in order to conserve memory.
|
||||
struct BranchNodeData
|
||||
{
|
||||
BranchNodeData()
|
||||
: open(false),
|
||||
subTreeCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Child nodes. Note that this may be empty even if m_hasChildren in case this branch
|
||||
// of the tree wasn't expanded and realized yet.
|
||||
wxDataViewTreeNodes m_nodes;
|
||||
// Child nodes. Note that this may be empty even if m_hasChildren in
|
||||
// case this branch of the tree wasn't expanded and realized yet.
|
||||
wxDataViewTreeNodes nodes;
|
||||
|
||||
// True if the node has children, i.e. if model's IsContainer() returned true for it.
|
||||
bool m_hasChildren;
|
||||
// Is the branch node currently open (expanded)?
|
||||
bool open;
|
||||
|
||||
// Is the branch node currently open (expanded)?
|
||||
bool m_open;
|
||||
// Total count of expanded (i.e. visible with the help of some
|
||||
// scrolling) items in the subtree, but excluding this node. I.e. it is
|
||||
// 0 for leaves and is the number of rows the subtree occupies for
|
||||
// branch nodes.
|
||||
int subTreeCount;
|
||||
};
|
||||
|
||||
// Total count of expanded (i.e. visible with the help of some scrolling) items in the subtree,
|
||||
// but excluding this node. I.e. it is 0 for leaves and is the number of rows the subtree occupies
|
||||
// for branch nodes.
|
||||
int m_subTreeCount;
|
||||
BranchNodeData *m_branchData;
|
||||
};
|
||||
|
||||
|
||||
@ -1909,14 +1958,17 @@ bool Walker( wxDataViewTreeNode * node, DoJob & func )
|
||||
break;
|
||||
}
|
||||
|
||||
const wxDataViewTreeNodes& nodes = node->GetNodes();
|
||||
|
||||
for ( wxDataViewTreeNodes::const_iterator i = nodes.begin();
|
||||
i != nodes.end();
|
||||
++i )
|
||||
if ( node->HasChildren() )
|
||||
{
|
||||
if ( Walker(*i, func) )
|
||||
return true;
|
||||
const wxDataViewTreeNodes& nodes = node->GetNodes();
|
||||
|
||||
for ( wxDataViewTreeNodes::const_iterator i = nodes.begin();
|
||||
i != nodes.end();
|
||||
++i )
|
||||
{
|
||||
if ( Walker(*i, func) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1942,8 +1994,8 @@ bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxData
|
||||
wxDataViewTreeNode *itemNode = new wxDataViewTreeNode(parentNode, item);
|
||||
itemNode->SetHasChildren(GetOwner()->GetModel()->IsContainer(item));
|
||||
|
||||
parentNode->AddNode(itemNode);
|
||||
parentNode->SetHasChildren(true);
|
||||
parentNode->AddNode(itemNode);
|
||||
parentNode->ChangeSubTreeCount(+1);
|
||||
|
||||
m_count = -1;
|
||||
@ -1997,6 +2049,7 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
|
||||
if ( !parentNode )
|
||||
return false;
|
||||
|
||||
wxCHECK_MSG( parentNode->HasChildren(), false, "parent node doesn't have children?" );
|
||||
const wxDataViewTreeNodes& parentsChildren = parentNode->GetNodes();
|
||||
|
||||
// We can't use FindNode() to find 'item', because it was already
|
||||
@ -2703,12 +2756,14 @@ public:
|
||||
// If the current node has only leaf children, we can find the
|
||||
// desired node directly. This can speed up finding the node
|
||||
// in some cases, and will have a very good effect for list views.
|
||||
if ( (int)node->GetNodes().size() == node->GetSubTreeCount() )
|
||||
if ( node->HasChildren() &&
|
||||
(int)node->GetNodes().size() == node->GetSubTreeCount() )
|
||||
{
|
||||
const int index = static_cast<int>(row) - current - 1;
|
||||
ret = node->GetNodes()[index];
|
||||
return DoJob::OK;
|
||||
}
|
||||
|
||||
return DoJob::CONT;
|
||||
}
|
||||
}
|
||||
@ -3199,10 +3254,9 @@ void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
|
||||
|
||||
static void DestroyTreeHelper( wxDataViewTreeNode * node )
|
||||
{
|
||||
wxDataViewTreeNodes& nodes = node->GetNodes();
|
||||
|
||||
if( !nodes.empty() )
|
||||
if ( node->HasChildren() )
|
||||
{
|
||||
wxDataViewTreeNodes& nodes = node->GetNodes();
|
||||
const int len = nodes.size();
|
||||
for (int i = 0; i < len; i++)
|
||||
DestroyTreeHelper(nodes[i]);
|
||||
|
Loading…
Reference in New Issue
Block a user