summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-10-24 21:59:55 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-10-24 21:59:55 (GMT)
commita9c607a1be25b43a17ea55b21459a0433f4f3d5b (patch)
tree0bc9018cb2b533d32cf8693871eef563835973b0 /src
parent7ba652c99e843b21c108fc242b8faa7f5f9502c0 (diff)
Provided a dialog box to manage snapshots.
Diffstat (limited to 'src')
-rw-r--r--src/analysis/db/client.c73
-rw-r--r--src/analysis/db/client.h9
-rw-r--r--src/gui/core/Makefile.am4
-rw-r--r--src/gui/core/gresource.xml2
-rw-r--r--src/gui/dialogs/Makefile.am2
-rw-r--r--src/gui/dialogs/gresource.xml1
-rw-r--r--src/gui/dialogs/snapshots.c873
-rw-r--r--src/gui/dialogs/snapshots.h40
-rw-r--r--src/gui/dialogs/snapshots.ui427
-rw-r--r--src/gui/menus/binary.c57
10 files changed, 1484 insertions, 4 deletions
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index 9558f85..b4e856f 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -1569,3 +1569,76 @@ bool g_hub_client_set_snapshot_desc(GHubClient *client, const snapshot_id_t *id,
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à traiter. *
+* *
+* Description : Restaure un ancien instantané. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_hub_client_restore_snapshot(GHubClient *client, const snapshot_id_t *id)
+{
+ bool result; /* Bilan à retourner */
+
+ result = false;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à traiter. *
+* *
+* Description : Crée un nouvel instantané à partir d'un autre. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_hub_client_create_snapshot(GHubClient *client, const snapshot_id_t *id)
+{
+ bool result; /* Bilan à retourner */
+
+ result = false;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* id = identifiant d'instantané à traiter. *
+* rec = programme une suppression récursive. *
+* *
+* Description : Supprime un ancien instantané. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_hub_client_remove_snapshot(GHubClient *client, const snapshot_id_t *id, bool rec)
+{
+ bool result; /* Bilan à retourner */
+
+ result = false;
+
+ return result;
+
+}
diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h
index 5ad4ed0..af47b5c 100644
--- a/src/analysis/db/client.h
+++ b/src/analysis/db/client.h
@@ -89,6 +89,15 @@ bool g_hub_client_set_snapshot_name(GHubClient *, const snapshot_id_t *, const c
/* Définit la description d'un instantané donné. */
bool g_hub_client_set_snapshot_desc(GHubClient *, const snapshot_id_t *, const char *);
+/* Restaure un ancien instantané. */
+bool g_hub_client_restore_snapshot(GHubClient *, const snapshot_id_t *);
+
+/* Crée un nouvel instantané à partir d'un autre. */
+bool g_hub_client_create_snapshot(GHubClient *, const snapshot_id_t *);
+
+/* Supprime un ancien instantané. */
+bool g_hub_client_remove_snapshot(GHubClient *, const snapshot_id_t *, bool);
+
#endif /* _ANALYSIS_DB_CLIENT_H */
diff --git a/src/gui/core/Makefile.am b/src/gui/core/Makefile.am
index d23dc07..db9fd47 100644
--- a/src/gui/core/Makefile.am
+++ b/src/gui/core/Makefile.am
@@ -8,7 +8,9 @@ RES_FILES = \
../../../pixmaps/collapse.png \
../../../pixmaps/collapse_dark.png \
../../../pixmaps/expand.png \
- ../../../pixmaps/expand_dark.png
+ ../../../pixmaps/expand_dark.png \
+ ../../../pixmaps/snapshot.png \
+ ../../../pixmaps/snapshot_current.png
libguicore_la_SOURCES = \
core.h core.c \
diff --git a/src/gui/core/gresource.xml b/src/gui/core/gresource.xml
index ad3688c..6f5cb94 100644
--- a/src/gui/core/gresource.xml
+++ b/src/gui/core/gresource.xml
@@ -6,5 +6,7 @@
<file compressed="true" alias="collapse_dark.png">../../../pixmaps/collapse_dark.png</file>
<file compressed="true" alias="expand.png">../../../pixmaps/expand.png</file>
<file compressed="true" alias="expand_dark.png">../../../pixmaps/expand_dark.png</file>
+ <file compressed="true" alias="snapshot.png">../../../pixmaps/snapshot.png</file>
+ <file compressed="true" alias="snapshot_current.png">../../../pixmaps/snapshot_current.png</file>
</gresource>
</gresources>
diff --git a/src/gui/dialogs/Makefile.am b/src/gui/dialogs/Makefile.am
index ae5180b..575defd 100644
--- a/src/gui/dialogs/Makefile.am
+++ b/src/gui/dialogs/Makefile.am
@@ -10,6 +10,7 @@ UI_FILES = \
preferences.ui \
prefs_fgraph.ui \
prefs_labels.ui \
+ snapshots.ui \
storage.ui
libguidialogs_la_SOURCES = \
@@ -25,6 +26,7 @@ libguidialogs_la_SOURCES = \
prefs_fgraph.h prefs_fgraph.c \
prefs_labels.h prefs_labels.c \
resources.h resources.c \
+ snapshots.h snapshots.c \
storage.h storage.c
libguidialogs_la_LDFLAGS =
diff --git a/src/gui/dialogs/gresource.xml b/src/gui/dialogs/gresource.xml
index 1d18e39..bf81af4 100644
--- a/src/gui/dialogs/gresource.xml
+++ b/src/gui/dialogs/gresource.xml
@@ -7,6 +7,7 @@
<file compressed="true">preferences.ui</file>
<file compressed="true">prefs_fgraph.ui</file>
<file compressed="true">prefs_labels.ui</file>
+ <file compressed="true">snapshots.ui</file>
<file compressed="true">storage.ui</file>
</gresource>
</gresources>
diff --git a/src/gui/dialogs/snapshots.c b/src/gui/dialogs/snapshots.c
new file mode 100644
index 0000000..1fcea67
--- /dev/null
+++ b/src/gui/dialogs/snapshots.c
@@ -0,0 +1,873 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * snapshots.c - gestion des instantanés de base de données
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "snapshots.h"
+
+
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+
+
+#include <i18n.h>
+
+
+
+/* Colonnes de l'arborescence d'instantanés */
+typedef enum _SnapshotTreeColumn
+{
+ STC_ICON, /* Image de représentation */
+ STC_TITLE, /* Meilleure représentation */
+
+ STC_ID, /* Identifiant de l'instantané */
+ STC_TIMESTAMP, /* Valeur brute d'horodatage */
+ STC_NAME, /* Désignation de l'instantané */
+ STC_DESC, /* Description de l'instantané */
+
+} SnapshotTreeColumn;
+
+
+/* Réagit à une fermeture de la boîte de dialogue. */
+static void on_dialog_destroy(GtkWidget *, GtkBuilder *);
+
+/* Réagit à un changement dans le choix du serveur. */
+static void on_server_selection_changed(GtkComboBox *, GtkBuilder *);
+
+/* Recherche un élément d'arborescence selon un identifiant. */
+static bool find_suitable_parent(GtkTreeModel *, GtkTreeIter *, const char *, GtkTreeIter *);
+
+/* Met à jour l'affichage avec une nouvelle liste d'instantanés. */
+static void on_snapshots_updated(GHubClient *, GtkBuilder *);
+
+/* Réinitialise la zone d'affichage des informations. */
+static void reset_information_area(GtkBuilder *);
+
+/* Active ou non l'accès à la zone d'affichage des informations. */
+static void update_information_area_access(GtkBuilder *, bool);
+
+/* Active ou non l'accès à la zone de contrôle des instantanés. */
+static void update_control_area_access(GtkBuilder *, bool, bool, bool);
+
+/* Met à jour l'affichage des informations d'un instantané. */
+static void on_tree_selection_changed(GtkTreeSelection *, GtkBuilder *);
+
+/* Restaure sur demande un nouvel instantané. */
+static void restore_old_snapshot(GtkToolButton *, GtkBuilder *);
+
+/* Crée sur demande un nouvel instantané. */
+static void create_new_snapshot(GtkToolButton *, GtkBuilder *);
+
+/* Supprime sur demande un instantané. */
+static void remove_old_snapshot(GtkToolButton *, GtkBuilder *);
+
+/* Supprime sur demande un instantané et ses successeurs. */
+static void delete_old_snapshot(GtkToolButton *, GtkBuilder *);
+
+/* Applique à un instantané ses nouvelles informations. */
+static void apply_new_snapshot_info(GtkButton *, GtkBuilder *);
+
+/* Ferme la boîte de dialogue. */
+static void close_dialog_box(GtkButton *, GtkBuilder *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : binary = binaire chargé en mémoire à traiter. *
+* parent = fenêtre principale de l'éditeur. *
+* outb = constructeur à détruire après usage. [OUT] *
+* *
+* Description : Affiche un gestionnaire d'instantanés de base de données. *
+* *
+* Retour : Adresse de la fenêtre mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkWidget *create_snapshots_dialog(GLoadedBinary *binary, GtkWindow *parent, GtkBuilder **outb)
+{
+ GtkWidget *result; /* Fenêtre à renvoyer */
+ GtkBuilder *builder; /* Constructeur utilisé */
+ GFile *file; /* Accès à une image interne */
+ GIcon *icon; /* Image de représentation */
+ GtkComboBox *combo; /* Liste de serveurs */
+
+ builder = gtk_builder_new_from_resource("/org/chrysalide/gui/dialogs/snapshots.ui");
+ *outb = builder;
+
+ result = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
+
+ gtk_window_set_transient_for(GTK_WINDOW(result), parent);
+
+ g_object_ref(G_OBJECT(result));
+ g_object_set_data_full(G_OBJECT(builder), "window", result, g_object_unref);
+
+ g_object_ref(G_OBJECT(binary));
+ g_object_set_data_full(G_OBJECT(builder), "binary", binary, g_object_unref);
+
+ file = g_file_new_for_uri("resource:///org/chrysalide/gui/core/images/snapshot.png");
+ icon = g_file_icon_new(file);
+ g_object_set_data_full(G_OBJECT(builder), "icon", icon, g_object_unref);
+
+ file = g_file_new_for_uri("resource:///org/chrysalide/gui/core/images/snapshot_current.png");
+ icon = g_file_icon_new(file);
+ g_object_set_data_full(G_OBJECT(builder), "current_icon", icon, g_object_unref);
+
+ /* Connexion des signaux */
+
+ gtk_builder_add_callback_symbols(builder,
+ "on_dialog_destroy", G_CALLBACK(on_dialog_destroy),
+ "on_server_selection_changed", G_CALLBACK(on_server_selection_changed),
+ "on_tree_selection_changed", G_CALLBACK(on_tree_selection_changed),
+ "restore_old_snapshot", G_CALLBACK(restore_old_snapshot),
+ "create_new_snapshot", G_CALLBACK(create_new_snapshot),
+ "remove_old_snapshot", G_CALLBACK(remove_old_snapshot),
+ "delete_old_snapshot", G_CALLBACK(delete_old_snapshot),
+ "apply_new_snapshot_info", G_CALLBACK(apply_new_snapshot_info),
+ "close_dialog_box", G_CALLBACK(close_dialog_box),
+ NULL);
+
+ gtk_builder_connect_signals(builder, builder);
+
+ /* Mise à jour de l'interface */
+
+ reset_information_area(builder);
+ update_control_area_access(builder, false, false, false);
+
+ combo = GTK_COMBO_BOX(gtk_builder_get_object(builder, "servers"));
+
+ gtk_combo_box_set_active(combo, 0);
+
+ return result;
+
+}
+
+/******************************************************************************
+* *
+* Paramètres : dialog = fenêtre en cours de suppression. *
+* builder = espace de référencement global. *
+* *
+* Description : Réagit à une fermeture de la boîte de dialogue. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_dialog_destroy(GtkWidget *dialog, GtkBuilder *builder)
+{
+ GHubClient *client; /* Cible des interactions */
+
+ /* Déconnexion de l'ancien */
+
+ client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client"));
+
+ if (client != NULL)
+ g_signal_handlers_disconnect_by_func(client, on_snapshots_updated, builder);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : combo = liste de sélection à l'origine de la procédure. *
+* builder = espace de référencement global. *
+* *
+* Description : Réagit à un changement dans le choix du serveur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_server_selection_changed(GtkComboBox *combo, GtkBuilder *builder)
+{
+ GHubClient *client; /* Cible des interactions */
+ gint active; /* Indice du serveur retenu */
+ GLoadedBinary *binary; /* Binaire en cours d'étude */
+ GtkTreeStore *store; /* Modèle de gestion */
+
+ /* Déconnexion de l'ancien */
+
+ client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client"));
+
+ if (client != NULL)
+ g_signal_handlers_disconnect_by_func(client, on_snapshots_updated, builder);
+
+ /* Connexion nouvelle */
+
+ active = gtk_combo_box_get_active(combo);
+
+ binary = G_LOADED_BINARY(g_object_get_data(G_OBJECT(builder), "binary"));
+
+ client = g_loaded_binary_get_client(binary, active == 0);
+
+ if (client == NULL)
+ {
+ g_object_set_data(G_OBJECT(builder), "client", NULL);
+
+ store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store"));
+ gtk_tree_store_clear(store);
+
+ reset_information_area(builder);
+ update_control_area_access(builder, false, false, false);
+
+ }
+
+ else
+ {
+ g_object_ref(G_OBJECT(client));
+ g_object_set_data_full(G_OBJECT(builder), "client", client, g_object_unref);
+
+ g_signal_connect(client, "snapshots-updated", G_CALLBACK(on_snapshots_updated), builder);
+
+ on_snapshots_updated(client, builder);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : model = modèle de gestion de données à consulter. *
+* iter = point de départ des recherches. *
+* id = identifiant de l'instantané recherché. *
+* found = emplacement de l'éventuel noeud trouvé. [OUT] *
+* *
+* Description : Recherche un élément d'arborescence selon un identifiant. *
+* *
+* Retour : true pour indiquer une recherche fructueuse, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool find_suitable_parent(GtkTreeModel *model, GtkTreeIter *iter, const char *id, GtkTreeIter *found)
+{
+ bool result; /* Bilan à retourner */
+ gchar *value; /* Identifiant courant */
+ gint count; /* Quantité de fils présents */
+ gint i; /* Boucle de parcours */
+ GtkTreeIter child; /* Localisation d'un fils */
+#ifndef NDEBUG
+ gboolean status; /* Bilan d'une consultation */
+#endif
+
+ gtk_tree_model_get(model, iter, STC_ID, &value, -1);
+
+ result = (strcmp(value, id) == 0);
+
+ g_free(value);
+
+ if (result)
+ *found = *iter;
+
+ else
+ {
+ count = gtk_tree_model_iter_n_children(model, iter);
+
+ for (i = 0; i < count && !result; i++)
+ {
+#ifndef NDEBUG
+ status = gtk_tree_model_iter_nth_child(model, &child, iter, i);
+ assert(status);
+#else
+ gtk_tree_model_iter_nth_child(model, &child, iter, i);
+#endif
+
+ result = find_suitable_parent(model, &child, id, found);
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client connecté à l'origine de la procédure. *
+* builder = espace de référencement global. *
+* *
+* Description : Met à jour l'affichage avec une nouvelle liste d'instantanés.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_snapshots_updated(GHubClient *client, GtkBuilder *builder)
+{
+ GtkTreeStore *store; /* Modèle de gestion */
+ snapshot_info_t *info; /* Liste d'instantanés présents*/
+ size_t count; /* Taille de cette liste */
+ bool status; /* Validité de cet identifiant */
+ size_t i; /* Boucle de parcours */
+ char *id; /* Identifiant du parent */
+ GtkTreeIter iter; /* Point d'insertion */
+#ifndef NDEBUG
+ gboolean check; /* Vérification par principe */
+#endif
+ GtkTreeIter parent; /* Parent du point d'insertion */
+ GIcon *icon; /* Image de représentation */
+ char *name; /* Désignation d'instantané */
+ snapshot_id_t current; /* Instantané courant */
+ GtkTreeView *treeview; /* Arborescence graphique */
+ const char *raw; /* Identifiant brut */
+ GtkTreeSelection *selection; /* Gestionnaire de sélection */
+
+ store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store"));
+
+ gtk_tree_store_clear(store);
+
+ status = g_hub_client_get_snapshots(client, &info, &count);
+
+ if (!status)
+ {
+ reset_information_area(builder);
+ update_control_area_access(builder, false, false, false);
+ }
+
+ else
+ {
+ /* Remplissage */
+
+ for (i = 0; i < count; i++)
+ {
+ id = snapshot_id_as_string(get_snapshot_info_parent_id(&info[i]));
+
+ if (strcmp(id, NO_SNAPSHOT_ROOT) == 0)
+ gtk_tree_store_append(store, &iter, NULL);
+
+ else
+ {
+#ifndef NDEBUG
+ check = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
+ assert(check);
+#else
+ gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
+#endif
+
+ status = find_suitable_parent(GTK_TREE_MODEL(store), &iter, id, &parent);
+ assert(status);
+
+ gtk_tree_store_append(store, &iter, &parent);
+
+ }
+
+ id = snapshot_id_as_string(get_snapshot_info_id(&info[i]));
+
+ icon = G_ICON(g_object_get_data(G_OBJECT(builder), "icon"));
+
+ name = get_snapshot_info_name(&info[i]);
+
+ gtk_tree_store_set(store, &iter,
+ STC_ICON, icon,
+ STC_TITLE, name != NULL ? name : id,
+ STC_ID, id,
+ STC_TIMESTAMP, get_snapshot_info_created(&info[i]),
+ STC_NAME, name,
+ STC_DESC, get_snapshot_info_desc(&info[i]),
+ -1);
+
+ exit_snapshot_info(&info[i]);
+
+ }
+
+ free(info);
+
+ /* Ajout de l'instantané courant */
+
+ status = g_hub_client_get_current_snapshot(client, &current);
+
+ if (status)
+ {
+ id = snapshot_id_as_string(&current);
+
+#ifndef NDEBUG
+ check = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
+ assert(check);
+#else
+ gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
+#endif
+
+ status = find_suitable_parent(GTK_TREE_MODEL(store), &iter, id, &parent);
+
+ if (status)
+ {
+ gtk_tree_store_append(store, &iter, &parent);
+
+ icon = G_ICON(g_object_get_data(G_OBJECT(builder), "current_icon"));
+
+ gtk_tree_store_set(store, &iter,
+ STC_ICON, icon,
+ STC_TITLE, _("Current"),
+ -1);
+
+ }
+
+ }
+
+ /* Plein affichage */
+
+ treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview"));
+
+ gtk_tree_view_expand_all(treeview);
+
+ /* Remise en place de la dernière sélection */
+
+ raw = g_object_get_data(G_OBJECT(builder), "selected");
+
+ if (raw != NULL)
+ {
+#ifndef NDEBUG
+ check = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
+ assert(check);
+#else
+ gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
+#endif
+
+ status = find_suitable_parent(GTK_TREE_MODEL(store), &iter, raw, &iter);
+
+ if (status)
+ {
+ selection = gtk_tree_view_get_selection(treeview);
+
+ gtk_tree_selection_select_iter(selection, &iter);
+
+ }
+
+ else
+ {
+ reset_information_area(builder);
+
+ update_control_area_access(builder, false, false, false);
+
+ g_object_set_data(G_OBJECT(builder), "selected", NULL);
+
+ }
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : builder = espace de référencement global. *
+* *
+* Description : Réinitialise la zone d'affichage des informations. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void reset_information_area(GtkBuilder *builder)
+{
+ GtkLabel *label; /* Etiquette à faire évoluer */
+ GtkEntry *entry; /* Zone de saisie à actualiser */
+
+ label = GTK_LABEL(gtk_builder_get_object(builder, "identifier"));
+ gtk_label_set_text(label, "-");
+
+ label = GTK_LABEL(gtk_builder_get_object(builder, "timestamp"));
+ gtk_label_set_text(label, "-");
+
+ entry = GTK_ENTRY(gtk_builder_get_object(builder, "name"));
+ gtk_entry_set_text(entry, "");
+
+ entry = GTK_ENTRY(gtk_builder_get_object(builder, "description"));
+ gtk_entry_set_text(entry, "");
+
+ update_information_area_access(builder, false);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : builder = espace de référencement global. *
+* state = état des possibilités d'interactions à appliquer. *
+* *
+* Description : Active ou non l'accès à la zone d'affichage des informations.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void update_information_area_access(GtkBuilder *builder, bool state)
+{
+ GtkWidget *widget; /* Composant à traiter */
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "identifier"));
+ gtk_widget_set_sensitive(widget, state);
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "timestamp"));
+ gtk_widget_set_sensitive(widget, state);
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "name"));
+ gtk_widget_set_sensitive(widget, state);
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "description"));
+ gtk_widget_set_sensitive(widget, state);
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "apply"));
+ gtk_widget_set_sensitive(widget, state);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : builder = espace de référencement global. *
+* restore = accès à la restauration d'un instantané. *
+* create = accès à la création d'un nouvel instantané. *
+* delete = accès à la suppression d'instantanés. *
+* *
+* Description : Active ou non l'accès à la zone de contrôle des instantanés. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void update_control_area_access(GtkBuilder *builder, bool restore, bool create, bool delete)
+{
+ GtkWidget *widget; /* Composant à traiter */
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "restore"));
+ gtk_widget_set_sensitive(widget, restore);
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "create"));
+ gtk_widget_set_sensitive(widget, create);
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "remove"));
+ gtk_widget_set_sensitive(widget, delete);
+
+ widget = GTK_WIDGET(gtk_builder_get_object(builder, "delete"));
+ gtk_widget_set_sensitive(widget, delete);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : selection = nouvelle sélection à appliquer. *
+* builder = espace de référencement global. *
+* *
+* Description : Met à jour l'affichage des informations d'un instantané. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_tree_selection_changed(GtkTreeSelection *selection, GtkBuilder *builder)
+{
+ GtkTreeModel *model; /* Modèle de gestion */
+ GtkTreeIter iter; /* Point de sélection */
+ gchar *id; /* Identifiant d'instantané */
+ guint64 timestamp; /* Horodatage associé */
+ gchar *name; /* Eventuelle désignation */
+ gchar *desc; /* Eventuelle description */
+ GtkLabel *label; /* Etiquette à faire évoluer */
+ char buf[27]; /* Tampon pour la date */
+ GtkEntry *entry; /* Zone de saisie à actualiser */
+ gboolean is_not_root; /* Particularité de sélection */
+
+ if (gtk_tree_selection_get_selected(selection, &model, &iter))
+ {
+ gtk_tree_model_get(model, &iter,
+ STC_ID, &id,
+ STC_TIMESTAMP, &timestamp,
+ STC_NAME, &name,
+ STC_DESC, &desc,
+ -1);
+
+ if (id == NULL)
+ {
+ assert(name == NULL);
+ assert(desc == NULL);
+
+ reset_information_area(builder);
+
+ update_control_area_access(builder, false, true, false);
+
+ g_object_set_data(G_OBJECT(builder), "selected", NULL);
+
+ }
+
+ else
+ {
+ label = GTK_LABEL(gtk_builder_get_object(builder, "identifier"));
+ gtk_label_set_text(label, id);
+
+ ctime_r((time_t []) { timestamp / 1000000 }, buf);
+ buf[strlen(buf) - 1] = 0;
+
+ label = GTK_LABEL(gtk_builder_get_object(builder, "timestamp"));
+ gtk_label_set_text(label, buf);
+
+ entry = GTK_ENTRY(gtk_builder_get_object(builder, "name"));
+ gtk_entry_set_text(entry, name != NULL ? name : "");
+
+ if (name != NULL)
+ g_free(name);
+
+ entry = GTK_ENTRY(gtk_builder_get_object(builder, "description"));
+ gtk_entry_set_text(entry, desc != NULL ? desc : "");
+
+ if (desc != NULL)
+ g_free(desc);
+
+ update_information_area_access(builder, true);
+
+ is_not_root = gtk_tree_model_iter_parent(model, (GtkTreeIter []) { { 0 } }, &iter);
+
+ update_control_area_access(builder, true, false, is_not_root);
+
+ g_object_set_data_full(G_OBJECT(builder), "selected", id, g_free);
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = composant GTK à l'origine de la procédure. *
+* builder = espace de référencement global. *
+* *
+* Description : Restaure sur demande un nouvel instantané. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void restore_old_snapshot(GtkToolButton *button, GtkBuilder *builder)
+{
+ const char *raw; /* Identifiant brut */
+ snapshot_id_t id; /* Identifiant utilisable */
+ bool status; /* Bilan d'une conversion */
+ GHubClient *client; /* Cible des interactions */
+
+ raw = g_object_get_data(G_OBJECT(builder), "selected");
+
+ status = init_snapshot_id_from_text(&id, raw);
+
+ if (status)
+ {
+ client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client"));
+
+ g_hub_client_restore_snapshot(client, &id);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = composant GTK à l'origine de la procédure. *
+* builder = espace de référencement global. *
+* *
+* Description : Crée sur demande un nouvel instantané. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void create_new_snapshot(GtkToolButton *button, GtkBuilder *builder)
+{
+ const char *raw; /* Identifiant brut */
+ snapshot_id_t id; /* Identifiant utilisable */
+ bool status; /* Bilan d'une conversion */
+ GHubClient *client; /* Cible des interactions */
+
+ raw = g_object_get_data(G_OBJECT(builder), "selected");
+
+ status = init_snapshot_id_from_text(&id, raw);
+
+ if (status)
+ {
+ client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client"));
+
+ g_hub_client_create_snapshot(client, &id);
+
+ }
+
+}
+
+/******************************************************************************
+* *
+* Paramètres : button = composant GTK à l'origine de la procédure. *
+* builder = espace de référencement global. *
+* *
+* Description : Supprime sur demande un instantané. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void remove_old_snapshot(GtkToolButton *button, GtkBuilder *builder)
+{
+ const char *raw; /* Identifiant brut */
+ snapshot_id_t id; /* Identifiant utilisable */
+ bool status; /* Bilan d'une conversion */
+ GHubClient *client; /* Cible des interactions */
+
+ raw = g_object_get_data(G_OBJECT(builder), "selected");
+
+ status = init_snapshot_id_from_text(&id, raw);
+
+ if (status)
+ {
+ client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client"));
+
+ g_hub_client_remove_snapshot(client, &id, false);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = composant GTK à l'origine de la procédure. *
+* builder = espace de référencement global. *
+* *
+* Description : Supprime sur demande un instantané et ses successeurs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void delete_old_snapshot(GtkToolButton *button, GtkBuilder *builder)
+{
+ const char *raw; /* Identifiant brut */
+ snapshot_id_t id; /* Identifiant utilisable */
+ bool status; /* Bilan d'une conversion */
+ GHubClient *client; /* Cible des interactions */
+
+ raw = g_object_get_data(G_OBJECT(builder), "selected");
+
+ status = init_snapshot_id_from_text(&id, raw);
+
+ if (status)
+ {
+ client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client"));
+
+ g_hub_client_remove_snapshot(client, &id, true);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = composant GTK à l'origine de la procédure. *
+* builder = espace de référencement global. *
+* *
+* Description : Applique à un instantané ses nouvelles informations. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void apply_new_snapshot_info(GtkButton *button, GtkBuilder *builder)
+{
+ const char *raw; /* Identifiant brut */
+ snapshot_id_t id; /* Identifiant utilisable */
+ bool status; /* Bilan d'une conversion */
+ GHubClient *client; /* Cible des interactions */
+ GtkEntry *entry; /* Zone de saisie à actualiser */
+
+ raw = g_object_get_data(G_OBJECT(builder), "selected");
+
+ status = init_snapshot_id_from_text(&id, raw);
+
+ if (status)
+ {
+ client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client"));
+
+ entry = GTK_ENTRY(gtk_builder_get_object(builder, "name"));
+ g_hub_client_set_snapshot_name(client, &id, gtk_entry_get_text(entry));
+
+ entry = GTK_ENTRY(gtk_builder_get_object(builder, "description"));
+ g_hub_client_set_snapshot_desc(client, &id, gtk_entry_get_text(entry));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = composant GTK à l'origine de la procédure. *
+* builder = espace de référencement global. *
+* *
+* Description : Ferme la boîte de dialogue. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void close_dialog_box(GtkButton *button, GtkBuilder *builder)
+{
+ GtkDialog *dialog; /* Fenêtre à manipuler */
+
+ dialog = GTK_DIALOG(gtk_builder_get_object(builder, "window"));
+
+ gtk_dialog_response(dialog, GTK_RESPONSE_CLOSE);
+
+}
diff --git a/src/gui/dialogs/snapshots.h b/src/gui/dialogs/snapshots.h
new file mode 100644
index 0000000..05f3ac3
--- /dev/null
+++ b/src/gui/dialogs/snapshots.h
@@ -0,0 +1,40 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * snapshots.h - prototypes pour la gestion des instantanés de base de données
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GUI_DIALOGS_SNAPSHOTS_H
+#define _GUI_DIALOGS_SNAPSHOTS_H
+
+
+#include <gtk/gtk.h>
+
+
+#include "../../analysis/binary.h"
+
+
+
+/* Affiche un gestionnaire d'instantanés de base de données. */
+GtkWidget *create_snapshots_dialog(GLoadedBinary *, GtkWindow *, GtkBuilder **);
+
+
+
+#endif /* _GUI_DIALOGS_SNAPSHOTS_H */
diff --git a/src/gui/dialogs/snapshots.ui b/src/gui/dialogs/snapshots.ui
new file mode 100644
index 0000000..7c6d472
--- /dev/null
+++ b/src/gui/dialogs/snapshots.ui
@@ -0,0 +1,427 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.21.0 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image-add">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-add</property>
+ </object>
+ <object class="GtkImage" id="image-delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-delete</property>
+ <property name="icon_size">3</property>
+ </object>
+ <object class="GtkImage" id="image-remove">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-remove</property>
+ </object>
+ <object class="GtkImage" id="image-restore">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-media-play</property>
+ <property name="icon_size">3</property>
+ </object>
+ <object class="GtkTreeStore" id="store">
+ <columns>
+ <!-- column-name icon -->
+ <column type="GIcon"/>
+ <!-- column-name title -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name timestamp -->
+ <column type="guint64"/>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ <!-- column-name desc -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="window">
+ <property name="width_request">530</property>
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">Snapshot management</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <signal name="destroy" handler="on_dialog_destroy" swapped="no"/>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="margin_left">8</property>
+ <property name="margin_right">8</property>
+ <property name="margin_top">8</property>
+ <property name="margin_bottom">8</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="can_focus">False</property>
+ <property name="margin_top">8</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="apply">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="apply_new_snapshot_info" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="close_dialog_box" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Server:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="servers">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <items>
+ <item translatable="yes">Internal</item>
+ </items>
+ <signal name="changed" handler="on_server_selection_changed" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">store</property>
+ <property name="headers_visible">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection">
+ <signal name="changed" handler="on_tree_selection_changed" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">column</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="snapicon"/>
+ <attributes>
+ <attribute name="gicon">0</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkToolButton" id="restore">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Restore an old snapshot</property>
+ <property name="label_widget">image-restore</property>
+ <signal name="clicked" handler="restore_old_snapshot" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="create">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Create a new snapshot</property>
+ <property name="label_widget">image-add</property>
+ <signal name="clicked" handler="create_new_snapshot" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="remove">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Remove a snapshot from the snapshot tree</property>
+ <property name="label_widget">image-remove</property>
+ <signal name="clicked" handler="remove_old_snapshot" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Delete a snapshot with all its children</property>
+ <property name="label_widget">image-delete</property>
+ <signal name="clicked" handler="delete_old_snapshot" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="name">œ</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">8</property>
+ <property name="column_spacing">8</property>
+ <property name="row_homogeneous">True</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Identifier:</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Timestamp:</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Name:</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Description:</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="identifier">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes">-</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="timestamp">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes">-</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="placeholder_text" translatable="yes">No name</property>
+ <property name="input_hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_NONE</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="description">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="placeholder_text" translatable="yes">No description</property>
+ <property name="input_hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_NONE</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Description</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/src/gui/menus/binary.c b/src/gui/menus/binary.c
index cb131d7..aeaf6f6 100644
--- a/src/gui/menus/binary.c
+++ b/src/gui/menus/binary.c
@@ -34,6 +34,7 @@
#include "../dialogs/export_disass.h"
#include "../dialogs/export_graph.h"
#include "../dialogs/gotox.h"
+#include "../dialogs/snapshots.h"
#include "../dialogs/storage.h"
#include "../../gtkext/easygtk.h"
#include "../../gtkext/gtkdisplaypanel.h"
@@ -47,9 +48,12 @@ static void mcb_binary_entry_points(GtkMenuItem *, GMenuBar *);
/* Réagit au menu "Binaire -> Attacher un débogueur". */
static void mcb_binary_attach_debugger(GtkMenuItem *, GMenuBar *);
-/* Réagit au menu "Binaire -> Enregistrements...". */
+/* Réagit au menu "Binaire -> Enregistrements". */
static void mcb_binary_storage(GtkMenuItem *, GMenuBar *);
+/* Réagit au menu "Binaire -> Instantanés". */
+static void mcb_binary_snapshots(GtkMenuItem *, GMenuBar *);
+
/* Réagit au menu "Binaire -> Exporter -> Désassemblage". */
static void mcb_binary_export_disass(GtkMenuItem *, gpointer);
@@ -96,13 +100,21 @@ GtkWidget *build_menu_binary(GObject *ref, GMenuBar *bar)
G_CALLBACK(mcb_binary_attach_debugger), bar);
gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+ /* Séparation */
+
submenuitem = qck_create_menu_separator();
gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
- submenuitem = qck_create_menu_item(ref, "mnu_binary_storage", _("Storage..."),
+ /* Bases de données */
+
+ submenuitem = qck_create_menu_item(ref, "mnu_binary_storage", _("Storage"),
G_CALLBACK(mcb_binary_storage), bar);
gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+ submenuitem = qck_create_menu_item(ref, "mnu_binary_snapshots", _("Snapshots"),
+ G_CALLBACK(mcb_binary_snapshots), bar);
+ gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
+
/* Séparation */
submenuitem = qck_create_menu_separator();
@@ -271,7 +283,7 @@ static void mcb_binary_attach_debugger(GtkMenuItem *menuitem, GMenuBar *bar)
* Paramètres : menuitem = élément de menu sélectionné. *
* bar = barre de menu parente. *
* *
-* Description : Réagit au menu "Binaire -> Enregistrements...". *
+* Description : Réagit au menu "Binaire -> Enregistrements". *
* *
* Retour : - *
* *
@@ -312,6 +324,45 @@ static void mcb_binary_storage(GtkMenuItem *menuitem, GMenuBar *bar)
/******************************************************************************
* *
* Paramètres : menuitem = élément de menu sélectionné. *
+* bar = barre de menu parente. *
+* *
+* Description : Réagit au menu "Binaire -> Instantanés". *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void mcb_binary_snapshots(GtkMenuItem *menuitem, GMenuBar *bar)
+{
+ GLoadedBinary *binary; /* Edition courante */
+ GtkBuilder *builder; /* Constructeur utilisé */
+ GtkWindow *editor; /* Fenêtre graphique principale*/
+ GtkWidget *dialog; /* Boîte de dialogue à montrer */
+
+ binary = G_LOADED_BINARY(get_current_content());
+
+ editor = get_editor_window();
+
+ dialog = create_snapshots_dialog(binary, editor, &builder);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+
+ gtk_widget_destroy(dialog);
+
+ g_object_unref(G_OBJECT(builder));
+
+ g_object_unref(G_OBJECT(editor));
+
+ g_object_unref(G_OBJECT(binary));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : menuitem = élément de menu sélectionné. *
* unused = adresse non utilisée ici. *
* *
* Description : Réagit au menu "Binaire -> Exporter -> Désassemblage". *