customize treeview sort

 
person.h

#ifndef _MODEL_H
#define _MODEL_H


#include 
 
 
  
  
#include 
  
  
   
   
#include 
   
   
    
    

#define PERSON_TYPE   (  person_get_type() )
#define PERSON(obj)     ( G_TYPE_CHECK_INSTANCE_CAST((obj), PERSON_TYPE, CPerson) )
#define PERSON_CLASS(klass)  ( G_TYPE_CHECK_CLASS_CAST((klass), PERSON_TYPE, CPersonClass ) )
#define IS_PERSON(obj)      ( G_TYPE_CHECK_INSTANCE_TYPE((obj), PERSON_TYPE) )
#define IS_PERSONCALSS(klass)    ( G_TYPE_CHECK_CLASS_TYPE((klass), PERSON_TYPE) )
#define PERSON_GET_CLASS(obj)   ( G_TYPE_INSTANCE_GET_CLASS(), PERSON_TYPE, CPersonClass )

enum
{
    PERSON_COL_RECORD = 0,
    PERSON_COL_NAME,
    PERSON_COL_AGE,
    PERSON_COL_ALL,
};

typedef struct _PersonNode PersonNode;
typedef struct _CPerson CPerson;
typedef struct _CPersonClass CPersonClass;
struct _PersonNode
{
    gchar* name;
    gint age;
};

struct _CPerson
{
    GObject parent;
    
    gint row_n;
    GList* row;

    gint col_n;
    GType col_type[PERSON_COL_ALL];

    GtkSortType type;
    gint sort_id;
    
    gint stamp;
};
struct _CPersonClass
{
    GObjectClass parent_class;
    
};


/* all of internal interface */
GType person_get_type(void);
/*{@ property definition for person 
  */
#define  PERSON_PROPERTY_INDEX_NAME 1
/*@} end definition 
  */
  
/* print function name*/
#define PERSON_PRINT_SELF() g_printf("%s/n",__FUNCTION__);

/* user interface */
CPerson* person_new();
void person_append_record( CPerson* person, gchar* name, gint age );
void person_preappend_record( CPerson* person, gchar* name, gint age );

/*
  *  sort 
  */

enum{

    SORT_PERSON_NONE,
    SORT_PERSON_NAME,
    SORT_PERSON_AGE,
    
};


#endif/* person.h*/

person.c
#include "model.h"
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
        static void person_init( CPerson* person) { PERSON_PRINT_SELF(); person->col_n = PERSON_COL_ALL; person->col_type[PERSON_COL_RECORD] = G_TYPE_POINTER; person->col_type[PERSON_COL_NAME] = G_TYPE_STRING; person->col_type[PERSON_COL_AGE] = G_TYPE_INT; person->row = NULL; person->row_n = 0; person->sort_id = 0; person->type = 0; person->stamp = g_random_int(); } static void class_init(CPersonClass* klass) { GObjectClass* obj_class = G_OBJECT_CLASS(klass); } static GtkTreeModelFlags _get_flags(GtkTreeModel* tree_model) { g_return_val_if_fail( IS_PERSON(tree_model), (GtkTreeModelFlags)0 ); return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY; } static gint _get_n_columns( GtkTreeModel* tree_model) { g_return_val_if_fail( IS_PERSON(tree_model), 0); g_print("%s num=%d/n", __FUNCTION__, PERSON(tree_model)->col_n); return PERSON(tree_model)->col_n; } static GType _get_column_type(GtkTreeModel* tree_model, gint index) { g_return_val_if_fail( IS_PERSON(tree_model), 0); g_return_val_if_fail( index < PERSON(tree_model)->col_n && index >=0, 0); g_print("%s %dth type=%d/n", __FUNCTION__,index, PERSON(tree_model)->col_type[index]); return PERSON(tree_model)->col_type[index]; } gboolean _get_iter(GtkTreeModel* tree_model, GtkTreeIter* iter, GtkTreePath* path) { CPerson* pm =0; gint * indice = 0, depth = 0; gint n = 0; PersonNode* node; g_assert(IS_PERSON(tree_model)); g_assert(path!=NULL); pm = PERSON(tree_model); indice = gtk_tree_path_get_indices(path); depth = gtk_tree_path_get_depth(path); g_assert(depth==1); n = indice[0]; if( n >= PERSON(tree_model)->row_n || n < 0) return FALSE; node = (PersonNode*)g_list_nth_data(PERSON(tree_model)->row, n); g_assert(node); iter->stamp = pm->stamp; iter->user_data = node; iter->user_data2 = NULL; iter->user_data3 = NULL; return TRUE; } static GtkTreePath* _get_path(GtkTreeModel* tree_model, GtkTreeIter* iter) { GtkTreePath* path = 0; PersonNode* node = 0; CPerson* pm = 0; g_return_val_if_fail( IS_PERSON(tree_model), NULL); g_return_val_if_fail( iter, NULL); g_return_val_if_fail( iter->user_data, NULL); pm = PERSON(tree_model); node = (PersonNode*)iter->user_data; path = gtk_tree_path_new(); gtk_tree_path_append_index(path, g_list_index(pm->row, node) ); return path; } static void _get_value(GtkTreeModel* model, GtkTreeIter* iter, gint column, GValue* value) { CPerson* pm; PersonNode* node; g_return_if_fail( IS_PERSON(model)); g_return_if_fail( iter); g_return_if_fail(column< PERSON(model)->col_n && column >=0); g_value_init(value, PERSON(model)->col_type[column]); node = (PersonNode*) iter->user_data; switch(column) { case PERSON_COL_NAME: g_value_set_string(value, node->name); break; case PERSON_COL_AGE: g_value_set_int(value, node->age); break; default: break; } PERSON_PRINT_SELF(); } static gboolean _iter_next(GtkTreeModel* model, GtkTreeIter* iter) { CPerson* pm; PersonNode* node, *next; g_return_val_if_fail( IS_PERSON(model), FALSE); g_return_val_if_fail( iter&&iter->user_data, FALSE); pm = PERSON(model); node = (PersonNode*) iter->user_data; next = (PersonNode*)g_list_nth_data(pm->row, g_list_index(pm->row, node)+1); g_print("free iter %d/n", g_list_index(pm->row, node)); if(!next) return FALSE; iter->stamp = pm->stamp; iter->user_data = next; return TRUE; } static gboolean _iter_children(GtkTreeModel* model, GtkTreeIter* iter, GtkTreeIter* parent) { CPerson* pm; g_return_val_if_fail( IS_PERSON(model), FALSE); g_return_val_if_fail( !parent, FALSE); pm = PERSON(model); if( pm->row_n == 0) return FALSE; iter->stamp = pm->stamp; iter->user_data = g_list_nth_data(pm->row, 0); PERSON_PRINT_SELF(); return TRUE; } static gboolean _iter_has_child(GtkTreeModel* model, GtkTreeIter* iter) { PERSON_PRINT_SELF(); return FALSE; } static gboolean _iter_n_child(GtkTreeModel* model, GtkTreeIter* iter) { CPerson* pm; PERSON_PRINT_SELF(); g_return_val_if_fail( IS_PERSON(model), FALSE); g_return_val_if_fail( iter==NULL || iter->user_data!=NULL, FALSE); pm = PERSON(model); if(!iter) return pm->row_n; return FALSE; } static gboolean _iter_nth_child(GtkTreeModel* model, GtkTreeIter* iter, GtkTreeIter* parent, gint n) { CPerson* pm; PersonNode* node = 0; PERSON_PRINT_SELF(); g_return_val_if_fail( IS_PERSON(model), FALSE); g_return_val_if_fail(!parent, FALSE); pm = PERSON(model); if( n >= pm->row_n ) return FALSE; g_print("%d/n", n); node = g_list_nth_data(pm->row, n); iter->stamp = pm->stamp; iter->user_data = node; return TRUE; } static gboolean _iter_parent(GtkTreeModel* model, GtkTreeIter* iter, GtkTreeIter* child) { return FALSE; } static void interface_init(GtkTreeModelIface* iface) { iface->get_flags = _get_flags; iface->get_n_columns = _get_n_columns; iface->get_column_type = _get_column_type; iface->get_iter = _get_iter; iface->get_path= _get_path; iface->get_value = _get_value; iface->iter_next = _iter_next; iface->iter_children = _iter_children; iface->iter_has_child = _iter_has_child; iface->iter_n_children = _iter_n_child; iface->iter_nth_child = _iter_nth_child; iface->iter_parent = _iter_parent; iface->ref_node = NULL; iface->unref_node = NULL; PERSON_PRINT_SELF(); } static void sort_interface_init( GtkTreeSortableIface* iface); GType person_get_type(void) { static GType person_type = 0; if(!person_type){ GTypeInfo info = { sizeof(CPersonClass), /* base init&finalize*/ NULL, NULL, /*Class init & finalize*/ (GClassInitFunc)class_init, NULL, NULL, sizeof(CPerson), 0, (GInstanceInitFunc)person_init }; person_type = g_type_register_static( G_TYPE_OBJECT, "person", &info, 0); if(1) { static const GInterfaceInfo iface_info = { (GInterfaceInitFunc)interface_init, NULL, NULL}; g_type_add_interface_static( person_type, GTK_TYPE_TREE_MODEL, &iface_info); } if(1) { static const GInterfaceInfo sort_iface_info = { (GInterfaceInitFunc)sort_interface_init, NULL, NULL}; g_type_add_interface_static( person_type, GTK_TYPE_TREE_SORTABLE, &sort_iface_info); } } return person_type; } /* sort interface */ static void person_model_resort(CPerson* model); static void _set_sort_column_id( GtkTreeSortable* sortable, gint sort_column_id, GtkSortType order) { CPerson* item = 0; PERSON_PRINT_SELF() g_return_if_fail(sortable); g_return_if_fail(IS_PERSON(sortable)); item = PERSON(sortable); if( item->sort_id==sort_column_id && item->type==order) return; item->sort_id = sort_column_id; item->type = order; person_model_resort(PERSON(sortable)); gtk_tree_sortable_sort_column_changed(sortable); } static gboolean _get_sort_column_id( GtkTreeSortable* sortable, gint* sort_column_id, GtkSortType* order) { CPerson* item = 0; PERSON_PRINT_SELF() g_return_val_if_fail(sortable, FALSE); g_return_val_if_fail(IS_PERSON(sortable), FALSE); item = PERSON(sortable); if(sort_column_id) *sort_column_id = item->sort_id; if(order) *order = item->type; return TRUE; } static void _set_sort_func(GtkTreeSortable* sortable, gint sort_column_id, GtkTreeIterCompareFunc func, gpointer data, GtkDestroyNotify destroy ) { PERSON_PRINT_SELF() return; } static void _set_default_sort_func(GtkTreeSortable* sortable, GtkTreeIterCompareFunc func, gpointer data, GtkDestroyNotify destroy ) { PERSON_PRINT_SELF() return; } static gboolean _has_default_sort_func(GtkTreeSortable* sortable) { PERSON_PRINT_SELF() return FALSE; } static void sort_interface_init( GtkTreeSortableIface* iface) { PERSON_PRINT_SELF(); iface->get_sort_column_id = _get_sort_column_id; iface->set_sort_column_id = _set_sort_column_id; iface->set_sort_func = _set_sort_func; iface->set_default_sort_func = _set_default_sort_func; iface->has_default_sort_func = _has_default_sort_func; } CPerson* person_new() { CPerson* person = 0; //if used the gtype system, we'd call this API for init. //g_type_init(); person = g_object_new(PERSON_TYPE, NULL); return person; } void person_append_record( CPerson* person, gchar* name, gint age ) { GtkTreeModel* model; GtkTreePath* path; GtkTreeIter iter; PersonNode *new1; g_return_if_fail( person); g_return_if_fail(name); new1= g_new0(PersonNode, 1); new1->name = g_strdup(name); new1->age = age; person->row = g_list_append(person->row, new1); person->row_n++; path = gtk_tree_path_new(); gtk_tree_path_append_index(path, g_list_index(person->row, new1) ); _get_iter(GTK_TREE_MODEL(person), &iter, path); gtk_tree_model_row_inserted(GTK_TREE_MODEL(person), path, &iter); gtk_tree_path_free(path); } void person_preappend_record( CPerson* person, gchar* name, gint age ) { GtkTreeModel* model; GtkTreePath* path; GtkTreeIter iter; PersonNode *new1; g_return_if_fail( person); g_return_if_fail(name); person->row_n++; new1= g_new0(PersonNode, 1); new1->name = g_strdup(name); new1->age = age; person->row = g_list_prepend(person->row, new1); path = gtk_tree_path_new(); gtk_tree_path_append_index(path, 0); _get_iter(GTK_TREE_MODEL(person), &iter, path); gtk_tree_model_row_inserted(GTK_TREE_MODEL(person), path, &iter); gtk_tree_path_free(path); } static gint person_record_compare(gint sort_id, PersonNode* a, PersonNode* b) { switch(sort_id) { case SORT_PERSON_NONE: return 0; case SORT_PERSON_AGE: if(a->age == b->age) return 0; if(a->age > b->age) return 1; return -1; case SORT_PERSON_NAME: return g_utf8_collate(a->name, b->name); default: break; } return 0; } static gint person_qsort_compare_func(gpointer a, gpointer b, CPerson* list) { gint ret = 0; g_assert( a&&b&&list); ret = person_record_compare(list->sort_id, (PersonNode*)a, (PersonNode*)b); if(ret!=0 && list->type==GTK_SORT_DESCENDING) ret = ret>0?-1:1; return ret; } static void person_model_resort(CPerson* model) { GList* list_addr = 0, *temp = 0; gint* new = 0, i = 0; GtkTreePath *path = 0; GtkTreeIter iter ; g_return_if_fail(model); g_return_if_fail(IS_PERSON(model)); PERSON_PRINT_SELF() if(model->sort_id==0) return; if(model->row_n==0) return; list_addr = g_list_copy(model->row); new = g_new0(gint, g_list_length(model->row)); model->row = g_list_sort_with_data(model->row, (GCompareDataFunc)person_qsort_compare_func, model); temp = model->row; while(list_addr) { new[i++] = g_list_index(model->row, list_addr->data); list_addr = g_list_next(list_addr); } g_list_free(list_addr); gint k = 0; path = gtk_tree_path_new(); gtk_tree_model_rows_reordered(GTK_TREE_MODEL(model), path, NULL, new); gtk_tree_path_free(path); g_free(new); } main.c #include 
       
         #include 
        
          #include 
         
           #include "callback.h" #include "model.h" struct _GWindow { GtkWidget* window; GtkWidget* main_image; GtkWidget* sub_image; GtkWidget* button_start; GtkWidget* button_stop; GtkWidget* tree; }; typedef struct _GWindow GWindow; void lookup_widget(GladeXML* xml, GWindow* all) { all->window = glade_xml_get_widget(xml, "g_window"); g_assert(all->window!=NULL); all->main_image = glade_xml_get_widget(xml, "g_main_image"); g_assert(all->main_image!=NULL); all->sub_image= glade_xml_get_widget(xml, "g_sub_image"); g_assert(all->sub_image!=NULL); all->button_start= glade_xml_get_widget(xml, "button_start"); g_assert(all->button_start!=NULL); all->button_stop= glade_xml_get_widget(xml, "button_stop"); g_assert(all->button_stop!=NULL); all->tree= glade_xml_get_widget(xml, "treeview"); g_assert(all->tree!=NULL); } gboolean timeout(gpointer data) { gtk_widget_queue_draw(GTK_WIDGET(((GWindow*)(data))->main_image)); } void append_data(CPerson * person) { person_append_record(person, "first", 12 ); person_append_record(person, "second", 14 ); } void set_mode(GtkWidget* view) { CPerson* person; GtkTreeViewColumn* col; GtkCellRenderer* render; person = person_new(); append_data(person); gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(person)); render = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new(); gtk_tree_view_column_pack_start (col, render, TRUE); gtk_tree_view_column_add_attribute (col, render, "text", PERSON_COL_NAME); gtk_tree_view_column_set_title (col, "Name"); gtk_tree_view_append_column(GTK_TREE_VIEW(view),col); render = gtk_cell_renderer_text_new(); col = gtk_tree_view_column_new(); gtk_tree_view_column_pack_start (col, render, TRUE); gtk_tree_view_column_add_attribute (col, render, "text", PERSON_COL_AGE); gtk_tree_view_column_set_title (col, "age"); gtk_tree_view_append_column(GTK_TREE_VIEW(view),col); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(person), 2, 0); } gboolean listview_add(gpointer data) { GtkWidget* tree = GTK_WIDGET(data); static gint i = 100; static gint sort[] = {0, 1}; person_preappend_record( PERSON( gtk_tree_view_get_model(tree)), "add", i++); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(tree)), 1, 0); return TRUE; } gint main(gint argc, gchar* argv[]) { GladeXML* xml=0; GWindow window; gint x, y; gtk_init(&argc, &argv); xml = glade_xml_new("rsc/g.glade",NULL,NULL); g_assert(xml!=NULL); glade_xml_signal_autoconnect(xml); lookup_widget(xml, &window); set_mode(window.tree); g_signal_connect (G_OBJECT (window.window), "delete_event", GTK_SIGNAL_FUNC (gtk_main_quit), NULL); g_timeout_add(3000, listview_add, window.tree); gtk_main(); } 
          
 
          
         
        
      
     
     
    
    
   
   
  
  
 
 
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值