/****************************************************************************** * @file main_window.c * @brief Implémentation de la fenêtre principale. ******************************************************************************/ #include "views/main_window.h" #include "widgets/sidebar.h" #include "widgets/workspace.h" #include "widgets/investigation_tree_view.h" #include "widgets/task_panel.h" #include /** * @brief Largeur initiale de la fenêtre principale. */ #define MAIN_WINDOW_DEFAULT_WIDTH 1100 /** * @brief Hauteur initiale de la fenêtre principale. */ #define MAIN_WINDOW_DEFAULT_HEIGHT 650 /** * @brief Position initiale de la séparation horizontale. */ #define MAIN_WINDOW_SIDEBAR_POSITION 640 /** * @brief Position initiale de la séparation verticale. */ #define MAIN_WINDOW_TASK_PANEL_POSITION 390 /** * @brief Titre par défaut de la fenêtre. */ #define MAIN_WINDOW_DEFAULT_TITLE \ "Labfy Investigation" /** * @brief Texte affiché lorsqu'aucune enquête n'est ouverte. */ #define MAIN_WINDOW_NO_INVESTIGATION_STATUS \ "Aucune enquête ouverte" /** * @struct MainWindow * @brief Représentation interne de la fenêtre principale. * * Cette structure reste privée au module. Elle conserve les composants * nécessaires à l'organisation générale de l'interface. */ struct MainWindow { GtkWindow *window; GtkWidget *main_box; GtkWidget *action_bar; GtkWidget *new_investigation_button; GtkWidget *open_investigation_button; GtkWidget *import_evidence_button; GtkWidget *add_social_account_button; GtkWidget *add_person_button; GtkWidget *show_graph_button; GtkWidget *content_paned; GtkWidget *main_paned; GtkWidget *status_label; GtkWidget *quit_button; Sidebar *sidebar; Workspace *workspace; TaskPanel *task_panel; MainWindowNewInvestigationCallback new_investigation_callback; gpointer new_investigation_user_data; MainWindowOpenInvestigationCallback open_investigation_callback; gpointer open_investigation_user_data; MainWindowImportEvidenceCallback import_evidence_callback; gpointer import_evidence_user_data; MainWindowAddSocialAccountCallback add_social_account_callback; gpointer add_social_account_user_data; MainWindowAddPersonCallback add_person_callback; gpointer add_person_user_data; MainWindowShowGraphCallback show_graph_callback; gpointer show_graph_user_data; MainWindowVerifyEvidenceCallback verify_evidence_callback; 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; gpointer analyze_eml_user_data; MainWindowAnalyzeRibCallback analyze_rib_callback; gpointer analyze_rib_user_data; MainWindowExtractMetadataCallback extract_metadata_callback; gpointer extract_metadata_user_data; MainWindowRecoverPdfPasswordCallback recover_pdf_password_callback; gpointer recover_pdf_password_user_data; MainWindowGraphNodeMovedCallback graph_node_moved_callback; gpointer graph_node_moved_user_data; MainWindowGraphTransformChangedCallback graph_transform_changed_callback; gpointer graph_transform_changed_user_data; MainWindowExtractionDropCallback extraction_drop_callback; gpointer extraction_drop_user_data; MainWindowResetGraphLayoutCallback reset_graph_layout_callback; gpointer reset_graph_layout_user_data; MainWindowAddRelationCallback add_relation_callback; gpointer add_relation_user_data; MainWindowEditRelationCallback edit_relation_callback; gpointer edit_relation_user_data; MainWindowDeleteRelationCallback delete_relation_callback; gpointer delete_relation_user_data; MainWindowPersonRoleCallback person_role_callback; gpointer person_role_user_data; MainWindowPersonConfidenceCallback person_confidence_callback; gpointer person_confidence_user_data; MainWindowPersonNameCallback person_name_callback; gpointer person_name_user_data; MainWindowPersonEvidenceCallback person_evidence_callback; gpointer person_evidence_user_data; MainWindowEntitySelectedCallback entity_selected_callback; gpointer entity_selected_user_data; MainWindowOsintActionCallback osint_action_callback; gpointer osint_action_user_data; MainWindowQuitCallback quit_callback; gpointer quit_user_data; }; /** * @brief Relaie une action OSINT vers le contrôleur applicatif. */ static void main_window_on_osint_action_requested( const char *action_identifier, const char *target_identifier, const char *target_value, gpointer user_data ) { MainWindow *main_window = user_data; if (main_window == NULL || main_window->osint_action_callback == NULL) { return; } main_window->osint_action_callback( action_identifier, target_identifier, target_value, main_window->osint_action_user_data ); } /** @brief Relaie la modification d'une preuve vers l'application. */ static void main_window_on_edit_evidence_requested( const char *evidence_identifier, gpointer user_data ) { MainWindow *main_window = user_data; if (main_window == NULL || main_window->edit_evidence_callback == NULL) return; main_window->edit_evidence_callback( evidence_identifier, main_window->edit_evidence_user_data); } /** @brief Relaie la demande d'analyse EML vers l'application. */ static void main_window_on_analyze_eml_requested(const char *identifier, gpointer data) { MainWindow *main_window = data; if (main_window != NULL && main_window->analyze_eml_callback != NULL) main_window->analyze_eml_callback(identifier, main_window->analyze_eml_user_data); } /** @brief Relaie la demande d'analyse OCR d'un RIB. */ static void main_window_on_analyze_rib_requested(const char *identifier, gpointer data) { MainWindow *window = data; if (window != NULL && window->analyze_rib_callback != NULL) window->analyze_rib_callback(identifier, window->analyze_rib_user_data); } /** @brief Relaie la demande d'extraction des métadonnées. */ static void main_window_on_extract_metadata_requested(const char *identifier, gpointer data) { MainWindow *window = data; if (window != NULL && window->extract_metadata_callback != NULL) window->extract_metadata_callback(identifier, window->extract_metadata_user_data); } /** @brief Relaie la demande de récupération du mot de passe PDF. */ static void main_window_on_recover_pdf_password_requested( const char *identifier, gpointer data) { MainWindow *window = data; if (window != NULL && window->recover_pdf_password_callback != NULL) window->recover_pdf_password_callback(identifier, window->recover_pdf_password_user_data); } /** * @brief Ouvre dans le workspace l'entité choisie dans la sidebar. */ static void main_window_on_sidebar_entity_selected( const char *entity_identifier, gpointer user_data ) { MainWindow *main_window = user_data; if (main_window == NULL || entity_identifier == NULL || entity_identifier[0] == '\0') { return; } workspace_select_graph_entity( main_window->workspace, entity_identifier ); } /** * @brief Ouvre dans le workspace la relation choisie dans la sidebar. */ static void main_window_on_sidebar_relation_selected( const char *relation_identifier, gpointer user_data ) { MainWindow *main_window = user_data; if (main_window == NULL || relation_identifier == NULL || relation_identifier[0] == '\0') { return; } workspace_select_graph_relation( main_window->workspace, relation_identifier ); } /** * @brief Transmet la demande de création d'une enquête au contrôleur. * * @param button Bouton ayant reçu le clic. * @param user_data Pointeur vers MainWindow. */ static void main_window_on_new_investigation_clicked( GtkButton *button, gpointer user_data ) { MainWindow *main_window = user_data; (void) button; if (main_window == NULL || main_window->new_investigation_callback == NULL) { return; } main_window->new_investigation_callback( main_window->new_investigation_user_data ); } /** * @brief Transmet la demande d'ouverture d'une enquête au contrôleur. * * @param button Bouton ayant reçu le clic. * @param user_data Pointeur vers MainWindow. */ static void main_window_on_open_investigation_clicked( GtkButton *button, gpointer user_data ) { MainWindow *main_window = user_data; (void) button; if (main_window == NULL || main_window->open_investigation_callback == NULL) { return; } main_window->open_investigation_callback( main_window->open_investigation_user_data ); } /** * @brief Transmet la demande d'import d'une preuve au contrôleur. * * @param button Bouton ayant reçu le clic. * @param user_data Pointeur vers MainWindow. */ static void main_window_on_import_evidence_clicked( GtkButton *button, gpointer user_data ) { MainWindow *main_window = user_data; (void) button; if (main_window == NULL || main_window->import_evidence_callback == NULL) { return; } main_window->import_evidence_callback( main_window->import_evidence_user_data ); } /** @brief Relaie la demande d'ajout d'un compte social. */ static void main_window_on_add_social_account_clicked( GtkButton *button, gpointer user_data) { MainWindow *main_window = user_data; (void) button; if (main_window == NULL || main_window->add_social_account_callback == NULL) return; main_window->add_social_account_callback( main_window->add_social_account_user_data); } /** @brief Relaie la demande d'ajout d'une personne. */ static void main_window_on_add_person_clicked(GtkButton *button, gpointer data) { MainWindow *main_window = data; (void) button; if (main_window != NULL && main_window->add_person_callback != NULL) main_window->add_person_callback(main_window->add_person_user_data); } /** * @brief Transmet la demande de fermeture au contrôleur. * * @param button Bouton ayant reçu le clic. * @param user_data Pointeur vers MainWindow. */ static void main_window_on_show_graph_clicked( GtkButton *button, gpointer user_data ) { MainWindow *main_window = user_data; (void) button; if (main_window == NULL || main_window->show_graph_callback == NULL) { return; } main_window->show_graph_callback( main_window->show_graph_user_data ); } /** * @brief Transmet la demande de fermeture au contrôleur. * * @param button Bouton ayant reçu le clic. * @param user_data Pointeur vers MainWindow. */ static void main_window_on_quit_clicked( GtkButton *button, gpointer user_data ) { MainWindow *main_window = user_data; (void) button; if (main_window == NULL || main_window->quit_callback == NULL) { return; } main_window->quit_callback( main_window->quit_user_data ); } /** * @brief Crée un bouton d'action compact avec une icône. * * @param icon_name Nom de l'icône symbolique GTK. * @param tooltip_text Texte de l'infobulle. * * @return Nouveau bouton GTK. */ static GtkWidget *main_window_create_action_button( const char *icon_name, const char *tooltip_text ) { GtkWidget *button = NULL; if (icon_name == NULL || icon_name[0] == '\0') { return NULL; } button = gtk_button_new_from_icon_name( icon_name ); if (button == NULL) { return NULL; } gtk_widget_add_css_class( button, "flat" ); if (tooltip_text != NULL && tooltip_text[0] != '\0') { gtk_widget_set_tooltip_text( button, tooltip_text ); } return button; } /** * @brief Relaie la demande de vérification provenant du Workspace. */ static void main_window_on_graph_node_moved( const char *entity_identifier, double x, double y, gpointer user_data ) { MainWindow *main_window = user_data; if (main_window == NULL || main_window->graph_node_moved_callback == NULL || entity_identifier == NULL || entity_identifier[0] == '\0') { return; } main_window->graph_node_moved_callback( entity_identifier, x, y, main_window->graph_node_moved_user_data ); } static void main_window_on_graph_transform_changed(gpointer user_data) { MainWindow *main_window = user_data; if (main_window != NULL && main_window->graph_transform_changed_callback != NULL) main_window->graph_transform_changed_callback( main_window->graph_transform_changed_user_data); } static void main_window_on_extraction_dropped(const char *file_path, const char *target_entity_identifier, gpointer user_data) { MainWindow *main_window = user_data; if (main_window != NULL && main_window->extraction_drop_callback != NULL) main_window->extraction_drop_callback(file_path, target_entity_identifier, main_window->extraction_drop_user_data); } /** * @brief Relaie la demande de vérification provenant du Workspace. */ static void main_window_on_reset_graph_layout_requested( gpointer user_data ) { MainWindow *main_window = user_data; if (main_window == NULL || main_window->reset_graph_layout_callback == NULL) { return; } main_window->reset_graph_layout_callback( main_window->reset_graph_layout_user_data ); } /** * @brief Relaie la demande d'ajout d'une relation. */ static void main_window_on_add_relation_requested( const char *source_entity_identifier, gpointer user_data ) { MainWindow *main_window = user_data; if (main_window == NULL || main_window->add_relation_callback == NULL || source_entity_identifier == NULL || !g_uuid_string_is_valid( source_entity_identifier )) { return; } main_window->add_relation_callback( source_entity_identifier, main_window->add_relation_user_data ); } /** @brief Relaie la demande de modification d'une relation. */ static void main_window_on_edit_relation_requested( const char *relation_identifier, gpointer user_data) { MainWindow *main_window = user_data; if (main_window == NULL || main_window->edit_relation_callback == NULL || relation_identifier == NULL) { return; } main_window->edit_relation_callback(relation_identifier, main_window->edit_relation_user_data); } /** @brief Relaie la demande de suppression d'une relation. */ static void main_window_on_delete_relation_requested( const char *relation_identifier, gpointer user_data) { MainWindow *main_window = user_data; if (main_window != NULL && main_window->delete_relation_callback != NULL) main_window->delete_relation_callback(relation_identifier, main_window->delete_relation_user_data); } /** @brief Relaie la catégorisation d'une personne. */ static void main_window_on_person_role_changed(const char *entity_identifier, PersonRole role, gpointer user_data) { MainWindow *main_window = user_data; if (main_window != NULL && main_window->person_role_callback != NULL) main_window->person_role_callback(entity_identifier, role, main_window->person_role_user_data); } /** @brief Relaie la modification de confiance d'une personne. */ static void main_window_on_person_confidence_changed( const char *entity_identifier, gint confidence, gpointer user_data) { MainWindow *main_window = user_data; if (main_window != NULL && main_window->person_confidence_callback != NULL) main_window->person_confidence_callback(entity_identifier, confidence, main_window->person_confidence_user_data); } /** @brief Relaie la modification du nom affiché d'une personne. */ static void main_window_on_person_name_changed(const char *entity_identifier, const char *display_name, gpointer user_data) { MainWindow *main_window = user_data; if (main_window != NULL && main_window->person_name_callback != NULL) main_window->person_name_callback(entity_identifier, display_name, main_window->person_name_user_data); } /** @brief Relaie la gestion des preuves d'une personne. */ static void main_window_on_person_evidence_requested(const char *identifier, gpointer user_data) { MainWindow *window = user_data; if (window != NULL && window->person_evidence_callback != NULL) 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) { MainWindow *window = user_data; if (window != NULL && window->entity_selected_callback != NULL) window->entity_selected_callback(identifier, window->entity_selected_user_data); } /** * @brief Relaie la demande de vérification provenant du Workspace. */ static void main_window_on_verify_evidence_requested( const char *evidence_identifier, gpointer user_data ) { MainWindow *main_window = user_data; if (main_window == NULL || main_window->verify_evidence_callback == NULL || evidence_identifier == NULL || evidence_identifier[0] == '\0') { return; } main_window->verify_evidence_callback( evidence_identifier, main_window->verify_evidence_user_data ); } MainWindow *main_window_new( GtkApplication *application, TaskManager *task_manager ) { MainWindow *main_window = NULL; GtkWidget *sidebar_widget = NULL; GtkWidget *workspace_widget = NULL; GtkWidget *task_panel_widget = NULL; GtkWidget *action_spacer = NULL; if (application == NULL || task_manager == NULL) { return NULL; } main_window = g_new0(MainWindow, 1); main_window->window = GTK_WINDOW( gtk_application_window_new(application) ); if (main_window->window == NULL) { main_window_free(main_window); return NULL; } gtk_window_set_title( main_window->window, MAIN_WINDOW_DEFAULT_TITLE ); gtk_window_set_default_size( main_window->window, MAIN_WINDOW_DEFAULT_WIDTH, MAIN_WINDOW_DEFAULT_HEIGHT ); /* * La boîte principale organise verticalement : * * 1. la zone centrale ; * 2. la barre d'état. */ main_window->main_box = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 ); /* * Barre regroupant les actions générales de l'application. */ main_window->action_bar = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 4 ); gtk_widget_set_margin_start( main_window->action_bar, 8 ); gtk_widget_set_margin_end( main_window->action_bar, 8 ); gtk_widget_set_margin_top( main_window->action_bar, 8 ); gtk_widget_set_margin_bottom( main_window->action_bar, 8 ); main_window->new_investigation_button = main_window_create_action_button( "document-new-symbolic", "Créer une nouvelle enquête" ); main_window->open_investigation_button = main_window_create_action_button( "document-open-symbolic", "Ouvrir une enquête" ); main_window->import_evidence_button = main_window_create_action_button( "document-save-symbolic", "Importer une preuve" ); main_window->add_social_account_button = main_window_create_action_button( "contact-new-symbolic", "Ajouter un compte social" ); main_window->add_person_button = main_window_create_action_button( "avatar-default-symbolic", "Ajouter une personne"); main_window->show_graph_button = main_window_create_action_button( "go-previous-symbolic", "Revenir au graphe" ); main_window->quit_button = main_window_create_action_button( "application-exit-symbolic", "Quitter Labfy Investigation" ); action_spacer = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); gtk_widget_set_hexpand( action_spacer, TRUE ); /* * Aucun import n'est autorisé sans enquête ouverte. */ gtk_widget_set_sensitive( main_window->import_evidence_button, FALSE ); gtk_widget_set_sensitive(main_window->add_social_account_button, FALSE); gtk_widget_set_sensitive(main_window->add_person_button, FALSE); gtk_widget_set_sensitive( main_window->show_graph_button, FALSE ); gtk_box_append( GTK_BOX(main_window->action_bar), main_window->new_investigation_button ); gtk_box_append( GTK_BOX(main_window->action_bar), main_window->open_investigation_button ); gtk_box_append( GTK_BOX(main_window->action_bar), main_window->import_evidence_button ); gtk_box_append(GTK_BOX(main_window->action_bar), main_window->add_social_account_button); gtk_box_append(GTK_BOX(main_window->action_bar), main_window->add_person_button); gtk_box_append( GTK_BOX(main_window->action_bar), main_window->show_graph_button ); gtk_box_append( GTK_BOX(main_window->action_bar), action_spacer ); gtk_box_append( GTK_BOX(main_window->action_bar), main_window->quit_button ); g_signal_connect( main_window->new_investigation_button, "clicked", G_CALLBACK( main_window_on_new_investigation_clicked ), main_window ); g_signal_connect( main_window->open_investigation_button, "clicked", G_CALLBACK( main_window_on_open_investigation_clicked ), main_window ); g_signal_connect( main_window->import_evidence_button, "clicked", G_CALLBACK( main_window_on_import_evidence_clicked ), main_window ); g_signal_connect(main_window->add_social_account_button, "clicked", G_CALLBACK(main_window_on_add_social_account_clicked), main_window); g_signal_connect(main_window->add_person_button, "clicked", G_CALLBACK(main_window_on_add_person_clicked), main_window); g_signal_connect( main_window->show_graph_button, "clicked", G_CALLBACK( main_window_on_show_graph_clicked ), main_window ); g_signal_connect( main_window->quit_button, "clicked", G_CALLBACK( main_window_on_quit_clicked ), main_window ); /* * GtkPaned sépare horizontalement le panneau latéral * et la zone de travail. */ main_window->main_paned = gtk_paned_new( GTK_ORIENTATION_HORIZONTAL ); gtk_widget_set_hexpand( main_window->main_paned, TRUE ); gtk_widget_set_vexpand( main_window->main_paned, TRUE ); /* * Création du panneau latéral via son propre module. * * MainWindow ne connaît pas son contenu interne. */ main_window->sidebar = sidebar_new(); if (main_window->sidebar == NULL) { main_window_free(main_window); return NULL; } sidebar_widget = sidebar_get_widget( main_window->sidebar ); if (sidebar_widget == NULL) { main_window_free(main_window); return NULL; } main_window->workspace = workspace_new(); if (main_window->workspace == NULL) { main_window_free(main_window); return NULL; } sidebar_set_entity_selection_callback( main_window->sidebar, main_window_on_sidebar_entity_selected, main_window ); sidebar_set_relation_selection_callback( main_window->sidebar, main_window_on_sidebar_relation_selected, main_window ); workspace_set_verify_evidence_callback( main_window->workspace, main_window_on_verify_evidence_requested, main_window ); workspace_set_graph_node_moved_callback( main_window->workspace, main_window_on_graph_node_moved, main_window ); workspace_set_graph_transform_changed_callback( main_window->workspace, main_window_on_graph_transform_changed, main_window); workspace_set_extraction_drop_callback(main_window->workspace, main_window_on_extraction_dropped, main_window); workspace_set_reset_graph_layout_callback( main_window->workspace, main_window_on_reset_graph_layout_requested, main_window ); workspace_set_add_relation_callback( main_window->workspace, main_window_on_add_relation_requested, main_window ); workspace_set_edit_relation_callback(main_window->workspace, main_window_on_edit_relation_requested, main_window); workspace_set_delete_relation_callback(main_window->workspace, main_window_on_delete_relation_requested, main_window); workspace_set_person_role_callback(main_window->workspace, main_window_on_person_role_changed, main_window); workspace_set_person_confidence_callback(main_window->workspace, main_window_on_person_confidence_changed, main_window); workspace_set_person_name_callback(main_window->workspace, 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); workspace_set_osint_action_callback( main_window->workspace, main_window_on_osint_action_requested, main_window ); workspace_set_edit_evidence_callback( main_window->workspace, main_window_on_edit_evidence_requested, main_window ); workspace_set_analyze_eml_callback(main_window->workspace, main_window_on_analyze_eml_requested, main_window); workspace_set_analyze_rib_callback(main_window->workspace, main_window_on_analyze_rib_requested, main_window); workspace_set_extract_metadata_callback(main_window->workspace, main_window_on_extract_metadata_requested, main_window); workspace_set_recover_pdf_password_callback(main_window->workspace, main_window_on_recover_pdf_password_requested, main_window); workspace_widget = workspace_get_widget( main_window->workspace ); if (workspace_widget == NULL) { main_window_free(main_window); return NULL; } main_window->task_panel = task_panel_new( task_manager ); if (main_window->task_panel == NULL) { main_window_free( main_window ); return NULL; } task_panel_widget = task_panel_get_widget( main_window->task_panel ); if (task_panel_widget == NULL) { main_window_free( main_window ); return NULL; } /* * Placement des deux composants dans GtkPaned. */ gtk_paned_set_start_child( GTK_PANED(main_window->main_paned), sidebar_widget ); gtk_paned_set_end_child( GTK_PANED(main_window->main_paned), workspace_widget ); /* * Position initiale de la poignée de séparation. */ gtk_paned_set_position( GTK_PANED(main_window->main_paned), MAIN_WINDOW_SIDEBAR_POSITION ); /* * La sidebar conserve sa largeur lorsque la fenêtre est agrandie. * La zone de travail récupère l'espace supplémentaire. */ gtk_paned_set_resize_start_child( GTK_PANED(main_window->main_paned), FALSE ); gtk_paned_set_resize_end_child( GTK_PANED(main_window->main_paned), TRUE ); /* * Les deux panneaux peuvent être réduits manuellement. */ gtk_paned_set_shrink_start_child( GTK_PANED(main_window->main_paned), TRUE ); gtk_paned_set_shrink_end_child( GTK_PANED(main_window->main_paned), TRUE ); main_window->content_paned = gtk_paned_new( GTK_ORIENTATION_VERTICAL ); gtk_widget_set_hexpand( main_window->content_paned, TRUE ); gtk_widget_set_vexpand( main_window->content_paned, TRUE ); gtk_paned_set_start_child( GTK_PANED(main_window->content_paned), main_window->main_paned ); gtk_paned_set_end_child( GTK_PANED(main_window->content_paned), task_panel_widget ); gtk_paned_set_position( GTK_PANED(main_window->content_paned), MAIN_WINDOW_TASK_PANEL_POSITION ); gtk_paned_set_resize_start_child( GTK_PANED(main_window->content_paned), TRUE ); gtk_paned_set_resize_end_child( GTK_PANED(main_window->content_paned), FALSE ); gtk_paned_set_shrink_start_child( GTK_PANED(main_window->content_paned), TRUE ); gtk_paned_set_shrink_end_child( GTK_PANED(main_window->content_paned), TRUE ); main_window->status_label = gtk_label_new( MAIN_WINDOW_NO_INVESTIGATION_STATUS ); gtk_widget_set_halign( main_window->status_label, GTK_ALIGN_START ); gtk_widget_set_margin_start( main_window->status_label, 8 ); gtk_widget_set_margin_end( main_window->status_label, 8 ); gtk_widget_set_margin_top( main_window->status_label, 6 ); gtk_widget_set_margin_bottom( main_window->status_label, 6 ); /* * Assemblage vertical : * * Barre d'actions * GtkPaned * Barre d'état */ gtk_box_append( GTK_BOX(main_window->main_box), main_window->action_bar ); gtk_box_append( GTK_BOX(main_window->main_box), main_window->content_paned ); gtk_box_append( GTK_BOX(main_window->main_box), main_window->status_label ); gtk_window_set_child( main_window->window, main_window->main_box ); /* * Ce volet vertical sépare la zone principale du panneau d'activité. */ return main_window; } void main_window_present(MainWindow *main_window) { if (main_window == NULL || main_window->window == NULL) { return; } gtk_window_present(main_window->window); } GtkWindow *main_window_get_window( const MainWindow *main_window ) { if (main_window == NULL) { return NULL; } return main_window->window; } void main_window_set_tree_model( MainWindow *main_window, const InvestigationTreeModel *tree_model ) { if (main_window == NULL) { return; } sidebar_set_tree_model( main_window->sidebar, tree_model ); } void main_window_set_evidence_model( MainWindow *main_window, EvidenceCategoryModel *evidence_category_model ) { if (main_window == NULL) { return; } sidebar_set_evidence_model( main_window->sidebar, evidence_category_model ); } void main_window_set_investigation( MainWindow *main_window, const char *investigation_name, const char *investigation_root_path ) { char *window_title = NULL; char *status_text = NULL; gboolean has_name = FALSE; gboolean has_root_path = FALSE; if (main_window == NULL) { return; } has_name = investigation_name != NULL && investigation_name[0] != '\0'; has_root_path = investigation_root_path != NULL && investigation_root_path[0] != '\0'; if (has_name) { window_title = g_strdup_printf( "%s — %s", MAIN_WINDOW_DEFAULT_TITLE, investigation_name ); } else { window_title = g_strdup( MAIN_WINDOW_DEFAULT_TITLE ); } if (has_name && has_root_path) { status_text = g_strdup_printf( "Enquête ouverte : %s — %s", investigation_name, investigation_root_path ); } else if (has_name) { status_text = g_strdup_printf( "Enquête ouverte : %s", investigation_name ); } else if (has_root_path) { status_text = g_strdup_printf( "Enquête ouverte : %s", investigation_root_path ); } else { status_text = g_strdup( MAIN_WINDOW_NO_INVESTIGATION_STATUS ); } if (main_window->window != NULL) { gtk_window_set_title( main_window->window, window_title ); } if (main_window->status_label != NULL) { gtk_label_set_text( GTK_LABEL(main_window->status_label), status_text ); } g_free(status_text); g_free(window_title); } void main_window_set_graph_loading( MainWindow *main_window ) { if (main_window == NULL) { return; } gtk_widget_set_sensitive( main_window->show_graph_button, FALSE ); sidebar_set_graph_model( main_window->sidebar, NULL ); workspace_set_graph_loading( main_window->workspace ); } void main_window_set_graph( MainWindow *main_window, const InvestigationGraphModel *graph_model, const InvestigationGraphLayout *graph_layout ) { if (main_window == NULL) { return; } workspace_set_graph( main_window->workspace, graph_model, graph_layout ); sidebar_set_graph_model( main_window->sidebar, graph_model ); gtk_widget_set_sensitive( main_window->show_graph_button, graph_model != NULL ); } gboolean main_window_get_graph_view_transform( MainWindow *main_window, double *zoom, double *offset_x, double *offset_y) { return main_window != NULL && workspace_get_graph_view_transform( main_window->workspace, zoom, offset_x, offset_y); } void main_window_set_graph_view_transform( MainWindow *main_window, double zoom, double offset_x, double offset_y) { if (main_window != NULL) workspace_set_graph_view_transform( main_window->workspace, zoom, offset_x, offset_y); } gboolean main_window_select_graph_relation(MainWindow *main_window, const char *relation_identifier) { if (main_window == NULL) return FALSE; return workspace_select_graph_relation(main_window->workspace, relation_identifier); } gboolean main_window_select_graph_entity(MainWindow *main_window, const char *entity_identifier) { if (main_window == NULL) return FALSE; return workspace_select_graph_entity(main_window->workspace, entity_identifier); } void main_window_set_graph_error( MainWindow *main_window, const char *message ) { if (main_window == NULL) { return; } gtk_widget_set_sensitive( main_window->show_graph_button, FALSE ); sidebar_set_graph_model( main_window->sidebar, NULL ); workspace_set_graph_error( main_window->workspace, message ); } void main_window_clear_graph( MainWindow *main_window ) { if (main_window == NULL) { return; } gtk_widget_set_sensitive( main_window->show_graph_button, FALSE ); sidebar_set_graph_model( main_window->sidebar, NULL ); workspace_clear_graph( main_window->workspace ); } void main_window_reset_graph_layout( MainWindow *main_window ) { if (main_window == NULL) { return; } workspace_reset_graph_layout( main_window->workspace ); } void main_window_set_status( MainWindow *main_window, const char *status_text ) { const char *safe_status_text = NULL; if (main_window == NULL || main_window->status_label == NULL) { return; } safe_status_text = status_text != NULL && status_text[0] != '\0' ? status_text : MAIN_WINDOW_NO_INVESTIGATION_STATUS; gtk_label_set_text( GTK_LABEL(main_window->status_label), safe_status_text ); } void main_window_set_osint_tool_state( MainWindow *main_window, const char *tool_identifier, OsintActionToolState state, const char *version ) { if (main_window == NULL) { return; } workspace_set_osint_tool_state( main_window->workspace, tool_identifier, state, version ); } void main_window_set_osint_action_callback( MainWindow *main_window, MainWindowOsintActionCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->osint_action_callback = callback; main_window->osint_action_user_data = user_data; } void main_window_set_edit_evidence_callback( MainWindow *main_window, MainWindowEditEvidenceCallback callback, gpointer user_data ) { if (main_window == NULL) return; main_window->edit_evidence_callback = callback; main_window->edit_evidence_user_data = user_data; } void main_window_set_analyze_eml_callback(MainWindow *main_window, MainWindowAnalyzeEmlCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->analyze_eml_callback = callback; main_window->analyze_eml_user_data = user_data; } void main_window_set_analyze_rib_callback(MainWindow *main_window, MainWindowAnalyzeRibCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->analyze_rib_callback = callback; main_window->analyze_rib_user_data = user_data; } void main_window_set_extract_metadata_callback(MainWindow *main_window, MainWindowExtractMetadataCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->extract_metadata_callback = callback; main_window->extract_metadata_user_data = user_data; } void main_window_set_recover_pdf_password_callback(MainWindow *main_window, MainWindowRecoverPdfPasswordCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->recover_pdf_password_callback = callback; main_window->recover_pdf_password_user_data = user_data; } void main_window_set_tree_selection_callback( MainWindow *main_window, InvestigationTreeViewSelectionCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } sidebar_set_selection_callback( main_window->sidebar, callback, user_data ); } void main_window_set_evidence_selection_callback( MainWindow *main_window, MainWindowEvidenceSelectionCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->evidence_selection_callback = callback; main_window->evidence_selection_user_data = user_data; sidebar_set_evidence_selection_callback( main_window->sidebar, callback, user_data ); } void main_window_set_new_investigation_callback( MainWindow *main_window, MainWindowNewInvestigationCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->new_investigation_callback = callback; main_window->new_investigation_user_data = user_data; } void main_window_set_open_investigation_callback( MainWindow *main_window, MainWindowOpenInvestigationCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->open_investigation_callback = callback; main_window->open_investigation_user_data = user_data; } void main_window_set_import_evidence_callback( MainWindow *main_window, MainWindowImportEvidenceCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->import_evidence_callback = callback; main_window->import_evidence_user_data = user_data; } void main_window_set_add_social_account_callback( MainWindow *main_window, MainWindowAddSocialAccountCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->add_social_account_callback = callback; main_window->add_social_account_user_data = user_data; } void main_window_set_add_person_callback(MainWindow *main_window, MainWindowAddPersonCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->add_person_callback = callback; main_window->add_person_user_data = user_data; } void main_window_set_show_graph_callback( MainWindow *main_window, MainWindowShowGraphCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->show_graph_callback = callback; main_window->show_graph_user_data = user_data; } void main_window_set_import_evidence_enabled( MainWindow *main_window, gboolean enabled ) { if (main_window == NULL || main_window->import_evidence_button == NULL) { return; } gtk_widget_set_sensitive( main_window->import_evidence_button, enabled ); } void main_window_set_add_social_account_enabled( MainWindow *main_window, gboolean enabled) { if (main_window == NULL || main_window->add_social_account_button == NULL) return; gtk_widget_set_sensitive(main_window->add_social_account_button, enabled); } void main_window_set_add_person_enabled(MainWindow *main_window, gboolean enabled) { if (main_window == NULL || main_window->add_person_button == NULL) return; gtk_widget_set_sensitive(main_window->add_person_button, enabled); } void main_window_set_verify_evidence_callback( MainWindow *main_window, MainWindowVerifyEvidenceCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->verify_evidence_callback = callback; main_window->verify_evidence_user_data = user_data; } void main_window_set_graph_node_moved_callback( MainWindow *main_window, MainWindowGraphNodeMovedCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->graph_node_moved_callback = callback; main_window->graph_node_moved_user_data = user_data; } void main_window_set_graph_transform_changed_callback( MainWindow *main_window, MainWindowGraphTransformChangedCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->graph_transform_changed_callback = callback; main_window->graph_transform_changed_user_data = user_data; } void main_window_set_extraction_drop_callback( MainWindow *main_window, MainWindowExtractionDropCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->extraction_drop_callback = callback; main_window->extraction_drop_user_data = user_data; } void main_window_set_reset_graph_layout_callback( MainWindow *main_window, MainWindowResetGraphLayoutCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->reset_graph_layout_callback = callback; main_window->reset_graph_layout_user_data = user_data; } void main_window_set_add_relation_callback( MainWindow *main_window, MainWindowAddRelationCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->add_relation_callback = callback; main_window->add_relation_user_data = user_data; } void main_window_set_edit_relation_callback(MainWindow *main_window, MainWindowEditRelationCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->edit_relation_callback = callback; main_window->edit_relation_user_data = user_data; } void main_window_set_delete_relation_callback(MainWindow *main_window, MainWindowDeleteRelationCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->delete_relation_callback = callback; main_window->delete_relation_user_data = user_data; } void main_window_set_relation_selected_callback(MainWindow *main_window, MainWindowRelationSelectedCallback callback, gpointer user_data) { if (main_window == NULL) return; workspace_set_relation_selected_callback(main_window->workspace, (WorkspaceRelationSelectedCallback) callback, user_data); } void main_window_set_relation_evidences(MainWindow *main_window, const GPtrArray *evidence_records) { if (main_window == NULL) return; workspace_set_relation_evidences(main_window->workspace, evidence_records); } void main_window_set_person_role_callback(MainWindow *main_window, MainWindowPersonRoleCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->person_role_callback = callback; main_window->person_role_user_data = user_data; } void main_window_set_person_confidence_callback(MainWindow *main_window, MainWindowPersonConfidenceCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->person_confidence_callback = callback; main_window->person_confidence_user_data = user_data; } void main_window_set_person_name_callback(MainWindow *main_window, MainWindowPersonNameCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->person_name_callback = callback; main_window->person_name_user_data = user_data; } void main_window_set_person_evidence_callback(MainWindow *main_window, MainWindowPersonEvidenceCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->person_evidence_callback = callback; main_window->person_evidence_user_data = user_data; } void main_window_set_entity_selected_callback(MainWindow *main_window, MainWindowEntitySelectedCallback callback, gpointer user_data) { if (main_window == NULL) return; main_window->entity_selected_callback = callback; main_window->entity_selected_user_data = user_data; } void main_window_set_person_evidences(MainWindow *main_window, const GPtrArray *records) { if (main_window == NULL) return; workspace_set_person_evidences(main_window->workspace, records); } void main_window_set_quit_callback( MainWindow *main_window, MainWindowQuitCallback callback, gpointer user_data ) { if (main_window == NULL) { return; } main_window->quit_callback = callback; main_window->quit_user_data = user_data; } void main_window_set_selected_node( MainWindow *main_window, const InvestigationNode *node ) { if (main_window == NULL) { return; } workspace_set_selected_node( main_window->workspace, node ); } void main_window_set_selected_evidence( MainWindow *main_window, const EvidenceRecord *evidence_record ) { if (main_window == NULL) { return; } workspace_set_selected_evidence( main_window->workspace, evidence_record ); } void main_window_set_evidence_observations(MainWindow *main_window, const GPtrArray *observations) { if (main_window != NULL) workspace_set_evidence_observations(main_window->workspace, observations); } void main_window_set_observation_remove_callback(MainWindow *main_window, void (*callback)(const char *, gpointer), gpointer user_data) { if (main_window != NULL) workspace_set_observation_remove_callback(main_window->workspace, callback, user_data); } void main_window_set_eml_analysis_available( MainWindow *main_window, gboolean available) { if (main_window != NULL) workspace_set_eml_analysis_available( main_window->workspace, available); } void main_window_set_evidence_preview(MainWindow *main_window, const char *file_path, const char *display_name) { if (main_window == NULL) return; workspace_set_evidence_preview(main_window->workspace, file_path, display_name); } void main_window_free( MainWindow *main_window ) { if (main_window == NULL) { return; } /* * TaskPanel possède un timer et un callback enregistré dans * TaskManager. Ils doivent être retirés avant la destruction * des widgets GTK. */ task_panel_free( main_window->task_panel ); main_window->task_panel = NULL; /* * Empêche la destruction du modèle de transmettre une dernière * sélection à Application. */ if (main_window->sidebar != NULL) { sidebar_set_selection_callback( main_window->sidebar, NULL, NULL ); /* * Le modèle est détaché pendant que le GtkListView existe * encore. */ sidebar_set_tree_model( main_window->sidebar, NULL ); sidebar_set_evidence_selection_callback( main_window->sidebar, NULL, NULL ); sidebar_set_evidence_model( main_window->sidebar, NULL ); sidebar_set_entity_selection_callback( main_window->sidebar, NULL, NULL ); sidebar_set_relation_selection_callback( main_window->sidebar, NULL, NULL ); sidebar_set_graph_model( main_window->sidebar, NULL ); } /* * Les structures qui manipulent encore leurs widgets doivent être * nettoyées avant gtk_window_destroy(). */ sidebar_free( main_window->sidebar ); if (main_window->workspace != NULL) { workspace_set_verify_evidence_callback( main_window->workspace, NULL, NULL ); workspace_set_graph_node_moved_callback( main_window->workspace, NULL, NULL ); workspace_set_graph_transform_changed_callback( main_window->workspace, NULL, NULL); workspace_set_reset_graph_layout_callback( main_window->workspace, NULL, NULL ); workspace_set_add_relation_callback( main_window->workspace, NULL, NULL ); workspace_set_edit_relation_callback(main_window->workspace, NULL, NULL); workspace_set_person_role_callback(main_window->workspace, NULL, NULL); main_window->graph_node_moved_callback = NULL; main_window->graph_node_moved_user_data = NULL; main_window->reset_graph_layout_callback = NULL; main_window->reset_graph_layout_user_data = NULL; main_window->add_relation_callback = NULL; main_window->add_relation_user_data = NULL; main_window->edit_relation_callback = NULL; main_window->edit_relation_user_data = NULL; main_window->person_role_callback = NULL; main_window->person_role_user_data = NULL; main_window->show_graph_callback = NULL; main_window->show_graph_user_data = NULL; main_window_clear_graph( main_window ); } workspace_free( main_window->workspace ); main_window->sidebar = NULL; main_window->workspace = NULL; /* * Les modules ne manipulent plus leurs widgets. * GTK peut maintenant détruire tout l'arbre sans callback vers * des structures déjà libérées. */ if (main_window->window != NULL) { gtk_window_destroy( main_window->window ); main_window->window = NULL; } g_free( main_window ); }