18 KiB
Ticket #030 — Créer une enquête depuis l’interface GTK
Contexte
Le ticket #029 a intégré InvestigationSession au cycle de vie de l’application.
L’application sait désormais :
- ouvrir une enquête existante ;
- conserver sa connexion SQLite ;
- charger ses métadonnées persistées ;
- construire son arborescence ;
- afficher son nom et son chemin dans la fenêtre principale ;
- conserver l’ancienne enquête si une nouvelle ouverture échoue.
Cependant, lorsqu’aucune enquête n’existe encore, l’utilisateur ne peut pas en créer une depuis l’interface.
Le dossier sélectionné est actuellement toujours interprété comme une enquête existante. Si la base suivante est absente :
00_BaseDeDonnees/Enquete.sqlite
l’ouverture échoue, ce qui est volontairement sûr.
La création d’une nouvelle enquête doit être une action explicite et séparée de l’ouverture.
Objectif
Ajouter une première fonctionnalité GTK réellement utilisable :
Créer une nouvelle enquête
Le flux attendu est :
clic sur « Nouvelle enquête »
↓
sélection du dossier parent
↓
saisie du nom de l’enquête
↓
validation des paramètres
↓
investigation_project_create()
↓
investigation_session_open()
↓
construction de l’arborescence
↓
installation dans Application
↓
mise à jour de MainWindow
L’utilisateur ne doit jamais avoir à créer manuellement :
00_BaseDeDonnees
Enquete.sqlite
01_Preuves_Originales
...
09_Hash
Architecture attendue
MainWindow
│
└── bouton « Nouvelle enquête »
│
▼
CreateInvestigationDialog
│
├── dossier parent
├── nom de l’enquête
└── validation
│
▼
Application
│
├── investigation_project_create()
├── investigation_session_open()
├── investigation_tree_builder_build()
└── main_window_set_investigation()
Travail à réaliser
1. Créer un module de dialogue dédié
Créer :
include/views/create_investigation_dialog.h
src/views/create_investigation_dialog.c
Le module doit rester indépendant de SQLite.
Il ne doit pas inclure :
#include <sqlite3.h>
Il ne doit pas appeler :
database_initialize
investigation_project_create
investigation_session_open
Son rôle est uniquement de recueillir les informations saisies par l’utilisateur.
2. Définir le callback public
Dans :
include/views/create_investigation_dialog.h
déclarer :
typedef void (*CreateInvestigationDialogCallback)(
const char *parent_directory,
const char *investigation_name,
gpointer user_data
);
Puis :
void create_investigation_dialog_present(
GtkWindow *parent_window,
CreateInvestigationDialogCallback callback,
gpointer user_data
);
Le callback reçoit :
parent_directory
investigation_name
user_data
En cas d’annulation :
parent_directory == NULL
investigation_name == NULL
Les chaînes transmises au callback ne restent valides que pendant l’appel.
Le callback doit les copier s’il souhaite les conserver.
3. Concevoir le dialogue GTK
Le dialogue doit contenir au minimum :
Titre : Nouvelle enquête
Dossier parent :
[ chemin sélectionné ] [ Parcourir ]
Nom de l’enquête :
[ ]
[ Annuler ] [ Créer ]
Le bouton Créer doit être désactivé tant que :
aucun dossier parent valide n’est sélectionné
ou
le nom est vide
Le dialogue peut utiliser :
GtkWindow
GtkBox
GtkLabel
GtkEntry
GtkButton
GtkFileDialog
Ne pas utiliser les anciennes API GTK3 synchrones.
4. Sélectionner le dossier parent
Le bouton :
Parcourir
doit ouvrir un sélecteur de dossier GTK4.
Le dossier choisi représente le parent dans lequel le nouveau dossier d’enquête sera créé.
Exemple :
Dossier parent :
/home/fy59/Documents/Enquetes
Nom :
Arnaque_Billets
Résultat attendu :
/home/fy59/Documents/Enquetes/Arnaque_Billets
Le dossier parent doit déjà exister.
5. Valider le nom dans le dialogue
Le nom doit être refusé s’il est :
NULL
vide
uniquement composé d’espaces
Il doit aussi être refusé s’il contient un séparateur de chemin :
/
et, pour rester portable :
\
Exemples invalides :
Enquetes/Test
Enquetes\Test
Les espaces en début et fin doivent être supprimés avant l’envoi au callback.
Utiliser :
g_strstrip()
sur une copie allouée.
Le dialogue ne doit pas modifier directement le contenu interne de GtkEntry.
6. Ajouter le bouton dans MainWindow
Modifier :
include/views/main_window.h
src/views/main_window.c
Ajouter un bouton visible :
Nouvelle enquête
Il peut être placé dans une barre horizontale au-dessus du GtkPaned.
Organisation attendue :
MainWindow
└── main_box
├── action_bar
│ └── bouton Nouvelle enquête
├── main_paned
└── status_label
Ajouter dans la structure privée :
GtkWidget *action_bar;
GtkWidget *new_investigation_button;
7. Ajouter un callback de fenêtre
Définir dans :
include/views/main_window.h
un type de callback :
typedef void (*MainWindowNewInvestigationCallback)(
gpointer user_data
);
Ajouter :
void main_window_set_new_investigation_callback(
MainWindow *main_window,
MainWindowNewInvestigationCallback callback,
gpointer user_data
);
MainWindow ne doit pas créer elle-même l’enquête.
Elle ne doit faire que transmettre le clic au contrôleur Application.
8. Conserver les données de callback
Dans la structure privée de MainWindow, ajouter :
MainWindowNewInvestigationCallback
new_investigation_callback;
gpointer
new_investigation_user_data;
Le bouton GTK doit être relié à un callback privé :
static void main_window_on_new_investigation_clicked(
GtkButton *button,
gpointer user_data
);
Ce callback doit appeler :
main_window->new_investigation_callback(
main_window->new_investigation_user_data
);
uniquement si le callback est défini.
9. Ajouter le contrôleur dans Application
Modifier :
src/core/application.c
Ajouter :
static void application_on_new_investigation_requested(
gpointer user_data
);
Cette fonction doit ouvrir :
create_investigation_dialog_present()
en utilisant :
main_window_get_window(
application->main_window
);
10. Traiter le résultat du dialogue
Ajouter :
static void application_on_create_investigation(
const char *parent_directory,
const char *investigation_name,
gpointer user_data
);
En cas d’annulation :
parent_directory == NULL
investigation_name == NULL
la fonction doit simplement retourner.
Aucun état existant ne doit être modifié.
11. Créer le projet
Appeler :
char *created_root_path = NULL;
puis :
created_root_path = investigation_project_create(
parent_directory,
investigation_name
);
Si la création échoue :
ancienne session conservée
ancien arbre conservé
aucune modification de MainWindow
warning explicite
Exemple :
g_warning(
"Impossible de créer l'enquête '%s' dans '%s'.",
investigation_name,
parent_directory
);
12. Ouvrir immédiatement la nouvelle enquête
Après une création valide, ouvrir :
InvestigationSession *new_session = NULL;
GError *error = NULL;
avec :
new_session = investigation_session_open(
created_root_path,
&error
);
La nouvelle enquête doit être utilisable sans redémarrer l’application.
13. Construire son arbre
Récupérer :
const InvestigationProject *project = NULL;
const char *root_path = NULL;
Puis construire :
InvestigationTreeModel *new_tree_model = NULL;
avec :
new_tree_model = investigation_tree_builder_build(
root_path
);
14. Factoriser l’installation d’une session
Le ticket #029 contient déjà une logique de remplacement dans :
application_on_folder_selected()
Cette logique ne doit pas être dupliquée.
Créer une fonction privée :
static gboolean application_install_session(
Application *application,
InvestigationSession *new_session,
InvestigationTreeModel *new_tree_model
);
Cette fonction doit :
- valider ses paramètres ;
- récupérer le projet ;
- récupérer le record ;
- récupérer le chemin racine ;
- récupérer le nom ;
- libérer l’ancien arbre ;
- fermer l’ancienne session ;
- installer les nouveaux objets ;
- mettre à jour la sidebar ;
- mettre à jour le titre et la barre d’état.
Elle retourne :
TRUE en cas de succès
FALSE en cas d’échec
15. Propriété des objets dans la fonction factorisée
Avant l’appel réussi à :
application_install_session()
le code appelant possède :
new_session
new_tree_model
En cas de succès, Application devient propriétaire des deux objets.
En cas d’échec, le code appelant reste propriétaire et doit les libérer.
Cette règle doit être documentée clairement.
16. Adapter l’ouverture existante
Modifier :
application_on_folder_selected()
pour utiliser également :
application_install_session()
Le flux devient :
investigation_session_open()
↓
investigation_tree_builder_build()
↓
application_install_session()
Cela garantit que l’ouverture et la création utilisent exactement le même mécanisme d’installation.
17. Gérer un échec après création du projet
Si le dossier et la base ont été créés avec succès mais que :
investigation_session_open()
ou :
investigation_tree_builder_build()
échouent, ne pas supprimer automatiquement le nouveau projet.
Raison :
la création SQLite a pu réussir
le dossier contient potentiellement déjà des informations utiles
une suppression automatique après création complète serait risquée
Afficher un warning explicite indiquant que le projet a été créé mais n’a pas pu être ouvert.
Exemple :
L’enquête a été créée dans '<chemin>', mais son ouverture a échoué.
Le chemin doit être laissé à l’utilisateur pour diagnostic.
18. Mettre à jour le statut pendant la création
Optionnel mais recommandé :
Avant la création :
Création de l’enquête…
Après succès :
Enquête ouverte : <nom> — <chemin>
En cas d’échec, le statut précédent doit être restauré ou conservé.
Ne pas laisser le statut bloqué sur :
Création de l’enquête…
si l’opération échoue.
19. Ajouter une fonction de statut générique
Pour éviter que Application manipule directement GtkLabel, ajouter dans :
include/views/main_window.h
void main_window_set_status(
MainWindow *main_window,
const char *status_text
);
Implémenter dans :
src/views/main_window.c
La fonction doit :
- accepter
main_window == NULL; - accepter
status_text == NULL; - afficher une chaîne sûre ;
- utiliser
gtk_label_set_text().
Pour status_text == NULL, afficher :
Aucune enquête ouverte
Tests manuels
20. Création valide
Lancer :
make
make run
Cliquer sur :
Nouvelle enquête
Sélectionner :
/home/fy59/Documents/Enquetes
Saisir par exemple :
Test_Enquete
Vérifier la création de :
/home/fy59/Documents/Enquetes/Test_Enquete/
Vérifier la présence de :
00_BaseDeDonnees/Enquete.sqlite
01_Preuves_Originales
02_Preuves_Traitees
03_Chronologie
04_Entites
05_Rapports
06_Exports
07_Notes
08_Sources
09_Hash
Vérifier aussi :
arborescence visible
titre mis à jour
barre d’état mise à jour
aucune erreur SQLite
21. Nom vide
Laisser le nom vide.
Le bouton Créer doit rester désactivé.
Aucun dossier ne doit être créé.
22. Nom composé d’espaces
Saisir uniquement :
Le bouton Créer doit rester désactivé ou la validation doit refuser l’opération.
Aucun dossier ne doit être créé.
23. Nom contenant un séparateur
Tester :
Test/Enquete
puis :
Test\Enquete
La création doit être refusée.
24. Dossier déjà existant
Créer une première fois :
Test_Enquete
Puis tenter de recréer le même nom dans le même dossier parent.
Vérifier :
aucun écrasement
aucune modification du projet existant
warning explicite
ancienne session conservée
25. Annulation du dialogue
Ouvrir le dialogue puis cliquer sur :
Annuler
Vérifier :
aucun crash
aucun dossier créé
ancienne session conservée
fenêtre toujours utilisable
26. Création après ouverture d’une enquête
Lorsque l’action « Nouvelle enquête » est disponible pendant une session active :
- ouvrir une enquête A ;
- créer une enquête B ;
- vérifier que B remplace A uniquement après création et ouverture complètes.
Si la création de B échoue, A doit rester active.
Gestion de la mémoire
Dialogue
Le dialogue possède :
sa fenêtre GTK
ses widgets
ses chaînes temporaires
Il doit être détruit après :
création
annulation
fermeture de la fenêtre
Application
Application possède après succès :
InvestigationSession
InvestigationTreeModel
Variables temporaires
Le callback de création possède temporairement :
created_root_path
new_session
new_tree_model
GError
Tous les chemins d’échec doivent libérer les ressources qu’ils possèdent encore.
Critères d’acceptation
- Un bouton
Nouvelle enquêteest visible. - Le bouton ouvre un dialogue dédié.
- Le dialogue permet de sélectionner un dossier parent.
- Le dialogue permet de saisir un nom.
- Le nom vide est refusé.
- Le nom composé d’espaces est refusé.
- Les séparateurs
/et\sont refusés. - Le bouton
Créern’est actif que lorsque les données sont valides. - La création utilise
investigation_project_create(). - La nouvelle enquête est ouverte avec
investigation_session_open(). - L’arborescence est construite automatiquement.
- La session est installée dans
Application. - Le nom et le chemin sont affichés.
- L’ancienne session est conservée en cas d’échec.
- L’ancien arbre est conservé en cas d’échec.
- La logique d’installation n’est pas dupliquée.
- Le dialogue ne connaît ni SQLite ni
Database. - Aucun dossier existant n’est écrasé.
- L’annulation ne modifie aucun état.
- Les anciens tests restent valides.
makeréussit sans warning.make testréussit.- Le test manuel de création valide réussit.
git diff --checkne retourne aucune erreur.
Audit attendu
Le dialogue ne doit contenir aucune dépendance métier :
rg -n \
'sqlite3_|database_|investigation_project_create|investigation_session_open' \
include/views/create_investigation_dialog.h \
src/views/create_investigation_dialog.c
Résultat attendu :
aucune sortie
Vérifier la factorisation :
rg -n \
'application_install_session' \
src/core/application.c
Vérifier que les deux flux l’utilisent :
application_on_folder_selected
application_on_create_investigation
Vérifier l’absence de SQLite dans Application :
rg -n \
'sqlite3_|#include <sqlite3.h>' \
src/core/application.c
Résultat attendu :
aucune sortie
Hors périmètre
Ce ticket ne doit pas ajouter :
- une barre de menu complète ;
- un raccourci clavier ;
- la suppression d’une enquête ;
- le renommage d’une enquête ;
- le déplacement d’une enquête ;
- la restauration de la dernière enquête ;
- une liste des enquêtes récentes ;
- une confirmation de fermeture ;
- l’import de preuves ;
- les DAO des preuves ;
- une boîte d’erreur avancée ;
- la gestion de modèles d’enquête personnalisés.
Fichiers principalement concernés
include/views/create_investigation_dialog.h
src/views/create_investigation_dialog.c
include/views/main_window.h
src/views/main_window.c
src/core/application.c
Le fichier suivant ne devrait pas nécessiter de modification :
include/core/application.h
Le Makefile de production détecte automatiquement le nouveau fichier .c avec :
SRC := $(shell find src -name "*.c")
Aucune nouvelle cible de test n’est obligatoire pour ce ticket GTK.
Résultat attendu
À la fin du ticket, l’utilisateur doit pouvoir lancer l’application sans disposer d’une enquête préalable.
Il doit pouvoir :
ouvrir l’application
↓
cliquer sur « Nouvelle enquête »
↓
choisir ~/Documents/Enquetes
↓
saisir un nom
↓
créer l’enquête
↓
voir immédiatement son arborescence
Cette fonctionnalité constitue la première opération complète utilisable depuis GTK.
Commit attendu
Avant le commit :
make clean
make
make test
git diff --check
git status --short
Préparer les fichiers :
git add \
include/views/create_investigation_dialog.h \
src/views/create_investigation_dialog.c \
include/views/main_window.h \
src/views/main_window.c \
src/core/application.c
Contrôler :
git diff --cached --stat
git diff --cached
Créer le commit :
git commit -m "feat(ui): add investigation creation workflow"
Puis pousser après validation complète :
git push