GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dialog-report-style-sheet.c
1 /********************************************************************
2  * dialog-report-style-sheet.c -- window for configuring HTML style *
3  * sheets in GnuCash *
4  * Copyright (C) 2000 Bill Gribble <[email protected]> *
5  * Copyright (c) 2006 David Hampton <[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 <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 
30 #include "dialog-report-style-sheet.h"
31 #include "dialog-options.h"
32 #include "dialog-utils.h"
33 #include "gnc-gtk-utils.h"
34 #include "gnc-guile-utils.h"
35 #include "gnc-report.h"
36 #include "gnc-ui.h"
37 
38 StyleSheetDialog * gnc_style_sheet_dialog = NULL;
39 
41 {
42  GtkWidget * toplevel;
43  GtkTreeView * list_view;
44  GtkListStore * list_store;
45  GtkWidget * options_frame;
46 };
47 
48 typedef struct ss_info
49 {
50  GNCOptionWin * odialog;
51  GNCOptionDB * odb;
52  SCM stylesheet;
53  GtkTreeRowReference *row_ref;
54 } ss_info;
55 
56 enum
57 {
58  COLUMN_NAME,
59  COLUMN_STYLESHEET,
60  COLUMN_DIALOG,
61  N_COLUMNS
62 };
63 
64 
65 /************************************************************
66  * Style Sheet Edit Dialog (I.E. an options dialog) *
67  ************************************************************/
68 
69 static void
70 dirty_same_stylesheet(gpointer key, gpointer val, gpointer data)
71 {
72  SCM dirty_ss = data;
73  SCM rep_ss = NULL;
74  SCM report = val;
75  SCM func = NULL;
76 
77  func = scm_c_eval_string("gnc:report-stylesheet");
78  if (scm_is_procedure(func))
79  rep_ss = scm_call_1(func, report);
80  else
81  return;
82 
83  if (scm_is_true(scm_eq_p(rep_ss, dirty_ss)))
84  {
85  func = scm_c_eval_string("gnc:report-set-dirty?!");
86  /* This makes _me_ feel dirty! */
87  if (scm_is_procedure(func))
88  scm_call_2(func, report, SCM_BOOL_T);
89  }
90 }
91 
92 static void
93 gnc_style_sheet_options_apply_cb(GNCOptionWin * propertybox,
94  gpointer user_data)
95 {
96  ss_info * ssi = (ss_info *)user_data;
97  GHashTable *reports = NULL;
98 
99  /* FIXME: shouldn't be global */
100  reports = gnc_reports_get_global();
101  if (reports)
102  g_hash_table_foreach(reports, dirty_same_stylesheet, ssi->stylesheet);
103 
104  gnc_option_db_commit(ssi->odb);
105 }
106 
107 
108 static void
109 gnc_style_sheet_options_close_cb(GNCOptionWin * propertybox,
110  gpointer user_data)
111 {
112  ss_info * ssi = user_data;
113  GtkTreeIter iter;
114 
115  if (gtk_tree_row_reference_valid (ssi->row_ref))
116  {
117  StyleSheetDialog * ss = gnc_style_sheet_dialog;
118  GtkTreePath *path = gtk_tree_row_reference_get_path (ssi->row_ref);
119  if (gtk_tree_model_get_iter (GTK_TREE_MODEL(ss->list_store), &iter, path))
120  gtk_list_store_set (ss->list_store, &iter,
121  COLUMN_DIALOG, NULL,
122  -1);
123  gtk_tree_path_free(path);
124  }
125  gtk_tree_row_reference_free (ssi->row_ref);
126  gnc_options_dialog_destroy(ssi->odialog);
127  gnc_option_db_destroy(ssi->odb);
128  scm_gc_unprotect_object(ssi->stylesheet);
129  g_free(ssi);
130 }
131 
132 
133 static ss_info *
134 gnc_style_sheet_dialog_create(StyleSheetDialog * ss,
135  gchar *name,
136  SCM sheet_info,
137  GtkTreeRowReference *row_ref)
138 {
139  SCM get_options = scm_c_eval_string("gnc:html-style-sheet-options");
140 
141  SCM scm_options = scm_call_1(get_options, sheet_info);
142  ss_info * ssinfo = g_new0(ss_info, 1);
143  GtkWidget * window;
144  gchar * title;
145 
146  title = g_strdup_printf(_("HTML Style Sheet Properties: %s"), name);
147  ssinfo->odialog = gnc_options_dialog_new(title);
148  ssinfo->odb = gnc_option_db_new(scm_options);
149  ssinfo->stylesheet = sheet_info;
150  ssinfo->row_ref = row_ref;
151  g_free(title);
152 
153  scm_gc_protect_object(ssinfo->stylesheet);
154  g_object_ref(gnc_options_dialog_widget(ssinfo->odialog));
155 
156  gnc_options_dialog_build_contents(ssinfo->odialog,
157  ssinfo->odb);
158  gnc_options_dialog_set_apply_cb(ssinfo->odialog,
159  gnc_style_sheet_options_apply_cb,
160  ssinfo);
161  gnc_options_dialog_set_close_cb(ssinfo->odialog,
162  gnc_style_sheet_options_close_cb,
163  ssinfo);
164  window = gnc_options_dialog_widget(ssinfo->odialog);
165  gtk_window_set_transient_for(GTK_WINDOW(window),
166  GTK_WINDOW(gnc_style_sheet_dialog->toplevel));
167  gtk_window_set_destroy_with_parent(GTK_WINDOW(window), TRUE);
168  gtk_window_present(GTK_WINDOW(window));
169 
170  return(ssinfo);
171 }
172 
173 
174 static SCM
175 gnc_style_sheet_new (StyleSheetDialog * ssd)
176 {
177  SCM make_ss = scm_c_eval_string("gnc:make-html-style-sheet");
178  SCM templates = scm_c_eval_string("(gnc:get-html-templates)");
179  SCM t_name = scm_c_eval_string("gnc:html-style-sheet-template-name");
180  SCM new_ss = SCM_BOOL_F;
181  GtkWidget * template_combo;
182  GtkTreeModel * template_model;
183  GtkTreeIter iter;
184  GtkWidget * name_entry;
185  gint dialog_retval;
186  GList *template_names = NULL;
187 
188  /* get the new name for the style sheet */
189  GtkBuilder *builder;
190  GtkWidget *dlg;
191 
192  builder = gtk_builder_new();
193  gnc_builder_add_from_file (builder, "dialog-report.glade", "template_liststore");
194  gnc_builder_add_from_file (builder, "dialog-report.glade", "New Style Sheet Dialog");
195 
196  dlg = GTK_WIDGET(gtk_builder_get_object (builder, "New Style Sheet Dialog"));
197  template_combo = GTK_WIDGET(gtk_builder_get_object (builder, "template_combobox"));
198  name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "name_entry"));
199 
200  g_assert(ssd);
201 
202  /* Erase the initial dummy entry. */
203  template_model = gtk_combo_box_get_model(GTK_COMBO_BOX(template_combo));
204  gtk_list_store_clear(GTK_LIST_STORE(template_model));
205 
206  /* put in the list of style sheet type names */
207  for (; !scm_is_null(templates); templates = SCM_CDR(templates))
208  {
209  gchar* orig_name;
210 
211  SCM t = SCM_CAR(templates);
212  orig_name = gnc_scm_call_1_to_string(t_name, t);
213 
214  /* Store the untranslated names for lookup later */
215  template_names = g_list_prepend (template_names, (gpointer)orig_name);
216 
217  /* The displayed name should be translated */
218  gtk_list_store_append(GTK_LIST_STORE(template_model), &iter);
219  gtk_list_store_set (GTK_LIST_STORE(template_model), &iter, 0, _(orig_name), -1);
220 
221  /* Note: don't g_free orig_name here - template_names still refers to it*/
222  }
223  gtk_combo_box_set_active(GTK_COMBO_BOX(template_combo), 0);
224 
225  /* get the name */
226  gtk_window_set_transient_for (GTK_WINDOW(dlg), GTK_WINDOW(ssd->toplevel));
227  dialog_retval = gtk_dialog_run(GTK_DIALOG(dlg));
228 
229  if (dialog_retval == GTK_RESPONSE_OK)
230  {
231  gint choice = gtk_combo_box_get_active (GTK_COMBO_BOX(template_combo));
232  const char *template_str = g_list_nth_data (template_names, choice);
233  const char *name_str = gtk_entry_get_text(GTK_ENTRY(name_entry));
234  if (name_str && strlen(name_str) == 0)
235  {
236  /* If the name is empty, we display an error dialog but
237  * refuse to create the new style sheet. */
238  gnc_error_dialog (ssd->toplevel, "%s", _("You must provide a name for the new style sheet."));
239  name_str = NULL;
240  }
241  if (template_str && name_str)
242  {
243  new_ss = scm_call_2(make_ss,
244  scm_from_utf8_string(template_str),
245  scm_from_utf8_string(name_str));
246  }
247  }
248 
249  g_list_free_full (template_names, g_free);
250 
251  g_object_unref(G_OBJECT(builder));
252 
253  gtk_widget_destroy(dlg);
254  return(new_ss);
255 }
256 
257 
258 /************************************************************
259  * Style Sheet Selection Dialog *
260  ************************************************************/
261 static void
262 gnc_style_sheet_select_dialog_add_one(StyleSheetDialog * ss,
263  SCM sheet_info,
264  gboolean select)
265 {
266  SCM get_name;
267  gchar *c_name;
268  GtkTreeSelection *selection;
269  GtkTreeIter iter;
270 
271  get_name = scm_c_eval_string ("gnc:html-style-sheet-name");
272  c_name = gnc_scm_call_1_to_string (get_name, sheet_info);
273  if (!c_name)
274  return;
275 
276  /* add the column name */
277  scm_gc_protect_object (sheet_info);
278  gtk_list_store_append (ss->list_store, &iter);
279  gtk_list_store_set (ss->list_store, &iter,
280  /* Translate the displayed name */
281  COLUMN_NAME, _(c_name),
282  COLUMN_STYLESHEET, sheet_info,
283  -1);
284  g_free (c_name);
285  /* The translation of the name fortunately doesn't affect the
286  * lookup because that is done through the sheet_info argument. */
287 
288  if (select)
289  {
290  selection = gtk_tree_view_get_selection (ss->list_view);
291  gtk_tree_selection_select_iter (selection, &iter);
292  }
293 }
294 
295 static void
296 gnc_style_sheet_select_dialog_fill(StyleSheetDialog * ss)
297 {
298  SCM stylesheets = scm_c_eval_string("(gnc:get-html-style-sheets)");
299  SCM sheet_info;
300 
301  /* pack it full of content */
302  for (; !scm_is_null(stylesheets); stylesheets = SCM_CDR(stylesheets))
303  {
304  sheet_info = SCM_CAR(stylesheets);
305  gnc_style_sheet_select_dialog_add_one(ss, sheet_info, FALSE);
306  }
307 }
308 
309 static void
310 gnc_style_sheet_select_dialog_response_cb (GtkDialog *unused,
311  gint response,
312  gpointer user_data)
313 {
314  StyleSheetDialog * ss;
315  GtkTreeSelection * selection;
316  GtkTreeRowReference * row_ref;
317  GtkTreeModel * model;
318  GtkTreePath * path;
319  GtkTreeIter iter;
320  ss_info * ssinfo;
321  SCM remover;
322  SCM sheet_info;
323  gchar *name;
324 
325  ss = (StyleSheetDialog *)user_data;
326  switch (response)
327  {
328  case GNC_RESPONSE_NEW:
329  sheet_info = gnc_style_sheet_new(ss);
330  if (sheet_info == SCM_BOOL_F)
331  break;
332  gnc_style_sheet_select_dialog_add_one(ss, sheet_info, TRUE);
333  /* Fall through */
334 
335  case GNC_RESPONSE_EDIT:
336  selection = gtk_tree_view_get_selection (ss->list_view);
337  if (gtk_tree_selection_get_selected (selection, &model, &iter))
338  {
339  gtk_tree_model_get (model, &iter,
340  COLUMN_NAME, &name,
341  COLUMN_STYLESHEET, &sheet_info,
342  -1);
343  /* Fire off options dialog here */
344  path = gtk_tree_model_get_path (GTK_TREE_MODEL(ss->list_store), &iter);
345  row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL(ss->list_store), path);
346  ssinfo = gnc_style_sheet_dialog_create(ss, name, sheet_info, row_ref);
347  gtk_list_store_set (ss->list_store, &iter,
348  COLUMN_DIALOG, ssinfo,
349  -1);
350  g_free(name);
351  }
352  break;
353 
354  case GNC_RESPONSE_DELETE:
355  selection = gtk_tree_view_get_selection (ss->list_view);
356  if (gtk_tree_selection_get_selected (selection, &model, &iter))
357  {
358  gtk_tree_model_get (model, &iter,
359  COLUMN_STYLESHEET, &sheet_info,
360  COLUMN_DIALOG, &ssinfo,
361  -1);
362  gtk_list_store_remove (ss->list_store, &iter);
363 
364  if (ssinfo)
365  gnc_style_sheet_options_close_cb(NULL, ssinfo);
366  remover = scm_c_eval_string("gnc:html-style-sheet-remove");
367  scm_call_1(remover, sheet_info);
368  scm_gc_unprotect_object(sheet_info);
369  }
370  break;
371 
372  case GTK_RESPONSE_CLOSE:
373  default:
374  gnc_style_sheet_dialog = NULL;
375  gtk_widget_destroy(ss->toplevel);
376  g_free(ss);
377  break;
378  }
379 }
380 
381 
382 static void
383 gnc_style_sheet_select_dialog_event_cb (GtkWidget *widget,
384  GdkEvent *event,
385  gpointer user_data)
386 {
387  StyleSheetDialog * ss = user_data;
388 
389  g_return_if_fail(event != NULL);
390  g_return_if_fail(ss != NULL);
391 
392  if (event->type != GDK_2BUTTON_PRESS)
393  return;
394 
395  /* Synthesize a click of the edit button */
396  gnc_style_sheet_select_dialog_response_cb (NULL, GNC_RESPONSE_EDIT, ss);
397 }
398 
399 
400 static StyleSheetDialog *
401 gnc_style_sheet_select_dialog_create(void)
402 {
403  StyleSheetDialog * ss = g_new0(StyleSheetDialog, 1);
404  GtkBuilder * builder;
405  GtkCellRenderer * renderer;
406  GtkTreeSelection * selection;
407 
408  builder = gtk_builder_new();
409  gnc_builder_add_from_file (builder, "dialog-report.glade", "Select Style Sheet Dialog");
410 
411  ss->toplevel = GTK_WIDGET(gtk_builder_get_object (builder, "Select Style Sheet Dialog"));
412 
413  ss->list_view = GTK_TREE_VIEW(gtk_builder_get_object (builder, "style_sheet_list_view"));
414  ss->list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER);
415  gtk_tree_view_set_model(ss->list_view, GTK_TREE_MODEL(ss->list_store));
416  g_object_unref(ss->list_store);
417  renderer = gtk_cell_renderer_text_new ();
418  gtk_tree_view_insert_column_with_attributes(ss->list_view, -1,
419  _("Style Sheet Name"), renderer,
420  "text", COLUMN_NAME,
421  NULL);
422 
423  selection = gtk_tree_view_get_selection (ss->list_view);
424  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
425 
426  g_signal_connect(ss->toplevel, "response",
427  G_CALLBACK(gnc_style_sheet_select_dialog_response_cb), ss);
428  g_signal_connect(ss->list_view, "event-after",
429  G_CALLBACK(gnc_style_sheet_select_dialog_event_cb), ss);
430 
431  gnc_style_sheet_select_dialog_fill(ss);
432 
433  gtk_widget_show_all(ss->toplevel);
434 
435  g_object_unref(G_OBJECT(builder));
436 
437  return ss;
438 }
439 
440 
441 void
442 gnc_style_sheet_dialog_open(void)
443 {
444  if (gnc_style_sheet_dialog)
445  {
446  gtk_window_present(GTK_WINDOW(gnc_style_sheet_dialog->toplevel));
447  }
448  else
449  {
450  gnc_style_sheet_dialog =
451  gnc_style_sheet_select_dialog_create();
452  }
453 }
454 
gtk helper routines.