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  string = gdk_rgba_to_string (&color);
509 
510  if (g_strcmp0 (string, DEFAULT_COLOR) == 0)
511  string = NULL;
512 
513  old_string = xaccAccountGetColor (account);
514 
515  if (!string && old_string)
516  xaccAccountSetColor (account, ""); // remove entry
517  else
518  {
519  if (g_strcmp0 (string, old_string) != 0)
520  xaccAccountSetColor (account, string); // update entry
521  }
522 
523  commodity = (gnc_commodity *)
524  gnc_general_select_get_selected (GNC_GENERAL_SELECT(aw->commodity_edit));
525  if (commodity &&
526  !gnc_commodity_equiv (commodity, xaccAccountGetCommodity (account)))
527  {
528  xaccAccountSetCommodity (account, commodity);
529  old_scu = 0;
530  }
531  else
532  {
533  old_scu = xaccAccountGetCommoditySCU (account);
534  }
535 
536  index = gtk_combo_box_get_active (GTK_COMBO_BOX(aw->account_scu));
537  nonstd = (index != 0);
538  if (nonstd != xaccAccountGetNonStdSCU (account))
539  xaccAccountSetNonStdSCU (account, nonstd);
540  new_scu = (nonstd ? pow (10, index - 1) : gnc_commodity_get_fraction (commodity));
541  if (old_scu != new_scu)
542  xaccAccountSetCommoditySCU (account, new_scu);
543 
544  string = gtk_entry_get_text (GTK_ENTRY(aw->code_entry));
545  old_string = xaccAccountGetCode (account);
546  if (g_strcmp0 (string, old_string) != 0)
547  xaccAccountSetCode (account, string);
548 
549  gtk_text_buffer_get_start_iter (aw->notes_text_buffer, &start);
550  gtk_text_buffer_get_end_iter (aw->notes_text_buffer, &end);
551  char *new_string = gtk_text_buffer_get_text (aw->notes_text_buffer, &start, &end, FALSE);
552  old_string = xaccAccountGetNotes (account);
553  if (g_strcmp0 (new_string, old_string))
554  xaccAccountSetNotes (account, new_string);
555  g_free (new_string);
556 
557  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->opening_balance_button));
558  if (xaccAccountGetIsOpeningBalance (account) != flag)
559  xaccAccountSetIsOpeningBalance (account, flag);
560 
561  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->tax_related_button));
562  if (xaccAccountGetTaxRelated (account) != flag)
563  xaccAccountSetTaxRelated (account, flag);
564 
565  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->placeholder_button));
566  if (xaccAccountGetPlaceholder (account) != flag)
567  xaccAccountSetPlaceholder (account, flag);
568 
569  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->hidden_button));
570  if (xaccAccountGetHidden (account) != flag)
571  xaccAccountSetHidden (account, flag);
572 
573  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->auto_interest_button));
574  if (xaccAccountGetAutoInterest (account) != flag)
575  xaccAccountSetAutoInterest (account, flag);
576 
577  parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
578 
579  if (parent_account == NULL)
580  parent_account = gnc_book_get_root_account (aw->book);
581  if (parent_account != gnc_account_get_parent (account))
582  gnc_account_append_child (parent_account, account);
583 
584  flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(
585  aw->include_balance_sub_accts));
586 
588 
589  higher_balance_limit_valid = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(
590  aw->higher_balance_limit_edit),
591  &balance_limit, TRUE, NULL);
592 
593  if (higher_balance_limit_valid == 0)
594  {
595  if (aw->balance_is_reversed)
596  {
597  balance_limit = gnc_numeric_neg (balance_limit);
598  xaccAccountSetLowerBalanceLimit (account, balance_limit);
599  }
600  else
601  xaccAccountSetHigherBalanceLimit (account, balance_limit);
602  }
603 
604  if (higher_balance_limit_valid == -1)
605  {
606  if (aw->balance_is_reversed)
608  else
610  }
611 
612  lower_balance_limit_valid = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(
613  aw->lower_balance_limit_edit),
614  &balance_limit, TRUE, NULL);
615 
616  if (lower_balance_limit_valid == 0)
617  {
618  if (aw->balance_is_reversed)
619  {
620  balance_limit = gnc_numeric_neg (balance_limit);
621  xaccAccountSetHigherBalanceLimit (account, balance_limit);
622  }
623  else
624  xaccAccountSetLowerBalanceLimit (account, balance_limit);
625  }
626 
627  if (lower_balance_limit_valid == -1)
628  {
629  if (aw->balance_is_reversed)
631  else
633  }
634 
635  if ((higher_balance_limit_valid == -1) && (lower_balance_limit_valid == -1))
637 
638  xaccAccountCommitEdit (account);
639 
640  balance = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT(aw->opening_balance_edit));
641 
642  if (gnc_numeric_zero_p (balance))
643  {
644  LEAVE("zero balance");
645  return;
646  }
647 
648  if (gnc_reverse_balance (account))
649  balance = gnc_numeric_neg (balance);
650 
651  date = gnc_date_edit_get_date (GNC_DATE_EDIT(aw->opening_balance_date_edit));
652 
653  use_equity = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(aw->opening_equity_radio));
654 
655  if (use_equity)
656  {
657  if (!gnc_account_create_opening_balance (account, balance, date, aw->book))
658  {
659  const char *message = _("Could not create opening balance.");
660  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
661  }
662  }
663  else
664  {
665  Account *transfer = NULL;
666 
667  transfer = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->transfer_tree));
668  if (!transfer)
669  {
670  LEAVE("no transfer account");
671  return;
672  }
673 
674  gnc_account_create_transfer_balance (aw->book, account, transfer, balance, date);
675  }
676  LEAVE(" ");
677 }
678 
679 static void
680 set_children_types (Account *account, GNCAccountType type)
681 {
682  GList *children, *iter;
683 
684  children = gnc_account_get_children (account);
685  if (children == NULL)
686  return;
687 
688  for (iter = children; iter; iter = iter->next)
689  {
690  account = iter->data;
691  if (type == xaccAccountGetType (account))
692  continue;
693 
694  /* Just refreshing won't work. */
695  aw_call_destroy_callbacks (account);
696 
697  xaccAccountBeginEdit (account);
698  xaccAccountSetType (account, type);
699  xaccAccountCommitEdit (account);
700 
701  set_children_types (account, type);
702  }
703  g_list_free (children);
704 }
705 
706 static void
707 make_children_compatible (AccountWindow *aw)
708 {
709  Account *account;
710 
711  g_return_if_fail (aw);
712 
713  if (aw->dialog_type == NEW_ACCOUNT)
714  return;
715 
716  account = aw_get_account (aw);
717  g_return_if_fail (account);
718 
719  if (xaccAccountTypesCompatible (aw->type, xaccAccountGetType (account)))
720  return;
721 
722  set_children_types (account, aw->type);
723 }
724 
725 static void
726 gnc_finish_ok (AccountWindow *aw)
727 {
728  ENTER("aw %p", aw);
729  gnc_suspend_gui_refresh ();
730 
731  /* make the account changes */
732  make_children_compatible (aw);
733  gnc_ui_to_account (aw);
734 
735  gnc_resume_gui_refresh ();
736 
737  /* do it all again, if needed */
738  if ((aw->dialog_type == NEW_ACCOUNT) && aw->next_name && *aw->next_name)
739  {
740  gnc_commodity *commodity;
741  Account *parent;
742  Account *account;
743 
744  /* Drop the old parent_tree so we can update it with an up to date one */
745  gtk_container_remove (GTK_CONTAINER(aw->parent_scroll), GTK_WIDGET(aw->parent_tree));
746  aw->parent_tree = gnc_tree_view_account_new (TRUE);
747  gtk_container_add (GTK_CONTAINER(aw->parent_scroll), GTK_WIDGET(aw->parent_tree));
748  gtk_widget_show (GTK_WIDGET(aw->parent_tree));
749 
750  aw_connect_selection_changed (aw);
751  gnc_suspend_gui_refresh ();
752 
753  parent = aw_get_account (aw);
754  account = xaccMallocAccount (aw->book);
755  aw->account = *xaccAccountGetGUID (account);
756  aw->type = xaccAccountGetType (parent);
757 
758  xaccAccountSetName (account, *aw->next_name);
759  aw->next_name++;
760 
761  gnc_account_to_ui (aw);
762 
763  gnc_account_window_set_name (aw);
764 
765  commodity = xaccAccountGetCommodity (parent);
766  gnc_general_select_set_selected (GNC_GENERAL_SELECT(aw->commodity_edit),
767  commodity);
768  gnc_account_commodity_from_type (aw, FALSE);
769 
770  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(
771  aw->parent_tree),
772  parent);
773 
774  gnc_resume_gui_refresh ();
775  LEAVE("1");
776  return;
777  }
778 
779  /* save for posterity */
780  aw->created_account = aw_get_account (aw);
781 
782  /* so it doesn't get freed on close */
783  aw->account = *guid_null ();
784 
785  gnc_close_gui_component (aw->component_id);
786  LEAVE("2");
787 }
788 
789 static void
790 add_children_to_expander (GObject *object, GParamSpec *param_spec, gpointer data)
791 {
792  GtkExpander *expander = GTK_EXPANDER(object);
793  Account *account = data;
794  GtkWidget *scrolled_window;
795  GtkTreeView *view;
796 
797  if (gtk_expander_get_expanded (expander) &&
798  !gtk_bin_get_child (GTK_BIN(expander)))
799  {
800  view = gnc_tree_view_account_new_with_root (account, FALSE);
801 
802  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
803  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolled_window),
804  GTK_POLICY_AUTOMATIC,
805  GTK_POLICY_AUTOMATIC);
806  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolled_window),
807  GTK_SHADOW_IN);
808  gtk_container_add (GTK_CONTAINER(scrolled_window), GTK_WIDGET(view));
809 
810  gtk_container_add (GTK_CONTAINER(expander), scrolled_window);
811  gtk_widget_set_vexpand (GTK_WIDGET(scrolled_window), TRUE);
812  gtk_widget_show_all (scrolled_window);
813  }
814 }
815 
816 /* Check whether there are children needing a type adjustment because of a
817  a change to an incompatible type (like after some reparenting) and let the
818  user decide whether he wants that */
819 static gboolean
820 verify_children_compatible (AccountWindow *aw)
821 {
822  Account *account;
823  GtkWidget *dialog, *vbox, *hbox, *label, *expander;
824  gchar *str;
825  gboolean result;
826 
827  if (aw == NULL)
828  return FALSE;
829 
830  account = aw_get_account (aw);
831  if (!account)
832  return FALSE;
833 
834  if (xaccAccountTypesCompatible (aw->type, xaccAccountGetType (account)))
835  return TRUE;
836 
837  if (gnc_account_n_children (account) == 0)
838  return TRUE;
839 
840  dialog = gtk_dialog_new_with_buttons ("",
841  GTK_WINDOW(aw->dialog),
842  GTK_DIALOG_DESTROY_WITH_PARENT |
843  GTK_DIALOG_MODAL,
844  _("_Cancel"), GTK_RESPONSE_CANCEL,
845  _("_OK"), GTK_RESPONSE_OK,
846  NULL);
847 
848  gtk_window_set_skip_taskbar_hint (GTK_WINDOW(dialog), TRUE);
849 
850  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
851  gtk_box_set_homogeneous (GTK_BOX(hbox), FALSE);
852  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
853  gtk_box_set_homogeneous (GTK_BOX(vbox), FALSE);
854 
855  gtk_box_pack_start (GTK_BOX(hbox),
856  gtk_image_new_from_icon_name ("dialog-information",
857  GTK_ICON_SIZE_DIALOG), FALSE, FALSE, 0);
858 
859  /* primary label */
860  label = gtk_label_new (_("Give the children the same type?"));
861  gtk_label_set_line_wrap (GTK_LABEL(label), TRUE);
862  gtk_label_set_selectable (GTK_LABEL(label), TRUE);
863  gnc_label_set_alignment (label, 0.0, 0.0);
864 
865  /* make label large */
866  gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-title");
867 
868  gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
869 
870  /* secondary label */
871  str = g_strdup_printf (_("The children of the edited account have to be "
872  "changed to type \"%s\" to make them compatible."),
873  xaccAccountGetTypeStr (aw->type));
874  label = gtk_label_new (str);
875  g_free (str);
876  gtk_label_set_line_wrap (GTK_LABEL(label), TRUE);
877  gtk_label_set_selectable (GTK_LABEL(label), TRUE);
878  gnc_label_set_alignment (label, 0.0, 0.0);
879  gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
880 
881  /* children */
882  expander = gtk_expander_new_with_mnemonic (_("_Show children accounts"));
883  gtk_expander_set_spacing (GTK_EXPANDER(expander), 6);
884  g_signal_connect (G_OBJECT(expander), "notify::expanded",
885  G_CALLBACK(add_children_to_expander), account);
886  gtk_box_pack_start (GTK_BOX(vbox), expander, TRUE, TRUE, 0);
887 
888  gtk_box_pack_start (GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
889 
890  gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area (GTK_DIALOG(dialog))),
891  hbox, TRUE, TRUE, 0);
892 
893  /* spacings */
894  gtk_container_set_border_width (GTK_CONTAINER(dialog), 5);
895  gtk_container_set_border_width (GTK_CONTAINER(hbox), 5);
896  gtk_box_set_spacing (GTK_BOX(gtk_dialog_get_content_area (GTK_DIALOG(dialog))), 14);
897 
898  gtk_widget_show_all (hbox);
899 
900  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
901 
902  result = (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_OK);
903 
904  gtk_widget_destroy (dialog);
905 
906  return result;
907 }
908 
909 static gboolean
910 gnc_filter_parent_accounts (Account *account, gpointer data)
911 {
912  AccountWindow *aw = data;
913  Account *aw_account = aw_get_account (aw);
914 
915  if (account == NULL)
916  return FALSE;
917 
918  if (aw_account == NULL)
919  return FALSE;
920 
921  if (gnc_account_is_root (account))
922  return TRUE;
923 
924  if (account == aw_account)
925  return FALSE;
926 
927  if (xaccAccountHasAncestor (account, aw_account))
928  return FALSE;
929 
930  return TRUE;
931 }
932 
933 static gboolean
934 gnc_common_ok (AccountWindow *aw)
935 {
936  Account *root, *account, *parent;
937  gnc_commodity * commodity;
938  gchar *fullname, *fullname_parent;
939  const gchar *name, *separator;
940  gboolean higher_limit_valid;
941  gnc_numeric higher_balance_limit;
942  gboolean lower_limit_valid;
943  gnc_numeric lower_balance_limit;
944 
945  ENTER("aw %p", aw);
946  root = gnc_book_get_root_account (aw->book);
947 
948  separator = gnc_get_account_separator_string ();
949 
950  /* check for valid name */
951  name = gtk_entry_get_text (GTK_ENTRY(aw->name_entry));
952  if (g_strcmp0 (name, "") == 0)
953  {
954  const char *message = _("The account must be given a name.");
955  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
956  LEAVE("bad name");
957  return FALSE;
958  }
959 
960  /* check for a duplicate name */
962  (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
963  if (parent == NULL)
964  {
965  account = gnc_account_lookup_by_full_name (root, name);
966  }
967  else
968  {
969  fullname_parent = gnc_account_get_full_name (parent);
970  fullname = g_strconcat (fullname_parent, separator, name, NULL);
971 
972  account = gnc_account_lookup_by_full_name (root, fullname);
973 
974  g_free (fullname_parent);
975  g_free (fullname);
976  }
977  if ((account != NULL) &&
978  !guid_equal (&aw->account, xaccAccountGetGUID (account)))
979  {
980  const char *message = _("There is already an account with that name.");
981  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
982  LEAVE("duplicate name");
983  return FALSE;
984  }
985 
986  /* Parent check, probably not needed, but be safe */
987  if (!gnc_filter_parent_accounts (parent, aw))
988  {
989  const char *message = _("You must choose a valid parent account.");
990  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
991  LEAVE("invalid parent");
992  return FALSE;
993  }
994 
995  /* check for valid type */
996  if (aw->type == ACCT_TYPE_INVALID)
997  {
998  const char *message = _("You must select an account type.");
999  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1000  LEAVE("invalid type");
1001  return FALSE;
1002  }
1003 
1004  /* check whether the types of child and parent are compatible */
1005  if (!xaccAccountTypesCompatible (xaccAccountGetType (parent), aw->type))
1006  {
1007  const char *message = _("The selected account type is incompatible with "
1008  "the one of the selected parent.");
1009  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1010  LEAVE("incompatible types");
1011  return FALSE;
1012  }
1013 
1014  /* check for commodity */
1015  commodity = (gnc_commodity *)
1016  gnc_general_select_get_selected (GNC_GENERAL_SELECT(aw->commodity_edit));
1017  if (!commodity)
1018  {
1019  const char *message = _("You must choose a commodity.");
1020  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1021  LEAVE("invalid commodity");
1022  return FALSE;
1023  }
1024 
1025  /* check for higher balance limit greater than lower */
1026  higher_limit_valid = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit),
1027  &higher_balance_limit, TRUE, NULL);
1028 
1029  lower_limit_valid = gnc_amount_edit_expr_is_valid (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit),
1030  &lower_balance_limit, TRUE, NULL);
1031 
1032  if ((lower_limit_valid == 0) && (higher_limit_valid == 0))
1033  {
1034  gint compare = gnc_numeric_compare (higher_balance_limit,
1035  lower_balance_limit);
1036 
1037  if ((compare == 0) && (!gnc_numeric_zero_p (higher_balance_limit)))
1038  {
1039  const char *message = _("Balance limits must be different unless they are both zero.");
1040  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1041  LEAVE("invalid balance limit, both the same but not zero");
1042  return FALSE;
1043  }
1044  else if (compare == -1)
1045  {
1046  const char *message = _("The lower balance limit must be less than the higher limit.");
1047  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1048  LEAVE("invalid balance limit, lower limit not less than upper");
1049  return FALSE;
1050  }
1051  }
1052 
1053  LEAVE("passed");
1054  return TRUE;
1055 }
1056 
1057 static void
1058 gnc_edit_account_ok (AccountWindow *aw)
1059 {
1060  Account *account;
1061 
1062  ENTER("aw %p", aw);
1063 
1064  account = aw_get_account (aw);
1065  if (!account)
1066  {
1067  LEAVE(" ");
1068  return;
1069  }
1070 
1071  if (!gnc_common_ok (aw))
1072  {
1073  LEAVE(" ");
1074  return;
1075  }
1076 
1077  if (!verify_children_compatible (aw))
1078  {
1079  LEAVE(" ");
1080  return;
1081  }
1082 
1083  gnc_finish_ok (aw);
1084  LEAVE(" ");
1085 }
1086 
1087 static void
1088 gnc_new_account_ok (AccountWindow *aw)
1089 {
1090  gnc_numeric balance;
1091 
1092  ENTER("aw %p", aw);
1093 
1094  if (!gnc_common_ok (aw))
1095  {
1096  LEAVE(" ");
1097  return;
1098  }
1099 
1100  if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(aw->opening_balance_edit), NULL))
1101  {
1102  const char *message = _("You must enter a valid opening balance "
1103  "or leave it blank.");
1104  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1105  LEAVE(" ");
1106  return;
1107  }
1108 
1109  balance = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT(aw->opening_balance_edit));
1110 
1111  if (!gnc_numeric_zero_p (balance))
1112  {
1113  gboolean use_equity;
1114 
1115  use_equity = gtk_toggle_button_get_active
1116  (GTK_TOGGLE_BUTTON(aw->opening_equity_radio));
1117 
1118  if (!use_equity)
1119  {
1120  Account *transfer = NULL;
1121 
1122  transfer = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(
1123  aw->transfer_tree));
1124  if (!transfer)
1125  {
1126  const char *message = _("You must select a transfer account or choose"
1127  " the opening balances equity account.");
1128  gnc_error_dialog (GTK_WINDOW(aw->dialog), "%s", message);
1129  LEAVE(" ");
1130  return;
1131  }
1132  }
1133  }
1134 
1135  gnc_finish_ok (aw);
1136  LEAVE(" ");
1137 }
1138 
1139 static void
1140 gnc_account_window_response_cb (GtkDialog *dialog,
1141  gint response,
1142  gpointer data)
1143 {
1144  AccountWindow *aw = data;
1145 
1146  ENTER("dialog %p, response %d, aw %p", dialog, response, aw);
1147  switch (response)
1148  {
1149  case GTK_RESPONSE_OK:
1150  switch (aw->dialog_type)
1151  {
1152  case NEW_ACCOUNT:
1153  DEBUG("new acct dialog, OK");
1154  gnc_new_account_ok (aw);
1155  break;
1156  case EDIT_ACCOUNT:
1157  DEBUG("edit acct dialog, OK");
1158  gnc_edit_account_ok (aw);
1159  break;
1160  default:
1161  g_assert_not_reached ();
1162  return;
1163  }
1164  break;
1165  case GTK_RESPONSE_HELP:
1166  switch (aw->dialog_type)
1167  {
1168  case NEW_ACCOUNT:
1169  DEBUG("new acct dialog, HELP");
1170  gnc_gnome_help (GTK_WINDOW(dialog), DF_MANUAL, DL_ACC);
1171  break;
1172  case EDIT_ACCOUNT:
1173  DEBUG("edit acct dialog, HELP");
1174  gnc_gnome_help (GTK_WINDOW(dialog), DF_MANUAL, DL_ACCEDIT);
1175  break;
1176  default:
1177  g_assert_not_reached ();
1178  return;
1179  }
1180  break;
1181  case GTK_RESPONSE_CANCEL:
1182  default:
1183  DEBUG("CANCEL");
1184  gnc_close_gui_component (aw->component_id);
1185  break;
1186  }
1187  LEAVE(" ");
1188 }
1189 
1190 void
1191 gnc_account_window_destroy_cb (GtkWidget *object, gpointer data)
1192 {
1193  AccountWindow *aw = data;
1194  Account *account;
1195 
1196  ENTER("object %p, aw %p", object, aw);
1197  account = aw_get_account (aw);
1198 
1199  aw_clear_selection_handler (aw);
1200  gnc_suspend_gui_refresh ();
1201 
1202  switch (aw->dialog_type)
1203  {
1204  case NEW_ACCOUNT:
1205  if (account != NULL)
1206  {
1207  xaccAccountBeginEdit (account);
1208  xaccAccountDestroy (account);
1209  aw->account = *guid_null ();
1210  }
1211 
1212  DEBUG ("account add window destroyed\n");
1213  break;
1214 
1215  case EDIT_ACCOUNT:
1216  break;
1217 
1218  default:
1219  PERR ("unexpected dialog type\n");
1220  gnc_resume_gui_refresh ();
1221  LEAVE(" ");
1222  return;
1223  }
1224 
1225  gnc_unregister_gui_component (aw->component_id);
1226 
1227  gnc_resume_gui_refresh ();
1228 
1229  if (aw->subaccount_names)
1230  {
1231  g_strfreev (aw->subaccount_names);
1232  aw->subaccount_names = NULL;
1233  aw->next_name = NULL;
1234  }
1235 
1236  g_free (aw);
1237  LEAVE(" ");
1238 }
1239 
1240 static void
1241 gnc_account_parent_changed_cb (GObject *selection, gpointer data)
1242 {
1243  AccountWindow *aw = data;
1244  Account *parent_account;
1245  guint32 types, old_types;
1246  GtkTreeModelSort *s_model;
1247  GtkTreeModel *type_model;
1248  gboolean combo_set = FALSE;
1249 
1250  g_return_if_fail (aw);
1251  g_return_if_fail (selection == aw->selection);
1252 
1254  GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
1255  if (!parent_account)
1256  return;
1257 
1258  if (gnc_account_is_root (parent_account))
1259  {
1260  types = aw->valid_types;
1261  }
1262  else
1263  {
1264  types = aw->valid_types &
1266  }
1267  s_model = GTK_TREE_MODEL_SORT(gtk_combo_box_get_model (GTK_COMBO_BOX(aw->type_combo)));
1268  type_model = gtk_tree_model_sort_get_model (s_model);
1269  if (!type_model)
1270  return;
1271 
1272  if (aw->type != aw->preferred_account_type &&
1273  (types & (1 << aw->preferred_account_type)) != 0)
1274  {
1275  /* we can change back to the preferred account type */
1276  aw->type = aw->preferred_account_type;
1277  combo_set = TRUE;
1278  }
1279  else if ((types & (1 << aw->type)) == 0)
1280  {
1281  /* our type is invalid now */
1282  aw->type = ACCT_TYPE_INVALID;
1283  }
1284  else
1285  {
1286  /* no type change, but maybe list of valid types changed */
1287  old_types = gnc_tree_model_account_types_get_mask (type_model);
1288  if (old_types != types)
1289  combo_set = TRUE;
1290  }
1291 
1292  gnc_tree_model_account_types_set_mask (type_model, types);
1293 
1294  if (combo_set)
1295  gnc_tree_model_account_types_set_active_combo (GTK_COMBO_BOX(aw->type_combo),
1296  1 << aw->type);
1297 
1298  gnc_account_window_set_name (aw);
1299 }
1300 
1301 static void
1302 set_auto_interest_box(AccountWindow *aw)
1303 {
1304  Account* account = aw_get_account (aw);
1305  gboolean type_ok = account_type_has_auto_interest_xfer (aw->type);
1306  gboolean pref_set = xaccAccountGetAutoInterest (account);
1307  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(aw->auto_interest_button),
1308  type_ok && pref_set);
1309  gtk_widget_set_sensitive (GTK_WIDGET(aw->auto_interest_button), type_ok);
1310 }
1311 
1312 static void
1313 gnc_account_type_combo_changed_cb (GtkComboBox *combo, gpointer data)
1314 {
1315  AccountWindow *aw = data;
1316  gboolean sensitive;
1317  GNCAccountType type_id;
1318 
1319  g_return_if_fail (aw != NULL);
1320 
1321  sensitive = FALSE;
1322 
1323  type_id = gnc_tree_model_account_types_get_active_combo (combo);
1324 
1325  if (type_id == ACCT_TYPE_NONE)
1326  {
1327  aw->type = ACCT_TYPE_INVALID;
1328  }
1329  else
1330  {
1331  aw->type = type_id;
1332  aw->preferred_account_type = type_id;
1333 
1334  gnc_account_commodity_from_type (aw, TRUE);
1335 
1336  sensitive = (aw->type != ACCT_TYPE_EQUITY &&
1337  aw->type != ACCT_TYPE_CURRENCY &&
1338  aw->type != ACCT_TYPE_STOCK &&
1339  aw->type != ACCT_TYPE_MUTUAL &&
1340  aw->type != ACCT_TYPE_TRADING);
1341  }
1342 
1343  gtk_widget_set_sensitive (aw->opening_balance_page, sensitive);
1344 
1345  if (!sensitive)
1346  {
1347  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(aw->opening_balance_edit),
1348  gnc_numeric_zero ());
1349  }
1350  set_auto_interest_box (aw);
1351 }
1352 
1353 static void
1354 gnc_account_type_view_create (AccountWindow *aw, guint32 compat_types)
1355 {
1356  GtkTreeModel *fmodel, *smodel;
1357  GtkCellRenderer *renderer;
1358 
1359  aw->valid_types &= compat_types;
1360  if (aw->valid_types == 0)
1361  {
1362  /* no type restrictions, choose aw->type */
1363  aw->valid_types = compat_types | (1 << aw->type);
1364  aw->preferred_account_type = aw->type;
1365  }
1366  else if ((aw->valid_types & (1 << aw->type)) != 0)
1367  {
1368  /* aw->type is valid */
1369  aw->preferred_account_type = aw->type;
1370  }
1371  else if ((aw->valid_types & (1 << last_used_account_type)) != 0)
1372  {
1373  /* last used account type is valid */
1374  aw->type = last_used_account_type;
1375  aw->preferred_account_type = last_used_account_type;
1376  }
1377  else
1378  {
1379  /* choose first valid account type */
1380  int i;
1381  aw->preferred_account_type = aw->type;
1382  aw->type = ACCT_TYPE_INVALID;
1383  for (i = 0; i < 32; i++)
1384  if ((aw->valid_types & (1 << i)) != 0)
1385  {
1386  aw->type = i;
1387  break;
1388  }
1389  }
1390 
1391  fmodel = gnc_tree_model_account_types_filter_using_mask (aw->valid_types);
1392 
1393  smodel = gtk_tree_model_sort_new_with_model (fmodel);
1394 
1395  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(smodel),
1396  GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME,
1397  GTK_SORT_ASCENDING);
1398 
1399  gtk_combo_box_set_model (GTK_COMBO_BOX(aw->type_combo), smodel);
1400 
1401  renderer = gtk_cell_renderer_text_new ();
1402  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(aw->type_combo), renderer, TRUE);
1403  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(aw->type_combo), renderer,
1404  "text", GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME, NULL);
1405 
1406  g_signal_connect (G_OBJECT(aw->type_combo), "changed",
1407  G_CALLBACK(gnc_account_type_combo_changed_cb), aw);
1408 
1409  g_object_unref (G_OBJECT(fmodel));
1410 
1411  gnc_tree_model_account_types_set_active_combo (GTK_COMBO_BOX(aw->type_combo),
1412  1 << aw->type);
1413 }
1414 
1415 void
1416 gnc_account_name_insert_text_cb (GtkWidget *entry,
1417  const gchar *text,
1418  gint length,
1419  gint *position,
1420  gpointer data)
1421 {
1422  GtkEditable *editable = GTK_EDITABLE(entry);
1423  const gchar *separator = NULL;
1424  gchar **strsplit;
1425 
1426  separator = gnc_get_account_separator_string ();
1427  strsplit = g_strsplit (text, separator, 0);
1428  if (strsplit[1] != NULL)
1429  {
1430  gchar *result = g_strjoinv (NULL, strsplit);
1431  g_signal_handlers_block_by_func (G_OBJECT(editable),
1432  G_CALLBACK(gnc_account_name_insert_text_cb),
1433  data);
1434  gtk_editable_insert_text (editable, result, g_utf8_strlen (result, -1), position);
1435  g_signal_handlers_unblock_by_func (G_OBJECT(editable),
1436  G_CALLBACK(gnc_account_name_insert_text_cb),
1437  data);
1438  g_signal_stop_emission_by_name (G_OBJECT(editable), "insert_text");
1439  g_free (result);
1440  }
1441 
1442  g_strfreev (strsplit);
1443 }
1444 
1445 void
1446 gnc_account_name_changed_cb (GtkWidget *widget, gpointer data)
1447 {
1448  AccountWindow *aw = data;
1449 
1450  gnc_account_window_set_name (aw);
1451 }
1452 
1453 void
1454 gnc_account_color_default_cb (GtkWidget *widget, gpointer data)
1455 {
1456  GdkRGBA color;
1457  AccountWindow *aw = data;
1458 
1459  gdk_rgba_parse (&color, DEFAULT_COLOR);
1460  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(aw->color_entry_button), &color);
1461 
1462 }
1463 
1464 static void
1465 commodity_changed_cb (GNCGeneralSelect *gsl, gpointer data)
1466 {
1467  AccountWindow *aw = data;
1468  gnc_commodity *currency;
1469  GtkTreeSelection *selection;
1470  Account *account = aw_get_account (aw);
1471 
1472  currency = (gnc_commodity *) gnc_general_select_get_selected (gsl);
1473  if (!currency)
1474  return;
1475 
1476  if (xaccAccountGetIsOpeningBalance (account))
1477  {
1478  Account *ob_account = gnc_account_lookup_by_opening_balance (gnc_book_get_root_account (aw->book), currency);
1479  if (ob_account != account)
1480  {
1481  gchar *dialog_msg = _("An account with opening balance already exists for the desired currency.");
1482  gchar *dialog_title = _("Cannot change currency");
1483  GtkWidget *dialog = gtk_message_dialog_new (gnc_ui_get_main_window (NULL),
1484  0,
1485  GTK_MESSAGE_ERROR,
1486  GTK_BUTTONS_OK,
1487  "%s", dialog_title);
1488  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
1489  "%s", dialog_msg);
1490  gtk_dialog_run (GTK_DIALOG(dialog));
1491  gtk_widget_destroy (dialog);
1492  g_signal_handlers_block_by_func (gsl, commodity_changed_cb, data);
1493  gnc_general_select_set_selected (gsl, xaccAccountGetCommodity (account));
1494  g_signal_handlers_unblock_by_func (gsl, commodity_changed_cb, data);
1495  return;
1496  }
1497  }
1498 
1499  gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT(aw->opening_balance_edit),
1500  gnc_commodity_get_fraction (currency));
1501  gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT(aw->opening_balance_edit),
1502  gnc_commodity_print_info (currency, FALSE));
1503 
1504  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(aw->transfer_tree));
1505  gtk_tree_selection_unselect_all (selection);
1506  gnc_account_opening_balance_button_update (aw, currency);
1507 }
1508 
1509 static gboolean
1510 account_commodity_filter (GtkTreeSelection *selection,
1511  GtkTreeModel *unused_model,
1512  GtkTreePath *s_path,
1513  gboolean path_currently_selected,
1514  gpointer user_data)
1515 {
1516  gnc_commodity *commodity;
1517  AccountWindow *aw;
1518  Account *account;
1519 
1520  g_return_val_if_fail (GTK_IS_TREE_SELECTION(selection), FALSE);
1521 
1522  aw = user_data;
1523 
1524  if (path_currently_selected)
1525  {
1526  /* already selected, don't waste time. */
1527  return TRUE;
1528  }
1529 
1530  account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(aw->transfer_tree), s_path);
1531  if (!account)
1532  {
1533  return FALSE;
1534  }
1535 
1536  commodity = (gnc_commodity *)
1537  gnc_general_select_get_selected (GNC_GENERAL_SELECT(aw->commodity_edit));
1538 
1539  return gnc_commodity_equiv (xaccAccountGetCommodity (account), commodity);
1540 }
1541 
1542 void
1543 opening_equity_cb (GtkWidget *w, gpointer data)
1544 {
1545  AccountWindow *aw = data;
1546  gboolean use_equity;
1547 
1548  use_equity = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1549 
1550  gtk_widget_set_sensitive (aw->transfer_account_scroll, !use_equity);
1551 }
1552 
1553 /********************************************************************\
1554  * gnc_account_window_create *
1555  * creates a window to create a new account. *
1556  * *
1557  * Args: parent - the parent window dialog *
1558  * Args: aw - the information structure for this window *
1559  * Return: the created window *
1560  \*******************************************************************/
1561 static void
1562 gnc_account_window_create (GtkWindow *parent, AccountWindow *aw)
1563 {
1564  GtkWidget *amount;
1565  GtkWidget *date_edit;
1566  GObject *awo;
1567  GtkWidget *box;
1568  GtkWidget *label;
1569  GtkBuilder *builder;
1570  GtkTreeSelection *selection;
1571  const gchar *tt = _("This Account contains Transactions.\nChanging this option is not possible.");
1572  guint32 compat_types = xaccAccountTypesValid ();
1573 
1574  ENTER("aw %p, modal %d", aw, aw->modal);
1575  builder = gtk_builder_new ();
1576  gnc_builder_add_from_file (builder, "dialog-account.glade", "fraction_liststore");
1577  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_dialog");
1578 
1579  aw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_dialog"));
1580  awo = G_OBJECT(aw->dialog);
1581 
1582  if (parent)
1583  gtk_window_set_transient_for (GTK_WINDOW(aw->dialog), parent);
1584 
1585  // Set the name for this dialog so it can be easily manipulated with css
1586  gtk_widget_set_name (GTK_WIDGET(aw->dialog), "gnc-id-account");
1587  gnc_widget_style_context_add_class (GTK_WIDGET(aw->dialog), "gnc-class-account");
1588 
1589 
1590  g_object_set_data (awo, "dialog_info", aw);
1591 
1592  if (!aw->modal)
1593  g_signal_connect (awo, "response",
1594  G_CALLBACK(gnc_account_window_response_cb), aw);
1595  else
1596  gtk_window_set_modal (GTK_WINDOW(aw->dialog), TRUE);
1597 
1598  aw->notebook = GTK_WIDGET(gtk_builder_get_object (builder, "account_notebook"));
1599  aw->name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "name_entry"));
1600  aw->description_entry = GTK_WIDGET(gtk_builder_get_object (builder, "description_entry"));
1601  aw->color_entry_button = GTK_WIDGET(gtk_builder_get_object (builder, "color_entry_button"));
1602  aw->color_default_button = GTK_WIDGET(gtk_builder_get_object (builder, "color_default_button"));
1603  aw->code_entry = GTK_WIDGET(gtk_builder_get_object (builder, "code_entry"));
1604  aw->notes_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(GTK_WIDGET(
1605  gtk_builder_get_object (builder,
1606  "notes_text"))));
1607 
1608  box = GTK_WIDGET(gtk_builder_get_object (builder, "commodity_hbox"));
1609  aw->commodity_edit = gnc_general_select_new (GNC_GENERAL_SELECT_TYPE_SELECT,
1610  gnc_commodity_edit_get_string,
1611  gnc_commodity_edit_new_select,
1612  &aw->commodity_mode);
1613 
1614  gtk_box_pack_start (GTK_BOX(box), aw->commodity_edit, TRUE, TRUE, 0);
1615  gtk_widget_show (aw->commodity_edit);
1616  // If the account has transactions, prevent changes by displaying a label and tooltip
1617  if (xaccAccountGetSplitsSize (aw_get_account (aw)) != 0)
1618  {
1619  gtk_widget_set_tooltip_text (aw->commodity_edit, tt);
1620  gtk_widget_set_sensitive (aw->commodity_edit, FALSE);
1621  }
1622 
1623  label = GTK_WIDGET(gtk_builder_get_object (builder, "security_label"));
1624  gnc_general_select_make_mnemonic_target (GNC_GENERAL_SELECT(aw->commodity_edit), label);
1625 
1626  g_signal_connect (G_OBJECT(aw->commodity_edit), "changed",
1627  G_CALLBACK(commodity_changed_cb), aw);
1628 
1629  aw->account_scu = GTK_WIDGET(gtk_builder_get_object (builder, "account_scu"));
1630 
1631  aw->parent_scroll = GTK_WIDGET(gtk_builder_get_object (builder, "parent_scroll"));
1632 
1633  aw->parent_tree = gnc_tree_view_account_new (TRUE);
1634  gtk_container_add (GTK_CONTAINER(aw->parent_scroll), GTK_WIDGET(aw->parent_tree));
1635  gtk_widget_show (GTK_WIDGET(aw->parent_tree));
1636  aw_connect_selection_changed (aw);
1637 
1638  aw->balance_grid = GTK_WIDGET(gtk_builder_get_object (builder, "balance_grid"));
1639 
1640  box = GTK_WIDGET(gtk_builder_get_object (builder, "higher_balance_limit_hbox"));
1641  aw->higher_balance_limit_edit = gnc_amount_edit_new ();
1642  gtk_box_pack_start (GTK_BOX(box), aw->higher_balance_limit_edit, TRUE, TRUE, 0);
1643  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit), TRUE);
1644  gnc_amount_edit_set_validate_on_change (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit), TRUE);
1645  gnc_amount_edit_show_warning_symbol (GNC_AMOUNT_EDIT(aw->higher_balance_limit_edit), TRUE);
1646  gtk_widget_show (aw->higher_balance_limit_edit);
1647 
1648  box = GTK_WIDGET(gtk_builder_get_object (builder, "lower_balance_limit_hbox"));
1649  aw->lower_balance_limit_edit = gnc_amount_edit_new ();
1650  gtk_box_pack_start (GTK_BOX(box), aw->lower_balance_limit_edit, TRUE, TRUE, 0);
1651  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit), TRUE);
1652  gnc_amount_edit_set_validate_on_change (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit), TRUE);
1653  gnc_amount_edit_show_warning_symbol (GNC_AMOUNT_EDIT(aw->lower_balance_limit_edit), TRUE);
1654  gtk_widget_show (aw->lower_balance_limit_edit);
1655 
1656  aw->include_balance_sub_accts = GTK_WIDGET(gtk_builder_get_object (builder, "include_sub_accts_tb"));
1657 
1658  aw->more_properties_page =
1659  gtk_notebook_get_nth_page (GTK_NOTEBOOK(aw->notebook), 1);
1660 
1661  aw->opening_balance_button = GTK_WIDGET(gtk_builder_get_object (builder, "opening_balance_button"));
1662  aw->tax_related_button = GTK_WIDGET(gtk_builder_get_object (builder, "tax_related_button"));
1663  aw->placeholder_button = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_button"));
1664  aw->hidden_button = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_button"));
1665  aw->auto_interest_button = GTK_WIDGET(gtk_builder_get_object (builder, "auto_interest_button"));
1666  set_auto_interest_box (aw);
1667 
1668 
1669  box = GTK_WIDGET(gtk_builder_get_object (builder, "opening_balance_box"));
1670  amount = gnc_amount_edit_new ();
1671  aw->opening_balance_edit = amount;
1672  gtk_box_pack_start (GTK_BOX(box), amount, TRUE, TRUE, 0);
1673  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT(amount), TRUE);
1674  gtk_widget_show (amount);
1675 
1676  label = GTK_WIDGET(gtk_builder_get_object (builder, "balance_label"));
1677  gnc_amount_edit_make_mnemonic_target (GNC_AMOUNT_EDIT(amount), label);
1678 
1679  box = GTK_WIDGET(gtk_builder_get_object (builder, "opening_balance_date_box"));
1680  label = GTK_WIDGET(gtk_builder_get_object (builder, "date_label"));
1681  date_edit = gnc_date_edit_new (gnc_time (NULL), 0, 0);
1682  gnc_date_make_mnemonic_target (GNC_DATE_EDIT(date_edit), label);
1683  aw->opening_balance_date_edit = date_edit;
1684  gtk_box_pack_start (GTK_BOX(box), date_edit, TRUE, TRUE, 0);
1685  gtk_widget_show (date_edit);
1686 
1687  aw->opening_balance_page =
1688  gtk_notebook_get_nth_page (GTK_NOTEBOOK(aw->notebook), 2);
1689 
1690  aw->opening_equity_radio = GTK_WIDGET(gtk_builder_get_object (builder,
1691  "opening_equity_radio"));
1692 
1693  box = GTK_WIDGET(gtk_builder_get_object (builder, "transfer_account_scroll"));
1694  aw->transfer_account_scroll = box;
1695 
1696  aw->transfer_tree = GTK_WIDGET(gnc_tree_view_account_new (FALSE));
1697  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(aw->transfer_tree));
1698  gtk_tree_selection_set_select_function (selection, account_commodity_filter, aw, NULL);
1699 
1700  gtk_container_add (GTK_CONTAINER(box), GTK_WIDGET(aw->transfer_tree));
1701  gtk_widget_show (GTK_WIDGET(aw->transfer_tree));
1702 
1703  label = GTK_WIDGET(gtk_builder_get_object (builder, "parent_label"));
1704  gtk_label_set_mnemonic_widget (GTK_LABEL(label), GTK_WIDGET(aw->parent_tree));
1705 
1706  /* This goes at the end so the select callback has good data. */
1707  aw->type_combo = GTK_WIDGET(gtk_builder_get_object (builder, "account_type_combo"));
1708 
1709  // If the account has transactions, reduce the available account types
1710  // to change the current account type to based on the following
1711  // restrictions:
1712  // - the new account type should not force a change of commodity
1713  // - the old/new type is not an immutable type. Types are marked as
1714  // immutable if gnucash depends on details that would be lost/missing
1715  // if changing from/to such a type. At the time of this writing the
1716  // immutable types are AR, AP and trading types.
1717  if (xaccAccountGetSplitsSize (aw_get_account (aw)) != 0)
1718  {
1719  GNCAccountType atype = xaccAccountGetType (aw_get_account (aw));
1720  compat_types = xaccAccountTypesCompatibleWith (atype);
1721  if (!compat_types)
1722  compat_types = xaccAccountTypesValid ();
1723  }
1724  gnc_account_type_view_create (aw, compat_types);
1725 
1726  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(aw->dialog), parent);
1727 
1728  gtk_widget_grab_focus (GTK_WIDGET(aw->name_entry));
1729 
1730  gtk_builder_connect_signals (builder, aw);
1731  g_object_unref (G_OBJECT(builder));
1732 
1733  LEAVE(" ");
1734 }
1735 
1736 static char *
1737 get_ui_fullname (AccountWindow *aw)
1738 {
1739  Account *parent_account;
1740  char *fullname;
1741  const gchar *name;
1742 
1743  name = gtk_entry_get_text (GTK_ENTRY(aw->name_entry));
1744  if (!name || *name == '\0')
1745  name = _("<No name>");
1746 
1747  parent_account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
1748 
1749  if (parent_account && !gnc_account_is_root (parent_account))
1750  {
1751  char *parent_name = gnc_account_get_full_name (parent_account);
1752  const gchar *separator = gnc_get_account_separator_string ();
1753 
1754  fullname = g_strconcat (parent_name, separator, name, NULL);
1755  g_free (parent_name);
1756  }
1757  else
1758  fullname = g_strdup (name);
1759 
1760  return fullname;
1761 }
1762 
1763 static void
1764 gnc_account_window_set_name (AccountWindow *aw)
1765 {
1766  char *fullname;
1767  char *title;
1768 
1769  if (!aw || !aw->parent_tree)
1770  return;
1771 
1772  fullname = get_ui_fullname (aw);
1773 
1774  if (aw->dialog_type == EDIT_ACCOUNT)
1775  title = g_strconcat(_("Edit Account"), " - ", fullname, NULL);
1776  else if (aw->next_name && (g_strv_length (aw->next_name) > 0))
1777  {
1778  const char *format = _("(%d) New Accounts");
1779  char *prefix = g_strdup_printf (format,
1780  g_strv_length (aw->next_name) + 1);
1781 
1782  title = g_strconcat (prefix, " - ", fullname, " …", NULL);
1783  g_free (prefix);
1784  }
1785  else
1786  title = g_strconcat (_("New Account"), " - ", fullname, NULL);
1787 
1788  gtk_window_set_title (GTK_WINDOW(aw->dialog), title);
1789 
1790  g_free (fullname);
1791  g_free (title);
1792 }
1793 
1794 static void
1795 close_handler (gpointer user_data)
1796 {
1797  AccountWindow *aw = user_data;
1798 
1799  ENTER("aw %p, modal %d", aw, aw->modal);
1800  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(aw->dialog));
1801 
1802  gtk_widget_destroy (GTK_WIDGET(aw->dialog));
1803  LEAVE(" ");
1804 }
1805 
1806 /********************************************************************\
1807  * gnc_ui_refresh_account_window *
1808  * refreshes the edit window *
1809  * *
1810  * Args: aw - the account window to refresh *
1811  * Return: none *
1812 \********************************************************************/
1813 static void
1814 gnc_ui_refresh_account_window (AccountWindow *aw)
1815 {
1816  if (aw == NULL)
1817  return;
1818 
1819  /* gnc_account_tree_refresh (GNC_ACCOUNT_TREE(aw->parent_tree));*/
1820 
1821  gnc_account_window_set_name (aw);
1822 }
1823 
1824 static void
1825 refresh_handler (GHashTable *changes, gpointer user_data)
1826 {
1827  AccountWindow *aw = user_data;
1828  Account *account;
1829 
1830  account = aw_get_account (aw);
1831  if (!account)
1832  {
1833  gnc_close_gui_component (aw->component_id);
1834  return;
1835  }
1836 
1837  if (changes)
1838  {
1839  const EventInfo *info = gnc_gui_get_entity_events (changes, &aw->account);
1840  if (info && (info->event_mask & QOF_EVENT_DESTROY))
1841  {
1842  gnc_close_gui_component (aw->component_id);
1843  return;
1844  }
1845  }
1846  gnc_ui_refresh_account_window (aw);
1847 }
1848 
1849 static AccountWindow *
1850 gnc_ui_new_account_window_internal (GtkWindow *parent,
1851  QofBook *book,
1852  Account *base_account,
1853  gchar **subaccount_names,
1854  GList *valid_types,
1855  const gnc_commodity * default_commodity,
1856  gboolean modal)
1857 {
1858  const gnc_commodity *commodity, *parent_commodity;
1859  AccountWindow *aw;
1860  Account *account;
1861  GList *list;
1862 
1863  g_return_val_if_fail(book, NULL);
1864 
1865  aw = g_new0 (AccountWindow, 1);
1866 
1867  aw->book = book;
1868  aw->modal = modal;
1869  aw->dialog_type = NEW_ACCOUNT;
1870 
1871  aw->valid_types = 0;
1872  for (list = valid_types; list; list = list->next)
1873  aw->valid_types |= (1 << GPOINTER_TO_INT (list->data));
1874 
1875  account = xaccMallocAccount (book);
1876  aw->account = *xaccAccountGetGUID (account);
1877 
1878  if (base_account)
1879  {
1880  aw->type = xaccAccountGetType (base_account);
1881  parent_commodity = xaccAccountGetCommodity (base_account);
1882  }
1883  else
1884  {
1885  aw->type = last_used_account_type;
1886  parent_commodity = gnc_default_currency ();
1887  }
1888 
1889  gnc_suspend_gui_refresh ();
1890 
1891  if (subaccount_names && *subaccount_names)
1892  {
1893  xaccAccountSetName (account, subaccount_names[0]);
1894  aw->subaccount_names = subaccount_names;
1895  aw->next_name = subaccount_names + 1;
1896  }
1897 
1898  gnc_account_window_create (parent, aw);
1899  gnc_account_to_ui (aw);
1900 
1901  gnc_resume_gui_refresh ();
1902 
1903  if (default_commodity != NULL)
1904  {
1905  commodity = default_commodity;
1906  if ((aw->type == ACCT_TYPE_STOCK) || (aw->type == ACCT_TYPE_MUTUAL))
1907  {
1908  gtk_entry_set_text (GTK_ENTRY(aw->name_entry),
1909  (gpointer) gnc_commodity_get_mnemonic (commodity));
1910  gtk_entry_set_text (GTK_ENTRY(aw->description_entry),
1911  (gpointer) gnc_commodity_get_fullname (commodity));
1912  }
1913  }
1914  else if ((aw->type != ACCT_TYPE_STOCK) && (aw->type != ACCT_TYPE_MUTUAL))
1915  {
1916  commodity = parent_commodity;
1917  }
1918  else
1919  {
1920  commodity = NULL;
1921  }
1922  gnc_general_select_set_selected (GNC_GENERAL_SELECT(aw->commodity_edit),
1923  (gpointer) commodity);
1924  gnc_account_commodity_from_type (aw, FALSE);
1925 
1926  if (base_account == NULL)
1927  {
1928  base_account = gnc_book_get_root_account (book);
1929  }
1930 
1931  gtk_tree_view_collapse_all (aw->parent_tree);
1932  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(
1933  aw->parent_tree),
1934  base_account);
1935 
1936  gtk_widget_show (aw->dialog);
1937 
1938  gnc_window_adjust_for_screen (GTK_WINDOW(aw->dialog));
1939 
1940  gnc_account_window_set_name (aw);
1941 
1942  aw->component_id = gnc_register_gui_component (DIALOG_NEW_ACCOUNT_CM_CLASS,
1943  refresh_handler,
1944  modal ? NULL : close_handler,
1945  aw);
1946 
1947  gnc_gui_component_set_session (aw->component_id, gnc_get_current_session());
1948  gnc_gui_component_watch_entity_type (aw->component_id,
1949  GNC_ID_ACCOUNT,
1950  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
1951  return aw;
1952 }
1953 
1954 static gchar **
1955 gnc_split_account_name (QofBook *book, const char *in_name, Account **base_account)
1956 {
1957  Account *root, *account;
1958  gchar **names, **ptr, **out_names;
1959  GList *list, *node;
1960 
1961  root = gnc_book_get_root_account (book);
1962  list = gnc_account_get_children (root);
1963  names = g_strsplit (in_name, gnc_get_account_separator_string (), -1);
1964 
1965  for (ptr = names; *ptr; ptr++)
1966  {
1967  /* Stop if there are no children at the current level. */
1968  if (list == NULL)
1969  break;
1970 
1971  /* Look for the first name in the children. */
1972  for (node = list; node; node = g_list_next (node))
1973  {
1974  account = node->data;
1975 
1976  if (g_strcmp0 (xaccAccountGetName (account), *ptr) == 0)
1977  {
1978  /* We found an account. */
1979  *base_account = account;
1980  break;
1981  }
1982  }
1983 
1984  /* Was there a match? If no, stop the traversal. */
1985  if (node == NULL)
1986  break;
1987 
1988  g_list_free (list);
1989  list = gnc_account_get_children (account);
1990  }
1991 
1992  out_names = g_strdupv (ptr);
1993  g_strfreev (names);
1994  if (list)
1995  g_list_free (list);
1996  return out_names;
1997 }
1998 
1999 /************************************************************
2000  * Entry points for a Modal Dialog *
2001  ************************************************************/
2002 
2003 Account *
2004 gnc_ui_new_accounts_from_name_window (GtkWindow *parent, const char *name)
2005 {
2006  return gnc_ui_new_accounts_from_name_with_defaults (parent, name, NULL,
2007  NULL, NULL);
2008 }
2009 
2010 Account *
2012  const char *name,
2013  GList *valid_types,
2014  const gnc_commodity * default_commodity,
2015  Account * parent_acct)
2016 {
2017  QofBook *book;
2018  AccountWindow *aw;
2019  Account *base_account = NULL;
2020  Account *created_account = NULL;
2021  gchar ** subaccount_names;
2022  gint response;
2023  gboolean done = FALSE;
2024 
2025  ENTER("name %s, valid %p, commodity %p, account %p",
2026  name, valid_types, default_commodity, parent_acct);
2027  book = gnc_get_current_book ();
2028  if (!name || *name == '\0')
2029  {
2030  subaccount_names = NULL;
2031  base_account = NULL;
2032  }
2033  else
2034  subaccount_names = gnc_split_account_name (book, name, &base_account);
2035 
2036  if (parent_acct != NULL)
2037  {
2038  base_account = parent_acct;
2039  }
2040  aw = gnc_ui_new_account_window_internal (parent, book, base_account,
2041  subaccount_names,
2042  valid_types,
2043  default_commodity,
2044  TRUE);
2045 
2046  while (!done)
2047  {
2048  response = gtk_dialog_run (GTK_DIALOG(aw->dialog));
2049 
2050  /* This can destroy the dialog */
2051  gnc_account_window_response_cb (GTK_DIALOG(aw->dialog), response, (gpointer)aw);
2052 
2053  switch (response)
2054  {
2055  case GTK_RESPONSE_OK:
2056  created_account = aw->created_account;
2057  done = (created_account != NULL);
2058  break;
2059 
2060  case GTK_RESPONSE_HELP:
2061  done = FALSE;
2062  break;
2063 
2064  default:
2065  done = TRUE;
2066  break;
2067  }
2068  }
2069 
2070  close_handler (aw);
2071  LEAVE("created %s (%p)", xaccAccountGetName (created_account), created_account);
2072  return created_account;
2073 }
2074 
2075 /************************************************************
2076  * Entry points for a non-Modal Dialog *
2077  ************************************************************/
2078 
2079 static gboolean
2080 find_by_account (gpointer find_data, gpointer user_data)
2081 {
2082  Account *account = find_data;
2083  AccountWindow *aw = user_data;
2084 
2085  if (!aw)
2086  return FALSE;
2087 
2088  return guid_equal (&aw->account, xaccAccountGetGUID (account));
2089 }
2090 
2091 /*
2092  * opens up a window to edit an account
2093  *
2094  * Args: account - the account to edit
2095  * Return: EditAccountWindow object
2096  */
2097 void
2098 gnc_ui_edit_account_window (GtkWindow *parent, Account *account)
2099 {
2100  AccountWindow * aw;
2101  Account *parent_acct;
2102 
2103  if (account == NULL)
2104  return;
2105 
2106  aw = gnc_find_first_gui_component (DIALOG_EDIT_ACCOUNT_CM_CLASS,
2107  find_by_account, account);
2108  if (aw)
2109  {
2110  gtk_window_present (GTK_WINDOW(aw->dialog));
2111  return;
2112  }
2113 
2114  aw = g_new0 (AccountWindow, 1);
2115 
2116  aw->book = gnc_account_get_book (account);
2117  aw->modal = FALSE;
2118  aw->dialog_type = EDIT_ACCOUNT;
2119  aw->account = *xaccAccountGetGUID (account);
2120  aw->subaccount_names = NULL;
2121  aw->type = xaccAccountGetType (account);
2122 
2123  gnc_suspend_gui_refresh ();
2124 
2125  gnc_account_window_create (parent, aw);
2126  gnc_account_to_ui (aw);
2127 
2128  gnc_resume_gui_refresh ();
2129 
2130  gtk_widget_show_all (aw->dialog);
2131  if (xaccAccountGetSplitsSize (account) != 0)
2132  gtk_widget_hide (aw->opening_balance_page);
2133 
2134  parent_acct = gnc_account_get_parent (account);
2135  if (parent_acct == NULL)
2136  parent_acct = account; // must be at the root
2137 
2138  gtk_tree_view_collapse_all (aw->parent_tree);
2139  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(
2140  aw->parent_tree),
2141  parent_acct);
2142 
2143  gnc_account_window_set_name (aw);
2144 
2145  gnc_window_adjust_for_screen (GTK_WINDOW(aw->dialog));
2146 
2147  aw->component_id = gnc_register_gui_component (DIALOG_EDIT_ACCOUNT_CM_CLASS,
2148  refresh_handler,
2149  close_handler, aw);
2150 
2151  gnc_gui_component_set_session (aw->component_id, gnc_get_current_session ());
2152  gnc_gui_component_watch_entity_type (aw->component_id,
2153  GNC_ID_ACCOUNT,
2154  QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
2155 
2156  gtk_window_present (GTK_WINDOW(aw->dialog));
2157 }
2158 
2159 void
2160 gnc_ui_new_account_with_types_and_commodity (GtkWindow *parent, QofBook *book, GList *valid_types,
2161  gnc_commodity *default_commodity)
2162 {
2163  gnc_ui_new_account_window_internal (parent, book, NULL, NULL,
2164  valid_types, default_commodity, FALSE);
2165 }
2166 
2167 /*
2168  * opens up a window to create a new account
2169  *
2170  * Args: book - containing book for the new account
2171  * parent_acct - The initial parent for the new account (optional)
2172  */
2173 void
2174 gnc_ui_new_account_window (GtkWindow *parent, QofBook *book,
2175  Account *parent_acct)
2176 {
2177  g_return_if_fail(book != NULL);
2178  if (parent_acct && book)
2179  g_return_if_fail(gnc_account_get_book (parent_acct) == book);
2180 
2181  gnc_ui_new_account_window_internal (parent, book, parent_acct, NULL, NULL,
2182  NULL, FALSE);
2183 }
2184 
2185 /************************************************************
2186  * Callbacks for a non-Modal Dialog *
2187  ************************************************************/
2188 
2189 /*
2190  * register a callback that gets called when the account has changed
2191  * so significantly that you need to destroy yourself. In particular
2192  * this is used by the ledger display to destroy ledgers when the
2193  * account type has changed.
2194  */
2195 void
2196 gnc_ui_register_account_destroy_callback (void (*cb)(Account *))
2197 {
2198  if (!cb)
2199  return;
2200 
2201  if (g_list_index (ac_destroy_cb_list, cb) == -1)
2202  ac_destroy_cb_list = g_list_append (ac_destroy_cb_list, cb);
2203 
2204  return;
2205 }
2206 
2207 /**************************************************/
2208 
2209 static void
2210 gnc_account_renumber_update_examples (RenumberDialog *data)
2211 {
2212  gchar *str;
2213  gint interval;
2214  gint digits;
2215  unsigned int num_digits = 1;
2216 
2217  g_return_if_fail (data->num_children > 0);
2218 
2219  const gchar *prefix = gtk_entry_get_text (GTK_ENTRY(data->prefix));
2220  interval = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(data->interval));
2221  digits = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(data->digits));
2222 
2223  if (interval <= 0)
2224  interval = 10;
2225 
2226  num_digits = (unsigned int)log10((double)(data->num_children * interval)) + 1;
2227 
2228  if (digits <= num_digits)
2229  {
2230  g_signal_handlers_block_by_func (GTK_SPIN_BUTTON(data->digits),
2231  (gpointer)gnc_account_renumber_digits_changed_cb,
2232  data);
2233  gtk_spin_button_set_value (GTK_SPIN_BUTTON(data->digits), num_digits);
2234  g_signal_handlers_unblock_by_func (GTK_SPIN_BUTTON(data->digits),
2235  (gpointer)gnc_account_renumber_digits_changed_cb,
2236  data);
2237  }
2238  else
2239  num_digits = digits;
2240 
2241  if (prefix && *prefix)
2242  str = g_strdup_printf ("%s-%0*d", prefix, num_digits, interval);
2243  else
2244  str = g_strdup_printf ("%0*d", num_digits, interval);
2245 
2246  gtk_label_set_text (GTK_LABEL(data->example1), str);
2247  g_free (str);
2248 
2249  if (prefix && *prefix)
2250  str = g_strdup_printf ("%s-%0*d", prefix, num_digits,
2251  interval * data->num_children);
2252  else
2253  str = g_strdup_printf ("%0*d", num_digits,
2254  interval * data->num_children);
2255 
2256  gtk_label_set_text (GTK_LABEL(data->example2), str);
2257 
2258  g_free (str);
2259 }
2260 
2261 void
2262 gnc_account_renumber_prefix_changed_cb (GtkEditable *editable,
2263  RenumberDialog *data)
2264 {
2265  gnc_account_renumber_update_examples (data);
2266 }
2267 
2268 void
2269 gnc_account_renumber_interval_changed_cb (GtkSpinButton *spinbutton,
2270  RenumberDialog *data)
2271 {
2272  gnc_account_renumber_update_examples (data);
2273 }
2274 
2275 void
2276 gnc_account_renumber_digits_changed_cb (GtkSpinButton *spinbutton,
2277  RenumberDialog *data)
2278 {
2279  gnc_account_renumber_update_examples (data);
2280 }
2281 
2282 void
2283 gnc_account_renumber_response_cb (GtkDialog *dialog,
2284  gint response,
2285  RenumberDialog *data)
2286 {
2287  if (response == GTK_RESPONSE_OK)
2288  {
2289  GList *children = gnc_account_get_children_sorted (data->parent);
2290  GList *tmp;
2291  gint interval;
2292  unsigned int num_digits, i;
2293 
2294  gtk_widget_hide (data->dialog);
2295 
2296  if (children == NULL)
2297  {
2298  PWARN("Can't renumber children of an account with no children!");
2299  g_free (data);
2300  return;
2301  }
2302  const gchar *prefix = gtk_entry_get_text (GTK_ENTRY(data->prefix));
2303  interval = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(data->interval));
2304  num_digits = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(data->digits));
2305 
2306  gnc_set_busy_cursor (NULL, TRUE);
2307  for (tmp = children, i = 1; tmp; tmp = g_list_next (tmp), i += 1)
2308  {
2309  gchar *str;
2310  if (prefix && *prefix)
2311  str = g_strdup_printf ("%s-%0*d", prefix,
2312  num_digits, interval * i);
2313  else
2314  str = g_strdup_printf ("%0*d", num_digits, interval * i);
2315 
2316  xaccAccountSetCode (tmp->data, str);
2317  g_free (str);
2318  }
2319  gnc_unset_busy_cursor (NULL);
2320  g_list_free (children);
2321  }
2322  gtk_widget_destroy (data->dialog);
2323  g_free (data);
2324 }
2325 
2326 void
2327 gnc_account_renumber_create_dialog (GtkWidget *window, Account *account)
2328 {
2329  RenumberDialog *data;
2330  GtkBuilder *builder;
2331  GtkWidget *widget;
2332  gchar *string, *fullname;
2333 
2334  /* This is a safety check; the menu item calling this dialog
2335  * should be disabled if the account has no children.
2336  */
2337  g_return_if_fail (gnc_account_n_children (account) > 0);
2338 
2339  data = g_new (RenumberDialog, 1);
2340  data->parent = account;
2341  data->num_children = gnc_account_n_children (account);
2342 
2343  builder = gtk_builder_new ();
2344  gnc_builder_add_from_file (builder, "dialog-account.glade", "interval_adjustment");
2345  gnc_builder_add_from_file (builder, "dialog-account.glade", "digit_spin_adjustment");
2346  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_renumber_dialog");
2347  data->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_renumber_dialog"));
2348  gtk_window_set_transient_for (GTK_WINDOW(data->dialog), GTK_WINDOW(window));
2349 
2350  g_object_set_data_full (G_OBJECT(data->dialog), "builder", builder,
2351  g_object_unref);
2352 
2353  widget = GTK_WIDGET(gtk_builder_get_object (builder, "header_label"));
2354  fullname = gnc_account_get_full_name (account);
2355  string = g_strdup_printf (_("Renumber the immediate sub-accounts of '%s'?"),
2356  fullname);
2357  gtk_label_set_text (GTK_LABEL(widget), string);
2358  g_free (string);
2359  g_free (fullname);
2360 
2361  data->prefix = GTK_WIDGET(gtk_builder_get_object (builder, "prefix_entry"));
2362  data->interval = GTK_WIDGET(gtk_builder_get_object (builder, "interval_spin"));
2363  data->digits = GTK_WIDGET(gtk_builder_get_object (builder, "digit_spin"));
2364  data->example1 = GTK_WIDGET(gtk_builder_get_object (builder, "example1_label"));
2365  data->example2 = GTK_WIDGET(gtk_builder_get_object (builder, "example2_label"));
2366 
2367  gtk_entry_set_text (GTK_ENTRY(data->prefix), xaccAccountGetCode (account));
2368  gnc_account_renumber_update_examples (data);
2369 
2370  gtk_builder_connect_signals (builder, data);
2371 
2372  gtk_widget_show_all (data->dialog);
2373 }
2374 
2375 static void
2376 default_color_button_cb (GtkButton *button, gpointer user_data)
2377 {
2378  GdkRGBA color;
2379 
2380  if (gdk_rgba_parse (&color, DEFAULT_COLOR))
2381  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(user_data), &color);
2382 }
2383 
2384 static void
2385 update_account_color (Account *acc, const gchar *old_color, const gchar *new_color, gboolean replace)
2386 {
2387  PINFO("Account is '%s', old_color is '%s', new_color is '%s', replace is %d",
2388  xaccAccountGetName (acc), old_color, new_color, replace);
2389 
2390  // have a new color, update if we can
2391  if (new_color)
2392  {
2393  if (!old_color || replace)
2394  {
2395  // check to see if the color is different from old one
2396  if (g_strcmp0 (new_color, old_color) != 0)
2397  xaccAccountSetColor (acc, new_color);
2398  }
2399  }
2400  else // change from a color to default one, remove color entry if we can
2401  {
2402  if (old_color && replace)
2403  xaccAccountSetColor (acc, ""); // remove entry
2404  }
2405 }
2406 
2407 static void
2408 enable_box_cb (GtkToggleButton *toggle_button, gpointer user_data)
2409 {
2410  gboolean sensitive = FALSE;
2411 
2412  if (gtk_toggle_button_get_active (toggle_button))
2413  sensitive = TRUE;
2414 
2415  gtk_widget_set_sensitive (GTK_WIDGET(user_data), sensitive);
2416 }
2417 
2418 void
2419 gnc_account_cascade_properties_dialog (GtkWidget *window, Account *account)
2420 {
2421  GtkWidget *dialog;
2422  GtkBuilder *builder;
2423  GtkWidget *label;
2424  GtkWidget *color_button, *over_write, *color_button_default;
2425  GtkWidget *enable_color, *enable_placeholder, *enable_hidden;
2426  GtkWidget *color_box, *placeholder_box, *hidden_box;
2427  GtkWidget *placeholder_button, *hidden_button;
2428 
2429  gchar *string, *fullname;
2430  const char *color_string;
2431  gchar *old_color_string = NULL;
2432  GdkRGBA color;
2433  gint response;
2434 
2435  // check if we actually do have sub accounts
2436  g_return_if_fail (gnc_account_n_children (account) > 0);
2437 
2438  builder = gtk_builder_new ();
2439  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_cascade_dialog");
2440  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_cascade_dialog"));
2441  gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(window));
2442 
2443  // Color section
2444  enable_color = GTK_WIDGET(gtk_builder_get_object (builder, "enable_cascade_color"));
2445  color_box = GTK_WIDGET(gtk_builder_get_object (builder, "color_box"));
2446 
2447  label = GTK_WIDGET(gtk_builder_get_object (builder, "color_label"));
2448  over_write = GTK_WIDGET(gtk_builder_get_object (builder, "replace_check"));
2449  color_button = GTK_WIDGET(gtk_builder_get_object (builder, "color_button"));
2450  color_button_default = GTK_WIDGET(gtk_builder_get_object (builder, "color_button_default"));
2451 
2452  gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER(color_button), FALSE);
2453 
2454  g_signal_connect (G_OBJECT(enable_color), "toggled",
2455  G_CALLBACK(enable_box_cb), (gpointer)color_box);
2456 
2457  g_signal_connect (G_OBJECT(color_button_default), "clicked",
2458  G_CALLBACK(default_color_button_cb), (gpointer)color_button);
2459 
2460  fullname = gnc_account_get_full_name (account);
2461  string = g_strdup_printf (_( "Set the account color for account '%s' "
2462  "including all sub-accounts to the selected color"),
2463  fullname);
2464  gtk_label_set_text (GTK_LABEL(label), string);
2465  g_free (string);
2466 
2467  color_string = xaccAccountGetColor (account); // get existing account color
2468 
2469  if (!color_string)
2470  color_string = DEFAULT_COLOR;
2471  else
2472  old_color_string = g_strdup (color_string); // save the old color string
2473 
2474  if (!gdk_rgba_parse (&color, color_string))
2475  gdk_rgba_parse (&color, DEFAULT_COLOR);
2476 
2477  // set the color chooser to account color
2478  gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(color_button), &color);
2479 
2480  // Placeholder section
2481  enable_placeholder = GTK_WIDGET(gtk_builder_get_object (builder, "enable_cascade_placeholder"));
2482  placeholder_box = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_box"));
2483  label = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_label"));
2484  placeholder_button = GTK_WIDGET(gtk_builder_get_object (builder, "placeholder_check_button"));
2485  g_signal_connect (G_OBJECT(enable_placeholder), "toggled",
2486  G_CALLBACK(enable_box_cb), (gpointer)placeholder_box);
2487 
2488  string = g_strdup_printf (_( "Set the account placeholder value for account '%s' "
2489  "including all sub-accounts"),
2490  fullname);
2491  gtk_label_set_text (GTK_LABEL(label), string);
2492  g_free (string);
2493 
2494  // Hidden section
2495  enable_hidden = GTK_WIDGET(gtk_builder_get_object (builder, "enable_cascade_hidden"));
2496  hidden_box = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_box"));
2497  label = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_label"));
2498  hidden_button = GTK_WIDGET(gtk_builder_get_object (builder, "hidden_check_button"));
2499  g_signal_connect (G_OBJECT(enable_hidden), "toggled",
2500  G_CALLBACK(enable_box_cb), (gpointer)hidden_box);
2501 
2502  string = g_strdup_printf (_( "Set the account hidden value for account '%s' "
2503  "including all sub-accounts"),
2504  fullname);
2505  gtk_label_set_text (GTK_LABEL(label), string);
2506  g_free (string);
2507  g_free (fullname);
2508 
2509  /* default to cancel */
2510  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
2511 
2512  gtk_builder_connect_signals (builder, dialog);
2513  g_object_unref (G_OBJECT(builder));
2514 
2515  gtk_widget_show_all (dialog);
2516 
2517  response = gtk_dialog_run (GTK_DIALOG(dialog));
2518 
2519  if (response == GTK_RESPONSE_OK)
2520  {
2521  GList *accounts = gnc_account_get_descendants (account);
2522  GdkRGBA new_color;
2523  const gchar *new_color_string = NULL;
2524  gboolean color_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(enable_color));
2525  gboolean placeholder_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(enable_placeholder));
2526  gboolean hidden_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(enable_hidden));
2527  gboolean replace = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(over_write));
2528  gboolean placeholder = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(placeholder_button));
2529  gboolean hidden = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(hidden_button));
2530 
2531  // Update Account Colors
2532  if (color_active)
2533  {
2534  gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(color_button), &new_color);
2535  new_color_string = gdk_rgba_to_string (&new_color);
2536 
2537  if (g_strcmp0 (new_color_string, DEFAULT_COLOR) == 0)
2538  new_color_string = NULL;
2539 
2540  // check/update selected account
2541  update_account_color (account, old_color_string, new_color_string, replace);
2542  }
2543 
2544  // Update Account Placeholder value
2545  if (placeholder_active)
2546  xaccAccountSetPlaceholder (account, placeholder);
2547 
2548  // Update Account Hidden value
2549  if (hidden_active)
2550  xaccAccountSetHidden (account, hidden);
2551 
2552  // Update SubAccounts
2553  if (accounts)
2554  {
2555  for (GList *acct = accounts; acct; acct = g_list_next(acct))
2556  {
2557  // Update SubAccount Colors
2558  if (color_active)
2559  {
2560  const char *string = xaccAccountGetColor (acct->data);
2561  update_account_color (acct->data, string, new_color_string, replace);
2562  }
2563  // Update SubAccount PlaceHolder
2564  if (placeholder_active)
2565  xaccAccountSetPlaceholder (acct->data, placeholder);
2566  // Update SubAccount Hidden
2567  if (hidden_active)
2568  xaccAccountSetHidden (acct->data, hidden);
2569  }
2570  }
2571  g_list_free (accounts);
2572  }
2573  if (old_color_string)
2574  g_free (old_color_string);
2575 
2576  gtk_widget_destroy (dialog);
2577 }
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:2877
#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:4264
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:4456
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:2776
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:2901
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:2678
gboolean xaccAccountGetNonStdSCU(const Account *acc)
Return boolean, indicating whether this account uses a non-standard SCU.
Definition: Account.cpp:2714
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:2584
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:3228
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2685
const char * xaccAccountGetCode(const Account *acc)
Get the account&#39;s accounting code.
Definition: Account.cpp:3305
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:4093
#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:4561
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:5012
int 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:4931
void xaccAccountDestroy(Account *acc)
The xaccAccountDestroy() routine can be used to get rid of an account.
Definition: Account.cpp:1593
#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:3319
#define xaccAccountGetGUID(X)
Definition: Account.h:248
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:3257
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition: Account.cpp:4201
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:4543
void xaccAccountClearLowerBalanceLimit(Account *acc)
Clear the lower balance limit for the account.
Definition: Account.cpp:5075
void xaccAccountSetColor(Account *acc, const char *str)
Set the account&#39;s Color.
Definition: Account.cpp:2542
void xaccAccountSetIncludeSubAccountBalances(Account *acc, gboolean inc_sub)
Set whether to include balances of sub accounts.
Definition: Account.cpp:5098
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:3312
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:2917
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:3124
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:4232
gboolean xaccAccountGetTaxRelated(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4087
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:2924
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:2662
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:4279
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:3005
void xaccAccountSetAutoInterest(Account *acc, gboolean val)
Set the "auto interest" flag for an account.
Definition: Account.cpp:4270
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:4219
guint32 xaccParentAccountTypesCompatibleWith(GNCAccountType type)
Return the bitmask of parent account types compatible with a given type.
Definition: Account.cpp:4496
gboolean xaccAccountGetIncludeSubAccountBalances(const Account *acc)
Get whether to include balances of sub accounts.
Definition: Account.cpp:5083
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:2908
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:4285
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1479
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:4313
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3413
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:1048
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4195
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:5023
gboolean xaccAccountGetHigherBalanceLimit(const Account *acc, gnc_numeric *balance)
Get the higher balance limit for the account.
Definition: Account.cpp:4891
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition: Account.cpp:1275
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
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:2698
Account * gnc_account_lookup_by_opening_balance(Account *account, gnc_commodity *commodity)
Find the opening balance account for the currency.
Definition: Account.cpp:3082
void xaccAccountClearHigherBalanceLimit(Account *acc)
Clear the higher balance limit for the account.
Definition: Account.cpp:5067
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3250
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:4446
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:1520
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:203
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account&#39;s commodity.
Definition: Account.cpp:2618
const char * xaccAccountGetNotes(const Account *acc)
Get the account&#39;s notes.
Definition: Account.cpp:3359
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2048