feat: display categorized evidence in sidebar
This commit is contained in:
parent
18566280a7
commit
5d87b35242
20 changed files with 6208 additions and 24 deletions
44
Makefile
44
Makefile
|
|
@ -70,6 +70,10 @@ TEST_EVIDENCE_IMPORT_TASK := tests/test_evidence_import_task
|
|||
TEST_EVIDENCE_TYPE := tests/test_evidence_type
|
||||
TEST_EVIDENCE_TYPE_DAO := tests/test_evidence_type_dao
|
||||
TEST_EVIDENCE_IMPORT_DIALOG := tests/test_evidence_import_dialog
|
||||
TEST_EVIDENCE_LIST_ITEM := tests/test_evidence_list_item
|
||||
TEST_EVIDENCE_LIST_MODEL := tests/test_evidence_list_model
|
||||
TEST_EVIDENCE_CATEGORY_ITEM := tests/test_evidence_category_item
|
||||
TEST_EVIDENCE_CATEGORY_MODEL := tests/test_evidence_category_model
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
|
|
@ -149,6 +153,19 @@ $(TEST_EVIDENCE_RECORD): \
|
|||
src/models/evidence_record.c
|
||||
$(CC) $(EVIDENCE_RECORD_TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||
|
||||
$(TEST_EVIDENCE_LIST_ITEM): \
|
||||
tests/test_evidence_list_item.c \
|
||||
src/widgets/evidence_list_item.c \
|
||||
src/models/evidence_record.c
|
||||
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||
|
||||
$(TEST_EVIDENCE_LIST_MODEL): \
|
||||
tests/test_evidence_list_model.c \
|
||||
src/widgets/evidence_list_model.c \
|
||||
src/widgets/evidence_list_item.c \
|
||||
src/models/evidence_record.c
|
||||
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||
|
||||
$(TEST_INVESTIGATION_DAO): \
|
||||
tests/test_investigation_dao.c \
|
||||
src/dao/investigation_dao.c \
|
||||
|
|
@ -304,6 +321,21 @@ $(TEST_EVIDENCE_IMPORT_DIALOG): \
|
|||
-o $@ \
|
||||
$(EVIDENCE_IMPORT_DIALOG_TEST_LDFLAGS)
|
||||
|
||||
$(TEST_EVIDENCE_CATEGORY_ITEM): \
|
||||
tests/test_evidence_category_item.c \
|
||||
src/widgets/evidence_category_item.c \
|
||||
src/widgets/evidence_list_item.c \
|
||||
src/models/evidence_record.c
|
||||
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||
|
||||
$(TEST_EVIDENCE_CATEGORY_MODEL): \
|
||||
tests/test_evidence_category_model.c \
|
||||
src/widgets/evidence_category_model.c \
|
||||
src/widgets/evidence_category_item.c \
|
||||
src/widgets/evidence_list_item.c \
|
||||
src/models/evidence_record.c
|
||||
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||
|
||||
test: \
|
||||
$(TEST_NODE) \
|
||||
$(TEST_TREE_MODEL) \
|
||||
|
|
@ -315,6 +347,10 @@ test: \
|
|||
$(TEST_ERROR) \
|
||||
$(TEST_INVESTIGATION_RECORD) \
|
||||
$(TEST_EVIDENCE_RECORD) \
|
||||
$(TEST_EVIDENCE_LIST_ITEM) \
|
||||
$(TEST_EVIDENCE_LIST_MODEL) \
|
||||
$(TEST_EVIDENCE_CATEGORY_ITEM) \
|
||||
$(TEST_EVIDENCE_CATEGORY_MODEL) \
|
||||
$(TEST_EVIDENCE_TYPE) \
|
||||
$(TEST_INVESTIGATION_DAO) \
|
||||
$(TEST_EVIDENCE_DAO) \
|
||||
|
|
@ -342,6 +378,10 @@ test: \
|
|||
@$(TEST_TRANSACTION)
|
||||
@$(TEST_ERROR)
|
||||
@$(TEST_INVESTIGATION_RECORD)
|
||||
@$(TEST_EVIDENCE_LIST_ITEM)
|
||||
@$(TEST_EVIDENCE_LIST_MODEL)
|
||||
@$(TEST_EVIDENCE_CATEGORY_ITEM)
|
||||
@$(TEST_EVIDENCE_CATEGORY_MODEL)
|
||||
@$(TEST_EVIDENCE_RECORD)
|
||||
@$(TEST_EVIDENCE_TYPE)
|
||||
@$(TEST_INVESTIGATION_DAO)
|
||||
|
|
@ -380,6 +420,10 @@ clean:
|
|||
$(TEST_ERROR) \
|
||||
$(TEST_INVESTIGATION_RECORD) \
|
||||
$(TEST_EVIDENCE_RECORD) \
|
||||
$(TEST_EVIDENCE_LIST_ITEM) \
|
||||
$(TEST_EVIDENCE_LIST_MODEL) \
|
||||
$(TEST_EVIDENCE_CATEGORY_ITEM) \
|
||||
$(TEST_EVIDENCE_CATEGORY_MODEL) \
|
||||
$(TEST_EVIDENCE_TYPE) \
|
||||
$(TEST_EVIDENCE_TYPE_DAO) \
|
||||
$(TEST_INVESTIGATION_DAO) \
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "widgets/investigation_tree_view.h"
|
||||
#include "core/investigation_node.h"
|
||||
#include "core/task_manager.h"
|
||||
#include "widgets/evidence_category_model.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
|
@ -37,6 +38,20 @@ typedef void (*MainWindowImportEvidenceCallback)(
|
|||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Callback appelé lorsqu'une preuve est sélectionnée.
|
||||
*
|
||||
* L'identifiant est emprunté et uniquement valide pendant l'appel.
|
||||
* Une sélection vide ou une catégorie transmet NULL.
|
||||
*
|
||||
* @param evidence_identifier UUID de la preuve, ou NULL.
|
||||
* @param user_data Données privées fournies par l'appelant.
|
||||
*/
|
||||
typedef void (*MainWindowEvidenceSelectionCallback)(
|
||||
const char *evidence_identifier,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Définit le callback du bouton « Nouvelle enquête ».
|
||||
*
|
||||
|
|
@ -100,6 +115,22 @@ void main_window_set_tree_model(
|
|||
const InvestigationTreeModel *tree_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Transmet le modèle des catégories de preuves à la Sidebar.
|
||||
*
|
||||
* MainWindow ne devient pas propriétaire du modèle.
|
||||
* Le modèle doit rester valide pendant son affichage.
|
||||
*
|
||||
* Passer NULL vide l'onglet Preuves.
|
||||
*
|
||||
* @param main_window Fenêtre principale.
|
||||
* @param evidence_category_model Modèle de catégories, ou NULL.
|
||||
*/
|
||||
void main_window_set_evidence_model(
|
||||
MainWindow *main_window,
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Met à jour l'identité de l'enquête affichée.
|
||||
*
|
||||
|
|
@ -128,6 +159,21 @@ void main_window_set_tree_selection_callback(
|
|||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Définit le callback de sélection d'une preuve.
|
||||
*
|
||||
* MainWindow transmet uniquement le callback à la Sidebar.
|
||||
*
|
||||
* @param main_window Fenêtre principale.
|
||||
* @param callback Callback facultatif.
|
||||
* @param user_data Données privées transmises au callback.
|
||||
*/
|
||||
void main_window_set_evidence_selection_callback(
|
||||
MainWindow *main_window,
|
||||
MainWindowEvidenceSelectionCallback callback,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Affiche dans le Workspace les informations du nœud sélectionné.
|
||||
*
|
||||
|
|
|
|||
100
include/widgets/evidence_category_item.h
Normal file
100
include/widgets/evidence_category_item.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_category_item.h
|
||||
* @brief Catégorie GTK regroupant plusieurs preuves affichées.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LABFY_INVESTIGATION_EVIDENCE_CATEGORY_ITEM_H
|
||||
#define LABFY_INVESTIGATION_EVIDENCE_CATEGORY_ITEM_H
|
||||
|
||||
#include "widgets/evidence_list_item.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* @brief Type GObject de EvidenceCategoryItem.
|
||||
*/
|
||||
#define EVIDENCE_TYPE_CATEGORY_ITEM \
|
||||
(evidence_category_item_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE(
|
||||
EvidenceCategoryItem,
|
||||
evidence_category_item,
|
||||
EVIDENCE,
|
||||
CATEGORY_ITEM,
|
||||
GObject
|
||||
)
|
||||
|
||||
/**
|
||||
* @brief Crée une catégorie de preuves.
|
||||
*
|
||||
* Le code et le libellé sont copiés et nettoyés.
|
||||
*
|
||||
* @param type_identifier Code métier stable de la catégorie.
|
||||
* @param label Libellé destiné à l'utilisateur.
|
||||
*
|
||||
* @return Nouvelle catégorie, ou NULL.
|
||||
*/
|
||||
EvidenceCategoryItem *evidence_category_item_new(
|
||||
const char *type_identifier,
|
||||
const char *label
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Ajoute une preuve à la catégorie.
|
||||
*
|
||||
* La catégorie conserve sa propre référence sur evidence_list_item.
|
||||
*
|
||||
* @param evidence_category_item Catégorie cible.
|
||||
* @param evidence_list_item Preuve d'affichage à ajouter.
|
||||
*
|
||||
* @return TRUE en cas de succès.
|
||||
*/
|
||||
gboolean evidence_category_item_append(
|
||||
EvidenceCategoryItem *evidence_category_item,
|
||||
EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le code métier de la catégorie.
|
||||
*
|
||||
* @return Chaîne empruntée, ou NULL.
|
||||
*/
|
||||
const char *evidence_category_item_get_type_identifier(
|
||||
const EvidenceCategoryItem *evidence_category_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le libellé utilisateur.
|
||||
*
|
||||
* @return Chaîne empruntée, ou NULL.
|
||||
*/
|
||||
const char *evidence_category_item_get_label(
|
||||
const EvidenceCategoryItem *evidence_category_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le nombre de preuves de la catégorie.
|
||||
*
|
||||
* @return Nombre de preuves, ou 0.
|
||||
*/
|
||||
guint evidence_category_item_get_count(
|
||||
const EvidenceCategoryItem *evidence_category_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le modèle contenant les preuves.
|
||||
*
|
||||
* La référence retournée est empruntée.
|
||||
*
|
||||
* @return GListModel emprunté, ou NULL.
|
||||
*/
|
||||
GListModel *evidence_category_item_get_children(
|
||||
EvidenceCategoryItem *evidence_category_item
|
||||
);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
128
include/widgets/evidence_category_model.h
Normal file
128
include/widgets/evidence_category_model.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_category_model.h
|
||||
* @brief Modèle GTK regroupant les preuves par catégorie.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LABFY_INVESTIGATION_EVIDENCE_CATEGORY_MODEL_H
|
||||
#define LABFY_INVESTIGATION_EVIDENCE_CATEGORY_MODEL_H
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* @brief Modèle opaque contenant des EvidenceCategoryItem.
|
||||
*/
|
||||
typedef struct EvidenceCategoryModel EvidenceCategoryModel;
|
||||
|
||||
/**
|
||||
* @brief Codes d'erreur produits par EvidenceCategoryModel.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/**
|
||||
* Un argument public est invalide.
|
||||
*/
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_INVALID_ARGUMENT,
|
||||
|
||||
/**
|
||||
* Le modèle contient un élément invalide.
|
||||
*/
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_INVALID_ITEM,
|
||||
|
||||
/**
|
||||
* Une catégorie n'a pas pu être créée.
|
||||
*/
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_CATEGORY,
|
||||
|
||||
/**
|
||||
* Une allocation a échoué.
|
||||
*/
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_MEMORY
|
||||
} EvidenceCategoryModelError;
|
||||
|
||||
/**
|
||||
* @brief Domaine d'erreur du modèle de catégories.
|
||||
*/
|
||||
#define EVIDENCE_CATEGORY_MODEL_ERROR \
|
||||
evidence_category_model_error_quark()
|
||||
|
||||
/**
|
||||
* @brief Retourne le domaine d'erreur du module.
|
||||
*
|
||||
* @return Quark associé à EvidenceCategoryModel.
|
||||
*/
|
||||
GQuark evidence_category_model_error_quark(void);
|
||||
|
||||
/**
|
||||
* @brief Crée un modèle de catégories vide.
|
||||
*
|
||||
* @return Nouveau modèle, ou NULL.
|
||||
*/
|
||||
EvidenceCategoryModel *evidence_category_model_new(void);
|
||||
|
||||
/**
|
||||
* @brief Libère le modèle.
|
||||
*
|
||||
* Cette fonction accepte NULL.
|
||||
*
|
||||
* @param evidence_category_model Modèle à libérer.
|
||||
*/
|
||||
void evidence_category_model_free(
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le modèle GTK contenant les catégories.
|
||||
*
|
||||
* La référence retournée est empruntée.
|
||||
*
|
||||
* @return GListModel emprunté, ou NULL.
|
||||
*/
|
||||
GListModel *evidence_category_model_get_list_model(
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le nombre de catégories.
|
||||
*
|
||||
* @return Nombre de catégories, ou 0.
|
||||
*/
|
||||
guint evidence_category_model_get_count(
|
||||
const EvidenceCategoryModel *evidence_category_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Regroupe les preuves par type métier.
|
||||
*
|
||||
* evidence_items doit contenir des EvidenceListItem.
|
||||
*
|
||||
* type_labels est une table facultative associant :
|
||||
*
|
||||
* - clé : code métier du type ;
|
||||
* - valeur : libellé utilisateur.
|
||||
*
|
||||
* La table est uniquement empruntée pendant l'appel.
|
||||
* Lorsqu'un libellé est absent, le code métier est utilisé.
|
||||
*
|
||||
* Le nouveau contenu est entièrement préparé avant que l'ancien modèle
|
||||
* soit remplacé.
|
||||
*
|
||||
* @param evidence_category_model Modèle à actualiser.
|
||||
* @param evidence_items Modèle contenant des EvidenceListItem.
|
||||
* @param type_labels Correspondance code vers libellé, ou NULL.
|
||||
* @param error Emplacement facultatif recevant une erreur.
|
||||
*
|
||||
* @return TRUE en cas de succès.
|
||||
*/
|
||||
gboolean evidence_category_model_replace(
|
||||
EvidenceCategoryModel *evidence_category_model,
|
||||
GListModel *evidence_items,
|
||||
GHashTable *type_labels,
|
||||
GError **error
|
||||
);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
124
include/widgets/evidence_list_item.h
Normal file
124
include/widgets/evidence_list_item.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_list_item.h
|
||||
* @brief Objet d'affichage GTK représentant une preuve importée.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LABFY_INVESTIGATION_EVIDENCE_LIST_ITEM_H
|
||||
#define LABFY_INVESTIGATION_EVIDENCE_LIST_ITEM_H
|
||||
|
||||
#include "models/evidence_record.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* @brief Type GObject de EvidenceListItem.
|
||||
*/
|
||||
#define EVIDENCE_TYPE_LIST_ITEM \
|
||||
(evidence_list_item_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE(
|
||||
EvidenceListItem,
|
||||
evidence_list_item,
|
||||
EVIDENCE,
|
||||
LIST_ITEM,
|
||||
GObject
|
||||
)
|
||||
|
||||
/**
|
||||
* @brief Crée un élément d'affichage depuis une preuve métier.
|
||||
*
|
||||
* Les valeurs nécessaires à l'interface sont copiées.
|
||||
* L'objet ne conserve aucun pointeur emprunté vers EvidenceRecord.
|
||||
*
|
||||
* L'appelant possède la référence retournée et doit la libérer
|
||||
* avec g_object_unref() ou g_clear_object().
|
||||
*
|
||||
* @param evidence_record Preuve métier valide.
|
||||
*
|
||||
* @return Nouvel élément d'affichage, ou NULL.
|
||||
*/
|
||||
EvidenceListItem *evidence_list_item_new(
|
||||
const EvidenceRecord *evidence_record
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne l'identifiant UUID de la preuve.
|
||||
*
|
||||
* Cet identifiant est utilisé pour signaler une sélection à Application.
|
||||
*
|
||||
* @return Chaîne empruntée, ou NULL.
|
||||
*/
|
||||
const char *evidence_list_item_get_identifier(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le nom original de la preuve.
|
||||
*
|
||||
* @return Chaîne empruntée, ou NULL.
|
||||
*/
|
||||
const char *evidence_list_item_get_original_name(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne l'identifiant métier du type de preuve.
|
||||
*
|
||||
* @return Chaîne empruntée, ou NULL.
|
||||
*/
|
||||
const char *evidence_list_item_get_type_identifier(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne la taille de la preuve.
|
||||
*
|
||||
* @return Taille en octets, ou 0.
|
||||
*/
|
||||
guint64 evidence_list_item_get_size_bytes(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne la date UTC de collecte.
|
||||
*
|
||||
* @return Chaîne empruntée, ou NULL.
|
||||
*/
|
||||
const char *evidence_list_item_get_collected_at(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne la source déclarée.
|
||||
*
|
||||
* @return Chaîne empruntée, ou NULL.
|
||||
*/
|
||||
const char *evidence_list_item_get_source(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne l'état d'intégrité.
|
||||
*
|
||||
* @return État d'intégrité enregistré.
|
||||
*/
|
||||
EvidenceIntegrityStatus evidence_list_item_get_integrity_status(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne un libellé utilisateur pour l'état d'intégrité.
|
||||
*
|
||||
* La chaîne retournée est statique et ne doit pas être libérée.
|
||||
*
|
||||
* @return Libellé d'état.
|
||||
*/
|
||||
const char *evidence_list_item_get_integrity_status_label(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
119
include/widgets/evidence_list_model.h
Normal file
119
include/widgets/evidence_list_model.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_list_model.h
|
||||
* @brief Modèle GTK en mémoire contenant la liste des preuves affichées.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LABFY_INVESTIGATION_EVIDENCE_LIST_MODEL_H
|
||||
#define LABFY_INVESTIGATION_EVIDENCE_LIST_MODEL_H
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* @brief Modèle opaque contenant des EvidenceListItem.
|
||||
*/
|
||||
typedef struct EvidenceListModel EvidenceListModel;
|
||||
|
||||
/**
|
||||
* @brief Codes d'erreur produits par EvidenceListModel.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/**
|
||||
* Un argument public est invalide.
|
||||
*/
|
||||
EVIDENCE_LIST_MODEL_ERROR_INVALID_ARGUMENT,
|
||||
|
||||
/**
|
||||
* Une allocation a échoué.
|
||||
*/
|
||||
EVIDENCE_LIST_MODEL_ERROR_MEMORY,
|
||||
|
||||
/**
|
||||
* Un EvidenceRecord ne peut pas produire un élément d'affichage.
|
||||
*/
|
||||
EVIDENCE_LIST_MODEL_ERROR_INVALID_RECORD
|
||||
} EvidenceListModelError;
|
||||
|
||||
/**
|
||||
* @brief Domaine d'erreur du modèle de liste.
|
||||
*/
|
||||
#define EVIDENCE_LIST_MODEL_ERROR \
|
||||
evidence_list_model_error_quark()
|
||||
|
||||
/**
|
||||
* @brief Retourne le domaine d'erreur du modèle.
|
||||
*
|
||||
* @return Quark GLib associé à EvidenceListModel.
|
||||
*/
|
||||
GQuark evidence_list_model_error_quark(void);
|
||||
|
||||
/**
|
||||
* @brief Crée un modèle de liste vide.
|
||||
*
|
||||
* @return Nouveau modèle, ou NULL.
|
||||
*/
|
||||
EvidenceListModel *evidence_list_model_new(void);
|
||||
|
||||
/**
|
||||
* @brief Libère le modèle et tous ses éléments.
|
||||
*
|
||||
* Cette fonction accepte NULL.
|
||||
*
|
||||
* @param evidence_list_model Modèle à libérer.
|
||||
*/
|
||||
void evidence_list_model_free(
|
||||
EvidenceListModel *evidence_list_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le GListModel utilisé par les widgets GTK.
|
||||
*
|
||||
* La référence retournée est empruntée.
|
||||
*
|
||||
* @param evidence_list_model Modèle valide.
|
||||
*
|
||||
* @return GListModel emprunté, ou NULL.
|
||||
*/
|
||||
GListModel *evidence_list_model_get_list_model(
|
||||
EvidenceListModel *evidence_list_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Retourne le nombre d'éléments affichés.
|
||||
*
|
||||
* @param evidence_list_model Modèle de liste.
|
||||
*
|
||||
* @return Nombre d'éléments, ou 0.
|
||||
*/
|
||||
guint evidence_list_model_get_count(
|
||||
const EvidenceListModel *evidence_list_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Remplace complètement le contenu du modèle.
|
||||
*
|
||||
* evidence_records doit contenir des pointeurs EvidenceRecord valides.
|
||||
*
|
||||
* Tous les nouveaux EvidenceListItem sont construits avant la modification
|
||||
* du modèle existant. En cas d'erreur, l'ancien contenu reste inchangé.
|
||||
*
|
||||
* Le tableau et les EvidenceRecord restent la propriété de l'appelant.
|
||||
*
|
||||
* @param evidence_list_model Modèle à mettre à jour.
|
||||
* @param evidence_records Tableau de EvidenceRecord.
|
||||
* @param error Emplacement facultatif recevant une erreur.
|
||||
*
|
||||
* @return TRUE en cas de succès.
|
||||
*/
|
||||
gboolean evidence_list_model_replace(
|
||||
EvidenceListModel *evidence_list_model,
|
||||
const GPtrArray *evidence_records,
|
||||
GError **error
|
||||
);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
99
include/widgets/evidence_tree_view.h
Normal file
99
include/widgets/evidence_tree_view.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_tree_view.h
|
||||
* @brief Affichage GTK hiérarchique des catégories et preuves importées.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LABFY_INVESTIGATION_EVIDENCE_TREE_VIEW_H
|
||||
#define LABFY_INVESTIGATION_EVIDENCE_TREE_VIEW_H
|
||||
|
||||
#include "widgets/evidence_category_model.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* @brief Vue opaque affichant les preuves regroupées par catégorie.
|
||||
*/
|
||||
typedef struct EvidenceTreeView EvidenceTreeView;
|
||||
|
||||
/**
|
||||
* @brief Callback appelé lorsqu'une preuve est sélectionnée.
|
||||
*
|
||||
* L'identifiant est emprunté et uniquement valide pendant l'appel.
|
||||
*
|
||||
* Lorsque la sélection est vide ou correspond à une catégorie,
|
||||
* evidence_identifier vaut NULL.
|
||||
*
|
||||
* @param evidence_identifier UUID de la preuve sélectionnée, ou NULL.
|
||||
* @param user_data Données privées fournies par l'appelant.
|
||||
*/
|
||||
typedef void (*EvidenceTreeViewSelectionCallback)(
|
||||
const char *evidence_identifier,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Crée une vue hiérarchique vide.
|
||||
*
|
||||
* @return Nouvelle vue, ou NULL.
|
||||
*/
|
||||
EvidenceTreeView *evidence_tree_view_new(void);
|
||||
|
||||
/**
|
||||
* @brief Retourne le widget GTK racine.
|
||||
*
|
||||
* Le widget retourné est emprunté.
|
||||
*
|
||||
* @param evidence_tree_view Vue à consulter.
|
||||
*
|
||||
* @return GtkScrolledWindow racine, ou NULL.
|
||||
*/
|
||||
GtkWidget *evidence_tree_view_get_widget(
|
||||
const EvidenceTreeView *evidence_tree_view
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Installe un modèle de catégories.
|
||||
*
|
||||
* La vue ne devient pas propriétaire de EvidenceCategoryModel.
|
||||
* Le modèle doit rester valide pendant son utilisation.
|
||||
*
|
||||
* Passer NULL vide la vue.
|
||||
*
|
||||
* @param evidence_tree_view Vue à actualiser.
|
||||
* @param evidence_category_model Modèle de catégories, ou NULL.
|
||||
*/
|
||||
void evidence_tree_view_set_model(
|
||||
EvidenceTreeView *evidence_tree_view,
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Définit le callback de sélection.
|
||||
*
|
||||
* @param evidence_tree_view Vue à configurer.
|
||||
* @param callback Callback facultatif.
|
||||
* @param user_data Données privées transmises au callback.
|
||||
*/
|
||||
void evidence_tree_view_set_selection_callback(
|
||||
EvidenceTreeView *evidence_tree_view,
|
||||
EvidenceTreeViewSelectionCallback callback,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Libère la structure d'encapsulation.
|
||||
*
|
||||
* Les widgets GTK intégrés dans la fenêtre restent gérés par l'arbre GTK.
|
||||
* Cette fonction accepte NULL.
|
||||
*
|
||||
* @param evidence_tree_view Vue à libérer.
|
||||
*/
|
||||
void evidence_tree_view_free(
|
||||
EvidenceTreeView *evidence_tree_view
|
||||
);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "core/investigation_tree_model.h"
|
||||
#include "widgets/investigation_tree_view.h"
|
||||
#include "widgets/evidence_category_model.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
|
@ -19,6 +20,20 @@
|
|||
*/
|
||||
typedef struct Sidebar Sidebar;
|
||||
|
||||
/**
|
||||
* @brief Callback appelé lorsqu'une preuve est sélectionnée.
|
||||
*
|
||||
* L'identifiant est emprunté et uniquement valide pendant l'appel.
|
||||
* Une sélection vide ou une catégorie transmet NULL.
|
||||
*
|
||||
* @param evidence_identifier UUID de la preuve, ou NULL.
|
||||
* @param user_data Données privées fournies par l'appelant.
|
||||
*/
|
||||
typedef void (*SidebarEvidenceSelectionCallback)(
|
||||
const char *evidence_identifier,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Crée un nouveau panneau de navigation latéral.
|
||||
*
|
||||
|
|
@ -71,6 +86,33 @@ void sidebar_set_selection_callback(
|
|||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Installe le modèle des catégories de preuves.
|
||||
*
|
||||
* La Sidebar ne devient pas propriétaire du modèle.
|
||||
* Passer NULL rétablit l'état vide.
|
||||
*
|
||||
* @param sidebar Barre latérale à actualiser.
|
||||
* @param evidence_category_model Modèle de catégories, ou NULL.
|
||||
*/
|
||||
void sidebar_set_evidence_model(
|
||||
Sidebar *sidebar,
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Définit le callback de sélection d'une preuve.
|
||||
*
|
||||
* @param sidebar Barre latérale à configurer.
|
||||
* @param callback Callback facultatif.
|
||||
* @param user_data Données privées transmises au callback.
|
||||
*/
|
||||
void sidebar_set_evidence_selection_callback(
|
||||
Sidebar *sidebar,
|
||||
SidebarEvidenceSelectionCallback callback,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Libère la structure d'encapsulation du panneau latéral.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@
|
|||
#include "models/evidence_record.h"
|
||||
#include "dao/evidence_type_dao.h"
|
||||
#include "views/evidence_import_dialog.h"
|
||||
#include "dao/evidence_dao.h"
|
||||
#include "models/evidence_type.h"
|
||||
#include "widgets/evidence_list_model.h"
|
||||
#include "widgets/evidence_category_model.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -46,7 +50,8 @@ typedef enum
|
|||
APPLICATION_OPEN_ERROR_INVALID_ARGUMENT,
|
||||
APPLICATION_OPEN_ERROR_INVALID_PROJECT,
|
||||
APPLICATION_OPEN_ERROR_TREE_BUILD,
|
||||
APPLICATION_OPEN_ERROR_INSTALL
|
||||
APPLICATION_OPEN_ERROR_INSTALL,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE
|
||||
} ApplicationOpenError;
|
||||
|
||||
/**
|
||||
|
|
@ -81,10 +86,12 @@ struct Application
|
|||
InvestigationTreeModel *tree_model;
|
||||
TaskManager *task_manager;
|
||||
ToolInitializer *tool_initializer;
|
||||
EvidenceListModel *evidence_list_model;
|
||||
EvidenceCategoryModel *evidence_category_model;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Contexte conservé jusqu’à la fin d’un import.
|
||||
* @brief Contexte ApplicationOpenErrorconservé jusqu’à la fin d’un import.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -390,6 +397,469 @@ static void application_present_error(
|
|||
const char *message
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Charge les preuves de la session et construit leurs modèles GTK.
|
||||
*
|
||||
* Les nouveaux modèles sont entièrement préparés avant de remplacer
|
||||
* ceux actuellement affichés.
|
||||
*
|
||||
* En cas d'échec, les anciens modèles restent la propriété de
|
||||
* l'application et ne sont pas modifiés.
|
||||
*/
|
||||
static gboolean application_refresh_evidence_models(
|
||||
Application *application,
|
||||
GError **error
|
||||
)
|
||||
{
|
||||
Database *database = NULL;
|
||||
|
||||
EvidenceDao *evidence_dao = NULL;
|
||||
EvidenceTypeDao *evidence_type_dao = NULL;
|
||||
|
||||
GPtrArray *evidence_records = NULL;
|
||||
GPtrArray *evidence_types = NULL;
|
||||
|
||||
GHashTable *type_labels = NULL;
|
||||
|
||||
EvidenceListModel *new_evidence_list_model =
|
||||
NULL;
|
||||
|
||||
EvidenceCategoryModel *new_evidence_category_model =
|
||||
NULL;
|
||||
|
||||
GError *local_error = NULL;
|
||||
|
||||
guint type_index = 0;
|
||||
|
||||
gboolean refreshed = FALSE;
|
||||
|
||||
g_return_val_if_fail(
|
||||
error == NULL || *error == NULL,
|
||||
FALSE
|
||||
);
|
||||
|
||||
if (application == NULL ||
|
||||
application->main_window == NULL ||
|
||||
application->session == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
APPLICATION_OPEN_ERROR,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE,
|
||||
"L'application ou la session d'enquête est invalide."
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
database =
|
||||
investigation_session_get_database(
|
||||
application->session
|
||||
);
|
||||
|
||||
if (database == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
APPLICATION_OPEN_ERROR,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE,
|
||||
"La session ne fournit aucune connexion SQLite."
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
evidence_dao =
|
||||
evidence_dao_new(
|
||||
database,
|
||||
&local_error
|
||||
);
|
||||
|
||||
if (evidence_dao == NULL)
|
||||
{
|
||||
if (local_error != NULL)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error(
|
||||
error,
|
||||
local_error,
|
||||
"Impossible de créer le DAO des preuves : "
|
||||
);
|
||||
|
||||
local_error = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error(
|
||||
&local_error
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
APPLICATION_OPEN_ERROR,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE,
|
||||
"Impossible de créer le DAO des preuves."
|
||||
);
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
evidence_records =
|
||||
evidence_dao_list_all(
|
||||
evidence_dao,
|
||||
&local_error
|
||||
);
|
||||
|
||||
if (evidence_records == NULL)
|
||||
{
|
||||
if (local_error != NULL)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error(
|
||||
error,
|
||||
local_error,
|
||||
"Impossible de charger les preuves : "
|
||||
);
|
||||
|
||||
local_error = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error(
|
||||
&local_error
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
APPLICATION_OPEN_ERROR,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE,
|
||||
"Impossible de charger les preuves."
|
||||
);
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
evidence_type_dao =
|
||||
evidence_type_dao_new(
|
||||
database,
|
||||
&local_error
|
||||
);
|
||||
|
||||
if (evidence_type_dao == NULL)
|
||||
{
|
||||
if (local_error != NULL)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error(
|
||||
error,
|
||||
local_error,
|
||||
"Impossible de créer le DAO des types de preuve : "
|
||||
);
|
||||
|
||||
local_error = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error(
|
||||
&local_error
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
APPLICATION_OPEN_ERROR,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE,
|
||||
"Impossible de créer le DAO des types de preuve."
|
||||
);
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
evidence_types =
|
||||
evidence_type_dao_list_all(
|
||||
evidence_type_dao,
|
||||
&local_error
|
||||
);
|
||||
|
||||
if (evidence_types == NULL)
|
||||
{
|
||||
if (local_error != NULL)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error(
|
||||
error,
|
||||
local_error,
|
||||
"Impossible de charger les types de preuve : "
|
||||
);
|
||||
|
||||
local_error = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error(
|
||||
&local_error
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
APPLICATION_OPEN_ERROR,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE,
|
||||
"Impossible de charger les types de preuve."
|
||||
);
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
type_labels =
|
||||
g_hash_table_new_full(
|
||||
g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
g_free
|
||||
);
|
||||
|
||||
if (type_labels == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
APPLICATION_OPEN_ERROR,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE,
|
||||
"Impossible d'allouer la table des libellés."
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (type_index = 0;
|
||||
type_index < evidence_types->len;
|
||||
type_index++)
|
||||
{
|
||||
const EvidenceType *evidence_type =
|
||||
NULL;
|
||||
|
||||
const char *type_code = NULL;
|
||||
const char *type_label = NULL;
|
||||
|
||||
evidence_type =
|
||||
g_ptr_array_index(
|
||||
evidence_types,
|
||||
type_index
|
||||
);
|
||||
|
||||
if (evidence_type == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
type_code =
|
||||
evidence_type_get_code(
|
||||
evidence_type
|
||||
);
|
||||
|
||||
type_label =
|
||||
evidence_type_get_label(
|
||||
evidence_type
|
||||
);
|
||||
|
||||
if (type_code == NULL ||
|
||||
type_code[0] == '\0' ||
|
||||
type_label == NULL ||
|
||||
type_label[0] == '\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
g_hash_table_replace(
|
||||
type_labels,
|
||||
g_strdup(
|
||||
type_code
|
||||
),
|
||||
g_strdup(
|
||||
type_label
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
new_evidence_list_model =
|
||||
evidence_list_model_new();
|
||||
|
||||
new_evidence_category_model =
|
||||
evidence_category_model_new();
|
||||
|
||||
if (new_evidence_list_model == NULL ||
|
||||
new_evidence_category_model == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
APPLICATION_OPEN_ERROR,
|
||||
APPLICATION_OPEN_ERROR_EVIDENCE,
|
||||
"Impossible d'allouer les modèles d'affichage des preuves."
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!evidence_list_model_replace(
|
||||
new_evidence_list_model,
|
||||
evidence_records,
|
||||
&local_error
|
||||
))
|
||||
{
|
||||
if (local_error != NULL)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error(
|
||||
error,
|
||||
local_error,
|
||||
"Impossible de préparer la liste des preuves : "
|
||||
);
|
||||
|
||||
local_error = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error(
|
||||
&local_error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!evidence_category_model_replace(
|
||||
new_evidence_category_model,
|
||||
evidence_list_model_get_list_model(
|
||||
new_evidence_list_model
|
||||
),
|
||||
type_labels,
|
||||
&local_error
|
||||
))
|
||||
{
|
||||
if (local_error != NULL)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_propagate_prefixed_error(
|
||||
error,
|
||||
local_error,
|
||||
"Impossible de regrouper les preuves : "
|
||||
);
|
||||
|
||||
local_error = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error(
|
||||
&local_error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* La vue doit être détachée avant la libération de son ancien modèle.
|
||||
*/
|
||||
main_window_set_evidence_model(
|
||||
application->main_window,
|
||||
NULL
|
||||
);
|
||||
|
||||
evidence_category_model_free(
|
||||
application->evidence_category_model
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
application->evidence_list_model
|
||||
);
|
||||
|
||||
application->evidence_list_model =
|
||||
new_evidence_list_model;
|
||||
|
||||
application->evidence_category_model =
|
||||
new_evidence_category_model;
|
||||
|
||||
new_evidence_list_model =
|
||||
NULL;
|
||||
|
||||
new_evidence_category_model =
|
||||
NULL;
|
||||
|
||||
main_window_set_evidence_model(
|
||||
application->main_window,
|
||||
application->evidence_category_model
|
||||
);
|
||||
|
||||
refreshed = TRUE;
|
||||
|
||||
cleanup:
|
||||
|
||||
g_clear_error(
|
||||
&local_error
|
||||
);
|
||||
|
||||
evidence_category_model_free(
|
||||
new_evidence_category_model
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
new_evidence_list_model
|
||||
);
|
||||
|
||||
if (type_labels != NULL)
|
||||
{
|
||||
g_hash_table_unref(
|
||||
type_labels
|
||||
);
|
||||
}
|
||||
|
||||
if (evidence_types != NULL)
|
||||
{
|
||||
g_ptr_array_unref(
|
||||
evidence_types
|
||||
);
|
||||
}
|
||||
|
||||
if (evidence_records != NULL)
|
||||
{
|
||||
g_ptr_array_unref(
|
||||
evidence_records
|
||||
);
|
||||
}
|
||||
|
||||
evidence_type_dao_free(
|
||||
evidence_type_dao
|
||||
);
|
||||
|
||||
evidence_dao_free(
|
||||
evidence_dao
|
||||
);
|
||||
|
||||
return refreshed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Installe une nouvelle session et son arbre dans l'application.
|
||||
*
|
||||
|
|
@ -416,6 +886,8 @@ static gboolean application_install_session(
|
|||
const char *root_path = NULL;
|
||||
const char *investigation_name = NULL;
|
||||
|
||||
GError *evidence_error = NULL;
|
||||
|
||||
if (application == NULL ||
|
||||
application->main_window == NULL ||
|
||||
new_session == NULL ||
|
||||
|
|
@ -485,6 +957,54 @@ static gboolean application_install_session(
|
|||
TRUE
|
||||
);
|
||||
|
||||
/*
|
||||
* L'ancienne liste ne doit jamais rester affichée après
|
||||
* un changement d'enquête.
|
||||
*/
|
||||
main_window_set_evidence_model(
|
||||
application->main_window,
|
||||
NULL
|
||||
);
|
||||
|
||||
evidence_category_model_free(
|
||||
application->evidence_category_model
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
application->evidence_list_model
|
||||
);
|
||||
|
||||
application->evidence_category_model =
|
||||
NULL;
|
||||
|
||||
application->evidence_list_model =
|
||||
NULL;
|
||||
|
||||
if (!application_refresh_evidence_models(
|
||||
application,
|
||||
&evidence_error
|
||||
))
|
||||
{
|
||||
g_warning(
|
||||
"Impossible de charger les preuves de l'enquête : %s",
|
||||
evidence_error != NULL
|
||||
? evidence_error->message
|
||||
: "erreur inconnue"
|
||||
);
|
||||
|
||||
application_present_error(
|
||||
application,
|
||||
"Preuves indisponibles",
|
||||
evidence_error != NULL
|
||||
? evidence_error->message
|
||||
: "Les preuves enregistrées n'ont pas pu être chargées."
|
||||
);
|
||||
|
||||
g_clear_error(
|
||||
&evidence_error
|
||||
);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -2123,6 +2643,22 @@ void application_free(
|
|||
application->session
|
||||
);
|
||||
|
||||
if (application->main_window != NULL)
|
||||
{
|
||||
main_window_set_evidence_model(
|
||||
application->main_window,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
evidence_category_model_free(
|
||||
application->evidence_category_model
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
application->evidence_list_model
|
||||
);
|
||||
|
||||
/*
|
||||
* MainWindow contient TaskPanel.
|
||||
* Il doit être détruit avant TaskManager.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
/**
|
||||
* @brief Largeur initiale de la fenêtre principale.
|
||||
*/
|
||||
#define MAIN_WINDOW_DEFAULT_WIDTH 1000
|
||||
#define MAIN_WINDOW_DEFAULT_WIDTH 1100
|
||||
|
||||
/**
|
||||
* @brief Hauteur initiale de la fenêtre principale.
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
/**
|
||||
* @brief Position initiale de la séparation horizontale.
|
||||
*/
|
||||
#define MAIN_WINDOW_SIDEBAR_POSITION 250
|
||||
#define MAIN_WINDOW_SIDEBAR_POSITION 320
|
||||
|
||||
/**
|
||||
* @brief Position initiale de la séparation verticale.
|
||||
|
|
@ -716,6 +716,22 @@ void main_window_set_tree_model(
|
|||
);
|
||||
}
|
||||
|
||||
void main_window_set_evidence_model(
|
||||
MainWindow *main_window,
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
)
|
||||
{
|
||||
if (main_window == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sidebar_set_evidence_model(
|
||||
main_window->sidebar,
|
||||
evidence_category_model
|
||||
);
|
||||
}
|
||||
|
||||
void main_window_set_investigation(
|
||||
MainWindow *main_window,
|
||||
const char *investigation_name,
|
||||
|
|
@ -848,6 +864,24 @@ void main_window_set_tree_selection_callback(
|
|||
);
|
||||
}
|
||||
|
||||
void main_window_set_evidence_selection_callback(
|
||||
MainWindow *main_window,
|
||||
MainWindowEvidenceSelectionCallback callback,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
if (main_window == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sidebar_set_evidence_selection_callback(
|
||||
main_window->sidebar,
|
||||
callback,
|
||||
user_data
|
||||
);
|
||||
}
|
||||
|
||||
void main_window_set_new_investigation_callback(
|
||||
MainWindow *main_window,
|
||||
MainWindowNewInvestigationCallback callback,
|
||||
|
|
|
|||
331
src/widgets/evidence_category_item.c
Normal file
331
src/widgets/evidence_category_item.c
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_category_item.c
|
||||
* @brief Implémentation d'une catégorie de preuves affichées.
|
||||
******************************************************************************/
|
||||
|
||||
#include "widgets/evidence_category_item.h"
|
||||
|
||||
/**
|
||||
* @brief État interne de la catégorie.
|
||||
*/
|
||||
struct _EvidenceCategoryItem
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
char *type_identifier;
|
||||
char *label;
|
||||
|
||||
GListStore *children;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(
|
||||
EvidenceCategoryItem,
|
||||
evidence_category_item,
|
||||
G_TYPE_OBJECT
|
||||
)
|
||||
|
||||
/**
|
||||
* @brief Copie et nettoie une chaîne obligatoire.
|
||||
*/
|
||||
static char *evidence_category_item_duplicate_required_text(
|
||||
const char *value
|
||||
)
|
||||
{
|
||||
char *normalized_value = NULL;
|
||||
|
||||
if (value == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
normalized_value =
|
||||
g_strdup(
|
||||
value
|
||||
);
|
||||
|
||||
if (normalized_value == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_strstrip(
|
||||
normalized_value
|
||||
);
|
||||
|
||||
if (normalized_value[0] == '\0')
|
||||
{
|
||||
g_free(
|
||||
normalized_value
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return normalized_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Libère les ressources possédées par la catégorie.
|
||||
*/
|
||||
static void evidence_category_item_finalize(
|
||||
GObject *object
|
||||
)
|
||||
{
|
||||
EvidenceCategoryItem *evidence_category_item =
|
||||
EVIDENCE_CATEGORY_ITEM(
|
||||
object
|
||||
);
|
||||
|
||||
g_clear_pointer(
|
||||
&evidence_category_item->type_identifier,
|
||||
g_free
|
||||
);
|
||||
|
||||
g_clear_pointer(
|
||||
&evidence_category_item->label,
|
||||
g_free
|
||||
);
|
||||
|
||||
g_clear_object(
|
||||
&evidence_category_item->children
|
||||
);
|
||||
|
||||
G_OBJECT_CLASS(
|
||||
evidence_category_item_parent_class
|
||||
)->finalize(
|
||||
object
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialise la classe GObject.
|
||||
*/
|
||||
static void evidence_category_item_class_init(
|
||||
EvidenceCategoryItemClass *evidence_category_item_class
|
||||
)
|
||||
{
|
||||
GObjectClass *object_class =
|
||||
G_OBJECT_CLASS(
|
||||
evidence_category_item_class
|
||||
);
|
||||
|
||||
object_class->finalize =
|
||||
evidence_category_item_finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialise une catégorie vide.
|
||||
*/
|
||||
static void evidence_category_item_init(
|
||||
EvidenceCategoryItem *evidence_category_item
|
||||
)
|
||||
{
|
||||
evidence_category_item->children =
|
||||
g_list_store_new(
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
);
|
||||
}
|
||||
|
||||
EvidenceCategoryItem *evidence_category_item_new(
|
||||
const char *type_identifier,
|
||||
const char *label
|
||||
)
|
||||
{
|
||||
EvidenceCategoryItem *evidence_category_item =
|
||||
NULL;
|
||||
|
||||
char *normalized_type_identifier =
|
||||
NULL;
|
||||
|
||||
char *normalized_label =
|
||||
NULL;
|
||||
|
||||
normalized_type_identifier =
|
||||
evidence_category_item_duplicate_required_text(
|
||||
type_identifier
|
||||
);
|
||||
|
||||
normalized_label =
|
||||
evidence_category_item_duplicate_required_text(
|
||||
label
|
||||
);
|
||||
|
||||
if (normalized_type_identifier == NULL ||
|
||||
normalized_label == NULL)
|
||||
{
|
||||
g_free(
|
||||
normalized_label
|
||||
);
|
||||
|
||||
g_free(
|
||||
normalized_type_identifier
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evidence_category_item =
|
||||
g_object_new(
|
||||
EVIDENCE_TYPE_CATEGORY_ITEM,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (evidence_category_item == NULL ||
|
||||
evidence_category_item->children == NULL)
|
||||
{
|
||||
g_clear_object(
|
||||
&evidence_category_item
|
||||
);
|
||||
|
||||
g_free(
|
||||
normalized_label
|
||||
);
|
||||
|
||||
g_free(
|
||||
normalized_type_identifier
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evidence_category_item->type_identifier =
|
||||
normalized_type_identifier;
|
||||
|
||||
evidence_category_item->label =
|
||||
normalized_label;
|
||||
|
||||
return evidence_category_item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare deux preuves par nom original puis par identifiant.
|
||||
*/
|
||||
static gint evidence_category_item_compare_list_items(
|
||||
gconstpointer first_pointer,
|
||||
gconstpointer second_pointer,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
const EvidenceListItem *first_item =
|
||||
first_pointer;
|
||||
|
||||
const EvidenceListItem *second_item =
|
||||
second_pointer;
|
||||
|
||||
const char *first_name = NULL;
|
||||
const char *second_name = NULL;
|
||||
|
||||
gint comparison = 0;
|
||||
|
||||
(void) user_data;
|
||||
|
||||
first_name =
|
||||
evidence_list_item_get_original_name(
|
||||
first_item
|
||||
);
|
||||
|
||||
second_name =
|
||||
evidence_list_item_get_original_name(
|
||||
second_item
|
||||
);
|
||||
|
||||
comparison =
|
||||
g_utf8_collate(
|
||||
first_name,
|
||||
second_name
|
||||
);
|
||||
|
||||
if (comparison != 0)
|
||||
{
|
||||
return comparison;
|
||||
}
|
||||
|
||||
return g_strcmp0(
|
||||
evidence_list_item_get_identifier(
|
||||
first_item
|
||||
),
|
||||
evidence_list_item_get_identifier(
|
||||
second_item
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gboolean evidence_category_item_append(
|
||||
EvidenceCategoryItem *evidence_category_item,
|
||||
EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
if (evidence_category_item == NULL ||
|
||||
evidence_category_item->children == NULL ||
|
||||
evidence_list_item == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_list_store_insert_sorted(
|
||||
evidence_category_item->children,
|
||||
G_OBJECT(
|
||||
evidence_list_item
|
||||
),
|
||||
evidence_category_item_compare_list_items,
|
||||
NULL
|
||||
);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char *evidence_category_item_get_type_identifier(
|
||||
const EvidenceCategoryItem *evidence_category_item
|
||||
)
|
||||
{
|
||||
if (evidence_category_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_category_item->type_identifier;
|
||||
}
|
||||
|
||||
const char *evidence_category_item_get_label(
|
||||
const EvidenceCategoryItem *evidence_category_item
|
||||
)
|
||||
{
|
||||
if (evidence_category_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_category_item->label;
|
||||
}
|
||||
|
||||
guint evidence_category_item_get_count(
|
||||
const EvidenceCategoryItem *evidence_category_item
|
||||
)
|
||||
{
|
||||
if (evidence_category_item == NULL ||
|
||||
evidence_category_item->children == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_list_model_get_n_items(
|
||||
G_LIST_MODEL(
|
||||
evidence_category_item->children
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
GListModel *evidence_category_item_get_children(
|
||||
EvidenceCategoryItem *evidence_category_item
|
||||
)
|
||||
{
|
||||
if (evidence_category_item == NULL ||
|
||||
evidence_category_item->children == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return G_LIST_MODEL(
|
||||
evidence_category_item->children
|
||||
);
|
||||
}
|
||||
548
src/widgets/evidence_category_model.c
Normal file
548
src/widgets/evidence_category_model.c
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_category_model.c
|
||||
* @brief Regroupement des preuves par catégorie pour l'affichage GTK.
|
||||
******************************************************************************/
|
||||
|
||||
#include "widgets/evidence_category_model.h"
|
||||
|
||||
#include "widgets/evidence_category_item.h"
|
||||
#include "widgets/evidence_list_item.h"
|
||||
|
||||
/**
|
||||
* @brief État interne du modèle.
|
||||
*/
|
||||
struct EvidenceCategoryModel
|
||||
{
|
||||
GListStore *categories;
|
||||
};
|
||||
|
||||
GQuark evidence_category_model_error_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string(
|
||||
"labfy-investigation-evidence-category-model-error"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare deux catégories par libellé puis par code métier.
|
||||
*/
|
||||
static gint evidence_category_model_compare_categories(
|
||||
gconstpointer first_pointer,
|
||||
gconstpointer second_pointer,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
const EvidenceCategoryItem *first_category =
|
||||
first_pointer;
|
||||
|
||||
const EvidenceCategoryItem *second_category =
|
||||
second_pointer;
|
||||
|
||||
const char *first_label = NULL;
|
||||
const char *second_label = NULL;
|
||||
|
||||
gint comparison = 0;
|
||||
|
||||
(void) user_data;
|
||||
|
||||
first_label =
|
||||
evidence_category_item_get_label(
|
||||
first_category
|
||||
);
|
||||
|
||||
second_label =
|
||||
evidence_category_item_get_label(
|
||||
second_category
|
||||
);
|
||||
|
||||
comparison =
|
||||
g_utf8_collate(
|
||||
first_label,
|
||||
second_label
|
||||
);
|
||||
|
||||
if (comparison != 0)
|
||||
{
|
||||
return comparison;
|
||||
}
|
||||
|
||||
return g_strcmp0(
|
||||
evidence_category_item_get_type_identifier(
|
||||
first_category
|
||||
),
|
||||
evidence_category_item_get_type_identifier(
|
||||
second_category
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie qu'une chaîne obligatoire contient du texte.
|
||||
*/
|
||||
static gboolean evidence_category_model_value_has_text(
|
||||
const char *value
|
||||
)
|
||||
{
|
||||
return value != NULL &&
|
||||
value[0] != '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Libère les références temporaires d'un tableau d'ajouts.
|
||||
*/
|
||||
static void evidence_category_model_release_additions(
|
||||
gpointer *additions,
|
||||
guint addition_count
|
||||
)
|
||||
{
|
||||
guint addition_index = 0;
|
||||
|
||||
if (additions == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (addition_index = 0;
|
||||
addition_index < addition_count;
|
||||
addition_index++)
|
||||
{
|
||||
g_clear_object(
|
||||
&additions[addition_index]
|
||||
);
|
||||
}
|
||||
|
||||
g_free(
|
||||
additions
|
||||
);
|
||||
}
|
||||
|
||||
EvidenceCategoryModel *evidence_category_model_new(void)
|
||||
{
|
||||
EvidenceCategoryModel *evidence_category_model =
|
||||
NULL;
|
||||
|
||||
evidence_category_model =
|
||||
g_try_new0(
|
||||
EvidenceCategoryModel,
|
||||
1
|
||||
);
|
||||
|
||||
if (evidence_category_model == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evidence_category_model->categories =
|
||||
g_list_store_new(
|
||||
EVIDENCE_TYPE_CATEGORY_ITEM
|
||||
);
|
||||
|
||||
if (evidence_category_model->categories == NULL)
|
||||
{
|
||||
g_free(
|
||||
evidence_category_model
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_category_model;
|
||||
}
|
||||
|
||||
void evidence_category_model_free(
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
)
|
||||
{
|
||||
if (evidence_category_model == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_object(
|
||||
&evidence_category_model->categories
|
||||
);
|
||||
|
||||
g_free(
|
||||
evidence_category_model
|
||||
);
|
||||
}
|
||||
|
||||
GListModel *evidence_category_model_get_list_model(
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
)
|
||||
{
|
||||
if (evidence_category_model == NULL ||
|
||||
evidence_category_model->categories == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return G_LIST_MODEL(
|
||||
evidence_category_model->categories
|
||||
);
|
||||
}
|
||||
|
||||
guint evidence_category_model_get_count(
|
||||
const EvidenceCategoryModel *evidence_category_model
|
||||
)
|
||||
{
|
||||
if (evidence_category_model == NULL ||
|
||||
evidence_category_model->categories == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_list_model_get_n_items(
|
||||
G_LIST_MODEL(
|
||||
evidence_category_model->categories
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gboolean evidence_category_model_replace(
|
||||
EvidenceCategoryModel *evidence_category_model,
|
||||
GListModel *evidence_items,
|
||||
GHashTable *type_labels,
|
||||
GError **error
|
||||
)
|
||||
{
|
||||
GListStore *new_categories = NULL;
|
||||
|
||||
GHashTable *categories_by_type =
|
||||
NULL;
|
||||
|
||||
EvidenceListItem *evidence_list_item =
|
||||
NULL;
|
||||
|
||||
EvidenceCategoryItem *evidence_category_item =
|
||||
NULL;
|
||||
|
||||
gpointer *additions = NULL;
|
||||
|
||||
const char *type_identifier = NULL;
|
||||
const char *category_label = NULL;
|
||||
|
||||
guint evidence_count = 0;
|
||||
guint evidence_index = 0;
|
||||
|
||||
guint new_category_count = 0;
|
||||
guint category_index = 0;
|
||||
guint previous_category_count = 0;
|
||||
|
||||
gboolean replaced = FALSE;
|
||||
|
||||
g_return_val_if_fail(
|
||||
error == NULL || *error == NULL,
|
||||
FALSE
|
||||
);
|
||||
|
||||
if (evidence_category_model == NULL ||
|
||||
evidence_category_model->categories == NULL ||
|
||||
evidence_items == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_INVALID_ARGUMENT,
|
||||
"Le modèle de catégories ou la liste de preuves est invalide."
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!g_type_is_a(
|
||||
g_list_model_get_item_type(
|
||||
evidence_items
|
||||
),
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
))
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_INVALID_ARGUMENT,
|
||||
"Le modèle fourni ne contient pas des EvidenceListItem."
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
new_categories =
|
||||
g_list_store_new(
|
||||
EVIDENCE_TYPE_CATEGORY_ITEM
|
||||
);
|
||||
|
||||
categories_by_type =
|
||||
g_hash_table_new_full(
|
||||
g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (new_categories == NULL ||
|
||||
categories_by_type == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_MEMORY,
|
||||
"Impossible de préparer le regroupement des preuves."
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
evidence_count =
|
||||
g_list_model_get_n_items(
|
||||
evidence_items
|
||||
);
|
||||
|
||||
for (evidence_index = 0;
|
||||
evidence_index < evidence_count;
|
||||
evidence_index++)
|
||||
{
|
||||
evidence_list_item =
|
||||
g_list_model_get_item(
|
||||
evidence_items,
|
||||
evidence_index
|
||||
);
|
||||
|
||||
if (evidence_list_item == NULL ||
|
||||
!EVIDENCE_IS_LIST_ITEM(
|
||||
evidence_list_item
|
||||
))
|
||||
{
|
||||
g_set_error(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_INVALID_ITEM,
|
||||
"La preuve située à l'index %u est invalide.",
|
||||
evidence_index
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
type_identifier =
|
||||
evidence_list_item_get_type_identifier(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
if (!evidence_category_model_value_has_text(
|
||||
type_identifier
|
||||
))
|
||||
{
|
||||
g_set_error(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_INVALID_ITEM,
|
||||
"La preuve située à l'index %u ne possède aucun type.",
|
||||
evidence_index
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
evidence_category_item =
|
||||
g_hash_table_lookup(
|
||||
categories_by_type,
|
||||
type_identifier
|
||||
);
|
||||
|
||||
if (evidence_category_item == NULL)
|
||||
{
|
||||
category_label = NULL;
|
||||
|
||||
if (type_labels != NULL)
|
||||
{
|
||||
category_label =
|
||||
g_hash_table_lookup(
|
||||
type_labels,
|
||||
type_identifier
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Un type inconnu reste affichable.
|
||||
* Son code métier devient son libellé de secours.
|
||||
*/
|
||||
if (!evidence_category_model_value_has_text(
|
||||
category_label
|
||||
))
|
||||
{
|
||||
category_label =
|
||||
type_identifier;
|
||||
}
|
||||
|
||||
evidence_category_item =
|
||||
evidence_category_item_new(
|
||||
type_identifier,
|
||||
category_label
|
||||
);
|
||||
|
||||
if (evidence_category_item == NULL)
|
||||
{
|
||||
g_set_error(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_CATEGORY,
|
||||
"Impossible de créer la catégorie '%s'.",
|
||||
type_identifier
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
g_list_store_insert_sorted(
|
||||
new_categories,
|
||||
G_OBJECT(
|
||||
evidence_category_item
|
||||
),
|
||||
evidence_category_model_compare_categories,
|
||||
NULL
|
||||
);
|
||||
|
||||
/*
|
||||
* La table emprunte le pointeur.
|
||||
* Le GListStore possède la référence.
|
||||
*/
|
||||
g_hash_table_insert(
|
||||
categories_by_type,
|
||||
g_strdup(
|
||||
type_identifier
|
||||
),
|
||||
evidence_category_item
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_category_item
|
||||
);
|
||||
}
|
||||
|
||||
if (!evidence_category_item_append(
|
||||
evidence_category_item,
|
||||
evidence_list_item
|
||||
))
|
||||
{
|
||||
g_set_error(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_CATEGORY,
|
||||
"Impossible d'ajouter la preuve %u à sa catégorie.",
|
||||
evidence_index
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
g_clear_object(
|
||||
&evidence_list_item
|
||||
);
|
||||
|
||||
evidence_category_item =
|
||||
NULL;
|
||||
}
|
||||
|
||||
new_category_count =
|
||||
g_list_model_get_n_items(
|
||||
G_LIST_MODEL(
|
||||
new_categories
|
||||
)
|
||||
);
|
||||
|
||||
previous_category_count =
|
||||
g_list_model_get_n_items(
|
||||
G_LIST_MODEL(
|
||||
evidence_category_model->categories
|
||||
)
|
||||
);
|
||||
|
||||
if (new_category_count == 0)
|
||||
{
|
||||
g_list_store_remove_all(
|
||||
evidence_category_model->categories
|
||||
);
|
||||
|
||||
replaced = TRUE;
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
additions =
|
||||
g_try_new0(
|
||||
gpointer,
|
||||
new_category_count
|
||||
);
|
||||
|
||||
if (additions == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_MEMORY,
|
||||
"Impossible de préparer le remplacement des catégories."
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (category_index = 0;
|
||||
category_index < new_category_count;
|
||||
category_index++)
|
||||
{
|
||||
additions[category_index] =
|
||||
g_list_model_get_item(
|
||||
G_LIST_MODEL(
|
||||
new_categories
|
||||
),
|
||||
category_index
|
||||
);
|
||||
|
||||
if (additions[category_index] == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_CATEGORY,
|
||||
"Impossible de lire une catégorie préparée."
|
||||
);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_store_splice(
|
||||
evidence_category_model->categories,
|
||||
0,
|
||||
previous_category_count,
|
||||
additions,
|
||||
new_category_count
|
||||
);
|
||||
|
||||
replaced = TRUE;
|
||||
|
||||
cleanup:
|
||||
|
||||
g_clear_object(
|
||||
&evidence_list_item
|
||||
);
|
||||
|
||||
evidence_category_model_release_additions(
|
||||
additions,
|
||||
new_category_count
|
||||
);
|
||||
|
||||
if (categories_by_type != NULL)
|
||||
{
|
||||
g_hash_table_unref(
|
||||
categories_by_type
|
||||
);
|
||||
}
|
||||
|
||||
g_clear_object(
|
||||
&new_categories
|
||||
);
|
||||
|
||||
return replaced;
|
||||
}
|
||||
315
src/widgets/evidence_list_item.c
Normal file
315
src/widgets/evidence_list_item.c
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_list_item.c
|
||||
* @brief Implémentation de EvidenceListItem.
|
||||
******************************************************************************/
|
||||
|
||||
#include "widgets/evidence_list_item.h"
|
||||
|
||||
/**
|
||||
* @brief Données privées copiées pour l'affichage GTK.
|
||||
*/
|
||||
struct _EvidenceListItem
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
char *identifier;
|
||||
char *original_name;
|
||||
char *type_identifier;
|
||||
guint64 size_bytes;
|
||||
char *collected_at;
|
||||
char *source;
|
||||
|
||||
EvidenceIntegrityStatus integrity_status;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(
|
||||
EvidenceListItem,
|
||||
evidence_list_item,
|
||||
G_TYPE_OBJECT
|
||||
)
|
||||
|
||||
/**
|
||||
* @brief Libère les données possédées par l'objet.
|
||||
*/
|
||||
static void evidence_list_item_finalize(
|
||||
GObject *object
|
||||
)
|
||||
{
|
||||
EvidenceListItem *evidence_list_item =
|
||||
EVIDENCE_LIST_ITEM(
|
||||
object
|
||||
);
|
||||
|
||||
g_clear_pointer(
|
||||
&evidence_list_item->original_name,
|
||||
g_free
|
||||
);
|
||||
|
||||
g_clear_pointer(
|
||||
&evidence_list_item->type_identifier,
|
||||
g_free
|
||||
);
|
||||
|
||||
g_clear_pointer(
|
||||
&evidence_list_item->collected_at,
|
||||
g_free
|
||||
);
|
||||
|
||||
g_clear_pointer(
|
||||
&evidence_list_item->source,
|
||||
g_free
|
||||
);
|
||||
|
||||
G_OBJECT_CLASS(
|
||||
evidence_list_item_parent_class
|
||||
)->finalize(
|
||||
object
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialise la classe GObject.
|
||||
*/
|
||||
static void evidence_list_item_class_init(
|
||||
EvidenceListItemClass *evidence_list_item_class
|
||||
)
|
||||
{
|
||||
GObjectClass *object_class =
|
||||
G_OBJECT_CLASS(
|
||||
evidence_list_item_class
|
||||
);
|
||||
|
||||
object_class->finalize =
|
||||
evidence_list_item_finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialise une nouvelle instance vide.
|
||||
*/
|
||||
static void evidence_list_item_init(
|
||||
EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
evidence_list_item->integrity_status =
|
||||
EVIDENCE_INTEGRITY_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
EvidenceListItem *evidence_list_item_new(
|
||||
const EvidenceRecord *evidence_record
|
||||
)
|
||||
{
|
||||
EvidenceListItem *evidence_list_item = NULL;
|
||||
|
||||
const char *identifier = NULL;
|
||||
const char *original_name = NULL;
|
||||
const char *type_identifier = NULL;
|
||||
|
||||
if (evidence_record == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
identifier =
|
||||
evidence_record_get_identifier(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
original_name =
|
||||
evidence_record_get_original_name(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
type_identifier =
|
||||
evidence_record_get_type_identifier(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
/*
|
||||
* Ces deux valeurs sont obligatoires dans EvidenceRecord.
|
||||
* Cette vérification protège néanmoins l'adaptateur d'affichage.
|
||||
*/
|
||||
if (identifier == NULL ||
|
||||
original_name == NULL ||
|
||||
original_name[0] == '\0' ||
|
||||
type_identifier == NULL ||
|
||||
type_identifier[0] == '\0')
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evidence_list_item =
|
||||
g_object_new(
|
||||
EVIDENCE_TYPE_LIST_ITEM,
|
||||
NULL
|
||||
);
|
||||
|
||||
evidence_list_item->identifier =
|
||||
g_strdup(
|
||||
identifier
|
||||
);
|
||||
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evidence_list_item->original_name =
|
||||
g_strdup(
|
||||
original_name
|
||||
);
|
||||
|
||||
evidence_list_item->type_identifier =
|
||||
g_strdup(
|
||||
type_identifier
|
||||
);
|
||||
|
||||
evidence_list_item->size_bytes =
|
||||
evidence_record_get_size_bytes(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
evidence_list_item->collected_at =
|
||||
g_strdup(
|
||||
evidence_record_get_collected_at(
|
||||
evidence_record
|
||||
)
|
||||
);
|
||||
|
||||
evidence_list_item->source =
|
||||
g_strdup(
|
||||
evidence_record_get_source(
|
||||
evidence_record
|
||||
)
|
||||
);
|
||||
|
||||
evidence_list_item->integrity_status =
|
||||
evidence_record_get_integrity_status(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
if (evidence_list_item->identifier == NULL ||
|
||||
evidence_list_item->original_name == NULL ||
|
||||
evidence_list_item->type_identifier == NULL)
|
||||
{
|
||||
g_object_unref(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_list_item;
|
||||
}
|
||||
|
||||
const char *evidence_list_item_get_identifier(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_list_item->identifier;
|
||||
}
|
||||
|
||||
const char *evidence_list_item_get_original_name(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_list_item->original_name;
|
||||
}
|
||||
|
||||
const char *evidence_list_item_get_type_identifier(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_list_item->type_identifier;
|
||||
}
|
||||
|
||||
guint64 evidence_list_item_get_size_bytes(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return evidence_list_item->size_bytes;
|
||||
}
|
||||
|
||||
const char *evidence_list_item_get_collected_at(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_list_item->collected_at;
|
||||
}
|
||||
|
||||
const char *evidence_list_item_get_source(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_list_item->source;
|
||||
}
|
||||
|
||||
EvidenceIntegrityStatus evidence_list_item_get_integrity_status(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
return EVIDENCE_INTEGRITY_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
return evidence_list_item->integrity_status;
|
||||
}
|
||||
|
||||
const char *evidence_list_item_get_integrity_status_label(
|
||||
const EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
EvidenceIntegrityStatus integrity_status =
|
||||
evidence_list_item_get_integrity_status(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
switch (integrity_status)
|
||||
{
|
||||
case EVIDENCE_INTEGRITY_STATUS_VALID:
|
||||
return "Valide";
|
||||
|
||||
case EVIDENCE_INTEGRITY_STATUS_MISSING:
|
||||
return "Fichier absent";
|
||||
|
||||
case EVIDENCE_INTEGRITY_STATUS_MODIFIED:
|
||||
return "Modifiée";
|
||||
|
||||
case EVIDENCE_INTEGRITY_STATUS_ERROR:
|
||||
return "Erreur";
|
||||
|
||||
case EVIDENCE_INTEGRITY_STATUS_UNKNOWN:
|
||||
default:
|
||||
return "Non vérifiée";
|
||||
}
|
||||
}
|
||||
239
src/widgets/evidence_list_model.c
Normal file
239
src/widgets/evidence_list_model.c
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/******************************************************************************
|
||||
* @file evidence_list_model.c
|
||||
* @brief Implémentation du modèle de liste des preuves.
|
||||
******************************************************************************/
|
||||
|
||||
#include "widgets/evidence_list_model.h"
|
||||
|
||||
#include "widgets/evidence_list_item.h"
|
||||
|
||||
/**
|
||||
* @brief État interne du modèle de liste.
|
||||
*/
|
||||
struct EvidenceListModel
|
||||
{
|
||||
GListStore *items;
|
||||
};
|
||||
|
||||
GQuark evidence_list_model_error_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string(
|
||||
"labfy-investigation-evidence-list-model-error"
|
||||
);
|
||||
}
|
||||
|
||||
EvidenceListModel *evidence_list_model_new(void)
|
||||
{
|
||||
EvidenceListModel *evidence_list_model =
|
||||
NULL;
|
||||
|
||||
evidence_list_model =
|
||||
g_try_new0(
|
||||
EvidenceListModel,
|
||||
1
|
||||
);
|
||||
|
||||
if (evidence_list_model == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evidence_list_model->items =
|
||||
g_list_store_new(
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
);
|
||||
|
||||
if (evidence_list_model->items == NULL)
|
||||
{
|
||||
g_free(
|
||||
evidence_list_model
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return evidence_list_model;
|
||||
}
|
||||
|
||||
void evidence_list_model_free(
|
||||
EvidenceListModel *evidence_list_model
|
||||
)
|
||||
{
|
||||
if (evidence_list_model == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_object(
|
||||
&evidence_list_model->items
|
||||
);
|
||||
|
||||
g_free(
|
||||
evidence_list_model
|
||||
);
|
||||
}
|
||||
|
||||
GListModel *evidence_list_model_get_list_model(
|
||||
EvidenceListModel *evidence_list_model
|
||||
)
|
||||
{
|
||||
if (evidence_list_model == NULL ||
|
||||
evidence_list_model->items == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return G_LIST_MODEL(
|
||||
evidence_list_model->items
|
||||
);
|
||||
}
|
||||
|
||||
guint evidence_list_model_get_count(
|
||||
const EvidenceListModel *evidence_list_model
|
||||
)
|
||||
{
|
||||
if (evidence_list_model == NULL ||
|
||||
evidence_list_model->items == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_list_model_get_n_items(
|
||||
G_LIST_MODEL(
|
||||
evidence_list_model->items
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
gboolean evidence_list_model_replace(
|
||||
EvidenceListModel *evidence_list_model,
|
||||
const GPtrArray *evidence_records,
|
||||
GError **error
|
||||
)
|
||||
{
|
||||
GPtrArray *new_items = NULL;
|
||||
|
||||
guint record_index = 0;
|
||||
guint previous_count = 0;
|
||||
|
||||
g_return_val_if_fail(
|
||||
error == NULL || *error == NULL,
|
||||
FALSE
|
||||
);
|
||||
|
||||
if (evidence_list_model == NULL ||
|
||||
evidence_list_model->items == NULL ||
|
||||
evidence_records == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
EVIDENCE_LIST_MODEL_ERROR,
|
||||
EVIDENCE_LIST_MODEL_ERROR_INVALID_ARGUMENT,
|
||||
"Le modèle ou le tableau de preuves est invalide."
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Le tableau libère notre référence locale sur chaque objet.
|
||||
* GListStore prendra ensuite sa propre référence lors du splice.
|
||||
*/
|
||||
new_items =
|
||||
g_ptr_array_new_with_free_func(
|
||||
g_object_unref
|
||||
);
|
||||
|
||||
if (new_items == NULL)
|
||||
{
|
||||
g_set_error_literal(
|
||||
error,
|
||||
EVIDENCE_LIST_MODEL_ERROR,
|
||||
EVIDENCE_LIST_MODEL_ERROR_MEMORY,
|
||||
"Impossible d'allouer la nouvelle liste de preuves."
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (record_index = 0;
|
||||
record_index < evidence_records->len;
|
||||
record_index++)
|
||||
{
|
||||
const EvidenceRecord *evidence_record =
|
||||
NULL;
|
||||
|
||||
EvidenceListItem *evidence_list_item =
|
||||
NULL;
|
||||
|
||||
evidence_record =
|
||||
g_ptr_array_index(
|
||||
evidence_records,
|
||||
record_index
|
||||
);
|
||||
|
||||
evidence_list_item =
|
||||
evidence_list_item_new(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
if (evidence_list_item == NULL)
|
||||
{
|
||||
g_set_error(
|
||||
error,
|
||||
EVIDENCE_LIST_MODEL_ERROR,
|
||||
EVIDENCE_LIST_MODEL_ERROR_INVALID_RECORD,
|
||||
"La preuve située à l'index %u est invalide.",
|
||||
record_index
|
||||
);
|
||||
|
||||
g_ptr_array_unref(
|
||||
new_items
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_ptr_array_add(
|
||||
new_items,
|
||||
evidence_list_item
|
||||
);
|
||||
}
|
||||
|
||||
previous_count =
|
||||
g_list_model_get_n_items(
|
||||
G_LIST_MODEL(
|
||||
evidence_list_model->items
|
||||
)
|
||||
);
|
||||
|
||||
if (new_items->len == 0)
|
||||
{
|
||||
g_list_store_remove_all(
|
||||
evidence_list_model->items
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Tous les éléments sont prêts.
|
||||
* Le remplacement peut maintenant être effectué en une opération.
|
||||
*/
|
||||
g_list_store_splice(
|
||||
evidence_list_model->items,
|
||||
0,
|
||||
previous_count,
|
||||
new_items->pdata,
|
||||
new_items->len
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* GListStore possède désormais une référence sur chaque élément.
|
||||
*/
|
||||
g_ptr_array_unref(
|
||||
new_items
|
||||
);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
1027
src/widgets/evidence_tree_view.c
Normal file
1027
src/widgets/evidence_tree_view.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -6,13 +6,38 @@
|
|||
#include "widgets/sidebar.h"
|
||||
#include "core/investigation_node.h"
|
||||
#include "widgets/investigation_tree_view.h"
|
||||
#include "widgets/evidence_tree_view.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* @brief Largeur initiale du panneau latéral.
|
||||
*/
|
||||
#define SIDEBAR_DEFAULT_WIDTH 250
|
||||
#define SIDEBAR_DEFAULT_WIDTH 320
|
||||
|
||||
/**
|
||||
* @brief Identifiant de la page contenant l'arborescence.
|
||||
*/
|
||||
#define SIDEBAR_PAGE_FOLDER \
|
||||
"folder"
|
||||
|
||||
/**
|
||||
* @brief Identifiant de la page contenant les preuves.
|
||||
*/
|
||||
#define SIDEBAR_PAGE_EVIDENCE \
|
||||
"evidence"
|
||||
|
||||
/**
|
||||
* @brief État vide de l'onglet Preuves.
|
||||
*/
|
||||
#define SIDEBAR_EVIDENCE_STATE_EMPTY \
|
||||
"empty"
|
||||
|
||||
/**
|
||||
* @brief État contenant l'arbre des preuves.
|
||||
*/
|
||||
#define SIDEBAR_EVIDENCE_STATE_TREE \
|
||||
"tree"
|
||||
|
||||
/**
|
||||
* @struct Sidebar
|
||||
|
|
@ -25,23 +50,74 @@ struct Sidebar
|
|||
{
|
||||
GtkWidget *root_widget;
|
||||
GtkWidget *title_label;
|
||||
|
||||
GtkWidget *page_switcher;
|
||||
GtkWidget *stack;
|
||||
|
||||
GtkWidget *folder_page;
|
||||
|
||||
GtkWidget *evidence_page;
|
||||
GtkWidget *evidence_content_stack;
|
||||
GtkWidget *evidence_empty_page;
|
||||
GtkWidget *evidence_empty_label;
|
||||
|
||||
InvestigationTreeView *tree_view;
|
||||
EvidenceTreeView *evidence_tree_view;
|
||||
|
||||
SidebarEvidenceSelectionCallback
|
||||
evidence_selection_callback;
|
||||
|
||||
gpointer evidence_selection_user_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Relaie la sélection provenant de EvidenceTreeView.
|
||||
*/
|
||||
static void sidebar_on_evidence_selected(
|
||||
const char *evidence_identifier,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
Sidebar *sidebar =
|
||||
user_data;
|
||||
|
||||
if (sidebar == NULL ||
|
||||
sidebar->evidence_selection_callback == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sidebar->evidence_selection_callback(
|
||||
evidence_identifier,
|
||||
sidebar->evidence_selection_user_data
|
||||
);
|
||||
}
|
||||
|
||||
Sidebar *sidebar_new(void)
|
||||
{
|
||||
Sidebar *sidebar = NULL;
|
||||
sidebar = g_new0(Sidebar, 1);
|
||||
GtkWidget *tree_view_widget = NULL;
|
||||
|
||||
sidebar->root_widget = gtk_box_new(
|
||||
GtkWidget *tree_view_widget = NULL;
|
||||
GtkWidget *evidence_tree_widget = NULL;
|
||||
|
||||
sidebar =
|
||||
g_new0(
|
||||
Sidebar,
|
||||
1
|
||||
);
|
||||
|
||||
sidebar->root_widget =
|
||||
gtk_box_new(
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
0
|
||||
);
|
||||
|
||||
if (sidebar->root_widget == NULL)
|
||||
{
|
||||
sidebar_free(sidebar);
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -51,10 +127,23 @@ Sidebar *sidebar_new(void)
|
|||
-1
|
||||
);
|
||||
|
||||
sidebar->title_label = gtk_label_new(
|
||||
/*
|
||||
* Titre de l'enquête active.
|
||||
*/
|
||||
sidebar->title_label =
|
||||
gtk_label_new(
|
||||
"Dossier d'enquête"
|
||||
);
|
||||
|
||||
if (sidebar->title_label == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_widget_set_halign(
|
||||
sidebar->title_label,
|
||||
GTK_ALIGN_START
|
||||
|
|
@ -77,29 +166,155 @@ Sidebar *sidebar_new(void)
|
|||
|
||||
gtk_widget_set_margin_bottom(
|
||||
sidebar->title_label,
|
||||
12
|
||||
8
|
||||
);
|
||||
|
||||
gtk_box_append(
|
||||
GTK_BOX(sidebar->root_widget),
|
||||
GTK_BOX(
|
||||
sidebar->root_widget
|
||||
),
|
||||
sidebar->title_label
|
||||
);
|
||||
|
||||
sidebar->tree_view = investigation_tree_view_new();
|
||||
/*
|
||||
* GtkStack contenant les pages Dossier et Preuves.
|
||||
*/
|
||||
sidebar->stack =
|
||||
gtk_stack_new();
|
||||
|
||||
if (sidebar->tree_view == NULL)
|
||||
if (sidebar->stack == NULL)
|
||||
{
|
||||
sidebar_free(sidebar);
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree_view_widget = investigation_tree_view_get_widget(
|
||||
gtk_widget_set_hexpand(
|
||||
sidebar->stack,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_vexpand(
|
||||
sidebar->stack,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_stack_set_transition_type(
|
||||
GTK_STACK(
|
||||
sidebar->stack
|
||||
),
|
||||
GTK_STACK_TRANSITION_TYPE_CROSSFADE
|
||||
);
|
||||
|
||||
/*
|
||||
* Boutons permettant de sélectionner une page du GtkStack.
|
||||
*/
|
||||
sidebar->page_switcher =
|
||||
gtk_stack_switcher_new();
|
||||
|
||||
if (sidebar->page_switcher == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_stack_switcher_set_stack(
|
||||
GTK_STACK_SWITCHER(
|
||||
sidebar->page_switcher
|
||||
),
|
||||
GTK_STACK(
|
||||
sidebar->stack
|
||||
)
|
||||
);
|
||||
|
||||
gtk_widget_set_hexpand(
|
||||
sidebar->page_switcher,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_halign(
|
||||
sidebar->page_switcher,
|
||||
GTK_ALIGN_CENTER
|
||||
);
|
||||
|
||||
gtk_widget_set_margin_start(
|
||||
sidebar->page_switcher,
|
||||
8
|
||||
);
|
||||
|
||||
gtk_widget_set_margin_end(
|
||||
sidebar->page_switcher,
|
||||
8
|
||||
);
|
||||
|
||||
gtk_widget_set_margin_bottom(
|
||||
sidebar->page_switcher,
|
||||
8
|
||||
);
|
||||
|
||||
gtk_box_append(
|
||||
GTK_BOX(
|
||||
sidebar->root_widget
|
||||
),
|
||||
sidebar->page_switcher
|
||||
);
|
||||
|
||||
/*
|
||||
* Page Dossier.
|
||||
*/
|
||||
sidebar->folder_page =
|
||||
gtk_box_new(
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
0
|
||||
);
|
||||
|
||||
if (sidebar->folder_page == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_widget_set_hexpand(
|
||||
sidebar->folder_page,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_vexpand(
|
||||
sidebar->folder_page,
|
||||
TRUE
|
||||
);
|
||||
|
||||
sidebar->tree_view =
|
||||
investigation_tree_view_new();
|
||||
|
||||
if (sidebar->tree_view == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree_view_widget =
|
||||
investigation_tree_view_get_widget(
|
||||
sidebar->tree_view
|
||||
);
|
||||
|
||||
if (tree_view_widget == NULL)
|
||||
{
|
||||
sidebar_free(sidebar);
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -114,10 +329,279 @@ Sidebar *sidebar_new(void)
|
|||
);
|
||||
|
||||
gtk_box_append(
|
||||
GTK_BOX(sidebar->root_widget),
|
||||
GTK_BOX(
|
||||
sidebar->folder_page
|
||||
),
|
||||
tree_view_widget
|
||||
);
|
||||
|
||||
gtk_stack_add_titled(
|
||||
GTK_STACK(
|
||||
sidebar->stack
|
||||
),
|
||||
sidebar->folder_page,
|
||||
SIDEBAR_PAGE_FOLDER,
|
||||
"Dossier"
|
||||
);
|
||||
|
||||
/*
|
||||
* Page Preuves.
|
||||
*/
|
||||
sidebar->evidence_page =
|
||||
gtk_box_new(
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
0
|
||||
);
|
||||
|
||||
if (sidebar->evidence_page == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_widget_set_hexpand(
|
||||
sidebar->evidence_page,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_vexpand(
|
||||
sidebar->evidence_page,
|
||||
TRUE
|
||||
);
|
||||
|
||||
/*
|
||||
* Stack interne alternant entre l'état vide
|
||||
* et l'arborescence des preuves.
|
||||
*/
|
||||
sidebar->evidence_content_stack =
|
||||
gtk_stack_new();
|
||||
|
||||
if (sidebar->evidence_content_stack == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_widget_set_hexpand(
|
||||
sidebar->evidence_content_stack,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_vexpand(
|
||||
sidebar->evidence_content_stack,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_stack_set_transition_type(
|
||||
GTK_STACK(
|
||||
sidebar->evidence_content_stack
|
||||
),
|
||||
GTK_STACK_TRANSITION_TYPE_CROSSFADE
|
||||
);
|
||||
|
||||
/*
|
||||
* État vide.
|
||||
*/
|
||||
sidebar->evidence_empty_page =
|
||||
gtk_box_new(
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
0
|
||||
);
|
||||
|
||||
if (sidebar->evidence_empty_page == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_widget_set_hexpand(
|
||||
sidebar->evidence_empty_page,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_vexpand(
|
||||
sidebar->evidence_empty_page,
|
||||
TRUE
|
||||
);
|
||||
|
||||
sidebar->evidence_empty_label =
|
||||
gtk_label_new(
|
||||
"Aucune preuve importée dans cette enquête."
|
||||
);
|
||||
|
||||
if (sidebar->evidence_empty_label == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_label_set_wrap(
|
||||
GTK_LABEL(
|
||||
sidebar->evidence_empty_label
|
||||
),
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_label_set_justify(
|
||||
GTK_LABEL(
|
||||
sidebar->evidence_empty_label
|
||||
),
|
||||
GTK_JUSTIFY_CENTER
|
||||
);
|
||||
|
||||
gtk_widget_set_halign(
|
||||
sidebar->evidence_empty_label,
|
||||
GTK_ALIGN_CENTER
|
||||
);
|
||||
|
||||
gtk_widget_set_valign(
|
||||
sidebar->evidence_empty_label,
|
||||
GTK_ALIGN_CENTER
|
||||
);
|
||||
|
||||
gtk_widget_set_hexpand(
|
||||
sidebar->evidence_empty_label,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_vexpand(
|
||||
sidebar->evidence_empty_label,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_margin_start(
|
||||
sidebar->evidence_empty_label,
|
||||
20
|
||||
);
|
||||
|
||||
gtk_widget_set_margin_end(
|
||||
sidebar->evidence_empty_label,
|
||||
20
|
||||
);
|
||||
|
||||
gtk_box_append(
|
||||
GTK_BOX(
|
||||
sidebar->evidence_empty_page
|
||||
),
|
||||
sidebar->evidence_empty_label
|
||||
);
|
||||
|
||||
gtk_stack_add_named(
|
||||
GTK_STACK(
|
||||
sidebar->evidence_content_stack
|
||||
),
|
||||
sidebar->evidence_empty_page,
|
||||
SIDEBAR_EVIDENCE_STATE_EMPTY
|
||||
);
|
||||
|
||||
/*
|
||||
* Arborescence des catégories et preuves.
|
||||
*/
|
||||
sidebar->evidence_tree_view =
|
||||
evidence_tree_view_new();
|
||||
|
||||
if (sidebar->evidence_tree_view == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evidence_tree_widget =
|
||||
evidence_tree_view_get_widget(
|
||||
sidebar->evidence_tree_view
|
||||
);
|
||||
|
||||
if (evidence_tree_widget == NULL)
|
||||
{
|
||||
sidebar_free(
|
||||
sidebar
|
||||
);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gtk_widget_set_hexpand(
|
||||
evidence_tree_widget,
|
||||
TRUE
|
||||
);
|
||||
|
||||
gtk_widget_set_vexpand(
|
||||
evidence_tree_widget,
|
||||
TRUE
|
||||
);
|
||||
|
||||
evidence_tree_view_set_selection_callback(
|
||||
sidebar->evidence_tree_view,
|
||||
sidebar_on_evidence_selected,
|
||||
sidebar
|
||||
);
|
||||
|
||||
gtk_stack_add_named(
|
||||
GTK_STACK(
|
||||
sidebar->evidence_content_stack
|
||||
),
|
||||
evidence_tree_widget,
|
||||
SIDEBAR_EVIDENCE_STATE_TREE
|
||||
);
|
||||
|
||||
/*
|
||||
* Aucun modèle n'est encore installé.
|
||||
*/
|
||||
gtk_stack_set_visible_child_name(
|
||||
GTK_STACK(
|
||||
sidebar->evidence_content_stack
|
||||
),
|
||||
SIDEBAR_EVIDENCE_STATE_EMPTY
|
||||
);
|
||||
|
||||
gtk_box_append(
|
||||
GTK_BOX(
|
||||
sidebar->evidence_page
|
||||
),
|
||||
sidebar->evidence_content_stack
|
||||
);
|
||||
|
||||
gtk_stack_add_titled(
|
||||
GTK_STACK(
|
||||
sidebar->stack
|
||||
),
|
||||
sidebar->evidence_page,
|
||||
SIDEBAR_PAGE_EVIDENCE,
|
||||
"Preuves"
|
||||
);
|
||||
|
||||
/*
|
||||
* L'onglet Dossier reste sélectionné au démarrage.
|
||||
*/
|
||||
gtk_stack_set_visible_child_name(
|
||||
GTK_STACK(
|
||||
sidebar->stack
|
||||
),
|
||||
SIDEBAR_PAGE_FOLDER
|
||||
);
|
||||
|
||||
gtk_box_append(
|
||||
GTK_BOX(
|
||||
sidebar->root_widget
|
||||
),
|
||||
sidebar->stack
|
||||
);
|
||||
|
||||
return sidebar;
|
||||
}
|
||||
|
||||
|
|
@ -209,6 +693,64 @@ void sidebar_set_selection_callback(
|
|||
);
|
||||
}
|
||||
|
||||
void sidebar_set_evidence_model(
|
||||
Sidebar *sidebar,
|
||||
EvidenceCategoryModel *evidence_category_model
|
||||
)
|
||||
{
|
||||
if (sidebar == NULL ||
|
||||
sidebar->evidence_tree_view == NULL ||
|
||||
sidebar->evidence_content_stack == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
evidence_tree_view_set_model(
|
||||
sidebar->evidence_tree_view,
|
||||
evidence_category_model
|
||||
);
|
||||
|
||||
if (evidence_category_model == NULL ||
|
||||
evidence_category_model_get_count(
|
||||
evidence_category_model
|
||||
) == 0)
|
||||
{
|
||||
gtk_stack_set_visible_child_name(
|
||||
GTK_STACK(
|
||||
sidebar->evidence_content_stack
|
||||
),
|
||||
SIDEBAR_EVIDENCE_STATE_EMPTY
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_stack_set_visible_child_name(
|
||||
GTK_STACK(
|
||||
sidebar->evidence_content_stack
|
||||
),
|
||||
SIDEBAR_EVIDENCE_STATE_TREE
|
||||
);
|
||||
}
|
||||
|
||||
void sidebar_set_evidence_selection_callback(
|
||||
Sidebar *sidebar,
|
||||
SidebarEvidenceSelectionCallback callback,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
if (sidebar == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sidebar->evidence_selection_callback =
|
||||
callback;
|
||||
|
||||
sidebar->evidence_selection_user_data =
|
||||
user_data;
|
||||
}
|
||||
|
||||
void sidebar_free(Sidebar *sidebar)
|
||||
{
|
||||
if (sidebar == NULL)
|
||||
|
|
@ -218,6 +760,19 @@ void sidebar_free(Sidebar *sidebar)
|
|||
|
||||
investigation_tree_view_free(sidebar->tree_view);
|
||||
|
||||
if (sidebar->evidence_tree_view != NULL)
|
||||
{
|
||||
evidence_tree_view_set_selection_callback(
|
||||
sidebar->evidence_tree_view,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
evidence_tree_view_free(
|
||||
sidebar->evidence_tree_view
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Les widgets GTK sont intégrés dans l'arbre de widgets de la fenêtre.
|
||||
* GTK gère leur destruction lorsque la fenêtre est détruite.
|
||||
|
|
|
|||
332
tests/test_evidence_category_item.c
Normal file
332
tests/test_evidence_category_item.c
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/******************************************************************************
|
||||
* @file test_evidence_category_item.c
|
||||
* @brief Tests unitaires de EvidenceCategoryItem.
|
||||
******************************************************************************/
|
||||
|
||||
#include "widgets/evidence_category_item.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* @brief Crée une preuve métier valide.
|
||||
*/
|
||||
static EvidenceRecord *test_evidence_category_item_create_record(void)
|
||||
{
|
||||
EvidenceRecord *evidence_record = NULL;
|
||||
|
||||
GError *error = NULL;
|
||||
|
||||
evidence_record =
|
||||
evidence_record_new(
|
||||
"550e8400-e29b-41d4-a716-446655440000",
|
||||
"capture-instagram.png",
|
||||
"550e8400-e29b-41d4-a716-446655440000.png",
|
||||
"01_Preuves_Originales/Documents/"
|
||||
"550e8400-e29b-41d4-a716-446655440000.png",
|
||||
"image",
|
||||
4096,
|
||||
"00000000000000000000000000000000"
|
||||
"00000000000000000000000000000000",
|
||||
"2026-07-20T07:16:01Z",
|
||||
"2026-07-19T18:30:00Z",
|
||||
"Conversation Instagram",
|
||||
"Capture d'écran reçue.",
|
||||
EVIDENCE_INTEGRITY_STATUS_UNKNOWN,
|
||||
&error
|
||||
);
|
||||
|
||||
g_assert_no_error(
|
||||
error
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
return evidence_record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie la création d'une catégorie vide.
|
||||
*/
|
||||
static void test_evidence_category_item_new_valid(void)
|
||||
{
|
||||
EvidenceCategoryItem *evidence_category_item =
|
||||
NULL;
|
||||
|
||||
evidence_category_item =
|
||||
evidence_category_item_new(
|
||||
" image ",
|
||||
" Images "
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_category_item
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_category_item_get_type_identifier(
|
||||
evidence_category_item
|
||||
),
|
||||
==,
|
||||
"image"
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_category_item_get_label(
|
||||
evidence_category_item
|
||||
),
|
||||
==,
|
||||
"Images"
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_category_item_get_count(
|
||||
evidence_category_item
|
||||
),
|
||||
==,
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_category_item_get_children(
|
||||
evidence_category_item
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
g_list_model_get_item_type(
|
||||
evidence_category_item_get_children(
|
||||
evidence_category_item
|
||||
)
|
||||
),
|
||||
==,
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_category_item
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie l'ajout et la propriété des preuves.
|
||||
*/
|
||||
static void test_evidence_category_item_append(void)
|
||||
{
|
||||
EvidenceCategoryItem *evidence_category_item =
|
||||
NULL;
|
||||
|
||||
EvidenceRecord *evidence_record =
|
||||
NULL;
|
||||
|
||||
EvidenceListItem *evidence_list_item =
|
||||
NULL;
|
||||
|
||||
EvidenceListItem *stored_item =
|
||||
NULL;
|
||||
|
||||
evidence_category_item =
|
||||
evidence_category_item_new(
|
||||
"image",
|
||||
"Images"
|
||||
);
|
||||
|
||||
evidence_record =
|
||||
test_evidence_category_item_create_record();
|
||||
|
||||
evidence_list_item =
|
||||
evidence_list_item_new(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_category_item
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_category_item_append(
|
||||
evidence_category_item,
|
||||
evidence_list_item
|
||||
)
|
||||
);
|
||||
|
||||
/*
|
||||
* La catégorie possède maintenant sa propre référence.
|
||||
*/
|
||||
g_object_unref(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
evidence_record_free(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_category_item_get_count(
|
||||
evidence_category_item
|
||||
),
|
||||
==,
|
||||
1
|
||||
);
|
||||
|
||||
stored_item =
|
||||
g_list_model_get_item(
|
||||
evidence_category_item_get_children(
|
||||
evidence_category_item
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
stored_item
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_identifier(
|
||||
stored_item
|
||||
),
|
||||
==,
|
||||
"550e8400-e29b-41d4-a716-446655440000"
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_original_name(
|
||||
stored_item
|
||||
),
|
||||
==,
|
||||
"capture-instagram.png"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
stored_item
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_category_item
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie les arguments invalides.
|
||||
*/
|
||||
static void test_evidence_category_item_invalid_arguments(void)
|
||||
{
|
||||
EvidenceCategoryItem *evidence_category_item =
|
||||
NULL;
|
||||
|
||||
g_assert_null(
|
||||
evidence_category_item_new(
|
||||
NULL,
|
||||
"Images"
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_category_item_new(
|
||||
"image",
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_category_item_new(
|
||||
" ",
|
||||
"Images"
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_category_item_new(
|
||||
"image",
|
||||
" "
|
||||
)
|
||||
);
|
||||
|
||||
evidence_category_item =
|
||||
evidence_category_item_new(
|
||||
"image",
|
||||
"Images"
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_category_item
|
||||
);
|
||||
|
||||
g_assert_false(
|
||||
evidence_category_item_append(
|
||||
evidence_category_item,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_false(
|
||||
evidence_category_item_append(
|
||||
NULL,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_category_item_get_type_identifier(
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_category_item_get_label(
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_category_item_get_count(
|
||||
NULL
|
||||
),
|
||||
==,
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_category_item_get_children(
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_clear_object(
|
||||
&evidence_category_item
|
||||
);
|
||||
}
|
||||
|
||||
int main(
|
||||
int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
g_test_init(
|
||||
&argc,
|
||||
&argv,
|
||||
NULL
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-category-item/new-valid",
|
||||
test_evidence_category_item_new_valid
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-category-item/append",
|
||||
test_evidence_category_item_append
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-category-item/invalid-arguments",
|
||||
test_evidence_category_item_invalid_arguments
|
||||
);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
637
tests/test_evidence_category_model.c
Normal file
637
tests/test_evidence_category_model.c
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
/******************************************************************************
|
||||
* @file test_evidence_category_model.c
|
||||
* @brief Tests unitaires de EvidenceCategoryModel.
|
||||
******************************************************************************/
|
||||
|
||||
#include "widgets/evidence_category_model.h"
|
||||
|
||||
#include "widgets/evidence_category_item.h"
|
||||
#include "widgets/evidence_list_item.h"
|
||||
|
||||
#include "models/evidence_record.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* @brief Crée un élément d'affichage valide.
|
||||
*/
|
||||
static EvidenceListItem *test_evidence_category_model_create_item(
|
||||
const char *identifier,
|
||||
const char *original_name,
|
||||
const char *type_identifier
|
||||
)
|
||||
{
|
||||
EvidenceRecord *evidence_record = NULL;
|
||||
EvidenceListItem *evidence_list_item = NULL;
|
||||
|
||||
char *internal_name = NULL;
|
||||
char *relative_path = NULL;
|
||||
|
||||
GError *error = NULL;
|
||||
|
||||
internal_name =
|
||||
g_strdup_printf(
|
||||
"%s.bin",
|
||||
identifier
|
||||
);
|
||||
|
||||
relative_path =
|
||||
g_strdup_printf(
|
||||
"01_Preuves_Originales/Documents/%s.bin",
|
||||
identifier
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
internal_name
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
relative_path
|
||||
);
|
||||
|
||||
evidence_record =
|
||||
evidence_record_new(
|
||||
identifier,
|
||||
original_name,
|
||||
internal_name,
|
||||
relative_path,
|
||||
type_identifier,
|
||||
4096,
|
||||
"00000000000000000000000000000000"
|
||||
"00000000000000000000000000000000",
|
||||
"2026-07-20T07:16:01Z",
|
||||
"2026-07-19T18:30:00Z",
|
||||
NULL,
|
||||
NULL,
|
||||
EVIDENCE_INTEGRITY_STATUS_UNKNOWN,
|
||||
&error
|
||||
);
|
||||
|
||||
g_assert_no_error(
|
||||
error
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
evidence_list_item =
|
||||
evidence_list_item_new(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
evidence_record_free(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_free(
|
||||
relative_path
|
||||
);
|
||||
|
||||
g_free(
|
||||
internal_name
|
||||
);
|
||||
|
||||
return evidence_list_item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ajoute une preuve à un GListStore.
|
||||
*/
|
||||
static void test_evidence_category_model_append_item(
|
||||
GListStore *evidence_items,
|
||||
EvidenceListItem *evidence_list_item
|
||||
)
|
||||
{
|
||||
g_list_store_append(
|
||||
evidence_items,
|
||||
G_OBJECT(
|
||||
evidence_list_item
|
||||
)
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_list_item
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Crée la table des libellés de types.
|
||||
*/
|
||||
static GHashTable *test_evidence_category_model_create_labels(void)
|
||||
{
|
||||
GHashTable *type_labels =
|
||||
NULL;
|
||||
|
||||
type_labels =
|
||||
g_hash_table_new_full(
|
||||
g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
g_free
|
||||
);
|
||||
|
||||
g_hash_table_insert(
|
||||
type_labels,
|
||||
g_strdup("document"),
|
||||
g_strdup("Documents")
|
||||
);
|
||||
|
||||
g_hash_table_insert(
|
||||
type_labels,
|
||||
g_strdup("image"),
|
||||
g_strdup("Images")
|
||||
);
|
||||
|
||||
return type_labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie la création d'un modèle vide.
|
||||
*/
|
||||
static void test_evidence_category_model_new_empty(void)
|
||||
{
|
||||
EvidenceCategoryModel *evidence_category_model =
|
||||
NULL;
|
||||
|
||||
evidence_category_model =
|
||||
evidence_category_model_new();
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_category_model
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_category_model_get_list_model(
|
||||
evidence_category_model
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_category_model_get_count(
|
||||
evidence_category_model
|
||||
),
|
||||
==,
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
g_list_model_get_item_type(
|
||||
evidence_category_model_get_list_model(
|
||||
evidence_category_model
|
||||
)
|
||||
),
|
||||
==,
|
||||
EVIDENCE_TYPE_CATEGORY_ITEM
|
||||
);
|
||||
|
||||
evidence_category_model_free(
|
||||
evidence_category_model
|
||||
);
|
||||
|
||||
evidence_category_model_free(
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie le regroupement et le tri.
|
||||
*/
|
||||
static void test_evidence_category_model_group_and_sort(void)
|
||||
{
|
||||
EvidenceCategoryModel *evidence_category_model =
|
||||
NULL;
|
||||
|
||||
GListStore *evidence_items =
|
||||
NULL;
|
||||
|
||||
GHashTable *type_labels =
|
||||
NULL;
|
||||
|
||||
EvidenceCategoryItem *documents_category =
|
||||
NULL;
|
||||
|
||||
EvidenceCategoryItem *images_category =
|
||||
NULL;
|
||||
|
||||
EvidenceListItem *first_image =
|
||||
NULL;
|
||||
|
||||
evidence_category_model =
|
||||
evidence_category_model_new();
|
||||
|
||||
evidence_items =
|
||||
g_list_store_new(
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
);
|
||||
|
||||
type_labels =
|
||||
test_evidence_category_model_create_labels();
|
||||
|
||||
test_evidence_category_model_append_item(
|
||||
evidence_items,
|
||||
test_evidence_category_model_create_item(
|
||||
"550e8400-e29b-41d4-a716-446655440000",
|
||||
"zeta.png",
|
||||
"image"
|
||||
)
|
||||
);
|
||||
|
||||
test_evidence_category_model_append_item(
|
||||
evidence_items,
|
||||
test_evidence_category_model_create_item(
|
||||
"550e8400-e29b-41d4-a716-446655440001",
|
||||
"rapport.pdf",
|
||||
"document"
|
||||
)
|
||||
);
|
||||
|
||||
test_evidence_category_model_append_item(
|
||||
evidence_items,
|
||||
test_evidence_category_model_create_item(
|
||||
"550e8400-e29b-41d4-a716-446655440002",
|
||||
"alpha.png",
|
||||
"image"
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_category_model_replace(
|
||||
evidence_category_model,
|
||||
G_LIST_MODEL(
|
||||
evidence_items
|
||||
),
|
||||
type_labels,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_category_model_get_count(
|
||||
evidence_category_model
|
||||
),
|
||||
==,
|
||||
2
|
||||
);
|
||||
|
||||
documents_category =
|
||||
g_list_model_get_item(
|
||||
evidence_category_model_get_list_model(
|
||||
evidence_category_model
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
images_category =
|
||||
g_list_model_get_item(
|
||||
evidence_category_model_get_list_model(
|
||||
evidence_category_model
|
||||
),
|
||||
1
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_category_item_get_label(
|
||||
documents_category
|
||||
),
|
||||
==,
|
||||
"Documents"
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_category_item_get_count(
|
||||
documents_category
|
||||
),
|
||||
==,
|
||||
1
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_category_item_get_label(
|
||||
images_category
|
||||
),
|
||||
==,
|
||||
"Images"
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_category_item_get_count(
|
||||
images_category
|
||||
),
|
||||
==,
|
||||
2
|
||||
);
|
||||
|
||||
first_image =
|
||||
g_list_model_get_item(
|
||||
evidence_category_item_get_children(
|
||||
images_category
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_original_name(
|
||||
first_image
|
||||
),
|
||||
==,
|
||||
"alpha.png"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
first_image
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
images_category
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
documents_category
|
||||
);
|
||||
|
||||
g_hash_table_unref(
|
||||
type_labels
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_items
|
||||
);
|
||||
|
||||
evidence_category_model_free(
|
||||
evidence_category_model
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie le libellé de secours pour un type inconnu.
|
||||
*/
|
||||
static void test_evidence_category_model_unknown_type(void)
|
||||
{
|
||||
EvidenceCategoryModel *evidence_category_model =
|
||||
NULL;
|
||||
|
||||
GListStore *evidence_items =
|
||||
NULL;
|
||||
|
||||
EvidenceCategoryItem *category =
|
||||
NULL;
|
||||
|
||||
evidence_category_model =
|
||||
evidence_category_model_new();
|
||||
|
||||
evidence_items =
|
||||
g_list_store_new(
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
);
|
||||
|
||||
test_evidence_category_model_append_item(
|
||||
evidence_items,
|
||||
test_evidence_category_model_create_item(
|
||||
"550e8400-e29b-41d4-a716-446655440003",
|
||||
"archive.bin",
|
||||
"unknown"
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_category_model_replace(
|
||||
evidence_category_model,
|
||||
G_LIST_MODEL(
|
||||
evidence_items
|
||||
),
|
||||
NULL,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
category =
|
||||
g_list_model_get_item(
|
||||
evidence_category_model_get_list_model(
|
||||
evidence_category_model
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_category_item_get_label(
|
||||
category
|
||||
),
|
||||
==,
|
||||
"unknown"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
category
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_items
|
||||
);
|
||||
|
||||
evidence_category_model_free(
|
||||
evidence_category_model
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie les remplacements successifs et les erreurs.
|
||||
*/
|
||||
static void test_evidence_category_model_replace_and_clear(void)
|
||||
{
|
||||
EvidenceCategoryModel *evidence_category_model =
|
||||
NULL;
|
||||
|
||||
GListStore *valid_items =
|
||||
NULL;
|
||||
|
||||
GListStore *empty_items =
|
||||
NULL;
|
||||
|
||||
GListStore *invalid_items =
|
||||
NULL;
|
||||
|
||||
GObject *invalid_object =
|
||||
NULL;
|
||||
|
||||
GError *error = NULL;
|
||||
|
||||
evidence_category_model =
|
||||
evidence_category_model_new();
|
||||
|
||||
valid_items =
|
||||
g_list_store_new(
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
);
|
||||
|
||||
empty_items =
|
||||
g_list_store_new(
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
);
|
||||
|
||||
invalid_items =
|
||||
g_list_store_new(
|
||||
G_TYPE_OBJECT
|
||||
);
|
||||
|
||||
test_evidence_category_model_append_item(
|
||||
valid_items,
|
||||
test_evidence_category_model_create_item(
|
||||
"550e8400-e29b-41d4-a716-446655440004",
|
||||
"preuve.txt",
|
||||
"document"
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_category_model_replace(
|
||||
evidence_category_model,
|
||||
G_LIST_MODEL(
|
||||
valid_items
|
||||
),
|
||||
NULL,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
invalid_object =
|
||||
g_object_new(
|
||||
G_TYPE_OBJECT,
|
||||
NULL
|
||||
);
|
||||
|
||||
g_list_store_append(
|
||||
invalid_items,
|
||||
invalid_object
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
invalid_object
|
||||
);
|
||||
|
||||
g_assert_false(
|
||||
evidence_category_model_replace(
|
||||
evidence_category_model,
|
||||
G_LIST_MODEL(
|
||||
invalid_items
|
||||
),
|
||||
NULL,
|
||||
&error
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_error(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_INVALID_ARGUMENT
|
||||
);
|
||||
|
||||
g_clear_error(
|
||||
&error
|
||||
);
|
||||
|
||||
/*
|
||||
* L'ancien contenu est conservé après l'échec.
|
||||
*/
|
||||
g_assert_cmpuint(
|
||||
evidence_category_model_get_count(
|
||||
evidence_category_model
|
||||
),
|
||||
==,
|
||||
1
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_category_model_replace(
|
||||
evidence_category_model,
|
||||
G_LIST_MODEL(
|
||||
empty_items
|
||||
),
|
||||
NULL,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_category_model_get_count(
|
||||
evidence_category_model
|
||||
),
|
||||
==,
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_false(
|
||||
evidence_category_model_replace(
|
||||
NULL,
|
||||
G_LIST_MODEL(
|
||||
valid_items
|
||||
),
|
||||
NULL,
|
||||
&error
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_error(
|
||||
error,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR,
|
||||
EVIDENCE_CATEGORY_MODEL_ERROR_INVALID_ARGUMENT
|
||||
);
|
||||
|
||||
g_clear_error(
|
||||
&error
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
invalid_items
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
empty_items
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
valid_items
|
||||
);
|
||||
|
||||
evidence_category_model_free(
|
||||
evidence_category_model
|
||||
);
|
||||
}
|
||||
|
||||
int main(
|
||||
int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
g_test_init(
|
||||
&argc,
|
||||
&argv,
|
||||
NULL
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-category-model/new-empty",
|
||||
test_evidence_category_model_new_empty
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-category-model/group-and-sort",
|
||||
test_evidence_category_model_group_and_sort
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-category-model/unknown-type",
|
||||
test_evidence_category_model_unknown_type
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-category-model/replace-and-clear",
|
||||
test_evidence_category_model_replace_and_clear
|
||||
);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
336
tests/test_evidence_list_item.c
Normal file
336
tests/test_evidence_list_item.c
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
/******************************************************************************
|
||||
* @file test_evidence_list_item.c
|
||||
* @brief Tests unitaires de EvidenceListItem.
|
||||
******************************************************************************/
|
||||
|
||||
#include "widgets/evidence_list_item.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* @brief Crée une preuve métier valide pour les tests.
|
||||
*/
|
||||
static EvidenceRecord *test_evidence_list_item_create_record(
|
||||
const char *collected_at,
|
||||
const char *source,
|
||||
EvidenceIntegrityStatus integrity_status
|
||||
)
|
||||
{
|
||||
EvidenceRecord *evidence_record = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
evidence_record =
|
||||
evidence_record_new(
|
||||
"550e8400-e29b-41d4-a716-446655440000",
|
||||
"capture_originale.png",
|
||||
"550e8400-e29b-41d4-a716-446655440000.png",
|
||||
"01_Preuves_Originales/Documents/"
|
||||
"550e8400-e29b-41d4-a716-446655440000.png",
|
||||
"image",
|
||||
4096,
|
||||
"00000000000000000000000000000000"
|
||||
"00000000000000000000000000000000",
|
||||
"2026-07-20T07:16:01Z",
|
||||
collected_at,
|
||||
source,
|
||||
"Capture reçue pendant la conversation.",
|
||||
integrity_status,
|
||||
&error
|
||||
);
|
||||
|
||||
g_assert_no_error(
|
||||
error
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
return evidence_record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie la copie des valeurs nominales.
|
||||
*/
|
||||
static void test_evidence_list_item_new_valid(void)
|
||||
{
|
||||
EvidenceRecord *evidence_record = NULL;
|
||||
EvidenceListItem *evidence_list_item = NULL;
|
||||
|
||||
evidence_record =
|
||||
test_evidence_list_item_create_record(
|
||||
"2026-07-19T18:30:00Z",
|
||||
"Conversation Instagram",
|
||||
EVIDENCE_INTEGRITY_STATUS_VALID
|
||||
);
|
||||
|
||||
evidence_list_item =
|
||||
evidence_list_item_new(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_original_name(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
"capture_originale.png"
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_type_identifier(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
"image"
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_list_item_get_size_bytes(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
4096
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_collected_at(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
"2026-07-19T18:30:00Z"
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_source(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
"Conversation Instagram"
|
||||
);
|
||||
|
||||
g_assert_cmpint(
|
||||
evidence_list_item_get_integrity_status(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
EVIDENCE_INTEGRITY_STATUS_VALID
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_integrity_status_label(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
"Valide"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
evidence_record_free(
|
||||
evidence_record
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie que les chaînes ne dépendent plus du modèle métier.
|
||||
*/
|
||||
static void test_evidence_list_item_copies_strings(void)
|
||||
{
|
||||
EvidenceRecord *evidence_record = NULL;
|
||||
EvidenceListItem *evidence_list_item = NULL;
|
||||
|
||||
evidence_record =
|
||||
test_evidence_list_item_create_record(
|
||||
"2026-07-19T18:30:00Z",
|
||||
"Email reçu",
|
||||
EVIDENCE_INTEGRITY_STATUS_UNKNOWN
|
||||
);
|
||||
|
||||
evidence_list_item =
|
||||
evidence_list_item_new(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
evidence_record_free(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_original_name(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
"capture_originale.png"
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_source(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
"Email reçu"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_list_item
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie les valeurs facultatives absentes.
|
||||
*/
|
||||
static void test_evidence_list_item_optional_values(void)
|
||||
{
|
||||
EvidenceRecord *evidence_record = NULL;
|
||||
EvidenceListItem *evidence_list_item = NULL;
|
||||
|
||||
evidence_record =
|
||||
test_evidence_list_item_create_record(
|
||||
NULL,
|
||||
NULL,
|
||||
EVIDENCE_INTEGRITY_STATUS_UNKNOWN
|
||||
);
|
||||
|
||||
evidence_list_item =
|
||||
evidence_list_item_new(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_list_item_get_collected_at(
|
||||
evidence_list_item
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_list_item_get_source(
|
||||
evidence_list_item
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_integrity_status_label(
|
||||
evidence_list_item
|
||||
),
|
||||
==,
|
||||
"Non vérifiée"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
evidence_list_item
|
||||
);
|
||||
|
||||
evidence_record_free(
|
||||
evidence_record
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie les arguments NULL.
|
||||
*/
|
||||
static void test_evidence_list_item_null_values(void)
|
||||
{
|
||||
EvidenceListItem *evidence_list_item = NULL;
|
||||
|
||||
g_assert_null(
|
||||
evidence_list_item_new(
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_list_item_get_original_name(
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_list_item_get_type_identifier(
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_list_item_get_size_bytes(
|
||||
NULL
|
||||
),
|
||||
==,
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_list_item_get_collected_at(
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_null(
|
||||
evidence_list_item_get_source(
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpint(
|
||||
evidence_list_item_get_integrity_status(
|
||||
NULL
|
||||
),
|
||||
==,
|
||||
EVIDENCE_INTEGRITY_STATUS_UNKNOWN
|
||||
);
|
||||
|
||||
/*
|
||||
* g_clear_object() accepte un pointeur contenant NULL.
|
||||
*/
|
||||
g_clear_object(
|
||||
&evidence_list_item
|
||||
);
|
||||
}
|
||||
|
||||
int main(
|
||||
int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
g_test_init(
|
||||
&argc,
|
||||
&argv,
|
||||
NULL
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-item/new-valid",
|
||||
test_evidence_list_item_new_valid
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-item/copies-strings",
|
||||
test_evidence_list_item_copies_strings
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-item/optional-values",
|
||||
test_evidence_list_item_optional_values
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-item/null-values",
|
||||
test_evidence_list_item_null_values
|
||||
);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
592
tests/test_evidence_list_model.c
Normal file
592
tests/test_evidence_list_model.c
Normal file
|
|
@ -0,0 +1,592 @@
|
|||
/******************************************************************************
|
||||
* @file test_evidence_list_model.c
|
||||
* @brief Tests unitaires de EvidenceListModel.
|
||||
******************************************************************************/
|
||||
|
||||
#include "widgets/evidence_list_model.h"
|
||||
|
||||
#include "widgets/evidence_list_item.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* @brief Crée une preuve valide pour les tests.
|
||||
*/
|
||||
static EvidenceRecord *test_evidence_list_model_create_record(
|
||||
const char *uuid,
|
||||
const char *original_name,
|
||||
const char *source
|
||||
)
|
||||
{
|
||||
EvidenceRecord *evidence_record = NULL;
|
||||
|
||||
char *internal_name = NULL;
|
||||
char *relative_path = NULL;
|
||||
|
||||
GError *error = NULL;
|
||||
|
||||
internal_name =
|
||||
g_strdup_printf(
|
||||
"%s.bin",
|
||||
uuid
|
||||
);
|
||||
|
||||
relative_path =
|
||||
g_strdup_printf(
|
||||
"01_Preuves_Originales/Documents/%s.bin",
|
||||
uuid
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
internal_name
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
relative_path
|
||||
);
|
||||
|
||||
evidence_record =
|
||||
evidence_record_new(
|
||||
uuid,
|
||||
original_name,
|
||||
internal_name,
|
||||
relative_path,
|
||||
"document",
|
||||
4096,
|
||||
"00000000000000000000000000000000"
|
||||
"00000000000000000000000000000000",
|
||||
"2026-07-20T07:16:01Z",
|
||||
"2026-07-19T18:30:00Z",
|
||||
source,
|
||||
"Description de test.",
|
||||
EVIDENCE_INTEGRITY_STATUS_UNKNOWN,
|
||||
&error
|
||||
);
|
||||
|
||||
g_assert_no_error(
|
||||
error
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_record
|
||||
);
|
||||
|
||||
g_free(
|
||||
relative_path
|
||||
);
|
||||
|
||||
g_free(
|
||||
internal_name
|
||||
);
|
||||
|
||||
return evidence_record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Crée un tableau qui libère automatiquement ses preuves.
|
||||
*/
|
||||
static GPtrArray *test_evidence_list_model_create_records(void)
|
||||
{
|
||||
return g_ptr_array_new_with_free_func(
|
||||
(GDestroyNotify) evidence_record_free
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie la création d'un modèle vide.
|
||||
*/
|
||||
static void test_evidence_list_model_new_empty(void)
|
||||
{
|
||||
EvidenceListModel *evidence_list_model =
|
||||
NULL;
|
||||
|
||||
GListModel *list_model =
|
||||
NULL;
|
||||
|
||||
evidence_list_model =
|
||||
evidence_list_model_new();
|
||||
|
||||
g_assert_nonnull(
|
||||
evidence_list_model
|
||||
);
|
||||
|
||||
list_model =
|
||||
evidence_list_model_get_list_model(
|
||||
evidence_list_model
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
list_model
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_list_model_get_count(
|
||||
evidence_list_model
|
||||
),
|
||||
==,
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
g_list_model_get_item_type(
|
||||
list_model
|
||||
),
|
||||
==,
|
||||
EVIDENCE_TYPE_LIST_ITEM
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
evidence_list_model
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie l'alimentation nominale du modèle.
|
||||
*/
|
||||
static void test_evidence_list_model_replace_records(void)
|
||||
{
|
||||
EvidenceListModel *evidence_list_model =
|
||||
NULL;
|
||||
|
||||
GPtrArray *evidence_records =
|
||||
NULL;
|
||||
|
||||
EvidenceListItem *first_item =
|
||||
NULL;
|
||||
|
||||
evidence_list_model =
|
||||
evidence_list_model_new();
|
||||
|
||||
evidence_records =
|
||||
test_evidence_list_model_create_records();
|
||||
|
||||
g_ptr_array_add(
|
||||
evidence_records,
|
||||
test_evidence_list_model_create_record(
|
||||
"550e8400-e29b-41d4-a716-446655440000",
|
||||
"premiere-preuve.pdf",
|
||||
"Email reçu"
|
||||
)
|
||||
);
|
||||
|
||||
g_ptr_array_add(
|
||||
evidence_records,
|
||||
test_evidence_list_model_create_record(
|
||||
"550e8400-e29b-41d4-a716-446655440001",
|
||||
"deuxieme-preuve.png",
|
||||
"Conversation Instagram"
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_list_model_replace(
|
||||
evidence_list_model,
|
||||
evidence_records,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_list_model_get_count(
|
||||
evidence_list_model
|
||||
),
|
||||
==,
|
||||
2
|
||||
);
|
||||
|
||||
first_item =
|
||||
g_list_model_get_item(
|
||||
evidence_list_model_get_list_model(
|
||||
evidence_list_model
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_nonnull(
|
||||
first_item
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_original_name(
|
||||
first_item
|
||||
),
|
||||
==,
|
||||
"premiere-preuve.pdf"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
first_item
|
||||
);
|
||||
|
||||
/*
|
||||
* La liste doit rester valide après libération des EvidenceRecord.
|
||||
*/
|
||||
g_ptr_array_unref(
|
||||
evidence_records
|
||||
);
|
||||
|
||||
first_item =
|
||||
g_list_model_get_item(
|
||||
evidence_list_model_get_list_model(
|
||||
evidence_list_model
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_source(
|
||||
first_item
|
||||
),
|
||||
==,
|
||||
"Email reçu"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
first_item
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
evidence_list_model
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie qu'un rafraîchissement remplace l'ancien contenu.
|
||||
*/
|
||||
static void test_evidence_list_model_successive_replacements(void)
|
||||
{
|
||||
EvidenceListModel *evidence_list_model =
|
||||
NULL;
|
||||
|
||||
GPtrArray *first_records =
|
||||
NULL;
|
||||
|
||||
GPtrArray *second_records =
|
||||
NULL;
|
||||
|
||||
EvidenceListItem *remaining_item =
|
||||
NULL;
|
||||
|
||||
evidence_list_model =
|
||||
evidence_list_model_new();
|
||||
|
||||
first_records =
|
||||
test_evidence_list_model_create_records();
|
||||
|
||||
second_records =
|
||||
test_evidence_list_model_create_records();
|
||||
|
||||
g_ptr_array_add(
|
||||
first_records,
|
||||
test_evidence_list_model_create_record(
|
||||
"550e8400-e29b-41d4-a716-446655440002",
|
||||
"ancienne-preuve.txt",
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_ptr_array_add(
|
||||
second_records,
|
||||
test_evidence_list_model_create_record(
|
||||
"550e8400-e29b-41d4-a716-446655440003",
|
||||
"nouvelle-preuve.txt",
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_list_model_replace(
|
||||
evidence_list_model,
|
||||
first_records,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_list_model_replace(
|
||||
evidence_list_model,
|
||||
second_records,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_list_model_get_count(
|
||||
evidence_list_model
|
||||
),
|
||||
==,
|
||||
1
|
||||
);
|
||||
|
||||
remaining_item =
|
||||
g_list_model_get_item(
|
||||
evidence_list_model_get_list_model(
|
||||
evidence_list_model
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
g_assert_cmpstr(
|
||||
evidence_list_item_get_original_name(
|
||||
remaining_item
|
||||
),
|
||||
==,
|
||||
"nouvelle-preuve.txt"
|
||||
);
|
||||
|
||||
g_object_unref(
|
||||
remaining_item
|
||||
);
|
||||
|
||||
g_ptr_array_unref(
|
||||
second_records
|
||||
);
|
||||
|
||||
g_ptr_array_unref(
|
||||
first_records
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
evidence_list_model
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie qu'un tableau vide efface le modèle.
|
||||
*/
|
||||
static void test_evidence_list_model_replace_empty(void)
|
||||
{
|
||||
EvidenceListModel *evidence_list_model =
|
||||
NULL;
|
||||
|
||||
GPtrArray *evidence_records =
|
||||
NULL;
|
||||
|
||||
GPtrArray *empty_records =
|
||||
NULL;
|
||||
|
||||
evidence_list_model =
|
||||
evidence_list_model_new();
|
||||
|
||||
evidence_records =
|
||||
test_evidence_list_model_create_records();
|
||||
|
||||
empty_records =
|
||||
test_evidence_list_model_create_records();
|
||||
|
||||
g_ptr_array_add(
|
||||
evidence_records,
|
||||
test_evidence_list_model_create_record(
|
||||
"550e8400-e29b-41d4-a716-446655440004",
|
||||
"preuve-temporaire.txt",
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_list_model_replace(
|
||||
evidence_list_model,
|
||||
evidence_records,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_list_model_replace(
|
||||
evidence_list_model,
|
||||
empty_records,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_cmpuint(
|
||||
evidence_list_model_get_count(
|
||||
evidence_list_model
|
||||
),
|
||||
==,
|
||||
0
|
||||
);
|
||||
|
||||
g_ptr_array_unref(
|
||||
empty_records
|
||||
);
|
||||
|
||||
g_ptr_array_unref(
|
||||
evidence_records
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
evidence_list_model
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Vérifie les arguments invalides et le remplacement atomique.
|
||||
*/
|
||||
static void test_evidence_list_model_invalid_records(void)
|
||||
{
|
||||
EvidenceListModel *evidence_list_model =
|
||||
NULL;
|
||||
|
||||
GPtrArray *valid_records =
|
||||
NULL;
|
||||
|
||||
GPtrArray *invalid_records =
|
||||
NULL;
|
||||
|
||||
GError *error = NULL;
|
||||
|
||||
evidence_list_model =
|
||||
evidence_list_model_new();
|
||||
|
||||
valid_records =
|
||||
test_evidence_list_model_create_records();
|
||||
|
||||
invalid_records =
|
||||
test_evidence_list_model_create_records();
|
||||
|
||||
g_ptr_array_add(
|
||||
valid_records,
|
||||
test_evidence_list_model_create_record(
|
||||
"550e8400-e29b-41d4-a716-446655440005",
|
||||
"preuve-conservee.txt",
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_true(
|
||||
evidence_list_model_replace(
|
||||
evidence_list_model,
|
||||
valid_records,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
/*
|
||||
* NULL représente ici une ligne métier invalide.
|
||||
*/
|
||||
g_ptr_array_add(
|
||||
invalid_records,
|
||||
NULL
|
||||
);
|
||||
|
||||
g_assert_false(
|
||||
evidence_list_model_replace(
|
||||
evidence_list_model,
|
||||
invalid_records,
|
||||
&error
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_error(
|
||||
error,
|
||||
EVIDENCE_LIST_MODEL_ERROR,
|
||||
EVIDENCE_LIST_MODEL_ERROR_INVALID_RECORD
|
||||
);
|
||||
|
||||
g_clear_error(
|
||||
&error
|
||||
);
|
||||
|
||||
/*
|
||||
* L'ancien élément doit toujours être présent.
|
||||
*/
|
||||
g_assert_cmpuint(
|
||||
evidence_list_model_get_count(
|
||||
evidence_list_model
|
||||
),
|
||||
==,
|
||||
1
|
||||
);
|
||||
|
||||
g_assert_false(
|
||||
evidence_list_model_replace(
|
||||
NULL,
|
||||
valid_records,
|
||||
&error
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_error(
|
||||
error,
|
||||
EVIDENCE_LIST_MODEL_ERROR,
|
||||
EVIDENCE_LIST_MODEL_ERROR_INVALID_ARGUMENT
|
||||
);
|
||||
|
||||
g_clear_error(
|
||||
&error
|
||||
);
|
||||
|
||||
g_assert_false(
|
||||
evidence_list_model_replace(
|
||||
evidence_list_model,
|
||||
NULL,
|
||||
&error
|
||||
)
|
||||
);
|
||||
|
||||
g_assert_error(
|
||||
error,
|
||||
EVIDENCE_LIST_MODEL_ERROR,
|
||||
EVIDENCE_LIST_MODEL_ERROR_INVALID_ARGUMENT
|
||||
);
|
||||
|
||||
g_clear_error(
|
||||
&error
|
||||
);
|
||||
|
||||
g_ptr_array_unref(
|
||||
invalid_records
|
||||
);
|
||||
|
||||
g_ptr_array_unref(
|
||||
valid_records
|
||||
);
|
||||
|
||||
evidence_list_model_free(
|
||||
evidence_list_model
|
||||
);
|
||||
}
|
||||
|
||||
int main(
|
||||
int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
g_test_init(
|
||||
&argc,
|
||||
&argv,
|
||||
NULL
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-model/new-empty",
|
||||
test_evidence_list_model_new_empty
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-model/replace-records",
|
||||
test_evidence_list_model_replace_records
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-model/successive-replacements",
|
||||
test_evidence_list_model_successive_replacements
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-model/replace-empty",
|
||||
test_evidence_list_model_replace_empty
|
||||
);
|
||||
|
||||
g_test_add_func(
|
||||
"/evidence-list-model/invalid-records",
|
||||
test_evidence_list_model_invalid_records
|
||||
);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
Loading…
Reference in a new issue