diff options
author | Bruno Coudoin <bcoudoin@src.gnome.org> | 2009-02-17 23:18:08 (GMT) |
---|---|---|
committer | Bruno Coudoin <bcoudoin@src.gnome.org> | 2009-02-17 23:18:08 (GMT) |
commit | 460c950a51fe6fdb51a10710a9b6f9d7085880c7 (patch) | |
tree | 83d31a852ea0ea4108307a9aad89f91c8e4532b5 | |
parent | b061947341f605b9d6318daeb8e3f643f51e3ff8 (diff) |
merged 3722 from trunk
svn path=/branches/GCOMPRIS_8_3/; revision=3723
32 files changed, 1258 insertions, 575 deletions
@@ -1,3 +1,81 @@ + +2009-02-17 Bruno coudoin <bruno.coudoin@free.fr> + + - Merged 3722 fromm trunk + - Miquel DE IZARRA Added support for editing the content + of the missing letter activity. + + * boards/missing_letter/Makefile.am: + * boards/missing_letter/board1.xml.in: + * boards/missing_letter/board2.xml.in: + * boards/missing_letter/board3.xml.in: + * boards/missing_letter/board4.xml.in: + * src/boards/Makefile.am: + * src/boards/missingletter.c: (pause_board), (start_board), + (end_board), (set_level), (missing_letter_next_level), + (missing_letter_create_item), (game_won), (init_xml), + (add_xml_data), (missing_read_xml_file), + (missing_destroy_board_list), (conf_ok), (config_start): + * src/boards/missingletter_config.c: (new_clicked), + (delete_clicked), (valid_entry), (apply_clicked), (up_clicked), + (down_clicked), (_save), (save_clicked), (level_changed), + (text_changed), (selection_changed), (destroy_conf_data), + (configure_colummns), (config_missing_letter): + * src/boards/reading.c: (reading_create_item), (get_random_word): + * src/gcompris/board_config_wordlist.c: (gc_board_config_wordlist): + * src/gcompris/gc_net.c: (gc_net_get_url_from_file), + (gc_cache_import_pixmap): + * src/gcompris/gc_net.h: + * src/gcompris/gcompris.c: (main): + +2009-02-05 Bruno coudoin <bruno.coudoin@free.fr> + + From trunk 3720 + Miguel DE IZARRA added support for online wordlist. + This save custom data in user_dir and make a content.txt (a md5sum + like file) listing custom files. Simply put this files in a web server + to diffuse in classroom. + + GCompris clients are launch with --server and --cache-dir + On start, client download content.txt from server. + + And when a client need a file: + - first he search in server list (from content.txt) + - if found, he check md5 of file in cache_dir + - if md5 isn't ok, file is download in cache_dir + file in cache_dir is used + - if not found, search in package_dir (like now) + + * configure.in: + * src/boards/advanced_colors.c: (read_xml_file): + * src/boards/imageid.c: (read_xml_file): + * src/boards/missingletter.c: (read_xml_file): + * src/boards/python/admin/board_list.py: + * src/boards/read_colors.c: (read_xml_file): + * src/boards/shapegame.c: (read_xml_file): + * src/boards/superbrain.c: (mark_pieces): + * src/boards/wordprocessor.c: (load_buffer): + * src/gcompris/Makefile.am: + * src/gcompris/board_config_wordlist.c: (_return_clicked), + (gc_board_config_wordlist): + * src/gcompris/cache.c: + * src/gcompris/config.c: (set_locale_flag): + * src/gcompris/dialog.c: + * src/gcompris/gameutil.c: (gc_pixmap_load), + (gc_file_find_absolute), (gc_file_find_absolute_writeable): + * src/gcompris/gameutil.h: + * src/gcompris/gc_core.h: + * src/gcompris/gc_net.c: (load_md5file), (gc_net_init), + (gc_net_destroy), (gc_net_get_url_from_file), (gc_cache_init), + (gc_cache_get_relative), (gc_cache_add), (gc_cache_remove), + (_table_foreach), (gc_cache_save), (gc_cache_destroy): + * src/gcompris/gc_net.h: + * src/gcompris/gcompris.c: (setup_window), (cleanup), (main): + * src/gcompris/images_selector.c: (gc_selector_images_start), + (read_xml_file): + * src/gcompris/skin.c: (skin_xml_load): + * src/gcompris/wordlist.c: (gc_wordlist_save): + 2009-02-01 Bruno coudoin <bruno.coudoin@free.fr> From trunk 3718 diff --git a/boards/missing_letter/Makefile.am b/boards/missing_letter/Makefile.am index 4bffd44..3d8c1e3 100644 --- a/boards/missing_letter/Makefile.am +++ b/boards/missing_letter/Makefile.am @@ -2,7 +2,10 @@ xmldir = $(pkgdatadir)/@PACKAGE_DATA_DIR@/missing_letter xml_in_files = \ - board1.xml.in + board1.xml.in \ + board2.xml.in \ + board3.xml.in \ + board4.xml.in xml_DATA = $(xml_in_files:.xml.in=.xml) diff --git a/boards/missing_letter/board1.xml.in b/boards/missing_letter/board1.xml.in index 221d6db..4a9a491 100644 --- a/boards/missing_letter/board1.xml.in +++ b/boards/missing_letter/board1.xml.in @@ -36,113 +36,5 @@ <pixmapfile>imageid/bed.png</pixmapfile> <_data>bed/_ed/b/l/f</_data> </Board> - <Board> - <pixmapfile>imageid/bottle.png</pixmapfile> - <_data>bottle/_ottle/b/t/p</_data> - </Board> - <Board> - <pixmapfile>imageid/cake.png</pixmapfile> - <_data>cake/_ake/c/p/d</_data> - </Board> - <Board> - <pixmapfile>imageid/ballon.png</pixmapfile> - <_data>ball/_all/b/p/d</_data> - </Board> - <Board> - <pixmapfile>imageid/avion.png</pixmapfile> - <_data>plane/p_ane/l/j/i</_data> - </Board> - <Board> - <pixmapfile>imageid/chien.png</pixmapfile> - <_data>dog/d_g/o/g/a</_data> - </Board> - <Board> - <pixmapfile>imageid/fish.png</pixmapfile> - <_data>fish/_ish/f/h/l</_data> - </Board> - <Board> - <pixmapfile>imageid/car.png</pixmapfile> - <_data>car/_ar/c/k/b</_data> - </Board> - <Board> - <pixmapfile>imageid/cartable.png</pixmapfile> - <_data>satchel/_atchel/s/c/l</_data> - </Board> - <Board> - <pixmapfile>imageid/banana.png</pixmapfile> - <_data>banana/_anana/b/p/d</_data> - </Board> - <Board> - <pixmapfile>imageid/maison.png</pixmapfile> - <_data>house/h_use/o/f/u</_data> - </Board> - <Board> - <pixmapfile>imageid/pomme.png</pixmapfile> - <_data>apple/appl_/e/h/a</_data> - </Board> - <Board> - <pixmapfile>imageid/bed.png</pixmapfile> - <_data>bed/b_d/e/a/i</_data> - </Board> - <Board> - <pixmapfile>imageid/bottle.png</pixmapfile> - <_data>bottle/b_ttle/o/u/d</_data> - </Board> - <Board> - <pixmapfile>imageid/cake.png</pixmapfile> - <_data>cake/c_ke/a/o/e</_data> - </Board> - <Board> - <pixmapfile>imageid/ballon.png</pixmapfile> - <_data>ball/b_ll/a/u/o</_data> - </Board> - <Board> - <pixmapfile>imageid/avion.png</pixmapfile> - <_data>plane/pl_ne/a/o/s</_data> - </Board> - <Board> - <pixmapfile>imageid/chien.png</pixmapfile> - <_data>dog/do_/g/p/q</_data> - </Board> - <Board> - <pixmapfile>imageid/fish.png</pixmapfile> - <_data>fish/fis_/h/o/i</_data> - </Board> - <Board> - <pixmapfile>imageid/car.png</pixmapfile> - <_data>car/ca_/r/w/k</_data> - </Board> - <Board> - <pixmapfile>imageid/cartable.png</pixmapfile> - <_data>satchel/sa_chel/t/p/c</_data> - </Board> - <Board> - <pixmapfile>imageid/banana.png</pixmapfile> - <_data>banana/ba_ana/n/m/b</_data> - </Board> - <Board> - <pixmapfile>imageid/maison.png</pixmapfile> - <_data>house/_ouse/h/e/j</_data> - </Board> - <Board> - <pixmapfile>imageid/pomme.png</pixmapfile> - <_data>apple/app_e/l/h/n</_data> - </Board> - <Board> - <pixmapfile>imageid/bed.png</pixmapfile> - <_data>bed/be_/d/p/b</_data> - </Board> - <Board> - <pixmapfile>imageid/bottle.png</pixmapfile> - <_data>bottle/bott_e/l/y/r</_data> - </Board> - <Board> - <pixmapfile>imageid/cake.png</pixmapfile> - <_data>cake/ca_e/k/q/c</_data> - </Board> - <Board> - <pixmapfile>imageid/ballon.png</pixmapfile> - <_data>ball/bal_/l/h/s</_data> - </Board> </missing_letter> diff --git a/boards/missing_letter/board2.xml.in b/boards/missing_letter/board2.xml.in new file mode 100644 index 0000000..3f82d24 --- /dev/null +++ b/boards/missing_letter/board2.xml.in @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<missing_letter> + <Board> + <pixmapfile>imageid/bottle.png</pixmapfile> + <_data>bottle/_ottle/b/t/p</_data> + </Board> + <Board> + <pixmapfile>imageid/cake.png</pixmapfile> + <_data>cake/_ake/c/p/d</_data> + </Board> + <Board> + <pixmapfile>imageid/ballon.png</pixmapfile> + <_data>ball/_all/b/p/d</_data> + </Board> + <Board> + <pixmapfile>imageid/avion.png</pixmapfile> + <_data>plane/p_ane/l/j/i</_data> + </Board> + <Board> + <pixmapfile>imageid/chien.png</pixmapfile> + <_data>dog/d_g/o/g/a</_data> + </Board> + <Board> + <pixmapfile>imageid/fish.png</pixmapfile> + <_data>fish/_ish/f/h/l</_data> + </Board> + <Board> + <pixmapfile>imageid/car.png</pixmapfile> + <_data>car/_ar/c/k/b</_data> + </Board> + <Board> + <pixmapfile>imageid/cartable.png</pixmapfile> + <_data>satchel/_atchel/s/c/l</_data> + </Board> + <Board> + <pixmapfile>imageid/banana.png</pixmapfile> + <_data>banana/_anana/b/p/d</_data> + </Board> +</missing_letter> + diff --git a/boards/missing_letter/board3.xml.in b/boards/missing_letter/board3.xml.in new file mode 100644 index 0000000..8d84227 --- /dev/null +++ b/boards/missing_letter/board3.xml.in @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<missing_letter> + <Board> + <pixmapfile>imageid/maison.png</pixmapfile> + <_data>house/h_use/o/f/u</_data> + </Board> + <Board> + <pixmapfile>imageid/pomme.png</pixmapfile> + <_data>apple/appl_/e/h/a</_data> + </Board> + <Board> + <pixmapfile>imageid/bed.png</pixmapfile> + <_data>bed/b_d/e/a/i</_data> + </Board> + <Board> + <pixmapfile>imageid/bottle.png</pixmapfile> + <_data>bottle/b_ttle/o/u/d</_data> + </Board> + <Board> + <pixmapfile>imageid/cake.png</pixmapfile> + <_data>cake/c_ke/a/o/e</_data> + </Board> + <Board> + <pixmapfile>imageid/ballon.png</pixmapfile> + <_data>ball/b_ll/a/u/o</_data> + </Board> + <Board> + <pixmapfile>imageid/avion.png</pixmapfile> + <_data>plane/pl_ne/a/o/s</_data> + </Board> + <Board> + <pixmapfile>imageid/chien.png</pixmapfile> + <_data>dog/do_/g/p/q</_data> + </Board> + <Board> + <pixmapfile>imageid/fish.png</pixmapfile> + <_data>fish/fis_/h/o/i</_data> + </Board> +</missing_letter> + diff --git a/boards/missing_letter/board4.xml.in b/boards/missing_letter/board4.xml.in new file mode 100644 index 0000000..6cc224f --- /dev/null +++ b/boards/missing_letter/board4.xml.in @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<missing_letter> + <Board> + <pixmapfile>imageid/car.png</pixmapfile> + <_data>car/ca_/r/w/k</_data> + </Board> + <Board> + <pixmapfile>imageid/cartable.png</pixmapfile> + <_data>satchel/sa_chel/t/p/c</_data> + </Board> + <Board> + <pixmapfile>imageid/banana.png</pixmapfile> + <_data>banana/ba_ana/n/m/b</_data> + </Board> + <Board> + <pixmapfile>imageid/maison.png</pixmapfile> + <_data>house/_ouse/h/e/j</_data> + </Board> + <Board> + <pixmapfile>imageid/pomme.png</pixmapfile> + <_data>apple/app_e/l/h/n</_data> + </Board> + <Board> + <pixmapfile>imageid/bed.png</pixmapfile> + <_data>bed/be_/d/p/b</_data> + </Board> + <Board> + <pixmapfile>imageid/bottle.png</pixmapfile> + <_data>bottle/bott_e/l/y/r</_data> + </Board> + <Board> + <pixmapfile>imageid/cake.png</pixmapfile> + <_data>cake/ca_e/k/q/c</_data> + </Board> + <Board> + <pixmapfile>imageid/ballon.png</pixmapfile> + <_data>ball/bal_/l/h/s</_data> + </Board> +</missing_letter> + diff --git a/configure.in b/configure.in index 2f3700d..f7f181d 100644 --- a/configure.in +++ b/configure.in @@ -398,6 +398,20 @@ if test x$TETEX = xno; then AC_MSG_WARN(Couldn't find texi2html usualy in the tetex package, please install it) fi + +dnl GNET support +AC_MSG_CHECKING([wether we build with GNET (if not, networking will be disabled)]) +AC_ARG_ENABLE(gnet, + AC_HELP_STRING( + [--disable-gnet], + [Turn on gnet (will let GCompris fetch content from a web server)]), + with_gnet="$enableval", with_gnet="no") +AC_MSG_RESULT($with_gnet) + +if test x$with_gnet = xyes; then + PKG_CHECK_MODULES(GNET, gnet-2.0,, AC_MSG_ERROR([*** GNET not found!])) + AC_DEFINE([USE_GNET], 1,[Networking is enabled]) +fi dnl SQLITE support AC_MSG_CHECKING([wether we build with SQLITE (if not profile will be disabled)]) diff --git a/src/boards/Makefile.am b/src/boards/Makefile.am index 2e705a1..7e714ef 100644 --- a/src/boards/Makefile.am +++ b/src/boards/Makefile.am @@ -170,7 +170,7 @@ libimageid_la_SOURCES = imageid.c libmissingletter_la_LDFLAGS = $(shared) $(no_undefined) -module -avoid-version $(gc_libs) $(XML_LIBS) libmissingletter_la_LIBADD = -libmissingletter_la_SOURCES = missingletter.c +libmissingletter_la_SOURCES = missingletter.c missingletter_config.c libclick_on_letter_la_LDFLAGS = $(shared) $(no_undefined) -module -avoid-version $(gc_libs) diff --git a/src/boards/advanced_colors.c b/src/boards/advanced_colors.c index c1a8e14..2f94ef6 100644 --- a/src/boards/advanced_colors.c +++ b/src/boards/advanced_colors.c @@ -521,7 +521,7 @@ static gboolean read_xml_file(char *fname) g_return_val_if_fail(fname!=NULL,FALSE); /* parse the new file and put the result into newdoc */ - doc = gc_net_load_xml(fname); + doc = xmlParseFile(fname); /* in case something went wrong */ if(!doc) diff --git a/src/boards/imageid.c b/src/boards/imageid.c index 6499871..984dcfb 100644 --- a/src/boards/imageid.c +++ b/src/boards/imageid.c @@ -633,7 +633,7 @@ static gboolean read_xml_file(char *fname) g_return_val_if_fail(fname!=NULL,FALSE); /* parse the new file and put the result into newdoc */ - doc = gc_net_load_xml(fname); + doc = xmlParseFile(fname); /* in case something went wrong */ if(!doc) diff --git a/src/boards/missingletter.c b/src/boards/missingletter.c index ffe9621..4915082 100644 --- a/src/boards/missingletter.c +++ b/src/boards/missingletter.c @@ -27,7 +27,7 @@ #define SOUNDLISTFILE PACKAGE -static GcomprisBoard *gcomprisBoard = NULL; +GcomprisBoard *gcomprisBoard_missing = NULL; static gboolean board_paused = TRUE; static void start_board (GcomprisBoard *agcomprisBoard); @@ -43,6 +43,9 @@ static void config_start(GcomprisBoard *agcomprisBoard, GcomprisProfile *aProfile); static void config_stop(void); +/* from missingletter_config.c */ +void config_missing_letter(GcomprisBoardConf *config); + typedef struct _Board Board; struct _Board { char *pixmapfile; @@ -56,12 +59,10 @@ struct _Board { static Board * board; /* XML */ -static gboolean read_xml_file(char *fname); static void init_xml(void); -static void add_xml_data(xmlDocPtr, xmlNodePtr, GNode *); -static void parse_doc(xmlDocPtr doc); -static gboolean read_xml_file(char *fname); -static void destroy_board_list(); +static void add_xml_data(xmlDocPtr, xmlNodePtr, GList**); +gboolean missing_read_xml_file(char *fname, GList**); +void missing_destroy_board_list(GList *); static void destroy_board(Board * board); /* This is the list of boards */ @@ -70,12 +71,7 @@ static GList *board_list = NULL; #define VERTICAL_SEPARATION 30 #define HORIZONTAL_SEPARATION 30 -//NUMBER_OF_SUBLEVELS*NUMBER_OF_LEVELS must equal the number of boards in XML file -#define NUMBER_OF_SUBLEVELS 9 -#define NUMBER_OF_LEVELS 4 - /* ================================================================ */ -static int board_number; // between 0 and board_list.length-1 static int right_word; // between 1 and 3, indicates which choice is the right one (the player clicks on it static GnomeCanvasGroup *boardRootItem = NULL; @@ -132,7 +128,7 @@ GET_BPLUGIN_INFO(missingletter) */ static void pause_board (gboolean pause) { - if(gcomprisBoard==NULL) + if(gcomprisBoard_missing==NULL) return; gc_bar_hide(FALSE); @@ -150,6 +146,7 @@ static void pause_board (gboolean pause) static void start_board (GcomprisBoard *agcomprisBoard) { GHashTable *config = gc_db_get_board_conf(); + gchar * filename; gc_locale_set(g_hash_table_lookup( config, "locale")); @@ -157,19 +154,23 @@ static void start_board (GcomprisBoard *agcomprisBoard) if(agcomprisBoard!=NULL) { - gcomprisBoard=agcomprisBoard; - gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), + gcomprisBoard_missing=agcomprisBoard; + gc_set_background(gnome_canvas_root(gcomprisBoard_missing->canvas), "opt/missingletter-bg.jpg"); - gcomprisBoard->level=1; - gcomprisBoard->maxlevel=NUMBER_OF_LEVELS; - gcomprisBoard->sublevel=1; - gcomprisBoard->number_of_sublevel=NUMBER_OF_SUBLEVELS; /* Go to next level after this number of 'play' */ + gcomprisBoard_missing->level=1; + + /* Calculate the maxlevel based on the available data file for this board */ + gcomprisBoard_missing->maxlevel = 1; + while((filename = gc_file_find_absolute("%s/board%d.xml", + gcomprisBoard_missing->boarddir, ++gcomprisBoard_missing->maxlevel))) + g_free(filename); + + gcomprisBoard_missing->maxlevel--; + + gcomprisBoard_missing->sublevel=1; + gcomprisBoard_missing->number_of_sublevel=G_MAXINT; + init_xml(); - g_assert(NUMBER_OF_LEVELS*NUMBER_OF_SUBLEVELS == g_list_length(board_list)); - gc_score_start(SCORESTYLE_NOTE, - 50, - gcomprisBoard->height - 50, - gcomprisBoard->number_of_sublevel); gc_bar_set(GC_BAR_CONFIG | GC_BAR_LEVEL); missing_letter_next_level(); @@ -182,27 +183,29 @@ static void start_board (GcomprisBoard *agcomprisBoard) static void end_board () { - if(gcomprisBoard!=NULL) + if(gcomprisBoard_missing!=NULL) { pause_board(TRUE); gc_score_end(); missing_letter_destroy_all_items(); - destroy_board_list(); + missing_destroy_board_list(board_list); + board_list = NULL; } gc_locale_reset(); - gcomprisBoard = NULL; + gcomprisBoard_missing = NULL; } static void set_level (guint level) { - if(gcomprisBoard!=NULL) + if(gcomprisBoard_missing!=NULL) { - gcomprisBoard->level=level; - gcomprisBoard->sublevel=1; + gcomprisBoard_missing->level=level; + gcomprisBoard_missing->sublevel=1; + init_xml(); missing_letter_next_level(); } } @@ -228,16 +231,16 @@ is_our_board (GcomprisBoard *gcomprisBoard) /* set initial values for the next level */ static void missing_letter_next_level() { - gc_bar_set_level(gcomprisBoard); + gc_bar_set_level(gcomprisBoard_missing); missing_letter_destroy_all_items(); selected_button = NULL; gamewon = FALSE; - gc_score_set(gcomprisBoard->sublevel); + gc_score_set(gcomprisBoard_missing->sublevel); /* Try the next level */ - missing_letter_create_item(gnome_canvas_root(gcomprisBoard->canvas)); + missing_letter_create_item(gnome_canvas_root(gcomprisBoard_missing->canvas)); } /* ==================================== */ @@ -268,27 +271,24 @@ static GnomeCanvasItem *missing_letter_create_item(GnomeCanvasGroup *parent) gint txt_area_x = 515; gint txt_area_y = 435; - board_number = (gcomprisBoard->level-1) * NUMBER_OF_SUBLEVELS + gcomprisBoard->sublevel-1; - - g_assert(board_number >= 0 && board_number < g_list_length(board_list)); place = g_random_int_range( 0, 3); g_assert(place >= 0 && place < 3); right_word = place+1; boardRootItem = GNOME_CANVAS_GROUP( - gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas), + gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard_missing->canvas), gnome_canvas_group_get_type (), "x", (double) 0, "y", (double) 0, NULL)); button_pixmap = gc_skin_pixmap_load("button.png"); /* display the image */ - board = g_list_nth_data(board_list, board_number); + board = g_list_nth_data(board_list, gcomprisBoard_missing->sublevel-1); g_assert(board != NULL); pixmap = gc_pixmap_load(board->pixmapfile); - yOffset = (gcomprisBoard->height - gdk_pixbuf_get_height(button_pixmap) - gdk_pixbuf_get_height(pixmap) - 2*VERTICAL_SEPARATION)/2; + yOffset = (gcomprisBoard_missing->height - gdk_pixbuf_get_height(button_pixmap) - gdk_pixbuf_get_height(pixmap) - 2*VERTICAL_SEPARATION)/2; text_s = gnome_canvas_item_new (boardRootItem, gnome_canvas_text_get_type (), @@ -345,7 +345,7 @@ static GnomeCanvasItem *missing_letter_create_item(GnomeCanvasGroup *parent) break; } - yOffset = ( gcomprisBoard->height - 3*gdk_pixbuf_get_height(button_pixmap) - 2*VERTICAL_SEPARATION) / 2; + yOffset = ( gcomprisBoard_missing->height - 3*gdk_pixbuf_get_height(button_pixmap) - 2*VERTICAL_SEPARATION) / 2; xOffset = (img_area_x-gdk_pixbuf_get_width(button_pixmap))/2; button1 = gnome_canvas_item_new (boardRootItem, gnome_canvas_pixbuf_get_type (), @@ -438,13 +438,15 @@ static GnomeCanvasItem *missing_letter_create_item(GnomeCanvasGroup *parent) } /* ==================================== */ static void game_won() { - gcomprisBoard->sublevel++; + gcomprisBoard_missing->sublevel++; - if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) { + if(gcomprisBoard_missing->sublevel>gcomprisBoard_missing->number_of_sublevel) { /* Try the next level */ - gcomprisBoard->sublevel=1; - gcomprisBoard->level++; - if(gcomprisBoard->level>gcomprisBoard->maxlevel) { + gcomprisBoard_missing->sublevel=1; + gcomprisBoard_missing->level++; + init_xml(); + + if(gcomprisBoard_missing->level>gcomprisBoard_missing->maxlevel) { gc_bonus_end_display(GC_BOARD_FINISHED_TUXPLANE); return; } @@ -563,16 +565,27 @@ static void init_xml() { char *filename; - filename = gc_file_find_absolute("%s/board1.xml", - gcomprisBoard->boarddir); - - g_assert(read_xml_file(filename)== TRUE); - + if(board_list) + { + missing_destroy_board_list(board_list); + board_list = NULL; + } + filename = gc_file_find_absolute("%s/board%d.xml", + gcomprisBoard_missing->boarddir, + gcomprisBoard_missing->level); + missing_read_xml_file(filename, &board_list); + gcomprisBoard_missing->number_of_sublevel = g_list_length(board_list); g_free(filename); + + gc_score_end(); + gc_score_start(SCORESTYLE_NOTE, + 50, + gcomprisBoard_missing->height - 50, + gcomprisBoard_missing->number_of_sublevel); } /* ==================================== */ -static void add_xml_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child) +static void add_xml_data(xmlDocPtr doc, xmlNodePtr xmlnode, GList **list) { gchar *pixmapfile = NULL; gchar *question = NULL, *answer = NULL; @@ -594,22 +607,17 @@ static void add_xml_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child) { if(data==NULL) { - data = gettext((gchar *)xmlNodeListGetString(doc, xmlnode->xmlChildrenNode, 1)); + gchar *tmp; + tmp = (gchar *)xmlNodeListGetString(doc, xmlnode->xmlChildrenNode, 1); + data = g_strdup(gettext(tmp)); + g_free(tmp); } } xmlnode = xmlnode->next; } - // I really don't know why this test, but otherwise, the list is doubled - // with 1 line on 2 filled with NULL elements - if ( pixmapfile == NULL || data == NULL) - return; - -/* if ((i=sscanf(data, "%s / %s / %s / %s / %s", answer, question, l1, l2, l3)) != 5) - printf("Error sscanf result != 5 = %i\n",i); -*/ gchar **all_answer = g_strsplit(data, "/", 5); - /* Dont free data, it's a gettext static message */ + g_free(data); answer = all_answer[0]; question = all_answer[1]; @@ -628,33 +636,23 @@ static void add_xml_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child) g_strfreev(all_answer); - board_list = g_list_append (board_list, board); + *list = g_list_append (*list, board); } -/* ==================================== */ -static void parse_doc(xmlDocPtr doc) -{ - xmlNodePtr node; - - for(node = doc->children->children; node != NULL; node = node->next) { - if ( g_strcasecmp((gchar *)node->name, "Board") == 0 ) - add_xml_data(doc, node,NULL); - } - -} /* ==================================== */ /* read an xml file into our memory structures and update our view, dump any old data we have in memory if we can load a new set */ -static gboolean read_xml_file(char *fname) +gboolean missing_read_xml_file(char *fname, GList **list) { /* pointer to the new doc */ xmlDocPtr doc; + xmlNodePtr node; g_return_val_if_fail(fname!=NULL,FALSE); /* parse the new file and put the result into newdoc */ - doc = gc_net_load_xml(fname); + doc = xmlParseFile(fname); /* in case something went wrong */ if(!doc) @@ -670,17 +668,21 @@ static gboolean read_xml_file(char *fname) return FALSE; } - parse_doc(doc); + for(node = doc->children->children; node != NULL; node = node->next) { + if ( g_strcasecmp((gchar *)node->name, "Board") == 0 ) + add_xml_data(doc, node, list); + } xmlFreeDoc(doc); return TRUE; } + /* ======================================= */ -static void destroy_board_list() { +void missing_destroy_board_list(GList *list) { Board *board; - while(g_list_length(board_list)>0) + while(g_list_length(list)>0) { - board = g_list_nth_data(board_list, 0); - board_list = g_list_remove (board_list, board); + board = g_list_nth_data(list, 0); + list = g_list_remove (list, board); destroy_board(board); } } @@ -722,14 +724,14 @@ static void save_table (gpointer key, static GcomprisConfCallback conf_ok(GHashTable *table) { if (!table){ - if (gcomprisBoard) + if (gcomprisBoard_missing) pause_board(FALSE); return NULL; } g_hash_table_foreach(table, (GHFunc) save_table, NULL); - if (gcomprisBoard){ + if (gcomprisBoard_missing){ gc_locale_reset(); GHashTable *config; @@ -744,8 +746,6 @@ static GcomprisConfCallback conf_ok(GHashTable *table) if (profile_conf) g_hash_table_destroy(config); - destroy_board_list(); - init_xml(); missing_letter_next_level(); @@ -754,6 +754,7 @@ static GcomprisConfCallback conf_ok(GHashTable *table) board_conf = NULL; profile_conf = NULL; + pause_board(FALSE); return NULL; } @@ -765,7 +766,7 @@ config_start(GcomprisBoard *agcomprisBoard, board_conf = agcomprisBoard; profile_conf = aProfile; - if (gcomprisBoard) + if (gcomprisBoard_missing) pause_board(TRUE); gchar *label = g_strdup_printf(_("<b>%s</b> configuration\n for profile <b>%s</b>"), @@ -783,7 +784,7 @@ config_start(GcomprisBoard *agcomprisBoard, gchar *locale = g_hash_table_lookup( config, "locale"); gc_board_config_combo_locales(bconf, locale); - + config_missing_letter(bconf); } diff --git a/src/boards/missingletter_config.c b/src/boards/missingletter_config.c new file mode 100644 index 0000000..b3600b6 --- /dev/null +++ b/src/boards/missingletter_config.c @@ -0,0 +1,599 @@ +#include "gcompris/gcompris.h" +#include <string.h> + +/* from missingletter.c */ +typedef struct _Board Board; +struct _Board { + char *pixmapfile; + char *question; + char *answer; + char *l1; + char *l2; + char *l3; + }; + +extern GcomprisBoard *gcomprisBoard_missing; +gboolean missing_read_xml_file(char *fname, GList**); +void missing_destroy_board_list(GList *); + +typedef struct + { + GtkComboBox *combo_level; + GtkTreeView *view; + + GtkFileChooserButton *pixmap; + GtkEntry *question, *answer, *choice; + gboolean changed; + } _config_missing; + +enum + { + QUESTION_COLUMN, + ANSWER_COLUMN, + CHOICE_COLUMN, + PIXMAP_COLUMN, + PIXBUF_COLUMN, + N_COLUMNS + }; + +#define ICON_SIZE 32 + +static void new_clicked(GtkButton *b, gpointer data) +{ + _config_missing *u = (_config_missing*)data; + GtkListStore *ls; + GtkTreeIter iter; + + ls = GTK_LIST_STORE(gtk_tree_view_get_model(u->view)); + gtk_list_store_append(ls, &iter); + gtk_list_store_set(ls, &iter, + QUESTION_COLUMN, "", + ANSWER_COLUMN, "", + CHOICE_COLUMN, "", + PIXMAP_COLUMN, "", + PIXBUF_COLUMN, NULL, + -1); + GtkTreeSelection* sel = gtk_tree_view_get_selection(u->view); + gtk_tree_selection_select_iter(sel , &iter); +} + +static void delete_clicked(GtkButton *b, gpointer data) +{ + _config_missing *u = (_config_missing*)data; + GtkTreeSelection *selection = gtk_tree_view_get_selection(u->view); + GtkTreeModel *model; + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + u->changed = TRUE; + } +} + +static gboolean valid_entry(gchar *question, gchar *answer, + gchar *choice, gchar *pixmap) +{ + gboolean result=FALSE; + gchar **split; + + if(choice && question && answer && pixmap && + strlen(choice)==3 && strlen(question) && strlen(answer) + && strchr(question, '_')) + { + split = g_strsplit(question, "_", 2); + if(g_str_has_prefix(answer, split[0]) && + g_str_has_suffix(answer, split[1]) && + answer[strlen(split[0])] == choice[0]) + result = TRUE; + g_strfreev(split); + } + return result; +} + +static void apply_clicked(GtkButton *b, gpointer data) +{ + _config_missing *u = (_config_missing*)data; + const gchar *question, *answer, *choice; + gchar *pixmap, *pixfile; + GtkTreeSelection *selection = gtk_tree_view_get_selection(u->view); + GtkTreeModel *model; + GtkTreeIter iter; + + question = gtk_entry_get_text(u->question); + answer = gtk_entry_get_text(u->answer); + choice = gtk_entry_get_text(u->choice); + pixmap = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(u->pixmap)); + + if(valid_entry((gchar*)question, (gchar*) answer, (gchar*)choice, pixmap)) + { + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + pixfile = gc_cache_import_pixmap(pixmap, "imageid", 300, 300); + GdkPixbuf *pixbuf = + gdk_pixbuf_new_from_file_at_size(pixmap, ICON_SIZE, + ICON_SIZE, NULL); + + gtk_list_store_set(GTK_LIST_STORE(model),&iter, + QUESTION_COLUMN, question, + ANSWER_COLUMN, answer, + CHOICE_COLUMN, choice, + PIXMAP_COLUMN, pixfile, + PIXBUF_COLUMN, pixbuf, + -1); + u->changed = TRUE; + g_free(pixfile); + g_object_unref(pixbuf); + } + } + g_free(pixmap); +} + +static void up_clicked(GtkButton *b, gpointer data) +{ + _config_missing *u = (_config_missing*)data; + GtkTreeSelection *selection = gtk_tree_view_get_selection(u->view); + GtkTreeIter itera, iterb; + GtkTreeModel *model; + GtkTreePath *tpa, *tpb; + gchar *pa, *pb; + + if (gtk_tree_selection_get_selected (selection, &model, &itera)) + { + pa = gtk_tree_model_get_string_from_iter(model, &itera); + tpa = gtk_tree_path_new_from_string(pa); + tpb = gtk_tree_path_copy(tpa); + gtk_tree_path_prev(tpb); + pb = gtk_tree_path_to_string(tpb); + gtk_tree_model_get_iter_from_string(model, &iterb, pb); + gtk_list_store_swap(GTK_LIST_STORE(model), &itera, &iterb); + gtk_tree_path_free(tpa); + gtk_tree_path_free(tpb); + g_free(pa); + g_free(pb); + u->changed = TRUE; + } +} + +static void down_clicked(GtkButton *b, gpointer data) +{ + _config_missing *u = (_config_missing*)data; + GtkTreeSelection *selection = gtk_tree_view_get_selection(u->view); + GtkTreeIter itera, iterb; + GtkTreeModel *model; + GtkTreePath *tpa, *tpb; + gchar *pa, *pb; + + if (gtk_tree_selection_get_selected (selection, &model, &itera)) + { + pa = gtk_tree_model_get_string_from_iter(model, &itera); + tpa = gtk_tree_path_new_from_string(pa); + tpb = gtk_tree_path_copy(tpa); + gtk_tree_path_next(tpb); + pb = gtk_tree_path_to_string(tpb); + if(gtk_tree_model_get_iter_from_string(model, &iterb, pb)) + gtk_list_store_swap(GTK_LIST_STORE(model), &itera, &iterb); + gtk_tree_path_free(tpa); + gtk_tree_path_free(tpb); + g_free(pa); + g_free(pb); + u->changed = TRUE; + } +} + +static gboolean _save(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + gchar *question, *answer, *choice, *pixmap; + gchar *tmp = NULL; + xmlNodePtr root, node; + + gtk_tree_model_get (model, iter, + QUESTION_COLUMN, &question, + ANSWER_COLUMN, &answer, + CHOICE_COLUMN, &choice, + PIXMAP_COLUMN, &pixmap, + -1); + if(valid_entry(question, answer, choice, pixmap)) + { + tmp = g_strdup_printf("%s/%s/%c/%c/%c", + answer, question, + choice[0], choice[1], choice[2]); + + root =(xmlNodePtr)data; + node = xmlNewChild(root, NULL, BAD_CAST "Board", NULL); + xmlNewChild(node, NULL,BAD_CAST "pixmapfile", BAD_CAST pixmap); + xmlNewChild(node, NULL, BAD_CAST "data", BAD_CAST tmp); + } + g_free(tmp); + g_free(question); + g_free(answer); + g_free(choice); + return FALSE; +} + +static void save_clicked(GtkButton *b, gpointer data) +{ + _config_missing *u = (_config_missing*)data; + GtkTreeModel *model; + gchar *filename; + xmlNodePtr root; + xmlDocPtr doc; + int level; + + level = gtk_combo_box_get_active(u->combo_level)+1; + if(level==0) + return; + if(! u->changed) + return; + model = gtk_tree_view_get_model(u->view); + doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION); + root = xmlNewNode(NULL, BAD_CAST "missing_letter"); + xmlDocSetRootElement(doc,root); + + gtk_tree_model_foreach(model, _save, root); + + filename = + gc_file_find_absolute_writeable("%s/board%d.xml", + gcomprisBoard_missing->boarddir, level); + if(xmlSaveFormatFileEnc(filename, doc, NULL, 1)<0) + g_warning("Fail to write %s", filename); + g_free(filename); + xmlFreeDoc(doc); + u->changed = FALSE; +} + +static void level_changed(GtkComboBox *combo, gpointer data) +{ + _config_missing *u = (_config_missing*)data; + GtkListStore *ls; + GtkTreeIter iter; + gchar *filename; + GList *list=NULL, *l; + gchar *tmp; + int level, result; + + level = gtk_combo_box_get_active(u->combo_level)+1; + if(level==0) + return; + if(u->changed) + { + GtkWidget *dialog; + + dialog = gtk_dialog_new_with_buttons("Save changes ?", + NULL, + GTK_DIALOG_MODAL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + NULL); + result = gtk_dialog_run(GTK_DIALOG(dialog)); + switch(result) + { + case GTK_RESPONSE_ACCEPT: + save_clicked(NULL, data); + break; + default: + u->changed=FALSE; + break; + } + gtk_widget_destroy (dialog); + } + ls = GTK_LIST_STORE(gtk_tree_view_get_model(u->view)); + filename = gc_file_find_absolute("%s/board%d.xml", + gcomprisBoard_missing->boarddir, level); + missing_read_xml_file(filename,&list); + g_free(filename); + gtk_list_store_clear(ls); + for(l=list; l; l=l->next) + { + Board *b = l->data; + gchar *pixfile = gc_file_find_absolute(b->pixmapfile); + GdkPixbuf *pixbuf; + + pixbuf = + gdk_pixbuf_new_from_file_at_size(pixfile, ICON_SIZE, ICON_SIZE, + NULL); + + tmp = g_strdup_printf("%s%s%s", b->l1, b->l2, b->l3); + + gtk_list_store_append(ls, &iter); + gtk_list_store_set(ls, &iter, + QUESTION_COLUMN, b->question, + ANSWER_COLUMN, b->answer, + CHOICE_COLUMN, tmp, + PIXMAP_COLUMN, b->pixmapfile, + PIXBUF_COLUMN, pixbuf, + -1); + g_free(tmp); + g_free(pixfile); + g_object_unref(pixbuf); + } + missing_destroy_board_list(list); +} + +static void text_changed(GtkWidget *widget, gpointer data) +{ + _config_missing *u = (_config_missing*)data; + + const gchar *question, *answer, *choice; + + question = gtk_entry_get_text(u->question); + answer = gtk_entry_get_text(u->answer); + choice = gtk_entry_get_text(u->choice); + + if(widget == (GtkWidget*)u->answer) + { + if(g_str_has_prefix(answer,question)) + { + gtk_entry_set_text(u->question,answer); + } + } + else if(widget ==(GtkWidget*) u->question) + { + if(strchr(question, '_')) + { + gchar ** split = g_strsplit(question,"_",2); + if(answer[strlen(split[0])]!= choice[0]) + { + gchar *tmp; + tmp = g_new0(gchar, 4); + tmp[0]= answer[strlen(split[0])]; + gtk_entry_set_text(u->choice, tmp); + g_free(tmp); + } + g_strfreev(split); + } + } +} + +void selection_changed (GtkTreeSelection *selection,gpointer data) +{ + _config_missing *u = (_config_missing*)data; + gchar *question, *answer, *choice, *pixmap, *pixfile; + GtkTreeModel *model; + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, + QUESTION_COLUMN, &question, + ANSWER_COLUMN, &answer, + CHOICE_COLUMN, &choice, + PIXMAP_COLUMN, &pixmap, + -1); + gtk_entry_set_text(u->question, question); + gtk_entry_set_text(u->answer, answer); + gtk_entry_set_text(u->choice, choice); + pixfile = gc_file_find_absolute(pixmap); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(u->pixmap), pixfile); + + g_free(question); + g_free(answer); + g_free(choice); + g_free(pixmap); + g_free(pixfile); + } +} + +void destroy_conf_data(void *not_used, gpointer *data) +{ + g_free(data); +} + +static void configure_colummns(GtkTreeView *treeview) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + /* pixbuf column */ + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes(_("Pixbuf"), + renderer, "pixbuf", PIXBUF_COLUMN, NULL); + gtk_tree_view_append_column(treeview, column); + + /* Answer column */ + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Answer"), + renderer, "text", ANSWER_COLUMN, NULL); + gtk_tree_view_append_column(treeview, column); + + /* Question column */ + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Question"), + renderer, "text", QUESTION_COLUMN, NULL); + gtk_tree_view_append_column(treeview, column); + + /* Choice column */ + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Choice"), + renderer, "text", CHOICE_COLUMN, NULL); + gtk_tree_view_append_column(treeview, column); +#if 0 + /* pixmap column */ + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Pixmap"), + renderer, "text", PIXMAP_COLUMN, NULL); + gtk_tree_view_append_column(treeview, column); +#endif +} + + void config_missing_letter(GcomprisBoardConf *config) + { + GtkWidget *frame, *view, *pixmap, *question, *answer, *choice; + GtkWidget *level, *vbox, *hbox, *label; + GtkWidget *bbox, *button, *table; + GtkFileFilter *file_filter; + _config_missing *conf_data; + int i; + + conf_data = g_new0(_config_missing,1); + + /* frame */ + frame = gtk_frame_new(""); + gtk_widget_show(frame); + gtk_box_pack_start(GTK_BOX(config->main_conf_box), frame, TRUE, TRUE, 8); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_widget_show(vbox); + gtk_container_add(GTK_CONTAINER(frame), vbox); + + /* hbox */ + hbox = gtk_hbox_new(FALSE, 8); + gtk_widget_show(hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 8); + + /* combo level */ + label = gtk_label_new(_("Choice of the level")); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 8); + + level = gtk_combo_box_new_text(); + for(i=1; i< gcomprisBoard_missing->maxlevel; i++) + { + gchar *tmp; + tmp = g_strdup_printf(_("Level %d"), i); + gtk_combo_box_append_text(GTK_COMBO_BOX(level), tmp); + g_free(tmp); + } + gtk_widget_show(level); + gtk_box_pack_start(GTK_BOX(hbox), level, FALSE, FALSE, 8); + + /* list view */ + GtkListStore *list = gtk_list_store_new(N_COLUMNS, + G_TYPE_STRING, /*Question */ + G_TYPE_STRING, /* Answer */ + G_TYPE_STRING, /* Choice */ + G_TYPE_STRING, /* pixmap */ + GDK_TYPE_PIXBUF /* pixbuf */ + ); + + view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list)); + configure_colummns(GTK_TREE_VIEW(view)); + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (view), ANSWER_COLUMN); + gtk_widget_set_size_request(view, -1, 200); + gtk_widget_show(view); + + GtkScrolledWindow *scroll = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL,NULL)); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_widget_show(GTK_WIDGET(scroll)); + gtk_container_add(GTK_CONTAINER(scroll), view); + + gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scroll), TRUE, TRUE, 10); + + /* button box */ + bbox = gtk_hbutton_box_new(); + gtk_widget_show(bbox); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 8); + button = gtk_button_new_from_stock(GTK_STOCK_NEW); + gtk_widget_show(button); + gtk_container_add(GTK_CONTAINER(bbox), button); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(new_clicked), (gpointer) conf_data); + + button = gtk_button_new_from_stock(GTK_STOCK_DELETE); + gtk_widget_show(button); + gtk_container_add(GTK_CONTAINER(bbox), button); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(delete_clicked), (gpointer) conf_data); + + button = gtk_button_new_from_stock(GTK_STOCK_APPLY); + gtk_widget_show(button); + gtk_container_add(GTK_CONTAINER(bbox), button); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(apply_clicked), (gpointer) conf_data); + + button = gtk_button_new_from_stock(GTK_STOCK_GO_UP); + gtk_widget_show(button); + gtk_container_add(GTK_CONTAINER(bbox), button); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(up_clicked), (gpointer) conf_data); + + button = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN); + gtk_widget_show(button); + gtk_container_add(GTK_CONTAINER(bbox), button); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(down_clicked), (gpointer) conf_data); + + button = gtk_button_new_from_stock(GTK_STOCK_SAVE); + gtk_widget_show(button); + gtk_container_add(GTK_CONTAINER(bbox), button); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(save_clicked), (gpointer) conf_data); + + /* table */ + table = gtk_table_new(2, 4, FALSE); + gtk_widget_show(table); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 8); + + /* answer */ + label = gtk_label_new(_("Answer")); + gtk_widget_show(label); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + + answer = gtk_entry_new(); + gtk_widget_show(answer); + gtk_table_attach_defaults(GTK_TABLE(table), answer, 1, 2, 0, 1); + + /* pixmap */ + label = gtk_label_new(_("Picture")); + gtk_widget_show(label); + gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 0, 1); + + pixmap = gtk_file_chooser_button_new(_("Choice of the filename"), + GTK_FILE_CHOOSER_ACTION_OPEN); + + file_filter = gtk_file_filter_new(); + gtk_file_filter_add_pixbuf_formats(file_filter); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(pixmap), file_filter); + gtk_widget_show(pixmap); + gtk_table_attach_defaults(GTK_TABLE(table), pixmap, 3, 4, 0, 1); + + /* question */ + label = gtk_label_new(_("Question")); + gtk_widget_show(label); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + + question = gtk_entry_new(); + gtk_widget_show(question); + gtk_table_attach_defaults(GTK_TABLE(table), question, 1, 2, 1, 2); + + /* choice */ + label = gtk_label_new(_("Choice")); + gtk_widget_show(label); + gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 1, 2); + + choice = gtk_entry_new(); + gtk_entry_set_max_length(GTK_ENTRY(choice), 3); + gtk_widget_show(choice); + gtk_table_attach_defaults(GTK_TABLE(table), choice, 3, 4, 1, 2); + + conf_data -> combo_level = GTK_COMBO_BOX(level); + conf_data -> view = GTK_TREE_VIEW(view); + conf_data -> pixmap = GTK_FILE_CHOOSER_BUTTON(pixmap); + conf_data -> question = GTK_ENTRY(question); + conf_data -> answer = GTK_ENTRY(answer); + conf_data -> choice = GTK_ENTRY(choice); + + GtkTreeSelection *selection; + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + + g_signal_connect(G_OBJECT(selection), + "changed", + G_CALLBACK(selection_changed), + (gpointer) conf_data); + g_signal_connect(G_OBJECT(frame), "destroy", + G_CALLBACK(destroy_conf_data), (gpointer) conf_data); + g_signal_connect(G_OBJECT(level), "changed", + G_CALLBACK(level_changed), (gpointer) conf_data); + g_signal_connect(G_OBJECT(question), "changed", + G_CALLBACK(text_changed), (gpointer) conf_data); + g_signal_connect(G_OBJECT(answer), "changed", + G_CALLBACK(text_changed), (gpointer) conf_data); + + gtk_combo_box_set_active(GTK_COMBO_BOX(level), 0); + level_changed(GTK_COMBO_BOX(level),conf_data); + } + diff --git a/src/boards/python/admin/board_list.py b/src/boards/python/admin/board_list.py index f29a448..4408dd2 100644 --- a/src/boards/python/admin/board_list.py +++ b/src/boards/python/admin/board_list.py @@ -167,13 +167,6 @@ class Board_list: self.button_locales_sound.show() box3.pack_end(self.button_locales_sound, False, False, 0) - self.button_wordlist = gtk.Button(_('Wordlist')) - self.button_wordlist.connect("clicked", self.wordlist) - self.button_wordlist.show() - box3.pack_end(self.button_wordlist, False, False, 0) - #not ready yet - self.button_wordlist.set_sensitive(False) - self.button_login = gtk.Button(_('Login')) self.button_login.connect("clicked", self.login_configure) self.button_login.show() diff --git a/src/boards/read_colors.c b/src/boards/read_colors.c index 67dc229..b6e3c7e 100644 --- a/src/boards/read_colors.c +++ b/src/boards/read_colors.c @@ -473,7 +473,7 @@ static gboolean read_xml_file(char *fname) g_return_val_if_fail(fname!=NULL,FALSE); /* parse the new file and put the result into newdoc */ - doc = gc_net_load_xml(fname); + doc = xmlParseFile(fname); /* in case something went wrong */ if(!doc) diff --git a/src/boards/reading.c b/src/boards/reading.c index 49210fc..f530f3c 100644 --- a/src/boards/reading.c +++ b/src/boards/reading.c @@ -458,7 +458,15 @@ static gboolean reading_create_item(GnomeCanvasGroup *parent) word = g_strdup(textToFind); } - g_assert(word!=NULL); + if(word==NULL) + { + gc_dialog(_("Skip this level. Not enough word in the list !"), + (DialogBoxCallBack)reading_next_level); + gcomprisBoard->level++; + if(gcomprisBoard->level>gcomprisBoard->maxlevel) // the current board is finished : bail out + gc_bonus_end_display(GC_BOARD_FINISHED_RANDOM); + return FALSE; + } if(textToFindIndex>=0) textToFindIndex--; @@ -777,6 +785,7 @@ static gchar * get_random_word(const gchar* except) { gchar *word; + int count=0; word = gc_wordlist_random_word_get(gc_wordlist, gcomprisBoard->level); @@ -784,6 +793,12 @@ get_random_word(const gchar* except) while(strcmp(except, word)==0) { g_free(word); + + if(count++>100) + { + word = NULL; + break; + } word = gc_wordlist_random_word_get(gc_wordlist, gcomprisBoard->level); } diff --git a/src/boards/shapegame.c b/src/boards/shapegame.c index fd68350..3fdb49e 100644 --- a/src/boards/shapegame.c +++ b/src/boards/shapegame.c @@ -1743,7 +1743,7 @@ read_xml_file(char *fname) g_return_val_if_fail(fname!=NULL,FALSE); /* parse the new file and put the result into newdoc */ - doc = gc_net_load_xml(fname); + doc = xmlParseFile(fname); /* in case something went wrong */ if(!doc) return FALSE; diff --git a/src/boards/superbrain.c b/src/boards/superbrain.c index 88295b1..f61015b 100644 --- a/src/boards/superbrain.c +++ b/src/boards/superbrain.c @@ -618,6 +618,10 @@ static void mark_pieces() current_y_position -= Y_STEP; + GList *l; + for(l=listPieces; l; l= l->next) + g_free(l->data); + g_list_free(listPieces); superbrain_create_item(boardRootItem); diff --git a/src/boards/wordprocessor.c b/src/boards/wordprocessor.c index 3420099..133077c 100644 --- a/src/boards/wordprocessor.c +++ b/src/boards/wordprocessor.c @@ -1027,7 +1027,7 @@ load_buffer(gchar *file, gchar *file_type) GtkTextIter iter_start, iter_end; /* parse the new file and put the result into newdoc */ - doc = gc_net_load_xml(file); + doc = xmlParseFile(file); /* in case something went wrong */ if(!doc) diff --git a/src/gcompris/Makefile.am b/src/gcompris/Makefile.am index c4707ed..d6ebad3 100644 --- a/src/gcompris/Makefile.am +++ b/src/gcompris/Makefile.am @@ -77,7 +77,6 @@ gcompris_SOURCES = \ board_config.h board_config.c \ bonus.c \ bonus.h \ - cache.c \ config.c \ dialog.c \ drag.c \ diff --git a/src/gcompris/board_config_wordlist.c b/src/gcompris/board_config_wordlist.c index c0dd7c1..a6364b2 100644 --- a/src/gcompris/board_config_wordlist.c +++ b/src/gcompris/board_config_wordlist.c @@ -49,7 +49,7 @@ static void _combo_level_changed(GtkComboBox *combo_level, gpointer user_data) } wordsArray = g_malloc0(sizeof(gpointer)*(g_slist_length(lw->words)+1)); - + for(i=0, list = lw->words; list; list=list->next) { wordsArray[i]=(gchar*)list->data; @@ -118,6 +118,22 @@ static void _textview_changed(GtkWidget *w, gpointer data) gtk_widget_set_sensitive(GTK_WIDGET(u->button), TRUE); } +static void _return_clicked(GtkWidget *w, gpointer data) +{ + int level; + user_param_type_wordlist *u = (user_param_type_wordlist*)data; + gchar *filename; + + filename = gc_file_find_absolute_writeable(u->wordlist->filename); + gc_cache_remove(filename); + g_free(filename); + + level = gtk_combo_box_get_active(u->combo_level)+1; + _combo_lang_changed(u->combo_lang, u); + gtk_combo_box_set_active(u->combo_level, level-1); + _combo_level_changed(u->combo_level, u); +} + static void _button_clicked(GtkWidget *w, gpointer data) { user_param_type_wordlist *u = (user_param_type_wordlist*)data; @@ -143,7 +159,7 @@ static void _button_clicked(GtkWidget *w, gpointer data) static void _destroy(GtkWidget *w, gpointer data) { user_param_type_wordlist *u = (user_param_type_wordlist*)data; - + gc_wordlist_free(u->wordlist); g_free(u); } @@ -161,7 +177,7 @@ GtkWidget *gc_board_config_wordlist(GcomprisBoardConf *config, const gchar *file const gchar *locale; /* frame */ - frame = gtk_frame_new("Change wordlist"); + frame = gtk_frame_new(_("Configure the list of words")); gtk_widget_show(frame); gtk_box_pack_start(GTK_BOX(config->main_conf_box), frame, FALSE, FALSE, 8); @@ -190,7 +206,7 @@ GtkWidget *gc_board_config_wordlist(GcomprisBoardConf *config, const gchar *file gtk_widget_show(combo_lang); hbox = gtk_hbox_new(FALSE, 8); - label = gtk_label_new(_("Choice language")); + label = gtk_label_new(_("Choice of the language")); gtk_widget_show(label); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 8); @@ -202,7 +218,7 @@ GtkWidget *gc_board_config_wordlist(GcomprisBoardConf *config, const gchar *file gtk_widget_show(combo_level); hbox = gtk_hbox_new(FALSE, 8); - label = gtk_label_new(_("Choice level")); + label = gtk_label_new(_("Choice of the level")); gtk_widget_show(label); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 8); @@ -223,10 +239,18 @@ GtkWidget *gc_board_config_wordlist(GcomprisBoardConf *config, const gchar *file gtk_container_add (GTK_CONTAINER(scroll), textview); /* valid button */ + hbox = gtk_hbox_new(FALSE, 8); + gtk_widget_show(hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 8); + + GtkWidget * b_default = gtk_button_new_with_label(_("Back to default")); + gtk_widget_show(b_default); + gtk_box_pack_start(GTK_BOX(hbox), b_default, FALSE, FALSE, 8); + button = gtk_button_new_from_stock(GTK_STOCK_APPLY); gtk_widget_show(button); gtk_widget_set_sensitive(button, FALSE); - gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 8); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 8); /* user_data */ user_data = g_malloc0(sizeof(user_param_type_wordlist)); @@ -246,6 +270,8 @@ GtkWidget *gc_board_config_wordlist(GcomprisBoardConf *config, const gchar *file G_CALLBACK(_textview_changed), (gpointer)user_data); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(_button_clicked), (gpointer)user_data); + g_signal_connect(G_OBJECT(b_default), "clicked", + G_CALLBACK(_return_clicked), (gpointer)user_data); _combo_lang_changed(GTK_COMBO_BOX(combo_lang), user_data); diff --git a/src/gcompris/cache.c b/src/gcompris/cache.c deleted file mode 100644 index 5eac982..0000000 --- a/src/gcompris/cache.c +++ /dev/null @@ -1,204 +0,0 @@ -/* gcompris - gameutil_net.c - * - * Time-stamp: <2006/07/10 01:24:04 bruno> - * - * Copyright (C) 2006 Bruno Coudoin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "gcompris.h" -#include "gc_core.h" -#include <string.h> - -/** \file Implementation of the cache functionality - * - */ - -/* The max size of the cache in bytes, - * 0 = NO LIMITS - * -1 = NO CACHE - */ -#ifdef USE_GNET -static int cache_max_size = 1000; - -static GHashTable *hash_cache = NULL; -#endif - -/** For debug only - */ -#ifdef USE_GNET -static void -_dump_cache(gchar *key, - gchar *value, - gpointer dummy) -{ - printf("cache %s = %s\n", key, value); -} - -static void dump_cache(void) -{ - g_hash_table_foreach(hash_cache, - (GHFunc) _dump_cache, - NULL); -} -#endif - -/** - * recursively parse the cache and fill up the hash with files there - */ -void _cache_init(const gchar *basedir, const gchar *currentdir) -{ -#ifdef USE_GNET - GcomprisProperties *properties = gc_prop_get(); - GDir *dir; - const gchar *file; - - if(!currentdir) - currentdir = basedir; - - dir = g_dir_open(currentdir, 0, NULL); - - printf(" _cache_init %s\n", currentdir); - - while((file = g_dir_read_name(dir))) - { - gchar *fullfile = g_strconcat(currentdir, "/", file, NULL); - printf(" processing file = %s\n", fullfile); - - if(g_file_test(fullfile, G_FILE_TEST_IS_DIR)) - { - _cache_init(basedir, fullfile); - } - else if(g_file_test(fullfile, G_FILE_TEST_IS_REGULAR)) - { - /* Strip file to get the KEY part out of it */ - printf(" Adding '%s' in the cache\n", fullfile); - g_hash_table_insert(hash_cache, - g_strconcat(properties->server, "/", - fullfile + strlen(basedir) + 1, - NULL), - g_strdup(fullfile)); - - } - g_free(fullfile); - } - - g_dir_close(dir); -#endif -} - -/** Initialize the cache system - * - * \param max_size: the max size in byte of the cache - * - */ -void gc_cache_init(int max_size) -{ -#ifdef USE_GNET - cache_max_size = max_size; - - /* No server defined, the cache is useless */ - if(!gc_prop_get()->server || - !gc_prop_get()->cache_dir) - return; - - hash_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - - printf("gc_cache_init\n"); - - /* try to create it */ - printf("Creating cache dir %s\n", gc_prop_get()->cache_dir); - if(g_mkdir_with_parents(gc_prop_get()->cache_dir, 0755)) - { - g_error("Failed to create the cache directory"); - } - printf(" opened top directory\n"); - /* Load the previous cache directory if any */ - _cache_init(gc_prop_get()->cache_dir, NULL); - - dump_cache(); -#endif -} - -/** End the cache system - * - */ -void gc_cache_end() -{ -#ifdef USE_GNET - - if(!hash_cache) - return; - - g_hash_table_destroy (hash_cache); - hash_cache = NULL; -#endif -} - - -#ifdef USE_GNET -static void -_clear_cache(gchar *key, - gchar *value, - gpointer dummy) -{ - printf("NOT IMPLEMENTED: Clearing chache %s:%s\n", key, value); -} -#endif - -/** Clear the cache. All files in the cache are removed - * - */ -void gc_cache_clear() -{ -#ifdef USE_GNET - g_hash_table_foreach(hash_cache, - (GHFunc) _clear_cache, - NULL); - -#endif -} - -/** Get a file from the cache based on it's URL - * - */ -gchar *gc_cache_get(gchar *url) -{ -#ifdef USE_GNET - return((char *)g_hash_table_lookup(hash_cache, url)); -#else - return NULL; -#endif -} - -/** Put and Get a file from the cache. The data in 'buffer' are saved in the - * cache under the name 'url'. A file is created and is returned. - * - * \param url: the url of the data in buffer - * \param buffer: the data for the url - * \param length: length of contents, or -1 if contents is a nul-terminated string - * - * \return a full path to the file in the cache - */ -gchar *gc_cache_insert(const gchar *url, const char *buffer, gssize length) -{ -#ifdef USE_GNET - /* Save the buffer in the cache */ - if(g_file_set_contents("TBD", buffer, length, NULL)) - g_hash_table_replace(hash_cache, (gpointer) url, (gpointer) "TBD"); -#endif - return("TBD"); -} diff --git a/src/gcompris/config.c b/src/gcompris/config.c index 18e18a3..3873a0e 100644 --- a/src/gcompris/config.c +++ b/src/gcompris/config.c @@ -630,7 +630,7 @@ set_locale_flag(gchar *locale) if(filename) { - pixmap = gc_net_load_pixmap(filename); + pixmap = gdk_pixbuf_new_from_file(filename,NULL); gnome_canvas_item_set (item_locale_flag, "pixbuf", pixmap, diff --git a/src/gcompris/dialog.c b/src/gcompris/dialog.c index b28ec10..9c89f25 100644 --- a/src/gcompris/dialog.c +++ b/src/gcompris/dialog.c @@ -27,9 +27,6 @@ static GnomeCanvasGroup *rootDialogItem = NULL; static GnomeCanvasItem *itemDialogText = NULL; static gint item_event_ok(GnomeCanvasItem *item, GdkEvent *event, DialogBoxCallBack dbcb); -typedef void (*sighandler_t)(int); - - /* * Close the dialog box if it was open. It not, do nothing. */ diff --git a/src/gcompris/gameutil.c b/src/gcompris/gameutil.c index db4c416..efccb69 100644 --- a/src/gcompris/gameutil.c +++ b/src/gcompris/gameutil.c @@ -32,10 +32,6 @@ #include "gcompris.h" -extern GnomeCanvas *canvas; - -typedef void (*sighandler_t)(int); - /* GdkPixbuf RGBA C-Source image dump for a NULL image*/ #ifdef __SUNPRO_C #pragma align 4 (null_img) @@ -87,7 +83,7 @@ GdkPixbuf *gc_pixmap_load(const gchar *format, ...) filename = gc_file_find_absolute(pixmapfile); if(filename) - pixmap = gc_net_load_pixmap(filename); + pixmap = gdk_pixbuf_new_from_file(filename,NULL); if (!filename || !pixmap) { @@ -542,8 +538,7 @@ gc_file_find_absolute(const gchar *format, ...) va_end (args); /* Check it's already found */ - if( g_file_test (filename, G_FILE_TEST_EXISTS) - || gc_net_is_url(filename) ) + if( g_file_test (filename, G_FILE_TEST_EXISTS)) { return filename; } @@ -552,6 +547,9 @@ gc_file_find_absolute(const gchar *format, ...) * Search it on the file system */ + if(properties->server) + dir_to_search[i++] = ""; + dir_to_search[i++] = properties->user_dir; dir_to_search[i++] = properties->package_data_dir; dir_to_search[i++] = NULL; @@ -602,6 +600,7 @@ gc_file_find_absolute(const gchar *format, ...) g_free(filename2); goto FOUND; } + g_free(absolute_filename); /* Now check if this file is on the net */ if((absolute_filename = gc_net_get_url_from_file(filename2, NULL))) @@ -640,6 +639,35 @@ gc_file_find_absolute(const gchar *format, ...) return absolute_filename; } +gchar* +gc_file_find_absolute_writeable(const gchar *format, ...) +{ + gchar *filename, *absolute_filename, *dirname; + GcomprisProperties *prop; + va_list args; + + va_start (args, format); + filename = g_strdup_vprintf (format, args); + va_end (args); + + prop = gc_prop_get(); + absolute_filename = g_build_filename(prop->user_dir, filename,NULL); + g_free(filename); + dirname = g_path_get_dirname(absolute_filename); + if(!g_file_test(dirname, G_FILE_TEST_IS_DIR)) + { + if(g_mkdir_with_parents(dirname, 0755)) + { + g_free(absolute_filename); + absolute_filename=NULL; + } + } + g_free(dirname); + if(absolute_filename) + gc_cache_add(absolute_filename); + return absolute_filename; +} + /** Create a directory if needed. * * \param rootdir: the directory to create diff --git a/src/gcompris/gameutil.h b/src/gcompris/gameutil.h index d82a100..d838508 100644 --- a/src/gcompris/gameutil.h +++ b/src/gcompris/gameutil.h @@ -63,6 +63,7 @@ GnomeCanvasGroup *gc_difficulty_display(GnomeCanvasGroup *parent, double x, doub /* find the complete filename looking for the file everywhere (printf formatting supported) */ gchar *gc_file_find_absolute(const gchar *filename, ...); +gchar *gc_file_find_absolute_writeable(const gchar *filename, ...); int gc_util_create_rootdir (gchar *rootdir); void gc_activity_intro_play (GcomprisBoard *gcomprisBoard); diff --git a/src/gcompris/gc_core.h b/src/gcompris/gc_core.h index 9a80cb2..b5d4a72 100644 --- a/src/gcompris/gc_core.h +++ b/src/gcompris/gc_core.h @@ -49,11 +49,4 @@ void gc_mime_type_load(); /** log */ void gc_log_start (GcomprisBoard *gcomprisBoard); -/** cache */ -void gc_cache_init(int max_size); -void gc_cache_end(); -void gc_cache_clear(); -gchar *gc_cache_get(gchar *url); -gchar *gc_cache_insert(const gchar *url, const char *buffer, gssize length); - #endif diff --git a/src/gcompris/gc_net.c b/src/gcompris/gc_net.c index 385a67b..455f925 100644 --- a/src/gcompris/gc_net.c +++ b/src/gcompris/gc_net.c @@ -21,10 +21,11 @@ #include "gc_net.h" #include "gc_core.h" - +#include <string.h> #ifdef USE_GNET #include <gnet.h> #endif +#include <glib/gstdio.h> /* FIXME: Should not be needed, a bug in gnet header ? */ gboolean gnet_http_get (const gchar *url, @@ -32,17 +33,33 @@ gboolean gnet_http_get (const gchar *url, gsize *length, guint *response); -#include <string.h> - #ifdef USE_GNET -static GSList *server_content_list = NULL; +static GHashTable *server_content = NULL; #define SUPPORT_OR_RETURN(rv) {if(!gc_prop_get()->server) return rv;} #else #define SUPPORT_OR_RETURN(rv) { return rv; } #endif +static void load_md5file(GHashTable *ht, gchar *content) +{ + gchar **lines, **keyval; + int i; -static inline int my_strcmp(gchar *a, gchar *b) { return strcmp( a, b); } + lines = g_strsplit(content, "\n", 0); + if(lines && lines[0]) + { + for(i=0; lines[i]; i++) + { + keyval = g_strsplit(lines[i], " ", 2); + if(keyval && keyval[0]) + { + g_hash_table_insert(ht, g_strdup(keyval[1]), g_strdup(keyval[0])); + } + g_strfreev(keyval); + } + } + g_strfreev(lines); +} /** Init the network library, must be called once before using it * @@ -70,15 +87,8 @@ void gc_net_init() if(gnet_http_get(url, &buf, &buflen, &response) && response == 200) { - char line[200]; - int i = 0; - /* Parse each line of the buffer and save it in 'server_content_list' */ - while( i < buflen) - { - sscanf(buf+i, "%s", (char *)&line); - server_content_list = g_slist_prepend(server_content_list, g_strdup(line)); - i+=strlen(line)+1; - } + server_content = g_hash_table_new(g_str_hash, g_str_equal); + load_md5file(server_content, buf); } else { @@ -93,81 +103,11 @@ void gc_net_init() #endif } -/** Load a pixmap localy or from the network - * - * \param pixmapfile : a full URL to the file to load as an image - * in case a local file is given, it will be loaded. - * \return a GdkPixbuf or NULL - */ -GdkPixbuf *gc_net_load_pixmap(const char *url) -{ - if(!gc_net_is_url(url)) - return(gdk_pixbuf_new_from_file (url, NULL)); - - SUPPORT_OR_RETURN(NULL); - -#ifdef USE_GNET - gchar *buf = NULL; - gsize buflen; - guint response; - - g_warning("Loading image from url '%s'", url); - - if(gnet_http_get(url, &buf, &buflen, &response) && response == 200) - { - GdkPixbuf *pixmap=NULL; - GdkPixbufLoader* loader; - loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, (guchar *)buf, buflen, NULL); - g_free(buf); - gdk_pixbuf_loader_close(loader, NULL); - pixmap = gdk_pixbuf_loader_get_pixbuf(loader); - if(!pixmap) - g_warning("Loading image from url '%s' returned a null pointer", url); - - return(pixmap); - } - - g_free(buf); - return(NULL); - -#endif -} - -/** Load an xml file from the network - * - * \param xmlfile : a full URL to the xml file to load as an xmlDocPtr - * in case a local file is given, it will be loaded. - * \return a xmlDocPtr or NULL - */ -xmlDocPtr gc_net_load_xml(const char *url) +void gc_net_destroy(void) { - if(!gc_net_is_url(url)) - return(xmlParseFile(url)); - - SUPPORT_OR_RETURN(NULL); - -#ifdef USE_GNET - gchar *buf = NULL; - gsize buflen; - guint response; - - g_warning("Loading xml file from url '%s'", url); - - if(gnet_http_get(url, &buf, &buflen, &response) && response == 200) - { - xmlDocPtr doc = xmlParseMemory((const char *)buf, buflen); - g_free(buf); - if(!buf) - g_warning("Loading xml file from url '%s' returned a null pointer", url); - - return(doc); - } - - g_free(buf); - return(NULL); - -#endif + if(server_content) + g_hash_table_destroy(server_content); + server_content = NULL; } /** return an absolute URL if the given file is part of the file available on our server @@ -182,51 +122,70 @@ gc_net_get_url_from_file(const gchar *format, ...) #ifdef USE_GNET GcomprisProperties *properties = gc_prop_get(); - gchar *file, *url; + gchar *file, *cache=NULL, *value; va_list args; + gboolean cache_ok=FALSE; va_start (args, format); file = g_strdup_vprintf (format, args); va_end (args); - /* FIXME: In case the file does not starts with boards/, preprend it */ + g_warning("gc_net_get_url_from_file '%s'", file); + + value = g_hash_table_lookup(server_content, (gpointer) file); + if(value) { - if(strncmp(file, "boards/", 7)) - { - gchar *file2 = g_strconcat("boards/", file, NULL); - g_free(file); - file = file2; - } - } + cache = g_strconcat(properties->cache_dir, "/", file, NULL); + if(g_file_test(cache, G_FILE_TEST_IS_REGULAR)) + { + gchar * content; + gsize length; + GMD5 *md5cache, *md5serv; - g_warning("gc_net_get_url_from_file '%s'", file); - if(!g_slist_find_custom(server_content_list,(gconstpointer) file, (GCompareFunc) my_strcmp)) + /* calc md5 of cache file */ + g_file_get_contents(cache, &content, &length, NULL); + md5cache = gnet_md5_new(content, length); + g_free(content); + + md5serv = gnet_md5_new_string(value); + + cache_ok = gnet_md5_equal(md5serv, md5cache); + + gnet_md5_delete(md5serv); + gnet_md5_delete(md5cache); + } + if(cache_ok==0) { - g_free(file); - return NULL; + gchar *url; + gchar *buf = NULL; + gsize buflen; + guint response; + + url = g_strconcat(properties->server, "/", file, NULL); + if(gnet_http_get(url, &buf, &buflen, &response) && response == 200) + { + gchar *dirname; + + dirname = g_path_get_dirname(cache); + g_mkdir_with_parents(dirname, 0755); + g_free(dirname); + g_file_set_contents(cache, buf, buflen, NULL); + g_free(buf); + } + else + { /* file is in content.txt but not in server */ + g_free(cache); + cache = NULL; + } } - url = g_strconcat(properties->server, "/", file, NULL); + } g_free(file); - g_warning("gc_net_get_url_from_file returns url '%s'", url); - return url; + return cache; #endif } -/** return TRUE if the url starts with http:// - * - * \param url: an url to check - * \return TRUE is the url starts with 'http://' - */ -gboolean -gc_net_is_url(const gchar *url) -{ - if( !url || strncmp(url, "http://", 7) ) - return FALSE; - - return TRUE; -} - +#if 0 /** return a glist with the content of the files in the given directory * * \param dir: the directory to scan @@ -256,3 +215,157 @@ GSList *gc_net_dir_read_name(const gchar* dir, const gchar *ext) return(filelist); #endif } +#endif + + +#define CONTENT_FILENAME "content.txt" + +static GHashTable *cache_content=NULL; + +void gc_cache_init(void) +{ + gchar *filename; + gchar *buf; + gsize buflen; + + cache_content = g_hash_table_new(g_str_hash, g_str_equal); + filename = gc_file_find_absolute_writeable(CONTENT_FILENAME); + + if(g_file_get_contents(filename, &buf, &buflen,NULL)) + { + load_md5file(cache_content, buf); + g_free(buf); + } + g_free(filename); +} + +static gchar *gc_cache_get_relative(gchar *filename) +{ + gchar *filename_content, *dirname; + + filename_content = gc_file_find_absolute_writeable(CONTENT_FILENAME); + dirname = g_path_get_dirname(filename_content); + if(g_str_has_prefix(filename, dirname)) + filename = filename + strlen(dirname) + 1; + g_free(filename_content); + g_free(dirname); + return filename; +} + +void gc_cache_add(gchar *filename) +{ + if(cache_content==NULL) + return; + if(g_str_has_suffix(filename, CONTENT_FILENAME)) + return; + + filename = gc_cache_get_relative(filename); + g_hash_table_insert(cache_content, g_strdup(filename), g_strdup("0")); +} + +gchar* gc_cache_import_pixmap(gchar *filename, gchar *boarddir, gint width, gint height) +{ + GdkPixbuf *pixmap; + gchar *basename, *file, *ext, *name, *abs; + + if(!g_path_is_absolute(filename)) + return g_strdup(filename); + basename = g_path_get_basename(filename); + name = g_build_filename(boarddir, basename,NULL); + abs = gc_file_find_absolute(name); + if(abs && strcmp(abs,filename)==0) + { + g_free(basename); + g_free(abs); + return name; + } + pixmap = gdk_pixbuf_new_from_file_at_size(filename, width, height,NULL); + if(!pixmap) + { + g_free(abs); + g_free(basename); + g_free(name); + return NULL; + } + + file = gc_file_find_absolute_writeable(name); + ext = strchr(basename, '.')+1; + if(strcmp(ext, "jpg")==0) + ext ="jpeg"; + + gdk_pixbuf_save(pixmap, file, ext, NULL,NULL); + + g_free(abs); + g_free(basename); + g_free(file); + return name; +} + +void gc_cache_remove(gchar *filename) +{ + g_remove(filename); + filename = gc_cache_get_relative(filename); + g_hash_table_remove(cache_content, filename); +} + +struct _table_data +{ +FILE *pf; +gchar *path; +}; + +static void _table_foreach(gpointer key, gpointer value, gpointer user_data) +{ + struct _table_data *data = (struct _table_data*)user_data; + gchar * content, *filename; + gsize length; + GMD5 *md5; + + if(strcmp(value, "0")==0) + { + filename = g_build_filename(data->path, (gchar*)key, NULL); + if(g_file_get_contents(filename, &content, &length, NULL)) + { + md5 = gnet_md5_new(content, length); + value = gnet_md5_get_string(md5); + gnet_md5_delete(md5); + g_free(content); + } + g_free(filename); + } + if(strcmp(value, "0")) + { + fprintf(data->pf, "%s %s\n", (gchar*)value, (gchar*)key); + } +} + +void gc_cache_save(void) +{ + struct _table_data data; + FILE *pf; + gchar *filename; + + filename = gc_file_find_absolute_writeable(CONTENT_FILENAME); + pf = fopen(filename, "w"); + if(!pf) + { + g_warning("Couldn't save %s\n", filename); + return; + } + + data.pf = pf; + data.path = g_path_get_dirname(filename); + g_hash_table_foreach(cache_content, _table_foreach, &data); + + g_free(filename); + g_free(data.path); + fclose(pf); +} + +void gc_cache_destroy(void) +{ + gc_cache_save(); + g_hash_table_destroy(cache_content); + cache_content = NULL; +} + diff --git a/src/gcompris/gc_net.h b/src/gcompris/gc_net.h index dc777e1..b8675b5 100644 --- a/src/gcompris/gc_net.h +++ b/src/gcompris/gc_net.h @@ -35,10 +35,15 @@ #include "gcompris.h" void gc_net_init(); -GdkPixbuf *gc_net_load_pixmap(const char *url); -xmlDocPtr gc_net_load_xml(const char *url); gchar *gc_net_get_url_from_file(const gchar *format, ...); -gboolean gc_net_is_url(const char *url); GSList *gc_net_dir_read_name(const gchar* dir, const gchar *ext); +void gc_net_destroy(); + +void gc_cache_init(void); +void gc_cache_add(gchar *filename); +gchar* gc_cache_import_pixmap(gchar *filename, gchar *boarddir, gint width, gint height); +void gc_cache_remove(gchar *filename); +void gc_cache_save(void); +void gc_cache_destroy(void); #endif diff --git a/src/gcompris/gcompris.c b/src/gcompris/gcompris.c index fa13bf0..fafdbf8 100644 --- a/src/gcompris/gcompris.c +++ b/src/gcompris/gcompris.c @@ -675,7 +675,7 @@ static void setup_window () if(!icon_file) g_warning ("Couldn't find file %s !", icon_file); - icon_pixbuf = gc_net_load_pixmap(icon_file); + icon_pixbuf = gdk_pixbuf_new_from_file(icon_file,NULL); if (!icon_pixbuf) { g_warning ("Failed to load pixbuf file: %s\n", @@ -1057,6 +1057,8 @@ static void cleanup() xf86_vidmode_set_fullscreen(FALSE); #endif gc_menu_destroy(); + gc_net_destroy(); + gc_cache_destroy(); gc_prop_destroy(gc_prop_get()); } @@ -1692,8 +1694,7 @@ main (int argc, char *argv[]) } } } - /* FIXME: Need to translate */ - printf("Number of activities: %d\n", board_count); + printf(_("Number of activities: %d\n"), board_count); exit(0); } @@ -1729,7 +1730,7 @@ main (int argc, char *argv[]) { if (g_access(properties->database, R_OK)==-1) { - printf("%s exists but is not readable or writable", properties->database); + printf(_("%s exists but is not readable or writable"), properties->database); exit(0); } } @@ -1788,8 +1789,10 @@ main (int argc, char *argv[]) if (popt_server){ #ifdef USE_GNET properties->server = g_strdup(popt_server); + printf(" Server '%s'\n", properties->server); #else - printf("The --server option cannot be used because GCompris has been compiled without network support!"); + printf(_("The --server option cannot be used because" + "GCompris has been compiled without network support!")); exit(1); #endif } @@ -1803,7 +1806,11 @@ main (int argc, char *argv[]) } if (popt_server){ + if(popt_cache_dir) properties->cache_dir = g_strdup(popt_cache_dir); + else + properties->cache_dir = g_build_filename(g_get_user_cache_dir(), "gcompris", NULL); + printf(" Cache dir '%s'\n",properties->cache_dir); } if (popt_drag_mode){ @@ -1835,7 +1842,8 @@ main (int argc, char *argv[]) if(properties->profile == NULL) { - printf("ERROR: Profile '%s' is not found. Run 'gcompris --profile-list' to list available ones\n", + printf(_("ERROR: Profile '%s' is not found." + " Run 'gcompris --profile-list' to list available ones\n"), popt_profile); exit(1); } @@ -1871,6 +1879,10 @@ main (int argc, char *argv[]) /*------------------------------------------------------------*/ + /* networking init */ + gc_net_init(); + gc_cache_init(); + gc_skin_load(properties->skin); if(properties->music || properties->fx) @@ -1879,12 +1891,6 @@ main (int argc, char *argv[]) /* Gdk-Pixbuf */ gdk_rgb_init(); - /* Cache init */ - gc_cache_init(-1); - - /* networking init */ - gc_net_init(); - setup_window (); if (properties->fullscreen) diff --git a/src/gcompris/images_selector.c b/src/gcompris/images_selector.c index d97092c..f6cb334 100644 --- a/src/gcompris/images_selector.c +++ b/src/gcompris/images_selector.c @@ -277,8 +277,8 @@ gc_selector_images_start (GcomprisBoard *gcomprisBoard, gchar *dataset, g_free(dataseturl); dataseturl = g_strconcat("boards/", dataset, NULL); - - filelist = gc_net_dir_read_name(dataseturl, ".xml"); + /* TODO */ + filelist = NULL; //gc_net_dir_read_name(dataseturl, ".xml"); for (i = filelist; i != NULL; i = g_slist_next (i)) { @@ -822,7 +822,7 @@ read_xml_file(gchar *fname) g_return_val_if_fail(fname!=NULL, FALSE); - doc = gc_net_load_xml(fname); + doc = xmlParseFile(fname); /* in case something went wrong */ if(!doc) diff --git a/src/gcompris/skin.c b/src/gcompris/skin.c index 42d1d8b..a8abbe7 100644 --- a/src/gcompris/skin.c +++ b/src/gcompris/skin.c @@ -271,7 +271,7 @@ skin_xml_load (gchar* skin) return; } - xmldoc = gc_net_load_xml(xmlfilename); + xmldoc = xmlParseFile(xmlfilename); g_free(xmlfilename); if(!xmldoc) diff --git a/src/gcompris/wordlist.c b/src/gcompris/wordlist.c index 9e2186a..59dfb61 100644 --- a/src/gcompris/wordlist.c +++ b/src/gcompris/wordlist.c @@ -385,7 +385,7 @@ void gc_wordlist_save(GcomprisWordlist *wordlist) } } - filename = gc_file_find_absolute(wordlist->filename); + filename = gc_file_find_absolute_writeable(wordlist->filename); if(filename) { if(xmlSaveFormatFileEnc(filename, doc, NULL, 1)<0) |