[gnome-latex: 137/205] Possibility to create new templates
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-latex: 137/205] Possibility to create new templates
- Date: Fri, 14 Dec 2018 10:58:24 +0000 (UTC)
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]