]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/dataview.cpp
added wxUTF8StringBuffer for writing UTF8 data into wxString efficiently, similarly...
[wxWidgets.git] / src / gtk / dataview.cpp
index 41ed1b24e8335c0187ac19ff9afe7f9d651b81c9..c74207cd42464426eea0a1d9b67566afeb78a4d3 100644 (file)
@@ -26,6 +26,8 @@
 #include "wx/calctrl.h"
 #include "wx/popupwin.h"
 #include "wx/icon.h"
+#include "wx/list.h"
+#include "wx/listimpl.cpp"
 
 
 #include "wx/gtk/private.h"
@@ -41,7 +43,9 @@
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
-wxDataViewModel *g_model = NULL;
+class wxDataViewCtrlInternal;
+
+wxDataViewCtrlInternal *g_internal = NULL;
 
 class wxGtkTreeModelNode;
 
@@ -53,6 +57,9 @@ typedef struct _GtkWxTreeModel       GtkWxTreeModel;
 // wxDataViewCtrlInternal
 //-----------------------------------------------------------------------------
 
+WX_DECLARE_LIST(wxDataViewItem, ItemList);
+WX_DEFINE_LIST(ItemList);
+
 class wxDataViewCtrlInternal
 {
 public:
@@ -74,10 +81,18 @@ public:
     GtkWxTreeModel* GetGtkModel()       { return m_gtk_model; }
 
     bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
-    bool ItemDeleted( const wxDataViewItem &item );
-    
+    bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
+    bool ItemChanged( const wxDataViewItem &item );
+    bool ValueChanged( const wxDataViewItem &item, unsigned int col );
+    bool Cleared();
     void Resort();
     
+    void SetSortOrder( GtkSortType sort_order ) { m_sort_order = sort_order; }
+    GtkSortType GetSortOrder()                  { return m_sort_order; }
+
+    void SetSortColumn( unsigned int column )   { m_sort_column = column; }
+    unsigned int GetSortColumn()                { return m_sort_column; }
+    
 protected:
     void InitTree();
     wxGtkTreeModelNode *FindNode( const wxDataViewItem &item );
@@ -91,6 +106,8 @@ private:
     wxDataViewModel      *m_wx_model;
     GtkWxTreeModel       *m_gtk_model;
     wxDataViewCtrl       *m_owner;
+    GtkSortType           m_sort_order;
+    unsigned int          m_sort_column;
 };
 
 
@@ -112,13 +129,13 @@ public:
         m_parent = parent; 
         m_item = item;
         m_internal = internal;
-        g_model = internal->GetDataViewModel();
+        g_internal = internal;
         m_children = new wxGtkTreeModelChildren( wxGtkTreeModelNodeCmp );
     }
     
     ~wxGtkTreeModelNode()
     { 
-        g_model = m_internal->GetDataViewModel();
+        g_internal = m_internal;
         size_t count = m_children->GetCount();
         size_t i;
         for (i = 0; i < count; i++)
@@ -131,20 +148,20 @@ public:
 
     unsigned int AddNode( wxGtkTreeModelNode* child ) 
         { 
-            g_model = m_internal->GetDataViewModel();
+            g_internal = m_internal;
             m_nodes.Add( child );
             return m_children->Add( child->GetItem().GetID() );
         }
         
     unsigned int AddLeave( void* id )
         {
-            g_model = m_internal->GetDataViewModel();
+            g_internal = m_internal;
             return m_children->Add( id );
         }
         
     void DeleteChild( void* id )
         {
-            g_model = m_internal->GetDataViewModel();
+            g_internal = m_internal;
             size_t pos;
             size_t count = m_children->GetCount();
             for (pos = 0; pos < count; pos++)
@@ -195,7 +212,10 @@ private:
 
 int LINKAGEMODE wxGtkTreeModelNodeCmp( void* id1, void* id2 )
 {
-    return g_model->Compare( id1, id2 );
+    int ret = g_internal->GetDataViewModel()->Compare( id1, id2, 
+        g_internal->GetSortColumn(), (g_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
+        
+    return ret;
 }
 
 //-----------------------------------------------------------------------------
@@ -583,42 +603,38 @@ gboolean wxgtk_tree_model_get_sort_column_id    (GtkTreeSortable        *sortabl
     g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE);
 
     if (sort_column_id)
-        *sort_column_id = tree_model->internal->GetDataViewModel()->GetSortingColumn();
+        *sort_column_id = tree_model->internal->GetSortColumn();
         
     if (order)
-    {
-        bool ascending = tree_model->internal->GetDataViewModel()->GetSortOrderAscending();
-        if (ascending)
-            *order = GTK_SORT_ASCENDING;
-        else
-            *order = GTK_SORT_DESCENDING;
-    }
+        *order = tree_model->internal->GetSortOrder();
         
     return TRUE;
 }
 
-void     wxgtk_tree_model_set_sort_column_id    (GtkTreeSortable        *sortable,
+void     wxgtk_tree_model_set_sort_column_id  (GtkTreeSortable        *sortable,
                                                      gint                      sort_column_id,
                                                      GtkSortType               order)
 {
     GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
     g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
 
-    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()))
+    if ((sort_column_id == (gint) tree_model->internal->GetSortColumn()) &&
+        (order == tree_model->internal->GetSortOrder()))
         return;
     
-    tree_model->internal->GetDataViewModel()->SetSortingColumn( sort_column_id );
+    tree_model->internal->SetSortColumn( sort_column_id );
     
-    tree_model->internal->GetDataViewModel()->SetSortOrderAscending( ascending );
+    tree_model->internal->SetSortOrder( order );
     
     gtk_tree_sortable_sort_column_changed (sortable);
     
     tree_model->internal->GetDataViewModel()->Resort();
+
+    wxDataViewCtrl *dv = tree_model->internal->GetOwner();    
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, dv->GetId() );
+    // TODO event.SetDataViewColumn( column );
+    event.SetModel( dv->GetModel() );
+    dv->GetEventHandler()->ProcessEvent( event );
 }
 
 void     wxgtk_tree_model_set_sort_func         (GtkTreeSortable        *sortable,
@@ -1015,7 +1031,7 @@ public:
     ~wxGtkDataViewModelNotifier();
 
     virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
-    virtual bool ItemDeleted( const wxDataViewItem &item );
+    virtual bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
     virtual bool ItemChanged( const wxDataViewItem &item );
     virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col );
     virtual bool Cleared();
@@ -1062,7 +1078,7 @@ bool wxGtkDataViewModelNotifier::ItemAdded( const wxDataViewItem &parent, const
     return true;
 }
 
-bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &item )
+bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
 {
     GtkTreeIter iter;
     iter.stamp = m_wxgtk_model->stamp;
@@ -1074,7 +1090,7 @@ bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &item )
         GTK_TREE_MODEL(m_wxgtk_model), path );
     gtk_tree_path_free (path);
 
-    m_owner->GtkGetInternal()->ItemDeleted( item );
+    m_owner->GtkGetInternal()->ItemDeleted( parent, item );
     
     return true;
 }
@@ -1096,6 +1112,8 @@ bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem &item )
         GTK_TREE_MODEL(m_wxgtk_model), path, &iter );
     gtk_tree_path_free (path);
 
+    m_owner->GtkGetInternal()->ItemChanged( item );
+    
     return true;
 }
 
@@ -1129,14 +1147,22 @@ bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsig
             // Redraw
             gtk_widget_queue_draw_area( GTK_WIDGET(widget),
                 cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height );
+                
+            m_owner->GtkGetInternal()->ValueChanged( item, model_col );
+            
+            return true;
         }
     }
 
-    return true;
+    return false;
 }
 
 bool wxGtkDataViewModelNotifier::Cleared()
 {
+    // TODO: delete everything
+
+    m_owner->GtkGetInternal()->Cleared();
+    
     return false;
 }
 
@@ -1822,7 +1848,7 @@ gtk_dataview_header_button_press_callback( GtkWidget *widget,
         event.SetDataViewColumn( column );
         event.SetModel( dv->GetModel() );
         if (dv->GetEventHandler()->ProcessEvent( event ))
-            return TRUE;
+            return FALSE;
     }
 
     return FALSE;
@@ -2135,7 +2161,7 @@ void wxDataViewColumn::SetWidth( int width )
 
 void wxGtkTreeModelNode::Resort()
 {
-    g_model = m_internal->GetDataViewModel();
+    g_internal = m_internal;
     
     size_t child_count = GetChildCount();
     if (child_count == 0)
@@ -2222,6 +2248,8 @@ wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner,
     m_wx_model = wx_model; 
     m_gtk_model = gtk_model; 
     m_root = NULL; 
+    m_sort_order = GTK_SORT_ASCENDING;
+    m_sort_column = 0;
     InitTree();
 }
     
@@ -2249,6 +2277,9 @@ void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node )
                 node->AddNode( new wxGtkTreeModelNode( node, child, this ) );
             else
                 node->AddLeave( child.GetID() );
+    
+            // Don't send any events here
+    
             child = m_wx_model->GetNextSibling( child );
         }
     }
@@ -2266,19 +2297,66 @@ bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDa
         parent_node->AddNode( new wxGtkTreeModelNode( parent_node, item, this ) );
     else
         parent_node->AddLeave( item.GetID() );
+        
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    event.SetItem( item );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+
     return true;
 }
 
-bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &item )
+bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
 {
-    wxGtkTreeModelNode *parent = FindParentNode( item );
-    parent->DeleteChild( item.GetID() );
+    wxGtkTreeModelNode *parent_node = FindNode( parent );
+    parent_node->DeleteChild( item.GetID() );
+    
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    event.SetItem( item );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+
+    return true;
+}
+
+bool wxDataViewCtrlInternal::ItemChanged( const wxDataViewItem &item )
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    event.SetItem( item );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+    
+    return true;
+}
+
+bool wxDataViewCtrlInternal::ValueChanged( const wxDataViewItem &item, unsigned int col )
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    event.SetColumn( col );
+    event.SetItem( item );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+    
+    return true;
+}
+
+bool wxDataViewCtrlInternal::Cleared()
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+    
     return true;
 }
 
 gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path )
 {
-    g_model = m_wx_model;
+    g_internal = this;
     
     int depth = gtk_tree_path_get_depth( path );
 
@@ -2320,7 +2398,7 @@ gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path
 
 GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
 {
-    g_model = m_wx_model;
+    g_internal = this;
     
     GtkTreePath *retval = gtk_tree_path_new ();
     void *id = iter->user_data;    
@@ -2340,7 +2418,7 @@ GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
 
 GtkTreePath *wxDataViewCtrlInternal::get_path_safe( GtkTreeIter *iter )
 {
-    g_model = m_wx_model;
+    g_internal = this;
     
     GtkTreePath *retval = gtk_tree_path_new ();
     void *id = iter->user_data;    
@@ -2367,9 +2445,12 @@ GtkTreePath *wxDataViewCtrlInternal::get_path_safe( GtkTreeIter *iter )
 
 gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter )
 {
-    g_model = m_wx_model;
+    g_internal = this;
     
     wxGtkTreeModelNode *parent = FindParentNode( iter );
+    if( parent == NULL )
+        return FALSE;
+
     unsigned int pos = parent->GetChildren().Index( iter->user_data );
     
     if (pos == parent->GetChildCount()-1)
@@ -2383,7 +2464,7 @@ gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter )
 
 gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter *parent )
 {
-    g_model = m_wx_model;
+    g_internal = this;
     
     wxDataViewItem item( (void*) parent->user_data );
     
@@ -2404,7 +2485,7 @@ gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter *
 
 gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter )
 {
-    g_model = m_wx_model;
+    g_internal = this;
     
     wxDataViewItem item( (void*) iter->user_data );
     bool is_container = m_wx_model->IsContainer( item );
@@ -2420,7 +2501,7 @@ gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter )
 
 gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
 {
-    g_model = m_wx_model;
+    g_internal = this;
     
     wxDataViewItem item( (void*) iter->user_data );
     
@@ -2437,7 +2518,7 @@ gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
 
 gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n )
 {
-    g_model = m_wx_model;
+    g_internal = this;
     
     void* id = NULL;
     if (parent) id = (void*) parent->user_data;
@@ -2459,7 +2540,7 @@ gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter
 
 gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *child )
 {
-    g_model = m_wx_model;
+    g_internal = this;
 
     wxGtkTreeModelNode *node = FindParentNode( child );
     if (!node)
@@ -2472,30 +2553,48 @@ gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *ch
 }
     
 static wxGtkTreeModelNode*
-wxDataViewCtrlInternal_FindNode( wxGtkTreeModelNode *node, const wxDataViewItem &item )
+wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
 {
-    if (!node) return NULL;
+    if( model == NULL )
+        return NULL;
 
-    size_t count = node->GetNodesCount();
-    size_t i;
-    for (i = 0; i < count; i++)
+    ItemList list;
+    list.DeleteContents( true );
+    wxDataViewItem it( item );
+    while( it.IsOk() )
     {
-        wxGtkTreeModelNode *child = node->GetNodes().Item( i );
-        if (child->GetItem().GetID() == item.GetID())
-        {
-            // wxPrintf( "leave findnode at %d\n", i );
-            return child;
-        }
-            
-        wxGtkTreeModelNode *node2 = wxDataViewCtrlInternal_FindNode( child, item );
-        if (node2)
+        wxDataViewItem * pItem = new wxDataViewItem( it );
+        list.Insert( pItem );
+        it = model->GetParent( it );
+    }
+
+    wxGtkTreeModelNode * node = treeNode;
+    for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
+    {
+        if( node && node->GetNodes().GetCount() != 0 )
         {
-            // wxPrintf( "branch findnode at %d\n", i );
-            return node2;
+            int len = node->GetNodes().GetCount();
+            wxGtkTreeModelNodes nodes = node->GetNodes();
+            int j = 0;
+            for( ; j < len; j ++)
+            {
+                if( nodes[j]->GetItem() == *(n->GetData()))
+                {
+                    node = nodes[j];
+                    break;
+                }    
+            }
+
+            if( j == len )
+            {
+                return NULL;
+            }
         }
+        else
+            return NULL;
     }
-    
-    return NULL;
+    return node;
+
 }
 
 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
@@ -2507,7 +2606,7 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
     if (!item.IsOk())
         return m_root;
     
-    wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_root, item );
+    wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
     
     if (!result)
     {
@@ -2524,7 +2623,7 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item
     if (!item.IsOk())
         return m_root;
 
-    wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_root, item );
+    wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
     
     if (!result)
     {
@@ -2537,31 +2636,56 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item
 }
 
 static wxGtkTreeModelNode*
-wxDataViewCtrlInternal_FindParentNode( wxGtkTreeModelNode *node, const wxDataViewItem &item )
+wxDataViewCtrlInternal_FindParentNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, 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( model == NULL )
+        return NULL;
+
+    ItemList list;
+    list.DeleteContents( true );
+    if( !item.IsOk() )
+        return NULL;
+
+    wxDataViewItem it( model->GetParent( item ) );
+    while( it.IsOk() )
     {
-        if (children.Item( pos ) == id)
-            return node;
+        wxDataViewItem * pItem = new wxDataViewItem( it );
+        list.Insert( pItem );
+        it = model->GetParent( it );
     }
 
-    size_t node_count = node->GetNodesCount();
-    for (pos = 0; pos < node_count; pos++)
+    wxGtkTreeModelNode * node = treeNode;
+    for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
     {
-        wxGtkTreeModelNode *child = node->GetNodes().Item( pos );
-    
-        wxGtkTreeModelNode *node2 = wxDataViewCtrlInternal_FindParentNode( child, item );
-        if (node2)
+        if( node && node->GetNodes().GetCount() != 0 )
         {
-            // wxPrintf( "branch findnode at %d\n", i );
-            return node2;
+            int len = node->GetNodes().GetCount();
+            wxGtkTreeModelNodes nodes = node->GetNodes();
+            int j = 0;
+            for( ; j < len; j ++)
+            {
+                if( nodes[j]->GetItem() == *(n->GetData()))
+                {
+                    node = nodes[j];
+                    break;
+                }    
+            }
+
+            if( j == len )
+            {
+                return NULL;
+            }
         }
+        else
+            return NULL;
+    }
+    //Examine whether the node is item's parent node
+    int len = node->GetChildCount();
+    for( int i = 0; i < len ; i ++ )
+    {
+        if( node->GetChildren().Item( i ) == item.GetID() )
+            return node;
     }
-    
     return NULL;
 }
 
@@ -2574,7 +2698,7 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( GtkTreeIter *iter )
     if (!item.IsOk())
         return NULL;
 
-    return wxDataViewCtrlInternal_FindParentNode( m_root, item );
+    return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
 }
 
 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( const wxDataViewItem &item )
@@ -2582,7 +2706,7 @@ wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( const wxDataViewItem
     if (!item.IsOk())
         return NULL;
 
-    return wxDataViewCtrlInternal_FindParentNode( m_root, item );
+    return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
 }
 
 //-----------------------------------------------------------------------------
@@ -2596,7 +2720,7 @@ wxdataview_selection_changed_callback( GtkTreeSelection* selection, wxDataViewCt
         return;
 
     wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_SELECTED, dv->GetId() );
-    // TODO: item
+    event.SetItem( dv->GetSelection() );
     event.SetModel( dv->GetModel() );
     dv->GetEventHandler()->ProcessEvent( event );
 }
@@ -2615,8 +2739,60 @@ wxdataview_row_activated_callback( GtkTreeView* treeview, GtkTreePath *path,
     dv->GetEventHandler()->ProcessEvent( event );
 }
 
+static gboolean
+wxdataview_test_expand_row_callback( GtkTreeView* treeview, GtkTreeIter* iter,
+                                     GtkTreePath *path, wxDataViewCtrl *dv )
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, dv->GetId() );
+
+    wxDataViewItem item( (void*) iter->user_data );;
+    event.SetItem( item );
+    event.SetModel( dv->GetModel() );
+    dv->GetEventHandler()->ProcessEvent( event );
+  
+    return !event.IsAllowed();
+}
+
+static void
+wxdataview_row_expanded_callback( GtkTreeView* treeview, GtkTreeIter* iter,
+                                  GtkTreePath *path, wxDataViewCtrl *dv )
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED, dv->GetId() );
+
+    wxDataViewItem item( (void*) iter->user_data );;
+    event.SetItem( item );
+    event.SetModel( dv->GetModel() );
+    dv->GetEventHandler()->ProcessEvent( event );
+}
+
+static gboolean
+wxdataview_test_collapse_row_callback( GtkTreeView* treeview, GtkTreeIter* iter,
+                                       GtkTreePath *path, wxDataViewCtrl *dv )
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING, dv->GetId() );
+
+    wxDataViewItem item( (void*) iter->user_data );;
+    event.SetItem( item );
+    event.SetModel( dv->GetModel() );
+    dv->GetEventHandler()->ProcessEvent( event );
+    
+    return !event.IsAllowed();
+}
+
+static void
+wxdataview_row_collapsed_callback( GtkTreeView* treeview, GtkTreeIter* iter,
+                                   GtkTreePath *path, wxDataViewCtrl *dv )
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED, dv->GetId() );
+
+    wxDataViewItem item( (void*) iter->user_data );;
+    event.SetItem( item );
+    event.SetModel( dv->GetModel() );
+    dv->GetEventHandler()->ProcessEvent( event );
+}
+
 //-----------------------------------------------------------------------------
-// wxDataViewCtrl
+    // wxDataViewCtrl
 //-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
@@ -2640,8 +2816,7 @@ void gtk_dataviewctrl_size_callback( GtkWidget *WXUNUSED(widget),
                                      GtkAllocation *alloc,
                                      wxDataViewCtrl *win )
 {
-
-    wxWindowList::Node *node = win->GetChildren().GetFirst();
+    wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
     while (node)
     {
         wxWindow *child = node->GetData();
@@ -2750,9 +2925,21 @@ bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
 
     GtkEnableSelectionEvents();
 
-    g_signal_connect_after (m_treeview, "row_activated",
+    g_signal_connect_after (m_treeview, "row-activated",
                             G_CALLBACK (wxdataview_row_activated_callback), this);
 
+    g_signal_connect (m_treeview, "test-collapse-row",
+                            G_CALLBACK (wxdataview_test_collapse_row_callback), this);
+
+    g_signal_connect_after (m_treeview, "row-collapsed",
+                            G_CALLBACK (wxdataview_row_collapsed_callback), this);
+
+    g_signal_connect (m_treeview, "test-expand-row",
+                            G_CALLBACK (wxdataview_test_expand_row_callback), this);
+                            
+    g_signal_connect_after (m_treeview, "row-expanded",
+                            G_CALLBACK (wxdataview_row_expanded_callback), this);
+
     return true;
 }
 
@@ -2808,6 +2995,22 @@ wxDataViewItem wxDataViewCtrl::GetSelection()
     
     if (m_windowStyle & wxDV_MULTIPLE)
     {
+        // Report the first one
+        GtkTreeModel *model;
+        GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
+    
+        if (list)
+        {
+            GtkTreePath *path = (GtkTreePath*) list->data;
+            GtkTreeIter iter;
+            m_internal->get_iter( &iter, path );
+            
+            // delete list
+            g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
+            g_list_free( list );
+            
+            return wxDataViewItem( (void*) iter.user_data );
+        }
     }
     else
     {
@@ -2822,6 +3025,137 @@ wxDataViewItem wxDataViewCtrl::GetSelection()
     return wxDataViewItem(0);
 }
 
+int wxDataViewCtrl::GetSelections( wxDataViewItemArray & sel ) const
+{
+    sel.Clear();
+
+    GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+    if (HasFlag(wxDV_MULTIPLE))
+    {
+        GtkTreeModel *model;
+        GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
+
+        int count = 0;
+        while (list)
+        {
+            GtkTreePath *path = (GtkTreePath*) list->data;
+            
+            GtkTreeIter iter;
+            m_internal->get_iter( &iter, path );
+
+            sel.Add( wxDataViewItem( (void*) iter.user_data ) );
+
+            list = g_list_next( list );
+            count++;
+        }
+
+        // delete list
+        g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
+        g_list_free( list );
+
+        return count;
+    }
+    else
+    {
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        gboolean has_selection = gtk_tree_selection_get_selected( selection, &model, &iter );
+        if (has_selection)
+        {
+            sel.Add( wxDataViewItem( (void*) iter.user_data) );
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+void wxDataViewCtrl::SetSelections( const wxDataViewItemArray & sel )
+{
+    GtkDisableSelectionEvents();
+    
+    GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+
+    gtk_tree_selection_unselect_all( selection );
+    
+    size_t i;
+    for (i = 0; i < sel.GetCount(); i++)
+    {
+        GtkTreeIter iter;
+        iter.user_data = (gpointer) sel[i].GetID();
+        gtk_tree_selection_select_iter( selection, &iter );
+    }
+    
+    GtkEnableSelectionEvents();
+}
+
+void wxDataViewCtrl::Select( const wxDataViewItem & item )
+{
+    GtkDisableSelectionEvents();
+
+    GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+
+    GtkTreeIter iter;
+    iter.user_data = (gpointer) item.GetID();
+    gtk_tree_selection_select_iter( selection, &iter );
+
+    GtkEnableSelectionEvents();
+}
+
+void wxDataViewCtrl::Unselect( const wxDataViewItem & item )
+{
+    GtkDisableSelectionEvents();
+
+    GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+
+    GtkTreeIter iter;
+    iter.user_data = (gpointer) item.GetID();
+    gtk_tree_selection_unselect_iter( selection, &iter );
+
+    GtkEnableSelectionEvents();
+}
+
+bool wxDataViewCtrl::IsSelected( const wxDataViewItem & item ) const
+{
+    GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+
+    GtkTreeIter iter;
+    iter.user_data = (gpointer) item.GetID();
+    
+    return gtk_tree_selection_iter_is_selected( selection, &iter );
+}
+
+void wxDataViewCtrl::SelectAll()
+{
+    GtkDisableSelectionEvents();
+    
+    GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+    
+    gtk_tree_selection_select_all( selection );
+    
+    GtkEnableSelectionEvents();
+}
+
+void wxDataViewCtrl::UnselectAll()
+{
+    GtkDisableSelectionEvents();
+    
+    GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
+    
+    gtk_tree_selection_unselect_all( selection );
+    
+    GtkEnableSelectionEvents();
+}
+
+void wxDataViewCtrl::EnsureVisible( const wxDataViewItem & item, wxDataViewColumn *column )
+{
+    GtkTreeIter iter;
+    iter.user_data = (gpointer) item.GetID();
+    GtkTreePath *path = m_internal->get_path( &iter );
+    gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(m_treeview), path, NULL, false, 0.0, 0.0 );
+    gtk_tree_path_free( path );
+}
+
 void wxDataViewCtrl::DoSetExpanderColumn()
 {
 }
@@ -2833,15 +3167,15 @@ void wxDataViewCtrl::DoSetIndent()
 void wxDataViewCtrl::GtkDisableSelectionEvents()
 {
     GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
-    g_signal_connect_after (selection, "changed",
-                            G_CALLBACK (wxdataview_selection_changed_callback), this);
+    g_signal_handlers_disconnect_by_func( selection,
+                            (gpointer) (wxdataview_selection_changed_callback), this);
 }
 
 void wxDataViewCtrl::GtkEnableSelectionEvents()
 {
     GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
-    g_signal_handlers_disconnect_by_func( selection,
-                            (gpointer) (wxdataview_selection_changed_callback), this);
+    g_signal_connect_after (selection, "changed",
+                            G_CALLBACK (wxdataview_selection_changed_callback), this);
 }
 
 // static