X. Fermer▲
X-A. Aperçu▲
X-B. Fermer un fichier▲
Maintenant que nous allouons de la mémoire, il faut la libérer à un endroit. Logiquement cela va être fait à la fermeture du document, en guise d'exercice, je vous laisse créer le bouton dans notre boîte à bouton…
…
Allez je vous aide, le stock id correspondant est GTK_STOCK_CLOSE.
Voilà maintenant, si tout c'est bien passé, vous devriez être arrivé dans le fichier callback.c avec quelque chose ressemblant à :
void
cb_close (
GtkWidget *
p_widget, gpointer user_data)
{
/* ... */
}
Lorsque l'on ferme un document, il faut vider le GtkTextView (avec les onglets, on se contentera de le supprimer), pour cela, il faut récupérer le début et la fin du GtkTextBuffer et demander à GTK+ de supprimer tout ce qui ce trouve entre les deux itérateurs :
/* Avant de fermer, il faut verifier qu'un document a bien ete ouvert */
if
(
docs.actif)
{
GtkTextIter start;
GtkTextIter end;
GtkTextBuffer *
p_text_buffer =
NULL
;
p_text_buffer =
gtk_text_view_get_buffer (
docs.actif->
p_text_view);
gtk_text_buffer_get_bounds (
p_text_buffer, &
start, &
end);
gtk_text_buffer_delete (
p_text_buffer, &
start, &
end);
/* ... */
}
else
{
print_warning (
"
Aucun document ouvert
"
);
}
Bien sûr il ne faut pas oublier de libérer la mémoire :
g_free (
docs.actif->
chemin), docs.actif->
chemin =
NULL
;
docs.actif->
p_text_view =
NULL
;
g_free (
docs.actif), docs.actif =
NULL
;
Pour symboliser la fermeture d'un document, nous désactivons le GtkTextView lors de la fermeture (ne pas oublier de le faire aussi dans main.c) :
gtk_widget_set_sensitive (
GTK_WIDGET (
docs.actif->
p_text_view), FALSE);
Et nous le réactivons lors de l'ouverture si celle si réussie :
gtk_widget_set_sensitive (
GTK_WIDGET (
docs.actif->
p_text_view), TRUE);
Lorsque l'utilisateur quitte l'application, il faut bien sûr fermer le document, s'il y en a un ouvert :
void
cb_quit (
GtkWidget *
p_widget, gpointer user_data)
{
if
(
docs.actif)
{
cb_close (
p_widget, user_data);
}
gtk_main_quit
(
);
}
Et aussi lorsqu'il crée un nouveau document (et par conséquent lorsqu'il ouvre un fichier puisque l'on fait appel à cb_new) :
void
cb_new (
GtkWidget *
p_widget, gpointer user_data)
{
if
(
docs.actif)
{
cb_close (
p_widget, user_data);
}
/* ... */
}
X-C. Enregistrer avant de fermer▲
Si le document a été modifié depuis la dernière sauvegarde, généralement le programme le signale à l'utilisateur et lui propose de sauvegarder ou d'annuler la fermeture. Pour ce faire, nous devons modifier la fonction cb_close, avant de fermer le document, nous allons afficher une boîte de dialogue.
Pour créer une boîte de dialogue simplement, il existe la classe GtkDialog et comme nous avons besoin de boutons (pour que l'utilisateur fasse son choix), nous allons créer notre boîte avec la fonction :
GtkWidget *
gtk_dialog_new_with_buttons (
const
gchar *
title, GtkWindow *
parent, GtkDialogFlags flags, const
gchar *
first_button_text, ...);
Nous retrouvons les mêmes options que pour le GtkFileChooserDialog, mis à part option du type GtkDialogFlags :
typedef
enum
{
GTK_DIALOG_MODAL =
1
<<
0
, /* appel gtk_window_set_modal (win, TRUE) */
GTK_DIALOG_DESTROY_WITH_PARENT =
1
<<
1
, /* appel gtk_window_set_destroy_with_parent () */
GTK_DIALOG_NO_SEPARATOR =
1
<<
2
/* Pas de barre de separation au-dessus des boutons */
}
GtkDialogFlags;
Nous nous contenterons de rendre notre fenêtre modale (7).
Pour avoir accès à notre fenêtre principale, nous ajoutons un champ p_main_window à notre structure globale docs_t que nous initialisons dans la fonction main :
docs.p_main_window =
GTK_WINDOW (
p_window);
Il nous reste plus qu'à créer notre boîte de dialogue avec trois boutons : Oui, Non, Annuler :
if
(!
docs.actif->
sauve)
{
GtkWidget *
p_dialog =
NULL
;
p_dialog =
gtk_dialog_new_with_buttons (
"
Sauvegarder
"
,
docs.p_main_window,
GTK_DIALOG_MODAL,
GTK_STOCK_YES, GTK_RESPONSE_YES,
GTK_STOCK_NO, GTK_RESPONSE_NO,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL
);
/* ... */
Nous obtenons donc une structure de type GtkDialog :
typedef
struct
{
GtkWidget *
vbox;
GtkWidget *
action_area;
}
GtkDialog;
Nous remarquons que cette structure contient deux membres qui permettent d'accéder à une GtkBox, où nous allons ajouter le contenu de la fenêtre, et à la partie contenant les boutons.
Ensuite la construction de la fenêtre est identique à celle de la fenêtre principale, ici nous nous contenterons d'ajouter un GtkLabel :
GtkWidget *
p_label =
NULL
;
/* ... */
p_label =
gtk_label_new (
"
Voulez-vous sauvegarder les modifications ?
"
);
gtk_box_pack_start (
GTK_BOX (
GTK_DIALOG (
p_dialog)->
vbox), p_label, TRUE, TRUE, 0
);
Une fois notre fenêtre prête, il suffit de faire appel à la fonction gtk_dialog_run qui va afficher notre GtkDialog et nous retourner la réponse id correspondant au bouton cliqué par l'utilisateur :
switch
(
gtk_dialog_run (
GTK_DIALOG (
p_dialog)))
{
case
GTK_RESPONSE_YES:
cb_save (
p_widget, user_data);
break
;
case
GTK_RESPONSE_NO:
break
;
case
GTK_RESPONSE_CANCEL:
gtk_widget_destroy (
p_dialog);
return
;
break
;
}
gtk_widget_destroy (
p_dialog);
}
/* ... */
Si l'utilisateur clique sur non, on ne fait rien (le document sera simplement fermé), sur oui, on enregistre avant de fermer et pour finir, s'il annule on quitte la fonction.