feat(gui): add investigation folder selector

This commit is contained in:
grayTerminal-sh 2026-07-10 17:08:14 +02:00
parent df5d9c8b6c
commit aa2b903487
5 changed files with 236 additions and 0 deletions

View file

@ -0,0 +1,38 @@
# Ticket #002
## Titre
Ajouter le sélecteur de dossier denquête.
## Objectif
Permettre à lutilisateur de sélectionner un dossier denquête au lancement de lapplication.
## Responsabilités
- afficher un dialogue GTK de sélection de dossier ;
- retourner le dossier sélectionné ;
- gérer lannulation sans erreur ;
- transmettre le chemin au module Application.
## Hors périmètre
- création de `00_BaseDeDonnees` ;
- ouverture de SQLite ;
- initialisation du schéma ;
- validation complète dune enquête.
## Critères dacceptation
- [ ] Le dialogue souvre au lancement.
- [ ] Un dossier peut être sélectionné.
- [ ] Lannulation est gérée proprement.
- [ ] Le chemin sélectionné est affiché dans la fenêtre.
- [ ] Aucun warning.
- [ ] Les fonctions publiques sont documentées.
- [ ] Aucun état global.
## Commit attendu
```text
feat(gui): add investigation folder selector

View file

@ -0,0 +1,46 @@
/******************************************************************************
* @file folder_dialog.h
* @brief Interface du dialogue de sélection d'un dossier d'enquête.
******************************************************************************/
#ifndef LABFY_INVESTIGATION_FOLDER_DIALOG_H
#define LABFY_INVESTIGATION_FOLDER_DIALOG_H
#include <gtk/gtk.h>
/**
* @brief Fonction appelée après la fermeture du dialogue de sélection.
*
* @param folder_path Chemin du dossier sélectionné, ou NULL si l'utilisateur
* a annulé la sélection.
* @param user_data Données transmises lors de l'ouverture du dialogue.
*
* Le chemin reçu reste valide uniquement pendant l'appel de cette fonction.
* Il doit être copié si le code appelant souhaite le conserver.
*
* @param callback
* Fonction appelée lorsque le dialogue est fermé.
*
* Si l'utilisateur annule la sélection,
* folder_path vaut NULL.
*/
typedef void (*FolderDialogCallback)(
const char *folder_path,
gpointer user_data
);
/**
* @brief Ouvre un dialogue permettant de sélectionner un dossier.
*
* @param parent Fenêtre parente du dialogue.
* Peut être NULL.
* @param callback Fonction appelée lorsque le dialogue est terminé.
* @param user_data Données transmises à la fonction de rappel.
*/
void folder_dialog_select_folder(
GtkWindow *parent,
FolderDialogCallback callback,
gpointer user_data
);
#endif

View file

@ -4,6 +4,7 @@
******************************************************************************/
#include "core/application.h"
#include "views/folder_dialog.h"
#include <gtk/gtk.h>
@ -39,6 +40,27 @@ struct Application
* @param gtk_application Application GTK ayant reçu le signal.
* @param user_data Données utilisateur associées au signal.
*/
static void application_on_folder_selected(
const char *folder_path,
gpointer user_data
)
{
GtkWindow *window = GTK_WINDOW(user_data);
if (folder_path == NULL)
{
gtk_window_set_title(
window,
"Labfy Investigation — aucune enquête sélectionnée"
);
return;
}
gtk_window_set_title(window, folder_path);
}
static void application_on_activate(GtkApplication *gtk_application,
gpointer user_data)
{
@ -56,6 +78,12 @@ static void application_on_activate(GtkApplication *gtk_application,
);
gtk_window_present(GTK_WINDOW(window));
folder_dialog_select_folder(
GTK_WINDOW(window),
application_on_folder_selected,
window
);
}
Application *application_new(void)
@ -113,3 +141,5 @@ void application_free(Application *application)
g_free(application);
}

View file

@ -0,0 +1,122 @@
/******************************************************************************
* @file folder_dialog.c
* @brief Implémentation du dialogue de sélection d'un dossier d'enquête.
******************************************************************************/
#include "views/folder_dialog.h"
#include <gio/gio.h>
/**
* @struct FolderDialogContext
* @brief Conserve les données nécessaires pendant l'opération asynchrone.
*
* Le dialogue GTK ne se termine pas immédiatement. Ce contexte permet donc
* de conserver le callback et ses données jusqu'à la fermeture du dialogue.
*/
typedef struct
{
FolderDialogCallback callback;
gpointer user_data;
} FolderDialogContext;
/**
* @brief Libère le contexte associé au dialogue.
*
* @param context Contexte à libérer.
*/
static void folder_dialog_context_free(FolderDialogContext *context)
{
g_free(context);
}
/**
* @brief Traite le résultat de la sélection du dossier.
*
* @param source_object Objet ayant lancé l'opération asynchrone.
* @param result Résultat transmis par GTK.
* @param user_data Contexte du dialogue.
*/
static void folder_dialog_on_folder_selected(
GObject *source_object,
GAsyncResult *result,
gpointer user_data
)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG(source_object);
FolderDialogContext *context = user_data;
GError *error = NULL;
GFile *folder = NULL;
char *folder_path = NULL;
folder = gtk_file_dialog_select_folder_finish(dialog, result, &error);
if (folder == NULL)
{
/*
* Une annulation est un comportement normal de l'utilisateur.
* Elle est transmise au code appelant sous la forme d'un chemin NULL.
*/
if (error != NULL &&
!g_error_matches(error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_DISMISSED))
{
g_warning(
"Impossible de sélectionner le dossier : %s",
error->message
);
}
if (context->callback != NULL)
{
context->callback(NULL, context->user_data);
}
g_clear_error(&error);
folder_dialog_context_free(context);
return;
}
folder_path = g_file_get_path(folder);
if (context->callback != NULL)
{
context->callback(folder_path, context->user_data);
}
g_free(folder_path);
g_object_unref(folder);
folder_dialog_context_free(context);
}
void folder_dialog_select_folder(
GtkWindow *parent,
FolderDialogCallback callback,
gpointer user_data
)
{
GtkFileDialog *dialog = NULL;
FolderDialogContext *context = NULL;
context = g_new0(FolderDialogContext, 1);
context->callback = callback;
context->user_data = user_data;
dialog = gtk_file_dialog_new();
gtk_file_dialog_set_title(
dialog,
"Sélectionner un dossier d'enquête"
);
gtk_file_dialog_set_modal(dialog, TRUE);
gtk_file_dialog_select_folder(
dialog,
parent,
NULL,
folder_dialog_on_folder_selected,
context
);
g_object_unref(dialog);
}