GnuCash  5.6-150-g038405b370+
dialog-account.c
1 /********************************************************************\
2  * dialog-account.c -- window for creating and editing accounts for *
3  * GnuCash *
4  * Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
5  * Copyright (C) 2003,2005,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 #include <math.h>
30 #ifdef G_OS_WIN32
31 #include <pow.h>
32 #endif
33 #include <string.h>
34 
35 #include "Transaction.h"
36 #include "dialog-account.h"
37 #include "dialog-commodity.h"
38 #include "dialog-utils.h"
39 #include "gnc-amount-edit.h"
40 #include "gnc-general-select.h"
41 #include "gnc-commodity.h"
42 #include "gnc-commodity-edit.h"
43 #include "gnc-component-manager.h"
44 #include "gnc-date-edit.h"
45 #include "gnc-engine.h"
46 #include "gnc-gui-query.h"
47 #include "gnc-session.h"
49 #include "gnc-tree-view-account.h"
50 #include "gnc-ui.h"
51 #include "gnc-ui-util.h"
52 #include <gnc-locale-tax.h>
53 
54 #define DIALOG_NEW_ACCOUNT_CM_CLASS "dialog-new-account"
55 #define DIALOG_EDIT_ACCOUNT_CM_CLASS "dialog-edit-account"
56 #define GNC_PREFS_GROUP "dialogs.account"
57 #define DEFAULT_COLOR "rgb(237,236,235)"
58 
59 enum account_cols
60 {
61  ACCOUNT_COL_FULLNAME = 0,
62  ACCOUNT_COL_FIELDNAME,
63  ACCOUNT_COL_OLD_VALUE,
64  ACCOUNT_COL_NEW_VALUE,
65  NUM_ACCOUNT_COLS
66 };
67 
68 typedef enum
69 {
70  NEW_ACCOUNT,
71  EDIT_ACCOUNT
72 } AccountDialogType;
73 
74 typedef struct _AccountWindow
75 {
76  QofBook *book;
77  gboolean modal;
78  GtkWidget *dialog;
79 
80  AccountDialogType dialog_type;
81 
82  GncGUID account;
83  Account *created_account;
84 
85  gchar **subaccount_names;
86  gchar **next_name;
87 
88  GNCAccountType type;
89 
90  GtkWidget *notebook;
91 
92  GtkWidget *name_entry;
93  GtkWidget *description_entry;
94  GtkWidget *color_entry_button;
95  GtkWidget *color_default_button;
96  GtkWidget *code_entry;
97  GtkTextBuffer *notes_text_buffer;
98 
99  GtkWidget *commodity_edit;
100  dialog_commodity_mode commodity_mode;
101  GtkWidget *account_scu;
102 
103  guint32 valid_types;
104  GNCAccountType preferred_account_type;
105  GtkWidget *type_combo;
106  GtkTreeView *parent_tree;
107  GtkWidget *parent_scroll;
108 
109  GtkWidget *more_properties_page;
110 
111  GtkWidget *balance_grid;
112  GtkWidget *higher_balance_limit_edit;
113  GtkWidget *lower_balance_limit_edit;
114  GtkWidget *include_balance_sub_accts;
115  gboolean balance_is_reversed;
116 
117  GtkWidget *opening_balance_button;
118  GtkWidget *opening_balance_edit;
119  GtkWidget *opening_balance_date_edit;
120  GtkWidget *opening_balance_page;
121 
122  GtkWidget *opening_equity_radio;
123  GtkWidget *transfer_account_scroll;
124  GtkWidget *transfer_tree;
125 
126  GtkWidget *tax_related_button;
127  GtkWidget *placeholder_button;
128  GtkWidget *hidden_button;
129  GtkWidget *auto_interest_button;
130 
131  gint component_id;
132 
133  GObject *selection;
134  gulong handler_id;
135 } AccountWindow;
136 
137 typedef struct _RenumberDialog
138 {
139  GtkWidget *dialog;
140  GtkWidget *prefix;
141  GtkWidget *interval;
142  GtkWidget *digits;
143  GtkWidget *example1;
144  GtkWidget *example2;
145 
146  Account *parent;
147  gint num_children;
149 
151 static QofLogModule log_module = GNC_MOD_GUI;
152 
153 static GNCAccountType last_used_account_type = ACCT_TYPE_BANK;
154 
155 static GList *ac_destroy_cb_list = NULL;
156 
158 static void gnc_account_window_set_name (AccountWindow *aw);
159 
160 void gnc_account_renumber_prefix_changed_cb (GtkEditable *editable, RenumberDialog *data);
161 void gnc_account_renumber_interval_changed_cb (GtkSpinButton *spinbutton, RenumberDialog *data);
162 void gnc_account_renumber_digits_changed_cb (GtkSpinButton *spinbutton, RenumberDialog *data);
163 void gnc_account_renumber_response_cb (GtkDialog *dialog, gint response, RenumberDialog *data);
164 
165 void gnc_account_window_destroy_cb (GtkWidget *object, gpointer data);
166 void opening_equity_cb (GtkWidget *w, gpointer data);
167 static void gnc_account_parent_changed_cb (GObject *selection, gpointer data);
168 void gnc_account_name_changed_cb (GtkWidget *widget, gpointer data);
169 void gnc_account_color_default_cb (GtkWidget *widget, gpointer data);
170 void gnc_account_name_insert_text_cb (GtkWidget *entry,
171  const gchar *text,
172  gint length,
173  gint *position,
174  gpointer data);
175 static void set_auto_interest_box (AccountWindow *aw);
176 static gboolean account_commodity_filter (GtkTreeSelection* selection,
177  GtkTreeModel* unused_model,
178  GtkTreePath* s_path,
179  gboolean path_currently_selected,
180  gpointer user_data);
181 
184 static void
185 aw_call_destroy_callbacks (Account* acc)
186 {
187  GList *node;
188  void (*cb)(Account*);
189 
190  for (node = ac_destroy_cb_list; node; node = node->next)
191  {
192  cb = node->data;
193  (cb)(acc);
194  }
195 }
196 
197 static Account *
198 aw_get_account (AccountWindow *aw)
199 {
200  if (!aw)
201  return NULL;
202 
203  return xaccAccountLookup (&aw->account, aw->book);
204 }
205 
206 static void
207 aw_clear_selection_handler (AccountWindow *aw)
208 {
209  if (aw->selection && aw->handler_id)
210  g_signal_handler_disconnect (aw->selection, aw->handler_id);
211  aw->selection = NULL;
212  aw->handler_id = 0;
213 }
214 
215 static void
216 aw_connect_selection_changed (AccountWindow *aw)
217 {
218  aw_clear_selection_handler (aw);
219  aw->selection = G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW(aw->parent_tree)));
220  aw->handler_id = g_signal_connect (G_OBJECT(aw->selection), "changed",
221  G_CALLBACK(gnc_account_parent_changed_cb),
222  aw);
223 }
224 
225 static void
226 gnc_account_commodity_from_type (AccountWindow * aw, gboolean update)
227 {
228  dialog_commodity_mode new_mode;
229 
230  if (aw->type == ACCT_TYPE_TRADING)
231  new_mode = DIAG_COMM_ALL;
232  else if ((aw->type == ACCT_TYPE_STOCK) || (aw->type == ACCT_TYPE_MUTUAL))
234  else
235  new_mode = DIAG_COMM_CURRENCY;
236 
237  if (update && (new_mode != aw->commodity_mode))
238  {
239  gnc_general_select_set_selected (GNC_GENERAL_SELECT(aw->commodity_edit),
240  NULL);
241  }
242  aw->commodity_mode = new_mode;
243 }
244 
245 static void
246 gnc_account_opening_balance_button_update (AccountWindow *aw, gnc_commodity *commodity)
247 {
248  Account *account = aw_get_account (aw);
249  Account *ob_account = gnc_account_lookup_by_opening_balance (gnc_book_get_root_account (aw->book), commodity);
250  gboolean has_splits = (xaccAccountGetSplitsSize (account) != 0);
251 
252  if (aw->type != ACCT_TYPE_EQUITY)
253  {
254  gtk_widget_set_sensitive (aw->opening_balance_button, FALSE);
255  return;
256  }
257 
258  /* The opening balance flag can be edited, if the associated feature is enabled and
259  * there is no opening balance account or we are editing the only opening balance account
260  * and it has no splits assigned.
261  */
262  if (!gnc_using_equity_type_opening_balance_account (gnc_get_current_book()))
263  return;
264 
265  switch (aw->dialog_type)
266  {
267  case EDIT_ACCOUNT:
268  gtk_widget_set_sensitive (aw->opening_balance_button, (ob_account == NULL ||
269  ob_account == account) &&
270  has_splits == 0);
271  break;
272  case NEW_ACCOUNT:
273  gtk_widget_set_sensitive (aw->opening_balance_button, ob_account == NULL);
274  break;
275  }
276 }
277 
278 /* Copy the account values to the GUI widgets */
279 static void
280 gnc_account_to_ui (AccountWindow *aw)
281 {
282  Account *account;
283  gnc_commodity * commodity;
284  const char *string;
285  GdkRGBA color;
286  gboolean flag, nonstd_scu;
287  gint index;
288  gnc_numeric balance_limit;
289  gboolean balance_limit_valid;
290 
291  ENTER("%p", aw);
292  account = aw_get_account (aw);
293  if (!account)
294  {
295  LEAVE("no account");
296  return;
297  }
298 
299  string = xaccAccountGetName (account);
300  if (string == NULL)
301  string = "";
302  gtk_entry_set_text (GTK_ENTRY(aw->name_entry), string);
303 
304  string = xaccAccountGetDescription (account);
305  if (string == NULL)
306  string = "";
307  gtk_entry_set_text (GTK_ENTRY(aw->description_entry), string);
308 
309  string = xaccAccountGetColor (account);
310 
311  if (!string)
312  string = DEFAULT_COLOR;
313 
314  if (!gdk_rgba_parse (&color, string))
315  gdk_rgba_parse (&color, DEFAULT_COLOR);
316 
317  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(aw->color_entry_button), &color);
318 
319  commodity = xaccAccountGetCommodity (account);
320  gnc_general_select_set_selected (GNC_GENERAL_SELECT(aw->commodity_edit),
321  commodity);
322  gnc_account_commodity_from_type (aw, FALSE);
323 
324  nonstd_scu = xaccAccountGetNonStdSCU (account);
325  if (nonstd_scu)
326  {
327  index = xaccAccountGetCommoditySCUi (account);
328  index = log10 (index) + 1;
329  }
330  else
331  {
332  index = 0;
333  }
334  gtk_combo_box_set_active (GTK_COMBO_BOX(aw->account_scu), index);
335 
336  string = xaccAccountGetCode (account);
337  if (string == NULL)
338  string = "";
339  gtk_entry_set_text (GTK_ENTRY(aw->code_entry), string);
340 
341  string = xaccAccountGetNotes (account);
342  if (string == NULL)
343  string = "";
344 
345  gtk_text_buffer_set_text (aw->notes_text_buffer, string, strlen(string));
346 
347  gnc_account_opening_balance_button_update (aw, commodity);
348 
349  flag = xaccAccountGetIsOpeningBalance (account);
350  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(aw->opening_balance_button),
351  flag);
352 
353  flag = xaccAccountGetTaxRelated (account);
354  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(aw->tax_related_button),
355  flag);
356 
357  flag = xaccAccountGetPlaceholder (account);
358  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(aw->placeholder_button),
359  flag);
360 
361  flag = xaccAccountGetHidden (account);
362  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(aw->hidden_button),
363  flag);
364 
365  aw->balance_is_reversed = gnc_reverse_balance (account);
366 
368 
369  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(aw->include_balance_sub_accts),
370  flag);
371 
372  balance_limit_valid = xaccAccountGetHigherBalanceLimit (account, &balance_limit);
373  if (balance_limit_valid)
374  {
375  if (aw->balance_is_reversed)
376  {
377  balance_limit = gnc_numeric_neg (balance_limit);
378  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit),
379  balance_limit);
380  }
381  else
382  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit),
383  balance_limit);
384  }
385 
386  balance_limit_valid = xaccAccountGetLowerBalanceLimit (account, &balance_limit);
387  if (balance_limit_valid)
388  {
389  if (aw->balance_is_reversed)
390  {
391  balance_limit = gnc_numeric_neg (balance_limit);
392  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit),
393  balance_limit);
394  }
395  else
396  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit),
397  balance_limit);
398  }
399 
400  set_auto_interest_box (aw);
401  LEAVE(" ");
402 }
403 
404 static gboolean
405 gnc_account_create_transfer_balance (QofBook *book,
406  Account *account,
407  Account *transfer,
408  gnc_numeric balance,
409  time64 date)
410 {
411  Transaction *trans;
412  Split *split;
413 
414  if (gnc_numeric_zero_p (balance))
415  return TRUE;
416 
417  g_return_val_if_fail (account != NULL, FALSE);
418  g_return_val_if_fail (transfer != NULL, FALSE);
419 
420  xaccAccountBeginEdit (account);
421  xaccAccountBeginEdit (transfer);
422 
423  trans = xaccMallocTransaction (book);
424 
425  xaccTransBeginEdit (trans);
426 
427  xaccTransSetCurrency (trans, gnc_account_or_default_currency (account, NULL));
429  xaccTransSetDescription (trans, _("Opening Balance"));
430 
431  split = xaccMallocSplit (book);
432 
433  xaccTransAppendSplit (trans, split);
434  xaccAccountInsertSplit (account, split);
435 
436  xaccSplitSetAmount (split, balance);
437  xaccSplitSetValue (split, balance);
438 
439  balance = gnc_numeric_neg (balance);
440 
441  split = xaccMallocSplit (book);
442 
443  xaccTransAppendSplit (trans, split);
444  xaccAccountInsertSplit (transfer, split);
445 
446  xaccSplitSetAmount (split, balance);
447  xaccSplitSetValue (split, balance);
448 
449  xaccTransCommitEdit (trans);
450  xaccAccountCommitEdit (transfer);
451  xaccAccountCommitEdit (account);
452 
453  return TRUE;
454 }
455 
456 /* Record the GUI values into the Account structure */
457 static void
458 gnc_ui_to_account (AccountWindow *aw)
459 {
460  Account *account;
461  gnc_commodity *commodity;
462  Account *parent_account;
463  const char *old_string;
464  const char *string;
465  GdkRGBA color;
466  gboolean flag;
467  gnc_numeric balance;
468  gnc_numeric balance_limit;
469  gint higher_balance_limit_valid;
470  gint lower_balance_limit_valid;
471  gboolean use_equity, nonstd;
472  time64 date;
473  gint index, old_scu, new_scu;
474  GtkTextIter start, end;
475 
476  account = aw_get_account (aw);
477  if (!account)
478  {
479  LEAVE("no account");
480  return;
481  }
482 
483  if (aw->dialog_type == EDIT_ACCOUNT
484  && aw->type != xaccAccountGetType (account))
485  {
486  /* Just refreshing won't work. */
487  aw_call_destroy_callbacks (account);
488  }
489 
490  xaccAccountBeginEdit (account);
491 
492  if (aw->type != xaccAccountGetType (account))
493  xaccAccountSetType (account, aw->type);
494 
495  last_used_account_type = aw->type;
496 
497  string = gtk_entry_get_text (GTK_ENTRY(aw->name_entry));
498  old_string = xaccAccountGetName (account);
499  if (g_strcmp0 (string, old_string) != 0)
500  xaccAccountSetName (account, string);
501 
502  string = gtk_entry_get_text (GTK_ENTRY(aw->description_entry));
503  old_string = xaccAccountGetDescription (account);
504  if (g_strcmp0 (string, old_string) != 0)
505  xaccAccountSetDescription (account, string);
506 
507  gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(aw->color_entry_button), &color);
508  char* new_string = gdk_rgba_to_string (&color);
509 
510  old_string = xaccAccountGetColor (account);
511 
512  if (!g_strcmp0 (new_string, DEFAULT_COLOR) && old_string)
513  xaccAccountSetColor (account, ""); // remove entry
514  else
515  {
516  if (g_strcmp0 (new_string, old_string) != 0)
517  xaccAccountSetColor (account, new_string); // update entry
518  }
519  g_free (new_string);
520 
521  commodity = (gnc_commodity *)
522  gnc_general_select_get_selected (GNC_GENERAL_SELECT(aw->commodity_edit));
523  if (commodity &&
524  !gnc_commodity_equiv (commodity, xaccAccountGetCommodity (account)))
525  {
526  xaccAccountSetCommodity (account, commodity);
527  old_scu = 0;
528  }
529  else
530  {
531  old_scu = xaccAccountGetCommoditySCU (account);
532  }
533 
534  index = gtk_combo_box_get_active (GTK_COMBO_BOX(aw->account_scu));
535  nonstd = (index != 0);
536  if (nonstd != xaccAccountGetNonStdSCU (account))
537  xaccAccountSetNonStdSCU (account, nonstd);
538  new_scu = (nonstd ? pow (10, index - 1) : gnc_commodity_get_fraction (commodity));
539  if (old_scu != new_scu)
540  xaccAccountSetCommoditySCU (account, new_scu);
541 
542  string = gtk_entry_get_text (GTK_ENTRY(aw->code_entry));
543  old_string = xaccAccountGetCode (account);
544  if (g_strcmp0 (string, old_string) != 0)
545  xaccAccountSetCode (account, string);
546 
547  gtk_text_buffer_get_start_iter (aw->notes_text_buffer, &start);
548  gtk_text_buffer_get_end_iter (aw->notes_text_buffer, &end);
549  new_string = gtk_text_buffer_get_text (aw->notes_text_buffer, &start, &end,
550  FALSE);
551  old_string = xaccAccountGetNotes (account);
552  if (g_strcmp0 (new_string, old_string))
553  xaccAccountSetNotes (account, new_string);
554  g_free (new_string);
555 
556  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->opening_balance_button));
557  if (xaccAccountGetIsOpeningBalance (account) != flag)
558  xaccAccountSetIsOpeningBalance (account, flag);
559 
560  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->tax_related_button));
561  if (xaccAccountGetTaxRelated (account) != flag)
562  xaccAccountSetTaxRelated (account, flag);
563 
564  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->placeholder_button));
565  if (xaccAccountGetPlaceholder (account) != flag)
566  xaccAccountSetPlaceholder (account, flag);
567 
568  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->hidden_button));
569  if (xaccAccountGetHidden (account) != flag)
570  xaccAccountSetHidden (account, flag);
571 
572  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->auto_interest_button));
573  if (xaccAccountGetAutoInterest (account) != flag)
574  xaccAccountSetAutoInterest (account, flag);
575 
576  parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
577 
578  if (parent_account == NULL)
579  parent_account = gnc_book_get_root_account (aw->book);
580  if (parent_account != gnc_account_get_parent (account))
581  gnc_account_append_child (parent_account, account);
582 
583  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(
584  aw->include_balance_sub_accts));
585 
587 
588  higher_balance_limit_valid = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(
589  aw->higher_balance_limit_edit),
590  &balance_limit, TRUE, NULL);
591 
592  if (higher_balance_limit_valid == 0)
593  {
594  if (aw->balance_is_reversed)
595  {
596  balance_limit = gnc_numeric_neg (balance_limit);
597  xaccAccountSetLowerBalanceLimit (account, balance_limit);
598  }
599  else
600  xaccAccountSetHigherBalanceLimit (account, balance_limit);
601  }
602 
603  if (higher_balance_limit_valid == -1)
604  {
605  if (aw->balance_is_reversed)
607  else
609  }
610 
611  lower_balance_limit_valid = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(
612  aw->lower_balance_limit_edit),
613  &balance_limit, TRUE, NULL);
614 
615  if (lower_balance_limit_valid == 0)
616  {
617  if (aw->balance_is_reversed)
618  {
619  balance_limit = gnc_numeric_neg (balance_limit);
620  xaccAccountSetHigherBalanceLimit (account, balance_limit);
621  }
622  else
623  xaccAccountSetLowerBalanceLimit (account, balance_limit);
624  }
625 
626  if (lower_balance_limit_valid == -1)
627  {
628  if (aw->balance_is_reversed)
630  else
632  }
633 
634  if ((higher_balance_limit_valid == -1) && (lower_balance_limit_valid == -1))
636 
637  xaccAccountCommitEdit (account);
638 
639  balance = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT(aw->opening_balance_edit));
640 
641  if (gnc_numeric_zero_p (balance))
642  {
643  LEAVE("zero balance");
644  return;
645  }
646 
647  if (gnc_reverse_balance (account))
648  balance = gnc_numeric_neg (balance);
649 
650  date = gnc_date_edit_get_date (GNC_DATE_EDIT(aw->opening_balance_date_edit));
651 
652  use_equity = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->opening_equity_radio));
653 
654  if (use_equity)
655  {
656  if (!gnc_account_create_opening_balance (account, balance, date, aw->book))
657  {
658  const char *message = _("Could not create opening balance.");
659  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
660  }
661  }
662  else
663  {
664  Account *transfer = NULL;
665 
666  transfer = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->transfer_tree));
667  if (!transfer)
668  {
669  LEAVE("no transfer account");
670  return;
671  }
672 
673  gnc_account_create_transfer_balance (aw->book, account, transfer, balance, date);
674  }
675  LEAVE(" ");
676 }
677 
678 static void
679 set_children_types (Account *account, GNCAccountType type)
680 {
681  GList *children, *iter;
682 
683  children = gnc_account_get_children (account);
684  if (children == NULL)
685  return;
686 
687  for (iter = children; iter; iter = iter->next)
688  {
689  account = iter->data;
690  if (type == xaccAccountGetType (account))
691  continue;
692 
693  /* Just refreshing won't work. */
694  aw_call_destroy_callbacks (account);
695 
696  xaccAccountBeginEdit (account);
697  xaccAccountSetType (account, type);
698  xaccAccountCommitEdit (account);
699 
700  set_children_types (account, type);
701  }
702  g_list_free (children);
703 }
704 
705 static void
706 make_children_compatible (AccountWindow *aw)
707 {
708  Account *account;
709 
710  g_return_if_fail (aw);
711 
712  if (aw->dialog_type == NEW_ACCOUNT)
713  return;
714 
715  account = aw_get_account (aw);
716  g_return_if_fail (account);
717 
718  if (xaccAccountTypesCompatible (aw->type, xaccAccountGetType (account)))
719  return;
720 
721  set_children_types (account, aw->type);
722 }
723 
724 static void
725 gnc_finish_ok (AccountWindow *aw)
726 {
727  ENTER("aw %p", aw);
728  gnc_suspend_gui_refresh ();
729 
730  /* make the account changes */
731  make_children_compatible (aw);
732  gnc_ui_to_account (aw);
733 
734  gnc_resume_gui_refresh ();
735 
736  /* do it all again, if needed */
737  if ((aw->dialog_type == NEW_ACCOUNT) && aw->next_name && *aw->next_name)
738  {
739  gnc_commodity *commodity;
740  Account *parent;
741  Account *account;
742 
743  /* Drop the old parent_tree so we can update it with an up to date one */
744  gtk_container_remove (GTK_CONTAINER(aw->parent_scroll), GTK_WIDGET(aw->parent_tree));
745  aw->parent_tree = gnc_tree_view_account_new (TRUE);
746  gtk_container_add (GTK_CONTAINER(aw->parent_scroll), GTK_WIDGET(aw->parent_tree));
747  gtk_widget_show (GTK_WIDGET(aw->parent_tree));
748 
749  aw_connect_selection_changed (aw);
750  gnc_suspend_gui_refresh ();
751 
752  parent = aw_get_account (aw);
753  account = xaccMallocAccount (aw->book);
754  aw->account = *xaccAccountGetGUID (account);
755  aw->type = xaccAccountGetType (parent);
756 
757  xaccAccountSetName (account, *aw->next_name);
758  aw->next_name++;
759 
760  gnc_account_to_ui (aw);
761 
762  gnc_account_window_set_name (aw);
763 
764  commodity = xaccAccountGetCommodity (parent);
765  gnc_general_select_set_selected (GNC_GENERAL_SELECT(aw->commodity_edit),
766  commodity);
767  gnc_account_commodity_from_type (aw, FALSE);
768 
769  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(
770  aw->parent_tree),
771  parent);
772 
773  gnc_resume_gui_refresh ();
774  LEAVE("1");
775  return;
776  }
777 
778  /* save for posterity */
779  aw->created_account = aw_get_account (aw);
780 
781  /* so it doesn't get freed on close */
782  aw->account = *guid_null ();
783 
784  gnc_close_gui_component (aw->component_id);
785  LEAVE("2");
786 }
787 
788 static void
789 add_children_to_expander (GObject *object, GParamSpec *param_spec, gpointer data)
790 {
791  GtkExpander *expander = GTK_EXPANDER(object);
792  Account *account = data;
793  GtkWidget *scrolled_window;
794  GtkTreeView *view;
795 
796  if (gtk_expander_get_expanded (expander) &&
797  !gtk_bin_get_child (GTK_BIN(expander)))
798  {
799  view = gnc_tree_view_account_new_with_root (account, FALSE);
800 
801  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
802  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolled_window),
803  GTK_POLICY_AUTOMATIC,
804  GTK_POLICY_AUTOMATIC);
805  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolled_window),
806  GTK_SHADOW_IN);
807  gtk_container_add (GTK_CONTAINER(scrolled_window), GTK_WIDGET(view));
808 
809  gtk_container_add (GTK_CONTAINER(expander), scrolled_window);
810  gtk_widget_set_vexpand (GTK_WIDGET(scrolled_window), TRUE);
811  gtk_widget_show_all (scrolled_window);
812  }
813 }
814 
815 /* Check whether there are children needing a type adjustment because of a
816  a change to an incompatible type (like after some reparenting) and let the
817  user decide whether he wants that */
818 static gboolean
819 verify_children_compatible (AccountWindow *aw)
820 {
821  Account *account;
822  GtkWidget *dialog, *vbox, *hbox, *label, *expander;
823  gchar *str;
824  gboolean result;
825 
826  if (aw == NULL)
827  return FALSE;
828 
829  account = aw_get_account (aw);
830  if (!account)
831  return FALSE;
832 
833  if (xaccAccountTypesCompatible (aw->type, xaccAccountGetType (account)))
834  return TRUE;
835 
836  if (gnc_account_n_children (account) == 0)
837  return TRUE;
838 
839  dialog = gtk_dialog_new_with_buttons ("",
840  GTK_WINDOW(aw->dialog),
841  GTK_DIALOG_DESTROY_WITH_PARENT |
842  GTK_DIALOG_MODAL,
843  _("_Cancel"), GTK_RESPONSE_CANCEL,
844  _("_OK"), GTK_RESPONSE_OK,
845  NULL);
846 
847  gtk_window_set_skip_taskbar_hint (GTK_WINDOW(dialog), TRUE);
848 
849  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
850  gtk_box_set_homogeneous (GTK_BOX(hbox), FALSE);
851  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
852  gtk_box_set_homogeneous (GTK_BOX(vbox), FALSE);
853 
854  gtk_box_pack_start (GTK_BOX(hbox),
855  gtk_image_new_from_icon_name ("dialog-information",
856  GTK_ICON_SIZE_DIALOG), FALSE, FALSE, 0);
857 
858  /* primary label */
859  label = gtk_label_new (_("Give the children the same type?"));
860  gtk_label_set_line_wrap (GTK_LABEL(label), TRUE);
861  gtk_label_set_selectable (GTK_LABEL(label), TRUE);
862  gnc_label_set_alignment (label, 0.0, 0.0);
863 
864  /* make label large */
865  gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-title");
866 
867  gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
868 
869  /* secondary label */
870  str = g_strdup_printf (_("The children of the edited account have to be "
871  "changed to type \"%s\" to make them compatible."),
872  xaccAccountGetTypeStr (aw->type));
873  label = gtk_label_new (str);
874  g_free (str);
875  gtk_label_set_line_wrap (GTK_LABEL(label), TRUE);
876  gtk_label_set_selectable (GTK_LABEL(label), TRUE);
877  gnc_label_set_alignment (label, 0.0, 0.0);
878  gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
879 
880  /* children */
881  expander = gtk_expander_new_with_mnemonic (_("_Show children accounts"));
882  gtk_expander_set_spacing (GTK_EXPANDER(expander), 6);
883  g_signal_connect (G_OBJECT(expander), "notify::expanded",
884  G_CALLBACK(add_children_to_expander), account);
885  gtk_box_pack_start (GTK_BOX(vbox), expander, TRUE, TRUE, 0);
886 
887  gtk_box_pack_start (GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
888 
889  gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area (GTK_DIALOG(dialog))),
890  hbox, TRUE, TRUE, 0);
891 
892  /* spacings */
893  gtk_container_set_border_width (GTK_CONTAINER(dialog), 5);
894  gtk_container_set_border_width (GTK_CONTAINER(hbox), 5);
895  gtk_box_set_spacing (GTK_BOX(gtk_dialog_get_content_area (GTK_DIALOG(dialog))), 14);
896 
897  gtk_widget_show_all (hbox);
898 
899  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
900 
901  result = (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_OK);
902 
903  gtk_widget_destroy (dialog);
904 
905  return result;
906 }
907 
908 static gboolean
909 gnc_filter_parent_accounts (Account *account, gpointer data)
910 {
911  AccountWindow *aw = data;
912  Account *aw_account = aw_get_account (aw);
913 
914  if (account == NULL)
915  return FALSE;
916 
917  if (aw_account == NULL)
918  return FALSE;
919 
920  if (gnc_account_is_root (account))
921  return TRUE;
922 
923  if (account == aw_account)
924  return FALSE;
925 
926  if (xaccAccountHasAncestor (account, aw_account))
927  return FALSE;
928 
929  return TRUE;
930 }
931 
932 static gboolean
933 gnc_common_ok (AccountWindow *aw)
934 {
935  Account *root, *account, *parent;
936  gnc_commodity * commodity;
937  gchar *fullname, *fullname_parent;
938  const gchar *name, *separator;
939  gboolean higher_limit_valid;
940  gnc_numeric higher_balance_limit;
941  gboolean lower_limit_valid;
942  gnc_numeric lower_balance_limit;
943 
944  ENTER("aw %p", aw);
945  root = gnc_book_get_root_account (aw->book);
946 
947  separator = gnc_get_account_separator_string ();
948 
949  /* check for valid name */
950  name = gtk_entry_get_text (GTK_ENTRY(aw->name_entry));
951  if (g_strcmp0 (name, "") == 0)
952  {
953  const char *message = _("The account must be given a name.");
954  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
955  LEAVE("bad name");
956  return FALSE;
957  }
958 
959  /* check for a duplicate name */
961  (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
962  if (parent == NULL)
963  {
964  account = gnc_account_lookup_by_full_name (root, name);
965  }
966  else
967  {
968  fullname_parent = gnc_account_get_full_name (parent);
969  fullname = g_strconcat (fullname_parent, separator, name, NULL);
970 
971  account = gnc_account_lookup_by_full_name (root, fullname);
972 
973  g_free (fullname_parent);
974  g_free (fullname);
975  }
976  if ((account != NULL) &&
977  !guid_equal (&aw->account, xaccAccountGetGUID (account)))
978  {
979  const char *message = _("There is already an account with that name.");
980  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
981  LEAVE("duplicate name");
982  return FALSE;
983  }
984 
985  /* Parent check, probably not needed, but be safe */
986  if (!gnc_filter_parent_accounts (parent, aw))
987  {
988  const char *message = _("You must choose a valid parent account.");
989  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
990  LEAVE("invalid parent");
991  return FALSE;
992  }
993 
994  /* check for valid type */
995  if (aw->type == ACCT_TYPE_INVALID)
996  {
997  const char *message = _("You must select an account type.");
998  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
999  LEAVE("invalid type");
1000  return FALSE;
1001  }
1002 
1003  /* check whether the types of child and parent are compatible */
1004  if (!xaccAccountTypesCompatible (xaccAccountGetType (parent), aw->type))
1005  {
1006  const char *message = _("The selected account type is incompatible with "
1007  "the one of the selected parent.");
1008  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1009  LEAVE("incompatible types");
1010  return FALSE;
1011  }
1012 
1013  /* check for commodity */
1014  commodity = (gnc_commodity *)
1015  gnc_general_select_get_selected (GNC_GENERAL_SELECT(aw->commodity_edit));
1016  if (!commodity)
1017  {
1018  const char *message = _("You must choose a commodity.");
1019  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1020  LEAVE("invalid commodity");
1021  return FALSE;
1022  }
1023 
1024  /* check for higher balance limit greater than lower */
1025  higher_limit_valid = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit),
1026  &higher_balance_limit, TRUE, NULL);
1027 
1028  lower_limit_valid = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit),
1029  &lower_balance_limit, TRUE, NULL);
1030 
1031  if ((lower_limit_valid == 0) && (higher_limit_valid == 0))
1032  {
1033  gint compare = gnc_numeric_compare (higher_balance_limit,
1034  lower_balance_limit);
1035 
1036  if ((compare == 0) && (!gnc_numeric_zero_p (higher_balance_limit)))
1037  {
1038  const char *message = _("Balance limits must be different unless they are both zero.");
1039  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1040  LEAVE("invalid balance limit, both the same but not zero");
1041  return FALSE;
1042  }
1043  else if (compare == -1)
1044  {
1045  const char *message = _("The lower balance limit must be less than the higher limit.");
1046  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1047  LEAVE("invalid balance limit, lower limit not less than upper");
1048  return FALSE;
1049  }
1050  }
1051 
1052  LEAVE("passed");
1053  return TRUE;
1054 }
1055 
1056 static void
1057 gnc_edit_account_ok (AccountWindow *aw)
1058 {
1059  Account *account;
1060 
1061  ENTER("aw %p", aw);
1062 
1063  account = aw_get_account (aw);
1064  if (!account)
1065  {
1066  LEAVE(" ");
1067  return;
1068  }
1069 
1070  if (!gnc_common_ok (aw))
1071  {
1072  LEAVE(" ");
1073  return;
1074  }
1075 
1076  if (!verify_children_compatible (aw))
1077  {
1078  LEAVE(" ");
1079  return;
1080  }
1081 
1082  gnc_finish_ok (aw);
1083  LEAVE(" ");
1084 }
1085 
1086 static void
1087 gnc_new_account_ok (AccountWindow *aw)
1088 {
1089  gnc_numeric balance;
1090 
1091  ENTER("aw %p", aw);
1092 
1093  if (!gnc_common_ok (aw))
1094  {
1095  LEAVE(" ");
1096  return;
1097  }
1098 
1099  if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(aw->opening_balance_edit), NULL))
1100  {
1101  const char *message = _("You must enter a valid opening balance "
1102  "or leave it blank.");
1103  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1104  LEAVE(" ");
1105  return;
1106  }
1107 
1108  balance = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT(aw->opening_balance_edit));
1109 
1110  if (!gnc_numeric_zero_p (balance))
1111  {
1112  gboolean use_equity;
1113 
1114  use_equity = gtk_toggle_button_get_active
1115  (GTK_TOGGLE_BUTTON(aw->opening_equity_radio));
1116 
1117  if (!use_equity)
1118  {
1119  Account *transfer = NULL;
1120 
1121  transfer = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(
1122  aw->transfer_tree));
1123  if (!transfer)
1124  {
1125  const char *message = _("You must select a transfer account or choose"
1126  " the opening balances equity account.");
1127  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1128  LEAVE(" ");
1129  return;
1130  }
1131  }
1132  }
1133 
1134  gnc_finish_ok (aw);
1135  LEAVE(" ");
1136 }
1137 
1138 static void
1139 gnc_account_window_response_cb (GtkDialog *dialog,
1140  gint response,
1141  gpointer data)
1142 {
1143  AccountWindow *aw = data;
1144 
1145  ENTER("dialog %p, response %d, aw %p", dialog, response, aw);
1146  switch (response)
1147  {
1148  case GTK_RESPONSE_OK:
1149  switch (aw->dialog_type)
1150  {
1151  case NEW_ACCOUNT:
1152  DEBUG("new acct dialog, OK");
1153  gnc_new_account_ok (aw);
1154  break;
1155  case EDIT_ACCOUNT:
1156  DEBUG("edit acct dialog, OK");
1157  gnc_edit_account_ok (aw);
1158  break;
1159  default:
1160  g_assert_not_reached ();
1161  return;
1162  }
1163  break;
1164  case GTK_RESPONSE_HELP:
1165  switch (aw->dialog_type)
1166  {
1167  case NEW_ACCOUNT:
1168  DEBUG("new acct dialog, HELP");
1169  gnc_gnome_help (GTK_WINDOW(dialog), DF_MANUAL, DL_ACC);
1170  break;
1171  case EDIT_ACCOUNT:
1172  DEBUG("edit acct dialog, HELP");
1173  gnc_gnome_help (GTK_WINDOW(dialog), DF_MANUAL, DL_ACCEDIT);
1174  break;
1175  default:
1176  g_assert_not_reached ();
1177  return;
1178  }
1179  break;
1180  case GTK_RESPONSE_CANCEL:
1181  default:
1182  DEBUG("CANCEL");
1183  gnc_close_gui_component (aw->component_id);
1184  break;
1185  }
1186  LEAVE(" ");
1187 }
1188 
1189 void
1190 gnc_account_window_destroy_cb (GtkWidget *object, gpointer data)
1191 {
1192  AccountWindow *aw = data;
1193  Account *account;
1194 
1195  ENTER("object %p, aw %p", object, aw);
1196  account = aw_get_account (aw);
1197 
1198  aw_clear_selection_handler (aw);
1199  gnc_suspend_gui_refresh ();
1200 
1201  switch (aw->dialog_type)
1202  {
1203  case NEW_ACCOUNT:
1204  if (account != NULL)
1205  {
1206  xaccAccountBeginEdit (account);
1207  xaccAccountDestroy (account);
1208  aw->account = *guid_null ();
1209  }
1210 
1211  DEBUG ("account add window destroyed\n");
1212  break;
1213 
1214  case EDIT_ACCOUNT:
1215  break;
1216 
1217  default:
1218  PERR ("unexpected dialog type\n");
1219  gnc_resume_gui_refresh ();
1220  LEAVE(" ");
1221  return;
1222  }
1223 
1224  gnc_unregister_gui_component (aw->component_id);
1225 
1226  gnc_resume_gui_refresh ();
1227 
1228  if (aw->subaccount_names)
1229  {
1230  g_strfreev (aw->subaccount_names);
1231  aw->subaccount_names = NULL;
1232  aw->next_name = NULL;
1233  }
1234 
1235  g_free (aw);
1236  LEAVE(" ");
1237 }
1238 
1239 static void
1240 gnc_account_parent_changed_cb (GObject *selection, gpointer data)
1241 {
1242  AccountWindow *aw = data;
1243  Account *parent_account;
1244  guint32 types, old_types;
1245  GtkTreeModelSort *s_model;
1246  GtkTreeModel *type_model;
1247  gboolean combo_set = FALSE;
1248 
1249  g_return_if_fail (aw);
1250  g_return_if_fail (selection == aw->selection);
1251 
1253  GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
1254  if (!parent_account)
1255  return;
1256 
1257  if (gnc_account_is_root (parent_account))
1258  {
1259  types = aw->valid_types;
1260  }
1261  else
1262  {
1263  types = aw->valid_types &
1265  }
1266  s_model = GTK_TREE_MODEL_SORT(gtk_combo_box_get_model (GTK_COMBO_BOX(aw->type_combo)));
1267  type_model = gtk_tree_model_sort_get_model (s_model);
1268  if (!type_model)
1269  return;
1270 
1271  if (aw->type != aw->preferred_account_type &&
1272  (types & (1 << aw->preferred_account_type)) != 0)
1273  {
1274  /* we can change back to the preferred account type */
1275  aw->type = aw->preferred_account_type;
1276  combo_set = TRUE;
1277  }
1278  else if ((types & (1 << aw->type)) == 0)
1279  {
1280  /* our type is invalid now */
1281  aw->type = ACCT_TYPE_INVALID;
1282  }
1283  else
1284  {
1285  /* no type change, but maybe list of valid types changed */
1286  old_types = gnc_tree_model_account_types_get_mask (type_model);
1287  if (old_types != types)
1288  combo_set = TRUE;
1289  }
1290 
1291  gnc_tree_model_account_types_set_mask (type_model, types);
1292 
1293  if (combo_set)
1294  gnc_tree_model_account_types_set_active_combo (GTK_COMBO_BOX(aw->type_combo),
1295  1 << aw->type);
1296 
1297  gnc_account_window_set_name (aw);
1298 }
1299 
1300 static void
1301 set_auto_interest_box(AccountWindow *aw)
1302 {
1303  Account* account = aw_get_account (aw);
1304  gboolean type_ok = account_type_has_auto_interest_xfer (aw->type);
1305  gboolean pref_set = xaccAccountGetAutoInterest (account);
1306  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(aw->auto_interest_button),
1307  type_ok && pref_set);
1308  gtk_widget_set_sensitive (GTK_WIDGET(aw->auto_interest_button), type_ok);
1309 }
1310 
1311 static void
1312 gnc_account_type_combo_changed_cb (GtkComboBox *combo, gpointer data)
1313 {
1314  AccountWindow *aw = data;
1315  gboolean sensitive;
1316  GNCAccountType type_id;
1317 
1318  g_return_if_fail (aw != NULL);
1319 
1320  sensitive = FALSE;
1321 
1322  type_id = gnc_tree_model_account_types_get_active_combo (combo);
1323 
1324  if (type_id == ACCT_TYPE_NONE)
1325  {
1326  aw->type = ACCT_TYPE_INVALID;
1327  }
1328  else
1329  {
1330  aw->type = type_id;
1331  aw->preferred_account_type = type_id;
1332 
1333  gnc_account_commodity_from_type (aw, TRUE);
1334 
1335  sensitive = (aw->type != ACCT_TYPE_EQUITY &&
1336  aw->type != ACCT_TYPE_CURRENCY &&
1337  aw->type != ACCT_TYPE_STOCK &&
1338  aw->type != ACCT_TYPE_MUTUAL &&
1339  aw->type != ACCT_TYPE_TRADING);
1340  }
1341 
1342  gtk_widget_set_sensitive (aw->opening_balance_page, sensitive);
1343 
1344  if (!sensitive)
1345  {
1346  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(aw->opening_balance_edit),
1347  gnc_numeric_zero ());
1348  }
1349  set_auto_interest_box (aw);
1350 }
1351 
1352 static void
1353 gnc_account_type_view_create (AccountWindow *aw, guint32 compat_types)
1354 {
1355  GtkTreeModel *fmodel, *smodel;
1356  GtkCellRenderer *renderer;
1357 
1358  aw->valid_types &= compat_types;
1359  if (aw->valid_types == 0)
1360  {
1361  /* no type restrictions, choose aw->type */
1362  aw->valid_types = compat_types | (1 << aw->type);
1363  aw->preferred_account_type = aw->type;
1364  }
1365  else if ((aw->valid_types & (1 << aw->type)) != 0)
1366  {
1367  /* aw->type is valid */
1368  aw->preferred_account_type = aw->type;
1369  }
1370  else if ((aw->valid_types & (1 << last_used_account_type)) != 0)
1371  {
1372  /* last used account type is valid */
1373  aw->type = last_used_account_type;
1374  aw->preferred_account_type = last_used_account_type;
1375  }
1376  else
1377  {
1378  /* choose first valid account type */
1379  int i;
1380  aw->preferred_account_type = aw->type;
1381  aw->type = ACCT_TYPE_INVALID;
1382  for (i = 0; i < 32; i++)
1383  if ((aw->valid_types & (1 << i)) != 0)
1384  {
1385  aw->type = i;
1386  break;
1387  }
1388  }
1389 
1390  fmodel = gnc_tree_model_account_types_filter_using_mask (aw->valid_types);
1391 
1392  smodel = gtk_tree_model_sort_new_with_model (fmodel);
1393 
1394  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(smodel),
1395  GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME,
1396  GTK_SORT_ASCENDING);
1397 
1398  gtk_combo_box_set_model (GTK_COMBO_BOX(aw->type_combo), smodel);
1399 
1400  renderer = gtk_cell_renderer_text_new ();
1401  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(aw->type_combo), renderer, TRUE);
1402  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(aw->type_combo), renderer,
1403  "text", GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME, NULL);
1404 
1405  g_signal_connect (G_OBJECT(aw->type_combo), "changed",
1406  G_CALLBACK(gnc_account_type_combo_changed_cb), aw);
1407 
1408  g_object_unref (G_OBJECT(fmodel));
1409 
1410  gnc_tree_model_account_types_set_active_combo (GTK_COMBO_BOX(aw->type_combo),
1411  1 << aw->type);
1412 }
1413 
1414 void
1415 gnc_account_name_insert_text_cb (GtkWidget *entry,
1416  const gchar *text,
1417  gint length,
1418  gint *position,
1419  gpointer data)
1420 {
1421  GtkEditable *editable = GTK_EDITABLE(entry);
1422  const gchar *separator = NULL;
1423  gchar **strsplit;
1424 
1425  separator = gnc_get_account_separator_string ();
1426  strsplit = g_strsplit (text, separator, 0);
1427  if (strsplit[1] != NULL)
1428  {
1429  gchar *result = g_strjoinv (NULL, strsplit);
1430  g_signal_handlers_block_by_func (G_OBJECT(editable),
1431  G_CALLBACK(gnc_account_name_insert_text_cb),
1432  data);
1433  gtk_editable_insert_text (editable, result, g_utf8_strlen (result, -1), position);
1434  g_signal_handlers_unblock_by_func (G_OBJECT(editable),
1435  G_CALLBACK(gnc_account_name_insert_text_cb),
1436  data);
1437  g_signal_stop_emission_by_name (G_OBJECT(editable), "insert_text");
1438  g_free (result);
1439  }
1440 
1441  g_strfreev (strsplit);
1442 }
1443 
1444 void
1445 gnc_account_name_changed_cb (GtkWidget *widget, gpointer data)
1446 {
1447  AccountWindow *aw = data;
1448 
1449  gnc_account_window_set_name (aw);
1450 }
1451 
1452 void
1453 gnc_account_color_default_cb (GtkWidget *widget, gpointer data)
1454 {
1455  GdkRGBA color;
1456  AccountWindow *aw = data;
1457 
1458  gdk_rgba_parse (&color, DEFAULT_COLOR);
1459  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(aw->color_entry_button), &color);
1460 
1461 }
1462 
1463 static void
1464 commodity_changed_cb (GNCGeneralSelect *gsl, gpointer data)
1465 {
1466  AccountWindow *aw = data;
1467  gnc_commodity *currency;
1468  GtkTreeSelection *selection;
1469  Account *account = aw_get_account (aw);
1470 
1471  currency = (gnc_commodity *) gnc_general_select_get_selected (gsl);
1472  if (!currency)
1473  return;
1474 
1475  if (xaccAccountGetIsOpeningBalance (account))
1476  {
1477  Account *ob_account = gnc_account_lookup_by_opening_balance (gnc_book_get_root_account (aw->book), currency);
1478  if (ob_account != account)
1479  {
1480  gchar *dialog_msg = _("An account with opening balance already exists for the desired currency.");
1481  gchar *dialog_title = _("Cannot change currency");
1482  GtkWidget *dialog = gtk_message_dialog_new (gnc_ui_get_main_window (NULL),
1483  0,
1484  GTK_MESSAGE_ERROR,
1485  GTK_BUTTONS_OK,
1486  "%s", dialog_title);
1487  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
1488  "%s", dialog_msg);
1489  gtk_dialog_run (GTK_DIALOG(dialog));
1490  gtk_widget_destroy (dialog);
1491  g_signal_handlers_block_by_func (gsl, commodity_changed_cb, data);
1492  gnc_general_select_set_selected (gsl, xaccAccountGetCommodity (account));
1493  g_signal_handlers_unblock_by_func (gsl, commodity_changed_cb, data);
1494  return;
1495  }
1496  }
1497 
1498  gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT(aw->opening_balance_edit),
1499  gnc_commodity_get_fraction (currency));
1500  gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT(aw->opening_balance_edit),
1501  gnc_commodity_print_info (currency, FALSE));
1502 
1503  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(aw->transfer_tree));
1504  gtk_tree_selection_unselect_all (selection);
1505  gnc_account_opening_balance_button_update (aw, currency);
1506 }
1507 
1508 static gboolean
1509 account_commodity_filter (GtkTreeSelection *selection,
1510  GtkTreeModel *unused_model,
1511  GtkTreePath *s_path,
1512  gboolean path_currently_selected,
1513  gpointer user_data)
1514 {
1515  gnc_commodity *commodity;
1516  AccountWindow *aw;
1517  Account *account;
1518 
1519  g_return_val_if_fail (GTK_IS_TREE_SELECTION(selection), FALSE);
1520 
1521  aw = user_data;
1522 
1523  if (path_currently_selected)
1524  {
1525  /* already selected, don't waste time. */
1526  return TRUE;
1527  }
1528 
1529  account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(aw->transfer_tree), s_path);
1530  if (!account)
1531  {
1532  return FALSE;
1533  }
1534 
1535  commodity = (gnc_commodity *)
1536  gnc_general_select_get_selected (GNC_GENERAL_SELECT(aw->commodity_edit));
1537 
1538  return gnc_commodity_equiv (xaccAccountGetCommodity (account), commodity);
1539 }
1540 
1541 void
1542 opening_equity_cb (GtkWidget *w, gpointer data)
1543 {
1544  AccountWindow *aw = data;
1545  gboolean use_equity;
1546 
1547  use_equity = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1548 
1549  gtk_widget_set_sensitive (aw->transfer_account_scroll, !use_equity);
1550 }
1551 
1552 /********************************************************************\
1553  * gnc_account_window_create *
1554  * creates a window to create a new account. *
1555  * *
1556  * Args: parent - the parent window dialog *
1557  * Args: aw - the information structure for this window *
1558  * Return: the created window *
1559  \*******************************************************************/
1560 static void
1561 gnc_account_window_create (GtkWindow *parent, AccountWindow *aw)
1562 {
1563  GtkWidget *amount;
1564  GtkWidget *date_edit;
1565  GObject *awo;
1566  GtkWidget *box;
1567  GtkWidget *label;
1568  GtkBuilder *builder;
1569  GtkTreeSelection *selection;
1570  const gchar *tt = _("This Account contains Transactions.\nChanging this option is not possible.");
1571  guint32 compat_types = xaccAccountTypesValid ();
1572 
1573  ENTER("aw %p, modal %d", aw, aw->modal);
1574  builder = gtk_builder_new ();
1575  gnc_builder_add_from_file (builder, "dialog-account.glade", "fraction_liststore");
1576  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_dialog");
1577 
1578  aw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_dialog"));
1579  awo = G_OBJECT(aw->dialog);
1580 
1581  if (parent)
1582  gtk_window_set_transient_for (GTK_WINDOW(aw->dialog), parent);
1583 
1584  // Set the name for this dialog so it can be easily manipulated with css
1585  gtk_widget_set_name (GTK_WIDGET(aw->dialog), "gnc-id-account");
1586  gnc_widget_style_context_add_class (GTK_WIDGET(aw->dialog), "gnc-class-account");
1587 
1588 
1589  g_object_set_data (awo, "dialog_info", aw);
1590 
1591  if (!aw->modal)
1592  g_signal_connect (awo, "response",
1593  G_CALLBACK(gnc_account_window_response_cb), aw);
1594  else
1595  gtk_window_set_modal (GTK_WINDOW(aw->dialog), TRUE);
1596 
1597  aw->notebook = GTK_WIDGET(gtk_builder_get_object (builder, "account_notebook"));
1598  aw->name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "name_entry"));
1599  aw->description_entry = GTK_WIDGET(gtk_builder_get_object (builder, "description_entry"));
1600  aw->color_entry_button = GTK_WIDGET(gtk_builder_get_object (builder, "color_entry_button"));
1601  aw->color_default_button = GTK_WIDGET(gtk_builder_get_object (builder, "color_default_button"));
1602  aw->code_entry = GTK_WIDGET(gtk_builder_get_object (builder, "code_entry"));
1603  aw->notes_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(GTK_WIDGET(
1604  gtk_builder_get_object (builder,
1605  "notes_text"))));
1606 
1607  box = GTK_WIDGET(gtk_builder_get_object (builder, "commodity_hbox"));
1608  aw->commodity_edit = gnc_general_select_new (GNC_GENERAL_SELECT_TYPE_SELECT,
1609  gnc_commodity_edit_get_string,
1610  gnc_commodity_edit_new_select,
1611  &aw->commodity_mode);
1612 
1613  gtk_box_pack_start (GTK_BOX(box), aw->commodity_edit, TRUE, TRUE, 0);
1614  gtk_widget_show (aw->commodity_edit);
1615  // If the account has transactions, prevent changes by displaying a label and tooltip
1616  if (xaccAccountGetSplitsSize (aw_get_account (aw)) != 0)
1617  {
1618  gtk_widget_set_tooltip_text (aw->commodity_edit, tt);
1619  gtk_widget_set_sensitive (aw->commodity_edit, FALSE);
1620  }
1621 
1622  label = GTK_WIDGET(gtk_builder_get_object (builder, "security_label"));
1623  gnc_general_select_make_mnemonic_target (GNC_GENERAL_SELECT(aw->commodity_edit), label);
1624 
1625  g_signal_connect (G_OBJECT(aw->commodity_edit), "changed",
1626  G_CALLBACK(commodity_changed_cb), aw);
1627 
1628  aw->account_scu = GTK_WIDGET(gtk_builder_get_object (builder, "account_scu"));
1629 
1630  aw->parent_scroll = GTK_WIDGET(gtk_builder_get_object (builder, "parent_scroll"));
1631 
1632  aw->parent_tree = gnc_tree_view_account_new (TRUE);
1633  gtk_container_add (GTK_CONTAINER(aw->parent_scroll), GTK_WIDGET(aw->parent_tree));
1634  gtk_widget_show (GTK_WIDGET(aw->parent_tree));
1635  aw_connect_selection_changed (aw);
1636 
1637  aw->balance_grid = GTK_WIDGET(gtk_builder_get_object (builder, "balance_grid"));
1638 
1639  box = GTK_WIDGET(gtk_builder_get_object (builder, "higher_balance_limit_hbox"));
1640  aw->higher_balance_limit_edit = gnc_amount_edit_new ();
1641  gtk_box_pack_start (GTK_BOX(box), aw->higher_balance_limit_edit, TRUE, TRUE, 0);
1642  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit), TRUE);
1643  gnc_amount_edit_set_validate_on_change (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit), TRUE);
1644  gnc_amount_edit_show_warning_symbol (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit), TRUE);
1645  gtk_widget_show (aw->higher_balance_limit_edit);
1646 
1647  box = GTK_WIDGET(gtk_builder_get_object (builder, "lower_balance_limit_hbox"));
1648  aw->lower_balance_limit_edit = gnc_amount_edit_new ();
1649  gtk_box_pack_start (GTK_BOX(box), aw->lower_balance_limit_edit, TRUE, TRUE, 0);
1650  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit), TRUE);
1651  gnc_amount_edit_set_validate_on_change (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit), TRUE);
1652  gnc_amount_edit_show_warning_symbol (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit), TRUE);
1653  gtk_widget_show (aw->lower_balance_limit_edit);
1654 
1655  aw->include_balance_sub_accts = GTK_WIDGET(gtk_builder_get_object (builder, "include_sub_accts_tb"));
1656 
1657  aw->more_properties_page =
1658  gtk_notebook_get_nth_page (GTK_NOTEBOOK(aw->notebook), 1);
1659 
1660  aw->opening_balance_button = GTK_WIDGET(gtk_builder_get_object (builder, "opening_balance_button"));
1661  aw->tax_related_button = GTK_WIDGET(gtk_builder_get_object (builder, "tax_related_button"));
1662  aw->placeholder_button = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_button"));
1663  aw->hidden_button = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_button"));
1664  aw->auto_interest_button = GTK_WIDGET(gtk_builder_get_object (builder, "auto_interest_button"));
1665  set_auto_interest_box (aw);
1666 
1667 
1668  box = GTK_WIDGET(gtk_builder_get_object (builder, "opening_balance_box"));
1669  amount = gnc_amount_edit_new ();
1670  aw->opening_balance_edit = amount;
1671  gtk_box_pack_start (GTK_BOX(box), amount, TRUE, TRUE, 0);
1672  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT(amount), TRUE);
1673  gtk_widget_show (amount);
1674 
1675  label = GTK_WIDGET(gtk_builder_get_object (builder, "balance_label"));
1676  gnc_amount_edit_make_mnemonic_target (GNC_AMOUNT_EDIT(amount), label);
1677 
1678  box = GTK_WIDGET(gtk_builder_get_object (builder, "opening_balance_date_box"));
1679  label = GTK_WIDGET(gtk_builder_get_object (builder, "date_label"));
1680  date_edit = gnc_date_edit_new (gnc_time (NULL), 0, 0);
1681  gnc_date_make_mnemonic_target (GNC_DATE_EDIT(date_edit), label);
1682  aw->opening_balance_date_edit = date_edit;
1683  gtk_box_pack_start (GTK_BOX(box), date_edit, TRUE, TRUE, 0);
1684  gtk_widget_show (date_edit);
1685 
1686  aw->opening_balance_page =
1687  gtk_notebook_get_nth_page (GTK_NOTEBOOK(aw->notebook), 2);
1688 
1689  aw->opening_equity_radio = GTK_WIDGET(gtk_builder_get_object (builder,
1690  "opening_equity_radio"));
1691 
1692  box = GTK_WIDGET(gtk_builder_get_object (builder, "transfer_account_scroll"));
1693  aw->transfer_account_scroll = box;
1694 
1695  aw->transfer_tree = GTK_WIDGET(gnc_tree_view_account_new (FALSE));
1696  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(aw->transfer_tree));
1697  gtk_tree_selection_set_select_function (selection, account_commodity_filter, aw, NULL);
1698 
1699  gtk_container_add (GTK_CONTAINER(box), GTK_WIDGET(aw->transfer_tree));
1700  gtk_widget_show (GTK_WIDGET(aw->transfer_tree));
1701 
1702  label = GTK_WIDGET(gtk_builder_get_object (builder, "parent_label"));
1703  gtk_label_set_mnemonic_widget (GTK_LABEL(label), GTK_WIDGET(aw->parent_tree));
1704 
1705  /* This goes at the end so the select callback has good data. */
1706  aw->type_combo = GTK_WIDGET(gtk_builder_get_object (builder, "account_type_combo"));
1707 
1708  // If the account has transactions, reduce the available account types
1709  // to change the current account type to based on the following
1710  // restrictions:
1711  // - the new account type should not force a change of commodity
1712  // - the old/new type is not an immutable type. Types are marked as
1713  // immutable if gnucash depends on details that would be lost/missing
1714  // if changing from/to such a type. At the time of this writing the
1715  // immutable types are AR, AP and trading types.
1716  if (xaccAccountGetSplitsSize (aw_get_account (aw)) != 0)
1717  {
1718  GNCAccountType atype = xaccAccountGetType (aw_get_account (aw));
1719  compat_types = xaccAccountTypesCompatibleWith (atype);
1720  if (!compat_types)
1721  compat_types = xaccAccountTypesValid ();
1722  }
1723  gnc_account_type_view_create (aw, compat_types);
1724 
1725  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(aw->dialog), parent);
1726 
1727  gtk_widget_grab_focus (GTK_WIDGET(aw->name_entry));
1728 
1729  gtk_builder_connect_signals (builder, aw);
1730  g_object_unref (G_OBJECT(builder));
1731 
1732  LEAVE(" ");
1733 }
1734 
1735 static char *
1736 get_ui_fullname (AccountWindow *aw)
1737 {
1738  Account *parent_account;
1739  char *fullname;
1740  const gchar *name;
1741 
1742  name = gtk_entry_get_text (GTK_ENTRY(aw->name_entry));
1743  if (!name || *name == '\0')
1744  name = _("<No name>");
1745 
1746  parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
1747 
1748  if (parent_account && !gnc_account_is_root (parent_account))
1749  {
1750  char *parent_name = gnc_account_get_full_name (parent_account);
1751  const gchar *separator = gnc_get_account_separator_string ();
1752 
1753  fullname = g_strconcat (parent_name, separator, name, NULL);
1754  g_free (parent_name);
1755  }
1756  else
1757  fullname = g_strdup (name);
1758 
1759  return fullname;
1760 }
1761 
1762 static void
1763 gnc_account_window_set_name (AccountWindow *aw)
1764 {
1765  char *fullname;
1766  char *title;
1767 
1768  if (!aw || !aw->parent_tree)
1769  return;
1770 
1771  fullname = get_ui_fullname (aw);
1772 
1773  if (aw->dialog_type == EDIT_ACCOUNT)
1774  title = g_strconcat(_("Edit Account"), " - ", fullname, NULL);
1775  else if (aw->next_name && (g_strv_length (aw->next_name) > 0))
1776  {
1777  const char *format = _("(%d) New Accounts");
1778  char *prefix = g_strdup_printf (format,
1779  g_strv_length (aw->next_name) + 1);
1780 
1781  title = g_strconcat (prefix, " - ", fullname, " …", NULL);
1782  g_free (prefix);
1783  }
1784  else
1785  title = g_strconcat (_("New Account"), " - ", fullname, NULL);
1786 
1787  gtk_window_set_title (GTK_WINDOW(aw->dialog), title);
1788 
1789  g_free (fullname);
1790  g_free (title);
1791 }
1792 
1793 static void
1794 close_handler (gpointer user_data)
1795 {
1796  AccountWindow *aw = user_data;
1797 
1798  ENTER("aw %p, modal %d", aw, aw->modal);
1799  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(aw->dialog));
1800 
1801  gtk_widget_destroy (GTK_WIDGET(aw->dialog));
1802  LEAVE(" ");
1803 }
1804 
1805 /********************************************************************\
1806  * gnc_ui_refresh_account_window *
1807  * refreshes the edit window *
1808  * *
1809  * Args: aw - the account window to refresh *
1810  * Return: none *
1811 \********************************************************************/
1812 static void
1813 gnc_ui_refresh_account_window (AccountWindow *aw)
1814 {
1815  if (aw == NULL)
1816  return;
1817 
1818  /* gnc_account_tree_refresh (GNC_ACCOUNT_TREE(aw->parent_tree));*/
1819 
1820  gnc_account_window_set_name (aw);
1821 }
1822 
1823 static void
1824 refresh_handler (GHashTable *changes, gpointer user_data)
1825 {
1826  AccountWindow *aw = user_data;
1827  Account *account;
1828 
1829  account = aw_get_account (aw);
1830  if (!account)
1831  {
1832  gnc_close_gui_component (aw->component_id);
1833  return;
1834  }
1835 
1836  if (changes)
1837  {
1838  const EventInfo *info = gnc_gui_get_entity_events (changes, &aw->account);
1839  if (info && (info->event_mask & QOF_EVENT_DESTROY))
1840  {
1841  gnc_close_gui_component (aw->component_id);
1842  return;
1843  }
1844  }
1845  gnc_ui_refresh_account_window (aw);
1846 }
1847 
1848 static AccountWindow *
1849 gnc_ui_new_account_window_internal (GtkWindow *parent,
1850  QofBook *book,
1851  Account *base_account,
1852  gchar **subaccount_names,
1853  GList *valid_types,
1854  const gnc_commodity * default_commodity,
1855  gboolean modal)
1856 {
1857  const gnc_commodity *commodity, *parent_commodity;
1858  AccountWindow *aw;
1859  Account *account;
1860  GList *list;
1861 
1862  g_return_val_if_fail(book, NULL);
1863 
1864  aw = g_new0 (AccountWindow, 1);
1865 
1866  aw->book = book;
1867  aw->modal = modal;
1868  aw->dialog_type = NEW_ACCOUNT;
1869 
1870  aw->valid_types = 0;
1871  for (list = valid_types; list; list = list->next)
1872  aw->valid_types |= (1 << GPOINTER_TO_INT (list->data));
1873 
1874  account = xaccMallocAccount (book);
1875  aw->account = *xaccAccountGetGUID (account);
1876 
1877  if (base_account)
1878  {
1879  aw->type = xaccAccountGetType (base_account);
1880  parent_commodity = xaccAccountGetCommodity (base_account);
1881  }
1882  else
1883  {
1884  aw->type = last_used_account_type;
1885  parent_commodity = gnc_default_currency ();
1886  }
1887 
1888  gnc_suspend_gui_refresh ();
1889 
1890  if (subaccount_names && *subaccount_names)
1891  {
1892  xaccAccountSetName (account, subaccount_names[0]);
1893  aw->subaccount_names = subaccount_names;
1894  aw->next_name = subaccount_names + 1;
1895  }
1896 
1897  gnc_account_window_create (parent, aw);
1898  gnc_account_to_ui (aw);
1899 
1900  gnc_resume_gui_refresh ();
1901 
1902  if (default_commodity != NULL)
1903  {
1904  commodity = default_commodity;
1905  if ((aw->type == ACCT_TYPE_STOCK) || (aw->type == ACCT_TYPE_MUTUAL))
1906  {
1907  gtk_entry_set_text (GTK_ENTRY(aw->name_entry),
1908  (gpointer) gnc_commodity_get_mnemonic (commodity));
1909  gtk_entry_set_text (GTK_ENTRY(aw->description_entry),
1910  (gpointer) gnc_commodity_get_fullname (commodity));
1911  }
1912  }
1913  else if ((aw->type != ACCT_TYPE_STOCK) && (aw->type != ACCT_TYPE_MUTUAL))
1914  {
1915  commodity = parent_commodity;
1916  }
1917  else
1918  {
1919  commodity = NULL;
1920  }
1921  gnc_general_select_set_selected (GNC_GENERAL_SELECT(aw->commodity_edit),
1922  (gpointer) commodity);
1923  gnc_account_commodity_from_type (aw, FALSE);
1924 
1925  if (base_account == NULL)
1926  {
1927  base_account = gnc_book_get_root_account (book);
1928  }
1929 
1930  gtk_tree_view_collapse_all (aw->parent_tree);
1931  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(
1932  aw->parent_tree),
1933  base_account);
1934 
1935  gtk_widget_show (aw->dialog);
1936 
1937  gnc_window_adjust_for_screen (GTK_WINDOW(aw->dialog));
1938 
1939  gnc_account_window_set_name (aw);
1940 
1941  aw->component_id = gnc_register_gui_component (DIALOG_NEW_ACCOUNT_CM_CLASS,
1942  refresh_handler,
1943  modal ? NULL : close_handler,
1944  aw);
1945 
1946  gnc_gui_component_set_session (aw->component_id, gnc_get_current_session());
1947  gnc_gui_component_watch_entity_type (aw->component_id,
1948  GNC_ID_ACCOUNT,
1949  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
1950  return aw;
1951 }
1952 
1953 static gchar **
1954 gnc_split_account_name (QofBook *book, const char *in_name, Account **base_account)
1955 {
1956  Account *root, *account;
1957  gchar **names, **ptr, **out_names;
1958  GList *list, *node;
1959 
1960  root = gnc_book_get_root_account (book);
1961  list = gnc_account_get_children (root);
1962  names = g_strsplit (in_name, gnc_get_account_separator_string (), -1);
1963 
1964  for (ptr = names; *ptr; ptr++)
1965  {
1966  /* Stop if there are no children at the current level. */
1967  if (list == NULL)
1968  break;
1969 
1970  /* Look for the first name in the children. */
1971  for (node = list; node; node = g_list_next (node))
1972  {
1973  account = node->data;
1974 
1975  if (g_strcmp0 (xaccAccountGetName (account), *ptr) == 0)
1976  {
1977  /* We found an account. */
1978  *base_account = account;
1979  break;
1980  }
1981  }
1982 
1983  /* Was there a match? If no, stop the traversal. */
1984  if (node == NULL)
1985  break;
1986 
1987  g_list_free (list);
1988  list = gnc_account_get_children (account);
1989  }
1990 
1991  out_names = g_strdupv (ptr);
1992  g_strfreev (names);
1993  if (list)
1994  g_list_free (list);
1995  return out_names;
1996 }
1997 
1998 /************************************************************
1999  * Entry points for a Modal Dialog *
2000  ************************************************************/
2001 
2002 Account *
2003 gnc_ui_new_accounts_from_name_window (GtkWindow *parent, const char *name)
2004 {
2005  return gnc_ui_new_accounts_from_name_with_defaults (parent, name, NULL,
2006  NULL, NULL);
2007 }
2008 
2009 Account *
2011  const char *name,
2012  GList *valid_types,
2013  const gnc_commodity * default_commodity,
2014  Account * parent_acct)
2015 {
2016  QofBook *book;
2017  AccountWindow *aw;
2018  Account *base_account = NULL;
2019  Account *created_account = NULL;
2020  gchar ** subaccount_names;
2021  gint response;
2022  gboolean done = FALSE;
2023 
2024  ENTER("name %s, valid %p, commodity %p, account %p",
2025  name, valid_types, default_commodity, parent_acct);
2026  book = gnc_get_current_book ();
2027  if (!name || *name == '\0')
2028  {
2029  subaccount_names = NULL;
2030  base_account = NULL;
2031  }
2032  else
2033  subaccount_names = gnc_split_account_name (book, name, &base_account);
2034 
2035  if (parent_acct != NULL)
2036  {
2037  base_account = parent_acct;
2038  }
2039  aw = gnc_ui_new_account_window_internal (parent, book, base_account,
2040  subaccount_names,
2041  valid_types,
2042  default_commodity,
2043  TRUE);
2044 
2045  while (!done)
2046  {
2047  response = gtk_dialog_run (GTK_DIALOG(aw->dialog));
2048 
2049  /* This can destroy the dialog */
2050  gnc_account_window_response_cb (GTK_DIALOG(aw->dialog), response, (gpointer)aw);
2051 
2052  switch (response)
2053  {
2054  case GTK_RESPONSE_OK:
2055  created_account = aw->created_account;
2056  done = (created_account != NULL);
2057  break;
2058 
2059  case GTK_RESPONSE_HELP:
2060  done = FALSE;
2061  break;
2062 
2063  default:
2064  done = TRUE;
2065  break;
2066  }
2067  }
2068 
2069  close_handler (aw);
2070  LEAVE("created %s (%p)", xaccAccountGetName (created_account), created_account);
2071  return created_account;
2072 }
2073 
2074 /************************************************************
2075  * Entry points for a non-Modal Dialog *
2076  ************************************************************/
2077 
2078 static gboolean
2079 find_by_account (gpointer find_data, gpointer user_data)
2080 {
2081  Account *account = find_data;
2082  AccountWindow *aw = user_data;
2083 
2084  if (!aw)
2085  return FALSE;
2086 
2087  return guid_equal (&aw->account, xaccAccountGetGUID (account));
2088 }
2089 
2090 /*
2091  * opens up a window to edit an account
2092  *
2093  * Args: account - the account to edit
2094  * Return: EditAccountWindow object
2095  */
2096 void
2097 gnc_ui_edit_account_window (GtkWindow *parent, Account *account)
2098 {
2099  AccountWindow * aw;
2100  Account *parent_acct;
2101 
2102  if (account == NULL)
2103  return;
2104 
2105  aw = gnc_find_first_gui_component (DIALOG_EDIT_ACCOUNT_CM_CLASS,
2106  find_by_account, account);
2107  if (aw)
2108  {
2109  gtk_window_present (GTK_WINDOW(aw->dialog));
2110  return;
2111  }
2112 
2113  aw = g_new0 (AccountWindow, 1);
2114 
2115  aw->book = gnc_account_get_book (account);
2116  aw->modal = FALSE;
2117  aw->dialog_type = EDIT_ACCOUNT;
2118  aw->account = *xaccAccountGetGUID (account);
2119  aw->subaccount_names = NULL;
2120  aw->type = xaccAccountGetType (account);
2121 
2122  gnc_suspend_gui_refresh ();
2123 
2124  gnc_account_window_create (parent, aw);
2125  gnc_account_to_ui (aw);
2126 
2127  gnc_resume_gui_refresh ();
2128 
2129  gtk_widget_show_all (aw->dialog);
2130  if (xaccAccountGetSplitsSize (account) != 0)
2131  gtk_widget_hide (aw->opening_balance_page);
2132 
2133  parent_acct = gnc_account_get_parent (account);
2134  if (parent_acct == NULL)
2135  parent_acct = account; // must be at the root
2136 
2137  gtk_tree_view_collapse_all (aw->parent_tree);
2138  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(
2139  aw->parent_tree),
2140  parent_acct);
2141 
2142  gnc_account_window_set_name (aw);
2143 
2144  gnc_window_adjust_for_screen (GTK_WINDOW(aw->dialog));
2145 
2146  aw->component_id = gnc_register_gui_component (DIALOG_EDIT_ACCOUNT_CM_CLASS,
2147  refresh_handler,
2148  close_handler, aw);
2149 
2150  gnc_gui_component_set_session (aw->component_id, gnc_get_current_session ());
2151  gnc_gui_component_watch_entity_type (aw->component_id,
2152  GNC_ID_ACCOUNT,
2153  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
2154 
2155  gtk_window_present (GTK_WINDOW(aw->dialog));
2156 }
2157 
2158 void
2159 gnc_ui_new_account_with_types_and_commodity (GtkWindow *parent, QofBook *book, GList *valid_types,
2160  gnc_commodity *default_commodity)
2161 {
2162  gnc_ui_new_account_window_internal (parent, book, NULL, NULL,
2163  valid_types, default_commodity, FALSE);
2164 }
2165 
2166 /*
2167  * opens up a window to create a new account
2168  *
2169  * Args: book - containing book for the new account
2170  * parent_acct - The initial parent for the new account (optional)
2171  */
2172 void
2173 gnc_ui_new_account_window (GtkWindow *parent, QofBook *book,
2174  Account *parent_acct)
2175 {
2176  g_return_if_fail(book != NULL);
2177  if (parent_acct && book)
2178  g_return_if_fail(gnc_account_get_book (parent_acct) == book);
2179 
2180  gnc_ui_new_account_window_internal (parent, book, parent_acct, NULL, NULL,
2181  NULL, FALSE);
2182 }
2183 
2184 /************************************************************
2185  * Callbacks for a non-Modal Dialog *
2186  ************************************************************/
2187 
2188 /*
2189  * register a callback that gets called when the account has changed
2190  * so significantly that you need to destroy yourself. In particular
2191  * this is used by the ledger display to destroy ledgers when the
2192  * account type has changed.
2193  */
2194 void
2195 gnc_ui_register_account_destroy_callback (void (*cb)(Account *))
2196 {
2197  if (!cb)
2198  return;
2199 
2200  if (g_list_index (ac_destroy_cb_list, cb) == -1)
2201  ac_destroy_cb_list = g_list_append (ac_destroy_cb_list, cb);
2202 
2203  return;
2204 }
2205 
2206 /**************************************************/
2207 
2208 static void
2209 gnc_account_renumber_update_examples (RenumberDialog *data)
2210 {
2211  gchar *str;
2212  gint interval;
2213  gint digits;
2214  unsigned int num_digits = 1;
2215 
2216  g_return_if_fail (data->num_children > 0);
2217 
2218  const gchar *prefix = gtk_entry_get_text (GTK_ENTRY(data->prefix));
2219  interval = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(data->interval));
2220  digits = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(data->digits));
2221 
2222  if (interval <= 0)
2223  interval = 10;
2224 
2225  num_digits = (unsigned int)log10((double)(data->num_children * interval)) + 1;
2226 
2227  if (digits <= num_digits)
2228  {
2229  g_signal_handlers_block_by_func (GTK_SPIN_BUTTON(data->digits),
2230  (gpointer)gnc_account_renumber_digits_changed_cb,
2231  data);
2232  gtk_spin_button_set_value (GTK_SPIN_BUTTON(data->digits), num_digits);
2233  g_signal_handlers_unblock_by_func (GTK_SPIN_BUTTON(data->digits),
2234  (gpointer)gnc_account_renumber_digits_changed_cb,
2235  data);
2236  }
2237  else
2238  num_digits = digits;
2239 
2240  if (prefix && *prefix)
2241  str = g_strdup_printf ("%s-%0*d", prefix, num_digits, interval);
2242  else
2243  str = g_strdup_printf ("%0*d", num_digits, interval);
2244 
2245  gtk_label_set_text (GTK_LABEL(data->example1), str);
2246  g_free (str);
2247 
2248  if (prefix && *prefix)
2249  str = g_strdup_printf ("%s-%0*d", prefix, num_digits,
2250  interval * data->num_children);
2251  else
2252  str = g_strdup_printf ("%0*d", num_digits,
2253  interval * data->num_children);
2254 
2255  gtk_label_set_text (GTK_LABEL(data->example2), str);
2256 
2257  g_free (str);
2258 }
2259 
2260 void
2261 gnc_account_renumber_prefix_changed_cb (GtkEditable *editable,
2262  RenumberDialog *data)
2263 {
2264  gnc_account_renumber_update_examples (data);
2265 }
2266 
2267 void
2268 gnc_account_renumber_interval_changed_cb (GtkSpinButton *spinbutton,
2269  RenumberDialog *data)
2270 {
2271  gnc_account_renumber_update_examples (data);
2272 }
2273 
2274 void
2275 gnc_account_renumber_digits_changed_cb (GtkSpinButton *spinbutton,
2276  RenumberDialog *data)
2277 {
2278  gnc_account_renumber_update_examples (data);
2279 }
2280 
2281 void
2282 gnc_account_renumber_response_cb (GtkDialog *dialog,
2283  gint response,
2284  RenumberDialog *data)
2285 {
2286  if (response == GTK_RESPONSE_OK)
2287  {
2288  GList *children = gnc_account_get_children_sorted (data->parent);
2289  GList *tmp;
2290  gint interval;
2291  unsigned int num_digits, i;
2292 
2293  gtk_widget_hide (data->dialog);
2294 
2295  if (children == NULL)
2296  {
2297  PWARN("Can't renumber children of an account with no children!");
2298  g_free (data);
2299  return;
2300  }
2301  const gchar *prefix = gtk_entry_get_text (GTK_ENTRY(data->prefix));
2302  interval = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(data->interval));
2303  num_digits = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(data->digits));
2304 
2305  gnc_set_busy_cursor (NULL, TRUE);
2306  for (tmp = children, i = 1; tmp; tmp = g_list_next (tmp), i += 1)
2307  {
2308  gchar *str;
2309  if (prefix && *prefix)
2310  str = g_strdup_printf ("%s-%0*d", prefix,
2311  num_digits, interval * i);
2312  else
2313  str = g_strdup_printf ("%0*d", num_digits, interval * i);
2314 
2315  xaccAccountSetCode (tmp->data, str);
2316  g_free (str);
2317  }
2318  gnc_unset_busy_cursor (NULL);
2319  g_list_free (children);
2320  }
2321  gtk_widget_destroy (data->dialog);
2322  g_free (data);
2323 }
2324 
2325 void
2326 gnc_account_renumber_create_dialog (GtkWidget *window, Account *account)
2327 {
2328  RenumberDialog *data;
2329  GtkBuilder *builder;
2330  GtkWidget *widget;
2331  gchar *string, *fullname;
2332 
2333  /* This is a safety check; the menu item calling this dialog
2334  * should be disabled if the account has no children.
2335  */
2336  g_return_if_fail (gnc_account_n_children (account) > 0);
2337 
2338  data = g_new (RenumberDialog, 1);
2339  data->parent = account;
2340  data->num_children = gnc_account_n_children (account);
2341 
2342  builder = gtk_builder_new ();
2343  gnc_builder_add_from_file (builder, "dialog-account.glade", "interval_adjustment");
2344  gnc_builder_add_from_file (builder, "dialog-account.glade", "digit_spin_adjustment");
2345  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_renumber_dialog");
2346  data->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_renumber_dialog"));
2347  gtk_window_set_transient_for (GTK_WINDOW(data->dialog), GTK_WINDOW(window));
2348 
2349  g_object_set_data_full (G_OBJECT(data->dialog), "builder", builder,
2350  g_object_unref);
2351 
2352  widget = GTK_WIDGET(gtk_builder_get_object (builder, "header_label"));
2353  fullname = gnc_account_get_full_name (account);
2354  string = g_strdup_printf (_("Renumber the immediate sub-accounts of '%s'?"),
2355  fullname);
2356  gtk_label_set_text (GTK_LABEL(widget), string);
2357  g_free (string);
2358  g_free (fullname);
2359 
2360  data->prefix = GTK_WIDGET(gtk_builder_get_object (builder, "prefix_entry"));
2361  data->interval = GTK_WIDGET(gtk_builder_get_object (builder, "interval_spin"));
2362  data->digits = GTK_WIDGET(gtk_builder_get_object (builder, "digit_spin"));
2363  data->example1 = GTK_WIDGET(gtk_builder_get_object (builder, "example1_label"));
2364  data->example2 = GTK_WIDGET(gtk_builder_get_object (builder, "example2_label"));
2365 
2366  gtk_entry_set_text (GTK_ENTRY(data->prefix), xaccAccountGetCode (account));
2367  gnc_account_renumber_update_examples (data);
2368 
2369  gtk_builder_connect_signals (builder, data);
2370 
2371  gtk_widget_show_all (data->dialog);
2372 }
2373 
2374 static void
2375 default_color_button_cb (GtkButton *button, gpointer user_data)
2376 {
2377  GdkRGBA color;
2378 
2379  if (gdk_rgba_parse (&color, DEFAULT_COLOR))
2380  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(user_data), &color);
2381 }
2382 
2383 static void
2384 update_account_color (Account *acc, const gchar *old_color, const gchar *new_color, gboolean replace)
2385 {
2386  PINFO("Account is '%s', old_color is '%s', new_color is '%s', replace is %d",
2387  xaccAccountGetName (acc), old_color, new_color, replace);
2388 
2389  // have a new color, update if we can
2390  if (new_color)
2391  {
2392  if (!old_color || replace)
2393  {
2394  // check to see if the color is different from old one
2395  if (g_strcmp0 (new_color, old_color) != 0)
2396  xaccAccountSetColor (acc, new_color);
2397  }
2398  }
2399  else // change from a color to default one, remove color entry if we can
2400  {
2401  if (old_color && replace)
2402  xaccAccountSetColor (acc, ""); // remove entry
2403  }
2404 }
2405 
2406 static void
2407 enable_box_cb (GtkToggleButton *toggle_button, gpointer user_data)
2408 {
2409  gboolean sensitive = FALSE;
2410 
2411  if (gtk_toggle_button_get_active (toggle_button))
2412  sensitive = TRUE;
2413 
2414  gtk_widget_set_sensitive (GTK_WIDGET(user_data), sensitive);
2415 }
2416 
2417 void
2418 gnc_account_cascade_properties_dialog (GtkWidget *window, Account *account)
2419 {
2420  GtkWidget *dialog;
2421  GtkBuilder *builder;
2422  GtkWidget *label;
2423  GtkWidget *color_button, *over_write, *color_button_default;
2424  GtkWidget *enable_color, *enable_placeholder, *enable_hidden;
2425  GtkWidget *color_box, *placeholder_box, *hidden_box;
2426  GtkWidget *placeholder_button, *hidden_button;
2427 
2428  gchar *string, *fullname;
2429  const char *color_string;
2430  gchar *old_color_string = NULL;
2431  GdkRGBA color;
2432  gint response;
2433 
2434  // check if we actually do have sub accounts
2435  g_return_if_fail (gnc_account_n_children (account) > 0);
2436 
2437  builder = gtk_builder_new ();
2438  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_cascade_dialog");
2439  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_cascade_dialog"));
2440  gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(window));
2441 
2442  // Color section
2443  enable_color = GTK_WIDGET(gtk_builder_get_object (builder, "enable_cascade_color"));
2444  color_box = GTK_WIDGET(gtk_builder_get_object (builder, "color_box"));
2445 
2446  label = GTK_WIDGET(gtk_builder_get_object (builder, "color_label"));
2447  over_write = GTK_WIDGET(gtk_builder_get_object (builder, "replace_check"));
2448  color_button = GTK_WIDGET(gtk_builder_get_object (builder, "color_button"));
2449  color_button_default = GTK_WIDGET(gtk_builder_get_object (builder, "color_button_default"));
2450 
2451  gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER(color_button), FALSE);
2452 
2453  g_signal_connect (G_OBJECT(enable_color), "toggled",
2454  G_CALLBACK(enable_box_cb), (gpointer)color_box);
2455 
2456  g_signal_connect (G_OBJECT(color_button_default), "clicked",
2457  G_CALLBACK(default_color_button_cb), (gpointer)color_button);
2458 
2459  fullname = gnc_account_get_full_name (account);
2460  string = g_strdup_printf (_( "Set the account color for account '%s' "
2461  "including all sub-accounts to the selected color"),
2462  fullname);
2463  gtk_label_set_text (GTK_LABEL(label), string);
2464  g_free (string);
2465 
2466  color_string = xaccAccountGetColor (account); // get existing account color
2467 
2468  if (!color_string)
2469  color_string = DEFAULT_COLOR;
2470  else
2471  old_color_string = g_strdup (color_string); // save the old color string
2472 
2473  if (!gdk_rgba_parse (&color, color_string))
2474  gdk_rgba_parse (&color, DEFAULT_COLOR);
2475 
2476  // set the color chooser to account color
2477  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(color_button), &color);
2478 
2479  // Placeholder section
2480  enable_placeholder = GTK_WIDGET(gtk_builder_get_object (builder, "enable_cascade_placeholder"));
2481  placeholder_box = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_box"));
2482  label = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_label"));
2483  placeholder_button = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_check_button"));
2484  g_signal_connect (G_OBJECT(enable_placeholder), "toggled",
2485  G_CALLBACK(enable_box_cb), (gpointer)placeholder_box);
2486 
2487  string = g_strdup_printf (_( "Set the account placeholder value for account '%s' "
2488  "including all sub-accounts"),
2489  fullname);
2490  gtk_label_set_text (GTK_LABEL(label), string);
2491  g_free (string);
2492 
2493  // Hidden section
2494  enable_hidden = GTK_WIDGET(gtk_builder_get_object (builder, "enable_cascade_hidden"));
2495  hidden_box = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_box"));
2496  label = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_label"));
2497  hidden_button = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_check_button"));
2498  g_signal_connect (G_OBJECT(enable_hidden), "toggled",
2499  G_CALLBACK(enable_box_cb), (gpointer)hidden_box);
2500 
2501  string = g_strdup_printf (_( "Set the account hidden value for account '%s' "
2502  "including all sub-accounts"),
2503  fullname);
2504  gtk_label_set_text (GTK_LABEL(label), string);
2505  g_free (string);
2506  g_free (fullname);
2507 
2508  /* default to cancel */
2509  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
2510 
2511  gtk_builder_connect_signals (builder, dialog);
2512  g_object_unref (G_OBJECT(builder));
2513 
2514  gtk_widget_show_all (dialog);
2515 
2516  response = gtk_dialog_run (GTK_DIALOG(dialog));
2517 
2518  if (response == GTK_RESPONSE_OK)
2519  {
2520  GList *accounts = gnc_account_get_descendants (account);
2521  GdkRGBA new_color;
2522  gchar *new_color_string = NULL;
2523  gboolean color_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(enable_color));
2524  gboolean placeholder_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(enable_placeholder));
2525  gboolean hidden_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(enable_hidden));
2526  gboolean replace = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(over_write));
2527  gboolean placeholder = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(placeholder_button));
2528  gboolean hidden = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(hidden_button));
2529 
2530  // Update Account Colors
2531  if (color_active)
2532  {
2533  gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(color_button), &new_color);
2534  new_color_string = gdk_rgba_to_string (&new_color);
2535 
2536  if (g_strcmp0 (new_color_string, DEFAULT_COLOR) == 0)
2537  {
2538  g_free (new_color_string);
2539  new_color_string = NULL;
2540  }
2541 
2542  // check/update selected account
2543  update_account_color (account, old_color_string, new_color_string, replace);
2544  }
2545 
2546  // Update Account Placeholder value
2547  if (placeholder_active)
2548  xaccAccountSetPlaceholder (account, placeholder);
2549 
2550  // Update Account Hidden value
2551  if (hidden_active)
2552  xaccAccountSetHidden (account, hidden);
2553 
2554  // Update SubAccounts
2555  if (accounts)
2556  {
2557  for (GList *acct = accounts; acct; acct = g_list_next(acct))
2558  {
2559  // Update SubAccount Colors
2560  if (color_active)
2561  {
2562  const char *string = xaccAccountGetColor (acct->data);
2563  update_account_color (acct->data, string, new_color_string, replace);
2564  }
2565  // Update SubAccount PlaceHolder
2566  if (placeholder_active)
2567  xaccAccountSetPlaceholder (acct->data, placeholder);
2568  // Update SubAccount Hidden
2569  if (hidden_active)
2570  xaccAccountSetHidden (acct->data, hidden);
2571  }
2572  }
2573  g_list_free (accounts);
2574  g_free (new_color_string);
2575  }
2576  if (old_color_string)
2577  g_free (old_color_string);
2578 
2579  gtk_widget_destroy (dialog);
2580 }
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Set the account&#39;s type.
Definition: Account.cpp:2418
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition: Account.cpp:2902
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:381
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
gboolean xaccAccountGetAutoInterest(const Account *acc)
Get the "auto interest" flag for an account.
Definition: Account.cpp:4126
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
Dialog box should only allow selection of a currency.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
Account * gnc_ui_new_accounts_from_name_window(GtkWindow *parent, const char *name)
Display a modal window for creating a new account.
guint32 xaccAccountTypesCompatibleWith(GNCAccountType type)
Return the bitmask of account types compatible with a given type.
Definition: Account.cpp:4318
void gnc_account_append_child(Account *new_parent, Account *child)
This function will remove from the child account any pre-existing parent relationship, and will then add the account as a child of the new parent.
Definition: Account.cpp:2803
gboolean gnc_account_is_root(const Account *account)
This routine indicates whether the specified account is the root node of an account tree...
Definition: Account.cpp:2920
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
int xaccAccountGetCommoditySCUi(const Account *acc)
Return the &#39;internal&#39; SCU setting.
Definition: Account.cpp:2705
gboolean xaccAccountGetNonStdSCU(const Account *acc)
Return boolean, indicating whether this account uses a non-standard SCU.
Definition: Account.cpp:2741
This file contains the functions to present a gui to the user for creating a new account or editing a...
void xaccAccountSetNotes(Account *acc, const char *str)
Set the account&#39;s notes.
Definition: Account.cpp:2629
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
utility functions for the GnuCash UI
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3233
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2712
const char * xaccAccountGetCode(const Account *acc)
Get the account&#39;s accounting code.
Definition: Account.cpp:3302
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
STRUCTS.
void xaccAccountSetTaxRelated(Account *acc, gboolean tax_related)
DOCUMENT ME!
Definition: Account.cpp:3992
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
Mutual Fund accounts will typically be shown in registers which show three columns: price...
Definition: Account.h:125
void gnc_ui_new_account_with_types_and_commodity(GtkWindow *parent, QofBook *book, GList *valid_types, gnc_commodity *default_commodity)
Display a window for creating a new account.
void xaccAccountSetCode(Account *acc, const char *str)
Set the account&#39;s accounting code.
Definition: Account.cpp:2459
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
guint32 xaccAccountTypesValid(void)
Returns the bitmask of the account type enums that are valid.
Definition: Account.cpp:4423
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccAccountSetHigherBalanceLimit(Account *acc, gnc_numeric balance)
Set the higher balance limit for the account.
Definition: Account.cpp:4684
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void gnc_ui_edit_account_window(GtkWindow *parent, Account *account)
Display a window for editing the attributes of an existing account.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
Account used to record multiple commodity transactions.
Definition: Account.h:155
Dialog box should allow selection of anything.
gboolean xaccAccountGetLowerBalanceLimit(const Account *acc, gnc_numeric *balance)
Get the lower balance limit for the account.
Definition: Account.cpp:4677
void xaccAccountDestroy(Account *acc)
The xaccAccountDestroy() routine can be used to get rid of an account.
Definition: Account.cpp:1588
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
Stock accounts will typically be shown in registers which show three columns: price, number of shares, and value.
Definition: Account.h:122
const char * xaccAccountGetColor(const Account *acc)
Get the account&#39;s color.
Definition: Account.cpp:3316
#define xaccAccountGetGUID(X)
Definition: Account.h:252
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
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:3271
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition: Account.cpp:4076
gboolean xaccAccountTypesCompatible(GNCAccountType parent_type, GNCAccountType child_type)
Return TRUE if accounts of type parent_type can have accounts of type child_type as children...
Definition: Account.cpp:4405
void xaccAccountClearLowerBalanceLimit(Account *acc)
Clear the lower balance limit for the account.
Definition: Account.cpp:4702
void xaccAccountSetColor(Account *acc, const char *str)
Set the account&#39;s Color.
Definition: Account.cpp:2587
void xaccAccountSetIncludeSubAccountBalances(Account *acc, gboolean inc_sub)
Set whether to include balances of sub accounts.
Definition: Account.cpp:4714
GtkTreeView implementation for gnucash account tree.
void gnc_gnome_help(GtkWindow *parent, const char *file_name, const char *anchor)
Launch the systems default help browser, gnome&#39;s yelp for linux, and open to a given link within a gi...
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
Definition: guid.cpp:204
GtkTreeView * gnc_tree_view_account_new_with_root(Account *root, gboolean show_root)
Create a new account tree view.
Dialog box should allow selection of anything but a currency and should include the "ALL" namespace t...
const char * xaccAccountGetDescription(const Account *acc)
Get the account&#39;s description.
Definition: Account.cpp:3309
GtkTreeView * gnc_tree_view_account_new(gboolean show_root)
Create a new account tree view.
GList * gnc_account_get_children_sorted(const Account *account)
This routine returns a GList of all children accounts of the specified account, ordered by xaccAccoun...
Definition: Account.cpp:2936
The bank account type denotes a savings or checking account held at a bank.
Definition: Account.h:107
dialog_commodity_mode
The dialog commodity types are used to determine what commodity namespaces the currency dialog will p...
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Retrieve the full name for the specified commodity.
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name, but uses fully-qualified names using the given separator.
Definition: Account.cpp:3129
Account * gnc_tree_view_account_get_account_from_path(GncTreeViewAccount *view, GtkTreePath *s_path)
This function returns the account associated with the specified path.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
void xaccAccountSetIsOpeningBalance(Account *acc, gboolean val)
Set the "opening-balance" flag for an account.
Definition: Account.cpp:4104
gboolean xaccAccountGetTaxRelated(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:3986
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
gint gnc_account_n_children(const Account *account)
Return the number of children of the specified account.
Definition: Account.cpp:2943
All type declarations for the whole Gnucash engine.
void gnc_ui_new_account_window(GtkWindow *parent, QofBook *book, Account *parent_acct)
Display a window for creating a new account.
The currency account type indicates that the account is a currency trading account.
Definition: Account.h:129
void xaccAccountSetCommoditySCU(Account *acc, int scu)
Set the SCU for the account.
Definition: Account.cpp:2689
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Definition: Account.h:101
gboolean xaccAccountGetHidden(const Account *acc)
Get the "hidden" flag for an account.
Definition: Account.cpp:4141
GtkTreeModel implementation to display account types in a GtkTreeView.
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition: Account.cpp:3010
void xaccAccountSetAutoInterest(Account *acc, gboolean val)
Set the "auto interest" flag for an account.
Definition: Account.cpp:4132
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
gboolean xaccAccountGetIsOpeningBalance(const Account *acc)
Get the "opening-balance" flag for an account.
Definition: Account.cpp:4094
guint32 xaccParentAccountTypesCompatibleWith(GNCAccountType type)
Return the bitmask of parent account types compatible with a given type.
Definition: Account.cpp:4358
gboolean xaccAccountGetIncludeSubAccountBalances(const Account *acc)
Get whether to include balances of sub accounts.
Definition: Account.cpp:4708
void gnc_tree_view_account_set_selected_account(GncTreeViewAccount *view, Account *account)
This function selects an account in the account tree view.
Not a type.
Definition: Account.h:104
GList * gnc_account_get_children(const Account *account)
This routine returns a GList of all children accounts of the specified account.
Definition: Account.cpp:2927
Account * gnc_ui_new_accounts_from_name_with_defaults(GtkWindow *parent, const char *name, GList *valid_types, const gnc_commodity *default_commodity, Account *parent_acct)
Display a modal window for creating a new account.
void xaccAccountSetHidden(Account *acc, gboolean val)
Set the "hidden" flag for an account.
Definition: Account.cpp:4147
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1473
gboolean xaccAccountHasAncestor(const Account *acc, const Account *ancestor)
Returns true if the account is &#39;ancestor&#39; or has &#39;ancestor&#39; as an ancestor.
Definition: Account.cpp:4175
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3367
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1052
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4070
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...
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void xaccAccountSetLowerBalanceLimit(Account *acc, gnc_numeric balance)
Set the lower balance limit for the account.
Definition: Account.cpp:4690
gboolean xaccAccountGetHigherBalanceLimit(const Account *acc, gnc_numeric *balance)
Get the higher balance limit for the account.
Definition: Account.cpp:4670
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition: Account.cpp:1269
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:260
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void xaccAccountSetDescription(Account *acc, const char *str)
Set the account&#39;s description.
Definition: Account.cpp:2478
void xaccAccountSetNonStdSCU(Account *acc, gboolean flag)
Set the flag indicating that this account uses a non-standard SCU.
Definition: Account.cpp:2725
Account * gnc_account_lookup_by_opening_balance(Account *account, gnc_commodity *commodity)
Find the opening balance account for the currency.
Definition: Account.cpp:3087
void xaccAccountClearHigherBalanceLimit(Account *acc)
Clear the higher balance limit for the account.
Definition: Account.cpp:4696
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3255
Equity account is used to balance the balance sheet.
Definition: Account.h:146
const char * xaccAccountGetTypeStr(GNCAccountType type)
The xaccAccountGetTypeStr() routine returns a string suitable for use in the GUI/Interface.
Definition: Account.cpp:4308
Not a type.
Definition: Account.h:105
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1514
void xaccAccountSetName(Account *acc, const char *str)
Set the account&#39;s name.
Definition: Account.cpp:2439
"select" and "new" commodity windows
Commodity handling public routines.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
const gchar * gnc_get_account_separator_string(void)
Returns the account separation character chosen by the user.
Definition: Account.cpp:205
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account&#39;s commodity.
Definition: Account.cpp:2645
const char * xaccAccountGetNotes(const Account *acc)
Get the account&#39;s notes.
Definition: Account.cpp:3340
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2048