r15141 - gnucash/branches/2.0 - Handle type-compatibility when reparenting accounts: #344966.
Derek Atkins
warlord at cvs.gnucash.org
Fri Nov 24 14:54:22 EST 2006
Author: warlord
Date: 2006-11-24 14:54:20 -0500 (Fri, 24 Nov 2006)
New Revision: 15141
Trac: http://svn.gnucash.org/trac/changeset/15141
Modified:
gnucash/branches/2.0/
gnucash/branches/2.0/ChangeLog
gnucash/branches/2.0/src/engine/Account.c
gnucash/branches/2.0/src/engine/Account.h
gnucash/branches/2.0/src/gnome-utils/dialog-account.c
gnucash/branches/2.0/src/gnome-utils/gnc-tree-model-account-types.c
gnucash/branches/2.0/src/gnome-utils/gnc-tree-model-account-types.h
gnucash/branches/2.0/src/import-export/import-account-matcher.c
Log:
Handle type-compatibility when reparenting accounts: #344966.
Add xaccAccountTypesCompatibleWith and change
xaccAccountTypesCompatible to use that.
Add gnc_tree_model_account_types_set_mask and bind mask to the
filter model instead using it as data of the filter function,
because those can only be set once per filter.
f_model is not always set in
gnc_tree_model_account_types_get_selection because of a bug in
gtk+ (#357791). Also add gnc_tree_model_account_types_get_mask.
Make the account type list in the account dialog dynamically
filtered based on compatibility to the parent account.
* add gnc_account_parent_changed_cb. Filter by valid_types & parent
compatible types
* add aw->preferred_account_type to remember what we chose but may not
work currently
* make valid_types a guint32 (was GList*)
* last_used_account_type is only set in gnc_ui_to_account
Free a list in import-account-matcher.c.
Ease account type changes in the account dialog after OK is
clicked. Before, we did not enforce compatibility with the parent
account and suggested to change only children or children and all
parent accounts up to the top-level one. We do enforce it now and
only need to look at the children.
The filling of the hash of (children) account (type) changes has
been replaced by showing the user a filtered account tree and the
types are adjusted recursively once the user verified the change.
This is another attempt to resolve #344966.
Merge r14894, r14895, r14896, r14897, r14898, r14899
Property changes on: gnucash/branches/2.0
___________________________________________________________________
Name: svk:merge
- 3889ce50-311e-0410-a464-f059747ec5d1:/local/gnucash/branches/2.0:697
d2ab10a8-8a95-4986-baff-8d511d9f15b2:/local/gnucash/branches/2.0:13623
d2ab10a8-8a95-4986-baff-8d511d9f15b2:/local/gnucash/trunk:13282
+ 3889ce50-311e-0410-a464-f059747ec5d1:/local/gnucash/branches/2.0:697
d2ab10a8-8a95-4986-baff-8d511d9f15b2:/local/gnucash/branches/2.0:13624
d2ab10a8-8a95-4986-baff-8d511d9f15b2:/local/gnucash/trunk:13282
Modified: gnucash/branches/2.0/ChangeLog
===================================================================
--- gnucash/branches/2.0/ChangeLog 2006-11-24 19:54:02 UTC (rev 15140)
+++ gnucash/branches/2.0/ChangeLog 2006-11-24 19:54:20 UTC (rev 15141)
@@ -63,6 +63,45 @@
therefore crashes on Solaris and Windows. r14675 had fixed that, r14945
(me) undermined it though. (#378881).
+2006-09-26 Andreas Köhler <andi5.py at gmx.net>
+
+ Handle type-compatibility when reparenting accounts: #344966.
+
+ Add xaccAccountTypesCompatibleWith and change
+ xaccAccountTypesCompatible to use that.
+
+ Add gnc_tree_model_account_types_set_mask and bind mask to the
+ filter model instead using it as data of the filter function,
+ because those can only be set once per filter.
+
+ f_model is not always set in
+ gnc_tree_model_account_types_get_selection because of a bug in
+ gtk+ (#357791). Also add gnc_tree_model_account_types_get_mask.
+
+ Make the account type list in the account dialog dynamically
+ filtered based on compatibility to the parent account.
+
+ * add gnc_account_parent_changed_cb. Filter by valid_types & parent
+ compatible types
+ * add aw->preferred_account_type to remember what we chose but may not
+ work currently
+ * make valid_types a guint32 (was GList*)
+ * last_used_account_type is only set in gnc_ui_to_account
+
+ Free a list in import-account-matcher.c.
+
+ Ease account type changes in the account dialog after OK is
+ clicked. Before, we did not enforce compatibility with the parent
+ account and suggested to change only children or children and all
+ parent accounts up to the top-level one. We do enforce it now and
+ only need to look at the children.
+
+ The filling of the hash of (children) account (type) changes has
+ been replaced by showing the user a filtered account tree and the
+ types are adjusted recursively once the user verified the change.
+
+ This is another attempt to resolve #344966.
+
2006-10-08 Chris Lyttle <chris at wilddev.net>
* NEWS: Added some text about the release.
Modified: gnucash/branches/2.0/src/engine/Account.c
===================================================================
--- gnucash/branches/2.0/src/engine/Account.c 2006-11-24 19:54:02 UTC (rev 15140)
+++ gnucash/branches/2.0/src/engine/Account.c 2006-11-24 19:54:20 UTC (rev 15141)
@@ -2177,49 +2177,52 @@
/********************************************************************\
\********************************************************************/
+guint32
+xaccAccountTypesCompatibleWith (GNCAccountType type)
+{
+ switch (type) {
+ case BANK:
+ case CASH:
+ case ASSET:
+ case STOCK:
+ case MUTUAL:
+ case CURRENCY:
+ case CREDIT:
+ case LIABILITY:
+ case RECEIVABLE:
+ case PAYABLE:
+ return
+ (1 << BANK) |
+ (1 << CASH) |
+ (1 << ASSET) |
+ (1 << STOCK) |
+ (1 << MUTUAL) |
+ (1 << CURRENCY) |
+ (1 << CREDIT) |
+ (1 << LIABILITY) |
+ (1 << RECEIVABLE) |
+ (1 << PAYABLE);
+ case INCOME:
+ case EXPENSE:
+ return
+ (1 << INCOME) |
+ (1 << EXPENSE);
+ case EQUITY:
+ return
+ (1 << EQUITY);
+ default:
+ PERR("bad account type: %d", type);
+ return 0;
+ }
+}
+
gboolean
xaccAccountTypesCompatible (GNCAccountType parent_type,
GNCAccountType child_type)
{
- gboolean compatible = FALSE;
-
- switch(parent_type)
- {
- case BANK:
- case CASH:
- case ASSET:
- case STOCK:
- case MUTUAL:
- case CURRENCY:
- case CREDIT:
- case LIABILITY:
- case RECEIVABLE:
- case PAYABLE:
- compatible = ((child_type == BANK) ||
- (child_type == CASH) ||
- (child_type == ASSET) ||
- (child_type == STOCK) ||
- (child_type == MUTUAL) ||
- (child_type == CURRENCY) ||
- (child_type == CREDIT) ||
- (child_type == LIABILITY)||
- (child_type == RECEIVABLE)||
- (child_type == PAYABLE));
- break;
- case INCOME:
- case EXPENSE:
- compatible = ((child_type == INCOME) ||
- (child_type == EXPENSE));
- break;
- case EQUITY:
- compatible = (child_type == EQUITY);
- break;
- default:
- PERR("bad account type: %d", parent_type);
- break;
- }
-
- return compatible;
+ return ((xaccAccountTypesCompatibleWith (parent_type) &
+ (1 << child_type))
+ != 0);
}
guint32
Modified: gnucash/branches/2.0/src/engine/Account.h
===================================================================
--- gnucash/branches/2.0/src/engine/Account.h 2006-11-24 19:54:02 UTC (rev 15140)
+++ gnucash/branches/2.0/src/engine/Account.h 2006-11-24 19:54:20 UTC (rev 15141)
@@ -505,6 +505,9 @@
* to the local language. */
GNCAccountType xaccAccountGetTypeFromStr (const gchar *str);
+/** Return the bitmask of account types compatible with a given type. */
+guint32 xaccAccountTypesCompatibleWith (GNCAccountType type);
+
/** Return TRUE if accounts of type parent_type can have accounts
* of type child_type as children. */
gboolean xaccAccountTypesCompatible (GNCAccountType parent_type,
Modified: gnucash/branches/2.0/src/gnome-utils/dialog-account.c
===================================================================
--- gnucash/branches/2.0/src/gnome-utils/dialog-account.c 2006-11-24 19:54:02 UTC (rev 15140)
+++ gnucash/branches/2.0/src/gnome-utils/dialog-account.c 2006-11-24 19:54:20 UTC (rev 15141)
@@ -86,8 +86,9 @@
GtkWidget * commodity_edit;
dialog_commodity_mode commodity_mode;
GtkWidget * account_scu;
-
- GList * valid_types;
+
+ guint32 valid_types;
+ GNCAccountType preferred_account_type;
GtkWidget * type_view;
GtkTreeView * parent_tree;
@@ -121,13 +122,12 @@
/** Static Globals *******************************************************/
static QofLogModule log_module = GNC_MOD_GUI;
-static int last_used_account_type = BANK;
+static GNCAccountType last_used_account_type = BANK;
static GList *ac_destroy_cb_list = NULL;
/** Declarations *********************************************************/
static void gnc_account_window_set_name (AccountWindow *aw);
-static void make_account_changes(GHashTable *change_type);
void gnc_account_renumber_prefix_changed_cb (GtkEditable *editable, RenumberDialog *data);
void gnc_account_renumber_interval_changed_cb (GtkSpinButton *spinbutton, RenumberDialog *data);
@@ -233,9 +233,6 @@
flag = xaccAccountGetHidden (account);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aw->hidden_button),
flag);
-
- gtk_tree_view_collapse_all (aw->parent_tree);
- gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree), account);
LEAVE(" ");
}
@@ -313,11 +310,18 @@
return;
}
+ if (aw->type != xaccAccountGetType (account)) {
+ /* Just refreshing won't work. */
+ aw_call_destroy_callbacks (account);
+ }
+
xaccAccountBeginEdit (account);
if (aw->type != xaccAccountGetType (account))
xaccAccountSetType (account, aw->type);
+ last_used_account_type = aw->type;
+
string = gtk_entry_get_text (GTK_ENTRY(aw->name_entry));
old_string = xaccAccountGetName (account);
if (safe_strcmp (string, old_string) != 0)
@@ -428,15 +432,57 @@
}
-static void
-gnc_finish_ok (AccountWindow *aw,
- GHashTable *change_type)
+static void
+set_children_types (Account *account, GNCAccountType type)
{
- ENTER("aw %p, hash table %p", aw, change_type);
+ AccountGroup *children;
+ GList *iter;
+
+ children = xaccAccountGetChildren (account);
+ if (children == NULL)
+ return;
+
+ for (iter=xaccGroupGetAccountList (children); iter; iter=iter->next) {
+ account = iter->data;
+ if (type == xaccAccountGetType(account))
+ continue;
+
+ /* Just refreshing won't work. */
+ aw_call_destroy_callbacks (account);
+
+ xaccAccountBeginEdit (account);
+ xaccAccountSetType (account, type);
+ xaccAccountCommitEdit (account);
+
+ set_children_types (account, type);
+ }
+}
+
+static void
+make_children_compatible (AccountWindow *aw)
+{
+ Account *account;
+
+ g_return_if_fail (aw);
+
+ account = aw_get_account (aw);
+ g_return_if_fail (account);
+
+ if (xaccAccountTypesCompatible (xaccAccountGetType (account), aw->type))
+ return;
+
+ set_children_types (account, aw->type);
+}
+
+
+static void
+gnc_finish_ok (AccountWindow *aw)
+{
+ ENTER("aw %p", aw);
gnc_suspend_gui_refresh ();
/* make the account changes */
- make_account_changes (change_type);
+ make_children_compatible (aw);
gnc_ui_to_account (aw);
gnc_resume_gui_refresh ();
@@ -486,156 +532,43 @@
}
-/* Record all of the children of the given account as needing their
- * type changed to the one specified. */
static void
-gnc_edit_change_account_types(GHashTable *change_type, Account *account,
- Account *except, GNCAccountType type)
+add_children_to_expander (GObject *object, GParamSpec *param_spec, gpointer data)
{
- AccountGroup *children;
- GList *list;
- GList *node;
+ GtkExpander *expander = GTK_EXPANDER (object);
+ Account *account = data;
+ GtkWidget *scrolled_window;
+ GtkTreeView *view;
- if ((change_type == NULL) || (account == NULL))
- return;
+ if (gtk_expander_get_expanded (expander) &&
+ !gtk_bin_get_child (GTK_BIN (expander))) {
- if (account == except)
- return;
+ view = gnc_tree_view_account_new_with_group (
+ xaccAccountGetChildren (account), FALSE);
- g_hash_table_insert(change_type, account, GINT_TO_POINTER(type));
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (view));
- children = xaccAccountGetChildren(account);
- if (children == NULL)
- return;
-
- list = xaccGroupGetAccountList (children);
-
- for (node= list; node; node = node->next)
- {
- account = node->data;
- gnc_edit_change_account_types(change_type, account, except, type);
+ gtk_container_add (GTK_CONTAINER (expander), scrolled_window);
+ gtk_widget_show_all (scrolled_window);
}
}
-
-/* helper function to perform changes to accounts */
-static void
-change_func (gpointer key, gpointer value, gpointer unused)
-{
- Account *account = key;
- int type;
-
- if (account == NULL)
- return;
-
- xaccAccountBeginEdit(account);
-
- type = GPOINTER_TO_INT(value);
-
- if (type == xaccAccountGetType(account))
- return;
-
- /* Just refreshing won't work. */
- aw_call_destroy_callbacks (account);
-
- xaccAccountSetType(account, type);
-
- xaccAccountCommitEdit(account);
-}
-
-
-/* Perform the changes to accounts dictated by the hash tables */
-static void
-make_account_changes(GHashTable *change_type)
-{
- if (change_type != NULL)
- g_hash_table_foreach(change_type, change_func, NULL);
-}
-
-
-typedef struct
-{
- Account *account;
- GtkCList *list;
- guint count;
-} FillStruct;
-
-static void
-fill_helper(gpointer key, gpointer value, gpointer data)
-{
- Account *account = key;
- FillStruct *fs = data;
- gchar *full_name;
- gchar *account_field_name;
- gchar *account_field_value;
- gchar *value_str;
-
- if (fs == NULL) return;
- if (fs->account == account) return;
-
- full_name = xaccAccountGetFullName(account);
- if(!full_name)
- full_name = g_strdup("");
-
- account_field_name = g_strdup("Type");
- if (!account_field_name)
- account_field_name = g_strdup("");
-
- account_field_value =
- g_strdup (xaccAccountGetTypeStr(xaccAccountGetType(account)));
- if (!account_field_value)
- account_field_value = g_strdup("");
-
- value_str = g_strdup(xaccAccountGetTypeStr(GPOINTER_TO_INT(value)));
-
- {
- gchar *strings[5];
-
- strings[0] = full_name;
- strings[1] = account_field_name;
- strings[2] = account_field_value;
- strings[3] = value_str;
- strings[4] = NULL;
-
- gtk_clist_append(fs->list, strings);
- }
-
- g_free(full_name);
- g_free(account_field_name);
- g_free(account_field_value);
- g_free(value_str);
- fs->count++;
-}
-
-static guint
-fill_list(Account *account, GtkCList *list,
- GHashTable *change)
-{
- FillStruct fs;
-
- if (change == NULL)
- return 0;
-
- fs.account = account;
- fs.list = list;
- fs.count = 0;
-
- g_hash_table_foreach(change, fill_helper, &fs);
-
- return fs.count;
-}
-
-
-/* Present a dialog of proposed account changes for the user's ok */
+/* Check whether there are children needing a type adjustment because of a
+ a change to an incompatible type (like after some reparenting) and let the
+ user decide whether he wants that */
static gboolean
-extra_change_verify (AccountWindow *aw,
- GHashTable *change_type)
+verify_children_compatible (AccountWindow *aw)
{
Account *account;
- GtkCList *list;
- gchar *titles[5];
+ AccountGroup *children;
+ GtkWidget *dialog, *vbox, *hbox, *label, *expander;
+ gchar *str;
gboolean result;
- guint size;
if (aw == NULL)
return FALSE;
@@ -644,69 +577,88 @@
if (!account)
return FALSE;
- titles[0] = _("Account");
- titles[1] = _("Field");
- titles[2] = _("Old Value");
- titles[3] = _("New Value");
- titles[4] = NULL;
+ if (xaccAccountTypesCompatible (xaccAccountGetType (account), aw->type))
+ return TRUE;
- list = GTK_CLIST(gtk_clist_new_with_titles(4, titles));
+ children = xaccAccountGetChildren (account);
+ if (!children ||
+ !xaccGroupGetNumAccounts (children))
+ return TRUE;
- size = 0;
- size += fill_list(account, list, change_type);
+ dialog = gtk_dialog_new_with_buttons ("",
+ GTK_WINDOW(aw->dialog),
+ GTK_DIALOG_DESTROY_WITH_PARENT |
+ GTK_DIALOG_MODAL,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
- if (size == 0)
- {
- gtk_widget_destroy(GTK_WIDGET(list));
- return TRUE;
- }
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE);
- gtk_clist_column_titles_passive(list);
- gtk_clist_set_sort_column(list, 0);
- gtk_clist_sort(list);
- gtk_clist_columns_autosize(list);
+ hbox = gtk_hbox_new (FALSE, 12);
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_start (
+ GTK_BOX (hbox),
+ gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG),
+ FALSE, FALSE, 0);
+
+ /* primary label */
+ label = gtk_label_new (_("Give the children the same type?"));
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
{
- GtkWidget *dialog;
- GtkWidget *scroll;
- GtkWidget *label;
- GtkWidget *frame;
- GtkWidget *vbox;
+ gint size;
+ PangoFontDescription *font_desc;
- dialog = gtk_dialog_new_with_buttons (_("Verify Changes"),
- GTK_WINDOW(aw->dialog),
- GTK_DIALOG_DESTROY_WITH_PARENT |
- GTK_DIALOG_MODAL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- NULL);
+ size = pango_font_description_get_size (label->style->font_desc);
+ font_desc = pango_font_description_new ();
+ pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD);
+ pango_font_description_set_size (font_desc, size * PANGO_SCALE_LARGE);
+ gtk_widget_modify_font (label, font_desc);
+ pango_font_description_free (font_desc);
+ }
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
- gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
- gtk_window_set_default_size (GTK_WINDOW (dialog), 0, 300);
+ /* secondary label */
+ str = g_strdup_printf (_("The children of the edited account have to be "
+ "changed to type \"%s\" to make them compatible."),
+ xaccAccountGetTypeStr (aw->type));
+ label = gtk_label_new (str);
+ g_free (str);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
- vbox = GTK_DIALOG (dialog)->vbox;
+ /* children */
+ expander = gtk_expander_new_with_mnemonic (_("_Show children accounts"));
+ gtk_expander_set_spacing (GTK_EXPANDER (expander), 6);
+ g_signal_connect (G_OBJECT (expander), "notify::expanded",
+ G_CALLBACK (add_children_to_expander), account);
+ gtk_box_pack_start (GTK_BOX (vbox), expander, TRUE, TRUE, 0);
- label = gtk_label_new(_("The following changes must be made. Continue?"));
- gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
- frame = gtk_frame_new(NULL);
- gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
+ TRUE, TRUE, 0);
- scroll = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
- GTK_POLICY_NEVER,
- GTK_POLICY_AUTOMATIC);
+ /* spacings */
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 14);
+ gtk_container_set_border_width (
+ GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6);
- gtk_container_add(GTK_CONTAINER(frame), scroll);
- gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
- gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(list));
+ gtk_widget_show_all (hbox);
- gtk_widget_show_all(vbox);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
- result = (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK);
+ result = (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK);
- gtk_widget_destroy(dialog);
- }
+ gtk_widget_destroy(dialog);
return result;
}
@@ -798,6 +750,15 @@
return FALSE;
}
+ /* check whether the types of child and parent are compatible */
+ if (!xaccAccountTypesCompatible (aw->type, xaccAccountGetType (parent))) {
+ const char *message = _("The selected account type is incompatible with "
+ "the one of the selected parent.");
+ gnc_error_dialog(aw->dialog, message);
+ LEAVE("incompatible types");
+ return FALSE;
+ }
+
/* check for commodity */
commodity = (gnc_commodity *)
gnc_general_select_get_selected (GNC_GENERAL_SELECT (aw->commodity_edit));
@@ -815,18 +776,8 @@
static void
gnc_edit_account_ok(AccountWindow *aw)
{
- GHashTable *change_type;
-
- gboolean change_children;
- gboolean has_children;
- gboolean change_all;
-
- Account *new_parent;
Account *account;
- AccountGroup *children;
- GNCAccountType current_type;
-
ENTER("aw %p", aw);
account = aw_get_account (aw);
@@ -840,73 +791,12 @@
return;
}
- change_type = g_hash_table_new (NULL, NULL);
-
- children = xaccAccountGetChildren(account);
- if (children == NULL)
- has_children = FALSE;
- else if (xaccGroupGetNumAccounts(children) == 0)
- has_children = FALSE;
- else
- has_children = TRUE;
-
- current_type = xaccAccountGetType(account);
-
- /* If the account has children and the new type isn't compatible
- * with the old type, the children's types must be changed. */
- change_children = (has_children &&
- !xaccAccountTypesCompatible(current_type, aw->type));
-
- /* If the new parent's type is not compatible with the new type,
- * the whole sub-tree containing the account must be re-typed. */
- new_parent = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree));
- if (new_parent != aw->top_level_account)
- {
- int parent_type;
-
- parent_type = xaccAccountGetType(new_parent);
-
- if (!xaccAccountTypesCompatible(parent_type, aw->type))
- change_all = TRUE;
- else
- change_all = FALSE;
- }
- else
- change_all = FALSE;
-
- if (change_children)
- gnc_edit_change_account_types(change_type, account, NULL, aw->type);
-
- if (change_all)
- {
- Account *ancestor;
- Account *temp;
-
- temp = new_parent;
-
- do
- {
- ancestor = temp;
- temp = xaccAccountGetParentAccount(ancestor);
- } while (temp != NULL);
-
- gnc_edit_change_account_types(change_type, ancestor, account, aw->type);
- }
-
- if (!extra_change_verify(aw, change_type))
- {
- g_hash_table_destroy(change_type);
+ if (!verify_children_compatible (aw)) {
LEAVE(" ");
return;
}
- if (current_type != aw->type)
- /* Just refreshing won't work. */
- aw_call_destroy_callbacks (account);
-
- gnc_finish_ok (aw, change_type);
-
- g_hash_table_destroy (change_type);
+ gnc_finish_ok (aw);
LEAVE(" ");
}
@@ -958,7 +848,7 @@
}
}
- gnc_finish_ok (aw, NULL);
+ gnc_finish_ok (aw);
LEAVE(" ");
}
@@ -1056,12 +946,64 @@
aw->next_name = NULL;
}
- g_list_free (aw->valid_types);
g_free (aw);
LEAVE(" ");
}
static void
+gnc_account_parent_changed_cb (GtkTreeSelection *selection, gpointer data)
+{
+ AccountWindow *aw = data;
+ Account *parent_account;
+ guint32 types, old_types;
+ GtkTreeModel *type_model;
+ GtkTreeSelection *type_selection;
+ gboolean scroll_to = FALSE;
+
+ g_return_if_fail (aw);
+
+ parent_account = gnc_tree_view_account_get_selected_account (
+ GNC_TREE_VIEW_ACCOUNT (aw->parent_tree));
+ if (!parent_account)
+ return;
+
+ if (parent_account == aw->top_level_account) {
+ types = aw->valid_types;
+ } else {
+ types = aw->valid_types &
+ xaccAccountTypesCompatibleWith (xaccAccountGetType (parent_account));
+ }
+
+ type_model = gtk_tree_view_get_model (GTK_TREE_VIEW (aw->type_view));
+ if (!type_model)
+ return;
+
+ if (aw->type != aw->preferred_account_type &&
+ (types & (1 << aw->preferred_account_type)) != 0) {
+ /* we can change back to the preferred account type */
+ aw->type = aw->preferred_account_type;
+ scroll_to = TRUE;
+ }
+ else if ((types & (1 << aw->type)) == 0) {
+ /* our type is invalid now */
+ aw->type = BAD_TYPE;
+ }
+ else {
+ /* no type change, but maybe list of valid types changed */
+ old_types = gnc_tree_model_account_types_get_mask (type_model);
+ if (old_types != types)
+ scroll_to = TRUE;
+ }
+
+ gnc_tree_model_account_types_set_mask (type_model, types);
+
+ if (scroll_to) {
+ type_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (aw->type_view));
+ gnc_tree_model_account_types_set_selection(type_selection, 1 << aw->type);
+ }
+}
+
+static void
gnc_account_type_changed_cb (GtkTreeSelection *selection, gpointer data)
{
AccountWindow *aw = data;
@@ -1077,7 +1019,7 @@
aw->type = BAD_TYPE;
} else {
aw->type = type_id;
- last_used_account_type = type_id;
+ aw->preferred_account_type = type_id;
gnc_account_commodity_from_type (aw, TRUE);
@@ -1095,18 +1037,6 @@
}
}
-static GNCAccountType
-gnc_account_choose_new_acct_type (AccountWindow *aw)
-{
- if (g_list_index (aw->valid_types, GINT_TO_POINTER(aw->type)) != -1)
- return aw->type;
-
- if (g_list_index (aw->valid_types, GINT_TO_POINTER(last_used_account_type)) != -1)
- return last_used_account_type;
-
- return ((GNCAccountType)(aw->valid_types->data));
-}
-
static void
gnc_account_type_view_create (AccountWindow *aw)
{
@@ -1114,20 +1044,35 @@
GtkTreeSelection *selection;
GtkCellRenderer *renderer;
GtkTreeView *view;
- GList *list;
- guint32 types = 0;
- if ((aw->dialog_type == NEW_ACCOUNT) && aw->valid_types)
- aw->type = gnc_account_choose_new_acct_type (aw);
+ if (aw->valid_types == 0) {
+ /* no type restrictions, choose aw->type */
+ aw->valid_types = xaccAccountTypesValid () | (1 << aw->type);
+ aw->preferred_account_type = aw->type;
+ }
+ else if ((aw->valid_types & (1 << aw->type)) != 0) {
+ /* aw->type is valid */
+ aw->preferred_account_type = aw->type;
+ }
+ else if ((aw->valid_types & (1 << last_used_account_type)) != 0) {
+ /* last used account type is valid */
+ aw->type = last_used_account_type;
+ aw->preferred_account_type = last_used_account_type;
+ }
+ else {
+ /* choose first valid account type */
+ int i;
+ aw->preferred_account_type = aw->type;
+ aw->type = BAD_TYPE;
+ for (i=0; i<32; i++)
+ if ((aw->valid_types & (1 << i)) != 0) {
+ aw->type = i;
+ break;
+ }
+ }
- if (aw->valid_types == NULL)
- types = xaccAccountTypesValid () | (1 << aw->type);
- else
- for (list = aw->valid_types; list; list = list->next)
- types |= (1 << GPOINTER_TO_INT(list->data));
+ model = gnc_tree_model_account_types_filter_using_mask (aw->valid_types);
- model = gnc_tree_model_account_types_filter_using_mask (types);
-
view = GTK_TREE_VIEW (aw->type_view);
gtk_tree_view_set_model (view, model);
g_object_unref (G_OBJECT (model));
@@ -1142,7 +1087,7 @@
selection = gtk_tree_view_get_selection (view);
g_signal_connect (G_OBJECT (selection), "changed",
G_CALLBACK (gnc_account_type_changed_cb), aw);
-
+
gnc_tree_model_account_types_set_selection(selection, 1 << aw->type);
}
@@ -1226,7 +1171,6 @@
static void
gnc_account_window_create(AccountWindow *aw)
{
- GtkDialog *awd;
GtkWidget *amount;
GObject *awo;
GtkWidget *box;
@@ -1239,7 +1183,6 @@
aw->dialog = glade_xml_get_widget (xml, "Account Dialog");
awo = G_OBJECT (aw->dialog);
- awd = GTK_DIALOG (awo);
g_object_set_data (awo, "dialog_info", aw);
@@ -1285,6 +1228,9 @@
aw->parent_tree = gnc_tree_view_account_new(TRUE);
gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(aw->parent_tree));
gtk_widget_show(GTK_WIDGET(aw->parent_tree));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (aw->parent_tree));
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (gnc_account_parent_changed_cb), aw);
aw->top_level_account =
gnc_tree_view_account_get_top_level (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree));
@@ -1476,13 +1422,17 @@
gnc_commodity *commodity, *parent_commodity;
AccountWindow *aw;
Account *account;
+ GList *list;
aw = g_new0 (AccountWindow, 1);
aw->modal = modal;
aw->dialog_type = NEW_ACCOUNT;
- aw->valid_types = g_list_copy (valid_types);
+ aw->valid_types = 0;
+ for (list = valid_types; list; list = list->next)
+ aw->valid_types |= (1 << GPOINTER_TO_INT (list->data));
+
account = xaccMallocAccount (gnc_get_current_book ());
aw->account = *xaccAccountGetGUID (account);
@@ -1519,16 +1469,15 @@
commodity);
gnc_account_commodity_from_type (aw, FALSE);
- gtk_widget_show (aw->dialog);
+ if (base_account == NULL)
+ base_account = aw->top_level_account;
- if (base_account == NULL) {
- base_account = aw->top_level_account;
- }
-
gtk_tree_view_collapse_all (aw->parent_tree);
- gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT (aw->parent_tree),
- base_account);
+ gnc_tree_view_account_set_selected_account (
+ GNC_TREE_VIEW_ACCOUNT (aw->parent_tree), base_account);
+ gtk_widget_show (aw->dialog);
+
gnc_window_adjust_for_screen (GTK_WINDOW(aw->dialog));
gnc_account_window_set_name (aw);
@@ -1536,7 +1485,7 @@
aw->component_id = gnc_register_gui_component (DIALOG_NEW_ACCOUNT_CM_CLASS,
refresh_handler,
modal ? NULL : close_handler,
- aw);
+ aw);
gnc_gui_component_set_session (aw->component_id, gnc_get_current_session());
gnc_gui_component_watch_entity_type (aw->component_id,
@@ -1604,10 +1553,11 @@
return gnc_ui_new_accounts_from_name_with_defaults(name, valid_types, NULL, NULL);
}
-Account * gnc_ui_new_accounts_from_name_with_defaults (const char *name,
- GList *valid_types,
- gnc_commodity * default_commodity,
- Account * parent)
+Account *
+gnc_ui_new_accounts_from_name_with_defaults (const char *name,
+ GList *valid_types,
+ gnc_commodity * default_commodity,
+ Account * parent)
{
AccountWindow *aw;
Account *base_account = NULL;
@@ -1721,7 +1671,9 @@
if (parent == NULL)
parent = aw->top_level_account;
- gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(aw->parent_tree), parent);
+ gtk_tree_view_collapse_all (aw->parent_tree);
+ gnc_tree_view_account_set_selected_account (
+ GNC_TREE_VIEW_ACCOUNT(aw->parent_tree), parent);
gnc_account_window_set_name (aw);
@@ -1769,16 +1721,7 @@
gnc_ui_new_account_with_types( AccountGroup *unused,
GList *valid_types )
{
- GList *validTypesCopy = g_list_copy( valid_types );
- AccountWindow *aw;
-
- aw = gnc_ui_new_account_window_internal( NULL, NULL, validTypesCopy, NULL, FALSE );
- if ( validTypesCopy != NULL ) {
- /* Attach it with "[...]_full" so we can set the appropriate
- * GtkDestroyNotify func. */
- g_object_set_data_full( G_OBJECT(aw->dialog), "validTypesListCopy",
- validTypesCopy, (GDestroyNotify)g_list_free );
- }
+ gnc_ui_new_account_window_internal( NULL, NULL, valid_types, NULL, FALSE );
}
/************************************************************
Modified: gnucash/branches/2.0/src/gnome-utils/gnc-tree-model-account-types.c
===================================================================
--- gnucash/branches/2.0/src/gnome-utils/gnc-tree-model-account-types.c 2006-11-24 19:54:02 UTC (rev 15140)
+++ gnucash/branches/2.0/src/gnome-utils/gnc-tree-model-account-types.c 2006-11-24 19:54:20 UTC (rev 15141)
@@ -35,6 +35,8 @@
static QofLogModule log_module = GNC_MOD_GUI;
static GtkTreeModel *account_types_tree_model = NULL;
+#define TYPE_MASK "type-mask"
+
/* Functions for the type system */
static void
gnc_tree_model_account_types_class_init (GncTreeModelAccountTypesClass *klass);
@@ -153,13 +155,15 @@
static gboolean
-gnc_tree_model_account_types_is_valid (GtkTreeModel *model,
+gnc_tree_model_account_types_is_valid (GtkTreeModel *model,
GtkTreeIter *iter, gpointer data)
{
GNCAccountType type;
- guint32 valid_types = GPOINTER_TO_UINT (data);
+ GObject *f_model = G_OBJECT (data);
+ guint32 valid_types = GPOINTER_TO_UINT (g_object_get_data (
+ f_model, TYPE_MASK));
- gtk_tree_model_get (model, iter,
+ gtk_tree_model_get (model, iter,
GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE, &type, -1);
return (valid_types & (1 << type)) ? TRUE : FALSE;
}
@@ -176,16 +180,35 @@
{
GtkTreeModel *f_model;
- f_model = gtk_tree_model_filter_new(gnc_tree_model_account_types_master(),
+ f_model = gtk_tree_model_filter_new (gnc_tree_model_account_types_master (),
NULL);
+ g_object_set_data (G_OBJECT (f_model), TYPE_MASK, GUINT_TO_POINTER (types));
gtk_tree_model_filter_set_visible_func (
GTK_TREE_MODEL_FILTER (f_model), gnc_tree_model_account_types_is_valid,
- GUINT_TO_POINTER (types), NULL);
+ f_model, NULL);
return f_model;
}
+void
+gnc_tree_model_account_types_set_mask (GtkTreeModel *f_model,
+ guint32 types)
+{
+ g_return_if_fail (f_model);
+
+ g_object_set_data (G_OBJECT (f_model), TYPE_MASK, GUINT_TO_POINTER (types));
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (f_model));
+}
+
guint32
+gnc_tree_model_account_types_get_mask (GtkTreeModel *f_model)
+{
+ g_return_val_if_fail (f_model, 0);
+
+ return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (f_model), TYPE_MASK));
+}
+
+guint32
gnc_tree_model_account_types_get_selected (GncTreeModelAccountTypes * model)
{
GncTreeModelAccountTypesPrivate *priv;
@@ -221,7 +244,12 @@
view = gtk_tree_selection_get_tree_view(sel);
g_return_val_if_fail (view, 0);
+ /* circumvent a bug in gtk+ not always filling f_model */
+ f_model = NULL;
list = gtk_tree_selection_get_selected_rows(sel, &f_model);
+ if (!f_model)
+ f_model = gtk_tree_view_get_model(view);
+
model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
if (model != account_types_tree_model)
PERR("TreeSelection's TreeModel is not the account-types Model");
Modified: gnucash/branches/2.0/src/gnome-utils/gnc-tree-model-account-types.h
===================================================================
--- gnucash/branches/2.0/src/gnome-utils/gnc-tree-model-account-types.h 2006-11-24 19:54:02 UTC (rev 15140)
+++ gnucash/branches/2.0/src/gnome-utils/gnc-tree-model-account-types.h 2006-11-24 19:54:20 UTC (rev 15141)
@@ -113,6 +113,13 @@
Caller is responsible for ref/unref. */
GtkTreeModel * gnc_tree_model_account_types_filter_using_mask (guint32 types);
+/* Update the set of the visibible account types in 'f_model' to 'types'. */
+void gnc_tree_model_account_types_set_mask (GtkTreeModel *f_model,
+ guint32 types);
+
+/* Return the current set of the visibible account types. */
+guint32 gnc_tree_model_account_types_get_mask (GtkTreeModel *f_model);
+
/* Return the bitmask of the account type enums reflecting the state
of the tree selection. If your view allows the selection of
multiple account types, use must use this function to get the
Modified: gnucash/branches/2.0/src/import-export/import-account-matcher.c
===================================================================
--- gnucash/branches/2.0/src/import-export/import-account-matcher.c 2006-11-24 19:54:02 UTC (rev 15140)
+++ gnucash/branches/2.0/src/import-export/import-account-matcher.c 2006-11-24 19:54:20 UTC (rev 15141)
@@ -98,17 +98,18 @@
Account *selected_account, *new_account;
GList * valid_types = NULL;
/*DEBUG("Begin"); */
-
+
if(picker->new_account_default_type!=NO_TYPE)
{
/*Yes, this is weird, but we really DO want to pass the value instead of the pointer...*/
- valid_types = g_list_prepend(valid_types, (gpointer)picker->new_account_default_type);
+ valid_types = g_list_prepend(valid_types, GINT_TO_POINTER(picker->new_account_default_type));
}
selected_account = gnc_tree_view_account_get_selected_account(picker->account_tree);
new_account = gnc_ui_new_accounts_from_name_with_defaults ( picker->account_human_description,
valid_types,
picker->new_account_default_commodity,
selected_account);
+ g_list_free(valid_types);
gnc_tree_view_account_set_selected_account(picker->account_tree, new_account);
}
More information about the gnucash-changes
mailing list