Commit d7127846 authored by Sven Neumann's avatar Sven Neumann Committed by Sven Neumann

app/gui/Makefile.am new files. A simple XML parser for the gimp-tips.xml

2002-02-25  Sven Neumann  <sven@gimp.org>

	* app/gui/Makefile.am
	* app/gui/tips-parser.[ch]: new files. A simple XML parser for the
	gimp-tips.xml file.

	* app/gui/tips-dialog.c: Removed old gimp_tips.txt parsing code and
	switched to use gimp-tips.xml with the new parser. This needs some
	more work ...
parent 0492a030
2002-02-25 Sven Neumann <sven@gimp.org>
* app/gui/Makefile.am
* app/gui/tips-parser.[ch]: new files. A simple XML parser for the
gimp-tips.xml file.
* app/gui/tips-dialog.c: Removed old gimp_tips.txt parsing code and
switched to use gimp-tips.xml with the new parser. This needs some
more work ...
2002-02-24 Sven Neumann <sven@gimp.org>
* HACKING
......
......@@ -31,31 +31,29 @@
#include "core/core-types.h"
#include "tips-dialog.h"
#include "tips-parser.h"
#include "gimprc.h"
#include "libgimp/gimpintl.h"
#define TIPS_DIR_NAME "tips"
static void tips_dialog_destroy (GtkWidget *widget,
gpointer data);
static void tips_show_previous (GtkWidget *widget,
gpointer data);
static void tips_show_next (GtkWidget *widget,
gpointer data);
static void tips_toggle_update (GtkWidget *widget,
gpointer data);
static void tips_dialog_destroy (GtkWidget *widget,
gpointer data);
static void tips_show_previous (GtkWidget *widget,
gpointer data);
static void tips_show_next (GtkWidget *widget,
gpointer data);
static void tips_toggle_update (GtkWidget *widget,
gpointer data);
static void read_tips_file (gchar *filename);
static GtkWidget *tips_dialog = NULL;
static GtkWidget *tips_label = NULL;
static gchar **tips_text = NULL;
static gint tips_count = 0;
static gint old_show_tips = 0;
static GtkWidget *tips_dialog = NULL;
static GtkWidget *tips_label = NULL;
static GList *tips = NULL;
static gint tips_count = 0;
static gint old_show_tips = 0;
GtkWidget *
......@@ -67,18 +65,28 @@ tips_dialog_create (void)
GtkWidget *bbox;
GtkWidget *button;
GdkPixbuf *wilber;
GimpTip *tip;
gchar *filename;
if (tips_count == 0)
if (!tips)
{
gchar *temp;
temp = g_build_filename (gimp_data_directory (), TIPS_DIR_NAME,
_("gimp_tips.txt"), NULL);
read_tips_file (temp);
g_free (temp);
GError *error = NULL;
gchar *filename;
filename = g_build_filename (gimp_data_directory (), "tips",
"gimp-tips.xml", NULL);
tips = gimp_tips_from_file (filename, NULL, &error);
g_free (filename);
if (error)
{
tips = g_list_prepend (NULL, gimp_tip_new (NULL, error->message));
g_error_free (error);
}
}
tips_count = g_list_length (tips);
if (gimprc.last_tip >= tips_count || gimprc.last_tip < 0)
gimprc.last_tip = 0;
......@@ -113,7 +121,9 @@ tips_dialog_create (void)
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
tips_label = gtk_label_new (tips_text[gimprc.last_tip]);
tip = g_list_nth_data (tips, gimprc.last_tip);
tips_label = gtk_label_new (tip->thetip);
gtk_label_set_justify (GTK_LABEL (tips_label), GTK_JUSTIFY_LEFT);
gtk_misc_set_alignment (GTK_MISC (tips_label), 0.5, 0.5);
gtk_box_pack_start (GTK_BOX (hbox), tips_label, TRUE, TRUE, 3);
......@@ -212,6 +222,9 @@ tips_dialog_destroy (GtkWidget *widget,
tips_dialog = NULL;
gimp_tips_free (tips);
tips = NULL;
/* the last-shown-tip is now saved in sessionrc */
if (gimprc.show_tips != old_show_tips)
......@@ -229,24 +242,32 @@ static void
tips_show_previous (GtkWidget *widget,
gpointer data)
{
GimpTip *tip;
gimprc.last_tip--;
if (gimprc.last_tip < 0)
gimprc.last_tip = tips_count - 1;
gtk_label_set_text (GTK_LABEL (tips_label), tips_text[gimprc.last_tip]);
tip = g_list_nth_data (tips, gimprc.last_tip);
gtk_label_set_text (GTK_LABEL (tips_label), tip->thetip);
}
static void
tips_show_next (GtkWidget *widget,
gpointer data)
{
GimpTip *tip;
gimprc.last_tip++;
if (gimprc.last_tip >= tips_count)
gimprc.last_tip = 0;
gtk_label_set_text (GTK_LABEL (tips_label), tips_text[gimprc.last_tip]);
tip = g_list_nth_data (tips, gimprc.last_tip);
gtk_label_set_text (GTK_LABEL (tips_label), tip->thetip);
}
static void
......@@ -262,63 +283,3 @@ tips_toggle_update (GtkWidget *widget,
else
*toggle_val = FALSE;
}
static void
store_tip (gchar *str)
{
tips_count++;
tips_text = g_realloc (tips_text, sizeof (gchar *) * tips_count);
tips_text[tips_count - 1] = str;
}
static void
read_tips_file (gchar *filename)
{
FILE *fp;
gchar *tip = NULL;
gchar *str = NULL;
fp = fopen (filename, "rt");
if (!fp)
{
store_tip (_("Your GIMP tips file appears to be missing!\n"
"There should be a file called gimp_tips.txt in\n"
"the tips subfolder of the GIMP data folder.\n"
"Please check your installation."));
return;
}
str = g_new (char, 1024);
while (!feof (fp))
{
if (!fgets (str, 1024, fp))
continue;
if (str[0] == '#' || str[0] == '\n')
{
if (tip != NULL)
{
tip[strlen (tip) - 1] = '\000';
store_tip (tip);
tip = NULL;
}
}
else
{
if (tip == NULL)
{
tip = g_malloc (strlen (str) + 1);
strcpy (tip, str);
}
else
{
tip = g_realloc (tip, strlen (tip) + strlen (str) + 1);
strcat (tip, str);
}
}
}
if (tip != NULL)
store_tip (tip);
g_free (str);
fclose (fp);
}
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* tips-parser.c -- Parse the gimp-tips.xml file.
* Copyright (C) 2002 Sven Neumann <sven@gimp.org>
*
* 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 "config.h"
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "tips-parser.h"
#include "libgimp/gimpintl.h"
typedef enum
{
TIPS_START,
TIPS_IN_TIPS,
TIPS_IN_TIP,
TIPS_IN_WELCOME,
TIPS_IN_THETIP,
TIPS_UNKNOWN
} TipsParserState;
typedef enum
{
TIPS_LANG_NONE,
TIPS_LANG_MATCH,
TIPS_LANG_MISMATCH,
} TipsParserLangState;
typedef struct _TipsParser TipsParser;
struct _TipsParser
{
TipsParserState state;
TipsParserState last_known_state;
const gchar *lang;
TipsParserLangState lang_state;
gint unknown_depth;
GString *value;
GimpTip *current_tip;
GList *tips;
};
static void tips_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error);
static void tips_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void tips_parser_characters (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error);
static void tips_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data);
static void tips_parser_start_unknown (TipsParser *parser);
static void tips_parser_end_unknown (TipsParser *parser);
static void tips_parser_parse_lang (TipsParser *parser,
const gchar **names,
const gchar **values);
static void tips_parser_set_by_lang (TipsParser *parser,
gchar **dest);
static const GMarkupParser markup_parser =
{
tips_parser_start_element,
tips_parser_end_element,
tips_parser_characters,
NULL, /* passthrough */
tips_parser_error
};
GimpTip *
gimp_tip_new (const gchar *welcome,
const gchar *thetip)
{
GimpTip *tip = g_new (GimpTip, 1);
tip->welcome = welcome ? g_strdup (welcome) : NULL;
tip->thetip = thetip ? g_strdup (thetip) : NULL;
return tip;
}
void
gimp_tip_free (GimpTip *tip)
{
if (!tip)
return;
g_free (tip->welcome);
g_free (tip->thetip);
g_free (tip);
}
GList *
gimp_tips_from_file (const gchar *filename,
const gchar *language,
GError **error)
{
GMarkupParseContext *context;
TipsParser *parser;
FILE *fp;
gsize bytes;
gchar buf[4096];
GList *tips = NULL;
GError *parse_error = NULL;
fp = fopen (filename, "r");
if (!fp)
{
g_set_error (error,
0, /* error domain */
0, /* error code */
_("Your GIMP tips file appears to be missing!\n"
"There should be a file called gimp-tips.xml in "
"the tips subfolder of the GIMP data folder.\n"
"Please check your installation."));
return NULL;
}
parser = g_new0 (TipsParser, 1);
parser->lang = language;
parser->value = g_string_new (NULL);
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
while ((bytes = fread (buf, sizeof (gchar), sizeof (buf), fp)) > 0 &&
g_markup_parse_context_parse (context, buf, bytes, &parse_error))
;
/* FIXME */
if (parse_error)
g_clear_error (&parse_error);
g_markup_parse_context_end_parse (context, &parse_error);
/* FIXME */
if (parse_error)
g_clear_error (&parse_error);
fclose (fp);
g_markup_parse_context_free (context);
if (parser->state != TIPS_START)
{
g_set_error (error,
0, /* error domain */
0, /* error code */
_("Your GIMP tips file could not be parsed correctly!\n"
"Please check your installation."));
}
tips = g_list_reverse (parser->tips);
gimp_tip_free (parser->current_tip);
g_string_free (parser->value, TRUE);
g_free (parser);
return tips;
}
void
gimp_tips_free (GList *tips)
{
GList *list;
for (list = tips; list; list = list->next)
gimp_tip_free (list->data);
g_list_free (tips);
}
static void
tips_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
TipsParser *parser = (TipsParser *) user_data;
switch (parser->state)
{
case TIPS_START:
if (strcmp (element_name, "gimp-tips") == 0)
parser->state = TIPS_IN_TIPS;
else
tips_parser_start_unknown (parser);
break;
case TIPS_IN_TIPS:
if (strcmp (element_name, "tip") == 0)
{
parser->state = TIPS_IN_TIP;
parser->current_tip = g_new0 (GimpTip, 1);
}
else
tips_parser_start_unknown (parser);
break;
case TIPS_IN_TIP:
if (strcmp (element_name, "welcome") == 0)
{
parser->state = TIPS_IN_WELCOME;
tips_parser_parse_lang (parser, attribute_names, attribute_values);
}
else if (strcmp (element_name, "thetip") == 0)
{
parser->state = TIPS_IN_THETIP;
tips_parser_parse_lang (parser, attribute_names, attribute_values);
}
else
tips_parser_start_unknown (parser);
break;
case TIPS_IN_WELCOME:
case TIPS_IN_THETIP:
case TIPS_UNKNOWN:
tips_parser_start_unknown (parser);
break;
}
}
static void
tips_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
{
TipsParser *parser = (TipsParser *) user_data;
switch (parser->state)
{
case TIPS_START:
g_warning ("tips_parser: This shouldn't happen.\n");
break;
case TIPS_IN_TIPS:
parser->state = TIPS_START;
break;
case TIPS_IN_TIP:
parser->state = TIPS_IN_TIPS;
parser->tips = g_list_prepend (parser->tips, parser->current_tip);
parser->current_tip = NULL;
break;
case TIPS_IN_WELCOME:
tips_parser_set_by_lang (parser, &parser->current_tip->welcome);
parser->state = TIPS_IN_TIP;
break;
case TIPS_IN_THETIP:
tips_parser_set_by_lang (parser, &parser->current_tip->thetip);
parser->state = TIPS_IN_TIP;
break;
break;
case TIPS_UNKNOWN:
tips_parser_end_unknown (parser);
}
g_string_assign (parser->value, "");
}
static void
tips_parser_characters (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
{
TipsParser *parser = (TipsParser *) user_data;
switch (parser->state)
{
case TIPS_IN_WELCOME:
case TIPS_IN_THETIP:
if (parser->lang_state != TIPS_LANG_MISMATCH)
g_string_append (parser->value, text);
break;
default:
break;
}
}
static void
tips_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data)
{
g_warning (error->message);
}
static void
tips_parser_start_unknown (TipsParser *parser)
{
if (parser->unknown_depth == 0)
parser->last_known_state = parser->state;
parser->state = TIPS_UNKNOWN;
parser->unknown_depth++;
}
static void
tips_parser_end_unknown (TipsParser *parser)
{
g_assert (parser->unknown_depth > 0 && parser->state == TIPS_UNKNOWN);
parser->unknown_depth--;
if (parser->unknown_depth == 0)
parser->state = parser->last_known_state;
}
static void
tips_parser_parse_lang (TipsParser *parser,
const gchar **names,
const gchar **values)
{
parser->lang_state = TIPS_LANG_NONE;
while (*names && *values)
{
if (strcmp (*names, "xml:lang") == 0 && **values)
{
parser->lang_state = ((parser->lang &&
strcmp (*values, parser->lang) == 0) ?
TIPS_LANG_MATCH : TIPS_LANG_MISMATCH);
}
names++;
values++;
}
}
static void
tips_parser_set_by_lang (TipsParser *parser,
gchar **dest)
{
switch (parser->lang_state)
{
case TIPS_LANG_NONE:
if (!parser->lang)
{
g_free (*dest);
*dest = g_strdup (parser->value->str);
}
else if (*dest == NULL)
{
*dest = g_strdup (parser->value->str);
}
break;
case TIPS_LANG_MATCH:
g_free (*dest);
*dest = g_strdup (parser->value->str);
break;
case TIPS_LANG_MISMATCH:
break;
}
}
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* tips-parser.h -- Parse the gimp-tips.xml file.
* Copyright (C) 2002 Sven Neumann <sven@gimp.org>
*
* 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.
*/
#ifndef __TIPS_PARSER_H__
#define __TIPS_PARSER_H__
typedef struct _GimpTip GimpTip;
struct _GimpTip
{
gchar *welcome;
gchar *thetip;
};
GimpTip * gimp_tip_new (const gchar *welcome,
const gchar *thetip);
void gimp_tip_free (GimpTip *tip);
GList * gimp_tips_from_file (const gchar *filename,
const gchar *language,
GError **error);
void gimp_tips_free (GList *tips);
#endif /* __TIPS_PARSER_H__ */
......@@ -115,6 +115,8 @@ libappgui_a_SOURCES = @STRIP_BEGIN@ \
test-commands.h \
tips-dialog.c \
tips-dialog.h \
tips-parser.c \
tips-parser.h \
tool-options-dialog.c \
tool-options-dialog.h \
toolbox.c \
......
......@@ -31,31 +31,29 @@
#include "core/core-types.h"
#include "tips-dialog.h"
#include "tips-parser.h"
#include "gimprc.h"
#include "libgimp/gimpintl.h"
#define TIPS_DIR_NAME "tips"
static void tips_dialog_destroy (GtkWidget *widget,
gpointer data);
static void tips_show_previous (GtkWidget *widget,
gpointer data);
static void tips_show_next (GtkWidget *widget,
gpointer data);
static void tips_toggle_update (GtkWidget *widget,
gpointer data);
static void tips_dialog_destroy (GtkWidget *widget,
gpointer data);
static void tips_show_previous (GtkWidget *widget,
gpointer data);
static void tips_show_next (GtkWidget *widget,
gpointer data);
static void tips_toggle_update (GtkWidget *widget,
gpointer data);
static void read_tips_file (gchar *filename);
static GtkWidget *tips_dialog = NULL;
static GtkWidget *tips_label = NULL;
static gchar **tips_text = NULL;
static gint tips_count = 0;
static gint old_show_tips = 0;
static GtkWidget *tips_dialog = NULL;
static GtkWidget *tips_label = NULL;
static GList *tips = NULL;
static gint tips_count = 0;
static gint old_show_tips = 0;
GtkWidget *
......@@ -67,18 +65,28 @@ tips_dialog_create (void)
GtkWidget *bbox;
GtkWidget *button;
GdkPixbuf *wilber;
GimpTip *tip;
gchar *filename;
if (tips_count == 0)
if (!tips)
{
gchar *temp;
temp = g_build_filename (gimp_data_directory (), TIPS_DIR_NAME,
_("gimp_tips.txt"), NULL);
read_tips_file (temp);
g_free (temp);
GError *error = NULL;
gchar *filename;