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 "widgets/investigation_tree_view.h"
|
||||
#include "core/investigation_node.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
|
@ -63,6 +64,19 @@ void main_window_set_tree_selection_callback(
|
|||
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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#ifndef LABFY_INVESTIGATION_WORKSPACE_H
|
||||
#define LABFY_INVESTIGATION_WORKSPACE_H
|
||||
|
||||
|
||||
#include "core/investigation_node.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/**
|
||||
|
|
@ -37,6 +40,22 @@ GtkWidget *workspace_get_widget(
|
|||
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.
|
||||
*
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -129,6 +129,11 @@ static void application_on_tree_node_selected(
|
|||
return;
|
||||
}
|
||||
|
||||
main_window_set_selected_node(
|
||||
application->main_window,
|
||||
node
|
||||
);
|
||||
|
||||
if (node == NULL)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (main_window == NULL)
|
||||
|
|
|
|||
|
|
@ -21,8 +21,34 @@ struct Workspace
|
|||
GtkWidget *title_label;
|
||||
GtkWidget *status_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 = NULL;
|
||||
|
|
@ -102,11 +128,64 @@ Workspace *workspace_new(void)
|
|||
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(workspace->root_widget),
|
||||
workspace->welcome_box
|
||||
);
|
||||
|
||||
gtk_box_append(
|
||||
GTK_BOX(workspace->root_widget),
|
||||
workspace->node_box
|
||||
);
|
||||
|
||||
workspace_show_welcome(workspace);
|
||||
|
||||
return workspace;
|
||||
}
|
||||
|
||||
|
|
@ -122,6 +201,122 @@ GtkWidget *workspace_get_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)
|
||||
{
|
||||
if (workspace == NULL)
|
||||
|
|
|
|||
Loading…
Reference in a new issue