GnuCash  5.6-150-g038405b370+
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
dialog-tax-table.c
1 /*
2  * dialog-tax-table.c -- Dialog to create and edit tax-tables
3  * Copyright (C) 2002 Derek Atkins
4  * Author: Derek Atkins <warlord@MIT.EDU>
5  *
6  * Copyright (c) 2006 David Hampton <hampton@employees.org>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, contact:
20  *
21  * Free Software Foundation Voice: +1-617-542-5942
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
23  * Boston, MA 02110-1301, USA gnu@gnu.org
24  */
25 
26 #include <config.h>
27 
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 
31 #include "dialog-utils.h"
32 #include "gnc-component-manager.h"
33 #include "gnc-session.h"
34 #include "gnc-ui.h"
35 #include "gnc-gui-query.h"
36 #include "gnc-gtk-utils.h"
37 #include "gnc-ui-util.h"
38 #include "qof.h"
39 #include "gnc-amount-edit.h"
40 #include "gnc-tree-view-account.h"
41 
42 #include "gncTaxTable.h"
43 #include "dialog-tax-table.h"
44 
45 #define DIALOG_TAX_TABLE_CM_CLASS "tax-table-dialog"
46 #define GNC_PREFS_GROUP "dialogs.business.tax-tables"
47 
48 enum tax_table_cols
49 {
50  TAX_TABLE_COL_NAME = 0,
51  TAX_TABLE_COL_POINTER,
52  NUM_TAX_TABLE_COLS
53 };
54 
55 enum tax_entry_cols
56 {
57  TAX_ENTRY_COL_NAME = 0,
58  TAX_ENTRY_COL_POINTER,
59  TAX_ENTRY_COL_AMOUNT,
60  NUM_TAX_ENTRY_COLS
61 };
62 
63 void tax_table_new_table_cb (GtkButton *button, TaxTableWindow *ttw);
64 void tax_table_rename_table_cb (GtkButton *button, TaxTableWindow *ttw);
65 void tax_table_delete_table_cb (GtkButton *button, TaxTableWindow *ttw);
66 void tax_table_new_entry_cb (GtkButton *button, TaxTableWindow *ttw);
67 void tax_table_edit_entry_cb (GtkButton *button, TaxTableWindow *ttw);
68 void tax_table_delete_entry_cb (GtkButton *button, TaxTableWindow *ttw);
69 void tax_table_window_close (GtkWidget *widget, gpointer data);
70 void tax_table_window_destroy_cb (GtkWidget *widget, gpointer data);
71 
73 {
74  GtkWidget *dialog;
75  GtkWidget *names_view;
76  GtkWidget *entries_view;
77 
78  GncTaxTable *current_table;
79  GncTaxTableEntry *current_entry;
80  QofBook *book;
81  gint component_id;
82  QofSession *session;
83 };
84 
85 typedef struct _new_taxtable
86 {
87  GtkWidget *dialog;
88  GtkWidget *name_entry;
89  GtkWidget *amount_entry;
90  GtkWidget *acct_tree;
91 
92  GncTaxTable *created_table;
93  TaxTableWindow *ttw;
94  GncTaxTableEntry *entry;
95  gint type;
96  gboolean new_table;
97 } NewTaxTable;
98 
99 static gboolean
100 new_tax_table_check_entry (NewTaxTable *ntt, GError **error)
101 {
102  GNCPrintAmountInfo print_info;
103  gnc_numeric value;
104  gint result;
105  GError *tmp_error = NULL;
106 
107  if (ntt->type == GNC_AMT_TYPE_VALUE)
108  {
109  Account *acc = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(ntt->acct_tree));
110  gnc_commodity *currency = xaccAccountGetCommodity (acc);
111  print_info = gnc_commodity_print_info (currency, FALSE);
112  gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT(ntt->amount_entry),
113  gnc_commodity_get_fraction (currency));
114  }
115  else
116  {
117  print_info = gnc_integral_print_info ();
118  print_info.max_decimal_places = 5;
119  gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (ntt->amount_entry), 100000);
120  }
121 
122  gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT(ntt->amount_entry), print_info);
123 
124  result = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(ntt->amount_entry),
125  &value, TRUE, &tmp_error);
126 
127  if (result == 1)
128  {
129  if (error)
130  g_propagate_error (error, tmp_error);
131  else
132  g_error_free (tmp_error);
133  return FALSE;
134  }
135  return TRUE;
136 }
137 
138 static gboolean
139 new_tax_table_ok_cb (NewTaxTable *ntt)
140 {
141  TaxTableWindow *ttw;
142  const char *name = NULL;
143  char *message;
144  Account *acc;
145  gnc_numeric amount;
146  GError *error = NULL;
147 
148  g_return_val_if_fail (ntt, FALSE);
149  ttw = ntt->ttw;
150 
151  /* Verify that we've got real, valid data */
152 
153  /* verify the name, maybe */
154  if (ntt->new_table)
155  {
156  name = gtk_entry_get_text (GTK_ENTRY(ntt->name_entry));
157  if (name == NULL || *name == '\0')
158  {
159  message = _("You must provide a name for this Tax Table.");
160  gnc_error_dialog (GTK_WINDOW(ntt->dialog), "%s", message);
161  return FALSE;
162  }
163  if (gncTaxTableLookupByName (ttw->book, name))
164  {
165  message = g_strdup_printf (_(
166  "You must provide a unique name for this Tax Table. "
167  "Your choice \"%s\" is already in use."), name);
168  gnc_error_dialog (GTK_WINDOW(ntt->dialog), "%s", message);
169  g_free (message);
170  return FALSE;
171  }
172  }
173 
174  /* test for valid value */
175  if (!new_tax_table_check_entry (ntt, &error))
176  {
177  message = g_strdup (error->message);
178  gnc_error_dialog (GTK_WINDOW(ntt->dialog), "%s", message);
179  g_free (message);
180  g_error_free (error);
181  return FALSE;
182  }
183 
184  /* verify the amount. Note that negative values are allowed (required for European tax rules) */
185  amount = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT(ntt->amount_entry));
186  if (ntt->type == GNC_AMT_TYPE_PERCENT &&
188  gnc_numeric_create (100, 1)) > 0)
189  {
190  message = _("Percentage amount must be between -100 and 100.");
191  gnc_error_dialog (GTK_WINDOW(ntt->dialog), "%s", message);
192  return FALSE;
193  }
194 
195  /* verify the account */
196  acc = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(ntt->acct_tree));
197  if (acc == NULL)
198  {
199  message = _("You must choose a Tax Account.");
200  gnc_error_dialog (GTK_WINDOW(ntt->dialog), "%s", message);
201  return FALSE;
202  }
203 
204  gnc_suspend_gui_refresh ();
205 
206  /* Ok, it's all valid, now either change to add this thing */
207  if (ntt->new_table)
208  {
209  GncTaxTable *table = gncTaxTableCreate (ttw->book);
210  gncTaxTableBeginEdit (table);
211  gncTaxTableSetName (table, name);
212  /* Reset the current table */
213  ttw->current_table = table;
214  ntt->created_table = table;
215  }
216  else
217  gncTaxTableBeginEdit (ttw->current_table);
218 
219  /* Create/edit the entry */
220  {
221  GncTaxTableEntry *entry;
222 
223  if (ntt->entry)
224  {
225  entry = ntt->entry;
226  }
227  else
228  {
229  entry = gncTaxTableEntryCreate ();
230  gncTaxTableAddEntry (ttw->current_table, entry);
231  ttw->current_entry = entry;
232  }
233 
234  gncTaxTableEntrySetAccount (entry, acc);
235  gncTaxTableEntrySetType (entry, ntt->type);
236  gncTaxTableEntrySetAmount (entry, amount);
237  }
238 
239  /* Mark the table as changed and commit it */
240  gncTaxTableChanged (ttw->current_table);
241  gncTaxTableCommitEdit (ttw->current_table);
242 
243  gnc_resume_gui_refresh ();
244  return TRUE;
245 }
246 
247 static void
248 combo_changed (GtkWidget *widget, NewTaxTable *ntt)
249 {
250  gint index;
251 
252  g_return_if_fail (GTK_IS_COMBO_BOX(widget));
253  g_return_if_fail (ntt);
254 
255  index = gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
256  ntt->type = index + 1;
257 
258  new_tax_table_check_entry (ntt, NULL);
259 }
260 
261 static void
262 tax_table_account_selection_changed_cb (GtkTreeSelection *treeselection,
263  NewTaxTable *ntt)
264 {
265  new_tax_table_check_entry (ntt, NULL);
266 }
267 
268 static GncTaxTable *
269 new_tax_table_dialog (TaxTableWindow *ttw, gboolean new_table,
270  GncTaxTableEntry *entry, const char *name)
271 {
272  GncTaxTable *created_table = NULL;
273  NewTaxTable *ntt;
274  GtkBuilder *builder;
275  GtkWidget *box, *widget, *combo;
276  gboolean done;
277  gint response, index;
278  GtkTreeSelection *selection;
279 
280  if (!ttw) return NULL;
281  if (new_table && entry) return NULL;
282 
283  ntt = g_new0 (NewTaxTable, 1);
284  ntt->ttw = ttw;
285  ntt->entry = entry;
286  ntt->new_table = new_table;
287 
288  if (entry)
289  ntt->type = gncTaxTableEntryGetType (entry);
290  else
291  ntt->type = GNC_AMT_TYPE_PERCENT;
292 
293  /* Open and read the Glade File */
294  builder = gtk_builder_new ();
295  gnc_builder_add_from_file (builder, "dialog-tax-table.glade", "type_liststore");
296  gnc_builder_add_from_file (builder, "dialog-tax-table.glade", "new_tax_table_dialog");
297 
298  ntt->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "new_tax_table_dialog"));
299 
300  // Set the name for this dialog so it can be easily manipulated with css
301  gtk_widget_set_name (GTK_WIDGET(ntt->dialog), "gnc-id-tax-table");
302  gnc_widget_style_context_add_class (GTK_WIDGET(ntt->dialog), "gnc-class-taxes");
303 
304  ntt->name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "name_entry"));
305  if (name)
306  gtk_entry_set_text (GTK_ENTRY(ntt->name_entry), name);
307 
308  /* Create the menu */
309  combo = GTK_WIDGET(gtk_builder_get_object (builder, "type_combobox"));
310  index = ntt->type ? ntt->type : GNC_AMT_TYPE_VALUE;
311  gtk_combo_box_set_active (GTK_COMBO_BOX(combo), index - 1);
312  g_signal_connect (combo, "changed", G_CALLBACK(combo_changed), ntt);
313 
314  /* Attach our own widgets */
315  box = GTK_WIDGET(gtk_builder_get_object (builder, "amount_box"));
316  ntt->amount_entry = widget = gnc_amount_edit_new ();
317  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT(widget), TRUE);
318  gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT(widget), 100000);
319  gtk_box_pack_start (GTK_BOX(box), widget, TRUE, TRUE, 0);
320 
321  box = GTK_WIDGET(gtk_builder_get_object (builder, "acct_window"));
322  ntt->acct_tree = GTK_WIDGET(gnc_tree_view_account_new (FALSE));
323  gtk_container_add (GTK_CONTAINER(box), ntt->acct_tree);
324  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(ntt->acct_tree), FALSE);
325 
326  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(ntt->acct_tree));
327  g_signal_connect (G_OBJECT(selection), "changed",
328  G_CALLBACK(tax_table_account_selection_changed_cb), ntt);
329 
330  /* Make 'enter' do the right thing */
331  gtk_entry_set_activates_default (GTK_ENTRY(gnc_amount_edit_gtk_entry
332  (GNC_AMOUNT_EDIT(ntt->amount_entry))),
333  TRUE);
334 
335  /* Fix mnemonics for generated target widgets */
336  widget = GTK_WIDGET(gtk_builder_get_object (builder, "value_label"));
337  gnc_amount_edit_make_mnemonic_target (GNC_AMOUNT_EDIT(ntt->amount_entry), widget);
338  widget = GTK_WIDGET(gtk_builder_get_object (builder, "account_label"));
339  gtk_label_set_mnemonic_widget (GTK_LABEL(widget), ntt->acct_tree);
340 
341  /* Fill in the widgets appropriately */
342  if (entry)
343  {
344  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(ntt->amount_entry),
345  gncTaxTableEntryGetAmount (entry));
346  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(ntt->acct_tree),
347  gncTaxTableEntryGetAccount (entry));
348  }
349 
350  /* Set our parent */
351  gtk_window_set_transient_for (GTK_WINDOW(ntt->dialog), GTK_WINDOW(ttw->dialog));
352 
353  /* Setup signals */
354  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, ntt);
355 
356  /* Show what we should */
357  gtk_widget_show_all (ntt->dialog);
358  if (new_table == FALSE)
359  {
360  gtk_widget_hide (GTK_WIDGET(gtk_builder_get_object (builder, "table_title")));
361  gtk_widget_hide (GTK_WIDGET(gtk_builder_get_object (builder, "table_name")));
362  gtk_widget_hide (GTK_WIDGET(gtk_builder_get_object (builder, "spacer")));
363  gtk_widget_hide (ntt->name_entry);
364  /* Tables are great for layout, but a pain when you hide widgets */
365  GTK_WIDGET(gtk_builder_get_object (builder, "ttd_table"));
366  gtk_widget_grab_focus (gnc_amount_edit_gtk_entry
367  (GNC_AMOUNT_EDIT(ntt->amount_entry)));
368  }
369  else
370  gtk_widget_grab_focus (ntt->name_entry);
371 
372  /* Display the dialog now that we're done manipulating it */
373  gtk_widget_show (ntt->dialog);
374 
375  done = FALSE;
376  while (!done)
377  {
378  response = gtk_dialog_run (GTK_DIALOG(ntt->dialog));
379  switch (response)
380  {
381  case GTK_RESPONSE_OK:
382  if (new_tax_table_ok_cb (ntt))
383  {
384  created_table = ntt->created_table;
385  done = TRUE;
386  }
387  break;
388  default:
389  done = TRUE;
390  break;
391  }
392  }
393 
394  g_object_unref (G_OBJECT(builder));
395 
396  gtk_widget_destroy (ntt->dialog);
397  g_free (ntt);
398 
399  return created_table;
400 }
401 
402 /***********************************************************************/
403 
404 static void
405 tax_table_entries_refresh (TaxTableWindow *ttw)
406 {
407  GList *list, *node;
408  GtkTreeView *view;
409  GtkListStore *store;
410  GtkTreeIter iter;
411  GtkTreePath *path;
412  GtkTreeSelection *selection;
413  GtkTreeRowReference *reference = NULL;
414  GncTaxTableEntry *selected_entry;
415 
416  g_return_if_fail (ttw);
417 
418  view = GTK_TREE_VIEW(ttw->entries_view);
419  store = GTK_LIST_STORE(gtk_tree_view_get_model (view));
420 
421  /* Clear the list */
422  selected_entry = ttw->current_entry;
423  gtk_list_store_clear (store);
424  if (ttw->current_table == NULL)
425  return;
426 
427  /* Add the items to the list */
428  list = gncTaxTableGetEntries (ttw->current_table);
429  if (list)
430  list = g_list_reverse (g_list_copy (list));
431 
432  for (node = list ; node; node = node->next)
433  {
434  char *row_text[3];
435  GncTaxTableEntry *entry = node->data;
436  Account *acc = gncTaxTableEntryGetAccount (entry);
437  gnc_numeric amount = gncTaxTableEntryGetAmount (entry);
438 
439  row_text[0] = gnc_account_get_full_name (acc);
440  switch (gncTaxTableEntryGetType (entry))
441  {
443  row_text[1] =
444  g_strdup_printf ("%s%%",
445  xaccPrintAmount (amount,
446  gnc_default_print_info (FALSE)));
447  break;
448  case GNC_AMT_TYPE_VALUE:
449  row_text[1] =
450  g_strdup_printf ("%s",
451  xaccPrintAmount (amount,
452  gnc_default_print_info (TRUE)));
453  break;
454  default:
455  row_text[1] = NULL;
456  break;
457  }
458 
459  gtk_list_store_prepend (store, &iter);
460  gtk_list_store_set (store, &iter,
461  TAX_ENTRY_COL_NAME, row_text[0],
462  TAX_ENTRY_COL_POINTER, entry,
463  TAX_ENTRY_COL_AMOUNT, row_text[1],
464  -1);
465  if (entry == selected_entry)
466  {
467  path = gtk_tree_model_get_path (GTK_TREE_MODEL(store), &iter);
468  reference = gtk_tree_row_reference_new (GTK_TREE_MODEL(store), path);
469  gtk_tree_path_free (path);
470  }
471 
472  g_free (row_text[0]);
473  g_free (row_text[1]);
474  }
475 
476  if (list)
477  g_list_free (list);
478 
479  if (reference)
480  {
481  path = gtk_tree_row_reference_get_path (reference);
482  gtk_tree_row_reference_free (reference);
483  if (path)
484  {
485  selection = gtk_tree_view_get_selection (view);
486  gtk_tree_selection_select_path (selection, path);
487  gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
488  gtk_tree_path_free (path);
489  }
490  }
491 }
492 
493 static void
494 tax_table_window_refresh (TaxTableWindow *ttw)
495 {
496  GList *list, *node;
497  GtkTreeView *view;
498  GtkListStore *store;
499  GtkTreeIter iter;
500  GtkTreePath *path;
501  GtkTreeSelection *selection;
502  GtkTreeRowReference *reference = NULL;
503  GncTaxTable *saved_current_table = ttw->current_table;
504 
505  g_return_if_fail (ttw);
506  view = GTK_TREE_VIEW(ttw->names_view);
507  store = GTK_LIST_STORE(gtk_tree_view_get_model (view));
508 
509  /* Clear the list */
510  gtk_list_store_clear(store);
511 
512  gnc_gui_component_clear_watches (ttw->component_id);
513 
514  /* Add the items to the list */
515  list = gncTaxTableGetTables (ttw->book);
516  if (list)
517  list = g_list_reverse (g_list_copy (list));
518 
519  for (node = list; node; node = node->next)
520  {
521  GncTaxTable *table = node->data;
522 
523  gnc_gui_component_watch_entity (ttw->component_id,
525  QOF_EVENT_MODIFY);
526 
527  gtk_list_store_prepend (store, &iter);
528  gtk_list_store_set (store, &iter,
529  TAX_TABLE_COL_NAME, gncTaxTableGetName (table),
530  TAX_TABLE_COL_POINTER, table,
531  -1);
532 
533  if (table == saved_current_table)
534  {
535  path = gtk_tree_model_get_path (GTK_TREE_MODEL(store), &iter);
536  reference = gtk_tree_row_reference_new (GTK_TREE_MODEL(store), path);
537  gtk_tree_path_free (path);
538  }
539  }
540 
541  if (list)
542  g_list_free (list);
543 
544  gnc_gui_component_watch_entity_type (ttw->component_id,
545  GNC_TAXTABLE_MODULE_NAME,
546  QOF_EVENT_CREATE | QOF_EVENT_DESTROY);
547 
548  if (reference)
549  {
550  path = gtk_tree_row_reference_get_path (reference);
551  gtk_tree_row_reference_free (reference);
552  if (path)
553  {
554  selection = gtk_tree_view_get_selection (view);
555  gtk_tree_selection_select_path (selection, path);
556  gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
557  gtk_tree_path_free (path);
558  }
559  }
560 
561  tax_table_entries_refresh (ttw);
562  /* select_row() above will refresh the entries window */
563 }
564 
565 static void
566 tax_table_selection_changed (GtkTreeSelection *selection,
567  gpointer user_data)
568 {
569  TaxTableWindow *ttw = user_data;
571  GtkTreeModel *model;
572  GtkTreeIter iter;
573 
574  g_return_if_fail (ttw);
575 
576  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
577  return;
578 
579  gtk_tree_model_get (model, &iter, TAX_TABLE_COL_POINTER, &table, -1);
580  g_return_if_fail (table);
581 
582  /* If we've changed, then reset the entry list */
583  if (table != ttw->current_table)
584  {
585  ttw->current_table = table;
586  ttw->current_entry = NULL;
587  }
588  /* And force a refresh of the entries */
589  tax_table_entries_refresh (ttw);
590 }
591 
592 static void
593 tax_table_entry_selection_changed (GtkTreeSelection *selection,
594  gpointer user_data)
595 {
596  TaxTableWindow *ttw = user_data;
597  GtkTreeModel *model;
598  GtkTreeIter iter;
599 
600  g_return_if_fail (ttw);
601 
602  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
603  {
604  ttw->current_entry = NULL;
605  return;
606  }
607 
608  gtk_tree_model_get (model, &iter, TAX_ENTRY_COL_POINTER, &ttw->current_entry, -1);
609 }
610 
611 static void
612 tax_table_entry_row_activated (GtkTreeView *tree_view,
613  GtkTreePath *path,
614  GtkTreeViewColumn *column,
615  gpointer user_data)
616 {
617  TaxTableWindow *ttw = user_data;
618 
619  new_tax_table_dialog (ttw, FALSE, ttw->current_entry, NULL);
620 }
621 
622 void
623 tax_table_new_table_cb (GtkButton *button, TaxTableWindow *ttw)
624 {
625  g_return_if_fail (ttw);
626  new_tax_table_dialog (ttw, TRUE, NULL, NULL);
627 }
628 
629 
630 static const char
631 *rename_tax_table_dialog (GtkWidget *parent,
632  const char *title,
633  const char *msg,
634  const char *button_name,
635  const char *text)
636 {
637  GtkWidget *vbox;
638  GtkWidget *main_vbox;
639  GtkWidget *label;
640  GtkWidget *textbox;
641  GtkWidget *dialog;
642  GtkWidget *dvbox;
643 
644  main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
645  gtk_box_set_homogeneous (GTK_BOX(main_vbox), FALSE);
646  gtk_container_set_border_width (GTK_CONTAINER(main_vbox), 6);
647  gtk_widget_show (main_vbox);
648 
649  label = gtk_label_new (msg);
650  gtk_label_set_justify (GTK_LABEL(label), GTK_JUSTIFY_LEFT);
651  gtk_box_pack_start (GTK_BOX(main_vbox), label, FALSE, FALSE, 0);
652  gtk_widget_show (label);
653 
654  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
655  gtk_box_set_homogeneous (GTK_BOX(vbox), TRUE);
656  gtk_container_set_border_width (GTK_CONTAINER(vbox), 6);
657  gtk_container_add (GTK_CONTAINER(main_vbox), vbox);
658  gtk_widget_show (vbox);
659 
660  textbox = gtk_entry_new ();
661  gtk_widget_show (textbox);
662  gtk_entry_set_text (GTK_ENTRY(textbox), text);
663  gtk_box_pack_start (GTK_BOX(vbox), textbox, FALSE, FALSE, 0);
664 
665  dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW(parent),
666  GTK_DIALOG_DESTROY_WITH_PARENT,
667  _("_Cancel"), GTK_RESPONSE_CANCEL,
668  button_name, GTK_RESPONSE_OK,
669  NULL);
670  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
671 
672  dvbox = gtk_dialog_get_content_area (GTK_DIALOG(dialog));
673  gtk_box_pack_start (GTK_BOX(dvbox), main_vbox, TRUE, TRUE, 0);
674 
675  if (gtk_dialog_run (GTK_DIALOG(dialog)) != GTK_RESPONSE_OK)
676  {
677  gtk_widget_destroy (dialog);
678  return NULL;
679  }
680 
681  text = g_strdup (gtk_entry_get_text (GTK_ENTRY(textbox)));
682  gtk_widget_destroy (dialog);
683  return text;
684 }
685 
686 void
687 tax_table_rename_table_cb (GtkButton *button, TaxTableWindow *ttw)
688 {
689  const char *oldname;
690  const char *newname;
691  g_return_if_fail (ttw);
692 
693  if (!ttw->current_table)
694  return;
695 
696  oldname = gncTaxTableGetName (ttw->current_table);
697  newname = rename_tax_table_dialog (ttw->dialog, (_("Rename")),
698  (_("Please enter new name")),
699  (_("_Rename")), oldname);
700 
701  if (newname && *newname != '\0' && (g_strcmp0 (oldname, newname) != 0))
702  {
703  if (gncTaxTableLookupByName (ttw->book, newname))
704  {
705  char *message = g_strdup_printf (_("Tax table name \"%s\" already exists."),
706  newname);
707  gnc_error_dialog (GTK_WINDOW(ttw->dialog), "%s", message);
708  g_free (message);
709  }
710  else
711  {
712  gncTaxTableSetName (ttw->current_table, newname);
713  }
714  }
715 }
716 
717 
718 void
719 tax_table_delete_table_cb (GtkButton *button, TaxTableWindow *ttw)
720 {
721  g_return_if_fail (ttw);
722 
723  if (!ttw->current_table)
724  return;
725 
726  if (gncTaxTableGetRefcount (ttw->current_table) > 0)
727  {
728  char *message =
729  g_strdup_printf (_("Tax table \"%s\" is in use. You cannot delete it."),
730  gncTaxTableGetName (ttw->current_table));
731  gnc_error_dialog (GTK_WINDOW(ttw->dialog), "%s", message);
732  g_free (message);
733  return;
734  }
735 
736  if (gnc_verify_dialog (GTK_WINDOW(ttw->dialog), FALSE,
737  _("Are you sure you want to delete \"%s\"?"),
738  gncTaxTableGetName (ttw->current_table)))
739  {
740  /* Ok, let's remove it */
741  gnc_suspend_gui_refresh ();
742  gncTaxTableBeginEdit (ttw->current_table);
743  gncTaxTableDestroy (ttw->current_table);
744  ttw->current_table = NULL;
745  ttw->current_entry = NULL;
746  gnc_resume_gui_refresh ();
747  }
748 }
749 
750 void
751 tax_table_new_entry_cb (GtkButton *button, TaxTableWindow *ttw)
752 {
753  g_return_if_fail (ttw);
754  if (!ttw->current_table)
755  return;
756  new_tax_table_dialog (ttw, FALSE, NULL, NULL);
757 }
758 
759 void
760 tax_table_edit_entry_cb (GtkButton *button, TaxTableWindow *ttw)
761 {
762  g_return_if_fail (ttw);
763  if (!ttw->current_entry)
764  return;
765  new_tax_table_dialog (ttw, FALSE, ttw->current_entry, NULL);
766 }
767 
768 void
769 tax_table_delete_entry_cb (GtkButton *button, TaxTableWindow *ttw)
770 {
771  g_return_if_fail (ttw);
772  if (!ttw->current_table || !ttw->current_entry)
773  return;
774 
775  if (g_list_length (gncTaxTableGetEntries (ttw->current_table)) <= 1)
776  {
777  char *message = _("You cannot remove the last entry from the tax table. "
778  "Try deleting the tax table if you want to do that.");
779  gnc_error_dialog (GTK_WINDOW(ttw->dialog) , "%s", message);
780  return;
781  }
782 
783  if (gnc_verify_dialog (GTK_WINDOW(ttw->dialog), FALSE, "%s",
784  _("Are you sure you want to delete this entry?")))
785  {
786  /* Ok, let's remove it */
787  gnc_suspend_gui_refresh ();
788  gncTaxTableBeginEdit (ttw->current_table);
789  gncTaxTableRemoveEntry (ttw->current_table, ttw->current_entry);
790  gncTaxTableEntryDestroy (ttw->current_entry);
791  gncTaxTableChanged (ttw->current_table);
792  gncTaxTableCommitEdit (ttw->current_table);
793  ttw->current_entry = NULL;
794  gnc_resume_gui_refresh ();
795  }
796 }
797 
798 static void
799 tax_table_window_refresh_handler (GHashTable *changes, gpointer data)
800 {
801  TaxTableWindow *ttw = data;
802 
803  g_return_if_fail (data);
804  tax_table_window_refresh (ttw);
805 }
806 
807 static void
808 tax_table_window_close_handler (gpointer data)
809 {
810  TaxTableWindow *ttw = data;
811  g_return_if_fail (ttw);
812 
813  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(ttw->dialog));
814  gtk_widget_destroy (ttw->dialog);
815 }
816 
817 void
818 tax_table_window_close (GtkWidget *widget, gpointer data)
819 {
820  TaxTableWindow *ttw = data;
821  gnc_close_gui_component (ttw->component_id);
822 }
823 
824 static gboolean
825 tax_table_window_delete_event_cb (GtkWidget *widget,
826  GdkEvent *event,
827  gpointer user_data)
828 {
829  TaxTableWindow *ttw = user_data;
830  // this cb allows the window size to be saved on closing with the X
831  gnc_save_window_size (GNC_PREFS_GROUP,
832  GTK_WINDOW(ttw->dialog));
833  return FALSE;
834 }
835 
836 void
837 tax_table_window_destroy_cb (GtkWidget *widget, gpointer data)
838 {
839  TaxTableWindow *ttw = data;
840 
841  if (!ttw) return;
842 
843  gnc_unregister_gui_component (ttw->component_id);
844 
845  if (ttw->dialog)
846  {
847  gtk_widget_destroy (ttw->dialog);
848  ttw->dialog = NULL;
849  }
850  g_free (ttw);
851 }
852 
853 static gboolean
854 tax_table_window_key_press_cb (GtkWidget *widget, GdkEventKey *event,
855  gpointer data)
856 {
857  TaxTableWindow *ttw = data;
858 
859  if (event->keyval == GDK_KEY_Escape)
860  {
861  tax_table_window_close_handler (ttw);
862  return TRUE;
863  }
864  else
865  return FALSE;
866 }
867 
868 static gboolean
869 find_handler (gpointer find_data, gpointer data)
870 {
871  TaxTableWindow *ttw = data;
872  QofBook *book = find_data;
873 
874  return (ttw != NULL && ttw->book == book);
875 }
876 
877 /* Create a tax-table window */
878 TaxTableWindow *
879 gnc_ui_tax_table_window_new (GtkWindow *parent, QofBook *book)
880 {
881  TaxTableWindow *ttw;
882  GtkBuilder *builder;
883  GtkTreeView *view;
884  GtkTreeViewColumn *column;
885  GtkCellRenderer *renderer;
886  GtkListStore *store;
887  GtkTreeSelection *selection;
888 
889  if (!book) return NULL;
890 
891  /*
892  * Find an existing tax-table window. If found, bring it to
893  * the front. If we have an actual owner, then set it in
894  * the window.
895  */
896  ttw = gnc_find_first_gui_component (DIALOG_TAX_TABLE_CM_CLASS, find_handler,
897  book);
898  if (ttw)
899  {
900  gtk_window_present (GTK_WINDOW(ttw->dialog));
901  return ttw;
902  }
903 
904  /* Didn't find one -- create a new window */
905  ttw = g_new0 (TaxTableWindow, 1);
906  ttw->book = book;
907  ttw->session = gnc_get_current_session ();
908 
909  /* Open and read the Glade File */
910  builder = gtk_builder_new ();
911  gnc_builder_add_from_file (builder, "dialog-tax-table.glade", "tax_table_window");
912  ttw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "tax_table_window"));
913  ttw->names_view = GTK_WIDGET(gtk_builder_get_object (builder, "tax_tables_view"));
914  ttw->entries_view = GTK_WIDGET(gtk_builder_get_object (builder, "tax_table_entries"));
915 
916  // Set the name for this dialog so it can be easily manipulated with css
917  gtk_widget_set_name (GTK_WIDGET(ttw->dialog), "gnc-id-new-tax-table");
918  gnc_widget_style_context_add_class (GTK_WIDGET(ttw->dialog), "gnc-class-taxes");
919 
920  g_signal_connect (ttw->dialog, "delete-event",
921  G_CALLBACK(tax_table_window_delete_event_cb), ttw);
922 
923  g_signal_connect (ttw->dialog, "key_press_event",
924  G_CALLBACK (tax_table_window_key_press_cb), ttw);
925 
926  /* Create the tax tables view */
927  view = GTK_TREE_VIEW(ttw->names_view);
928  store = gtk_list_store_new (NUM_TAX_TABLE_COLS, G_TYPE_STRING,
929  G_TYPE_POINTER);
930  gtk_tree_view_set_model (view, GTK_TREE_MODEL(store));
931  g_object_unref (store);
932 
933  /* default sort order */
934  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(store),
935  TAX_TABLE_COL_NAME,
936  GTK_SORT_ASCENDING);
937 
938  renderer = gtk_cell_renderer_text_new ();
939  column = gtk_tree_view_column_new_with_attributes ("", renderer,
940  "text", TAX_TABLE_COL_NAME,
941  NULL);
942  g_object_set (G_OBJECT(column), "reorderable", TRUE, NULL);
943  gtk_tree_view_append_column (view, column);
944  gtk_tree_view_column_set_sort_column_id (column, TAX_TABLE_COL_NAME);
945 
946  selection = gtk_tree_view_get_selection (view);
947  g_signal_connect (selection, "changed",
948  G_CALLBACK(tax_table_selection_changed), ttw);
949 
950  /* Create the tax table entries view */
951  view = GTK_TREE_VIEW(ttw->entries_view);
952  store = gtk_list_store_new (NUM_TAX_ENTRY_COLS, G_TYPE_STRING,
953  G_TYPE_POINTER, G_TYPE_STRING);
954  gtk_tree_view_set_model (view, GTK_TREE_MODEL(store));
955  g_object_unref (store);
956 
957  /* default sort order */
958  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(store),
959  TAX_ENTRY_COL_NAME,
960  GTK_SORT_ASCENDING);
961 
962  renderer = gtk_cell_renderer_text_new ();
963  column = gtk_tree_view_column_new_with_attributes ("", renderer,
964  "text", TAX_ENTRY_COL_NAME,
965  NULL);
966  g_object_set (G_OBJECT(column), "reorderable", TRUE, NULL);
967  gtk_tree_view_append_column (view, column);
968  gtk_tree_view_column_set_sort_column_id (column, TAX_ENTRY_COL_NAME);
969 
970  selection = gtk_tree_view_get_selection (view);
971  g_signal_connect (selection, "changed",
972  G_CALLBACK(tax_table_entry_selection_changed), ttw);
973  g_signal_connect (view, "row-activated",
974  G_CALLBACK(tax_table_entry_row_activated), ttw);
975 
976  /* Setup signals */
977  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, ttw);
978 
979  /* register with component manager */
980  ttw->component_id =
981  gnc_register_gui_component (DIALOG_TAX_TABLE_CM_CLASS,
982  tax_table_window_refresh_handler,
983  tax_table_window_close_handler,
984  ttw);
985 
986  gnc_gui_component_set_session (ttw->component_id, ttw->session);
987 
988  tax_table_window_refresh (ttw);
989  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(ttw->dialog), parent);
990  gtk_widget_show_all (ttw->dialog);
991 
992  g_object_unref (G_OBJECT(builder));
993 
994  return ttw;
995 }
996 
997 /* Create a new tax-table by name */
998 GncTaxTable *
999 gnc_ui_tax_table_new_from_name (GtkWindow *parent, QofBook *book, const char *name)
1000 {
1001  TaxTableWindow *ttw;
1002 
1003  if (!book) return NULL;
1004 
1005  ttw = gnc_ui_tax_table_window_new (parent, book);
1006  if (!ttw) return NULL;
1007 
1008  return new_tax_table_dialog (ttw, TRUE, NULL, name);
1009 }
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
utility functions for the GnuCash UI
gtk helper routines.
STRUCTS.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
tax is a number
Definition: gncTaxTable.h:80
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3275
#define gncTaxTableGetGUID(x)
Definition: gncTaxTable.h:214
GtkTreeView implementation for gnucash account tree.
GtkTreeView * gnc_tree_view_account_new(gboolean show_root)
Create a new account tree view.
Tax Table programming interface.
tax is a percentage
Definition: gncTaxTable.h:81
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
void gnc_tree_view_account_set_selected_account(GncTreeViewAccount *view, Account *account)
This function selects an account in the account tree view.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3371
Account * gnc_tree_view_account_get_selected_account(GncTreeViewAccount *view)
This function returns the account associated with the selected item in the account tree view...
modtime is the internal date of the last modtime See libgnucash/engine/TaxTableBillTermImmutability.txt for an explanation of the following Code that handles refcount, parent, child, invisible and children is identical to that in ::GncBillTerm