Logo Search packages:      
Sourcecode: kanatest version File versions

stats.c

/*
 * Kanatest
 *
 * Copyright (C) 2001-2004, 2006 Tomasz Maka <pasp@users.sourceforge.net>
 *
 * 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 <config.h>

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <libxml/parser.h>

#include "i18n.h"
#include "gui_utils.h"
#include "main.h"
#include "test.h"
#include "chart.h"
#include "prefs.h"
#include "stats.h"


/*--------------------------------------------------------------------*/

void
stats_window_close_cb (GtkWidget *widget, gpointer user_data) {

    GUI *appGUI = (GUI *)user_data;

    appGUI->sts->active_tab = gtk_notebook_get_current_page (GTK_NOTEBOOK (appGUI->sts->notebook));

    gtk_window_get_size (GTK_WINDOW((appGUI->sts)->stat_window),
                        &config.stat_size_x, &config.stat_size_y);
    gdk_window_get_root_origin (appGUI->sts->stat_window->window,
                                &config.stat_window_x, &config.stat_window_y);
    gtk_widget_destroy (appGUI->sts->stat_window);
}

/*--------------------------------------------------------------------*/

void
stats_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) {
    stats_window_close_cb (widget, user_data);
}

/*--------------------------------------------------------------------*/

gint
stats_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {

    GUI *appGUI = (GUI *)user_data;

    if (event->keyval == GDK_Escape) {
        stats_window_close_cb(widget, appGUI);
        return TRUE;
    }

    return FALSE;
}

/*--------------------------------------------------------------------*/

void
stats_reset_cb (GtkWidget *widget, gpointer user_data) {

GtkWidget *info_dialog, *label;
gint i, response;
GtkWidget *remove_lessons_check_button;
GtkWidget *remove_hiragana_stats_check_button;
GtkWidget *remove_katakana_stats_check_button;
gchar buffer[BUFFER_SIZE];

    GUI *appGUI = (GUI *)user_data;

    g_snprintf (buffer, BUFFER_SIZE, "\n%s:", _("Please select options"));

    info_dialog = gtk_message_dialog_new (GTK_WINDOW(appGUI->sts->stat_window),
                                          GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
                                          GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, buffer);

    gtk_window_set_title(GTK_WINDOW(info_dialog), _("Question"));
    gtk_widget_show (info_dialog);

    if (stats_get_records(appGUI) != 0) {
        remove_lessons_check_button = gtk_check_button_new_with_mnemonic (_("Remove lessons list"));
        gtk_widget_show (remove_lessons_check_button);
        gtk_box_pack_start (GTK_BOX(GTK_DIALOG(info_dialog)->vbox), remove_lessons_check_button, FALSE, TRUE, 2);
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(remove_lessons_check_button ), TRUE);
    }

    remove_hiragana_stats_check_button = gtk_check_button_new_with_mnemonic (_("Remove Hiragana statistics"));
    gtk_widget_show (remove_hiragana_stats_check_button);
    gtk_box_pack_start (GTK_BOX(GTK_DIALOG(info_dialog)->vbox), remove_hiragana_stats_check_button, FALSE, TRUE, 2);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(remove_hiragana_stats_check_button ), TRUE);

    remove_katakana_stats_check_button = gtk_check_button_new_with_mnemonic (_("Remove Katakana statistics"));
    gtk_widget_show (remove_katakana_stats_check_button);
    gtk_box_pack_start (GTK_BOX(GTK_DIALOG(info_dialog)->vbox), remove_katakana_stats_check_button, FALSE, TRUE, 2);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(remove_katakana_stats_check_button ), TRUE);

    label = gtk_label_new (_("No further recovery will be possible. Continue ?"));
    gtk_widget_show (label);
    gtk_box_pack_start (GTK_BOX(GTK_DIALOG(info_dialog)->vbox), label, TRUE, TRUE, 6);

    response = gtk_dialog_run(GTK_DIALOG(info_dialog));

    if (response == GTK_RESPONSE_YES) {

        if (stats_get_records(appGUI) != 0 && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(remove_lessons_check_button )) ==  TRUE) {
            stats_remove_list (appGUI);
        }

        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(remove_hiragana_stats_check_button )) ==  TRUE) {
            for (i=0; i < NUMBER_OF_SIGNS; i++) {
                appGUI->sts->correct_hiragana_counters[i] = 0;
                appGUI->sts->hiragana_counters[i] = 0;
            }
        }

        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(remove_katakana_stats_check_button )) ==  TRUE) {
            for (i=0; i < NUMBER_OF_SIGNS; i++) {
                appGUI->sts->correct_katakana_counters[i] = 0;
                appGUI->sts->katakana_counters[i] = 0;
            }
        }

        gtk_widget_destroy(info_dialog);
        stats_window_close_cb(appGUI->sts->stat_window, appGUI);

    } else {
        gtk_widget_destroy(info_dialog);
    }
}

/*--------------------------------------------------------------------*/

void
stats_column_clicked_cb (GtkTreeViewColumn *treeviewcolumn, gpointer user_data) {

    MESSAGE *msg = (MESSAGE *)user_data;

    msg->appGUI->sts->old_column = config.stats_sort_column;
    config.stats_sort_column = (gint) msg->data;

    if (msg->appGUI->sts->disable_dir == FALSE) {

        if (msg->appGUI->sts->old_column == config.stats_sort_column) {
            config.stats_sort_column_dir *= -1;
        } else {
            config.stats_sort_column_dir = 1;
        }
    }
}

/*--------------------------------------------------------------------*/

void
stats_create_window (GUI *appGUI) {

GtkWidget       *vbox1, *vbox2;
GtkWidget       *vbox3, *vbox4;
GtkWidget       *vbox5, *vbox6;
GtkWidget       *hbuttonbox;
GtkWidget       *close_button;
GtkWidget       *reset_button;
GtkWidget       *hseparator;
GtkWidget       *stats_scrolledwindow;
GtkWidget       *stats_treeview;
GtkWidget       *label;
GtkWidget       *table_hiragana;
GtkWidget       *scrolledwindow_hiragana;
GtkWidget       *viewport_hiragana;
GtkWidget       *table_katakana;
GtkWidget       *scrolledwindow_katakana;
GtkWidget       *viewport_katakana;
GtkWidget       *frames_hiragana[CHART_ROWS*CHART_COLUMNS];
GtkWidget       *frames_katakana[CHART_ROWS*CHART_COLUMNS];
GtkListStore    *stats_store;
GtkTreeModel    *stats_model;
GtkCellRenderer *stats_renderer;
GtkTreeIter     stats_iter;
gint            i, j, cpos, pos;
GSList          *lnode;
gchar           buffer[BUFFER_SIZE];
static          MESSAGE msg[NUMBER_OF_COLUMNS];
gdouble         ratio;
gchar           color_str[BUFFER_SIZE];
stats_entry     *entry;

GtkTreeViewColumn   *stats_column[NUMBER_OF_COLUMNS];

gchar *column_names[NUMBER_OF_COLUMNS] = {
    _("Date"), _("Test mode"), _("Test time"), _("Questions"),
    _("Correct"), _("Wrong"), _("Ratio (%)"), _("Kana set")
};

    appGUI->sts->stat_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_transient_for(GTK_WINDOW(appGUI->sts->stat_window),GTK_WINDOW(appGUI->main_window));
    gtk_window_set_modal(GTK_WINDOW(appGUI->sts->stat_window), TRUE);
    gtk_container_set_border_width (GTK_CONTAINER (appGUI->sts->stat_window), 12);
    gtk_window_set_title (GTK_WINDOW (appGUI->sts->stat_window), _("Statistics"));

    g_signal_connect (G_OBJECT (appGUI->sts->stat_window), "delete_event",
                        G_CALLBACK(stats_delete_event_cb), appGUI);
    g_signal_connect (G_OBJECT(appGUI->sts->stat_window), "key_press_event",
                        G_CALLBACK(stats_key_press_cb), appGUI);

    gtk_window_move (GTK_WINDOW (appGUI->sts->stat_window),
                                config.stat_window_x, config.stat_window_y);

    gtk_window_set_default_size (GTK_WINDOW(appGUI->sts->stat_window),
                                config.stat_size_x, config.stat_size_y);

    gtk_window_set_resizable (GTK_WINDOW (appGUI->sts->stat_window), TRUE);


    vbox1 = gtk_vbox_new (FALSE, 0);
    gtk_widget_show (vbox1);
    gtk_container_add (GTK_CONTAINER (appGUI->sts->stat_window), vbox1);

    appGUI->sts->notebook = gtk_notebook_new ();
    GTK_WIDGET_UNSET_FLAGS(appGUI->sts->notebook, GTK_CAN_FOCUS);
    gtk_widget_show (appGUI->sts->notebook);
    gtk_box_pack_start (GTK_BOX (vbox1), appGUI->sts->notebook, TRUE, TRUE, 4);

    /* lessons stats */

    vbox2 = gtk_vbox_new (FALSE, 0);
    gtk_widget_show (vbox2);
    label = gtk_label_new (_("Lessons"));
    if (stats_get_records(appGUI) != 0) {
        gtk_notebook_append_page(GTK_NOTEBOOK(appGUI->sts->notebook), vbox2, label);
    }

    stats_scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
    gtk_widget_show (stats_scrolledwindow);
    gtk_box_pack_start (GTK_BOX (vbox2), stats_scrolledwindow, TRUE, TRUE, 4);
    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (stats_scrolledwindow), GTK_SHADOW_IN);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (stats_scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

    stats_store = gtk_list_store_new (NUMBER_OF_COLUMNS,
                                      G_TYPE_STRING,
                                      G_TYPE_STRING,
                                      G_TYPE_STRING,
                                      G_TYPE_INT,
                                      G_TYPE_INT,
                                      G_TYPE_INT,
                                      G_TYPE_INT,
                                      G_TYPE_STRING);

    stats_model = GTK_TREE_MODEL(stats_store);

    stats_treeview = gtk_tree_view_new_with_model (stats_model);
    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (stats_treeview), TRUE);
    gtk_tree_view_set_search_column (GTK_TREE_VIEW (stats_treeview), 0);
    gtk_container_add(GTK_CONTAINER (stats_scrolledwindow), stats_treeview);
    gtk_widget_show (stats_treeview);

    stats_renderer = gtk_cell_renderer_text_new ();

    for (i=0; i < NUMBER_OF_COLUMNS; i++) {
        stats_column[i] = gtk_tree_view_column_new_with_attributes (column_names[i],
                                stats_renderer, "text", i, NULL);
        gtk_tree_view_column_set_sort_column_id (stats_column[i], i);
        gtk_tree_view_append_column (GTK_TREE_VIEW(stats_treeview), stats_column[i]);
        msg[i].data = (gpointer)i;
        msg[i].appGUI = appGUI;
        g_signal_connect (G_OBJECT(stats_column[i]), "clicked",
                          G_CALLBACK(stats_column_clicked_cb), &msg[i]);
    }

    /* hiragana stats */

    vbox3 = gtk_vbox_new (FALSE, 0);
    gtk_widget_show (vbox3);
    label = gtk_label_new (_("Hiragana"));
    gtk_notebook_append_page(GTK_NOTEBOOK(appGUI->sts->notebook), vbox3, label);

    scrolledwindow_hiragana = gtk_scrolled_window_new (NULL, NULL);
    gtk_widget_show (scrolledwindow_hiragana);
    gtk_box_pack_start (GTK_BOX (vbox3), scrolledwindow_hiragana, TRUE, TRUE, 0);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_hiragana), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);

    viewport_hiragana = gtk_viewport_new (NULL, NULL);
    gtk_widget_show (viewport_hiragana);
    gtk_container_add (GTK_CONTAINER (scrolledwindow_hiragana), viewport_hiragana);

    vbox4 = gtk_vbox_new (FALSE, 0);
    gtk_widget_show (vbox4);
    gtk_container_add (GTK_CONTAINER (viewport_hiragana), vbox4);

    table_hiragana = gtk_table_new (CHART_ROWS, CHART_COLUMNS, FALSE);
    gtk_widget_show (table_hiragana);
    gtk_box_pack_start (GTK_BOX (vbox4), table_hiragana, FALSE, TRUE, 0);

    cpos = pos = 0;

    for(j=0; j < CHART_ROWS; j++) {
        for(i=0; i < CHART_COLUMNS; i++) {

            if(get_kana_sign_mask(j, i)) {

                frames_hiragana[pos] = gtk_frame_new (NULL);
                gtk_widget_show (frames_hiragana[pos]);
                gtk_table_attach (GTK_TABLE (table_hiragana), frames_hiragana[pos], i, i+1, j, j+1,
                                  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
                                  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
                gtk_container_set_border_width (GTK_CONTAINER (frames_hiragana[pos]), 2);
                gtk_frame_set_shadow_type (GTK_FRAME (frames_hiragana[pos]), GTK_SHADOW_ETCHED_OUT);

                appGUI->chr->labels[pos] = gtk_label_new (NULL);
                gtk_widget_show (appGUI->chr->labels[pos]);
                gtk_container_add (GTK_CONTAINER (frames_hiragana[pos]), appGUI->chr->labels[pos]);
                gtk_misc_set_padding (GTK_MISC (appGUI->chr->labels[pos]), 0, 4);

                if (appGUI->sts->hiragana_counters[cpos] > 0) {
                    ratio = ((double)appGUI->sts->correct_hiragana_counters[cpos]/appGUI->sts->hiragana_counters[cpos])*100.0;
                } else {
                    ratio = 0;
                }

                g_strlcpy (color_str, "#b00000", BUFFER_SIZE);     /* red */
                if (ratio > 50 && ratio < 80) {
                    g_strlcpy (color_str, "#0000b0", BUFFER_SIZE);     /* blue */
                } else if (ratio >= 80) {
                    g_strlcpy (color_str, "#008800", BUFFER_SIZE);     /* green */
                }

                g_snprintf (buffer, BUFFER_SIZE, "<span face='%s'>%s/%s</span>: <span color='%s'>%d/%d</span> (%.f %%)",
                            config.kana_font_face,
                            get_kana_sign(cpos, HIRAGANA), get_kana_sign(cpos, ROMAJI), color_str, 
                            appGUI->sts->correct_hiragana_counters[cpos], appGUI->sts->hiragana_counters[cpos], ratio);

                gtk_label_set_markup (GTK_LABEL (appGUI->chr->labels[pos]), buffer);
                cpos++;
            }

            pos++;
        }
    }

    /* katakana */

    vbox5 = gtk_vbox_new (FALSE, 0);
    gtk_widget_show (vbox5);
    label = gtk_label_new (_("Katakana"));
    gtk_notebook_append_page(GTK_NOTEBOOK(appGUI->sts->notebook), vbox5, label);

    scrolledwindow_katakana = gtk_scrolled_window_new (NULL, NULL);
    gtk_widget_show (scrolledwindow_katakana);
    gtk_box_pack_start (GTK_BOX (vbox5), scrolledwindow_katakana, TRUE, TRUE, 0);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow_katakana), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);

    viewport_katakana = gtk_viewport_new (NULL, NULL);
    gtk_widget_show (viewport_katakana);
    gtk_container_add (GTK_CONTAINER (scrolledwindow_katakana), viewport_katakana);

    vbox6 = gtk_vbox_new (FALSE, 0);
    gtk_widget_show (vbox6);
    gtk_container_add (GTK_CONTAINER (viewport_katakana), vbox6);

    table_katakana = gtk_table_new (CHART_ROWS, CHART_COLUMNS, FALSE);
    gtk_widget_show (table_katakana);
    gtk_box_pack_start (GTK_BOX (vbox6), table_katakana, FALSE, TRUE, 0);

    cpos = pos = 0;

    for(j=0; j < CHART_ROWS; j++) {
        for(i=0; i < CHART_COLUMNS; i++) {

            if(get_kana_sign_mask(j, i)) {

                frames_katakana[pos] = gtk_frame_new (NULL);
                gtk_widget_show (frames_katakana[pos]);
                gtk_table_attach (GTK_TABLE (table_katakana), frames_katakana[pos], i, i+1, j, j+1,
                                  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
                                  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
                gtk_container_set_border_width (GTK_CONTAINER (frames_katakana[pos]), 2);
                gtk_frame_set_shadow_type (GTK_FRAME (frames_katakana[pos]), GTK_SHADOW_ETCHED_OUT);


                appGUI->chr->labels[pos] = gtk_label_new (NULL);
                gtk_widget_show (appGUI->chr->labels[pos]);
                gtk_container_add (GTK_CONTAINER (frames_katakana[pos]), appGUI->chr->labels[pos]);
                gtk_misc_set_padding (GTK_MISC (appGUI->chr->labels[pos]), 0, 4);

                if (appGUI->sts->katakana_counters[cpos] > 0) {
                    ratio = ((double)appGUI->sts->correct_katakana_counters[cpos]/appGUI->sts->katakana_counters[cpos])*100.0;
                } else {
                    ratio = 0;
                }

                g_strlcpy (color_str, "#b00000", BUFFER_SIZE);     /* red */
                if (ratio > 50 && ratio < 80) {
                    g_strlcpy (color_str, "#0000b0", BUFFER_SIZE);     /* blue */
                } else if (ratio >= 80) {
                    g_strlcpy (color_str, "#008800", BUFFER_SIZE);     /* green */
                }

                g_snprintf (buffer, BUFFER_SIZE, "<span face='%s'>%s/%s</span>: <span color='%s'>%d/%d</span> (%.f %%)",
                            config.kana_font_face,
                            get_kana_sign(cpos, KATAKANA), get_kana_sign(cpos, ROMAJI), color_str, 
                            appGUI->sts->correct_katakana_counters[cpos], appGUI->sts->katakana_counters[cpos], ratio);

                gtk_label_set_markup (GTK_LABEL (appGUI->chr->labels[pos]), buffer);
                cpos++;
            }

            pos++;
        }
    }


    /* buttons */

    hbuttonbox = gtk_hbutton_box_new ();
    gtk_widget_show (hbuttonbox);
    gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_EDGE);
    gtk_box_pack_end (GTK_BOX (vbox1), hbuttonbox, FALSE, TRUE, 0);

    hseparator = gtk_hseparator_new ();
    gtk_widget_show (hseparator);
    gtk_box_pack_end (GTK_BOX (vbox1), hseparator, FALSE, TRUE, 8);

    reset_button = gui_stock_label_button(_("Reset"), GTK_STOCK_CLEAR);
    gtk_widget_show (reset_button);
    g_signal_connect (G_OBJECT (reset_button), "clicked",
                        G_CALLBACK (stats_reset_cb), appGUI);
    gtk_container_add (GTK_CONTAINER (hbuttonbox), reset_button);

    close_button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
    gtk_widget_show (close_button);
    g_signal_connect (G_OBJECT (close_button), "clicked",
                        G_CALLBACK (stats_window_close_cb), appGUI);
    gtk_container_add (GTK_CONTAINER (hbuttonbox), close_button);
    GTK_WIDGET_SET_FLAGS (close_button, GTK_CAN_DEFAULT);

    if (appGUI->sts->active_tab != -1) {
        gtk_notebook_set_current_page (GTK_NOTEBOOK (appGUI->sts->notebook), appGUI->sts->active_tab);
    }

    gtk_widget_grab_default (close_button);

    /*------------------------------------------------------------------------------*/

    if (appGUI->sts->stats_list != NULL) {

        for (i = 0, lnode = appGUI->sts->stats_list; lnode != NULL; lnode = lnode->next, i++) {

            entry = g_slist_nth_data (appGUI->sts->stats_list, i);

            gtk_list_store_append (stats_store, &stats_iter);

            g_snprintf (buffer, BUFFER_SIZE, "%4d.%02d.%02d, %02d:%02d", entry->date_year, entry->date_month+1, 
                        entry->date_day+1, entry->date_hour, entry->date_minute);
            gtk_list_store_set (stats_store, &stats_iter, 0, buffer, -1);

            switch(entry->test_repeat_mode) {
                case REPEAT_WRONG:
                    g_snprintf (buffer, BUFFER_SIZE, "%s (%s)", get_test_mode_name (entry->test_mode), _("RW"));
                    break;
                case REPEAT_ALL:
                    g_snprintf (buffer, BUFFER_SIZE, "%s (%s)", get_test_mode_name (entry->test_mode), _("RA"));
                    break;
                default:
                    g_snprintf (buffer, BUFFER_SIZE, "%s", get_test_mode_name (entry->test_mode));
                    break;
            }

            gtk_list_store_set (stats_store, &stats_iter, 1, buffer,
                                2, test_sec2str(entry->test_time, TRUE), 3, entry->test_questions,
                                4, entry->test_correct_answers, 5, entry->test_questions-entry->test_correct_answers,
                                6, (gint)((gfloat)(entry->test_correct_answers)/entry->test_questions*100.0),
                                7, get_kana_set_name(entry->test_kana_set), -1);
        }

    }

    appGUI->sts->disable_dir = TRUE;

    g_signal_emit_by_name (stats_column[config.stats_sort_column], "clicked");

    if (config.stats_sort_column_dir == -1) {
        g_signal_emit_by_name (stats_column[config.stats_sort_column], "clicked");
    }

    appGUI->sts->disable_dir = FALSE;

    gtk_widget_show (appGUI->sts->stat_window);
}

/*--------------------------------------------------------------------*/

void
stats_free_list (GUI *appGUI) {

    if (appGUI->sts->stats_list != NULL) {
        g_slist_free(appGUI->sts->stats_list);
        appGUI->sts->stats_list = NULL;
    }
}

/*--------------------------------------------------------------------*/

void
stats_remove_list (GUI *appGUI) {

stats_entry *entry;
gint i;

    if (appGUI->sts->stats_list != NULL) {

        i = stats_get_records(appGUI);

        while (i >= 0) {
            entry = g_slist_nth_data (appGUI->sts->stats_list, i);
            appGUI->sts->stats_list = g_slist_remove (appGUI->sts->stats_list, entry);
            --i;
        }
    }
}

/*--------------------------------------------------------------------*/

gint
stats_get_records (GUI *appGUI) {

    gint i;
    GSList *lnode;

    if (appGUI->sts->stats_list != NULL) {

        for (i = 0, lnode = appGUI->sts->stats_list; lnode != NULL; lnode = lnode->next, i++);
        return i;

    } else {
        return 0;
    }
}

/*--------------------------------------------------------------------*/

void    
stats_add_entry (stats_entry *entry, GUI *appGUI) {

    if (entry != NULL) {
        appGUI->sts->stats_list = g_slist_append (appGUI->sts->stats_list, entry);
    } else {
        g_warning ("Cannot allocate memory.");
    }
}

/*--------------------------------------------------------------------*/

gchar *
get_kana_token (gint token, gint type) {

static gchar temp[BUFFER_SIZE];

    g_snprintf (temp, BUFFER_SIZE, "%s_%d", get_kana_sign (token, ROMAJI), type);
    if (temp[2] == ',') temp[2] = '_';  /* special case: di,ji */

    return temp;
}

/*--------------------------------------------------------------------*/

void
stats_read_list (gchar *stats_filename, gchar *config_dirname, GUI *appGUI) {

xmlDocPtr doc;
xmlChar *key;
xmlNodePtr node, cnode, hiragana_node, katakana_node;
gchar *prop;
gint i, count, correct, id;
stats_entry *entry = NULL;

    appGUI->sts->stats_list = NULL;

    if((doc = xmlParseFile (prefs_get_config_filename (stats_filename, config_dirname)))) {

        if(!(node = xmlDocGetRootElement (doc))) {
            return;
        }

        if(!xmlStrcmp (node->name, (xmlChar *) STATS_NAME)) {

            /* read note */
            node = node->xmlChildrenNode;

            while (node != NULL) {

                if(!xmlStrcmp (node->name, (xmlChar *) "test_stats")) {

                    cnode = node->xmlChildrenNode;

                    entry = g_new0 (stats_entry, 1);
                    if (entry == NULL) continue;

                    entry->date_day = entry->date_month = entry->date_year = 0;
                    entry->date_hour = entry->date_minute = entry->test_time = 0;
                    entry->test_mode = entry->test_kana_set = entry->test_questions = 0;
                    entry->test_correct_answers = entry->test_repeat_mode = 0;

                    while (cnode != NULL) {

                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "date_day"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->date_day = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "date_month"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->date_month = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "date_year"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->date_year = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "date_hour"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->date_hour = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "date_minute"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->date_minute = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "test_time"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->test_time = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "test_mode"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->test_mode = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "test_kana_set"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->test_kana_set = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "test_questions"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->test_questions = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "test_correct_answers"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    entry->test_correct_answers = atoi ((gchar *) key);
                            xmlFree (key);
                        }
                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "test_rwaq"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                entry->test_repeat_mode = (!atoi ((gchar *) key)?REPEAT_NONE:REPEAT_WRONG);
                            xmlFree (key);
                        }

                        if ((!xmlStrcmp (cnode->name, (const xmlChar *) "test_repeat_mode"))) {
                            key = xmlNodeListGetString (doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                entry->test_repeat_mode = atoi ((gchar *) key);
                            xmlFree (key);
                        }

                        cnode = cnode->next;
                    }

                    stats_add_entry (entry, appGUI);
                }

                node = node->next;
            }

        }

        xmlFree(node);
        xmlFreeDoc(doc);
    }

    i = 0;

    if((doc = xmlParseFile (prefs_get_config_filename (KANAS_FILENAME, config_dirname)))) {

        if(!(node = xmlDocGetRootElement (doc))) {
            return;
        }

        if(!xmlStrcmp (node->name, (xmlChar *) STATS_NAME)) {

            /* read hiragana stats */
            hiragana_node = node->xmlChildrenNode;

            while (hiragana_node != NULL) {

                if (i < NUMBER_OF_SIGNS) {
                    if(!xmlStrcmp (hiragana_node->name, (xmlChar *) get_kana_token (i, HIRAGANA))) {

                        prop = (gchar *) xmlGetProp (hiragana_node, (const xmlChar *) "count");
                        if (prop != NULL) {
                            count = atoi (prop);
                            xmlFree (prop);
                        }
                        prop = (gchar *) xmlGetProp (hiragana_node, (const xmlChar *) "correct");
                        if (prop != NULL) {
                            correct = atoi (prop);
                            xmlFree (prop);
                        }
                        prop = (gchar *) xmlGetProp (hiragana_node, (const xmlChar *) "id");
                        if (prop != NULL) {
                            id = atoi (prop);
                            xmlFree (prop);
                        }

                        if (id >= 0 && id < NUMBER_OF_SIGNS) {
                            appGUI->sts->hiragana_counters[id] = count;
                            appGUI->sts->correct_hiragana_counters[id] = correct;
                        }

                        i++;
                    }
                }

                hiragana_node = hiragana_node->next;
            }

            i = 0;

            /* read katakana stats */
            katakana_node = node->xmlChildrenNode;

            while (katakana_node != NULL) {

                if (i < NUMBER_OF_SIGNS) {
                    if(!xmlStrcmp (katakana_node->name, (xmlChar *) get_kana_token (i, KATAKANA))) {

                        prop = (gchar *) xmlGetProp (katakana_node, (const xmlChar *) "count");
                        if (prop != NULL) {
                            count = atoi (prop);
                            xmlFree (prop);
                        }
                        prop = (gchar *) xmlGetProp (katakana_node, (const xmlChar *) "correct");
                        if (prop != NULL) {
                            correct = atoi (prop);
                            xmlFree (prop);
                        }
                        prop = (gchar *) xmlGetProp (katakana_node, (const xmlChar *) "id");
                        if (prop != NULL) {
                            id = atoi (prop);
                            xmlFree (prop);
                        }

                        if (id >= 0 && id < NUMBER_OF_SIGNS) {
                            appGUI->sts->katakana_counters[id] = count;
                            appGUI->sts->correct_katakana_counters[id] = correct;
                        }

                        i++;
                    }
                }

                katakana_node = katakana_node->next;
            }
        }
    }
}

/*--------------------------------------------------------------------*/

void
stats_write_list (gchar *stats_filename, gchar *config_dirname, GUI *appGUI) {

GSList *lnode;
stats_entry *entry;
gint i;
xmlDocPtr doc;
xmlNodePtr node, stats_node, kana_node;
gchar temp[BUFFER_SIZE];

    /* write lessons stats */

    doc = xmlNewDoc ((const xmlChar *) "1.0");
    node = xmlNewNode (NULL, (const xmlChar *) STATS_NAME);
    xmlDocSetRootElement (doc, node);

    for (i = 0, lnode = appGUI->sts->stats_list; lnode; lnode = lnode->next, i++) {

        entry = g_slist_nth_data (appGUI->sts->stats_list, i);
        stats_node = xmlNewChild (node, NULL, (const xmlChar *) "test_stats", (xmlChar *) NULL);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->date_day);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "date_day", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->date_month);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "date_month", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->date_year);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "date_year", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->date_hour);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "date_hour", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->date_minute);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "date_minute", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->test_time);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "test_time", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->test_mode);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "test_mode", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->test_kana_set);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "test_kana_set", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->test_questions);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "test_questions", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->test_correct_answers);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "test_correct_answers", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", entry->test_repeat_mode);
        xmlNewChild (stats_node, NULL, (const xmlChar *) "test_repeat_mode", (xmlChar *) temp);
    }

    xmlSaveFormatFile (prefs_get_config_filename (stats_filename, config_dirname), doc, 1);
    xmlFreeDoc (doc);

    /* write kanas stats */

    doc = xmlNewDoc ((const xmlChar *) "1.0");
    node = xmlNewNode (NULL, (const xmlChar *) STATS_NAME);
    xmlDocSetRootElement (doc, node);

    for (i=0; i < NUMBER_OF_SIGNS; i++) {
        kana_node = xmlNewChild (node, NULL, (const xmlChar *) get_kana_token (i, HIRAGANA), NULL);

        g_snprintf (temp, BUFFER_SIZE, "%d", appGUI->sts->hiragana_counters[i]);
        xmlNewProp (kana_node, (const xmlChar *) "count", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", appGUI->sts->correct_hiragana_counters[i]);
        xmlNewProp (kana_node, (const xmlChar *) "correct", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", i);
        xmlNewProp (kana_node, (const xmlChar *) "id", (xmlChar *) temp);
    }

    for (i=0; i < NUMBER_OF_SIGNS; i++) {
        kana_node = xmlNewChild (node, NULL, (const xmlChar *) get_kana_token (i, KATAKANA), NULL);

        g_snprintf (temp, BUFFER_SIZE, "%d", appGUI->sts->katakana_counters[i]);
        xmlNewProp (kana_node, (const xmlChar *) "count", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", appGUI->sts->correct_katakana_counters[i]);
        xmlNewProp (kana_node, (const xmlChar *) "correct", (xmlChar *) temp);
        g_snprintf (temp, BUFFER_SIZE, "%d", i);
        xmlNewProp (kana_node, (const xmlChar *) "id", (xmlChar *) temp);
    }

    xmlSaveFormatFile (prefs_get_config_filename (KANAS_FILENAME, config_dirname), doc, 1);
    xmlFreeDoc (doc);
}


/*--------------------------------------------------------------------*/


Generated by  Doxygen 1.6.0   Back to index