[gnome-latex: 12/205] Files with tabs, close a file. The main window is now accessible with the extern variable "docs", be



commit f36ae0b24130d73e92cb5414eee81743ba103c37
Author: Sébastien Wilmet <sebastien wilmet gmail com>
Date:   Tue Aug 4 17:23:08 2009 +0200

    Files with tabs, close a file.
    The main window is now accessible with the extern variable "docs",
    before it was with data passed in callbacks but it becames too
    complicated

 TODO            |   6 +-
 src/Makefile    |   2 +-
 src/callbacks.c | 220 ++++++++++++++++++++++++++++++++++++++++++--------------
 src/callbacks.h |  13 ++--
 src/main.c      |  53 +++++---------
 src/main.h      |   8 +--
 src/ui.xml      |   3 +
 7 files changed, 202 insertions(+), 103 deletions(-)
---
diff --git a/TODO b/TODO
index 41b25ad..0131a95 100644
--- a/TODO
+++ b/TODO
@@ -9,8 +9,10 @@ Jul 31, 2009 to Aug 7, 2009
        x save 
        x save as
        x new
-       - close
-       - tabs
+       x close
+       x tabs
+       - change title of tabs
+       - tabs with close buttons
 
 [-] GtkSourceView
        - syntaxic color
diff --git a/src/Makefile b/src/Makefile
index d8409d9..6a008f5 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,5 +1,5 @@
 CC = gcc
-CFLAGS = -g -W -Wall -std=c99 $(shell pkg-config --cflags gtk+-2.0) -DGTK_DISABLE_DEPRECATED=1
+CFLAGS = -g -Wall -std=c99 $(shell pkg-config --cflags gtk+-2.0) -DGTK_DISABLE_DEPRECATED=1
 LDFLAGS = $(shell pkg-config --libs gtk+-2.0)
 OBJ = main.o callbacks.o error.o
 
diff --git a/src/callbacks.c b/src/callbacks.c
index 7dacc06..4b913ea 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -8,26 +8,28 @@
 #include "callbacks.h"
 #include "error.h"
 
-static void open_file (const gchar *file_name, GtkTextView *text_view);
-static void save_as_dialog (widgets_t *widgets);
+static void create_document_in_new_tab (gchar *path, gchar *text, GtkWidget *label);
+static void save_as_dialog (void);
 static void file_save (void);
+static gboolean close_all (void);
 
 void
-cb_new (GtkAction *action, widgets_t *widgets)
+cb_new (void)
 {
-       docs.active->path = NULL;
-       docs.active->saved = TRUE;
+       char *default_text = "\\documentclass[a4paper,11pt]{article}\n"
+               "\\begin{document}\n"
+               "\\end{document}";
+       GtkWidget *label = gtk_label_new (_("New document"));
 
-       GtkTextBuffer *text_buffer = gtk_text_view_get_buffer (docs.active->text_view);
-       gtk_text_buffer_set_text (text_buffer, "", -1);
+       create_document_in_new_tab (NULL, default_text, label);
 }
 
 void
-cb_open (GtkAction *action, widgets_t *widgets)
+cb_open (void)
 {
        GtkWidget *dialog = gtk_file_chooser_dialog_new (
                        _("Open File"),
-                       GTK_WINDOW (widgets->window),
+                       docs.main_window,
                        GTK_FILE_CHOOSER_ACTION_OPEN,
                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
@@ -36,32 +38,36 @@ cb_open (GtkAction *action, widgets_t *widgets)
 
        if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
        {
-               char *filename;
-               filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
-
-               docs.active->path = g_strdup (filename);
-               docs.active->saved = TRUE;
-
-               //TODO open the file in a new tab
-               open_file (filename, docs.active->text_view);
-               
+               gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
                print_info ("Open file: \"%s\"", filename);
+               gchar *contents = NULL;
+               if (g_file_get_contents (filename, &contents, NULL, NULL))
+               {
+                       // convert the text to UTF-8
+                       gchar *text_utf8 = g_locale_to_utf8 (contents, -1, NULL, NULL, NULL);
+
+                       GtkWidget *label = gtk_label_new (g_path_get_basename (filename));
+                       create_document_in_new_tab (filename, text_utf8, label);
+                       g_free (contents);
+                       g_free (text_utf8);
+               }
+               else
+                       print_warning ("impossible to open the file \"%s\"", filename);
 
                g_free (filename);
        }
-
        gtk_widget_destroy (dialog);
 }
 
 void
-cb_save (GtkAction *action, widgets_t *widgets)
+cb_save (void)
 {
-       if (docs.active)
+       if (docs.active != NULL)
        {
                if (! docs.active->saved)
                {
                        if (docs.active->path == NULL)
-                               save_as_dialog (widgets);
+                               save_as_dialog ();
 
                        file_save();
                }
@@ -72,15 +78,15 @@ cb_save (GtkAction *action, widgets_t *widgets)
 }
 
 void
-cb_save_as (GtkAction *action, widgets_t *widgets)
+cb_save_as (void)
 {
-       if (docs.active)
+       if (docs.active != NULL)
        {
                document_t doc_backup = *docs.active;
 
                docs.active->path = NULL;
                docs.active->saved = FALSE;
-               cb_save (action, widgets);
+               cb_save ();
 
                // if the user click on cancel
                if (! docs.active->saved)
@@ -92,13 +98,89 @@ cb_save_as (GtkAction *action, widgets_t *widgets)
 }
 
 void
-cb_about_dialog (GtkAction *action, widgets_t *widgets)
+cb_close (void)
+{
+       if (docs.active != NULL)
+       {
+               /* if the document is not saved, ask the user for saving changes before
+                * closing */
+               if (! docs.active->saved)
+               {
+                       GtkWidget *dialog = gtk_dialog_new_with_buttons (
+                                       _("Close the document"),
+                                       docs.main_window,
+                                       GTK_DIALOG_MODAL,
+                                       GTK_STOCK_YES, GTK_RESPONSE_YES,
+                                       GTK_STOCK_NO, GTK_RESPONSE_NO,
+                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                       NULL
+                       );
+                       GtkWidget *label = gtk_label_new (_("Save changes to document before closing?"));
+                       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label, TRUE, FALSE, 10);
+                       gtk_widget_show_all (GTK_DIALOG (dialog)->vbox);
+
+                       switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+                       {
+                               // save changes before closing
+                               case GTK_RESPONSE_YES:
+                                       cb_save ();
+                                       break;
+
+                               // close the document without saving changes
+                               case GTK_RESPONSE_NO:
+                                       break;
+                               
+                               // do nothing, the document is not closed
+                               case GTK_RESPONSE_CANCEL:
+                                       gtk_widget_destroy (dialog);
+                                       return;
+                       }
+
+                       gtk_widget_destroy (dialog);
+               }
+
+               /* close the tab */
+               docs.all = g_list_remove (docs.all, docs.active);
+               g_free (docs.active->path);
+               g_free (docs.active);
+               gtk_notebook_remove_page (docs.notebook, gtk_notebook_get_current_page (docs.notebook));
+               if (gtk_notebook_get_n_pages (docs.notebook) > 0)
+                       docs.active = g_list_nth_data (docs.all, gtk_notebook_get_current_page 
(docs.notebook));
+               else
+                       docs.active = NULL;
+       }
+
+       else
+               print_warning ("no document opened");
+}
+
+void
+cb_quit (void)
+{
+       if (close_all ())
+       {
+               print_info ("Bye bye");
+               gtk_main_quit ();
+       }
+}
+
+gboolean
+cb_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+       cb_quit ();
+
+       // the destroy signal is not emitted
+       return TRUE;
+}
+
+void
+cb_about_dialog (void)
 {
        gchar *comments = _(PROGRAM_NAME " is a LaTeX development environment for the GNOME Desktop");
        gchar *copyright = "Copyright © 2009 Sébastien Wilmet";
 
        //TODO show the appropriate text for the GPL 3 licence
-       gchar *licence = "GPL 3 or later";
+       gchar *licence = "GNU General Public Licence version 3 or later";
 
        //TODO set the url hook
        gchar *website = "http://latexila.sourceforge.net/";;
@@ -110,7 +192,7 @@ cb_about_dialog (GtkAction *action, widgets_t *widgets)
        };
 
        gtk_show_about_dialog (
-                       GTK_WINDOW (widgets->window),
+                       docs.main_window,
                        "program-name", PROGRAM_NAME,
                        "authors", authors,
                        "comments", comments,
@@ -125,46 +207,63 @@ cb_about_dialog (GtkAction *action, widgets_t *widgets)
 }
 
 void
-cb_quit (void)
+cb_text_changed (GtkWidget *widget, gpointer user_data)
 {
-       print_info ("Bye bye");
-       gtk_main_quit ();
+       if (docs.active != NULL)
+               docs.active->saved = FALSE;
 }
 
 void
-cb_text_changed (GtkWidget *widget, gpointer user_data)
+cb_page_change (GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer user_data)
 {
-       if (docs.active)
-               docs.active->saved = FALSE;
+       docs.active = g_list_nth_data (docs.all, page_num);
+       print_info ("switch-page: %d (%s)", page_num, docs.active->path);
 }
 
+/*****************************
+ * local functions
+ *****************************/
+
 static void
-open_file (const gchar *file_name, GtkTextView *text_view)
+create_document_in_new_tab (gchar *path, gchar *text, GtkWidget *label)
 {
-       // the arguments must not be NULL
-       g_return_if_fail (file_name && text_view);
-
-       gchar *contents = NULL;
-
-       if (g_file_get_contents (file_name, &contents, NULL, NULL))
-       {
-               GtkTextBuffer *text_buffer = gtk_text_view_get_buffer (text_view);
-               gchar *utf8 = g_locale_to_utf8 (contents, -1, NULL, NULL, NULL);
-               gtk_text_buffer_set_text (text_buffer, utf8, -1);
-               g_free (contents);
-               g_free (utf8);
-       }
-
-       else
-               print_warning ("impossible to open the file \"%s\"", file_name);
+       // create a new document_t structure
+       // if path = NULL, this is a new document
+       // else, the user opened a document
+       document_t *new_doc = g_malloc (sizeof (document_t));
+       new_doc->path = path;
+       new_doc->saved = (path == NULL) ? FALSE : TRUE;
+       new_doc->text_view = GTK_TEXT_VIEW (gtk_text_view_new ());
+
+       docs.all = g_list_append (docs.all, new_doc);
+       docs.active = new_doc;
+
+       // put the text into the buffer
+       GtkTextBuffer *text_buffer = gtk_text_view_get_buffer (new_doc->text_view);
+       gtk_text_buffer_set_text (text_buffer, text, -1);
+
+       // when the text is modified
+       g_signal_connect (G_OBJECT (text_buffer), "changed",
+                       G_CALLBACK (cb_text_changed), NULL);
+
+       // with a scrollbar
+       GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+                       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (new_doc->text_view));
+       gtk_widget_show_all (sw);
+
+       // add the new document in a new tab
+       gint index = gtk_notebook_append_page (docs.notebook, sw, label);
+       gtk_notebook_set_current_page (docs.notebook, index);
 }
 
 static void
-save_as_dialog (widgets_t *widgets)
+save_as_dialog (void)
 {
        GtkWidget *dialog = gtk_file_chooser_dialog_new (
                        _("Save File"),
-                       GTK_WINDOW (widgets->window),
+                       docs.main_window,
                        GTK_FILE_CHOOSER_ACTION_SAVE,
                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
@@ -212,3 +311,18 @@ file_save (void)
                }
        }
 }
+
+static gboolean
+close_all (void)
+{
+       while (docs.active != NULL)
+       {
+               int tmp = gtk_notebook_get_n_pages (docs.notebook);
+               gtk_notebook_set_current_page (docs.notebook, 0);
+               cb_close ();
+               if (gtk_notebook_get_n_pages (docs.notebook) >= tmp)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
diff --git a/src/callbacks.h b/src/callbacks.h
index 3e4dc91..ad4fe3a 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -1,12 +1,15 @@
 #ifndef CALLBACKS_H
 #define CALLBACKS_H
 
-void cb_new (GtkAction *action, widgets_t *widgets);
-void cb_open (GtkAction *action, widgets_t *widgets);
-void cb_save (GtkAction *action, widgets_t *widgets);
-void cb_save_as (GtkAction *action, widgets_t *widgets);
-void cb_about_dialog (GtkAction *action, widgets_t *widgets);
+void cb_new (void);
+void cb_open (void);
+void cb_save (void);
+void cb_save_as (void);
+void cb_close (void);
 void cb_quit (void);
+void cb_about_dialog (void);
 void cb_text_changed (GtkWidget *widget, gpointer user_data);
+void cb_page_change (GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer user_data);
+gboolean cb_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data);
 
 #endif /* CALLBACKS_H */
diff --git a/src/main.c b/src/main.c
index 676bc6d..92c8084 100644
--- a/src/main.c
+++ b/src/main.c
@@ -8,7 +8,7 @@
 #include "callbacks.h"
 #include "error.h"
 
-docs_t docs = {NULL, NULL};
+docs_t docs = {NULL, NULL, NULL, NULL}; 
 
 int
 main (int argc, char *argv[])
@@ -22,11 +22,13 @@ main (int argc, char *argv[])
 
        /* main window */
        GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-       g_signal_connect (G_OBJECT (window), "destroy",
-                       G_CALLBACK (cb_quit), NULL);
+       g_signal_connect (G_OBJECT (window), "delete_event",
+                       G_CALLBACK (cb_delete_event), NULL);
        gtk_window_set_title (GTK_WINDOW (window), PROGRAM_NAME);
        gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
-       gtk_window_set_default_size (GTK_WINDOW (window), 500, 400);
+       gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
+
+       docs.main_window = GTK_WINDOW (window);
 
        /* boxes */
        GtkWidget *main_vbox = gtk_vbox_new (FALSE, 0);
@@ -51,6 +53,8 @@ main (int argc, char *argv[])
                        _("Save the current file"), G_CALLBACK (cb_save)},
                {"FileSaveAs", GTK_STOCK_SAVE_AS, _("Save as..."), "<Shift><Control>S",
                        _("Save the current file with a different name"), G_CALLBACK (cb_save_as)},
+               {"FileClose", GTK_STOCK_CLOSE, _("Close"), "<Control>W",
+                       _("Close the current file"), G_CALLBACK (cb_close)},
                {"FileQuit", GTK_STOCK_QUIT, _("Quit"), "<Control>Q",
                        _("Quit the program"), G_CALLBACK (cb_quit)},
                
@@ -77,16 +81,9 @@ main (int argc, char *argv[])
 
        guint nb_entries = G_N_ELEMENTS (entries);
 
-       // this structure contain the window and the widgets used in callbacks
-       // functions
-       // so the widgets must be initialized before the call of
-       // gtk_action_group_add_actions ()
-       widgets_t widgets;
-       widgets.window = window;
-
        // create the action group and the ui manager
        GtkActionGroup *action_group = gtk_action_group_new ("menuActionGroup");
-       gtk_action_group_add_actions (action_group, entries, nb_entries, &widgets);
+       gtk_action_group_add_actions (action_group, entries, nb_entries, NULL);
        GtkUIManager *ui_manager = gtk_ui_manager_new ();
        gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 
@@ -115,31 +112,15 @@ main (int argc, char *argv[])
        GtkWidget *vpaned = gtk_vpaned_new ();
        gtk_box_pack_start (GTK_BOX (main_vbox), vpaned, TRUE, TRUE, 0);
 
-       /* source view */
-       GtkWidget *source_view = gtk_text_view_new ();
-       GtkTextBuffer *source_buffer = gtk_text_view_get_buffer (
-                       GTK_TEXT_VIEW (source_view));
-       char *source_default_text = "\\documentclass[a4paper,11pt]{article}\n"
-               "\\begin{document}\n"
-               "\\end{document}";
-       gtk_text_buffer_set_text (source_buffer, source_default_text, -1);
-
-       // when the text is modified, the "saved" field of document_t must be FALSE
-       g_signal_connect (G_OBJECT (source_buffer), "changed",
-                       G_CALLBACK (cb_text_changed), NULL);
-
-       // with a scrollbar
-       GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
-       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
-                       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-       gtk_paned_pack1 (GTK_PANED (vpaned), sw, TRUE, TRUE);
-       gtk_container_add (GTK_CONTAINER (sw), source_view);
+       /* source view with tabs */
+       GtkWidget *notebook = gtk_notebook_new ();
+       g_signal_connect (G_OBJECT (notebook), "switch-page",
+                       G_CALLBACK (cb_page_change), NULL);
+       gtk_paned_pack1 (GTK_PANED (vpaned), notebook, TRUE, TRUE);
+       docs.notebook = GTK_NOTEBOOK (notebook);
 
-       // initialize the extern structure docs
-       document_t first_document = {NULL, FALSE, GTK_TEXT_VIEW (source_view)};
-       docs.active = &first_document;
-       
        /* log zone */
+       //TODO set a default height
        GtkWidget *log_view = gtk_text_view_new ();
        GtkTextBuffer *log_buffer = gtk_text_view_get_buffer (
                        GTK_TEXT_VIEW (log_view));
@@ -147,7 +128,7 @@ main (int argc, char *argv[])
        gtk_text_view_set_editable (GTK_TEXT_VIEW(log_view), FALSE);
        
        // with a scrollbar
-       sw = gtk_scrolled_window_new (NULL, NULL);
+       GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
        gtk_paned_pack2 (GTK_PANED (vpaned), sw, TRUE, TRUE);
diff --git a/src/main.h b/src/main.h
index 84991f2..b1f7d00 100644
--- a/src/main.h
+++ b/src/main.h
@@ -6,12 +6,6 @@
 #define PROGRAM_NAME "LaTeXila"
 #define PROGRAM_VERSION "0.0.1"
 
-// used for data callbacks
-typedef struct
-{
-       GtkWidget *window;
-} widgets_t;
-
 // each document opened is represented by a document_t structure
 typedef struct
 {
@@ -24,6 +18,8 @@ typedef struct
 {
        GList *all;
        document_t *active;
+       GtkWindow *main_window;
+       GtkNotebook *notebook;
 } docs_t;
 
 // all the documents are accessible by the docs variable
diff --git a/src/ui.xml b/src/ui.xml
index a9ca677..4c5abb1 100644
--- a/src/ui.xml
+++ b/src/ui.xml
@@ -8,8 +8,11 @@ In the code, GtkUIManager is used to construct them.
     <menu action="File">
       <menuitem action="FileNew" />
       <menuitem action="FileOpen" />
+      <separator />
       <menuitem action="FileSave" />
       <menuitem action="FileSaveAs" />
+      <separator />
+      <menuitem action="FileClose" />
       <menuitem action="FileQuit" />
     </menu>
     


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]