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();
}
发表于 @ 2008年07月24日 14:16:00|评论(loading...)|收藏