Simplified generic wxDataViewCtrl's tree structure.

Use just one type, wxDataViewTreeNode, to represent any kind of node.
Previously a complicated structure that represented leaves and non-leaf
nodes differently was used. This make the code way too complicated and
caused some smaller bugs (see e.g. #13256).

As a side effect, this change makes the control react correctly to
changes in IsContainer() return values.

Also fixes #13256.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68913 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík
2011-08-27 13:24:19 +00:00
parent b632efe0d6
commit 422aa8ecfe

View File

@@ -275,57 +275,45 @@ public:
class wxDataViewTreeNode; class wxDataViewTreeNode;
WX_DEFINE_ARRAY( wxDataViewTreeNode *, wxDataViewTreeNodes ); WX_DEFINE_ARRAY( wxDataViewTreeNode *, wxDataViewTreeNodes );
WX_DEFINE_ARRAY( void* , wxDataViewTreeLeaves);
int LINKAGEMODE wxGenericTreeModelNodeCmp( wxDataViewTreeNode ** node1, int LINKAGEMODE wxGenericTreeModelNodeCmp( wxDataViewTreeNode ** node1,
wxDataViewTreeNode ** node2); wxDataViewTreeNode ** node2);
int LINKAGEMODE wxGenericTreeModelItemCmp( void ** id1, void ** id2);
class wxDataViewTreeNode class wxDataViewTreeNode
{ {
public: public:
wxDataViewTreeNode( wxDataViewTreeNode * parent = NULL ) wxDataViewTreeNode(wxDataViewTreeNode *parent, const wxDataViewItem& item)
: m_item(item),
m_parent(parent),
m_hasChildren(false),
m_open(false),
m_subTreeCount(0)
{ {
m_parent = parent;
if (!parent)
m_open = true;
else
m_open = false;
m_hasChildren = false;
m_subTreeCount = 0;
} }
~wxDataViewTreeNode() static wxDataViewTreeNode* CreateRootNode()
{ {
wxDataViewTreeNode *n = new wxDataViewTreeNode(NULL, wxDataViewItem());
n->m_open = true;
n->m_hasChildren = true;
return n;
} }
wxDataViewTreeNode * GetParent() const { return m_parent; } wxDataViewTreeNode * GetParent() const { return m_parent; }
void SetParent( wxDataViewTreeNode * parent ) { m_parent = parent; }
wxDataViewTreeNodes & GetNodes() { return m_nodes; } wxDataViewTreeNodes & GetNodes() { return m_nodes; }
wxDataViewTreeLeaves & GetChildren() { return m_leaves; }
void AddNode( wxDataViewTreeNode * node ) void AddNode( wxDataViewTreeNode * node )
{ {
m_leaves.Add( node->GetItem().GetID() );
if (g_column >= -1)
m_leaves.Sort( &wxGenericTreeModelItemCmp );
m_nodes.Add( node ); m_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) if (g_column >= -1)
m_nodes.Sort( &wxGenericTreeModelNodeCmp ); m_nodes.Sort( &wxGenericTreeModelNodeCmp );
} }
void AddLeaf( void * leaf )
{
m_leaves.Add( leaf );
if (g_column >= -1)
m_leaves.Sort( &wxGenericTreeModelItemCmp );
}
wxDataViewItem & GetItem() { return m_item; }
const wxDataViewItem & GetItem() const { return m_item; } const wxDataViewItem & GetItem() const { return m_item; }
void SetItem( const wxDataViewItem & item ) { m_item = item; } void SetItem( const wxDataViewItem & item ) { m_item = item; }
unsigned int GetChildrenNumber() const { return m_leaves.GetCount(); }
unsigned int GetNodeNumber() const { return m_nodes.GetCount(); }
int GetIndentLevel() const int GetIndentLevel() const
{ {
int ret = 0; int ret = 0;
@@ -345,12 +333,12 @@ public:
void ToggleOpen() void ToggleOpen()
{ {
int len = m_nodes.GetCount();
int sum = 0; int sum = 0;
for ( int i = 0;i < len; i ++)
sum += m_nodes[i]->GetSubTreeCount();
sum += m_leaves.GetCount(); const int len = m_nodes.GetCount();
for ( int i = 0;i < len; i ++)
sum += 1 + m_nodes[i]->GetSubTreeCount();
if (m_open) if (m_open)
{ {
ChangeSubTreeCount(-sum); ChangeSubTreeCount(-sum);
@@ -359,19 +347,24 @@ public:
else else
{ {
m_open = !m_open; m_open = !m_open;
ChangeSubTreeCount(sum); 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; } bool HasChildren() const { return m_hasChildren; }
void SetHasChildren(bool has) { m_hasChildren = has; } void SetHasChildren(bool has) { m_hasChildren = has; }
void SetSubTreeCount( int num ) { m_subTreeCount = num; }
int GetSubTreeCount() const { return m_subTreeCount; } int GetSubTreeCount() const { return m_subTreeCount; }
void ChangeSubTreeCount( int num ) void ChangeSubTreeCount( int num )
{ {
if( !m_open ) if( !m_open )
return; return;
m_subTreeCount += num; m_subTreeCount += num;
wxASSERT( m_subTreeCount >= 0 );
if( m_parent ) if( m_parent )
m_parent->ChangeSubTreeCount(num); m_parent->ChangeSubTreeCount(num);
} }
@@ -383,47 +376,43 @@ public:
m_nodes.Sort( &wxGenericTreeModelNodeCmp ); m_nodes.Sort( &wxGenericTreeModelNodeCmp );
int len = m_nodes.GetCount(); int len = m_nodes.GetCount();
for (int i = 0; i < len; i ++) for (int i = 0; i < len; i ++)
{
if ( m_nodes[i]->HasChildren() )
m_nodes[i]->Resort(); m_nodes[i]->Resort();
m_leaves.Sort( &wxGenericTreeModelItemCmp );
} }
} }
// returns node corresponding to 'item' if its in m_nodes or NULL otherwise
wxDataViewTreeNode *FindItemAsNode(const wxDataViewItem& item) const
{
for ( wxDataViewTreeNodes::const_iterator i = m_nodes.begin();
i != m_nodes.end();
++i )
{
if( (*i)->GetItem() == item )
return *i;
}
return NULL;
} }
private: private:
wxDataViewTreeNode *m_parent; // Corresponding model item.
wxDataViewTreeNodes m_nodes;
wxDataViewTreeLeaves m_leaves;
wxDataViewItem m_item; wxDataViewItem m_item;
bool m_open;
wxDataViewTreeNode *m_parent;
// 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;
// True if the node has children, i.e. if model's IsContainer() returned true for it.
bool m_hasChildren; bool m_hasChildren;
// 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 m_subTreeCount; int m_subTreeCount;
}; };
int LINKAGEMODE wxGenericTreeModelNodeCmp( wxDataViewTreeNode ** node1, int LINKAGEMODE wxGenericTreeModelNodeCmp( wxDataViewTreeNode ** node1,
wxDataViewTreeNode ** node2) wxDataViewTreeNode ** node2)
{ {
return g_model->Compare( (*node1)->GetItem(), (*node2)->GetItem(), g_column, g_asending ); return g_model->Compare( (*node1)->GetItem(), (*node2)->GetItem(), g_column, g_asending );
} }
int LINKAGEMODE wxGenericTreeModelItemCmp( void ** id1, void ** id2)
{
return g_model->Compare( wxDataViewItem(*id1), wxDataViewItem(*id2), g_column, g_asending );
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// wxDataViewMainWindow // wxDataViewMainWindow
@@ -1365,8 +1354,7 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i
// TODO: maybe there is something system colour to use // TODO: maybe there is something system colour to use
m_penExpander = wxPen(wxColour(0,0,0)); m_penExpander = wxPen(wxColour(0,0,0));
m_root = new wxDataViewTreeNode( NULL ); m_root = wxDataViewTreeNode::CreateRootNode();
m_root->SetHasChildren(true);
// Make m_count = -1 will cause the class recaculate the real displaying number of rows. // Make m_count = -1 will cause the class recaculate the real displaying number of rows.
m_count = -1; m_count = -1;
@@ -1545,9 +1533,6 @@ wxBitmap wxDataViewMainWindow::CreateItemBitmap( unsigned int row, int &indent )
indent = GetOwner()->GetIndent() * node->GetIndentLevel(); indent = GetOwner()->GetIndent() * node->GetIndentLevel();
indent = indent + m_lineHeight; indent = indent + m_lineHeight;
// try to use the m_lineHeight as the expander space // try to use the m_lineHeight as the expander space
if(!node->HasChildren())
delete node;
} }
width -= indent; width -= indent;
@@ -1844,12 +1829,6 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
// force the expander column to left-center align // force the expander column to left-center align
cell->SetAlignment( wxALIGN_CENTER_VERTICAL ); cell->SetAlignment( wxALIGN_CENTER_VERTICAL );
} }
if (node && !node->HasChildren())
{
// Yes, if the node does not have any child, it must be a leaf which
// mean that it is a temporarily created by GetTreeNodeByRow
wxDELETE(node);
}
wxRect item_rect = cell_rect; wxRect item_rect = cell_rect;
item_rect.Deflate(PADDING_RIGHTLEFT, 0); item_rect.Deflate(PADDING_RIGHTLEFT, 0);
@@ -1914,13 +1893,11 @@ public:
// 2: Job not done, continue // 2: Job not done, continue
enum { OK = 0 , IGR = 1, CONT = 2 }; enum { OK = 0 , IGR = 1, CONT = 2 };
virtual int operator() ( wxDataViewTreeNode * node ) = 0; virtual int operator() ( wxDataViewTreeNode * node ) = 0;
virtual int operator() ( void * n ) = 0;
}; };
bool Walker( wxDataViewTreeNode * node, DoJob & func ) bool Walker( wxDataViewTreeNode * node, DoJob & func )
{ {
if( node==NULL ) wxCHECK_MSG( node, false, "can't walk NULL node" );
return false;
switch( func( node ) ) switch( func( node ) )
{ {
@@ -1929,47 +1906,24 @@ bool Walker( wxDataViewTreeNode * node, DoJob & func )
case DoJob::IGR: case DoJob::IGR:
return false; return false;
case DoJob::CONT: case DoJob::CONT:
default: break;
;
} }
const wxDataViewTreeNodes& nodes = node->GetNodes(); const wxDataViewTreeNodes& nodes = node->GetNodes();
const wxDataViewTreeLeaves& leaves = node->GetChildren();
int len_nodes = nodes.GetCount(); for ( wxDataViewTreeNodes::const_iterator i = nodes.begin();
int len = leaves.GetCount(); i != nodes.end();
int i = 0, nodes_i = 0; ++i )
for(; i < len; i ++ )
{ {
void * n = leaves[i]; if ( Walker(*i, func) )
if( nodes_i < len_nodes && n == nodes[nodes_i]->GetItem().GetID() )
{
wxDataViewTreeNode * nd = nodes[nodes_i];
nodes_i++;
if( Walker( nd , func ) )
return true; return true;
}
}
else
switch( func( n ) )
{
case DoJob::OK :
return true;
case DoJob::IGR:
continue;
case DoJob::CONT:
default:
;
}
}
return false; return false;
} }
bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item) bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item)
{ {
if (IsVirtualList()) if (IsVirtualList())
{ {
wxDataViewVirtualListModel *list_model = wxDataViewVirtualListModel *list_model =
@@ -1980,25 +1934,17 @@ bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxData
{ {
SortPrepare(); SortPrepare();
wxDataViewTreeNode * node; wxDataViewTreeNode *parentNode = FindNode(parent);
node = FindNode(parent);
if( node == NULL ) if ( !parentNode )
return false; return false;
node->SetHasChildren( true ); wxDataViewTreeNode *itemNode = new wxDataViewTreeNode(parentNode, item);
itemNode->SetHasChildren(GetOwner()->GetModel()->IsContainer(item));
if( g_model->IsContainer( item ) ) parentNode->AddNode(itemNode);
{ parentNode->SetHasChildren(true);
wxDataViewTreeNode * newnode = new wxDataViewTreeNode( node ); parentNode->ChangeSubTreeCount(+1);
newnode->SetItem(item);
newnode->SetHasChildren( true );
node->AddNode( newnode);
}
else
node->AddLeaf( item.GetID() );
node->ChangeSubTreeCount(1);
m_count = -1; m_count = -1;
} }
@@ -2051,42 +1997,51 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
if ( !parentNode ) if ( !parentNode )
return false; return false;
int itemPosInNode = parentNode->GetChildren().Index(item.GetID()); const wxDataViewTreeNodes& parentsChildren = parentNode->GetNodes();
if ( itemPosInNode == wxNOT_FOUND )
return false;
bool isContainer = false; // We can't use FindNode() to find 'item', because it was already
// removed from the model by the time ItemDeleted() is called, so we
// have to do it manually. We keep track of its position as well for
// later use.
int itemPosInNode = 0;
wxDataViewTreeNode *itemNode = NULL; wxDataViewTreeNode *itemNode = NULL;
for ( wxDataViewTreeNodes::const_iterator i = parentsChildren.begin();
const wxDataViewTreeNodes nodes = parentNode->GetNodes(); i != parentsChildren.end();
for (size_t i = 0; i < nodes.GetCount(); i ++) ++i, ++itemPosInNode )
{ {
if (nodes[i]->GetItem() == item) if( (*i)->GetItem() == item )
{ {
isContainer = true; itemNode = *i;
itemNode = nodes[i];
break; break;
} }
} }
// Delete the item from wxDataViewTreeNode representation: // If the parent wasn't expanded, it's possible that we didn't have a
int itemsDeleted = 1; // node corresponding to 'item' and so there's nothing left to do.
parentNode->GetChildren().Remove( item.GetID() ); if ( !itemNode )
if( isContainer )
{ {
wxDataViewTreeNode *n = parentNode->FindItemAsNode(item); // If this was the last child to be removed, it's possible the parent
// node became a leaf. Let's ask the model about it.
if ( parentNode->GetNodes().empty() )
parentNode->SetHasChildren(GetOwner()->GetModel()->IsContainer(parent));
wxCHECK_MSG( n != NULL, false, "item not found" ); return false;
parentNode->GetNodes().Remove( n );
itemsDeleted += n->GetSubTreeCount();
::DestroyTreeHelper(n);
} }
// Delete the item from wxDataViewTreeNode representation:
const int itemsDeleted = 1 + itemNode->GetSubTreeCount();
parentNode->GetNodes().Remove(itemNode);
::DestroyTreeHelper(itemNode);
parentNode->ChangeSubTreeCount(-itemsDeleted);
// Make the row number invalid and get a new valid one when user call GetRowCount // Make the row number invalid and get a new valid one when user call GetRowCount
m_count = -1; m_count = -1;
parentNode->ChangeSubTreeCount(-itemsDeleted);
// If this was the last child to be removed, it's possible the parent
// node became a leaf. Let's ask the model about it.
if ( parentNode->GetNodes().empty() )
parentNode->SetHasChildren(GetOwner()->GetModel()->IsContainer(parent));
// Update selection by removing 'item' and its entire children tree from the selection. // Update selection by removing 'item' and its entire children tree from the selection.
if ( !m_selection.empty() ) if ( !m_selection.empty() )
@@ -2102,13 +2057,11 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
else else
{ {
// row number is that of the sibling above 'item' + its subtree if any + 1 // row number is that of the sibling above 'item' + its subtree if any + 1
const wxDataViewItem sibling = wxDataViewItem(parentNode->GetChildren()[itemPosInNode - 1]); const wxDataViewTreeNode *siblingNode = parentNode->GetNodes()[itemPosInNode - 1];
const wxDataViewTreeNode *siblingNode = parentNode->FindItemAsNode(sibling);
itemRow = GetRowByItem(sibling); itemRow = GetRowByItem(siblingNode->GetItem()) +
if ( siblingNode ) siblingNode->GetSubTreeCount() +
itemRow += siblingNode->GetSubTreeCount(); 1;
itemRow += 1;
} }
wxDataViewSelection newsel(wxDataViewSelectionCmp); wxDataViewSelection newsel(wxDataViewSelectionCmp);
@@ -2590,13 +2543,6 @@ int wxDataViewMainWindow::GetLineStart( unsigned int row ) const
wxDataViewItem item = node->GetItem(); wxDataViewItem item = node->GetItem();
if (node && !node->HasChildren())
{
// Yes, if the node does not have any child, it must be a leaf which
// mean that it is a temporarily created by GetTreeNodeByRow
wxDELETE(node);
}
unsigned int cols = GetOwner()->GetColumnCount(); unsigned int cols = GetOwner()->GetColumnCount();
unsigned int col; unsigned int col;
int height = m_lineHeight; int height = m_lineHeight;
@@ -2651,13 +2597,6 @@ int wxDataViewMainWindow::GetLineAt( unsigned int y ) const
wxDataViewItem item = node->GetItem(); wxDataViewItem item = node->GetItem();
if (node && !node->HasChildren())
{
// Yes, if the node does not have any child, it must be a leaf which
// mean that it is a temporarily created by GetTreeNodeByRow
wxDELETE(node);
}
unsigned int cols = GetOwner()->GetColumnCount(); unsigned int cols = GetOwner()->GetColumnCount();
unsigned int col; unsigned int col;
int height = m_lineHeight; int height = m_lineHeight;
@@ -2701,13 +2640,6 @@ int wxDataViewMainWindow::GetLineHeight( unsigned int row ) const
wxDataViewItem item = node->GetItem(); wxDataViewItem item = node->GetItem();
if (node && !node->HasChildren())
{
// Yes, if the node does not have any child, it must be a leaf which
// mean that it is a temporarily created by GetTreeNodeByRow
wxDELETE(node);
}
int height = m_lineHeight; int height = m_lineHeight;
unsigned int cols = GetOwner()->GetColumnCount(); unsigned int cols = GetOwner()->GetColumnCount();
@@ -2738,76 +2670,6 @@ int wxDataViewMainWindow::GetLineHeight( unsigned int row ) const
} }
} }
class RowToItemJob: public DoJob
{
public:
RowToItemJob( unsigned int row , int current )
{ this->row = row; this->current = current; }
virtual ~RowToItemJob() {}
virtual int operator() ( wxDataViewTreeNode * node )
{
current ++;
if( current == static_cast<int>(row))
{
ret = node->GetItem();
return DoJob::OK;
}
if( node->GetSubTreeCount() + current < static_cast<int>(row) )
{
current += node->GetSubTreeCount();
return DoJob::IGR;
}
else
{
// If the current has no child node, we can find the desired item of the row
// number directly.
// This if can speed up finding in some case, and will has a very good effect
// when it comes to list view
if( node->GetNodes().GetCount() == 0)
{
int index = static_cast<int>(row) - current - 1;
ret = wxDataViewItem(node->GetChildren().Item( index ));
return DoJob::OK;
}
return DoJob::CONT;
}
}
virtual int operator() ( void * n )
{
current ++;
if( current == static_cast<int>(row))
{
ret = wxDataViewItem( n );
return DoJob::OK;
}
return DoJob::CONT;
}
wxDataViewItem GetResult() const
{ return ret; }
private:
unsigned int row;
int current;
wxDataViewItem ret;
};
wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row) const
{
if (IsVirtualList())
{
return wxDataViewItem( wxUIntToPtr(row+1) );
}
else
{
RowToItemJob job( row, -2 );
Walker( m_root , job );
return job.GetResult();
}
}
class RowToTreeNodeJob: public DoJob class RowToTreeNodeJob: public DoJob
{ {
@@ -2819,7 +2681,6 @@ public:
ret = NULL; ret = NULL;
parent = node; parent = node;
} }
virtual ~RowToTreeNodeJob(){ }
virtual int operator() ( wxDataViewTreeNode * node ) virtual int operator() ( wxDataViewTreeNode * node )
{ {
@@ -2839,37 +2700,19 @@ public:
{ {
parent = node; parent = node;
// If the current node has no children, we can find the desired item of the // If the current node has only leaf children, we can find the
// row number directly. // desired node directly. This can speed up finding the node
// This if can speed up finding in some case, and will have a very good // in some cases, and will have a very good effect for list views.
// effect for list views. if ( (int)node->GetNodes().size() == node->GetSubTreeCount() )
if( node->GetNodes().GetCount() == 0)
{ {
int index = static_cast<int>(row) - current - 1; const int index = static_cast<int>(row) - current - 1;
void * n = node->GetChildren().Item( index ); ret = node->GetNodes()[index];
ret = new wxDataViewTreeNode( parent );
ret->SetItem( wxDataViewItem( n ));
ret->SetHasChildren(false);
return DoJob::OK; return DoJob::OK;
} }
return DoJob::CONT; return DoJob::CONT;
} }
} }
virtual int operator() ( void * n )
{
current ++;
if( current == static_cast<int>(row))
{
ret = new wxDataViewTreeNode( parent );
ret->SetItem( wxDataViewItem( n ));
ret->SetHasChildren(false);
return DoJob::OK;
}
return DoJob::CONT;
}
wxDataViewTreeNode * GetResult() const wxDataViewTreeNode * GetResult() const
{ return ret; } { return ret; }
@@ -2889,6 +2732,19 @@ wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row) co
return job.GetResult(); return job.GetResult();
} }
wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row) const
{
if (IsVirtualList())
{
return wxDataViewItem( wxUIntToPtr(row+1) );
}
else
{
wxDataViewTreeNode *node = GetTreeNodeByRow(row);
return node ? node->GetItem() : wxDataViewItem();
}
}
bool bool
wxDataViewMainWindow::SendExpanderEvent(wxEventType type, wxDataViewMainWindow::SendExpanderEvent(wxEventType type,
const wxDataViewItem& item) const wxDataViewItem& item)
@@ -2913,10 +2769,7 @@ bool wxDataViewMainWindow::IsExpanded( unsigned int row ) const
return false; return false;
if (!node->HasChildren()) if (!node->HasChildren())
{
delete node;
return false; return false;
}
return node->IsOpen(); return node->IsOpen();
} }
@@ -2931,10 +2784,7 @@ bool wxDataViewMainWindow::HasChildren( unsigned int row ) const
return false; return false;
if (!node->HasChildren()) if (!node->HasChildren())
{
delete node;
return false; return false;
}
return true; return true;
} }
@@ -2949,10 +2799,7 @@ void wxDataViewMainWindow::Expand( unsigned int row )
return; return;
if (!node->HasChildren()) if (!node->HasChildren())
{
delete node;
return; return;
}
if (!node->IsOpen()) if (!node->IsOpen())
{ {
@@ -2965,7 +2812,7 @@ void wxDataViewMainWindow::Expand( unsigned int row )
node->ToggleOpen(); node->ToggleOpen();
// build the children of current node // build the children of current node
if( node->GetChildrenNumber() == 0 ) if( node->GetNodes().empty() )
{ {
SortPrepare(); SortPrepare();
::BuildTreeHelper(GetOwner()->GetModel(), node->GetItem(), node); ::BuildTreeHelper(GetOwner()->GetModel(), node->GetItem(), node);
@@ -3004,10 +2851,7 @@ void wxDataViewMainWindow::Collapse(unsigned int row)
return; return;
if (!node->HasChildren()) if (!node->HasChildren())
{
delete node;
return; return;
}
if (node->IsOpen()) if (node->IsOpen())
{ {
@@ -3096,8 +2940,11 @@ wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item
{ {
if( node->HasChildren() ) if( node->HasChildren() )
{ {
if( node->GetChildrenNumber() == 0 ) if( node->GetNodes().empty() )
{ {
// Even though the item is a container, it doesn't have any
// child nodes in the control's representation yet. We have
// to realize its subtree now.
SortPrepare(); SortPrepare();
::BuildTreeHelper(model, node->GetItem(), node); ::BuildTreeHelper(model, node->GetItem(), node);
} }
@@ -3202,9 +3049,6 @@ wxRect wxDataViewMainWindow::GetItemRect( const wxDataViewItem & item,
wxDataViewTreeNode* node = GetTreeNodeByRow(row); wxDataViewTreeNode* node = GetTreeNodeByRow(row);
indent = GetOwner()->GetIndent() * node->GetIndentLevel(); indent = GetOwner()->GetIndent() * node->GetIndentLevel();
indent = indent + m_lineHeight; // use m_lineHeight as the width of the expander indent = indent + m_lineHeight; // use m_lineHeight as the width of the expander
if(!node->HasChildren())
delete node;
} }
wxRect itemRect( xpos + indent, wxRect itemRect( xpos + indent,
@@ -3265,14 +3109,6 @@ public:
} }
virtual int operator() ( void * n )
{
ret ++;
if( n == item.GetID() )
return DoJob::OK;
return DoJob::CONT;
}
// the row number is begin from zero // the row number is begin from zero
int GetResult() const int GetResult() const
{ return ret -1; } { return ret -1; }
@@ -3328,27 +3164,18 @@ static void BuildTreeHelper( const wxDataViewModel * model, const wxDataViewIte
wxDataViewItemArray children; wxDataViewItemArray children;
unsigned int num = model->GetChildren( item, children); unsigned int num = model->GetChildren( item, children);
unsigned int index = 0; for ( unsigned int index = 0; index < num; index++ )
while( index < num )
{ {
wxDataViewTreeNode *n = new wxDataViewTreeNode(node, children[index]);
if( model->IsContainer(children[index]) ) if( model->IsContainer(children[index]) )
{
wxDataViewTreeNode * n = new wxDataViewTreeNode( node );
n->SetItem(children[index]);
n->SetHasChildren( true ); n->SetHasChildren( true );
node->AddNode(n); node->AddNode(n);
} }
else
{
node->AddLeaf( children[index].GetID() );
}
index ++;
}
node->SetSubTreeCount( num );
wxDataViewTreeNode * n = node->GetParent();
if( n != NULL)
n->ChangeSubTreeCount(num);
wxASSERT( node->IsOpen() );
node->ChangeSubTreeCount(+num);
} }
void wxDataViewMainWindow::BuildTree(wxDataViewModel * model) void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
@@ -3361,8 +3188,7 @@ void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
return; return;
} }
m_root = new wxDataViewTreeNode( NULL ); m_root = wxDataViewTreeNode::CreateRootNode();
m_root->SetHasChildren(true);
// First we define a invalid item to fetch the top-level elements // First we define a invalid item to fetch the top-level elements
wxDataViewItem item; wxDataViewItem item;
@@ -3373,10 +3199,11 @@ void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
static void DestroyTreeHelper( wxDataViewTreeNode * node ) static void DestroyTreeHelper( wxDataViewTreeNode * node )
{ {
if( node->GetNodeNumber() != 0 )
{
int len = node->GetNodeNumber();
wxDataViewTreeNodes& nodes = node->GetNodes(); wxDataViewTreeNodes& nodes = node->GetNodes();
if( !nodes.empty() )
{
const int len = nodes.size();
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
DestroyTreeHelper(nodes[i]); DestroyTreeHelper(nodes[i]);
} }
@@ -3458,9 +3285,6 @@ void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
{ {
wxDataViewTreeNode *parent_node = node->GetParent(); wxDataViewTreeNode *parent_node = node->GetParent();
if(!node->HasChildren())
delete node;
if (parent_node) if (parent_node)
{ {
int parent = GetRowByItem( parent_node->GetItem() ); int parent = GetRowByItem( parent_node->GetItem() );
@@ -3628,8 +3452,6 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
m_underMouse = node; m_underMouse = node;
} }
} }
if (node!=NULL && !node->HasChildren())
delete node;
} }
if (!hoverOverExpander) if (!hoverOverExpander)
{ {