Logo Search packages:      
Sourcecode: kanatest version File versions

stats.c

/*
 * Kanatest
 *
 * Copyright (C) 2001-2004, 2006 Tomasz MÄ…ka <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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <unistd.h>
#include <sys/stat.h>
#include <linux/limits.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include "i18n.h"
#include "gui.h"
#include "prefs.h"
#include "main.h"
#include "test.h"
#include "stats.h"

GtkWidget *stat_window;

gint old_column, disable_dir;
GSList *stats_list;

extern GtkWidget *main_window;

void 
stats_window_close_cb(void) {

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

    gtk_widget_destroy (stat_window);
}


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

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

    return FALSE;
}


void 
stats_reset_cb (void) {

GtkWidget *info_dialog;
gint response;

        info_dialog = gtk_message_dialog_new (GTK_WINDOW(stat_window), 
                                              GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
                                              GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, 
                                              _("All statistics entries will be destroyed. Continue ?"));

        gtk_window_set_title(GTK_WINDOW(info_dialog), _("Question"));
        gtk_widget_show (info_dialog);
        response = gtk_dialog_run(GTK_DIALOG(info_dialog));
        gtk_widget_destroy(info_dialog);

        if (response == GTK_RESPONSE_YES) {   
            stats_remove_list ();
            stats_window_close_cb();
        }
}

void
stats_column_clicked_cb (GtkTreeViewColumn *treeviewcolumn, gpointer user_data) {

    old_column = config.stats_sort_column;  
    config.stats_sort_column = (gint) user_data;

    if (disable_dir == FALSE) {

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

void 
stats_create_window (void) {

GtkWidget       *vbox1;
GtkWidget       *hbuttonbox;
GtkWidget       *close_button;
GtkWidget       *reset_button;
GtkWidget       *hseparator;
GtkWidget       *stats_scrolledwindow;
GtkWidget       *stats_treeview;
GtkListStore    *stats_store;
GtkTreeModel    *stats_model;
GtkCellRenderer *stats_renderer;
GtkTreeIter     stats_iter;
gint            i;
GSList          *lnode;
gchar           buffer[BUFFER_SIZE];

struct stats_entry *a;

GtkTreeViewColumn   *stats_column[NUMBER_OF_COLUMNS];

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


    if (stats_get_records() == 0) {

        stats_info_no_stats();

    } else {

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

        g_signal_connect (G_OBJECT (stat_window), "delete_event",
                            G_CALLBACK(stats_window_close_cb), NULL);
        g_signal_connect (G_OBJECT(stat_window), "key_press_event",
                            G_CALLBACK(stats_key_press_cb), NULL);

        gtk_window_set_default_size (GTK_WINDOW(stat_window),
                                    config.stat_size_x, config.stat_size_y);

        gtk_window_set_resizable (GTK_WINDOW (stat_window), TRUE);

        gtk_window_move (GTK_WINDOW (stat_window),
                                    config.stat_window_x, config.stat_window_y);
        gtk_widget_show (stat_window);

        vbox1 = gtk_vbox_new (FALSE, 0);
        gtk_widget_show (vbox1);
        gtk_container_add (GTK_CONTAINER (stat_window), vbox1);

        stats_scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
        gtk_widget_show (stats_scrolledwindow);
        gtk_box_pack_start (GTK_BOX (vbox1), 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]);
            g_signal_connect (G_OBJECT(stats_column[i]), "clicked",
                              G_CALLBACK(stats_column_clicked_cb), (gpointer) i);
        }

        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 stats"), GTK_STOCK_CLEAR);
        gtk_widget_show (reset_button);
        g_signal_connect (G_OBJECT (reset_button), "clicked",
                            G_CALLBACK (stats_reset_cb), NULL);
        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), NULL);
        gtk_container_add (GTK_CONTAINER (hbuttonbox), close_button);
        GTK_WIDGET_SET_FLAGS (close_button, GTK_CAN_DEFAULT);

        gtk_widget_grab_default (close_button);


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

        if (stats_list != NULL) {

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

                a = g_slist_nth_data (stats_list, i);

                gtk_list_store_append (stats_store, &stats_iter);

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

                if (a->test_rwaq == TRUE) {
                    sprintf(buffer, _("%s (R)"), _(kana_mode_names[a->test_mode]));
                } else {
                    sprintf(buffer, _("%s"), _(kana_mode_names[a->test_mode]));
                }

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

        } 
 
        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");   
        }

        disable_dir = FALSE;
    }
}

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

void 
stats_info_no_stats(void) {

GtkWidget *info_dialog;

        info_dialog = gtk_message_dialog_new (GTK_WINDOW(main_window), 
                                              GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
                                              GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, 
                                              _("Statistics are not available. The results table is empty."));

        gtk_window_set_title(GTK_WINDOW(info_dialog), _("Warning"));
        gtk_widget_show (info_dialog);
        gtk_dialog_run(GTK_DIALOG(info_dialog));
        gtk_widget_destroy(info_dialog);
}


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

gchar* 
stats_get_filename (void)
{
static gchar dirname[PATH_MAX], filename[PATH_MAX];
struct stat cfg;

    strncpy (dirname, getenv ("HOME"), PATH_MAX);
    strcat (dirname, "/");
    strcat (dirname, CONFIG_DIRNAME);

    if(stat (dirname, &cfg) < 0)
        mkdir (dirname, S_IRUSR | S_IWUSR | S_IXUSR);

    strcpy (filename, dirname);
    strcat (filename, "/");
    strcat (filename, STATS_FILENAME);

    return filename;
}

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

void
stats_free_list (void) {

    if (stats_list != NULL) {
        g_slist_free(stats_list);
        stats_list = NULL;
    }
}

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

void
stats_remove_list (void) {

struct stats_entry *a;
gint i;

    if (stats_list != NULL) {

        i = stats_get_records();

        while (i >= 0) {
            a = g_slist_nth_data (stats_list, i);
            stats_list = g_slist_remove (stats_list, a);   
            --i;
        }
    }
}

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

gint
stats_get_records (void) {

    gint i;
    GSList *lnode;

    if (stats_list != NULL) {

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

    } else {

        return 0;
    }
}

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

void
stats_add_entry (guint day, guint month, guint year, guint hour, guint minute, guint time, guint mode, 
                 guint kana_set, guint questions, guint correct_answers, guint rwaq) {

struct stats_entry *a;

    a = g_malloc(sizeof(struct stats_entry));

    if (a != NULL) {

        a->date_day = day;
        a->date_month = month;
        a->date_year = year;
        a->date_hour = hour;
        a->date_minute = minute;
        a->test_time = time;
        a->test_mode = mode;
        a->test_kana_set = kana_set;
        a->test_questions = questions;
        a->test_correct_answers = correct_answers;
        a->test_rwaq = rwaq;

        stats_list = g_slist_append (stats_list, a);

    } else {

        fprintf (stderr, "*** ERROR: cannot allocate memory for stats structure\n");

    }
}


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

void
stats_read_list (void) {

xmlDocPtr doc;
xmlChar *key;
xmlNodePtr node, cnode;
guint day, month, year, hour, minute, time, mode;
guint kana_set, questions, correct_answers, rwaq;

    stats_list = NULL;

    if((doc = xmlParseFile(stats_get_filename()))) {

        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;

                    day = month = year = hour = minute = time = mode = 0;
                    kana_set = questions = correct_answers = rwaq = 0;

                    while (cnode != NULL) {

                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "date_day"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    day = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "date_month"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    month = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "date_year"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    year = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "date_hour"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    hour = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "date_minute"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    minute = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "test_time"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    time = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "test_mode"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    mode = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "test_kana_set"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    kana_set = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "test_questions"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    questions = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "test_correct_answers"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    correct_answers = atoi ((gchar *) key);
                            xmlFree(key);
                        }
                        if ((!xmlStrcmp(cnode->name, (const xmlChar *) "test_rwaq"))) {
                            key = xmlNodeListGetString(doc, cnode->xmlChildrenNode, 1);
                            if (key != NULL)
                                    rwaq = atoi ((gchar *) key);
                            xmlFree(key);
                        }

                        cnode = cnode->next;
                    }

                    stats_add_entry (day, month, year, hour, minute, time, mode, kana_set, questions, correct_answers, rwaq);
           
                }

                node = node->next;
            }

        }

        xmlFree(node);
        xmlFreeDoc(doc);
    }

}

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

void
stats_write_list (void) {

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


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

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

        a = g_slist_nth_data (stats_list, i);
        stats_node = xmlNewChild(node, NULL, (const xmlChar *) "test_stats", (xmlChar *) NULL);
        sprintf(temp, "%d", a->date_day);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "date_day", (xmlChar *) temp);
        sprintf(temp, "%d", a->date_month);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "date_month", (xmlChar *) temp);
        sprintf(temp, "%d", a->date_year);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "date_year", (xmlChar *) temp);
        sprintf(temp, "%d", a->date_hour);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "date_hour", (xmlChar *) temp);
        sprintf(temp, "%d", a->date_minute);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "date_minute", (xmlChar *) temp);
        sprintf(temp, "%d", a->test_time);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "test_time", (xmlChar *) temp);
        sprintf(temp, "%d", a->test_mode);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "test_mode", (xmlChar *) temp);
        sprintf(temp, "%d", a->test_kana_set);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "test_kana_set", (xmlChar *) temp);
        sprintf(temp, "%d", a->test_questions);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "test_questions", (xmlChar *) temp);
        sprintf(temp, "%d", a->test_correct_answers);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "test_correct_answers", (xmlChar *) temp);
        sprintf(temp, "%d", a->test_rwaq);
        xmlNewChild(stats_node, NULL, (const xmlChar *) "test_rwaq", (xmlChar *) temp);
    }

    stats_free_list();

    xmlSaveFormatFile(stats_get_filename(), doc, 1);
    xmlFreeDoc(doc);
}


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


Generated by  Doxygen 1.6.0   Back to index