[gnome-latex: 137/205] Possibility to create new templates



commit 2cf7dfef765a153972da695132d3d9835ad8e660
Author: Sébastien Wilmet <sebastien wilmet gmail com>
Date:   Wed Dec 16 00:05:46 2009 +0100

    Possibility to create new templates
    
    The templates are saved in the user data directory. The filename of the
    first template is "0.tex", then "1.tex", etc. There is a key-value file
    to store the names of the templates.

 AUTHORS         |   4 +
 TODO            |  10 +-
 src/callbacks.c |   3 +-
 src/main.c      |   2 +-
 src/prefs.c     |   2 +-
 src/templates.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 src/templates.h |   1 +
 src/ui.c        |   2 +
 src/ui.xml      |   2 +
 9 files changed, 329 insertions(+), 41 deletions(-)
---
diff --git a/AUTHORS b/AUTHORS
index d02c61f..0a2ca75 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1 +1,5 @@
+Main developer:
 Sébastien Wilmet <sebastien wilmet gmail com>
+
+Thanks to:
+Stéphane Roy
diff --git a/TODO b/TODO
index 0658fe1..a3f8886 100644
--- a/TODO
+++ b/TODO
@@ -3,7 +3,7 @@ TODO LaTeXila
 [-] Templates
        x create a few default templates
        x on the action "new file", possibility to select a template
-       - possibility to create new templates
+       x possibility to create new templates
        - possibility to delete templates (not the defaults)
 
 [-] BibTeX support
@@ -12,4 +12,12 @@ TODO LaTeXila
 
 [-] comment/uncomment selected lines
 
+[-] indent/unindent lines
+
+[-] more preferences for the source view
+       - style of indentation
+       - ...
+
+[-] documentation
+
 [-] replace the notebook in the side pane by a combo box with a close button
diff --git a/src/callbacks.c b/src/callbacks.c
index c9ab996..ac49dbf 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -1272,8 +1272,7 @@ file_save (void)
        print_info ("save current buffer to \"%s\"", latexila.active_doc->path);
 
        GtkTextBuffer *text_buffer = GTK_TEXT_BUFFER (latexila.active_doc->source_buffer);
-       GtkTextIter start;
-       GtkTextIter end;
+       GtkTextIter start, end;
        gtk_text_buffer_get_bounds (text_buffer, &start, &end);
        gchar *contents = gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE);
        gchar *locale = g_locale_from_utf8 (contents, -1, NULL, NULL, &error);
diff --git a/src/main.c b/src/main.c
index c40b2d2..a9532cf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,7 +1,7 @@
 /*
  * This file is part of LaTeXila.
  *
- * Copyright © 2009 Sébastien Wilmet, Stéphane Roy
+ * Copyright © 2009 Sébastien Wilmet
  *
  * LaTeXila is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/src/prefs.c b/src/prefs.c
index bc84ba6..896d73f 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -83,6 +83,7 @@ load_preferences (preferences_t *prefs)
        gchar *rc_file = get_rc_file ();
        if (! g_file_test (rc_file, G_FILE_TEST_EXISTS))
        {
+               g_free (rc_file);
                load_default_preferences (prefs);
                return;
        }
@@ -96,7 +97,6 @@ load_preferences (preferences_t *prefs)
        {
                print_warning ("load user preferences failed: %s", error->message);
                g_error_free (error);
-               error = NULL;
                load_default_preferences (prefs);
                return;
        }
diff --git a/src/templates.c b/src/templates.c
index 47ed465..7062df9 100644
--- a/src/templates.c
+++ b/src/templates.c
@@ -23,6 +23,7 @@
 #include <libintl.h>
 #include <gtk/gtk.h>
 #include <gtksourceview/gtksourceview.h>
+#include <sys/stat.h> // for S_IRWXU
 
 #include "main.h"
 #include "config.h"
@@ -30,12 +31,19 @@
 #include "callbacks.h"
 #include "templates.h"
 
-static void add_template_from_string (GtkListStore *store, gchar *name,
-               gchar *icon, gchar *contents);
-static void add_template_from_file (GtkListStore *store, gchar *name,
-               gchar *icon, gchar *filename);
+static void add_template_from_string (GtkListStore *store, const gchar *name,
+               const gchar *icon, const gchar *contents);
+static void add_template_from_file (GtkListStore *store, const gchar *name,
+               const gchar *icon, const gchar *path);
+static GtkWidget * create_icon_view (GtkListStore *store);
+static void cb_icon_view_selection_changed (GtkIconView *icon_view,
+               gpointer other_icon_view);
+static gchar * get_rc_file (void);
+static void add_personnal_template (const gchar *name, const gchar *contents);
 
-static GtkListStore *store;
+static GtkListStore *default_store;
+static GtkListStore *personnal_store;
+static gint nb_personnal_templates;
 
 void
 cb_new (void)
@@ -47,39 +55,77 @@ cb_new (void)
                        GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
                        NULL);
 
-       gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 200);
+       gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 350);
        
        GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 
-       GtkWidget *icon_view = gtk_icon_view_new_with_model (
-                       GTK_TREE_MODEL (store));
-       gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view),
-                       GTK_SELECTION_SINGLE);
-       gtk_icon_view_set_columns (GTK_ICON_VIEW (icon_view), -1);
-       gtk_icon_view_set_text_column (GTK_ICON_VIEW (icon_view),
-                       COLUMN_TEMPLATE_NAME);
-       gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view),
-                       COLUMN_TEMPLATE_PIXBUF);
+       /* icon view for the default templates */
+       GtkWidget *icon_view_default_templates = create_icon_view (default_store);
 
        // with a scrollbar (without that there is a problem for resizing the
        // dialog, we can make it bigger but not smaller...)
        GtkWidget *scrollbar = gtk_scrolled_window_new (NULL, NULL);
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollbar),
                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-       gtk_container_add (GTK_CONTAINER (scrollbar), icon_view);
+       gtk_container_add (GTK_CONTAINER (scrollbar), icon_view_default_templates);
+
+       // with a frame
+       GtkWidget *frame = gtk_frame_new (_("Default templates"));
+       gtk_container_add (GTK_CONTAINER (frame), scrollbar);
+
+       gtk_box_pack_start (GTK_BOX (content_area), frame, TRUE, TRUE, 10);
+
+       /* icon view for the personnal templates */
+       GtkWidget *icon_view_personnal_templates = create_icon_view (personnal_store);
+
+       // with a scrollbar
+       scrollbar = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollbar),
+                       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_container_add (GTK_CONTAINER (scrollbar), icon_view_personnal_templates);
+
+       // with a frame
+       frame = gtk_frame_new (_("Your personnal templates"));
+       gtk_container_add (GTK_CONTAINER (frame), scrollbar);
+
+       gtk_box_pack_start (GTK_BOX (content_area), frame, TRUE, TRUE, 10);
 
-       gtk_box_pack_start (GTK_BOX (content_area), scrollbar, TRUE, TRUE, 0);
        gtk_widget_show_all (content_area);
 
+       /* signals */
+       g_signal_connect (G_OBJECT (icon_view_default_templates),
+                       "selection-changed",
+                       G_CALLBACK (cb_icon_view_selection_changed),
+                       GTK_ICON_VIEW (icon_view_personnal_templates));
+
+       g_signal_connect (G_OBJECT (icon_view_personnal_templates),
+                       "selection-changed",
+                       G_CALLBACK (cb_icon_view_selection_changed),
+                       GTK_ICON_VIEW (icon_view_default_templates));
+
        if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
        {
                GList *selected_items = gtk_icon_view_get_selected_items (
-                               GTK_ICON_VIEW (icon_view));
+                               GTK_ICON_VIEW (icon_view_default_templates));
+               GtkTreeModel *model = GTK_TREE_MODEL (default_store);
+
+               // if no item is selected in the default templates, maybe one item is
+               // selected in the personnal templates
+               if (g_list_length (selected_items) == 0)
+               {
+                       // free the GList
+                       g_list_foreach (selected_items, (GFunc) gtk_tree_path_free, NULL);
+                       g_list_free (selected_items);
+
+                       selected_items = gtk_icon_view_get_selected_items (
+                                       GTK_ICON_VIEW (icon_view_personnal_templates));
+                       model = GTK_TREE_MODEL (personnal_store);
+               }
+
                GtkTreePath *path = g_list_nth_data (selected_items, 0);
-               GtkTreeModel *model = GTK_TREE_MODEL (store);
                GtkTreeIter iter;
-
                gchar *contents = NULL;
+
                if (path != NULL && gtk_tree_model_get_iter (model, &iter, path))
                {
                        gtk_tree_model_get (model, &iter,
@@ -101,28 +147,153 @@ cb_new (void)
        gtk_widget_destroy (dialog);
 }
 
+void
+cb_create_template (void)
+{
+       if (latexila.active_doc == NULL)
+               return;
+
+       GtkWidget *dialog = gtk_dialog_new_with_buttons (_("New Template..."),
+                       latexila.main_window, 0,
+                       GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                       GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+                       NULL);
+
+       GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+       GtkWidget *hbox = gtk_hbox_new (FALSE, 5);
+       GtkWidget *label = gtk_label_new (_("Name of the new template:"));
+       GtkWidget *entry = gtk_entry_new ();
+
+       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+       gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
+       gtk_box_pack_start (GTK_BOX (content_area), hbox, FALSE, FALSE, 10);
+
+       gtk_widget_show_all (content_area);
+
+       while (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+       {
+               if (gtk_entry_get_text_length (GTK_ENTRY (entry)) == 0)
+                       continue;
+
+               const gchar *name = gtk_entry_get_text (GTK_ENTRY (entry));
+
+               GtkTextBuffer *buffer =
+                       GTK_TEXT_BUFFER (latexila.active_doc->source_buffer);
+               GtkTextIter start, end;
+               gtk_text_buffer_get_bounds (buffer, &start, &end);
+               gchar *contents = gtk_text_buffer_get_text (buffer, &start, &end,
+                               FALSE);
+
+               add_template_from_string (personnal_store, name,
+                               DATA_DIR "/images/templates/article.png", contents);
+               add_personnal_template (name, contents);
+
+               g_free (contents);
+               break;
+       }
+
+       gtk_widget_destroy (dialog);
+}
+
 void
 init_templates (void)
 {
-       store = gtk_list_store_new (N_COLUMNS_TEMPLATE,
+       /* default templates */
+       default_store = gtk_list_store_new (N_COLUMNS_TEMPLATE,
                        GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
 
-       add_template_from_string (store, _("Empty"),
+       add_template_from_string (default_store, _("Empty"),
                        DATA_DIR "/images/templates/empty.png", "");
-       add_template_from_file (store, _("Article"),
-                       DATA_DIR "/images/templates/article.png", _("article-en.tex"));
-       add_template_from_file (store, _("Report"),
-                       DATA_DIR "/images/templates/report.png", _("report-en.tex"));
-       add_template_from_file (store, _("Book"),
-                       DATA_DIR "/images/templates/book.png", _("book-en.tex"));
-       add_template_from_file (store, _("Letter"),
-                       DATA_DIR "/images/templates/letter.png", _("letter-en.tex"));
 
+       // article
+       gchar *path = g_strdup_printf (DATA_DIR "/templates/%s",
+                       _("article-en.tex"));
+       add_template_from_file (default_store, _("Article"),
+                       DATA_DIR "/images/templates/article.png", path);
+       g_free (path);
+
+       // report
+       path = g_strdup_printf (DATA_DIR "/templates/%s",
+                       _("report-en.tex"));
+       add_template_from_file (default_store, _("Report"),
+                       DATA_DIR "/images/templates/report.png", path);
+       g_free (path);
+
+       // book
+       path = g_strdup_printf (DATA_DIR "/templates/%s",
+                       _("book-en.tex"));
+       add_template_from_file (default_store, _("Book"),
+                       DATA_DIR "/images/templates/book.png", path);
+       g_free (path);
+
+       // letter
+       path = g_strdup_printf (DATA_DIR "/templates/%s",
+                       _("letter-en.tex"));
+       add_template_from_file (default_store, _("Letter"),
+                       DATA_DIR "/images/templates/letter.png", path);
+       g_free (path);
+
+
+       /* personnal templates */
+       personnal_store = gtk_list_store_new (N_COLUMNS_TEMPLATE,
+                       GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+       nb_personnal_templates = 0;
+
+       gchar *rc_file = get_rc_file ();
+       if (! g_file_test (rc_file, G_FILE_TEST_EXISTS))
+       {
+               g_free (rc_file);
+               return;
+       }
+
+       gchar *rc_path = g_path_get_dirname (rc_file);
+
+       GKeyFile *key_file = g_key_file_new ();
+       GError *error = NULL;
+       g_key_file_load_from_file (key_file, rc_file, G_KEY_FILE_NONE, &error);
+       g_free (rc_file);
+
+       if (error != NULL)
+       {
+               print_warning ("load templates failed: %s", error->message);
+               g_error_free (error);
+               g_free (rc_path);
+               return;
+       }
+
+       gsize length;
+       gchar **names = g_key_file_get_string_list (key_file, PROGRAM_NAME,
+                       "names", &length, &error);
+       if (error != NULL)
+       {
+               print_warning ("load templates failed: %s", error->message);
+               g_error_free (error);
+               g_key_file_free (key_file);
+               g_free (rc_path);
+               return;
+       }
+
+       nb_personnal_templates = length;
+
+       for (gint i = 0 ; i < length ; i++)
+       {
+               gchar *file = g_strdup_printf ("%s/%d.tex", rc_path, i);
+
+               if (! g_file_test (file, G_FILE_TEST_EXISTS))
+                       continue;
+               
+               add_template_from_file (personnal_store, names[i],
+                               DATA_DIR "/images/templates/article.png", file);
+       }
+
+       g_strfreev (names);
+       g_key_file_free (key_file);
 }
 
 static void
-add_template_from_string (GtkListStore *store, gchar *name, gchar *icon,
-               gchar *contents)
+add_template_from_string (GtkListStore *store, const gchar *name,
+               const gchar *icon, const gchar *contents)
 {
        if (contents == NULL)
                return;
@@ -149,14 +320,12 @@ add_template_from_string (GtkListStore *store, gchar *name, gchar *icon,
 }
 
 static void
-add_template_from_file (GtkListStore *store, gchar *name, gchar *icon,
-               gchar *filename)
+add_template_from_file (GtkListStore *store, const gchar *name,
+               const gchar *icon, const gchar *path)
 {
        gchar *contents = NULL;
        GError *error = NULL;
-       gchar *path = g_strdup_printf (DATA_DIR "/templates/%s", filename);
        g_file_get_contents (path, &contents, NULL, &error);
-       g_free (path);
 
        if (error != NULL)
        {
@@ -172,3 +341,106 @@ add_template_from_file (GtkListStore *store, gchar *name, gchar *icon,
        g_free (text_utf8);
        g_free (contents);
 }
+
+static GtkWidget *
+create_icon_view (GtkListStore *store)
+{
+       GtkWidget *icon_view = gtk_icon_view_new_with_model (
+                       GTK_TREE_MODEL (store));
+       gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view),
+                       GTK_SELECTION_SINGLE);
+       gtk_icon_view_set_text_column (GTK_ICON_VIEW (icon_view),
+                       COLUMN_TEMPLATE_NAME);
+       gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view),
+                       COLUMN_TEMPLATE_PIXBUF);
+
+       return icon_view;
+}
+
+static void
+cb_icon_view_selection_changed (GtkIconView *icon_view,
+               gpointer other_icon_view)
+{
+       // only one item of the two icon views can be selected at once
+       
+       // we unselect all the items of the other icon view only if the current icon
+       // view have an item selected, because when we unselect all the items the
+       // "selection-changed" signal is emitted for the other icon view, so for the
+       // other icon view this function is also called but no item is selected so
+       // nothing is done and the item selected by the user keeps selected
+
+       GList *selected_items = gtk_icon_view_get_selected_items (icon_view);
+
+       if (g_list_length (selected_items) > 0)
+               gtk_icon_view_unselect_all ((GtkIconView *) other_icon_view);
+
+       // free the GList
+       g_list_foreach (selected_items, (GFunc) gtk_tree_path_free, NULL);
+       g_list_free (selected_items);
+}
+
+static gchar *
+get_rc_file (void)
+{
+       // rc_file must be freed
+       gchar *rc_file = g_build_filename (g_get_user_data_dir (), "latexila",
+                       "templatesrc", NULL);
+       return rc_file;
+}
+
+static void
+add_personnal_template (const gchar *name, const gchar *contents)
+{
+       nb_personnal_templates++;
+
+       gchar **names = g_malloc (nb_personnal_templates * sizeof (gchar *));
+       gchar **names_i = names;
+       
+       GtkTreeIter iter;
+       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (personnal_store), &iter);
+       do
+       {
+               gtk_tree_model_get (GTK_TREE_MODEL (personnal_store), &iter,
+                               COLUMN_TEMPLATE_NAME, names_i, -1);
+               names_i++;
+       } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (personnal_store), &iter));
+
+       GKeyFile *key_file = g_key_file_new ();
+       g_key_file_set_string_list (key_file, PROGRAM_NAME, "names",
+                       (const gchar * const *) names,
+                       nb_personnal_templates);
+
+       /* save the rc file */
+       gchar *rc_file = get_rc_file ();
+       gchar *rc_path = g_path_get_dirname (rc_file);
+       g_mkdir_with_parents(rc_path, S_IRWXU);
+       gchar *key_file_data = g_key_file_to_data (key_file, NULL, NULL);
+
+       GError *error = NULL;
+       g_file_set_contents (rc_file, key_file_data, -1, &error);
+
+       g_free (rc_file);
+       g_free (key_file_data);
+       g_key_file_free (key_file);
+
+       if (error != NULL)
+       {
+               print_warning ("impossible to save templates: %s", error->message);
+               g_error_free (error);
+               g_free (rc_path);
+               return;
+       }
+
+       gchar *file = g_strdup_printf ("%s/%d.tex", rc_path,
+                       nb_personnal_templates - 1);
+       g_file_set_contents (file, contents, -1, &error);
+
+       if (error != NULL)
+       {
+               print_warning ("impossible to save templates: %s", error->message);
+               g_error_free (error);
+       }
+
+       g_free (rc_path);
+       g_free (file);
+}
diff --git a/src/templates.h b/src/templates.h
index 59a7027..9033218 100644
--- a/src/templates.h
+++ b/src/templates.h
@@ -21,6 +21,7 @@
 #define TEMPLATES_H
 
 void cb_new (void);
+void cb_create_template (void);
 void init_templates (void);
 
 enum templates
diff --git a/src/ui.c b/src/ui.c
index cb29d6f..dc3400b 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -80,6 +80,8 @@ static GtkActionEntry entries[] = {
                N_("Save the current file"), G_CALLBACK (cb_save)},
        {"FileSaveAs", GTK_STOCK_SAVE_AS, N_("Save as..."), "<Shift><Control>S",
                N_("Save the current file with a different name"), G_CALLBACK (cb_save_as)},
+       {"FileCreateTemplate", NULL, N_("Create Template From Document..."), NULL,
+               N_("Create a new template from the current document"), G_CALLBACK (cb_create_template)},
        {"FileClose", GTK_STOCK_CLOSE, N_("Close"), "<Control>W",
                N_("Close the current file"), G_CALLBACK (cb_close)},
        {"FileQuit", GTK_STOCK_QUIT, N_("Quit"), "<Control>Q",
diff --git a/src/ui.xml b/src/ui.xml
index c6db81e..8ad2ff4 100644
--- a/src/ui.xml
+++ b/src/ui.xml
@@ -32,6 +32,8 @@ In the code, GtkUIManager is used to construct them.
       <menuitem action="FileSave" />
       <menuitem action="FileSaveAs" />
       <separator />
+      <menuitem action="FileCreateTemplate" />
+      <separator />
       <menuitem action="FileClose" />
       <menuitem action="FileQuit" />
     </menu>


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