Confirmer la réinitialisation de la disposition du graphe

This commit is contained in:
grayTerminal-sh 2026-07-22 07:35:15 +02:00
parent 0f67118f5b
commit 0069e99529
3 changed files with 645 additions and 7 deletions

View file

@ -18,6 +18,20 @@ typedef enum
APPLICATION_MESSAGE_DIALOG_INFORMATION
} ApplicationMessageDialogType;
/**
* @brief Callback appelé à la fermeture d'un dialogue de confirmation.
*
* Le callback est appelé une seule fois après un clic sur l'un des boutons
* ou après une fermeture manuelle de la fenêtre.
*
* @param confirmed TRUE si l'utilisateur confirme, sinon FALSE.
* @param user_data Données empruntées fournies par l'appelant.
*/
typedef void (*ApplicationMessageDialogConfirmationCallback)(
gboolean confirmed,
gpointer user_data
);
/**
* @brief Affiche une fenêtre modale contenant un message.
*
@ -35,4 +49,31 @@ void application_message_dialog_present(
const char *message
);
/**
* @brief Affiche un dialogue modal demandant une confirmation.
*
* Le bouton d'annulation transmet FALSE. Le bouton de confirmation transmet
* TRUE. Fermer la fenêtre manuellement équivaut à une annulation.
*
* callback et user_data sont empruntés jusqu'à la fermeture du dialogue.
* confirm_label peut être NULL ou vide pour utiliser « Confirmer ».
*
* @param parent_window Fenêtre parente, ou NULL.
* @param message_type Type de message.
* @param title Titre de la fenêtre, ou NULL.
* @param message Message principal, ou NULL.
* @param confirm_label Libellé du bouton de confirmation, ou NULL.
* @param callback Callback facultatif recevant la réponse.
* @param user_data Données empruntées transmises au callback.
*/
void application_message_dialog_present_confirmation(
GtkWindow *parent_window,
ApplicationMessageDialogType message_type,
const char *title,
const char *message,
const char *confirm_label,
ApplicationMessageDialogConfirmationCallback callback,
gpointer user_data
);
#endif

View file

@ -4278,17 +4278,15 @@ static void application_on_graph_node_moved(
}
/**
* @brief Ferme proprement l'application.
* @brief Supprime les positions persistées et restaure la grille automatique.
*
* @param user_data Pointeur vers Application.
* Cette fonction est appelée uniquement après une confirmation explicite.
* L'affichage et le modèle en mémoire restent inchangés en cas d'échec SQLite.
*/
static void application_on_reset_graph_layout_requested(
gpointer user_data
static void application_reset_graph_layout(
Application *application
)
{
Application *application =
user_data;
Database *database =
NULL;
@ -4402,6 +4400,61 @@ static void application_on_reset_graph_layout_requested(
);
}
/**
* @brief Traite la réponse du dialogue de confirmation.
*/
static void application_on_reset_graph_layout_confirmed(
gboolean confirmed,
gpointer user_data
)
{
Application *application =
user_data;
if (!confirmed)
{
return;
}
application_reset_graph_layout(
application
);
}
/**
* @brief Demande confirmation avant toute suppression de position.
*/
static void application_on_reset_graph_layout_requested(
gpointer user_data
)
{
Application *application =
user_data;
if (application == NULL ||
application->main_window == NULL ||
application->session == NULL ||
application->graph_model == NULL ||
application->graph_layout == NULL)
{
return;
}
application_message_dialog_present_confirmation(
main_window_get_window(
application->main_window
),
APPLICATION_MESSAGE_DIALOG_WARNING,
"Réinitialiser la disposition du graphe",
"Toutes les positions personnalisées des nœuds seront supprimées. "
"Le graphe retrouvera sa disposition automatique.\n\n"
"Cette action ne peut pas être annulée.",
"Réinitialiser",
application_on_reset_graph_layout_confirmed,
application
);
}
/**
* @brief Ferme proprement l'application.
*

View file

@ -16,6 +16,25 @@
#define APPLICATION_MESSAGE_DIALOG_DEFAULT_MESSAGE \
"Aucun détail supplémentaire n'est disponible."
/**
* @brief Libellé par défaut du bouton de confirmation.
*/
#define APPLICATION_MESSAGE_DIALOG_DEFAULT_CONFIRM_LABEL \
"Confirmer"
/**
* @brief État privé d'un dialogue de confirmation.
*/
typedef struct
{
GtkWindow *dialog_window;
ApplicationMessageDialogConfirmationCallback callback;
gpointer user_data;
gboolean completed;
} ApplicationMessageDialogConfirmationContext;
/**
* @brief Retourne le libellé correspondant au type de message.
*
@ -335,3 +354,528 @@ void application_message_dialog_present(
dialog_window
);
}
/**
* @brief Libère le contexte associé à une fenêtre de confirmation.
*/
static void application_message_dialog_confirmation_context_free(
gpointer data
)
{
ApplicationMessageDialogConfirmationContext *context =
data;
if (context == NULL)
{
return;
}
context->dialog_window =
NULL;
context->callback =
NULL;
context->user_data =
NULL;
g_free(
context
);
}
/**
* @brief Termine une confirmation et transmet son résultat une seule fois.
*
* Lorsque destroy_window vaut TRUE, la fenêtre est détruite avant l'appel
* du callback. Les valeurs du callback sont donc copiées localement avant
* la destruction du contexte attaché à la fenêtre.
*/
static void application_message_dialog_complete_confirmation(
ApplicationMessageDialogConfirmationContext *context,
gboolean confirmed,
gboolean destroy_window
)
{
ApplicationMessageDialogConfirmationCallback callback =
NULL;
gpointer user_data =
NULL;
GtkWindow *dialog_window =
NULL;
if (context == NULL ||
context->completed)
{
return;
}
context->completed =
TRUE;
callback =
context->callback;
user_data =
context->user_data;
dialog_window =
context->dialog_window;
context->callback =
NULL;
context->user_data =
NULL;
if (destroy_window &&
dialog_window != NULL)
{
gtk_window_destroy(
dialog_window
);
}
if (callback != NULL)
{
callback(
confirmed,
user_data
);
}
}
/**
* @brief Annule le dialogue depuis son bouton.
*/
static void application_message_dialog_on_cancel_clicked(
GtkButton *button,
gpointer user_data
)
{
ApplicationMessageDialogConfirmationContext *context =
user_data;
(void) button;
application_message_dialog_complete_confirmation(
context,
FALSE,
TRUE
);
}
/**
* @brief Confirme le dialogue depuis son bouton principal.
*/
static void application_message_dialog_on_confirm_clicked(
GtkButton *button,
gpointer user_data
)
{
ApplicationMessageDialogConfirmationContext *context =
user_data;
(void) button;
application_message_dialog_complete_confirmation(
context,
TRUE,
TRUE
);
}
/**
* @brief Traite la fermeture manuelle comme une annulation.
*/
static gboolean application_message_dialog_on_confirmation_close_requested(
GtkWindow *dialog_window,
gpointer user_data
)
{
ApplicationMessageDialogConfirmationContext *context =
user_data;
(void) dialog_window;
application_message_dialog_complete_confirmation(
context,
FALSE,
FALSE
);
/*
* FALSE laisse GTK poursuivre la fermeture normale de la fenêtre.
*/
return FALSE;
}
void application_message_dialog_present_confirmation(
GtkWindow *parent_window,
ApplicationMessageDialogType message_type,
const char *title,
const char *message,
const char *confirm_label,
ApplicationMessageDialogConfirmationCallback callback,
gpointer user_data
)
{
GtkWindow *dialog_window =
NULL;
GtkWidget *main_box =
NULL;
GtkWidget *type_label =
NULL;
GtkWidget *title_label =
NULL;
GtkWidget *message_label =
NULL;
GtkWidget *button_box =
NULL;
GtkWidget *cancel_button =
NULL;
GtkWidget *confirm_button =
NULL;
ApplicationMessageDialogConfirmationContext *context =
NULL;
const char *safe_title =
NULL;
const char *safe_message =
NULL;
const char *safe_confirm_label =
NULL;
const char *type_text =
NULL;
safe_title =
application_message_dialog_get_safe_title(
message_type,
title
);
safe_message =
application_message_dialog_get_safe_message(
message
);
safe_confirm_label =
confirm_label != NULL &&
confirm_label[0] != '\0'
? confirm_label
: APPLICATION_MESSAGE_DIALOG_DEFAULT_CONFIRM_LABEL;
type_text =
application_message_dialog_get_type_label(
message_type
);
context =
g_try_new0(
ApplicationMessageDialogConfirmationContext,
1
);
if (context == NULL)
{
return;
}
dialog_window =
GTK_WINDOW(
gtk_window_new()
);
context->dialog_window =
dialog_window;
context->callback =
callback;
context->user_data =
user_data;
context->completed =
FALSE;
g_object_set_data_full(
G_OBJECT(
dialog_window
),
"application-message-dialog-confirmation-context",
context,
application_message_dialog_confirmation_context_free
);
gtk_window_set_title(
dialog_window,
safe_title
);
gtk_window_set_default_size(
dialog_window,
APPLICATION_MESSAGE_DIALOG_DEFAULT_WIDTH,
-1
);
gtk_window_set_modal(
dialog_window,
TRUE
);
gtk_window_set_destroy_with_parent(
dialog_window,
TRUE
);
gtk_window_set_resizable(
dialog_window,
FALSE
);
if (parent_window != NULL)
{
gtk_window_set_transient_for(
dialog_window,
parent_window
);
}
main_box =
gtk_box_new(
GTK_ORIENTATION_VERTICAL,
12
);
gtk_widget_set_margin_start(
main_box,
20
);
gtk_widget_set_margin_end(
main_box,
20
);
gtk_widget_set_margin_top(
main_box,
20
);
gtk_widget_set_margin_bottom(
main_box,
20
);
type_label =
gtk_label_new(
type_text
);
gtk_widget_set_halign(
type_label,
GTK_ALIGN_START
);
gtk_label_set_xalign(
GTK_LABEL(
type_label
),
0.0F
);
title_label =
gtk_label_new(
safe_title
);
gtk_widget_set_halign(
title_label,
GTK_ALIGN_START
);
gtk_label_set_xalign(
GTK_LABEL(
title_label
),
0.0F
);
gtk_label_set_wrap(
GTK_LABEL(
title_label
),
TRUE
);
gtk_widget_add_css_class(
title_label,
"title-2"
);
message_label =
gtk_label_new(
safe_message
);
gtk_widget_set_halign(
message_label,
GTK_ALIGN_FILL
);
gtk_label_set_xalign(
GTK_LABEL(
message_label
),
0.0F
);
gtk_label_set_wrap(
GTK_LABEL(
message_label
),
TRUE
);
gtk_label_set_wrap_mode(
GTK_LABEL(
message_label
),
PANGO_WRAP_WORD_CHAR
);
gtk_label_set_selectable(
GTK_LABEL(
message_label
),
TRUE
);
gtk_label_set_max_width_chars(
GTK_LABEL(
message_label
),
70
);
button_box =
gtk_box_new(
GTK_ORIENTATION_HORIZONTAL,
8
);
gtk_widget_set_halign(
button_box,
GTK_ALIGN_END
);
cancel_button =
gtk_button_new_with_label(
"Annuler"
);
confirm_button =
gtk_button_new_with_label(
safe_confirm_label
);
gtk_widget_add_css_class(
confirm_button,
"destructive-action"
);
g_signal_connect(
cancel_button,
"clicked",
G_CALLBACK(
application_message_dialog_on_cancel_clicked
),
context
);
g_signal_connect(
confirm_button,
"clicked",
G_CALLBACK(
application_message_dialog_on_confirm_clicked
),
context
);
g_signal_connect(
dialog_window,
"close-request",
G_CALLBACK(
application_message_dialog_on_confirmation_close_requested
),
context
);
gtk_box_append(
GTK_BOX(
button_box
),
cancel_button
);
gtk_box_append(
GTK_BOX(
button_box
),
confirm_button
);
gtk_box_append(
GTK_BOX(
main_box
),
type_label
);
gtk_box_append(
GTK_BOX(
main_box
),
title_label
);
gtk_box_append(
GTK_BOX(
main_box
),
message_label
);
gtk_box_append(
GTK_BOX(
main_box
),
button_box
);
gtk_window_set_child(
dialog_window,
main_box
);
gtk_widget_grab_focus(
cancel_button
);
gtk_window_present(
dialog_window
);
}