GnuCash  5.6-150-g038405b370+
dialog-billterms.c
1 /*
2  * dialog-billterms.c -- Dialog to create and edit billing terms
3  * Copyright (C) 2002 Derek Atkins
4  * Author: Derek Atkins <warlord@MIT.EDU>
5  * Copyright (c) 2006 David Hampton <hampton@employees.org>
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 gnu@gnu.org
23  */
24 
25 #include <config.h>
26 
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 
30 #include "dialog-utils.h"
31 #include "gnc-component-manager.h"
32 #include "gnc-session.h"
33 #include "gnc-ui.h"
34 #include "gnc-gui-query.h"
35 #include "gnc-ui-util.h"
36 #include "qof.h"
37 
38 #include "gncBillTerm.h"
39 #include "dialog-billterms.h"
40 
41 #define DIALOG_BILLTERMS_CM_CLASS "billterms-dialog"
42 #define GNC_PREFS_GROUP "dialogs.bill-terms"
43 
44 enum term_cols
45 {
46  BILL_TERM_COL_NAME = 0,
47  BILL_TERM_COL_TERM,
48  NUM_BILL_TERM_COLS
49 };
50 
51 void billterms_new_term_cb (GtkButton *button, BillTermsWindow *btw);
52 void billterms_delete_term_cb (GtkButton *button, BillTermsWindow *btw);
53 void billterms_edit_term_cb (GtkButton *button, BillTermsWindow *btw);
54 void billterms_window_close (GtkWidget *widget, gpointer data);
55 void billterms_window_destroy_cb (GtkWidget *widget, gpointer data);
56 void billterms_type_combobox_changed (GtkComboBox *cb, gpointer data);
57 
58 typedef struct _billterm_notebook
59 {
60  GtkWidget *notebook;
61 
62  /* "Days" widgets */
63  GtkWidget *days_due_days;
64  GtkWidget *days_disc_days;
65  GtkWidget *days_disc;
66 
67  /* "Proximo" widgets */
68  GtkWidget *prox_due_day;
69  GtkWidget *prox_disc_day;
70  GtkWidget *prox_disc;
71  GtkWidget *prox_cutoff;
72 
73  /* What kind of term is this? */
74  GncBillTermType type;
75 } BillTermNB;
76 
78 {
79  GtkWidget *window;
80  GtkWidget *terms_view;
81  GtkWidget *desc_entry;
82  GtkWidget *type_label;
83  GtkWidget *term_vbox;
84  BillTermNB notebook;
85 
86  GncBillTerm *current_term;
87  QofBook *book;
88  gint component_id;
89  QofSession *session;
90 };
91 
92 typedef struct _new_billterms
93 {
94  GtkWidget *dialog;
95  GtkWidget *name_entry;
96  GtkWidget *desc_entry;
97  BillTermNB notebook;
98 
99  BillTermsWindow *btw;
100  GncBillTerm *this_term;
101 } NewBillTerm;
102 
103 
104 static GtkWidget *
105 read_widget (GtkBuilder *builder, char *name, gboolean read_only)
106 {
107  GtkWidget *widget = GTK_WIDGET(gtk_builder_get_object (builder, name));
108  if (read_only)
109  {
110  GtkAdjustment *adj;
111  gtk_editable_set_editable (GTK_EDITABLE(widget), FALSE);
112  adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON(widget));
113  gtk_adjustment_set_step_increment (adj, 0.0);
114  gtk_adjustment_set_page_increment (adj, 0.0);
115  }
116 
117  return widget;
118 }
119 
120 /* NOTE: The caller needs to unref once they attach */
121 static void
122 init_notebook_widgets (BillTermNB *notebook, gboolean read_only,
123  gpointer user_data)
124 {
125  GtkBuilder *builder;
126  GtkWidget *parent;
127 
128  /* Load the notebook from Glade File */
129  builder = gtk_builder_new ();
130  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "discount_adj");
131  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "discount_days_adj");
132  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "due_days_adj");
133  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "pdiscount_adj");
134  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "pdiscount_day_adj");
135  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "pdue_day_adj");
136  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "pcutoff_day_adj");
137  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "terms_notebook_window");
138  notebook->notebook = GTK_WIDGET(gtk_builder_get_object (builder, "term_notebook"));
139  parent = GTK_WIDGET(gtk_builder_get_object (builder, "terms_notebook_window"));
140 
141  // Set the name for this dialog so it can be easily manipulated with css
142  gtk_widget_set_name (GTK_WIDGET(notebook->notebook), "gnc-id-bill-term");
143  gnc_widget_style_context_add_class (GTK_WIDGET(notebook->notebook), "gnc-class-bill-terms");
144 
145  /* load the "days" widgets */
146  notebook->days_due_days = read_widget (builder, "days:due_days", read_only);
147  notebook->days_disc_days = read_widget (builder, "days:discount_days", read_only);
148  notebook->days_disc = read_widget (builder, "days:discount", read_only);
149 
150  /* load the "proximo" widgets */
151  notebook->prox_due_day = read_widget (builder, "prox:due_day", read_only);
152  notebook->prox_disc_day = read_widget (builder, "prox:discount_day", read_only);
153  notebook->prox_disc = read_widget (builder, "prox:discount", read_only);
154  notebook->prox_cutoff = read_widget (builder, "prox:cutoff_day", read_only);
155 
156  /* Disconnect the notebook from the window */
157  g_object_ref (notebook->notebook);
158  gtk_container_remove (GTK_CONTAINER(parent), notebook->notebook);
159  g_object_unref (G_OBJECT(builder));
160  gtk_widget_destroy (parent);
161 
162  /* NOTE: The caller needs to unref once they attach */
163 }
164 
165 static void
166 set_numeric (GtkWidget *widget, GncBillTerm *term,
167  void (*func)(GncBillTerm *, gnc_numeric))
168 {
169  gnc_numeric val;
170  gdouble fl = 0.0;
171 
172  fl = gtk_spin_button_get_value (GTK_SPIN_BUTTON(widget));
174  func (term, val);
175 }
176 
177 static void
178 get_numeric (GtkWidget *widget, GncBillTerm *term,
179  gnc_numeric (*func)(const GncBillTerm *))
180 {
181  gnc_numeric val;
182  gdouble fl;
183 
184  val = func (term);
185  fl = gnc_numeric_to_double (val);
186  gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), fl);
187 }
188 
189 static void
190 set_int (GtkWidget *widget, GncBillTerm *term,
191  void (*func)(GncBillTerm *, gint))
192 {
193  gint val;
194 
195  val = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(widget));
196  func (term, val);
197 }
198 
199 static void
200 get_int (GtkWidget *widget, GncBillTerm *term,
201  gint (*func)(const GncBillTerm *))
202 {
203  gint val;
204 
205  val = func (term);
206  gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), (gfloat)val);
207 }
208 
209 /* return TRUE if anything truly changed */
210 static gboolean
211 ui_to_billterm (NewBillTerm *nbt)
212 {
213  BillTermNB *notebook;
214  GncBillTerm *term;
215  const char *text;
216 
217  term = nbt->this_term;
218  notebook = &nbt->notebook;
219 
220  text = gtk_entry_get_text (GTK_ENTRY(nbt->desc_entry));
221  if (text)
222  gncBillTermSetDescription (term, text);
223 
224  gncBillTermSetType (nbt->this_term, nbt->notebook.type);
225 
226  switch (nbt->notebook.type)
227  {
228  case GNC_TERM_TYPE_DAYS:
229  set_int (notebook->days_due_days, term, gncBillTermSetDueDays);
230  set_int (notebook->days_disc_days, term, gncBillTermSetDiscountDays);
231  set_numeric (notebook->days_disc, term, gncBillTermSetDiscount);
232  break;
233 
234  case GNC_TERM_TYPE_PROXIMO:
235  set_int (notebook->prox_due_day, term, gncBillTermSetDueDays);
236  set_int (notebook->prox_disc_day, term, gncBillTermSetDiscountDays);
237  set_numeric (notebook->prox_disc, term, gncBillTermSetDiscount);
238  set_int (notebook->prox_cutoff, term, gncBillTermSetCutoff);
239  break;
240  }
241 
242  return gncBillTermIsDirty (term);
243 }
244 
245 static void
246 billterm_to_ui (GncBillTerm *term, GtkWidget *desc, BillTermNB *notebook)
247 {
248  gtk_entry_set_text (GTK_ENTRY(desc), gncBillTermGetDescription (term));
249  notebook->type = gncBillTermGetType (term);
250 
251  switch (notebook->type)
252  {
253  case GNC_TERM_TYPE_DAYS:
254  get_int (notebook->days_due_days, term, gncBillTermGetDueDays);
255  get_int (notebook->days_disc_days, term, gncBillTermGetDiscountDays);
256  get_numeric (notebook->days_disc, term, gncBillTermGetDiscount);
257  break;
258 
259  case GNC_TERM_TYPE_PROXIMO:
260  get_int (notebook->prox_due_day, term, gncBillTermGetDueDays);
261  get_int (notebook->prox_disc_day, term, gncBillTermGetDiscountDays);
262  get_numeric (notebook->prox_disc, term, gncBillTermGetDiscount);
263  get_int (notebook->prox_cutoff, term, gncBillTermGetCutoff);
264  break;
265  }
266 }
267 
268 static gboolean
269 verify_term_ok (NewBillTerm *nbt)
270 {
271  char *message = _("Discount days cannot be more than due days.");
272  gboolean result;
273  BillTermNB *notebook;
274  gint days_due_days, days_disc_days;
275  gint prox_due_days, prox_disc_days;
276 
277  notebook = &nbt->notebook;
278  result = TRUE;
279 
280 
281  days_due_days = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(notebook->days_due_days));
282  days_disc_days = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(notebook->days_disc_days));
283  prox_due_days = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(notebook->prox_due_day));
284  prox_disc_days = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(notebook->prox_disc_day));
285 
286  switch (nbt->notebook.type)
287  {
288  case GNC_TERM_TYPE_DAYS:
289  if (days_due_days<days_disc_days)
290  {
291  gnc_error_dialog (GTK_WINDOW(nbt->dialog), "%s", message);
292  result = FALSE;
293  }
294  break;
295  case GNC_TERM_TYPE_PROXIMO:
296  if (prox_due_days<prox_disc_days)
297  {
298  gnc_error_dialog (GTK_WINDOW(nbt->dialog), "%s", message);
299  result = FALSE;
300  }
301  break;
302  }
303 
304  return result;
305 }
306 
307 static gboolean
308 new_billterm_ok_cb (NewBillTerm *nbt)
309 {
310  BillTermsWindow *btw;
311  const char *name = NULL;
312  char *message;
313 
314  g_return_val_if_fail (nbt, FALSE);
315  btw = nbt->btw;
316 
317  /* Verify that we've got real, valid data */
318 
319  /* verify the name, maybe */
320  if (nbt->this_term == NULL)
321  {
322  name = gtk_entry_get_text (GTK_ENTRY(nbt->name_entry));
323  if (name == NULL || *name == '\0')
324  {
325  message = _("You must provide a name for this Billing Term.");
326  gnc_error_dialog (GTK_WINDOW(nbt->dialog), "%s", message);
327  return FALSE;
328  }
329  if (gncBillTermLookupByName (btw->book, name))
330  {
331  message = g_strdup_printf (_(
332  "You must provide a unique name for this Billing Term. "
333  "Your choice \"%s\" is already in use."), name);
334  gnc_error_dialog (GTK_WINDOW(nbt->dialog), "%s", message);
335  g_free (message);
336  return FALSE;
337  }
338  }
339 
340  /* Verify the actual data */
341  if (!verify_term_ok (nbt))
342  return FALSE;
343 
344  gnc_suspend_gui_refresh ();
345 
346  /* Ok, it's all valid, now either change or add this thing */
347  if (nbt->this_term == NULL)
348  {
349  nbt->this_term = gncBillTermCreate (btw->book);
350  gncBillTermBeginEdit (nbt->this_term);
351  gncBillTermSetName (nbt->this_term, name);
352  /* Reset the current term */
353  btw->current_term = nbt->this_term;
354  }
355  else
356  gncBillTermBeginEdit (btw->current_term);
357 
358  /* Fill in the rest of the term */
359  if (ui_to_billterm (nbt))
360  gncBillTermChanged (btw->current_term);
361 
362  /* Mark the table as changed and commit it */
363  gncBillTermCommitEdit (btw->current_term);
364 
365  gnc_resume_gui_refresh ();
366  return TRUE;
367 }
368 
369 static void
370 show_notebook (BillTermNB *notebook)
371 {
372  g_return_if_fail (notebook->type > 0);
373  gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook->notebook),
374  notebook->type - 1);
375 }
376 
377 static void
378 maybe_set_type (NewBillTerm *nbt, GncBillTermType type)
379 {
380  /* See if anything to do? */
381  if (type == nbt->notebook.type)
382  return;
383 
384  /* Yep. Let's refresh */
385  nbt->notebook.type = type;
386  show_notebook (&nbt->notebook);
387 }
388 
389 void
390 billterms_type_combobox_changed (GtkComboBox *cb, gpointer data)
391 {
392  NewBillTerm *nbt = data;
393  gint value;
394 
395  value = gtk_combo_box_get_active (cb);
396  maybe_set_type (nbt, value + 1);
397 }
398 
399 static GncBillTerm *
400 new_billterm_dialog (BillTermsWindow *btw, GncBillTerm *term,
401  const char *name)
402 {
403  GncBillTerm *created_term = NULL;
404  NewBillTerm *nbt;
405  GtkBuilder *builder;
406  GtkWidget *box, *combo_box;
407  gint response;
408  gboolean done;
409  const gchar *dialog_name;
410  const gchar *dialog_desc;
411  const gchar *dialog_combo;
412  const gchar *dialog_nb;
413 
414  if (!btw) return NULL;
415 
416  nbt = g_new0 (NewBillTerm, 1);
417  nbt->btw = btw;
418  nbt->this_term = term;
419 
420  /* Open and read the Glade File */
421  if (term == NULL)
422  {
423  dialog_name = "new_term_dialog";
424  dialog_desc = "description_entry";
425  dialog_combo = "type_combobox";
426  dialog_nb = "note_book_hbox";
427  }
428  else
429  {
430  dialog_name = "edit_term_dialog";
431  dialog_desc = "entry_desc";
432  dialog_combo = "type_combo";
433  dialog_nb = "notebook_hbox";
434  }
435  builder = gtk_builder_new ();
436  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "type_liststore");
437  gnc_builder_add_from_file (builder, "dialog-billterms.glade", dialog_name);
438  nbt->dialog = GTK_WIDGET(gtk_builder_get_object (builder, dialog_name));
439  nbt->name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "name_entry"));
440  nbt->desc_entry = GTK_WIDGET(gtk_builder_get_object (builder, dialog_desc));
441 
442  // Set the name for this dialog so it can be easily manipulated with css
443  gtk_widget_set_name (GTK_WIDGET(nbt->dialog), "gnc-id-new-bill-terms");
444  gnc_widget_style_context_add_class (GTK_WIDGET(nbt->dialog), "gnc-class-bill-terms");
445 
446  if (name)
447  gtk_entry_set_text (GTK_ENTRY(nbt->name_entry), name);
448 
449  /* Initialize the notebook widgets */
450  init_notebook_widgets (&nbt->notebook, FALSE, nbt);
451 
452  /* Attach the notebook */
453  box = GTK_WIDGET(gtk_builder_get_object (builder, dialog_nb));
454  gtk_box_pack_start (GTK_BOX(box), nbt->notebook.notebook, TRUE, TRUE, 0);
455  g_object_unref (nbt->notebook.notebook);
456 
457  /* Fill in the widgets appropriately */
458  if (term)
459  billterm_to_ui (term, nbt->desc_entry, &nbt->notebook);
460  else
461  nbt->notebook.type = GNC_TERM_TYPE_DAYS;
462 
463  /* Create the menu */
464  combo_box = GTK_WIDGET(gtk_builder_get_object (builder, dialog_combo));
465  gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box), nbt->notebook.type - 1);
466 
467  /* Show the right notebook page */
468  show_notebook (&nbt->notebook);
469 
470  /* Setup signals */
471  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, nbt);
472 
473  gtk_window_set_transient_for (GTK_WINDOW(nbt->dialog),
474  GTK_WINDOW(btw->window));
475 
476  /* Show what we should */
477  gtk_widget_show_all (nbt->dialog);
478  if (term)
479  {
480  gtk_widget_grab_focus (nbt->desc_entry);
481  }
482  else
483  gtk_widget_grab_focus (nbt->name_entry);
484 
485  done = FALSE;
486  while (!done)
487  {
488  response = gtk_dialog_run (GTK_DIALOG(nbt->dialog));
489  switch (response)
490  {
491  case GTK_RESPONSE_OK:
492  if (new_billterm_ok_cb (nbt))
493  {
494  created_term = nbt->this_term;
495  done = TRUE;
496  }
497  break;
498  default:
499  done = TRUE;
500  break;
501  }
502  }
503 
504  g_object_unref (G_OBJECT(builder));
505 
506  gtk_widget_destroy (nbt->dialog);
507  g_free (nbt);
508 
509  return created_term;
510 }
511 
512 /***********************************************************************/
513 
514 static void
515 billterms_term_refresh (BillTermsWindow *btw)
516 {
517  char *type_label;
518 
519  g_return_if_fail (btw);
520 
521  if (!btw->current_term)
522  {
523  gtk_widget_hide (btw->term_vbox);
524  return;
525  }
526 
527  gtk_widget_show_all (btw->term_vbox);
528  billterm_to_ui (btw->current_term, btw->desc_entry, &btw->notebook);
529  switch (gncBillTermGetType (btw->current_term))
530  {
531  case GNC_TERM_TYPE_DAYS:
532  type_label = _("Days");
533  break;
534  case GNC_TERM_TYPE_PROXIMO:
535  type_label = _("Proximo");
536  break;
537  default:
538  type_label = _("Unknown");
539  break;
540  }
541  show_notebook (&btw->notebook);
542  gtk_label_set_text (GTK_LABEL(btw->type_label), type_label);
543 }
544 
545 static void
546 billterms_window_refresh (BillTermsWindow *btw)
547 {
548  GList *list, *node;
549  GncBillTerm *term;
550  GtkTreeView *view;
551  GtkListStore *store;
552  GtkTreeIter iter;
553  GtkTreePath *path;
554  GtkTreeSelection *selection;
555  GtkTreeRowReference *reference = NULL;
556 
557  g_return_if_fail (btw);
558  view = GTK_TREE_VIEW(btw->terms_view);
559  store = GTK_LIST_STORE(gtk_tree_view_get_model (view));
560  selection = gtk_tree_view_get_selection (view);
561 
562  /* Clear the list */
563  gtk_list_store_clear (store);
564  gnc_gui_component_clear_watches (btw->component_id);
565 
566  /* Add the items to the list */
567  list = gncBillTermGetTerms (btw->book);
568 
569  /* If there are no terms, clear the term display */
570  if (list == NULL)
571  {
572  btw->current_term = NULL;
573  billterms_term_refresh (btw);
574  }
575  else
576  {
577  list = g_list_reverse (g_list_copy (list));
578  }
579 
580  for ( node = list; node; node = node->next)
581  {
582  term = node->data;
583  gnc_gui_component_watch_entity (btw->component_id,
584  gncBillTermGetGUID (term),
585  QOF_EVENT_MODIFY);
586 
587  gtk_list_store_prepend (store, &iter);
588  gtk_list_store_set (store, &iter,
589  BILL_TERM_COL_NAME, gncBillTermGetName (term),
590  BILL_TERM_COL_TERM, term,
591  -1);
592  if (term == btw->current_term)
593  {
594  path = gtk_tree_model_get_path (GTK_TREE_MODEL(store), &iter);
595  reference = gtk_tree_row_reference_new (GTK_TREE_MODEL(store), path);
596  gtk_tree_path_free (path);
597  }
598  }
599 
600  g_list_free (list);
601 
602  gnc_gui_component_watch_entity_type (btw->component_id,
603  GNC_BILLTERM_MODULE_NAME,
604  QOF_EVENT_CREATE | QOF_EVENT_DESTROY);
605 
606  if (reference)
607  {
608  path = gtk_tree_row_reference_get_path (reference);
609  gtk_tree_row_reference_free (reference);
610  if (path)
611  {
612  gtk_tree_selection_select_path (selection, path);
613  gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
614  gtk_tree_path_free (path);
615  }
616  }
617  else
618  {
619  GtkTreeIter iter;
620  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter))
621  gtk_tree_selection_select_iter (selection, &iter);
622  }
623 }
624 
625 static void
626 billterm_selection_changed (GtkTreeSelection *selection,
627  BillTermsWindow *btw)
628 {
629  GncBillTerm *term = NULL;
630  GtkTreeModel *model;
631  GtkTreeIter iter;
632 
633  g_return_if_fail (btw);
634 
635  if (gtk_tree_selection_get_selected (selection, &model, &iter))
636  gtk_tree_model_get (model, &iter, BILL_TERM_COL_TERM, &term, -1);
637 
638  /* If we've changed, then reset the term list */
639  if (GNC_IS_BILLTERM(term) && (term != btw->current_term))
640  btw->current_term = term;
641 
642  /* And force a refresh of the entries */
643  billterms_term_refresh (btw);
644 }
645 
646 static void
647 billterm_selection_activated (GtkTreeView *tree_view,
648  GtkTreePath *path,
649  GtkTreeViewColumn *column,
650  BillTermsWindow *btw)
651 {
652  new_billterm_dialog (btw, btw->current_term, NULL);
653 }
654 
655 void
656 billterms_new_term_cb (GtkButton *button, BillTermsWindow *btw)
657 {
658  g_return_if_fail (btw);
659  new_billterm_dialog (btw, NULL, NULL);
660 }
661 
662 void
663 billterms_delete_term_cb (GtkButton *button, BillTermsWindow *btw)
664 {
665  g_return_if_fail (btw);
666 
667  if (!btw->current_term)
668  return;
669 
670  if (gncBillTermGetRefcount (btw->current_term) > 0)
671  {
672  gnc_error_dialog (GTK_WINDOW(btw->window),
673  _("Term \"%s\" is in use. You cannot delete it."),
674  gncBillTermGetName (btw->current_term));
675  return;
676  }
677 
678  if (gnc_verify_dialog (GTK_WINDOW(btw->window), FALSE,
679  _("Are you sure you want to delete \"%s\"?"),
680  gncBillTermGetName (btw->current_term)))
681  {
682  /* Ok, let's remove it */
683  gnc_suspend_gui_refresh ();
684  gncBillTermBeginEdit (btw->current_term);
685  gncBillTermDestroy (btw->current_term);
686  btw->current_term = NULL;
687  gnc_resume_gui_refresh ();
688  }
689 }
690 
691 void
692 billterms_edit_term_cb (GtkButton *button, BillTermsWindow *btw)
693 {
694  g_return_if_fail (btw);
695  if (!btw->current_term)
696  return;
697  new_billterm_dialog (btw, btw->current_term, NULL);
698 }
699 
700 static void
701 billterms_window_refresh_handler (GHashTable *changes, gpointer data)
702 {
703  BillTermsWindow *btw = data;
704 
705  g_return_if_fail (data);
706  billterms_window_refresh (btw);
707 }
708 
709 static void
710 billterms_window_close_handler (gpointer data)
711 {
712  BillTermsWindow *btw = data;
713 
714  g_return_if_fail (btw);
715 
716  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(btw->window));
717  gtk_widget_destroy (btw->window);
718 }
719 
720 void
721 billterms_window_close (GtkWidget *widget, gpointer data)
722 {
723  BillTermsWindow *btw = data;
724 
725  gnc_close_gui_component (btw->component_id);
726 }
727 
728 static gboolean
729 billterms_window_delete_event_cb (GtkWidget *widget,
730  GdkEvent *event,
731  gpointer data)
732 {
733  BillTermsWindow *btw = data;
734 
735  if (!btw) return FALSE;
736 
737  // this cb allows the window size to be saved on closing with the X
738  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(btw->window));
739  return FALSE;
740 }
741 
742 void
743 billterms_window_destroy_cb (GtkWidget *widget, gpointer data)
744 {
745  BillTermsWindow *btw = data;
746 
747  if (!btw) return;
748 
749  gnc_unregister_gui_component (btw->component_id);
750 
751  if (btw->window)
752  {
753  gtk_widget_destroy (btw->window);
754  btw->window = NULL;
755  }
756  g_free (btw);
757 }
758 
759 static gboolean
760 billterms_window_key_press_cb (GtkWidget *widget, GdkEventKey *event,
761  gpointer data)
762 {
763  BillTermsWindow *btw = data;
764 
765  if (event->keyval == GDK_KEY_Escape)
766  {
767  billterms_window_close_handler (btw);
768  return TRUE;
769  }
770  else
771  return FALSE;
772 }
773 
774 static gboolean
775 find_handler (gpointer find_data, gpointer data)
776 {
777  BillTermsWindow *btw = data;
778  QofBook *book = find_data;
779 
780  return (btw != NULL && btw->book == book);
781 }
782 
783 /* Create a billterms window */
784 BillTermsWindow *
785 gnc_ui_billterms_window_new (GtkWindow *parent, QofBook *book)
786 {
787  BillTermsWindow *btw;
788  GtkBuilder *builder;
789  GtkWidget *widget;
790  GtkTreeView *view;
791  GtkTreeViewColumn *column;
792  GtkCellRenderer *renderer;
793  GtkListStore *store;
794  GtkTreeSelection *selection;
795 
796  if (!book) return NULL;
797 
798  /*
799  * Find an existing billterm window. If found, bring it to
800  * the front. If we have an actual owner, then set it in
801  * the window.
802  */
803  btw = gnc_find_first_gui_component (DIALOG_BILLTERMS_CM_CLASS,
804  find_handler, book);
805  if (btw)
806  {
807  gtk_window_present (GTK_WINDOW(btw->window));
808  return btw;
809  }
810 
811  /* Didn't find one -- create a new window */
812  btw = g_new0 (BillTermsWindow, 1);
813  btw->book = book;
814  btw->session = gnc_get_current_session ();
815 
816  /* Open and read the Glade File */
817  builder = gtk_builder_new ();
818  gnc_builder_add_from_file (builder, "dialog-billterms.glade", "terms_window");
819  btw->window = GTK_WIDGET(gtk_builder_get_object (builder, "terms_window"));
820  btw->terms_view = GTK_WIDGET(gtk_builder_get_object (builder, "terms_view"));
821  btw->desc_entry = GTK_WIDGET(gtk_builder_get_object (builder, "desc_entry"));
822  btw->type_label = GTK_WIDGET(gtk_builder_get_object (builder, "type_label"));
823  btw->term_vbox = GTK_WIDGET(gtk_builder_get_object (builder, "term_vbox"));
824 
825  // Set the name for this dialog so it can be easily manipulated with css
826  gtk_widget_set_name (GTK_WIDGET(btw->window), "gnc-id-bill-terms");
827  gnc_widget_style_context_add_class (GTK_WIDGET(btw->window), "gnc-class-bill-terms");
828 
829  g_signal_connect (btw->window, "key_press_event",
830  G_CALLBACK(billterms_window_key_press_cb), btw);
831 
832  /* Initialize the view */
833  view = GTK_TREE_VIEW(btw->terms_view);
834  store = gtk_list_store_new (NUM_BILL_TERM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
835  gtk_tree_view_set_model (view, GTK_TREE_MODEL(store));
836  g_object_unref (store);
837 
838  renderer = gtk_cell_renderer_text_new ();
839  column = gtk_tree_view_column_new_with_attributes ("", renderer,
840  "text", BILL_TERM_COL_NAME,
841  NULL);
842  gtk_tree_view_append_column (view, column);
843 
844  g_signal_connect (view, "row-activated",
845  G_CALLBACK(billterm_selection_activated), btw);
846  selection = gtk_tree_view_get_selection (view);
847  g_signal_connect (selection, "changed",
848  G_CALLBACK(billterm_selection_changed), btw);
849 
850  /* Initialize the notebook widgets */
851  init_notebook_widgets (&btw->notebook, TRUE, btw);
852 
853  /* Attach the notebook */
854  widget = GTK_WIDGET(gtk_builder_get_object (builder, "notebook_box"));
855  gtk_box_pack_start (GTK_BOX(widget), btw->notebook.notebook,
856  TRUE, TRUE, 0);
857  g_object_unref (btw->notebook.notebook);
858 
859  /* Setup signals */
860  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, btw);
861 
862  /* register with component manager */
863  btw->component_id =
864  gnc_register_gui_component (DIALOG_BILLTERMS_CM_CLASS,
865  billterms_window_refresh_handler,
866  billterms_window_close_handler,
867  btw);
868 
869  gnc_gui_component_set_session (btw->component_id, btw->session);
870 
871  g_signal_connect (G_OBJECT(btw->window), "delete-event",
872  G_CALLBACK(billterms_window_delete_event_cb), btw);
873 
874  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(btw->window), GTK_WINDOW(parent));
875 
876  gtk_widget_show_all (btw->window);
877  billterms_window_refresh (btw);
878 
879  g_object_unref (G_OBJECT(builder));
880 
881  return btw;
882 }
883 
884 #if 0
885 /* Create a new billterms by name */
886 GncBillTerm *
887 gnc_ui_billterms_new_from_name (GtkWindow *parent, QofBook *book, const char *name)
888 {
889  BillTermsWindow *btw;
890 
891  if (!book) return NULL;
892 
893  btw = gnc_ui_billterms_window_new (parent, book);
894  if (!btw) return NULL;
895 
896  return new_billterm_dialog (btw, NULL, name);
897 }
898 #endif
gnc_numeric double_to_gnc_numeric(double in, gint64 denom, gint how)
Convert a floating-point number to a gnc_numeric.
utility functions for the GnuCash UI
double gnc_numeric_to_double(gnc_numeric in)
Convert numeric to floating-point value.
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
Billing Term interface.