548 lines
12 KiB
C
548 lines
12 KiB
C
/******************************************************************************
|
|
* @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;
|
|
}
|