stat.c

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /*
00003   stat.c
00004   an heraia plugin to calculate some stats on the opened file
00005 
00006   (C) Copyright 2007 - 2011 Olivier Delhomme
00007   e-mail : heraia@delhomme.org
00008   URL    : http://heraia.tuxfamily.org
00009 
00010   This program is free software; you can redistribute it and/or modify
00011   it under the terms of the GNU General Public License as published by
00012   the Free Software Foundation; either version 2, or  (at your option)
00013   any later version.
00014 
00015   This program is distributed in the hope that it will be useful,
00016   but WITHOUT ANY WARRANTY;  without even the implied warranty of
00017   MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the
00018   GNU General Public License for more details.
00019 
00020   You should have received a copy of the GNU General Public License
00021   along with this program; if not, write to the Free Software
00022   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023 */
00024 /**
00025  * @file stat.c
00026  * does some basic statistics on the file and displays them
00027  * in a numerical or graphical way (histograms : 1D and 2D)
00028  */
00029 #include "stat.h"
00030 
00031 /* The functions for the plugin's usage */
00032 static void stat_window_connect_signals(heraia_plugin_t *plugin);
00033 
00034 static void statw_close_clicked(GtkWidget *widget, gpointer data);
00035 static void destroy_stat_window(GtkWidget *widget, GdkEvent  *event, gpointer data);
00036 
00037 static void statw_save_as_clicked(GtkWidget *widget, gpointer data);
00038 static void statw_export_to_csv_clicked(GtkWidget *widget, gpointer data);
00039 static void statw_export_to_gnuplot_clicked(GtkWidget *widget, gpointer data);
00040 static void statw_export_to_pcv_clicked(GtkWidget *widget, gpointer data);
00041 
00042 static gchar *stat_select_file_to_save(const gchar *window_text, stat_t *extra);
00043 static void histo_radiobutton_toggled(GtkWidget *widget, gpointer data);
00044 static gboolean delete_stat_window_event(GtkWidget *widget, GdkEvent  *event, gpointer data );
00045 static void realize_some_numerical_stat(heraia_struct_t *main_struct, heraia_plugin_t *plugin);
00046 static void init_stats_histos(heraia_plugin_t *plugin);
00047 static void set_statw_button_state(GtkBuilder *xml, gboolean sensitive);
00048 static void populate_stats_histos(heraia_struct_t *main_struct, heraia_plugin_t *plugin);
00049 static void calc_infos_histo_1D(stat_t *extra);
00050 static void calc_infos_histo_2D(stat_t *extra);
00051 static void init_stats_pixbufs(stat_t *extra);
00052 static void make_pixbufs_from_histos(stat_t *extra);
00053 static void plot_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y, guchar red, guchar green, guchar blue, guchar alpha);
00054 static void do_pixbuf_1D_from_histo1D(stat_t *extra);
00055 static void do_pixbuf_2D_from_histo2D(stat_t *extra, guint max_2D);
00056 
00057 
00058 /**
00059  *  Initialisation plugin function called when the plugin is loaded
00060  *  (some sort of pre-init)
00061  *  @param[in,out] plugin : plugin's structure
00062  *  @return returns the plugin structure
00063  */
00064 heraia_plugin_t *heraia_plugin_init(heraia_plugin_t *plugin)
00065 {
00066     stat_t *extra = NULL;            /**< extra structure specific to this plugin */
00067     window_prop_t *stat_prop = NULL; /**< window properties                       */
00068 
00069     plugin->state             = PLUGIN_STATE_INITIALIZING;
00070     plugin->xml = NULL;
00071 
00072     plugin->info->api_version = API_VERSION;
00073     plugin->info->type        = PLUGIN_TYPE;
00074     plugin->info->priority    = HERAIA_PRIORITY_DEFAULT;
00075     plugin->info->name        = PLUGIN_NAME;
00076     plugin->info->version     = PLUGIN_VERSION;
00077     plugin->info->summary     = PLUGIN_SUMMARY;
00078     plugin->info->description = PLUGIN_DESCRIPTION;
00079     plugin->info->author      = PLUGIN_AUTHOR;
00080     plugin->info->homepage    = PLUGIN_HOMEPAGE;
00081 
00082     plugin->init_proc    = init;
00083     plugin->quit_proc    = quit;
00084     plugin->run_proc     = run;
00085     plugin->refresh_proc = refresh;
00086 
00087     plugin->filter->extensions = NULL;
00088     plugin->filter->import     = NULL;
00089     plugin->filter->export     = NULL;
00090 
00091     /* add the extra struct to the plugin one */
00092     extra = (stat_t *) g_malloc0 (sizeof(stat_t));
00093     extra->infos_1D = (histo_infos_t *) g_malloc0 (sizeof(histo_infos_t));
00094     extra->infos_2D = (histo_infos_t *) g_malloc0 (sizeof(histo_infos_t));
00095     extra->dirname = NULL;
00096 
00097     /* window properties */
00098     stat_prop = (window_prop_t *) g_malloc0(sizeof(window_prop_t));
00099     stat_prop->displayed = FALSE; /* by default, it might be anything else */
00100     stat_prop->x = 0;
00101     stat_prop->y = 0;
00102 
00103     plugin->win_prop = stat_prop;
00104 
00105     plugin->extra = extra;
00106 
00107 
00108     return plugin;
00109 }
00110 
00111 
00112 /* the plugin interface functions */
00113 /**
00114  *  The real init function of the plugin (called at init time)
00115  * @param main_struct : main structure
00116  */
00117 void init(heraia_struct_t *main_struct)
00118 {
00119     heraia_plugin_t *plugin = NULL;
00120 
00121     log_message(main_struct, G_LOG_LEVEL_INFO, Q_("Initializing plugin %s"), PLUGIN_NAME);
00122     /* first, know who we are ! */
00123     plugin = find_plugin_by_name(main_struct->plugins_list, PLUGIN_NAME);
00124 
00125     if (plugin != NULL)
00126         {
00127             /* load the xml interface */
00128             log_message(main_struct, G_LOG_LEVEL_INFO, Q_("Plugin from %s found !"), plugin->info->author);
00129             if (load_plugin_xml(main_struct, plugin) == TRUE)
00130                 {
00131                     log_message(main_struct, G_LOG_LEVEL_INFO, Q_("%s xml interface loaded."), plugin->info->name);
00132                 }
00133             else
00134                 {
00135                     log_message(main_struct, G_LOG_LEVEL_WARNING, Q_("Unable to load %s xml interface."), plugin->info->name);
00136                 }
00137 
00138             /* greyed save as button and others */
00139             set_statw_button_state(plugin->xml, FALSE);
00140 
00141             /* shows or hide the interface (hides it at first as all windows shows up) */
00142             if (plugin->win_prop->displayed == FALSE)
00143                 {
00144                     gtk_widget_hide(GTK_WIDGET(heraia_get_widget(plugin->xml, "stat_window")));
00145                 }
00146             else
00147                 {
00148                     gtk_check_menu_item_set_active(plugin->cmi_entry, TRUE);
00149                 }
00150 
00151             /* connect some signals handlers */
00152             stat_window_connect_signals(plugin);
00153         }
00154 }
00155 
00156 
00157 /**
00158  *  Normaly this is called when the plugin is unloaded
00159  *  One may wait it's entire life for this to be called !! ;)
00160  */
00161 void quit(void)
00162 {
00163     g_print(Q_("Quitting %s\n"), PLUGIN_NAME);
00164 }
00165 
00166 
00167 /**
00168  * This function is called via a signal handler when the menu entry is toggled
00169  * @param widget : widget which called the function (unused)
00170  * @param data : user data for the plugin, here MUST be heraia_struct_t * main
00171  *        structure
00172  */
00173 void run(GtkWidget *widget, gpointer data)
00174 {
00175     heraia_struct_t *main_struct = (heraia_struct_t *) data; /* the signal send the pointer to this structure */
00176     heraia_plugin_t *plugin = NULL;
00177     gboolean menu_state = FALSE;
00178 
00179     /* first, know who we are ! */
00180     plugin = find_plugin_by_name(main_struct->plugins_list, PLUGIN_NAME);
00181 
00182     if (plugin != NULL)
00183         {
00184             menu_state = gtk_check_menu_item_get_active(plugin->cmi_entry);
00185 
00186             show_hide_widget(GTK_WIDGET(heraia_get_widget(plugin->xml, "stat_window")), menu_state, plugin->win_prop);
00187 
00188             if (menu_state == TRUE)
00189                 {
00190                     plugin->state = PLUGIN_STATE_RUNNING;
00191                     realize_some_numerical_stat(main_struct, plugin);
00192                 }
00193             else
00194                 {
00195                     plugin->state = PLUGIN_STATE_NONE;
00196                 }
00197         }
00198 }
00199 
00200 
00201 /**
00202  * Sets stat window's button's sensitive property
00203  * @param xml : The plugin's xml description
00204  * @param sensitive : whether the buttons are greyed (FALSE) or not (TRUE)
00205  */
00206 static void set_statw_button_state(GtkBuilder *xml, gboolean sensitive)
00207 {
00208     if (xml != NULL)
00209     {
00210         gtk_widget_set_sensitive(heraia_get_widget(xml, "statw_save_as"), sensitive);
00211         gtk_widget_set_sensitive(heraia_get_widget(xml, "statw_export_to_csv"), sensitive);
00212         gtk_widget_set_sensitive(heraia_get_widget(xml, "statw_export_to_gnuplot"), sensitive);
00213         gtk_widget_set_sensitive(heraia_get_widget(xml, "statw_export_to_pcv"), sensitive);
00214     }
00215 }
00216 
00217 
00218 /**
00219  *  The refresh function is called when a new file is loaded or when the cursor is moved
00220  *  Here we want to refresh the plugin only if a new file is loaded AND if the plugin
00221  *  is already displayed (running)
00222  * @param main_struct : main structure
00223  * @param data : user data (the plugin itself) MUST be heraia_plugin_t *plugin
00224  *               structure
00225  */
00226 void refresh(heraia_struct_t *main_struct, void *data)
00227 {
00228     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00229 
00230     if (main_struct != NULL && plugin != NULL)
00231         {
00232             if (main_struct->event == HERAIA_REFRESH_NEW_FILE || main_struct->event == HERAIA_REFRESH_TAB_CHANGED) /* && plugin->state == PLUGIN_STATE_RUNNING) */
00233                 {
00234                     set_statw_button_state(plugin->xml, TRUE);
00235                     plugin->run_proc(NULL, (gpointer) main_struct);
00236                 }
00237         }
00238 }
00239 /* end of the plugin interface functions */
00240 
00241 
00242 /**
00243  *  Usefull functions for the stat plugin
00244  *  those may be included in an another .c source file ?!
00245  */
00246 
00247 /**
00248  * Closes stat window
00249  * @param widget : the widget which called this function
00250  * @param event : the event that issued the signal (unused here)
00251  * @param data : user data, MUST be heraia_plugin_t *plugin
00252  * @return resturns always FALSE (does not propagate the signal)
00253  */
00254 static gboolean delete_stat_window_event(GtkWidget *widget, GdkEvent  *event, gpointer data)
00255 {
00256     statw_close_clicked(widget, data);
00257 
00258     return TRUE;
00259 }
00260 
00261 
00262 /**
00263 
00264  * Closes stat window
00265  * @param widget : the widget which called this function
00266  * @param event : the event that issued the signal (unused here)
00267  * @param data : user data, MUST be heraia_plugin_t *plugin
00268  */
00269 static void destroy_stat_window(GtkWidget *widget, GdkEvent  *event, gpointer data)
00270 {
00271     statw_close_clicked(widget, data);
00272 }
00273 
00274 
00275 /**
00276  *  What to do when the window is closed
00277  * @param widget : the widget which called this function (unused here)
00278  * @param data : user data, MUST be heraia_plugin_t *plugin
00279  */
00280 static void statw_close_clicked(GtkWidget *widget, gpointer data)
00281 {
00282     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00283 
00284     if (plugin != NULL)
00285         {
00286             show_hide_widget(GTK_WIDGET(heraia_get_widget(plugin->xml, "stat_window")), FALSE, plugin->win_prop);
00287             gtk_check_menu_item_set_active(plugin->cmi_entry, FALSE);
00288         }
00289 }
00290 
00291 
00292 /**
00293  *  What to do when the save as button is clicked
00294  * @param widget : the widget which called this function (unused here)
00295  * @param data : user data, MUST be heraia_plugin_t *plugin
00296  */
00297 static void statw_save_as_clicked(GtkWidget *widget, gpointer data)
00298 {
00299     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00300     stat_t *extra = NULL;
00301     GtkImage *image = NULL;
00302     GdkPixbuf *pixbuf = NULL;
00303     gchar *filename = NULL;
00304     GError **error = NULL;
00305 
00306     if (plugin != NULL)
00307         {
00308             extra = (stat_t *) plugin->extra;
00309 
00310             image = GTK_IMAGE(heraia_get_widget(plugin->xml, "histo_image"));
00311             pixbuf = gtk_image_get_pixbuf(image);
00312 
00313             filename = stat_select_file_to_save(Q_("Enter filename's to save the image to"), extra);
00314             if (filename != NULL)
00315             {
00316                 gdk_pixbuf_save(pixbuf, filename, "png", error, "compression", "9", NULL);
00317                 g_free(filename);
00318             }
00319         }
00320 }
00321 
00322 
00323 /**
00324  *  Selecting the file filename where to save the file
00325  * @param window_text : text to be displayed in the selection window
00326  * @return returns the new filename where to save a file
00327  */
00328 static gchar *stat_select_file_to_save(const gchar *window_text, stat_t *extra)
00329 {
00330     GtkFileChooser *file_chooser = NULL;
00331     gint response_id = 0;
00332     gchar *filename;
00333 
00334     file_chooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(window_text, NULL,
00335                                                                 GTK_FILE_CHOOSER_ACTION_SAVE,
00336                                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
00337                                                                 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
00338                                                                 NULL));
00339 
00340     /* for the moment we do not want to retrieve multiples selections */
00341     gtk_window_set_modal(GTK_WINDOW(file_chooser), TRUE);
00342     gtk_file_chooser_set_select_multiple(file_chooser, FALSE);
00343     gtk_file_chooser_set_do_overwrite_confirmation(file_chooser, TRUE);
00344 
00345     /* If it exists define a new directory name */
00346     if (extra != NULL && extra->dirname != NULL)
00347         {
00348             gtk_file_chooser_set_current_folder(file_chooser, extra->dirname);
00349         }
00350 
00351     response_id = gtk_dialog_run(GTK_DIALOG(file_chooser));
00352 
00353     switch (response_id)
00354         {
00355             case GTK_RESPONSE_OK:
00356                 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser));
00357 
00358                 /* Saving directory name in order to use it at a later call */
00359                 if (filename != NULL)
00360                     {
00361                         if (extra->dirname != NULL)
00362                             {
00363                                 g_free(extra->dirname);
00364                             }
00365                         extra->dirname = g_path_get_dirname(filename);
00366                     }
00367 
00368                 break;
00369             case GTK_RESPONSE_CANCEL:
00370             default:
00371                 filename = NULL;
00372                 break;
00373         }
00374 
00375     gtk_widget_destroy(GTK_WIDGET(file_chooser));
00376     return filename;
00377 }
00378 
00379 
00380 /**
00381  * What to do when "export to csv" button is clicked
00382  * @param widget : the widget which called this function
00383  * @param data : user data, MUST be heraia_plugin_t *plugin
00384  */
00385 static void statw_export_to_csv_clicked(GtkWidget *widget, gpointer data)
00386 {
00387     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00388     stat_t *extra = NULL;
00389     gchar *filename = NULL;
00390     FILE *fp = NULL;
00391     guint i = 0;
00392     guint j = 0;
00393 
00394     if (plugin != NULL)
00395         {
00396             extra = (stat_t *) plugin->extra;
00397 
00398             filename = stat_select_file_to_save(Q_("Enter filename to export data as CSV to"), extra);
00399 
00400             if (filename != NULL)
00401                 {
00402                     fp = g_fopen(filename, "w+");
00403                 }
00404 
00405             if (fp != NULL && extra != NULL)
00406                 {
00407                     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00408                         {
00409                             /* 1D display */
00410                             fprintf(fp, Q_("\"Byte\";\"Count\"\n"));
00411 
00412                             for (i=0; i<=255; i++)
00413                                 {
00414                                     fprintf(fp, "%d;%llu\n", i, (long long unsigned int) extra->histo1D[i]);
00415                                 }
00416 
00417                         }
00418                     else
00419                     {
00420                         /* 2D display */
00421                         fprintf(fp, Q_("\"Byte/Byte\";"));
00422                         for (j=0; j<255; j++)
00423                             {
00424                                 fprintf(fp, "\"%d\";", j);
00425                             }
00426                         fprintf(fp, "\"%d\"\n", 255);
00427 
00428                         for (i=0; i<=255; i++)
00429                             {
00430                                 fprintf(fp, "\"%d\";", i);
00431                                 for (j=0 ; j<255; j++)
00432                                     {
00433                                         fprintf(fp, "\"%llu\";", (long long unsigned int) extra->histo2D[i][j]);
00434                                     }
00435                                 fprintf(fp, "\"%llu\"\n", (long long unsigned int) extra->histo2D[i][255]);
00436                             }
00437                     }
00438                     fclose(fp);
00439                 }
00440 
00441             if (filename != NULL)
00442                 {
00443                     g_free(filename);
00444                 }
00445         }
00446 }
00447 
00448 
00449 /**
00450  * What to do when "export to gnuplot" button is clicked
00451  * @param widget : the widget which called this function
00452  * @param data : user data, MUST be heraia_plugin_t *plugin
00453  */
00454 static void statw_export_to_gnuplot_clicked(GtkWidget *widget, gpointer data)
00455 {
00456     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00457     stat_t *extra = NULL;
00458     gchar *filename = NULL;
00459     FILE *fp = NULL;
00460     guint i = 0;
00461     guint j = 0;
00462 
00463     if (plugin != NULL)
00464         {
00465             extra = (stat_t *) plugin->extra;
00466 
00467             filename = stat_select_file_to_save(Q_("Enter filename to export data as gnuplot to"), extra);
00468 
00469             if (filename != NULL)
00470                 {
00471                     fp = g_fopen(filename, "w+");
00472                 }
00473 
00474             if (fp != NULL && extra != NULL)
00475                 {
00476                     /* common settings */
00477                     fprintf(fp, "set terminal png transparent nocrop enhanced small size 1280,960\n");
00478                     fprintf(fp, "set output '%s.png'\n", g_path_get_basename(filename));
00479                     fprintf(fp, "set xrange [-10:265]\n");
00480                     fprintf(fp, "set xlabel 'Bytes'\n");
00481 
00482                     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00483                         {
00484                             /* 1D display */
00485                             fprintf(fp, Q_("set title 'Classical histogram'\n"));  /**< @todo we might add here the name of the file being edited */
00486                             fprintf(fp, "set ylabel 'Count'\n");
00487                             fprintf(fp, Q_("plot '-' title 'Byte count' with impulses\n")); /* plot and set are gnuplot commands please do not translate them ! */
00488 
00489                             for (i=0; i<=255; i++)
00490                                 {
00491                                     fprintf(fp, "%llu\n", (long long unsigned int) extra->histo1D[i]);
00492                                 }
00493                             fprintf(fp, "e\n");
00494                         }
00495                     else
00496                         {
00497                             /* 2D display */
00498                             fprintf(fp, Q_("set title 'Heatmap histogram'\n"));  /**< @todo we might add here the name of the file being edited */
00499                             fprintf(fp, "set bar 1.000000\n");
00500                             fprintf(fp, "set style rectangle back fc lt -3 fillstyle solid 1.00 border -1\n");
00501                             fprintf(fp, "unset key\n");
00502                             fprintf(fp, "set view map\n");
00503                             fprintf(fp, "set yrange [-10:265]\n");
00504                             fprintf(fp, "set ylabel 'Bytes'\n");
00505                             fprintf(fp, "set palette rgbformulae 36, 13, 15\n");
00506                             fprintf(fp, "splot '-' matrix with image\n");
00507 
00508                             for (i=0; i<=255; i++)
00509                                 {
00510                                     for (j=0; j<=255; j++)
00511                                         {
00512                                             fprintf(fp, "%llu ", (long long unsigned int) extra->histo2D[i][j]);
00513                                         }
00514                                     fprintf(fp, "\n");
00515                                 }
00516 
00517                             fprintf(fp, "e\n");
00518                             fprintf(fp, "e\n");
00519                         }
00520                     fclose(fp);
00521                 }
00522 
00523             if (filename != NULL)
00524                 {
00525                     g_free(filename);
00526                 }
00527         }
00528 }
00529 
00530 
00531 /**
00532  * What to do when "export to pcv" button is clicked
00533  * @param widget : the widget which called this function
00534  * @param data : user data, MUST be heraia_plugin_t *plugin
00535  */
00536 static void statw_export_to_pcv_clicked(GtkWidget *widget, gpointer data)
00537 {
00538     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00539     stat_t *extra = NULL;
00540     gchar *filename = NULL;
00541     FILE *fp = NULL;
00542     guint i = 0;
00543     guint j = 0;
00544 
00545     if (plugin != NULL)
00546         {
00547             extra = (stat_t *) plugin->extra;
00548 
00549             filename = stat_select_file_to_save(Q_("Enter filename to export data as PCV to"), extra);
00550 
00551             if (filename != NULL)
00552                 {
00553                     fp = g_fopen(filename, "w+");
00554                 }
00555 
00556             if (fp != NULL && extra != NULL)
00557                 {
00558                     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00559                         {
00560                             /* 1D display */
00561                             fprintf(fp, "header {\n");
00562                             fprintf(fp, "\theight = \"960\";\n");
00563                             fprintf(fp, "\twidth = \"1280\";\n");
00564                             fprintf(fp, Q_("\ttitle = \"Classical histogram\";\n"));
00565                             fprintf(fp, "}\n");
00566                             fprintf(fp, "axes {\n");
00567                             fprintf(fp, Q_("\tinteger b [label=\"Bytes\"];\n"));
00568                             fprintf(fp, Q_("\tinteger c [label=\"Byte count\"];\n"));
00569                             fprintf(fp, "}\n");
00570                             fprintf(fp, "data {\n");
00571 
00572                             for (i=0; i<=255; i++)
00573                                 {
00574                                     fprintf(fp, "\tb=\"%d\", c=\"%llu\";\n", i, (long long unsigned int) extra->histo1D[i]);
00575                                 }
00576                             fprintf(fp, "}\n");
00577                         }
00578                     else
00579                         {
00580                             /* 2D display */
00581                             fprintf(fp, "header {\n");
00582                             fprintf(fp, "\theight = \"960\";\n");
00583                             fprintf(fp, "\twidth = \"1280\";\n");
00584                             fprintf(fp, Q_("\ttitle = \"Classical histogram\";\n"));
00585                             fprintf(fp, "}\n");
00586                             fprintf(fp, "axes {\n");
00587                             fprintf(fp, Q_("\tchar a [label=\"Bytes\"];\n"));
00588                             fprintf(fp, Q_("\tport c [label=\"Byte count\"];\n"));
00589                             fprintf(fp, Q_("\tchar b [label=\"Bytes\"];\n"));
00590                             fprintf(fp, "}\n");
00591                             fprintf(fp, "data {\n");
00592 
00593                             for (i=0; i<=255; i++)
00594                                 {
00595                                     for (j=0; j<=255; j++)
00596                                         {
00597                                             if (extra->histo2D[i][j] == extra->infos_2D->max)
00598                                                 {
00599                                                     fprintf(fp, "\ta=\"%d\", c=\"%llu\", b=\"%d\" [color=\"red\"];\n", i, (long long unsigned int) extra->histo2D[i][j], j);
00600                                                 }
00601                                             else
00602                                                 {
00603                                                     if (extra->histo2D[i][j] == extra->infos_2D->min)
00604                                                         {
00605                                                             fprintf(fp, "\ta=\"%d\", c=\"%llu\", b=\"%d\" [color=\"green\"];\n", i, (long long unsigned int) extra->histo2D[i][j], j);
00606                                                         }
00607                                                     else
00608                                                         {
00609                                                             fprintf(fp, "\ta=\"%d\", c=\"%llu\", b=\"%d\";\n", i, (long long unsigned int) extra->histo2D[i][j], j);
00610                                                         }
00611                                                 }
00612                                         }
00613                                 }
00614                             fprintf(fp, "}\n");
00615                         }
00616                     fclose(fp);
00617                 }
00618 
00619             if (filename != NULL)
00620                 {
00621                     g_free(filename);
00622                 }
00623         }
00624 }
00625 
00626 
00627 /**
00628  *  What to do when the user chooses a 1D or 2D histo
00629  * @param widget : the widget which called this function (unused here)
00630  * @param data : user data, MUST be heraia_plugin_t *plugin
00631  */
00632 static void histo_radiobutton_toggled(GtkWidget *widget, gpointer data)
00633 {
00634     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00635 
00636     if (plugin != NULL)
00637         {
00638             GtkImage *image = GTK_IMAGE(heraia_get_widget(plugin->xml, "histo_image"));
00639             stat_t *extra = (stat_t *) plugin->extra;
00640 
00641             if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00642                 {
00643                     gtk_image_set_from_pixbuf(image, extra->pixbuf_1D);
00644                 }
00645             else
00646                 {
00647                     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_2D"))) == TRUE)
00648                         {
00649                             gtk_image_set_from_pixbuf(image, extra->pixbuf_2D);
00650                         }
00651                 }
00652         }
00653 }
00654 
00655 
00656 /**
00657  *  Connects all the signals to the correct functions
00658  * @param plugin : main plugin structure
00659  */
00660 static void stat_window_connect_signals(heraia_plugin_t *plugin)
00661 {
00662 
00663     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "stat_window")), "delete_event",
00664                      G_CALLBACK(delete_stat_window_event), plugin);
00665 
00666     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "stat_window")), "destroy",
00667                      G_CALLBACK(destroy_stat_window), plugin);
00668 
00669     /* Close Button */
00670     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_close_b")), "clicked",
00671                      G_CALLBACK(statw_close_clicked), plugin);
00672 
00673     /* RadioButton */
00674     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "rb_1D")), "toggled",
00675                      G_CALLBACK(histo_radiobutton_toggled), plugin);
00676 
00677     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "rb_2D")), "toggled",
00678                      G_CALLBACK(histo_radiobutton_toggled), plugin);
00679 
00680     /* Save As Button */
00681     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_save_as")), "clicked",
00682                      G_CALLBACK(statw_save_as_clicked), plugin);
00683 
00684     /* CVS button */
00685     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_export_to_csv")), "clicked",
00686                      G_CALLBACK(statw_export_to_csv_clicked), plugin);
00687 
00688     /* Gnuplot button */
00689     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_export_to_gnuplot")), "clicked",
00690                      G_CALLBACK(statw_export_to_gnuplot_clicked), plugin);
00691 
00692     /* PCV button */
00693     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_export_to_pcv")), "clicked",
00694                      G_CALLBACK(statw_export_to_pcv_clicked), plugin);
00695 
00696     /* the toogle button is already connected to the run_proc function ! */
00697 }
00698 
00699 
00700 /**
00701  * Do format a date form a time_t value
00702  * @param time_t value
00703  * @return a gchar which represents the value as a date
00704  */
00705 static gchar *transform_time_t_to_gchar(time_t *a_time)
00706 {
00707     gchar *buf = NULL;
00708     struct tm *tm = NULL;
00709     size_t char_size = 0;
00710 
00711     buf = (gchar *) g_malloc0(22*sizeof(gchar));
00712 
00713     tm = gmtime(a_time);
00714 
00715     char_size = strftime(buf, 22, "%x %X", tm);
00716 
00717     if (char_size <= 0)
00718         {
00719             return NULL;
00720         }
00721     else
00722         {
00723             return buf;
00724         }
00725 }
00726 
00727 
00728 /**
00729  * Do some stats on the selected file (entire file is used)
00730  * @param main_struct : main structure from heraia
00731  * @param plugin : main plugin structure (the plugin itself in fact)
00732  */
00733 static void realize_some_numerical_stat(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00734 {
00735     struct stat *stat_buf;
00736     gchar *buf = NULL;           /**< used for date printing */
00737     gchar *filename = NULL;
00738     stat_t *extra = NULL;
00739     GtkTextView *textview = GTK_TEXT_VIEW(heraia_get_widget(plugin->xml, "statw_textview"));
00740 
00741     if (main_struct != NULL && main_struct->current_doc != NULL)
00742         {
00743             filename = doc_t_document_get_filename(main_struct->current_doc);
00744         }
00745 
00746     if (filename != NULL)
00747         {
00748             log_message(main_struct, G_LOG_LEVEL_INFO, Q_("Calculating stats on %s"),  filename);
00749 
00750             stat_buf = (struct stat *) g_malloc0 (sizeof(struct stat));
00751             g_lstat(filename, stat_buf);
00752             if (S_ISREG(stat_buf->st_mode))
00753                 {
00754                     kill_text_from_textview(textview);
00755                     add_text_to_textview(textview, Q_("File size : %Ld bytes\n\n"), stat_buf->st_size);
00756 
00757                     buf = transform_time_t_to_gchar(&(stat_buf->st_mtime));
00758                     if (buf != NULL)
00759                         {
00760                             add_text_to_textview(textview, Q_("Last intern modification : %s\n"), buf);
00761                             g_free(buf);
00762                         }
00763 
00764                     buf = transform_time_t_to_gchar(&(stat_buf->st_atime));
00765                     if (buf != NULL)
00766                         {
00767                             add_text_to_textview(textview, Q_("Last acces to the file   : %s\n"), buf);
00768                             g_free(buf);
00769                         }
00770 
00771                     buf = transform_time_t_to_gchar(&(stat_buf->st_ctime));
00772                     if (buf != NULL)
00773                         {
00774                             add_text_to_textview(textview, Q_("Last extern modification : %s\n"), buf);
00775                             g_free(buf);
00776                         }
00777 
00778 
00779                     populate_stats_histos(main_struct, plugin);
00780 
00781                     extra = (stat_t *) plugin->extra;
00782 
00783                     add_text_to_textview(textview, Q_("\n1D histogram statistics :\n"));
00784                     add_text_to_textview(textview, Q_("     . minimum          : %lld\n"), extra->infos_1D->min);
00785                     add_text_to_textview(textview, Q_("     . maximum          : %lld\n"), extra->infos_1D->max);
00786                     add_text_to_textview(textview, Q_("     . mean             : %lld\n"), extra->infos_1D->mean);
00787                     add_text_to_textview(textview, Q_("     . number of values : %lld\n"), extra->infos_1D->nb_val);
00788                     add_text_to_textview(textview, Q_("\n2D histogram statistics :\n"));
00789                     add_text_to_textview(textview, Q_("     . minimum          : %lld\n"), extra->infos_2D->min);
00790                     add_text_to_textview(textview, Q_("     . maximum          : %lld\n"), extra->infos_2D->max);
00791                     add_text_to_textview(textview, Q_("     . mean             : %lld\n"), extra->infos_2D->mean);
00792                     add_text_to_textview(textview, Q_("     . number of values : %lld\n"), extra->infos_2D->nb_val);
00793                     log_message(main_struct, G_LOG_LEVEL_INFO, Q_("Histos calculated !"));
00794                 }
00795         }
00796 }
00797 
00798 
00799 /**
00800  *  Inits the histograms
00801  */
00802 static void init_stats_histos(heraia_plugin_t *plugin)
00803 {
00804     guint i = 0;
00805     guint j = 0;
00806     stat_t *extra = NULL;
00807 
00808     /* inits the structures */
00809     extra = (stat_t *) plugin->extra;
00810     for (i=0; i<=255; i++)
00811         {
00812             extra->histo1D[i] = 0 ;
00813             for (j=0; j<=255; j++)
00814                 extra->histo2D[i][j] = 0 ;
00815         }
00816 }
00817 
00818 
00819 /**
00820  *  Populates the histograms
00821  */
00822 static void populate_stats_histos(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00823 {
00824     Heraia_Hex *gh = GTK_HEX(main_struct->current_doc->hex_widget);
00825     guint64 i = 0;
00826     guint64 taille = ghex_file_size(gh);
00827     guchar c1, c2;
00828     stat_t *extra = (stat_t *) plugin->extra;
00829     GtkImage *image = GTK_IMAGE(heraia_get_widget(plugin->xml, "histo_image"));
00830     GtkToggleButton *rb_1D = GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"));
00831     GtkToggleButton *rb_2D = GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_2D"));
00832 
00833     init_stats_histos(plugin);
00834 
00835     while (i < taille)
00836         {
00837             c1 = gtk_hex_get_byte(gh, i);
00838             extra->histo1D[c1]++;
00839             if (i+1 < taille)
00840                 {
00841                     i++;
00842                     c2 = gtk_hex_get_byte(gh, i);
00843                     extra->histo1D[c2]++;
00844                     extra->histo2D[c1][c2]++;
00845                 }
00846             i++;
00847         }
00848 
00849     make_pixbufs_from_histos(extra);
00850 
00851     if (gtk_toggle_button_get_active(rb_1D) == TRUE)
00852         {
00853             gtk_image_set_from_pixbuf(image, extra->pixbuf_1D);
00854         }
00855     else
00856         {
00857             if (gtk_toggle_button_get_active(rb_2D) == TRUE)
00858                 {
00859                     gtk_image_set_from_pixbuf(image, extra->pixbuf_2D);
00860                 }
00861         }
00862 }
00863 
00864 
00865 /**
00866  *  Seeks the histo1D struct to find the maximum value
00867  */
00868 static void calc_infos_histo_1D(stat_t *extra)
00869 {
00870     guint i = 0;
00871     gint64 n = 1;
00872     guint64 max = 0;
00873     guint64 min = G_MAXUINT64;
00874     gint64 mean = extra->histo1D[0];
00875     gint64 diff = 0;
00876 
00877     extra->infos_1D->nb_val = 0;
00878 
00879     for (i=0; i<=255; i++)
00880         {
00881             /* maximum value */
00882             if (extra->histo1D[i] > max)
00883                 max = extra->histo1D[i];
00884 
00885             /* minimum value */
00886             if (extra->histo1D[i] < min)
00887                 min = extra->histo1D[i];
00888 
00889             /* number of different values */
00890             if (extra->histo1D[i] > 0)
00891                 extra->infos_1D->nb_val++;
00892 
00893             /* mean calculation */
00894             diff = extra->histo1D[i] - mean;
00895             mean = mean + diff/n;
00896             n++;
00897         }
00898 
00899     extra->infos_1D->min = min;
00900     extra->infos_1D->max = max;
00901     extra->infos_1D->mean = (guint64) mean;
00902 }
00903 
00904 
00905 /**
00906  *  Seeks the histo2D struct to find the maximum value
00907  */
00908 static void calc_infos_histo_2D(stat_t *extra)
00909 {
00910     guint i = 0;
00911     guint j = 0;
00912     gint64 n = 1;
00913     guint64 max = 0;
00914     guint64 min = G_MAXUINT;
00915     gint64 mean = extra->histo2D[0][0];
00916     gint64 diff = 0;
00917 
00918     extra->infos_2D->nb_val = 0;
00919 
00920     for (i=0; i<=255; i++)
00921         {
00922             for (j=0; j<=255; j++)
00923                 {
00924                     /* maximum value */
00925                     if (extra->histo2D[i][j] > max)
00926                         max = extra->histo2D[i][j];
00927 
00928                     /* minimum value */
00929                     if (extra->histo2D[i][j] < min)
00930                         min = extra->histo2D[i][j];
00931 
00932                     /* number of different values */
00933                     if (extra->histo2D[i][j] > 0)
00934                         extra->infos_2D->nb_val++;
00935 
00936                     /* mean calculation */
00937                     diff = extra->histo2D[i][j] - mean;
00938                     mean = mean + diff/n;
00939                     n++;
00940                 }
00941         }
00942 
00943     extra->infos_2D->min = min;
00944     extra->infos_2D->max = max;
00945     extra->infos_2D->mean = (guint64) mean;
00946 }
00947 
00948 
00949 /**
00950  *  Inits the image buffers
00951  */
00952 static void init_stats_pixbufs(stat_t *extra)
00953 {
00954 
00955     extra->pixbuf_1D = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 255, 255);
00956     gdk_pixbuf_fill(extra->pixbuf_1D, 0xFFFFFF00);
00957     gdk_pixbuf_add_alpha(extra->pixbuf_1D, TRUE, (guchar) 255, (guchar) 255, (guchar) 255);
00958 
00959     extra->pixbuf_2D = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 255, 255);
00960     gdk_pixbuf_fill(extra->pixbuf_2D, 0xFFFFFF00);
00961     gdk_pixbuf_add_alpha(extra->pixbuf_2D, TRUE, (guchar) 255, (guchar) 255, (guchar) 255);
00962 
00963 }
00964 
00965 
00966 /**
00967  *  Makes the pixbufs from the histograms values
00968  */
00969 static void make_pixbufs_from_histos(stat_t *extra)
00970 {
00971     init_stats_pixbufs(extra);
00972     calc_infos_histo_1D(extra);
00973     calc_infos_histo_2D(extra);
00974 
00975     if (extra->infos_1D->max > 0)
00976         {
00977             do_pixbuf_1D_from_histo1D(extra);
00978         }
00979 
00980     if (extra->infos_2D->max > 0)
00981         {
00982             do_pixbuf_2D_from_histo2D(extra, extra->infos_2D->max);
00983         }
00984 }
00985 
00986 
00987 /**
00988  *  Prints a pixel in the corresponding pixbuf
00989  */
00990 static void plot_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y, guchar red, guchar green, guchar blue, guchar alpha)
00991 {
00992   guchar *pixels = NULL;
00993   guchar *p = NULL;
00994 
00995   pixels = gdk_pixbuf_get_pixels(pixbuf);
00996 
00997   p = pixels + y * gdk_pixbuf_get_rowstride(pixbuf) + x * gdk_pixbuf_get_n_channels(pixbuf);
00998 
00999   p[0] = red;
01000   p[1] = green;
01001   p[2] = blue;
01002   p[3] = alpha;
01003 
01004 }
01005 
01006 
01007 /**
01008  *  Prints a line of pixels in the corresponding pixbuf (1D histo)
01009  */
01010 static void line_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y)
01011 {
01012     guchar *pixels = NULL;
01013     guchar *p = NULL;
01014 
01015     if (pixbuf != NULL)
01016         {
01017 
01018             gint rowstride = gdk_pixbuf_get_rowstride(pixbuf);
01019             gint n_channels = gdk_pixbuf_get_n_channels(pixbuf);
01020 
01021             pixels = gdk_pixbuf_get_pixels(pixbuf);
01022 
01023             while (y<255)
01024                 {
01025                     p = pixels + y * rowstride + x * n_channels;
01026                     p[0] = (guchar) 255-(y/2);
01027                     p[1] = (guchar) 16;
01028                     p[2] = (guchar) y/2;
01029                     p[3] = (guchar) 255;
01030                     y++;
01031                 }
01032         }
01033 }
01034 
01035 
01036 /**
01037  *  Fills the pixbuf with the corresponding data from the
01038  *  histo1D struct
01039  */
01040 static void do_pixbuf_1D_from_histo1D(stat_t *extra)
01041 {
01042     guint i = 0;
01043     gint64 y = 0;
01044     gdouble inter = 0;
01045     gdouble y_norm = 0;
01046 
01047     for (i=0; i<=255; i++)
01048         {
01049             /* normalisation (here we know that max != 0 (cf make_pixbufs_from_histos) */
01050             y_norm = (gdouble) extra->infos_1D->max - (gdouble) extra->histo1D[i];
01051             inter = (gdouble) (y_norm*255) / (gdouble)(extra->infos_1D->max);
01052             y = (gint64) inter;
01053             line_in_pixbuf(extra->pixbuf_1D, i, y);
01054         }
01055 }
01056 
01057 
01058 /**
01059  *  Fills the pixbuf with the corresponding data from the
01060  *  histo2D struct
01061  *  It is really hard to make something very visible (to make colors
01062  *  look really different between to height values)
01063  */
01064 static void do_pixbuf_2D_from_histo2D(stat_t *extra, guint max_2D)
01065 {
01066     /* A sort of color 'normalization' */
01067     guint i = 0;
01068     guint j = 0;
01069     guchar red;
01070     guchar green;
01071     guchar blue;
01072     gdouble height = 0;
01073     gdouble max = 0;
01074     gdouble min = 0;
01075     gdouble mean = 0;
01076     gdouble threshold1 = 0;
01077     gdouble threshold2 = 0;
01078     guchar ceill;
01079     guchar floor;
01080 
01081     max = extra->infos_2D->max;
01082     min = extra->infos_2D->min;
01083     mean = extra->infos_2D->mean;
01084 
01085     threshold1 = min + (mean - min) / 2;
01086     threshold2 = mean + (max - mean) / 2;
01087 
01088     floor = (guchar) 50;
01089     ceill = (guchar) 200;
01090 
01091     for (i=0; i<=255; i++)
01092         {
01093             for (j=0; j<=255; j++)
01094                 {
01095                     height = extra->histo2D[i][j];  /* min .. max */
01096 
01097                     if (height > 0)
01098                         {
01099 
01100                             if (height >= min && height <= threshold1)
01101                                 {
01102                                     red = floor;
01103                                     green = floor;
01104                                     blue = (guchar) (height - min)*(ceill-floor) / threshold1;
01105                                     /*
01106                                      * height = (gdouble) (height*255) / (gdouble) extra->infos_2D->max;
01107                                      * red = (guchar)  height;
01108                                      * green = (guchar) 255 - (height);
01109                                      * blue = (guchar) height/2;
01110                                      */
01111                                     plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
01112                                 }
01113                             else if (height > threshold1 && height <= threshold2)
01114                                 {
01115                                     red = (guchar) floor;
01116                                     green = (guchar) (height - threshold1)*(ceill-floor) / (threshold2 - threshold1);
01117                                     blue = (guchar) floor; /* ceill - green;*/
01118                                     plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
01119                                 }
01120                             else if (height > threshold2 && height <= max)
01121                                 {
01122                                     red = (guchar) (height - threshold2)*(ceill-floor) / (max - threshold2);
01123                                     green = floor; /* ceill - red; */
01124                                     blue = floor;
01125                                     /*
01126                                      * height = (gdouble) height*255 / (gdouble) extra->infos_2D->max;
01127                                      * red = (guchar)  255 - (height);
01128                                      * green = (guchar) height/2;
01129                                      * blue = (guchar) height;
01130                                      */
01131                                     plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
01132                                 }
01133                         }
01134                 }
01135         }
01136 }
01137 
01138 
Generated on Mon May 2 21:04:49 2011 for Heraia by  doxygen 1.6.3