feat(gui): display selected node in workspace
This commit is contained in:
parent
6938529fb2
commit
ecac36fd8d
7 changed files with 474 additions and 0 deletions
225
docs/tickets/closed/TICKET-015.md
Normal file
225
docs/tickets/closed/TICKET-015.md
Normal file
|
|
@ -0,0 +1,225 @@
|
||||||
|
# Ticket #015
|
||||||
|
|
||||||
|
## Titre
|
||||||
|
|
||||||
|
Afficher le nœud sélectionné dans le `Workspace`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Afficher dans la zone de travail les informations principales du nœud sélectionné dans l'arborescence.
|
||||||
|
|
||||||
|
Lorsqu'un dossier ou un fichier est sélectionné, le `Workspace` doit afficher :
|
||||||
|
|
||||||
|
- son nom ;
|
||||||
|
- son type ;
|
||||||
|
- son parent éventuel ;
|
||||||
|
- son nombre d'enfants s'il s'agit d'un dossier.
|
||||||
|
|
||||||
|
Aucun fichier ne doit encore être ouvert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```text
|
||||||
|
InvestigationTreeView
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Application
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
MainWindow
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Workspace
|
||||||
|
```
|
||||||
|
|
||||||
|
`Application` reste le coordinateur.
|
||||||
|
|
||||||
|
`InvestigationTreeView` détecte la sélection.
|
||||||
|
|
||||||
|
`Workspace` affiche les informations reçues.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Responsabilités
|
||||||
|
|
||||||
|
### Application
|
||||||
|
|
||||||
|
Le module doit :
|
||||||
|
|
||||||
|
- recevoir le nœud sélectionné ;
|
||||||
|
- transmettre ce nœud à `MainWindow` ;
|
||||||
|
- ne pas modifier ni libérer le nœud.
|
||||||
|
|
||||||
|
### MainWindow
|
||||||
|
|
||||||
|
Le module doit :
|
||||||
|
|
||||||
|
- recevoir un nœud en lecture seule ;
|
||||||
|
- le transmettre au `Workspace`.
|
||||||
|
|
||||||
|
### Workspace
|
||||||
|
|
||||||
|
Le module doit :
|
||||||
|
|
||||||
|
- recevoir un `InvestigationNode` en lecture seule ;
|
||||||
|
- afficher son nom ;
|
||||||
|
- afficher son type ;
|
||||||
|
- afficher le nom de son parent si disponible ;
|
||||||
|
- afficher le nombre d'enfants pour un dossier ;
|
||||||
|
- restaurer la page d'accueil si le nœud vaut `NULL`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Principe de propriété
|
||||||
|
|
||||||
|
Le nœud sélectionné reste la propriété du `InvestigationTreeModel`.
|
||||||
|
|
||||||
|
`Application`, `MainWindow` et `Workspace` ne reçoivent qu'une référence non propriétaire :
|
||||||
|
|
||||||
|
```c
|
||||||
|
const InvestigationNode *node;
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucun de ces modules ne doit appeler :
|
||||||
|
|
||||||
|
```c
|
||||||
|
investigation_node_free(node);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fichiers concernés
|
||||||
|
|
||||||
|
```text
|
||||||
|
include/widgets/workspace.h
|
||||||
|
src/widgets/workspace.c
|
||||||
|
|
||||||
|
include/views/main_window.h
|
||||||
|
src/views/main_window.c
|
||||||
|
|
||||||
|
src/core/application.c
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucune modification du Core métier n'est nécessaire.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Interfaces publiques à ajouter
|
||||||
|
|
||||||
|
### Workspace
|
||||||
|
|
||||||
|
```c
|
||||||
|
void workspace_set_selected_node(
|
||||||
|
Workspace *workspace,
|
||||||
|
const InvestigationNode *node
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### MainWindow
|
||||||
|
|
||||||
|
```c
|
||||||
|
void main_window_set_selected_node(
|
||||||
|
MainWindow *main_window,
|
||||||
|
const InvestigationNode *node
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comportement attendu
|
||||||
|
|
||||||
|
### Aucun nœud sélectionné
|
||||||
|
|
||||||
|
```text
|
||||||
|
Labfy Investigation
|
||||||
|
|
||||||
|
Aucune enquête ouverte
|
||||||
|
|
||||||
|
Sélectionnez ou créez une enquête
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dossier sélectionné
|
||||||
|
|
||||||
|
```text
|
||||||
|
00_BaseDeDonnees
|
||||||
|
|
||||||
|
Type : dossier
|
||||||
|
Parent : Template
|
||||||
|
Enfants : 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fichier sélectionné
|
||||||
|
|
||||||
|
```text
|
||||||
|
Enquete.sqlite
|
||||||
|
|
||||||
|
Type : fichier
|
||||||
|
Parent : 00_BaseDeDonnees
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hors périmètre
|
||||||
|
|
||||||
|
Ce ticket ne doit pas :
|
||||||
|
|
||||||
|
- ouvrir le contenu d'un fichier ;
|
||||||
|
- afficher un aperçu ;
|
||||||
|
- lire les métadonnées du système de fichiers ;
|
||||||
|
- afficher la taille d'un fichier ;
|
||||||
|
- communiquer avec SQLite ;
|
||||||
|
- modifier l'arborescence ;
|
||||||
|
- gérer plusieurs sélections.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contraintes techniques
|
||||||
|
|
||||||
|
- C17 ;
|
||||||
|
- GTK4 uniquement ;
|
||||||
|
- aucun état global ;
|
||||||
|
- aucune propriété du nœud transférée au `Workspace` ;
|
||||||
|
- documentation Doxygen ;
|
||||||
|
- compilation sans warning ;
|
||||||
|
- aucun `Gtk-CRITICAL`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Critères d'acceptation
|
||||||
|
|
||||||
|
- [ ] Le projet compile sans warning.
|
||||||
|
- [ ] `make test` reste valide.
|
||||||
|
- [ ] La sélection d'un dossier met à jour le `Workspace`.
|
||||||
|
- [ ] La sélection d'un fichier met à jour le `Workspace`.
|
||||||
|
- [ ] Le nom est correct.
|
||||||
|
- [ ] Le type est correct.
|
||||||
|
- [ ] Le parent est correct.
|
||||||
|
- [ ] Le nombre d'enfants est correct pour un dossier.
|
||||||
|
- [ ] Une sélection `NULL` restaure la page d'accueil.
|
||||||
|
- [ ] Aucun module graphique ne libère le nœud.
|
||||||
|
- [ ] Aucun `Gtk-CRITICAL`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tests manuels
|
||||||
|
|
||||||
|
1. Ouvrir une enquête.
|
||||||
|
2. Sélectionner un dossier.
|
||||||
|
3. Vérifier les informations affichées.
|
||||||
|
4. Sélectionner un fichier.
|
||||||
|
5. Vérifier les informations affichées.
|
||||||
|
6. Changer d'enquête.
|
||||||
|
7. Vérifier que l'ancien nœud n'est plus affiché.
|
||||||
|
8. Lancer `make test`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commit attendu
|
||||||
|
|
||||||
|
```text
|
||||||
|
feat(gui): display selected node in workspace
|
||||||
|
```
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "core/investigation_tree_model.h"
|
#include "core/investigation_tree_model.h"
|
||||||
#include "widgets/investigation_tree_view.h"
|
#include "widgets/investigation_tree_view.h"
|
||||||
|
#include "core/investigation_node.h"
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
|
@ -63,6 +64,19 @@ void main_window_set_tree_selection_callback(
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Affiche dans le Workspace les informations du nœud sélectionné.
|
||||||
|
*
|
||||||
|
* La fenêtre principale ne devient pas propriétaire du nœud.
|
||||||
|
*
|
||||||
|
* @param main_window Fenêtre principale à mettre à jour.
|
||||||
|
* @param node Nœud sélectionné en lecture seule, ou NULL.
|
||||||
|
*/
|
||||||
|
void main_window_set_selected_node(
|
||||||
|
MainWindow *main_window,
|
||||||
|
const InvestigationNode *node
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Libère les ressources de la fenêtre.
|
* @brief Libère les ressources de la fenêtre.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@
|
||||||
#ifndef LABFY_INVESTIGATION_WORKSPACE_H
|
#ifndef LABFY_INVESTIGATION_WORKSPACE_H
|
||||||
#define LABFY_INVESTIGATION_WORKSPACE_H
|
#define LABFY_INVESTIGATION_WORKSPACE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "core/investigation_node.h"
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,6 +40,22 @@ GtkWidget *workspace_get_widget(
|
||||||
const Workspace *workspace
|
const Workspace *workspace
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Affiche les informations du nœud sélectionné.
|
||||||
|
*
|
||||||
|
* Le Workspace ne devient pas propriétaire du nœud.
|
||||||
|
* Le nœud doit rester valide pendant toute la durée de son affichage.
|
||||||
|
*
|
||||||
|
* Passer NULL restaure la page d'accueil.
|
||||||
|
*
|
||||||
|
* @param workspace Zone de travail à mettre à jour.
|
||||||
|
* @param node Nœud sélectionné en lecture seule, ou NULL.
|
||||||
|
*/
|
||||||
|
void workspace_set_selected_node(
|
||||||
|
Workspace *workspace,
|
||||||
|
const InvestigationNode *node
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Libère la structure d'encapsulation de la zone de travail.
|
* @brief Libère la structure d'encapsulation de la zone de travail.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -129,6 +129,11 @@ static void application_on_tree_node_selected(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main_window_set_selected_node(
|
||||||
|
application->main_window,
|
||||||
|
node
|
||||||
|
);
|
||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
{
|
{
|
||||||
g_print("Aucun nœud sélectionné.\n");
|
g_print("Aucun nœud sélectionné.\n");
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,22 @@ void main_window_set_tree_selection_callback(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void main_window_set_selected_node(
|
||||||
|
MainWindow *main_window,
|
||||||
|
const InvestigationNode *node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (main_window == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace_set_selected_node(
|
||||||
|
main_window->workspace,
|
||||||
|
node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void main_window_free(MainWindow *main_window)
|
void main_window_free(MainWindow *main_window)
|
||||||
{
|
{
|
||||||
if (main_window == NULL)
|
if (main_window == NULL)
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,34 @@ struct Workspace
|
||||||
GtkWidget *title_label;
|
GtkWidget *title_label;
|
||||||
GtkWidget *status_label;
|
GtkWidget *status_label;
|
||||||
GtkWidget *instruction_label;
|
GtkWidget *instruction_label;
|
||||||
|
|
||||||
|
GtkWidget *node_box;
|
||||||
|
GtkWidget *node_name_label;
|
||||||
|
GtkWidget *node_type_label;
|
||||||
|
GtkWidget *node_parent_label;
|
||||||
|
GtkWidget *node_children_label;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void workspace_show_welcome(
|
||||||
|
Workspace *workspace
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (workspace == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_set_visible(
|
||||||
|
workspace->welcome_box,
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_visible(
|
||||||
|
workspace->node_box,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Workspace *workspace_new(void)
|
Workspace *workspace_new(void)
|
||||||
{
|
{
|
||||||
Workspace *workspace = NULL;
|
Workspace *workspace = NULL;
|
||||||
|
|
@ -102,11 +128,64 @@ Workspace *workspace_new(void)
|
||||||
workspace->instruction_label
|
workspace->instruction_label
|
||||||
);
|
);
|
||||||
|
|
||||||
|
workspace->node_box = gtk_box_new(
|
||||||
|
GTK_ORIENTATION_VERTICAL,
|
||||||
|
12
|
||||||
|
);
|
||||||
|
|
||||||
|
if (workspace->node_box == NULL)
|
||||||
|
{
|
||||||
|
workspace_free(workspace);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_set_halign(
|
||||||
|
workspace->node_box,
|
||||||
|
GTK_ALIGN_CENTER
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_valign(
|
||||||
|
workspace->node_box,
|
||||||
|
GTK_ALIGN_CENTER
|
||||||
|
);
|
||||||
|
|
||||||
|
workspace->node_name_label = gtk_label_new(NULL);
|
||||||
|
workspace->node_type_label = gtk_label_new(NULL);
|
||||||
|
workspace->node_parent_label = gtk_label_new(NULL);
|
||||||
|
workspace->node_children_label = gtk_label_new(NULL);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(workspace->node_box),
|
||||||
|
workspace->node_name_label
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(workspace->node_box),
|
||||||
|
workspace->node_type_label
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(workspace->node_box),
|
||||||
|
workspace->node_parent_label
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(workspace->node_box),
|
||||||
|
workspace->node_children_label
|
||||||
|
);
|
||||||
|
|
||||||
gtk_box_append(
|
gtk_box_append(
|
||||||
GTK_BOX(workspace->root_widget),
|
GTK_BOX(workspace->root_widget),
|
||||||
workspace->welcome_box
|
workspace->welcome_box
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(workspace->root_widget),
|
||||||
|
workspace->node_box
|
||||||
|
);
|
||||||
|
|
||||||
|
workspace_show_welcome(workspace);
|
||||||
|
|
||||||
return workspace;
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,6 +201,122 @@ GtkWidget *workspace_get_widget(
|
||||||
return workspace->root_widget;
|
return workspace->root_widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void workspace_set_selected_node(
|
||||||
|
Workspace *workspace,
|
||||||
|
const InvestigationNode *node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const char *node_name = NULL;
|
||||||
|
const InvestigationNode *parent_node = NULL;
|
||||||
|
const char *parent_name = NULL;
|
||||||
|
InvestigationNodeType node_type;
|
||||||
|
size_t children_count = 0;
|
||||||
|
|
||||||
|
char *type_text = NULL;
|
||||||
|
char *parent_text = NULL;
|
||||||
|
char *children_text = NULL;
|
||||||
|
|
||||||
|
if (workspace == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
workspace_show_welcome(workspace);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_name = investigation_node_get_name(node);
|
||||||
|
node_type = investigation_node_get_type(node);
|
||||||
|
parent_node = investigation_node_get_parent(node);
|
||||||
|
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(workspace->node_name_label),
|
||||||
|
node_name != NULL ? node_name : "(sans nom)"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (node_type == INVESTIGATION_NODE_DIRECTORY)
|
||||||
|
{
|
||||||
|
type_text = g_strdup("Type : dossier");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type_text = g_strdup("Type : fichier");
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(workspace->node_type_label),
|
||||||
|
type_text
|
||||||
|
);
|
||||||
|
|
||||||
|
if (parent_node != NULL)
|
||||||
|
{
|
||||||
|
parent_name = investigation_node_get_name(parent_node);
|
||||||
|
|
||||||
|
parent_text = g_strdup_printf(
|
||||||
|
"Parent : %s",
|
||||||
|
parent_name != NULL ? parent_name : "(sans nom)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent_text = g_strdup("Parent : aucun");
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(workspace->node_parent_label),
|
||||||
|
parent_text
|
||||||
|
);
|
||||||
|
|
||||||
|
if (node_type == INVESTIGATION_NODE_DIRECTORY)
|
||||||
|
{
|
||||||
|
children_count =
|
||||||
|
investigation_node_get_children_count(node);
|
||||||
|
|
||||||
|
children_text = g_strdup_printf(
|
||||||
|
"Enfants : %zu",
|
||||||
|
children_count
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(workspace->node_children_label),
|
||||||
|
children_text
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_visible(
|
||||||
|
workspace->node_children_label,
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(workspace->node_children_label),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_visible(
|
||||||
|
workspace->node_children_label,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_set_visible(
|
||||||
|
workspace->welcome_box,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_visible(
|
||||||
|
workspace->node_box,
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(children_text);
|
||||||
|
g_free(parent_text);
|
||||||
|
g_free(type_text);
|
||||||
|
}
|
||||||
|
|
||||||
void workspace_free(Workspace *workspace)
|
void workspace_free(Workspace *workspace)
|
||||||
{
|
{
|
||||||
if (workspace == NULL)
|
if (workspace == NULL)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue