mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Merge webkit branch into trunk.
In order to use the webkit as the html engine, use --enable-webkit on the configure command. In SCM files, gnc-html-engine-supports-css can be used to determine whether the html engine is webkit (supports css) or gtkhtml (doesn't support css). git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18041 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
b810924125
commit
ea934ae4d0
21
configure.in
21
configure.in
@ -514,6 +514,26 @@ AC_SUBST(GCONFTOOL)
|
||||
AC_SUBST(GCONF_CFLAGS)
|
||||
AC_SUBST(GCONF_LIBS)
|
||||
|
||||
### --------------------------------------------------------------------------
|
||||
### look for webkit
|
||||
|
||||
AC_ARG_ENABLE(webkit,
|
||||
[AS_HELP_STRING([--enable-webkit],[build with the webkit HTML engine])],
|
||||
[case "${enableval}" in
|
||||
yes) want_webkit=true ;;
|
||||
no) want_webkit=false ;;
|
||||
*) want_webkit=false ;;
|
||||
esac],
|
||||
[want_webkit=false])
|
||||
if test x${want_webkit} = xtrue
|
||||
then
|
||||
PKG_CHECK_MODULES(WEBKIT, webkit-1.0 >= "1.0")
|
||||
AC_DEFINE(WANT_WEBKIT,1,[Use webkit instead of gtkhtml])
|
||||
fi
|
||||
AM_CONDITIONAL(HTML_USING_WEBKIT, test x${want_webkit} = xtrue)
|
||||
AC_SUBST(WEBKIT_CFLAGS)
|
||||
AC_SUBST(WEBKIT_LIBS)
|
||||
|
||||
### --------------------------------------------------------------------------
|
||||
### LIBXML -- GNOME_XML_LIB is defined by GNOME_XML_CHECK
|
||||
|
||||
@ -1511,6 +1531,7 @@ AC_CONFIG_FILES(po/Makefile.in
|
||||
src/gnome-utils/test/Makefile
|
||||
src/gnome-utils/ui/Makefile
|
||||
src/gnome-search/Makefile
|
||||
src/html/Makefile
|
||||
src/import-export/Makefile
|
||||
src/import-export/test/Makefile
|
||||
src/import-export/qif-import/Makefile
|
||||
|
@ -15,6 +15,7 @@ GUI_SUBDIRS_1 = \
|
||||
tax \
|
||||
app-utils \
|
||||
gnome-utils \
|
||||
html \
|
||||
gnome-search
|
||||
|
||||
GUI_SUBDIRS_2 = \
|
||||
|
@ -12,6 +12,7 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/gnome \
|
||||
-I${top_srcdir}/src/app-utils \
|
||||
-I${top_srcdir}/src/gnome-search \
|
||||
-I${top_srcdir}/src/html \
|
||||
-I${top_srcdir}/src/report/report-gnome \
|
||||
-I${top_srcdir}/src/business/business-core \
|
||||
-I${top_srcdir}/src/business/business-ledger \
|
||||
@ -22,8 +23,6 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${GNOME_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GDK_PIXBUF_CFLAGS} \
|
||||
${GLIB_CFLAGS} \
|
||||
${GUILE_INCS}
|
||||
|
||||
@ -76,6 +75,7 @@ libgncmod_business_gnome_la_LIBADD = \
|
||||
${top_builddir}/src/gnome-search/libgncmod-gnome-search.la \
|
||||
${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
|
||||
${top_builddir}/src/app-utils/libgncmod-app-utils.la \
|
||||
${top_builddir}/src/html/libgncmod-html.la \
|
||||
${top_builddir}/src/engine/libgncmod-engine.la \
|
||||
${top_builddir}/src/core-utils/libgnc-core-utils.la \
|
||||
${top_builddir}/src/gnc-module/libgnc-module.la \
|
||||
|
@ -11,8 +11,6 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${GNOME_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GDK_PIXBUF_CFLAGS} \
|
||||
${GLIB_CFLAGS} \
|
||||
${GUILE_INCS}
|
||||
|
||||
|
@ -18,9 +18,9 @@ AM_CPPFLAGS = \
|
||||
${GLADE_CFLAGS} \
|
||||
${GTK_CFLAGS} \
|
||||
${GNOME_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GNOME_PRINT_CFLAGS} \
|
||||
${GUILE_INCS} \
|
||||
${GOFFICE_CFLAGS}
|
||||
${QOF_CFLAGS}
|
||||
|
||||
libgncmod_gnome_utils_la_SOURCES = \
|
||||
QuickFill.c \
|
||||
@ -63,9 +63,6 @@ libgncmod_gnome_utils_la_SOURCES = \
|
||||
gnc-general-select.c \
|
||||
gnc-gnome-utils.c \
|
||||
gnc-gui-query.c \
|
||||
gnc-html-graph-gog.c \
|
||||
gnc-html-history.c \
|
||||
gnc-html.c \
|
||||
gnc-icons.c \
|
||||
gnc-main-window.c \
|
||||
gnc-menu-extensions.c \
|
||||
@ -134,9 +131,6 @@ gncinclude_HEADERS = \
|
||||
gnc-general-select.h \
|
||||
gnc-gnome-utils.h \
|
||||
gnc-gui-query.h \
|
||||
gnc-html-graph-gog.h \
|
||||
gnc-html-history.h \
|
||||
gnc-html.h \
|
||||
gnc-icons.h \
|
||||
gnc-main-window.h \
|
||||
gnc-menu-extensions.h \
|
||||
@ -186,14 +180,11 @@ libgncmod_gnome_utils_la_LIBADD = \
|
||||
$(top_builddir)/lib/libc/libc-missing.la \
|
||||
${top_builddir}/src/libqof/qof/libgnc-qof.la \
|
||||
${GNOME_LIBS} \
|
||||
${GTKHTML_LIBS} \
|
||||
${GUILE_LIBS} \
|
||||
${GDK_PIXBUF_LIBS} \
|
||||
${GNOME_PRINT_LIBS} \
|
||||
${GLADE_LIBS} \
|
||||
${GUILE_LIBS} \
|
||||
${GLIB_LIBS} \
|
||||
${DB_LIBS} \
|
||||
${GOFFICE_LIBS} \
|
||||
${REGEX_LIBS} \
|
||||
${LIBXML2_LIBS}
|
||||
|
||||
@ -202,7 +193,7 @@ if HAVE_X11_XLIB_H
|
||||
endif
|
||||
|
||||
if BUILDING_FROM_SVN
|
||||
swig-gnome-utils.c: gnome-utils.i gnc-html.h \
|
||||
swig-gnome-utils.c: gnome-utils.i \
|
||||
${top_srcdir}/src/base-typemaps.i
|
||||
$(SWIG) -guile $(SWIG_ARGS) -Linkage module \
|
||||
-I${top_srcdir}/src -o $@ $<
|
||||
@ -220,11 +211,6 @@ EXTRA_DIST = \
|
||||
${gncmod_DATA} \
|
||||
${gncscm_DATA}
|
||||
|
||||
if !GTKHTML_USES_GTKPRINT
|
||||
AM_CPPFLAGS += ${GNOME_PRINT_CFLAGS}
|
||||
libgncmod_gnome_utils_la_LIBADD += ${GNOME_PRINT_LIBS}
|
||||
endif
|
||||
|
||||
## We borrow guile's convention and use @-...-@ as the substitution
|
||||
## brackets here, instead of the usual @...@. This prevents autoconf
|
||||
## from substituting the values directly into the left-hand sides of
|
||||
|
@ -32,12 +32,12 @@
|
||||
#endif
|
||||
#include <libxml/xmlIO.h>
|
||||
|
||||
#include "gnc-html-graph-gog.h"
|
||||
//#include "gnc-html-graph-gog.h"
|
||||
|
||||
#include "druid-gconf-setup.h"
|
||||
#include "gnc-gconf-utils.h"
|
||||
#include "gnc-gnome-utils.h"
|
||||
#include "gnc-html.h"
|
||||
//#include "gnc-html.h"
|
||||
#include "gnc-engine.h"
|
||||
#include "gnc-path.h"
|
||||
#include "gnc-ui.h"
|
||||
|
@ -1,835 +0,0 @@
|
||||
/********************************************************************
|
||||
* gnc-html-graph-gog.c -- GNC/HTML Graphing support via GOG *
|
||||
* *
|
||||
* Copyright (C) 2005 Joshua Sled <jsled@asynchronous.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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtkhtml/gtkhtml.h>
|
||||
#include <gtkhtml/gtkhtml-embedded.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-ui-util.h"
|
||||
#include "gnc-html-graph-gog.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-engine.h"
|
||||
#include <goffice/goffice.h>
|
||||
#include <goffice/graph/gog-chart.h>
|
||||
#include <goffice/graph/gog-graph.h>
|
||||
#include <goffice/graph/gog-object.h>
|
||||
#if defined(HAVE_GOFFICE_0_5)
|
||||
# include <goffice/graph/gog-renderer.h>
|
||||
#elif defined(GOFFICE_WITH_CAIRO)
|
||||
# include <goffice/graph/gog-renderer-cairo.h>
|
||||
#else
|
||||
# include <goffice/graph/gog-renderer-pixbuf.h>
|
||||
#endif
|
||||
#ifndef GTKHTML_USES_GTKPRINT
|
||||
# include <goffice/graph/gog-renderer-gnome-print.h>
|
||||
#endif
|
||||
#include <goffice/graph/gog-style.h>
|
||||
#include <goffice/graph/gog-styled-object.h>
|
||||
#include <goffice/graph/gog-plot.h>
|
||||
#include <goffice/graph/gog-series.h>
|
||||
#include <goffice/utils/go-color.h>
|
||||
#include <goffice/utils/go-marker.h>
|
||||
#include <goffice/graph/gog-data-set.h>
|
||||
#include <goffice/data/go-data-simple.h>
|
||||
#include <goffice/app/go-plugin.h>
|
||||
#include <goffice/app/go-plugin-loader-module.h>
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* - scatter-plot marker selection
|
||||
* - series-color, piecharts (hard, not really supported by GOG)
|
||||
* and scatters (or drop feature)
|
||||
* - title-string freeing (fixmes)
|
||||
* - general graph cleanup
|
||||
**/
|
||||
|
||||
#undef G_LOG_DOMAIN
|
||||
#define G_LOG_DOMAIN "gnc.gui.html.graph.gog"
|
||||
|
||||
static int handle_piechart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer d);
|
||||
static int handle_barchart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer d);
|
||||
static int handle_linechart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer d);
|
||||
static int handle_scatter(gnc_html * html, GtkHTMLEmbedded * eb, gpointer d);
|
||||
|
||||
#ifdef GTKHTML_USES_GTKPRINT
|
||||
static void draw_print_cb(GtkHTMLEmbedded *eb, cairo_t *cr, gpointer graph);
|
||||
#else
|
||||
static void draw_print_cb(GtkHTMLEmbedded *eb, GnomePrintContext *context, gpointer graph);
|
||||
#endif
|
||||
|
||||
static gboolean create_basic_plot_elements(const char *plot_type, GogObject **out_graph, GogObject **out_chart, GogPlot **out_plot);
|
||||
|
||||
static double * read_doubles(const char * string, int nvalues);
|
||||
|
||||
static void set_chart_titles_from_hash(GogObject *chart, GtkHTMLEmbedded * eb);
|
||||
static void set_chart_titles(GogObject *chart, const char *title, const char* sub_title);
|
||||
static void set_chart_axis_labels_from_hash(GogObject *chart, GtkHTMLEmbedded * eb);
|
||||
static void set_chart_axis_labels(GogObject *chart, const char *x_axis_label, const char* y_axis_label);
|
||||
static void gtkhtml_pre_3_10_1_bug_workaround(GtkHTMLEmbedded *eb);
|
||||
|
||||
void
|
||||
gnc_html_graph_gog_init(void)
|
||||
{
|
||||
|
||||
g_debug( "init gog graphing" );
|
||||
|
||||
libgoffice_init();
|
||||
|
||||
/* Initialize plugins manager */
|
||||
go_plugins_init (NULL, NULL, NULL, NULL, TRUE, GO_PLUGIN_LOADER_MODULE_TYPE);
|
||||
|
||||
gnc_html_register_object_handler( "gnc-guppi-pie", handle_piechart );
|
||||
gnc_html_register_object_handler( "gnc-guppi-bar", handle_barchart );
|
||||
gnc_html_register_object_handler( "gnc-guppi-scatter", handle_scatter );
|
||||
gnc_html_register_object_handler( "gnc-guppi-line", handle_linechart );
|
||||
}
|
||||
|
||||
static double *
|
||||
read_doubles(const char * string, int nvalues)
|
||||
{
|
||||
int n;
|
||||
gchar *next;
|
||||
double * retval = g_new0(double, nvalues);
|
||||
|
||||
// guile is going to (puts ...) the elements of the double array
|
||||
// together. In non-POSIX locales, that will be in a format that
|
||||
// the locale-specific sscanf will not be able to parse.
|
||||
gnc_push_locale("C");
|
||||
{
|
||||
for (n=0; n<nvalues; n++) {
|
||||
retval[n] = strtod(string, &next);
|
||||
string = next;
|
||||
}
|
||||
}
|
||||
gnc_pop_locale();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static char **
|
||||
read_strings(const char * string, int nvalues)
|
||||
{
|
||||
int n;
|
||||
int choffset=0;
|
||||
int accum = 0;
|
||||
char ** retval = g_new0(char *, nvalues);
|
||||
char thischar;
|
||||
const char * inptr = string;
|
||||
int escaped = FALSE;
|
||||
|
||||
for (n=0; n < nvalues; n++) {
|
||||
retval[n] = g_new0(char, strlen(string+accum)+1);
|
||||
retval[n][0] = 0;
|
||||
choffset = 0;
|
||||
while ((thischar = *inptr) != 0) {
|
||||
if (thischar == '\\') {
|
||||
escaped = TRUE;
|
||||
inptr++;
|
||||
}
|
||||
else if ((thischar != ' ') || escaped) {
|
||||
retval[n][choffset] = thischar;
|
||||
retval[n][choffset+1] = 0;
|
||||
choffset++;
|
||||
escaped = FALSE;
|
||||
inptr++;
|
||||
}
|
||||
else {
|
||||
/* an unescaped space */
|
||||
escaped = FALSE;
|
||||
inptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
accum += choffset;
|
||||
/* printf("retval[%d] = '%s'\n", n, retval[n]); */
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
add_pixbuf_graph_widget( GtkHTMLEmbedded *eb, GogObject *graph )
|
||||
{
|
||||
GtkWidget *widget;
|
||||
#if defined(HAVE_GOFFICE_0_5)
|
||||
GogRenderer *renderer;
|
||||
#elif defined(GOFFICE_WITH_CAIRO)
|
||||
GogRendererCairo *cairo_renderer;
|
||||
#else
|
||||
GogRendererPixbuf *pixbuf_renderer;
|
||||
#endif
|
||||
GdkPixbuf *buf;
|
||||
gboolean update_status;
|
||||
|
||||
// Note that this shouldn't be necessary as per discussion with Jody...
|
||||
// ... but it is because we don't embed in a control which passes the
|
||||
// update requests back to the graph widget, a-la the foo-canvas that
|
||||
// gnumeric uses. We probably _should_ do something like that, though.
|
||||
gog_object_update (GOG_OBJECT (graph));
|
||||
|
||||
#if defined(HAVE_GOFFICE_0_5)
|
||||
renderer = GOG_RENDERER (g_object_new (GOG_RENDERER_TYPE,
|
||||
"model", graph,
|
||||
NULL));
|
||||
update_status = gog_renderer_update (renderer, eb->width, eb->height);
|
||||
buf = gog_renderer_get_pixbuf (renderer);
|
||||
#elif defined(GOFFICE_WITH_CAIRO)
|
||||
cairo_renderer = GOG_RENDERER_CAIRO (g_object_new (GOG_RENDERER_CAIRO_TYPE,
|
||||
"model", graph,
|
||||
NULL));
|
||||
update_status = gog_renderer_cairo_update (cairo_renderer,
|
||||
eb->width, eb->height, 1.0);
|
||||
buf = gog_renderer_cairo_get_pixbuf (cairo_renderer);
|
||||
#else
|
||||
pixbuf_renderer = GOG_RENDERER_PIXBUF (g_object_new (GOG_RENDERER_PIXBUF_TYPE,
|
||||
"model", graph,
|
||||
NULL));
|
||||
update_status = gog_renderer_pixbuf_update (pixbuf_renderer,
|
||||
eb->width, eb->height, 1.0);
|
||||
buf = gog_renderer_pixbuf_get (pixbuf_renderer);
|
||||
#endif
|
||||
|
||||
widget = gtk_image_new_from_pixbuf (buf);
|
||||
gtk_widget_set_size_request (widget, eb->width, eb->height);
|
||||
gtk_widget_show_all (widget);
|
||||
gtk_container_add (GTK_CONTAINER (eb), widget);
|
||||
|
||||
// blindly copied from gnc-html-guppi.c..
|
||||
gtk_widget_set_size_request (GTK_WIDGET (eb), eb->width, eb->height);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (eb), "graph", graph, g_object_unref);
|
||||
g_signal_connect (G_OBJECT (eb), "draw_print",
|
||||
G_CALLBACK (draw_print_cb), NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_basic_plot_elements(const char *plot_type_name,
|
||||
GogObject **out_graph,
|
||||
GogObject **out_chart,
|
||||
GogPlot **out_plot)
|
||||
{
|
||||
*out_graph = g_object_new(GOG_GRAPH_TYPE, NULL);
|
||||
*out_chart = gog_object_add_by_name(*out_graph, "Chart", NULL);
|
||||
*out_plot = gog_plot_new_by_name(plot_type_name);
|
||||
if (!*out_plot)
|
||||
{
|
||||
// FIXME - log betterer; should probably use GError?
|
||||
g_warning("gog: unable to load %s plugin", plot_type_name);
|
||||
return FALSE;
|
||||
}
|
||||
gog_object_add_by_name(*out_chart, "Plot", GOG_OBJECT(*out_plot) );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_titles_from_hash(GogObject *chart, GtkHTMLEmbedded * eb)
|
||||
{
|
||||
set_chart_titles(chart,
|
||||
(const char *)g_hash_table_lookup(eb->params, "title"),
|
||||
(const char *)g_hash_table_lookup(eb->params, "subtitle"));
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_titles(GogObject *chart, const char *title, const char* sub_title)
|
||||
{
|
||||
gchar *my_sub_title, *total_title;
|
||||
GOData *title_scalar;
|
||||
GogObject *tmp;
|
||||
|
||||
if (sub_title)
|
||||
my_sub_title = g_strdup_printf("%s(%s)", title ? " " : "", sub_title);
|
||||
else
|
||||
my_sub_title = g_strdup("");
|
||||
|
||||
total_title = g_strdup_printf("%s%s", title ? title : "", my_sub_title);
|
||||
|
||||
tmp = gog_object_add_by_name(chart, "Title", NULL);
|
||||
title_scalar = go_data_scalar_str_new(total_title, TRUE);
|
||||
gog_dataset_set_dim(GOG_DATASET(tmp), 0, title_scalar, NULL);
|
||||
|
||||
g_free(my_sub_title);
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_axis_labels_from_hash(GogObject *chart, GtkHTMLEmbedded * eb)
|
||||
{
|
||||
set_chart_axis_labels(chart,
|
||||
(const char *)g_hash_table_lookup(eb->params, "x_axis_label"),
|
||||
(const char *)g_hash_table_lookup(eb->params, "y_axis_label"));
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_axis_labels(GogObject *chart, const char *x_axis_label, const char* y_axis_label)
|
||||
{
|
||||
if (x_axis_label != NULL)
|
||||
{
|
||||
GogObject *xaxis, *label;
|
||||
GOData *data;
|
||||
xaxis = gog_object_get_child_by_role(chart, gog_object_find_role_by_name(chart, "X-Axis"));
|
||||
label = gog_object_add_by_name(xaxis, "Label", NULL);
|
||||
data = go_data_scalar_str_new(x_axis_label, FALSE);
|
||||
gog_dataset_set_dim(GOG_DATASET(label), 0, data, NULL);
|
||||
}
|
||||
|
||||
if (y_axis_label != NULL)
|
||||
{
|
||||
GogObject *yaxis, *label;
|
||||
GOData *data;
|
||||
yaxis = gog_object_get_child_by_role(chart, gog_object_find_role_by_name(chart, "Y-Axis"));
|
||||
label = gog_object_add_by_name(yaxis, "Label", NULL);
|
||||
data = go_data_scalar_str_new(y_axis_label, FALSE);
|
||||
gog_dataset_set_dim(GOG_DATASET(label), 0, data, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtkhtml_pre_3_10_1_bug_workaround(GtkHTMLEmbedded *eb)
|
||||
{
|
||||
/* HACK ALERT! Compensate for bug in gtkhtml < 3.10.1
|
||||
Gtkhtml set the width parameter twice (=width, =height), so both,
|
||||
width (==height) and height (<1) were incorrect. */
|
||||
if (eb->height < 1)
|
||||
{
|
||||
eb->height = eb->width; /* only squares here :( */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the following parameters:
|
||||
* title: text
|
||||
* subtitle: text
|
||||
* datasize: (length data), sscanf( .., %d, (int)&datasize )
|
||||
* data: (foreach (lambda (datum) (push datum) (push " ")) data)
|
||||
* colors: string; space-seperated?
|
||||
* labels: string; space-seperated?
|
||||
* slice_urls_[123]: ?
|
||||
* legend_urls_[123]: ?
|
||||
*/
|
||||
static gboolean
|
||||
handle_piechart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer unused)
|
||||
{
|
||||
GogObject *graph, *chart;
|
||||
GogPlot *plot;
|
||||
GogSeries *series;
|
||||
GOData *labelData, *sliceData;
|
||||
int datasize;
|
||||
double *data = NULL;
|
||||
char **labels = NULL, **colors = NULL;
|
||||
|
||||
gtkhtml_pre_3_10_1_bug_workaround(eb);
|
||||
|
||||
// parse data from the text-ized params.
|
||||
{
|
||||
char *datasizeStr, *dataStr, *labelsStr, *colorStr;
|
||||
|
||||
datasizeStr = g_hash_table_lookup(eb->params, "datasize");
|
||||
dataStr = g_hash_table_lookup(eb->params, "data" );
|
||||
labelsStr = g_hash_table_lookup(eb->params, "labels");
|
||||
colorStr = g_hash_table_lookup(eb->params, "colors");
|
||||
g_return_val_if_fail( datasizeStr != NULL
|
||||
&& dataStr != NULL
|
||||
&& labelsStr != NULL
|
||||
&& colorStr != NULL, FALSE );
|
||||
datasize = atoi( datasizeStr );
|
||||
data = read_doubles( dataStr, datasize );
|
||||
labels = read_strings( labelsStr, datasize );
|
||||
colors = read_strings( colorStr, datasize );
|
||||
}
|
||||
|
||||
if (!create_basic_plot_elements("GogPiePlot", &graph, &chart, &plot))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
gog_object_add_by_name(chart, "Legend", NULL);
|
||||
|
||||
GOG_STYLED_OBJECT(graph)->style->outline.width = 5;
|
||||
GOG_STYLED_OBJECT(graph)->style->outline.color = RGBA_BLACK;
|
||||
|
||||
series = gog_plot_new_series(plot);
|
||||
labelData = go_data_vector_str_new((char const * const *)labels, datasize, NULL);
|
||||
gog_series_set_dim(series, 0, labelData, NULL);
|
||||
go_data_emit_changed(GO_DATA(labelData));
|
||||
|
||||
sliceData = go_data_vector_val_new(data, datasize, NULL);
|
||||
gog_series_set_dim(series, 1, sliceData, NULL);
|
||||
go_data_emit_changed(GO_DATA(sliceData));
|
||||
|
||||
// fixme: colors
|
||||
set_chart_titles_from_hash(chart, eb);
|
||||
|
||||
add_pixbuf_graph_widget (eb, graph);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* data_rows:int
|
||||
* data_cols:int
|
||||
* data:doubles[], data_rows*data_cols
|
||||
* x_axis_label:string
|
||||
* y_axis_label:string
|
||||
* row_labels:string[]
|
||||
* col_labels:string[]
|
||||
* col_colors:string[]
|
||||
* rotate_row_labels:boolean
|
||||
* stacked:boolean
|
||||
**/
|
||||
static gboolean
|
||||
handle_barchart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer unused)
|
||||
{
|
||||
GogObject *graph, *chart;
|
||||
GogPlot *plot;
|
||||
GogSeries *series;
|
||||
GogStyle *style;
|
||||
GOData *label_data, *slice_data;
|
||||
int data_rows, data_cols;
|
||||
double *data = NULL;
|
||||
char **col_labels = NULL, **row_labels = NULL, **col_colors = NULL;
|
||||
gboolean rotate_row_labels = FALSE;
|
||||
gboolean stacked = FALSE;
|
||||
char *bar_type = "normal";
|
||||
int bar_overlap = 0 /*percent*/; // seperate bars; no overlap.
|
||||
|
||||
gtkhtml_pre_3_10_1_bug_workaround (eb);
|
||||
|
||||
// parse data from the text-ized params
|
||||
// series => bars [gnc:cols]
|
||||
// series-elements => segments [gnc:rows]
|
||||
{
|
||||
char *data_rows_str, *data_cols_str, *data_str, *col_labels_str, *row_labels_str;
|
||||
char *col_colors_str, *rotate_row_labels_str = NULL, *stacked_str = NULL;
|
||||
|
||||
data_rows_str = g_hash_table_lookup (eb->params, "data_rows");
|
||||
data_cols_str = g_hash_table_lookup (eb->params, "data_cols");
|
||||
data_str = g_hash_table_lookup (eb->params, "data" );
|
||||
row_labels_str = g_hash_table_lookup (eb->params, "row_labels");
|
||||
col_labels_str = g_hash_table_lookup (eb->params, "col_labels");
|
||||
col_colors_str = g_hash_table_lookup (eb->params, "col_colors");
|
||||
rotate_row_labels_str = g_hash_table_lookup (eb->params, "rotate_row_labels");
|
||||
stacked_str = g_hash_table_lookup (eb->params, "stacked");
|
||||
|
||||
rotate_row_labels = (gboolean) atoi (rotate_row_labels_str);
|
||||
stacked = (gboolean) atoi (stacked_str);
|
||||
|
||||
#if 0 // too strong at the moment.
|
||||
g_return_val_if_fail (data_rows_str != NULL
|
||||
&& data_cols_str != NULL
|
||||
&& data_str != NULL
|
||||
&& col_labels_str != NULL
|
||||
&& row_labels_str != NULL
|
||||
&& col_colors_str != NULL, FALSE );
|
||||
#endif // 0
|
||||
data_rows = atoi (data_rows_str);
|
||||
data_cols = atoi (data_cols_str);
|
||||
data = read_doubles (data_str, data_rows*data_cols);
|
||||
row_labels = read_strings (row_labels_str, data_rows);
|
||||
col_labels = read_strings (col_labels_str, data_cols);
|
||||
col_colors = read_strings (col_colors_str, data_cols);
|
||||
}
|
||||
|
||||
if (!create_basic_plot_elements("GogBarColPlot", &graph, &chart, &plot)) {
|
||||
return FALSE;
|
||||
}
|
||||
gog_object_add_by_name(chart, "Legend", NULL);
|
||||
|
||||
if ( stacked ) {
|
||||
// when stacked, we want the bars on _top_ of eachother.
|
||||
bar_type = "stacked";
|
||||
bar_overlap = 100 /*percent*/;
|
||||
}
|
||||
|
||||
g_object_set (G_OBJECT (plot),
|
||||
//"vary_style_by_element", TRUE,
|
||||
"type", bar_type,
|
||||
"overlap_percentage", bar_overlap,
|
||||
NULL);
|
||||
label_data = go_data_vector_str_new ((char const * const *)row_labels, data_rows, NULL);
|
||||
{
|
||||
// foreach row:
|
||||
// series = row
|
||||
GdkColor color;
|
||||
int i;
|
||||
for (i = 0; i < data_cols; i++) {
|
||||
GError *err = NULL;
|
||||
|
||||
series = gog_plot_new_series (plot);
|
||||
gog_object_set_name (GOG_OBJECT (series), col_labels[i], &err);
|
||||
if (err != NULL)
|
||||
{
|
||||
g_warning("error setting name [%s] on series [%d]: [%s]",
|
||||
col_labels[i], i, err->message);
|
||||
}
|
||||
|
||||
g_object_ref (label_data);
|
||||
gog_series_set_dim (series, 0, label_data, NULL);
|
||||
go_data_emit_changed (GO_DATA (label_data));
|
||||
|
||||
slice_data = go_data_vector_val_new (data + (i*data_rows), data_rows, NULL);
|
||||
gog_series_set_dim (series, 1, slice_data, NULL);
|
||||
go_data_emit_changed (GO_DATA (slice_data));
|
||||
|
||||
style = gog_styled_object_get_style (GOG_STYLED_OBJECT (series));
|
||||
style->fill.type = GOG_FILL_STYLE_PATTERN;
|
||||
if (gdk_color_parse (col_colors[i], &color)) {
|
||||
style->fill.auto_back = FALSE;
|
||||
go_pattern_set_solid (&style->fill.pattern, GDK_TO_UINT (color));
|
||||
} else {
|
||||
g_warning("cannot parse color [%s]", col_colors[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rotate_row_labels) {
|
||||
GogObject *object = gog_object_get_child_by_role (
|
||||
chart, gog_object_find_role_by_name (chart, "X-Axis"));
|
||||
style = gog_styled_object_get_style (GOG_STYLED_OBJECT (object));
|
||||
gog_style_set_text_angle (style, 90.0);
|
||||
}
|
||||
|
||||
set_chart_titles_from_hash (chart, eb);
|
||||
set_chart_axis_labels_from_hash (chart, eb);
|
||||
|
||||
// we need to do this twice for the barchart... :p
|
||||
gog_object_update (GOG_OBJECT (graph));
|
||||
|
||||
add_pixbuf_graph_widget (eb, graph);
|
||||
|
||||
g_debug("barchart rendered.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* data_rows:int
|
||||
* data_cols:int
|
||||
* data:doubles[], data_rows*data_cols
|
||||
* x_axis_label:string
|
||||
* y_axis_label:string
|
||||
* row_labels:string[]
|
||||
* col_labels:string[]
|
||||
* col_colors:string[]
|
||||
* rotate_row_labels:boolean
|
||||
* stacked:boolean
|
||||
* markers:boolean
|
||||
* major_grid:boolean
|
||||
* minor_grid:boolean
|
||||
**/
|
||||
static gboolean
|
||||
handle_linechart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer unused)
|
||||
{
|
||||
GogObject *graph, *chart;
|
||||
GogPlot *plot;
|
||||
GogSeries *series;
|
||||
GogStyle *style;
|
||||
GOData *label_data, *slice_data;
|
||||
int data_rows, data_cols;
|
||||
double *data = NULL;
|
||||
char **col_labels = NULL, **row_labels = NULL, **col_colors = NULL;
|
||||
gboolean rotate_row_labels = FALSE;
|
||||
gboolean stacked = FALSE;
|
||||
gboolean markers = FALSE;
|
||||
gboolean major_grid = FALSE;
|
||||
gboolean minor_grid = FALSE;
|
||||
char *line_type = "normal";
|
||||
|
||||
gtkhtml_pre_3_10_1_bug_workaround (eb);
|
||||
|
||||
// parse data from the text-ized params
|
||||
// series => lines [gnc:cols]
|
||||
// series-elements => segments [gnc:rows]
|
||||
{
|
||||
char *data_rows_str, *data_cols_str, *data_str, *col_labels_str, *row_labels_str;
|
||||
char *col_colors_str, *rotate_row_labels_str = NULL, *stacked_str = NULL, *markers_str = NULL;
|
||||
char *major_grid_str = NULL, *minor_grid_str = NULL;
|
||||
|
||||
data_rows_str = g_hash_table_lookup (eb->params, "data_rows");
|
||||
data_cols_str = g_hash_table_lookup (eb->params, "data_cols");
|
||||
data_str = g_hash_table_lookup (eb->params, "data" );
|
||||
row_labels_str = g_hash_table_lookup (eb->params, "row_labels");
|
||||
col_labels_str = g_hash_table_lookup (eb->params, "col_labels");
|
||||
col_colors_str = g_hash_table_lookup (eb->params, "col_colors");
|
||||
rotate_row_labels_str = g_hash_table_lookup (eb->params, "rotate_row_labels");
|
||||
stacked_str = g_hash_table_lookup (eb->params, "stacked");
|
||||
markers_str = g_hash_table_lookup (eb->params, "markers");
|
||||
major_grid_str = g_hash_table_lookup (eb->params, "major_grid");
|
||||
minor_grid_str = g_hash_table_lookup (eb->params, "minor_grid");
|
||||
|
||||
rotate_row_labels = (gboolean) atoi (rotate_row_labels_str);
|
||||
stacked = (gboolean) atoi (stacked_str);
|
||||
markers = (gboolean) atoi (markers_str);
|
||||
major_grid = (gboolean) atoi (major_grid_str);
|
||||
minor_grid = (gboolean) atoi (minor_grid_str);
|
||||
|
||||
#if 0 // too strong at the moment.
|
||||
g_return_val_if_fail (data_rows_str != NULL
|
||||
&& data_cols_str != NULL
|
||||
&& data_str != NULL
|
||||
&& col_labels_str != NULL
|
||||
&& row_labels_str != NULL
|
||||
&& col_colors_str != NULL, FALSE );
|
||||
#endif // 0
|
||||
|
||||
data_rows = atoi (data_rows_str);
|
||||
data_cols = atoi (data_cols_str);
|
||||
data = read_doubles (data_str, data_rows*data_cols);
|
||||
row_labels = read_strings (row_labels_str, data_rows);
|
||||
col_labels = read_strings (col_labels_str, data_cols);
|
||||
col_colors = read_strings (col_colors_str, data_cols);
|
||||
}
|
||||
|
||||
if (!create_basic_plot_elements("GogLinePlot", &graph, &chart, &plot)) {
|
||||
return FALSE;
|
||||
}
|
||||
gog_object_add_by_name(chart, "Legend", NULL);
|
||||
|
||||
if ( stacked ) {
|
||||
// when stacked, we want the lines on _top_ of eachother.
|
||||
line_type = "stacked";
|
||||
}
|
||||
|
||||
g_object_set (G_OBJECT (plot),
|
||||
//"vary_style_by_element", TRUE,
|
||||
"type", line_type,
|
||||
"default-style-has-markers", markers,
|
||||
NULL);
|
||||
label_data = go_data_vector_str_new ((char const * const *)row_labels, data_rows, NULL);
|
||||
{
|
||||
// foreach row:
|
||||
// series = row
|
||||
GdkColor color;
|
||||
int i;
|
||||
for (i = 0; i < data_cols; i++) {
|
||||
GError *err = NULL;
|
||||
|
||||
series = gog_plot_new_series (plot);
|
||||
gog_object_set_name (GOG_OBJECT (series), col_labels[i], &err);
|
||||
if (err != NULL)
|
||||
{
|
||||
g_warning("error setting name [%s] on series [%d]: [%s]",
|
||||
col_labels[i], i, err->message);
|
||||
}
|
||||
|
||||
g_object_ref (label_data);
|
||||
gog_series_set_dim (series, 0, label_data, NULL);
|
||||
go_data_emit_changed (GO_DATA (label_data));
|
||||
|
||||
slice_data = go_data_vector_val_new (data + (i*data_rows), data_rows, NULL);
|
||||
gog_series_set_dim (series, 1, slice_data, NULL);
|
||||
go_data_emit_changed (GO_DATA (slice_data));
|
||||
|
||||
style = gog_styled_object_get_style (GOG_STYLED_OBJECT (series));
|
||||
style->fill.type = GOG_FILL_STYLE_PATTERN;
|
||||
if (gdk_color_parse (col_colors[i], &color)) {
|
||||
style->fill.auto_back = FALSE;
|
||||
go_pattern_set_solid (&style->fill.pattern, GDK_TO_UINT (color));
|
||||
} else {
|
||||
g_warning("cannot parse color [%s]", col_colors[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rotate_row_labels) {
|
||||
GogObject *object = gog_object_get_child_by_role (
|
||||
chart, gog_object_find_role_by_name (chart, "X-Axis"));
|
||||
style = gog_styled_object_get_style (GOG_STYLED_OBJECT (object));
|
||||
gog_style_set_text_angle (style, 90.0);
|
||||
}
|
||||
|
||||
if (major_grid || minor_grid) {
|
||||
GogObject *object;
|
||||
gog_object_add_by_name(chart,"Grid", NULL);
|
||||
object = gog_object_get_child_by_role (chart, gog_object_find_role_by_name (chart, "Y-Axis"));
|
||||
if (major_grid)
|
||||
gog_object_add_by_name (GOG_OBJECT (object),"MajorGrid", NULL);
|
||||
if (minor_grid)
|
||||
gog_object_add_by_name (GOG_OBJECT (object),"MinorGrid", NULL);
|
||||
}
|
||||
|
||||
set_chart_titles_from_hash (chart, eb);
|
||||
set_chart_axis_labels_from_hash (chart, eb);
|
||||
|
||||
// we need to do this twice for the linechart... :p
|
||||
gog_object_update (GOG_OBJECT (graph));
|
||||
|
||||
add_pixbuf_graph_widget (eb, graph);
|
||||
|
||||
g_debug("linechart rendered.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
handle_scatter(gnc_html * html, GtkHTMLEmbedded * eb, gpointer unused)
|
||||
{
|
||||
GogObject *graph, *chart;
|
||||
GogPlot *plot;
|
||||
GogSeries *series;
|
||||
GOData *sliceData;
|
||||
GogStyle *style;
|
||||
int datasize;
|
||||
double *xData, *yData;
|
||||
gchar *marker_str, *color_str;
|
||||
gboolean fill = FALSE;
|
||||
|
||||
gtkhtml_pre_3_10_1_bug_workaround(eb);
|
||||
|
||||
{
|
||||
char *datasizeStr, *xDataStr, *yDataStr;
|
||||
|
||||
datasizeStr = g_hash_table_lookup( eb->params, "datasize" );
|
||||
datasize = atoi( datasizeStr );
|
||||
|
||||
xDataStr = g_hash_table_lookup( eb->params, "x_data" );
|
||||
xData = read_doubles( xDataStr, datasize );
|
||||
|
||||
yDataStr = g_hash_table_lookup( eb->params, "y_data" );
|
||||
yData = read_doubles( yDataStr, datasize );
|
||||
|
||||
marker_str = g_hash_table_lookup(eb->params, "marker");
|
||||
color_str = g_hash_table_lookup(eb->params, "color");
|
||||
}
|
||||
|
||||
if (!create_basic_plot_elements("GogXYPlot", &graph, &chart, &plot))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
series = gog_plot_new_series( plot );
|
||||
style = gog_styled_object_get_style(GOG_STYLED_OBJECT(series));
|
||||
|
||||
sliceData = go_data_vector_val_new( xData, datasize, NULL );
|
||||
gog_series_set_dim( series, 0, sliceData, NULL );
|
||||
go_data_emit_changed (GO_DATA (sliceData));
|
||||
|
||||
sliceData = go_data_vector_val_new( yData, datasize, NULL );
|
||||
gog_series_set_dim( series, 1, sliceData, NULL );
|
||||
go_data_emit_changed (GO_DATA (sliceData));
|
||||
|
||||
/* set marker shape */
|
||||
if (marker_str) {
|
||||
GOMarkerShape shape;
|
||||
|
||||
if (g_str_has_prefix(marker_str, "filled ")) {
|
||||
fill = TRUE;
|
||||
marker_str += 7;
|
||||
}
|
||||
shape = go_marker_shape_from_str(marker_str);
|
||||
if (shape != GO_MARKER_NONE) {
|
||||
style->marker.auto_shape = FALSE;
|
||||
go_marker_set_shape(style->marker.mark, shape);
|
||||
} else {
|
||||
g_warning("cannot parse marker shape [%s]", marker_str);
|
||||
}
|
||||
}
|
||||
|
||||
/* set marker and line colors */
|
||||
if (color_str) {
|
||||
GdkColor color;
|
||||
if (gdk_color_parse(color_str, &color)) {
|
||||
style->marker.auto_outline_color = FALSE;
|
||||
go_marker_set_outline_color(style->marker.mark, GDK_TO_UINT(color));
|
||||
style->line.auto_color = FALSE;
|
||||
style->line.color = GDK_TO_UINT(color);
|
||||
} else {
|
||||
g_warning("cannot parse color [%s]", color_str);
|
||||
}
|
||||
}
|
||||
|
||||
/* set marker fill colors */
|
||||
if (fill) {
|
||||
style->marker.auto_fill_color = style->marker.auto_outline_color;
|
||||
go_marker_set_fill_color(style->marker.mark,
|
||||
go_marker_get_outline_color(style->marker.mark));
|
||||
} else {
|
||||
GogStyle *chart_style =
|
||||
gog_styled_object_get_style(GOG_STYLED_OBJECT(chart));
|
||||
|
||||
if (chart_style->fill.type == GOG_FILL_STYLE_PATTERN
|
||||
&& chart_style->fill.pattern.pattern == GO_PATTERN_SOLID) {
|
||||
style->marker.auto_fill_color = FALSE;
|
||||
go_marker_set_fill_color(style->marker.mark,
|
||||
chart_style->fill.pattern.back);
|
||||
} else if (chart_style->fill.type == GOG_FILL_STYLE_PATTERN
|
||||
&& chart_style->fill.pattern.pattern
|
||||
== GO_PATTERN_FOREGROUND_SOLID) {
|
||||
style->marker.auto_fill_color = FALSE;
|
||||
go_marker_set_fill_color(style->marker.mark,
|
||||
chart_style->fill.pattern.fore);
|
||||
} else {
|
||||
g_warning("fill color of markers can only be set like a solid fill "
|
||||
"pattern of the chart");
|
||||
}
|
||||
}
|
||||
|
||||
set_chart_titles_from_hash(chart, eb);
|
||||
set_chart_axis_labels_from_hash(chart, eb);
|
||||
|
||||
// And twice for the scatter, too... :p
|
||||
gog_object_update(GOG_OBJECT(graph));
|
||||
|
||||
add_pixbuf_graph_widget (eb, graph);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef GTKHTML_USES_GTKPRINT
|
||||
static void
|
||||
draw_print_cb(GtkHTMLEmbedded *eb, cairo_t *cr, gpointer unused)
|
||||
{
|
||||
GogGraph *graph = GOG_GRAPH(g_object_get_data(G_OBJECT(eb), "graph"));
|
||||
# ifdef HAVE_GOFFICE_0_5
|
||||
GogRenderer *rend = g_object_new(GOG_RENDERER_TYPE, "model", graph, NULL);
|
||||
# else
|
||||
GogRendererCairo *rend = g_object_new(GOG_RENDERER_CAIRO_TYPE, "model", graph,
|
||||
"cairo", cr, "is-vector", TRUE, NULL);
|
||||
# endif
|
||||
|
||||
/* assuming pixel size is 0.5, cf. gtkhtml/src/htmlprinter.c */
|
||||
cairo_scale(cr, 0.5, 0.5);
|
||||
|
||||
cairo_translate(cr, 0, -eb->height);
|
||||
|
||||
# ifdef HAVE_GOFFICE_0_5
|
||||
gog_renderer_render_to_cairo(rend, cr, eb->width, eb->height);
|
||||
# else
|
||||
gog_renderer_cairo_update(rend, eb->width, eb->height, 1.0);
|
||||
# endif
|
||||
g_object_unref(rend);
|
||||
}
|
||||
|
||||
#else /* !GTKHTML_USES_GTKPRINT */
|
||||
static void
|
||||
draw_print_cb(GtkHTMLEmbedded *eb, GnomePrintContext *context, gpointer unused)
|
||||
{
|
||||
GogGraph *graph = GOG_GRAPH (g_object_get_data (G_OBJECT (eb), "graph"));
|
||||
|
||||
/* assuming pixel size is 0.5, cf. gtkhtml/src/htmlprinter.c */
|
||||
gnome_print_scale (context, 0.5, 0.5);
|
||||
|
||||
gnome_print_translate (context, 0, eb->height);
|
||||
gog_graph_print_to_gnome_print (graph, context, eb->width, eb->height);
|
||||
}
|
||||
#endif /* GTKHTML_USES_GTKPRINT */
|
@ -1,6 +0,0 @@
|
||||
#ifndef GNC_HTML_GRAPH_GOG_H
|
||||
#define GNC_HTML_GRAPH_GOG_H 1
|
||||
|
||||
void gnc_html_graph_gog_init(void);
|
||||
|
||||
#endif /* GNC_HTML_GRAPH_GOG_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,171 +0,0 @@
|
||||
/********************************************************************
|
||||
* gnc-html.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_H
|
||||
#define GNC_HTML_H
|
||||
|
||||
#include <gtkhtml/gtkhtml.h>
|
||||
|
||||
typedef char * URLType;
|
||||
|
||||
#define URL_TYPE_FILE "file"
|
||||
#define URL_TYPE_JUMP "jump"
|
||||
#define URL_TYPE_HTTP "http"
|
||||
#define URL_TYPE_FTP "ftp"
|
||||
#define URL_TYPE_SECURE "secure"
|
||||
#define URL_TYPE_REGISTER "register" /* for gnucash register popups */
|
||||
#define URL_TYPE_ACCTTREE "accttree" /* for account tree windows */
|
||||
#define URL_TYPE_REPORT "report" /* for gnucash report popups */
|
||||
#define URL_TYPE_OPTIONS "options" /* for editing report options */
|
||||
#define URL_TYPE_SCHEME "scheme" /* for scheme code evaluation */
|
||||
#define URL_TYPE_HELP "help" /* for a gnucash help window */
|
||||
#define URL_TYPE_XMLDATA "xmldata" /* links to gnucash XML data files */
|
||||
#define URL_TYPE_PRICE "price" /* for price editor popups */
|
||||
#define URL_TYPE_OTHER "other"
|
||||
#define URL_TYPE_BUDGET "budget"
|
||||
|
||||
#include "gnc-html-history.h"
|
||||
|
||||
typedef struct gnc_html_struct gnc_html;
|
||||
|
||||
/* The result structure of url handlers. Strings should be g_malloc'd
|
||||
* by the handler and will be freed by gnc_html. */
|
||||
typedef struct
|
||||
{
|
||||
/* The following members are used if the handler succeeds (returns TRUE). */
|
||||
|
||||
gboolean load_to_stream; /* If TRUE, the url should be loaded from
|
||||
* a stream using the rest of the data in
|
||||
* the struct into the original gnc_html
|
||||
* object. If FALSE, the handler will
|
||||
* perform all needed actions itself. */
|
||||
|
||||
URLType url_type; /* Defaults to original */
|
||||
char * location; /* If NULL, use original (NULL is default) */
|
||||
char * label; /* If NULL, use original (NULL is default) */
|
||||
|
||||
URLType base_type;
|
||||
char * base_location;
|
||||
|
||||
/* The following members are used if the handler fails (returns FALSE). */
|
||||
char * error_message;
|
||||
} GNCURLResult;
|
||||
|
||||
typedef int (* GncHTMLUrltypeCB)(URLType ut);
|
||||
typedef void (* GncHTMLFlyoverCB)(gnc_html * html, const char * url,
|
||||
gpointer data);
|
||||
typedef void (* GncHTMLLoadCB)(gnc_html * html, URLType type,
|
||||
const char * location, const char * label,
|
||||
gpointer data);
|
||||
typedef int (* GncHTMLButtonCB)(gnc_html * html, GdkEventButton * event,
|
||||
gpointer data);
|
||||
|
||||
typedef gboolean (* GncHTMLObjectCB)(gnc_html * html, GtkHTMLEmbedded * eb,
|
||||
gpointer data);
|
||||
typedef int (* GncHTMLActionCB)(gnc_html * html, const char * method,
|
||||
const char * action, GHashTable * form_data);
|
||||
typedef gboolean (* GncHTMLStreamCB)(const char *location, char **data, int *datalen);
|
||||
typedef gboolean (* GncHTMLUrlCB)(const char *location, const char *label,
|
||||
gboolean new_window, GNCURLResult * result);
|
||||
|
||||
gnc_html * gnc_html_new(GtkWindow *parent);
|
||||
void gnc_html_destroy(gnc_html * html);
|
||||
void gnc_html_show_url(gnc_html * html,
|
||||
URLType type,
|
||||
const char * location,
|
||||
const char * label,
|
||||
gboolean new_window_hint);
|
||||
void gnc_html_show_data(gnc_html * html,
|
||||
const char * data, int datalen);
|
||||
void gnc_html_reload(gnc_html * html);
|
||||
void gnc_html_copy(gnc_html *html);
|
||||
gboolean gnc_html_export(gnc_html * html, const char *file);
|
||||
void gnc_html_print(gnc_html * html);
|
||||
void gnc_html_cancel(gnc_html * html);
|
||||
|
||||
char * gnc_build_url (URLType type, const gchar * location,
|
||||
const gchar * label);
|
||||
|
||||
/* Register a new URLType.
|
||||
* returns TRUE if succesful, FALSE if type already exists.
|
||||
*
|
||||
* protocol should be an empty string if there is no corresponding protocol.
|
||||
* if protocol is NULL, this function returns FALSE.
|
||||
*/
|
||||
gboolean gnc_html_register_urltype (URLType type, const char *protocol);
|
||||
|
||||
/* object handlers deal with <object classid="foo"> objects in HTML.
|
||||
* the handlers are looked up at object load time. */
|
||||
//#if 0
|
||||
void gnc_html_register_object_handler(const char * classid,
|
||||
GncHTMLObjectCB hand);
|
||||
//#endif
|
||||
void gnc_html_unregister_object_handler(const char * classid);
|
||||
|
||||
/* action handlers deal with submitting forms of the type
|
||||
* <FORM action="gnc-action:action?args">. Normal get/post http:
|
||||
* forms are handled as would be expected, with no callback. */
|
||||
void gnc_html_register_action_handler(const char * action,
|
||||
GncHTMLActionCB hand);
|
||||
void gnc_html_unregister_action_handler(const char * action);
|
||||
|
||||
/* stream handlers load data for particular URLTypes. */
|
||||
void gnc_html_register_stream_handler(URLType url_type,
|
||||
GncHTMLStreamCB hand);
|
||||
void gnc_html_unregister_stream_handler(URLType url_type);
|
||||
|
||||
/* handlers for particular URLTypes. */
|
||||
void gnc_html_register_url_handler(URLType url_type,
|
||||
GncHTMLUrlCB hand);
|
||||
void gnc_html_unregister_url_handler(URLType url_type);
|
||||
|
||||
URLType gnc_html_parse_url(gnc_html * html, const gchar * url,
|
||||
char ** url_location, char ** url_label);
|
||||
|
||||
/* some string coding/decoding routines */
|
||||
char * gnc_html_encode_string(const char * in);
|
||||
char * gnc_html_decode_string(const char * in);
|
||||
char * gnc_html_escape_newlines(const char * in);
|
||||
char * gnc_html_unescape_newlines(const char * in);
|
||||
|
||||
/* utilities for dealing with encoded argument strings for forms */
|
||||
char * gnc_html_pack_form_data(GHashTable * form_data);
|
||||
GHashTable * gnc_html_unpack_form_data(const char * encoding);
|
||||
void gnc_html_merge_form_data(GHashTable * fdata, const char * enc);
|
||||
void gnc_html_free_form_data(GHashTable * fdata);
|
||||
|
||||
gnc_html_history * gnc_html_get_history(gnc_html * html);
|
||||
GtkWidget * gnc_html_get_widget(gnc_html * html);
|
||||
|
||||
/* setting callbacks */
|
||||
void gnc_html_set_urltype_cb(gnc_html * html, GncHTMLUrltypeCB urltype_cb);
|
||||
void gnc_html_set_load_cb(gnc_html * html, GncHTMLLoadCB load_cb,
|
||||
gpointer data);
|
||||
void gnc_html_set_flyover_cb(gnc_html * html, GncHTMLFlyoverCB newwin_cb,
|
||||
gpointer data);
|
||||
void gnc_html_set_button_cb(gnc_html * html, GncHTMLButtonCB button_cb,
|
||||
gpointer data);
|
||||
|
||||
/* Initialize the html subsystem */
|
||||
void gnc_html_initialize (void);
|
||||
|
||||
#endif
|
@ -65,7 +65,7 @@
|
||||
#include "gnc-main.h"
|
||||
#include "gnc-gconf-utils.h"
|
||||
// +JSLED
|
||||
#include "gnc-html.h"
|
||||
//#include "gnc-html.h"
|
||||
#include "gnc-autosave.h"
|
||||
#ifdef HAVE_GTK_2_10
|
||||
# include "print-session.h"
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "gnc-module-api.h"
|
||||
|
||||
#include "dialog-options.h"
|
||||
#include "gnc-html.h"
|
||||
#include "qof.h"
|
||||
#include "gnc-gui-query.h"
|
||||
|
||||
@ -77,7 +76,6 @@ libgncmod_gnome_utils_gnc_module_init(int refcount) {
|
||||
/* Initialize the options-ui database */
|
||||
if (refcount == 0) {
|
||||
gnc_options_ui_initialize ();
|
||||
gnc_html_initialize ();
|
||||
|
||||
/* register the druid pieces */
|
||||
gnc_druid_gnome_register();
|
||||
|
@ -3,6 +3,7 @@
|
||||
/* Includes the header in the wrapper code */
|
||||
#include <config.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib-object.h>
|
||||
#include <dialog-options.h>
|
||||
#include <dialog-utils.h>
|
||||
#include <druid-utils.h>
|
||||
@ -11,7 +12,6 @@
|
||||
#include <gnc-file.h>
|
||||
#include <gnc-gnome-utils.h>
|
||||
#include <gnc-gui-query.h>
|
||||
#include <gnc-html.h>
|
||||
#include <gnc-main-window.h>
|
||||
#include <gnc-window.h>
|
||||
#include <gnc-menu-extensions.h>
|
||||
@ -24,10 +24,6 @@ SCM scm_init_sw_gnome_utils_module (void);
|
||||
|
||||
%import "base-typemaps.i"
|
||||
|
||||
/* Parse the header file to generate wrappers */
|
||||
%include "gnc-html.h"
|
||||
|
||||
|
||||
GNCOptionWin * gnc_options_dialog_new(gchar *title);
|
||||
void gnc_options_dialog_destroy(GNCOptionWin * win);
|
||||
void gnc_options_dialog_build_contents(GNCOptionWin *propertybox,
|
||||
@ -56,30 +52,3 @@ void gnc_unset_busy_cursor (GtkWidget *w);
|
||||
void gnc_window_show_progress (const char *message, double percentage);
|
||||
|
||||
gboolean gnucash_ui_is_running(void);
|
||||
|
||||
%init {
|
||||
{
|
||||
char tmp[100];
|
||||
|
||||
#define SET_ENUM(e) snprintf(tmp, 100, "(set! %s (%s))", (e), (e)); \
|
||||
scm_c_eval_string(tmp);
|
||||
|
||||
SET_ENUM("URL-TYPE-FILE");
|
||||
SET_ENUM("URL-TYPE-JUMP");
|
||||
SET_ENUM("URL-TYPE-HTTP");
|
||||
SET_ENUM("URL-TYPE-FTP");
|
||||
SET_ENUM("URL-TYPE-SECURE");
|
||||
SET_ENUM("URL-TYPE-REGISTER");
|
||||
SET_ENUM("URL-TYPE-ACCTTREE");
|
||||
SET_ENUM("URL-TYPE-REPORT");
|
||||
SET_ENUM("URL-TYPE-OPTIONS");
|
||||
SET_ENUM("URL-TYPE-SCHEME");
|
||||
SET_ENUM("URL-TYPE-HELP");
|
||||
SET_ENUM("URL-TYPE-XMLDATA");
|
||||
SET_ENUM("URL-TYPE-PRICE");
|
||||
SET_ENUM("URL-TYPE-OTHER");
|
||||
|
||||
#undefine SET_ENUM
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,13 +12,15 @@ libgnc_gnome_la_LIBADD = \
|
||||
${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
|
||||
${top_builddir}/src/backend/xml/libgnc-backend-xml-utils.la \
|
||||
${top_builddir}/src/app-utils/libgncmod-app-utils.la \
|
||||
${top_builddir}/src/html/libgncmod-html.la \
|
||||
${top_builddir}/src/engine/libgncmod-engine.la \
|
||||
${top_builddir}/src/core-utils/libgnc-core-utils.la \
|
||||
${top_builddir}/src/libqof/qof/libgnc-qof.la \
|
||||
${GLADE_LIBS} \
|
||||
${GUILE_LIBS} \
|
||||
${GNOME_LIBS} \
|
||||
${GLIB_LIBS}
|
||||
${GLIB_LIBS} \
|
||||
${QOF_LIBS}
|
||||
|
||||
libgnc_gnome_la_SOURCES = \
|
||||
swig-gnome.c \
|
||||
@ -112,6 +114,7 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/backend/xml \
|
||||
-I${top_srcdir}/src/gnome-utils \
|
||||
-I${top_srcdir}/src/gnome-search \
|
||||
-I${top_srcdir}/src/html \
|
||||
-I${top_srcdir}/src/register/ledger-core \
|
||||
-I${top_srcdir}/src/register/register-core \
|
||||
-I${top_srcdir}/src/register/register-gnome \
|
||||
@ -121,8 +124,7 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${GUILE_INCS} \
|
||||
${GNOME_CFLAGS} \
|
||||
${GDK_PIXBUF_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GNOME_PRINT_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
$(GLIB_CFLAGS)
|
||||
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include "gnc-gconf-utils.h"
|
||||
#include "gnc-gnome-utils.h"
|
||||
#include "gnc-gobject-utils.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-icons.h"
|
||||
#include "gnc-plugin-account-tree.h"
|
||||
#include "gnc-session.h"
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "dialog-options.h"
|
||||
#include "dialog-utils.h"
|
||||
#include "gnc-gnome-utils.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-icons.h"
|
||||
#include "gnc-plugin-page-budget.h"
|
||||
#include "gnc-plugin-budget.h"
|
||||
|
110
src/html/Makefile.am
Normal file
110
src/html/Makefile.am
Normal file
@ -0,0 +1,110 @@
|
||||
#SUBDIRS = . test
|
||||
SUBDIRS = .
|
||||
|
||||
pkglib_LTLIBRARIES = libgncmod-html.la
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/core-utils \
|
||||
-I${top_srcdir}/src/gnc-module \
|
||||
-I${top_srcdir}/src/engine \
|
||||
-I${top_srcdir}/src/gnome-utils \
|
||||
-I${top_srcdir}/src/app-utils \
|
||||
-I${top_srcdir}/src \
|
||||
-I${top_builddir}/src \
|
||||
-I${top_srcdir}/lib/libc \
|
||||
${QOF_CFLAGS} \
|
||||
${GLIB_CFLAGS} \
|
||||
${GTK_CFLAGS} \
|
||||
${GNOME_CFLAGS} \
|
||||
${GOFFICE_CFLAGS}
|
||||
|
||||
libgncmod_html_la_SOURCES = \
|
||||
gncmod-html.c \
|
||||
gnc-html.c \
|
||||
gnc-html-history.c \
|
||||
gnc-html-graph-gog.c \
|
||||
gnc-html-factory.c \
|
||||
swig-gnc-html.c
|
||||
|
||||
gncincludedir = ${GNC_INCLUDE_DIR}
|
||||
gncinclude_HEADERS = \
|
||||
gnc-html-graph-gog.h \
|
||||
gnc-html-history.h \
|
||||
gnc-html.h \
|
||||
gnc-html-factory.h
|
||||
|
||||
libgncmod_html_la_LDFLAGS = -avoid-version
|
||||
|
||||
libgncmod_html_la_LIBADD = \
|
||||
${top_builddir}/src/core-utils/libgnc-core-utils.la \
|
||||
${top_builddir}/src/gnc-module/libgnc-module.la \
|
||||
${top_builddir}/src/engine/libgncmod-engine.la \
|
||||
${top_builddir}/src/calculation/libgncmod-calculation.la \
|
||||
${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
|
||||
${top_builddir}/src/app-utils/libgncmod-app-utils.la \
|
||||
$(top_builddir)/lib/libc/libc-missing.la \
|
||||
${GNOME_LIBS} \
|
||||
${GDK_PIXBUF_LIBS} \
|
||||
${GLIB_LIBS} \
|
||||
${DB_LIBS} \
|
||||
${QOF_LIBS} \
|
||||
${GOFFICE_LIBS} \
|
||||
${GUILE_LIBS} \
|
||||
${REGEX_LIBS}
|
||||
|
||||
if HTML_USING_WEBKIT
|
||||
AM_CPPFLAGS += ${WEBKIT_CFLAGS}
|
||||
libgncmod_html_la_SOURCES += \
|
||||
gnc-html-webkit.c \
|
||||
gnc-html-graph-gog-webkit.c
|
||||
libgncmod_html_la_LIBADD += \
|
||||
${WEBKIT_LIBS}
|
||||
else
|
||||
AM_CPPFLAGS += ${GTKHTML_CFLAGS}
|
||||
libgncmod_html_la_SOURCES += \
|
||||
gnc-html-gtkhtml.c \
|
||||
gnc-html-graph-gog-gtkhtml.c
|
||||
libgncmod_html_la_LIBADD += \
|
||||
${GTKHTML_LIBS}
|
||||
|
||||
if !GTKHTML_USES_GTKPRINT
|
||||
AM_CPPFLAGS += ${GNOME_PRINT_CFLAGS}
|
||||
libgncmod_html_la_LIBADD += ${GNOME_PRINT_LIBS}
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
if BUILDING_FROM_SVN
|
||||
swig-gnc-html.c: gnc-html.i gnc-html.h \
|
||||
${top_srcdir}/src/base-typemaps.i
|
||||
$(SWIG) -guile $(SWIG_ARGS) -Linkage module \
|
||||
-I${top_srcdir}/src -o $@ $<
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
gnc-svninfo.h \
|
||||
gnc-html.i
|
||||
|
||||
if !GTKHTML_USES_GTKPRINT
|
||||
AM_CPPFLAGS += ${GNOME_PRINT_CFLAGS}
|
||||
libgncmod_html_la_LIBADD += ${GNOME_PRINT_LIBS}
|
||||
endif
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES) gnucash
|
||||
MAINTAINERCLEANFILES = swig-html.c
|
||||
|
||||
# FIXME: Symlinking directories only works on non-win32.
|
||||
if !PLATFORM_WIN32
|
||||
#
|
||||
# I hate inconsistent standards. Autotools puts help files into
|
||||
# ${datadir}/gnome/help/${program} while the gnome2 libraries expect
|
||||
# them in ${pkgdatadir}/gnome/help/${program}.
|
||||
#
|
||||
install-data-hook:
|
||||
$(LN_S) -f ../gnome ${DESTDIR}${pkgdatadir}
|
||||
|
||||
uninstall-hook:
|
||||
rm -f ${DESTDIR}${pkgdatadir}/gnome
|
||||
endif
|
||||
|
||||
INCLUDES = -DG_LOG_DOMAIN=\"gnc.html\"
|
52
src/html/gnc-html-extras.h
Normal file
52
src/html/gnc-html-extras.h
Normal file
@ -0,0 +1,52 @@
|
||||
/********************************************************************
|
||||
* gnc-html-extras.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_EXTRAS_H
|
||||
#define GNC_HTML_EXTRAS_H
|
||||
|
||||
// This file is needed so that these definitions can be separately included in the
|
||||
// gnc-html.i file. The full gnc-html.h file can't be parsed because of the new
|
||||
// use of GObject
|
||||
|
||||
typedef gchar* URLType;
|
||||
|
||||
#define URL_TYPE_FILE "file"
|
||||
#define URL_TYPE_JUMP "jump"
|
||||
#define URL_TYPE_HTTP "http"
|
||||
#define URL_TYPE_FTP "ftp"
|
||||
#define URL_TYPE_SECURE "secure"
|
||||
#define URL_TYPE_REGISTER "register" /* for gnucash register popups */
|
||||
#define URL_TYPE_ACCTTREE "accttree" /* for account tree windows */
|
||||
#define URL_TYPE_REPORT "report" /* for gnucash report popups */
|
||||
#define URL_TYPE_OPTIONS "options" /* for editing report options */
|
||||
#define URL_TYPE_SCHEME "scheme" /* for scheme code evaluation */
|
||||
#define URL_TYPE_HELP "help" /* for a gnucash help window */
|
||||
#define URL_TYPE_XMLDATA "xmldata" /* links to gnucash XML data files */
|
||||
#define URL_TYPE_PRICE "price" /* for price editor popups */
|
||||
#define URL_TYPE_OTHER "other"
|
||||
#define URL_TYPE_BUDGET "budget"
|
||||
|
||||
gchar* gnc_build_url( URLType type, const gchar* location, const gchar* label );
|
||||
|
||||
gboolean gnc_html_engine_supports_css( void );
|
||||
|
||||
#endif
|
56
src/html/gnc-html-factory.c
Normal file
56
src/html/gnc-html-factory.c
Normal file
@ -0,0 +1,56 @@
|
||||
/********************************************************************
|
||||
* gnc-html_factory.c -- Factory to create HTML component *
|
||||
* *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-html-gtkhtml.h"
|
||||
#include "gnc-html-webkit.h"
|
||||
#include "qoflog.h"
|
||||
#include "gnc-engine.h"
|
||||
|
||||
#include "gnc-html-factory.h"
|
||||
|
||||
/* indicates the debugging module that this .o belongs to. */
|
||||
static QofLogModule log_module = GNC_MOD_HTML;
|
||||
|
||||
GncHtml* gnc_html_factory_create_html( void )
|
||||
{
|
||||
#ifdef WANT_WEBKIT
|
||||
return gnc_html_webkit_new();
|
||||
#else
|
||||
return gnc_html_gtkhtml_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
gnc_html_engine_supports_css( void )
|
||||
{
|
||||
#ifdef WANT_WEBKIT
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
30
src/html/gnc-html-factory.h
Normal file
30
src/html/gnc-html-factory.h
Normal file
@ -0,0 +1,30 @@
|
||||
/********************************************************************
|
||||
* gnc-html-factory.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_FACTORY_H
|
||||
#define GNC_HTML_FACTORY_H
|
||||
|
||||
#include "gnc-html.h"
|
||||
|
||||
GncHtml* gnc_html_factory_create_html( void );
|
||||
|
||||
#endif
|
515
src/html/gnc-html-graph-gog-gtkhtml.c
Normal file
515
src/html/gnc-html-graph-gog-gtkhtml.c
Normal file
@ -0,0 +1,515 @@
|
||||
/********************************************************************
|
||||
* gnc-html-graph-gog.c -- GNC/HTML Graphing support via GOG *
|
||||
* *
|
||||
* Copyright (C) 2005 Joshua Sled <jsled@asynchronous.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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtkhtml/gtkhtml.h>
|
||||
#include <gtkhtml/gtkhtml-embedded.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-ui-util.h"
|
||||
#include "gnc-html-graph-gog.h"
|
||||
#include "gnc-html-graph-gog-gtkhtml.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-engine.h"
|
||||
#include <goffice/goffice.h>
|
||||
#include <goffice/graph/gog-chart.h>
|
||||
#include <goffice/graph/gog-graph.h>
|
||||
#include <goffice/graph/gog-object.h>
|
||||
#if defined(HAVE_GOFFICE_0_5)
|
||||
# include <goffice/graph/gog-renderer.h>
|
||||
#elif defined(GOFFICE_WITH_CAIRO)
|
||||
# include <goffice/graph/gog-renderer-cairo.h>
|
||||
#else
|
||||
# include <goffice/graph/gog-renderer-pixbuf.h>
|
||||
#endif
|
||||
#ifndef GTKHTML_USES_GTKPRINT
|
||||
# include <goffice/graph/gog-renderer-gnome-print.h>
|
||||
#endif
|
||||
#include <goffice/graph/gog-style.h>
|
||||
#include <goffice/graph/gog-styled-object.h>
|
||||
#include <goffice/graph/gog-plot.h>
|
||||
#include <goffice/graph/gog-series.h>
|
||||
#include <goffice/utils/go-color.h>
|
||||
#include <goffice/utils/go-marker.h>
|
||||
#include <goffice/graph/gog-data-set.h>
|
||||
#include <goffice/data/go-data-simple.h>
|
||||
#include <goffice/app/go-plugin.h>
|
||||
#include <goffice/app/go-plugin-loader-module.h>
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* - scatter-plot marker selection
|
||||
* - series-color, piecharts (hard, not really supported by GOG)
|
||||
* and scatters (or drop feature)
|
||||
* - title-string freeing (fixmes)
|
||||
* - general graph cleanup
|
||||
**/
|
||||
|
||||
#undef G_LOG_DOMAIN
|
||||
#define G_LOG_DOMAIN "gnc.html.graph.gog.gtkhtml"
|
||||
|
||||
static int handle_piechart( GncHtml* html, gpointer eb, gpointer d );
|
||||
static int handle_barchart( GncHtml* html, gpointer eb, gpointer d );
|
||||
static int handle_linechart( GncHtml* html, gpointer eb, gpointer d );
|
||||
static int handle_scatter( GncHtml* html, gpointer eb, gpointer d );
|
||||
|
||||
#ifdef GTKHTML_USES_GTKPRINT
|
||||
static void draw_print_cb(GtkHTMLEmbedded *eb, cairo_t *cr, gpointer graph);
|
||||
#else
|
||||
static void draw_print_cb(GtkHTMLEmbedded *eb, GnomePrintContext *context, gpointer graph);
|
||||
#endif
|
||||
|
||||
static gboolean create_basic_plot_elements(const char *plot_type, GogObject **out_graph, GogObject **out_chart, GogPlot **out_plot);
|
||||
|
||||
static double * read_doubles(const char * string, int nvalues);
|
||||
|
||||
static void set_chart_titles_from_hash(GogObject *chart, gpointer eb);
|
||||
static void set_chart_titles(GogObject *chart, const char *title, const char* sub_title);
|
||||
static void set_chart_axis_labels_from_hash(GogObject *chart, gpointer eb);
|
||||
static void set_chart_axis_labels(GogObject *chart, const char *x_axis_label, const char* y_axis_label);
|
||||
|
||||
void
|
||||
gnc_html_graph_gog_gtkhtml_init( void )
|
||||
{
|
||||
gnc_html_graph_gog_init();
|
||||
|
||||
gnc_html_register_object_handler( "gnc-guppi-pie", handle_piechart );
|
||||
gnc_html_register_object_handler( "gnc-guppi-bar", handle_barchart );
|
||||
gnc_html_register_object_handler( "gnc-guppi-scatter", handle_scatter );
|
||||
gnc_html_register_object_handler( "gnc-guppi-line", handle_linechart );
|
||||
}
|
||||
|
||||
static double *
|
||||
read_doubles(const char * string, int nvalues)
|
||||
{
|
||||
int n;
|
||||
gchar *next;
|
||||
double * retval = g_new0(double, nvalues);
|
||||
|
||||
// guile is going to (puts ...) the elements of the double array
|
||||
// together. In non-POSIX locales, that will be in a format that
|
||||
// the locale-specific sscanf will not be able to parse.
|
||||
gnc_push_locale("C");
|
||||
{
|
||||
for (n=0; n<nvalues; n++) {
|
||||
retval[n] = strtod(string, &next);
|
||||
string = next;
|
||||
}
|
||||
}
|
||||
gnc_pop_locale();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static char **
|
||||
read_strings(const char * string, int nvalues)
|
||||
{
|
||||
int n;
|
||||
int choffset=0;
|
||||
int accum = 0;
|
||||
char ** retval = g_new0(char *, nvalues);
|
||||
char thischar;
|
||||
const char * inptr = string;
|
||||
int escaped = FALSE;
|
||||
|
||||
for (n=0; n < nvalues; n++) {
|
||||
retval[n] = g_new0(char, strlen(string+accum)+1);
|
||||
retval[n][0] = 0;
|
||||
choffset = 0;
|
||||
while ((thischar = *inptr) != 0) {
|
||||
if (thischar == '\\') {
|
||||
escaped = TRUE;
|
||||
inptr++;
|
||||
}
|
||||
else if ((thischar != ' ') || escaped) {
|
||||
retval[n][choffset] = thischar;
|
||||
retval[n][choffset+1] = 0;
|
||||
choffset++;
|
||||
escaped = FALSE;
|
||||
inptr++;
|
||||
}
|
||||
else {
|
||||
/* an unescaped space */
|
||||
escaped = FALSE;
|
||||
inptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
accum += choffset;
|
||||
/* printf("retval[%d] = '%s'\n", n, retval[n]); */
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
add_pixbuf_graph_widget( GtkHTMLEmbedded *eb, GdkPixbuf* buf )
|
||||
{
|
||||
GtkWidget *widget;
|
||||
gboolean update_status;
|
||||
GogGraph *graph = GOG_GRAPH(g_object_get_data( G_OBJECT(buf), "graph" ));
|
||||
|
||||
widget = gtk_image_new_from_pixbuf (buf);
|
||||
gtk_widget_set_size_request (widget, eb->width, eb->height);
|
||||
gtk_widget_show_all (widget);
|
||||
gtk_container_add (GTK_CONTAINER (eb), widget);
|
||||
|
||||
// blindly copied from gnc-html-guppi.c..
|
||||
gtk_widget_set_size_request (GTK_WIDGET (eb), eb->width, eb->height);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (eb), "graph", graph, g_object_unref);
|
||||
g_signal_connect (G_OBJECT (eb), "draw_print",
|
||||
G_CALLBACK (draw_print_cb), NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_basic_plot_elements(const char *plot_type_name,
|
||||
GogObject **out_graph,
|
||||
GogObject **out_chart,
|
||||
GogPlot **out_plot)
|
||||
{
|
||||
*out_graph = g_object_new(GOG_GRAPH_TYPE, NULL);
|
||||
*out_chart = gog_object_add_by_name(*out_graph, "Chart", NULL);
|
||||
*out_plot = gog_plot_new_by_name(plot_type_name);
|
||||
if (!*out_plot)
|
||||
{
|
||||
// FIXME - log betterer; should probably use GError?
|
||||
g_warning("gog: unable to load %s plugin", plot_type_name);
|
||||
return FALSE;
|
||||
}
|
||||
gog_object_add_by_name(*out_chart, "Plot", GOG_OBJECT(*out_plot) );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_titles_from_hash(GogObject *chart, gpointer eb)
|
||||
{
|
||||
set_chart_titles(chart,
|
||||
(const char *)gnc_html_get_embedded_param(eb, "title"),
|
||||
(const char *)gnc_html_get_embedded_param(eb, "subtitle"));
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_titles(GogObject *chart, const char *title, const char* sub_title)
|
||||
{
|
||||
gchar *my_sub_title, *total_title;
|
||||
GOData *title_scalar;
|
||||
GogObject *tmp;
|
||||
|
||||
if (sub_title)
|
||||
my_sub_title = g_strdup_printf("%s(%s)", title ? " " : "", sub_title);
|
||||
else
|
||||
my_sub_title = g_strdup("");
|
||||
|
||||
total_title = g_strdup_printf("%s%s", title ? title : "", my_sub_title);
|
||||
|
||||
tmp = gog_object_add_by_name(chart, "Title", NULL);
|
||||
title_scalar = go_data_scalar_str_new(total_title, TRUE);
|
||||
gog_dataset_set_dim(GOG_DATASET(tmp), 0, title_scalar, NULL);
|
||||
|
||||
g_free(my_sub_title);
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_axis_labels_from_hash(GogObject *chart, gpointer eb)
|
||||
{
|
||||
set_chart_axis_labels(chart,
|
||||
gnc_html_get_embedded_param(eb, "x_axis_label"),
|
||||
gnc_html_get_embedded_param(eb, "y_axis_label"));
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_axis_labels(GogObject *chart, const char *x_axis_label, const char* y_axis_label)
|
||||
{
|
||||
if (x_axis_label != NULL)
|
||||
{
|
||||
GogObject *xaxis, *label;
|
||||
GOData *data;
|
||||
xaxis = gog_object_get_child_by_role(chart, gog_object_find_role_by_name(chart, "X-Axis"));
|
||||
label = gog_object_add_by_name(xaxis, "Label", NULL);
|
||||
data = go_data_scalar_str_new(x_axis_label, FALSE);
|
||||
gog_dataset_set_dim(GOG_DATASET(label), 0, data, NULL);
|
||||
}
|
||||
|
||||
if (y_axis_label != NULL)
|
||||
{
|
||||
GogObject *yaxis, *label;
|
||||
GOData *data;
|
||||
yaxis = gog_object_get_child_by_role(chart, gog_object_find_role_by_name(chart, "Y-Axis"));
|
||||
label = gog_object_add_by_name(yaxis, "Label", NULL);
|
||||
data = go_data_scalar_str_new(y_axis_label, FALSE);
|
||||
gog_dataset_set_dim(GOG_DATASET(label), 0, data, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the following parameters:
|
||||
* title: text
|
||||
* subtitle: text
|
||||
* datasize: (length data), sscanf( .., %d, (int)&datasize )
|
||||
* data: (foreach (lambda (datum) (push datum) (push " ")) data)
|
||||
* colors: string; space-seperated?
|
||||
* labels: string; space-seperated?
|
||||
* slice_urls_[123]: ?
|
||||
* legend_urls_[123]: ?
|
||||
*/
|
||||
static gboolean
|
||||
handle_piechart( GncHtml* html, gpointer eb, gpointer unused )
|
||||
{
|
||||
GncHtmlPieChartInfo pieChartInfo;
|
||||
|
||||
// parse data from the text-ized params.
|
||||
{
|
||||
const char *datasizeStr, *dataStr, *labelsStr, *colorStr;
|
||||
|
||||
datasizeStr = gnc_html_get_embedded_param(eb, "datasize");
|
||||
dataStr = gnc_html_get_embedded_param(eb, "data" );
|
||||
labelsStr = gnc_html_get_embedded_param(eb, "labels");
|
||||
colorStr = gnc_html_get_embedded_param(eb, "colors");
|
||||
g_return_val_if_fail( datasizeStr != NULL
|
||||
&& dataStr != NULL
|
||||
&& labelsStr != NULL
|
||||
&& colorStr != NULL, FALSE );
|
||||
pieChartInfo.datasize = atoi( datasizeStr );
|
||||
pieChartInfo.data = read_doubles( dataStr, pieChartInfo.datasize );
|
||||
pieChartInfo.labels = read_strings( labelsStr, pieChartInfo.datasize );
|
||||
pieChartInfo.colors = read_strings( colorStr, pieChartInfo.datasize );
|
||||
}
|
||||
|
||||
pieChartInfo.title = (const char *)gnc_html_get_embedded_param(eb, "title");
|
||||
pieChartInfo.subtitle = (const char *)gnc_html_get_embedded_param(eb, "subtitle");
|
||||
pieChartInfo.width = ((GtkHTMLEmbedded*)eb)->width;
|
||||
pieChartInfo.height = ((GtkHTMLEmbedded*)eb)->height;
|
||||
|
||||
add_pixbuf_graph_widget( eb, gnc_html_graph_gog_create_piechart( &pieChartInfo ) );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* data_rows:int
|
||||
* data_cols:int
|
||||
* data:doubles[], data_rows*data_cols
|
||||
* x_axis_label:string
|
||||
* y_axis_label:string
|
||||
* row_labels:string[]
|
||||
* col_labels:string[]
|
||||
* col_colors:string[]
|
||||
* rotate_row_labels:boolean
|
||||
* stacked:boolean
|
||||
**/
|
||||
static gboolean
|
||||
handle_barchart( GncHtml* html, gpointer eb, gpointer unused )
|
||||
{
|
||||
GncHtmlBarChartInfo barChartInfo;
|
||||
|
||||
// parse data from the text-ized params
|
||||
// series => bars [gnc:cols]
|
||||
// series-elements => segments [gnc:rows]
|
||||
{
|
||||
const char *data_rows_str, *data_cols_str, *data_str, *col_labels_str, *row_labels_str;
|
||||
const char *col_colors_str, *rotate_row_labels_str = NULL, *stacked_str = NULL;
|
||||
|
||||
data_rows_str = gnc_html_get_embedded_param (eb, "data_rows");
|
||||
data_cols_str = gnc_html_get_embedded_param (eb, "data_cols");
|
||||
data_str = gnc_html_get_embedded_param (eb, "data" );
|
||||
row_labels_str = gnc_html_get_embedded_param (eb, "row_labels");
|
||||
col_labels_str = gnc_html_get_embedded_param (eb, "col_labels");
|
||||
col_colors_str = gnc_html_get_embedded_param (eb, "col_colors");
|
||||
rotate_row_labels_str = gnc_html_get_embedded_param (eb, "rotate_row_labels");
|
||||
stacked_str = gnc_html_get_embedded_param (eb, "stacked");
|
||||
|
||||
barChartInfo.rotate_row_labels = (gboolean) atoi (rotate_row_labels_str);
|
||||
barChartInfo.stacked = (gboolean) atoi (stacked_str);
|
||||
|
||||
#if 0 // too strong at the moment.
|
||||
g_return_val_if_fail (data_rows_str != NULL
|
||||
&& data_cols_str != NULL
|
||||
&& data_str != NULL
|
||||
&& col_labels_str != NULL
|
||||
&& row_labels_str != NULL
|
||||
&& col_colors_str != NULL, FALSE );
|
||||
#endif // 0
|
||||
barChartInfo.data_rows = atoi (data_rows_str);
|
||||
barChartInfo.data_cols = atoi (data_cols_str);
|
||||
barChartInfo.data = read_doubles (data_str, barChartInfo.data_rows*barChartInfo.data_cols);
|
||||
barChartInfo.row_labels = read_strings (row_labels_str, barChartInfo.data_rows);
|
||||
barChartInfo.col_labels = read_strings (col_labels_str, barChartInfo.data_cols);
|
||||
barChartInfo.col_colors = read_strings (col_colors_str, barChartInfo.data_cols);
|
||||
}
|
||||
|
||||
barChartInfo.title = (const char *)gnc_html_get_embedded_param(eb, "title");
|
||||
barChartInfo.subtitle = (const char *)gnc_html_get_embedded_param(eb, "subtitle");
|
||||
barChartInfo.width = ((GtkHTMLEmbedded*)eb)->width;
|
||||
barChartInfo.height = ((GtkHTMLEmbedded*)eb)->height;
|
||||
barChartInfo.x_axis_label = gnc_html_get_embedded_param(eb, "x_axis_label"),
|
||||
barChartInfo.y_axis_label = gnc_html_get_embedded_param(eb, "y_axis_label");
|
||||
|
||||
add_pixbuf_graph_widget( eb, gnc_html_graph_gog_create_barchart( &barChartInfo ) );
|
||||
|
||||
g_debug("barchart rendered.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* data_rows:int
|
||||
* data_cols:int
|
||||
* data:doubles[], data_rows*data_cols
|
||||
* x_axis_label:string
|
||||
* y_axis_label:string
|
||||
* row_labels:string[]
|
||||
* col_labels:string[]
|
||||
* col_colors:string[]
|
||||
* rotate_row_labels:boolean
|
||||
* stacked:boolean
|
||||
* markers:boolean
|
||||
* major_grid:boolean
|
||||
* minor_grid:boolean
|
||||
**/
|
||||
static gboolean
|
||||
handle_linechart( GncHtml* html, gpointer eb, gpointer unused )
|
||||
{
|
||||
GncHtmlLineChartInfo lineChartInfo;
|
||||
|
||||
// parse data from the text-ized params
|
||||
// series => lines [gnc:cols]
|
||||
// series-elements => segments [gnc:rows]
|
||||
{
|
||||
const char *data_rows_str, *data_cols_str, *data_str, *col_labels_str, *row_labels_str;
|
||||
const char *col_colors_str, *rotate_row_labels_str = NULL, *stacked_str = NULL, *markers_str = NULL;
|
||||
const char *major_grid_str = NULL, *minor_grid_str = NULL;
|
||||
|
||||
data_rows_str = gnc_html_get_embedded_param (eb, "data_rows");
|
||||
data_cols_str = gnc_html_get_embedded_param (eb, "data_cols");
|
||||
data_str = gnc_html_get_embedded_param (eb, "data" );
|
||||
row_labels_str = gnc_html_get_embedded_param (eb, "row_labels");
|
||||
col_labels_str = gnc_html_get_embedded_param (eb, "col_labels");
|
||||
col_colors_str = gnc_html_get_embedded_param (eb, "col_colors");
|
||||
rotate_row_labels_str = gnc_html_get_embedded_param (eb, "rotate_row_labels");
|
||||
stacked_str = gnc_html_get_embedded_param (eb, "stacked");
|
||||
markers_str = gnc_html_get_embedded_param (eb, "markers");
|
||||
major_grid_str = gnc_html_get_embedded_param (eb, "major_grid");
|
||||
minor_grid_str = gnc_html_get_embedded_param (eb, "minor_grid");
|
||||
|
||||
lineChartInfo.rotate_row_labels = (gboolean) atoi (rotate_row_labels_str);
|
||||
lineChartInfo.stacked = (gboolean) atoi (stacked_str);
|
||||
lineChartInfo.markers = (gboolean) atoi (markers_str);
|
||||
lineChartInfo.major_grid = (gboolean) atoi (major_grid_str);
|
||||
lineChartInfo.minor_grid = (gboolean) atoi (minor_grid_str);
|
||||
|
||||
lineChartInfo.data_rows = atoi (data_rows_str);
|
||||
lineChartInfo.data_cols = atoi (data_cols_str);
|
||||
lineChartInfo.data = read_doubles (data_str, lineChartInfo.data_rows*lineChartInfo.data_cols);
|
||||
lineChartInfo.row_labels = read_strings (row_labels_str, lineChartInfo.data_rows);
|
||||
lineChartInfo.col_labels = read_strings (col_labels_str, lineChartInfo.data_cols);
|
||||
lineChartInfo.col_colors = read_strings (col_colors_str, lineChartInfo.data_cols);
|
||||
}
|
||||
|
||||
lineChartInfo.title = (const char *)gnc_html_get_embedded_param(eb, "title");
|
||||
lineChartInfo.subtitle = (const char *)gnc_html_get_embedded_param(eb, "subtitle");
|
||||
lineChartInfo.width = ((GtkHTMLEmbedded*)eb)->width;
|
||||
lineChartInfo.height = ((GtkHTMLEmbedded*)eb)->height;
|
||||
lineChartInfo.x_axis_label = gnc_html_get_embedded_param(eb, "x_axis_label"),
|
||||
lineChartInfo.y_axis_label = gnc_html_get_embedded_param(eb, "y_axis_label");
|
||||
|
||||
add_pixbuf_graph_widget( eb, gnc_html_graph_gog_create_linechart( &lineChartInfo ) );
|
||||
|
||||
g_debug("linechart rendered.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
handle_scatter( GncHtml* html, gpointer eb, gpointer unused )
|
||||
{
|
||||
GncHtmlScatterPlotInfo scatterPlotInfo;
|
||||
|
||||
{
|
||||
const char *datasizeStr, *xDataStr, *yDataStr;
|
||||
|
||||
datasizeStr = gnc_html_get_embedded_param( eb, "datasize" );
|
||||
scatterPlotInfo.datasize = atoi( datasizeStr );
|
||||
|
||||
xDataStr = gnc_html_get_embedded_param( eb, "x_data" );
|
||||
scatterPlotInfo.xData = read_doubles( xDataStr, scatterPlotInfo.datasize );
|
||||
|
||||
yDataStr = gnc_html_get_embedded_param( eb, "y_data" );
|
||||
scatterPlotInfo.yData = read_doubles( yDataStr, scatterPlotInfo.datasize );
|
||||
|
||||
scatterPlotInfo.marker_str = gnc_html_get_embedded_param(eb, "marker");
|
||||
scatterPlotInfo.color_str = gnc_html_get_embedded_param(eb, "color");
|
||||
}
|
||||
|
||||
scatterPlotInfo.title = (const char *)gnc_html_get_embedded_param(eb, "title");
|
||||
scatterPlotInfo.subtitle = (const char *)gnc_html_get_embedded_param(eb, "subtitle");
|
||||
scatterPlotInfo.width = ((GtkHTMLEmbedded*)eb)->width;
|
||||
scatterPlotInfo.height = ((GtkHTMLEmbedded*)eb)->height;
|
||||
scatterPlotInfo.x_axis_label = gnc_html_get_embedded_param(eb, "x_axis_label"),
|
||||
scatterPlotInfo.y_axis_label = gnc_html_get_embedded_param(eb, "y_axis_label");
|
||||
|
||||
add_pixbuf_graph_widget( eb, gnc_html_graph_gog_create_scatterplot( &scatterPlotInfo ) );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef GTKHTML_USES_GTKPRINT
|
||||
static void
|
||||
draw_print_cb(GtkHTMLEmbedded *eb, cairo_t *cr, gpointer unused)
|
||||
{
|
||||
GogGraph *graph = GOG_GRAPH(g_object_get_data(G_OBJECT(eb), "graph"));
|
||||
# ifdef HAVE_GOFFICE_0_5
|
||||
GogRenderer *rend = g_object_new(GOG_RENDERER_TYPE, "model", graph, NULL);
|
||||
# else
|
||||
GogRendererCairo *rend = g_object_new(GOG_RENDERER_CAIRO_TYPE, "model", graph,
|
||||
"cairo", cr, "is-vector", TRUE, NULL);
|
||||
# endif
|
||||
|
||||
/* assuming pixel size is 0.5, cf. gtkhtml/src/htmlprinter.c */
|
||||
cairo_scale(cr, 0.5, 0.5);
|
||||
|
||||
cairo_translate(cr, 0, -eb->height);
|
||||
|
||||
# ifdef HAVE_GOFFICE_0_5
|
||||
gog_renderer_render_to_cairo(rend, cr, eb->width, eb->height);
|
||||
# else
|
||||
gog_renderer_cairo_update(rend, eb->width, eb->height, 1.0);
|
||||
# endif
|
||||
g_object_unref(rend);
|
||||
}
|
||||
|
||||
#else /* !GTKHTML_USES_GTKPRINT */
|
||||
static void
|
||||
draw_print_cb(GtkHTMLEmbedded *eb, GnomePrintContext *context, gpointer unused)
|
||||
{
|
||||
GogGraph *graph = GOG_GRAPH (g_object_get_data (G_OBJECT (eb), "graph"));
|
||||
|
||||
/* assuming pixel size is 0.5, cf. gtkhtml/src/htmlprinter.c */
|
||||
gnome_print_scale (context, 0.5, 0.5);
|
||||
|
||||
gnome_print_translate (context, 0, eb->height);
|
||||
gog_graph_print_to_gnome_print (graph, context, eb->width, eb->height);
|
||||
}
|
||||
#endif /* GTKHTML_USES_GTKPRINT */
|
30
src/html/gnc-html-graph-gog-gtkhtml.h
Normal file
30
src/html/gnc-html-graph-gog-gtkhtml.h
Normal file
@ -0,0 +1,30 @@
|
||||
/********************************************************************
|
||||
* gnc-html_graph_gog_gtkhtml.h -- display html with gnc special *
|
||||
* tags *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_GRAPH_GOG_GTKHTML_H
|
||||
#define GNC_HTML_GRAPH_GOG_GTKHTML_H 1
|
||||
|
||||
void gnc_html_graph_gog_gtkhtml_init( void );
|
||||
|
||||
#endif /* GNC_HTML_GRAPH_GOG_GTKHTML_H */
|
489
src/html/gnc-html-graph-gog-webkit.c
Normal file
489
src/html/gnc-html-graph-gog-webkit.c
Normal file
@ -0,0 +1,489 @@
|
||||
/********************************************************************
|
||||
* gnc-html-graph-gog_webkit.c -- GNC/HTML Graphing support via GOG *
|
||||
* *
|
||||
* Copyright (C) 2005 Joshua Sled <jsled@asynchronous.org> *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <webkit/webkit.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-ui-util.h"
|
||||
#include "gnc-html-graph-gog.h"
|
||||
#include "gnc-html-graph-gog-webkit.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-engine.h"
|
||||
#include <goffice/goffice.h>
|
||||
#include <goffice/graph/gog-chart.h>
|
||||
#include <goffice/graph/gog-graph.h>
|
||||
#include <goffice/graph/gog-object.h>
|
||||
#if defined(HAVE_GOFFICE_0_5)
|
||||
# include <goffice/graph/gog-renderer.h>
|
||||
#elif defined(GOFFICE_WITH_CAIRO)
|
||||
# include <goffice/graph/gog-renderer-cairo.h>
|
||||
#else
|
||||
# include <goffice/graph/gog-renderer-pixbuf.h>
|
||||
#endif
|
||||
#ifndef GTKHTML_USES_GTKPRINT
|
||||
# include <goffice/graph/gog-renderer-gnome-print.h>
|
||||
#endif
|
||||
#include <goffice/graph/gog-style.h>
|
||||
#include <goffice/graph/gog-styled-object.h>
|
||||
#include <goffice/graph/gog-plot.h>
|
||||
#include <goffice/graph/gog-series.h>
|
||||
#include <goffice/utils/go-color.h>
|
||||
#include <goffice/utils/go-marker.h>
|
||||
#include <goffice/graph/gog-data-set.h>
|
||||
#include <goffice/data/go-data-simple.h>
|
||||
#include <goffice/app/go-plugin.h>
|
||||
#include <goffice/app/go-plugin-loader-module.h>
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* - scatter-plot marker selection
|
||||
* - series-color, piecharts (hard, not really supported by GOG)
|
||||
* and scatters (or drop feature)
|
||||
* - title-string freeing (fixmes)
|
||||
* - general graph cleanup
|
||||
**/
|
||||
|
||||
/* indicates the debugging module that this .o belongs to. */
|
||||
#undef G_LOG_DOMAIN
|
||||
#define G_LOG_DOMAIN "gnc.html.graph.gog.webkit"
|
||||
static QofLogModule log_module = GNC_MOD_HTML;
|
||||
|
||||
static int handle_piechart( GncHtml* html, gpointer eb, gpointer d );
|
||||
static int handle_barchart( GncHtml* html, gpointer eb, gpointer d );
|
||||
static int handle_linechart( GncHtml* html, gpointer eb, gpointer d );
|
||||
static int handle_scatter( GncHtml* html, gpointer eb, gpointer d );
|
||||
|
||||
static double * read_doubles(const char * string, int nvalues);
|
||||
|
||||
void
|
||||
gnc_html_graph_gog_webkit_init( void )
|
||||
{
|
||||
g_debug( "init gog graphing" );
|
||||
|
||||
libgoffice_init();
|
||||
|
||||
/* Initialize plugins manager */
|
||||
go_plugins_init( NULL, NULL, NULL, NULL, TRUE, GO_PLUGIN_LOADER_MODULE_TYPE );
|
||||
|
||||
gnc_html_register_object_handler( "gnc-guppi-pie", handle_piechart );
|
||||
gnc_html_register_object_handler( "gnc-guppi-bar", handle_barchart );
|
||||
gnc_html_register_object_handler( "gnc-guppi-scatter", handle_scatter );
|
||||
gnc_html_register_object_handler( "gnc-guppi-line", handle_linechart );
|
||||
}
|
||||
|
||||
static double *
|
||||
read_doubles(const char * string, int nvalues)
|
||||
{
|
||||
int n;
|
||||
gchar *next;
|
||||
double * retval = g_new0(double, nvalues);
|
||||
|
||||
// guile is going to (puts ...) the elements of the double array
|
||||
// together. In non-POSIX locales, that will be in a format that
|
||||
// the locale-specific sscanf will not be able to parse.
|
||||
gnc_push_locale("C");
|
||||
{
|
||||
for (n=0; n<nvalues; n++) {
|
||||
retval[n] = strtod(string, &next);
|
||||
string = next;
|
||||
}
|
||||
}
|
||||
gnc_pop_locale();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static char **
|
||||
read_strings(const char * string, int nvalues)
|
||||
{
|
||||
int n;
|
||||
int choffset=0;
|
||||
int accum = 0;
|
||||
char ** retval = g_new0(char *, nvalues);
|
||||
char thischar;
|
||||
const char * inptr = string;
|
||||
int escaped = FALSE;
|
||||
|
||||
for (n=0; n < nvalues; n++) {
|
||||
retval[n] = g_new0(char, strlen(string+accum)+1);
|
||||
retval[n][0] = 0;
|
||||
choffset = 0;
|
||||
while ((thischar = *inptr) != 0) {
|
||||
if (thischar == '\\') {
|
||||
escaped = TRUE;
|
||||
inptr++;
|
||||
}
|
||||
else if ((thischar != ' ') || escaped) {
|
||||
retval[n][choffset] = thischar;
|
||||
retval[n][choffset+1] = 0;
|
||||
choffset++;
|
||||
escaped = FALSE;
|
||||
inptr++;
|
||||
}
|
||||
else {
|
||||
/* an unescaped space */
|
||||
escaped = FALSE;
|
||||
inptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
accum += choffset;
|
||||
/* printf("retval[%d] = '%s'\n", n, retval[n]); */
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
get_int_value( gchar** str, const gchar* name )
|
||||
{
|
||||
gchar* p;
|
||||
gchar* tag_name;
|
||||
int val = -1;
|
||||
|
||||
tag_name = g_strdup_printf( "%s=", name );
|
||||
p = g_strstr_len( *str, -1, tag_name );
|
||||
if( p != NULL ) {
|
||||
val = atoi( p+strlen( tag_name ) );
|
||||
*str = p+strlen( tag_name );
|
||||
}
|
||||
g_free( tag_name );
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int
|
||||
get_int_param( gchar** str, const gchar* name )
|
||||
{
|
||||
gchar* p;
|
||||
gchar* tag_string;
|
||||
int val = -1;
|
||||
|
||||
tag_string = g_strdup_printf( "<param name=\"%s\" value=\"", name );
|
||||
p = g_strstr_len( *str, -1, tag_string );
|
||||
if( p != NULL ) {
|
||||
val = atoi( p+strlen( tag_string ) );
|
||||
*str = p+strlen( tag_string );
|
||||
}
|
||||
g_free( tag_string );
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static gchar*
|
||||
get_string_param( gchar** str, const gchar* name )
|
||||
{
|
||||
gchar* p;
|
||||
gchar* p_end;
|
||||
gchar* tag_string;
|
||||
gchar* val = NULL;
|
||||
|
||||
tag_string = g_strdup_printf( "<param name=\"%s\" value=\"", name );
|
||||
p = g_strstr_len( *str, -1, tag_string );
|
||||
if( p != NULL ) {
|
||||
p += strlen( tag_string );
|
||||
p_end = g_strstr_len( p, -1, "\">\n" );
|
||||
val = g_strndup( p, (p_end-p) );
|
||||
*str = p_end+strlen( "\">\n" );
|
||||
}
|
||||
g_free( tag_string );
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static gchar*
|
||||
convert_pixbuf_to_base64_string( GdkPixbuf* pixbuf )
|
||||
{
|
||||
gchar* pixel_buffer;
|
||||
gsize pixel_buffer_size;
|
||||
GError* error = NULL;
|
||||
gchar* base64_buf;
|
||||
|
||||
if( !gdk_pixbuf_save_to_buffer( pixbuf, &pixel_buffer, &pixel_buffer_size, "png",
|
||||
&error, NULL ) ) {
|
||||
PERR( "Unable to save pixbuf to buffer: %s\n", error->message );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
base64_buf = g_base64_encode( pixel_buffer, pixel_buffer_size );
|
||||
g_free( pixel_buffer );
|
||||
return base64_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the following parameters:
|
||||
* title: text
|
||||
* subtitle: text
|
||||
* datasize: (length data), sscanf( .., %d, (int)&datasize )
|
||||
* data: (foreach (lambda (datum) (push datum) (push " ")) data)
|
||||
* colors: string; space-seperated?
|
||||
* labels: string; space-seperated?
|
||||
* slice_urls_[123]: ?
|
||||
* legend_urls_[123]: ?
|
||||
*/
|
||||
static gboolean
|
||||
handle_piechart( GncHtml* html, gpointer eb, gpointer d )
|
||||
{
|
||||
gchar* object_info = (gchar*)eb;
|
||||
gchar** pResult = (gchar**)d;
|
||||
GncHtmlPieChartInfo pieChartInfo;
|
||||
GdkPixbuf* pixbuf;
|
||||
gchar* p;
|
||||
gchar* p_end;
|
||||
gchar* temp_str;
|
||||
gchar* base64_buf;
|
||||
|
||||
pieChartInfo.width = get_int_value( &object_info, "width" );
|
||||
pieChartInfo.height = get_int_value( &object_info, "height" );
|
||||
pieChartInfo.title = get_string_param( &object_info, "title" );
|
||||
pieChartInfo.subtitle = get_string_param( &object_info, "subtitle" );
|
||||
pieChartInfo.datasize = get_int_param( &object_info, "datasize" );
|
||||
temp_str = get_string_param( &object_info, "data" );
|
||||
if( temp_str != NULL ) {
|
||||
pieChartInfo.data = read_doubles( temp_str, pieChartInfo.datasize );
|
||||
}
|
||||
temp_str = get_string_param( &object_info, "colors" );
|
||||
if( temp_str != NULL ) {
|
||||
pieChartInfo.colors = read_strings( temp_str, pieChartInfo.datasize );
|
||||
g_free( temp_str );
|
||||
}
|
||||
temp_str = get_string_param( &object_info, "labels" );
|
||||
if( temp_str != NULL ) {
|
||||
pieChartInfo.labels = read_strings( temp_str, pieChartInfo.datasize );
|
||||
g_free( temp_str );
|
||||
}
|
||||
|
||||
pixbuf = gnc_html_graph_gog_create_piechart( &pieChartInfo );
|
||||
if( pieChartInfo.title != NULL ) g_free( (gchar*)pieChartInfo.title );
|
||||
if( pieChartInfo.subtitle != NULL ) g_free( (gchar*)pieChartInfo.subtitle );
|
||||
|
||||
base64_buf = convert_pixbuf_to_base64_string( pixbuf );
|
||||
if( base64_buf == NULL ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*pResult = g_strdup_printf( "<img src=\"data:image/png;base64,%s \" alt=\"Cannot display piechart\"/>", base64_buf );
|
||||
g_free( base64_buf );
|
||||
|
||||
g_debug("piechart rendered.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* data_rows:int
|
||||
* data_cols:int
|
||||
* data:doubles[], data_rows*data_cols
|
||||
* x_axis_label:string
|
||||
* y_axis_label:string
|
||||
* row_labels:string[]
|
||||
* col_labels:string[]
|
||||
* col_colors:string[]
|
||||
* rotate_row_labels:boolean
|
||||
* stacked:boolean
|
||||
**/
|
||||
static gboolean
|
||||
handle_barchart( GncHtml* html, gpointer eb, gpointer d )
|
||||
{
|
||||
gchar* object_info = (gchar*)eb;
|
||||
gchar** pResult = (gchar**)d;
|
||||
GncHtmlBarChartInfo barChartInfo;
|
||||
GdkPixbuf* pixbuf;
|
||||
gchar* p;
|
||||
gchar* p_end;
|
||||
gchar* temp_str;
|
||||
gchar* base64_buf;
|
||||
|
||||
barChartInfo.width = get_int_value( &object_info, "width" );
|
||||
barChartInfo.height = get_int_value( &object_info, "height" );
|
||||
barChartInfo.title = get_string_param( &object_info, "title" );
|
||||
barChartInfo.subtitle = get_string_param( &object_info, "subtitle" );
|
||||
barChartInfo.data_rows = get_int_param( &object_info, "data_rows" );
|
||||
barChartInfo.data_cols = get_int_param( &object_info, "data_cols" );
|
||||
temp_str = get_string_param( &object_info, "data" );
|
||||
if( temp_str != NULL ) {
|
||||
barChartInfo.data = read_doubles( temp_str, barChartInfo.data_rows*barChartInfo.data_cols );
|
||||
}
|
||||
barChartInfo.x_axis_label = get_string_param( &object_info, "x_axis_label" );
|
||||
barChartInfo.y_axis_label = get_string_param( &object_info, "y_axis_label" );
|
||||
temp_str = get_string_param( &object_info, "col_colors" );
|
||||
if( temp_str != NULL ) {
|
||||
barChartInfo.col_colors = read_strings( temp_str, barChartInfo.data_cols );
|
||||
g_free( temp_str );
|
||||
}
|
||||
temp_str = get_string_param( &object_info, "row_labels" );
|
||||
if( temp_str != NULL ) {
|
||||
barChartInfo.row_labels = read_strings( temp_str, barChartInfo.data_rows );
|
||||
g_free( temp_str );
|
||||
}
|
||||
temp_str = get_string_param( &object_info, "col_labels" );
|
||||
if( temp_str != NULL ) {
|
||||
barChartInfo.col_labels = read_strings( temp_str, barChartInfo.data_cols );
|
||||
g_free( temp_str );
|
||||
}
|
||||
barChartInfo.rotate_row_labels = get_int_param( &object_info, "rotate_row_labels" );
|
||||
barChartInfo.stacked = get_int_param( &object_info, "stacked" );
|
||||
|
||||
pixbuf = gnc_html_graph_gog_create_barchart( &barChartInfo );
|
||||
if( barChartInfo.title != NULL ) g_free( (gchar*)barChartInfo.title );
|
||||
if( barChartInfo.subtitle != NULL ) g_free( (gchar*)barChartInfo.subtitle );
|
||||
if( barChartInfo.x_axis_label != NULL ) g_free( (gchar*)barChartInfo.x_axis_label );
|
||||
if( barChartInfo.y_axis_label != NULL ) g_free( (gchar*)barChartInfo.y_axis_label );
|
||||
|
||||
base64_buf = convert_pixbuf_to_base64_string( pixbuf );
|
||||
if( base64_buf == NULL ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*pResult = g_strdup_printf( "<img src=\"data:image/png;base64,%s \" alt=\"Cannot display barchart\"/>", base64_buf );
|
||||
|
||||
g_debug("barchart rendered.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* data_rows:int
|
||||
* data_cols:int
|
||||
* data:doubles[], data_rows*data_cols
|
||||
* x_axis_label:string
|
||||
* y_axis_label:string
|
||||
* row_labels:string[]
|
||||
* col_labels:string[]
|
||||
* col_colors:string[]
|
||||
* rotate_row_labels:boolean
|
||||
* stacked:boolean
|
||||
* markers:boolean
|
||||
* major_grid:boolean
|
||||
* minor_grid:boolean
|
||||
**/
|
||||
static gboolean
|
||||
handle_linechart( GncHtml* html, gpointer eb, gpointer d )
|
||||
{
|
||||
gchar* object_info = (gchar*)eb;
|
||||
gchar** pResult = (gchar**)d;
|
||||
GncHtmlLineChartInfo lineChartInfo;
|
||||
GdkPixbuf* pixbuf;
|
||||
gchar* p;
|
||||
gchar* p_end;
|
||||
gchar* temp_str;
|
||||
gchar* base64_buf;
|
||||
|
||||
lineChartInfo.width = get_int_value( &object_info, "width" );
|
||||
lineChartInfo.height = get_int_value( &object_info, "height" );
|
||||
lineChartInfo.title = get_string_param( &object_info, "title" );
|
||||
lineChartInfo.subtitle = get_string_param( &object_info, "subtitle" );
|
||||
lineChartInfo.data_rows = get_int_param( &object_info, "data_rows" );
|
||||
lineChartInfo.data_cols = get_int_param( &object_info, "data_cols" );
|
||||
temp_str = get_string_param( &object_info, "data" );
|
||||
if( temp_str != NULL ) {
|
||||
lineChartInfo.data = read_doubles( temp_str, lineChartInfo.data_rows*lineChartInfo.data_cols );
|
||||
}
|
||||
lineChartInfo.x_axis_label = get_string_param( &object_info, "x_axis_label" );
|
||||
lineChartInfo.y_axis_label = get_string_param( &object_info, "y_axis_label" );
|
||||
temp_str = get_string_param( &object_info, "col_colors" );
|
||||
if( temp_str != NULL ) {
|
||||
lineChartInfo.col_colors = read_strings( temp_str, lineChartInfo.data_cols );
|
||||
g_free( temp_str );
|
||||
}
|
||||
temp_str = get_string_param( &object_info, "row_labels" );
|
||||
if( temp_str != NULL ) {
|
||||
lineChartInfo.row_labels = read_strings( temp_str, lineChartInfo.data_rows );
|
||||
g_free( temp_str );
|
||||
}
|
||||
temp_str = get_string_param( &object_info, "col_labels" );
|
||||
if( temp_str != NULL ) {
|
||||
lineChartInfo.col_labels = read_strings( temp_str, lineChartInfo.data_cols );
|
||||
g_free( temp_str );
|
||||
}
|
||||
lineChartInfo.rotate_row_labels = get_int_param( &object_info, "rotate_row_labels" );
|
||||
lineChartInfo.stacked = get_int_param( &object_info, "stacked" );
|
||||
lineChartInfo.markers = get_int_param( &object_info, "markers" );
|
||||
lineChartInfo.major_grid = get_int_param( &object_info, "major_grid" );
|
||||
lineChartInfo.minor_grid = get_int_param( &object_info, "minor_grid" );
|
||||
|
||||
pixbuf = gnc_html_graph_gog_create_linechart( &lineChartInfo );
|
||||
if( lineChartInfo.title != NULL ) g_free( (gchar*)lineChartInfo.title );
|
||||
if( lineChartInfo.subtitle != NULL ) g_free( (gchar*)lineChartInfo.subtitle );
|
||||
if( lineChartInfo.x_axis_label != NULL ) g_free( (gchar*)lineChartInfo.x_axis_label );
|
||||
if( lineChartInfo.y_axis_label != NULL ) g_free( (gchar*)lineChartInfo.y_axis_label );
|
||||
|
||||
base64_buf = convert_pixbuf_to_base64_string( pixbuf );
|
||||
if( base64_buf == NULL ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*pResult = g_strdup_printf( "<img src=\"data:image/png;base64,%s \" alt=\"Cannot display linechart\"/>", base64_buf );
|
||||
|
||||
g_debug("linechart rendered.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
handle_scatter( GncHtml* html, gpointer eb, gpointer d )
|
||||
{
|
||||
gchar* object_info = (gchar*)eb;
|
||||
gchar** pResult = (gchar**)d;
|
||||
GncHtmlScatterPlotInfo scatterPlotInfo;
|
||||
GdkPixbuf* pixbuf;
|
||||
gchar* p;
|
||||
gchar* p_end;
|
||||
gchar* temp_str;
|
||||
gchar* base64_buf;
|
||||
|
||||
scatterPlotInfo.width = get_int_value( &object_info, "width" );
|
||||
scatterPlotInfo.height = get_int_value( &object_info, "height" );
|
||||
scatterPlotInfo.title = get_string_param( &object_info, "title" );
|
||||
scatterPlotInfo.subtitle = get_string_param( &object_info, "subtitle" );
|
||||
scatterPlotInfo.x_axis_label = get_string_param( &object_info, "x_axis_label" );
|
||||
scatterPlotInfo.y_axis_label = get_string_param( &object_info, "y_axis_label" );
|
||||
scatterPlotInfo.marker_str = get_string_param( &object_info, "marker" );
|
||||
scatterPlotInfo.color_str = get_string_param( &object_info, "color" );
|
||||
scatterPlotInfo.datasize = get_int_param( &object_info, "datasize" );
|
||||
temp_str = get_string_param( &object_info, "x_data" );
|
||||
if( temp_str != NULL ) {
|
||||
scatterPlotInfo.xData = read_doubles( temp_str, scatterPlotInfo.datasize );
|
||||
}
|
||||
temp_str = get_string_param( &object_info, "y_data" );
|
||||
if( temp_str != NULL ) {
|
||||
scatterPlotInfo.yData = read_doubles( temp_str, scatterPlotInfo.datasize );
|
||||
}
|
||||
|
||||
pixbuf = gnc_html_graph_gog_create_scatterplot( &scatterPlotInfo );
|
||||
if( scatterPlotInfo.title != NULL ) g_free( (gchar*)scatterPlotInfo.title );
|
||||
if( scatterPlotInfo.subtitle != NULL ) g_free( (gchar*)scatterPlotInfo.subtitle );
|
||||
|
||||
base64_buf = convert_pixbuf_to_base64_string( pixbuf );
|
||||
if( base64_buf == NULL ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*pResult = g_strdup_printf( "<img src=\"data:image/png;base64,%s \" alt=\"Cannot display scatterplot\"/>", base64_buf );
|
||||
|
||||
g_debug("scatterplot rendered.");
|
||||
return TRUE;
|
||||
}
|
30
src/html/gnc-html-graph-gog-webkit.h
Normal file
30
src/html/gnc-html-graph-gog-webkit.h
Normal file
@ -0,0 +1,30 @@
|
||||
/********************************************************************
|
||||
* gnc-html_graph_gog_webkit.h -- display html with gnc special *
|
||||
* tags *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_GRAPH_GOG_WEBKIT_H
|
||||
#define GNC_HTML_GRAPH_GOG_WEBKIT_H 1
|
||||
|
||||
void gnc_html_graph_gog_webkit_init( void );
|
||||
|
||||
#endif /* GNC_HTML_GRAPH_GOG_WEBKIT_H */
|
528
src/html/gnc-html-graph-gog.c
Normal file
528
src/html/gnc-html-graph-gog.c
Normal file
@ -0,0 +1,528 @@
|
||||
/********************************************************************
|
||||
* gnc-html-graph-gog.c -- GNC/HTML Graphing support via GOG *
|
||||
* *
|
||||
* Copyright (C) 2005 Joshua Sled <jsled@asynchronous.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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-html-graph-gog.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-engine.h"
|
||||
#include <goffice/goffice.h>
|
||||
#include <goffice/graph/gog-chart.h>
|
||||
#include <goffice/graph/gog-graph.h>
|
||||
#include <goffice/graph/gog-object.h>
|
||||
#if defined(HAVE_GOFFICE_0_5)
|
||||
# include <goffice/graph/gog-renderer.h>
|
||||
#elif defined(GOFFICE_WITH_CAIRO)
|
||||
# include <goffice/graph/gog-renderer-cairo.h>
|
||||
#else
|
||||
# include <goffice/graph/gog-renderer-pixbuf.h>
|
||||
#endif
|
||||
#ifndef GTKHTML_USES_GTKPRINT
|
||||
# include <goffice/graph/gog-renderer-gnome-print.h>
|
||||
#endif
|
||||
#include <goffice/graph/gog-style.h>
|
||||
#include <goffice/graph/gog-styled-object.h>
|
||||
#include <goffice/graph/gog-plot.h>
|
||||
#include <goffice/graph/gog-series.h>
|
||||
#include <goffice/utils/go-color.h>
|
||||
#include <goffice/utils/go-marker.h>
|
||||
#include <goffice/graph/gog-data-set.h>
|
||||
#include <goffice/data/go-data-simple.h>
|
||||
#include <goffice/app/go-plugin.h>
|
||||
#include <goffice/app/go-plugin-loader-module.h>
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* - scatter-plot marker selection
|
||||
* - series-color, piecharts (hard, not really supported by GOG)
|
||||
* and scatters (or drop feature)
|
||||
* - title-string freeing (fixmes)
|
||||
* - general graph cleanup
|
||||
**/
|
||||
|
||||
#undef G_LOG_DOMAIN
|
||||
#define G_LOG_DOMAIN "gnc.html.graph.gog"
|
||||
|
||||
static gboolean create_basic_plot_elements(const char *plot_type, GogObject **out_graph, GogObject **out_chart, GogPlot **out_plot);
|
||||
|
||||
static void set_chart_titles(GogObject *chart, const char *title, const char* sub_title);
|
||||
static void set_chart_axis_labels(GogObject *chart, const char *x_axis_label, const char* y_axis_label);
|
||||
|
||||
void
|
||||
gnc_html_graph_gog_init( void )
|
||||
{
|
||||
static gboolean initialized = FALSE;
|
||||
|
||||
if( !initialized ) {
|
||||
g_debug( "init gog graphing" );
|
||||
|
||||
libgoffice_init();
|
||||
|
||||
/* Initialize plugins manager */
|
||||
go_plugins_init( NULL, NULL, NULL, NULL, TRUE, GO_PLUGIN_LOADER_MODULE_TYPE );
|
||||
|
||||
initialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static GdkPixbuf*
|
||||
create_graph_pixbuf( GogObject *graph, int width, int height )
|
||||
{
|
||||
#if defined(HAVE_GOFFICE_0_5)
|
||||
GogRenderer *renderer;
|
||||
#elif defined(GOFFICE_WITH_CAIRO)
|
||||
GogRendererCairo *cairo_renderer;
|
||||
#else
|
||||
GogRendererPixbuf *pixbuf_renderer;
|
||||
#endif
|
||||
GdkPixbuf *buf;
|
||||
gboolean update_status;
|
||||
|
||||
// Note that this shouldn't be necessary as per discussion with Jody...
|
||||
// ... but it is because we don't embed in a control which passes the
|
||||
// update requests back to the graph widget, a-la the foo-canvas that
|
||||
// gnumeric uses. We probably _should_ do something like that, though.
|
||||
gog_object_update (GOG_OBJECT (graph));
|
||||
|
||||
#if defined(HAVE_GOFFICE_0_5)
|
||||
renderer = GOG_RENDERER(g_object_new( GOG_RENDERER_TYPE, "model", graph, NULL ));
|
||||
update_status = gog_renderer_update( renderer, width, height );
|
||||
buf = gog_renderer_get_pixbuf( renderer );
|
||||
#elif defined(GOFFICE_WITH_CAIRO)
|
||||
cairo_renderer = GOG_RENDERER_CAIRO(g_object_new( GOG_RENDERER_CAIRO_TYPE,
|
||||
"model", graph,
|
||||
NULL ));
|
||||
update_status = gog_renderer_cairo_update( cairo_renderer, width, height, 1.0 );
|
||||
buf = gog_renderer_cairo_get_pixbuf( cairo_renderer );
|
||||
#else
|
||||
pixbuf_renderer = GOG_RENDERER_PIXBUF(g_object_new( GOG_RENDERER_PIXBUF_TYPE,
|
||||
"model", graph,
|
||||
NULL));
|
||||
update_status = gog_renderer_pixbuf_update( pixbuf_renderer, width, height, 1.0 );
|
||||
buf = gog_renderer_pixbuf_get( pixbuf_renderer );
|
||||
#endif
|
||||
|
||||
g_object_set_data_full( G_OBJECT(buf), "graph", graph, g_object_unref );
|
||||
return buf;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_basic_plot_elements(const char *plot_type_name,
|
||||
GogObject **out_graph,
|
||||
GogObject **out_chart,
|
||||
GogPlot **out_plot)
|
||||
{
|
||||
*out_graph = g_object_new(GOG_GRAPH_TYPE, NULL);
|
||||
*out_chart = gog_object_add_by_name(*out_graph, "Chart", NULL);
|
||||
*out_plot = gog_plot_new_by_name(plot_type_name);
|
||||
if (!*out_plot)
|
||||
{
|
||||
// FIXME - log betterer; should probably use GError?
|
||||
g_warning("gog: unable to load %s plugin", plot_type_name);
|
||||
return FALSE;
|
||||
}
|
||||
gog_object_add_by_name(*out_chart, "Plot", GOG_OBJECT(*out_plot) );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_titles(GogObject *chart, const char *title, const char* sub_title)
|
||||
{
|
||||
gchar *my_sub_title, *total_title;
|
||||
GOData *title_scalar;
|
||||
GogObject *tmp;
|
||||
|
||||
if (sub_title)
|
||||
my_sub_title = g_strdup_printf("%s(%s)", title ? " " : "", sub_title);
|
||||
else
|
||||
my_sub_title = g_strdup("");
|
||||
|
||||
total_title = g_strdup_printf("%s%s", title ? title : "", my_sub_title);
|
||||
|
||||
tmp = gog_object_add_by_name(chart, "Title", NULL);
|
||||
title_scalar = go_data_scalar_str_new(total_title, TRUE);
|
||||
gog_dataset_set_dim(GOG_DATASET(tmp), 0, title_scalar, NULL);
|
||||
|
||||
g_free(my_sub_title);
|
||||
}
|
||||
|
||||
static void
|
||||
set_chart_axis_labels(GogObject *chart, const char *x_axis_label, const char* y_axis_label)
|
||||
{
|
||||
if (x_axis_label != NULL)
|
||||
{
|
||||
GogObject *xaxis, *label;
|
||||
GOData *data;
|
||||
xaxis = gog_object_get_child_by_role(chart, gog_object_find_role_by_name(chart, "X-Axis"));
|
||||
label = gog_object_add_by_name(xaxis, "Label", NULL);
|
||||
data = go_data_scalar_str_new(x_axis_label, FALSE);
|
||||
gog_dataset_set_dim(GOG_DATASET(label), 0, data, NULL);
|
||||
}
|
||||
|
||||
if (y_axis_label != NULL)
|
||||
{
|
||||
GogObject *yaxis, *label;
|
||||
GOData *data;
|
||||
yaxis = gog_object_get_child_by_role(chart, gog_object_find_role_by_name(chart, "Y-Axis"));
|
||||
label = gog_object_add_by_name(yaxis, "Label", NULL);
|
||||
data = go_data_scalar_str_new(y_axis_label, FALSE);
|
||||
gog_dataset_set_dim(GOG_DATASET(label), 0, data, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the following parameters:
|
||||
* title: text
|
||||
* subtitle: text
|
||||
* datasize: (length data), sscanf( .., %d, (int)&datasize )
|
||||
* data: (foreach (lambda (datum) (push datum) (push " ")) data)
|
||||
* colors: string; space-seperated?
|
||||
* labels: string; space-seperated?
|
||||
* slice_urls_[123]: ?
|
||||
* legend_urls_[123]: ?
|
||||
*/
|
||||
GdkPixbuf*
|
||||
gnc_html_graph_gog_create_piechart( GncHtmlPieChartInfo* info )
|
||||
{
|
||||
GogObject *graph, *chart;
|
||||
GogPlot *plot;
|
||||
GogSeries *series;
|
||||
GOData *labelData, *sliceData;
|
||||
GdkPixbuf* pixbuf;
|
||||
|
||||
if( !create_basic_plot_elements( "GogPiePlot", &graph, &chart, &plot ) ) {
|
||||
return NULL;
|
||||
}
|
||||
gog_object_add_by_name( chart, "Legend", NULL );
|
||||
|
||||
GOG_STYLED_OBJECT(graph)->style->outline.width = 5;
|
||||
GOG_STYLED_OBJECT(graph)->style->outline.color = RGBA_BLACK;
|
||||
|
||||
series = gog_plot_new_series( plot );
|
||||
labelData = go_data_vector_str_new( (gchar const * const *)info->labels, info->datasize, NULL );
|
||||
gog_series_set_dim( series, 0, labelData, NULL );
|
||||
go_data_emit_changed( GO_DATA(labelData) );
|
||||
|
||||
sliceData = go_data_vector_val_new( info->data, info->datasize, NULL );
|
||||
gog_series_set_dim( series, 1, sliceData, NULL );
|
||||
go_data_emit_changed( GO_DATA(sliceData) );
|
||||
|
||||
// fixme: colors
|
||||
set_chart_titles( chart, info->title, info->subtitle );
|
||||
|
||||
pixbuf = create_graph_pixbuf( graph, info->width, info->height );
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* data_rows:int
|
||||
* data_cols:int
|
||||
* data:doubles[], data_rows*data_cols
|
||||
* x_axis_label:string
|
||||
* y_axis_label:string
|
||||
* row_labels:string[]
|
||||
* col_labels:string[]
|
||||
* col_colors:string[]
|
||||
* rotate_row_labels:boolean
|
||||
* stacked:boolean
|
||||
**/
|
||||
GdkPixbuf*
|
||||
gnc_html_graph_gog_create_barchart( GncHtmlBarChartInfo* info )
|
||||
{
|
||||
GogObject *graph, *chart;
|
||||
GogPlot *plot;
|
||||
GogSeries *series;
|
||||
GogStyle *style;
|
||||
GOData *label_data, *slice_data;
|
||||
char *bar_type = "normal";
|
||||
int bar_overlap = 0 /*percent*/; // seperate bars; no overlap.
|
||||
GdkPixbuf* pixbuf;
|
||||
|
||||
if( !create_basic_plot_elements( "GogBarColPlot", &graph, &chart, &plot ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
gog_object_add_by_name( chart, "Legend", NULL );
|
||||
|
||||
if( info->stacked ) {
|
||||
// when stacked, we want the bars on _top_ of eachother.
|
||||
bar_type = "stacked";
|
||||
bar_overlap = 100 /*percent*/;
|
||||
}
|
||||
|
||||
g_object_set( G_OBJECT(plot),
|
||||
//"vary_style_by_element", TRUE,
|
||||
"type", bar_type,
|
||||
"overlap_percentage", bar_overlap,
|
||||
NULL);
|
||||
label_data = go_data_vector_str_new( (gchar const * const *)info->row_labels, info->data_rows, NULL );
|
||||
{
|
||||
// foreach row:
|
||||
// series = row
|
||||
GdkColor color;
|
||||
int i;
|
||||
for( i = 0; i < info->data_cols; i++ ) {
|
||||
GError *err = NULL;
|
||||
|
||||
series = gog_plot_new_series( plot );
|
||||
gog_object_set_name( GOG_OBJECT(series), info->col_labels[i], &err );
|
||||
if( err != NULL ) {
|
||||
g_warning( "error setting name [%s] on series [%d]: [%s]",
|
||||
info->col_labels[i], i, err->message);
|
||||
}
|
||||
|
||||
g_object_ref( label_data );
|
||||
gog_series_set_dim( series, 0, label_data, NULL );
|
||||
go_data_emit_changed( GO_DATA(label_data) );
|
||||
|
||||
slice_data = go_data_vector_val_new( info->data + (i*info->data_rows), info->data_rows, NULL );
|
||||
gog_series_set_dim( series, 1, slice_data, NULL );
|
||||
go_data_emit_changed( GO_DATA(slice_data) );
|
||||
|
||||
style = gog_styled_object_get_style( GOG_STYLED_OBJECT(series) );
|
||||
style->fill.type = GOG_FILL_STYLE_PATTERN;
|
||||
if( gdk_color_parse( info->col_colors[i], &color ) ) {
|
||||
style->fill.auto_back = FALSE;
|
||||
go_pattern_set_solid( &style->fill.pattern, GDK_TO_UINT(color) );
|
||||
} else {
|
||||
g_warning( "cannot parse color [%s]", info->col_colors[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( info->rotate_row_labels ) {
|
||||
GogObject *object = gog_object_get_child_by_role(
|
||||
chart, gog_object_find_role_by_name( chart, "X-Axis" ) );
|
||||
style = gog_styled_object_get_style( GOG_STYLED_OBJECT(object) );
|
||||
gog_style_set_text_angle( style, 90.0 );
|
||||
}
|
||||
|
||||
set_chart_titles( chart, info->title, info->subtitle );
|
||||
set_chart_axis_labels( chart, info->x_axis_label, info->y_axis_label );
|
||||
|
||||
// we need to do this twice for the barchart... :p
|
||||
gog_object_update( GOG_OBJECT(graph) );
|
||||
|
||||
pixbuf = create_graph_pixbuf( graph, info->width, info->height );
|
||||
g_debug( "barchart rendered." );
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* data_rows:int
|
||||
* data_cols:int
|
||||
* data:doubles[], data_rows*data_cols
|
||||
* x_axis_label:string
|
||||
* y_axis_label:string
|
||||
* row_labels:string[]
|
||||
* col_labels:string[]
|
||||
* col_colors:string[]
|
||||
* rotate_row_labels:boolean
|
||||
* stacked:boolean
|
||||
* markers:boolean
|
||||
* major_grid:boolean
|
||||
* minor_grid:boolean
|
||||
**/
|
||||
GdkPixbuf*
|
||||
gnc_html_graph_gog_create_linechart( GncHtmlLineChartInfo* info )
|
||||
{
|
||||
GogObject *graph, *chart;
|
||||
GogPlot *plot;
|
||||
GogSeries *series;
|
||||
GogStyle *style;
|
||||
GOData *label_data, *slice_data;
|
||||
gchar* line_type = "normal";
|
||||
GdkPixbuf* pixbuf;
|
||||
|
||||
if( !create_basic_plot_elements( "GogLinePlot", &graph, &chart, &plot ) ) {
|
||||
return NULL;
|
||||
}
|
||||
gog_object_add_by_name( chart, "Legend", NULL );
|
||||
|
||||
if( info->stacked ) {
|
||||
// when stacked, we want the lines on _top_ of eachother.
|
||||
line_type = "stacked";
|
||||
}
|
||||
|
||||
g_object_set( G_OBJECT(plot),
|
||||
//"vary_style_by_element", TRUE,
|
||||
"type", line_type,
|
||||
"default-style-has-markers", info->markers,
|
||||
NULL);
|
||||
label_data = go_data_vector_str_new( (gchar const * const *)info->row_labels, info->data_rows, NULL );
|
||||
{
|
||||
// foreach row:
|
||||
// series = row
|
||||
GdkColor color;
|
||||
int i;
|
||||
for( i = 0; i < info->data_cols; i++ ) {
|
||||
GError *err = NULL;
|
||||
|
||||
series = gog_plot_new_series( plot );
|
||||
gog_object_set_name( GOG_OBJECT(series), info->col_labels[i], &err );
|
||||
if( err != NULL ) {
|
||||
g_warning( "error setting name [%s] on series [%d]: [%s]",
|
||||
info->col_labels[i], i, err->message );
|
||||
}
|
||||
|
||||
g_object_ref( label_data );
|
||||
gog_series_set_dim( series, 0, label_data, NULL );
|
||||
go_data_emit_changed( GO_DATA(label_data) );
|
||||
|
||||
slice_data = go_data_vector_val_new( info->data + (i* info->data_rows), info->data_rows, NULL );
|
||||
gog_series_set_dim( series, 1, slice_data, NULL );
|
||||
go_data_emit_changed( GO_DATA(slice_data) );
|
||||
|
||||
style = gog_styled_object_get_style( GOG_STYLED_OBJECT(series) );
|
||||
style->fill.type = GOG_FILL_STYLE_PATTERN;
|
||||
if( gdk_color_parse( info->col_colors[i], &color ) ) {
|
||||
style->fill.auto_back = FALSE;
|
||||
go_pattern_set_solid( &style->fill.pattern, GDK_TO_UINT(color) );
|
||||
} else {
|
||||
g_warning( "cannot parse color [%s]", info->col_colors[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( info->rotate_row_labels ) {
|
||||
GogObject *object = gog_object_get_child_by_role(
|
||||
chart, gog_object_find_role_by_name( chart, "X-Axis" ) );
|
||||
style = gog_styled_object_get_style( GOG_STYLED_OBJECT(object) );
|
||||
gog_style_set_text_angle( style, 90.0 );
|
||||
}
|
||||
|
||||
if( info->major_grid || info->minor_grid ) {
|
||||
GogObject *object;
|
||||
gog_object_add_by_name( chart,"Grid", NULL );
|
||||
object = gog_object_get_child_by_role( chart,
|
||||
gog_object_find_role_by_name( chart, "Y-Axis" ) );
|
||||
if( info->major_grid ) {
|
||||
gog_object_add_by_name( GOG_OBJECT(object), "MajorGrid", NULL );
|
||||
}
|
||||
if( info->minor_grid ) {
|
||||
gog_object_add_by_name( GOG_OBJECT (object), "MinorGrid", NULL );
|
||||
}
|
||||
}
|
||||
|
||||
set_chart_titles( chart, info->title, info->subtitle );
|
||||
set_chart_axis_labels( chart, info->x_axis_label, info->y_axis_label );
|
||||
|
||||
// we need to do this twice for the linechart... :p
|
||||
gog_object_update( GOG_OBJECT(graph) );
|
||||
|
||||
pixbuf = create_graph_pixbuf( graph, info->width, info->height );
|
||||
g_debug( "linechart rendered." );
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
GdkPixbuf*
|
||||
gnc_html_graph_gog_create_scatterplot( GncHtmlScatterPlotInfo* info )
|
||||
{
|
||||
GogObject *graph, *chart;
|
||||
GogPlot *plot;
|
||||
GogSeries *series;
|
||||
GOData *sliceData;
|
||||
GogStyle *style;
|
||||
gboolean fill = FALSE;
|
||||
|
||||
if( !create_basic_plot_elements( "GogXYPlot", &graph, &chart, &plot ) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
series = gog_plot_new_series( plot );
|
||||
style = gog_styled_object_get_style( GOG_STYLED_OBJECT(series) );
|
||||
|
||||
sliceData = go_data_vector_val_new( info->xData, info->datasize, NULL );
|
||||
gog_series_set_dim( series, 0, sliceData, NULL );
|
||||
go_data_emit_changed( GO_DATA(sliceData) );
|
||||
|
||||
sliceData = go_data_vector_val_new( info->yData, info->datasize, NULL );
|
||||
gog_series_set_dim( series, 1, sliceData, NULL );
|
||||
go_data_emit_changed( GO_DATA(sliceData) );
|
||||
|
||||
/* set marker shape */
|
||||
if( info->marker_str != NULL ) {
|
||||
GOMarkerShape shape;
|
||||
|
||||
if( g_str_has_prefix( info->marker_str, "filled ") ) {
|
||||
fill = TRUE;
|
||||
info->marker_str += 7;
|
||||
}
|
||||
shape = go_marker_shape_from_str( info->marker_str );
|
||||
if( shape != GO_MARKER_NONE ) {
|
||||
style->marker.auto_shape = FALSE;
|
||||
go_marker_set_shape( style->marker.mark, shape );
|
||||
} else {
|
||||
g_warning( "cannot parse marker shape [%s]", info->marker_str );
|
||||
}
|
||||
}
|
||||
|
||||
/* set marker and line colors */
|
||||
if( info->color_str != NULL ) {
|
||||
GdkColor color;
|
||||
if( gdk_color_parse( info->color_str, &color ) ) {
|
||||
style->marker.auto_outline_color = FALSE;
|
||||
go_marker_set_outline_color( style->marker.mark, GDK_TO_UINT(color) );
|
||||
style->line.auto_color = FALSE;
|
||||
style->line.color = GDK_TO_UINT(color);
|
||||
} else {
|
||||
g_warning( "cannot parse color [%s]", info->color_str );
|
||||
}
|
||||
}
|
||||
|
||||
/* set marker fill colors */
|
||||
if( fill ) {
|
||||
style->marker.auto_fill_color = style->marker.auto_outline_color;
|
||||
go_marker_set_fill_color( style->marker.mark,
|
||||
go_marker_get_outline_color( style->marker.mark ) );
|
||||
} else {
|
||||
GogStyle *chart_style = gog_styled_object_get_style( GOG_STYLED_OBJECT(chart) );
|
||||
|
||||
if( chart_style->fill.type == GOG_FILL_STYLE_PATTERN
|
||||
&& chart_style->fill.pattern.pattern == GO_PATTERN_SOLID ) {
|
||||
style->marker.auto_fill_color = FALSE;
|
||||
go_marker_set_fill_color( style->marker.mark, chart_style->fill.pattern.back );
|
||||
} else if( chart_style->fill.type == GOG_FILL_STYLE_PATTERN
|
||||
&& chart_style->fill.pattern.pattern == GO_PATTERN_FOREGROUND_SOLID ) {
|
||||
style->marker.auto_fill_color = FALSE;
|
||||
go_marker_set_fill_color( style->marker.mark, chart_style->fill.pattern.fore );
|
||||
} else {
|
||||
g_warning( "fill color of markers can only be set like a solid fill "
|
||||
"pattern of the chart" );
|
||||
}
|
||||
}
|
||||
|
||||
set_chart_titles( chart, info->title, info->subtitle );
|
||||
set_chart_axis_labels( chart, info->x_axis_label, info->y_axis_label );
|
||||
|
||||
// And twice for the scatter, too... :p
|
||||
gog_object_update( GOG_OBJECT(graph) );
|
||||
|
||||
return create_graph_pixbuf( graph, info->width, info->height );
|
||||
}
|
96
src/html/gnc-html-graph-gog.h
Normal file
96
src/html/gnc-html-graph-gog.h
Normal file
@ -0,0 +1,96 @@
|
||||
/********************************************************************
|
||||
* gnc-html_graph_gog.h -- display html with gnc special *
|
||||
* tags *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_GRAPH_GOG_H
|
||||
#define GNC_HTML_GRAPH_GOG_H 1
|
||||
|
||||
typedef struct {
|
||||
gint width;
|
||||
gint height;
|
||||
const gchar* title;
|
||||
const gchar* subtitle;
|
||||
gint datasize;
|
||||
gdouble* data;
|
||||
gchar** labels;
|
||||
gchar** colors;
|
||||
} GncHtmlPieChartInfo;
|
||||
|
||||
typedef struct {
|
||||
gint width;
|
||||
gint height;
|
||||
const gchar* title;
|
||||
const gchar* subtitle;
|
||||
gint data_rows;
|
||||
gint data_cols;
|
||||
gdouble* data;
|
||||
gchar** col_labels;
|
||||
gchar** row_labels;
|
||||
gchar** col_colors;
|
||||
const gchar* x_axis_label;
|
||||
const gchar* y_axis_label;
|
||||
gboolean rotate_row_labels;
|
||||
gboolean stacked;
|
||||
} GncHtmlBarChartInfo;
|
||||
|
||||
typedef struct {
|
||||
gint width;
|
||||
gint height;
|
||||
const gchar* title;
|
||||
const gchar* subtitle;
|
||||
gint data_rows;
|
||||
gint data_cols;
|
||||
gdouble* data;
|
||||
gchar** col_labels;
|
||||
gchar** row_labels;
|
||||
gchar** col_colors;
|
||||
gboolean rotate_row_labels;
|
||||
gboolean stacked;
|
||||
gboolean markers;
|
||||
gboolean major_grid;
|
||||
gboolean minor_grid;
|
||||
const gchar* x_axis_label;
|
||||
const gchar* y_axis_label;
|
||||
} GncHtmlLineChartInfo;
|
||||
|
||||
typedef struct {
|
||||
gint width;
|
||||
gint height;
|
||||
const gchar* title;
|
||||
const gchar* subtitle;
|
||||
const gchar* x_axis_label;
|
||||
const gchar* y_axis_label;
|
||||
gint datasize;
|
||||
gdouble* xData;
|
||||
gdouble* yData;
|
||||
const gchar* marker_str;
|
||||
const gchar* color_str;
|
||||
} GncHtmlScatterPlotInfo;
|
||||
|
||||
void gnc_html_graph_gog_init( void );
|
||||
GdkPixbuf* gnc_html_graph_gog_create_piechart( GncHtmlPieChartInfo* info );
|
||||
GdkPixbuf* gnc_html_graph_gog_create_barchart( GncHtmlBarChartInfo* info );
|
||||
GdkPixbuf* gnc_html_graph_gog_create_linechart( GncHtmlLineChartInfo* info );
|
||||
GdkPixbuf* gnc_html_graph_gog_create_scatterplot( GncHtmlScatterPlotInfo* info );
|
||||
|
||||
#endif /* GNC_HTML_GRAPH_GOG_H */
|
34
src/html/gnc-html-gtkhtml-p.h
Normal file
34
src/html/gnc-html-gtkhtml-p.h
Normal file
@ -0,0 +1,34 @@
|
||||
/********************************************************************
|
||||
* gnc-html-gtkhtml-p.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_GTKHTML_P_H
|
||||
#define GNC_HTML_GTKHTML_P_H
|
||||
|
||||
#include "gnc-html-p.h"
|
||||
|
||||
struct _GncHtmlGtkhtmlPrivate {
|
||||
struct _GncHtmlPrivate base;
|
||||
|
||||
GtkWidget* html; /* gtkhtml widget itself */
|
||||
};
|
||||
|
||||
#endif
|
932
src/html/gnc-html-gtkhtml.c
Normal file
932
src/html/gnc-html-gtkhtml.c
Normal file
@ -0,0 +1,932 @@
|
||||
/********************************************************************
|
||||
* gnc-html-gtkhtml.c -- display HTML with some special gnucash *
|
||||
* tags. *
|
||||
* *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* Copyright (C) 2001 Linas Vepstas <linas@linas.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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
********************************************************************/
|
||||
|
||||
// libgtkhtml docs:
|
||||
// http://www.fifi.org/doc/libgtkhtml-dev/html/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <regex.h>
|
||||
#include <libguile.h>
|
||||
|
||||
#include <gtkhtml/gtkhtml.h>
|
||||
#include <gtkhtml/gtkhtml-embedded.h>
|
||||
|
||||
#include "Account.h"
|
||||
#include "print-session.h"
|
||||
#include "gnc-engine.h"
|
||||
#include "gnc-gui-query.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-html-gtkhtml.h"
|
||||
#include "gnc-html-history.h"
|
||||
#include "gnc-html-graph-gog-gtkhtml.h"
|
||||
#include "gnc-ui.h"
|
||||
#include "gnc-ui-util.h"
|
||||
|
||||
G_DEFINE_TYPE(GncHtmlGtkhtml, gnc_html_gtkhtml, GNC_TYPE_HTML )
|
||||
|
||||
static void gnc_html_gtkhtml_dispose( GObject* obj );
|
||||
static void gnc_html_gtkhtml_finalize( GObject* obj );
|
||||
static void gnc_html_gtkhtml_class_init( GncHtmlGtkhtmlClass* klass );
|
||||
static void gnc_html_gtkhtml_init( GncHtmlGtkhtml* gs );
|
||||
|
||||
//#define GNC_HTML_GTKHTML_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), GNC_TYPE_HTML_GTKHTML, GncHtmlGtkhtmlPrivate))
|
||||
#define GNC_HTML_GTKHTML_GET_PRIVATE(o) (GNC_HTML_GTKHTML(o)->priv)
|
||||
|
||||
#include "gnc-html-gtkhtml-p.h"
|
||||
|
||||
/* indicates the debugging module that this .o belongs to. */
|
||||
static QofLogModule log_module = GNC_MOD_HTML;
|
||||
|
||||
/* hashes for URLType -> protocol and protocol -> URLType */
|
||||
//extern GHashTable* gnc_html_type_to_proto_hash;
|
||||
extern GHashTable* gnc_html_proto_to_type_hash;
|
||||
|
||||
/* hashes an HTML <object classid="ID"> classid to a handler function */
|
||||
extern GHashTable* gnc_html_object_handlers;
|
||||
|
||||
/* hashes handlers for loading different URLType data */
|
||||
extern GHashTable* gnc_html_stream_handlers;
|
||||
|
||||
/* hashes handlers for handling different URLType data */
|
||||
extern GHashTable* gnc_html_url_handlers;
|
||||
|
||||
static char error_404_format[] = "<html><body><h3>%s</h3><p>%s</body></html>";
|
||||
static char error_404_title[] = N_("Not found");
|
||||
static char error_404_body[] = N_("The specified URL could not be loaded.");
|
||||
|
||||
static void gtkhtml_pre_3_10_1_bug_workaround( GtkHTMLEmbedded* eb );
|
||||
static void gnc_html_url_requested_cb( GtkHTML* html, gchar* url,
|
||||
GtkHTMLStream* handle, gpointer data );
|
||||
static void gnc_html_on_url_cb( GtkHTML* html, const gchar* url, gpointer data );
|
||||
static void gnc_html_set_base_cb( GtkHTML* gtkhtml, const gchar* base, gpointer data );
|
||||
static void gnc_html_link_clicked_cb( GtkHTML* html, const gchar* url, gpointer data );
|
||||
static gboolean gnc_html_object_requested_cb( GtkHTML* html, GtkHTMLEmbedded* eb,
|
||||
gpointer data );
|
||||
static int gnc_html_button_press_cb( GtkWidget* widg, GdkEventButton* event,
|
||||
gpointer user_data );
|
||||
static void impl_gtkhtml_show_url( GncHtml* self, URLType type,
|
||||
const gchar* location, const gchar* label,
|
||||
gboolean new_window_hint );
|
||||
static void impl_gtkhtml_show_data( GncHtml* self, const gchar* data, int datalen );
|
||||
static void impl_gtkhtml_reload( GncHtml* self );
|
||||
static void impl_gtkhtml_copy_to_clipboard( GncHtml* self );
|
||||
static gboolean impl_gtkhtml_export_to_file( GncHtml* self, const gchar* filepath );
|
||||
static void impl_gtkhtml_print( GncHtml* self );
|
||||
static void impl_gtkhtml_cancel( GncHtml* self );
|
||||
static void impl_gtkhtml_set_parent( GncHtml* self, GtkWindow* parent );
|
||||
|
||||
static void
|
||||
gnc_html_gtkhtml_init( GncHtmlGtkhtml* self )
|
||||
{
|
||||
GncHtmlGtkhtmlPrivate* priv;
|
||||
GncHtmlGtkhtmlPrivate* new_priv;
|
||||
|
||||
new_priv = g_realloc( GNC_HTML(self)->priv, sizeof(GncHtmlGtkhtmlPrivate) );
|
||||
priv = self->priv = new_priv;
|
||||
|
||||
priv->html = gtk_html_new();
|
||||
gtk_container_add( GTK_CONTAINER(priv->base.container),
|
||||
GTK_WIDGET(priv->html) );
|
||||
|
||||
#ifdef HAVE_GTK_2_10
|
||||
g_object_ref_sink( priv->base.container );
|
||||
#else
|
||||
g_object_ref( priv->base.container );
|
||||
gtk_object_sink( GTK_OBJECT(priv->base.container) );
|
||||
#endif
|
||||
|
||||
/* signals */
|
||||
g_signal_connect( priv->html, "url_requested",
|
||||
G_CALLBACK(gnc_html_url_requested_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect( priv->html, "on_url",
|
||||
G_CALLBACK(gnc_html_on_url_cb),
|
||||
self );
|
||||
|
||||
g_signal_connect( priv->html, "set_base",
|
||||
G_CALLBACK(gnc_html_set_base_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect(priv->html, "link_clicked",
|
||||
G_CALLBACK(gnc_html_link_clicked_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect (priv->html, "object_requested",
|
||||
G_CALLBACK (gnc_html_object_requested_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect (priv->html, "button_press_event",
|
||||
G_CALLBACK (gnc_html_button_press_cb),
|
||||
self);
|
||||
|
||||
gtk_html_load_empty(GTK_HTML(priv->html));
|
||||
|
||||
LEAVE("retval %p", self);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_gtkhtml_class_init( GncHtmlGtkhtmlClass* klass )
|
||||
{
|
||||
GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
|
||||
GncHtmlClass* html_class = GNC_HTML_CLASS(klass);
|
||||
|
||||
gobject_class->dispose = gnc_html_gtkhtml_dispose;
|
||||
gobject_class->finalize = gnc_html_gtkhtml_finalize;
|
||||
|
||||
html_class->show_url = impl_gtkhtml_show_url;
|
||||
html_class->show_data = impl_gtkhtml_show_data;
|
||||
html_class->reload = impl_gtkhtml_reload;
|
||||
html_class->copy_to_clipboard = impl_gtkhtml_copy_to_clipboard;
|
||||
html_class->export_to_file = impl_gtkhtml_export_to_file;
|
||||
html_class->print = impl_gtkhtml_print;
|
||||
html_class->cancel = impl_gtkhtml_cancel;
|
||||
html_class->set_parent = impl_gtkhtml_set_parent;
|
||||
|
||||
// Initialize graphing support
|
||||
gnc_html_graph_gog_gtkhtml_init();
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_gtkhtml_dispose( GObject* obj )
|
||||
{
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(obj);
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
|
||||
if( priv->html != NULL ) {
|
||||
g_object_unref( G_OBJECT(priv->html) );
|
||||
priv->html = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(gnc_html_gtkhtml_parent_class)->dispose( obj );
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_gtkhtml_finalize( GObject* obj )
|
||||
{
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(obj);
|
||||
|
||||
// if( self->priv != NULL ) {
|
||||
// g_free( self->priv );
|
||||
self->priv = NULL;
|
||||
// }
|
||||
|
||||
G_OBJECT_CLASS(gnc_html_gtkhtml_parent_class)->finalize( obj );
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static char*
|
||||
extract_base_name(URLType type, const gchar* path)
|
||||
{
|
||||
gchar machine_rexp[] = "^(//[^/]*)/*(/.*)?$";
|
||||
gchar path_rexp[] = "^/*(.*)/+([^/]*)$";
|
||||
regex_t compiled_m, compiled_p;
|
||||
regmatch_t match[4];
|
||||
gchar * machine=NULL, * location = NULL, * base=NULL;
|
||||
gchar * basename=NULL;
|
||||
|
||||
DEBUG(" ");
|
||||
if(!path) return NULL;
|
||||
|
||||
regcomp(&compiled_m, machine_rexp, REG_EXTENDED);
|
||||
regcomp(&compiled_p, path_rexp, REG_EXTENDED);
|
||||
|
||||
if (!safe_strcmp (type, URL_TYPE_HTTP) ||
|
||||
!safe_strcmp (type, URL_TYPE_SECURE) ||
|
||||
!safe_strcmp (type, URL_TYPE_FTP)) {
|
||||
|
||||
/* step 1: split the machine name away from the path
|
||||
* components */
|
||||
if(!regexec(&compiled_m, path, 4, match, 0)) {
|
||||
/* $1 is the machine name */
|
||||
if(match[1].rm_so != -1) {
|
||||
machine = g_strndup(path+match[1].rm_so,
|
||||
match[1].rm_eo - match[1].rm_so);
|
||||
}
|
||||
/* $2 is the path */
|
||||
if(match[2].rm_so != -1) {
|
||||
location = g_strndup(path+match[2].rm_so,
|
||||
match[2].rm_eo - match[2].rm_so);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
location = g_strdup(path);
|
||||
}
|
||||
/* step 2: split up the path into prefix and file components */
|
||||
if(location) {
|
||||
if(!regexec(&compiled_p, location, 4, match, 0)) {
|
||||
if(match[1].rm_so != -1) {
|
||||
base = g_strndup(location+match[1].rm_so,
|
||||
match[1].rm_eo - match[1].rm_so);
|
||||
} else {
|
||||
base = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
regfree(&compiled_m);
|
||||
regfree(&compiled_p);
|
||||
|
||||
if(machine) {
|
||||
if(base && (strlen(base) > 0)) {
|
||||
basename = g_strconcat(machine, "/", base, "/", NULL);
|
||||
} else {
|
||||
basename = g_strconcat(machine, "/", NULL);
|
||||
}
|
||||
} else {
|
||||
if(base && (strlen(base) > 0)) {
|
||||
basename = g_strdup(base);
|
||||
} else {
|
||||
basename = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_free(machine);
|
||||
g_free(base);
|
||||
g_free(location);
|
||||
return basename;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
http_allowed()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
https_allowed()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* gnc_html_start_request: starts the gnc-http object working on an
|
||||
* http/https request.
|
||||
************************************************************/
|
||||
static void
|
||||
gnc_html_start_request( GncHtmlGtkhtml* self, gchar * uri, GtkHTMLStream * handle )
|
||||
{
|
||||
GList * handles = NULL;
|
||||
gint need_request = FALSE;
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
|
||||
/* we want to make a list of handles to fill with this URI.
|
||||
* multiple handles with the same URI will all get filled when the
|
||||
* request comes in. */
|
||||
DEBUG("requesting %s", uri);
|
||||
handles = g_hash_table_lookup( priv->base.request_info, uri );
|
||||
if( handles == NULL ) {
|
||||
need_request = TRUE;
|
||||
}
|
||||
|
||||
handles = g_list_append( handles, handle );
|
||||
g_hash_table_insert( priv->base.request_info, uri, handles );
|
||||
|
||||
if( need_request ) {
|
||||
g_critical("we've not supported network requests for years");
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_load_to_stream : actually do the work of loading the HTML
|
||||
* or binary data referenced by a URL and feeding it into the GtkHTML
|
||||
* widget.
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_load_to_stream( GncHtmlGtkhtml* self, GtkHTMLStream* handle,
|
||||
URLType type, const gchar* location,
|
||||
const gchar* label )
|
||||
{
|
||||
gchar* fdata = NULL;
|
||||
int fdata_len = 0;
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
|
||||
DEBUG( "type %s, location %s, label %s", type ? type : "(null)",
|
||||
location ? location : "(null)", label ? label : "(null)");
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
|
||||
if( gnc_html_stream_handlers != NULL ) {
|
||||
GncHTMLStreamCB stream_handler;
|
||||
|
||||
stream_handler = g_hash_table_lookup( gnc_html_stream_handlers, type );
|
||||
if( stream_handler ) {
|
||||
gboolean ok = stream_handler( location, &fdata, &fdata_len );
|
||||
|
||||
if( ok ) {
|
||||
fdata = fdata ? fdata : g_strdup( "" );
|
||||
gtk_html_write( GTK_HTML(priv->html), handle, fdata, fdata_len );
|
||||
gtk_html_end( GTK_HTML(priv->html), handle, GTK_HTML_STREAM_OK );
|
||||
} else {
|
||||
fdata = fdata ? fdata :
|
||||
g_strdup_printf( error_404_format,
|
||||
_(error_404_title), _(error_404_body) );
|
||||
gtk_html_write( GTK_HTML(priv->html), handle, fdata, strlen(fdata) );
|
||||
gtk_html_end( GTK_HTML(priv->html), handle, GTK_HTML_STREAM_ERROR );
|
||||
}
|
||||
|
||||
g_free( fdata );
|
||||
|
||||
if( label ) {
|
||||
while( gtk_events_pending() ) {
|
||||
gtk_main_iteration();
|
||||
}
|
||||
gtk_html_jump_to_anchor( GTK_HTML(priv->html), label );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
if( !safe_strcmp( type, URL_TYPE_SECURE ) ||
|
||||
!safe_strcmp( type, URL_TYPE_HTTP ) ) {
|
||||
|
||||
if( !safe_strcmp( type, URL_TYPE_SECURE ) ) {
|
||||
if( !https_allowed() ) {
|
||||
gnc_error_dialog( priv->base.parent,
|
||||
_("Secure HTTP access is disabled. "
|
||||
"You can enable it in the Network section of "
|
||||
"the Preferences dialog."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !http_allowed() ) {
|
||||
gnc_error_dialog( priv->base.parent,
|
||||
_("Network HTTP access is disabled. "
|
||||
"You can enable it in the Network section of "
|
||||
"the Preferences dialog."));
|
||||
} else {
|
||||
char *fullurl;
|
||||
|
||||
fullurl = gnc_build_url( type, location, label );
|
||||
gnc_html_start_request( self, fullurl, handle );
|
||||
}
|
||||
|
||||
} else {
|
||||
PWARN( "load_to_stream for inappropriate type\n"
|
||||
"\turl = '%s#%s'\n",
|
||||
location ? location : "(null)",
|
||||
label ? label : "(null)" );
|
||||
fdata = g_strdup_printf( error_404_format,
|
||||
_(error_404_title), _(error_404_body) );
|
||||
gtk_html_write( GTK_HTML(priv->html), handle, fdata, strlen (fdata) );
|
||||
gtk_html_end( GTK_HTML(priv->html), handle, GTK_HTML_STREAM_ERROR );
|
||||
g_free( fdata );
|
||||
}
|
||||
|
||||
} while( FALSE );
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_link_clicked_cb - called when user left-clicks on html
|
||||
* anchor.
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_link_clicked_cb( GtkHTML* html, const gchar* url, gpointer data )
|
||||
{
|
||||
URLType type;
|
||||
gchar* location = NULL;
|
||||
gchar* label = NULL;
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(data);
|
||||
|
||||
DEBUG("Clicked %s", url);
|
||||
type = gnc_html_parse_url( GNC_HTML(self), url, &location, &label );
|
||||
gnc_html_show_url( GNC_HTML(self), type, location, label, 0 );
|
||||
g_free( location );
|
||||
g_free( label );
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_url_requested_cb - called when a URL needs to be
|
||||
* loaded within the loading of a page (embedded image).
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_url_requested_cb( GtkHTML* html, gchar* url,
|
||||
GtkHTMLStream* handle, gpointer data )
|
||||
{
|
||||
URLType type;
|
||||
gchar* location = NULL;
|
||||
gchar* label = NULL;
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(data);
|
||||
|
||||
DEBUG( "requesting %s", url );
|
||||
type = gnc_html_parse_url( GNC_HTML(self), url, &location, &label );
|
||||
gnc_html_load_to_stream( self, handle, type, location, label );
|
||||
g_free( location );
|
||||
g_free( label );
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_object_requested_cb - called when an applet needs to be
|
||||
* loaded.
|
||||
********************************************************************/
|
||||
|
||||
static gboolean
|
||||
gnc_html_object_requested_cb( GtkHTML* html, GtkHTMLEmbedded* eb,
|
||||
gpointer data )
|
||||
{
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(data);
|
||||
GncHTMLObjectCB h;
|
||||
|
||||
DEBUG( " " );
|
||||
if( !eb || !(eb->classid) || !gnc_html_object_handlers ) return FALSE;
|
||||
|
||||
gtkhtml_pre_3_10_1_bug_workaround( eb );
|
||||
h = g_hash_table_lookup( gnc_html_object_handlers, eb->classid );
|
||||
if( h ) {
|
||||
return h( GNC_HTML(self), eb, data );
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_on_url_cb - called when user rolls over html anchor
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_on_url_cb( GtkHTML* html, const gchar* url, gpointer data )
|
||||
{
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(data);
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
|
||||
DEBUG( "Rollover %s", url ? url : "(null)" );
|
||||
g_free( priv->base.current_link );
|
||||
priv->base.current_link = g_strdup( url );
|
||||
if( priv->base.flyover_cb ) {
|
||||
(priv->base.flyover_cb)( GNC_HTML(self), url, priv->base.flyover_cb_data );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_set_base_cb
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_set_base_cb( GtkHTML* gtkhtml, const gchar* base,
|
||||
gpointer data )
|
||||
{
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(data);
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
URLType type;
|
||||
gchar* location = NULL;
|
||||
gchar* label = NULL;
|
||||
|
||||
DEBUG( "Setting base location to %s", base );
|
||||
type = gnc_html_parse_url( GNC_HTML(self), base, &location, &label );
|
||||
|
||||
g_free( priv->base.base_location );
|
||||
g_free( label );
|
||||
|
||||
priv->base.base_type = type;
|
||||
priv->base.base_location = location;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_button_press_cb
|
||||
* mouse button callback (if any)
|
||||
********************************************************************/
|
||||
|
||||
static int
|
||||
gnc_html_button_press_cb( GtkWidget* widg, GdkEventButton* event,
|
||||
gpointer user_data )
|
||||
{
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(user_data);
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
|
||||
DEBUG( "Button Press" );
|
||||
if( priv->base.button_cb != NULL ) {
|
||||
(priv->base.button_cb)( GNC_HTML(self), event, priv->base.button_cb_data );
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_open_scm
|
||||
* insert some scheme-generated HTML
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_open_scm( GncHtmlGtkhtml* self, const gchar * location,
|
||||
const gchar * label, int newwin )
|
||||
{
|
||||
PINFO("location='%s'", location ? location : "(null)");
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_show_data
|
||||
* display some HTML that the creator of the gnc-html got from
|
||||
* somewhere.
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
impl_gtkhtml_show_data( GncHtml* self, const char * data, int datalen )
|
||||
{
|
||||
GtkHTMLStream * handle;
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
|
||||
DEBUG( "datalen %d, data %20.20s", datalen, data );
|
||||
handle = gtk_html_begin( GTK_HTML(priv->html) );
|
||||
gtk_html_write( GTK_HTML(priv->html), handle, data, datalen );
|
||||
gtk_html_end( GTK_HTML(priv->html), handle, GTK_HTML_STREAM_OK );
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_show_url
|
||||
*
|
||||
* open a URL. This is called when the user clicks a link or
|
||||
* for the creator of the gnc_html window to explicitly request
|
||||
* a URL.
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
impl_gtkhtml_show_url( GncHtml* self, URLType type,
|
||||
const gchar* location, const gchar* label,
|
||||
gboolean new_window_hint )
|
||||
{
|
||||
GncHTMLUrlCB url_handler;
|
||||
GtkHTMLStream * handle;
|
||||
gboolean new_window;
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
|
||||
DEBUG(" ");
|
||||
|
||||
if( self == NULL ) return;
|
||||
if( location == NULL ) return;
|
||||
|
||||
/* make sure it's OK to show this URL type in this window */
|
||||
if( new_window_hint == 0 ) {
|
||||
if( priv->base.urltype_cb ) {
|
||||
new_window = !((priv->base.urltype_cb)( type ));
|
||||
} else {
|
||||
new_window = FALSE;
|
||||
}
|
||||
} else {
|
||||
new_window = TRUE;
|
||||
}
|
||||
|
||||
if( !new_window ) {
|
||||
gnc_html_cancel( GNC_HTML(self) );
|
||||
}
|
||||
|
||||
if( gnc_html_url_handlers ) {
|
||||
url_handler = g_hash_table_lookup( gnc_html_url_handlers, type );
|
||||
} else {
|
||||
url_handler = NULL;
|
||||
}
|
||||
|
||||
if( url_handler ) {
|
||||
GNCURLResult result;
|
||||
gboolean ok;
|
||||
|
||||
result.load_to_stream = FALSE;
|
||||
result.url_type = type;
|
||||
result.location = NULL;
|
||||
result.label = NULL;
|
||||
result.base_type = URL_TYPE_FILE;
|
||||
result.base_location = NULL;
|
||||
result.error_message = NULL;
|
||||
|
||||
ok = url_handler( location, label, new_window, &result );
|
||||
if( !ok ) {
|
||||
if( result.error_message ) {
|
||||
gnc_error_dialog( priv->base.parent, "%s", result.error_message );
|
||||
} else {
|
||||
/* %s is a URL (some location somewhere). */
|
||||
gnc_error_dialog( priv->base.parent, _("There was an error accessing %s."), location );
|
||||
}
|
||||
|
||||
if( priv->base.load_cb ) {
|
||||
priv->base.load_cb( GNC_HTML(self), result.url_type,
|
||||
location, label, priv->base.load_cb_data );
|
||||
}
|
||||
} else if( result.load_to_stream ) {
|
||||
gnc_html_history_node *hnode;
|
||||
const char *new_location;
|
||||
const char *new_label;
|
||||
GtkHTMLStream * stream;
|
||||
|
||||
new_location = result.location ? result.location : location;
|
||||
new_label = result.label ? result.label : label;
|
||||
hnode = gnc_html_history_node_new( result.url_type, new_location, new_label );
|
||||
|
||||
gnc_html_history_append( priv->base.history, hnode );
|
||||
|
||||
g_free( priv->base.base_location );
|
||||
priv->base.base_type = result.base_type;
|
||||
priv->base.base_location =
|
||||
g_strdup( extract_base_name( result.base_type, new_location ) );
|
||||
DEBUG( "resetting base location to %s",
|
||||
priv->base.base_location ? priv->base.base_location : "(null)" );
|
||||
|
||||
stream = gtk_html_begin( GTK_HTML(priv->html) );
|
||||
gnc_html_load_to_stream( GNC_HTML_GTKHTML(self), stream, result.url_type,
|
||||
new_location, new_label );
|
||||
|
||||
if( priv->base.load_cb != NULL ) {
|
||||
priv->base.load_cb( GNC_HTML(self), result.url_type,
|
||||
new_location, new_label, priv->base.load_cb_data );
|
||||
}
|
||||
}
|
||||
|
||||
g_free( result.location );
|
||||
g_free( result.label );
|
||||
g_free( result.base_location );
|
||||
g_free( result.error_message );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( safe_strcmp( type, URL_TYPE_SCHEME ) == 0 ) {
|
||||
gnc_html_open_scm( GNC_HTML_GTKHTML(self), location, label, new_window );
|
||||
|
||||
} else if( safe_strcmp( type, URL_TYPE_JUMP ) == 0 ) {
|
||||
gtk_html_jump_to_anchor( GTK_HTML(priv->html), label );
|
||||
|
||||
} else if( safe_strcmp( type, URL_TYPE_SECURE ) == 0 ||
|
||||
safe_strcmp( type, URL_TYPE_HTTP ) == 0 ||
|
||||
safe_strcmp( type, URL_TYPE_FILE ) == 0 ) {
|
||||
|
||||
do {
|
||||
if( safe_strcmp( type, URL_TYPE_SECURE ) == 0 ) {
|
||||
if( !https_allowed() ) {
|
||||
gnc_error_dialog( priv->base.parent,
|
||||
_("Secure HTTP access is disabled. "
|
||||
"You can enable it in the Network section of "
|
||||
"the Preferences dialog.") );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( safe_strcmp( type, URL_TYPE_HTTP ) == 0 ) {
|
||||
if( !http_allowed() ) {
|
||||
gnc_error_dialog( priv->base.parent,
|
||||
_("Network HTTP access is disabled. "
|
||||
"You can enable it in the Network section of "
|
||||
"the Preferences dialog.") );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
priv->base.base_type = type;
|
||||
|
||||
if( priv->base.base_location != NULL ) g_free( priv->base.base_location );
|
||||
priv->base.base_location = extract_base_name( type, location );
|
||||
|
||||
/* FIXME : handle new_window = 1 */
|
||||
gnc_html_history_append( priv->base.history,
|
||||
gnc_html_history_node_new( type, location, label ) );
|
||||
handle = gtk_html_begin( GTK_HTML(priv->html) );
|
||||
gnc_html_load_to_stream( GNC_HTML_GTKHTML(self), handle, type, location, label );
|
||||
|
||||
} while( FALSE );
|
||||
|
||||
} else {
|
||||
PERR( "URLType %s not supported.", type );
|
||||
}
|
||||
|
||||
if( priv->base.load_cb != NULL ) {
|
||||
(priv->base.load_cb)( GNC_HTML(self), type, location, label, priv->base.load_cb_data );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_reload
|
||||
* reload the current page
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
impl_gtkhtml_reload( GncHtml* self )
|
||||
{
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
gnc_html_history_node * n;
|
||||
|
||||
DEBUG(" ");
|
||||
n = gnc_html_history_get_current( priv->base.history );
|
||||
if( n != NULL ) {
|
||||
gnc_html_show_url( self, n->type, n->location, n->label, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_gtkhtml_new
|
||||
* create and set up a new gtkhtml widget.
|
||||
********************************************************************/
|
||||
|
||||
GncHtml*
|
||||
gnc_html_gtkhtml_new( void )
|
||||
{
|
||||
GncHtmlGtkhtml* self = g_object_new( GNC_TYPE_HTML_GTKHTML, NULL );
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
|
||||
return GNC_HTML(self);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_cancel
|
||||
* cancel any outstanding HTML fetch requests.
|
||||
********************************************************************/
|
||||
|
||||
static gboolean
|
||||
gtkhtml_cancel_helper(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
g_free(key);
|
||||
g_list_free((GList *)value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
impl_gtkhtml_cancel( GncHtml* self )
|
||||
{
|
||||
GncHtmlGtkhtmlPrivate* priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
/* remove our own references to requests */
|
||||
//gnc_http_cancel_requests( priv->http );
|
||||
|
||||
g_hash_table_foreach_remove( priv->base.request_info, gtkhtml_cancel_helper, NULL );
|
||||
}
|
||||
|
||||
static void
|
||||
impl_gtkhtml_copy_to_clipboard( GncHtml* self )
|
||||
{
|
||||
GncHtmlGtkhtmlPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
|
||||
priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
gtk_html_copy( GTK_HTML(priv->html) );
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* gnc_html_export_to_file : wrapper around the builtin function in gtkhtml
|
||||
**************************************************************/
|
||||
|
||||
static gboolean
|
||||
raw_html_receiver( gpointer engine,
|
||||
const gchar* data,
|
||||
size_t len,
|
||||
gpointer user_data )
|
||||
{
|
||||
FILE *fh = (FILE *) user_data;
|
||||
size_t written;
|
||||
|
||||
do {
|
||||
written = fwrite (data, 1, len, fh);
|
||||
len -= written;
|
||||
} while (len > 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
impl_gtkhtml_export_to_file( GncHtml* self, const char *filepath )
|
||||
{
|
||||
FILE *fh;
|
||||
GncHtmlGtkhtmlPrivate* priv;
|
||||
|
||||
g_return_val_if_fail( self != NULL, FALSE );
|
||||
g_return_val_if_fail( filepath != NULL, FALSE );
|
||||
|
||||
priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
fh = g_fopen( filepath, "w" );
|
||||
if( fh == 0 )
|
||||
return FALSE;
|
||||
|
||||
gtk_html_save( GTK_HTML(priv->html), GINT_TO_POINTER(raw_html_receiver), fh );
|
||||
fclose (fh);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef GTKHTML_USES_GTKPRINT
|
||||
static void
|
||||
draw_page_cb(GtkPrintOperation *operation, GtkPrintContext *context,
|
||||
gint page_nr, gpointer user_data)
|
||||
{
|
||||
GncHtmlGtkhtml* self = GNC_HTML_GTKHTML(user_data);
|
||||
GncHtmlGtkhtmlPrivate* priv;
|
||||
|
||||
priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
gtk_html_print_page( GTK_HTML(priv->html), context );
|
||||
}
|
||||
|
||||
static void
|
||||
impl_gtkhtml_print( GncHtml* self )
|
||||
{
|
||||
GtkPrintOperation *print;
|
||||
GtkPrintOperationResult res;
|
||||
GncHtmlGtkhtmlPrivate* priv;
|
||||
|
||||
priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
print = gtk_print_operation_new();
|
||||
|
||||
gnc_print_operation_init(print);
|
||||
gtk_print_operation_set_use_full_page(print, FALSE);
|
||||
gtk_print_operation_set_unit(print, GTK_UNIT_POINTS);
|
||||
gtk_print_operation_set_n_pages(print, 1);
|
||||
g_signal_connect(print, "draw_page", G_CALLBACK(draw_page_cb), self);
|
||||
|
||||
res = gtk_print_operation_run(print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
|
||||
GTK_WINDOW(priv->base.parent), NULL);
|
||||
|
||||
if( res == GTK_PRINT_OPERATION_RESULT_APPLY ) {
|
||||
gnc_print_operation_save_print_settings( print );
|
||||
}
|
||||
|
||||
g_object_unref(print);
|
||||
}
|
||||
|
||||
#else /* !GTKHTML_USES_GTKPRINT */
|
||||
void
|
||||
gnc_html_print( GncHtml* html )
|
||||
{
|
||||
PrintSession *ps;
|
||||
|
||||
ps = gnc_print_session_create( FALSE );
|
||||
if( ps == NULL ) {
|
||||
/* user cancelled */
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_html_print( GTK_HTML(html->html), ps->context );
|
||||
gnc_print_session_done( ps );
|
||||
}
|
||||
#endif /* GTKHTML_USES_GTKPRINT */
|
||||
|
||||
static void
|
||||
impl_gtkhtml_set_parent( GncHtml* self, GtkWindow* parent )
|
||||
{
|
||||
GncHtmlGtkhtmlPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
|
||||
priv = GNC_HTML_GTKHTML_GET_PRIVATE(self);
|
||||
priv->base.parent = GTK_WIDGET(parent);
|
||||
}
|
||||
|
||||
const gchar*
|
||||
gnc_html_get_embedded_param( gpointer eb, const gchar* param_name )
|
||||
{
|
||||
GtkHTMLEmbedded* gtk_eb = (GtkHTMLEmbedded*)eb;
|
||||
|
||||
return (const gchar *)g_hash_table_lookup(gtk_eb->params, param_name);
|
||||
}
|
||||
|
||||
static void
|
||||
gtkhtml_pre_3_10_1_bug_workaround(GtkHTMLEmbedded *eb)
|
||||
{
|
||||
/* HACK ALERT! Compensate for bug in gtkhtml < 3.10.1
|
||||
Gtkhtml set the width parameter twice (=width, =height), so both,
|
||||
width (==height) and height (<1) were incorrect. */
|
||||
if( eb->height < 1 ) {
|
||||
eb->height = eb->width; /* only squares here :( */
|
||||
}
|
||||
}
|
59
src/html/gnc-html-gtkhtml.h
Normal file
59
src/html/gnc-html-gtkhtml.h
Normal file
@ -0,0 +1,59 @@
|
||||
/********************************************************************
|
||||
* gnc-html-gtkhtml.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_GTKHTML_H
|
||||
#define GNC_HTML_GTKHTML_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "gnc-html.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GNC_TYPE_HTML_GTKHTML (gnc_html_gtkhtml_get_type())
|
||||
#define GNC_HTML_GTKHTML(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GNC_TYPE_HTML_GTKHTML, GncHtmlGtkhtml))
|
||||
#define GNC_HTML_GTKHTML_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GNC_TYPE_HTML_GTKHTML, GncHtmlGtkhtmlClass))
|
||||
#define GNC_IS_HTML_GTKHTML(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GNC_TYPE_HTML_GTKHTML))
|
||||
#define GNC_IS_HTML_GTKHTML_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GNC_TYPE_HTML_GTKHTML))
|
||||
#define GNC_HTML_GTKHTML_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GNC_TYPE_HTML_GTKHTML, GncHtmlGtkhtmlClass))
|
||||
|
||||
typedef struct _GncHtmlGtkhtml GncHtmlGtkhtml;
|
||||
typedef struct _GncHtmlGtkhtmlClass GncHtmlGtkhtmlClass;
|
||||
typedef struct _GncHtmlGtkhtmlPrivate GncHtmlGtkhtmlPrivate;
|
||||
|
||||
struct _GncHtmlGtkhtml {
|
||||
GncHtml parent_instance;
|
||||
|
||||
/*< private >*/
|
||||
GncHtmlGtkhtmlPrivate* priv;
|
||||
};
|
||||
|
||||
struct _GncHtmlGtkhtmlClass {
|
||||
GncHtmlClass parent_class;
|
||||
};
|
||||
|
||||
GType gnc_html_gtkhtml_get_type( void );
|
||||
|
||||
GncHtml* gnc_html_gtkhtml_new( void );
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
49
src/html/gnc-html-p.h
Normal file
49
src/html/gnc-html-p.h
Normal file
@ -0,0 +1,49 @@
|
||||
/********************************************************************
|
||||
* gnc-html-p.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_P_H
|
||||
#define GNC_HTML_P_H
|
||||
|
||||
struct _GncHtmlPrivate {
|
||||
GtkWidget* parent; /* window this html goes into */
|
||||
GtkWidget* container; /* parent of the gtkhtml widget */
|
||||
gchar* current_link; /* link under mouse pointer */
|
||||
|
||||
URLType base_type; /* base of URL (path - filename) */
|
||||
gchar* base_location;
|
||||
|
||||
GHashTable* request_info; /* hash uri to GList of GtkHTMLStream * */
|
||||
|
||||
/* callbacks */
|
||||
GncHTMLUrltypeCB urltype_cb; /* is this type OK for this instance? */
|
||||
GncHTMLLoadCB load_cb;
|
||||
GncHTMLFlyoverCB flyover_cb;
|
||||
GncHTMLButtonCB button_cb;
|
||||
|
||||
gpointer flyover_cb_data;
|
||||
gpointer load_cb_data;
|
||||
gpointer button_cb_data;
|
||||
|
||||
gnc_html_history * history;
|
||||
};
|
||||
|
||||
#endif
|
35
src/html/gnc-html-webkit-p.h
Normal file
35
src/html/gnc-html-webkit-p.h
Normal file
@ -0,0 +1,35 @@
|
||||
/********************************************************************
|
||||
* gnc-html-webkit-p.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_WEBKIT_P_H
|
||||
#define GNC_HTML_WEBKIT_P_H
|
||||
|
||||
#include "gnc-html-p.h"
|
||||
|
||||
struct _GncHtmlWebkitPrivate {
|
||||
struct _GncHtmlPrivate base;
|
||||
|
||||
WebKitWebView* web_view; /* webkit widget itself */
|
||||
gchar* html_string; /* html string being displayed */
|
||||
};
|
||||
|
||||
#endif
|
930
src/html/gnc-html-webkit.c
Normal file
930
src/html/gnc-html-webkit.c
Normal file
@ -0,0 +1,930 @@
|
||||
/********************************************************************
|
||||
* gnc-html_webkit.c -- display HTML with some special gnucash tags.*
|
||||
* *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* Copyright (C) 2001 Linas Vepstas <linas@linas.org> *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <regex.h>
|
||||
#include <libguile.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <webkit/webkit.h>
|
||||
|
||||
#include "Account.h"
|
||||
#include "gnc-gui-query.h"
|
||||
#include "gnc-engine.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-html-webkit.h"
|
||||
#include "gnc-html-history.h"
|
||||
#include "gnc-html-graph-gog-webkit.h"
|
||||
|
||||
G_DEFINE_TYPE(GncHtmlWebkit, gnc_html_webkit, GNC_TYPE_HTML )
|
||||
|
||||
static void gnc_html_webkit_dispose( GObject* obj );
|
||||
static void gnc_html_webkit_finalize( GObject* obj );
|
||||
static void gnc_html_webkit_class_init( GncHtmlWebkitClass* klass );
|
||||
static void gnc_html_webkit_init( GncHtmlWebkit* gs );
|
||||
|
||||
#define GNC_HTML_WEBKIT_GET_PRIVATE(o) (GNC_HTML_WEBKIT(o)->priv)
|
||||
|
||||
#include "gnc-html-webkit-p.h"
|
||||
|
||||
/* indicates the debugging module that this .o belongs to. */
|
||||
static QofLogModule log_module = GNC_MOD_HTML;
|
||||
|
||||
/* hashes for URLType -> protocol and protocol -> URLType */
|
||||
//extern GHashTable* gnc_html_type_to_proto_hash;
|
||||
extern GHashTable* gnc_html_proto_to_type_hash;
|
||||
|
||||
/* hashes an HTML <object classid="ID"> classid to a handler function */
|
||||
extern GHashTable* gnc_html_object_handlers;
|
||||
|
||||
/* hashes handlers for loading different URLType data */
|
||||
extern GHashTable* gnc_html_stream_handlers;
|
||||
|
||||
/* hashes handlers for handling different URLType data */
|
||||
extern GHashTable* gnc_html_url_handlers;
|
||||
|
||||
static char error_404_format[] = "<html><body><h3>%s</h3><p>%s</body></html>";
|
||||
static char error_404_title[] = N_("Not found");
|
||||
static char error_404_body[] = N_("The specified URL could not be loaded.");
|
||||
|
||||
static void webkit_navigation_requested_cb( WebKitWebView* web_view, GObject* arg1,
|
||||
GObject* arg2, gpointer data );
|
||||
static void webkit_on_url_cb( WebKitWebView* web_view, gchar* title, gchar* url,
|
||||
gpointer data );
|
||||
static gchar* handle_embedded_object( GncHtmlWebkit* self, gchar* html_str );
|
||||
#if 0
|
||||
static void gnc_html_set_base_cb( GtkHTML* gtkhtml, const gchar* base, gpointer data );
|
||||
static void gnc_html_link_clicked_cb( GtkHTML* html, const gchar* url, gpointer data );
|
||||
static gboolean gnc_html_object_requested_cb( GtkHTML* html, GtkHTMLEmbedded* eb,
|
||||
gpointer data );
|
||||
#endif
|
||||
static int gnc_html_button_press_cb( GtkWidget* widg, GdkEventButton* event,
|
||||
gpointer user_data );
|
||||
static void impl_webkit_show_url( GncHtml* self, URLType type,
|
||||
const gchar* location, const gchar* label,
|
||||
gboolean new_window_hint );
|
||||
static void impl_webkit_show_data( GncHtml* self, const gchar* data, int datalen );
|
||||
static void impl_webkit_reload( GncHtml* self );
|
||||
static void impl_webkit_copy_to_clipboard( GncHtml* self );
|
||||
static gboolean impl_webkit_export_to_file( GncHtml* self, const gchar* filepath );
|
||||
static void impl_webkit_print( GncHtml* self );
|
||||
static void impl_webkit_cancel( GncHtml* self );
|
||||
static void impl_webkit_set_parent( GncHtml* self, GtkWindow* parent );
|
||||
|
||||
static void
|
||||
gnc_html_webkit_init( GncHtmlWebkit* self )
|
||||
{
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
GncHtmlWebkitPrivate* new_priv;
|
||||
|
||||
new_priv = g_realloc( GNC_HTML(self)->priv, sizeof(GncHtmlWebkitPrivate) );
|
||||
priv = self->priv = new_priv;
|
||||
GNC_HTML(self)->priv = (GncHtmlPrivate*)priv;
|
||||
|
||||
priv->html_string = NULL;
|
||||
priv->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
|
||||
|
||||
gtk_container_add( GTK_CONTAINER(priv->base.container),
|
||||
GTK_WIDGET(priv->web_view) );
|
||||
|
||||
#ifdef HAVE_GTK_2_10
|
||||
g_object_ref_sink( priv->base.container );
|
||||
#else
|
||||
g_object_ref( priv->base.container );
|
||||
gtk_object_sink( GTK_OBJECT(priv->base.container) );
|
||||
#endif
|
||||
|
||||
/* signals */
|
||||
g_signal_connect( priv->web_view, "navigation-requested",
|
||||
G_CALLBACK(webkit_navigation_requested_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect( priv->web_view, "hovering-over-link",
|
||||
G_CALLBACK(webkit_on_url_cb),
|
||||
self );
|
||||
|
||||
#if 0
|
||||
g_signal_connect( priv->html, "set_base",
|
||||
G_CALLBACK(gnc_html_set_base_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect(priv->html, "link_clicked",
|
||||
G_CALLBACK(gnc_html_link_clicked_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect (priv->html, "object_requested",
|
||||
G_CALLBACK (gnc_html_object_requested_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect (priv->html, "button_press_event",
|
||||
G_CALLBACK (gnc_html_button_press_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect (priv->html, "submit",
|
||||
G_CALLBACK(gnc_html_submit_cb),
|
||||
self);
|
||||
#endif
|
||||
|
||||
LEAVE("retval %p", self);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_webkit_class_init( GncHtmlWebkitClass* klass )
|
||||
{
|
||||
GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
|
||||
GncHtmlClass* html_class = GNC_HTML_CLASS(klass);
|
||||
|
||||
gobject_class->dispose = gnc_html_webkit_dispose;
|
||||
gobject_class->finalize = gnc_html_webkit_finalize;
|
||||
|
||||
html_class->show_url = impl_webkit_show_url;
|
||||
html_class->show_data = impl_webkit_show_data;
|
||||
html_class->reload = impl_webkit_reload;
|
||||
html_class->copy_to_clipboard = impl_webkit_copy_to_clipboard;
|
||||
html_class->export_to_file = impl_webkit_export_to_file;
|
||||
html_class->print = impl_webkit_print;
|
||||
html_class->cancel = impl_webkit_cancel;
|
||||
html_class->set_parent = impl_webkit_set_parent;
|
||||
|
||||
// Initialize graphing support
|
||||
gnc_html_graph_gog_webkit_init();
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_webkit_dispose( GObject* obj )
|
||||
{
|
||||
GncHtmlWebkit* self = GNC_HTML_WEBKIT(obj);
|
||||
GncHtmlWebkitPrivate* priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
|
||||
if( priv->web_view != NULL ) {
|
||||
gtk_container_remove( GTK_CONTAINER(priv->base.container),
|
||||
GTK_WIDGET(priv->web_view) );
|
||||
g_object_unref( G_OBJECT(priv->web_view) );
|
||||
priv->web_view = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(gnc_html_webkit_parent_class)->dispose( obj );
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_webkit_finalize( GObject* obj )
|
||||
{
|
||||
GncHtmlWebkit* self = GNC_HTML_WEBKIT(obj);
|
||||
|
||||
// if( self->priv != NULL ) {
|
||||
// g_free( self->priv );
|
||||
self->priv = NULL;
|
||||
// }
|
||||
|
||||
G_OBJECT_CLASS(gnc_html_webkit_parent_class)->finalize( obj );
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static char*
|
||||
extract_base_name(URLType type, const gchar* path)
|
||||
{
|
||||
gchar machine_rexp[] = "^(//[^/]*)/*(/.*)?$";
|
||||
gchar path_rexp[] = "^/*(.*)/+([^/]*)$";
|
||||
regex_t compiled_m, compiled_p;
|
||||
regmatch_t match[4];
|
||||
gchar * machine=NULL, * location = NULL, * base=NULL;
|
||||
gchar * basename=NULL;
|
||||
|
||||
DEBUG(" ");
|
||||
if(!path) return NULL;
|
||||
|
||||
regcomp(&compiled_m, machine_rexp, REG_EXTENDED);
|
||||
regcomp(&compiled_p, path_rexp, REG_EXTENDED);
|
||||
|
||||
if (!safe_strcmp (type, URL_TYPE_HTTP) ||
|
||||
!safe_strcmp (type, URL_TYPE_SECURE) ||
|
||||
!safe_strcmp (type, URL_TYPE_FTP)) {
|
||||
|
||||
/* step 1: split the machine name away from the path
|
||||
* components */
|
||||
if(!regexec(&compiled_m, path, 4, match, 0)) {
|
||||
/* $1 is the machine name */
|
||||
if(match[1].rm_so != -1) {
|
||||
machine = g_strndup(path+match[1].rm_so,
|
||||
match[1].rm_eo - match[1].rm_so);
|
||||
}
|
||||
/* $2 is the path */
|
||||
if(match[2].rm_so != -1) {
|
||||
location = g_strndup(path+match[2].rm_so,
|
||||
match[2].rm_eo - match[2].rm_so);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
location = g_strdup(path);
|
||||
}
|
||||
/* step 2: split up the path into prefix and file components */
|
||||
if(location) {
|
||||
if(!regexec(&compiled_p, location, 4, match, 0)) {
|
||||
if(match[1].rm_so != -1) {
|
||||
base = g_strndup(location+match[1].rm_so,
|
||||
match[1].rm_eo - match[1].rm_so);
|
||||
} else {
|
||||
base = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
regfree(&compiled_m);
|
||||
regfree(&compiled_p);
|
||||
|
||||
if(machine) {
|
||||
if(base && (strlen(base) > 0)) {
|
||||
basename = g_strconcat(machine, "/", base, "/", NULL);
|
||||
} else {
|
||||
basename = g_strconcat(machine, "/", NULL);
|
||||
}
|
||||
} else {
|
||||
if(base && (strlen(base) > 0)) {
|
||||
basename = g_strdup(base);
|
||||
} else {
|
||||
basename = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_free(machine);
|
||||
g_free(base);
|
||||
g_free(location);
|
||||
return basename;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
http_allowed()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
https_allowed()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gchar*
|
||||
handle_embedded_object( GncHtmlWebkit* self, gchar* html_str )
|
||||
{
|
||||
// Find the <object> tag and get the classid from it. This will provide the correct
|
||||
// object callback handler. Pass the <object> entity text to the handler. What should
|
||||
// come back is embedded image information.
|
||||
gchar* object_tag;
|
||||
gchar* end_object_tag;
|
||||
gchar* object_contents;
|
||||
gchar* html_str_start;
|
||||
gchar* html_str_middle;
|
||||
gchar* html_str_result;
|
||||
gchar* classid;
|
||||
gchar* classid_end;
|
||||
gchar* object_classid;
|
||||
GncHTMLObjectCB h;
|
||||
|
||||
object_tag = g_strstr_len( html_str, -1, "<object classid=" );
|
||||
if( object_tag == NULL ) {
|
||||
// Hmmm... no object tag
|
||||
return html_str;
|
||||
}
|
||||
classid = object_tag+strlen( "<object classid=" )+1;
|
||||
classid_end = g_strstr_len( classid, -1, "\"" );
|
||||
object_classid = g_strndup( classid, (classid_end-classid) );
|
||||
end_object_tag = g_strstr_len( object_tag, -1, "</object>" );
|
||||
if( end_object_tag == NULL ) {
|
||||
// Hmmm... no object end tag
|
||||
return html_str;
|
||||
}
|
||||
end_object_tag += strlen( "</object>" );
|
||||
object_contents = g_strndup( object_tag, (end_object_tag-object_tag) );
|
||||
|
||||
h = g_hash_table_lookup( gnc_html_object_handlers, object_classid );
|
||||
if( h != NULL ) {
|
||||
(void)h( GNC_HTML(self), object_contents, &html_str_middle );
|
||||
} else {
|
||||
html_str_middle = g_strdup_printf( "No handler found for classid \"%s\"", object_classid );
|
||||
}
|
||||
|
||||
html_str_start = g_strndup( html_str, (object_tag-html_str) );
|
||||
html_str_result = g_strdup_printf( "%s%s%s", html_str_start, html_str_middle, end_object_tag );
|
||||
|
||||
g_free( html_str_start );
|
||||
g_free( html_str_middle );
|
||||
return html_str_result;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* load_to_stream : actually do the work of loading the HTML
|
||||
* or binary data referenced by a URL and feeding it into the GtkHTML
|
||||
* widget.
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
load_to_stream( GncHtmlWebkit* self, URLType type,
|
||||
const gchar* location, const gchar* label )
|
||||
{
|
||||
gchar* fdata = NULL;
|
||||
int fdata_len = 0;
|
||||
GncHtmlWebkitPrivate* priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
|
||||
DEBUG( "type %s, location %s, label %s", type ? type : "(null)",
|
||||
location ? location : "(null)", label ? label : "(null)");
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
|
||||
if( gnc_html_stream_handlers != NULL ) {
|
||||
GncHTMLStreamCB stream_handler;
|
||||
|
||||
stream_handler = g_hash_table_lookup( gnc_html_stream_handlers, type );
|
||||
if( stream_handler ) {
|
||||
gboolean ok = stream_handler( location, &fdata, &fdata_len );
|
||||
|
||||
if( ok ) {
|
||||
fdata = fdata ? fdata : g_strdup( "" );
|
||||
|
||||
// Until webkitgtk supports download requests, look for "<object classid="
|
||||
// indicating the beginning of an embedded graph. If found, handle it
|
||||
if( g_strstr_len( fdata, -1, "<object classid=" ) != NULL ) {
|
||||
gchar* new_fdata;
|
||||
new_fdata = handle_embedded_object( self, fdata );
|
||||
g_free( fdata );
|
||||
fdata = new_fdata;
|
||||
}
|
||||
|
||||
// Save a copy for export purposes
|
||||
if( priv->html_string != NULL ) {
|
||||
g_free( priv->html_string );
|
||||
}
|
||||
priv->html_string = g_strdup( fdata );
|
||||
webkit_web_view_load_html_string( priv->web_view, fdata, "base-uri" );
|
||||
} else {
|
||||
fdata = fdata ? fdata :
|
||||
g_strdup_printf( error_404_format,
|
||||
_(error_404_title), _(error_404_body) );
|
||||
webkit_web_view_load_html_string( priv->web_view, fdata, "base-uri" );
|
||||
}
|
||||
|
||||
g_free( fdata );
|
||||
|
||||
if( label ) {
|
||||
while( gtk_events_pending() ) {
|
||||
gtk_main_iteration();
|
||||
}
|
||||
// gtk_html_jump_to_anchor( GTK_HTML(priv->html), label );
|
||||
g_assert( FALSE );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
if( !safe_strcmp( type, URL_TYPE_SECURE ) ||
|
||||
!safe_strcmp( type, URL_TYPE_HTTP ) ) {
|
||||
|
||||
if( !safe_strcmp( type, URL_TYPE_SECURE ) ) {
|
||||
if( !https_allowed() ) {
|
||||
gnc_error_dialog( priv->base.parent,
|
||||
_("Secure HTTP access is disabled. "
|
||||
"You can enable it in the Network section of "
|
||||
"the Preferences dialog."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !http_allowed() ) {
|
||||
gnc_error_dialog( priv->base.parent,
|
||||
_("Network HTTP access is disabled. "
|
||||
"You can enable it in the Network section of "
|
||||
"the Preferences dialog."));
|
||||
} else {
|
||||
char *fullurl;
|
||||
|
||||
fullurl = gnc_build_url( type, location, label );
|
||||
}
|
||||
|
||||
} else {
|
||||
PWARN( "load_to_stream for inappropriate type\n"
|
||||
"\turl = '%s#%s'\n",
|
||||
location ? location : "(null)",
|
||||
label ? label : "(null)" );
|
||||
fdata = g_strdup_printf( error_404_format,
|
||||
_(error_404_title), _(error_404_body) );
|
||||
webkit_web_view_load_html_string( priv->web_view, fdata, "base-uri" );
|
||||
g_free( fdata );
|
||||
}
|
||||
|
||||
} while( FALSE );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/********************************************************************
|
||||
* gnc_html_link_clicked_cb - called when user left-clicks on html
|
||||
* anchor.
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_link_clicked_cb( GtkHTML* html, const gchar* url, gpointer data )
|
||||
{
|
||||
URLType type;
|
||||
gchar* location = NULL;
|
||||
gchar* label = NULL;
|
||||
GncHtmlWebkit* self = GNC_HTML_WEBKIT(data);
|
||||
|
||||
DEBUG("Clicked %s", url);
|
||||
type = gnc_html_parse_url( GNC_HTML(self), url, &location, &label );
|
||||
gnc_html_show_url( GNC_HTML(self), type, location, label, 0 );
|
||||
g_free( location );
|
||||
g_free( label );
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************
|
||||
* webkit_navigation_requested_cb - called when a URL needs to be
|
||||
* loaded within the loading of a page (embedded image).
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
webkit_navigation_requested_cb( WebKitWebView* web_view, GObject* arg1,
|
||||
GObject* arg2, gpointer data )
|
||||
{
|
||||
URLType type;
|
||||
gchar* location = NULL;
|
||||
gchar* label = NULL;
|
||||
GncHtmlWebkit* self = GNC_HTML_WEBKIT(data);
|
||||
WebKitNetworkRequest* req = WEBKIT_NETWORK_REQUEST(arg2);
|
||||
const gchar* url = webkit_network_request_get_uri( req );
|
||||
|
||||
DEBUG( "requesting %s", url );
|
||||
type = gnc_html_parse_url( GNC_HTML(self), url, &location, &label );
|
||||
gnc_html_show_url( GNC_HTML(self), type, location, label, 0 );
|
||||
// load_to_stream( self, type, location, label );
|
||||
g_free( location );
|
||||
g_free( label );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/********************************************************************
|
||||
* gnc_html_object_requested_cb - called when an applet needs to be
|
||||
* loaded.
|
||||
********************************************************************/
|
||||
|
||||
static gboolean
|
||||
gnc_html_object_requested_cb( GtkHTML* html, GtkHTMLEmbedded* eb,
|
||||
gpointer data )
|
||||
{
|
||||
GncHtmlWebkit* self = GNC_HTML_WEBKIT(data);
|
||||
GncHTMLObjectCB h;
|
||||
|
||||
DEBUG( " " );
|
||||
if( !eb || !(eb->classid) || !gnc_html_object_handlers ) return FALSE;
|
||||
|
||||
h = g_hash_table_lookup( gnc_html_object_handlers, eb->classid );
|
||||
if( h ) {
|
||||
return h( GNC_HTML(self), eb, data );
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************
|
||||
* webkit_on_url_cb - called when user rolls over html anchor
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
webkit_on_url_cb( WebKitWebView* web_view, gchar* title, gchar* url, gpointer data )
|
||||
{
|
||||
GncHtmlWebkit* self = GNC_HTML_WEBKIT(data);
|
||||
GncHtmlWebkitPrivate* priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
|
||||
DEBUG( "Rollover %s", url ? url : "(null)" );
|
||||
g_free( priv->base.current_link );
|
||||
priv->base.current_link = g_strdup( url );
|
||||
if( priv->base.flyover_cb ) {
|
||||
(priv->base.flyover_cb)( GNC_HTML(self), url, priv->base.flyover_cb_data );
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/********************************************************************
|
||||
* gnc_html_set_base_cb
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_set_base_cb( GtkHTML* gtkhtml, const gchar* base,
|
||||
gpointer data )
|
||||
{
|
||||
GncHtmlWebkit* self = GNC_HTML_WEBKIT(data);
|
||||
GncHtmlWebkitPrivate* priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
URLType type;
|
||||
gchar* location = NULL;
|
||||
gchar* label = NULL;
|
||||
|
||||
DEBUG( "Setting base location to %s", base );
|
||||
type = gnc_html_parse_url( GNC_HTML(self), base, &location, &label );
|
||||
|
||||
g_free( priv->base.base_location );
|
||||
g_free( label );
|
||||
|
||||
priv->base.base_type = type;
|
||||
priv->base.base_location = location;
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_button_press_cb
|
||||
* mouse button callback (if any)
|
||||
********************************************************************/
|
||||
|
||||
static int
|
||||
gnc_html_button_press_cb( GtkWidget* widg, GdkEventButton* event,
|
||||
gpointer user_data )
|
||||
{
|
||||
GncHtmlWebkit* self = GNC_HTML_WEBKIT(user_data);
|
||||
GncHtmlWebkitPrivate* priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
|
||||
DEBUG( "Button Press" );
|
||||
if( priv->base.button_cb != NULL ) {
|
||||
(priv->base.button_cb)( GNC_HTML(self), event, priv->base.button_cb_data );
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_open_scm
|
||||
* insert some scheme-generated HTML
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
gnc_html_open_scm( GncHtmlWebkit* self, const gchar * location,
|
||||
const gchar * label, int newwin )
|
||||
{
|
||||
PINFO("location='%s'", location ? location : "(null)");
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_show_data
|
||||
* display some HTML that the creator of the gnc-html got from
|
||||
* somewhere.
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
impl_webkit_show_data( GncHtml* self, const gchar* data, int datalen )
|
||||
{
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
|
||||
|
||||
DEBUG( "datalen %d, data %20.20s", datalen, data );
|
||||
|
||||
priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
webkit_web_view_load_html_string( priv->web_view, data, "base-uri" );
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_show_url
|
||||
*
|
||||
* open a URL. This is called when the user clicks a link or
|
||||
* for the creator of the gnc_html window to explicitly request
|
||||
* a URL.
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
impl_webkit_show_url( GncHtml* self, URLType type,
|
||||
const gchar* location, const gchar* label,
|
||||
gboolean new_window_hint )
|
||||
{
|
||||
GncHTMLUrlCB url_handler;
|
||||
gboolean new_window;
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
|
||||
g_return_if_fail( location != NULL );
|
||||
|
||||
priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
|
||||
/* make sure it's OK to show this URL type in this window */
|
||||
if( new_window_hint == 0 ) {
|
||||
if( priv->base.urltype_cb ) {
|
||||
new_window = !((priv->base.urltype_cb)( type ));
|
||||
} else {
|
||||
new_window = FALSE;
|
||||
}
|
||||
} else {
|
||||
new_window = TRUE;
|
||||
}
|
||||
|
||||
if( !new_window ) {
|
||||
gnc_html_cancel( GNC_HTML(self) );
|
||||
}
|
||||
|
||||
if( gnc_html_url_handlers ) {
|
||||
url_handler = g_hash_table_lookup( gnc_html_url_handlers, type );
|
||||
} else {
|
||||
url_handler = NULL;
|
||||
}
|
||||
|
||||
if( url_handler ) {
|
||||
GNCURLResult result;
|
||||
gboolean ok;
|
||||
|
||||
result.load_to_stream = FALSE;
|
||||
result.url_type = type;
|
||||
result.location = NULL;
|
||||
result.label = NULL;
|
||||
result.base_type = URL_TYPE_FILE;
|
||||
result.base_location = NULL;
|
||||
result.error_message = NULL;
|
||||
|
||||
ok = url_handler( location, label, new_window, &result );
|
||||
if( !ok ) {
|
||||
if( result.error_message ) {
|
||||
gnc_error_dialog( priv->base.parent, "%s", result.error_message );
|
||||
} else {
|
||||
/* %s is a URL (some location somewhere). */
|
||||
gnc_error_dialog( priv->base.parent, _("There was an error accessing %s."), location );
|
||||
}
|
||||
|
||||
if( priv->base.load_cb ) {
|
||||
priv->base.load_cb( GNC_HTML(self), result.url_type,
|
||||
location, label, priv->base.load_cb_data );
|
||||
}
|
||||
} else if( result.load_to_stream ) {
|
||||
gnc_html_history_node *hnode;
|
||||
const char *new_location;
|
||||
const char *new_label;
|
||||
|
||||
new_location = result.location ? result.location : location;
|
||||
new_label = result.label ? result.label : label;
|
||||
hnode = gnc_html_history_node_new( result.url_type, new_location, new_label );
|
||||
|
||||
gnc_html_history_append( priv->base.history, hnode );
|
||||
|
||||
g_free( priv->base.base_location );
|
||||
priv->base.base_type = result.base_type;
|
||||
priv->base.base_location =
|
||||
g_strdup( extract_base_name( result.base_type, new_location ) );
|
||||
DEBUG( "resetting base location to %s",
|
||||
priv->base.base_location ? priv->base.base_location : "(null)" );
|
||||
|
||||
load_to_stream( GNC_HTML_WEBKIT(self), result.url_type,
|
||||
new_location, new_label );
|
||||
|
||||
if( priv->base.load_cb != NULL ) {
|
||||
priv->base.load_cb( GNC_HTML(self), result.url_type,
|
||||
new_location, new_label, priv->base.load_cb_data );
|
||||
}
|
||||
}
|
||||
|
||||
g_free( result.location );
|
||||
g_free( result.label );
|
||||
g_free( result.base_location );
|
||||
g_free( result.error_message );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( safe_strcmp( type, URL_TYPE_SCHEME ) == 0 ) {
|
||||
gnc_html_open_scm( GNC_HTML_WEBKIT(self), location, label, new_window );
|
||||
|
||||
} else if( safe_strcmp( type, URL_TYPE_JUMP ) == 0 ) {
|
||||
// gtk_html_jump_to_anchor( GTK_HTML(priv->html), label );
|
||||
g_assert( FALSE );
|
||||
|
||||
} else if( safe_strcmp( type, URL_TYPE_SECURE ) == 0 ||
|
||||
safe_strcmp( type, URL_TYPE_HTTP ) == 0 ||
|
||||
safe_strcmp( type, URL_TYPE_FILE ) == 0 ) {
|
||||
|
||||
do {
|
||||
if( safe_strcmp( type, URL_TYPE_SECURE ) == 0 ) {
|
||||
if( !https_allowed() ) {
|
||||
gnc_error_dialog( priv->base.parent,
|
||||
_("Secure HTTP access is disabled. "
|
||||
"You can enable it in the Network section of "
|
||||
"the Preferences dialog.") );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( safe_strcmp( type, URL_TYPE_HTTP ) == 0 ) {
|
||||
if( !http_allowed() ) {
|
||||
gnc_error_dialog( priv->base.parent,
|
||||
_("Network HTTP access is disabled. "
|
||||
"You can enable it in the Network section of "
|
||||
"the Preferences dialog.") );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
priv->base.base_type = type;
|
||||
|
||||
if( priv->base.base_location != NULL ) g_free( priv->base.base_location );
|
||||
priv->base.base_location = extract_base_name( type, location );
|
||||
|
||||
/* FIXME : handle new_window = 1 */
|
||||
gnc_html_history_append( priv->base.history,
|
||||
gnc_html_history_node_new( type, location, label ) );
|
||||
load_to_stream( GNC_HTML_WEBKIT(self), type, location, label );
|
||||
|
||||
} while( FALSE );
|
||||
|
||||
} else {
|
||||
PERR( "URLType %s not supported.", type );
|
||||
}
|
||||
|
||||
if( priv->base.load_cb != NULL ) {
|
||||
(priv->base.load_cb)( GNC_HTML(self), type, location, label, priv->base.load_cb_data );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_reload
|
||||
* reload the current page
|
||||
********************************************************************/
|
||||
|
||||
static void
|
||||
impl_webkit_reload( GncHtml* self )
|
||||
{
|
||||
gnc_html_history_node * n;
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
|
||||
|
||||
priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
n = gnc_html_history_get_current( priv->base.history );
|
||||
if( n != NULL ) {
|
||||
gnc_html_show_url( self, n->type, n->location, n->label, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_new
|
||||
* create and set up a new webkit widget.
|
||||
********************************************************************/
|
||||
|
||||
GncHtml*
|
||||
gnc_html_webkit_new( void )
|
||||
{
|
||||
GncHtmlWebkit* self = g_object_new( GNC_TYPE_HTML_WEBKIT, NULL );
|
||||
GncHtmlWebkitPrivate* priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
|
||||
return GNC_HTML(self);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_cancel
|
||||
* cancel any outstanding HTML fetch requests.
|
||||
********************************************************************/
|
||||
|
||||
static gboolean
|
||||
webkit_cancel_helper(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
g_free(key);
|
||||
g_list_free((GList *)value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
impl_webkit_cancel( GncHtml* self )
|
||||
{
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
|
||||
|
||||
priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
|
||||
/* remove our own references to requests */
|
||||
//gnc_http_cancel_requests( priv->http );
|
||||
|
||||
g_hash_table_foreach_remove( priv->base.request_info, webkit_cancel_helper, NULL );
|
||||
}
|
||||
|
||||
static void
|
||||
impl_webkit_copy_to_clipboard( GncHtml* self )
|
||||
{
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
|
||||
|
||||
priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
if( webkit_web_view_can_copy_clipboard( priv->web_view ) ) {
|
||||
webkit_web_view_copy_clipboard( priv->web_view );
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* gnc_html_export_to_file : wrapper around the builtin function in webkit
|
||||
**************************************************************/
|
||||
static gboolean
|
||||
impl_webkit_export_to_file( GncHtml* self, const char *filepath )
|
||||
{
|
||||
FILE *fh;
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
|
||||
g_return_val_if_fail( self != NULL, FALSE );
|
||||
g_return_val_if_fail( GNC_IS_HTML_WEBKIT(self), FALSE );
|
||||
g_return_val_if_fail( filepath != NULL, FALSE );
|
||||
|
||||
priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
if( priv->html_string == NULL ) {
|
||||
return FALSE;
|
||||
}
|
||||
fh = g_fopen( filepath, "w" );
|
||||
if( fh != NULL ) {
|
||||
gint written;
|
||||
gint len = strlen( priv->html_string );
|
||||
|
||||
written = fwrite( priv->html_string, 1, len, fh );
|
||||
fclose (fh);
|
||||
|
||||
if( written != len ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
impl_webkit_print( GncHtml* self )
|
||||
{
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
// static void (*webkit_web_frame_print)( WebKitWebFrame* frame ) = NULL;
|
||||
WebKitWebFrame* frame;
|
||||
extern void webkit_web_frame_print( WebKitWebFrame* frame );
|
||||
|
||||
/* HACK ALERT
|
||||
*
|
||||
* The api to print isn't exported, but exists and works, so let's dig for it.
|
||||
*/
|
||||
#if 0
|
||||
if( webkit_web_frame_print == NULL ) {
|
||||
void* handle = dlopen( "/usr/lib/libwebkit-1.0.so", RTLD_LAZY );
|
||||
webkit_web_frame_print = dlsym( handle, "webkit_web_frame_print" );
|
||||
dlclose( handle );
|
||||
}
|
||||
#endif
|
||||
|
||||
priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
frame = webkit_web_view_get_main_frame( priv->web_view );
|
||||
webkit_web_frame_print( frame );
|
||||
}
|
||||
|
||||
static void
|
||||
impl_webkit_set_parent( GncHtml* self, GtkWindow* parent )
|
||||
{
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
|
||||
|
||||
priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
|
||||
priv->base.parent = GTK_WIDGET(parent);
|
||||
}
|
59
src/html/gnc-html-webkit.h
Normal file
59
src/html/gnc-html-webkit.h
Normal file
@ -0,0 +1,59 @@
|
||||
/********************************************************************
|
||||
* gnc-html-webkit.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2009 Phil Longstaff <plongstaff@rogers.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_WEBKIT_H
|
||||
#define GNC_HTML_WEBKIT_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "gnc-html.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GNC_TYPE_HTML_WEBKIT (gnc_html_webkit_get_type())
|
||||
#define GNC_HTML_WEBKIT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GNC_TYPE_HTML_WEBKIT, GncHtmlWebkit))
|
||||
#define GNC_HTML_WEBKIT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GNC_TYPE_HTML_WEBKIT, GncHtmlWebkitClass))
|
||||
#define GNC_IS_HTML_WEBKIT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GNC_TYPE_HTML_WEBKIT))
|
||||
#define GNC_IS_HTML_WEBKIT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GNC_TYPE_HTML_WEBKIT))
|
||||
#define GNC_HTML_WEBKIT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GNC_TYPE_HTML_WEBKIT, GncHtmlWebkitClass))
|
||||
|
||||
typedef struct _GncHtmlWebkit GncHtmlWebkit;
|
||||
typedef struct _GncHtmlWebkitClass GncHtmlWebkitClass;
|
||||
typedef struct _GncHtmlWebkitPrivate GncHtmlWebkitPrivate;
|
||||
|
||||
struct _GncHtmlWebkit {
|
||||
GncHtml parent_instance;
|
||||
|
||||
/*< private >*/
|
||||
GncHtmlWebkitPrivate* priv;
|
||||
};
|
||||
|
||||
struct _GncHtmlWebkitClass {
|
||||
GncHtmlClass parent_class;
|
||||
};
|
||||
|
||||
GType gnc_html_webkit_get_type( void );
|
||||
|
||||
GncHtml* gnc_html_webkit_new( void );
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
800
src/html/gnc-html.c
Normal file
800
src/html/gnc-html.c
Normal file
@ -0,0 +1,800 @@
|
||||
/********************************************************************
|
||||
* gnc-html.c -- display HTML with some special gnucash tags. *
|
||||
* *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* Copyright (C) 2001 Linas Vepstas <linas@linas.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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
********************************************************************/
|
||||
|
||||
// libgtkhtml docs:
|
||||
// http://www.fifi.org/doc/libgtkhtml-dev/html/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <regex.h>
|
||||
#include <libguile.h>
|
||||
|
||||
#include "Account.h"
|
||||
#include "print-session.h"
|
||||
#include "gnc-engine.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-html-history.h"
|
||||
|
||||
/* indicates the debugging module that this .o belongs to. */
|
||||
static QofLogModule log_module = GNC_MOD_HTML;
|
||||
|
||||
/* hashes for URLType -> protocol and protocol -> URLType */
|
||||
static GHashTable * gnc_html_type_to_proto_hash = NULL;
|
||||
GHashTable * gnc_html_proto_to_type_hash = NULL;
|
||||
|
||||
/* hashes an HTML <object classid="ID"> classid to a handler function */
|
||||
GHashTable* gnc_html_object_handlers = NULL;
|
||||
|
||||
/* hashes handlers for loading different URLType data */
|
||||
GHashTable* gnc_html_stream_handlers = NULL;
|
||||
|
||||
/* hashes handlers for handling different URLType data */
|
||||
GHashTable* gnc_html_url_handlers = NULL;
|
||||
|
||||
/* hashes an HTML <object classid="ID"> classid to a handler function */
|
||||
extern GHashTable* gnc_html_object_handlers;
|
||||
|
||||
static char error_404_format[] =
|
||||
"<html><body><h3>%s</h3><p>%s</body></html>";
|
||||
static char error_404_title[] = N_("Not found");
|
||||
static char error_404_body[] =
|
||||
N_("The specified URL could not be loaded.");
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE(GncHtml, gnc_html, GTK_TYPE_BIN)
|
||||
|
||||
static void gnc_html_class_init( GncHtmlClass* klass );
|
||||
static void gnc_html_dispose( GObject* obj );
|
||||
static void gnc_html_finalize( GObject* obj );
|
||||
|
||||
//#define GNC_HTML_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), GNC_TYPE_HTML, GncHtmlPrivate))
|
||||
#define GNC_HTML_GET_PRIVATE(o) (GNC_HTML(o)->priv)
|
||||
|
||||
#include "gnc-html-p.h"
|
||||
|
||||
static void
|
||||
gnc_html_class_init( GncHtmlClass* klass )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
gobject_class->dispose = gnc_html_dispose;
|
||||
gobject_class->finalize = gnc_html_finalize;
|
||||
|
||||
klass->show_url = NULL;
|
||||
klass->show_data = NULL;
|
||||
klass->reload = NULL;
|
||||
klass->copy_to_clipboard = NULL;
|
||||
klass->export_to_file = NULL;
|
||||
klass->print = NULL;
|
||||
klass->cancel = NULL;
|
||||
klass->parse_url = NULL;
|
||||
klass->set_parent = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_init( GncHtml* self )
|
||||
{
|
||||
GncHtmlPrivate* priv;
|
||||
priv = self->priv = g_new0( GncHtmlPrivate, 1 );
|
||||
|
||||
priv->container = gtk_scrolled_window_new( NULL, NULL );
|
||||
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(priv->container),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC );
|
||||
priv->request_info = g_hash_table_new( g_str_hash, g_str_equal );
|
||||
priv->history = gnc_html_history_new();
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_dispose( GObject* obj )
|
||||
{
|
||||
GncHtml* self = GNC_HTML(obj);
|
||||
GncHtmlPrivate* priv = GNC_HTML_GET_PRIVATE(self);
|
||||
|
||||
if( priv->container != NULL ) {
|
||||
gtk_widget_destroy( GTK_WIDGET(priv->container) );
|
||||
g_object_unref( G_OBJECT(priv->container) );
|
||||
priv->container = NULL;
|
||||
}
|
||||
if( priv->request_info != NULL ) {
|
||||
g_hash_table_destroy( priv->request_info );
|
||||
priv->request_info = NULL;
|
||||
}
|
||||
if( priv->history != NULL ) {
|
||||
gnc_html_history_destroy( priv->history );
|
||||
priv->history = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(gnc_html_parent_class)->dispose( obj );
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_html_finalize( GObject* obj )
|
||||
{
|
||||
GncHtml* self = GNC_HTML(obj);
|
||||
|
||||
if( self->priv != NULL ) {
|
||||
g_free( self->priv );
|
||||
self->priv = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(gnc_html_parent_class)->finalize( obj );
|
||||
}
|
||||
|
||||
/***********************************************************************************/
|
||||
|
||||
static char*
|
||||
extract_machine_name( const gchar* path )
|
||||
{
|
||||
gchar machine_rexp[] = "^(//[^/]*)/*(.*)?$";
|
||||
regex_t compiled_m;
|
||||
regmatch_t match[4];
|
||||
gchar* machine = NULL;
|
||||
|
||||
if( path == NULL ) return NULL;
|
||||
|
||||
regcomp( &compiled_m, machine_rexp, REG_EXTENDED );
|
||||
|
||||
/* step 1: split the machine name away from the path
|
||||
* components */
|
||||
if( !regexec( &compiled_m, path, 4, match, 0 ) ) {
|
||||
/* $1 is the machine name */
|
||||
if( match[1].rm_so != -1 ) {
|
||||
machine = g_strndup( path+match[1].rm_so, match[1].rm_eo - match[1].rm_so );
|
||||
}
|
||||
}
|
||||
return machine;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_parse_url
|
||||
* this takes a URL and determines the protocol type, location, and
|
||||
* possible anchor name from the URL.
|
||||
********************************************************************/
|
||||
|
||||
URLType
|
||||
gnc_html_parse_url( GncHtml* self, const gchar* url,
|
||||
gchar** url_location, gchar** url_label )
|
||||
{
|
||||
gchar uri_rexp[] = "^(([^:][^:]+):)?([^#]+)?(#(.*))?$";
|
||||
regex_t compiled;
|
||||
regmatch_t match[6];
|
||||
gchar* protocol = NULL;
|
||||
gchar* path = NULL;
|
||||
gchar* label = NULL;
|
||||
gboolean found_protocol = FALSE;
|
||||
gboolean found_path = FALSE;
|
||||
gboolean found_label = FALSE;
|
||||
URLType retval;
|
||||
GncHtmlPrivate* priv = GNC_HTML_GET_PRIVATE(self);
|
||||
|
||||
g_return_val_if_fail( self != NULL, NULL );
|
||||
g_return_val_if_fail( GNC_IS_HTML(self), NULL );
|
||||
|
||||
DEBUG( "parsing %s, base_location %s",
|
||||
url ? url : "(null)",
|
||||
self ? (priv->base_location ? priv->base_location
|
||||
: "(null base_location)")
|
||||
: "(null html)");
|
||||
|
||||
regcomp( &compiled, uri_rexp, REG_EXTENDED );
|
||||
|
||||
if( !regexec( &compiled, url, 6, match, 0 ) ) {
|
||||
if( match[2].rm_so != -1 ) {
|
||||
protocol = g_new0( gchar, match[2].rm_eo - match[2].rm_so + 1 );
|
||||
strncpy( protocol, url + match[2].rm_so, match[2].rm_eo - match[2].rm_so );
|
||||
protocol[match[2].rm_eo - match[2].rm_so] = 0;
|
||||
found_protocol = TRUE;
|
||||
}
|
||||
if( match[3].rm_so != -1 ) {
|
||||
path = g_new0( gchar, match[3].rm_eo - match[3].rm_so + 1 );
|
||||
strncpy( path, url+match[3].rm_so, match[3].rm_eo - match[3].rm_so );
|
||||
path[match[3].rm_eo - match[3].rm_so] = 0;
|
||||
found_path = TRUE;
|
||||
}
|
||||
if( match[5].rm_so != -1 ) {
|
||||
label = g_new0( gchar, match[5].rm_eo - match[5].rm_so + 1 );
|
||||
strncpy( label, url+match[5].rm_so, match[5].rm_eo - match[5].rm_so );
|
||||
label[match[5].rm_eo - match[5].rm_so] = 0;
|
||||
found_label = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
regfree( &compiled );
|
||||
|
||||
if( found_protocol ) {
|
||||
retval = g_hash_table_lookup( gnc_html_proto_to_type_hash, protocol );
|
||||
if( retval == NULL ) {
|
||||
PWARN( "unhandled URL type for '%s'", url ? url : "(null)" );
|
||||
retval = URL_TYPE_OTHER;
|
||||
}
|
||||
} else if( found_label && !found_path ) {
|
||||
retval = URL_TYPE_JUMP;
|
||||
} else {
|
||||
if( self ) {
|
||||
retval = priv->base_type;
|
||||
} else {
|
||||
retval = URL_TYPE_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free( protocol );
|
||||
|
||||
if( !safe_strcmp( retval, URL_TYPE_FILE ) ) {
|
||||
if( !found_protocol && path && self && priv->base_location ) {
|
||||
if( g_path_is_absolute( path ) ) {
|
||||
*url_location = g_strdup( path );
|
||||
} else {
|
||||
*url_location = g_build_filename( priv->base_location, path, (gchar*)NULL );
|
||||
}
|
||||
g_free( path );
|
||||
} else {
|
||||
*url_location = g_strdup( path );
|
||||
g_free( path );
|
||||
}
|
||||
|
||||
} else if( !safe_strcmp( retval, URL_TYPE_JUMP ) ) {
|
||||
*url_location = NULL;
|
||||
g_free( path );
|
||||
|
||||
} else {
|
||||
/* case URL_TYPE_OTHER: */
|
||||
|
||||
if( !found_protocol && path && self && priv->base_location ) {
|
||||
if( g_path_is_absolute( path ) ) {
|
||||
*url_location = g_build_filename( extract_machine_name( priv->base_location ),
|
||||
path, (gchar*)NULL );
|
||||
} else {
|
||||
*url_location = g_build_filename( priv->base_location, path, (gchar*)NULL );
|
||||
}
|
||||
g_free( path );
|
||||
} else {
|
||||
*url_location = g_strdup( path );
|
||||
g_free( path );
|
||||
}
|
||||
}
|
||||
|
||||
*url_label = label;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_show_data
|
||||
* display some HTML that the creator of the gnc-html got from
|
||||
* somewhere.
|
||||
********************************************************************/
|
||||
|
||||
void
|
||||
gnc_html_show_data( GncHtml* self, const gchar* data, int datalen )
|
||||
{
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
if( GNC_HTML_GET_CLASS(self)->show_data != NULL ) {
|
||||
GNC_HTML_GET_CLASS(self)->show_data( self, data, datalen );
|
||||
} else {
|
||||
DEBUG( "'show_data' not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_show_url
|
||||
*
|
||||
* open a URL. This is called when the user clicks a link or
|
||||
* for the creator of the gnc_html window to explicitly request
|
||||
* a URL.
|
||||
********************************************************************/
|
||||
|
||||
void
|
||||
gnc_html_show_url( GncHtml* self, URLType type,
|
||||
const gchar* location, const gchar* label,
|
||||
gboolean new_window_hint )
|
||||
{
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
if( GNC_HTML_GET_CLASS(self)->show_url != NULL ) {
|
||||
GNC_HTML_GET_CLASS(self)->show_url( self, type, location, label, new_window_hint );
|
||||
} else {
|
||||
DEBUG( "'show_url' not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_reload
|
||||
* reload the current page
|
||||
********************************************************************/
|
||||
|
||||
void
|
||||
gnc_html_reload( GncHtml* self )
|
||||
{
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
if( GNC_HTML_GET_CLASS(self)->reload != NULL ) {
|
||||
GNC_HTML_GET_CLASS(self)->reload( self );
|
||||
} else {
|
||||
DEBUG( "'reload' not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_cancel
|
||||
* cancel any outstanding HTML fetch requests.
|
||||
********************************************************************/
|
||||
|
||||
void
|
||||
gnc_html_cancel( GncHtml* self )
|
||||
{
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
if( GNC_HTML_GET_CLASS(self)->cancel != NULL ) {
|
||||
GNC_HTML_GET_CLASS(self)->cancel( self );
|
||||
} else {
|
||||
DEBUG( "'cancel' not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_destroy
|
||||
* destroy the struct
|
||||
********************************************************************/
|
||||
|
||||
void
|
||||
gnc_html_destroy( GncHtml* self )
|
||||
{
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
g_object_unref( G_OBJECT(self) );
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_set_urltype_cb( GncHtml* self, GncHTMLUrltypeCB urltype_cb )
|
||||
{
|
||||
GncHtmlPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
priv = GNC_HTML_GET_PRIVATE(self);
|
||||
priv->urltype_cb = urltype_cb;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_set_load_cb( GncHtml* self, GncHTMLLoadCB load_cb, gpointer data )
|
||||
{
|
||||
GncHtmlPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
priv = GNC_HTML_GET_PRIVATE(self);
|
||||
priv->load_cb = load_cb;
|
||||
priv->load_cb_data = data;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_set_flyover_cb( GncHtml* self, GncHTMLFlyoverCB flyover_cb, gpointer data )
|
||||
{
|
||||
GncHtmlPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
priv = GNC_HTML_GET_PRIVATE(self);
|
||||
priv->flyover_cb = flyover_cb;
|
||||
priv->flyover_cb_data = data;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_set_button_cb( GncHtml* self, GncHTMLButtonCB button_cb, gpointer data )
|
||||
{
|
||||
GncHtmlPrivate* priv;
|
||||
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
priv = GNC_HTML_GET_PRIVATE(self);
|
||||
priv->button_cb = button_cb;
|
||||
priv->button_cb_data = data;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_copy_to_clipboard( GncHtml* self )
|
||||
{
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
if( GNC_HTML_GET_CLASS(self)->copy_to_clipboard != NULL ) {
|
||||
GNC_HTML_GET_CLASS(self)->copy_to_clipboard( self );
|
||||
} else {
|
||||
DEBUG( "'copy_to_clipboard' not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* gnc_html_export_to_file : wrapper around the builtin function in gtkhtml
|
||||
**************************************************************/
|
||||
|
||||
gboolean
|
||||
gnc_html_export_to_file( GncHtml* self, const gchar* filepath )
|
||||
{
|
||||
g_return_val_if_fail( self != NULL, FALSE );
|
||||
g_return_val_if_fail( GNC_IS_HTML(self), FALSE );
|
||||
|
||||
if( GNC_HTML_GET_CLASS(self)->export_to_file != NULL ) {
|
||||
return GNC_HTML_GET_CLASS(self)->export_to_file( self, filepath );
|
||||
} else {
|
||||
DEBUG( "'export_to_file' not implemented" );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_print( GncHtml* self )
|
||||
{
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
if( GNC_HTML_GET_CLASS(self)->print != NULL ) {
|
||||
GNC_HTML_GET_CLASS(self)->print( self );
|
||||
} else {
|
||||
DEBUG( "'print' not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
gnc_html_history *
|
||||
gnc_html_get_history( GncHtml* self )
|
||||
{
|
||||
g_return_val_if_fail( self != NULL, NULL );
|
||||
g_return_val_if_fail( GNC_IS_HTML(self), NULL );
|
||||
|
||||
return GNC_HTML_GET_PRIVATE(self)->history;
|
||||
}
|
||||
|
||||
|
||||
GtkWidget *
|
||||
gnc_html_get_widget( GncHtml* self )
|
||||
{
|
||||
g_return_val_if_fail( self != NULL, NULL );
|
||||
g_return_val_if_fail( GNC_IS_HTML(self), NULL );
|
||||
|
||||
return GNC_HTML_GET_PRIVATE(self)->container;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_set_parent( GncHtml* self, GtkWindow* parent )
|
||||
{
|
||||
g_return_if_fail( self != NULL );
|
||||
g_return_if_fail( GNC_IS_HTML(self) );
|
||||
|
||||
if( GNC_HTML_GET_CLASS(self)->set_parent != NULL ) {
|
||||
GNC_HTML_GET_CLASS(self)->set_parent( self, parent );
|
||||
} else {
|
||||
DEBUG( "'set_parent' not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
/* Register the URLType if it doesn't already exist.
|
||||
* Returns TRUE if successful, FALSE if the type already exists.
|
||||
*/
|
||||
gboolean
|
||||
gnc_html_register_urltype( URLType type, const char *protocol )
|
||||
{
|
||||
if (!gnc_html_type_to_proto_hash) {
|
||||
gnc_html_type_to_proto_hash = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
gnc_html_proto_to_type_hash = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
}
|
||||
if (!protocol) return FALSE;
|
||||
if (g_hash_table_lookup (gnc_html_type_to_proto_hash, type))
|
||||
return FALSE;
|
||||
|
||||
g_hash_table_insert (gnc_html_type_to_proto_hash, type, (gpointer)protocol);
|
||||
if (*protocol)
|
||||
g_hash_table_insert (gnc_html_proto_to_type_hash, (gpointer)protocol, type);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_initialize( void )
|
||||
{
|
||||
int i;
|
||||
static struct {
|
||||
URLType type;
|
||||
char * protocol;
|
||||
} types[] = {
|
||||
{ URL_TYPE_FILE, "file" },
|
||||
{ URL_TYPE_JUMP, "" },
|
||||
{ URL_TYPE_HTTP, "http" },
|
||||
{ URL_TYPE_FTP, "ftp" },
|
||||
{ URL_TYPE_SECURE, "https" },
|
||||
{ URL_TYPE_REGISTER, "gnc-register" },
|
||||
{ URL_TYPE_ACCTTREE, "gnc-acct-tree" },
|
||||
{ URL_TYPE_REPORT, "gnc-report" },
|
||||
{ URL_TYPE_OPTIONS, "gnc-options" },
|
||||
{ URL_TYPE_SCHEME, "gnc-scm" },
|
||||
{ URL_TYPE_HELP, "gnc-help" },
|
||||
{ URL_TYPE_XMLDATA, "gnc-xml" },
|
||||
{ URL_TYPE_PRICE, "gnc-price" },
|
||||
{ URL_TYPE_BUDGET, "gnc-budget" },
|
||||
{ URL_TYPE_OTHER, "" },
|
||||
{ NULL, NULL }};
|
||||
|
||||
for (i = 0; types[i].type; i++)
|
||||
gnc_html_register_urltype (types[i].type, types[i].protocol);
|
||||
}
|
||||
|
||||
char *
|
||||
gnc_build_url (URLType type, const gchar * location, const gchar * label)
|
||||
{
|
||||
char * type_name;
|
||||
|
||||
DEBUG(" ");
|
||||
type_name = g_hash_table_lookup (gnc_html_type_to_proto_hash, type);
|
||||
if (!type_name)
|
||||
type_name = "";
|
||||
|
||||
if(label) {
|
||||
return g_strdup_printf("%s%s%s#%s", type_name, (*type_name ? ":" : ""),
|
||||
(location ? location : ""),
|
||||
label ? label : "");
|
||||
}
|
||||
else {
|
||||
return g_strdup_printf("%s%s%s", type_name, (*type_name ? ":" : ""),
|
||||
(location ? location : ""));
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* gnc_html_encode_string
|
||||
* RFC 1738 encoding of string for submission with an HTML form.
|
||||
* GPL code lifted from gtkhtml. copyright notice:
|
||||
*
|
||||
* Copyright (C) 1997 Martin Jones (mjones@kde.org)
|
||||
* Copyright (C) 1997 Torben Weis (weis@kde.org)
|
||||
* Copyright (C) 1999 Helix Code, Inc.
|
||||
********************************************************************/
|
||||
|
||||
char *
|
||||
gnc_html_encode_string(const char * str)
|
||||
{
|
||||
static gchar *safe = "$-._!*(),"; /* RFC 1738 */
|
||||
unsigned pos = 0;
|
||||
GString *encoded = g_string_new ("");
|
||||
gchar buffer[5], *ptr;
|
||||
guchar c;
|
||||
|
||||
if(!str) return NULL;
|
||||
|
||||
while(pos < strlen(str)) {
|
||||
c = (unsigned char) str[pos];
|
||||
|
||||
if ((( c >= 'A') && ( c <= 'Z')) ||
|
||||
(( c >= 'a') && ( c <= 'z')) ||
|
||||
(( c >= '0') && ( c <= '9')) ||
|
||||
(strchr(safe, c))) {
|
||||
encoded = g_string_append_c (encoded, c);
|
||||
}
|
||||
else if ( c == ' ' ) {
|
||||
encoded = g_string_append_c (encoded, '+');
|
||||
}
|
||||
else if ( c == '\n' ) {
|
||||
encoded = g_string_append (encoded, "%0D%0A");
|
||||
}
|
||||
else if ( c != '\r' ) {
|
||||
sprintf( buffer, "%%%02X", (int)c );
|
||||
encoded = g_string_append (encoded, buffer);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
ptr = encoded->str;
|
||||
|
||||
g_string_free (encoded, FALSE);
|
||||
|
||||
return (char *)ptr;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
gnc_html_decode_string(const char * str)
|
||||
{
|
||||
static gchar * safe = "$-._!*(),"; /* RFC 1738 */
|
||||
GString * decoded = g_string_new ("");
|
||||
const gchar * ptr;
|
||||
guchar c;
|
||||
guint hexval;
|
||||
ptr = str;
|
||||
|
||||
if(!str) return NULL;
|
||||
|
||||
while(*ptr) {
|
||||
c = (unsigned char) *ptr;
|
||||
if ((( c >= 'A') && ( c <= 'Z')) ||
|
||||
(( c >= 'a') && ( c <= 'z')) ||
|
||||
(( c >= '0') && ( c <= '9')) ||
|
||||
(strchr(safe, c))) {
|
||||
decoded = g_string_append_c (decoded, c);
|
||||
}
|
||||
else if ( c == '+' ) {
|
||||
decoded = g_string_append_c (decoded, ' ');
|
||||
}
|
||||
else if (!strncmp(ptr, "%0D0A", 5)) {
|
||||
decoded = g_string_append (decoded, "\n");
|
||||
ptr += 4;
|
||||
}
|
||||
else if(c == '%') {
|
||||
ptr++;
|
||||
if (1 == sscanf(ptr, "%02X", &hexval))
|
||||
decoded = g_string_append_c(decoded, (char)hexval);
|
||||
else
|
||||
decoded = g_string_append_c(decoded, ' ');
|
||||
ptr++;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
ptr = decoded->str;
|
||||
g_string_free (decoded, FALSE);
|
||||
|
||||
return (char *)ptr;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* escape/unescape_newlines : very simple string encoding for GPG
|
||||
* ASCII-armored text.
|
||||
********************************************************************/
|
||||
|
||||
char *
|
||||
gnc_html_unescape_newlines(const gchar * in)
|
||||
{
|
||||
const char * ip = in;
|
||||
char * cstr = NULL;
|
||||
GString * rv = g_string_new("");
|
||||
|
||||
for(ip=in; *ip; ip++) {
|
||||
if((*ip == '\\') && (*(ip+1)=='n')) {
|
||||
g_string_append(rv, "\n");
|
||||
ip++;
|
||||
}
|
||||
else {
|
||||
g_string_append_c(rv, *ip);
|
||||
}
|
||||
}
|
||||
|
||||
g_string_append_c(rv, 0);
|
||||
cstr = rv->str;
|
||||
g_string_free(rv, FALSE);
|
||||
return cstr;
|
||||
}
|
||||
|
||||
char *
|
||||
gnc_html_escape_newlines(const gchar * in)
|
||||
{
|
||||
char *out;
|
||||
const char * ip = in;
|
||||
GString * escaped = g_string_new("");
|
||||
|
||||
for(ip=in; *ip; ip++) {
|
||||
if(*ip == '\012') {
|
||||
g_string_append(escaped, "\\n");
|
||||
}
|
||||
else {
|
||||
g_string_append_c(escaped, *ip);
|
||||
}
|
||||
}
|
||||
g_string_append_c(escaped, 0);
|
||||
out = escaped->str;
|
||||
g_string_free(escaped, FALSE);
|
||||
return out;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_register_object_handler( const char * classid,
|
||||
GncHTMLObjectCB hand )
|
||||
{
|
||||
g_return_if_fail( classid != NULL );
|
||||
|
||||
if( gnc_html_object_handlers == NULL ) {
|
||||
gnc_html_object_handlers = g_hash_table_new( g_str_hash, g_str_equal );
|
||||
}
|
||||
|
||||
gnc_html_unregister_object_handler( classid );
|
||||
if( hand != NULL ) {
|
||||
g_hash_table_insert( gnc_html_object_handlers, g_strdup( classid ), hand );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_unregister_object_handler( const gchar* classid )
|
||||
{
|
||||
gchar* keyptr = NULL;
|
||||
gchar* valptr = NULL;
|
||||
gchar** p_keyptr = &keyptr;
|
||||
gchar** p_valptr = &valptr;
|
||||
|
||||
if( g_hash_table_lookup_extended( gnc_html_object_handlers,
|
||||
classid,
|
||||
(gpointer *)p_keyptr,
|
||||
(gpointer *)p_valptr) ) {
|
||||
g_hash_table_remove( gnc_html_object_handlers, classid );
|
||||
g_free( keyptr );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_register_stream_handler( URLType url_type, GncHTMLStreamCB hand )
|
||||
{
|
||||
g_return_if_fail( url_type != NULL && *url_type != '\0' );
|
||||
|
||||
if( gnc_html_stream_handlers == NULL ) {
|
||||
gnc_html_stream_handlers = g_hash_table_new( g_str_hash, g_str_equal );
|
||||
}
|
||||
|
||||
gnc_html_unregister_stream_handler( url_type );
|
||||
if( hand != NULL ) {
|
||||
g_hash_table_insert( gnc_html_stream_handlers, url_type, hand );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_unregister_stream_handler( URLType url_type )
|
||||
{
|
||||
g_hash_table_remove( gnc_html_stream_handlers, url_type );
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_register_url_handler( URLType url_type, GncHTMLUrlCB hand )
|
||||
{
|
||||
g_return_if_fail( url_type != NULL && *url_type != '\0' );
|
||||
|
||||
if( gnc_html_url_handlers == NULL ) {
|
||||
gnc_html_url_handlers = g_hash_table_new( g_str_hash, g_str_equal );
|
||||
}
|
||||
|
||||
gnc_html_unregister_url_handler( url_type );
|
||||
if( hand != NULL ) {
|
||||
g_hash_table_insert( gnc_html_url_handlers, url_type, hand );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_html_unregister_url_handler( URLType url_type )
|
||||
{
|
||||
g_hash_table_remove( gnc_html_url_handlers, url_type );
|
||||
}
|
268
src/html/gnc-html.h
Normal file
268
src/html/gnc-html.h
Normal file
@ -0,0 +1,268 @@
|
||||
/********************************************************************
|
||||
* gnc-html.h -- display html with gnc special tags *
|
||||
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_HTML_H
|
||||
#define GNC_HTML_H
|
||||
|
||||
/**
|
||||
* A GncHtml object is an abstract base for an html engine used to display reports and
|
||||
* charts in gnucash. It must be overridden to create specific objects using specific
|
||||
* html engines (e.g. gtkhtml, webkit).
|
||||
*/
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GNC_TYPE_HTML (gnc_html_get_type())
|
||||
#define GNC_HTML(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GNC_TYPE_HTML, GncHtml))
|
||||
#define GNC_HTML_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GNC_TYPE_HTML, GncHtmlClass))
|
||||
#define GNC_IS_HTML(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GNC_TYPE_HTML))
|
||||
#define GNC_IS_HTML_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((o), GNC_TYPE_HTML))
|
||||
#define GNC_HTML_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GNC_TYPE_HTML, GncHtmlClass))
|
||||
|
||||
GType gnc_html_get_type(void);
|
||||
|
||||
typedef struct _GncHtml GncHtml;
|
||||
typedef struct _GncHtmlClass GncHtmlClass;
|
||||
typedef struct _GncHtmlPrivate GncHtmlPrivate;
|
||||
|
||||
#include "gnc-html-extras.h"
|
||||
|
||||
/* The result structure of url handlers. Strings should be g_malloc'd
|
||||
* by the handler and will be freed by gnc_html. */
|
||||
typedef struct
|
||||
{
|
||||
/* The following members are used if the handler succeeds (returns TRUE). */
|
||||
|
||||
gboolean load_to_stream; /* If TRUE, the url should be loaded from
|
||||
* a stream using the rest of the data in
|
||||
* the struct into the original gnc_html
|
||||
* object. If FALSE, the handler will
|
||||
* perform all needed actions itself. */
|
||||
|
||||
URLType url_type; /* Defaults to original */
|
||||
gchar* location; /* If NULL, use original (NULL is default) */
|
||||
gchar* label; /* If NULL, use original (NULL is default) */
|
||||
|
||||
URLType base_type;
|
||||
gchar* base_location;
|
||||
|
||||
/* The following members are used if the handler fails (returns FALSE). */
|
||||
gchar* error_message;
|
||||
} GNCURLResult;
|
||||
|
||||
typedef gboolean (* GncHTMLObjectCB)(GncHtml* html, gpointer eb,
|
||||
gpointer data);
|
||||
typedef gboolean (* GncHTMLStreamCB)(const gchar* location, gchar** data, int* datalen);
|
||||
typedef gboolean (* GncHTMLUrlCB)(const gchar* location, const gchar* label,
|
||||
gboolean new_window, GNCURLResult* result);
|
||||
|
||||
/**
|
||||
* Registers a new URLType.
|
||||
* returns TRUE if succesful, FALSE if type already exists.
|
||||
*
|
||||
* @param type New URL type
|
||||
* @param prococol Protocol - should be an empty string if there is no corresponding protocol.
|
||||
* @return TRUE if successful, FALSE if type already exists or protocol is NULL.
|
||||
*/
|
||||
gboolean gnc_html_register_urltype( URLType type, const gchar* protocol );
|
||||
|
||||
/**
|
||||
* Initializes the html subsystem
|
||||
*/
|
||||
void gnc_html_initialize( void );
|
||||
|
||||
gchar* gnc_html_encode_string( const gchar* in );
|
||||
gchar* gnc_html_decode_string( const gchar* in );
|
||||
gchar* gnc_html_escape_newlines( const gchar* in );
|
||||
gchar* gnc_html_unescape_newlines( const gchar* in );
|
||||
|
||||
/* object handlers deal with <object classid="foo"> objects in HTML.
|
||||
* the handlers are looked up at object load time. */
|
||||
void gnc_html_register_object_handler( const gchar* classid, GncHTMLObjectCB hand );
|
||||
void gnc_html_unregister_object_handler( const gchar* classid );
|
||||
|
||||
/* stream handlers load data for particular URLTypes. */
|
||||
void gnc_html_register_stream_handler( URLType url_type, GncHTMLStreamCB hand );
|
||||
void gnc_html_unregister_stream_handler( URLType url_type );
|
||||
|
||||
/* handlers for particular URLTypes. */
|
||||
void gnc_html_register_url_handler( URLType url_type, GncHTMLUrlCB hand );
|
||||
void gnc_html_unregister_url_handler( URLType url_type );
|
||||
|
||||
#include "gnc-html-history.h"
|
||||
|
||||
typedef int (* GncHTMLUrltypeCB)(URLType ut);
|
||||
typedef void (* GncHTMLFlyoverCB)(GncHtml* html, const gchar* url,
|
||||
gpointer data);
|
||||
typedef void (* GncHTMLLoadCB)(GncHtml* html, URLType type,
|
||||
const gchar* location, const gchar* label,
|
||||
gpointer data);
|
||||
typedef int (* GncHTMLButtonCB)(GncHtml* html, GdkEventButton* event,
|
||||
gpointer data);
|
||||
|
||||
struct _GncHtmlClass
|
||||
{
|
||||
GtkBinClass parent_class;
|
||||
|
||||
/* Methods */
|
||||
void (*show_url)( GncHtml* html,
|
||||
URLType type,
|
||||
const gchar* location,
|
||||
const gchar* label,
|
||||
gboolean new_window_hint );
|
||||
void (*show_data)( GncHtml* html, const gchar* data, int datalen );
|
||||
void (*reload)( GncHtml* html );
|
||||
void (*copy_to_clipboard)( GncHtml* html );
|
||||
gboolean (*export_to_file)( GncHtml* html, const gchar* file );
|
||||
void (*print)( GncHtml* html );
|
||||
void (*cancel)( GncHtml* html );
|
||||
URLType (*parse_url)( GncHtml* html, const gchar* url,
|
||||
gchar** url_location, gchar** url_label );
|
||||
void (*set_parent)( GncHtml* html, GtkWindow* parent );
|
||||
};
|
||||
|
||||
struct _GncHtml
|
||||
{
|
||||
GtkBin parent_instance;
|
||||
|
||||
/*< private >*/
|
||||
GncHtmlPrivate* priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys a GncHtml object.
|
||||
*
|
||||
* @param html GncHtml object to destroy
|
||||
*/
|
||||
void gnc_html_destroy( GncHtml* html );
|
||||
|
||||
/**
|
||||
* Displays a URL in a GncHtml object.
|
||||
*
|
||||
* @param html GncHtml object
|
||||
*/
|
||||
void gnc_html_show_url( GncHtml* html, URLType type, const gchar* location,
|
||||
const gchar* label, gboolean new_window_hint );
|
||||
|
||||
/**
|
||||
* Displays an HTML string in a GncHtml object.
|
||||
*
|
||||
* @param html GncHtml object
|
||||
*/
|
||||
void gnc_html_show_data( GncHtml* html, const gchar* data, int datalen );
|
||||
|
||||
/**
|
||||
* Reloads the current GncHtml object.
|
||||
*
|
||||
* @param html GncHtml object
|
||||
*/
|
||||
void gnc_html_reload( GncHtml* html );
|
||||
|
||||
/**
|
||||
* Copies the html to the clipboard
|
||||
*
|
||||
* @param html GncHtml object
|
||||
*/
|
||||
void gnc_html_copy_to_clipboard( GncHtml* html );
|
||||
|
||||
/**
|
||||
* Exports the html to an external file.
|
||||
*
|
||||
* @param html GncHtml object
|
||||
* @param filename External file name
|
||||
* @param TRUE if successful, FALSE if unsuccessful
|
||||
*/
|
||||
gboolean gnc_html_export_to_file( GncHtml* html, const gchar* filename );
|
||||
|
||||
/**
|
||||
* Prints the report.
|
||||
*
|
||||
* @param html GncHtml object
|
||||
*/
|
||||
void gnc_html_print( GncHtml* html );
|
||||
|
||||
/**
|
||||
* Cancels the current operation
|
||||
*
|
||||
* @param html GncHtml object
|
||||
*/
|
||||
void gnc_html_cancel( GncHtml* html );
|
||||
|
||||
/**
|
||||
* Parses a URL into URI and label
|
||||
*
|
||||
* @param html GncHtml object
|
||||
* @param url URL
|
||||
* @param url_location Pointer where to store address of string containing main URI
|
||||
* @param url_label Pointer where to store address of string containing label
|
||||
*/
|
||||
URLType gnc_html_parse_url( GncHtml* html, const gchar* url,
|
||||
gchar** url_location, gchar** url_label );
|
||||
|
||||
/**
|
||||
* Returns the history for this html engine
|
||||
*
|
||||
* @param html GncHtml object
|
||||
* @return History
|
||||
*/
|
||||
gnc_html_history* gnc_html_get_history( GncHtml* html );
|
||||
|
||||
/**
|
||||
* Returns the main widget for this html engine
|
||||
*
|
||||
* @param html GncHtml object
|
||||
* @return Main widget
|
||||
*/
|
||||
GtkWidget* gnc_html_get_widget( GncHtml* html );
|
||||
|
||||
/**
|
||||
* Sets the parent window for this html engine. The engine will be embedded in this parent.
|
||||
*
|
||||
* @param html GncHtml object
|
||||
* @param parent Parent window
|
||||
*/
|
||||
void gnc_html_set_parent( GncHtml* html, GtkWindow* parent );
|
||||
|
||||
/* setting callbacks */
|
||||
void gnc_html_set_urltype_cb( GncHtml* html, GncHTMLUrltypeCB urltype_cb );
|
||||
void gnc_html_set_load_cb( GncHtml* html, GncHTMLLoadCB load_cb, gpointer data );
|
||||
void gnc_html_set_flyover_cb( GncHtml* html, GncHTMLFlyoverCB newwin_cb, gpointer data );
|
||||
void gnc_html_set_button_cb( GncHtml* html, GncHTMLButtonCB button_cb, gpointer data );
|
||||
|
||||
/* object handlers deal with <object classid="foo"> objects in HTML.
|
||||
* the handlers are looked up at object load time. */
|
||||
void gnc_html_register_object_handler( const gchar* classid, GncHTMLObjectCB hand );
|
||||
void gnc_html_unregister_object_handler( const gchar* classid );
|
||||
|
||||
/* stream handlers load data for particular URLTypes. */
|
||||
void gnc_html_register_stream_handler( URLType url_type, GncHTMLStreamCB hand );
|
||||
void gnc_html_unregister_stream_handler( URLType url_type );
|
||||
|
||||
/* handlers for particular URLTypes. */
|
||||
void gnc_html_register_url_handler( URLType url_type, GncHTMLUrlCB hand );
|
||||
void gnc_html_unregister_url_handler( URLType url_type );
|
||||
|
||||
const gchar* gnc_html_get_embedded_param( gpointer eb, const gchar* param_name );
|
||||
|
||||
#endif
|
51
src/html/gnc-html.i
Normal file
51
src/html/gnc-html.i
Normal file
@ -0,0 +1,51 @@
|
||||
%module sw_gnc_html
|
||||
%{
|
||||
/* Includes the header in the wrapper code */
|
||||
#include <config.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib-object.h>
|
||||
#include <dialog-options.h>
|
||||
#include <dialog-utils.h>
|
||||
#include <druid-utils.h>
|
||||
#include <gnc-amount-edit.h>
|
||||
#include <gnc-date-edit.h>
|
||||
#include <gnc-file.h>
|
||||
#include <gnc-gnome-utils.h>
|
||||
#include <gnc-gui-query.h>
|
||||
#include <gnc-html.h>
|
||||
|
||||
SCM scm_init_sw_gnc_html_module(void);
|
||||
%}
|
||||
|
||||
%import "base-typemaps.i"
|
||||
|
||||
/* Parse the header file to generate wrappers */
|
||||
%include "gnc-html-extras.h"
|
||||
|
||||
|
||||
%init {
|
||||
{
|
||||
char tmp[100];
|
||||
|
||||
#define SET_ENUM(e) snprintf(tmp, 100, "(set! %s (%s))", (e), (e)); \
|
||||
scm_c_eval_string(tmp);
|
||||
|
||||
SET_ENUM("URL-TYPE-FILE");
|
||||
SET_ENUM("URL-TYPE-JUMP");
|
||||
SET_ENUM("URL-TYPE-HTTP");
|
||||
SET_ENUM("URL-TYPE-FTP");
|
||||
SET_ENUM("URL-TYPE-SECURE");
|
||||
SET_ENUM("URL-TYPE-REGISTER");
|
||||
SET_ENUM("URL-TYPE-ACCTTREE");
|
||||
SET_ENUM("URL-TYPE-REPORT");
|
||||
SET_ENUM("URL-TYPE-OPTIONS");
|
||||
SET_ENUM("URL-TYPE-SCHEME");
|
||||
SET_ENUM("URL-TYPE-HELP");
|
||||
SET_ENUM("URL-TYPE-XMLDATA");
|
||||
SET_ENUM("URL-TYPE-PRICE");
|
||||
SET_ENUM("URL-TYPE-OTHER");
|
||||
|
||||
#undefine SET_ENUM
|
||||
}
|
||||
|
||||
}
|
82
src/html/gncmod-html.c
Normal file
82
src/html/gncmod-html.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*********************************************************************
|
||||
* gncmod-html.c
|
||||
* module definition/initialization for the html utilities
|
||||
*
|
||||
* Copyright (c) 2001 Linux Developers Group, Inc.
|
||||
*********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gmodule.h>
|
||||
#include <libguile.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "gnc-module.h"
|
||||
#include "gnc-module-api.h"
|
||||
|
||||
#include "gnc-html.h"
|
||||
#include "qof.h"
|
||||
|
||||
GNC_MODULE_API_DECL(libgncmod_html)
|
||||
|
||||
/* version of the gnc module system interface we require */
|
||||
int libgncmod_html_gnc_module_system_interface = 0;
|
||||
|
||||
/* module versioning uses libtool semantics. */
|
||||
int libgncmod_html_gnc_module_current = 0;
|
||||
int libgncmod_html_gnc_module_revision = 0;
|
||||
int libgncmod_html_gnc_module_age = 0;
|
||||
|
||||
|
||||
char *
|
||||
libgncmod_html_gnc_module_path( void )
|
||||
{
|
||||
return g_strdup( "gnucash/html" );
|
||||
}
|
||||
|
||||
char *
|
||||
libgncmod_html_gnc_module_description( void )
|
||||
{
|
||||
return g_strdup( "Utilities for using HTML with GnuCash" );
|
||||
}
|
||||
|
||||
static void
|
||||
lmod( char* mn )
|
||||
{
|
||||
char* form = g_strdup_printf( "(use-modules %s)\n", mn );
|
||||
scm_c_eval_string( form );
|
||||
g_free( form );
|
||||
}
|
||||
|
||||
extern SCM scm_init_sw_gnc_html_module( void );
|
||||
|
||||
int
|
||||
libgncmod_html_gnc_module_init( int refcount )
|
||||
{
|
||||
/* load the engine (we depend on it) */
|
||||
if( !gnc_module_load( "gnucash/engine", 0 ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* load the calculation module (we depend on it) */
|
||||
if( !gnc_module_load( "gnucash/calculation", 0 ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if( !gnc_module_load( "gnucash/app-utils", 0 ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
scm_init_sw_gnc_html_module();
|
||||
gnc_html_initialize();
|
||||
lmod( "(sw_gnc_html)" );
|
||||
// lmod( "(gnucash gnc_html)" );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
libgncmod_html_gnc_module_end( int refcount )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
@ -68,8 +68,6 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/gnome-utils \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${GNOME_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GDK_PIXBUF_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GUILE_INCS} \
|
||||
${GLIB_CFLAGS}
|
||||
|
@ -43,7 +43,6 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/lib/libc \
|
||||
-I${top_srcdir}/lib \
|
||||
${GNOME_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GUILE_INCS} \
|
||||
${GLIB_CFLAGS} \
|
||||
|
@ -74,7 +74,6 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${GUILE_INCS} \
|
||||
${GNOME_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GLIB_CFLAGS} \
|
||||
${AQBANKING_CFLAGS}
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include "druid-utils.h"
|
||||
#include "gnc-ui-util.h"
|
||||
#include "gnc-ui.h"
|
||||
#include "gnc-html.h"
|
||||
//#include "gnc-html.h"
|
||||
//#include "import-account-matcher.h"
|
||||
#include "gnc-component-manager.h"
|
||||
#include "gnc-session.h"
|
||||
|
@ -21,7 +21,8 @@ libgncmod_log_replay_la_LIBADD = \
|
||||
${top_builddir}/src/gnc-module/libgnc-module.la \
|
||||
${top_builddir}/src/libqof/qof/libgnc-qof.la \
|
||||
${GTK_LIBS} \
|
||||
${GLIB_LIBS}
|
||||
${GLIB_LIBS} \
|
||||
${QOF_LIBS}
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src \
|
||||
@ -34,7 +35,6 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/import-export \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${GNOME_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GUILE_INCS} \
|
||||
${GLIB_CFLAGS}
|
||||
|
@ -35,7 +35,6 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/import-export \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${GNOME_CFLAGS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GUILE_INCS} \
|
||||
${GLIB_CFLAGS} \
|
||||
|
@ -65,9 +65,7 @@ AM_CPPFLAGS = \
|
||||
${GUILE_INCS} \
|
||||
${GLIB_CFLAGS} \
|
||||
${GLADE_CFLAGS} \
|
||||
${GNOME_CFLAGS} \
|
||||
${GDK_PIXBUF_CFLAGS} \
|
||||
${GTKHTML_CFLAGS}
|
||||
${GNOME_CFLAGS}
|
||||
|
||||
uidir = $(GNC_UI_DIR)
|
||||
ui_DATA = \
|
||||
|
@ -11,11 +11,11 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/app-utils \
|
||||
-I${top_srcdir}/src/gnome-utils \
|
||||
-I${top_srcdir}/src/gnome \
|
||||
-I${top_srcdir}/src/html \
|
||||
-I${top_srcdir}/src/report/report-system \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${GLADE_CFLAGS} \
|
||||
${GUILE_INCS} \
|
||||
${GTKHTML_CFLAGS} \
|
||||
${GNOME_CFLAGS} \
|
||||
${GLIB_CFLAGS}
|
||||
|
||||
@ -44,6 +44,7 @@ libgncmod_report_gnome_la_LIBADD = \
|
||||
${top_builddir}/src/engine/libgncmod-engine.la \
|
||||
${top_builddir}/src/app-utils/libgncmod-app-utils.la \
|
||||
${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
|
||||
${top_builddir}/src/html/libgncmod-html.la \
|
||||
${top_builddir}/src/report/report-system/libgncmod-report-system.la \
|
||||
${top_builddir}/src/libqof/qof/libgnc-qof.la \
|
||||
${GLADE_LIBS} \
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "gnc-gnome-utils.h"
|
||||
#include "gnc-html-history.h"
|
||||
#include "gnc-html.h"
|
||||
#include "gnc-html-factory.h"
|
||||
#include "gnc-file.h"
|
||||
#include "gnc-plugin.h"
|
||||
#include "gnc-plugin-page-report.h"
|
||||
@ -112,7 +113,8 @@ typedef struct GncPluginPageReportPrivate
|
||||
gboolean reloading;
|
||||
|
||||
/// the gnc_html abstraction this PluginPage contains
|
||||
gnc_html *html;
|
||||
// gnc_html *html;
|
||||
GncHtml *html;
|
||||
|
||||
/// the container the above HTML widget is in.
|
||||
GtkContainer *container;
|
||||
@ -138,7 +140,8 @@ static void gnc_plugin_page_report_update_edit_menu (GncPluginPage *page, gboole
|
||||
static gboolean gnc_plugin_page_report_finish_pending (GncPluginPage *page);
|
||||
|
||||
static int gnc_plugin_page_report_check_urltype(URLType t);
|
||||
static void gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
|
||||
//static void gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
|
||||
static void gnc_plugin_page_report_load_cb(GncHtml * html, URLType type,
|
||||
const gchar * location, const gchar * label,
|
||||
gpointer data);
|
||||
static void gnc_plugin_page_report_expose_event_cb(GtkWidget *unused, GdkEventExpose *unused1, gpointer data);
|
||||
@ -324,7 +327,9 @@ gnc_plugin_page_report_create_widget( GncPluginPage *page )
|
||||
priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
|
||||
|
||||
topLvl = GTK_WINDOW(gnc_ui_get_toplevel());
|
||||
priv->html = gnc_html_new( topLvl );
|
||||
// priv->html = gnc_html_new( topLvl );
|
||||
priv->html = gnc_html_factory_create_html();
|
||||
gnc_html_set_parent( priv->html, topLvl );
|
||||
|
||||
gnc_html_history_set_node_destroy_cb(gnc_html_get_history(priv->html),
|
||||
gnc_plugin_page_report_history_destroy_cb,
|
||||
@ -357,6 +362,7 @@ gnc_plugin_page_report_create_widget( GncPluginPage *page )
|
||||
|
||||
gnc_window_set_progressbar_window( GNC_WINDOW(page->window) );
|
||||
gnc_html_show_url(priv->html, type, url_location, url_label, 0);
|
||||
g_free(url_location);
|
||||
gnc_window_set_progressbar_window( NULL );
|
||||
|
||||
g_signal_connect(priv->container, "expose_event",
|
||||
@ -427,7 +433,8 @@ gnc_plugin_page_report_setup( GncPluginPage *ppage )
|
||||
* called after a report is loaded into the gnc_html widget
|
||||
********************************************************************/
|
||||
static void
|
||||
gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
|
||||
//gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
|
||||
gnc_plugin_page_report_load_cb(GncHtml * html, URLType type,
|
||||
const gchar * location, const gchar * label,
|
||||
gpointer data)
|
||||
{
|
||||
@ -1428,7 +1435,7 @@ gnc_plugin_page_report_export_cb( GtkAction *action, GncPluginPageReport *report
|
||||
result = (res != SCM_BOOL_F);
|
||||
}
|
||||
else
|
||||
result = gnc_html_export (priv->html, filepath);
|
||||
result = gnc_html_export_to_file (priv->html, filepath);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@ -1485,7 +1492,7 @@ gnc_plugin_page_report_copy_cb(GtkAction *action, GncPluginPageReport *report)
|
||||
GncPluginPageReportPrivate *priv;
|
||||
|
||||
priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
|
||||
gnc_html_copy(priv->html);
|
||||
gnc_html_copy_to_clipboard(priv->html);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "gnc-report.h"
|
||||
#include "gnc-ui.h"
|
||||
#include "option-util.h"
|
||||
#include "gnc-html.h"
|
||||
#include "window-report.h"
|
||||
#include "guile-mappings.h"
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include <libguile.h>
|
||||
|
||||
#include "gnc-html.h"
|
||||
//#include "gnc-html.h"
|
||||
#include "qof.h"
|
||||
|
||||
typedef struct gnc_report_window_s gnc_report_window;
|
||||
|
@ -144,6 +144,7 @@ gnc_run_report (gint report_id, char ** data)
|
||||
|
||||
str = g_strdup_printf("(gnc:report-run %d)", report_id);
|
||||
scm_text = gfec_eval_string(str, error_handler);
|
||||
g_free(str);
|
||||
|
||||
if (scm_text == SCM_UNDEFINED || !SCM_STRINGP (scm_text))
|
||||
return FALSE;
|
||||
|
@ -17,7 +17,8 @@
|
||||
|
||||
(gnc:module-load "gnucash/engine" 0)
|
||||
(gnc:module-load "gnucash/app-utils" 0)
|
||||
(gnc:module-load "gnucash/gnome-utils" 0) ; for the html routines
|
||||
(gnc:module-load "gnucash/html" 0)
|
||||
(gnc:module-load "gnucash/gnome-utils" 0)
|
||||
|
||||
;; commodity-utilities.scm
|
||||
(export gnc:get-match-commodity-splits)
|
||||
|
Loading…
Reference in New Issue
Block a user