diff options
Diffstat (limited to 'tools/glade/glade/save.c')
-rw-r--r-- | tools/glade/glade/save.c | 1039 |
1 files changed, 1039 insertions, 0 deletions
diff --git a/tools/glade/glade/save.c b/tools/glade/glade/save.c new file mode 100644 index 00000000..ea9f8eee --- /dev/null +++ b/tools/glade/glade/save.c @@ -0,0 +1,1039 @@ +/* Gtk+ User Interface Builder + * Copyright (C) 1998 Damon Chaplin + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "gladeconfig.h" + +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifndef _WIN32 +#include <unistd.h> +#endif +#include <time.h> +#include <errno.h> +#include <locale.h> + +#include "glade_project.h" +#include "gbwidget.h" +#include "save.h" +#include "utils.h" + +/* This is set if we are saving a session. A bit of a hack. */ +char *GladeSessionFile = NULL; + + +/* The stuff to output at the start of XML files. */ +static gchar *GLADE_XML_BEGIN = + "<?xml version=\"1.0\" standalone=\"no\"?> <!--*- mode: xml -*-->\n" + "<!DOCTYPE glade-interface SYSTEM \"http://glade.gnome.org/glade-2.0.dtd\">\n\n"; + +static gchar *GLADE_PROJECT_XML_BEGIN = + "<?xml version=\"1.0\" standalone=\"no\"?> <!--*- mode: xml -*-->\n" + "<!DOCTYPE glade-project SYSTEM \"http://glade.gnome.org/glade-project-2.0.dtd\">\n\n"; + + +/* An internal struct to pass data to the save_component() and + save_named_style_callback() callbacks. */ +typedef struct _GladeSaveCallbackData GladeSaveCallbackData; +struct _GladeSaveCallbackData +{ + GbWidgetGetArgData *data; + FILE *fp; +}; + +/* An internal struct to pass data to the save_requires_tags_cb(). */ +typedef struct _GladeSaveRequiresData GladeSaveRequiresData; +struct _GladeSaveRequiresData +{ + /* We only support these 4 libs so we just have flags for each of them. */ + gboolean require_gnome; + gboolean require_gnome_canvas; + gboolean require_gnomedb; + gboolean require_bonobo; +}; + + +static GladeError* save_project_file_internal (GladeProject *project); +static GladeError* save_xml_file_internal (GladeProject *project); + +static void save_requires_tags (FILE *fp, GladeProject *project); +static void save_component (GtkWidget * item, + GladeSaveCallbackData * save_data); + +#ifdef GLADE_STYLE_SUPPORT +static void save_named_style_callback (const gchar * name, + GbStyle * gbstyle, + GladeSaveCallbackData * save_data); +static void save_named_style (const gchar * name, + GbStyle * gbstyle, + GbWidgetGetArgData * data, + FILE *fp); +#endif + +static void save_buffer_flush (GbWidgetGetArgData * data, + FILE *fp); + +static void save_translatable_strings (GbWidgetGetArgData * data); + + +/* We need this to make sure that numbers are output in a portable syntax, + instead of using the current locale. This code is from glibc info docs. */ +GladeError* +save_project_file (GladeProject *project) +{ + gchar *old_locale, *saved_locale; + GladeError *error; + + old_locale = setlocale (LC_NUMERIC, NULL); + saved_locale = g_strdup (old_locale); + setlocale (LC_NUMERIC, "C"); + + error = save_project_file_internal (project); + + if (!error) + error = save_xml_file_internal (project); + + setlocale (LC_NUMERIC, saved_locale); + g_free (saved_locale); + return error; +} + + +/* Backup the file, to <filename>.bak, if it exists. */ +static GladeError* +backup_file (const gchar *filename) +{ + gchar *backup_filename; + GladeError *error = NULL; + int status; + + if (!glade_util_file_exists (filename)) + return NULL; + + backup_filename = g_strdup_printf ("%s.bak", filename); +#if defined (__EMX__) || defined (_WIN32) + /* for OS/2 rename dosn't work if the dest. file exist ! remove it! */ + status = remove (backup_filename); +#endif + status = rename (filename, backup_filename); + + if (status == -1) + { + error = glade_error_new_system (_("Couldn't rename file:\n %s\nto:\n %s\n"), filename, backup_filename); + } + + g_free (backup_filename); + return error; +} + + +/* The main function to output the XML. It creates and initializes the + GbWidgetGetArgData, opens the file, outputs the project options, the + named styles, and then each component (window/dialog) in the interface. */ +static GladeError* +save_project_file_internal (GladeProject *project) +{ + gchar *xml_filename, *filename; + GladeError *error; + FILE *fp; + + if (GladeSessionFile) + xml_filename = GladeSessionFile; + else + xml_filename = glade_project_get_xml_filename (project); + + filename = g_strdup_printf ("%sp", xml_filename); + + if (!GladeSessionFile) + { + error = backup_file (filename); + if (error) + goto out; + } + + fp = glade_util_fopen (filename, "w"); + if (fp == NULL) + { + error = glade_error_new_system (_("Couldn't create file:\n %s\n"), + filename); + goto out; + } + + fprintf (fp, "%s", GLADE_PROJECT_XML_BEGIN); + + error = glade_project_save_options (project, fp); + + fclose (fp); + + out: + + g_free (filename); + + return error; +} + + +/* The main function to output the XML. It creates and initializes the + GbWidgetGetArgData, opens the file, outputs the project options, the + named styles, and then each component (window/dialog) in the interface. */ +static GladeError* +save_xml_file_internal (GladeProject *project) +{ + GbWidgetGetArgData data = { 0 }; + GladeSaveCallbackData save_data; + gchar *filename; + FILE *fp; + + MSG ("Saving project"); + + data.project = project; + data.action = GB_SAVING; + data.copying_to_clipboard = FALSE; + data.error = NULL; + + if (GladeSessionFile) + filename = GladeSessionFile; + else + filename = glade_project_get_xml_filename (project); + + if (!GladeSessionFile) + { + data.error = backup_file (filename); + if (data.error) + return data.error; + } + + fp = glade_util_fopen (filename, "w"); + if (fp == NULL) + return glade_error_new_system (_("Couldn't create file:\n %s\n"), + filename); + + /* Initialize the output buffer. */ + data.buffer = g_string_sized_new (1024); + data.indent = 0; + + /* See if we need the translatable strings file output. */ + data.save_translatable_strings = FALSE; + data.translatable_strings = NULL; + if (!GladeSessionFile) + { + data.save_translatable_strings = glade_project_get_output_translatable_strings (data.project); + if (data.save_translatable_strings) + data.translatable_strings = g_string_sized_new (1024); + } + + /* Output the XML version info and our root element '<glade-interface>'. */ + fprintf (fp, "%s", GLADE_XML_BEGIN); + fprintf (fp, "<glade-interface>\n"); + + /* Output the requires tags. */ + save_requires_tags (fp, project); + + /* Set up the struct to pass data to the callbacks. */ + save_data.data = &data; + save_data.fp = fp; + +#ifdef GLADE_STYLE_SUPPORT + if (!data.error) + { + /* Save default gbstyle first. */ + MSG ("Saving styles"); + save_named_style (gb_widget_default_gb_style->name, + gb_widget_default_gb_style, &data, fp); + /* Now save all the other named styles. */ + g_hash_table_foreach (gb_style_hash, (GHFunc) save_named_style_callback, + &save_data); + } +#endif + + if (!data.error) + { + MSG ("Saving components"); + glade_project_foreach_component (data.project, + (GtkCallback) save_component, + &save_data); + } + + /* Finish the root element. */ + if (!data.error) + { + fprintf (fp, "\n</glade-interface>\n"); + } + + /* Save the translatable strings file, if needed. */ + if (!data.error) + { + if (data.save_translatable_strings) + save_translatable_strings (&data); + } + + /* Free any memory used while saving. */ + g_string_free (data.buffer, TRUE); + if (data.translatable_strings) + g_string_free (data.translatable_strings, TRUE); + + fclose (fp); + + return data.error; +} + + +static void +save_requires_tags_cb (GtkWidget *widget, + GladeSaveRequiresData * requires_data) +{ + const char *type_name; + + type_name = g_type_name (G_OBJECT_TYPE (widget)); + + /* We assume that any classes starting with GnomeDB require the GnomeDB + support etc. Note that GNOME apps will probably require Bonobo for the + BonoboDock widgets used in GnomeApp. */ + if (!strncmp (type_name, "GnomeDb", 7)) + requires_data->require_gnomedb = TRUE; + else if (!strncmp (type_name, "GnomeCanvas", 11)) + requires_data->require_gnome_canvas = TRUE; + else if (!strncmp (type_name, "Gnome", 5)) + requires_data->require_gnome = TRUE; + else if (!strncmp (type_name, "Bonobo", 6)) + requires_data->require_bonobo = TRUE; + + /* Recursively check all children. */ + gb_widget_children_foreach (widget, (GtkCallback) save_requires_tags_cb, + requires_data); +} + +static void +save_requires_tags (FILE *fp, GladeProject *project) +{ + GladeSaveRequiresData requires_data; + + /* Assume we don't need any of them until we find one of their widgets. */ + requires_data.require_gnome = FALSE; + requires_data.require_gnome_canvas = FALSE; + requires_data.require_gnomedb = FALSE; + requires_data.require_bonobo = FALSE; + + glade_project_foreach_component (project, + (GtkCallback) save_requires_tags_cb, + &requires_data); + + /* Require "gnome", as provided in libgnomeui/glade/glade-gnome.c. + We now require GNOME for all GNOME projects, since even if they don't + contain GNOME widgets they may use stock GNOME items. */ + if (requires_data.require_gnome + || glade_project_get_gnome_support (project)) + fprintf (fp, "<requires lib=\"gnome\"/>\n"); + /* Require "canvas", as provided in libgnomecanvas/glade/glade-canvas.c. */ + if (requires_data.require_gnome_canvas) + fprintf (fp, "<requires lib=\"canvas\"/>\n"); + /* Require "gnomedb", as provided in libgnomedb/glade/glade-gnomedb.c. */ + if (requires_data.require_gnomedb) + fprintf (fp, "<requires lib=\"gnomedb\"/>\n"); + /* Require "bonobo", as provided in libbonoboui/glade/glade-bonobo.c. */ + if (requires_data.require_bonobo) + fprintf (fp, "<requires lib=\"bonobo\"/>\n"); +} + +/* This is called when iterating over the components in a project, to output + each component. It simply calls gb_widget_save() to recursively save the + XML for the component into the buffer, and it then flushes the buffer to + the output file. */ +static void +save_component (GtkWidget * component, + GladeSaveCallbackData * save_data) +{ + /* If an error has occurred, we return. */ + if (save_data->data->error) + return; + + gb_widget_save (component, save_data->data); + save_buffer_flush (save_data->data, save_data->fp); +} + + +/* This is called when iterating over the GHashTable of named styles. + If the style isn't the default style it is output here. The default + style is output first, since for all other styles we only output the + differences from the default. */ +#ifdef GLADE_STYLE_SUPPORT +static void +save_named_style_callback (const gchar * name, + GbStyle * gbstyle, + GladeSaveCallbackData * save_data) +{ + /* If an error has occurred, or this is the default GbStyle, we return. */ + if (save_data->data->error || gbstyle == gb_widget_default_gb_style) + { + return; + } + + save_named_style (name, gbstyle, save_data->data, save_data->fp); +} + + +/* Outputs a named style. */ +static void +save_named_style (const gchar * name, + GbStyle * gbstyle, + GbWidgetGetArgData * data, + FILE *fp) +{ + gboolean save_all = FALSE; + + MSG1 ("Saving style: %s", name); + /* If this is the default style, only save it if it is different to the + GTK default style, and if it is make sure we save everything. */ + if (gbstyle == gb_widget_default_gb_style) + { + if (gbstyle->style == gtk_widget_get_default_style ()) + return; + else + save_all = TRUE; + } + gb_widget_save_style (gbstyle, data, save_all); + save_buffer_flush (data, fp); +} +#endif + + +/* Adds a start tag, e.g. "<widget>", to the output buffer. */ +void +save_start_tag (GbWidgetGetArgData * data, const gchar * tag_name) +{ + save_buffer_add_indent (data->buffer, data->indent); + g_string_append_c (data->buffer, '<'); + g_string_append (data->buffer, tag_name); + g_string_append (data->buffer, ">\n"); + data->indent++; +} + + +/* Adds an end tag, e.g. "</widget>", to the output buffer. */ +void +save_end_tag (GbWidgetGetArgData * data, const gchar * tag_name) +{ + data->indent--; + save_buffer_add_indent (data->buffer, data->indent); + g_string_append (data->buffer, "</"); + g_string_append (data->buffer, tag_name); + g_string_append (data->buffer, ">\n"); +} + + +/* Adds a <widget> start tag to the output buffer, with the given class_name + and id, if they are not NULL. */ +void +save_widget_start_tag (GbWidgetGetArgData * data, const gchar * class_name, + const gchar *id) +{ + save_buffer_add_indent (data->buffer, data->indent); + g_string_append (data->buffer, "<widget"); + + if (class_name) + { + g_string_append (data->buffer, " class=\""); + save_buffer_add_string (data->buffer, class_name); + g_string_append_c (data->buffer, '"'); + } + + if (id) + { + g_string_append (data->buffer, " id=\""); + save_buffer_add_string (data->buffer, id); + g_string_append_c (data->buffer, '"'); + } + + g_string_append (data->buffer, ">\n"); + data->indent++; +} + + +/* Adds a <child> start tag to the output buffer, with the given child_name + if it is not NULL. */ +void +save_child_start_tag (GbWidgetGetArgData * data, const gchar * child_name) +{ + save_buffer_add_indent (data->buffer, data->indent); + g_string_append (data->buffer, "<child"); + + if (child_name) + { + g_string_append (data->buffer, " internal-child=\""); + save_buffer_add_string (data->buffer, child_name); + g_string_append_c (data->buffer, '"'); + } + + g_string_append (data->buffer, ">\n"); + data->indent++; +} + + +/* Adds a <placeholder/> tag to the output buffer. */ +void +save_placeholder (GbWidgetGetArgData * data) +{ + save_buffer_add_indent (data->buffer, data->indent); + g_string_append (data->buffer, "<placeholder/>\n"); +} + + +/* Starts a new line in the output buffer (without indenting). */ +void +save_newline (GbWidgetGetArgData * data) +{ + g_string_append_c (data->buffer, '\n'); +} + + +/* These functions are called to save different types of widget properties. + They all convert the property to a string representation and call + save_string() to output it. The tag_name is usually the long name of the + property, e.g. "GtkLabel::justify", so we cut out the first part and output + <justify>...</justify>. */ + +static void +save_string_internal (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value, + gboolean translatable, + const gchar *translator_comments, + gboolean has_context_prefix) +{ + gchar *tag_name_start; + + if (tag_value == NULL) + return; + + tag_name_start = glade_util_find_start_of_tag_name (tag_name); + save_buffer_add_indent (data->buffer, data->indent); + + g_string_append (data->buffer, "<property"); + + if (data->agent) + { + g_string_append (data->buffer, " agent=\""); + save_buffer_add_string (data->buffer, data->agent); + g_string_append_c (data->buffer, '"'); + } + + g_string_append (data->buffer, " name=\""); + save_buffer_add_string (data->buffer, tag_name_start); + g_string_append_c (data->buffer, '"'); + + if (translatable) + { + g_string_append (data->buffer, " translatable=\"yes\""); + + if (has_context_prefix) + g_string_append (data->buffer, " context=\"yes\""); + + if (translator_comments && *translator_comments) + { + g_string_append (data->buffer, " comments=\""); + save_buffer_add_string (data->buffer, translator_comments); + g_string_append_c (data->buffer, '"'); + } + } + + g_string_append_c (data->buffer, '>'); + save_buffer_add_string (data->buffer, tag_value); + g_string_append (data->buffer, "</property>\n"); +} + +void +save_string (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_string_internal (data, tag_name, tag_value, FALSE, NULL, FALSE); +} + + +void +save_translatable_string_internal (GbWidgetGetArgData * data, + const gchar * tag_name, + const gchar * tag_value) +{ + gboolean translatable, context; + gchar *comments; + + glade_util_get_translation_properties (data->widget, tag_name, &translatable, + &comments, &context); + save_string_internal (data, tag_name, tag_value, translatable, + comments, context); +} + + +void +save_translatable_string (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_translatable_string_internal (data, tag_name, tag_value); + if (data->save_translatable_strings) + save_add_translatable_string (data, tag_value); +} + + +void +save_text (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_string (data, tag_name, tag_value); +} + + +void +save_translatable_text (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_translatable_string (data, tag_name, tag_value); +} + + +/* This is like save_translatable_text() except it splits the text into lines + when adding to the translatable strings file. This is used for option menu + items and combo items. */ +void +save_translatable_text_in_lines (GbWidgetGetArgData * data, + const gchar * tag_name, + const gchar * tag_value) +{ + /* FIXME: This probably won't work if other apps just try to translate the + entire string. */ + save_translatable_string_internal (data, tag_name, tag_value); + + if (data->save_translatable_strings && tag_value) + { + gchar *items, *pos, *items_end; + + items = pos = g_strdup (tag_value); + items_end = &items[strlen (items)]; + + while (pos < items_end) + { + gchar *item_end = strchr (pos, '\n'); + if (item_end == NULL) + item_end = items_end; + *item_end = '\0'; + + save_add_translatable_string (data, pos); + + pos = item_end + 1; + } + + g_free (items); + } +} + + +void +save_int (GbWidgetGetArgData * data, const gchar * tag_name, + const gint tag_value) +{ + gchar buf[32]; + sprintf (buf, "%i", tag_value); + save_string (data, tag_name, buf); +} + + +void +save_float (GbWidgetGetArgData * data, const gchar * tag_name, + gfloat tag_value) +{ + gchar buf[32]; + sprintf (buf, "%.12g", tag_value); + save_string (data, tag_name, buf); +} + + +void +save_bool (GbWidgetGetArgData * data, const gchar * tag_name, gint tag_value) +{ + save_string (data, tag_name, tag_value ? "True" : "False"); +} + + +void +save_choice (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_string (data, tag_name, tag_value); +} + + +void +save_combo (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_string (data, tag_name, tag_value); +} + + +/* Colors are now saved as '#rrrrggggbbbb', where rgb are 0-65535. + We use gdk_color_parse() when loading, so color names can be used as well.*/ +void +save_color (GbWidgetGetArgData * data, const gchar * tag_name, + GdkColor * tag_value) +{ + gchar buf[32]; + + sprintf (buf, "#%04x%04x%04x", tag_value->red, tag_value->green, + tag_value->blue); + save_string (data, tag_name, buf); +} + + +void +save_bgpixmap (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_string (data, tag_name, tag_value); +} + + +void +save_dialog (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_string (data, tag_name, tag_value); +} + + +/* FIXME: I think this is broken. It should save it relative to the XML file.*/ +void +save_filename (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_string (data, tag_name, tag_value); +} + + +void +save_pixmap_filename (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + if (data->copying_to_clipboard) + { + /* When saving to the clipboard, we just save the full path. + This means it will still work if we paste into other projects. */ + save_string (data, tag_name, tag_value); + } + else + { + /* When saving the XML file, we save only the basename of the pixmap + files, since they should all be in the pixmaps directory. */ + gchar *pixmaps_dir, *filename; + + pixmaps_dir = glade_project_get_pixmaps_directory (data->project); + g_return_if_fail (pixmaps_dir != NULL); + g_return_if_fail (pixmaps_dir[0] != '\0'); + + if (tag_value == NULL || tag_value[0] == '\0') + { + filename = NULL; + } + else + { + filename = (gchar*) g_basename (tag_value); + } + + save_string (data, tag_name, filename); + } +} + + +void +save_font (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + save_string (data, tag_name, tag_value); +} + + +/* This saves a date in the RFC1123 format (an update of RFC822), + e.g. 'Sun, 06 Nov 1994 08:49:37 GMT'. */ +static void +format_date (char *buffer, + time_t tag_value) +{ + time_t time; + struct tm *t; + + time = tag_value; + t = gmtime (&time); + sprintf (buffer, "%s, %02d %s %04d %02d:%02d:%02d GMT", + GladeDayNames[t->tm_wday], t->tm_mday, GladeMonthNames[t->tm_mon], + t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec); +} + + +/* This saves a date in the RFC1123 format (an update of RFC822), + e.g. 'Sun, 06 Nov 1994 08:49:37 GMT'. */ +void +save_date (GbWidgetGetArgData * data, const gchar * tag_name, + time_t tag_value) +{ + gchar buffer[32]; + + format_date (buffer, tag_value); + save_string (data, tag_name, buffer); +} + + +void +save_icon (GbWidgetGetArgData * data, const gchar * tag_name, + const gchar * tag_value) +{ + /* If it is a stock icon we can save it as an oridnary string. + If it isn't, we need to save it as a pixmap filename, i.e. get rid of + the path and just save the basename. */ + if (glade_util_check_is_stock_id (tag_value)) + save_string (data, tag_name, tag_value); + else + save_pixmap_filename (data, tag_name, tag_value); +} + + +/* Adds a string to the output buffer, converting special characters to + entities, e.g. "<" is output as "<". */ +void +save_buffer_add_string (GString * buffer, const gchar * string) +{ + gchar ch; + + while ((ch = *string++)) + { + if (ch == '<') + g_string_append (buffer, "<"); + else if (ch == '>') + g_string_append (buffer, ">"); + else if (ch == '&') + g_string_append (buffer, "&"); + else if (ch == '"') + g_string_append (buffer, """); + else + g_string_append_c (buffer, ch); + } +} + + +/* Outputs the contents of the buffer to the file and resets the buffer. */ +static void +save_buffer_flush (GbWidgetGetArgData * data, + FILE *fp) +{ + gint bytes_written; + + bytes_written = fwrite (data->buffer->str, sizeof (gchar), data->buffer->len, + fp); + if (bytes_written != data->buffer->len) + { + MSG2 ("Bytes: %i Written: %i", data->buffer->len, bytes_written); + data->error = glade_error_new_system (_("Error writing XML file\n")); + } + + /* Reset the output buffer. */ + g_string_truncate (data->buffer, 0); + data->indent = 0; +} + + +/* Outputs tabs & spaces to indent the line according to the current + indentation level. Tabs are used to cut down on the file size a bit. */ +void +save_buffer_add_indent (GString *buffer, gint indent) +{ + gint i, ntabs, nspaces; + + ntabs = (indent * 2) / 8; + nspaces = (indent * 2) % 8; + + for (i = 0; i < ntabs; i++) + g_string_append_c (buffer, '\t'); + + for (i = 0; i < nspaces; i++) + g_string_append_c (buffer, ' '); +} + + +/* + * Translatable string functions. + */ + +/* This adds a translatable string to the buffer, wrapping it in the N_() + macro so xgettext can find it. */ +void +save_add_translatable_string (GbWidgetGetArgData * data, + const gchar * string) +{ + GString *buffer; + gchar escape_buffer[16]; + const gchar *p; + + /* If it is an empty string don't bother outputting it. */ + if (!string || string[0] == '\0') + return; + + buffer = data->translatable_strings; + g_string_append (buffer, "gchar *s = N_(\""); + + /* Step through each character of the given string, adding it to our GString + buffer, converting it so that it is valid in a literal C string. */ + for (p = string; *p; p++) + { + switch (*p) + { + case '\n': + g_string_append (buffer, "\\n\"\n \""); + break; + case '\r': + g_string_append (buffer, "\\r"); + break; + case '\t': + g_string_append (buffer, "\\t"); + break; + case '\\': + g_string_append (buffer, "\\\\"); + break; + case '"': + g_string_append (buffer, "\\\""); + break; + default: + if (isprint ((unsigned char) *p)) + { + g_string_append_c (buffer, *p); + } + else + { + sprintf (escape_buffer, "\\%02o", (guchar) *p); + g_string_append (buffer, escape_buffer); + } + break; + } + } + + g_string_append (buffer, "\");\n"); +} + + +/* This outputs the file containing all the translatable strings. */ +static void +save_translatable_strings (GbWidgetGetArgData * data) +{ + gchar *filename; + FILE *fp; + + filename = glade_project_get_translatable_strings_file (data->project); + + fp = glade_util_fopen (filename, "w"); + if (fp == NULL) + { + data->error = glade_error_new_system (_("Couldn't create file:\n %s\n"), + filename); + return; + } + + fprintf (fp, + _("/*\n" + " * Translatable strings file generated by Glade.\n" + " * Add this file to your project's POTFILES.in.\n" + " * DO NOT compile it as part of your application.\n" + " */\n" + "\n")); + + fprintf (fp, "%s", data->translatable_strings->str); + + fclose (fp); +} + + +void +save_signal (GbWidgetGetArgData *data, + gchar *signal_name, + gchar *handler, + gboolean after, + gchar *object, + time_t last_modification_time) +{ + /* Don't save signals without names or handlers. */ + if (!signal_name || !signal_name[0] || ! handler || !handler[0]) + return; + + save_buffer_add_indent (data->buffer, data->indent); + g_string_append (data->buffer, "<signal name=\""); + save_buffer_add_string (data->buffer, signal_name); + g_string_append (data->buffer, "\" handler=\""); + save_buffer_add_string (data->buffer, handler); + g_string_append (data->buffer, "\""); + + if (after) + g_string_append (data->buffer, " after=\"yes\""); + + if (object) + { + g_string_append (data->buffer, " object=\""); + save_buffer_add_string (data->buffer, object); + g_string_append (data->buffer, "\""); + } + + if (last_modification_time != 0) + { + gchar buffer[32]; + + format_date (buffer, last_modification_time); + + g_string_append (data->buffer, " last_modification_time=\""); + save_buffer_add_string (data->buffer, buffer); + g_string_append (data->buffer, "\""); + } + + g_string_append (data->buffer, "/>\n"); +} + + +void +save_accelerator (GbWidgetGetArgData *data, + guint8 modifiers, + gchar *key, + gchar *signal) +{ + gchar *modifiers_string; + + /* Don't save accelerators without signals or keys. */ + if (!key || !key[0] || !signal || !signal[0]) + return; + + save_buffer_add_indent (data->buffer, data->indent); + g_string_append (data->buffer, "<accelerator key=\""); + save_buffer_add_string (data->buffer, key); + g_string_append (data->buffer, "\""); + + modifiers_string = glade_util_create_modifiers_string (modifiers); + g_string_append (data->buffer, " modifiers=\""); + save_buffer_add_string (data->buffer, modifiers_string); + g_string_append (data->buffer, "\""); + + g_string_append (data->buffer, " signal=\""); + save_buffer_add_string (data->buffer, signal); + g_string_append (data->buffer, "\""); + + g_string_append (data->buffer, "/>\n"); +} + + |