3402 lines
82 KiB
C
3402 lines
82 KiB
C
/******************************************************************************
|
||
* @file workspace.c
|
||
* @brief Implémentation de la zone principale de travail.
|
||
******************************************************************************/
|
||
|
||
#include "widgets/workspace.h"
|
||
|
||
#include "models/entity_record.h"
|
||
#include "models/investigation_graph_model.h"
|
||
#include "models/osint_selection_context.h"
|
||
#include "models/osint_action_catalog.h"
|
||
#include "models/relation_record.h"
|
||
#include "widgets/entity_details_panel.h"
|
||
#include "widgets/investigation_graph_view.h"
|
||
|
||
#include <glib.h>
|
||
|
||
#define WORKSPACE_PAGE_WELCOME "welcome"
|
||
#define WORKSPACE_PAGE_NODE_INFORMATION "node-information"
|
||
#define WORKSPACE_PAGE_EVIDENCE_INFORMATION \
|
||
"evidence-information"
|
||
#define WORKSPACE_PAGE_GRAPH_STATE \
|
||
"graph-state"
|
||
#define WORKSPACE_PAGE_GRAPH_VIEW \
|
||
"graph-view"
|
||
|
||
/**
|
||
* @brief État métier représenté par la page du graphe.
|
||
*/
|
||
typedef enum
|
||
{
|
||
WORKSPACE_GRAPH_STATE_EMPTY,
|
||
WORKSPACE_GRAPH_STATE_LOADING,
|
||
WORKSPACE_GRAPH_STATE_READY,
|
||
WORKSPACE_GRAPH_STATE_ERROR
|
||
} WorkspaceGraphState;
|
||
|
||
/**
|
||
* @struct Workspace
|
||
* @brief Représentation interne de la zone de travail.
|
||
*/
|
||
struct Workspace
|
||
{
|
||
GtkWidget *root_widget;
|
||
GtkWidget *stack;
|
||
|
||
GtkWidget *welcome_page;
|
||
|
||
GtkWidget *graph_state_page;
|
||
GtkWidget *graph_spinner;
|
||
GtkWidget *graph_title_label;
|
||
GtkWidget *graph_details_label;
|
||
|
||
GtkWidget *graph_view_page;
|
||
GtkWidget *graph_toolbar;
|
||
GtkWidget *reset_graph_layout_button;
|
||
GtkWidget *osint_tools_button;
|
||
GtkWidget *osint_tools_popover;
|
||
GtkWidget *osint_tools_context_label;
|
||
GtkWidget *osint_tools_status_label;
|
||
GtkWidget *osint_tools_actions_box;
|
||
GtkWidget *graph_help_button;
|
||
GtkWidget *graph_help_popover;
|
||
|
||
InvestigationGraphView *graph_view;
|
||
EntityDetailsPanel *entity_details_panel;
|
||
GtkWidget *relation_details_panel;
|
||
GtkWidget *relation_details_title_label;
|
||
GtkWidget *relation_details_summary_label;
|
||
GtkWidget *relation_evidences_label;
|
||
GtkWidget *edit_relation_button;
|
||
GtkWidget *close_relation_details_button;
|
||
char *selected_relation_identifier;
|
||
|
||
GtkWidget *node_page;
|
||
|
||
GtkWidget *evidence_page;
|
||
GtkWidget *evidence_name_label;
|
||
|
||
GtkWidget *evidence_type_label;
|
||
GtkWidget *evidence_integrity_label;
|
||
GtkWidget *evidence_size_label;
|
||
GtkWidget *evidence_imported_at_label;
|
||
GtkWidget *evidence_collected_at_label;
|
||
GtkWidget *evidence_source_label;
|
||
GtkWidget *evidence_description_label;
|
||
GtkWidget *evidence_relative_path_label;
|
||
GtkWidget *evidence_internal_name_label;
|
||
GtkWidget *evidence_identifier_label;
|
||
GtkWidget *evidence_sha256_label;
|
||
GtkWidget *verify_evidence_button;
|
||
GtkWidget *edit_evidence_button;
|
||
GtkWidget *analyze_eml_button;
|
||
GtkWidget *evidence_preview_stack;
|
||
GtkWidget *evidence_preview_status;
|
||
GtkWidget *evidence_preview_picture;
|
||
GtkWidget *evidence_preview_video;
|
||
GtkWidget *evidence_preview_expand_button;
|
||
char *evidence_preview_path;
|
||
gboolean evidence_preview_is_video;
|
||
|
||
char *selected_evidence_identifier;
|
||
|
||
WorkspaceVerifyEvidenceCallback
|
||
verify_evidence_callback;
|
||
|
||
gpointer
|
||
verify_evidence_user_data;
|
||
|
||
WorkspaceEditEvidenceCallback edit_evidence_callback;
|
||
gpointer edit_evidence_user_data;
|
||
WorkspaceAnalyzeEmlCallback analyze_eml_callback;
|
||
gpointer analyze_eml_user_data;
|
||
|
||
WorkspaceGraphNodeMovedCallback
|
||
graph_node_moved_callback;
|
||
|
||
gpointer
|
||
graph_node_moved_user_data;
|
||
|
||
WorkspaceResetGraphLayoutCallback
|
||
reset_graph_layout_callback;
|
||
|
||
gpointer
|
||
reset_graph_layout_user_data;
|
||
|
||
WorkspaceAddRelationCallback
|
||
add_relation_callback;
|
||
|
||
gpointer
|
||
add_relation_user_data;
|
||
|
||
WorkspaceEditRelationCallback edit_relation_callback;
|
||
WorkspaceRelationSelectedCallback relation_selected_callback;
|
||
gpointer relation_selected_user_data;
|
||
gpointer edit_relation_user_data;
|
||
WorkspacePersonRoleCallback person_role_callback;
|
||
gpointer person_role_user_data;
|
||
|
||
WorkspaceOsintActionCallback
|
||
osint_action_callback;
|
||
|
||
gpointer
|
||
osint_action_user_data;
|
||
|
||
GtkWidget *node_name_label;
|
||
GtkWidget *node_path_label;
|
||
GtkWidget *node_type_label;
|
||
GtkWidget *node_parent_label;
|
||
GtkWidget *node_children_label;
|
||
|
||
const InvestigationGraphModel *graph_model;
|
||
const InvestigationGraphLayout *graph_layout;
|
||
|
||
OsintSelectionContext *osint_selection_context;
|
||
OsintActionCatalog *osint_action_catalog;
|
||
|
||
WorkspaceGraphState graph_state;
|
||
};
|
||
|
||
/**
|
||
* @brief Traite localement l'aperçu ou relaie une action OSINT exécutable.
|
||
*/
|
||
static void workspace_on_osint_action_clicked(
|
||
GtkButton *button,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
Workspace *workspace = user_data;
|
||
const char *action_identifier = g_object_get_data(
|
||
G_OBJECT(button),
|
||
"osint-action-identifier"
|
||
);
|
||
const char *target_value = NULL;
|
||
const char *target_identifier = NULL;
|
||
|
||
if (workspace == NULL || workspace->osint_tools_status_label == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (g_strcmp0(action_identifier, "selection-preview") == 0)
|
||
{
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->osint_tools_status_label),
|
||
"Aperçu local : aucun outil externe exécuté."
|
||
);
|
||
return;
|
||
}
|
||
|
||
target_value = osint_selection_context_get_value(
|
||
workspace->osint_selection_context
|
||
);
|
||
target_identifier = osint_selection_context_get_identifier(
|
||
workspace->osint_selection_context
|
||
);
|
||
|
||
if (workspace->osint_action_callback == NULL ||
|
||
action_identifier == NULL || target_identifier == NULL ||
|
||
target_value == NULL)
|
||
{
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->osint_tools_status_label),
|
||
"Impossible de transmettre cette action OSINT."
|
||
);
|
||
return;
|
||
}
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->osint_tools_status_label),
|
||
g_str_has_prefix(action_identifier, "history-")
|
||
? "Ouverture de l'historique enregistré."
|
||
: "Exécution lancée ; suivez sa progression dans les tâches."
|
||
);
|
||
|
||
gtk_popover_popdown(
|
||
GTK_POPOVER(workspace->osint_tools_popover)
|
||
);
|
||
|
||
workspace->osint_action_callback(
|
||
action_identifier,
|
||
target_identifier,
|
||
target_value,
|
||
workspace->osint_action_user_data
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @brief Actualise le menu OSINT selon la sélection du graphe.
|
||
*
|
||
* Aucun outil n'est encore exposé par ce ticket. Le menu prépare le point
|
||
* d'entrée contextuel et explique explicitement cet état à l'utilisateur.
|
||
*/
|
||
static void workspace_update_osint_tools_menu(
|
||
Workspace *workspace,
|
||
const OsintSelectionContext *context
|
||
)
|
||
{
|
||
const char *selection_kind =
|
||
NULL;
|
||
|
||
const char *selection_identifier =
|
||
NULL;
|
||
|
||
char *context_text =
|
||
NULL;
|
||
|
||
GPtrArray *compatible_actions =
|
||
NULL;
|
||
|
||
GtkWidget *child =
|
||
NULL;
|
||
|
||
if (workspace == NULL ||
|
||
workspace->osint_tools_button == NULL ||
|
||
workspace->osint_tools_context_label == NULL ||
|
||
workspace->osint_tools_status_label == NULL ||
|
||
workspace->osint_tools_actions_box == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
while ((child = gtk_widget_get_first_child(
|
||
workspace->osint_tools_actions_box
|
||
)) != NULL)
|
||
{
|
||
gtk_box_remove(GTK_BOX(workspace->osint_tools_actions_box), child);
|
||
}
|
||
|
||
if (osint_selection_context_get_kind(context) ==
|
||
OSINT_SELECTION_CONTEXT_KIND_ENTITY)
|
||
{
|
||
selection_kind =
|
||
"Entité";
|
||
|
||
selection_identifier =
|
||
osint_selection_context_get_identifier(context);
|
||
}
|
||
else if (osint_selection_context_get_kind(context) ==
|
||
OSINT_SELECTION_CONTEXT_KIND_RELATION)
|
||
{
|
||
selection_kind =
|
||
"Relation";
|
||
|
||
selection_identifier =
|
||
osint_selection_context_get_identifier(context);
|
||
}
|
||
|
||
gtk_widget_set_sensitive(
|
||
workspace->osint_tools_button,
|
||
selection_identifier != NULL &&
|
||
selection_identifier[0] != '\0'
|
||
);
|
||
|
||
if (selection_identifier == NULL ||
|
||
selection_identifier[0] == '\0')
|
||
{
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->osint_tools_context_label
|
||
),
|
||
"Sélectionnez un nœud du graphe."
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->osint_tools_status_label
|
||
),
|
||
"Les outils compatibles apparaîtront ici."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
compatible_actions = osint_action_catalog_list_compatible(
|
||
workspace->osint_action_catalog,
|
||
context
|
||
);
|
||
|
||
{
|
||
GtkWidget *history_button = gtk_button_new_with_label(
|
||
"Historique OSINT"
|
||
);
|
||
const char *history_action =
|
||
osint_selection_context_get_kind(context) ==
|
||
OSINT_SELECTION_CONTEXT_KIND_RELATION
|
||
? "history-relation" : "history-entity";
|
||
gtk_widget_set_tooltip_text(
|
||
history_button,
|
||
"Consulter les exécutions OSINT enregistrées pour cette sélection"
|
||
);
|
||
g_object_set_data_full(
|
||
G_OBJECT(history_button), "osint-action-identifier",
|
||
g_strdup(history_action), g_free
|
||
);
|
||
g_signal_connect(
|
||
history_button, "clicked",
|
||
G_CALLBACK(workspace_on_osint_action_clicked), workspace
|
||
);
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->osint_tools_actions_box), history_button
|
||
);
|
||
}
|
||
|
||
for (guint action_index = 0;
|
||
compatible_actions != NULL &&
|
||
action_index < compatible_actions->len;
|
||
action_index++)
|
||
{
|
||
const OsintAction *action = g_ptr_array_index(
|
||
compatible_actions,
|
||
action_index
|
||
);
|
||
const char *tool_version = osint_action_get_tool_version(action);
|
||
char *button_label = tool_version != NULL && tool_version[0] != '\0'
|
||
? g_strdup_printf("%s — %s", osint_action_get_label(action), tool_version)
|
||
: g_strdup(osint_action_get_label(action));
|
||
GtkWidget *action_button = gtk_button_new_with_label(button_label);
|
||
|
||
g_free(button_label);
|
||
|
||
if (action_button == NULL)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
gtk_widget_set_sensitive(
|
||
action_button,
|
||
osint_action_is_available(action)
|
||
);
|
||
gtk_widget_set_tooltip_text(
|
||
action_button,
|
||
osint_action_is_available(action)
|
||
? osint_action_get_description(action)
|
||
: osint_action_get_unavailable_reason(action)
|
||
);
|
||
g_object_set_data_full(
|
||
G_OBJECT(action_button),
|
||
"osint-action-identifier",
|
||
g_strdup(osint_action_get_identifier(action)),
|
||
g_free
|
||
);
|
||
g_signal_connect(
|
||
action_button,
|
||
"clicked",
|
||
G_CALLBACK(workspace_on_osint_action_clicked),
|
||
workspace
|
||
);
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->osint_tools_actions_box),
|
||
action_button
|
||
);
|
||
}
|
||
|
||
context_text =
|
||
g_strdup_printf(
|
||
"%s sélectionnée\n%s",
|
||
selection_kind,
|
||
selection_identifier
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->osint_tools_context_label
|
||
),
|
||
context_text != NULL
|
||
? context_text
|
||
: selection_kind
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->osint_tools_status_label
|
||
),
|
||
compatible_actions != NULL && compatible_actions->len > 0U
|
||
? "Actions compatibles avec la sélection."
|
||
: "Aucune action OSINT compatible."
|
||
);
|
||
|
||
g_free(
|
||
context_text
|
||
);
|
||
|
||
g_clear_pointer(&compatible_actions, g_ptr_array_unref);
|
||
}
|
||
|
||
/**
|
||
* @brief Ajoute une ligne de métadonnée dans la grille.
|
||
*
|
||
* @return Label GTK destiné à recevoir la valeur.
|
||
*/
|
||
static GtkWidget *workspace_add_evidence_field(
|
||
GtkGrid *grid,
|
||
gint row,
|
||
const char *title
|
||
)
|
||
{
|
||
GtkWidget *title_label = NULL;
|
||
GtkWidget *value_label = NULL;
|
||
|
||
if (grid == NULL ||
|
||
title == NULL ||
|
||
title[0] == '\0')
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
title_label =
|
||
gtk_label_new(
|
||
title
|
||
);
|
||
|
||
value_label =
|
||
gtk_label_new(
|
||
NULL
|
||
);
|
||
|
||
if (title_label == NULL ||
|
||
value_label == NULL)
|
||
{
|
||
g_clear_object(
|
||
&value_label
|
||
);
|
||
|
||
g_clear_object(
|
||
&title_label
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(title_label),
|
||
0.0F
|
||
);
|
||
|
||
gtk_widget_set_valign(
|
||
title_label,
|
||
GTK_ALIGN_START
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
title_label,
|
||
"dim-label"
|
||
);
|
||
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(value_label),
|
||
0.0F
|
||
);
|
||
|
||
gtk_label_set_wrap(
|
||
GTK_LABEL(value_label),
|
||
TRUE
|
||
);
|
||
|
||
gtk_label_set_wrap_mode(
|
||
GTK_LABEL(value_label),
|
||
PANGO_WRAP_WORD_CHAR
|
||
);
|
||
|
||
gtk_label_set_selectable(
|
||
GTK_LABEL(value_label),
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_set_hexpand(
|
||
value_label,
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_set_halign(
|
||
value_label,
|
||
GTK_ALIGN_FILL
|
||
);
|
||
|
||
gtk_widget_set_valign(
|
||
value_label,
|
||
GTK_ALIGN_START
|
||
);
|
||
|
||
gtk_grid_attach(
|
||
grid,
|
||
title_label,
|
||
0,
|
||
row,
|
||
1,
|
||
1
|
||
);
|
||
|
||
gtk_grid_attach(
|
||
grid,
|
||
value_label,
|
||
1,
|
||
row,
|
||
1,
|
||
1
|
||
);
|
||
|
||
return value_label;
|
||
}
|
||
|
||
/**
|
||
* @brief Définit une valeur avec un texte de remplacement.
|
||
*/
|
||
static void workspace_set_field_text(
|
||
GtkWidget *label,
|
||
const char *value,
|
||
const char *fallback
|
||
)
|
||
{
|
||
if (label == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(label),
|
||
value != NULL && value[0] != '\0'
|
||
? value
|
||
: fallback
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @brief Convertit un statut d'intégrité en texte utilisateur.
|
||
*/
|
||
static const char *workspace_get_integrity_status_text(
|
||
EvidenceIntegrityStatus integrity_status
|
||
)
|
||
{
|
||
switch (integrity_status)
|
||
{
|
||
case EVIDENCE_INTEGRITY_STATUS_UNKNOWN:
|
||
return "Non vérifiée";
|
||
|
||
case EVIDENCE_INTEGRITY_STATUS_VALID:
|
||
return "Valide";
|
||
|
||
case EVIDENCE_INTEGRITY_STATUS_MISSING:
|
||
return "Fichier absent";
|
||
|
||
case EVIDENCE_INTEGRITY_STATUS_MODIFIED:
|
||
return "Fichier modifié";
|
||
|
||
case EVIDENCE_INTEGRITY_STATUS_ERROR:
|
||
return "Erreur de vérification";
|
||
|
||
default:
|
||
return "Statut inconnu";
|
||
}
|
||
}
|
||
|
||
/** @brief Affiche une erreur asynchrone produite par le moteur vidéo. */
|
||
static void workspace_on_video_error_changed(GObject *object,
|
||
GParamSpec *parameter, gpointer user_data)
|
||
{
|
||
Workspace *workspace = user_data;
|
||
const GError *error = NULL;
|
||
(void) parameter;
|
||
if (workspace == NULL || !GTK_IS_MEDIA_STREAM(object)) return;
|
||
error = gtk_media_stream_get_error(GTK_MEDIA_STREAM(object));
|
||
if (error == NULL) return;
|
||
gtk_label_set_text(GTK_LABEL(workspace->evidence_preview_status),
|
||
error->message != NULL ? error->message :
|
||
"Le moteur vidéo ne peut pas lire ce fichier.");
|
||
gtk_stack_set_visible_child_name(GTK_STACK(
|
||
workspace->evidence_preview_stack), "status");
|
||
gtk_widget_set_sensitive(workspace->evidence_preview_expand_button,
|
||
FALSE);
|
||
}
|
||
|
||
/** @brief Arrête et détache le média vidéo actuellement affiché. */
|
||
static void workspace_clear_evidence_preview(Workspace *workspace)
|
||
{
|
||
GtkMediaStream *stream = NULL;
|
||
if (workspace == NULL) return;
|
||
if (workspace->evidence_preview_video != NULL)
|
||
{
|
||
stream = gtk_video_get_media_stream(
|
||
GTK_VIDEO(workspace->evidence_preview_video));
|
||
if (stream != NULL)
|
||
{
|
||
g_signal_handlers_disconnect_by_data(stream, workspace);
|
||
gtk_media_stream_pause(stream);
|
||
}
|
||
gtk_video_set_media_stream(GTK_VIDEO(
|
||
workspace->evidence_preview_video), NULL);
|
||
}
|
||
if (workspace->evidence_preview_picture != NULL)
|
||
gtk_picture_set_paintable(GTK_PICTURE(
|
||
workspace->evidence_preview_picture), NULL);
|
||
g_clear_pointer(&workspace->evidence_preview_path, g_free);
|
||
workspace->evidence_preview_is_video = FALSE;
|
||
if (workspace->evidence_preview_expand_button != NULL)
|
||
gtk_widget_set_sensitive(workspace->evidence_preview_expand_button,
|
||
FALSE);
|
||
}
|
||
|
||
/** @brief Ouvre le média courant dans une fenêtre d'aperçu agrandie. */
|
||
static void workspace_on_expand_evidence_preview(GtkButton *button,
|
||
gpointer user_data)
|
||
{
|
||
Workspace *workspace = user_data;
|
||
GtkWindow *window = NULL;
|
||
GtkWidget *content = NULL;
|
||
(void) button;
|
||
if (workspace == NULL || workspace->evidence_preview_path == NULL) return;
|
||
window = GTK_WINDOW(gtk_window_new());
|
||
gtk_window_set_title(window, "Aperçu de la preuve");
|
||
gtk_window_set_default_size(window, 960, 720);
|
||
if (workspace->evidence_preview_is_video)
|
||
{
|
||
content = gtk_video_new_for_filename(workspace->evidence_preview_path);
|
||
gtk_video_set_autoplay(GTK_VIDEO(content), FALSE);
|
||
}
|
||
else
|
||
{
|
||
content = gtk_picture_new_for_filename(workspace->evidence_preview_path);
|
||
gtk_picture_set_can_shrink(GTK_PICTURE(content), TRUE);
|
||
gtk_picture_set_content_fit(GTK_PICTURE(content), GTK_CONTENT_FIT_CONTAIN);
|
||
}
|
||
gtk_window_set_child(window, content);
|
||
gtk_window_present(window);
|
||
}
|
||
|
||
/** @brief Convertit le statut d'une relation en texte utilisateur. */
|
||
static const char *workspace_get_relation_status_text(RelationStatus status)
|
||
{
|
||
switch (status)
|
||
{
|
||
case RELATION_STATUS_ACTIVE: return "Active";
|
||
case RELATION_STATUS_ARCHIVED: return "Archivée";
|
||
case RELATION_STATUS_DELETED: return "Supprimée";
|
||
case RELATION_STATUS_DISPUTED: return "Contestée";
|
||
case RELATION_STATUS_UNKNOWN:
|
||
default: return "Inconnu";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Transmet la sélection du graphe au volet de détails.
|
||
*/
|
||
static void workspace_on_graph_node_moved(
|
||
const char *entity_identifier,
|
||
double x,
|
||
double y,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
Workspace *workspace =
|
||
user_data;
|
||
|
||
if (workspace == NULL ||
|
||
workspace->graph_node_moved_callback == NULL ||
|
||
entity_identifier == NULL ||
|
||
entity_identifier[0] == '\0')
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->graph_node_moved_callback(
|
||
entity_identifier,
|
||
x,
|
||
y,
|
||
workspace->graph_node_moved_user_data
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @brief Transmet la sélection du graphe au volet de détails.
|
||
*/
|
||
static void workspace_on_graph_node_selected(
|
||
const EntityRecord *entity_record,
|
||
const RelationRecord *relation_record,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
Workspace *workspace =
|
||
user_data;
|
||
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
g_clear_pointer(
|
||
&workspace->osint_selection_context,
|
||
osint_selection_context_free
|
||
);
|
||
g_clear_pointer(&workspace->selected_relation_identifier, g_free);
|
||
|
||
if (entity_record != NULL)
|
||
{
|
||
workspace->osint_selection_context =
|
||
osint_selection_context_new_entity(entity_record, NULL);
|
||
}
|
||
|
||
if (workspace->entity_details_panel != NULL)
|
||
{
|
||
entity_details_panel_set_entity(
|
||
workspace->entity_details_panel,
|
||
entity_record
|
||
);
|
||
}
|
||
|
||
if (workspace->relation_details_panel != NULL)
|
||
{
|
||
gtk_widget_set_can_target(workspace->relation_details_panel,
|
||
relation_record != NULL);
|
||
gtk_widget_set_visible(
|
||
workspace->relation_details_panel,
|
||
relation_record != NULL
|
||
);
|
||
}
|
||
|
||
if (relation_record != NULL &&
|
||
workspace->relation_details_title_label != NULL &&
|
||
workspace->relation_details_summary_label != NULL)
|
||
{
|
||
workspace->selected_relation_identifier = g_strdup(
|
||
relation_record_get_identifier(relation_record));
|
||
const EntityRecord *source_entity =
|
||
investigation_graph_model_find_entity(
|
||
workspace->graph_model,
|
||
relation_record_get_source_entity_identifier(relation_record)
|
||
);
|
||
const EntityRecord *target_entity =
|
||
investigation_graph_model_find_entity(
|
||
workspace->graph_model,
|
||
relation_record_get_target_entity_identifier(relation_record)
|
||
);
|
||
|
||
workspace->osint_selection_context =
|
||
osint_selection_context_new_relation(
|
||
relation_record,
|
||
source_entity,
|
||
target_entity,
|
||
NULL
|
||
);
|
||
const char *label = relation_record_get_label(relation_record);
|
||
char *summary = g_strdup_printf(
|
||
"%s → %s\n\nType : %s\nConfiance : %d %%\nStatut : %s\n"
|
||
"Justification : %s\nCréée le : %s\nModifiée le : %s\nUUID : %s",
|
||
source_entity != NULL ? entity_record_get_value(source_entity) :
|
||
"Source inconnue",
|
||
target_entity != NULL ? entity_record_get_value(target_entity) :
|
||
"Cible inconnue",
|
||
relation_record_get_relation_type(relation_record),
|
||
relation_record_get_confidence(relation_record),
|
||
workspace_get_relation_status_text(
|
||
relation_record_get_status(relation_record)),
|
||
relation_record_get_justification(relation_record) != NULL
|
||
? relation_record_get_justification(relation_record)
|
||
: "Non renseignée",
|
||
relation_record_get_created_at(relation_record),
|
||
relation_record_get_updated_at(relation_record),
|
||
relation_record_get_identifier(relation_record)
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->relation_details_title_label),
|
||
label != NULL && label[0] != '\0' ? label : "Relation"
|
||
);
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->relation_details_summary_label),
|
||
summary != NULL ? summary : "Informations indisponibles"
|
||
);
|
||
g_free(summary);
|
||
|
||
if (workspace->relation_selected_callback != NULL)
|
||
workspace->relation_selected_callback(
|
||
workspace->selected_relation_identifier,
|
||
workspace->relation_selected_user_data);
|
||
}
|
||
|
||
workspace_update_osint_tools_menu(
|
||
workspace,
|
||
workspace->osint_selection_context
|
||
);
|
||
}
|
||
|
||
/** @brief Relaie la demande de modification de la relation affichée. */
|
||
static void workspace_on_edit_relation_clicked(GtkButton *button,
|
||
gpointer user_data)
|
||
{
|
||
Workspace *workspace = user_data;
|
||
(void) button;
|
||
if (workspace == NULL || workspace->edit_relation_callback == NULL ||
|
||
workspace->selected_relation_identifier == NULL)
|
||
{
|
||
return;
|
||
}
|
||
workspace->edit_relation_callback(workspace->selected_relation_identifier,
|
||
workspace->edit_relation_user_data);
|
||
}
|
||
|
||
/** @brief Ferme le volet de relation et désélectionne le graphe. */
|
||
static void workspace_on_close_relation_details_clicked(GtkButton *button,
|
||
gpointer user_data)
|
||
{
|
||
Workspace *workspace = user_data;
|
||
(void) button;
|
||
if (workspace != NULL)
|
||
investigation_graph_view_clear_selection(workspace->graph_view);
|
||
}
|
||
|
||
/**
|
||
* @brief Relaie la demande d'ajout d'une relation.
|
||
*/
|
||
static void workspace_on_add_relation_requested(
|
||
const char *source_entity_identifier,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
Workspace *workspace =
|
||
user_data;
|
||
|
||
if (workspace == NULL ||
|
||
workspace->add_relation_callback == NULL ||
|
||
source_entity_identifier == NULL ||
|
||
!g_uuid_string_is_valid(
|
||
source_entity_identifier
|
||
))
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->add_relation_callback(
|
||
source_entity_identifier,
|
||
workspace->add_relation_user_data
|
||
);
|
||
}
|
||
|
||
/** @brief Relaie le changement de catégorie d'une personne. */
|
||
static void workspace_on_person_role_changed(const char *entity_identifier,
|
||
PersonRole role, gpointer user_data)
|
||
{
|
||
Workspace *workspace = user_data;
|
||
if (workspace != NULL && workspace->person_role_callback != NULL)
|
||
workspace->person_role_callback(entity_identifier, role,
|
||
workspace->person_role_user_data);
|
||
}
|
||
|
||
/**
|
||
* @brief Désélectionne le nœud lorsque le volet est fermé manuellement.
|
||
*/
|
||
static void workspace_on_entity_details_closed(
|
||
gpointer user_data
|
||
)
|
||
{
|
||
Workspace *workspace =
|
||
user_data;
|
||
|
||
if (workspace == NULL ||
|
||
workspace->graph_view == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
investigation_graph_view_clear_selection(
|
||
workspace->graph_view
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @brief Affiche l'état principal courant du Workspace.
|
||
*
|
||
* Sans enquête, la page d'accueil est utilisée. Le chargement et les erreurs
|
||
* utilisent la page d'état. Un graphe prêt utilise la vue graphique.
|
||
*/
|
||
static void workspace_show_default(
|
||
Workspace *workspace
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
switch (workspace->graph_state)
|
||
{
|
||
case WORKSPACE_GRAPH_STATE_EMPTY:
|
||
gtk_stack_set_visible_child_name(
|
||
GTK_STACK(workspace->stack),
|
||
WORKSPACE_PAGE_WELCOME
|
||
);
|
||
|
||
return;
|
||
|
||
case WORKSPACE_GRAPH_STATE_READY:
|
||
gtk_stack_set_visible_child_name(
|
||
GTK_STACK(workspace->stack),
|
||
WORKSPACE_PAGE_GRAPH_VIEW
|
||
);
|
||
|
||
return;
|
||
|
||
case WORKSPACE_GRAPH_STATE_LOADING:
|
||
case WORKSPACE_GRAPH_STATE_ERROR:
|
||
default:
|
||
gtk_stack_set_visible_child_name(
|
||
GTK_STACK(workspace->stack),
|
||
WORKSPACE_PAGE_GRAPH_STATE
|
||
);
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Transmet la demande de vérification de la preuve affichée.
|
||
*/
|
||
static void workspace_on_reset_graph_layout_clicked(
|
||
GtkButton *button,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
Workspace *workspace =
|
||
user_data;
|
||
|
||
(void) button;
|
||
|
||
if (workspace == NULL ||
|
||
workspace->graph_state != WORKSPACE_GRAPH_STATE_READY ||
|
||
workspace->graph_model == NULL ||
|
||
workspace->reset_graph_layout_callback == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->reset_graph_layout_callback(
|
||
workspace->reset_graph_layout_user_data
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @brief Transmet la demande de vérification de la preuve affichée.
|
||
*/
|
||
static void workspace_on_verify_evidence_clicked(
|
||
GtkButton *button,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
Workspace *workspace =
|
||
user_data;
|
||
|
||
(void) button;
|
||
|
||
if (workspace == NULL ||
|
||
workspace->verify_evidence_callback == NULL ||
|
||
workspace->selected_evidence_identifier == NULL ||
|
||
workspace->selected_evidence_identifier[0] == '\0')
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->verify_evidence_callback(
|
||
workspace->selected_evidence_identifier,
|
||
workspace->verify_evidence_user_data
|
||
);
|
||
}
|
||
|
||
/** @brief Transmet la demande de modification de la preuve affichée. */
|
||
static void workspace_on_edit_evidence_clicked(
|
||
GtkButton *button, gpointer user_data
|
||
)
|
||
{
|
||
Workspace *workspace = user_data;
|
||
(void) button;
|
||
if (workspace == NULL || workspace->edit_evidence_callback == NULL ||
|
||
workspace->selected_evidence_identifier == NULL) return;
|
||
workspace->edit_evidence_callback(
|
||
workspace->selected_evidence_identifier,
|
||
workspace->edit_evidence_user_data);
|
||
}
|
||
/** @brief Transmet la demande d'analyse de la preuve EML affichée. */
|
||
static void workspace_on_analyze_eml_clicked(GtkButton *button, gpointer data)
|
||
{
|
||
Workspace *workspace = data; (void) button;
|
||
if (workspace != NULL && workspace->analyze_eml_callback != NULL &&
|
||
workspace->selected_evidence_identifier != NULL)
|
||
workspace->analyze_eml_callback(workspace->selected_evidence_identifier,
|
||
workspace->analyze_eml_user_data);
|
||
}
|
||
|
||
Workspace *workspace_new(void)
|
||
{
|
||
GtkWidget *evidence_content = NULL;
|
||
GtkWidget *evidence_separator = NULL;
|
||
GtkWidget *evidence_grid = NULL;
|
||
|
||
Workspace *workspace = NULL;
|
||
|
||
workspace = g_new0(Workspace, 1);
|
||
|
||
workspace->root_widget = gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
0
|
||
);
|
||
|
||
if (workspace->root_widget == NULL)
|
||
{
|
||
workspace_free(workspace);
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_hexpand(
|
||
workspace->root_widget,
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_set_vexpand(
|
||
workspace->root_widget,
|
||
TRUE
|
||
);
|
||
|
||
workspace->stack = gtk_stack_new();
|
||
|
||
if (workspace->stack == NULL)
|
||
{
|
||
workspace_free(workspace);
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_hexpand(
|
||
workspace->stack,
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_set_vexpand(
|
||
workspace->stack,
|
||
TRUE
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->root_widget),
|
||
workspace->stack
|
||
);
|
||
|
||
/*
|
||
* Page d'accueil.
|
||
*/
|
||
workspace->welcome_page = gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
12
|
||
);
|
||
|
||
if (workspace->welcome_page == NULL)
|
||
{
|
||
workspace_free(workspace);
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_halign(
|
||
workspace->welcome_page,
|
||
GTK_ALIGN_CENTER
|
||
);
|
||
|
||
gtk_widget_set_valign(
|
||
workspace->welcome_page,
|
||
GTK_ALIGN_CENTER
|
||
);
|
||
|
||
gtk_stack_add_named(
|
||
GTK_STACK(workspace->stack),
|
||
workspace->welcome_page,
|
||
WORKSPACE_PAGE_WELCOME
|
||
);
|
||
|
||
/*
|
||
* Page d'informations sur le nœud.
|
||
*/
|
||
workspace->node_page = gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
12
|
||
);
|
||
|
||
if (workspace->node_page == NULL)
|
||
{
|
||
workspace_free(workspace);
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_halign(
|
||
workspace->node_page,
|
||
GTK_ALIGN_CENTER
|
||
);
|
||
|
||
gtk_widget_set_valign(
|
||
workspace->node_page,
|
||
GTK_ALIGN_CENTER
|
||
);
|
||
|
||
workspace->node_name_label = gtk_label_new(NULL);
|
||
workspace->node_path_label = gtk_label_new(NULL);
|
||
workspace->node_type_label = gtk_label_new(NULL);
|
||
workspace->node_parent_label = gtk_label_new(NULL);
|
||
workspace->node_children_label = gtk_label_new(NULL);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->node_page),
|
||
workspace->node_name_label
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->node_page),
|
||
workspace->node_path_label
|
||
);
|
||
|
||
gtk_label_set_wrap(
|
||
GTK_LABEL(workspace->node_path_label),
|
||
TRUE
|
||
);
|
||
|
||
gtk_label_set_selectable(
|
||
GTK_LABEL(workspace->node_path_label),
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_set_halign(
|
||
workspace->node_path_label,
|
||
GTK_ALIGN_CENTER
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->node_page),
|
||
workspace->node_type_label
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->node_page),
|
||
workspace->node_parent_label
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->node_page),
|
||
workspace->node_children_label
|
||
);
|
||
|
||
gtk_stack_add_named(
|
||
GTK_STACK(workspace->stack),
|
||
workspace->node_page,
|
||
WORKSPACE_PAGE_NODE_INFORMATION
|
||
);
|
||
|
||
/*
|
||
* Page détaillée d'une preuve.
|
||
*/
|
||
workspace->evidence_page =
|
||
gtk_scrolled_window_new();
|
||
|
||
if (workspace->evidence_page == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_hexpand(
|
||
workspace->evidence_page,
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_set_vexpand(
|
||
workspace->evidence_page,
|
||
TRUE
|
||
);
|
||
|
||
gtk_scrolled_window_set_policy(
|
||
GTK_SCROLLED_WINDOW(
|
||
workspace->evidence_page
|
||
),
|
||
GTK_POLICY_AUTOMATIC,
|
||
GTK_POLICY_AUTOMATIC
|
||
);
|
||
|
||
evidence_content =
|
||
gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
16
|
||
);
|
||
|
||
if (evidence_content == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_margin_start(
|
||
evidence_content,
|
||
24
|
||
);
|
||
|
||
gtk_widget_set_margin_end(
|
||
evidence_content,
|
||
24
|
||
);
|
||
|
||
gtk_widget_set_margin_top(
|
||
evidence_content,
|
||
24
|
||
);
|
||
|
||
gtk_widget_set_margin_bottom(
|
||
evidence_content,
|
||
24
|
||
);
|
||
|
||
workspace->evidence_name_label =
|
||
gtk_label_new(
|
||
NULL
|
||
);
|
||
|
||
if (workspace->evidence_name_label == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(
|
||
workspace->evidence_name_label
|
||
),
|
||
0.0F
|
||
);
|
||
|
||
gtk_label_set_wrap(
|
||
GTK_LABEL(
|
||
workspace->evidence_name_label
|
||
),
|
||
TRUE
|
||
);
|
||
|
||
gtk_label_set_selectable(
|
||
GTK_LABEL(
|
||
workspace->evidence_name_label
|
||
),
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
workspace->evidence_name_label,
|
||
"title-2"
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(evidence_content),
|
||
workspace->evidence_name_label
|
||
);
|
||
|
||
workspace->evidence_preview_stack = gtk_stack_new();
|
||
workspace->evidence_preview_status = gtk_label_new(
|
||
"Aucun aperçu disponible pour cette preuve.");
|
||
workspace->evidence_preview_picture = gtk_picture_new();
|
||
workspace->evidence_preview_video = gtk_video_new();
|
||
workspace->evidence_preview_expand_button =
|
||
gtk_button_new_with_label("Agrandir l’aperçu");
|
||
gtk_widget_set_size_request(workspace->evidence_preview_stack, -1, 360);
|
||
gtk_widget_set_hexpand(workspace->evidence_preview_stack, TRUE);
|
||
gtk_picture_set_can_shrink(GTK_PICTURE(
|
||
workspace->evidence_preview_picture), TRUE);
|
||
gtk_picture_set_content_fit(GTK_PICTURE(
|
||
workspace->evidence_preview_picture), GTK_CONTENT_FIT_CONTAIN);
|
||
gtk_video_set_autoplay(GTK_VIDEO(workspace->evidence_preview_video), FALSE);
|
||
gtk_stack_add_named(GTK_STACK(workspace->evidence_preview_stack),
|
||
workspace->evidence_preview_status, "status");
|
||
gtk_stack_add_named(GTK_STACK(workspace->evidence_preview_stack),
|
||
workspace->evidence_preview_picture, "image");
|
||
gtk_stack_add_named(GTK_STACK(workspace->evidence_preview_stack),
|
||
workspace->evidence_preview_video, "video");
|
||
gtk_stack_set_visible_child_name(GTK_STACK(
|
||
workspace->evidence_preview_stack), "status");
|
||
gtk_widget_set_halign(workspace->evidence_preview_expand_button,
|
||
GTK_ALIGN_START);
|
||
gtk_widget_set_sensitive(workspace->evidence_preview_expand_button, FALSE);
|
||
g_signal_connect(workspace->evidence_preview_expand_button, "clicked",
|
||
G_CALLBACK(workspace_on_expand_evidence_preview), workspace);
|
||
gtk_box_append(GTK_BOX(evidence_content),
|
||
workspace->evidence_preview_stack);
|
||
gtk_box_append(GTK_BOX(evidence_content),
|
||
workspace->evidence_preview_expand_button);
|
||
|
||
workspace->verify_evidence_button =
|
||
gtk_button_new_with_label(
|
||
"Vérifier l'intégrité"
|
||
);
|
||
|
||
if (workspace->verify_evidence_button == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_halign(
|
||
workspace->verify_evidence_button,
|
||
GTK_ALIGN_START
|
||
);
|
||
|
||
gtk_widget_set_tooltip_text(
|
||
workspace->verify_evidence_button,
|
||
"Recalculer le SHA-256 et le comparer à l'empreinte enregistrée"
|
||
);
|
||
|
||
/*
|
||
* Aucun bouton actif tant qu'aucune preuve n'est affichée.
|
||
*/
|
||
gtk_widget_set_sensitive(
|
||
workspace->verify_evidence_button,
|
||
FALSE
|
||
);
|
||
|
||
g_signal_connect(
|
||
workspace->verify_evidence_button,
|
||
"clicked",
|
||
G_CALLBACK(
|
||
workspace_on_verify_evidence_clicked
|
||
),
|
||
workspace
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(evidence_content),
|
||
workspace->verify_evidence_button
|
||
);
|
||
|
||
workspace->edit_evidence_button = gtk_button_new_with_label(
|
||
"Modifier les métadonnées");
|
||
gtk_widget_set_halign(workspace->edit_evidence_button, GTK_ALIGN_START);
|
||
gtk_widget_set_sensitive(workspace->edit_evidence_button, FALSE);
|
||
gtk_widget_set_tooltip_text(workspace->edit_evidence_button,
|
||
"Corriger le classement sans modifier le fichier original");
|
||
g_signal_connect(workspace->edit_evidence_button, "clicked",
|
||
G_CALLBACK(workspace_on_edit_evidence_clicked), workspace);
|
||
gtk_box_append(GTK_BOX(evidence_content), workspace->edit_evidence_button);
|
||
workspace->analyze_eml_button = gtk_button_new_with_label(
|
||
"Analyser les en-têtes EML");
|
||
gtk_widget_set_halign(workspace->analyze_eml_button, GTK_ALIGN_START);
|
||
gtk_widget_set_sensitive(workspace->analyze_eml_button, FALSE);
|
||
gtk_widget_set_tooltip_text(workspace->analyze_eml_button,
|
||
"Créer une copie vérifiée puis analyser localement ses en-têtes");
|
||
g_signal_connect(workspace->analyze_eml_button, "clicked",
|
||
G_CALLBACK(workspace_on_analyze_eml_clicked), workspace);
|
||
gtk_box_append(GTK_BOX(evidence_content), workspace->analyze_eml_button);
|
||
|
||
evidence_separator =
|
||
gtk_separator_new(
|
||
GTK_ORIENTATION_HORIZONTAL
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(evidence_content),
|
||
evidence_separator
|
||
);
|
||
|
||
evidence_grid =
|
||
gtk_grid_new();
|
||
|
||
if (evidence_grid == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_grid_set_column_spacing(
|
||
GTK_GRID(evidence_grid),
|
||
24
|
||
);
|
||
|
||
gtk_grid_set_row_spacing(
|
||
GTK_GRID(evidence_grid),
|
||
12
|
||
);
|
||
|
||
gtk_widget_set_hexpand(
|
||
evidence_grid,
|
||
TRUE
|
||
);
|
||
|
||
workspace->evidence_type_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
0,
|
||
"Type"
|
||
);
|
||
|
||
workspace->evidence_integrity_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
1,
|
||
"Intégrité"
|
||
);
|
||
|
||
workspace->evidence_size_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
2,
|
||
"Taille"
|
||
);
|
||
|
||
workspace->evidence_imported_at_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
3,
|
||
"Importée le"
|
||
);
|
||
|
||
workspace->evidence_collected_at_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
4,
|
||
"Collectée le"
|
||
);
|
||
|
||
workspace->evidence_source_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
5,
|
||
"Source"
|
||
);
|
||
|
||
workspace->evidence_description_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
6,
|
||
"Description"
|
||
);
|
||
|
||
workspace->evidence_relative_path_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
7,
|
||
"Chemin relatif"
|
||
);
|
||
|
||
workspace->evidence_internal_name_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
8,
|
||
"Nom interne"
|
||
);
|
||
|
||
workspace->evidence_identifier_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
9,
|
||
"Identifiant"
|
||
);
|
||
|
||
workspace->evidence_sha256_label =
|
||
workspace_add_evidence_field(
|
||
GTK_GRID(evidence_grid),
|
||
10,
|
||
"SHA-256"
|
||
);
|
||
|
||
if (workspace->evidence_type_label == NULL ||
|
||
workspace->evidence_integrity_label == NULL ||
|
||
workspace->evidence_size_label == NULL ||
|
||
workspace->evidence_imported_at_label == NULL ||
|
||
workspace->evidence_collected_at_label == NULL ||
|
||
workspace->evidence_source_label == NULL ||
|
||
workspace->evidence_description_label == NULL ||
|
||
workspace->evidence_relative_path_label == NULL ||
|
||
workspace->evidence_internal_name_label == NULL ||
|
||
workspace->evidence_identifier_label == NULL ||
|
||
workspace->evidence_sha256_label == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(evidence_content),
|
||
evidence_grid
|
||
);
|
||
|
||
gtk_scrolled_window_set_child(
|
||
GTK_SCROLLED_WINDOW(
|
||
workspace->evidence_page
|
||
),
|
||
evidence_content
|
||
);
|
||
|
||
gtk_stack_add_named(
|
||
GTK_STACK(workspace->stack),
|
||
workspace->evidence_page,
|
||
WORKSPACE_PAGE_EVIDENCE_INFORMATION
|
||
);
|
||
|
||
/*
|
||
* Page d'état utilisée pendant le chargement ou en cas d'erreur.
|
||
*/
|
||
workspace->graph_state_page =
|
||
gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
12
|
||
);
|
||
|
||
if (workspace->graph_state_page == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_halign(
|
||
workspace->graph_state_page,
|
||
GTK_ALIGN_CENTER
|
||
);
|
||
|
||
gtk_widget_set_valign(
|
||
workspace->graph_state_page,
|
||
GTK_ALIGN_CENTER
|
||
);
|
||
|
||
workspace->graph_spinner =
|
||
gtk_spinner_new();
|
||
|
||
workspace->graph_title_label =
|
||
gtk_label_new(
|
||
NULL
|
||
);
|
||
|
||
workspace->graph_details_label =
|
||
gtk_label_new(
|
||
NULL
|
||
);
|
||
|
||
if (workspace->graph_spinner == NULL ||
|
||
workspace->graph_title_label == NULL ||
|
||
workspace->graph_details_label == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_add_css_class(
|
||
workspace->graph_title_label,
|
||
"title-2"
|
||
);
|
||
|
||
gtk_label_set_wrap(
|
||
GTK_LABEL(
|
||
workspace->graph_details_label
|
||
),
|
||
TRUE
|
||
);
|
||
|
||
gtk_label_set_justify(
|
||
GTK_LABEL(
|
||
workspace->graph_details_label
|
||
),
|
||
GTK_JUSTIFY_CENTER
|
||
);
|
||
|
||
gtk_widget_set_visible(
|
||
workspace->graph_spinner,
|
||
FALSE
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
workspace->graph_state_page
|
||
),
|
||
workspace->graph_spinner
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
workspace->graph_state_page
|
||
),
|
||
workspace->graph_title_label
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
workspace->graph_state_page
|
||
),
|
||
workspace->graph_details_label
|
||
);
|
||
|
||
gtk_stack_add_named(
|
||
GTK_STACK(workspace->stack),
|
||
workspace->graph_state_page,
|
||
WORKSPACE_PAGE_GRAPH_STATE
|
||
);
|
||
|
||
/*
|
||
* Page graphique : canvas principal et volet de détails superposé.
|
||
*/
|
||
workspace->graph_view_page =
|
||
gtk_overlay_new();
|
||
|
||
if (workspace->graph_view_page == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_hexpand(
|
||
workspace->graph_view_page,
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_set_vexpand(
|
||
workspace->graph_view_page,
|
||
TRUE
|
||
);
|
||
|
||
workspace->graph_view =
|
||
investigation_graph_view_new();
|
||
|
||
workspace->entity_details_panel =
|
||
entity_details_panel_new();
|
||
|
||
workspace->relation_details_panel = gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
12
|
||
);
|
||
workspace->relation_details_title_label = gtk_label_new(NULL);
|
||
workspace->relation_details_summary_label = gtk_label_new(NULL);
|
||
workspace->relation_evidences_label = gtk_label_new(
|
||
"Pièces jointes : chargement…");
|
||
workspace->edit_relation_button = gtk_button_new_with_label("Modifier");
|
||
workspace->close_relation_details_button =
|
||
gtk_button_new_from_icon_name("window-close-symbolic");
|
||
|
||
if (workspace->graph_view == NULL ||
|
||
workspace->entity_details_panel == NULL ||
|
||
workspace->relation_details_panel == NULL ||
|
||
workspace->relation_details_title_label == NULL ||
|
||
workspace->relation_details_summary_label == NULL ||
|
||
workspace->relation_evidences_label == NULL ||
|
||
workspace->edit_relation_button == NULL ||
|
||
workspace->close_relation_details_button == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_size_request(workspace->relation_details_panel, 300, -1);
|
||
gtk_widget_set_halign(workspace->relation_details_panel, GTK_ALIGN_END);
|
||
gtk_widget_set_valign(workspace->relation_details_panel, GTK_ALIGN_START);
|
||
gtk_widget_set_margin_end(workspace->relation_details_panel, 12);
|
||
gtk_widget_set_margin_top(workspace->relation_details_panel, 56);
|
||
gtk_widget_set_margin_start(workspace->relation_details_panel, 12);
|
||
gtk_widget_set_margin_bottom(workspace->relation_details_panel, 12);
|
||
/* `view` fournit le fond opaque du thème, comme le volet d'entité. */
|
||
gtk_widget_add_css_class(workspace->relation_details_panel, "view");
|
||
gtk_widget_add_css_class(workspace->relation_details_panel, "card");
|
||
gtk_widget_set_margin_start(workspace->relation_details_title_label, 16);
|
||
gtk_widget_set_margin_end(workspace->relation_details_title_label, 16);
|
||
gtk_widget_set_margin_top(workspace->relation_details_title_label, 16);
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(workspace->relation_details_title_label),
|
||
0.0F
|
||
);
|
||
gtk_widget_add_css_class(
|
||
workspace->relation_details_title_label,
|
||
"title-3"
|
||
);
|
||
gtk_widget_set_margin_start(workspace->relation_details_summary_label, 16);
|
||
gtk_widget_set_margin_end(workspace->relation_details_summary_label, 16);
|
||
gtk_widget_set_margin_bottom(workspace->relation_details_summary_label, 16);
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(workspace->relation_details_summary_label),
|
||
0.0F
|
||
);
|
||
gtk_label_set_wrap(
|
||
GTK_LABEL(workspace->relation_details_summary_label),
|
||
TRUE
|
||
);
|
||
gtk_label_set_selectable(
|
||
GTK_LABEL(workspace->relation_details_summary_label),
|
||
TRUE
|
||
);
|
||
gtk_widget_set_margin_start(workspace->relation_evidences_label, 16);
|
||
gtk_widget_set_margin_end(workspace->relation_evidences_label, 16);
|
||
gtk_widget_set_margin_bottom(workspace->relation_evidences_label, 12);
|
||
gtk_label_set_xalign(GTK_LABEL(workspace->relation_evidences_label), 0.0F);
|
||
gtk_label_set_wrap(GTK_LABEL(workspace->relation_evidences_label), TRUE);
|
||
gtk_label_set_selectable(GTK_LABEL(workspace->relation_evidences_label),
|
||
TRUE);
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->relation_details_panel),
|
||
workspace->relation_details_title_label
|
||
);
|
||
gtk_widget_set_tooltip_text(workspace->close_relation_details_button,
|
||
"Fermer le volet");
|
||
gtk_widget_add_css_class(workspace->close_relation_details_button, "flat");
|
||
gtk_box_append(GTK_BOX(workspace->relation_details_panel),
|
||
workspace->close_relation_details_button);
|
||
gtk_box_append(
|
||
GTK_BOX(workspace->relation_details_panel),
|
||
workspace->relation_details_summary_label
|
||
);
|
||
gtk_box_append(GTK_BOX(workspace->relation_details_panel),
|
||
workspace->relation_evidences_label);
|
||
gtk_box_append(GTK_BOX(workspace->relation_details_panel),
|
||
workspace->edit_relation_button);
|
||
g_signal_connect(workspace->edit_relation_button, "clicked",
|
||
G_CALLBACK(workspace_on_edit_relation_clicked), workspace);
|
||
g_signal_connect(workspace->close_relation_details_button, "clicked",
|
||
G_CALLBACK(workspace_on_close_relation_details_clicked), workspace);
|
||
gtk_widget_set_visible(workspace->relation_details_panel, FALSE);
|
||
gtk_widget_set_can_target(workspace->relation_details_panel, FALSE);
|
||
|
||
investigation_graph_view_set_selection_callback(
|
||
workspace->graph_view,
|
||
workspace_on_graph_node_selected,
|
||
workspace
|
||
);
|
||
|
||
investigation_graph_view_set_node_moved_callback(
|
||
workspace->graph_view,
|
||
workspace_on_graph_node_moved,
|
||
workspace
|
||
);
|
||
|
||
entity_details_panel_set_close_callback(
|
||
workspace->entity_details_panel,
|
||
workspace_on_entity_details_closed,
|
||
workspace
|
||
);
|
||
|
||
entity_details_panel_set_add_relation_callback(
|
||
workspace->entity_details_panel,
|
||
workspace_on_add_relation_requested,
|
||
workspace
|
||
);
|
||
|
||
entity_details_panel_set_person_role_callback(
|
||
workspace->entity_details_panel, workspace_on_person_role_changed,
|
||
workspace);
|
||
|
||
gtk_overlay_set_child(
|
||
GTK_OVERLAY(
|
||
workspace->graph_view_page
|
||
),
|
||
investigation_graph_view_get_widget(
|
||
workspace->graph_view
|
||
)
|
||
);
|
||
|
||
workspace->graph_toolbar =
|
||
gtk_box_new(
|
||
GTK_ORIENTATION_HORIZONTAL,
|
||
4
|
||
);
|
||
|
||
workspace->reset_graph_layout_button =
|
||
gtk_button_new_from_icon_name(
|
||
"view-refresh-symbolic"
|
||
);
|
||
|
||
workspace->osint_tools_button =
|
||
gtk_menu_button_new();
|
||
|
||
workspace->osint_tools_popover =
|
||
gtk_popover_new();
|
||
|
||
GtkWidget *osint_tools_content =
|
||
gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
8
|
||
);
|
||
|
||
GtkWidget *osint_tools_title =
|
||
gtk_label_new(
|
||
"Outils OSINT"
|
||
);
|
||
|
||
workspace->osint_tools_context_label =
|
||
gtk_label_new(
|
||
"Sélectionnez un nœud du graphe."
|
||
);
|
||
|
||
workspace->osint_tools_status_label =
|
||
gtk_label_new(
|
||
"Les outils compatibles apparaîtront ici."
|
||
);
|
||
|
||
workspace->osint_tools_actions_box = gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
6
|
||
);
|
||
|
||
workspace->osint_action_catalog =
|
||
osint_action_catalog_new_defaults();
|
||
|
||
if (workspace->graph_toolbar == NULL ||
|
||
workspace->reset_graph_layout_button == NULL ||
|
||
workspace->osint_tools_button == NULL ||
|
||
workspace->osint_tools_popover == NULL ||
|
||
osint_tools_content == NULL ||
|
||
osint_tools_title == NULL ||
|
||
workspace->osint_tools_context_label == NULL ||
|
||
workspace->osint_tools_status_label == NULL ||
|
||
workspace->osint_tools_actions_box == NULL ||
|
||
workspace->osint_action_catalog == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_widget_set_halign(
|
||
workspace->graph_toolbar,
|
||
GTK_ALIGN_START
|
||
);
|
||
|
||
gtk_widget_set_valign(
|
||
workspace->graph_toolbar,
|
||
GTK_ALIGN_START
|
||
);
|
||
|
||
gtk_widget_set_margin_start(
|
||
workspace->graph_toolbar,
|
||
12
|
||
);
|
||
|
||
gtk_widget_set_margin_top(
|
||
workspace->graph_toolbar,
|
||
12
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
workspace->graph_toolbar,
|
||
"toolbar"
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
workspace->reset_graph_layout_button,
|
||
"flat"
|
||
);
|
||
|
||
gtk_widget_set_tooltip_text(
|
||
workspace->reset_graph_layout_button,
|
||
"Réinitialiser la disposition du graphe"
|
||
);
|
||
|
||
gtk_widget_set_sensitive(
|
||
workspace->reset_graph_layout_button,
|
||
FALSE
|
||
);
|
||
|
||
gtk_menu_button_set_label(
|
||
GTK_MENU_BUTTON(
|
||
workspace->osint_tools_button
|
||
),
|
||
"Outils OSINT"
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
workspace->osint_tools_button,
|
||
"flat"
|
||
);
|
||
|
||
gtk_widget_set_tooltip_text(
|
||
workspace->osint_tools_button,
|
||
"Afficher les outils compatibles avec la sélection"
|
||
);
|
||
|
||
gtk_widget_set_sensitive(
|
||
workspace->osint_tools_button,
|
||
FALSE
|
||
);
|
||
|
||
gtk_widget_set_margin_start(
|
||
osint_tools_content,
|
||
16
|
||
);
|
||
|
||
gtk_widget_set_margin_end(
|
||
osint_tools_content,
|
||
16
|
||
);
|
||
|
||
gtk_widget_set_margin_top(
|
||
osint_tools_content,
|
||
14
|
||
);
|
||
|
||
gtk_widget_set_margin_bottom(
|
||
osint_tools_content,
|
||
14
|
||
);
|
||
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(
|
||
osint_tools_title
|
||
),
|
||
0.0F
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
osint_tools_title,
|
||
"heading"
|
||
);
|
||
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(
|
||
workspace->osint_tools_context_label
|
||
),
|
||
0.0F
|
||
);
|
||
|
||
gtk_label_set_selectable(
|
||
GTK_LABEL(
|
||
workspace->osint_tools_context_label
|
||
),
|
||
TRUE
|
||
);
|
||
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(
|
||
workspace->osint_tools_status_label
|
||
),
|
||
0.0F
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
workspace->osint_tools_status_label,
|
||
"dim-label"
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
osint_tools_content
|
||
),
|
||
osint_tools_title
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
osint_tools_content
|
||
),
|
||
workspace->osint_tools_context_label
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(osint_tools_content),
|
||
workspace->osint_tools_actions_box
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
osint_tools_content
|
||
),
|
||
workspace->osint_tools_status_label
|
||
);
|
||
|
||
gtk_popover_set_child(
|
||
GTK_POPOVER(
|
||
workspace->osint_tools_popover
|
||
),
|
||
osint_tools_content
|
||
);
|
||
|
||
gtk_menu_button_set_popover(
|
||
GTK_MENU_BUTTON(
|
||
workspace->osint_tools_button
|
||
),
|
||
workspace->osint_tools_popover
|
||
);
|
||
|
||
g_signal_connect(
|
||
workspace->reset_graph_layout_button,
|
||
"clicked",
|
||
G_CALLBACK(
|
||
workspace_on_reset_graph_layout_clicked
|
||
),
|
||
workspace
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
workspace->graph_toolbar
|
||
),
|
||
workspace->reset_graph_layout_button
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
workspace->graph_toolbar
|
||
),
|
||
workspace->osint_tools_button
|
||
);
|
||
|
||
gtk_overlay_add_overlay(
|
||
GTK_OVERLAY(
|
||
workspace->graph_view_page
|
||
),
|
||
workspace->graph_toolbar
|
||
);
|
||
|
||
gtk_overlay_set_clip_overlay(
|
||
GTK_OVERLAY(
|
||
workspace->graph_view_page
|
||
),
|
||
workspace->graph_toolbar,
|
||
TRUE
|
||
);
|
||
|
||
workspace->graph_help_button =
|
||
gtk_menu_button_new();
|
||
|
||
workspace->graph_help_popover =
|
||
gtk_popover_new();
|
||
|
||
GtkWidget *graph_help_content =
|
||
gtk_box_new(
|
||
GTK_ORIENTATION_VERTICAL,
|
||
8
|
||
);
|
||
|
||
GtkWidget *graph_help_title =
|
||
gtk_label_new(
|
||
"Commandes du graphe"
|
||
);
|
||
|
||
GtkWidget *graph_help_text =
|
||
gtk_label_new(
|
||
"• Clic : sélectionner un nœud\n"
|
||
"• Glisser un nœud : le déplacer\n"
|
||
"• Maj + glisser : déplacer la vue\n"
|
||
"• Ctrl + molette : zoomer\n"
|
||
"• Pincement : zoomer"
|
||
);
|
||
|
||
if (workspace->graph_help_button == NULL ||
|
||
workspace->graph_help_popover == NULL ||
|
||
graph_help_content == NULL ||
|
||
graph_help_title == NULL ||
|
||
graph_help_text == NULL)
|
||
{
|
||
workspace_free(
|
||
workspace
|
||
);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
gtk_menu_button_set_label(
|
||
GTK_MENU_BUTTON(
|
||
workspace->graph_help_button
|
||
),
|
||
"?"
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
workspace->graph_help_button,
|
||
"flat"
|
||
);
|
||
|
||
gtk_widget_set_tooltip_text(
|
||
workspace->graph_help_button,
|
||
"Afficher les commandes du graphe"
|
||
);
|
||
|
||
gtk_widget_set_can_target(
|
||
workspace->graph_help_button,
|
||
TRUE
|
||
);
|
||
|
||
gtk_widget_set_halign(
|
||
workspace->graph_help_button,
|
||
GTK_ALIGN_END
|
||
);
|
||
|
||
gtk_widget_set_valign(
|
||
workspace->graph_help_button,
|
||
GTK_ALIGN_START
|
||
);
|
||
|
||
gtk_widget_set_margin_end(
|
||
workspace->graph_help_button,
|
||
12
|
||
);
|
||
|
||
gtk_widget_set_margin_top(
|
||
workspace->graph_help_button,
|
||
12
|
||
);
|
||
|
||
gtk_widget_set_margin_start(
|
||
graph_help_content,
|
||
16
|
||
);
|
||
|
||
gtk_widget_set_margin_end(
|
||
graph_help_content,
|
||
16
|
||
);
|
||
|
||
gtk_widget_set_margin_top(
|
||
graph_help_content,
|
||
14
|
||
);
|
||
|
||
gtk_widget_set_margin_bottom(
|
||
graph_help_content,
|
||
14
|
||
);
|
||
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(
|
||
graph_help_title
|
||
),
|
||
0.0F
|
||
);
|
||
|
||
gtk_widget_add_css_class(
|
||
graph_help_title,
|
||
"heading"
|
||
);
|
||
|
||
gtk_label_set_xalign(
|
||
GTK_LABEL(
|
||
graph_help_text
|
||
),
|
||
0.0F
|
||
);
|
||
|
||
gtk_label_set_wrap(
|
||
GTK_LABEL(
|
||
graph_help_text
|
||
),
|
||
TRUE
|
||
);
|
||
|
||
gtk_label_set_wrap_mode(
|
||
GTK_LABEL(
|
||
graph_help_text
|
||
),
|
||
PANGO_WRAP_WORD_CHAR
|
||
);
|
||
|
||
gtk_label_set_max_width_chars(
|
||
GTK_LABEL(
|
||
graph_help_text
|
||
),
|
||
44
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
graph_help_content
|
||
),
|
||
graph_help_title
|
||
);
|
||
|
||
gtk_box_append(
|
||
GTK_BOX(
|
||
graph_help_content
|
||
),
|
||
graph_help_text
|
||
);
|
||
|
||
gtk_popover_set_child(
|
||
GTK_POPOVER(
|
||
workspace->graph_help_popover
|
||
),
|
||
graph_help_content
|
||
);
|
||
|
||
gtk_menu_button_set_popover(
|
||
GTK_MENU_BUTTON(
|
||
workspace->graph_help_button
|
||
),
|
||
workspace->graph_help_popover
|
||
);
|
||
|
||
gtk_overlay_add_overlay(
|
||
GTK_OVERLAY(
|
||
workspace->graph_view_page
|
||
),
|
||
entity_details_panel_get_widget(
|
||
workspace->entity_details_panel
|
||
)
|
||
);
|
||
|
||
gtk_overlay_add_overlay(
|
||
GTK_OVERLAY(workspace->graph_view_page),
|
||
workspace->relation_details_panel
|
||
);
|
||
|
||
gtk_overlay_set_clip_overlay(
|
||
GTK_OVERLAY(workspace->graph_view_page),
|
||
workspace->relation_details_panel,
|
||
TRUE
|
||
);
|
||
|
||
gtk_overlay_set_clip_overlay(
|
||
GTK_OVERLAY(
|
||
workspace->graph_view_page
|
||
),
|
||
entity_details_panel_get_widget(
|
||
workspace->entity_details_panel
|
||
),
|
||
TRUE
|
||
);
|
||
|
||
gtk_overlay_add_overlay(
|
||
GTK_OVERLAY(
|
||
workspace->graph_view_page
|
||
),
|
||
workspace->graph_help_button
|
||
);
|
||
|
||
gtk_overlay_set_clip_overlay(
|
||
GTK_OVERLAY(
|
||
workspace->graph_view_page
|
||
),
|
||
workspace->graph_help_button,
|
||
TRUE
|
||
);
|
||
|
||
|
||
gtk_stack_add_named(
|
||
GTK_STACK(workspace->stack),
|
||
workspace->graph_view_page,
|
||
WORKSPACE_PAGE_GRAPH_VIEW
|
||
);
|
||
|
||
workspace->graph_model =
|
||
NULL;
|
||
|
||
workspace->graph_layout =
|
||
NULL;
|
||
|
||
workspace->graph_state =
|
||
WORKSPACE_GRAPH_STATE_EMPTY;
|
||
|
||
workspace_show_default(
|
||
workspace
|
||
);
|
||
|
||
return workspace;
|
||
}
|
||
|
||
GtkWidget *workspace_get_widget(
|
||
const Workspace *workspace
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
return workspace->root_widget;
|
||
}
|
||
|
||
void workspace_set_selected_node(
|
||
Workspace *workspace,
|
||
const InvestigationNode *node
|
||
)
|
||
{
|
||
const char *node_name = NULL;
|
||
const InvestigationNode *parent_node = NULL;
|
||
const char *parent_name = NULL;
|
||
const char *node_path = NULL;
|
||
InvestigationNodeType node_type;
|
||
size_t children_count = 0;
|
||
|
||
const char *type_text = NULL;
|
||
char *parent_text = NULL;
|
||
char *children_text = NULL;
|
||
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
g_clear_pointer(
|
||
&workspace->selected_evidence_identifier,
|
||
g_free
|
||
);
|
||
|
||
if (workspace->verify_evidence_button != NULL)
|
||
{
|
||
gtk_widget_set_sensitive(
|
||
workspace->verify_evidence_button,
|
||
FALSE
|
||
);
|
||
}
|
||
if (workspace->edit_evidence_button != NULL)
|
||
gtk_widget_set_sensitive(workspace->edit_evidence_button, FALSE);
|
||
if (workspace->analyze_eml_button != NULL)
|
||
gtk_widget_set_sensitive(workspace->analyze_eml_button, FALSE);
|
||
|
||
if (node == NULL)
|
||
{
|
||
workspace_show_default(workspace);
|
||
return;
|
||
}
|
||
|
||
node_name = investigation_node_get_name(node);
|
||
node_path = investigation_node_get_path(node);
|
||
node_type = investigation_node_get_type(node);
|
||
parent_node = investigation_node_get_parent(node);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->node_name_label),
|
||
node_name != NULL ? node_name : "(sans nom)"
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->node_path_label),
|
||
node_path != NULL ? node_path : "(chemin indisponible)"
|
||
);
|
||
|
||
if (node_type == INVESTIGATION_NODE_DIRECTORY)
|
||
{
|
||
type_text = "Type : dossier";
|
||
}
|
||
else
|
||
{
|
||
type_text = "Type : fichier";
|
||
}
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->node_type_label),
|
||
type_text
|
||
);
|
||
|
||
if (parent_node != NULL)
|
||
{
|
||
parent_name = investigation_node_get_name(parent_node);
|
||
|
||
parent_text = g_strdup_printf(
|
||
"Parent : %s",
|
||
parent_name != NULL ? parent_name : "(sans nom)"
|
||
);
|
||
}
|
||
else
|
||
{
|
||
parent_text = g_strdup("Parent : aucun");
|
||
}
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->node_parent_label),
|
||
parent_text
|
||
);
|
||
|
||
if (node_type == INVESTIGATION_NODE_DIRECTORY)
|
||
{
|
||
children_count =
|
||
investigation_node_get_children_count(node);
|
||
|
||
children_text = g_strdup_printf(
|
||
"Enfants : %zu",
|
||
children_count
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->node_children_label),
|
||
children_text
|
||
);
|
||
|
||
gtk_widget_set_visible(
|
||
workspace->node_children_label,
|
||
TRUE
|
||
);
|
||
}
|
||
else
|
||
{
|
||
gtk_label_set_text(
|
||
GTK_LABEL(workspace->node_children_label),
|
||
""
|
||
);
|
||
|
||
gtk_widget_set_visible(
|
||
workspace->node_children_label,
|
||
FALSE
|
||
);
|
||
}
|
||
|
||
gtk_stack_set_visible_child_name(
|
||
GTK_STACK(workspace->stack),
|
||
WORKSPACE_PAGE_NODE_INFORMATION
|
||
);
|
||
|
||
g_free(children_text);
|
||
g_free(parent_text);
|
||
}
|
||
|
||
void workspace_set_selected_evidence(
|
||
Workspace *workspace,
|
||
const EvidenceRecord *evidence_record
|
||
)
|
||
{
|
||
char *human_size = NULL;
|
||
char *size_text = NULL;
|
||
|
||
guint64 size_bytes = 0;
|
||
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace_clear_evidence_preview(workspace);
|
||
if (workspace->evidence_preview_stack != NULL)
|
||
gtk_stack_set_visible_child_name(GTK_STACK(
|
||
workspace->evidence_preview_stack), "status");
|
||
|
||
g_clear_pointer(
|
||
&workspace->selected_evidence_identifier,
|
||
g_free
|
||
);
|
||
|
||
if (workspace->verify_evidence_button != NULL)
|
||
{
|
||
gtk_widget_set_sensitive(
|
||
workspace->verify_evidence_button,
|
||
FALSE
|
||
);
|
||
}
|
||
|
||
if (evidence_record == NULL)
|
||
{
|
||
workspace_show_default(
|
||
workspace
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
workspace->selected_evidence_identifier =
|
||
g_strdup(
|
||
evidence_record_get_identifier(
|
||
evidence_record
|
||
)
|
||
);
|
||
|
||
if (workspace->selected_evidence_identifier == NULL)
|
||
{
|
||
workspace_show_default(
|
||
workspace
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
gtk_widget_set_sensitive(
|
||
workspace->verify_evidence_button,
|
||
TRUE
|
||
);
|
||
gtk_widget_set_sensitive(workspace->edit_evidence_button, TRUE);
|
||
{
|
||
const char *name = evidence_record_get_original_name(evidence_record);
|
||
char *lower = name != NULL ? g_ascii_strdown(name, -1) : NULL;
|
||
gtk_widget_set_sensitive(workspace->analyze_eml_button,
|
||
lower != NULL && g_str_has_suffix(lower, ".eml"));
|
||
g_free(lower);
|
||
}
|
||
|
||
size_bytes =
|
||
evidence_record_get_size_bytes(
|
||
evidence_record
|
||
);
|
||
|
||
human_size =
|
||
g_format_size_full(
|
||
size_bytes,
|
||
G_FORMAT_SIZE_IEC_UNITS
|
||
);
|
||
|
||
size_text =
|
||
g_strdup_printf(
|
||
"%s (%" G_GUINT64_FORMAT " octets)",
|
||
human_size != NULL
|
||
? human_size
|
||
: "taille inconnue",
|
||
size_bytes
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_name_label,
|
||
evidence_record_get_original_name(
|
||
evidence_record
|
||
),
|
||
"(sans nom)"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_type_label,
|
||
evidence_record_get_type_identifier(
|
||
evidence_record
|
||
),
|
||
"(type inconnu)"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_integrity_label,
|
||
workspace_get_integrity_status_text(
|
||
evidence_record_get_integrity_status(
|
||
evidence_record
|
||
)
|
||
),
|
||
"Statut inconnu"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_size_label,
|
||
size_text,
|
||
"Taille inconnue"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_imported_at_label,
|
||
evidence_record_get_imported_at(
|
||
evidence_record
|
||
),
|
||
"(date inconnue)"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_collected_at_label,
|
||
evidence_record_get_collected_at(
|
||
evidence_record
|
||
),
|
||
"Non renseignée"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_source_label,
|
||
evidence_record_get_source(
|
||
evidence_record
|
||
),
|
||
"Non renseignée"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_description_label,
|
||
evidence_record_get_description(
|
||
evidence_record
|
||
),
|
||
"Non renseignée"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_relative_path_label,
|
||
evidence_record_get_relative_path(
|
||
evidence_record
|
||
),
|
||
"(chemin inconnu)"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_internal_name_label,
|
||
evidence_record_get_internal_name(
|
||
evidence_record
|
||
),
|
||
"(nom interne inconnu)"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_identifier_label,
|
||
evidence_record_get_identifier(
|
||
evidence_record
|
||
),
|
||
"(identifiant inconnu)"
|
||
);
|
||
|
||
workspace_set_field_text(
|
||
workspace->evidence_sha256_label,
|
||
evidence_record_get_sha256(
|
||
evidence_record
|
||
),
|
||
"(empreinte inconnue)"
|
||
);
|
||
|
||
gtk_stack_set_visible_child_name(
|
||
GTK_STACK(workspace->stack),
|
||
WORKSPACE_PAGE_EVIDENCE_INFORMATION
|
||
);
|
||
|
||
g_free(
|
||
size_text
|
||
);
|
||
|
||
g_free(
|
||
human_size
|
||
);
|
||
}
|
||
|
||
void workspace_set_evidence_preview(Workspace *workspace,
|
||
const char *file_path, const char *display_name)
|
||
{
|
||
GFile *file = NULL;
|
||
GFileInfo *info = NULL;
|
||
const char *content_type = NULL;
|
||
char *mime_type = NULL;
|
||
GtkMediaStream *stream = NULL;
|
||
GError *error = NULL;
|
||
if (workspace == NULL) return;
|
||
workspace_clear_evidence_preview(workspace);
|
||
if (file_path == NULL || file_path[0] == '\0')
|
||
{
|
||
gtk_label_set_text(GTK_LABEL(workspace->evidence_preview_status),
|
||
"Aucun aperçu disponible pour cette preuve.");
|
||
gtk_stack_set_visible_child_name(GTK_STACK(
|
||
workspace->evidence_preview_stack), "status");
|
||
return;
|
||
}
|
||
file = g_file_new_for_path(file_path);
|
||
info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
|
||
G_FILE_QUERY_INFO_NONE, NULL, &error);
|
||
if (info != NULL) content_type = g_file_info_get_content_type(info);
|
||
if (content_type != NULL) mime_type = g_content_type_get_mime_type(
|
||
content_type);
|
||
if (mime_type != NULL && g_str_has_prefix(mime_type, "image/"))
|
||
{
|
||
gtk_picture_set_filename(GTK_PICTURE(
|
||
workspace->evidence_preview_picture), file_path);
|
||
gtk_stack_set_visible_child_name(GTK_STACK(
|
||
workspace->evidence_preview_stack), "image");
|
||
workspace->evidence_preview_is_video = FALSE;
|
||
}
|
||
else if (mime_type != NULL && g_str_has_prefix(mime_type, "video/"))
|
||
{
|
||
stream = gtk_media_file_new_for_filename(file_path);
|
||
g_signal_connect(stream, "notify::error",
|
||
G_CALLBACK(workspace_on_video_error_changed), workspace);
|
||
gtk_video_set_media_stream(GTK_VIDEO(
|
||
workspace->evidence_preview_video), stream);
|
||
g_object_unref(stream);
|
||
gtk_stack_set_visible_child_name(GTK_STACK(
|
||
workspace->evidence_preview_stack), "video");
|
||
workspace->evidence_preview_is_video = TRUE;
|
||
}
|
||
else
|
||
{
|
||
char *message = g_strdup_printf(
|
||
"Aperçu indisponible pour %s%s%s.",
|
||
display_name != NULL ? display_name : "ce fichier",
|
||
error != NULL ? " : " : "",
|
||
error != NULL ? error->message : "format non pris en charge");
|
||
gtk_label_set_text(GTK_LABEL(workspace->evidence_preview_status),
|
||
message);
|
||
gtk_stack_set_visible_child_name(GTK_STACK(
|
||
workspace->evidence_preview_stack), "status");
|
||
g_free(message);
|
||
goto cleanup;
|
||
}
|
||
workspace->evidence_preview_path = g_strdup(file_path);
|
||
gtk_widget_set_sensitive(workspace->evidence_preview_expand_button,
|
||
workspace->evidence_preview_path != NULL);
|
||
cleanup:
|
||
g_clear_error(&error);
|
||
g_free(mime_type);
|
||
g_clear_object(&info);
|
||
g_clear_object(&file);
|
||
}
|
||
|
||
gboolean workspace_select_graph_entity(
|
||
Workspace *workspace,
|
||
const char *entity_identifier
|
||
)
|
||
{
|
||
if (workspace == NULL || workspace->graph_view == NULL)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
return investigation_graph_view_select_entity(
|
||
workspace->graph_view,
|
||
entity_identifier
|
||
);
|
||
}
|
||
|
||
gboolean workspace_select_graph_relation(
|
||
Workspace *workspace,
|
||
const char *relation_identifier
|
||
)
|
||
{
|
||
if (workspace == NULL || workspace->graph_view == NULL)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
return investigation_graph_view_select_relation(
|
||
workspace->graph_view,
|
||
relation_identifier
|
||
);
|
||
}
|
||
|
||
void workspace_set_osint_tool_state(
|
||
Workspace *workspace,
|
||
const char *tool_identifier,
|
||
OsintActionToolState state,
|
||
const char *version
|
||
)
|
||
{
|
||
if (workspace == NULL || workspace->osint_action_catalog == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
osint_action_catalog_update_tool_state(
|
||
workspace->osint_action_catalog,
|
||
tool_identifier,
|
||
state,
|
||
version
|
||
);
|
||
workspace_update_osint_tools_menu(
|
||
workspace,
|
||
workspace->osint_selection_context
|
||
);
|
||
}
|
||
|
||
void workspace_set_osint_action_callback(
|
||
Workspace *workspace,
|
||
WorkspaceOsintActionCallback callback,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->osint_action_callback = callback;
|
||
workspace->osint_action_user_data = user_data;
|
||
}
|
||
|
||
void workspace_set_graph_loading(
|
||
Workspace *workspace
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
g_clear_pointer(
|
||
&workspace->selected_evidence_identifier,
|
||
g_free
|
||
);
|
||
|
||
if (workspace->verify_evidence_button != NULL)
|
||
{
|
||
gtk_widget_set_sensitive(
|
||
workspace->verify_evidence_button,
|
||
FALSE
|
||
);
|
||
}
|
||
|
||
entity_details_panel_clear(
|
||
workspace->entity_details_panel
|
||
);
|
||
|
||
investigation_graph_view_clear(
|
||
workspace->graph_view
|
||
);
|
||
|
||
workspace->graph_model =
|
||
NULL;
|
||
|
||
workspace->graph_layout =
|
||
NULL;
|
||
|
||
workspace->graph_state =
|
||
WORKSPACE_GRAPH_STATE_LOADING;
|
||
|
||
gtk_widget_set_sensitive(
|
||
workspace->reset_graph_layout_button,
|
||
FALSE
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->graph_title_label
|
||
),
|
||
"Chargement de l’enquête…"
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->graph_details_label
|
||
),
|
||
"Lecture des entités et des relations"
|
||
);
|
||
|
||
gtk_widget_set_visible(
|
||
workspace->graph_spinner,
|
||
TRUE
|
||
);
|
||
|
||
gtk_spinner_start(
|
||
GTK_SPINNER(
|
||
workspace->graph_spinner
|
||
)
|
||
);
|
||
|
||
workspace_show_default(
|
||
workspace
|
||
);
|
||
}
|
||
|
||
void workspace_set_graph(
|
||
Workspace *workspace,
|
||
const InvestigationGraphModel *graph_model,
|
||
const InvestigationGraphLayout *graph_layout
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (graph_model == NULL)
|
||
{
|
||
workspace_clear_graph(
|
||
workspace
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
g_clear_pointer(
|
||
&workspace->selected_evidence_identifier,
|
||
g_free
|
||
);
|
||
|
||
if (workspace->verify_evidence_button != NULL)
|
||
{
|
||
gtk_widget_set_sensitive(
|
||
workspace->verify_evidence_button,
|
||
FALSE
|
||
);
|
||
}
|
||
|
||
entity_details_panel_clear(
|
||
workspace->entity_details_panel
|
||
);
|
||
|
||
investigation_graph_view_clear(
|
||
workspace->graph_view
|
||
);
|
||
|
||
workspace->graph_model =
|
||
graph_model;
|
||
|
||
workspace->graph_layout =
|
||
graph_layout;
|
||
|
||
investigation_graph_view_set_layout(
|
||
workspace->graph_view,
|
||
graph_layout
|
||
);
|
||
|
||
investigation_graph_view_set_graph(
|
||
workspace->graph_view,
|
||
graph_model
|
||
);
|
||
|
||
workspace->graph_state =
|
||
WORKSPACE_GRAPH_STATE_READY;
|
||
|
||
gtk_widget_set_sensitive(
|
||
workspace->reset_graph_layout_button,
|
||
TRUE
|
||
);
|
||
|
||
gtk_spinner_stop(
|
||
GTK_SPINNER(
|
||
workspace->graph_spinner
|
||
)
|
||
);
|
||
|
||
gtk_widget_set_visible(
|
||
workspace->graph_spinner,
|
||
FALSE
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->graph_title_label
|
||
),
|
||
""
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->graph_details_label
|
||
),
|
||
""
|
||
);
|
||
|
||
workspace_show_default(
|
||
workspace
|
||
);
|
||
}
|
||
|
||
void workspace_set_graph_error(
|
||
Workspace *workspace,
|
||
const char *message
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
g_clear_pointer(
|
||
&workspace->selected_evidence_identifier,
|
||
g_free
|
||
);
|
||
|
||
if (workspace->verify_evidence_button != NULL)
|
||
{
|
||
gtk_widget_set_sensitive(
|
||
workspace->verify_evidence_button,
|
||
FALSE
|
||
);
|
||
}
|
||
|
||
entity_details_panel_clear(
|
||
workspace->entity_details_panel
|
||
);
|
||
|
||
investigation_graph_view_clear(
|
||
workspace->graph_view
|
||
);
|
||
|
||
workspace->graph_model =
|
||
NULL;
|
||
|
||
workspace->graph_layout =
|
||
NULL;
|
||
|
||
workspace->graph_state =
|
||
WORKSPACE_GRAPH_STATE_ERROR;
|
||
|
||
gtk_widget_set_sensitive(
|
||
workspace->reset_graph_layout_button,
|
||
FALSE
|
||
);
|
||
|
||
gtk_spinner_stop(
|
||
GTK_SPINNER(
|
||
workspace->graph_spinner
|
||
)
|
||
);
|
||
|
||
gtk_widget_set_visible(
|
||
workspace->graph_spinner,
|
||
FALSE
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->graph_title_label
|
||
),
|
||
"Impossible de charger le graphe de l’enquête"
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->graph_details_label
|
||
),
|
||
message != NULL &&
|
||
message[0] != '\0'
|
||
? message
|
||
: "Aucun détail supplémentaire n’est disponible."
|
||
);
|
||
|
||
workspace_show_default(
|
||
workspace
|
||
);
|
||
}
|
||
|
||
void workspace_clear_graph(
|
||
Workspace *workspace
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
g_clear_pointer(
|
||
&workspace->selected_evidence_identifier,
|
||
g_free
|
||
);
|
||
|
||
if (workspace->verify_evidence_button != NULL)
|
||
{
|
||
gtk_widget_set_sensitive(
|
||
workspace->verify_evidence_button,
|
||
FALSE
|
||
);
|
||
}
|
||
|
||
entity_details_panel_clear(
|
||
workspace->entity_details_panel
|
||
);
|
||
|
||
investigation_graph_view_clear(
|
||
workspace->graph_view
|
||
);
|
||
|
||
workspace->graph_model =
|
||
NULL;
|
||
|
||
workspace->graph_layout =
|
||
NULL;
|
||
|
||
workspace->graph_state =
|
||
WORKSPACE_GRAPH_STATE_EMPTY;
|
||
|
||
gtk_widget_set_sensitive(
|
||
workspace->reset_graph_layout_button,
|
||
FALSE
|
||
);
|
||
|
||
gtk_spinner_stop(
|
||
GTK_SPINNER(
|
||
workspace->graph_spinner
|
||
)
|
||
);
|
||
|
||
gtk_widget_set_visible(
|
||
workspace->graph_spinner,
|
||
FALSE
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->graph_title_label
|
||
),
|
||
""
|
||
);
|
||
|
||
gtk_label_set_text(
|
||
GTK_LABEL(
|
||
workspace->graph_details_label
|
||
),
|
||
""
|
||
);
|
||
|
||
workspace_show_default(
|
||
workspace
|
||
);
|
||
}
|
||
|
||
void workspace_set_verify_evidence_callback(
|
||
Workspace *workspace,
|
||
WorkspaceVerifyEvidenceCallback callback,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->verify_evidence_callback =
|
||
callback;
|
||
|
||
workspace->verify_evidence_user_data =
|
||
user_data;
|
||
}
|
||
|
||
void workspace_set_edit_evidence_callback(
|
||
Workspace *workspace, WorkspaceEditEvidenceCallback callback,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
if (workspace == NULL) return;
|
||
workspace->edit_evidence_callback = callback;
|
||
workspace->edit_evidence_user_data = user_data;
|
||
}
|
||
void workspace_set_analyze_eml_callback(Workspace *workspace,
|
||
WorkspaceAnalyzeEmlCallback callback, gpointer user_data)
|
||
{
|
||
if (workspace == NULL) return;
|
||
workspace->analyze_eml_callback = callback;
|
||
workspace->analyze_eml_user_data = user_data;
|
||
}
|
||
|
||
void workspace_set_graph_node_moved_callback(
|
||
Workspace *workspace,
|
||
WorkspaceGraphNodeMovedCallback callback,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->graph_node_moved_callback =
|
||
callback;
|
||
|
||
workspace->graph_node_moved_user_data =
|
||
user_data;
|
||
}
|
||
|
||
void workspace_set_reset_graph_layout_callback(
|
||
Workspace *workspace,
|
||
WorkspaceResetGraphLayoutCallback callback,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->reset_graph_layout_callback =
|
||
callback;
|
||
|
||
workspace->reset_graph_layout_user_data =
|
||
user_data;
|
||
}
|
||
|
||
void workspace_set_add_relation_callback(
|
||
Workspace *workspace,
|
||
WorkspaceAddRelationCallback callback,
|
||
gpointer user_data
|
||
)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace->add_relation_callback =
|
||
callback;
|
||
|
||
workspace->add_relation_user_data =
|
||
user_data;
|
||
}
|
||
|
||
void workspace_set_edit_relation_callback(Workspace *workspace,
|
||
WorkspaceEditRelationCallback callback, gpointer user_data)
|
||
{
|
||
if (workspace == NULL) return;
|
||
workspace->edit_relation_callback = callback;
|
||
workspace->edit_relation_user_data = user_data;
|
||
}
|
||
|
||
void workspace_set_relation_selected_callback(Workspace *workspace,
|
||
WorkspaceRelationSelectedCallback callback, gpointer user_data)
|
||
{
|
||
if (workspace == NULL) return;
|
||
workspace->relation_selected_callback = callback;
|
||
workspace->relation_selected_user_data = user_data;
|
||
}
|
||
|
||
void workspace_set_relation_evidences(Workspace *workspace,
|
||
const GPtrArray *evidence_records)
|
||
{
|
||
GString *text = NULL;
|
||
if (workspace == NULL || workspace->relation_evidences_label == NULL)
|
||
return;
|
||
text = g_string_new("Pièces jointes");
|
||
if (evidence_records == NULL || evidence_records->len == 0)
|
||
g_string_append(text, " : aucune");
|
||
else
|
||
{
|
||
g_string_append_printf(text, " (%u) :", evidence_records->len);
|
||
for (guint index = 0; index < evidence_records->len; index++)
|
||
{
|
||
const EvidenceRecord *record = g_ptr_array_index(evidence_records,
|
||
index);
|
||
if (record == NULL) continue;
|
||
g_string_append_printf(text, "\n• %s — %s",
|
||
evidence_record_get_original_name(record),
|
||
evidence_record_get_type_identifier(record));
|
||
}
|
||
}
|
||
gtk_label_set_text(GTK_LABEL(workspace->relation_evidences_label),
|
||
text->str);
|
||
g_string_free(text, TRUE);
|
||
}
|
||
|
||
void workspace_set_person_role_callback(Workspace *workspace,
|
||
WorkspacePersonRoleCallback callback, gpointer user_data)
|
||
{
|
||
if (workspace == NULL) return;
|
||
workspace->person_role_callback = callback;
|
||
workspace->person_role_user_data = user_data;
|
||
}
|
||
|
||
void workspace_reset_graph_layout(
|
||
Workspace *workspace
|
||
)
|
||
{
|
||
if (workspace == NULL ||
|
||
workspace->graph_view == NULL ||
|
||
workspace->graph_state != WORKSPACE_GRAPH_STATE_READY ||
|
||
workspace->graph_model == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
entity_details_panel_clear(
|
||
workspace->entity_details_panel
|
||
);
|
||
|
||
investigation_graph_view_clear_selection(
|
||
workspace->graph_view
|
||
);
|
||
|
||
investigation_graph_view_reset_layout(
|
||
workspace->graph_view
|
||
);
|
||
}
|
||
|
||
void workspace_free(Workspace *workspace)
|
||
{
|
||
if (workspace == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
workspace_clear_evidence_preview(workspace);
|
||
|
||
g_clear_pointer(
|
||
&workspace->osint_selection_context,
|
||
osint_selection_context_free
|
||
);
|
||
g_clear_pointer(&workspace->selected_relation_identifier, g_free);
|
||
|
||
g_clear_pointer(
|
||
&workspace->osint_action_catalog,
|
||
osint_action_catalog_free
|
||
);
|
||
|
||
investigation_graph_view_set_selection_callback(
|
||
workspace->graph_view,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
investigation_graph_view_set_node_moved_callback(
|
||
workspace->graph_view,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
entity_details_panel_set_close_callback(
|
||
workspace->entity_details_panel,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
entity_details_panel_set_add_relation_callback(
|
||
workspace->entity_details_panel,
|
||
NULL,
|
||
NULL
|
||
);
|
||
entity_details_panel_set_person_role_callback(
|
||
workspace->entity_details_panel, NULL, NULL);
|
||
|
||
entity_details_panel_clear(
|
||
workspace->entity_details_panel
|
||
);
|
||
|
||
investigation_graph_view_clear(
|
||
workspace->graph_view
|
||
);
|
||
|
||
investigation_graph_view_free(
|
||
workspace->graph_view
|
||
);
|
||
|
||
entity_details_panel_free(
|
||
workspace->entity_details_panel
|
||
);
|
||
|
||
workspace->graph_view =
|
||
NULL;
|
||
|
||
workspace->entity_details_panel =
|
||
NULL;
|
||
|
||
workspace->graph_model =
|
||
NULL;
|
||
|
||
workspace->graph_layout =
|
||
NULL;
|
||
|
||
workspace->verify_evidence_callback =
|
||
NULL;
|
||
|
||
workspace->verify_evidence_user_data =
|
||
NULL;
|
||
|
||
workspace->graph_node_moved_callback =
|
||
NULL;
|
||
|
||
workspace->graph_node_moved_user_data =
|
||
NULL;
|
||
|
||
workspace->reset_graph_layout_callback =
|
||
NULL;
|
||
|
||
workspace->reset_graph_layout_user_data =
|
||
NULL;
|
||
|
||
workspace->add_relation_callback =
|
||
NULL;
|
||
|
||
workspace->add_relation_user_data =
|
||
NULL;
|
||
|
||
workspace->graph_toolbar =
|
||
NULL;
|
||
|
||
workspace->reset_graph_layout_button =
|
||
NULL;
|
||
|
||
workspace->graph_help_button =
|
||
NULL;
|
||
|
||
workspace->graph_help_popover =
|
||
NULL;
|
||
|
||
g_clear_pointer(
|
||
&workspace->selected_evidence_identifier,
|
||
g_free
|
||
);
|
||
|
||
g_free(workspace);
|
||
}
|