diff --git a/src/gnome-utils/dialog-account.c b/src/gnome-utils/dialog-account.c index bec68d95f3..6286c827a6 100644 --- a/src/gnome-utils/dialog-account.c +++ b/src/gnome-utils/dialog-account.c @@ -136,7 +136,6 @@ 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); @@ -319,6 +318,11 @@ gnc_ui_to_account(AccountWindow *aw) return; } + if (aw->type != xaccAccountGetType (account)) { + /* Just refreshing won't work. */ + aw_call_destroy_callbacks (account); + } + xaccAccountBeginEdit (account); if (aw->type != xaccAccountGetType (account)) @@ -436,15 +440,57 @@ gnc_ui_to_account(AccountWindow *aw) } -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 (); @@ -494,141 +540,43 @@ gnc_finish_ok (AccountWindow *aw, } -/* 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; - GtkListStore *list; - guint count; -} FillStruct; - -static void -fill_helper(gpointer key, gpointer value, gpointer data) -{ - Account *account = key; - FillStruct *fs = data; - gchar *full_name; - const gchar *account_field_name; - const gchar *account_field_value; - const gchar *value_str; - GtkTreeIter iter; - - if (fs == NULL) return; - if (fs->account == account) return; - - full_name = xaccAccountGetFullName(account); - account_field_name = _("Type"); - account_field_value = xaccAccountGetTypeStr(xaccAccountGetType(account)); - value_str = xaccAccountGetTypeStr(GPOINTER_TO_INT(value)); - - gtk_list_store_append(fs->list, &iter); - gtk_list_store_set(fs->list, &iter, - ACCOUNT_COL_FULLNAME, full_name, - ACCOUNT_COL_FIELDNAME, account_field_name, - ACCOUNT_COL_OLD_VALUE, account_field_value, - ACCOUNT_COL_NEW_VALUE, value_str, - -1); - g_free(full_name); - fs->count++; -} - -static guint -fill_list(Account *account, GtkListStore *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; - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - GtkTreeView *view; - GtkListStore *store; + AccountGroup *children; + GtkWidget *dialog, *vbox, *hbox, *label, *expander; + gchar *str; gboolean result; - guint size; if (aw == NULL) return FALSE; @@ -637,89 +585,88 @@ extra_change_verify (AccountWindow *aw, if (!account) return FALSE; - store = gtk_list_store_new(NUM_ACCOUNT_COLS, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING); - - size = 0; - size += fill_list(account, GTK_LIST_STORE(store), change_type); - - if (size == 0) - { - g_object_unref(store); + if (xaccAccountTypesCompatible (xaccAccountGetType (account), aw->type)) return TRUE; - } - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), - ACCOUNT_COL_FULLNAME, - GTK_SORT_ASCENDING); + children = xaccAccountGetChildren (account); + if (!children || + !xaccGroupGetNumAccounts (children)) + return TRUE; - view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store))); - g_object_unref(store); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Account"), renderer, - "text", ACCOUNT_COL_FULLNAME, - NULL); - gtk_tree_view_append_column(view, column); + 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); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Field"), renderer, - "text", ACCOUNT_COL_FIELDNAME, - NULL); - gtk_tree_view_append_column(view, column); + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Old Value"), renderer, - "text", ACCOUNT_COL_OLD_VALUE, - NULL); - gtk_tree_view_append_column(view, column); + hbox = gtk_hbox_new (FALSE, 12); + vbox = gtk_vbox_new (FALSE, 12); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("New Value"), renderer, - "text", ACCOUNT_COL_NEW_VALUE, - NULL); - gtk_tree_view_append_column(view, column); + 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); - - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); - gtk_window_set_default_size (GTK_WINDOW (dialog), 0, 300); - - vbox = GTK_DIALOG (dialog)->vbox; - - label = gtk_label_new(_("The following changes must be made. Continue?")); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(vbox), frame, 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); - - gtk_container_add(GTK_CONTAINER(frame), scroll); - gtk_container_set_border_width(GTK_CONTAINER(scroll), 5); - gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view)); - - gtk_widget_show_all(vbox); - - result = (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK); - - gtk_widget_destroy(dialog); + 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); + + /* 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); + + /* 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); + + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, + TRUE, TRUE, 0); + + /* 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_widget_show_all (hbox); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + + result = (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK); + + gtk_widget_destroy(dialog); return result; } @@ -811,6 +758,15 @@ gnc_common_ok (AccountWindow *aw) 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)); @@ -828,17 +784,7 @@ gnc_common_ok (AccountWindow *aw) 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); @@ -853,73 +799,12 @@ gnc_edit_account_ok(AccountWindow *aw) 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(" "); } @@ -971,7 +856,7 @@ gnc_new_account_ok (AccountWindow *aw) } } - gnc_finish_ok (aw, NULL); + gnc_finish_ok (aw); LEAVE(" "); }