]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/dataview.cpp
Avoid a hang if we're dragging a tab to a notebook that's a child of the original tab
[wxWidgets.git] / src / gtk / dataview.cpp
index db0403271913042d14108b6d94eec88a33556de3..41ed1b24e8335c0187ac19ff9afe7f9d651b81c9 100644 (file)
 #include <gdk/gdkkeysyms.h>
 
 //-----------------------------------------------------------------------------
-// classes
 //-----------------------------------------------------------------------------
 
-//-----------------------------------------------------------------------------
-// wxGtkTreeModelNode
-//-----------------------------------------------------------------------------
+wxDataViewModel *g_model = NULL;
 
 class wxGtkTreeModelNode;
 
-int LINKAGEMODE wxGtkTreeModelNodeCmp( wxGtkTreeModelNode* node1, wxGtkTreeModelNode* node2 );
-
-WX_DEFINE_SORTED_ARRAY( wxGtkTreeModelNode*, wxGtkTreeModelNodes );
-
-class wxGtkTreeModelNode
-{
-public:
-    wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item,
-      wxDataViewModel *model )
-    { 
-        m_parent = parent; 
-        m_item = item;
-        m_model = model;
-        m_children = new wxGtkTreeModelNodes( wxGtkTreeModelNodeCmp );
-    }
-    
-    ~wxGtkTreeModelNode()
-    { 
-        size_t count = m_children->GetCount();
-        size_t i;
-        for (i = 0; i < count; i++)
-        {
-            wxGtkTreeModelNode *child = m_children->Item( i );
-            delete child;
-        }
-        delete m_children;
-    }
-
-    wxGtkTreeModelNode* GetParent() 
-        { return m_parent; }
-    wxGtkTreeModelNodes &GetChildren() 
-        { return *m_children; }
-    wxGtkTreeModelNode* GetNthChild( unsigned int n ) 
-        { return m_children->Item( n ); }
-    unsigned int Add( wxGtkTreeModelNode* child ) 
-        { return m_children->Add( child ); }
-        
-    unsigned int GetChildCount() { return m_children->GetCount(); }
-
-    wxDataViewItem &GetItem() { return m_item; }
-    wxDataViewModel *GetModel() { return m_model; }
-
-    bool HasChildren() { return m_hasChildren; }
-    void SetHasChildren( bool has ) { m_hasChildren = has; }
-    
-    void Resort();
-    
-private:
-    wxGtkTreeModelNode  *m_parent;
-    wxGtkTreeModelNodes *m_children; 
-    wxDataViewItem       m_item; 
-    bool                 m_hasChildren;
-    wxDataViewModel     *m_model;
-};
-
-int LINKAGEMODE wxGtkTreeModelNodeCmp( wxGtkTreeModelNode* node1, wxGtkTreeModelNode* node2 )
-{
-    return node1->GetModel()->Compare( node1->GetItem(), node2->GetItem() );
-}
-
-
 extern "C" {
 typedef struct _GtkWxTreeModel       GtkWxTreeModel;
 }
 
+//-----------------------------------------------------------------------------
+// wxDataViewCtrlInternal
+//-----------------------------------------------------------------------------
+
 class wxDataViewCtrlInternal
 {
 public:
@@ -130,7 +70,8 @@ public:
     gboolean iter_parent( GtkTreeIter *iter, GtkTreeIter *child );
     
     wxDataViewModel* GetDataViewModel() { return m_wx_model; }
-    GtkWxTreeModel* GetOwner()          { return m_gtk_model; }
+    wxDataViewCtrl* GetOwner()          { return m_owner; }
+    GtkWxTreeModel* GetGtkModel()       { return m_gtk_model; }
 
     bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
     bool ItemDeleted( const wxDataViewItem &item );
@@ -141,6 +82,8 @@ protected:
     void InitTree();
     wxGtkTreeModelNode *FindNode( const wxDataViewItem &item );
     wxGtkTreeModelNode *FindNode( GtkTreeIter *iter );
+    wxGtkTreeModelNode *FindParentNode( const wxDataViewItem &item );
+    wxGtkTreeModelNode *FindParentNode( GtkTreeIter *iter );
     void BuildBranch( wxGtkTreeModelNode *branch );
     
 private:
@@ -150,6 +93,111 @@ private:
     wxDataViewCtrl       *m_owner;
 };
 
+
+//-----------------------------------------------------------------------------
+// wxGtkTreeModelNode
+//-----------------------------------------------------------------------------
+
+int LINKAGEMODE wxGtkTreeModelNodeCmp( void *id1, void *id2 );
+
+WX_DEFINE_ARRAY_PTR( wxGtkTreeModelNode*, wxGtkTreeModelNodes );
+WX_DEFINE_SORTED_ARRAY( void* , wxGtkTreeModelChildren );
+
+class wxGtkTreeModelNode
+{
+public:
+    wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item,
+      wxDataViewCtrlInternal *internal )
+    { 
+        m_parent = parent; 
+        m_item = item;
+        m_internal = internal;
+        g_model = internal->GetDataViewModel();
+        m_children = new wxGtkTreeModelChildren( wxGtkTreeModelNodeCmp );
+    }
+    
+    ~wxGtkTreeModelNode()
+    { 
+        g_model = m_internal->GetDataViewModel();
+        size_t count = m_children->GetCount();
+        size_t i;
+        for (i = 0; i < count; i++)
+        {
+            wxGtkTreeModelNode *child = m_nodes.Item( i );
+            delete child;
+        }
+        delete m_children;
+    }
+
+    unsigned int AddNode( wxGtkTreeModelNode* child ) 
+        { 
+            g_model = m_internal->GetDataViewModel();
+            m_nodes.Add( child );
+            return m_children->Add( child->GetItem().GetID() );
+        }
+        
+    unsigned int AddLeave( void* id )
+        {
+            g_model = m_internal->GetDataViewModel();
+            return m_children->Add( id );
+        }
+        
+    void DeleteChild( void* id )
+        {
+            g_model = m_internal->GetDataViewModel();
+            size_t pos;
+            size_t count = m_children->GetCount();
+            for (pos = 0; pos < count; pos++)
+            {
+                if (m_children->Item( pos ) == id)
+                {
+                    m_children->RemoveAt( pos );
+                    break;
+                }
+            }
+            count = m_nodes.GetCount();
+            for (pos = 0; pos < count; pos++)
+            {   
+                wxGtkTreeModelNode *node = m_nodes.Item( pos );
+                if (node->GetItem().GetID() == id)
+                {
+                    m_nodes.RemoveAt( pos );
+                    delete node;
+                    break;
+                }
+            }
+            
+        }
+        
+    wxGtkTreeModelNode* GetParent() 
+        { return m_parent; }
+    wxGtkTreeModelNodes &GetNodes() 
+        { return m_nodes; }
+    wxGtkTreeModelChildren &GetChildren() 
+        { return *m_children; }
+        
+    unsigned int GetChildCount() { return m_children->GetCount(); }
+    unsigned int GetNodesCount() { return m_nodes.GetCount(); }
+
+    wxDataViewItem &GetItem() { return m_item; }
+    wxDataViewCtrlInternal *GetInternal() { return m_internal; }
+    
+    void Resort();
+    
+private:
+    wxGtkTreeModelNode         *m_parent;
+    wxGtkTreeModelNodes         m_nodes;
+    wxGtkTreeModelChildren     *m_children;
+    wxDataViewItem              m_item; 
+    wxDataViewCtrlInternal     *m_internal;
+};
+
+
+int LINKAGEMODE wxGtkTreeModelNodeCmp( void* id1, void* id2 )
+{
+    return g_model->Compare( id1, id2 );
+}
+
 //-----------------------------------------------------------------------------
 // data
 //-----------------------------------------------------------------------------
@@ -556,17 +604,20 @@ void     wxgtk_tree_model_set_sort_column_id    (GtkTreeSortable        *sortabl
     GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
     g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
 
-    // TODO check for equality
-    
-    gtk_tree_sortable_sort_column_changed (sortable);
-
-    tree_model->internal->GetDataViewModel()->SetSortingColumn( sort_column_id );
-    
     bool ascending = TRUE;
     if (order != GTK_SORT_ASCENDING)
         ascending = FALSE;
+
+    if ((sort_column_id == (gint) tree_model->internal->GetDataViewModel()->GetSortingColumn()) &&
+        (ascending == tree_model->internal->GetDataViewModel()->GetSortOrderAscending()))
+        return;
+    
+    tree_model->internal->GetDataViewModel()->SetSortingColumn( sort_column_id );
+    
     tree_model->internal->GetDataViewModel()->SetSortOrderAscending( ascending );
     
+    gtk_tree_sortable_sort_column_changed (sortable);
+    
     tree_model->internal->GetDataViewModel()->Resort();
 }
 
@@ -2084,23 +2135,78 @@ void wxDataViewColumn::SetWidth( int width )
 
 void wxGtkTreeModelNode::Resort()
 {
-    wxGtkTreeModelNodes *new_array = new wxGtkTreeModelNodes( wxGtkTreeModelNodeCmp );
+    g_model = m_internal->GetDataViewModel();
+    
+    size_t child_count = GetChildCount();
+    if (child_count == 0)
+        return;
+
+    size_t node_count = GetNodesCount();
+
+    if (child_count == 1)
+    {
+        if (node_count == 1)
+        {
+            wxGtkTreeModelNode *node = m_nodes.Item( 0 );
+            node->Resort();
+        }
+        return;
+    }
+
+    wxGtkTreeModelChildren *new_array = new wxGtkTreeModelChildren( wxGtkTreeModelNodeCmp );
 
     size_t pos;
-    size_t count = m_children->GetCount();
+    for (pos = 0; pos < child_count; pos++)
+        new_array->Add( m_children->Item( pos ) );
+
+    gint *new_order = new gint[child_count];
     
-    for (pos = 0; pos < count; pos++)
+    for (pos = 0; pos < child_count; pos++)
     {
-        new_array->Add( m_children->Item( 0 ) );
-        m_children->RemoveAt( 0 );
+        void *id = new_array->Item( pos );
+        size_t old_pos;
+        for (old_pos = 0; old_pos < child_count; old_pos++)
+        {
+            if (id == m_children->Item(old_pos))
+            {
+                new_order[pos] = old_pos;
+                break;
+            }
+        }
     }
-    
+        
+//    for (pos = 0; pos < count; pos++)
+//        m_children->Clear();
     delete m_children;
+    
     m_children = new_array;
     
-    for (pos = 0; pos < count; pos++)
+    GtkTreeModel *gtk_tree_model = GTK_TREE_MODEL( m_internal->GetGtkModel() );
+
+    GtkTreePath *path = gtk_tree_path_new ();
+    wxGtkTreeModelNode *parent = GetParent();
+    void *id = GetItem().GetID();
+
+    while (parent)
     {
-        wxGtkTreeModelNode *node = m_children->Item( pos );
+        int pos = parent->GetChildren().Index( id );
+        gtk_tree_path_prepend_index( path, pos );
+        id = parent->GetItem().GetID();
+        parent = parent->GetParent();
+    }
+    
+    GtkTreeIter iter;
+    iter.user_data = id;
+    iter.stamp = m_internal->GetGtkModel()->stamp;
+    gtk_tree_model_rows_reordered( gtk_tree_model, path, &iter, new_order );
+    
+    gtk_tree_path_free (path);
+    
+    delete [] new_order;
+    
+    for (pos = 0; pos < node_count; pos++)
+    {
+        wxGtkTreeModelNode *node = m_nodes.Item( pos );
         node->Resort();
     }
 }
@@ -2127,7 +2233,7 @@ wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
 void wxDataViewCtrlInternal::InitTree()
 {
     wxDataViewItem item;
-    m_root = new wxGtkTreeModelNode( NULL, item, m_wx_model );
+    m_root = new wxGtkTreeModelNode( NULL, item, this );
 
     BuildBranch( m_root );
 }
@@ -2139,7 +2245,10 @@ void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node )
         wxDataViewItem child = m_wx_model->GetFirstChild( node->GetItem() );
         while (child.IsOk())
         {
-            node->Add( new wxGtkTreeModelNode( node, child, node->GetModel() ) );
+            if (m_wx_model->IsContainer( child ))
+                node->AddNode( new wxGtkTreeModelNode( node, child, this ) );
+            else
+                node->AddLeave( child.GetID() );
             child = m_wx_model->GetNextSibling( child );
         }
     }
@@ -2153,29 +2262,24 @@ void wxDataViewCtrlInternal::Resort()
 bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
 {
     wxGtkTreeModelNode *parent_node = FindNode( parent );
-    parent_node->Add( new wxGtkTreeModelNode( parent_node, item, parent_node->GetModel() ) );
+    if (m_wx_model->IsContainer( item ))
+        parent_node->AddNode( new wxGtkTreeModelNode( parent_node, item, this ) );
+    else
+        parent_node->AddLeave( item.GetID() );
     return true;
 }
 
 bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &item )
 {
-    wxGtkTreeModelNode *node = FindNode( item );
-    wxGtkTreeModelNode *parent = node->GetParent();
-    size_t pos;
-    for (pos = 0; pos < parent->GetChildren().GetCount(); pos++)
-    {
-        if (node == parent->GetChildren().Item( pos ))
-        {
-            parent->GetChildren().RemoveAt( pos );
-            continue;
-        }
-    }
-
+    wxGtkTreeModelNode *parent = FindParentNode( item );
+    parent->DeleteChild( item.GetID() );
     return true;
 }
 
 gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path )
 {
+    g_model = m_wx_model;
+    
     int depth = gtk_tree_path_get_depth( path );
 
     wxGtkTreeModelNode *node = m_root;
@@ -2189,28 +2293,46 @@ gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path
         if (pos < 0) return FALSE;
         if ((size_t)pos >= node->GetChildCount()) return FALSE;
         
-        node = node->GetChildren().Item( (size_t) pos );
-    }
+        void* id = node->GetChildren().Item( (size_t) pos );
+        
+        if (i == depth-1)
+        {
+            iter->stamp = m_gtk_model->stamp;
+            iter->user_data = id;
+            return TRUE;
+        }
 
-    iter->stamp = m_gtk_model->stamp;
-    iter->user_data = (gpointer) node->GetItem().GetID();
+        size_t count = node->GetNodes().GetCount();
+        size_t pos2;
+        for (pos2 = 0; pos2 < count; pos2++)
+        {
+            wxGtkTreeModelNode *child_node = node->GetNodes().Item( pos2 );
+            if (child_node->GetItem().GetID() == id)
+            {
+                node = child_node;
+                break;
+            }
+        }        
+    }
 
-    return TRUE;
+    return FALSE;
 }
 
 GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
 {
+    g_model = m_wx_model;
+    
     GtkTreePath *retval = gtk_tree_path_new ();
+    void *id = iter->user_data;    
     
-    wxGtkTreeModelNode *node = FindNode( iter );
-    while (node->GetParent())
+    wxGtkTreeModelNode *node = FindParentNode( iter );
+    while (node)
     {
-        wxGtkTreeModelNode *parent = node->GetParent();
-        int pos = parent->GetChildren().Index( node );
-        
+        int pos = node->GetChildren().Index( id );
         gtk_tree_path_prepend_index( retval, pos );
-
-        node = parent;
+        
+        id = node->GetItem().GetID();
+        node = node->GetParent();
     }
 
     return retval;
@@ -2218,23 +2340,26 @@ GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
 
 GtkTreePath *wxDataViewCtrlInternal::get_path_safe( GtkTreeIter *iter )
 {
+    g_model = m_wx_model;
+    
     GtkTreePath *retval = gtk_tree_path_new ();
+    void *id = iter->user_data;    
     
-    wxGtkTreeModelNode *node = FindNode( iter );
-    while (node->GetParent())
+    wxGtkTreeModelNode *node = FindParentNode( iter );
+    while (node)
     {
-        wxGtkTreeModelNode *parent = node->GetParent();
         size_t pos;
-        for (pos = 0; pos < parent->GetChildren().GetCount(); pos++)
+        for (pos = 0; pos < node->GetChildren().GetCount(); pos++)
         {
-            if (node == parent->GetChildren().Item( pos ))
+            if (id == node->GetChildren().Item( pos ))
             {
                 gtk_tree_path_prepend_index( retval, (int) pos );
                 continue;
             }
         }
 
-        node = parent;
+        id = node->GetItem().GetID();
+        node = node->GetParent();
     }
 
     return retval;
@@ -2242,51 +2367,64 @@ GtkTreePath *wxDataViewCtrlInternal::get_path_safe( GtkTreeIter *iter )
 
 gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter )
 {
-    wxGtkTreeModelNode *node = FindNode( iter );
-    wxGtkTreeModelNode *parent = node->GetParent();
-    unsigned int pos = parent->GetChildren().Index( node );
+    g_model = m_wx_model;
     
-    if (pos == parent->GetChildren().GetCount()-1)
+    wxGtkTreeModelNode *parent = FindParentNode( iter );
+    unsigned int pos = parent->GetChildren().Index( iter->user_data );
+    
+    if (pos == parent->GetChildCount()-1)
         return FALSE;
         
-    node = parent->GetChildren().Item( pos+1 );
-    
     iter->stamp = m_gtk_model->stamp;
-    iter->user_data = (gpointer) node->GetItem().GetID();
+    iter->user_data = parent->GetChildren().Item( pos+1 );
 
     return TRUE;
 }
 
 gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter *parent )
 {
+    g_model = m_wx_model;
+    
     wxDataViewItem item( (void*) parent->user_data );
     
-    if (!m_wx_model->HasChildren( item ))
+    if (!m_wx_model->IsContainer( item ))
         return FALSE;
         
     wxGtkTreeModelNode *parent_node = FindNode( parent );
     BuildBranch( parent_node );
-        
-    wxGtkTreeModelNode *first_child_node = parent_node->GetChildren().Item( 0 );
     
+    if (parent_node->GetChildCount() == 0)
+        return FALSE;
+        
     iter->stamp = m_gtk_model->stamp;
-    iter->user_data = (gpointer) first_child_node->GetItem().GetID();
+    iter->user_data = (gpointer) parent_node->GetChildren().Item( 0 );
 
     return TRUE;
 }
 
 gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter )
 {
+    g_model = m_wx_model;
+    
     wxDataViewItem item( (void*) iter->user_data );
+    bool is_container = m_wx_model->IsContainer( item );
     
-    return m_wx_model->HasChildren( item );
+    if (!is_container)
+        return FALSE;
+    
+    wxGtkTreeModelNode *node = FindNode( iter );
+    BuildBranch( node );
+    
+    return (node->GetChildCount() > 0);
 }
 
 gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
 {
+    g_model = m_wx_model;
+    
     wxDataViewItem item( (void*) iter->user_data );
     
-    if (!m_wx_model->HasChildren( item ))
+    if (!m_wx_model->IsContainer( item ))
         return 0;
     
     wxGtkTreeModelNode *parent_node = FindNode( iter );
@@ -2299,34 +2437,31 @@ gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
 
 gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n )
 {
+    g_model = m_wx_model;
+    
     void* id = NULL;
     if (parent) id = (void*) parent->user_data;
     wxDataViewItem item( id );
     
-    if (!m_wx_model->HasChildren( item ))
+    if (!m_wx_model->IsContainer( item ))
         return FALSE;
     
     wxGtkTreeModelNode *parent_node = FindNode( parent );
     BuildBranch( parent_node );
 
-    wxGtkTreeModelNode *child_node = parent_node->GetChildren().Item( (size_t) n );
-    if (!child_node)
-        return FALSE;
-
     // wxPrintf( "iter_nth_child %d\n", n );
     
     iter->stamp = m_gtk_model->stamp;
-    iter->user_data = (gpointer) child_node->GetItem().GetID();
+    iter->user_data = parent_node->GetChildren().Item( n );
 
     return TRUE;
 }
 
 gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *child )
 {
-    wxDataViewItem item( (void*) child->user_data );
-    
-    wxGtkTreeModelNode *node = FindNode( child );
-    node = node->GetParent();
+    g_model = m_wx_model;
+
+    wxGtkTreeModelNode *node = FindParentNode( child );
     if (!node)
         return FALSE;
     
@@ -2341,11 +2476,11 @@ wxDataViewCtrlInternal_FindNode( wxGtkTreeModelNode *node, const wxDataViewItem
 {
     if (!node) return NULL;
 
-    size_t count = node->GetChildCount();
+    size_t count = node->GetNodesCount();
     size_t i;
     for (i = 0; i < count; i++)
     {
-        wxGtkTreeModelNode *child = node->GetChildren().Item( i );
+        wxGtkTreeModelNode *child = node->GetNodes().Item( i );
         if (child->GetItem().GetID() == item.GetID())
         {
             // wxPrintf( "leave findnode at %d\n", i );
@@ -2369,6 +2504,8 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
         return m_root;
 
     wxDataViewItem item( (void*) iter->user_data );
+    if (!item.IsOk())
+        return m_root;
     
     wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_root, item );
     
@@ -2384,6 +2521,9 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
 
 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item )
 {
+    if (!item.IsOk())
+        return m_root;
+
     wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_root, item );
     
     if (!result)
@@ -2396,6 +2536,55 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item
     return result;
 }
 
+static wxGtkTreeModelNode*
+wxDataViewCtrlInternal_FindParentNode( wxGtkTreeModelNode *node, const wxDataViewItem &item )
+{
+    size_t child_count = node->GetChildCount();
+    void *id = item.GetID();
+    const wxGtkTreeModelChildren &children = node->GetChildren();
+    size_t pos;
+    for (pos = 0; pos < child_count; pos++)
+    {
+        if (children.Item( pos ) == id)
+            return node;
+    }
+
+    size_t node_count = node->GetNodesCount();
+    for (pos = 0; pos < node_count; pos++)
+    {
+        wxGtkTreeModelNode *child = node->GetNodes().Item( pos );
+    
+        wxGtkTreeModelNode *node2 = wxDataViewCtrlInternal_FindParentNode( child, item );
+        if (node2)
+        {
+            // wxPrintf( "branch findnode at %d\n", i );
+            return node2;
+        }
+    }
+    
+    return NULL;
+}
+
+wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( GtkTreeIter *iter )
+{
+    if (!iter)
+        return NULL;
+        
+    wxDataViewItem item( (void*) iter->user_data );
+    if (!item.IsOk())
+        return NULL;
+
+    return wxDataViewCtrlInternal_FindParentNode( m_root, item );
+}
+
+wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( const wxDataViewItem &item )
+{
+    if (!item.IsOk())
+        return NULL;
+
+    return wxDataViewCtrlInternal_FindParentNode( m_root, item );
+}
+
 //-----------------------------------------------------------------------------
 // wxDataViewCtrl signal callbacks
 //-----------------------------------------------------------------------------