SF.net SVN: geany: [1811] trunk

eht16 at users.sourceforge.net eht16 at xxxxx
Sun Aug 19 17:40:19 UTC 2007


Revision: 1811
          http://geany.svn.sourceforge.net/geany/?rev=1811&view=rev
Author:   eht16
Date:     2007-08-19 10:40:19 -0700 (Sun, 19 Aug 2007)

Log Message:
-----------
New plugin: Export as HTML and LaTeX.
Add some functions to the plugin API needed by the Export plugin.

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/plugins/Makefile.am
    trunk/plugins/makefile.win32
    trunk/po/POTFILES.in
    trunk/src/plugindata.h
    trunk/src/plugins.c

Added Paths:
-----------
    trunk/plugins/export.c

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2007-08-17 14:50:55 UTC (rev 1810)
+++ trunk/ChangeLog	2007-08-19 17:40:19 UTC (rev 1811)
@@ -1,3 +1,11 @@
+2007-08-19  Enrico Tröger  <enrico(dot)troeger(at)uvena(dot)de>
+
+ * plugins/export.c, plugins/Makefile.am, plugins/makefile.win32,
+   po/POTFILES.in, src/plugins.c, src/plugindata.h:
+   New plugin: Export as HTML and LaTeX.
+   Add some functions to the plugin API needed by the Export plugin.
+
+
 2007-08-17  Nick Treleaven  <nick(dot)treleaven(at)btinternet(dot)com>
 
  * src/plugins.c:

Modified: trunk/plugins/Makefile.am
===================================================================
--- trunk/plugins/Makefile.am	2007-08-17 14:50:55 UTC (rev 1810)
+++ trunk/plugins/Makefile.am	2007-08-19 17:40:19 UTC (rev 1811)
@@ -14,6 +14,7 @@
 demoplugin_la_LDFLAGS    = -module -avoid-version
 classbuilder_la_LDFLAGS  = -module -avoid-version
 htmlchars_la_LDFLAGS     = -module -avoid-version
+export_la_LDFLAGS        = -module -avoid-version
 
 if PLUGINS
 
@@ -21,7 +22,8 @@
 plugin_LTLIBRARIES = \
 	demoplugin.la \
 	classbuilder.la \
-	htmlchars.la
+	htmlchars.la \
+	export.la
 
 # Plugins not to be installed
 #noinst_LTLIBRARIES = \
@@ -30,10 +32,12 @@
 demoplugin_la_SOURCES    = demoplugin.c
 classbuilder_la_SOURCES  = classbuilder.c
 htmlchars_la_SOURCES     = htmlchars.c
+export_la_SOURCES        = export.c
 
 demoplugin_la_LIBADD    = $(GTK_LIBS)
 classbuilder_la_LIBADD  = $(GTK_LIBS)
 htmlchars_la_LIBADD     = $(GTK_LIBS)
+export_la_LIBADD        = $(GTK_LIBS)
 
 endif # PLUGINS
 

Added: trunk/plugins/export.c
===================================================================
--- trunk/plugins/export.c	                        (rev 0)
+++ trunk/plugins/export.c	2007-08-19 17:40:19 UTC (rev 1811)
@@ -0,0 +1,663 @@
+/*
+ *      export.c - this file is part of Geany, a fast and lightweight IDE
+ *
+ *      Copyright 2007 Enrico Tröger <enrico.troeger at uvena.de>
+ *      Copyright 2007 Nick Treleaven <nick.treleaven at btinternet.com>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *
+ * $Id: demoplugin.c 1749 2007-07-27 10:37:22Z ntrel $
+ */
+
+/* Export plugin. */
+
+#include "geany.h"
+#include "support.h"
+#include "plugindata.h"
+#include "editor.h"
+#include "document.h"
+#include <ctype.h>
+
+
+PluginFields	*plugin_fields;
+GeanyData		*geany_data;
+
+VERSION_CHECK(10)
+PLUGIN_INFO(_("Export"), _("Exports the current file into different formats."))
+
+#define doc_array	geany_data->doc_array
+#define scintilla	geany_data->sci
+#define utils		geany_data->utils
+#define support		geany_data->support
+#define dialogs		geany_data->dialogs
+#define msgwin		geany_data->msgwindow
+
+#define ROTATE_RGB(color) \
+	(((color) & 0xFF0000) >> 16) + ((color) & 0x00FF00) + (((color) & 0x0000FF) << 16)
+#define TEMPLATE_HTML "\
+<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\
+  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
+<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n\
+\n\
+<head>\n\
+	<title>{export_filename}</title>\n\
+	<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />\n\
+	<meta name=\"generator\" content=\"Geany " VERSION "\" />\n\
+	<style type=\"text/css\">\n\
+{export_styles}\n\
+	</style>\n\
+</head>\n\
+\n\
+<body>\n\
+<p>\n\
+{export_content}\n\
+</p>\n\
+</body>\n\
+</html>\n"
+
+#define TEMPLATE_LATEX "\
+\\documentclass[a4paper]{article}\n\
+\\usepackage[a4paper,margin=2cm]{geometry}\n\
+\\usepackage[utf8x]{inputenc}\n\
+\\usepackage[T1]{fontenc}\n\
+\\usepackage{color}\n\
+{export_styles}\n\
+\\begin{document}\
+\n\
+\\noindent\n\
+\\ttfamily\n\
+\\setlength{\\fboxrule}{0pt}\n\
+\\setlength{\\fboxsep}{0pt}\n\
+{export_content}\
+\\end{document}\n"
+
+
+enum
+{
+	FORE = 0,
+	BACK,
+	BOLD,
+	ITALIC,
+	USED,
+	MAX_TYPES
+};
+
+typedef void (*ExportFunc) (gint idx, const gchar *filename, gboolean use_zoom);
+typedef struct
+{
+	gint idx;
+	gboolean have_zoom_level_checkbox;
+	ExportFunc export_func;
+} ExportInfo;
+
+static void on_file_save_dialog_response(GtkDialog *dialog, gint response, gpointer user_data);
+static void write_html_file(gint idx, const gchar *filename, gboolean use_zoom);
+static void write_latex_file(gint idx, const gchar *filename, gboolean use_zoom);
+
+
+/* converts a RGB colour into a LaTeX compatible representation, taken from SciTE */
+static gchar* get_tex_rgb(gint rgb_colour)
+{
+	//texcolor[rgb]{0,0.5,0}{....}
+	gdouble rf = (rgb_colour % 256) / 256.0;
+	gdouble gf = ((rgb_colour & - 16711936) / 256) / 256.0;
+	gdouble bf = ((rgb_colour & 0xff0000) / 65536) / 256.0;
+	gint r = (gint) (rf * 10 + 0.5);
+	gint g = (gint) (gf * 10 + 0.5);
+	gint b = (gint) (bf * 10 + 0.5);
+
+	return g_strdup_printf("%d.%d, %d.%d, %d.%d", r / 10, r % 10, g / 10, g % 10, b / 10, b % 10);
+}
+
+
+// convert a style number (0..127) into a string representation (aa, ab, .., ba, bb, .., zy, zz)
+static gchar *get_tex_style(gint style)
+{
+	static gchar buf[4];
+	int i = 0;
+
+	do
+	{
+		buf[i] = (style % 26) + 'a';
+		style /= 26;
+		i++;
+	} while (style > 0);
+	buf[i] = '\0';
+
+	return buf;
+}
+
+
+static void create_file_save_as_dialog(const gchar *extension, ExportFunc func,
+									   gboolean show_zoom_level_checkbox)
+{
+	gint idx;
+	GtkWidget *dialog;
+	GtkTooltips *tooltips;
+	ExportInfo *exi;
+
+	if (extension == NULL)
+		return;
+
+	idx = geany_data->document->get_cur_idx();
+	tooltips = GTK_TOOLTIPS(support->lookup_widget(geany_data->app->window, "tooltips"));
+
+	exi = g_new(ExportInfo, 1);
+	exi->idx = idx;
+	exi->export_func = func;
+	exi->have_zoom_level_checkbox = FALSE;
+
+	dialog = gtk_file_chooser_dialog_new(_("Export File"), GTK_WINDOW(geany_data->app->window),
+				GTK_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
+	gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+	gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
+	gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), TRUE);
+	gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
+	gtk_widget_set_name(dialog, "GeanyExportDialog");
+
+	gtk_dialog_add_buttons(GTK_DIALOG(dialog),
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
+	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
+
+	if (show_zoom_level_checkbox)
+	{
+		GtkWidget *vbox, *check_zoom_level;
+
+		vbox = gtk_vbox_new(FALSE, 0);
+		check_zoom_level = gtk_check_button_new_with_mnemonic(_("_Use current zoom level"));
+		gtk_tooltips_set_tip(tooltips, check_zoom_level,
+			_("Renders the font size of the document together with the current zoom level."), NULL);
+		gtk_box_pack_start(GTK_BOX(vbox), check_zoom_level, FALSE, FALSE, 0);
+		gtk_widget_show_all(vbox);
+		gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), vbox);
+
+		g_object_set_data_full(G_OBJECT(dialog), "check_zoom_level",
+					gtk_widget_ref(check_zoom_level), (GDestroyNotify) gtk_widget_unref);
+
+		exi->have_zoom_level_checkbox = TRUE;
+	}
+
+	g_signal_connect((gpointer) dialog, "delete_event",
+		G_CALLBACK(gtk_widget_hide_on_delete), NULL);
+	g_signal_connect((gpointer) dialog, "response",
+		G_CALLBACK(on_file_save_dialog_response), exi);
+
+	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(geany_data->app->window));
+
+	// if the current document has a filename we use it as the default.
+	gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(dialog));
+	if (doc_list[idx].file_name != NULL)
+	{
+		gchar *base_name = g_path_get_basename(doc_list[idx].file_name);
+		gchar *short_name = utils->remove_ext_from_filename(base_name);
+		gchar *file_name = g_strconcat(short_name, extension, NULL);
+		gchar *locale_filename = utils->get_locale_from_utf8(doc_list[idx].file_name);
+		gchar *locale_dirname = g_path_get_dirname(locale_filename);
+		// set the current name to base_name.html which probably doesn't exist yet so
+		// gtk_file_chooser_set_filename() can't be used and we need
+		// gtk_file_chooser_set_current_folder() additionally
+		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), locale_dirname);
+		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), file_name);
+		g_free(locale_filename);
+		g_free(short_name);
+		g_free(file_name);
+		g_free(base_name);
+	}
+	else
+	{
+		gchar *fname = g_strconcat(GEANY_STRING_UNTITLED, extension, NULL);
+
+		gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(dialog));
+		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), fname);
+
+		// use default startup directory(if set) if no files are open
+		if (geany_data->app->default_open_path != NULL &&
+			*(geany_data->app->default_open_path) != '\0')
+		{
+			if (g_path_is_absolute(geany_data->app->default_open_path))
+			{
+				gchar *def_path = utils->get_locale_from_utf8(geany_data->app->default_open_path);
+				gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), def_path);
+				g_free(def_path);
+			}
+		}
+		g_free(fname);
+	}
+	gtk_dialog_run(GTK_DIALOG(dialog));
+}
+
+
+static void on_menu_create_latex_activate(gint idx, const gchar *filename, gboolean use_zoom)
+{
+	create_file_save_as_dialog(".tex", write_latex_file, FALSE);
+}
+
+
+static void on_menu_create_html_activate(gint idx, const gchar *filename, gboolean use_zoom)
+{
+	create_file_save_as_dialog(".html", write_html_file, TRUE);
+}
+
+
+static void write_data(const gchar *filename, const gchar *data)
+{
+	gint error_nr = utils->write_file(filename, data);
+	gchar *utf8_filename = utils->get_utf8_from_locale(filename);
+
+	if (error_nr == 0)
+		msgwin->status_add(_("Document successfully exported as '%s'."), utf8_filename);
+	else
+		msgwin->status_add(_("File '%s' could not be written (%s)."),
+			utf8_filename, g_strerror(error_nr));
+
+	g_free(utf8_filename);
+}
+
+
+static void on_file_save_dialog_response(GtkDialog *dialog, gint response, gpointer user_data)
+{
+	ExportInfo *exi = user_data;
+
+	if (response == GTK_RESPONSE_ACCEPT && exi != NULL)
+	{
+		gchar *new_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+		gchar *utf8_filename;
+		gboolean use_zoom_level = FALSE;
+
+		if (exi->have_zoom_level_checkbox)
+		{
+			use_zoom_level = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+				support->lookup_widget(GTK_WIDGET(dialog), "check_zoom_level")));
+		}
+
+		utf8_filename = utils->get_utf8_from_locale(new_filename);
+
+		// check if file exists and ask whether to overwrite or not
+		if (g_file_test(new_filename, G_FILE_TEST_EXISTS))
+		{
+			if (dialogs->show_question(
+				_("The file '%s' already exists. Do you want to overwrite it?"),
+				utf8_filename) == FALSE)
+				return;
+		}
+
+		exi->export_func(exi->idx, new_filename, use_zoom_level);
+
+		g_free(utf8_filename);
+		g_free(new_filename);
+	}
+	g_free(exi);
+	gtk_widget_destroy(GTK_WIDGET(dialog));
+}
+
+
+static void write_latex_file(gint idx, const gchar *filename, gboolean use_zoom)
+{
+	gint i, style = -1, old_style = 0, column = 0;
+	gchar c, c_next, *tmp;
+	// 0 - fore, 1 - back, 2 - bold, 3 - italic, 4 - font size, 5 - used(0/1)
+	gint styles[STYLE_MAX + 1][MAX_TYPES];
+	gchar *latex;
+	gboolean block_open = FALSE;
+	GString *body;
+	GString *cmds;
+
+	// first read all styles from Scintilla
+	for (i = 0; i <= STYLE_MAX; i++)
+	{
+		styles[i][FORE] = scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETFORE, i, 0);
+		styles[i][BACK] = scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETBACK, i, 0);
+		styles[i][BOLD] = scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETBOLD, i, 0);
+		styles[i][ITALIC] = scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETITALIC, i, 0);
+		styles[i][USED] = 0;
+	}
+
+	// read the document and write the LaTeX code
+	body = g_string_new("");
+	for (i = 0; i < scintilla->get_length(doc_list[idx].sci); i++)
+	{
+		style = scintilla->get_style_at(doc_list[idx].sci, i);
+		c = scintilla->get_char_at(doc_list[idx].sci, i);
+		c_next = scintilla->get_char_at(doc_list[idx].sci, i + 1);
+
+		if (style != old_style || ! block_open)
+		{
+			old_style = style;
+			styles[style][USED] = 1;
+			if (block_open)
+			{
+				g_string_append(body, "}\n");
+				block_open = FALSE;
+			}
+			g_string_append_printf(body, "\\style%s{", get_tex_style(style));
+
+			block_open = TRUE;
+		}
+		// escape the current character if necessary else just add it
+		switch (c)
+		{
+			case '\r':
+			case '\n':
+			{
+				if (c == '\r' && c_next == '\n')
+					continue; // when using CR/LF skip CR and add the line break with LF
+
+				if (block_open)
+				{
+					g_string_append(body, "}");
+					block_open = FALSE;
+				}
+				g_string_append(body, " \\\\\n");
+				column = -1;
+				break;
+			}
+			case '\t':
+			{
+				gint tab_stop = geany_data->editor_prefs->tab_width -
+					(column % geany_data->editor_prefs->tab_width);
+
+				column += tab_stop - 1; // -1 because we add 1 at the end of the loop
+				g_string_append_printf(body, "\\hspace*{%dem}", tab_stop);
+				break;
+			}
+			case ' ':
+			{
+				if (c_next == ' ')
+					g_string_append(body, "{\\hspace*{1em}}");
+				else
+					g_string_append_c(body, ' ');
+				break;
+			}
+			case '{':
+			case '}':
+			case '_':
+			case '&':
+			case '$':
+			case '#':
+			case '%':
+			{
+				g_string_append_printf(body, "\\%c", c);
+				break;
+			}
+			case '\\':
+			{
+				g_string_append(body, "\\textbackslash");
+				break;
+			}
+			case '~':
+			{
+				g_string_append(body, "\\symbol{126}");
+				break;
+			}
+			case '^':
+			{
+				g_string_append(body, "\\symbol{92}");
+				break;
+			}
+			case '-':  // mask "--"
+			{
+				if (c_next == '-')
+					g_string_append(body, "-\\@-");
+				break;
+			}
+			default: g_string_append_c(body, c);
+		}
+		column++;
+	}
+	if (block_open)
+	{
+		g_string_append(body, "}\n");
+		block_open = FALSE;
+	}
+
+	// force writing of style 0 (used at least for line breaks)
+	styles[0][USED] = 1;
+
+	// write used styles in the header
+	cmds = g_string_new("");
+	for (i = 0; i <= STYLE_MAX; i++)
+	{
+		if (styles[i][USED])
+		{
+			g_string_append_printf(cmds,
+				"\\newcommand{\\style%s}[1]{\\noindent{", get_tex_style(i));
+			if (styles[i][BOLD])
+				g_string_append(cmds, "\\textbf{");
+			if (styles[i][ITALIC])
+				g_string_append(cmds, "\\textit{");
+
+			tmp = get_tex_rgb(styles[i][FORE]);
+			g_string_append_printf(cmds, "\\textcolor[rgb]{%s}{", tmp);
+			g_free(tmp);
+			tmp = get_tex_rgb(styles[i][BACK]);
+			g_string_append_printf(cmds, "\\fcolorbox[rgb]{0, 0, 0}{%s}{", tmp);
+			g_string_append(cmds, "#1}}");
+			g_free(tmp);
+
+			if (styles[i][BOLD])
+				g_string_append_c(cmds, '}');
+			if (styles[i][ITALIC])
+				g_string_append_c(cmds, '}');
+			g_string_append(cmds, "}}\n");
+		}
+	}
+
+	// write all
+	latex = g_strdup(TEMPLATE_LATEX);
+	latex = utils->str_replace(latex, "{export_content}", body->str);
+	latex = utils->str_replace(latex, "{export_styles}", cmds->str);
+	// {export_filename} is currently unused but maybe someone want to use it
+	if (doc_list[idx].file_name == NULL)
+		latex = utils->str_replace(latex, "{export_filename}", GEANY_STRING_UNTITLED);
+	else
+		latex = utils->str_replace(latex, "{export_filename}", doc_list[idx].file_name);
+
+	write_data(filename, latex);
+
+	g_string_free(body, TRUE);
+	g_string_free(cmds, TRUE);
+	g_free(latex);
+}
+
+
+static void write_html_file(gint idx, const gchar *filename, gboolean use_zoom)
+{
+	gint i, style = -1, old_style = 0, column = 0;
+	gchar c, c_next;
+	// 0 - fore, 1 - back, 2 - bold, 3 - italic, 4 - font size, 5 - used(0/1)
+	gint styles[STYLE_MAX + 1][MAX_TYPES];
+	gboolean span_open = FALSE;
+	gchar *html;
+	const gchar *font_name;
+	gint font_size;
+	PangoFontDescription *font_desc;
+	GString *body;
+	GString *css;
+
+	// first read all styles from Scintilla
+	for (i = 0; i <= STYLE_MAX; i++)
+	{
+		styles[i][FORE] = ROTATE_RGB(scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETFORE, i, 0));
+		styles[i][BACK] = ROTATE_RGB(scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETBACK, i, 0));
+		styles[i][BOLD] = scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETBOLD, i, 0);
+		styles[i][ITALIC] = scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETITALIC, i, 0);
+		styles[i][USED] = 0;
+	}
+
+	// read Geany's font and font size
+	font_desc = pango_font_description_from_string(geany_data->app->editor_font);
+	font_name = pango_font_description_get_family(font_desc);
+	//font_size = pango_font_description_get_size(font_desc) / PANGO_SCALE;
+	// take the zoom level also into account
+	font_size = scintilla->send_message(doc_list[idx].sci, SCI_STYLEGETSIZE, 0, 0);
+	if (use_zoom)
+		font_size += scintilla->get_zoom(doc_list[idx].sci);
+
+	// read the document and write the HTML body
+	body = g_string_new("");
+	for (i = 0; i < scintilla->get_length(doc_list[idx].sci); i++)
+	{
+		style = scintilla->get_style_at(doc_list[idx].sci, i);
+		c = scintilla->get_char_at(doc_list[idx].sci, i);
+		// scintilla->get_char_at() takes care of index boundaries and return 0 if i is too high
+		c_next = scintilla->get_char_at(doc_list[idx].sci, i + 1);
+
+		if ((style != old_style || ! span_open) && ! isspace(c))
+		{
+			old_style = style;
+			styles[style][USED] = 1;
+			if (span_open)
+			{
+				g_string_append(body, "</span>");
+			}
+			g_string_append_printf(body, "<span class=\"style_%d\">", style);
+
+			span_open = TRUE;
+		}
+		// escape the current character if necessary else just add it
+		switch (c)
+		{
+			case '\r':
+			case '\n':
+			{
+				if (c == '\r' && c_next == '\n')
+					continue; // when using CR/LF skip CR and add the line break with LF
+
+				if (span_open)
+				{
+					g_string_append(body, "</span>");
+					span_open = FALSE;
+				}
+				g_string_append(body, "<br />\n");
+				column = -1;
+				break;
+			}
+			case '\t':
+			{
+				gint j;
+				gint tab_stop = geany_data->editor_prefs->tab_width -
+					(column % geany_data->editor_prefs->tab_width);
+
+				column += tab_stop - 1; // -1 because we add 1 at the end of the loop
+				for (j = 0; j < tab_stop; j++)
+				{
+					g_string_append(body, " ");
+				}
+				break;
+			}
+			case ' ':
+			{
+				g_string_append(body, " ");
+				break;
+			}
+			case '<':
+			{
+				g_string_append(body, "<");
+				break;
+			}
+			case '>':
+			{
+				g_string_append(body, ">");
+				break;
+			}
+			case '&':
+			{
+				g_string_append(body, "&");
+				break;
+			}
+			default: g_string_append_c(body, c);
+		}
+		column++;
+	}
+	if (span_open)
+	{
+		g_string_append(body, "</span>");
+		span_open = FALSE;
+	}
+
+	// write used styles in the header
+	css = g_string_new("");
+	g_string_append_printf(css,
+	"\tbody\n\t{\n\t\tfont-family: %s, monospace;\n\t\tfont-size: %dpt;\n\t}\n",
+				font_name, font_size);
+
+	for (i = 0; i <= STYLE_MAX; i++)
+	{
+		if (styles[i][USED])
+		{
+			g_string_append_printf(css,
+	"\t.style_%d\n\t{\n\t\tcolor: #%06x;\n\t\tbackground-color: #%06x;\n%s%s\t}\n",
+				i, styles[i][FORE], styles[i][BACK],
+				(styles[i][BOLD]) ? "\t\tfont-weight: bold;\n" : "",
+				(styles[i][ITALIC]) ? "\t\tfont-style: italic;\n" : "");
+		}
+	}
+
+	// write all
+	html = g_strdup(TEMPLATE_HTML);
+	html = utils->str_replace(html, "{export_content}", body->str);
+	html = utils->str_replace(html, "{export_styles}", css->str);
+	if (doc_list[idx].file_name == NULL)
+		html = utils->str_replace(html, "{export_filename}", GEANY_STRING_UNTITLED);
+	else
+		html = utils->str_replace(html, "{export_filename}", doc_list[idx].file_name);
+
+	write_data(filename, html);
+
+	pango_font_description_free(font_desc);
+	g_string_free(body, TRUE);
+	g_string_free(css, TRUE);
+	g_free(html);
+}
+
+
+void init(GeanyData *data)
+{
+	GtkWidget *menu_export;
+	GtkWidget *menu_export_menu;
+	GtkWidget *menu_create_html;
+	GtkWidget *menu_create_latex;
+
+	menu_export = gtk_image_menu_item_new_with_mnemonic(_("_Export"));
+	gtk_container_add(GTK_CONTAINER(data->tools_menu), menu_export);
+
+	menu_export_menu = gtk_menu_new ();
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_export), menu_export_menu);
+
+	// HTML
+	menu_create_html = gtk_menu_item_new_with_mnemonic(_("As HTML"));
+	gtk_container_add(GTK_CONTAINER (menu_export_menu), menu_create_html);
+
+	g_signal_connect((gpointer) menu_create_html, "activate",
+		G_CALLBACK(on_menu_create_html_activate), NULL);
+
+	// LaTeX
+	menu_create_latex = gtk_menu_item_new_with_mnemonic(_("As LaTeX"));
+	gtk_container_add(GTK_CONTAINER (menu_export_menu), menu_create_latex);
+
+	g_signal_connect((gpointer) menu_create_latex, "activate",
+		G_CALLBACK(on_menu_create_latex_activate), NULL);
+
+	gtk_widget_show_all(menu_export);
+
+	plugin_fields->menu_item = menu_export;
+}
+
+
+void cleanup()
+{
+	gtk_widget_destroy(plugin_fields->menu_item);
+}

Modified: trunk/plugins/makefile.win32
===================================================================
--- trunk/plugins/makefile.win32	2007-08-17 14:50:55 UTC (rev 1810)
+++ trunk/plugins/makefile.win32	2007-08-19 17:40:19 UTC (rev 1811)
@@ -43,7 +43,8 @@
 plugins: \
 		htmlchars.dll \
 		demoplugin.dll \
-		classbuilder.dll
+		classbuilder.dll \
+		export.dll
 
 clean:
 	-$(RM) deps.mak *.o *.dll

Modified: trunk/po/POTFILES.in
===================================================================
--- trunk/po/POTFILES.in	2007-08-17 14:50:55 UTC (rev 1810)
+++ trunk/po/POTFILES.in	2007-08-19 17:40:19 UTC (rev 1811)
@@ -36,3 +36,4 @@
 src/win32.c
 plugins/classbuilder.c
 plugins/htmlchars.c
+plugins/export.c

Modified: trunk/src/plugindata.h
===================================================================
--- trunk/src/plugindata.h	2007-08-17 14:50:55 UTC (rev 1810)
+++ trunk/src/plugindata.h	2007-08-19 17:40:19 UTC (rev 1811)
@@ -68,7 +68,7 @@
 
 /* The API version should be incremented whenever any plugin data types below are
  * modified. */
-static const gint api_version = 11;
+static const gint api_version = 12;
 
 /* The ABI version should be incremented whenever existing fields in the plugin
  * data types below have to be changed or reordered. It should stay the same if fields
@@ -144,6 +144,8 @@
 	struct UtilsFuncs		*utils;
 	struct UIUtilsFuncs		*ui;
 	struct SupportFuncs		*support;
+	struct DialogFuncs		*dialogs;
+	struct MsgWinFuncs		*msgwindow;
 }
 GeanyData;
 
@@ -205,6 +207,9 @@
 	void	(*ensure_line_is_visible) (struct _ScintillaObject* sci, gint line);
 	void	(*scroll_caret) (struct _ScintillaObject* sci);
 	gint	(*find_bracematch) (struct _ScintillaObject* sci, gint pos);
+	gint	(*get_style_at) (struct _ScintillaObject *sci, gint position);
+	gchar	(*get_char_at) (struct _ScintillaObject *sci, gint pos);
+	gint	(*get_zoom) (struct _ScintillaObject * sci);
 }
 ScintillaFuncs;
 
@@ -219,6 +224,10 @@
 	gboolean	(*str_equal) (const gchar *a, const gchar *b);
 	gchar*		(*str_replace) (gchar *haystack, const gchar *needle, const gchar *replacement);
 	GSList*		(*get_file_list) (const gchar *path, guint *length, GError **error);
+	gint		(*write_file) (const gchar *filename, const gchar *text);
+	gchar*		(*get_locale_from_utf8) (const gchar *utf8_text);
+	gchar*		(*get_utf8_from_locale) (const gchar *locale_text);
+	gchar*		(*remove_ext_from_filename) (const gchar *filename);
 }
 UtilsFuncs;
 
@@ -229,6 +238,13 @@
 }
 UIUtilsFuncs;
 
+typedef struct DialogFuncs
+{
+	gboolean	(*show_question) (const gchar *text, ...);
+	void		(*show_msgbox) (gint type, const gchar *text, ...);
+}
+DialogFuncs;
+
 typedef struct SupportFuncs
 {
 	GtkWidget*	(*lookup_widget) (GtkWidget *widget, const gchar *widget_name);
@@ -236,6 +252,13 @@
 SupportFuncs;
 
 
+typedef struct MsgWinFuncs
+{
+	void		(*status_add) (const gchar *format, ...);
+}
+MsgWinFuncs;
+
+
 typedef struct GeanyCallback
 {
 	gchar		*signal_name;

Modified: trunk/src/plugins.c
===================================================================
--- trunk/src/plugins.c	2007-08-17 14:50:55 UTC (rev 1810)
+++ trunk/src/plugins.c	2007-08-19 17:40:19 UTC (rev 1811)
@@ -43,6 +43,8 @@
 #include "sciwrappers.h"
 #include "ui_utils.h"
 #include "editor.h"
+#include "dialogs.h"
+#include "msgwindow.h"
 #include "geanyobject.h"
 
 #ifdef G_OS_WIN32
@@ -109,7 +111,10 @@
 	&sci_get_line_is_visible,
 	&sci_ensure_line_is_visible,
 	&sci_scroll_caret,
-	&sci_find_bracematch
+	&sci_find_bracematch,
+	&sci_get_style_at,
+	&sci_get_char_at,
+	&sci_get_zoom
 };
 
 static TemplateFuncs template_funcs = {
@@ -119,7 +124,11 @@
 static UtilsFuncs utils_funcs = {
 	&utils_str_equal,
 	&utils_str_replace,
-	&utils_get_file_list
+	&utils_get_file_list,
+	&utils_write_file,
+	&utils_get_locale_from_utf8,
+	&utils_get_utf8_from_locale,
+	&utils_remove_ext_from_filename
 };
 
 static UIUtilsFuncs uiutils_funcs = {
@@ -127,11 +136,20 @@
 	&ui_frame_new_with_alignment
 };
 
+static DialogFuncs dialog_funcs = {
+	&dialogs_show_question,
+	&dialogs_show_msgbox
+};
+
 static SupportFuncs support_funcs = {
 	&lookup_widget
 };
 
+static MsgWinFuncs msgwin_funcs = {
+	&msgwin_status_add
+};
 
+
 static GeanyData geany_data = {
 	NULL,
 	NULL,
@@ -144,7 +162,9 @@
 	&template_funcs,
 	&utils_funcs,
 	&uiutils_funcs,
-	&support_funcs
+	&support_funcs,
+	&dialog_funcs,
+	&msgwin_funcs
 };
 
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Commits mailing list