From c34819ee2c5d8d4fb536ea469588d8f0ccbf08e0 Mon Sep 17 00:00:00 2001 From: Tom Willemsen Date: Tue, 19 Oct 2010 01:28:46 +0200 Subject: [PATCH] Data Data is gotten from an sqlite3 database New series can be added to the database --- src/Makefile | 5 +- src/c-main-window.c | 87 +++++++++++++++++++++-- src/c-main-window.h | 6 ++ src/c-new-item-dialog.c | 3 +- src/collections.c | 25 +++++++ src/collections.h | 2 + src/data.c | 153 ++++++++++++++++++++++++++++++++++++++++ src/data.h | 11 +++ src/interface.c | 5 +- 9 files changed, 287 insertions(+), 10 deletions(-) create mode 100644 src/collections.h create mode 100644 src/data.c create mode 100644 src/data.h diff --git a/src/Makefile b/src/Makefile index 24b89b6..895314b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -CFLAGS=`pkg-config hildon-1 --cflags --libs` +CFLAGS=`pkg-config hildon-1 sqlite3 --cflags --libs` all: $(CC) -Wall -Wextra -pedantic \ @@ -6,6 +6,7 @@ all: interface.c \ c-main-window.c \ c-new-item-dialog.c \ + data.c \ $(CFLAGS) \ -o collections @@ -13,4 +14,4 @@ all: check-syntax: /scratchbox/login $(CC) -pedantic -Wall -Wextra -fsyntax-only \ `readlink -f $(CHK_SOURCES)` \ - `/scratchbox/login pkg-config hildon-1 --cflags --libs` + `/scratchbox/login pkg-config hildon-1 sqlite3 --cflags --libs` diff --git a/src/c-main-window.c b/src/c-main-window.c index 79c47c6..2afc87b 100644 --- a/src/c-main-window.c +++ b/src/c-main-window.c @@ -4,6 +4,7 @@ #include #include #include "c-new-item-dialog.h" +#include "data.h" #include "interface.h" G_DEFINE_TYPE(CMainWindow, c_main_window, HILDON_TYPE_STACKABLE_WINDOW) @@ -17,12 +18,31 @@ enum { static void c_main_window_add_menu(CMainWindow *window); static void c_main_window_on_new(GtkWidget *widget, GtkWindow *window); +static void c_main_window_on_selection_changed(GtkTreeSelection *selection, + gpointer user_data); GtkWidget *c_main_window_new(void) { return g_object_new(C_TYPE_MAIN_WINDOW, NULL); } +void c_main_window_load(CMainWindow *self) +{ + GList *list; + + gtk_list_store_clear(self->store); + + list = data_get_series(); + + while (list) { + struct collection *col = list->data; + c_main_window_add_line(self, col->name, col->current_qty, col->total_qty); + list = g_list_next(list); + } + + g_list_free_1(list); +} + void c_main_window_add_line(CMainWindow *window, const gchar *name, gint current_qty, @@ -36,6 +56,22 @@ void c_main_window_add_line(CMainWindow *window, -1); } +void c_main_window_set_no_select(CMainWindow *self) +{ + if (GTK_IS_WIDGET(self->add_button)) + gtk_widget_set_sensitive(GTK_WIDGET(self->add_button), FALSE); + if (GTK_IS_WIDGET(self->remove_button)) + gtk_widget_set_sensitive(GTK_WIDGET(self->remove_button), FALSE); +} + +void c_main_window_set_has_select(CMainWindow *self) +{ + if (GTK_IS_WIDGET(self->add_button)) + gtk_widget_set_sensitive(GTK_WIDGET(self->add_button), TRUE); + if (GTK_IS_WIDGET(self->remove_button)) + gtk_widget_set_sensitive(GTK_WIDGET(self->remove_button), TRUE); +} + static void c_main_window_class_init(CMainWindowClass *class) {} @@ -43,7 +79,10 @@ static void c_main_window_init(CMainWindow *window) { GtkCellRenderer *renderer; GtkWidget *view; + GtkWidget *vbox; + GtkWidget *hbuttonbox; GtkTreeViewColumn *current_column; + GtkTreeSelection *selection; int index; index = -1; @@ -58,7 +97,15 @@ static void c_main_window_init(CMainWindow *window) G_TYPE_INT, G_TYPE_INT); + vbox = gtk_vbox_new(FALSE, 0); + view = gtk_tree_view_new(); + gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(selection, "changed", + G_CALLBACK(c_main_window_on_selection_changed), + (gpointer)window); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), @@ -71,7 +118,10 @@ static void c_main_window_init(CMainWindow *window) gtk_tree_view_column_set_expand(current_column, TRUE); renderer = gtk_cell_renderer_text_new(); - gtk_object_set(GTK_OBJECT(renderer), "xalign", 1.0, NULL); + gtk_object_set(GTK_OBJECT(renderer), + "xalign", 1.0, + "width", 100, + NULL); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), ++index, "", @@ -80,7 +130,10 @@ static void c_main_window_init(CMainWindow *window) NULL); renderer = gtk_cell_renderer_text_new(); - gtk_object_set(GTK_OBJECT(renderer), "xalign", 1.0, NULL); + gtk_object_set(GTK_OBJECT(renderer), + "xalign", 1.0, + "width", 100, + NULL); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), ++index, "", @@ -92,7 +145,19 @@ static void c_main_window_init(CMainWindow *window) GTK_TREE_MODEL(window->store)); g_object_unref(window->store); - gtk_container_add(GTK_CONTAINER(window), view); + hbuttonbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_END); + gtk_box_pack_start(GTK_BOX(vbox), hbuttonbox, FALSE, TRUE, 0); + + window->add_button = gtk_button_new_from_stock(GTK_STOCK_ADD); + gtk_box_pack_start(GTK_BOX(hbuttonbox), window->add_button, FALSE, FALSE, 0); + + window->remove_button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); + gtk_box_pack_start(GTK_BOX(hbuttonbox), window->remove_button, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + + c_main_window_set_no_select(window); } static void c_main_window_add_menu(CMainWindow *window) @@ -141,6 +206,20 @@ static void c_main_window_on_new(GtkWidget *widget, GtkWindow *window) } if (name != NULL) { - c_main_window_add_line(C_MAIN_WINDOW(window), name, 0, total_qty); + if (data_add_series(name, total_qty)) + c_main_window_load(C_MAIN_WINDOW(window)); } } + +static void c_main_window_on_selection_changed(GtkTreeSelection *selection, + gpointer user_data) +{ + gint count; + CMainWindow *self = (CMainWindow *)user_data; + + count = gtk_tree_selection_count_selected_rows(selection); + if (count == 0) + c_main_window_set_no_select(self); + else + c_main_window_set_has_select(self); +} diff --git a/src/c-main-window.h b/src/c-main-window.h index 185f532..29af0f5 100644 --- a/src/c-main-window.h +++ b/src/c-main-window.h @@ -45,16 +45,22 @@ struct _CMainWindow GtkTreeIter iter; GtkListStore *store; + + GtkWidget *add_button; + GtkWidget *remove_button; }; GType c_main_window_get_type(void); GtkWidget *c_main_window_new(void); +void c_main_window_load(CMainWindow *self); void c_main_window_add_line(CMainWindow *window, const gchar *name, gint current_qty, gint total_qty); +void c_main_window_set_no_select(CMainWindow *self); +void c_main_window_set_has_select(CMainWindow *self); G_END_DECLS diff --git a/src/c-new-item-dialog.c b/src/c-new-item-dialog.c index 75142e9..76b0686 100644 --- a/src/c-new-item-dialog.c +++ b/src/c-new-item-dialog.c @@ -30,7 +30,7 @@ static void c_new_item_dialog_init(CNewItemDialog *dialog) content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - hbox = gtk_vbox_new(FALSE, 0); + hbox = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(content_area), hbox); dialog->name_entry = hildon_entry_new(HILDON_SIZE_AUTO); @@ -38,6 +38,7 @@ static void c_new_item_dialog_init(CNewItemDialog *dialog) gtk_box_pack_start(GTK_BOX(hbox), dialog->name_entry, TRUE, TRUE, 0); dialog->qty_entry = hildon_entry_new(HILDON_SIZE_AUTO); + g_object_set(G_OBJECT(dialog->qty_entry), "width-chars", 5, NULL); hildon_entry_set_text(HILDON_ENTRY(dialog->qty_entry), "0"); gtk_box_pack_start(GTK_BOX(hbox), dialog->qty_entry, TRUE, TRUE, 0); diff --git a/src/collections.c b/src/collections.c index 38d9f76..56c75b7 100644 --- a/src/collections.c +++ b/src/collections.c @@ -1,5 +1,30 @@ #include +#include #include "interface.h" +#include "collections.h" + +gchar *collections_get_data_file(void) +{ + static gchar *filedir = NULL; + + if (filedir == NULL) { + filedir = g_strdup_printf("%s/collections.db", + collections_get_config_dir()); + } + + return filedir; +} + +gchar *collections_get_config_dir(void) +{ + static gchar *filedir = NULL; + + if (filedir == NULL) { + filedir = g_strdup_printf("%s/.collections", getenv("HOME")); + } + + return filedir; +} int main(int argc, char *argv[]) { diff --git a/src/collections.h b/src/collections.h new file mode 100644 index 0000000..b3f9240 --- /dev/null +++ b/src/collections.h @@ -0,0 +1,2 @@ +gchar *collections_get_data_file(void); +gchar *collections_get_config_dir(void); diff --git a/src/data.c b/src/data.c new file mode 100644 index 0000000..0013ed2 --- /dev/null +++ b/src/data.c @@ -0,0 +1,153 @@ +#include "data.h" +#include +#include +#include +#include +#include +#include +#include +#include "collections.h" + +static gboolean data_check_and_create_database(gchar *data_file); +static gint data_create_new_database(const char *filename); + +GList *data_get_series(void) +{ + sqlite3 *database; + sqlite3_stmt *statement; + gchar *data_file; + GList *list = NULL; + + data_file = collections_get_data_file(); + + if (data_check_and_create_database(data_file)) { + if (sqlite3_open(data_file, &database) == SQLITE_OK) { + int res; + const char *sqlStatement = + " SELECT name, " + " current_qty, " + " total_qty " + " FROM collection " + " ORDER BY name " + " COLLATE NOCASE "; + + res = sqlite3_prepare_v2(database, + sqlStatement, + strlen(sqlStatement), + &statement, NULL); + if (res == SQLITE_OK) { + while (sqlite3_step(statement) == SQLITE_ROW) { + struct collection *col = + (struct collection *)malloc(sizeof(struct collection *)); + + col->name = g_strdup(sqlite3_column_text(statement, 0)); + col->current_qty = sqlite3_column_int(statement, 1); + col->total_qty = sqlite3_column_int(statement, 2); + + list = g_list_append(list, (gpointer)col); + } + } + else + g_print("error %d: %s\n", res, sqlite3_errmsg(database)); + /* Release the compiled statement from memory */ + sqlite3_finalize(statement); + } + sqlite3_close(database); + } + + return list; +} + +gboolean data_add_series(gchar *name, int total_qty) +{ + sqlite3 *database; + sqlite3_stmt *statement; + gchar *data_file; + + data_file = collections_get_data_file(); + + if (data_check_and_create_database(data_file)) { + if (sqlite3_open(data_file, &database) == SQLITE_OK) { + int res; + const char *sqlStatement = + g_strdup_printf("INSERT INTO collection (name, current_qty, total_qty) " + " VALUES ('%s', 0, %d)", name, total_qty); + + res = sqlite3_prepare_v2(database, + sqlStatement, + strlen(sqlStatement), + &statement, NULL); + if (res == SQLITE_OK) { + if (sqlite3_step(statement) == SQLITE_DONE) + return TRUE; + } + } + } + + return FALSE; +} + +static gboolean data_check_and_create_database(gchar *data_file) +{ + if (!access(data_file, R_OK) == 0) + if (data_create_new_database(data_file)) { + g_printerr("Couldn't create a new database\n"); + return FALSE; /* Couldn't create database, can't continue */ + } + + return TRUE; +} + +static gint data_create_new_database(const char *filename) +{ + sqlite3 *db; + char *zErrMsg = 0; + int rc; + + if (access(collections_get_config_dir(), R_OK) == -1) { + if (mkdir(collections_get_config_dir(), S_IRWXU) == -1) + g_printerr("Can't create directory: %s\n", strerror(errno)); + } + + /* Open database connection, create file */ + rc = sqlite3_open(filename, &db); + if (rc) { + g_printerr("Can't open database: %s\n", sqlite3_errmsg(db)); + if (db) + sqlite3_close(db); + return -1; + } + + /* Create collections table */ + rc = sqlite3_exec(db, "CREATE TABLE collection(" + "id INTEGER PRIMARY KEY," + "name VARCHAR(100)," + "current_qty INTEGER," + "total_qty INTEGER" + ")", NULL, NULL, &zErrMsg); + if (rc != SQLITE_OK) { + g_printerr("Can't create collection table: %s\n", zErrMsg); + sqlite3_free(zErrMsg); + sqlite3_close(db); + return -1; + } + + /* Create items table */ + rc = sqlite3_exec(db, "CREATE TABLE item(" + "collection_id INTEGER," + "id INTEGER," + "title VARCHAR(100)," + "PRIMARY KEY(collection_id, id)," + "FOREIGN KEY(collection_id)" + " REFERENCES collection(id)" + ")", NULL, NULL, &zErrMsg); + if (rc != SQLITE_OK) { + g_printerr("Can't create item table: %s\n", zErrMsg); + sqlite3_free(zErrMsg); + sqlite3_close(db); + return -1; + } + + sqlite3_close(db); + return 0; +} diff --git a/src/data.h b/src/data.h new file mode 100644 index 0000000..3ebbb2e --- /dev/null +++ b/src/data.h @@ -0,0 +1,11 @@ +#include + +struct collection +{ + const gchar *name; + gint current_qty; + gint total_qty; +}; + +GList *data_get_series(void); +gboolean data_add_series(gchar *name, int total_qty); diff --git a/src/interface.c b/src/interface.c index 5e68160..2e54ecd 100644 --- a/src/interface.c +++ b/src/interface.c @@ -2,6 +2,7 @@ #include "interface.h" #include "c-main-window.h" #include "c-new-item-dialog.h" +#include "data.h" void interface_show_main_window(void) { @@ -10,9 +11,7 @@ void interface_show_main_window(void) window = c_main_window_new(); gtk_widget_show_all(window); - c_main_window_add_line(C_MAIN_WINDOW(window), "Biomega", 2, 0); - c_main_window_add_line(C_MAIN_WINDOW(window), "Blame!", 7, 10); - c_main_window_add_line(C_MAIN_WINDOW(window), "Hellsing", 2, 14); + c_main_window_load(C_MAIN_WINDOW(window)); } GtkWidget *interface_show_new_item_dialog(GtkWindow *window)