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