diff --git a/include/widgets/entity_details_panel.h b/include/widgets/entity_details_panel.h index 4eba95b..31001f4 100644 --- a/include/widgets/entity_details_panel.h +++ b/include/widgets/entity_details_panel.h @@ -69,6 +69,9 @@ typedef void (*EntityDetailsPanelPersonNameCallback)( /** @brief Callback appelé pour gérer les preuves d'une personne. */ typedef void (*EntityDetailsPanelPersonEvidenceCallback)( const char *entity_identifier, gpointer user_data); +/** @brief Callback appelé lorsqu'une preuve associée est activée. */ +typedef void (*EntityDetailsPanelEvidenceActivatedCallback)( + const char *evidence_identifier, gpointer user_data); /** @brief Callback appelé pour ouvrir les recherches OSINT compatibles. */ typedef void (*EntityDetailsPanelOsintCallback)( const char *entity_identifier, gpointer user_data); @@ -178,6 +181,10 @@ void entity_details_panel_set_person_name_callback( void entity_details_panel_set_person_evidence_callback( EntityDetailsPanel *details_panel, EntityDetailsPanelPersonEvidenceCallback callback, gpointer user_data); +void entity_details_panel_set_evidence_activated_callback( + EntityDetailsPanel *details_panel, + EntityDetailsPanelEvidenceActivatedCallback callback, + gpointer user_data); /** @brief Définit le callback du bouton de recherche OSINT. */ void entity_details_panel_set_osint_callback(EntityDetailsPanel *details_panel, EntityDetailsPanelOsintCallback callback, gpointer user_data); diff --git a/include/widgets/workspace.h b/include/widgets/workspace.h index 580cab5..02099e7 100644 --- a/include/widgets/workspace.h +++ b/include/widgets/workspace.h @@ -129,6 +129,8 @@ typedef void (*WorkspacePersonNameCallback)(const char *entity_identifier, /** @brief Callback appelé pour gérer les preuves d'une personne. */ typedef void (*WorkspacePersonEvidenceCallback)( const char *entity_identifier, gpointer user_data); +typedef void (*WorkspaceEvidenceActivatedCallback)( + const char *evidence_identifier, gpointer user_data); /** @brief Callback appelé quand une entité devient sélectionnée. */ typedef void (*WorkspaceEntitySelectedCallback)( const char *entity_identifier, gpointer user_data); @@ -416,6 +418,10 @@ void workspace_set_person_name_callback(Workspace *workspace, /** @brief Définit le callback de gestion des preuves d'une personne. */ void workspace_set_person_evidence_callback(Workspace *workspace, WorkspacePersonEvidenceCallback callback, gpointer user_data); +void workspace_set_evidence_activated_callback( + Workspace *workspace, + WorkspaceEvidenceActivatedCallback callback, + gpointer user_data); /** @brief Définit le callback de sélection d'une entité. */ void workspace_set_entity_selected_callback(Workspace *workspace, WorkspaceEntitySelectedCallback callback, gpointer user_data); diff --git a/src/views/main_window.c b/src/views/main_window.c index d78cf62..99cda85 100644 --- a/src/views/main_window.c +++ b/src/views/main_window.c @@ -106,6 +106,9 @@ struct MainWindow gpointer verify_evidence_user_data; + MainWindowEvidenceSelectionCallback evidence_selection_callback; + gpointer evidence_selection_user_data; + MainWindowEditEvidenceCallback edit_evidence_callback; gpointer edit_evidence_user_data; MainWindowAnalyzeEmlCallback analyze_eml_callback; @@ -631,6 +634,15 @@ static void main_window_on_person_evidence_requested(const char *identifier, window->person_evidence_callback(identifier, window->person_evidence_user_data); } + +static void main_window_on_evidence_activated(const char *identifier, + gpointer user_data) +{ + MainWindow *window = user_data; + if (window != NULL && window->evidence_selection_callback != NULL) + window->evidence_selection_callback(identifier, + window->evidence_selection_user_data); +} /** @brief Relaie la sélection d'une entité vers le contrôleur. */ static void main_window_on_entity_selected(const char *identifier, gpointer user_data) @@ -993,6 +1005,8 @@ MainWindow *main_window_new( main_window_on_person_name_changed, main_window); workspace_set_person_evidence_callback(main_window->workspace, main_window_on_person_evidence_requested, main_window); + workspace_set_evidence_activated_callback(main_window->workspace, + main_window_on_evidence_activated, main_window); workspace_set_entity_selected_callback(main_window->workspace, main_window_on_entity_selected, main_window); @@ -1614,6 +1628,9 @@ void main_window_set_evidence_selection_callback( return; } + main_window->evidence_selection_callback = callback; + main_window->evidence_selection_user_data = user_data; + sidebar_set_evidence_selection_callback( main_window->sidebar, callback, diff --git a/src/widgets/entity_details_panel.c b/src/widgets/entity_details_panel.c index 7fccabd..d25294c 100644 --- a/src/widgets/entity_details_panel.c +++ b/src/widgets/entity_details_panel.c @@ -40,6 +40,7 @@ struct EntityDetailsPanel GtkWidget *person_evidence_button; GtkWidget *person_evidence_summary_label; GtkWidget *entity_evidence_box; + GtkWidget *evidence_buttons_box; char *selected_entity_identifier; char *selected_entity_type; @@ -62,6 +63,8 @@ struct EntityDetailsPanel gpointer person_name_user_data; EntityDetailsPanelPersonEvidenceCallback person_evidence_callback; gpointer person_evidence_user_data; + EntityDetailsPanelEvidenceActivatedCallback evidence_activated_callback; + gpointer evidence_activated_user_data; EntityDetailsPanelOsintCallback osint_callback; gpointer osint_user_data; }; @@ -99,6 +102,18 @@ static void entity_details_panel_on_person_evidence_clicked(GtkButton *button, panel->person_evidence_user_data); } +static void entity_details_panel_on_evidence_activated(GtkButton *button, + gpointer user_data) +{ + EntityDetailsPanel *panel = user_data; + const char *identifier = g_object_get_data(G_OBJECT(button), + "evidence-identifier"); + if (panel != NULL && panel->evidence_activated_callback != NULL && + identifier != NULL) + panel->evidence_activated_callback(identifier, + panel->evidence_activated_user_data); +} + /** @brief Relaie le nouveau nom affiché explicitement enregistré. */ static void entity_details_panel_on_person_name_clicked(GtkButton *button, gpointer user_data) @@ -853,6 +868,8 @@ EntityDetailsPanel *entity_details_panel_new(void) "Gérer les pièces jointes"); details_panel->person_evidence_summary_label = gtk_label_new( "Pièces jointes : chargement…"); + details_panel->evidence_buttons_box = gtk_box_new( + GTK_ORIENTATION_VERTICAL, 4); gtk_label_set_xalign(GTK_LABEL( details_panel->person_evidence_summary_label), 0.0F); gtk_label_set_wrap(GTK_LABEL( @@ -863,6 +880,8 @@ EntityDetailsPanel *entity_details_panel_new(void) gtk_label_new("Preuves associées à cette entité")); gtk_box_append(GTK_BOX(details_panel->entity_evidence_box), details_panel->person_evidence_summary_label); + gtk_box_append(GTK_BOX(details_panel->entity_evidence_box), + details_panel->evidence_buttons_box); gtk_box_append(GTK_BOX(details_panel->entity_evidence_box), details_panel->person_evidence_button); gtk_box_append(GTK_BOX(details_box), details_panel->person_role_box); @@ -1299,6 +1318,15 @@ void entity_details_panel_set_person_evidence_callback( details_panel->person_evidence_callback = callback; details_panel->person_evidence_user_data = user_data; } +void entity_details_panel_set_evidence_activated_callback( + EntityDetailsPanel *details_panel, + EntityDetailsPanelEvidenceActivatedCallback callback, + gpointer user_data) +{ + if (details_panel == NULL) return; + details_panel->evidence_activated_callback = callback; + details_panel->evidence_activated_user_data = user_data; +} void entity_details_panel_set_osint_callback(EntityDetailsPanel *details_panel, EntityDetailsPanelOsintCallback callback, gpointer user_data) { @@ -1314,24 +1342,52 @@ void entity_details_panel_set_osint_callback(EntityDetailsPanel *details_panel, void entity_details_panel_set_person_evidences(EntityDetailsPanel *panel, const GPtrArray *records) { - GString *text = NULL; + GtkWidget *child = NULL; if (panel == NULL || panel->person_evidence_summary_label == NULL) return; - text = g_string_new(NULL); + while (panel->evidence_buttons_box != NULL && + (child = gtk_widget_get_first_child( + panel->evidence_buttons_box)) != NULL) + gtk_box_remove(GTK_BOX(panel->evidence_buttons_box), child); if (records == NULL || records->len == 0) - g_string_append(text, "Aucune pièce jointe"); + gtk_label_set_text(GTK_LABEL(panel->person_evidence_summary_label), + "Aucune pièce jointe"); else + { + char *summary = g_strdup_printf("%u pièce%s jointe%s", + records->len, records->len > 1U ? "s" : "", + records->len > 1U ? "s" : ""); + gtk_label_set_text(GTK_LABEL(panel->person_evidence_summary_label), + summary); + g_free(summary); for (guint index = 0; index < records->len; index++) { const EvidenceRecord *record = g_ptr_array_index(records, index); + GtkWidget *button = NULL; + char *label = NULL; if (record == NULL) continue; - if (text->len > 0) g_string_append_c(text, '\n'); - g_string_append_printf(text, "• %s — %s", + label = g_strdup_printf("%s — %s", evidence_record_get_original_name(record), evidence_record_get_type_identifier(record)); + button = gtk_button_new_with_label(label); + gtk_widget_set_halign(button, GTK_ALIGN_FILL); + gtk_widget_set_tooltip_text(button, label); + gtk_widget_add_css_class(button, "flat"); + if (GTK_IS_LABEL(gtk_button_get_child(GTK_BUTTON(button)))) + { + GtkLabel *button_label = GTK_LABEL( + gtk_button_get_child(GTK_BUTTON(button))); + gtk_label_set_xalign(button_label, 0.0F); + gtk_label_set_ellipsize(button_label, PANGO_ELLIPSIZE_END); + gtk_label_set_max_width_chars(button_label, 28); + } + g_object_set_data_full(G_OBJECT(button), "evidence-identifier", + g_strdup(evidence_record_get_identifier(record)), g_free); + g_signal_connect(button, "clicked", + G_CALLBACK(entity_details_panel_on_evidence_activated), panel); + gtk_box_append(GTK_BOX(panel->evidence_buttons_box), button); + g_free(label); } - gtk_label_set_text(GTK_LABEL(panel->person_evidence_summary_label), - text->str); - g_string_free(text, TRUE); + } } gboolean entity_details_panel_is_open( diff --git a/src/widgets/workspace.c b/src/widgets/workspace.c index 3203adc..6d0b5cb 100644 --- a/src/widgets/workspace.c +++ b/src/widgets/workspace.c @@ -158,6 +158,8 @@ struct Workspace gpointer person_name_user_data; WorkspacePersonEvidenceCallback person_evidence_callback; gpointer person_evidence_user_data; + WorkspaceEvidenceActivatedCallback evidence_activated_callback; + gpointer evidence_activated_user_data; WorkspaceEntitySelectedCallback entity_selected_callback; gpointer entity_selected_user_data; @@ -967,6 +969,15 @@ static void workspace_on_person_evidence_requested(const char *identifier, workspace->person_evidence_user_data); } +static void workspace_on_evidence_activated(const char *identifier, + gpointer user_data) +{ + Workspace *workspace = user_data; + if (workspace != NULL && workspace->evidence_activated_callback != NULL) + workspace->evidence_activated_callback(identifier, + workspace->evidence_activated_user_data); +} + static void workspace_on_extraction_dropped(const char *file_path, const char *target_entity_identifier, gpointer user_data) { @@ -1982,6 +1993,9 @@ Workspace *workspace_new(void) entity_details_panel_set_person_evidence_callback( workspace->entity_details_panel, workspace_on_person_evidence_requested, workspace); + entity_details_panel_set_evidence_activated_callback( + workspace->entity_details_panel, workspace_on_evidence_activated, + workspace); entity_details_panel_set_osint_callback(workspace->entity_details_panel, workspace_on_entity_osint_requested, workspace); @@ -3568,6 +3582,15 @@ void workspace_set_person_evidence_callback(Workspace *workspace, workspace->person_evidence_callback = callback; workspace->person_evidence_user_data = user_data; } +void workspace_set_evidence_activated_callback( + Workspace *workspace, + WorkspaceEvidenceActivatedCallback callback, + gpointer user_data) +{ + if (workspace == NULL) return; + workspace->evidence_activated_callback = callback; + workspace->evidence_activated_user_data = user_data; +} void workspace_set_entity_selected_callback(Workspace *workspace, WorkspaceEntitySelectedCallback callback, gpointer user_data) {