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_run_report_id_string_with_error_handling (
const char * id_string,
char **data,
266 g_return_val_if_fail (id_string, FALSE);
267 g_return_val_if_fail (data, FALSE);
270 if (strncmp (
"id=", id_string, 3) != 0)
273 if (sscanf (id_string + 3,
"%d", &report_id) != 1)
276 return gnc_run_report_with_error_handling (report_id, data, errmsg);
280 gnc_get_default_report_font_family(
void)
283 GtkWidget *top_widget;
284 PangoFontDescription *font_desc;
285 GtkStyleContext *top_widget_style_c;
286 gchar *default_font_family;
288 top_list = gtk_window_list_toplevels();
289 if (top_list == NULL)
290 return g_strdup (
"Arial");
291 top_widget = GTK_WIDGET(top_list->data);
292 g_list_free(top_list);
293 top_widget_style_c = gtk_widget_get_style_context (top_widget);
294 gtk_style_context_get (top_widget_style_c, gtk_widget_get_state_flags (GTK_WIDGET(top_widget)),
295 "font", &font_desc, NULL);
297 default_font_family = g_strdup(pango_font_description_get_family (font_desc));
299 pango_font_description_free (font_desc);
301 if (!default_font_family)
302 return g_strdup (
"Arial");
303 else if (g_str_has_prefix (default_font_family,
".AppleSystemUIFont"))
305 g_free (default_font_family);
306 return g_strdup (
"Arial");
309 return default_font_family;
313 gnc_saved_reports_write_internal (
const gchar *file,
const gchar *contents, gboolean overwrite)
315 gboolean success = TRUE;
319 gint flags = O_WRONLY | O_CREAT | (overwrite ? O_TRUNC : O_APPEND);
325 if (strstr(file,
"backup"))
328 fd = g_open (file, flags, 0666);
331 PWARN(
"Cannot open file %s: %s\n", file, strerror(errno));
335 length = strlen (contents);
336 written = write(fd, contents, length);
340 PWARN(
"Cannot write to file %s: %s\n", file, strerror(errno));
343 else if (written != length)
346 PWARN(
"File %s truncated (provided %d, written %d)",
347 file, length, (
int)written);
351 else if (close(fd) == -1)
352 PWARN(
"Close failed for file %s: %s", file, strerror(errno));
358 gboolean gnc_saved_reports_backup (
void)
360 gboolean success = FALSE;
363 gchar *contents = NULL;
364 GError *save_error = NULL;
366 if (g_file_test (saved_rpts_path, G_FILE_TEST_EXISTS))
368 if (!g_file_get_contents (saved_rpts_path, &contents, NULL, &save_error))
370 PWARN (
"Couldn't read contents of %s.\nReason: %s", saved_rpts_path, save_error->message);
371 g_error_free (save_error);
377 DEBUG (
"creating backup of file %s", saved_rpts_bkp_path);
378 success = gnc_saved_reports_write_internal (saved_rpts_bkp_path, contents, TRUE);
381 g_free (saved_rpts_path);
382 g_free (saved_rpts_bkp_path);
389 gnc_saved_reports_write_to_file (
const gchar* report_def, gboolean overwrite)
391 gboolean success = FALSE;
396 DEBUG (
"writing to %s", saved_rpts_path);
397 success = gnc_saved_reports_write_internal (saved_rpts_path, report_def, overwrite);
400 g_free (saved_rpts_path);
406 gnc_get_optiondb_from_dispatcher(SCM dispatcher)
408 SCM get_options = scm_c_eval_string(
"gnc:optiondb");
409 if (dispatcher == SCM_BOOL_F)
411 auto scm_ptr{scm_call_1(get_options, dispatcher)};
412 auto smob{!scm_is_null(scm_ptr) && SCM_INSTANCEP(scm_ptr) &&
413 scm_is_true(scm_slot_exists_p(scm_ptr, SCM_EOL)) ?
414 scm_slot_ref(scm_ptr, SCM_EOL) : (scm_ptr)};
416 void *c_ptr{
nullptr};
417 if (!SCM_NULLP(smob))
419 if (SCM_POINTER_P(smob))
420 c_ptr = SCM_POINTER_VALUE(smob);
422 c_ptr =
reinterpret_cast<void*
>(SCM_CELL_WORD_1(smob));
427 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.