feat(relations): attach evidence to relations
This commit is contained in:
parent
f142de8663
commit
f585041736
7 changed files with 544 additions and 13 deletions
|
|
@ -68,6 +68,8 @@ GQuark create_relation_dialog_error_quark(void);
|
||||||
* @param parent Fenêtre GTK parente.
|
* @param parent Fenêtre GTK parente.
|
||||||
* @param source_entity_identifier UUID de l'entité source.
|
* @param source_entity_identifier UUID de l'entité source.
|
||||||
* @param entities Tableau de EntityRecord.
|
* @param entities Tableau de EntityRecord.
|
||||||
|
* @param evidence_records Tableau de EvidenceRecord disponibles.
|
||||||
|
* @param investigation_root_path Racine canonique de l'enquête.
|
||||||
* @param callback Fonction appelée après validation ou annulation.
|
* @param callback Fonction appelée après validation ou annulation.
|
||||||
* @param user_data Données privées transmises au callback.
|
* @param user_data Données privées transmises au callback.
|
||||||
* @param error Emplacement facultatif recevant une erreur immédiate.
|
* @param error Emplacement facultatif recevant une erreur immédiate.
|
||||||
|
|
@ -78,6 +80,8 @@ gboolean create_relation_dialog_present(
|
||||||
GtkWindow *parent,
|
GtkWindow *parent,
|
||||||
const char *source_entity_identifier,
|
const char *source_entity_identifier,
|
||||||
const GPtrArray *entities,
|
const GPtrArray *entities,
|
||||||
|
const GPtrArray *evidence_records,
|
||||||
|
const char *investigation_root_path,
|
||||||
CreateRelationDialogCallback callback,
|
CreateRelationDialogCallback callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
GError **error
|
GError **error
|
||||||
|
|
@ -88,11 +92,26 @@ gboolean create_relation_dialog_present(
|
||||||
*
|
*
|
||||||
* La source et la cible sont conservées ; les champs métier sont modifiables.
|
* La source et la cible sont conservées ; les champs métier sont modifiables.
|
||||||
* Le dialogue ne réalise aucune écriture SQLite.
|
* Le dialogue ne réalise aucune écriture SQLite.
|
||||||
|
*
|
||||||
|
* @param parent Fenêtre GTK parente.
|
||||||
|
* @param relation_record Relation existante à modifier.
|
||||||
|
* @param entities Tableau de EntityRecord.
|
||||||
|
* @param evidence_records Tableau de EvidenceRecord disponibles.
|
||||||
|
* @param selected_evidence_identifiers UUID des preuves déjà liées.
|
||||||
|
* @param investigation_root_path Racine canonique de l'enquête.
|
||||||
|
* @param callback Fonction appelée après validation ou annulation.
|
||||||
|
* @param user_data Données privées transmises au callback.
|
||||||
|
* @param error Emplacement facultatif recevant une erreur immédiate.
|
||||||
|
*
|
||||||
|
* @return TRUE si le dialogue a été créé et présenté.
|
||||||
*/
|
*/
|
||||||
gboolean edit_relation_dialog_present(
|
gboolean edit_relation_dialog_present(
|
||||||
GtkWindow *parent,
|
GtkWindow *parent,
|
||||||
const RelationRecord *relation_record,
|
const RelationRecord *relation_record,
|
||||||
const GPtrArray *entities,
|
const GPtrArray *entities,
|
||||||
|
const GPtrArray *evidence_records,
|
||||||
|
const GPtrArray *selected_evidence_identifiers,
|
||||||
|
const char *investigation_root_path,
|
||||||
CreateRelationDialogCallback callback,
|
CreateRelationDialogCallback callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
GError **error
|
GError **error
|
||||||
|
|
@ -171,6 +190,16 @@ gint create_relation_dialog_result_get_confidence(
|
||||||
const CreateRelationDialogResult *result
|
const CreateRelationDialogResult *result
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne les UUID de preuves sélectionnés.
|
||||||
|
*
|
||||||
|
* @param result Résultat validé du dialogue.
|
||||||
|
*
|
||||||
|
* @return Tableau emprunté d'UUID, ou NULL.
|
||||||
|
*/
|
||||||
|
const GPtrArray *create_relation_dialog_result_get_evidence_identifiers(
|
||||||
|
const CreateRelationDialogResult *result);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,12 @@ typedef void (*MainWindowEditRelationCallback)(
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** @brief Callback appelé quand une relation est sélectionnée. */
|
||||||
|
typedef void (*MainWindowRelationSelectedCallback)(
|
||||||
|
const char *relation_identifier,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
/** @brief Callback appelé pour catégoriser une personne. */
|
/** @brief Callback appelé pour catégoriser une personne. */
|
||||||
typedef void (*MainWindowPersonRoleCallback)(const char *entity_identifier,
|
typedef void (*MainWindowPersonRoleCallback)(const char *entity_identifier,
|
||||||
PersonRole role, gpointer user_data);
|
PersonRole role, gpointer user_data);
|
||||||
|
|
@ -244,6 +250,19 @@ void main_window_set_edit_relation_callback(
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** @brief Définit le callback de sélection d'une relation. */
|
||||||
|
void main_window_set_relation_selected_callback(
|
||||||
|
MainWindow *main_window,
|
||||||
|
MainWindowRelationSelectedCallback callback,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @brief Affiche les preuves associées à la relation sélectionnée. */
|
||||||
|
void main_window_set_relation_evidences(
|
||||||
|
MainWindow *main_window,
|
||||||
|
const GPtrArray *evidence_records
|
||||||
|
);
|
||||||
|
|
||||||
/** @brief Définit le callback de catégorisation d'une personne. */
|
/** @brief Définit le callback de catégorisation d'une personne. */
|
||||||
void main_window_set_person_role_callback(MainWindow *main_window,
|
void main_window_set_person_role_callback(MainWindow *main_window,
|
||||||
MainWindowPersonRoleCallback callback, gpointer user_data);
|
MainWindowPersonRoleCallback callback, gpointer user_data);
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,12 @@ typedef void (*WorkspaceEditRelationCallback)(
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** @brief Callback appelé quand une relation devient sélectionnée. */
|
||||||
|
typedef void (*WorkspaceRelationSelectedCallback)(
|
||||||
|
const char *relation_identifier,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
/** @brief Callback appelé pour catégoriser une personne. */
|
/** @brief Callback appelé pour catégoriser une personne. */
|
||||||
typedef void (*WorkspacePersonRoleCallback)(const char *entity_identifier,
|
typedef void (*WorkspacePersonRoleCallback)(const char *entity_identifier,
|
||||||
PersonRole role, gpointer user_data);
|
PersonRole role, gpointer user_data);
|
||||||
|
|
@ -315,6 +321,30 @@ void workspace_set_edit_relation_callback(
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Définit le callback de sélection d'une relation.
|
||||||
|
*
|
||||||
|
* @param workspace Zone de travail.
|
||||||
|
* @param callback Callback facultatif.
|
||||||
|
* @param user_data Données empruntées transmises au callback.
|
||||||
|
*/
|
||||||
|
void workspace_set_relation_selected_callback(
|
||||||
|
Workspace *workspace,
|
||||||
|
WorkspaceRelationSelectedCallback callback,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Affiche les preuves associées à la relation sélectionnée.
|
||||||
|
*
|
||||||
|
* @param workspace Zone de travail.
|
||||||
|
* @param evidence_records Tableau emprunté de EvidenceRecord, ou NULL.
|
||||||
|
*/
|
||||||
|
void workspace_set_relation_evidences(
|
||||||
|
Workspace *workspace,
|
||||||
|
const GPtrArray *evidence_records
|
||||||
|
);
|
||||||
|
|
||||||
/** @brief Définit le callback de catégorisation d'une personne. */
|
/** @brief Définit le callback de catégorisation d'une personne. */
|
||||||
void workspace_set_person_role_callback(Workspace *workspace,
|
void workspace_set_person_role_callback(Workspace *workspace,
|
||||||
WorkspacePersonRoleCallback callback, gpointer user_data);
|
WorkspacePersonRoleCallback callback, gpointer user_data);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
#include "dao/evidence_dao.h"
|
#include "dao/evidence_dao.h"
|
||||||
#include "dao/entity_dao.h"
|
#include "dao/entity_dao.h"
|
||||||
#include "dao/relation_dao.h"
|
#include "dao/relation_dao.h"
|
||||||
|
#include "dao/relation_evidence_dao.h"
|
||||||
#include "dao/osint_execution_dao.h"
|
#include "dao/osint_execution_dao.h"
|
||||||
#include "models/evidence_type.h"
|
#include "models/evidence_type.h"
|
||||||
#include "widgets/evidence_list_model.h"
|
#include "widgets/evidence_list_model.h"
|
||||||
|
|
@ -4873,7 +4874,7 @@ static void application_on_create_relation_completed(
|
||||||
if (!relation_service_create(
|
if (!relation_service_create(
|
||||||
relation_service,
|
relation_service,
|
||||||
relation_record,
|
relation_record,
|
||||||
NULL,
|
create_relation_dialog_result_get_evidence_identifiers(result),
|
||||||
&error
|
&error
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
|
|
@ -5020,6 +5021,7 @@ static void application_on_edit_relation_completed(
|
||||||
Application *application = context != NULL ? context->application : NULL;
|
Application *application = context != NULL ? context->application : NULL;
|
||||||
Database *database = NULL;
|
Database *database = NULL;
|
||||||
RelationDao *relation_dao = NULL;
|
RelationDao *relation_dao = NULL;
|
||||||
|
RelationEvidenceDao *relation_evidence_dao = NULL;
|
||||||
RelationRecord *existing = NULL;
|
RelationRecord *existing = NULL;
|
||||||
RelationRecord *updated = NULL;
|
RelationRecord *updated = NULL;
|
||||||
const InvestigationProject *project = NULL;
|
const InvestigationProject *project = NULL;
|
||||||
|
|
@ -5033,7 +5035,8 @@ static void application_on_edit_relation_completed(
|
||||||
database = investigation_session_get_database(application->session);
|
database = investigation_session_get_database(application->session);
|
||||||
project = investigation_session_get_project(application->session);
|
project = investigation_session_get_project(application->session);
|
||||||
relation_dao = relation_dao_new(database, &error);
|
relation_dao = relation_dao_new(database, &error);
|
||||||
if (relation_dao == NULL) goto failure;
|
relation_evidence_dao = relation_evidence_dao_new(database, &error);
|
||||||
|
if (relation_dao == NULL || relation_evidence_dao == NULL) goto failure;
|
||||||
existing = relation_dao_find_by_identifier(relation_dao,
|
existing = relation_dao_find_by_identifier(relation_dao,
|
||||||
context->relation_identifier, &error);
|
context->relation_identifier, &error);
|
||||||
if (existing == NULL) goto failure;
|
if (existing == NULL) goto failure;
|
||||||
|
|
@ -5052,9 +5055,47 @@ static void application_on_edit_relation_completed(
|
||||||
relation_record_get_status(existing), &error);
|
relation_record_get_status(existing), &error);
|
||||||
if (updated == NULL || !database_transaction_begin(database)) goto failure;
|
if (updated == NULL || !database_transaction_begin(database)) goto failure;
|
||||||
transaction_active = TRUE;
|
transaction_active = TRUE;
|
||||||
if (!relation_dao_update(relation_dao, updated, &error) ||
|
if (!relation_dao_update(relation_dao, updated, &error))
|
||||||
!database_transaction_commit(database))
|
|
||||||
goto failure;
|
goto failure;
|
||||||
|
{
|
||||||
|
GPtrArray *existing_evidence =
|
||||||
|
relation_evidence_dao_list_evidence_identifiers(
|
||||||
|
relation_evidence_dao, context->relation_identifier, &error);
|
||||||
|
const GPtrArray *selected_evidence =
|
||||||
|
create_relation_dialog_result_get_evidence_identifiers(result);
|
||||||
|
if (existing_evidence == NULL) goto failure;
|
||||||
|
for (guint index = 0; index < existing_evidence->len; index++)
|
||||||
|
{
|
||||||
|
const char *identifier = g_ptr_array_index(existing_evidence, index);
|
||||||
|
gboolean retained = FALSE;
|
||||||
|
for (guint selected_index = 0;
|
||||||
|
selected_index < selected_evidence->len; selected_index++)
|
||||||
|
if (g_strcmp0(identifier, g_ptr_array_index(selected_evidence,
|
||||||
|
selected_index)) == 0) retained = TRUE;
|
||||||
|
if (!retained && !relation_evidence_dao_unlink(
|
||||||
|
relation_evidence_dao, context->relation_identifier,
|
||||||
|
identifier, &error))
|
||||||
|
{
|
||||||
|
g_ptr_array_unref(existing_evidence);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (guint index = 0; index < selected_evidence->len; index++)
|
||||||
|
{
|
||||||
|
const char *identifier = g_ptr_array_index(selected_evidence, index);
|
||||||
|
gboolean exists = FALSE;
|
||||||
|
if (!relation_evidence_dao_exists(relation_evidence_dao,
|
||||||
|
context->relation_identifier, identifier, &exists, &error) ||
|
||||||
|
(!exists && !relation_evidence_dao_link(relation_evidence_dao,
|
||||||
|
context->relation_identifier, identifier, &error)))
|
||||||
|
{
|
||||||
|
g_ptr_array_unref(existing_evidence);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_ptr_array_unref(existing_evidence);
|
||||||
|
}
|
||||||
|
if (!database_transaction_commit(database)) goto failure;
|
||||||
transaction_active = FALSE;
|
transaction_active = FALSE;
|
||||||
main_window_set_status(application->main_window,
|
main_window_set_status(application->main_window,
|
||||||
"Relation modifiée. Actualisation du graphe…");
|
"Relation modifiée. Actualisation du graphe…");
|
||||||
|
|
@ -5077,6 +5118,7 @@ cleanup:
|
||||||
relation_record_free(updated);
|
relation_record_free(updated);
|
||||||
relation_record_free(existing);
|
relation_record_free(existing);
|
||||||
relation_dao_free(relation_dao);
|
relation_dao_free(relation_dao);
|
||||||
|
relation_evidence_dao_free(relation_evidence_dao);
|
||||||
create_relation_dialog_result_free(result);
|
create_relation_dialog_result_free(result);
|
||||||
application_edit_relation_context_free(context);
|
application_edit_relation_context_free(context);
|
||||||
}
|
}
|
||||||
|
|
@ -5089,8 +5131,13 @@ static void application_on_edit_relation_requested(
|
||||||
Database *database = NULL;
|
Database *database = NULL;
|
||||||
RelationDao *relation_dao = NULL;
|
RelationDao *relation_dao = NULL;
|
||||||
EntityDao *entity_dao = NULL;
|
EntityDao *entity_dao = NULL;
|
||||||
|
EvidenceDao *evidence_dao = NULL;
|
||||||
|
RelationEvidenceDao *relation_evidence_dao = NULL;
|
||||||
RelationRecord *relation = NULL;
|
RelationRecord *relation = NULL;
|
||||||
GPtrArray *entities = NULL;
|
GPtrArray *entities = NULL;
|
||||||
|
GPtrArray *evidences = NULL;
|
||||||
|
GPtrArray *selected_evidences = NULL;
|
||||||
|
const InvestigationProject *project = NULL;
|
||||||
ApplicationEditRelationContext *context = NULL;
|
ApplicationEditRelationContext *context = NULL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
|
|
@ -5099,16 +5146,27 @@ static void application_on_edit_relation_requested(
|
||||||
database = investigation_session_get_database(application->session);
|
database = investigation_session_get_database(application->session);
|
||||||
relation_dao = relation_dao_new(database, &error);
|
relation_dao = relation_dao_new(database, &error);
|
||||||
entity_dao = entity_dao_new(database, &error);
|
entity_dao = entity_dao_new(database, &error);
|
||||||
|
evidence_dao = evidence_dao_new(database, &error);
|
||||||
|
relation_evidence_dao = relation_evidence_dao_new(database, &error);
|
||||||
|
project = investigation_session_get_project(application->session);
|
||||||
if (relation_dao != NULL)
|
if (relation_dao != NULL)
|
||||||
relation = relation_dao_find_by_identifier(relation_dao,
|
relation = relation_dao_find_by_identifier(relation_dao,
|
||||||
relation_identifier, &error);
|
relation_identifier, &error);
|
||||||
if (entity_dao != NULL) entities = entity_dao_list_all(entity_dao, &error);
|
if (entity_dao != NULL) entities = entity_dao_list_all(entity_dao, &error);
|
||||||
if (relation == NULL || entities == NULL) goto failure;
|
if (evidence_dao != NULL) evidences = evidence_dao_list_all(evidence_dao,
|
||||||
|
&error);
|
||||||
|
if (relation_evidence_dao != NULL) selected_evidences =
|
||||||
|
relation_evidence_dao_list_evidence_identifiers(relation_evidence_dao,
|
||||||
|
relation_identifier, &error);
|
||||||
|
if (relation == NULL || entities == NULL || evidences == NULL ||
|
||||||
|
selected_evidences == NULL || project == NULL) goto failure;
|
||||||
context = g_new0(ApplicationEditRelationContext, 1);
|
context = g_new0(ApplicationEditRelationContext, 1);
|
||||||
context->application = application;
|
context->application = application;
|
||||||
context->relation_identifier = g_strdup(relation_identifier);
|
context->relation_identifier = g_strdup(relation_identifier);
|
||||||
if (context->relation_identifier == NULL || !edit_relation_dialog_present(
|
if (context->relation_identifier == NULL || !edit_relation_dialog_present(
|
||||||
main_window_get_window(application->main_window), relation, entities,
|
main_window_get_window(application->main_window), relation, entities,
|
||||||
|
evidences, selected_evidences,
|
||||||
|
investigation_project_get_root_path(project),
|
||||||
application_on_edit_relation_completed, context, &error))
|
application_on_edit_relation_completed, context, &error))
|
||||||
goto failure;
|
goto failure;
|
||||||
context = NULL;
|
context = NULL;
|
||||||
|
|
@ -5121,11 +5179,63 @@ cleanup:
|
||||||
application_edit_relation_context_free(context);
|
application_edit_relation_context_free(context);
|
||||||
g_clear_error(&error);
|
g_clear_error(&error);
|
||||||
g_clear_pointer(&entities, g_ptr_array_unref);
|
g_clear_pointer(&entities, g_ptr_array_unref);
|
||||||
|
g_clear_pointer(&evidences, g_ptr_array_unref);
|
||||||
|
g_clear_pointer(&selected_evidences, g_ptr_array_unref);
|
||||||
relation_record_free(relation);
|
relation_record_free(relation);
|
||||||
entity_dao_free(entity_dao);
|
entity_dao_free(entity_dao);
|
||||||
|
evidence_dao_free(evidence_dao);
|
||||||
|
relation_evidence_dao_free(relation_evidence_dao);
|
||||||
relation_dao_free(relation_dao);
|
relation_dao_free(relation_dao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Charge les preuves liées à la relation affichée dans le volet. */
|
||||||
|
static void application_on_relation_selected(
|
||||||
|
const char *relation_identifier,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Application *application = user_data;
|
||||||
|
Database *database = NULL;
|
||||||
|
RelationEvidenceDao *relation_evidence_dao = NULL;
|
||||||
|
EvidenceDao *evidence_dao = NULL;
|
||||||
|
GPtrArray *identifiers = NULL;
|
||||||
|
GPtrArray *records = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
if (application == NULL || application->session == NULL ||
|
||||||
|
relation_identifier == NULL) return;
|
||||||
|
database = investigation_session_get_database(application->session);
|
||||||
|
relation_evidence_dao = relation_evidence_dao_new(database, &error);
|
||||||
|
if (relation_evidence_dao == NULL) goto cleanup;
|
||||||
|
evidence_dao = evidence_dao_new(database, &error);
|
||||||
|
if (evidence_dao == NULL) goto cleanup;
|
||||||
|
identifiers = relation_evidence_dao_list_evidence_identifiers(
|
||||||
|
relation_evidence_dao, relation_identifier, &error);
|
||||||
|
if (identifiers == NULL) goto cleanup;
|
||||||
|
records = g_ptr_array_new_with_free_func((GDestroyNotify)
|
||||||
|
evidence_record_free);
|
||||||
|
if (records == NULL) goto cleanup;
|
||||||
|
for (guint index = 0; index < identifiers->len; index++)
|
||||||
|
{
|
||||||
|
EvidenceRecord *record = evidence_dao_find_by_identifier(evidence_dao,
|
||||||
|
g_ptr_array_index(identifiers, index), &error);
|
||||||
|
if (record == NULL) goto cleanup;
|
||||||
|
g_ptr_array_add(records, record);
|
||||||
|
}
|
||||||
|
main_window_set_relation_evidences(application->main_window, records);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_warning("Impossible de charger les preuves de la relation : %s",
|
||||||
|
error->message);
|
||||||
|
main_window_set_relation_evidences(application->main_window, NULL);
|
||||||
|
}
|
||||||
|
g_clear_error(&error);
|
||||||
|
g_clear_pointer(&records, g_ptr_array_unref);
|
||||||
|
g_clear_pointer(&identifiers, g_ptr_array_unref);
|
||||||
|
evidence_dao_free(evidence_dao);
|
||||||
|
relation_evidence_dao_free(relation_evidence_dao);
|
||||||
|
}
|
||||||
|
|
||||||
static void application_on_add_relation_requested(
|
static void application_on_add_relation_requested(
|
||||||
const char *source_entity_identifier,
|
const char *source_entity_identifier,
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
|
|
@ -5140,8 +5250,12 @@ static void application_on_add_relation_requested(
|
||||||
EntityDao *entity_dao =
|
EntityDao *entity_dao =
|
||||||
NULL;
|
NULL;
|
||||||
|
|
||||||
|
EvidenceDao *evidence_dao = NULL;
|
||||||
|
const InvestigationProject *project = NULL;
|
||||||
|
|
||||||
GPtrArray *entities =
|
GPtrArray *entities =
|
||||||
NULL;
|
NULL;
|
||||||
|
GPtrArray *evidences = NULL;
|
||||||
|
|
||||||
GError *error =
|
GError *error =
|
||||||
NULL;
|
NULL;
|
||||||
|
|
@ -5161,6 +5275,7 @@ static void application_on_add_relation_requested(
|
||||||
investigation_session_get_database(
|
investigation_session_get_database(
|
||||||
application->session
|
application->session
|
||||||
);
|
);
|
||||||
|
project = investigation_session_get_project(application->session);
|
||||||
|
|
||||||
if (database == NULL)
|
if (database == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -5202,11 +5317,16 @@ static void application_on_add_relation_requested(
|
||||||
&error
|
&error
|
||||||
);
|
);
|
||||||
|
|
||||||
|
evidence_dao = evidence_dao_new(database, &error);
|
||||||
|
if (evidence_dao != NULL)
|
||||||
|
evidences = evidence_dao_list_all(evidence_dao, &error);
|
||||||
|
evidence_dao_free(evidence_dao);
|
||||||
|
|
||||||
entity_dao_free(
|
entity_dao_free(
|
||||||
entity_dao
|
entity_dao
|
||||||
);
|
);
|
||||||
|
|
||||||
if (entities == NULL)
|
if (entities == NULL || evidences == NULL || project == NULL)
|
||||||
{
|
{
|
||||||
application_present_error(
|
application_present_error(
|
||||||
application,
|
application,
|
||||||
|
|
@ -5220,6 +5340,9 @@ static void application_on_add_relation_requested(
|
||||||
&error
|
&error
|
||||||
);
|
);
|
||||||
|
|
||||||
|
g_clear_pointer(&entities, g_ptr_array_unref);
|
||||||
|
g_clear_pointer(&evidences, g_ptr_array_unref);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5229,6 +5352,8 @@ static void application_on_add_relation_requested(
|
||||||
),
|
),
|
||||||
source_entity_identifier,
|
source_entity_identifier,
|
||||||
entities,
|
entities,
|
||||||
|
evidences,
|
||||||
|
investigation_project_get_root_path(project),
|
||||||
application_on_create_relation_completed,
|
application_on_create_relation_completed,
|
||||||
application,
|
application,
|
||||||
&error
|
&error
|
||||||
|
|
@ -5250,6 +5375,7 @@ static void application_on_add_relation_requested(
|
||||||
g_ptr_array_unref(
|
g_ptr_array_unref(
|
||||||
entities
|
entities
|
||||||
);
|
);
|
||||||
|
g_ptr_array_unref(evidences);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -6544,6 +6670,8 @@ static void application_on_activate(
|
||||||
|
|
||||||
main_window_set_edit_relation_callback(application->main_window,
|
main_window_set_edit_relation_callback(application->main_window,
|
||||||
application_on_edit_relation_requested, application);
|
application_on_edit_relation_requested, application);
|
||||||
|
main_window_set_relation_selected_callback(application->main_window,
|
||||||
|
application_on_relation_selected, application);
|
||||||
main_window_set_person_role_callback(application->main_window,
|
main_window_set_person_role_callback(application->main_window,
|
||||||
application_on_person_role_changed, application);
|
application_on_person_role_changed, application);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "views/create_relation_dialog.h"
|
#include "views/create_relation_dialog.h"
|
||||||
|
|
||||||
#include "models/entity_record.h"
|
#include "models/entity_record.h"
|
||||||
|
#include "models/evidence_record.h"
|
||||||
#include "models/relation_record.h"
|
#include "models/relation_record.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
@ -21,10 +22,32 @@ struct CreateRelationDialogResult
|
||||||
char *relation_type;
|
char *relation_type;
|
||||||
char *label;
|
char *label;
|
||||||
char *justification;
|
char *justification;
|
||||||
|
GPtrArray *evidence_identifiers;
|
||||||
|
|
||||||
gint confidence;
|
gint confidence;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief Copie privée des données nécessaires à la sélection d'une preuve. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *identifier;
|
||||||
|
char *name;
|
||||||
|
char *type;
|
||||||
|
char *date;
|
||||||
|
char *sha256;
|
||||||
|
char *absolute_path;
|
||||||
|
} CreateRelationEvidenceOption;
|
||||||
|
|
||||||
|
/** @brief Libère une option de preuve. */
|
||||||
|
static void create_relation_evidence_option_free(gpointer data)
|
||||||
|
{
|
||||||
|
CreateRelationEvidenceOption *option = data;
|
||||||
|
if (option == NULL) return;
|
||||||
|
g_free(option->identifier); g_free(option->name); g_free(option->type);
|
||||||
|
g_free(option->date); g_free(option->sha256); g_free(option->absolute_path);
|
||||||
|
g_free(option);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief État privé conservé pendant l'affichage du dialogue.
|
* @brief État privé conservé pendant l'affichage du dialogue.
|
||||||
*/
|
*/
|
||||||
|
|
@ -41,6 +64,13 @@ typedef struct
|
||||||
|
|
||||||
char *source_entity_identifier;
|
char *source_entity_identifier;
|
||||||
GPtrArray *target_identifiers;
|
GPtrArray *target_identifiers;
|
||||||
|
GPtrArray *evidence_options;
|
||||||
|
GPtrArray *evidence_check_buttons;
|
||||||
|
GtkWidget *evidence_preview_stack;
|
||||||
|
GtkWidget *evidence_preview_status;
|
||||||
|
GtkWidget *evidence_preview_picture;
|
||||||
|
GtkWidget *evidence_preview_video;
|
||||||
|
GtkWidget *evidence_metadata_label;
|
||||||
|
|
||||||
CreateRelationDialogCallback callback;
|
CreateRelationDialogCallback callback;
|
||||||
gpointer callback_data;
|
gpointer callback_data;
|
||||||
|
|
@ -263,6 +293,75 @@ static void create_relation_dialog_show_error(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Arrête la vidéo utilisée par l'aperçu des preuves. */
|
||||||
|
static void create_relation_dialog_clear_preview(
|
||||||
|
CreateRelationDialogState *state)
|
||||||
|
{
|
||||||
|
GtkMediaStream *stream = NULL;
|
||||||
|
if (state == NULL || state->evidence_preview_video == NULL ||
|
||||||
|
state->evidence_preview_picture == NULL) return;
|
||||||
|
stream = gtk_video_get_media_stream(GTK_VIDEO(
|
||||||
|
state->evidence_preview_video));
|
||||||
|
if (stream != NULL) gtk_media_stream_pause(stream);
|
||||||
|
gtk_video_set_media_stream(GTK_VIDEO(state->evidence_preview_video), NULL);
|
||||||
|
gtk_picture_set_paintable(GTK_PICTURE(
|
||||||
|
state->evidence_preview_picture), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Affiche la preuve dont la case vient d'être manipulée. */
|
||||||
|
static void create_relation_dialog_on_evidence_toggled(GtkCheckButton *button,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CreateRelationDialogState *state = user_data;
|
||||||
|
CreateRelationEvidenceOption *option = g_object_get_data(
|
||||||
|
G_OBJECT(button), "relation-evidence-option");
|
||||||
|
GFile *file = NULL;
|
||||||
|
GFileInfo *info = NULL;
|
||||||
|
const char *content_type = NULL;
|
||||||
|
char *mime = NULL;
|
||||||
|
char *metadata = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
if (state == NULL || option == NULL) return;
|
||||||
|
create_relation_dialog_clear_preview(state);
|
||||||
|
metadata = g_strdup_printf("%s\nType : %s\nDate : %s\nSHA-256 : %s",
|
||||||
|
option->name, option->type, option->date, option->sha256);
|
||||||
|
gtk_label_set_text(GTK_LABEL(state->evidence_metadata_label), metadata);
|
||||||
|
g_free(metadata);
|
||||||
|
if (option->absolute_path == NULL) goto unsupported;
|
||||||
|
file = g_file_new_for_path(option->absolute_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 = g_content_type_get_mime_type(content_type);
|
||||||
|
if (mime != NULL && g_str_has_prefix(mime, "image/"))
|
||||||
|
{
|
||||||
|
gtk_picture_set_filename(GTK_PICTURE(state->evidence_preview_picture),
|
||||||
|
option->absolute_path);
|
||||||
|
gtk_stack_set_visible_child_name(GTK_STACK(
|
||||||
|
state->evidence_preview_stack), "image");
|
||||||
|
}
|
||||||
|
else if (mime != NULL && g_str_has_prefix(mime, "video/"))
|
||||||
|
{
|
||||||
|
GtkMediaStream *stream = gtk_media_file_new_for_filename(
|
||||||
|
option->absolute_path);
|
||||||
|
gtk_video_set_media_stream(GTK_VIDEO(state->evidence_preview_video),
|
||||||
|
stream);
|
||||||
|
g_object_unref(stream);
|
||||||
|
gtk_stack_set_visible_child_name(GTK_STACK(
|
||||||
|
state->evidence_preview_stack), "video");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsupported:
|
||||||
|
gtk_label_set_text(GTK_LABEL(state->evidence_preview_status),
|
||||||
|
"Aperçu indisponible pour ce format.");
|
||||||
|
gtk_stack_set_visible_child_name(GTK_STACK(
|
||||||
|
state->evidence_preview_stack), "status");
|
||||||
|
}
|
||||||
|
g_clear_error(&error); g_free(mime);
|
||||||
|
g_clear_object(&info); g_clear_object(&file);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Libère l'état privé du dialogue.
|
* @brief Libère l'état privé du dialogue.
|
||||||
*/
|
*/
|
||||||
|
|
@ -282,6 +381,9 @@ static void create_relation_dialog_state_free(
|
||||||
&state->target_identifiers,
|
&state->target_identifiers,
|
||||||
g_ptr_array_unref
|
g_ptr_array_unref
|
||||||
);
|
);
|
||||||
|
create_relation_dialog_clear_preview(state);
|
||||||
|
g_clear_pointer(&state->evidence_options, g_ptr_array_unref);
|
||||||
|
g_clear_pointer(&state->evidence_check_buttons, g_ptr_array_unref);
|
||||||
|
|
||||||
g_free(
|
g_free(
|
||||||
state->source_entity_identifier
|
state->source_entity_identifier
|
||||||
|
|
@ -529,13 +631,32 @@ static void create_relation_dialog_on_create_clicked(
|
||||||
result->confidence =
|
result->confidence =
|
||||||
confidence;
|
confidence;
|
||||||
|
|
||||||
|
result->evidence_identifiers = g_ptr_array_new_with_free_func(g_free);
|
||||||
|
if (result->evidence_identifiers != NULL)
|
||||||
|
{
|
||||||
|
guint evidence_index = 0;
|
||||||
|
for (evidence_index = 0;
|
||||||
|
evidence_index < state->evidence_check_buttons->len;
|
||||||
|
evidence_index++)
|
||||||
|
{
|
||||||
|
GtkCheckButton *check_button = g_ptr_array_index(
|
||||||
|
state->evidence_check_buttons, evidence_index);
|
||||||
|
CreateRelationEvidenceOption *option = g_object_get_data(
|
||||||
|
G_OBJECT(check_button), "relation-evidence-option");
|
||||||
|
if (gtk_check_button_get_active(check_button) && option != NULL)
|
||||||
|
g_ptr_array_add(result->evidence_identifiers,
|
||||||
|
g_strdup(option->identifier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_free(
|
g_free(
|
||||||
justification_text
|
justification_text
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result->source_entity_identifier == NULL ||
|
if (result->source_entity_identifier == NULL ||
|
||||||
result->target_entity_identifier == NULL ||
|
result->target_entity_identifier == NULL ||
|
||||||
result->relation_type == NULL)
|
result->relation_type == NULL ||
|
||||||
|
result->evidence_identifiers == NULL)
|
||||||
{
|
{
|
||||||
create_relation_dialog_result_free(
|
create_relation_dialog_result_free(
|
||||||
result
|
result
|
||||||
|
|
@ -689,6 +810,9 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
const char *source_entity_identifier,
|
const char *source_entity_identifier,
|
||||||
const RelationRecord *existing_relation,
|
const RelationRecord *existing_relation,
|
||||||
const GPtrArray *entities,
|
const GPtrArray *entities,
|
||||||
|
const GPtrArray *evidence_records,
|
||||||
|
const GPtrArray *selected_evidence_identifiers,
|
||||||
|
const char *investigation_root_path,
|
||||||
CreateRelationDialogCallback callback,
|
CreateRelationDialogCallback callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
GError **error
|
GError **error
|
||||||
|
|
@ -733,6 +857,12 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
GtkWidget *justification_scrolled_window =
|
GtkWidget *justification_scrolled_window =
|
||||||
NULL;
|
NULL;
|
||||||
|
|
||||||
|
GtkWidget *evidence_box = NULL;
|
||||||
|
GtkWidget *evidence_list = NULL;
|
||||||
|
GtkWidget *evidence_list_scrolled = NULL;
|
||||||
|
GtkWidget *evidence_preview_box = NULL;
|
||||||
|
GtkWidget *evidence_title = NULL;
|
||||||
|
|
||||||
GtkWidget *button_box =
|
GtkWidget *button_box =
|
||||||
NULL;
|
NULL;
|
||||||
|
|
||||||
|
|
@ -764,7 +894,8 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
!g_uuid_string_is_valid(
|
!g_uuid_string_is_valid(
|
||||||
source_entity_identifier
|
source_entity_identifier
|
||||||
) ||
|
) ||
|
||||||
entities == NULL ||
|
entities == NULL || evidence_records == NULL ||
|
||||||
|
investigation_root_path == NULL ||
|
||||||
callback == NULL)
|
callback == NULL)
|
||||||
{
|
{
|
||||||
g_set_error_literal(
|
g_set_error_literal(
|
||||||
|
|
@ -804,6 +935,10 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
g_ptr_array_new_with_free_func(
|
g_ptr_array_new_with_free_func(
|
||||||
g_free
|
g_free
|
||||||
);
|
);
|
||||||
|
state->evidence_options = g_ptr_array_new_with_free_func(
|
||||||
|
create_relation_evidence_option_free);
|
||||||
|
state->evidence_check_buttons = g_ptr_array_new_with_free_func(
|
||||||
|
g_object_unref);
|
||||||
|
|
||||||
state->callback =
|
state->callback =
|
||||||
callback;
|
callback;
|
||||||
|
|
@ -817,7 +952,8 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
);
|
);
|
||||||
|
|
||||||
if (state->source_entity_identifier == NULL ||
|
if (state->source_entity_identifier == NULL ||
|
||||||
state->target_identifiers == NULL ||
|
state->target_identifiers == NULL || state->evidence_options == NULL ||
|
||||||
|
state->evidence_check_buttons == NULL ||
|
||||||
target_labels == NULL)
|
target_labels == NULL)
|
||||||
{
|
{
|
||||||
g_clear_object(
|
g_clear_object(
|
||||||
|
|
@ -976,6 +1112,43 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (guint evidence_index = 0; evidence_index < evidence_records->len;
|
||||||
|
evidence_index++)
|
||||||
|
{
|
||||||
|
const EvidenceRecord *record = g_ptr_array_index(evidence_records,
|
||||||
|
evidence_index);
|
||||||
|
CreateRelationEvidenceOption *option = NULL;
|
||||||
|
char *candidate = NULL;
|
||||||
|
char *canonical_root = NULL;
|
||||||
|
char *canonical_path = NULL;
|
||||||
|
const char *date = NULL;
|
||||||
|
if (record == NULL) continue;
|
||||||
|
option = g_try_new0(CreateRelationEvidenceOption, 1);
|
||||||
|
if (option == NULL) continue;
|
||||||
|
option->identifier = g_strdup(evidence_record_get_identifier(record));
|
||||||
|
option->name = g_strdup(evidence_record_get_original_name(record));
|
||||||
|
option->type = g_strdup(evidence_record_get_type_identifier(record));
|
||||||
|
date = evidence_record_get_collected_at(record);
|
||||||
|
if (date == NULL) date = evidence_record_get_imported_at(record);
|
||||||
|
option->date = g_strdup(date != NULL ? date : "Date inconnue");
|
||||||
|
option->sha256 = g_strdup(evidence_record_get_sha256(record));
|
||||||
|
candidate = g_build_filename(investigation_root_path,
|
||||||
|
evidence_record_get_relative_path(record), NULL);
|
||||||
|
canonical_root = g_canonicalize_filename(investigation_root_path, NULL);
|
||||||
|
canonical_path = g_canonicalize_filename(candidate, NULL);
|
||||||
|
if (canonical_root != NULL && canonical_path != NULL &&
|
||||||
|
g_str_has_prefix(canonical_path, canonical_root) &&
|
||||||
|
(canonical_path[strlen(canonical_root)] == G_DIR_SEPARATOR ||
|
||||||
|
canonical_path[strlen(canonical_root)] == '\0'))
|
||||||
|
option->absolute_path = g_strdup(canonical_path);
|
||||||
|
g_free(canonical_path); g_free(canonical_root); g_free(candidate);
|
||||||
|
if (option->identifier == NULL || option->name == NULL ||
|
||||||
|
option->type == NULL || option->sha256 == NULL)
|
||||||
|
create_relation_evidence_option_free(option);
|
||||||
|
else
|
||||||
|
g_ptr_array_add(state->evidence_options, option);
|
||||||
|
}
|
||||||
|
|
||||||
state->window =
|
state->window =
|
||||||
GTK_WINDOW(
|
GTK_WINDOW(
|
||||||
gtk_window_new()
|
gtk_window_new()
|
||||||
|
|
@ -1005,8 +1178,8 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
|
|
||||||
gtk_window_set_default_size(
|
gtk_window_set_default_size(
|
||||||
state->window,
|
state->window,
|
||||||
640,
|
920,
|
||||||
560
|
780
|
||||||
);
|
);
|
||||||
|
|
||||||
root_box =
|
root_box =
|
||||||
|
|
@ -1299,6 +1472,73 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
|
evidence_title = gtk_label_new("Pièces jointes à la relation");
|
||||||
|
gtk_label_set_xalign(GTK_LABEL(evidence_title), 0.0F);
|
||||||
|
evidence_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
|
||||||
|
evidence_list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
|
||||||
|
evidence_list_scrolled = gtk_scrolled_window_new();
|
||||||
|
gtk_widget_set_size_request(evidence_list_scrolled, 360, 240);
|
||||||
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(evidence_list_scrolled),
|
||||||
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||||
|
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(evidence_list_scrolled),
|
||||||
|
evidence_list);
|
||||||
|
for (guint evidence_index = 0;
|
||||||
|
evidence_index < state->evidence_options->len; evidence_index++)
|
||||||
|
{
|
||||||
|
CreateRelationEvidenceOption *option = g_ptr_array_index(
|
||||||
|
state->evidence_options, evidence_index);
|
||||||
|
char *display = g_strdup_printf("%s — %s — %s", option->name,
|
||||||
|
option->type, option->date);
|
||||||
|
GtkWidget *check = gtk_check_button_new_with_label(display);
|
||||||
|
gboolean active = FALSE;
|
||||||
|
g_free(display);
|
||||||
|
if (selected_evidence_identifiers != NULL)
|
||||||
|
for (guint selected_index = 0;
|
||||||
|
selected_index < selected_evidence_identifiers->len;
|
||||||
|
selected_index++)
|
||||||
|
if (g_strcmp0(option->identifier, g_ptr_array_index(
|
||||||
|
selected_evidence_identifiers, selected_index)) == 0)
|
||||||
|
active = TRUE;
|
||||||
|
gtk_check_button_set_active(GTK_CHECK_BUTTON(check), active);
|
||||||
|
g_object_set_data(G_OBJECT(check), "relation-evidence-option", option);
|
||||||
|
g_signal_connect(check, "toggled", G_CALLBACK(
|
||||||
|
create_relation_dialog_on_evidence_toggled), state);
|
||||||
|
gtk_box_append(GTK_BOX(evidence_list), check);
|
||||||
|
g_ptr_array_add(state->evidence_check_buttons, g_object_ref(check));
|
||||||
|
}
|
||||||
|
if (state->evidence_options->len == 0)
|
||||||
|
gtk_box_append(GTK_BOX(evidence_list), gtk_label_new(
|
||||||
|
"Aucune preuve enregistrée dans l’enquête."));
|
||||||
|
|
||||||
|
evidence_preview_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
|
||||||
|
gtk_widget_set_hexpand(evidence_preview_box, TRUE);
|
||||||
|
state->evidence_metadata_label = gtk_label_new(
|
||||||
|
"Sélectionnez une preuve pour afficher son aperçu.");
|
||||||
|
gtk_label_set_xalign(GTK_LABEL(state->evidence_metadata_label), 0.0F);
|
||||||
|
gtk_label_set_wrap(GTK_LABEL(state->evidence_metadata_label), TRUE);
|
||||||
|
gtk_label_set_selectable(GTK_LABEL(state->evidence_metadata_label), TRUE);
|
||||||
|
state->evidence_preview_stack = gtk_stack_new();
|
||||||
|
gtk_widget_set_size_request(state->evidence_preview_stack, 420, 220);
|
||||||
|
state->evidence_preview_status = gtk_label_new("Aucun aperçu.");
|
||||||
|
state->evidence_preview_picture = gtk_picture_new();
|
||||||
|
gtk_picture_set_content_fit(GTK_PICTURE(state->evidence_preview_picture),
|
||||||
|
GTK_CONTENT_FIT_CONTAIN);
|
||||||
|
state->evidence_preview_video = gtk_video_new();
|
||||||
|
gtk_video_set_autoplay(GTK_VIDEO(state->evidence_preview_video), FALSE);
|
||||||
|
gtk_stack_add_named(GTK_STACK(state->evidence_preview_stack),
|
||||||
|
state->evidence_preview_status, "status");
|
||||||
|
gtk_stack_add_named(GTK_STACK(state->evidence_preview_stack),
|
||||||
|
state->evidence_preview_picture, "image");
|
||||||
|
gtk_stack_add_named(GTK_STACK(state->evidence_preview_stack),
|
||||||
|
state->evidence_preview_video, "video");
|
||||||
|
gtk_box_append(GTK_BOX(evidence_preview_box),
|
||||||
|
state->evidence_metadata_label);
|
||||||
|
gtk_box_append(GTK_BOX(evidence_preview_box), state->evidence_preview_stack);
|
||||||
|
gtk_box_append(GTK_BOX(evidence_box), evidence_list_scrolled);
|
||||||
|
gtk_box_append(GTK_BOX(evidence_box), evidence_preview_box);
|
||||||
|
gtk_grid_attach(GTK_GRID(grid), evidence_title, 0, 5, 2, 1);
|
||||||
|
gtk_grid_attach(GTK_GRID(grid), evidence_box, 0, 6, 2, 1);
|
||||||
|
|
||||||
gtk_grid_attach(
|
gtk_grid_attach(
|
||||||
GTK_GRID(
|
GTK_GRID(
|
||||||
grid
|
grid
|
||||||
|
|
@ -1582,14 +1822,19 @@ static gboolean create_relation_dialog_present_internal(
|
||||||
|
|
||||||
gboolean create_relation_dialog_present(GtkWindow *parent,
|
gboolean create_relation_dialog_present(GtkWindow *parent,
|
||||||
const char *source_entity_identifier, const GPtrArray *entities,
|
const char *source_entity_identifier, const GPtrArray *entities,
|
||||||
|
const GPtrArray *evidence_records, const char *investigation_root_path,
|
||||||
CreateRelationDialogCallback callback, gpointer user_data, GError **error)
|
CreateRelationDialogCallback callback, gpointer user_data, GError **error)
|
||||||
{
|
{
|
||||||
return create_relation_dialog_present_internal(parent,
|
return create_relation_dialog_present_internal(parent,
|
||||||
source_entity_identifier, NULL, entities, callback, user_data, error);
|
source_entity_identifier, NULL, entities, evidence_records, NULL,
|
||||||
|
investigation_root_path, callback, user_data, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean edit_relation_dialog_present(GtkWindow *parent,
|
gboolean edit_relation_dialog_present(GtkWindow *parent,
|
||||||
const RelationRecord *relation_record, const GPtrArray *entities,
|
const RelationRecord *relation_record, const GPtrArray *entities,
|
||||||
|
const GPtrArray *evidence_records,
|
||||||
|
const GPtrArray *selected_evidence_identifiers,
|
||||||
|
const char *investigation_root_path,
|
||||||
CreateRelationDialogCallback callback, gpointer user_data, GError **error)
|
CreateRelationDialogCallback callback, gpointer user_data, GError **error)
|
||||||
{
|
{
|
||||||
if (relation_record == NULL)
|
if (relation_record == NULL)
|
||||||
|
|
@ -1601,7 +1846,9 @@ gboolean edit_relation_dialog_present(GtkWindow *parent,
|
||||||
}
|
}
|
||||||
return create_relation_dialog_present_internal(parent,
|
return create_relation_dialog_present_internal(parent,
|
||||||
relation_record_get_source_entity_identifier(relation_record),
|
relation_record_get_source_entity_identifier(relation_record),
|
||||||
relation_record, entities, callback, user_data, error);
|
relation_record, entities, evidence_records,
|
||||||
|
selected_evidence_identifiers, investigation_root_path,
|
||||||
|
callback, user_data, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_relation_dialog_result_free(
|
void create_relation_dialog_result_free(
|
||||||
|
|
@ -1633,11 +1880,19 @@ void create_relation_dialog_result_free(
|
||||||
result->source_entity_identifier
|
result->source_entity_identifier
|
||||||
);
|
);
|
||||||
|
|
||||||
|
g_clear_pointer(&result->evidence_identifiers, g_ptr_array_unref);
|
||||||
|
|
||||||
g_free(
|
g_free(
|
||||||
result
|
result
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GPtrArray *create_relation_dialog_result_get_evidence_identifiers(
|
||||||
|
const CreateRelationDialogResult *result)
|
||||||
|
{
|
||||||
|
return result != NULL ? result->evidence_identifiers : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const char *create_relation_dialog_result_get_source_identifier(
|
const char *create_relation_dialog_result_get_source_identifier(
|
||||||
const CreateRelationDialogResult *result
|
const CreateRelationDialogResult *result
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1672,6 +1672,21 @@ void main_window_set_edit_relation_callback(MainWindow *main_window,
|
||||||
main_window->edit_relation_user_data = user_data;
|
main_window->edit_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,
|
void main_window_set_person_role_callback(MainWindow *main_window,
|
||||||
MainWindowPersonRoleCallback callback, gpointer user_data)
|
MainWindowPersonRoleCallback callback, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ struct Workspace
|
||||||
GtkWidget *relation_details_panel;
|
GtkWidget *relation_details_panel;
|
||||||
GtkWidget *relation_details_title_label;
|
GtkWidget *relation_details_title_label;
|
||||||
GtkWidget *relation_details_summary_label;
|
GtkWidget *relation_details_summary_label;
|
||||||
|
GtkWidget *relation_evidences_label;
|
||||||
GtkWidget *edit_relation_button;
|
GtkWidget *edit_relation_button;
|
||||||
GtkWidget *close_relation_details_button;
|
GtkWidget *close_relation_details_button;
|
||||||
char *selected_relation_identifier;
|
char *selected_relation_identifier;
|
||||||
|
|
@ -130,6 +131,8 @@ struct Workspace
|
||||||
add_relation_user_data;
|
add_relation_user_data;
|
||||||
|
|
||||||
WorkspaceEditRelationCallback edit_relation_callback;
|
WorkspaceEditRelationCallback edit_relation_callback;
|
||||||
|
WorkspaceRelationSelectedCallback relation_selected_callback;
|
||||||
|
gpointer relation_selected_user_data;
|
||||||
gpointer edit_relation_user_data;
|
gpointer edit_relation_user_data;
|
||||||
WorkspacePersonRoleCallback person_role_callback;
|
WorkspacePersonRoleCallback person_role_callback;
|
||||||
gpointer person_role_user_data;
|
gpointer person_role_user_data;
|
||||||
|
|
@ -804,6 +807,11 @@ static void workspace_on_graph_node_selected(
|
||||||
summary != NULL ? summary : "Informations indisponibles"
|
summary != NULL ? summary : "Informations indisponibles"
|
||||||
);
|
);
|
||||||
g_free(summary);
|
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_update_osint_tools_menu(
|
||||||
|
|
@ -1677,6 +1685,8 @@ Workspace *workspace_new(void)
|
||||||
);
|
);
|
||||||
workspace->relation_details_title_label = gtk_label_new(NULL);
|
workspace->relation_details_title_label = gtk_label_new(NULL);
|
||||||
workspace->relation_details_summary_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->edit_relation_button = gtk_button_new_with_label("Modifier");
|
||||||
workspace->close_relation_details_button =
|
workspace->close_relation_details_button =
|
||||||
gtk_button_new_from_icon_name("window-close-symbolic");
|
gtk_button_new_from_icon_name("window-close-symbolic");
|
||||||
|
|
@ -1686,6 +1696,7 @@ Workspace *workspace_new(void)
|
||||||
workspace->relation_details_panel == NULL ||
|
workspace->relation_details_panel == NULL ||
|
||||||
workspace->relation_details_title_label == NULL ||
|
workspace->relation_details_title_label == NULL ||
|
||||||
workspace->relation_details_summary_label == NULL ||
|
workspace->relation_details_summary_label == NULL ||
|
||||||
|
workspace->relation_evidences_label == NULL ||
|
||||||
workspace->edit_relation_button == NULL ||
|
workspace->edit_relation_button == NULL ||
|
||||||
workspace->close_relation_details_button == NULL)
|
workspace->close_relation_details_button == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -1732,6 +1743,13 @@ Workspace *workspace_new(void)
|
||||||
GTK_LABEL(workspace->relation_details_summary_label),
|
GTK_LABEL(workspace->relation_details_summary_label),
|
||||||
TRUE
|
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_append(
|
||||||
GTK_BOX(workspace->relation_details_panel),
|
GTK_BOX(workspace->relation_details_panel),
|
||||||
workspace->relation_details_title_label
|
workspace->relation_details_title_label
|
||||||
|
|
@ -1745,6 +1763,8 @@ Workspace *workspace_new(void)
|
||||||
GTK_BOX(workspace->relation_details_panel),
|
GTK_BOX(workspace->relation_details_panel),
|
||||||
workspace->relation_details_summary_label
|
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),
|
gtk_box_append(GTK_BOX(workspace->relation_details_panel),
|
||||||
workspace->edit_relation_button);
|
workspace->edit_relation_button);
|
||||||
g_signal_connect(workspace->edit_relation_button, "clicked",
|
g_signal_connect(workspace->edit_relation_button, "clicked",
|
||||||
|
|
@ -3195,6 +3215,41 @@ void workspace_set_edit_relation_callback(Workspace *workspace,
|
||||||
workspace->edit_relation_user_data = user_data;
|
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,
|
void workspace_set_person_role_callback(Workspace *workspace,
|
||||||
WorkspacePersonRoleCallback callback, gpointer user_data)
|
WorkspacePersonRoleCallback callback, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue