GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dialog-report-column-view.c
1 /********************************************************************
2  * dialog-report-column-view.c -- editor for column view of reports *
3  * Copyright (C) 2001 Bill Gribble <[email protected]> *
4  * Copyright (c) 2006 David Hampton <[email protected]> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA [email protected] *
22  ********************************************************************/
23 
24 #include "config.h"
25 
26 #include <glib/gi18n.h>
27 #include <gtk/gtk.h>
28 #include <libguile.h>
29 #include "swig-runtime.h"
30 
31 #include "dialog-report-column-view.h"
32 #include "dialog-options.h"
33 #include "dialog-utils.h"
34 #include "option-util.h"
35 #include "window-report.h"
36 #include "guile-mappings.h"
37 #include "gnc-guile-utils.h"
38 #include "gnc-report.h"
39 
40 enum available_cols
41 {
42  AVAILABLE_COL_NAME = 0,
43  AVAILABLE_COL_ROW,
44  NUM_AVAILABLE_COLS
45 };
46 
47 enum contents_cols
48 {
49  CONTENTS_COL_NAME = 0,
50  CONTENTS_COL_ROW,
51  CONTENTS_COL_REPORT_ROWS,
52  CONTENTS_COL_REPORT_COLS,
53  NUM_CONTENTS_COLS
54 };
55 
57 {
58  GNCOptionWin * optwin;
59  GtkTreeView * available;
60  GtkTreeView * contents;
61 
62  SCM options;
63  SCM view;
64  GNCOptionDB * odb;
65 
66  SCM available_list;
67  int available_selected;
68 
69  SCM contents_list;
70  int contents_selected;
71 };
72 
73 void gnc_column_view_edit_add_cb(GtkButton * button, gpointer user_data);
74 void gnc_column_view_edit_remove_cb(GtkButton * button, gpointer user_data);
75 void gnc_edit_column_view_move_up_cb(GtkButton * button, gpointer user_data);
76 void gnc_edit_column_view_move_down_cb(GtkButton * button, gpointer user_data);
77 void gnc_column_view_edit_size_cb(GtkButton * button, gpointer user_data);
78 
79 static void
80 gnc_column_view_set_option(GNCOptionDB * odb, char * section, char * name,
81  SCM new_value)
82 {
83  GNCOption * option =
84  gnc_option_db_get_option_by_name(odb, section, name);
85 
86  if (option)
87  {
88  gnc_option_db_set_option(odb, section, name, new_value);
89 
90  /* set_option doesn't do this */
91  gnc_option_set_changed (option, TRUE);
92  }
93 }
94 
95 static void
96 gnc_column_view_edit_destroy(gnc_column_view_edit * view)
97 {
98  gnc_options_dialog_destroy(view->optwin);
99  scm_gc_unprotect_object(view->options);
100  scm_gc_unprotect_object(view->view);
101  gnc_option_db_destroy(view->odb);
102  g_free(view);
103 }
104 
105 static void
106 update_display_lists(gnc_column_view_edit * view)
107 {
108  SCM get_rpt_guids = scm_c_eval_string("gnc:all-report-template-guids");
109  SCM template_menu_name = scm_c_eval_string("gnc:report-template-menu-name/report-guid");
110  SCM report_menu_name = scm_c_eval_string("gnc:report-menu-name");
111  SCM rpt_guids = scm_call_0(get_rpt_guids);
112  SCM contents =
113  gnc_option_db_lookup_option(view->odb, "__general", "report-list",
114  SCM_BOOL_F);
115  SCM this_report;
116  SCM selection;
117  gchar *name;
118  int row, i, id;
119  GtkListStore *store;
120  GtkTreeIter iter;
121  GtkTreePath *path;
122  GtkTreeSelection *tree_selection;
123 
124 
125  /* Update the list of available reports (left selection box). */
126  row = view->available_selected;
127 
128  if (scm_is_list(view->available_list) && !scm_is_null (view->available_list))
129  {
130  row = MIN (row, scm_ilength (view->available_list) - 1);
131  selection = scm_list_ref (view->available_list, scm_from_int (row));
132  }
133  else
134  {
135  selection = SCM_UNDEFINED;
136  }
137 
138  scm_gc_unprotect_object(view->available_list);
139  view->available_list = rpt_guids;
140  scm_gc_protect_object(view->available_list);
141 
142  store = GTK_LIST_STORE(gtk_tree_view_get_model(view->available));
143  gtk_list_store_clear(store);
144 
145  if (scm_is_list(rpt_guids))
146  {
147  for (i = 0; !scm_is_null(rpt_guids); rpt_guids = SCM_CDR(rpt_guids), i++)
148  {
149  if (scm_is_equal (SCM_CAR(rpt_guids), selection))
150  row = i;
151  name = gnc_scm_to_utf8_string (scm_call_2(template_menu_name, SCM_CAR(rpt_guids),
152  SCM_BOOL_F));
153 
154  gtk_list_store_append(store, &iter);
155  gtk_list_store_set(store, &iter,
156  AVAILABLE_COL_NAME, _(name),
157  AVAILABLE_COL_ROW, i,
158  -1);
159  g_free (name);
160  }
161 
162  }
163 
164  tree_selection = gtk_tree_view_get_selection(view->available);
165  path = gtk_tree_path_new_from_indices(row, -1);
166  gtk_tree_selection_select_path(tree_selection, path);
167  gtk_tree_path_free(path);
168 
169 
170  /* Update the list of selected reports (right selection box). */
171  row = view->contents_selected;
172 
173  if (scm_is_list(view->contents_list) && !scm_is_null (view->contents_list))
174  {
175  row = MIN (row, scm_ilength (view->contents_list) - 1);
176  selection = scm_list_ref (view->contents_list, scm_from_int (row));
177  }
178  else
179  {
180  selection = SCM_UNDEFINED;
181  }
182 
183  scm_gc_unprotect_object(view->contents_list);
184  view->contents_list = contents;
185  scm_gc_protect_object(view->contents_list);
186 
187  store = GTK_LIST_STORE(gtk_tree_view_get_model(view->contents));
188  gtk_list_store_clear(store);
189  if (scm_is_list(contents))
190  {
191  for (i = 0; !scm_is_null(contents); contents = SCM_CDR(contents), i++)
192  {
193  if (scm_is_equal (SCM_CAR(contents), selection))
194  row = i;
195 
196  id = scm_to_int(SCM_CAAR(contents));
197  this_report = gnc_report_find(id);
198  name = gnc_scm_to_utf8_string (scm_call_1(report_menu_name, this_report));
199 
200  gtk_list_store_append(store, &iter);
201  gtk_list_store_set
202  (store, &iter,
203  CONTENTS_COL_NAME, _(name),
204  CONTENTS_COL_ROW, i,
205  CONTENTS_COL_REPORT_COLS, scm_to_int(SCM_CADR(SCM_CAR(contents))),
206  CONTENTS_COL_REPORT_ROWS, scm_to_int(SCM_CADDR(SCM_CAR(contents))),
207  -1);
208  g_free (name);
209  }
210  }
211 
212  tree_selection = gtk_tree_view_get_selection(view->contents);
213  path = gtk_tree_path_new_from_indices(row, -1);
214  gtk_tree_selection_select_path(tree_selection, path);
215  // gtk_tree_view_scroll_to_cell(view->contents, path, NULL, TRUE, 0.5, 0.0);
216  gtk_tree_path_free(path);
217 }
218 
219 static void
220 gnc_column_view_select_avail_cb(GtkTreeSelection *selection,
222 {
223  GtkTreeModel *model;
224  GtkTreeIter iter;
225 
226  if (gtk_tree_selection_get_selected(selection, &model, &iter))
227  gtk_tree_model_get(model, &iter,
228  AVAILABLE_COL_ROW, &r->available_selected,
229  -1);
230 }
231 
232 static void
233 gnc_column_view_select_contents_cb(GtkTreeSelection *selection,
235 {
236  GtkTreeModel *model;
237  GtkTreeIter iter;
238 
239  if (gtk_tree_selection_get_selected(selection, &model, &iter))
240  gtk_tree_model_get(model, &iter,
241  AVAILABLE_COL_ROW, &r->contents_selected,
242  -1);
243 }
244 
245 static void
246 gnc_column_view_edit_apply_cb(GNCOptionWin * w, gpointer user_data)
247 {
248  SCM dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
249  gnc_column_view_edit * win = user_data;
250 
251  if (!win) return;
252  gnc_option_db_commit(win->odb);
253  scm_call_2(dirty_report, win->view, SCM_BOOL_T);
254 }
255 
256 static void
257 gnc_column_view_edit_close_cb(GNCOptionWin * win, gpointer user_data)
258 {
259  gnc_column_view_edit * r = user_data;
260  SCM set_editor = scm_c_eval_string("gnc:report-set-editor-widget!");
261 
262  scm_call_2(set_editor, r->view, SCM_BOOL_F);
263  gnc_column_view_edit_destroy(r);
264 }
265 
266 
267 /********************************************************************
268  * gnc_column_view_edit_options
269  * create the editor.
270  ********************************************************************/
271 
272 GtkWidget *
273 gnc_column_view_edit_options(SCM options, SCM view)
274 {
275  SCM get_editor = scm_c_eval_string("gnc:report-editor-widget");
276  SCM ptr;
277  GtkWidget * editor;
278  GtkListStore *store;
279  GtkCellRenderer *renderer;
280  GtkTreeViewColumn *column;
281  GtkTreeSelection *selection;
282 
283  ptr = scm_call_1(get_editor, view);
284  if (ptr != SCM_BOOL_F)
285  {
286 #define FUNC_NAME "gtk_window_present"
287  GtkWindow * w = SWIG_MustGetPtr(ptr, SWIG_TypeQuery("_p_GtkWidget"), 1, 0);
288  gtk_window_present(w);
289 #undef FUNC_NAME
290  return NULL;
291  }
292  else
293  {
295  GtkBuilder *builder;
296 
297  r->optwin = gnc_options_dialog_new(NULL);
298 
299  /* Hide the generic dialog page list. */
300  gtk_widget_hide(gnc_options_page_list(r->optwin));
301 
302  builder = gtk_builder_new();
303  gnc_builder_add_from_file (builder, "dialog-report.glade", "view_contents_table");
304 
305  editor = GTK_WIDGET(gtk_builder_get_object (builder, "view_contents_table"));
306  r->available = GTK_TREE_VIEW (gtk_builder_get_object (builder, "available_view"));
307  r->contents = GTK_TREE_VIEW (gtk_builder_get_object (builder, "contents_view"));
308  r->options = options;
309  r->view = view;
310  r->available_selected = 0;
311  r->available_list = SCM_EOL;
312  r->contents_selected = 0;
313  r->contents_list = SCM_EOL;
314  r->odb = gnc_option_db_new(r->options);
315 
316  gnc_options_dialog_build_contents(r->optwin, r->odb);
317 
318  gtk_notebook_append_page(GTK_NOTEBOOK(gnc_options_dialog_notebook
319  (r->optwin)),
320  editor,
321  gtk_label_new(_("Contents")));
322 
323  scm_gc_protect_object(r->options);
324  scm_gc_protect_object(r->view);
325  scm_gc_protect_object(r->available_list);
326  scm_gc_protect_object(r->contents_list);
327 
328  /* Build the 'available' view */
329  store = gtk_list_store_new (NUM_AVAILABLE_COLS, G_TYPE_STRING, G_TYPE_INT);
330  gtk_tree_view_set_model(r->available, GTK_TREE_MODEL(store));
331  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), AVAILABLE_COL_NAME, GTK_SORT_ASCENDING);
332  g_object_unref(store);
333 
334  renderer = gtk_cell_renderer_text_new();
335  column = gtk_tree_view_column_new_with_attributes("", renderer,
336  "text", AVAILABLE_COL_NAME,
337  NULL);
338  gtk_tree_view_append_column(r->available, column);
339 
340  selection = gtk_tree_view_get_selection(r->available);
341  g_signal_connect(selection, "changed",
342  G_CALLBACK(gnc_column_view_select_avail_cb), r);
343 
344  /* Build the 'contents' view */
345  store = gtk_list_store_new (NUM_CONTENTS_COLS, G_TYPE_STRING, G_TYPE_INT,
346  G_TYPE_INT, G_TYPE_INT);
347  gtk_tree_view_set_model(r->contents, GTK_TREE_MODEL(store));
348  g_object_unref(store);
349 
350  renderer = gtk_cell_renderer_text_new();
351  column = gtk_tree_view_column_new_with_attributes(_("Report"), renderer,
352  "text", CONTENTS_COL_NAME,
353  NULL);
354  gtk_tree_view_append_column(r->contents, column);
355 
356  renderer = gtk_cell_renderer_text_new();
357  column = gtk_tree_view_column_new_with_attributes(_("Rows"), renderer,
358  "text", CONTENTS_COL_REPORT_ROWS,
359  NULL);
360  gtk_tree_view_append_column(r->contents, column);
361 
362  renderer = gtk_cell_renderer_text_new();
363  column = gtk_tree_view_column_new_with_attributes(_("Cols"), renderer,
364  "text", CONTENTS_COL_REPORT_COLS,
365  NULL);
366  gtk_tree_view_append_column(r->contents, column);
367 
368  selection = gtk_tree_view_get_selection(r->contents);
369  g_signal_connect(selection, "changed",
370  G_CALLBACK(gnc_column_view_select_contents_cb), r);
371 
372  update_display_lists(r);
373 
374  gnc_options_dialog_set_apply_cb(r->optwin,
375  gnc_column_view_edit_apply_cb, r);
376  gnc_options_dialog_set_close_cb(r->optwin,
377  gnc_column_view_edit_close_cb, r);
378 
379  gtk_widget_show(gnc_options_dialog_widget(r->optwin));
380 
381  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, r);
382 
383  g_object_unref(G_OBJECT(builder));
384 
385  return gnc_options_dialog_widget(r->optwin);
386  }
387 }
388 
389 void
390 gnc_column_view_edit_add_cb(GtkButton * button, gpointer user_data)
391 {
392  gnc_column_view_edit * r = user_data;
393  SCM make_report = scm_c_eval_string("gnc:make-report");
394  SCM mark_report = scm_c_eval_string("gnc:report-set-needs-save?!");
395  SCM template_name;
396  SCM new_report;
397  SCM newlist = SCM_EOL;
398  SCM oldlist = r->contents_list;
399  int count;
400  int oldlength, id;
401 
402  if (scm_is_list(r->available_list) &&
403  (scm_ilength(r->available_list) > r->available_selected))
404  {
405  template_name = scm_list_ref(r->available_list,
406  scm_from_int (r->available_selected));
407  new_report = scm_call_1(make_report, template_name);
408  id = scm_to_int(new_report);
409  scm_call_2(mark_report, gnc_report_find(id), SCM_BOOL_T);
410  oldlength = scm_ilength(r->contents_list);
411 
412  if (oldlength > r->contents_selected)
413  {
414  for (count = 0; count < r->contents_selected; count++)
415  {
416  newlist = scm_cons(SCM_CAR(oldlist), newlist);
417  oldlist = SCM_CDR(oldlist);
418  }
419  newlist = scm_append
420  (scm_listify(scm_reverse(scm_cons(SCM_LIST4(new_report,
421  scm_from_int (1),
422  scm_from_int (1),
423  SCM_BOOL_F),
424  newlist)),
425  oldlist,
426  SCM_UNDEFINED));
427  }
428  else
429  {
430  newlist = scm_append
431  (scm_listify(oldlist,
432  SCM_LIST1(SCM_LIST4(new_report,
433  scm_from_int (1),
434  scm_from_int (1),
435  SCM_BOOL_F)),
436  SCM_UNDEFINED));
437  r->contents_selected = oldlength;
438  }
439 
440  scm_gc_unprotect_object(r->contents_list);
441  r->contents_list = newlist;
442  scm_gc_protect_object(r->contents_list);
443 
444  gnc_column_view_set_option(r->odb, "__general", "report-list",
445  r->contents_list);
446  gnc_options_dialog_changed (r->optwin);
447  }
448 
449  update_display_lists(r);
450 }
451 
452 void
453 gnc_column_view_edit_remove_cb(GtkButton * button, gpointer user_data)
454 {
455  gnc_column_view_edit * r = user_data;
456  SCM newlist = SCM_EOL;
457  SCM oldlist = r->contents_list;
458  int count;
459  int oldlength;
460 
461  if (scm_is_list(r->contents_list))
462  {
463  oldlength = scm_ilength(r->contents_list);
464  if (oldlength > r->contents_selected)
465  {
466  for (count = 0; count < r->contents_selected; count++)
467  {
468  newlist = scm_cons(SCM_CAR(oldlist), newlist);
469  oldlist = SCM_CDR(oldlist);
470  }
471  if (count <= oldlength)
472  {
473  newlist = scm_append(scm_listify(scm_reverse(newlist), SCM_CDR(oldlist), SCM_UNDEFINED));
474  }
475  }
476 
477  if (r->contents_selected > 0 && oldlength == r->contents_selected + 1)
478  {
479  r->contents_selected --;
480  }
481 
482  scm_gc_unprotect_object(r->contents_list);
483  r->contents_list = newlist;
484  scm_gc_protect_object(r->contents_list);
485 
486  gnc_column_view_set_option(r->odb, "__general", "report-list",
487  r->contents_list);
488 
489  gnc_options_dialog_changed (r->optwin);
490  }
491 
492  update_display_lists(r);
493 }
494 
495 void
496 gnc_edit_column_view_move_up_cb(GtkButton * button, gpointer user_data)
497 {
498  gnc_column_view_edit * r = user_data;
499  SCM oldlist = r->contents_list;
500  SCM newlist = SCM_EOL;
501  SCM temp;
502  int oldlength;
503  int count;
504 
505  oldlength = scm_ilength(r->contents_list);
506  if ((r->contents_selected > 0) && (oldlength > r->contents_selected))
507  {
508  for (count = 1; count < r->contents_selected; count++)
509  {
510  newlist = scm_cons(SCM_CAR(oldlist), newlist);
511  oldlist = SCM_CDR(oldlist);
512  }
513  temp = SCM_CAR(oldlist);
514  oldlist = SCM_CDR(oldlist);
515  newlist = scm_cons(temp, scm_cons(SCM_CAR(oldlist), newlist));
516  newlist = scm_append(scm_listify(scm_reverse(newlist), SCM_CDR(oldlist), SCM_UNDEFINED));
517 
518  scm_gc_unprotect_object(r->contents_list);
519  r->contents_list = newlist;
520  scm_gc_protect_object(r->contents_list);
521 
522  r->contents_selected = r->contents_selected - 1;
523 
524  gnc_column_view_set_option(r->odb, "__general", "report-list",
525  r->contents_list);
526 
527  gnc_options_dialog_changed (r->optwin);
528 
529  update_display_lists(r);
530  }
531 }
532 
533 void
534 gnc_edit_column_view_move_down_cb(GtkButton * button, gpointer user_data)
535 {
536  gnc_column_view_edit * r = user_data;
537  SCM oldlist = r->contents_list;
538  SCM newlist = SCM_EOL;
539  SCM temp;
540  int oldlength;
541  int count;
542 
543  oldlength = scm_ilength(r->contents_list);
544  if (oldlength > (r->contents_selected + 1))
545  {
546  for (count = 0; count < r->contents_selected; count++)
547  {
548  newlist = scm_cons(SCM_CAR(oldlist), newlist);
549  oldlist = SCM_CDR(oldlist);
550  }
551  temp = SCM_CAR(oldlist);
552  oldlist = SCM_CDR(oldlist);
553  newlist = scm_cons(temp, scm_cons(SCM_CAR(oldlist), newlist));
554  newlist = scm_append(scm_listify(scm_reverse(newlist), SCM_CDR(oldlist), SCM_UNDEFINED));
555 
556  scm_gc_unprotect_object(r->contents_list);
557  r->contents_list = newlist;
558  scm_gc_protect_object(r->contents_list);
559 
560  r->contents_selected = r->contents_selected + 1;
561 
562  gnc_column_view_set_option(r->odb, "__general", "report-list",
563  r->contents_list);
564 
565  gnc_options_dialog_changed (r->optwin);
566 
567  update_display_lists(r);
568  }
569 }
570 
571 void
572 gnc_column_view_edit_size_cb(GtkButton * button, gpointer user_data)
573 {
574  gnc_column_view_edit * r = user_data;
575  GtkWidget * rowspin;
576  GtkWidget * colspin;
577  GtkWidget * dlg;
578  GtkBuilder *builder;
579  SCM current;
580  int length;
581  int dlg_ret;
582 
583  builder = gtk_builder_new();
584  gnc_builder_add_from_file (builder, "dialog-report.glade", "col_adjustment");
585  gnc_builder_add_from_file (builder, "dialog-report.glade", "row_adjustment");
586  gnc_builder_add_from_file (builder, "dialog-report.glade", "Edit Report Size");
587  dlg = GTK_WIDGET(gtk_builder_get_object (builder, "Edit Report Size"));
588 
589  /* get the spinner widgets */
590  rowspin = GTK_WIDGET(gtk_builder_get_object (builder, "row_spin"));
591  colspin = GTK_WIDGET(gtk_builder_get_object (builder, "col_spin"));
592 
593  length = scm_ilength(r->contents_list);
594  if (length > r->contents_selected)
595  {
596  current = scm_list_ref(r->contents_list,
597  scm_from_int (r->contents_selected));
598  gtk_spin_button_set_value(GTK_SPIN_BUTTON(colspin),
599  (float)scm_to_int(SCM_CADR(current)));
600  gtk_spin_button_set_value(GTK_SPIN_BUTTON(rowspin),
601  (float)scm_to_int(SCM_CADDR(current)));
602 
603  dlg_ret = gtk_dialog_run(GTK_DIALOG(dlg));
604  gtk_widget_hide(dlg);
605 
606  if (dlg_ret == GTK_RESPONSE_OK)
607  {
608  current = SCM_LIST4(SCM_CAR(current),
609  scm_from_int (gtk_spin_button_get_value_as_int
610  (GTK_SPIN_BUTTON(colspin))),
611  scm_from_int (gtk_spin_button_get_value_as_int
612  (GTK_SPIN_BUTTON(rowspin))),
613  SCM_BOOL_F);
614  scm_gc_unprotect_object(r->contents_list);
615  r->contents_list = scm_list_set_x(r->contents_list,
616  scm_from_int (r->contents_selected),
617  current);
618  scm_gc_protect_object(r->contents_list);
619  gnc_options_dialog_changed (r->optwin);
620  update_display_lists(r);
621  }
622 
623  g_object_unref(G_OBJECT(builder));
624 
625  gtk_widget_destroy(dlg);
626  }
627 }