diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d50497cf1..79a1cb3020 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,6 +226,8 @@ endif() pkg_check_modules (ZLIB REQUIRED zlib) +pkg_check_modules (JSON_GLIB REQUIRED json-glib-1.0) + if (MSVC) message (STATUS "Hint: To create the import libraries for the gnome DLLs (e.g. gconf-2.lib), use the dlltool as follows: pexports bin/libgconf-2-4.dll > lib/libgconf-2.def ; dlltool -d lib/libgconf-2.def -D bin/libgconf-2-4.dll -l lib/gconf-2.lib") diff --git a/gnucash/html/CMakeLists.txt b/gnucash/html/CMakeLists.txt index 9a5f30bb5f..86e79a2be6 100644 --- a/gnucash/html/CMakeLists.txt +++ b/gnucash/html/CMakeLists.txt @@ -12,6 +12,7 @@ set (html_HEADERS html-widget.hpp html-widget-wrapped.h my-test-of-cglib.h + gnc-html-litehtml-json.h ) set(cglib_remote_HEADERS @@ -34,6 +35,7 @@ set (html_SOURCES cairo-borders.cpp html-widget.cpp my-test-of-cglib.c + gnc-html-litehtml-json.c ) set(cglib_remote_SOURCES @@ -74,7 +76,8 @@ target_link_libraries(gnc-html PkgConfig::GTK3 ${LITEHTML_LDFLAGS} ${GUILE_LDFLAGS} - litehtml) + litehtml + ${JSON_GLIB_LDFLAGS}) target_compile_definitions(gnc-html PRIVATE -DG_LOG_DOMAIN=\"gnc.html\") @@ -88,6 +91,7 @@ PRIVATE ${CMAKE_SOURCE_DIR}/borrowed/litehtml/src/gumbo/include ${CMAKE_SOURCE_DIR}/borrowed/litehtml/src/gumbo/include/gumbo ${CMAKE_SOURCE_DIR}/borrowed/cglib + ${JSON_GLIB_INCLUDE_DIRS} ) if (APPLE) diff --git a/gnucash/html/gnc-html-litehtml-json.c b/gnucash/html/gnc-html-litehtml-json.c new file mode 100644 index 0000000000..b5e386b0ca --- /dev/null +++ b/gnucash/html/gnc-html-litehtml-json.c @@ -0,0 +1,233 @@ +/*******************************************************************\ + * gnc-html-litehtml-json.c -- create chart from json string * + * * + * Copyright (C) 2024 Robert Fewell * + * * + * * + * 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 * +\********************************************************************/ +/** @file gnc-html-litehtml-json.c + @brief Use json string to create chart + @author Copyright (c) 2024 Robert Fewell +*/ +#include +#include + +#include "json-glib/json-glib.h" + +#include "gnc-html-litehtml-json.h" + +#include "cglib.h" + +typedef struct general_data mygeneral_data; +typedef struct pie_data mypie_data; + +typedef struct _chart_data +{ + gchar *name; + gdouble value; + gchar *color; +} chart_data; + + +/* Replace 'target' with 'replacement' in the input string. */ +static gchar * +string_replace (const gchar *input, + const gchar *target, + const gchar *replacement) +{ + gchar **pieces; + gchar *output; + + pieces = g_strsplit (input, target, -1); + output = g_strjoinv (replacement, pieces); + g_strfreev (pieces); + + return output; +} + +static const gchar * +get_label (JsonReader *reader, gint element) +{ + if (element > json_reader_count_elements (reader)) + return NULL; + + json_reader_read_element (reader, element); + const char *label = json_reader_get_string_value (reader); + json_reader_end_element (reader); + + return label; +} + +static gdouble +get_value (JsonReader *reader, gint element) +{ + json_reader_read_element (reader, 0); + json_reader_read_member (reader, "data"); + + if (element > json_reader_count_elements (reader)) + return 0; + + json_reader_read_element (reader, element); + gdouble value = json_reader_get_double_value (reader); + json_reader_end_element (reader); + + json_reader_end_member (reader); //data + + json_reader_end_element (reader); //element 0 + + return value; +} + +static const gchar * +get_color (JsonReader *reader, gint element) +{ + json_reader_read_element (reader, 0); + json_reader_read_member (reader, "backgroundColor"); + + if (element > json_reader_count_elements (reader)) + return NULL; + + json_reader_read_element (reader, element); + const char *color = json_reader_get_string_value (reader); + json_reader_end_element (reader); + + json_reader_end_member (reader); //backgroundColor + + json_reader_end_element (reader); //element 0 + + return color; +} + +void +gnc_html_litehtml_json_create_chart (const gchar* json_text, const gchar* file_name) +{ + JsonParser *parser = json_parser_new (); + json_parser_load_from_data (parser, json_text, -1, NULL); + JsonReader *reader = json_reader_new (json_parser_get_root (parser)); + + const char *type = json_reader_get_string_value (reader); + + json_reader_end_member (reader); + +//FIXME.... + if (g_strcmp0 (type, "pie") != 0) + { + g_object_unref (reader); + g_object_unref (parser); + return; + } + + if (!json_reader_read_member (reader, "data")) + { + g_object_unref (reader); + g_object_unref (parser); + return; + } + json_reader_read_member (reader, "labels"); + gint count = json_reader_count_elements (reader); + + gint max_num_char = 0; + gdouble total = 0; + chart_data *cd = g_new0 (chart_data, count); + + for(int i = 0; i < count; i++) + { + cd[i].name = string_replace (get_label (reader, i), "&", "&"); + gint len = strlen (cd[i].name); + + if (len > max_num_char) + max_num_char = len; + } + + json_reader_end_member (reader); //labels + + json_reader_read_member (reader, "datasets"); + + for(int i = 0; i < count; i++) + { + cd[i].value = get_value (reader, i); + total = total + cd[i].value; + } + + for(int i = 0; i < count; i++) + { + cd[i].color = g_strdup (get_color (reader, i)); + } + + json_reader_end_member (reader); //datasets + + json_reader_end_member (reader); //data + + mygeneral_data* general = g_new0 (mygeneral_data, 1); + + general->stroke_width = 1; + general->margin = 40.0; // 20 top and 20 bottom + general->viewport_x = 960; // image width size 680 + general->viewport_y = 360; // image height size 400 + general->font_size = 12; + general->d_file = 0; + + // adjust width depending on max_num_char + general->viewport_x = (general->viewport_y - general->margin) + 40 + (max_num_char * general->font_size) * 0.6; + + mypie_data* pd = g_new0 (mypie_data, 1); + + general->file_name = malloc(sizeof(char) * 30); + strcpy(general->file_name, file_name); + + pd->general = general; + pd->n_slices = count; + pd->slices = malloc(sizeof(struct pie_slice) * pd->n_slices); + + pd->d_h1_font_size = 50; + pd->d_h2_font_size = 20; + + for(int i = 0; i < pd->n_slices; i++) + { + pd->slices[i].name = malloc(60); + strcpy(pd->slices[i].name, cd[i].name); + pd->slices[i].percentage = cd[i].value / total; + + char c; + int r, g, b; + sscanf(cd[i].color, "%c%02x%02x%02x", &c, &r, &g, &b); + + pd->slices[i].color.r = r; + pd->slices[i].color.g = g; + pd->slices[i].color.b = b; + } + + pie (pd); + + for(int i = 0; i < count; i++) + { + g_free (cd[i].name); + g_free (cd[i].color); + } + g_free (cd); + + g_free (pd->slices); + g_free (pd); + + g_free (general->file_name); + g_free (general); + + g_object_unref (reader); + g_object_unref (parser); +} diff --git a/gnucash/html/gnc-html-litehtml-json.h b/gnucash/html/gnc-html-litehtml-json.h new file mode 100644 index 0000000000..1f56373986 --- /dev/null +++ b/gnucash/html/gnc-html-litehtml-json.h @@ -0,0 +1,35 @@ +/*******************************************************************\ + * gnc-html-litehtml-json.h -- create chart from json string * + * * + * Copyright (C) 2024 Robert Fewell * + * * + * * + * 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 * +\********************************************************************/ +/** @file gnc-html-litehtml-json.h + @brief Use json string to create chart + @author Copyright (c) 2024 Robert Fewell +*/ +#ifndef GNC_HTML_LITEHTML_JSON_H +#define GNC_HTML_LITEHTML_JSON_H + +#include + +void gnc_html_litehtml_json_create_chart (const gchar* json_text, const gchar* file_name); + +#endif diff --git a/gnucash/html/gnc-html-litehtml.c b/gnucash/html/gnc-html-litehtml.c index ec785d5bf6..5e5cabe3d8 100644 --- a/gnucash/html/gnc-html-litehtml.c +++ b/gnucash/html/gnc-html-litehtml.c @@ -63,6 +63,7 @@ static void gnc_html_litehtml_finalize (GObject* obj); #include "gnc-html-litehtml-p.h" #include "my-test-of-cglib.h" +#include "gnc-html-litehtml-json.h" /* indicates the debugging module that this .o belongs to. */ static QofLogModule log_module = GNC_MOD_HTML; @@ -637,34 +638,48 @@ impl_litehtml_create_charts (GncHtml* self, const gchar* data, const gchar *repo if (!ptr) return FALSE; -//g_print("ptr '%s'\n", ptr); - priv = GNC_HTML_LITEHTML_GET_PRIVATE(self); gchar *ptr_end = g_strstr_len (ptr + 1, -1, "'"); gchar *image_name = strndup (ptr + 1, ptr_end - (ptr + 1)); -g_print("image_name '%s'\n", image_name); - gchar *start = g_strndup (data, (ptr + 1) - data); gchar *end = g_strdup (data + (ptr_end - data)); + gchar *json_start_ptr = g_strstr_len (end, -1, "var chartjsoptions = "); + + if (!json_start_ptr) + { + g_free (start); + g_free (end); + g_free (image_name); + return FALSE; + } + + gchar *json_end_ptr = g_strstr_len (end, -1, "};"); + + gchar *json_text = g_strndup (json_start_ptr + 20, json_end_ptr - (json_start_ptr + 19)); + gchar *image_uri_start = g_strndup (report_uri, strlen(report_uri) - file_temp_len); g_free (priv->html_string); priv->html_string = g_strconcat (start, image_uri_start, image_name, end, NULL); - gchar *image_path = g_strndup (priv->file_name, strlen(priv->file_name) - file_temp_len); + gchar *image_path_start = g_strndup (priv->file_name, strlen(priv->file_name) - file_temp_len); - my_test_of_cglib_charts (g_strconcat (image_path, image_name, NULL)); + gchar *image_path = g_strconcat (image_path_start, image_name, NULL); + + gnc_html_litehtml_json_create_chart (json_text, image_path); g_free (start); g_free (end); g_free (image_path); + g_free (image_path_start); g_free (image_uri_start); g_free (image_name); + g_free (json_text); return TRUE; } diff --git a/gnucash/report/html-chart.scm b/gnucash/report/html-chart.scm index bd2d94597d..4b40c5b162 100644 --- a/gnucash/report/html-chart.scm +++ b/gnucash/report/html-chart.scm @@ -462,7 +462,11 @@ document.getElementById(chartid).onclick = function(evt) { (size->str (gnc:html-chart-width chart)) (size->str (gnc:html-chart-height chart)))) - (push (format #f "chart-image\n" id )) +;; (push (format #f "chart-image\n" id )) + + (push (format #f "chart-image\n" id + (size->str (gnc:html-chart-height chart)))) + ;; (push "bob1\n") ;; (push "bob2\n") @@ -480,6 +484,7 @@ document.getElementById(chartid).onclick = function(evt) { ;; (push (format #f "\n" id)) ;; (push (format #f "\n" id)) ;; (push "\n") + (push "\n") (push (format #f "") + (push "\n") retval))