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