From 0680e22f915d1e429a155800648645f41063e9bc Mon Sep 17 00:00:00 2001
From: winckel <winckel@eurecom.fr>
Date: Mon, 4 Nov 2013 14:12:16 +0000
Subject: [PATCH] Added buttons, menu items and calback functions to open and
 save messages files. Added menu items and calback functions to open and save
 filters files. By default, the signal list tree view show the last received
 signals, this can be stop by selecting manually another signal (not the last
 one). Removed the "new" button, the signals list is cleared before each new
 aquisition or when opening a messages file becausethe signal list may not be
 compatible between to list of signals! Enabled column header clicks and
 created callback functions to display and modify column filters.

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4316 818b1a75-f10b-46b9-bf7c-635c3b92a50f
---
 .../utils/itti_analyzer/libui/ui_callbacks.c  | 254 ++++++++++--------
 .../utils/itti_analyzer/libui/ui_callbacks.h  |  30 ++-
 .../itti_analyzer/libui/ui_main_screen.h      |   4 +
 .../utils/itti_analyzer/libui/ui_menu_bar.c   |  75 +++++-
 .../utils/itti_analyzer/libui/ui_menu_bar.h   |   2 +
 .../itti_analyzer/libui/ui_notifications.c    |  85 +++++-
 .../itti_analyzer/libui/ui_notifications.h    |   6 +-
 .../utils/itti_analyzer/libui/ui_tree_view.c  |  26 +-
 .../utils/itti_analyzer/libui/ui_tree_view.h  |   6 +-
 9 files changed, 353 insertions(+), 135 deletions(-)

diff --git a/common/utils/itti_analyzer/libui/ui_callbacks.c b/common/utils/itti_analyzer/libui/ui_callbacks.c
index f4be4438e9d..1ae52ee580f 100644
--- a/common/utils/itti_analyzer/libui/ui_callbacks.c
+++ b/common/utils/itti_analyzer/libui/ui_callbacks.c
@@ -9,6 +9,7 @@
 
 #include "ui_notif_dlg.h"
 #include "ui_main_screen.h"
+#include "ui_menu_bar.h"
 #include "ui_callbacks.h"
 #include "ui_interface.h"
 #include "ui_notifications.h"
@@ -21,45 +22,59 @@
 
 static gboolean ui_handle_socket_connection_failed(gint fd);
 
-gboolean ui_callback_on_open(GtkWidget *widget,
-                             GdkEvent  *event,
-                             gpointer   data)
+gboolean ui_callback_on_open_messages(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
-    g_debug("Open event occurred");
-    CHECK_FCT(ui_file_chooser());
+    g_debug("Open replay event occurred");
+    CHECK_FCT(ui_messages_open_file_chooser());
+
+    return TRUE;
+}
+
+gboolean ui_callback_on_save_messages(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+    g_debug("Save replay event occurred");
+    // CHECK_FCT(ui_file_chooser());
+    return TRUE;
+}
+
+gboolean ui_callback_on_open_filters(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+    g_debug("Open filters event occurred");
+    CHECK_FCT(ui_filters_open_file_chooser());
+    return TRUE;
+}
+
+gboolean ui_callback_on_save_filters(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+    g_debug("Save filters event occurred");
+    CHECK_FCT(ui_filters_save_file_chooser());
     return TRUE;
 }
 
-gboolean ui_callback_on_about(GtkWidget *widget,
-                              GdkEvent  *event,
-                              gpointer   data)
+gboolean ui_callback_on_about(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
 
     return TRUE;
 }
 
-gboolean
-ui_callback_on_select_signal(GtkTreeSelection *selection,
-                             GtkTreeModel     *model,
-                             GtkTreePath      *path,
-                             gboolean          path_currently_selected,
-                             gpointer          user_data)
+gboolean ui_callback_on_select_signal(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path,
+                                      gboolean path_currently_selected, gpointer user_data)
 {
     ui_text_view_t *text_view;
     GtkTreeIter iter;
 
-    text_view = (ui_text_view_t *)user_data;
+    text_view = (ui_text_view_t *) user_data;
 
     g_assert(text_view != NULL);
 
-    if (gtk_tree_model_get_iter(model, &iter, path))
+    if (gtk_tree_model_get_iter (model, &iter, path))
     {
         GValue buffer_store = G_VALUE_INIT;
         gpointer buffer;
 
-        gtk_tree_model_get_value(model, &iter, COL_BUFFER, &buffer_store);
+        gtk_tree_model_get_value (model, &iter, COL_BUFFER, &buffer_store);
 
-        buffer = g_value_get_pointer(&buffer_store);
+        buffer = g_value_get_pointer (&buffer_store);
 
         if (!path_currently_selected)
         {
@@ -76,43 +91,47 @@ ui_callback_on_select_signal(GtkTreeSelection *selection,
 void ui_signal_add_to_list(gpointer data, gpointer user_data)
 {
     buffer_t *signal_buffer;
+    GtkTreePath *path;
+    GtkTreeViewColumn *focus_column;
 
-    signal_buffer = (buffer_t *)data;
+    gtk_tree_view_get_cursor (GTK_TREE_VIEW(ui_main_data.signalslist), &path, &focus_column);
 
-    get_message_id(root, signal_buffer, &signal_buffer->message_id);
+    signal_buffer = (buffer_t *) data;
 
-    ui_tree_view_new_signal_ind(signal_buffer->message_number,
-                                message_id_to_string(signal_buffer->message_id),
-                                get_origin_task_id(signal_buffer),
-                                get_destination_task_id(signal_buffer),
-                                data);
+    get_message_id (root, signal_buffer, &signal_buffer->message_id);
+
+    ui_tree_view_new_signal_ind (signal_buffer->message_number, message_id_to_string (signal_buffer->message_id),
+                                 get_origin_task_id (signal_buffer), get_destination_task_id (signal_buffer), data);
 
     /* Increment number of messages */
     ui_main_data.nb_message_received++;
+
+    /* Check if no signal was selected in the list or if it was the last signal */
+    if ((ui_main_data.path_last == NULL) || (gtk_tree_path_compare(ui_main_data.path_last, path) == 0))
+    {
+        /* Advance to the new last signal */
+        ui_callback_signal_go_to_last (NULL, NULL, NULL);
+    }
 }
 
-static gboolean ui_handle_update_signal_list(gint fd, void *data,
-                                             size_t data_length)
+static gboolean ui_handle_update_signal_list(gint fd, void *data, size_t data_length)
 {
     pipe_new_signals_list_message_t *signal_list_message;
 
     /* Enable buttons to move in the list of signals */
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_clear_button), TRUE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_button), TRUE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_last_button), TRUE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_first_button), TRUE);
+    ui_set_sensitive_move_buttons (TRUE);
 
-    signal_list_message = (pipe_new_signals_list_message_t *)data;
+    signal_list_message = (pipe_new_signals_list_message_t *) data;
 
     g_assert(signal_list_message != NULL);
     g_assert(signal_list_message->signal_list != NULL);
 
-    g_list_foreach(signal_list_message->signal_list, ui_signal_add_to_list, NULL);
+    g_list_foreach (signal_list_message->signal_list, ui_signal_add_to_list, NULL);
 
     /* Free the list but not user data associated with each element */
-    g_list_free(signal_list_message->signal_list);
+    g_list_free (signal_list_message->signal_list);
     /* Free the message */
-    free(signal_list_message);
+    free (signal_list_message);
 
     return TRUE;
 }
@@ -121,17 +140,15 @@ static gboolean ui_handle_socket_connection_failed(gint fd)
 {
     GtkWidget *dialogbox;
 
-    dialogbox = gtk_message_dialog_new(GTK_WINDOW(ui_main_data.window),
-                                       GTK_DIALOG_DESTROY_WITH_PARENT,
-                                       GTK_MESSAGE_ERROR,
-                                       GTK_BUTTONS_CLOSE,
-                                       "Failed to connect to provided host/ip address");
+    dialogbox = gtk_message_dialog_new (GTK_WINDOW(ui_main_data.window), GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+                                        "Failed to connect to provided host/ip address");
 
-    gtk_dialog_run(GTK_DIALOG(dialogbox));
-    gtk_widget_destroy(dialogbox);
+    gtk_dialog_run (GTK_DIALOG(dialogbox));
+    gtk_widget_destroy (dialogbox);
 
     /* Re-enable connect button */
-    ui_enable_connect_button();
+    ui_enable_connect_button ();
     return TRUE;
 }
 
@@ -139,45 +156,42 @@ static gboolean ui_handle_socket_connection_lost(gint fd)
 {
     GtkWidget *dialogbox;
 
-    dialogbox = gtk_message_dialog_new(GTK_WINDOW(ui_main_data.window),
-                                       GTK_DIALOG_DESTROY_WITH_PARENT,
-                                       GTK_MESSAGE_ERROR,
-                                       GTK_BUTTONS_CLOSE,
-                                       "Connection with remote host has been lost");
+    dialogbox = gtk_message_dialog_new (GTK_WINDOW(ui_main_data.window), GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+                                        "Connection with remote host has been lost");
 
-    gtk_dialog_run(GTK_DIALOG(dialogbox));
-    gtk_widget_destroy(dialogbox);
+    gtk_dialog_run (GTK_DIALOG(dialogbox));
+    gtk_widget_destroy (dialogbox);
 
     /* Re-enable connect button */
-    ui_enable_connect_button();
+    ui_enable_connect_button ();
     return TRUE;
 }
 
-static gboolean ui_handle_socket_xml_definition(gint fd, void *data,
-                                                size_t data_length)
+static gboolean ui_handle_socket_xml_definition(gint fd, void *data, size_t data_length)
 {
     pipe_xml_definition_message_t *xml_definition_message;
 
-    xml_definition_message = (pipe_xml_definition_message_t *)data;
+    xml_definition_message = (pipe_xml_definition_message_t *) data;
     g_assert(xml_definition_message != NULL);
     g_assert(data_length == sizeof(pipe_xml_definition_message_t));
 
-    xml_parse_buffer(xml_definition_message->xml_definition,
-                     xml_definition_message->xml_definition_length);
+    xml_parse_buffer (xml_definition_message->xml_definition, xml_definition_message->xml_definition_length);
 
-    free(data);
+    free (data);
 
     return TRUE;
 }
 
 gboolean ui_pipe_callback(gint source, gpointer user_data)
 {
-    void                *input_data = NULL;
-    size_t               input_data_length = 0;
-    pipe_input_header_t  input_header;
+    void *input_data = NULL;
+    size_t input_data_length = 0;
+    pipe_input_header_t input_header;
 
     /* Read the header */
-    if (read(source, &input_header, sizeof(input_header)) < 0) {
+    if (read (source, &input_header, sizeof(input_header)) < 0)
+    {
         g_warning("Failed to read from pipe %d: %s", source, g_strerror(errno));
         return FALSE;
     }
@@ -185,24 +199,27 @@ gboolean ui_pipe_callback(gint source, gpointer user_data)
     input_data_length = input_header.message_size - sizeof(input_header);
 
     /* Checking for non-header part */
-    if (input_data_length > 0) {
-        input_data = malloc(input_data_length);
+    if (input_data_length > 0)
+    {
+        input_data = malloc (input_data_length);
 
-        if (read(source, input_data, input_data_length) < 0) {
+        if (read (source, input_data, input_data_length) < 0)
+        {
             g_warning("Failed to read from pipe %d: %s", source, g_strerror(errno));
             return FALSE;
         }
     }
 
-    switch (input_header.message_type) {
+    switch (input_header.message_type)
+    {
         case UI_PIPE_CONNECTION_FAILED:
-            return ui_handle_socket_connection_failed(source);
+            return ui_handle_socket_connection_failed (source);
         case UI_PIPE_XML_DEFINITION:
-            return ui_handle_socket_xml_definition(source, input_data, input_data_length);
+            return ui_handle_socket_xml_definition (source, input_data, input_data_length);
         case UI_PIPE_CONNECTION_LOST:
-            return ui_handle_socket_connection_lost(source);
+            return ui_handle_socket_connection_lost (source);
         case UI_PIPE_UPDATE_SIGNAL_LIST:
-            return ui_handle_update_signal_list(source, input_data, input_data_length);
+            return ui_handle_update_signal_list (source, input_data, input_data_length);
         default:
             g_debug("[gui] Unhandled message type %u", input_header.message_type);
             g_assert_not_reached();
@@ -210,105 +227,108 @@ gboolean ui_pipe_callback(gint source, gpointer user_data)
     return FALSE;
 }
 
-gboolean ui_callback_on_connect(GtkWidget *widget,
-                                GdkEvent  *event,
-                                gpointer   data)
+gboolean ui_callback_on_connect(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
     /* We have to retrieve the ip address and port of remote host */
     const char *ip;
-    uint16_t    port;
-    int         pipe_fd[2];
+    uint16_t port;
+    int pipe_fd[2];
 
     g_debug("Connect event occurred");
 
-    port = atoi(gtk_entry_get_text(GTK_ENTRY(ui_main_data.portentry)));
-    ip = gtk_entry_get_text(GTK_ENTRY(ui_main_data.ipentry));
+    port = atoi (gtk_entry_get_text (GTK_ENTRY(ui_main_data.portentry)));
+    ip = gtk_entry_get_text (GTK_ENTRY(ui_main_data.ipentry));
 
-    if ((ip == NULL) || (port == 0)) {
+    if ((ip == NULL) || (port == 0))
+    {
         g_warning("NULL parameter given for ip address or port = 0");
         /* TODO: add dialog box here */
         return FALSE;
     }
 
-    ui_pipe_new(pipe_fd, ui_pipe_callback, NULL);
+    ui_pipe_new (pipe_fd, ui_pipe_callback, NULL);
 
-    memcpy(ui_main_data.pipe_fd, pipe_fd, sizeof(int) * 2);
+    memcpy (ui_main_data.pipe_fd, pipe_fd, sizeof(int) * 2);
 
     /* Disable the connect button */
-    ui_disable_connect_button();
+    ui_disable_connect_button ();
 
-    /* Disable buttons to move in the list of signals */
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_clear_button), FALSE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_button), FALSE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_last_button), FALSE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_first_button), FALSE);
-    ui_tree_view_destroy_list(ui_main_data.signalslist);
-
-    if (socket_connect_to_remote_host(ip, port, pipe_fd[1]) != 0) {
-        ui_enable_connect_button();
+    ui_callback_signal_clear_list (widget, event, data);
+
+    if (socket_connect_to_remote_host (ip, port, pipe_fd[1]) != 0)
+    {
+        ui_enable_connect_button ();
         return FALSE;
     }
 
     return TRUE;
 }
 
-gboolean ui_callback_on_disconnect(GtkWidget *widget,
-                                   GdkEvent  *event,
-                                   gpointer   data)
+gboolean ui_callback_on_disconnect(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
     /* We have to retrieve the ip address and port of remote host */
 
     g_debug("Disconnect event occurred");
 
-    ui_pipe_write_message(ui_main_data.pipe_fd[0], UI_PIPE_DISCONNECT_EVT,
-                          NULL, 0);
+    ui_pipe_write_message (ui_main_data.pipe_fd[0], UI_PIPE_DISCONNECT_EVT, NULL, 0);
 
-    ui_enable_connect_button();
+    ui_enable_connect_button ();
     return TRUE;
 }
 
-gboolean ui_callback_signal_go_to(GtkWidget *widget,
-                                  GdkEvent  *event,
-                                  gpointer   data)
+gboolean ui_callback_signal_go_to(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
+    ui_tree_view_select_row (ui_main_data.nb_message_received / 2, NULL);
     return TRUE;
 }
 
-gboolean ui_callback_signal_go_to_first(GtkWidget *widget,
-                                        GdkEvent  *event,
-                                        gpointer   data)
+gboolean ui_callback_signal_go_to_first(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
-    ui_tree_view_select_row(0);
+    ui_tree_view_select_row (0, NULL);
     return TRUE;
 }
 
-gboolean ui_callback_signal_go_to_last(GtkWidget *widget,
-                                       GdkEvent  *event,
-                                       gpointer   data)
+gboolean ui_callback_signal_go_to_last(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
-    ui_tree_view_select_row(ui_main_data.nb_message_received - 1);
+    GtkTreePath *path;
+
+    ui_tree_view_select_row (ui_main_data.nb_message_received - 1, &path);
+    ui_main_data.path_last = path;
+
     return TRUE;
 }
 
-gboolean ui_callback_signal_clear_list(GtkWidget *widget,
-                                       GdkEvent  *event,
-                                       gpointer   data)
+gboolean ui_callback_signal_clear_list(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
     /* Disable buttons to move in the list of signals */
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_clear_button), FALSE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_button), FALSE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_last_button), FALSE);
-    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_first_button), FALSE);
+    ui_set_sensitive_move_buttons (FALSE);
 
-    ui_tree_view_destroy_list(ui_main_data.signalslist);
+    /* Clear list of signals */
+    ui_tree_view_destroy_list (ui_main_data.signalslist);
     return TRUE;
 }
 
-gboolean ui_callback_on_tree_view_select(GtkWidget *widget,
-                                         GdkEvent  *event,
-                                         gpointer   data)
+gboolean ui_callback_on_tree_view_select(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
     /* We have to retrieve the ip address and port of remote host */
     g_debug("List selection event occurred");
     return TRUE;
 }
+
+gboolean ui_callback_on_tree_column_header_click_signal(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+    g_debug("ui_callback_on_tree_column_header_click_signal\n");
+    return TRUE;
+}
+
+gboolean ui_callback_on_tree_column_header_click_from(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+    g_debug("ui_callback_on_tree_column_header_click_from\n");
+    return TRUE;
+}
+
+gboolean ui_callback_on_tree_column_header_click_to(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+    g_debug("ui_callback_on_tree_column_header_click_to\n");
+    return TRUE;
+}
diff --git a/common/utils/itti_analyzer/libui/ui_callbacks.h b/common/utils/itti_analyzer/libui/ui_callbacks.h
index be3ccb90414..9524b7c8d38 100644
--- a/common/utils/itti_analyzer/libui/ui_callbacks.h
+++ b/common/utils/itti_analyzer/libui/ui_callbacks.h
@@ -1,9 +1,21 @@
 #ifndef UI_CALLBACKS_H_
 #define UI_CALLBACKS_H_
 
-gboolean ui_callback_on_open(GtkWidget *widget,
-                             GdkEvent  *event,
-                             gpointer   data);
+gboolean ui_callback_on_open_messages(GtkWidget *widget,
+                                      GdkEvent  *event,
+                                      gpointer   data);
+
+gboolean ui_callback_on_save_messages(GtkWidget *widget,
+                                      GdkEvent  *event,
+                                      gpointer   data);
+
+gboolean ui_callback_on_open_filters(GtkWidget *widget,
+                                     GdkEvent *event,
+                                     gpointer data);
+
+gboolean ui_callback_on_save_filters(GtkWidget *widget,
+                                     GdkEvent *event,
+                                     gpointer data);
 
 gboolean ui_callback_on_about(GtkWidget *widget,
                               GdkEvent  *event,
@@ -49,4 +61,16 @@ gboolean ui_callback_signal_clear_list(GtkWidget *widget,
 
 gboolean ui_pipe_callback(gint source, gpointer user_data);
 
+gboolean ui_callback_on_tree_column_header_click_signal(GtkWidget *widget,
+                                                        GdkEvent  *event,
+                                                        gpointer   data);
+
+gboolean ui_callback_on_tree_column_header_click_from(GtkWidget *widget,
+                                                      GdkEvent  *event,
+                                                      gpointer   data);
+
+gboolean ui_callback_on_tree_column_header_click_to(GtkWidget *widget,
+                                                    GdkEvent  *event,
+                                                    gpointer   data);
+
 #endif /* UI_CALLBACKS_H_ */
diff --git a/common/utils/itti_analyzer/libui/ui_main_screen.h b/common/utils/itti_analyzer/libui/ui_main_screen.h
index b9d2a5770ca..c30b1843294 100644
--- a/common/utils/itti_analyzer/libui/ui_main_screen.h
+++ b/common/utils/itti_analyzer/libui/ui_main_screen.h
@@ -14,6 +14,9 @@ typedef struct {
 
     /* Buttons */
     GtkToolItem *open_replay_file;
+    GtkToolItem *save_replay_file;
+    GtkToolItem *open_filters_file;
+    GtkToolItem *save_filters_file;
     GtkToolItem *connect;
     GtkToolItem *disconnect;
 
@@ -25,6 +28,7 @@ typedef struct {
     GtkToolItem *signals_go_to_first_button;
 
     GtkTreeSelection *selection;
+    GtkTreePath *path_last;
 
     /* Nb of messages received */
     guint nb_message_received;
diff --git a/common/utils/itti_analyzer/libui/ui_menu_bar.c b/common/utils/itti_analyzer/libui/ui_menu_bar.c
index c23ed2d2221..e2f5d2b396e 100644
--- a/common/utils/itti_analyzer/libui/ui_menu_bar.c
+++ b/common/utils/itti_analyzer/libui/ui_menu_bar.c
@@ -5,12 +5,24 @@
 #include "ui_menu_bar.h"
 #include "ui_callbacks.h"
 
+void ui_set_sensitive_move_buttons(gboolean enable)
+{
+    // gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_clear_button), enable);
+    // gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_button), enable);
+    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_last_button), enable);
+    gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.signals_go_to_first_button), enable);
+}
+
 int ui_menu_bar_create(GtkWidget *vbox)
 {
     GtkWidget *menubar;
     GtkWidget *filemenu, *helpmenu;
     GtkWidget *file;
     GtkWidget *help;
+    GtkWidget *open_messages;
+    GtkWidget *save_messages;
+    GtkWidget *open_filters;
+    GtkWidget *save_filters;
     GtkWidget *quit;
     GtkWidget *about;
 
@@ -23,11 +35,19 @@ int ui_menu_bar_create(GtkWidget *vbox)
     filemenu = gtk_menu_new();
 
     file = gtk_menu_item_new_with_label("File");
+    open_messages  = gtk_menu_item_new_with_label("Open messages file");
+    save_messages  = gtk_menu_item_new_with_label("Save messages file");
+    open_filters  = gtk_menu_item_new_with_label("Open filters file");
+    save_filters  = gtk_menu_item_new_with_label("Save filters file");
     quit  = gtk_menu_item_new_with_label("Quit");
 
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
 
     gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
+    gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open_messages);
+    gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), save_messages);
+    gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open_filters);
+    gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), save_filters);
     gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
 
     /* Create the Help submenu */
@@ -44,6 +64,18 @@ int ui_menu_bar_create(GtkWidget *vbox)
     /* Add the menubar to the vbox */
     gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
 
+    g_signal_connect(G_OBJECT(open_messages), "activate",
+                     G_CALLBACK(ui_callback_on_open_messages), NULL);
+
+    g_signal_connect(G_OBJECT(save_messages), "activate",
+                     G_CALLBACK(ui_callback_on_save_messages), NULL);
+
+    g_signal_connect(G_OBJECT(open_filters), "activate",
+                     G_CALLBACK(ui_callback_on_open_filters), NULL);
+
+    g_signal_connect(G_OBJECT(save_filters), "activate",
+                     G_CALLBACK(ui_callback_on_save_filters), NULL);
+
     g_signal_connect(G_OBJECT(quit), "activate",
                      G_CALLBACK(gtk_main_quit), NULL);
 
@@ -70,6 +102,7 @@ int ui_toolbar_create(GtkWidget *vbox)
 
     gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2);
 
+#if 0 /* Not useful anymore, signals list is cleared before every new replay file opening or remote connection */
     /* Button to clear signal list and clear signal dissect view */
     {
         ui_main_data.signals_clear_button = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
@@ -83,18 +116,55 @@ int ui_toolbar_create(GtkWidget *vbox)
         g_signal_connect(G_OBJECT(ui_main_data.signals_clear_button), "clicked",
                         G_CALLBACK(ui_callback_signal_clear_list), NULL);
     }
+#endif
 
     /* Button to open replay file */
     {
         ui_main_data.open_replay_file = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
         gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(ui_main_data.open_replay_file),
-                                    "Open new replay file");
+                                    "Open messages file");
         gtk_toolbar_insert(GTK_TOOLBAR(toolbar), ui_main_data.open_replay_file, -1);
 
         g_signal_connect(G_OBJECT(ui_main_data.open_replay_file), "clicked",
-                        G_CALLBACK(ui_callback_on_open), NULL);
+                        G_CALLBACK(ui_callback_on_open_messages), NULL);
+    }
+
+    /* Button to save replay file */
+    {
+        ui_main_data.save_replay_file = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
+        gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(ui_main_data.save_replay_file),
+                                    "Save messages file");
+        gtk_toolbar_insert(GTK_TOOLBAR(toolbar), ui_main_data.save_replay_file, -1);
+
+        g_signal_connect(G_OBJECT(ui_main_data.save_replay_file), "clicked",
+                        G_CALLBACK(ui_callback_on_save_messages), NULL);
+    }
+
+#if 0 /* Too much button in the bar, it is confusing ! */
+    /* Button to open filters file */
+    {
+        ui_main_data.open_filters_file = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
+        gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(ui_main_data.open_filters_file),
+                                    "Open filters file");
+        gtk_toolbar_insert(GTK_TOOLBAR(toolbar), ui_main_data.open_filters_file, -1);
+
+        g_signal_connect(G_OBJECT(ui_main_data.open_filters_file), "clicked",
+                        G_CALLBACK(ui_callback_on_open_filters), NULL);
+    }
+
+    /* Button to save filters file */
+    {
+        ui_main_data.save_filters_file = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
+        gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(ui_main_data.save_filters_file),
+                                    "Save filters file");
+        gtk_toolbar_insert(GTK_TOOLBAR(toolbar), ui_main_data.save_filters_file, -1);
+
+        g_signal_connect(G_OBJECT(ui_main_data.save_filters_file), "clicked",
+                        G_CALLBACK(ui_callback_on_save_filters), NULL);
     }
+#endif
 
+#if 0 /* This function is already handled by GTK */
     /* Button to go given signal number */
     {
         ui_main_data.signals_go_to_button = gtk_tool_button_new_from_stock(GTK_STOCK_INDEX);
@@ -108,6 +178,7 @@ int ui_toolbar_create(GtkWidget *vbox)
         g_signal_connect(G_OBJECT(ui_main_data.signals_go_to_button), "clicked",
                         G_CALLBACK(ui_callback_signal_go_to), NULL);
     }
+#endif
 
     /* Button to go to first signal in list */
     {
diff --git a/common/utils/itti_analyzer/libui/ui_menu_bar.h b/common/utils/itti_analyzer/libui/ui_menu_bar.h
index 22532079455..529a0674c38 100644
--- a/common/utils/itti_analyzer/libui/ui_menu_bar.h
+++ b/common/utils/itti_analyzer/libui/ui_menu_bar.h
@@ -1,6 +1,8 @@
 #ifndef UI_MENU_BAR_H_
 #define UI_MENU_BAR_H_
 
+void ui_set_sensitive_move_buttons(gboolean enable);
+
 int ui_menu_bar_create(GtkWidget *vbox);
 
 int ui_toolbar_create(GtkWidget *vbox);
diff --git a/common/utils/itti_analyzer/libui/ui_notifications.c b/common/utils/itti_analyzer/libui/ui_notifications.c
index 15caa49c89b..dbafad85115 100644
--- a/common/utils/itti_analyzer/libui/ui_notifications.c
+++ b/common/utils/itti_analyzer/libui/ui_notifications.c
@@ -10,6 +10,7 @@
 
 #include "ui_interface.h"
 #include "ui_main_screen.h"
+#include "ui_menu_bar.h"
 #include "ui_notifications.h"
 #include "ui_callbacks.h"
 
@@ -33,14 +34,16 @@ int ui_enable_connect_button(void)
     return RC_OK;
 }
 
-int ui_file_chooser(void)
+int ui_messages_open_file_chooser(void)
 {
     GtkWidget *filechooser;
     int result = RC_OK;
 
     filechooser = gtk_file_chooser_dialog_new ("Select file", GTK_WINDOW (ui_main_data.window),
-                                               GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
-                                               GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
+                                               GTK_FILE_CHOOSER_ACTION_OPEN,
+                                               GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+                                               GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                               NULL);
 
     /* Process the response */
     if (gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT)
@@ -50,14 +53,22 @@ int ui_file_chooser(void)
         int read_data = 0;
         void *input_data = NULL;
         size_t input_data_length = 0;
+        int read_messages = 0;
 
         filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
 
         source = open (filename, O_RDONLY);
-        if (source >= 0)
+        if (source < 0)
+        {
+            g_warning ("Failed to open file \"%s\": %s", filename, g_strerror (errno));
+            result = RC_FAIL;
+        }
+        else
         {
             itti_socket_header_t message_header;
 
+            ui_callback_signal_clear_list(NULL, NULL, NULL);
+
             do
             {
                 read_data = read (source, &message_header, sizeof(itti_socket_header_t));
@@ -106,6 +117,7 @@ int ui_file_chooser(void)
                             buffer->message_number = itti_signal_header->message_number;
 
                             ui_signal_add_to_list (buffer, NULL);
+                            read_messages ++;
                             break;
                         }
 
@@ -124,7 +136,13 @@ int ui_file_chooser(void)
                 }
             } while (read_data > 0);
 
-            g_debug ("Read %d message from file \"%s\"\n", ui_main_data.nb_message_received, filename);
+            if (read_messages > 0)
+            {
+                /* Enable buttons to move in the list of signals */
+                ui_set_sensitive_move_buttons(TRUE);
+            }
+
+            g_debug ("Read %d messages from file \"%s\"\n", read_messages, filename);
 
             close (source);
         }
@@ -137,6 +155,63 @@ int ui_file_chooser(void)
     return result;
 }
 
+int ui_filters_open_file_chooser(void)
+{
+    GtkWidget *filechooser;
+    int result = RC_OK;
+
+    filechooser = gtk_file_chooser_dialog_new ("Select file", GTK_WINDOW (ui_main_data.window),
+                                               GTK_FILE_CHOOSER_ACTION_OPEN,
+                                               GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+                                               GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                               NULL);
+
+    /* Process the response */
+    if (gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT)
+    {
+        char *filename;
+
+        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
+
+        g_free (filename);
+    }
+
+    gtk_widget_destroy (filechooser);
+
+    return RC_OK;
+}
+
+int ui_filters_save_file_chooser(void)
+{
+    GtkWidget *filechooser;
+    int result = RC_OK;
+
+    filechooser = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (ui_main_data.window),
+                                               GTK_FILE_CHOOSER_ACTION_SAVE,
+                                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                               GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                               NULL);
+
+    gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (filechooser), TRUE);
+
+    //gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filechooser), "filters.xml");
+    gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filechooser), "./filters.xml");
+
+    /* Process the response */
+    if (gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT)
+    {
+        char *filename;
+
+        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
+
+        g_free (filename);
+    }
+
+    gtk_widget_destroy (filechooser);
+
+    return RC_OK;
+}
+
 int ui_progress_bar_set_fraction(double fraction)
 {
 //     /* If not exist instantiate */
diff --git a/common/utils/itti_analyzer/libui/ui_notifications.h b/common/utils/itti_analyzer/libui/ui_notifications.h
index 4cee44c3546..fcb38540f82 100644
--- a/common/utils/itti_analyzer/libui/ui_notifications.h
+++ b/common/utils/itti_analyzer/libui/ui_notifications.h
@@ -5,7 +5,11 @@ int ui_disable_connect_button(void);
 
 int ui_enable_connect_button(void);
 
-int ui_file_chooser(void);
+int ui_messages_open_file_chooser(void);
+
+int ui_filters_open_file_chooser(void);
+
+int ui_filters_save_file_chooser(void);
 
 int ui_progress_bar_set_fraction(double fraction);
 
diff --git a/common/utils/itti_analyzer/libui/ui_tree_view.c b/common/utils/itti_analyzer/libui/ui_tree_view.c
index 269f65ad2c1..dcbadd65593 100644
--- a/common/utils/itti_analyzer/libui/ui_tree_view.c
+++ b/common/utils/itti_analyzer/libui/ui_tree_view.c
@@ -28,14 +28,20 @@ ui_tree_view_init_list(GtkWidget *list)
     column = gtk_tree_view_column_new_with_attributes(
         "Signal", renderer, "text", COL_SIGNAL, NULL);
     gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
+    g_signal_connect(G_OBJECT(column), "clicked",
+                     G_CALLBACK(ui_callback_on_tree_column_header_click_signal), NULL);
 
     column = gtk_tree_view_column_new_with_attributes(
         "From", renderer, "text", COL_FROM_TASK, NULL);
     gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
+    g_signal_connect(G_OBJECT(column), "clicked",
+                     G_CALLBACK(ui_callback_on_tree_column_header_click_from), NULL);
 
     column = gtk_tree_view_column_new_with_attributes(
         "To", renderer, "text", COL_TO_TASK, NULL);
     gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
+    g_signal_connect(G_OBJECT(column), "clicked",
+                     G_CALLBACK(ui_callback_on_tree_column_header_click_to), NULL);
 
     store = gtk_list_store_new(NUM_COLS,
                                G_TYPE_STRING,
@@ -86,6 +92,9 @@ void ui_tree_view_destroy_list(GtkWidget *list)
     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
 
     gtk_list_store_clear(store);
+
+    /* Reset number of messages */
+    ui_main_data.nb_message_received = 0;
 }
 
 int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox)
@@ -112,6 +121,7 @@ int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox)
                       ui_main_data.signalslist);
 
     ui_tree_view_init_list(ui_main_data.signalslist);
+    gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(ui_main_data.signalslist), TRUE);
 
     gtk_widget_set_size_request(GTK_WIDGET(scrolled_window), 500, -1);
     gtk_box_pack_start(GTK_BOX(hbox), scrolled_window, FALSE, FALSE, 0);
@@ -141,13 +151,21 @@ int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signa
     return RC_OK;
 }
 
-void ui_tree_view_select_row(gint row)
+void ui_tree_view_select_row(gint row, GtkTreePath **path)
 {
-    GtkTreePath *path;
+    GtkTreePath *path_row;
     gchar        indice[10];
 
     sprintf(indice, "%d", row);
 
-    path = gtk_tree_path_new_from_string(indice);
-    gtk_tree_view_set_cursor(GTK_TREE_VIEW(ui_main_data.signalslist), path, NULL, FALSE);
+    path_row = gtk_tree_path_new_from_string(indice);
+    /* Select the message in requested row */
+    gtk_tree_view_set_cursor(GTK_TREE_VIEW(ui_main_data.signalslist), path_row, NULL, FALSE);
+    /* Center the message in the middle of the list if possible */
+    gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ui_main_data.signalslist), path_row, NULL, TRUE, 0.5, 0.0);
+
+    if (path != NULL)
+    {
+        *path = path_row;
+    }
 }
diff --git a/common/utils/itti_analyzer/libui/ui_tree_view.h b/common/utils/itti_analyzer/libui/ui_tree_view.h
index 83691c66412..e04224c8578 100644
--- a/common/utils/itti_analyzer/libui/ui_tree_view.h
+++ b/common/utils/itti_analyzer/libui/ui_tree_view.h
@@ -1,7 +1,7 @@
 #ifndef UI_TREE_VIEW_H_
 #define UI_TREE_VIEW_H_
 
-enum
+typedef enum
 {
     COL_MSG_NUM = 0,
     COL_SIGNAL,
@@ -9,7 +9,7 @@ enum
     COL_TO_TASK,
     COL_BUFFER,
     NUM_COLS
-};
+} col_type_e;
 
 int ui_tree_view_create(GtkWidget *window, GtkWidget *vbox);
 
@@ -18,6 +18,6 @@ int ui_tree_view_new_signal_ind(const uint32_t message_number, const char *signa
 
 void ui_tree_view_destroy_list(GtkWidget *list);
 
-void ui_tree_view_select_row(gint row);
+void ui_tree_view_select_row(gint row, GtkTreePath **path);
 
 #endif /* UI_TREE_VIEW_H_ */
-- 
GitLab