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();}