From ef4279890a78cdc9f0f1b8f578ff0e573f922af3 Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Wed, 18 Jul 2007 13:23:57 +0000 Subject: [PATCH] First actual sorting for wxDataViewCtrl git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47545 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/dataview.h | 51 +++++++++++-- src/common/datavcmn.cpp | 50 ++++++++++++- src/gtk/dataview.cpp | 161 ++++++++++++++++++++++++++++------------ 3 files changed, 208 insertions(+), 54 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 90cb52b033..106829907a 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -85,9 +85,6 @@ bool operator == (const wxDataViewItem &left, const wxDataViewItem &right); // wxDataViewModel // --------------------------------------------------------- -typedef int (wxCALLBACK *wxDataViewModelCompare) - (const wxDataViewItem& item1, const wxDataViewItem& item2, unsigned int col, unsigned int option ); - class WXDLLIMPEXP_ADV wxDataViewModel: public wxObjectRefData { public: @@ -118,18 +115,58 @@ public: virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col ); virtual bool Cleared(); + // delegatd action + virtual void Resort(); + void AddNotifier( wxDataViewModelNotifier *notifier ); void RemoveNotifier( wxDataViewModelNotifier *notifier ); - void SetCompareFunction( wxDataViewModelCompare func ) { m_cmpFunc = func; } - wxDataViewModelCompare GetCompareFunction() { return m_cmpFunc; } + // default compare function + virtual int Compare( const wxDataViewItem &item1, const wxDataViewItem &item2 ); + + void SetSortingColumn( unsigned int col ) { m_sortingColumn = col; } + unsigned int GetSortingColumn() { return m_sortingColumn; } + void SetSortOrderAscending( bool ascending ) { m_ascending = true; } + bool GetSortOrderAscending() { return m_ascending; } + protected: // the user should not delete this class directly: he should use DecRef() instead! virtual ~wxDataViewModel() { } wxList m_notifiers; - wxDataViewModelCompare m_cmpFunc; + unsigned int m_sortingColumn; + bool m_ascending; +}; + +// --------------------------------------------------------- +// wxDataViewVirtualListModel +// --------------------------------------------------------- + +class wxDataViewIndexListModel: public wxDataViewModel +{ +public: + wxDataViewIndexListModel(); + ~wxDataViewIndexListModel(); + + virtual unsigned int GetRowCount() = 0; + + virtual void GetValue( wxVariant &variant, + unsigned int row, unsigned int col ) const = 0; + + virtual bool SetValue( const wxVariant &variant, + unsigned int row, unsigned int col ) = 0; + + void ItemPrepended(); + void ItemInserted( unsigned int before ); + void ItemAppended(); + void ItemChanged( unsigned int row ); + void ValueChanged( unsigned int row, unsigned int col ); + + wxDataViewItem GetItem( unsigned int row ); + + virtual int Compare( const wxDataViewItem &item1, const wxDataViewItem &item2 ); + }; // --------------------------------------------------------- @@ -147,6 +184,8 @@ public: virtual bool ItemChanged( const wxDataViewItem &item ) = 0; virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col ) = 0; virtual bool Cleared() = 0; + + virtual void Resort() { }; void SetOwner( wxDataViewModel *owner ) { m_owner = owner; } wxDataViewModel *GetOwner() { return m_owner; } diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index f8f5154fa2..cd2af9dc20 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -39,7 +39,7 @@ bool operator == (const wxDataViewItem &left, const wxDataViewItem &right) wxDataViewModel::wxDataViewModel() { m_notifiers.DeleteContents( true ); - m_cmpFunc = NULL; + m_sortingColumn = 0; } bool wxDataViewModel::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item ) @@ -122,6 +122,17 @@ bool wxDataViewModel::Cleared() return ret; } +void wxDataViewModel::Resort() +{ + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewModelNotifier* notifier = (wxDataViewModelNotifier*) node->GetData(); + notifier->Resort(); + node = node->GetNext(); + } +} + void wxDataViewModel::AddNotifier( wxDataViewModelNotifier *notifier ) { m_notifiers.Append( notifier ); @@ -133,6 +144,43 @@ void wxDataViewModel::RemoveNotifier( wxDataViewModelNotifier *notifier ) m_notifiers.DeleteObject( notifier ); } +int wxDataViewModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2 ) +{ + wxVariant value1,value2; + GetValue( value1, item1, m_sortingColumn ); + GetValue( value2, item2, m_sortingColumn ); + if (value1.GetType() == wxT("string")) + { + wxString str1 = value1.GetString(); + wxString str2 = value2.GetString(); + return str1.Cmp( str2 ); + } + if (value1.GetType() == wxT("long")) + { + long l1 = value1.GetLong(); + long l2 = value2.GetLong(); + return l1-l2; + } + if (value1.GetType() == wxT("double")) + { + double d1 = value1.GetDouble(); + double d2 = value2.GetDouble(); + if (d1 == d2) return 0; + if (d1 < d2) return 1; + return -1; + } + if (value1.GetType() == wxT("datetime")) + { + wxDateTime dt1 = value1.GetDateTime(); + wxDateTime dt2 = value2.GetDateTime(); + if (dt1.IsEqualTo(dt2)) return 0; + if (dt1.IsEarlierThan(dt2)) return 1; + return -1; + } + + return 0; +} + // --------------------------------------------------------- // wxDataViewRendererBase // --------------------------------------------------------- diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 7bab43fa23..f4f6ab4b5e 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -47,15 +47,21 @@ //----------------------------------------------------------------------------- class wxGtkTreeModelNode; -WX_DEFINE_ARRAY_PTR( wxGtkTreeModelNode*, wxGtkTreeModelNodes ); + +int LINKAGEMODE wxGtkTreeModelNodeCmp( wxGtkTreeModelNode* node1, wxGtkTreeModelNode* node2 ); + +WX_DEFINE_SORTED_ARRAY( wxGtkTreeModelNode*, wxGtkTreeModelNodes ); class wxGtkTreeModelNode { public: - wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item ) + wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item, + wxDataViewModel *model ) : + m_children( wxGtkTreeModelNodeCmp ) { m_parent = parent; m_item = item; + m_model = model; } ~wxGtkTreeModelNode() @@ -75,14 +81,13 @@ public: { return m_children; } wxGtkTreeModelNode* GetNthChild( unsigned int n ) { return m_children.Item( n ); } - void Insert( wxGtkTreeModelNode* child, unsigned int n) - { m_children.Insert( child, n); } - void Append( wxGtkTreeModelNode* child ) - { m_children.Add( child ); } + 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; } @@ -92,8 +97,14 @@ private: 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; @@ -107,6 +118,7 @@ public: gboolean get_iter( GtkTreeIter *iter, GtkTreePath *path ); GtkTreePath *get_path( GtkTreeIter *iter); + GtkTreePath *get_path_safe( GtkTreeIter *iter); gboolean iter_next( GtkTreeIter *iter ); gboolean iter_children( GtkTreeIter *iter, GtkTreeIter *parent); gboolean iter_has_child( GtkTreeIter *iter ); @@ -163,9 +175,6 @@ struct _GtkWxTreeModel /*< private >*/ gint stamp; wxDataViewCtrlInternal *internal; - - gint sort_column_id; - GtkSortType order; }; struct _GtkWxTreeModelClass @@ -188,6 +197,8 @@ static gboolean wxgtk_tree_model_get_iter (GtkTreeModel *tree_mo GtkTreePath *path); static GtkTreePath *wxgtk_tree_model_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter); +static GtkTreePath *wxgtk_tree_model_get_path_safe (GtkTreeModel *tree_model, + GtkTreeIter *iter); static void wxgtk_tree_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, @@ -326,8 +337,6 @@ wxgtk_tree_model_init (GtkWxTreeModel *tree_model) { tree_model->internal = NULL; tree_model->stamp = g_random_int(); - tree_model->sort_column_id = -2; - tree_model->order = GTK_SORT_ASCENDING; } static void @@ -405,6 +414,17 @@ wxgtk_tree_model_get_path (GtkTreeModel *tree_model, return wxtree_model->internal->get_path( iter ); } +static GtkTreePath * +wxgtk_tree_model_get_path_safe (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model; + g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), NULL); + g_return_val_if_fail (iter->stamp == GTK_WX_TREE_MODEL (wxtree_model)->stamp, NULL); + + return wxtree_model->internal->get_path_safe( iter ); +} + static void wxgtk_tree_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, @@ -509,14 +529,17 @@ gboolean wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortabl g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE); - if (tree_model->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) - return FALSE; - if (sort_column_id) - *sort_column_id = tree_model->sort_column_id; + *sort_column_id = tree_model->internal->GetDataViewModel()->GetSortingColumn(); if (order) - *order = tree_model->order; + { + bool ascending = tree_model->internal->GetDataViewModel()->GetSortOrderAscending(); + if (ascending) + *order = GTK_SORT_ASCENDING; + else + *order = GTK_SORT_DESCENDING; + } return TRUE; } @@ -526,20 +549,22 @@ void wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortabl GtkSortType order) { GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable; - g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) ); - if ((tree_model->sort_column_id == sort_column_id) && - (tree_model->order == order)) + // TODO check for equality + return; - - tree_model->sort_column_id = sort_column_id; - tree_model->order = order; - + gtk_tree_sortable_sort_column_changed (sortable); - wxPrintf( "wxgtk_tree_model_set_column_id, sort_column_id = %d, order = %d\n", sort_column_id, (int)order ); - // sort + tree_model->internal->GetDataViewModel()->SetSortingColumn( sort_column_id ); + + bool ascending = TRUE; + if (order != GTK_SORT_ASCENDING) + ascending = FALSE; + tree_model->internal->GetDataViewModel()->SetSortOrderAscending( ascending ); + + tree_model->internal->GetDataViewModel()->Resort(); } void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable, @@ -550,9 +575,6 @@ void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortabl { g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) ); g_return_if_fail (func != NULL); - - wxPrintf( "wxgtk_tree_model_set_sort_func, sort_column_id = %d\n", sort_column_id ); - // sort } void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable, @@ -991,7 +1013,7 @@ bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &item ) iter.stamp = m_wxgtk_model->stamp; iter.user_data = (gpointer) item.GetID(); - GtkTreePath *path = wxgtk_tree_model_get_path( + GtkTreePath *path = wxgtk_tree_model_get_path_safe( GTK_TREE_MODEL(m_wxgtk_model), &iter ); gtk_tree_model_row_deleted( GTK_TREE_MODEL(m_wxgtk_model), path ); @@ -2066,6 +2088,14 @@ wxDataViewCtrlInternal::~wxDataViewCtrlInternal() g_object_unref( m_gtk_model ); } +void wxDataViewCtrlInternal::InitTree() +{ + wxDataViewItem item; + m_root = new wxGtkTreeModelNode( NULL, item, m_wx_model ); + + BuildBranch( m_root ); +} + void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node ) { if (node->GetChildCount() == 0) @@ -2073,8 +2103,7 @@ void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node ) wxDataViewItem child = m_wx_model->GetFirstChild( node->GetItem() ); while (child.IsOk()) { - // wxPrintf( "AddItem %d\n", (int) child.GetID() ); - node->Append( new wxGtkTreeModelNode( node, child ) ); + node->Add( new wxGtkTreeModelNode( node, child, node->GetModel() ) ); child = m_wx_model->GetNextSibling( child ); } } @@ -2083,7 +2112,7 @@ void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node ) bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item ) { wxGtkTreeModelNode *parent_node = FindNode( parent ); - parent_node->Append( new wxGtkTreeModelNode( parent_node, item ) ); + parent_node->Add( new wxGtkTreeModelNode( parent_node, item, parent_node->GetModel() ) ); return true; } @@ -2091,8 +2120,15 @@ bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &item ) { wxGtkTreeModelNode *node = FindNode( item ); wxGtkTreeModelNode *parent = node->GetParent(); - parent->GetChildren().Remove( node ); - delete node; + size_t pos; + for (pos = 0; pos < parent->GetChildren().GetCount(); pos++) + { + if (node == parent->GetChildren().Item( pos )) + { + parent->GetChildren().RemoveAt( pos ); + continue; + } + } return true; } @@ -2139,14 +2175,43 @@ GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter ) return retval; } +GtkTreePath *wxDataViewCtrlInternal::get_path_safe( GtkTreeIter *iter ) +{ + GtkTreePath *retval = gtk_tree_path_new (); + + wxGtkTreeModelNode *node = FindNode( iter ); + while (node->GetParent()) + { + wxGtkTreeModelNode *parent = node->GetParent(); + size_t pos; + for (pos = 0; pos < parent->GetChildren().GetCount(); pos++) + { + if (node == parent->GetChildren().Item( pos )) + { + gtk_tree_path_prepend_index( retval, (int) pos ); + continue; + } + } + + node = parent; + } + + return retval; +} + gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter ) { - wxDataViewItem item( (void*) iter->user_data ); - item = m_wx_model->GetNextSibling( item ); - if (!item.IsOk()) + wxGtkTreeModelNode *node = FindNode( iter ); + wxGtkTreeModelNode *parent = node->GetParent(); + unsigned int pos = parent->GetChildren().Index( node ); + + if (pos == parent->GetChildren().GetCount()-1) return FALSE; - - iter->user_data = (gpointer) item.GetID(); + + node = parent->GetChildren().Item( pos+1 ); + + iter->stamp = m_gtk_model->stamp; + iter->user_data = (gpointer) node->GetItem().GetID(); return TRUE; } @@ -2185,6 +2250,8 @@ gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter ) wxGtkTreeModelNode *parent_node = FindNode( iter ); BuildBranch( parent_node ); + + // wxPrintf( "iter_n_children %d\n", parent_node->GetChildCount() ); return parent_node->GetChildCount(); } @@ -2204,6 +2271,8 @@ gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter 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(); @@ -2226,14 +2295,6 @@ gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *ch return TRUE; } -void wxDataViewCtrlInternal::InitTree() -{ - wxDataViewItem item; - m_root = new wxGtkTreeModelNode( NULL, item ); - - BuildBranch( m_root ); -} - static wxGtkTreeModelNode* wxDataViewCtrlInternal_FindNode( wxGtkTreeModelNode *node, const wxDataViewItem &item ) { @@ -2245,11 +2306,17 @@ wxDataViewCtrlInternal_FindNode( wxGtkTreeModelNode *node, const wxDataViewItem { wxGtkTreeModelNode *child = node->GetChildren().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) + { + // wxPrintf( "branch findnode at %d\n", i ); return node2; + } } return NULL;