From 1a038d63a03504de4587bc001367e206fbe4df64 Mon Sep 17 00:00:00 2001 From: Christopher James Lahey Date: Sun, 12 Mar 2000 15:32:47 +0000 Subject: Added e-text-test. 2000-03-12 Christopher James Lahey * widgets/e-text/.cvsignore: Added e-text-test. * addressbook/demo/e-test-model.c, addressbook/demo/e-test-model.h: A model storing data in an array of Address objects. * addressbook/demo/demo.c: Changed to use addressbook/demo/e-test-model.c and addressbook/demo/e-test-model.h. * addressbook/demo/Makefile.am: Added e-test-model.c and e-test-model.h. svn path=/trunk/; revision=2104 --- addressbook/demo/Makefile.am | 4 +- addressbook/demo/demo.c | 609 +++++++++++++++------------------------- addressbook/demo/e-test-model.c | 297 ++++++++++++++++++++ addressbook/demo/e-test-model.h | 64 +++++ 4 files changed, 597 insertions(+), 377 deletions(-) create mode 100644 addressbook/demo/e-test-model.c create mode 100644 addressbook/demo/e-test-model.h (limited to 'addressbook/demo') diff --git a/addressbook/demo/Makefile.am b/addressbook/demo/Makefile.am index 728f66d201..27b438549c 100644 --- a/addressbook/demo/Makefile.am +++ b/addressbook/demo/Makefile.am @@ -11,7 +11,9 @@ noinst_PROGRAMS = \ evolution-addressbook evolution_addressbook_SOURCES = \ - demo.c + demo.c \ + e-test-model.c \ + e-test-model.h evolution_addressbook_LDADD = \ $(EXTRA_GNOME_LIBS) \ diff --git a/addressbook/demo/demo.c b/addressbook/demo/demo.c index 4a45b50870..34b1f6f2c7 100644 --- a/addressbook/demo/demo.c +++ b/addressbook/demo/demo.c @@ -21,6 +21,8 @@ #include "table-test.h" +#include "e-test-model.h" + #define COLS 4 /* Here we define the initial layout of the table. This is an xml @@ -47,302 +49,128 @@ char *headers[COLS] = { "Phone" }; -typedef struct _address address; -typedef enum _rows rows; +typedef struct _View View; -struct _address { - gchar *email; - gchar *full_name; - gchar *street; - gchar *phone; -}; +typedef enum { + VIEW_TYPE_REFLOW, + VIEW_TYPE_TABLE +} ViewType; -enum _rows { - EMAIL, - FULL_NAME, - STREET, - PHONE, - LAST_COL -}; +typedef struct { + GtkAllocation last_alloc; + GnomeCanvasItem *reflow; + GtkWidget *canvas; + GnomeCanvasItem *rect; + int model_changed_id; +} Reflow; -/* Virtual Column list: - 0 Email - 1 Full Name - 2 Street - 3 Phone -*/ +struct _View { + ETestModel *model; + GtkWidget *window; + GtkWidget *frame; + GtkWidget *child; + ViewType type; + Reflow *reflow; +}; -static address **data; -static int data_count; -static ETableModel *e_table_model = NULL; -static GtkWidget *e_table; static int window_count = 0; +static GHashTable *models = NULL; -/* - * ETableSimple callbacks - * These are the callbacks that define the behavior of our custom model. - */ - -/* Since our model is a constant size, we can just return its size in - the column and row count fields. */ - -/* This function returns the number of columns in our ETableModel. */ -static int -my_col_count (ETableModel *etc, void *data) -{ - return COLS; -} - -/* This function returns the number of rows in our ETableModel. */ -static int -my_row_count (ETableModel *etc, void *data) -{ - return data_count; -} - -/* This function returns the value at a particular point in our ETableModel. */ -static void * -my_value_at (ETableModel *etc, int col, int row, void *unused) -{ - if ( col >= LAST_COL || row >= data_count ) - return NULL; - switch (col) { - case EMAIL: - return data[row]->email; - case FULL_NAME: - return data[row]->full_name; - case STREET: - return data[row]->street; - case PHONE: - return data[row]->phone; - default: - return NULL; - } -} - -/* This function sets the value at a particular point in our ETableModel. */ static void -my_set_value_at (ETableModel *etc, int col, int row, const void *val, void *unused) +remove_model(ETableModel *model, gchar *filename) { - if ( col >= LAST_COL || row >= data_count ) - return; - switch (col) { - case EMAIL: - g_free (data[row]->email); - data[row]->email = g_strdup (val); - break; - case FULL_NAME: - g_free (data[row]->full_name); - data[row]->full_name = g_strdup (val); - break; - case STREET: - g_free (data[row]->street); - data[row]->street = g_strdup (val); - break; - case PHONE: - g_free (data[row]->phone); - data[row]->phone = g_strdup (val); - break; - default: - return; - } + g_hash_table_remove(models, filename); + g_free(filename); } -/* This function returns whether a particular cell is editable. */ -static gboolean -my_is_cell_editable (ETableModel *etc, int col, int row, void *data) +static ETestModel * +get_model(char *filename) { - return TRUE; -} - -/* This function duplicates the value passed to it. */ -static void * -my_duplicate_value (ETableModel *etc, int col, const void *value, void *data) -{ - return g_strdup(value); -} - -/* This function frees the value passed to it. */ -static void -my_free_value (ETableModel *etc, int col, void *value, void *data) -{ - g_free(value); -} - -/* This function is for when the model is unfrozen. This can mostly - be ignored for simple models. */ -static void -my_thaw (ETableModel *etc, void *data) -{ -} - -static int idle; - -static gboolean -save(gpointer unused) -{ - int i; - xmlDoc *document = xmlNewDoc("1.0"); - xmlNode *root; - root = xmlNewDocNode(document, NULL, "address-book", NULL); - xmlDocSetRootElement(document, root); - for ( i = 0; i < data_count; i++ ) { - xmlNode *xml_address = xmlNewChild(root, NULL, "address", NULL); - if ( data[i]->email && *data[i]->email ) - xmlSetProp(xml_address, "email", data[i]->email); - if ( data[i]->email && *data[i]->street ) - xmlSetProp(xml_address, "street", data[i]->street); - if ( data[i]->email && *data[i]->full_name ) - xmlSetProp(xml_address, "full-name", data[i]->full_name); - if ( data[i]->email && *data[i]->phone ) - xmlSetProp(xml_address, "phone", data[i]->phone); + ETestModel *model; + if ( models == NULL ) { + models = g_hash_table_new(g_str_hash, g_str_equal); } - xmlSaveFile ("addressbook.xml", document); - idle = 0; - /* e_table_save_specification(E_TABLE(e_table), "spec"); */ - return FALSE; -} - -static void -queue_save() -{ - if ( !idle ) - idle = g_idle_add(save, NULL); -} - -static void -add_column (ETableModel *etc, address *newadd) -{ - data = g_realloc(data, (++data_count) * sizeof(address *)); - data[data_count - 1] = newadd; - queue_save(); - if ( etc ) - e_table_model_changed(etc); -} + model = g_hash_table_lookup(models, filename); + if ( model ) + return model; -static void -init_data() -{ - data = NULL; - data_count = 0; -} - -static void -create_model() -{ - xmlDoc *document; - xmlNode *xml_addressbook; - xmlNode *xml_address; - - /* First we fill in the simple data. */ - init_data(); - if ( g_file_exists("addressbook.xml") ) { - document = xmlParseFile("addressbook.xml"); - xml_addressbook = xmlDocGetRootElement(document); - for (xml_address = xml_addressbook->childs; xml_address; xml_address = xml_address->next) { - char *datum; - address *newadd; - - newadd = g_new(address, 1); - - datum = xmlGetProp(xml_address, "email"); - if ( datum ) { - newadd->email = g_strdup(datum); - xmlFree(datum); - } else - newadd->email = g_strdup(""); - - datum = xmlGetProp(xml_address, "street"); - if ( datum ) { - newadd->street = g_strdup(datum); - xmlFree(datum); - } else - newadd->street = g_strdup(""); - - datum = xmlGetProp(xml_address, "full-name"); - if ( datum ) { - newadd->full_name = g_strdup(datum); - xmlFree(datum); - } else - newadd->full_name = g_strdup(""); - - datum = xmlGetProp(xml_address, "phone"); - if ( datum ) { - newadd->phone = g_strdup(datum); - xmlFree(datum); - } else - newadd->phone = g_strdup(""); - add_column (NULL, newadd); - } - xmlFreeDoc(document); - } - - - e_table_model = e_table_simple_new ( - my_col_count, my_row_count, my_value_at, - my_set_value_at, my_is_cell_editable, - my_duplicate_value, my_free_value, my_thaw, NULL); + filename = g_strdup(filename); - gtk_signal_connect(GTK_OBJECT(e_table_model), "model_changed", - GTK_SIGNAL_FUNC(queue_save), NULL); - gtk_signal_connect(GTK_OBJECT(e_table_model), "model_row_changed", - GTK_SIGNAL_FUNC(queue_save), NULL); - gtk_signal_connect(GTK_OBJECT(e_table_model), "model_cell_changed", - GTK_SIGNAL_FUNC(queue_save), NULL); + model = E_TEST_MODEL(e_test_model_new(filename)); + g_hash_table_insert(models, + filename, model); + gtk_signal_connect(GTK_OBJECT(model), "destroy", + GTK_SIGNAL_FUNC(remove_model), filename); + return model; } static void add_address_cb(GtkWidget *button, gpointer data) { - address *newadd = g_new(address, 1); + View *view = (View *) data; + Address *newadd = g_new(Address, 1); newadd->email = g_strdup(""); newadd->phone = g_strdup(""); newadd->full_name = g_strdup(""); newadd->street = g_strdup(""); - add_column (e_table_model, newadd); + e_test_model_add_column (view->model, newadd); } -typedef struct { - GtkAllocation last_alloc; - GnomeCanvasItem *reflow; - GtkWidget *canvas; - GnomeCanvasItem *rect; -} reflow_demo; - static void rebuild_reflow(ETableModel *model, gpointer data) { int i; - reflow_demo *demo = (reflow_demo *)data; - gtk_object_destroy(GTK_OBJECT(demo->reflow)); - demo->reflow = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( demo->canvas ) ), + View *view = (View *) data; + Reflow *reflow = view->reflow; + if (!reflow) + return; + gtk_object_destroy(GTK_OBJECT(reflow->reflow)); + reflow->reflow = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( reflow->canvas ) ), e_reflow_get_type(), "x", (double) 0, "y", (double) 0, - "height", (double) 100, - "minimum_width", (double) 100, + "height", (double) reflow->last_alloc.height, + "minimum_width", (double) reflow->last_alloc.width, NULL ); - for ( i = 0; i < data_count; i++ ) + for ( i = 0; i < view->model->data_count; i++ ) { GnomeCanvasItem *item; - item = gnome_canvas_item_new( GNOME_CANVAS_GROUP(demo->reflow), + item = gnome_canvas_item_new( GNOME_CANVAS_GROUP(reflow->reflow), e_minicard_get_type(), - "model", e_table_model, + "model", view->model, "row", i, NULL); - e_reflow_add_item(E_REFLOW(demo->reflow), item); + e_reflow_add_item(E_REFLOW(reflow->reflow), item); } - e_canvas_item_request_reflow(demo->reflow); + e_canvas_item_request_reflow(reflow->reflow); +} + +static void +destroy_reflow(View *view) +{ + Reflow *reflow = view->reflow; + if ( !reflow ) + return; + + gtk_signal_disconnect(GTK_OBJECT(view->model), + reflow->model_changed_id); + g_free(reflow); + gtk_object_unref(GTK_OBJECT(view->model)); + view->reflow = NULL; } static void destroy_callback(GtkWidget *app, gpointer data) { - reflow_demo *demo = (reflow_demo *)data; - g_free(demo); + View *view = (View *)data; + if ( view->reflow ) { + destroy_reflow(view); + } + gtk_object_unref(GTK_OBJECT(view->model)); + g_free(view); window_count --; if ( window_count <= 0 ) exit(0); @@ -350,69 +178,64 @@ static void destroy_callback(GtkWidget *app, gpointer data) static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) { - double width; - reflow_demo *demo = (reflow_demo *)data; - demo->last_alloc = *allocation; - gnome_canvas_item_set( demo->reflow, - "height", (double) allocation->height, - NULL ); - gnome_canvas_item_set( demo->reflow, - "minimum_width", (double) allocation->width, - NULL ); - gtk_object_get(GTK_OBJECT(demo->reflow), - "width", &width, - NULL); - width = MAX(width, allocation->width); - gnome_canvas_set_scroll_region(GNOME_CANVAS( demo->canvas ), 0, 0, width, allocation->height ); - gnome_canvas_item_set( demo->rect, - "x2", (double) width, - "y2", (double) allocation->height, - NULL ); + double width; + View *view = (View *)data; + Reflow *reflow = view->reflow; + if ( !reflow ) + return; + reflow->last_alloc = *allocation; + gnome_canvas_item_set( reflow->reflow, + "height", (double) allocation->height, + NULL ); + gnome_canvas_item_set( reflow->reflow, + "minimum_width", (double) allocation->width, + NULL ); + gtk_object_get(GTK_OBJECT(reflow->reflow), + "width", &width, + NULL); + width = MAX(width, allocation->width); + gnome_canvas_set_scroll_region(GNOME_CANVAS( reflow->canvas ), 0, 0, width, allocation->height ); + gnome_canvas_item_set( reflow->rect, + "x2", (double) width, + "y2", (double) allocation->height, + NULL ); } static void resize(ECanvas *canvas, gpointer data) { double width; - reflow_demo *demo = (reflow_demo *)data; - gtk_object_get(GTK_OBJECT(demo->reflow), + View *view = (View *)data; + Reflow *reflow = view->reflow; + if ( !reflow ) + return; + gtk_object_get(GTK_OBJECT(reflow->reflow), "width", &width, NULL); - width = MAX(width, demo->last_alloc.width); - gnome_canvas_set_scroll_region(GNOME_CANVAS(demo->canvas), 0, 0, width, demo->last_alloc.height ); - gnome_canvas_item_set( demo->rect, + width = MAX(width, reflow->last_alloc.width); + gnome_canvas_set_scroll_region(GNOME_CANVAS(reflow->canvas), 0, 0, width, reflow->last_alloc.height ); + gnome_canvas_item_set( reflow->rect, "x2", (double) width, - "y2", (double) demo->last_alloc.height, + "y2", (double) reflow->last_alloc.height, NULL ); } -static void -create_reflow() +static GtkWidget * +create_reflow(View *view) { - GtkWidget *window, *frame; - GtkWidget *button; - GtkWidget *vbox; GtkWidget *inner_vbox; GtkWidget *scrollbar; int i; - reflow_demo *demo = g_new(reflow_demo, 1); + Reflow *reflow = g_new(Reflow, 1); + view->reflow = reflow; + + view->type = VIEW_TYPE_REFLOW; /* Next we create our model. This uses the functions we defined earlier. */ - if ( e_table_model == NULL ) - create_model(); - /* Here we create a window for our new table. This window - will get shown and the person will be able to test their - item. */ - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - /* This frame is simply to get a bevel around our table. */ - frame = gtk_frame_new (NULL); - /* Here we create the table. We give it the three pieces of - the table we've created, the header, the model, and the - initial layout. It does the rest. */ inner_vbox = gtk_vbox_new(FALSE, 0); - demo->canvas = e_canvas_new(); - demo->rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( demo->canvas ) ), + reflow->canvas = e_canvas_new(); + reflow->rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( reflow->canvas ) ), gnome_canvas_rect_get_type(), "x1", (double) 0, "y1", (double) 0, @@ -420,90 +243,63 @@ create_reflow() "y2", (double) 100, "fill_color", "white", NULL ); - demo->reflow = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( demo->canvas ) ), + reflow->reflow = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( reflow->canvas ) ), e_reflow_get_type(), "x", (double) 0, "y", (double) 0, "height", (double) 100, "minimum_width", (double) 100, NULL ); - - gtk_signal_connect( GTK_OBJECT( demo->canvas ), "reflow", + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( reflow->canvas ), "reflow", GTK_SIGNAL_FUNC( resize ), - ( gpointer ) demo); + ( gpointer ) view); - for ( i = 0; i < data_count; i++ ) + for ( i = 0; i < view->model->data_count; i++ ) { GnomeCanvasItem *item; - item = gnome_canvas_item_new( GNOME_CANVAS_GROUP(demo->reflow), + item = gnome_canvas_item_new( GNOME_CANVAS_GROUP(reflow->reflow), e_minicard_get_type(), - "model", e_table_model, + "model", view->model, "row", i, NULL); - e_reflow_add_item(E_REFLOW(demo->reflow), item); + e_reflow_add_item(E_REFLOW(reflow->reflow), item); } - gnome_canvas_set_scroll_region ( GNOME_CANVAS( demo->canvas ), + gnome_canvas_set_scroll_region ( GNOME_CANVAS( reflow->canvas ), 0, 0, 100, 100 ); - scrollbar = gtk_hscrollbar_new(gtk_layout_get_hadjustment(GTK_LAYOUT(demo->canvas))); - - /* Connect the signals */ - gtk_signal_connect( GTK_OBJECT( window ), "destroy", - GTK_SIGNAL_FUNC( destroy_callback ), - ( gpointer ) demo ); + scrollbar = gtk_hscrollbar_new(gtk_layout_get_hadjustment(GTK_LAYOUT(reflow->canvas))); - gtk_signal_connect( GTK_OBJECT( demo->canvas ), "size_allocate", + gtk_signal_connect( GTK_OBJECT( reflow->canvas ), "size_allocate", GTK_SIGNAL_FUNC( allocate_callback ), - ( gpointer ) demo ); + ( gpointer ) view ); - gdk_window_set_back_pixmap( GTK_LAYOUT(demo->canvas)->bin_window, NULL, FALSE); + gdk_window_set_back_pixmap( GTK_LAYOUT(reflow->canvas)->bin_window, NULL, FALSE); - vbox = gtk_vbox_new(FALSE, 0); - - button = gtk_button_new_with_label("Add address"); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(add_address_cb), demo); + reflow->model_changed_id = gtk_signal_connect(GTK_OBJECT( view->model ), "model_changed", + GTK_SIGNAL_FUNC(rebuild_reflow), view); - gtk_signal_connect(GTK_OBJECT( e_table_model), "model_changed", - GTK_SIGNAL_FUNC(rebuild_reflow), demo); + gtk_object_ref(GTK_OBJECT(view->model)); /* Build the gtk widget hierarchy. */ - gtk_box_pack_start(GTK_BOX(inner_vbox), demo->canvas, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(inner_vbox), reflow->canvas, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(inner_vbox), scrollbar, FALSE, FALSE, 0); - gtk_container_add (GTK_CONTAINER (frame), inner_vbox); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), vbox); - /* Size the initial window. */ - gtk_widget_set_usize (window, 200, 200); - /* Show it all. */ - gtk_widget_show_all (window); - window_count ++; -} - -static void e_table_destroy_callback(GtkWidget *app, gpointer data) -{ - window_count --; - if ( window_count <= 0 ) - exit(0); + return inner_vbox; } /* We create a window containing our new table. */ -static void -create_table() +static GtkWidget * +create_table(View *view) { - GtkWidget *window, *frame; ECell *cell_left_just; ETableHeader *e_table_header; - GtkWidget *button; - GtkWidget *vbox; + GtkWidget *e_table; int i; - /* Next we create our model. This uses the functions we defined - earlier. */ - if ( e_table_model == NULL ) - create_model(); + + view->type = VIEW_TYPE_TABLE; + /* Next we create a header. The ETableHeader is used in two different way. The first is the full_header. This is the @@ -520,12 +316,12 @@ create_table() the same renderer over and over again. If we had different types of columns, we could use a different renderer for each column. */ - cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT, TRUE); + cell_left_just = e_cell_text_new (E_TABLE_MODEL(view->model), NULL, GTK_JUSTIFY_LEFT, TRUE); /* Next we create a column object for each view column and add them to the header. We don't create a column object for the importance column since it will not be shown. */ - for (i = 0; i < COLS; i++){ + for (i = 0; i < LAST_COL; i++){ /* Create the column. */ ETableCol *ecol = e_table_col_new ( i, headers [i], @@ -535,46 +331,112 @@ create_table() e_table_header_add_column (e_table_header, ecol, i); } - /* Here we create a window for our new table. This window - will get shown and the person will be able to test their - item. */ - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - /* This frame is simply to get a bevel around our table. */ - frame = gtk_frame_new (NULL); /* Here we create the table. We give it the three pieces of the table we've created, the header, the model, and the initial layout. It does the rest. */ - e_table = e_table_new_from_spec_file (e_table_header, e_table_model, "spec"); + e_table = e_table_new_from_spec_file (e_table_header, E_TABLE_MODEL(view->model), "spec"); +#if 0 gtk_signal_connect(GTK_OBJECT(E_TABLE(e_table)->sort_info), "sort_info_changed", - GTK_SIGNAL_FUNC(queue_save), NULL); + GTK_SIGNAL_FUNC(queue_header_save), e_table->sort_info); gtk_signal_connect(GTK_OBJECT(E_TABLE(e_table)->header), "structure_change", - GTK_SIGNAL_FUNC(queue_save), NULL); + GTK_SIGNAL_FUNC(queue_header_save), e_table->sort_info); gtk_signal_connect(GTK_OBJECT(E_TABLE(e_table)->header), "dimension_change", - GTK_SIGNAL_FUNC(queue_save), NULL); + GTK_SIGNAL_FUNC(queue_header_save), e_table->sort_info); +#endif + + return e_table; +} + +static void +change_type(View *view, ViewType type) +{ + gtk_object_ref(GTK_OBJECT(view->model)); + if (view->reflow) + destroy_reflow(view); + gtk_widget_destroy(view->child); + switch(type) { + case VIEW_TYPE_REFLOW: + view->child = create_reflow(view); + break; + case VIEW_TYPE_TABLE: + view->child = create_table(view); + break; + } + gtk_container_add(GTK_CONTAINER(view->frame), view->child); + gtk_widget_show_all(view->child); + gtk_object_unref(GTK_OBJECT(view->model)); +} + +static void +change_callback(GtkWidget *button, View *view) +{ + if (view->type == VIEW_TYPE_REFLOW) + change_type(view, VIEW_TYPE_TABLE); + else + change_type(view, VIEW_TYPE_REFLOW); +} + +static GtkWidget * +create_window(char *filename, ViewType type) +{ + GtkWidget *button; + GtkWidget *change_button; + GtkWidget *vbox; + View *view = g_new(View, 1); + + view->reflow = NULL; + + view->model = get_model(filename); + + /* Here we create a window for our new table. This window + will get shown and the person will be able to test their + item. */ + view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect( GTK_OBJECT( view->window ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + view ); + + /* This frame is simply to get a bevel around our table. */ + view->frame = gtk_frame_new (NULL); + + switch(type) { + case VIEW_TYPE_REFLOW: + view->child = create_reflow(view); + break; + case VIEW_TYPE_TABLE: + view->child = create_table(view); + break; + } - gtk_signal_connect( GTK_OBJECT( window ), "destroy", - GTK_SIGNAL_FUNC( e_table_destroy_callback ), - NULL ); vbox = gtk_vbox_new(FALSE, 0); button = gtk_button_new_with_label("Add address"); gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(add_address_cb), NULL); + GTK_SIGNAL_FUNC(add_address_cb), view); + + change_button = gtk_button_new_with_label("Change View"); + gtk_signal_connect(GTK_OBJECT(change_button), "clicked", + GTK_SIGNAL_FUNC(change_callback), view); /* Build the gtk widget hierarchy. */ - gtk_container_add (GTK_CONTAINER (frame), e_table); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + gtk_container_add (GTK_CONTAINER (view->frame), view->child); + gtk_box_pack_start (GTK_BOX (vbox), view->frame, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_box_pack_start (GTK_BOX (vbox), change_button, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (view->window), vbox); /* Size the initial window. */ - gtk_widget_set_usize (window, 200, 200); + gtk_widget_set_usize (view->window, 200, 200); /* Show it all. */ - gtk_widget_show_all (window); + gtk_widget_show_all (view->window); + gtk_object_sink(GTK_OBJECT(view->model)); window_count ++; + return view->window; } /* This is the main function which just initializes gnome and call our create_table function */ @@ -588,21 +450,16 @@ main (int argc, char *argv []) gtk_widget_push_visual (gdk_rgb_get_visual ()); gtk_widget_push_colormap (gdk_rgb_get_cmap ()); - create_table(); - create_table(); - create_table(); - create_reflow(); - create_reflow(); + create_window("addressbook.xml", VIEW_TYPE_TABLE); + create_window("addressbook.xml", VIEW_TYPE_TABLE); + create_window("addressbook.xml", VIEW_TYPE_TABLE); + create_window("addressbook.xml", VIEW_TYPE_REFLOW); + create_window("addressbook.xml", VIEW_TYPE_REFLOW); + create_window("addressbook2.xml", VIEW_TYPE_TABLE); + create_window("addressbook2.xml", VIEW_TYPE_REFLOW); gtk_main (); e_cursors_shutdown (); return 0; } - - - - - - - diff --git a/addressbook/demo/e-test-model.c b/addressbook/demo/e-test-model.c new file mode 100644 index 0000000000..c218283e48 --- /dev/null +++ b/addressbook/demo/e-test-model.c @@ -0,0 +1,297 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * + * Author: + * Miguel de Icaza (miguel@gnu.org) + * + * (C) 1999 Helix Code, Inc. + */ + +#include +#include "e-test-model.h" +#include +#include +#include +#include + +#define PARENT_TYPE e_table_model_get_type() +/* + * ETestModel callbacks + * These are the callbacks that define the behavior of our custom model. + */ + +static void +test_destroy(GtkObject *object) +{ + ETestModel *model = E_TEST_MODEL(object); + int i; + for ( i = 0; i < model->data_count; i++ ) { + g_free(model->data[i]->email); + g_free(model->data[i]->full_name); + g_free(model->data[i]->street); + g_free(model->data[i]->phone); + g_free(model->data[i]); + } + g_free(model->data); + g_free(model->filename); +} + +/* This function returns the number of columns in our ETableModel. */ +static int +test_col_count (ETableModel *etc) +{ + return LAST_COL; +} + +/* This function returns the number of rows in our ETableModel. */ +static int +test_row_count (ETableModel *etc) +{ + ETestModel *test = E_TEST_MODEL(etc); + return test->data_count; +} + +/* This function returns the value at a particular point in our ETableModel. */ +static void * +test_value_at (ETableModel *etc, int col, int row) +{ + ETestModel *test = E_TEST_MODEL(etc); + if ( col >= LAST_COL || row >= test->data_count ) + return NULL; + switch (col) { + case EMAIL: + return test->data[row]->email; + case FULL_NAME: + return test->data[row]->full_name; + case STREET: + return test->data[row]->street; + case PHONE: + return test->data[row]->phone; + default: + return NULL; + } +} + +/* This function sets the value at a particular point in our ETableModel. */ +static void +test_set_value_at (ETableModel *etc, int col, int row, const void *val) +{ + ETestModel *test = E_TEST_MODEL(etc); + if ( col >= LAST_COL || row >= test->data_count ) + return; + switch (col) { + case EMAIL: + g_free (test->data[row]->email); + test->data[row]->email = g_strdup (val); + break; + case FULL_NAME: + g_free (test->data[row]->full_name); + test->data[row]->full_name = g_strdup (val); + break; + case STREET: + g_free (test->data[row]->street); + test->data[row]->street = g_strdup (val); + break; + case PHONE: + g_free (test->data[row]->phone); + test->data[row]->phone = g_strdup (val); + break; + default: + return; + } + if ( !etc->frozen ) + e_table_model_cell_changed(etc, col, row); +} + +/* This function returns whether a particular cell is editable. */ +static gboolean +test_is_cell_editable (ETableModel *etc, int col, int row) +{ + return TRUE; +} + +/* This function duplicates the value passed to it. */ +static void * +test_duplicate_value (ETableModel *etc, int col, const void *value) +{ + return g_strdup(value); +} + +/* This function frees the value passed to it. */ +static void +test_free_value (ETableModel *etc, int col, void *value) +{ + g_free(value); +} + +/* This function is for when the model is unfrozen. This can mostly + be ignored for simple models. */ +static void +test_thaw (ETableModel *etc) +{ + e_table_model_changed(etc); +} + +static void +e_test_model_class_init (GtkObjectClass *object_class) +{ + ETableModelClass *model_class = (ETableModelClass *) object_class; + + object_class->destroy = test_destroy; + + model_class->column_count = test_col_count; + model_class->row_count = test_row_count; + model_class->value_at = test_value_at; + model_class->set_value_at = test_set_value_at; + model_class->is_cell_editable = test_is_cell_editable; + model_class->duplicate_value = test_duplicate_value; + model_class->free_value = test_free_value; + model_class->thaw = test_thaw; +} + +static void +e_test_model_init (GtkObject *object) +{ + ETestModel *model = E_TEST_MODEL(object); + model->data = NULL; + model->data_count = 0; + model->idle = 0; +} + +GtkType +e_test_model_get_type (void) +{ + static GtkType type = 0; + + if (!type){ + GtkTypeInfo info = { + "ETestModel", + sizeof (ETestModel), + sizeof (ETestModelClass), + (GtkClassInitFunc) e_test_model_class_init, + (GtkObjectInitFunc) e_test_model_init, + NULL, /* reserved 1 */ + NULL, /* reserved 2 */ + (GtkClassInitFunc) NULL + }; + + type = gtk_type_unique (PARENT_TYPE, &info); + } + + return type; +} + +static gboolean +save(gpointer data) +{ + int i; + xmlDoc *document = xmlNewDoc("1.0"); + xmlNode *root; + ETestModel *model = data; + + root = xmlNewDocNode(document, NULL, "address-book", NULL); + xmlDocSetRootElement(document, root); + for ( i = 0; i < model->data_count; i++ ) { + xmlNode *xml_address = xmlNewChild(root, NULL, "address", NULL); + if ( model->data[i]->email && *model->data[i]->email ) + xmlSetProp(xml_address, "email", model->data[i]->email); + if ( model->data[i]->email && *model->data[i]->street ) + xmlSetProp(xml_address, "street", model->data[i]->street); + if ( model->data[i]->email && *model->data[i]->full_name ) + xmlSetProp(xml_address, "full-name", model->data[i]->full_name); + if ( model->data[i]->email && *model->data[i]->phone ) + xmlSetProp(xml_address, "phone", model->data[i]->phone); + } + xmlSaveFile (model->filename, document); + model->idle = 0; + gtk_object_unref(GTK_OBJECT(model)); + /* e_table_save_specification(E_TABLE(e_table), "spec"); */ + return FALSE; +} + +void +e_test_model_queue_save(ETestModel *model) +{ + if ( !model->idle ) { + gtk_object_ref(GTK_OBJECT(model)); + model->idle = g_idle_add(save, model); + } +} + +void +e_test_model_add_column (ETestModel *model, Address *newadd) +{ + model->data = g_realloc(model->data, (++model->data_count) * sizeof(Address *)); + model->data[model->data_count - 1] = newadd; + e_test_model_queue_save(model); + if ( model && !E_TABLE_MODEL(model)->frozen ) + e_table_model_changed(E_TABLE_MODEL(model)); +} + + +ETableModel * +e_test_model_new (gchar *filename) +{ + ETestModel *et; + xmlDoc *document; + xmlNode *xml_addressbook; + xmlNode *xml_address; + + et = gtk_type_new (e_test_model_get_type ()); + + /* First we fill in the simple data. */ + if ( g_file_exists(filename) ) { + e_table_model_freeze(E_TABLE_MODEL(et)); + document = xmlParseFile(filename); + xml_addressbook = xmlDocGetRootElement(document); + for (xml_address = xml_addressbook->childs; xml_address; xml_address = xml_address->next) { + char *datum; + Address *newadd; + + newadd = g_new(Address, 1); + + datum = xmlGetProp(xml_address, "email"); + if ( datum ) { + newadd->email = g_strdup(datum); + xmlFree(datum); + } else + newadd->email = g_strdup(""); + + datum = xmlGetProp(xml_address, "street"); + if ( datum ) { + newadd->street = g_strdup(datum); + xmlFree(datum); + } else + newadd->street = g_strdup(""); + + datum = xmlGetProp(xml_address, "full-name"); + if ( datum ) { + newadd->full_name = g_strdup(datum); + xmlFree(datum); + } else + newadd->full_name = g_strdup(""); + + datum = xmlGetProp(xml_address, "phone"); + if ( datum ) { + newadd->phone = g_strdup(datum); + xmlFree(datum); + } else + newadd->phone = g_strdup(""); + e_test_model_add_column (et, newadd); + } + xmlFreeDoc(document); + e_table_model_thaw(E_TABLE_MODEL(et)); + } + + et->filename = g_strdup(filename); + + + gtk_signal_connect(GTK_OBJECT(et), "model_changed", + GTK_SIGNAL_FUNC(e_test_model_queue_save), NULL); + gtk_signal_connect(GTK_OBJECT(et), "model_row_changed", + GTK_SIGNAL_FUNC(e_test_model_queue_save), NULL); + gtk_signal_connect(GTK_OBJECT(et), "model_cell_changed", + GTK_SIGNAL_FUNC(e_test_model_queue_save), NULL); + + return E_TABLE_MODEL(et); +} diff --git a/addressbook/demo/e-test-model.h b/addressbook/demo/e-test-model.h new file mode 100644 index 0000000000..dd3f8e0fa9 --- /dev/null +++ b/addressbook/demo/e-test-model.h @@ -0,0 +1,64 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +#ifndef _E_TEST_MODEL_H_ +#define _E_TEST_MODEL_H_ + +#include "e-table-model.h" + +#define E_TEST_MODEL_TYPE (e_test_model_get_type ()) +#define E_TEST_MODEL(o) (GTK_CHECK_CAST ((o), E_TEST_MODEL_TYPE, ETestModel)) +#define E_TEST_MODEL_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TEST_MODEL_TYPE, ETestModelClass)) +#define E_IS_TEST_MODEL(o) (GTK_CHECK_TYPE ((o), E_TEST_MODEL_TYPE)) +#define E_IS_TEST_MODEL_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TEST_MODEL_TYPE)) + +/* Virtual Column list: + 0 Email + 1 Full Name + 2 Street + 3 Phone +*/ +typedef struct _Address Address; +typedef enum _Rows Rows; + + +struct _Address { + gchar *email; + gchar *full_name; + gchar *street; + gchar *phone; +}; + +enum _Rows { + EMAIL, + FULL_NAME, + STREET, + PHONE, + LAST_COL +}; + + + +typedef struct { + ETableModel parent; + + Address **data; + int data_count; + + char *filename; + int idle; +} ETestModel; + + +typedef struct { + ETableModelClass parent_class; +} ETestModelClass; + + +GtkType e_test_model_get_type (void); +ETableModel *e_test_model_new (char *filename); + +void e_test_model_queue_save(ETestModel *model); +void e_test_model_add_column (ETestModel *model, Address *newadd); + + +#endif /* _E_TEST_MODEL_H_ */ + -- cgit v1.2.3