GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-report.c
1 /********************************************************************
2  * gnc-report.c -- C functions for reports. *
3  * *
4  * Copyright (C) 2001 Linux Developers Group *
5  * Copyright (C) 2006 Chris Shoemaker <[email protected]> *
6  * *
7  * This program is free software; you can redistribute it and/or *
8  * modify it under the terms of the GNU General Public License as *
9  * published by the Free Software Foundation; either version 2 of *
10  * the License, or (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License*
18  * along with this program; if not, contact: *
19  * *
20  * Free Software Foundation Voice: +1-617-542-5942 *
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22  * Boston, MA 02110-1301, USA [email protected] *
23  ********************************************************************/
24 
25 #include "config.h"
26 
27 #include <glib.h>
28 #include <glib/gstdio.h>
29 #include <gtk/gtk.h>
30 #include <libguile.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include "gfec.h"
34 #include <string.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 
38 #include "gnc-filepath-utils.h"
39 #include "gnc-guile-utils.h"
40 #include "gnc-report.h"
41 #include "gnc-engine.h"
42 
43 static QofLogModule log_module = GNC_MOD_GUI;
44 
45 /* Fow now, this is global, like it was in guile. It _should_ be per-book. */
46 static GHashTable *reports = NULL;
47 static gint report_next_serial_id = 0;
48 
49 static void
50 gnc_report_init_table(void)
51 {
52  if (!reports)
53  {
54  reports = g_hash_table_new_full(
55  g_int_hash, g_int_equal,
56  g_free, (GDestroyNotify) scm_gc_unprotect_object);
57  }
58 }
59 
60 void
61 gnc_report_remove_by_id(gint id)
62 {
63  if (reports)
64  g_hash_table_remove(reports, &id);
65 }
66 
67 SCM gnc_report_find(gint id)
68 {
69  gpointer report = NULL;
70 
71  if (reports)
72  {
73  report = g_hash_table_lookup(reports, &id);
74  }
75 
76  if (!report)
77  return SCM_BOOL_F;
78 
79  return report;
80 }
81 
82 gint gnc_report_add(SCM report)
83 {
84  SCM get_id = scm_c_eval_string("gnc:report-id");
85  SCM value;
86  gint id, *key;
87 
88  gnc_report_init_table();
89 
90  value = scm_call_1(get_id, report);
91  if (scm_is_number(value))
92  {
93  id = scm_to_int(value);
94  if (!g_hash_table_lookup(reports, &id))
95  {
96  key = g_new(gint, 1);
97  *key = id;
98  g_hash_table_insert(reports, key, (gpointer)report);
99  scm_gc_protect_object(report);
100  return id;
101  }
102  g_warning("Report specified id of %d is already is use. "
103  "Using generated id.", id);
104  }
105 
106  id = report_next_serial_id++;
107  while (id < G_MAXINT)
108  {
109  if (!g_hash_table_lookup(reports, &id))
110  {
111  key = g_new(gint, 1);
112  *key = id;
113  g_hash_table_insert(reports, key, (gpointer)report);
114  scm_gc_protect_object(report);
115  return id;
116  }
117  id = report_next_serial_id++;
118  }
119 
120  g_warning("Unable to add report to table. %d reports in use.", G_MAXINT);
121  report_next_serial_id = G_MAXINT;
122  return G_MAXINT;
123 }
124 
125 static gboolean
126 yes_remove(gpointer key, gpointer val, gpointer data)
127 {
128  return TRUE;
129 }
130 
131 void
132 gnc_reports_flush_global(void)
133 {
134  if (reports)
135  g_hash_table_foreach_remove(reports, yes_remove, NULL);
136 }
137 
138 GHashTable *
139 gnc_reports_get_global(void)
140 {
141  gnc_report_init_table();
142  return reports;
143 }
144 
145 static void
146 error_handler(const char *str)
147 {
148  g_warning("Failure running report: %s", str);
149 }
150 
151 gboolean
152 gnc_run_report (gint report_id, char ** data)
153 {
154  gchar *free_data;
155  SCM scm_text;
156  gchar *str;
157 
158  g_return_val_if_fail (data != NULL, FALSE);
159  *data = NULL;
160 
161  str = g_strdup_printf("(gnc:report-run %d)", report_id);
162  scm_text = gfec_eval_string(str, error_handler);
163  g_free(str);
164 
165  if (scm_text == SCM_UNDEFINED || !scm_is_string (scm_text))
166  return FALSE;
167 
168  *data = gnc_scm_to_utf8_string (scm_text);
169 
170  return TRUE;
171 }
172 
173 gboolean
174 gnc_run_report_id_string (const char * id_string, char **data)
175 {
176  gint report_id;
177 
178  g_return_val_if_fail (id_string != NULL, FALSE);
179  g_return_val_if_fail (data != NULL, FALSE);
180  *data = NULL;
181 
182  if (strncmp ("id=", id_string, 3) != 0)
183  return FALSE;
184 
185  if (sscanf (id_string + 3, "%d", &report_id) != 1)
186  return FALSE;
187 
188  return gnc_run_report (report_id, data);
189 }
190 
191 gchar*
192 gnc_report_name( SCM report )
193 {
194  SCM get_name = scm_c_eval_string("gnc:report-name");
195 
196  if (report == SCM_BOOL_F)
197  return NULL;
198 
199  return gnc_scm_call_1_to_string(get_name, report);
200 }
201 
202 gchar*
203 gnc_get_default_report_font_family(void)
204 {
205  GList* top_list;
206  GtkWidget* top_widget;
207  GtkStyle* top_widget_style;
208  const gchar* default_font_family;
209 
210  top_list = gtk_window_list_toplevels();
211  g_return_val_if_fail (top_list != NULL, NULL);
212  top_widget = GTK_WIDGET(top_list->data);
213  g_list_free(top_list);
214  top_widget_style = gtk_rc_get_style(top_widget);
215  default_font_family =
216  pango_font_description_get_family(top_widget_style->font_desc);
217 
218  if (default_font_family == NULL)
219  return g_strdup("Arial");
220  else
221  return g_strdup(default_font_family);
222 }
223 
224 static gboolean
225 gnc_saved_reports_write_internal (const gchar *file, const gchar *contents, gboolean overwrite)
226 {
227  gboolean success = TRUE;
228  gint fd;
229  extern int errno;
230  ssize_t written;
231  gint length;
232  gint flags = O_WRONLY | O_CREAT | (overwrite ? O_TRUNC : O_APPEND);
233 
234  fd = g_open (file, flags, 0666);
235  if (fd == -1)
236  {
237  PWARN("Cannot open file %s: %s\n", file, strerror(errno));
238  return FALSE;
239  }
240 
241  length = strlen (contents);
242  written = write(fd, contents, length);
243  if (written == -1 )
244  {
245  success = FALSE;
246  PWARN("Cannot write to file %s: %s\n", file, strerror(errno));
247  close(fd);
248  }
249  else if (written != length)
250  {
251  success = FALSE;
252  PWARN("File %s truncated (provided %d, written %d)",
253  file, length, (int)written);
254  /* Ignore errors on close */
255  close(fd);
256  }
257  else if (close(fd) == -1)
258  PWARN("Close failed for file %s: %s", file, strerror(errno));
259 
260  return success;
261 }
262 
263 
264 gboolean gnc_saved_reports_backup (void)
265 {
266  gboolean success = FALSE;
267  gchar *saved_rpts_path = gnc_build_dotgnucash_path (SAVED_REPORTS_FILE);
268  gchar *saved_rpts_bkp_path = g_strconcat (saved_rpts_path, "-backup", NULL);
269  gchar *contents = NULL;
270  GError *save_error = NULL;
271 
272  if (g_file_test (saved_rpts_path, G_FILE_TEST_EXISTS))
273  {
274  if (!g_file_get_contents (saved_rpts_path, &contents, NULL, &save_error))
275  {
276  PWARN ("Couldn't read contents of %s.\nReason: %s", saved_rpts_path, save_error->message);
277  g_error_free (save_error);
278  }
279  }
280 
281  if (contents)
282  {
283  DEBUG ("creating backup of file %s", saved_rpts_bkp_path);
284  success = gnc_saved_reports_write_internal (saved_rpts_bkp_path, contents, TRUE);
285  }
286 
287  g_free (saved_rpts_path);
288  g_free (saved_rpts_bkp_path);
289  g_free (contents);
290 
291  return success;
292 }
293 
294 gboolean
295 gnc_saved_reports_write_to_file (const gchar* report_def, gboolean overwrite)
296 {
297  gboolean success = FALSE;
298  gchar *saved_rpts_path = gnc_build_dotgnucash_path (SAVED_REPORTS_FILE);
299 
300  if (report_def)
301  {
302  DEBUG ("writing to %s", saved_rpts_path);
303  success = gnc_saved_reports_write_internal (saved_rpts_path, report_def, overwrite);
304  }
305 
306  g_free (saved_rpts_path);
307 
308  return success;
309 }
#define DEBUG(format, args...)
Definition: qoflog.h:255
gchar * gnc_build_dotgnucash_path(const gchar *filename)
Make a path to filename in the user's configuration directory.
#define PWARN(format, args...)
Definition: qoflog.h:243
All type declarations for the whole Gnucash engine.
File path resolution utility functions.
const gchar * QofLogModule
Definition: qofid.h:89