27 #define _GL_UNISTD_H //Deflect poisonous define in Guile's GnuLib 31 #include <glib/gstdio.h> 42 #include <gnc-guile-utils.h> 44 #include "gnc-report.h" 46 extern "C" SCM scm_init_sw_report_module(
void);
48 static QofLogModule log_module = GNC_MOD_GUI;
51 static GHashTable *reports = NULL;
52 static gint report_next_serial_id = 0;
55 try_load_config_array(
const gchar *fns[])
60 for (i = 0; fns[i]; i++)
63 if (gfec_try_load(filename))
74 update_message(
const gchar *msg)
81 load_custom_reports_stylesheets(
void)
85 static const gchar *saved_report_files[] =
87 SAVED_REPORTS_FILE, SAVED_REPORTS_FILE_OLD_REV, NULL
89 static const gchar *stylesheet_files[] = {
"stylesheets-2.0", NULL};
90 static int is_user_config_loaded = FALSE;
92 if (is_user_config_loaded)
94 else is_user_config_loaded = TRUE;
96 update_message(
"loading saved reports");
97 try_load_config_array(saved_report_files);
98 update_message(
"loading stylesheets");
99 try_load_config_array(stylesheet_files);
103 gnc_report_init (
void)
105 scm_init_sw_report_module();
106 scm_c_use_module (
"gnucash report");
107 scm_c_use_module (
"gnucash reports");
108 scm_c_eval_string(
"(report-module-loader (list '(gnucash report stylesheets)))");
110 load_custom_reports_stylesheets();
115 gnc_report_init_table(
void)
119 reports = g_hash_table_new_full(
120 g_int_hash, g_int_equal,
121 g_free, (GDestroyNotify) scm_gc_unprotect_object);
126 gnc_report_remove_by_id(gint
id)
129 g_hash_table_remove(reports, &
id);
132 SCM gnc_report_find(gint
id)
134 SCM report =
nullptr;
138 report =
static_cast<SCM
>(g_hash_table_lookup(reports, &
id));
147 gint gnc_report_add(SCM report)
149 SCM get_id = scm_c_eval_string(
"gnc:report-id");
153 gnc_report_init_table();
155 value = scm_call_1(get_id, report);
156 if (scm_is_number(value))
158 id = scm_to_int(value);
159 if (!g_hash_table_lookup(reports, &
id))
161 key = g_new(gint, 1);
163 g_hash_table_insert(reports, key, (gpointer)report);
164 scm_gc_protect_object(report);
167 g_warning(
"Report specified id of %d is already is use. " 168 "Using generated id.",
id);
171 id = report_next_serial_id++;
172 while (
id < G_MAXINT)
174 if (!g_hash_table_lookup(reports, &
id))
176 key = g_new(gint, 1);
178 g_hash_table_insert(reports, key, (gpointer)report);
179 scm_gc_protect_object(report);
182 id = report_next_serial_id++;
185 g_warning(
"Unable to add report to table. %d reports in use.", G_MAXINT);
186 report_next_serial_id = G_MAXINT;
191 yes_remove(gpointer key, gpointer val, gpointer data)
197 gnc_reports_flush_global(
void)
200 g_hash_table_foreach_remove(reports, yes_remove, NULL);
204 gnc_reports_foreach (GHFunc func, gpointer user_data)
206 gnc_report_init_table();
208 g_hash_table_foreach (reports, func, user_data);
212 gnc_run_report_with_error_handling (gint report_id, gchar ** data, gchar **errmsg)
214 SCM report, res, html, captured_error;
216 report = gnc_report_find (report_id);
217 g_return_val_if_fail (data, FALSE);
218 g_return_val_if_fail (errmsg, FALSE);
219 g_return_val_if_fail (!scm_is_false (report), FALSE);
221 res = scm_call_1 (scm_c_eval_string (
"gnc:render-report"), report);
222 html = scm_car (res);
223 captured_error = scm_cadr (res);
225 if (!scm_is_false (html))
227 *data = gnc_scm_to_utf8_string (html);
233 constexpr
const char* with_err =
"Report %s failed to generate html: %s";
234 constexpr
const char* without_err =
"Report %s Failed to generate html but didn't raise a Scheme exception.";
235 auto scm_err = scm_is_string (captured_error) ? gnc_scm_to_utf8_string (captured_error) :
238 if (scm_err && *scm_err)
239 *errmsg = g_strdup_printf (with_err, gnc_report_name (report), scm_err);
241 *errmsg = g_strdup_printf (without_err, gnc_report_name (report));
250 gnc_report_name( SCM report )
252 SCM get_name = scm_c_eval_string(
"gnc:report-name");
254 if (report == SCM_BOOL_F)
257 return gnc_scm_call_1_to_string(get_name, report);
261 gnc_report_id_string_to_report_id (
const char *id_string)
263 g_return_val_if_fail (id_string, -1);
266 uint rpt_id = std::strtoul (id_string, &end_ptr, 10);
267 if (end_ptr == id_string)
return -1;
268 if (*end_ptr ==
'\0')
return rpt_id;
269 if (*end_ptr !=
'|')
return -1;
271 auto anchor_str = end_ptr + 1;
272 uint anchor_id = std::strtoul (anchor_str, &end_ptr, 10);
273 if (end_ptr == anchor_str || *end_ptr !=
'\0')
return -1;
275 const SCM get_linked = scm_c_eval_string (
"gnc:report-get-linked-report");
276 return scm_to_uint (scm_call_2 (get_linked, scm_from_uint (rpt_id), scm_from_uint (anchor_id)));
280 gnc_run_report_id_string_with_error_handling (
const char * id_string,
char **data,
283 g_return_val_if_fail (id_string, FALSE);
284 g_return_val_if_fail (data, FALSE);
287 if (strncmp (
"id=", id_string, 3) != 0)
290 gint report_id = gnc_report_id_string_to_report_id (id_string + 3);
294 return gnc_run_report_with_error_handling (report_id, data, errmsg);
298 gnc_get_default_report_font_family(
void)
301 GtkWidget *top_widget;
302 PangoFontDescription *font_desc;
303 GtkStyleContext *top_widget_style_c;
304 gchar *default_font_family;
306 top_list = gtk_window_list_toplevels();
307 if (top_list == NULL)
308 return g_strdup (
"Arial");
309 top_widget = GTK_WIDGET(top_list->data);
310 g_list_free(top_list);
311 top_widget_style_c = gtk_widget_get_style_context (top_widget);
312 gtk_style_context_get (top_widget_style_c, gtk_widget_get_state_flags (GTK_WIDGET(top_widget)),
313 "font", &font_desc, NULL);
315 default_font_family = g_strdup(pango_font_description_get_family (font_desc));
317 pango_font_description_free (font_desc);
319 if (!default_font_family)
320 return g_strdup (
"Arial");
321 else if (g_str_has_prefix (default_font_family,
".AppleSystemUIFont"))
323 g_free (default_font_family);
324 return g_strdup (
"Arial");
327 return default_font_family;
331 gnc_saved_reports_write_internal (
const gchar *file,
const gchar *contents, gboolean overwrite)
333 gboolean success = TRUE;
337 gint flags = O_WRONLY | O_CREAT | (overwrite ? O_TRUNC : O_APPEND);
343 if (strstr(file,
"backup"))
346 fd = g_open (file, flags, 0666);
349 PWARN(
"Cannot open file %s: %s\n", file, strerror(errno));
353 length = strlen (contents);
354 written = write(fd, contents, length);
358 PWARN(
"Cannot write to file %s: %s\n", file, strerror(errno));
361 else if (written != length)
364 PWARN(
"File %s truncated (provided %d, written %d)",
365 file, length, (
int)written);
369 else if (close(fd) == -1)
370 PWARN(
"Close failed for file %s: %s", file, strerror(errno));
376 gboolean gnc_saved_reports_backup (
void)
378 gboolean success = FALSE;
381 gchar *contents = NULL;
382 GError *save_error = NULL;
384 if (g_file_test (saved_rpts_path, G_FILE_TEST_EXISTS))
386 if (!g_file_get_contents (saved_rpts_path, &contents, NULL, &save_error))
388 PWARN (
"Couldn't read contents of %s.\nReason: %s", saved_rpts_path, save_error->message);
389 g_error_free (save_error);
395 DEBUG (
"creating backup of file %s", saved_rpts_bkp_path);
396 success = gnc_saved_reports_write_internal (saved_rpts_bkp_path, contents, TRUE);
399 g_free (saved_rpts_path);
400 g_free (saved_rpts_bkp_path);
407 gnc_saved_reports_write_to_file (
const gchar* report_def, gboolean overwrite)
409 gboolean success = FALSE;
414 DEBUG (
"writing to %s", saved_rpts_path);
415 success = gnc_saved_reports_write_internal (saved_rpts_path, report_def, overwrite);
418 g_free (saved_rpts_path);
424 gnc_get_optiondb_from_dispatcher(SCM dispatcher)
426 SCM get_options = scm_c_eval_string(
"gnc:optiondb");
427 if (dispatcher == SCM_BOOL_F)
429 auto scm_ptr{scm_call_1(get_options, dispatcher)};
430 auto smob{!scm_is_null(scm_ptr) && SCM_INSTANCEP(scm_ptr) &&
431 scm_is_true(scm_slot_exists_p(scm_ptr, SCM_EOL)) ?
432 scm_slot_ref(scm_ptr, SCM_EOL) : (scm_ptr)};
434 void *c_ptr{
nullptr};
435 if (!SCM_NULLP(smob))
437 if (SCM_POINTER_P(smob))
438 c_ptr = SCM_POINTER_VALUE(smob);
440 c_ptr =
reinterpret_cast<void*
>(SCM_CELL_WORD_1(smob));
445 auto u_ptr{
static_cast<std::unique_ptr<GncOptionDB>*
>(c_ptr)};
Holds all of the options for a book, report, or stylesheet, organized by GncOptionSections.
gchar * gnc_build_userdata_path(const gchar *filename)
Make a path to filename in the user's gnucash data directory.
#define PINFO(format, args...)
Print an informational note.
#define DEBUG(format, args...)
Print a debugging message.
#define PWARN(format, args...)
Log a warning.
All type declarations for the whole Gnucash engine.
The primary C++ interface to options for books, reports, and stylesheets.
File path resolution utility functions.