Commit 55d14fd0 authored by Sven Neumann's avatar Sven Neumann Committed by Sven Neumann

Finished some work that Brix started on the help system. It's now possibly

2004-03-09  Sven Neumann  <sven@gimp.org>

	Finished some work that Brix started on the help system. It's
	now possibly to use an external web-browser for context help
	(bug #136081):

	* configure.in
	* plug-ins/Makefile.am
	* plug-ins/help/Makefile.am
	* plug-ins/help/domain.[ch]
	* plug-ins/help/help.c: new plug-in that does the help domain
	management. Most of this used to live in the helpbrowser plug-in.

	* plug-ins/helpbrowser/Makefile.am
	* plug-ins/helpbrowser/domain.[ch]: removed these two files here.

	* plug-ins/helpbrowser/helpbrowser.c: changed accordingly.

	* app/widgets/gimphelp.c: use the new help plug-in.
parent b4f3e1a8
2004-03-09 Sven Neumann <sven@gimp.org>
Finished some work that Brix started on the help system. It's
now possibly to use an external web-browser for context help
(bug #136081):
* configure.in
* plug-ins/Makefile.am
* plug-ins/help/Makefile.am
* plug-ins/help/domain.[ch]
* plug-ins/help/help.c: new plug-in that does the help domain
management. Most of this used to live in the helpbrowser plug-in.
* plug-ins/helpbrowser/Makefile.am
* plug-ins/helpbrowser/domain.[ch]: removed these two files here.
* plug-ins/helpbrowser/helpbrowser.c: changed accordingly.
* app/widgets/gimphelp.c: use the new help plug-in.
2004-03-08 Sven Neumann <sven@gimp.org>
* app/gui/convert-dialog.c (indexed_palette_select_palette): added
......@@ -2,7 +2,8 @@
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimphelp.c
* Copyright (C) 1999-2000 Michael Natterer <mitch@gimp.org>
* Copyright (C) 1999-2004 Michael Natterer <mitch@gimp.org>
* Henrik Brix Andersen <brix@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
......@@ -49,9 +50,8 @@
#include "gimp-intl.h"
#ifndef G_OS_WIN32
#define DEBUG_HELP
#endif
typedef struct _GimpIdleHelp GimpIdleHelp;
......@@ -66,15 +66,13 @@ struct _GimpIdleHelp
/* local function prototypes */
static gint gimp_idle_help (gpointer data);
static gboolean gimp_help_internal (Gimp *gimp,
const gchar *help_domain,
const gchar *help_locale,
const gchar *help_id);
static void gimp_help_web_browser (Gimp *gimp,
const gchar *help_domain,
const gchar *help_locale,
const gchar *help_id);
static gint gimp_idle_help (gpointer data);
static gboolean gimp_help_internal (Gimp *gimp);
static void gimp_help_call (Gimp *gimp,
const gchar *procedure,
const gchar *help_domain,
const gchar *help_locale,
const gchar *help_id);
/* public functions */
......@@ -88,9 +86,7 @@ gimp_help (Gimp *gimp,
if (GIMP_GUI_CONFIG (gimp->config)->use_help)
{
GimpIdleHelp *idle_help;
idle_help = g_new0 (GimpIdleHelp, 1);
GimpIdleHelp *idle_help = g_new0 (GimpIdleHelp, 1);
idle_help->gimp = gimp;
......@@ -112,38 +108,37 @@ gimp_help (Gimp *gimp,
static gboolean
gimp_idle_help (gpointer data)
{
GimpIdleHelp *idle_help = data;
GimpHelpBrowserType browser;
browser = GIMP_GUI_CONFIG (idle_help->gimp->config)->help_browser;
GimpIdleHelp *idle_help = data;
const gchar *procedure = NULL;
#ifdef DEBUG_HELP
g_print ("Help Domain: %s\n",
idle_help->help_domain ? idle_help->help_domain : "NULL");
g_print ("Help ID: %s\n\n",
idle_help->help_id ? idle_help->help_id : "NULL");
#endif /* DEBUG_HELP */
g_printerr ("Help Domain: %s\n",
idle_help->help_domain ? idle_help->help_domain : "NULL");
g_printerr ("Help ID: %s\n\n",
idle_help->help_id ? idle_help->help_id : "NULL");
#endif
switch (browser)
switch (GIMP_GUI_CONFIG (idle_help->gimp->config)->help_browser)
{
case GIMP_HELP_BROWSER_GIMP:
if (gimp_help_internal (idle_help->gimp,
idle_help->help_domain,
idle_help->help_locale,
idle_help->help_id))
break;
if (gimp_help_internal (idle_help->gimp))
{
procedure = "extension_gimp_help_browser_temp";
break;
}
case GIMP_HELP_BROWSER_WEB_BROWSER:
gimp_help_web_browser (idle_help->gimp,
idle_help->help_domain,
idle_help->help_locale,
idle_help->help_id);
break;
default:
/* FIXME: should check for procedure availability */
procedure = "plug_in_web_browser";
break;
}
gimp_help_call (idle_help->gimp,
procedure,
idle_help->help_domain,
idle_help->help_locale,
idle_help->help_id);
g_free (idle_help->help_domain);
g_free (idle_help->help_locale);
g_free (idle_help->help_id);
......@@ -168,10 +163,7 @@ gimp_help_internal_not_found_callback (GtkWidget *widget,
}
static gboolean
gimp_help_internal (Gimp *gimp,
const gchar *help_domain,
const gchar *help_locale,
const gchar *help_id)
gimp_help_internal (Gimp *gimp)
{
ProcRecord *proc_rec;
......@@ -187,10 +179,7 @@ gimp_help_internal (Gimp *gimp,
if (proc_rec == NULL)
{
Argument *args = NULL;
gint n_domains = 0;
gchar **help_domains = NULL;
gchar **help_uris = NULL;
Argument *args = NULL;
proc_rec = procedural_db_lookup (gimp, "extension_gimp_help_browser");
......@@ -217,21 +206,12 @@ gimp_help_internal (Gimp *gimp,
!= GIMP_HELP_BROWSER_WEB_BROWSER);
}
n_domains = plug_ins_help_domains (gimp, &help_domains, &help_uris);
args = g_new (Argument, 1);
args = g_new (Argument, 5);
args[0].arg_type = GIMP_PDB_INT32;
args[0].value.pdb_int = GIMP_RUN_INTERACTIVE;
args[1].arg_type = GIMP_PDB_INT32;
args[1].value.pdb_int = n_domains;
args[2].arg_type = GIMP_PDB_STRINGARRAY;
args[2].value.pdb_pointer = help_domains;
args[3].arg_type = GIMP_PDB_INT32;
args[3].value.pdb_int = n_domains;
args[4].arg_type = GIMP_PDB_STRINGARRAY;
args[4].value.pdb_pointer = help_uris;
plug_in_run (gimp, proc_rec, args, 5, FALSE, TRUE, -1);
args[0].arg_type = GIMP_PDB_INT32;
args[0].value.pdb_int = GIMP_RUN_INTERACTIVE;
plug_in_run (gimp, proc_rec, args, 1, FALSE, TRUE, -1);
procedural_db_destroy_args (args, 5);
}
......@@ -258,22 +238,6 @@ gimp_help_internal (Gimp *gimp,
return (GIMP_GUI_CONFIG (gimp->config)->help_browser
!= GIMP_HELP_BROWSER_WEB_BROWSER);
}
else
{
Argument *return_vals;
gint nreturn_vals;
return_vals =
procedural_db_run_proc (gimp,
"extension_gimp_help_browser_temp",
&nreturn_vals,
GIMP_PDB_STRING, help_domain,
GIMP_PDB_STRING, help_locale,
GIMP_PDB_STRING, help_id,
GIMP_PDB_END);
procedural_db_destroy_args (return_vals, nreturn_vals);
}
busy = FALSE;
......@@ -281,43 +245,80 @@ gimp_help_internal (Gimp *gimp,
}
static void
gimp_help_web_browser (Gimp *gimp,
const gchar *help_domain,
const gchar *help_locale,
const gchar *help_id)
gimp_help_call (Gimp *gimp,
const gchar *procedure,
const gchar *help_domain,
const gchar *help_locale,
const gchar *help_id)
{
Argument *return_vals;
gint nreturn_vals;
gchar *url;
ProcRecord *proc_rec;
if (! help_id)
help_id = GIMP_HELP_MAIN;
/* Check if a help parser is already running */
proc_rec = procedural_db_lookup (gimp, "extension_gimp_help_temp");
if (! help_domain)
if (proc_rec == NULL)
{
url = g_strconcat ("file:",
gimp_data_directory (), "/help/",
help_locale, "/",
help_id,
NULL);
Argument *args = NULL;
gint n_domains = 0;
gchar **help_domains = NULL;
gchar **help_uris = NULL;
proc_rec = procedural_db_lookup (gimp, "extension_gimp_help");
if (proc_rec == NULL)
{
/* FIXME: error msg */
return;
}
n_domains = plug_ins_help_domains (gimp, &help_domains, &help_uris);
args = g_new (Argument, 4);
args[0].arg_type = GIMP_PDB_INT32;
args[0].value.pdb_int = n_domains;
args[1].arg_type = GIMP_PDB_STRINGARRAY;
args[1].value.pdb_pointer = help_domains;
args[2].arg_type = GIMP_PDB_INT32;
args[2].value.pdb_int = n_domains;
args[3].arg_type = GIMP_PDB_STRINGARRAY;
args[3].value.pdb_pointer = help_uris;
plug_in_run (gimp, proc_rec, args, 4, FALSE, TRUE, -1);
procedural_db_destroy_args (args, 4);
}
else
/* Check if the help parser started properly */
proc_rec = procedural_db_lookup (gimp, "extension_gimp_help_temp");
if (proc_rec == NULL)
{
url = g_strconcat ("file:",
help_domain, "/",
help_locale, "/",
help_id,
NULL);
/* FIXME: error msg */
return;
}
else
{
Argument *return_vals;
gint n_return_vals;
return_vals =
procedural_db_run_proc (gimp,
"plug_in_web_browser",
&nreturn_vals,
GIMP_PDB_STRING, url,
GIMP_PDB_END);
#ifdef DEBUG_HELP
g_printerr ("Calling help via %s: %s %s %s\n",
procedure,
help_domain ? help_domain : NULL,
help_locale ? help_locale : NULL,
help_id ? help_id : NULL);
#endif
procedural_db_destroy_args (return_vals, nreturn_vals);
return_vals =
procedural_db_run_proc (gimp,
"extension_gimp_help_temp",
&n_return_vals,
GIMP_PDB_STRING, procedure,
GIMP_PDB_STRING, help_domain,
GIMP_PDB_STRING, help_locale,
GIMP_PDB_STRING, help_id,
GIMP_PDB_END);
g_free (url);
procedural_db_destroy_args (return_vals, n_return_vals);
}
}
......@@ -1549,6 +1549,7 @@ plug-ins/gimpressionist/Makefile
plug-ins/gimpressionist/Brushes/Makefile
plug-ins/gimpressionist/Paper/Makefile
plug-ins/gimpressionist/Presets/Makefile
plug-ins/help/Makefile
plug-ins/helpbrowser/Makefile
plug-ins/ifscompose/Makefile
plug-ins/imagemap/Makefile
......
......@@ -42,6 +42,7 @@ SUBDIRS = \
gflare \
gfli \
gimpressionist \
help \
$(helpbrowser) \
ifscompose \
imagemap \
......
## Process this file with automake to produce Makefile.in
libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
libexecdir = $(gimpplugindir)/plug-ins
libexec_PROGRAMS = help
help_SOURCES = \
domain.c \
domain.h \
help.c
INCLUDES = \
-I$(top_srcdir) \
$(GLIB_CFLAGS) \
-I$(includedir)
LDADD = \
$(libgimp) \
$(libgimpbase) \
$(GLIB_LIBS) \
$(RT_LIBS) \
$(INTLLIBS)
......@@ -68,8 +68,8 @@ domain_register (const gchar *domain_name,
g_return_if_fail (domain_name != NULL);
g_return_if_fail (domain_uri != NULL);
g_print ("helpbrowser: registering help domain \"%s\" with base uri \"%s\"\n",
domain_name, domain_uri);
g_printerr ("help: registering help domain \"%s\" with base uri \"%s\"\n",
domain_name, domain_uri);
if (! domain_hash)
domain_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
......@@ -83,7 +83,7 @@ domain_register (const gchar *domain_name,
HelpDomain *
domain_lookup (const gchar *domain_name)
{
g_return_val_if_fail (domain_name != NULL, NULL);
g_return_val_if_fail (domain_name, NULL);
if (domain_hash)
return g_hash_table_lookup (domain_hash, domain_name);
......@@ -406,8 +406,8 @@ domain_parser_parse_namespace (DomainParser *parser,
g_free (parser->id_attr_name);
parser->id_attr_name = g_strdup_printf ("%s:id", *names + 6);
g_print ("domain parser: id attribute name for \"%s\" is \"%s\"\n",
parser->domain->help_domain, parser->id_attr_name);
g_printerr ("help: id attribute name for \"%s\" is \"%s\"\n",
parser->domain->help_domain, parser->id_attr_name);
}
names++;
......@@ -446,6 +446,6 @@ domain_parser_parse_item (DomainParser *parser,
g_hash_table_insert (parser->domain->help_id_mapping,
g_strdup (id), g_strdup (ref));
g_print ("domain parser: added mapping \"%s\" -> \"%s\"\n", id, ref);
g_printerr ("help: added mapping \"%s\" -> \"%s\"\n", id, ref);
}
}
......@@ -26,7 +26,7 @@
#define __DOMAIN_H__
#define GIMP_HELP_DEFAULT_DOMAIN "http://www.gimp.org/help"
#define GIMP_HELP_DEFAULT_DOMAIN "http://www.gimp.org/help"
typedef struct _HelpDomain HelpDomain;
......
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* The GIMP Help Browser
* Copyright (C) 1999-2003 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
*
* domain.c
*
* 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 <errno.h>
#include <stdio.h>
#include <string.h>
#include <glib-object.h>
#include "libgimpbase/gimpbase.h"
#include "domain.h"
#include "libgimp/stdplugins-intl.h"
struct _HelpDomain
{
gchar *help_domain;
gchar *help_uri;
GHashTable *help_id_mapping;
};
/* local function prototypes */
HelpDomain * domain_new (const gchar *domain_name,
const gchar *domain_uri);
void domain_free (HelpDomain *domain);
gboolean domain_parse (HelpDomain *domain,
GError **error);
/* private variables */
static GHashTable *domain_hash = NULL;
/* public functions */
void
domain_register (const gchar *domain_name,
const gchar *domain_uri)
{
g_return_if_fail (domain_name != NULL);
g_return_if_fail (domain_uri != NULL);
g_printerr ("help: registering help domain \"%s\" with base uri \"%s\"\n",
domain_name, domain_uri);
if (! domain_hash)
domain_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify ) domain_free);
g_hash_table_insert (domain_hash,
g_strdup (domain_name),
domain_new (domain_name, domain_uri));
}
HelpDomain *
domain_lookup (const gchar *domain_name)
{
g_return_val_if_fail (domain_name, NULL);
if (domain_hash)
return g_hash_table_lookup (domain_hash, domain_name);
return NULL;
}
gchar *
domain_map (HelpDomain *domain,
const gchar *help_locale,
const gchar *help_id)
{
const gchar *ref;
gchar *full_uri;
g_return_val_if_fail (domain != NULL, NULL);
g_return_val_if_fail (help_locale != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
if (! domain->help_id_mapping)
{
GError *error = NULL;
if (! domain_parse (domain, &error) || error)
{
if (! domain->help_id_mapping)
g_message (_("Failed to open help files:\n%s"), error->message);
else
g_message (_("Parse error in help domain:\n%s\n\n"
"(Added entires before error anyway)"), error->message);
if (error)
g_clear_error (&error);
}
if (! domain->help_id_mapping)
return NULL;
}
ref = g_hash_table_lookup (domain->help_id_mapping, help_id);
if (! ref)
{
g_message (_("Help ID '%s' unknown"), help_id);
return NULL;
}
full_uri = g_strconcat (domain->help_uri, "/",
help_locale, "/",
ref, NULL);
return full_uri;
}
/* private functions */
HelpDomain *
domain_new (const gchar *domain_name,
const gchar *domain_uri)
{
HelpDomain *domain;
domain = g_new0 (HelpDomain, 1);
domain->help_domain = g_strdup (domain_name);
domain->help_uri = g_strdup (domain_uri);
return domain;
}
void
domain_free (HelpDomain *domain)
{
g_return_if_fail (domain != NULL);
if (domain->help_id_mapping)
g_hash_table_destroy (domain->help_id_mapping);
g_free (domain->help_domain);
g_free (domain->help_uri);
g_free (domain);
}
/* the domain mapping parser */
typedef enum
{
DOMAIN_START,
DOMAIN_IN_HELP,
DOMAIN_IN_ITEM,
DOMAIN_IN_UNKNOWN
} DomainParserState;
typedef struct
{
const gchar *filename;
DomainParserState state;
DomainParserState last_known_state;
gint markup_depth;
gint unknown_depth;
GString *value;
HelpDomain *domain;
gchar *id_attr_name;
} DomainParser;
static void domain_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error);
static void domain_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void domain_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data);
static void domain_parser_start_unknown (DomainParser *parser);
static void domain_parser_end_unknown (DomainParser *parser);
static void domain_parser_parse_namespace (DomainParser *parser,
const gchar **names,
const gchar **values);
static void domain_parser_parse_item (DomainParser *parser,
const gchar **names,
const gchar **values);
static const GMarkupParser markup_parser =
{
domain_parser_start_element,
domain_parser_end_element,
NULL, /* characters */
NULL, /* passthrough */
domain_parser_error
};
gboolean
domain_parse (HelpDomain *domain,
GError **error)
{
GMarkupParseContext *context;
DomainParser *parser;
gchar *base_dir;
gchar *filename;
FILE *fp;
gsize bytes;
gchar buf[4096];
g_return_val_if_fail (domain != NULL, FALSE);
g_return_val_if_fail (domain->help_id_mapping == NULL, FALSE);
base_dir = g_filename_from_uri (domain->help_uri, NULL, NULL);
filename = g_build_filename (base_dir, "gimp-help.xml", NULL);
g_free (base_dir);
fp = fopen (filename, "r");
if (! fp)
{
gchar *msg;
gchar *msg2;
if (! strcmp (domain->help_domain, GIMP_HELP_DEFAULT_DOMAIN))
msg = _("The GIMP help files are not installed.");
else
msg = _("The requested help files are not installed.");
msg2 = g_strdup_printf (_("Could not open '%s' for reading: %s"),
gimp_filename_to_utf8 (filename),
g_strerror (errno));
g_set_error (error, 0, 0, "%s\n\n%s\n\n%s",
msg, msg2, _("Please check your installation."));
g_free (msg2);
g_free (filename);
return FALSE;
}
parser = g_new0 (DomainParser, 1);
parser->filename = filename;
parser->value = g_string_new (NULL);
parser->id_attr_name = g_strdup ("id");
parser->domain = domain;
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, error))
;
if (error == NULL || *error == NULL)
g_markup_parse_context_end_parse (context, error);
fclose (fp);
g_markup_parse_context_free (context);
g_string_free (parser->value, TRUE);
g_free (parser->id_attr_name);
g_free (parser);
g_free (filename);
return (domain->help_id_mapping != NULL);
}
static void
domain_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
DomainParser *parser = (DomainParser *) user_data;
switch (parser->state)
{
case DOMAIN_START:
if (strcmp (element_name, "gimp-help") == 0)
{
parser->state = DOMAIN_IN_HELP;
domain_parser_parse_namespace (parser, attribute_names,
attribute_values);
}
else
domain_parser_start_unknown (parser);
break;
case DOMAIN_IN_HELP:
if (strcmp (element_name, "help-item") == 0)
{
parser->state = DOMAIN_IN_ITEM;
domain_parser_parse_item (parser, attribute_names,
attribute_values);
}
else
domain_parser_start_unknown (parser);
break;
case DOMAIN_IN_ITEM:
case DOMAIN_IN_UNKNOWN:
domain_parser_start_unknown (parser);
break;
}