diff options
author | Shaun McCance <shaunm@src.gnome.org> | 2004-12-11 21:45:05 +0000 |
---|---|---|
committer | Shaun McCance <shaunm@src.gnome.org> | 2004-12-11 21:45:05 +0000 |
commit | 2af99169da89e7c83f5874bdfabc186df622dfec (patch) | |
tree | 77c4cd6f80ebbeef70ed5948e1c3981a899d144d | |
parent | 268641630d06a370c1e5d29496975a9aec7dc06f (diff) | |
download | yelp-2af99169da89e7c83f5874bdfabc186df622dfec.tar.gz |
- Added yelp-xslt-pager.[ch] to abstract out common pager stuff
* src/Makefile.am:
* src/yelp-db-pager.c:
* src/yelp-db-pager.h:
* src/yelp-window.c:
* src/yelp-xslt-pager.c:
* src/yelp-xslt-pager.h:
- Added yelp-xslt-pager.[ch] to abstract out common pager stuff
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/yelp-db-pager.c | 409 | ||||
-rw-r--r-- | src/yelp-db-pager.h | 5 | ||||
-rw-r--r-- | src/yelp-window.c | 14 | ||||
-rw-r--r-- | src/yelp-xslt-pager.c | 454 | ||||
-rw-r--r-- | src/yelp-xslt-pager.h | 59 |
7 files changed, 635 insertions, 324 deletions
@@ -1,3 +1,13 @@ +2004-12-11 Shaun McCance <shaunm@gnome.org> + + * src/Makefile.am: + * src/yelp-db-pager.c: + * src/yelp-db-pager.h: + * src/yelp-window.c: + * src/yelp-xslt-pager.c: + * src/yelp-xslt-pager.h: + - Added yelp-xslt-pager.[ch] to abstract out common pager stuff + 2004-12-09 Shaun McCance <shaunm@gnome.org> * src/yelp-base.c: diff --git a/src/Makefile.am b/src/Makefile.am index 4f50c2ab..d2fb89bb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ # for debugging -#YELP_CFLAGS += -DYELP_DEBUG -pedantic -ansi -Werror +# YELP_CFLAGS += -DYELP_DEBUG -pedantic -ansi -Werror if ENABLE_MAN man_sources = yelp-man-parser.c yelp-man-parser.h yelp-man-pager.c yelp-man-pager.h @@ -57,6 +57,7 @@ test_pager_SOURCES = \ yelp-pager.c yelp-pager.h \ yelp-toc-pager.c yelp-toc-pager.h \ yelp-utils.c yelp-utils.h \ + yelp-xslt-pager.c yelp-xslt-pager.h \ yelp-marshal-main.c test-pager.c test_pager_LDADD = @YELP_LIBS@ $(POPT_LIBS) $(Z_LIBS) $(BZ_LIBS) @@ -74,15 +75,16 @@ yelp_SOURCES = \ yelp-cache.c yelp-cache.h \ yelp-db-pager.c yelp-db-pager.h \ yelp-error.c yelp-error.h \ - yelp-html-gecko.c yelp-html.h \ yelp-gecko-utils.cpp yelp-gecko-utils.h \ + yelp-html-gecko.c yelp-html.h \ yelp-io-channel.c yelp-io-channel.h \ yelp-pager.c yelp-pager.h \ yelp-settings.c yelp-settings.h \ yelp-toc-pager.c yelp-toc-pager.h \ - yelp-window.c yelp-window.h \ yelp-uri.c yelp-uri.h \ yelp-utils.c yelp-utils.h \ + yelp-window.c yelp-window.h \ + yelp-xslt-pager.c yelp-xslt-pager.h \ yelp-marshal-main.c yelp-main.c yelp_LDADD = @YELP_LIBS@ $(POPT_LIBS) $(Z_LIBS) $(BZ_LIBS) $(MOZILLA_COMPONENT_LIBS) diff --git a/src/yelp-db-pager.c b/src/yelp-db-pager.c index a546595b..53da99ab 100644 --- a/src/yelp-db-pager.c +++ b/src/yelp-db-pager.c @@ -47,8 +47,6 @@ #define d(x) #endif -#define YELP_NAMESPACE "http://www.gnome.org/yelp/ns" - #define DB_STYLESHEET_PATH DATADIR"/sgml/docbook/yelp/" #define DB_STYLESHEET DB_STYLESHEET_PATH"db2html.xsl" @@ -62,16 +60,9 @@ extern gboolean main_running; struct _YelpDBPagerPriv { GtkTreeModel *sects; - GHashTable *frags_hash; gchar *root_id; - - xmlDocPtr inputDoc; - xmlDocPtr outputDoc; - xmlParserCtxtPtr parserCtxt; - xsltStylesheetPtr stylesheet; - xsltTransformContextPtr transformContext; }; typedef struct _DBWalker DBWalker; @@ -92,11 +83,10 @@ static void db_pager_class_init (YelpDBPagerClass *klass); static void db_pager_init (YelpDBPager *pager); static void db_pager_dispose (GObject *gobject); -static void db_pager_error (YelpPager *pager); static void db_pager_cancel (YelpPager *pager); -static void db_pager_finish (YelpPager *pager); +static xmlDocPtr db_pager_parse (YelpPager *pager); +static gchar ** db_pager_params (YelpPager *pager); -gboolean db_pager_process (YelpPager *pager); const gchar * db_pager_resolve_frag (YelpPager *pager, const gchar *frag_id); GtkTreeModel * db_pager_get_sections (YelpPager *pager); @@ -108,15 +98,6 @@ static gboolean xml_is_division (xmlNodePtr node); static gboolean xml_is_info (xmlNodePtr node); static gchar * xml_get_title (xmlNodePtr node); -static void xslt_yelp_document (xsltTransformContextPtr ctxt, - xmlNodePtr node, - xmlNodePtr inst, - xsltStylePreCompPtr comp); -static void xslt_yelp_cache (xsltTransformContextPtr ctxt, - xmlNodePtr node, - xmlNodePtr inst, - xsltStylePreCompPtr comp); - static YelpPagerClass *parent_class; GType @@ -136,7 +117,7 @@ yelp_db_pager_get_type (void) 0, (GInstanceInitFunc) db_pager_init, }; - type = g_type_register_static (YELP_TYPE_PAGER, + type = g_type_register_static (YELP_TYPE_XSLT_PAGER, "YelpDBPager", &info, 0); } @@ -148,18 +129,21 @@ db_pager_class_init (YelpDBPagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); YelpPagerClass *pager_class = YELP_PAGER_CLASS (klass); + YelpXsltPagerClass *xslt_class = YELP_XSLT_PAGER_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->dispose = db_pager_dispose; - pager_class->error = db_pager_error; - pager_class->cancel = db_pager_cancel; - pager_class->finish = db_pager_finish; + pager_class->cancel = db_pager_cancel; - pager_class->process = db_pager_process; pager_class->resolve_frag = db_pager_resolve_frag; pager_class->get_sections = db_pager_get_sections; + + xslt_class->parse = db_pager_parse; + xslt_class->params = db_pager_params; + + xslt_class->stylesheet = DB_STYLESHEET; } static void @@ -212,65 +196,56 @@ yelp_db_pager_new (YelpDocInfo *doc_info) return (YelpPager *) pager; } -gboolean -db_pager_process (YelpPager *pager) +static xmlDocPtr +db_pager_parse (YelpPager *pager) { YelpDBPagerPriv *priv; YelpDocInfo *doc_info; gchar *filename; - gint params_i = 0; - gint i; + + xmlParserCtxtPtr parserCtxt; + xmlDocPtr doc; DBWalker *walker; xmlChar *id; GError *error = NULL; - GtkIconInfo *icon_info; - gchar *icon_file; - gchar *icons[YELP_NUM_ICONS]; - - const gchar *params[40]; - - d (g_print ("db_pager_process\n")); + d (g_print ("db_pager_parse\n")); doc_info = yelp_pager_get_doc_info (pager); - g_return_val_if_fail (pager != NULL, FALSE); - g_return_val_if_fail (YELP_IS_DB_PAGER (pager), FALSE); + g_return_val_if_fail (pager != NULL, NULL); + g_return_val_if_fail (YELP_IS_DB_PAGER (pager), NULL); priv = YELP_DB_PAGER (pager)->priv; + g_object_ref (pager); + if (yelp_pager_get_state (pager) >= YELP_PAGER_STATE_ERROR) goto done; filename = yelp_doc_info_get_filename (doc_info); - g_object_ref (pager); - yelp_toc_pager_pause (yelp_toc_pager_get ()); - - yelp_pager_set_state (pager, YELP_PAGER_STATE_PARSING); - g_signal_emit_by_name (pager, "parse"); - - priv->parserCtxt = xmlNewParserCtxt (); - priv->inputDoc = xmlCtxtReadFile (priv->parserCtxt, - (const char *) filename, NULL, - XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA | - XML_PARSE_NOENT | XML_PARSE_NONET ); - if (priv->inputDoc == NULL) { + parserCtxt = xmlNewParserCtxt (); + doc = xmlCtxtReadFile (parserCtxt, + (const char *) filename, NULL, + XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA | + XML_PARSE_NOENT | XML_PARSE_NONET ); + if (doc == NULL) { yelp_set_error (&error, YELP_ERROR_NO_DOC); yelp_pager_error (pager, error); goto done; } - xmlXIncludeProcessFlags (priv->inputDoc, + xmlXIncludeProcessFlags (doc, XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA | XML_PARSE_NOENT | XML_PARSE_NONET ); walker = g_new0 (DBWalker, 1); walker->pager = YELP_DB_PAGER (pager); - walker->doc = priv->inputDoc; + walker->doc = doc; walker->cur = xmlDocGetRootElement (walker->doc); - if (!xmlStrcmp (xmlDocGetRootElement (priv->inputDoc)->name, BAD_CAST "book")) + if (!xmlStrcmp (xmlDocGetRootElement (doc)->name, BAD_CAST "book")) walker->max_depth = BOOK_CHUNK_DEPTH; else walker->max_depth = ARTICLE_CHUNK_DEPTH; @@ -286,28 +261,54 @@ db_pager_process (YelpPager *pager) walker_walk_xml (walker); - CANCEL_CHECK; + done: + g_free (filename); + g_free (walker); - yelp_pager_set_state (pager, YELP_PAGER_STATE_RUNNING); - g_signal_emit_by_name (pager, "start"); + if (parserCtxt) + xmlFreeParserCtxt (parserCtxt); - EVENTS_PENDING; - CANCEL_CHECK; + g_object_unref (pager); - for (i = 0; i < YELP_NUM_ICONS; i++) { - icon_info = yelp_settings_get_icon (i); - if (icon_info) { - icon_file = (gchar *) gtk_icon_info_get_filename (icon_info); - if (icon_file) - icons[i] = g_strdup_printf ("\"%s\"", icon_file); - else - icons[i] = g_strdup ("\"\""); - gtk_icon_info_free (icon_info); - } else { - icons[i] = g_strdup ("\"\""); + return doc; +} + +static gchar ** +db_pager_params (YelpPager *pager) +{ + YelpDBPagerPriv *priv; + YelpDocInfo *doc_info; + gchar *filename; + gchar **params; + gint params_i = 0; + gint params_max = 20; + + GtkIconInfo *icon_info; + gchar *icon_file; + gint icons_i; + + d (g_print ("db_pager_process\n")); + + doc_info = yelp_pager_get_doc_info (pager); + + g_return_val_if_fail (pager != NULL, FALSE); + g_return_val_if_fail (YELP_IS_DB_PAGER (pager), FALSE); + priv = YELP_DB_PAGER (pager)->priv; + + if (yelp_pager_get_state (pager) >= YELP_PAGER_STATE_ERROR) + return NULL; + + filename = yelp_doc_info_get_filename (doc_info); + + params = g_new0 (gchar *, params_max); + + for (icons_i = 0; icons_i < YELP_NUM_ICONS; icons_i++) { + if ((params_i + 1) >= params_max - 1) { + params_max += 20; + params = g_renew (gchar *, params, params_max); } - switch (i) { + switch (icons_i) { case YELP_ICON_BLOCKQUOTE: params[params_i++] = "yelp.image.blockquote"; break; @@ -332,9 +333,24 @@ db_pager_process (YelpPager *pager) default: g_assert_not_reached (); } - params[params_i++] = icons[i]; + + icon_info = yelp_settings_get_icon (icons_i); + if (icon_info) { + icon_file = (gchar *) gtk_icon_info_get_filename (icon_info); + if (icon_file) + params[params_i++] = g_strdup_printf ("\"%s\"", icon_file); + else + params[params_i++] = g_strdup ("\"\""); + gtk_icon_info_free (icon_info); + } else { + params[params_i++] = g_strdup ("\"\""); + } } + if ((params_i + 10) >= params_max - 1) { + params_max += 20; + params = g_renew (gchar *, params, params_max); + } params[params_i++] = "stylesheet_path"; params[params_i++] = g_strdup_printf ("\"file://%s\"", DB_STYLESHEET_PATH); params[params_i++] = "html_extension"; @@ -345,81 +361,7 @@ db_pager_process (YelpPager *pager) params[params_i++] = g_strdup_printf ("\"file://%s\"", DATADIR "/yelp/icons/"); params[params_i++] = NULL; - priv->stylesheet = xsltParseStylesheetFile (DB_STYLESHEET); - if (!priv->stylesheet) { - yelp_set_error (&error, YELP_ERROR_PROC); - yelp_pager_error (pager, error); - goto done; - } - - priv->transformContext = xsltNewTransformContext (priv->stylesheet, - priv->inputDoc); - if (!priv->transformContext) { - yelp_set_error (&error, YELP_ERROR_PROC); - yelp_pager_error (pager, error); - goto done; - } - - priv->transformContext->_private = pager; - xsltRegisterExtElement (priv->transformContext, - "document", - YELP_NAMESPACE, - (xsltTransformFunction) xslt_yelp_document); - xsltRegisterExtElement (priv->transformContext, - "cache", - YELP_NAMESPACE, - (xsltTransformFunction) xslt_yelp_cache); - - EVENTS_PENDING; - CANCEL_CHECK; - - priv->outputDoc = xsltApplyStylesheetUser (priv->stylesheet, - priv->inputDoc, - params, NULL, NULL, - priv->transformContext); - CANCEL_CHECK; - g_signal_emit_by_name (pager, "finish"); - - done: - for (params_i = 0; params[params_i] != NULL; params_i++) - if (params_i % 2 == 1) - g_free (params[params_i]); - g_free (filename); - g_free (walker); - - if (priv->inputDoc) { - xmlFreeDoc (priv->inputDoc); - priv->inputDoc = NULL; - } - if (priv->outputDoc) { - xmlFreeDoc (priv->outputDoc); - priv->outputDoc = NULL; - } - if (priv->parserCtxt) { - xmlFreeParserCtxt (priv->parserCtxt); - priv->parserCtxt = NULL; - } - if (priv->stylesheet) { - xsltFreeStylesheet (priv->stylesheet); - priv->stylesheet = NULL; - } - if (priv->transformContext) { - xsltFreeTransformContext (priv->transformContext); - priv->transformContext = NULL; - } - - g_object_unref (pager); - - return FALSE; -} - -static void -db_pager_error (YelpPager *pager) -{ - d (g_print ("db_pager_error\n")); - yelp_pager_set_state (pager, YELP_PAGER_STATE_ERROR); - if (yelp_pager_get_state (pager) <= YELP_PAGER_STATE_RUNNING) - yelp_toc_pager_unpause (yelp_toc_pager_get ()); + return params; } static void @@ -430,8 +372,6 @@ db_pager_cancel (YelpPager *pager) d (g_print ("db_pager_cancel\n")); yelp_pager_set_state (pager, YELP_PAGER_STATE_INVALID); - if (yelp_pager_get_state (pager) <= YELP_PAGER_STATE_RUNNING) - yelp_toc_pager_unpause (yelp_toc_pager_get ()); gtk_tree_store_clear (GTK_TREE_STORE (priv->sects)); g_hash_table_foreach_remove (priv->frags_hash, gtk_true, NULL); @@ -439,35 +379,7 @@ db_pager_cancel (YelpPager *pager) g_free (priv->root_id); priv->root_id = NULL; - if (priv->inputDoc) { - xmlFreeDoc (priv->inputDoc); - priv->inputDoc = NULL; - } - if (priv->outputDoc) { - xmlFreeDoc (priv->outputDoc); - priv->outputDoc = NULL; - } - if (priv->parserCtxt) { - xmlFreeParserCtxt (priv->parserCtxt); - priv->parserCtxt = NULL; - } - if (priv->stylesheet) { - xsltFreeStylesheet (priv->stylesheet); - priv->stylesheet = NULL; - } - if (priv->transformContext) { - xsltFreeTransformContext (priv->transformContext); - priv->transformContext = NULL; - } -} - -static void -db_pager_finish (YelpPager *pager) -{ - d (g_print ("db_pager_finish\n")); - yelp_pager_set_state (pager, YELP_PAGER_STATE_FINISHED); - if (yelp_pager_get_state (pager) <= YELP_PAGER_STATE_RUNNING) - yelp_toc_pager_unpause (yelp_toc_pager_get ()); + YELP_PAGER_CLASS (parent_class)->cancel (pager); } const gchar * @@ -499,146 +411,7 @@ db_pager_get_sections (YelpPager *pager) return YELP_DB_PAGER (pager)->priv->sects; } -void -xslt_yelp_document (xsltTransformContextPtr ctxt, - xmlNodePtr node, - xmlNodePtr inst, - xsltStylePreCompPtr comp) -{ - GError *error; - YelpPage *page; - xmlChar *page_id = NULL; - xmlChar *page_title = NULL; - xmlChar *page_buf; - gint buf_size; - YelpPager *pager; - xsltStylesheetPtr style = NULL; - const char *old_outfile; - xmlDocPtr new_doc = NULL; - xmlDocPtr old_doc; - xmlNodePtr old_insert; - xmlNodePtr cur; - - if (!ctxt || !node || !inst || !comp) - return; - - pager = (YelpPager *) ctxt->_private; - - EVENTS_PENDING; - CANCEL_CHECK; - - d (g_print ("xslt_yelp_document\n")); - - page_id = xsltEvalAttrValueTemplate (ctxt, inst, - (const xmlChar *) "href", - NULL); - if (page_id == NULL) { - xsltTransformError (ctxt, NULL, inst, - _("No href attribute found on yelp:document")); - error = NULL; - yelp_pager_error (pager, error); - goto done; - } - d (g_print (" page_id = \"%s\"\n", page_id)); - - old_outfile = ctxt->outputFile; - old_doc = ctxt->output; - old_insert = ctxt->insert; - ctxt->outputFile = (const char *) page_id; - - style = xsltNewStylesheet (); - if (style == NULL) { - xsltTransformError (ctxt, NULL, inst, - _("Out of memory")); - error = NULL; - yelp_pager_error (pager, error); - goto done; - } - - style->omitXmlDeclaration = TRUE; - - new_doc = xmlNewDoc ("1.0"); - new_doc->charset = XML_CHAR_ENCODING_UTF8; - new_doc->dict = ctxt->dict; - xmlDictReference (new_doc->dict); - - ctxt->output = new_doc; - ctxt->insert = (xmlNodePtr) new_doc; - - xsltApplyOneTemplate (ctxt, node, inst->children, NULL, NULL); - - CANCEL_CHECK; - - xsltSaveResultToString (&page_buf, &buf_size, new_doc, style); - - ctxt->outputFile = old_outfile; - ctxt->output = old_doc; - ctxt->insert = old_insert; - - page_title = xml_get_title (node); - - CANCEL_CHECK; - - if (!page_title) - page_title = g_strdup ("FIXME"); - - page = g_new0 (YelpPage, 1); - - page->page_id = g_strdup (page_id); - xmlFree (page_id); - page_id = NULL; - - page->title = page_title; - page->contents = page_buf; - - cur = xmlDocGetRootElement (new_doc); - for (cur = cur->children; cur; cur = cur->next) { - if (!xmlStrcmp (cur->name, (xmlChar *) "head")) { - for (cur = cur->children; cur; cur = cur->next) { - if (!xmlStrcmp (cur->name, (xmlChar *) "link")) { - xmlChar *rel = xmlGetProp (cur, "rel"); - - if (!xmlStrcmp (rel, (xmlChar *) "Previous")) - page->prev_id = g_strdup (xmlGetProp (cur, "href")); - else if (!xmlStrcmp (rel, (xmlChar *) "Next")) - page->next_id = g_strdup (xmlGetProp (cur, "href")); - else if (!xmlStrcmp (rel, (xmlChar *) "Top")) - page->toc_id = g_strdup (xmlGetProp (cur, "href")); - - xmlFree (rel); - } - } - break; - } - } - - CANCEL_CHECK; - - yelp_pager_add_page (pager, page); - g_signal_emit_by_name (pager, "page", page->page_id); - - EVENTS_PENDING; - CANCEL_CHECK; - - done: - if (new_doc) - xmlFreeDoc (new_doc); - if (style) - xsltFreeStylesheet (style); -} - -void -xslt_yelp_cache (xsltTransformContextPtr ctxt, - xmlNodePtr node, - xmlNodePtr inst, - xsltStylePreCompPtr comp) -{ - xsltApplyOneTemplate (ctxt, node, inst->children, NULL, NULL); - - while (gtk_events_pending ()) - gtk_main_iteration (); - // FIXME : check for cancel -} +/******************************************************************************/ static void walker_walk_xml (DBWalker *walker) diff --git a/src/yelp-db-pager.h b/src/yelp-db-pager.h index 899b7ac7..40381278 100644 --- a/src/yelp-db-pager.h +++ b/src/yelp-db-pager.h @@ -26,6 +26,7 @@ #include <glib-object.h> #include "yelp-pager.h" +#include "yelp-xslt-pager.h" #define YELP_TYPE_DB_PAGER (yelp_db_pager_get_type ()) #define YELP_DB_PAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_DB_PAGER, YelpDBPager)) @@ -39,13 +40,13 @@ typedef struct _YelpDBPagerClass YelpDBPagerClass; typedef struct _YelpDBPagerPriv YelpDBPagerPriv; struct _YelpDBPager { - YelpPager parent; + YelpXsltPager parent; YelpDBPagerPriv *priv; }; struct _YelpDBPagerClass { - YelpPagerClass parent_class; + YelpXsltPagerClass parent_class; }; GType yelp_db_pager_get_type (void); diff --git a/src/yelp-window.c b/src/yelp-window.c index e36fba6f..da5a6b6a 100644 --- a/src/yelp-window.c +++ b/src/yelp-window.c @@ -257,6 +257,8 @@ struct _YelpWindowPriv { gulong finish_handler; guint idle_write; + gint toc_pause; + GtkActionGroup *action_group; GtkUIManager *ui_manager; @@ -1138,8 +1140,13 @@ window_do_load_pager (YelpWindow *window, G_CALLBACK (pager_finish_cb), window); - if (startnow) + if (startnow) { handled = yelp_pager_start (pager); + if (handled) { + yelp_toc_pager_pause (yelp_toc_pager_get ()); + priv->toc_pause++; + } + } // FIXME: error if !handled } @@ -1389,6 +1396,11 @@ window_disconnect (YelpWindow *window) if (GTK_WIDGET (window)->window) gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); + if (window->priv->toc_pause > 0) { + window->priv->toc_pause--; + yelp_toc_pager_unpause (yelp_toc_pager_get ()); + } + if (window->priv->current_doc) { if (priv->start_handler) { g_signal_handler_disconnect (pager, diff --git a/src/yelp-xslt-pager.c b/src/yelp-xslt-pager.c new file mode 100644 index 00000000..7d448652 --- /dev/null +++ b/src/yelp-xslt-pager.c @@ -0,0 +1,454 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2003 Shaun McCance <shaunm@gnome.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. + * + * Author: Shaun McCance <shaunm@gnome.org> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <libgnome/gnome-i18n.h> +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#include <libxml/xinclude.h> +#include <libxslt/xslt.h> +#include <libxslt/templates.h> +#include <libxslt/transform.h> +#include <libxslt/extensions.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/xsltutils.h> + +#include "yelp-error.h" +#include "yelp-settings.h" +#include "yelp-xslt-pager.h" + +#ifdef YELP_DEBUG +#define d(x) x +#else +#define d(x) +#endif + +#define YELP_NAMESPACE "http://www.gnome.org/yelp/ns" + +#define EVENTS_PENDING while (yelp_pager_get_state (pager) <= YELP_PAGER_STATE_RUNNING && gtk_events_pending ()) gtk_main_iteration (); +#define CANCEL_CHECK if (!main_running || yelp_pager_get_state (pager) >= YELP_PAGER_STATE_ERROR) goto done; + +extern gboolean main_running; + +struct _YelpXsltPagerPriv { + xmlDocPtr inputDoc; + xmlDocPtr outputDoc; + xsltStylesheetPtr stylesheet; + xsltTransformContextPtr transformContext; +}; + +static void xslt_pager_class_init (YelpXsltPagerClass *klass); +static void xslt_pager_init (YelpXsltPager *pager); +static void xslt_pager_dispose (GObject *gobject); + +static void xslt_pager_error (YelpPager *pager); +static void xslt_pager_cancel (YelpPager *pager); +static void xslt_pager_finish (YelpPager *pager); + +gboolean xslt_pager_process (YelpPager *pager); + +static void xslt_yelp_document (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltStylePreCompPtr comp); +static void xslt_yelp_cache (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltStylePreCompPtr comp); + +static YelpPagerClass *parent_class; + +GType +yelp_xslt_pager_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (YelpXsltPagerClass), + NULL, + NULL, + (GClassInitFunc) xslt_pager_class_init, + NULL, + NULL, + sizeof (YelpXsltPager), + 0, + (GInstanceInitFunc) xslt_pager_init, + }; + type = g_type_register_static (YELP_TYPE_PAGER, + "YelpXsltPager", + &info, 0); + } + return type; +} + +static void +xslt_pager_class_init (YelpXsltPagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + YelpPagerClass *pager_class = YELP_PAGER_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->dispose = xslt_pager_dispose; + + pager_class->error = xslt_pager_error; + pager_class->cancel = xslt_pager_cancel; + pager_class->finish = xslt_pager_finish; + + pager_class->process = xslt_pager_process; +} + +static void +xslt_pager_init (YelpXsltPager *pager) +{ + YelpXsltPagerPriv *priv; + + priv = g_new0 (YelpXsltPagerPriv, 1); + pager->priv = priv; +} + +static void +xslt_pager_dispose (GObject *object) +{ + YelpXsltPager *pager = YELP_XSLT_PAGER (object); + YelpXsltPagerPriv *priv = pager->priv; + + if (priv->inputDoc) + xmlFreeDoc (priv->inputDoc); + if (priv->outputDoc) + xmlFreeDoc (priv->outputDoc); + if (priv->stylesheet) + xsltFreeStylesheet (priv->stylesheet); + if (priv->transformContext) + xsltFreeTransformContext (priv->transformContext); + + g_free (pager->priv); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +/******************************************************************************/ + +gboolean +xslt_pager_process (YelpPager *pager) +{ + YelpXsltPagerPriv *priv; + YelpXsltPagerClass *klass; + + YelpDocInfo *doc_info; + gchar *filename; + + gchar **params; + gint params_i = 0; + + GError *error = NULL; + + d (g_print ("xslt_pager_process\n")); + + g_return_val_if_fail (pager != NULL, FALSE); + g_return_val_if_fail (YELP_IS_XSLT_PAGER (pager), FALSE); + + priv = YELP_XSLT_PAGER (pager)->priv; + klass = YELP_XSLT_PAGER_GET_CLASS (pager); + + doc_info = yelp_pager_get_doc_info (pager); + + if (yelp_pager_get_state (pager) >= YELP_PAGER_STATE_ERROR) + goto done; + + filename = yelp_doc_info_get_filename (doc_info); + + g_object_ref (pager); + + yelp_pager_set_state (pager, YELP_PAGER_STATE_PARSING); + g_signal_emit_by_name (pager, "parse"); + + priv->inputDoc = klass->parse (pager); + + if (priv->inputDoc == NULL) { + yelp_set_error (&error, YELP_ERROR_NO_DOC); + yelp_pager_error (pager, error); + goto done; + } + + EVENTS_PENDING; + CANCEL_CHECK; + + yelp_pager_set_state (pager, YELP_PAGER_STATE_RUNNING); + g_signal_emit_by_name (pager, "start"); + + EVENTS_PENDING; + CANCEL_CHECK; + + params = klass->params (pager); + + priv->stylesheet = xsltParseStylesheetFile (klass->stylesheet); + if (!priv->stylesheet) { + yelp_set_error (&error, YELP_ERROR_PROC); + yelp_pager_error (pager, error); + goto done; + } + + priv->transformContext = xsltNewTransformContext (priv->stylesheet, + priv->inputDoc); + if (!priv->transformContext) { + yelp_set_error (&error, YELP_ERROR_PROC); + yelp_pager_error (pager, error); + goto done; + } + + priv->transformContext->_private = pager; + xsltRegisterExtElement (priv->transformContext, + "document", + YELP_NAMESPACE, + (xsltTransformFunction) xslt_yelp_document); + xsltRegisterExtElement (priv->transformContext, + "cache", + YELP_NAMESPACE, + (xsltTransformFunction) xslt_yelp_cache); + + EVENTS_PENDING; + CANCEL_CHECK; + + priv->outputDoc = xsltApplyStylesheetUser (priv->stylesheet, + priv->inputDoc, + (const char **) params, + NULL, NULL, + priv->transformContext); + CANCEL_CHECK; + g_signal_emit_by_name (pager, "finish"); + + done: + for (params_i = 0; params[params_i] != NULL; params_i++) + if (params_i % 2 == 1) + g_free (params[params_i]); + g_free (params); + g_free (filename); + + if (priv->inputDoc) { + xmlFreeDoc (priv->inputDoc); + priv->inputDoc = NULL; + } + if (priv->outputDoc) { + xmlFreeDoc (priv->outputDoc); + priv->outputDoc = NULL; + } + if (priv->stylesheet) { + xsltFreeStylesheet (priv->stylesheet); + priv->stylesheet = NULL; + } + if (priv->transformContext) { + xsltFreeTransformContext (priv->transformContext); + priv->transformContext = NULL; + } + + g_object_unref (pager); + + return FALSE; +} + +static void +xslt_pager_error (YelpPager *pager) +{ + d (g_print ("xslt_pager_error\n")); + yelp_pager_set_state (pager, YELP_PAGER_STATE_ERROR); +} + +static void +xslt_pager_cancel (YelpPager *pager) +{ + YelpXsltPagerPriv *priv = YELP_XSLT_PAGER (pager)->priv; + + d (g_print ("xslt_pager_cancel\n")); + + yelp_pager_set_state (pager, YELP_PAGER_STATE_INVALID); + + if (priv->inputDoc) { + xmlFreeDoc (priv->inputDoc); + priv->inputDoc = NULL; + } + if (priv->outputDoc) { + xmlFreeDoc (priv->outputDoc); + priv->outputDoc = NULL; + } + if (priv->stylesheet) { + xsltFreeStylesheet (priv->stylesheet); + priv->stylesheet = NULL; + } + if (priv->transformContext) { + xsltFreeTransformContext (priv->transformContext); + priv->transformContext = NULL; + } +} + +static void +xslt_pager_finish (YelpPager *pager) +{ + d (g_print ("xslt_pager_finish\n")); + yelp_pager_set_state (pager, YELP_PAGER_STATE_FINISHED); +} + +/** XSLT Extension Elements ***************************************************/ + +void +xslt_yelp_document (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltStylePreCompPtr comp) +{ + GError *error; + YelpPage *page; + xmlChar *page_id = NULL; + xmlChar *page_title = NULL; + xmlChar *page_buf; + gint buf_size; + YelpPager *pager; + xsltStylesheetPtr style = NULL; + const char *old_outfile; + xmlDocPtr new_doc = NULL; + xmlDocPtr old_doc; + xmlNodePtr old_insert; + xmlNodePtr cur; + + if (!ctxt || !node || !inst || !comp) + return; + + pager = (YelpPager *) ctxt->_private; + + EVENTS_PENDING; + CANCEL_CHECK; + + d (g_print ("xslt_yelp_document\n")); + + page_id = xsltEvalAttrValueTemplate (ctxt, inst, + (const xmlChar *) "href", + NULL); + if (page_id == NULL) { + xsltTransformError (ctxt, NULL, inst, + _("No href attribute found on yelp:document")); + error = NULL; + yelp_pager_error (pager, error); + goto done; + } + d (g_print (" page_id = \"%s\"\n", page_id)); + + old_outfile = ctxt->outputFile; + old_doc = ctxt->output; + old_insert = ctxt->insert; + ctxt->outputFile = (const char *) page_id; + + style = xsltNewStylesheet (); + if (style == NULL) { + xsltTransformError (ctxt, NULL, inst, + _("Out of memory")); + error = NULL; + yelp_pager_error (pager, error); + goto done; + } + + style->omitXmlDeclaration = TRUE; + + new_doc = xmlNewDoc ("1.0"); + new_doc->charset = XML_CHAR_ENCODING_UTF8; + new_doc->dict = ctxt->dict; + xmlDictReference (new_doc->dict); + + ctxt->output = new_doc; + ctxt->insert = (xmlNodePtr) new_doc; + + xsltApplyOneTemplate (ctxt, node, inst->children, NULL, NULL); + + CANCEL_CHECK; + + xsltSaveResultToString (&page_buf, &buf_size, new_doc, style); + + ctxt->outputFile = old_outfile; + ctxt->output = old_doc; + ctxt->insert = old_insert; + + CANCEL_CHECK; + + if (!page_title) + page_title = g_strdup ("FIXME"); + + page = g_new0 (YelpPage, 1); + + page->page_id = g_strdup (page_id); + xmlFree (page_id); + page_id = NULL; + + page->title = page_title; + page->contents = page_buf; + + cur = xmlDocGetRootElement (new_doc); + for (cur = cur->children; cur; cur = cur->next) { + if (!xmlStrcmp (cur->name, (xmlChar *) "head")) { + for (cur = cur->children; cur; cur = cur->next) { + if (!xmlStrcmp (cur->name, (xmlChar *) "link")) { + xmlChar *rel = xmlGetProp (cur, "rel"); + + if (!xmlStrcmp (rel, (xmlChar *) "Previous")) + page->prev_id = g_strdup (xmlGetProp (cur, "href")); + else if (!xmlStrcmp (rel, (xmlChar *) "Next")) + page->next_id = g_strdup (xmlGetProp (cur, "href")); + else if (!xmlStrcmp (rel, (xmlChar *) "Top")) + page->toc_id = g_strdup (xmlGetProp (cur, "href")); + + xmlFree (rel); + } + } + break; + } + } + + CANCEL_CHECK; + + yelp_pager_add_page (pager, page); + g_signal_emit_by_name (pager, "page", page->page_id); + + EVENTS_PENDING; + CANCEL_CHECK; + + done: + if (new_doc) + xmlFreeDoc (new_doc); + if (style) + xsltFreeStylesheet (style); +} + +void +xslt_yelp_cache (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltStylePreCompPtr comp) +{ + xsltApplyOneTemplate (ctxt, node, inst->children, NULL, NULL); + + while (gtk_events_pending ()) + gtk_main_iteration (); + // FIXME : check for cancel +} diff --git a/src/yelp-xslt-pager.h b/src/yelp-xslt-pager.h new file mode 100644 index 00000000..b46cced5 --- /dev/null +++ b/src/yelp-xslt-pager.h @@ -0,0 +1,59 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2003 Shaun McCance <shaunm@gnome.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. + * + * Author: Shaun McCance <shaunm@gnome.org> + */ + +#ifndef __YELP_XSLT_PAGER_H__ +#define __YELP_XSLT_PAGER_H__ + +#include <glib-object.h> +#include <libxml/parser.h> + +#include "yelp-pager.h" + +#define YELP_TYPE_XSLT_PAGER (yelp_xslt_pager_get_type ()) +#define YELP_XSLT_PAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_XSLT_PAGER, YelpXsltPager)) +#define YELP_XSLT_PAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), YELP_TYPE_XSLT_PAGER, YelpXsltPagerClass)) +#define YELP_IS_XSLT_PAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_XSLT_PAGER)) +#define YELP_IS_XSLT_PAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_XSLT_PAGER)) +#define YELP_XSLT_PAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_XSLT_PAGER, YelpXsltPagerClass)) + +typedef struct _YelpXsltPager YelpXsltPager; +typedef struct _YelpXsltPagerClass YelpXsltPagerClass; +typedef struct _YelpXsltPagerPriv YelpXsltPagerPriv; + +struct _YelpXsltPager { + YelpPager parent; + + YelpXsltPagerPriv *priv; +}; + +struct _YelpXsltPagerClass { + YelpPagerClass parent_class; + + xmlDocPtr (*parse) (YelpPager *pager); + gchar ** (*params) (YelpPager *pager); + + gchar *stylesheet; +}; + +GType yelp_xslt_pager_get_type (void); + +#endif /* __YELP_XSLT_PAGER_H__ */ |