[Gnucash-changes] r12357 - gnucash/trunk - Add account-tree-view editing for name,code,desc,notes; refactor new-account-heirarchy druid for merging accounts into an existing book.

Joshua Sled jsled at cvs.gnucash.org
Sun Jan 15 18:04:21 EST 2006


Author: jsled
Date: 2006-01-15 18:04:19 -0500 (Sun, 15 Jan 2006)
New Revision: 12357
Trac: http://svn.gnucash.org/trac/changeset/12357

Added:
   gnucash/trunk/src/app-utils/gnc-account-merge.c
   gnucash/trunk/src/app-utils/gnc-account-merge.h
Modified:
   gnucash/trunk/ChangeLog
   gnucash/trunk/GNOME2_STATUS
   gnucash/trunk/src/app-utils/Makefile.am
   gnucash/trunk/src/gnome-utils/gnc-tree-view-account.c
   gnucash/trunk/src/gnome-utils/gnc-tree-view-account.h
   gnucash/trunk/src/gnome/dialog-new-user.c
   gnucash/trunk/src/gnome/druid-hierarchy.c
   gnucash/trunk/src/gnome/druid-hierarchy.h
   gnucash/trunk/src/gnome/druid-merge.c
   gnucash/trunk/src/gnome/druid-merge.h
   gnucash/trunk/src/gnome/glade/account.glade
   gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c
Log:
Add account-tree-view editing for name,code,desc,notes; refactor new-account-heirarchy druid for merging accounts into an existing book.


Modified: gnucash/trunk/ChangeLog
===================================================================
--- gnucash/trunk/ChangeLog	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/ChangeLog	2006-01-15 23:04:19 UTC (rev 12357)
@@ -1,3 +1,63 @@
+2006-01-15  Joshua Sled  <jsled at asynchronous.org>
+
+	* src/gnome-utils/gnc-tree-view-account.c
+	(gnc_tree_view_account_new_with_group):
+	Record editable text columns in private data structure.
+	(gtva_set_column_editor)
+	(gtva_setup_column_renderer_edited_cb) 
+	(gnc_tree_view_account_set_name_edited) 
+	(gnc_tree_view_account_set_code_edited) 
+	(gnc_tree_view_account_set_description_edited) 
+	(gnc_tree_view_account_set_notes_edited):
+	Add support for setting up column-edited callbacks.
+	(gnc_tree_view_account_name_edited_cb) 
+	(gnc_tree_view_account_code_edited_cb) 
+	(gnc_tree_view_account_description_edited_cb) 
+	(gnc_tree_view_account_notes_edited_cb):
+	Provide stock editable-column handlers.
+
+	* src/gnome/gnc-plugin-page-account-tree.c
+	(gnc_plugin_page_account_tree_create_widget): Setup default
+	editing callbacks for text columns.
+
+	* src/app-utils/gnc-account-merge.[ch]: Non-ui-specific utility
+	routines from account-hierarchy druid regarding account-hierarchy
+	merge logic and constraints.
+
+	* src/gnome/druid-hierarchy.c: Remove static variables describing
+	dialog and dialog-in-interaction-with the druid-merge.c code.
+	(gnc_create_hierarchy_druid, get_final_balance)
+	(set_final_balance): simplify to Map<Account*,
+	balance:gnc_numeric*>, which is more tolerant of Account-name
+	changes.
+	(gnc_ui_hierarchy_druid_with_callback): Add callback support for
+	caller to have calling-specific work done.
+	(use_existing_account_data_func): Conditionally add column
+	detailing the status of how this new hierarchy merges into the
+	existing one.
+	(on_final_account_next): Check to ensure there are no
+	account-hierarchy merge conflicts before allowing Next to final
+	page.
+	(balance_cell_data_func): Add new subtlety around opening-balance
+	editing in the face of hierarachy-merging.
+	(on_finish): Reorder dialog finishing to work around account-tree
+	model bug, starting-balance-transaction creation, data-merging,
+	when-completed callback creation.
+	(gnc_ui_hierarchy_druid_hook): Add callback to create new
+	account-page as consequence of new-file hook run.
+
+	* src/gnome/dialog-new-user.c (after_hierarchy_druid): Create+use
+	callback for new-user-dialog specific code.
+
+	* src/gnome/glade/account.glade: Change "opening balances" page
+	title, default dialog positioning hint (from none to parent-center).
+
+	* src/gnome/druid-merge.[ch]
+	(gnc_ui_qof_book_merge_druid): Remove hierarchy-druid wrapper.
+	: remove un-used qof_book_merge_druid.
+
+	* accounts/C/*: Add placeholder flag on relevant accounts.
+
 2006-01-13  Derek Atkins  <derek at ihtfp.com>
 
 	* src/gnome-utils/Makefile.am: revert 12296 and handle the

Modified: gnucash/trunk/GNOME2_STATUS
===================================================================
--- gnucash/trunk/GNOME2_STATUS	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/GNOME2_STATUS	2006-01-15 23:04:19 UTC (rev 12357)
@@ -1,4 +1,4 @@
-# -*- reStructuredText -*-
+# -*- rst -*-
 
 Intro
 -----
@@ -124,25 +124,12 @@
 
     - Still a lot of dead legacy code hanging around
 
-- New Account Hierarchy - somewhat works
+- New Account Hierarchy... - mostly works
 
-  - Placeholder status should be set on relevant (non-leaf) accounts?
+  - Better text on opening/balance merge druid-page needed.
 
-  - Sometimes crashes when loading account data.
+- Import QSF
 
-  - 2006-01-02: do these problems still exist?
-
-    - [jsled, 2006-01-03] yes...
-
-      - After opening, mousing over the existing account-tree changes all my
-        '$'s to 'USD'.
-
-      - I'm unable to cancel this dialog.
-
-- Account Hierarchy Merge - BROKEN
-
-  - Bad integration with Account Hierarchy druid
-
   - Static variables used for process/window state.
 
   - Misc errors with no apparent cause
@@ -151,44 +138,8 @@
 
     - (gnucash:27485): Gtk-CRITICAL **: gtk_widget_event: assertion `WIDGET_REALIZED_FOR_EVENT (widget, event)' failed
 
-  - Doesn't let you complete the conflict resolution process, thus you can never complete the druid.
-
-    - (jsled) actually, it just doesn't display the 1-conflict -> 0-conflict
-      transition in the UI correctly, but it does allow you to finish.
-
   - conflict-resolution process/display issues.
 
-  - weird...
-
-    - Merge Druid -forward-> Account Druid -cancel-| => book commodity (?) changes
-
-  - conflict resolution
-
-<jsled> hampton: hmm.  trying to figure out the ui here; I think it's:
-<jsled> 1/ make the account-name directly-editable in the account-tree view.
-<jsled> 2/ Change the "add opening balance" page to "edit accounts".
-<jsled> 3/ Add a "existing?" column next to the account name.
-<jsled> 4/ the accounts and editing becomes stateful in a semi-complex way:
-<hampton> That sounds like a plan.  #2 will also make account names editable anywhere where an account tree is used which is good (accounts page, budgets page) and bad (transfer dialog, etc.)
-<jsled> there's a 2-bit state space: placeholder-account? and shares-name-woth-existing?
-<jsled> re: editable names: ah, noted; configurably editable, then.
-<jsled> s/woth/with/
-<jsled> placeholder=true, shares=true: use existing, no problem.
-<jsled> placeholder=true, shares=false: create new, no problem
-<jsled> placeholder=false, shares=true: existing account with same name exists, problem (blocks druid close)
-<jsled> placeholder=false, shares=false: create new, no problem.
-<hampton> I would state it differently.
-<jsled> Maybe ... another Messages column to indicate the problem case...
-<hampton> shares=false, placeholder=don't care: create new, no problem.
-<hampton> shares=true, placeholder=same as existing: use existing, no problem
-<hampton> shares=true, placeholder=diff from existing: problem
-<jsled> Ah.  Yup.
-<jsled> Well, kinda.
-<jsled> Ignoring the placeholders for a moment, there are really two types of example-accounts: those that expect the name to be edited, and those that don't.
-<jsled> Those roughly correlate with the placeholder setting.
-<jsled> But if you're re-running the account-hierarchy druid to add another credit card, you should be encouraged to enter a different name for the leaf account.
-<hampton> Its more a question of where the dialog was called from. If from the new user code, you really don't need to edit names.  If called from the merge druid, the user should be encouraged to edit leaf names.
-
 - Backend
 
   - price_lookup awaits a solution - as a query instead of a backend operation.
@@ -204,8 +155,12 @@
 
   - SX Editor
 
-    - bug/crash: http://lists.gnucash.org/pipermail/gnucash-devel/2006-January/015300.html
+    - bugs/crashes:
 
+      - http://lists.gnucash.org/pipermail/gnucash-devel/2005-December/015097.html
+
+      - http://lists.gnucash.org/pipermail/gnucash-devel/2006-January/015300.html
+
     - Template-register View > {Basic, Auto-Split} options have no effect
 
       - Note: they *shouldn't* have any effect, as they don't apply to
@@ -229,11 +184,9 @@
 
     - "Report options", especially, since it often confuses users.
 
-- In-place editing
+- Example accounts should have relevant placeholder status.
 
-  - Provide in-place editing where feasable.  Eg.  Editing the account code
-    or the account name, but not being able to re-parent the account.  (Maybe
-    add DND support for this in long-term?)
+- Account tree drag-and-drop reparenting.
 
 - Find
 

Modified: gnucash/trunk/src/app-utils/Makefile.am
===================================================================
--- gnucash/trunk/src/app-utils/Makefile.am	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/app-utils/Makefile.am	2006-01-15 23:04:19 UTC (rev 12357)
@@ -19,6 +19,7 @@
 libgncmod_app_utils_la_SOURCES = \
   file-utils.c \
   gfec.c \
+  gnc-account-merge.c \
   gnc-accounting-period.c \
   gnc-component-manager.c \
   gnc-druid.c \
@@ -37,13 +38,14 @@
   gncmod-app-utils.c \
   gnc-ui-util.c \
   guile-util.c \
-  option-util.c 
+  option-util.c
 
 gncincludedir = ${GNC_INCLUDE_DIR}
 gncinclude_HEADERS = \
   file-utils.h \
   gfec.h \
   gnc-basic-gobject.h \
+  gnc-account-merge.h \
   gnc-accounting-period.h \
   gnc-component-manager.h \
   gnc-druid.h \

Added: gnucash/trunk/src/app-utils/gnc-account-merge.c
===================================================================
--- gnucash/trunk/src/app-utils/gnc-account-merge.c	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/app-utils/gnc-account-merge.c	2006-01-15 23:04:19 UTC (rev 12357)
@@ -0,0 +1,106 @@
+// Copyright (C) 2006 Joshua Sled <jsled at asynchronous.org>
+
+#include "gnc-account-merge.h"
+#include "Account.h"
+#include "Group.h"
+
+GncAccountMergeDisposition
+determine_account_merge_disposition(Account *existing_acct, Account *new_acct)
+{
+  g_assert(new_acct != NULL);
+
+  if (existing_acct == NULL)
+    return GNC_ACCOUNT_MERGE_DISPOSITION_CREATE_NEW;
+
+  if (xaccAccountGetPlaceholder(existing_acct) != xaccAccountGetPlaceholder(new_acct))
+    return GNC_ACCOUNT_MERGE_DISPOSITION_ERROR;
+
+  return GNC_ACCOUNT_MERGE_DISPOSITION_USE_EXISTING;
+}
+
+GncAccountMergeDisposition
+determine_merge_disposition(AccountGroup *existing_root, Account *new_acct)
+{
+  const char sep_char = '.';
+  Account *existing_acct;
+  gchar *full_name;
+  
+  full_name = xaccAccountGetFullName(new_acct, sep_char);
+  existing_acct = xaccGetAccountFromFullName(existing_root, full_name, sep_char);
+  g_free(full_name);
+
+  return determine_account_merge_disposition(existing_acct, new_acct);
+}
+
+static void
+_account_merge_error_detection(AccountGroup *existing, AccountGroup *new, GList **error_accum)
+{
+  AccountList *accts;
+  for (accts = xaccGroupGetAccountList(new); accts; accts = accts->next)
+  {
+    Account *new_acct, *existing_acct;
+    GncAccountMergeDisposition disp;
+    
+    new_acct = (Account*)accts->data;
+    existing_acct = xaccGetAccountFromName(existing, xaccAccountGetName(new_acct));
+    disp = determine_account_merge_disposition(existing_acct, new_acct);
+    if (disp == GNC_ACCOUNT_MERGE_DISPOSITION_ERROR)
+    {
+      GncAccountMergeError *err = g_new0(GncAccountMergeError, 1);
+      err->existing = existing_acct;
+      err->new = new_acct;
+      err->disposition = disp;
+      *error_accum = g_list_append(*error_accum, err);
+    }
+    _account_merge_error_detection(xaccAccountGetChildren(existing_acct),
+                                   xaccAccountGetChildren(new_acct),
+                                   error_accum);
+  }
+}
+
+GList*
+account_merge_error_detection(AccountGroup *existing, AccountGroup *new)
+{
+  GList *errors = NULL;
+  _account_merge_error_detection(existing, new, &errors);
+  return errors;
+}
+
+void
+account_group_merge(AccountGroup *existing_grp, AccountGroup *new_grp)
+{
+  GList *accounts_copy;
+  AccountList *accounts;
+  g_return_if_fail(new_grp != NULL);
+  g_return_if_fail(existing_grp != NULL);
+
+  // since we're have a chance of mutating the list (via
+  // xaccGroupInsertAccount) while we're iterating over it, iterate over a
+  // copy.
+  accounts_copy = g_list_copy(xaccGroupGetAccountList(new_grp));
+  for (accounts = accounts_copy; accounts; accounts = accounts->next)
+  {
+    Account *existing_named, *new_acct;
+    const char *name;
+
+    new_acct = (Account*)accounts->data;
+    name = xaccAccountGetName(new_acct);
+    existing_named = xaccGetAccountFromName(existing_grp, name);
+    switch (determine_account_merge_disposition(existing_named, new_acct))
+    {
+    case GNC_ACCOUNT_MERGE_DISPOSITION_ERROR:
+      g_assert_not_reached();
+      return;
+    case GNC_ACCOUNT_MERGE_DISPOSITION_USE_EXISTING:
+      // recurse
+      account_group_merge(xaccAccountGetChildren(existing_named),
+                          xaccAccountGetChildren(new_acct));
+      break;
+    case GNC_ACCOUNT_MERGE_DISPOSITION_CREATE_NEW:
+      // merge this one in.
+      xaccGroupInsertAccount(existing_grp, new_acct);
+      break;
+    }
+  }
+  g_list_free(accounts_copy);
+}

Added: gnucash/trunk/src/app-utils/gnc-account-merge.h
===================================================================
--- gnucash/trunk/src/app-utils/gnc-account-merge.h	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/app-utils/gnc-account-merge.h	2006-01-15 23:04:19 UTC (rev 12357)
@@ -0,0 +1,29 @@
+// Copyright (C) 2006 Joshua Sled <jsled at asynchronous.org>
+
+#ifndef GNC_ACCOUNT_MERGE_H
+#define GNC_ACCOUNT_MERGE_H
+
+#include "Account.h"
+#include "Group.h"
+
+typedef enum {
+  GNC_ACCOUNT_MERGE_DISPOSITION_ERROR,
+  GNC_ACCOUNT_MERGE_DISPOSITION_USE_EXISTING,
+  GNC_ACCOUNT_MERGE_DISPOSITION_CREATE_NEW
+} GncAccountMergeDisposition;
+
+typedef struct _merge_error {
+  Account *existing;
+  Account *new;
+  GncAccountMergeDisposition disposition;
+} GncAccountMergeError;
+
+GncAccountMergeDisposition determine_account_merge_disposition(Account *existing_acct, Account *new_acct);
+GncAccountMergeDisposition determine_merge_disposition(AccountGroup *existing_root, Account *new_acct);
+
+/** @return GList<GncAccountMergerError> **/
+GList* account_merge_error_detection(AccountGroup *existing, AccountGroup *new);
+
+void account_group_merge(AccountGroup *existing_grp, AccountGroup *new_grp);
+
+#endif // GNC_ACCOUNT_MERGE_H

Modified: gnucash/trunk/src/gnome/dialog-new-user.c
===================================================================
--- gnucash/trunk/src/gnome/dialog-new-user.c	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome/dialog-new-user.c	2006-01-15 23:04:19 UTC (rev 12357)
@@ -33,6 +33,8 @@
 #include "gnc-gconf-utils.h"
 #include "gnc-hooks.h"
 #include "gnc-ui.h"
+#include "gnc-main-window.h"
+#include "gnc-plugin-page-account-tree.h"
 
 #define GCONF_SECTION "dialogs/new_user"
 #define FIRST_STARTUP "first_startup"
@@ -43,10 +45,8 @@
 /* function to open a qif import druid */
 static void (*qifImportDruidFcn)(void) = NULL;
 
-
 static void gnc_ui_new_user_cancel_dialog (void);
 
-
 void
 gnc_new_user_dialog_register_qif_druid (void (*cb_fcn)(void))
 {
@@ -61,6 +61,18 @@
 }
 
 void
+after_hierarchy_druid(void)
+{
+  GncPluginPage *page;
+
+  gncp_new_user_finish ();
+  gnc_set_first_startup (FALSE);
+  
+  page = gnc_plugin_page_account_tree_new();
+  gnc_main_window_open_page(NULL, page);
+}
+
+void
 gnc_ui_new_user_dialog (void)
 {
   GtkWidget *dialog;
@@ -91,10 +103,10 @@
 		break;
 	  case GTK_RESPONSE_OK:
 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (new_accounts_button))) {
-			gnc_ui_hierarchy_druid ();
+			gnc_ui_hierarchy_druid_with_callback(after_hierarchy_druid);
 			break;
-		} else if ((qifImportDruidFcn != NULL) &&
-				gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (import_qif_button))) {
+		} else if ((qifImportDruidFcn != NULL)
+                           && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (import_qif_button))) {
 			qifImportDruidFcn();
 			gncp_new_user_finish ();
 			break;

Modified: gnucash/trunk/src/gnome/druid-hierarchy.c
===================================================================
--- gnucash/trunk/src/gnome/druid-hierarchy.c	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome/druid-hierarchy.c	2006-01-15 23:04:19 UTC (rev 12357)
@@ -30,6 +30,7 @@
 #include <unistd.h>
 
 #include "Group.h"
+#include "gnc-account-merge.h"
 #include "dialog-new-user.h"
 #include "dialog-utils.h"
 #include "druid-hierarchy.h"
@@ -44,12 +45,12 @@
 #include "gnc-component-manager.h"
 #include "../gnome-utils/gnc-dir.h"
 #include "gnc-gui-query.h"
-#include "gnc-main-window.h"
-#include "gnc-plugin-page-account-tree.h"
 #include "gnc-tree-view-account.h"
 #include "gnc-ui-util.h"
 #include "io-example-account.h"
 #include "top-level.h"
+#include "gnc-main-window.h"
+#include "gnc-plugin-page-account-tree.h"
 
 #include "gnc-engine.h"
 static QofLogModule log_module = GNC_MOD_IMPORT; 
@@ -65,10 +66,6 @@
   NUM_COLUMNS
 } ColumnNames;
 
-static GtkWidget *hierarchy_window = NULL;
-GtkWidget *qof_book_merge_window = NULL;
-static AccountGroup *our_final_group = NULL;
-QofBook *temporary;
 
 typedef struct {
   GtkWidget *dialog;
@@ -84,7 +81,16 @@
   GncTreeViewAccount *final_account_tree;
   GtkWidget *final_account_tree_box;
   Account *selected_account;
+  /** Map<Account*,gnc_numeric*> **/
   GHashTable *balance_hash;
+
+  AccountGroup *our_final_group;
+  QofBook *temporary;
+
+  gboolean account_list_added;
+
+  GncHierarchyDruidFinishedCallback when_completed;
+
 } hierarchy_data;
 
 void on_choose_account_categories_prepare (GnomeDruidPage  *gnomedruidpage,
@@ -97,27 +103,25 @@
 void on_final_account_prepare (GnomeDruidPage  *gnomedruidpage,
 			       gpointer         arg1,
 			       hierarchy_data  *data);
+gboolean on_final_account_next (GnomeDruidPage  *gnomedruidpage,
+                                gpointer         arg1,
+                                hierarchy_data  *data);
+
 void on_cancel (GnomeDruid      *gnomedruid, hierarchy_data *data);
 void on_finish (GnomeDruidPage  *gnomedruidpage, gpointer arg1, hierarchy_data *data);
 
+// ------------------------------------------------------------
 
-
 static void
-delete_hierarchy_window (void)
+delete_hierarchy_dialog (hierarchy_data *data)
 {
-  if (!hierarchy_window) return;
-
-  gtk_widget_destroy (hierarchy_window);
-  hierarchy_window = NULL;
+  gtk_widget_destroy (data->dialog);
 }
 
 static void
 destroy_hash_helper (gpointer key, gpointer value, gpointer user_data)
 {
-  char *fullname = key;
   gnc_numeric *balance = value;
-
-  g_free (fullname);
   g_free (balance);
 }
 
@@ -139,15 +143,11 @@
 get_final_balance (GHashTable *hash, Account *account)
 {
   gnc_numeric *balance;
-  char *fullname;
 
   if (!hash || !account)
     return gnc_numeric_zero ();
 
-  fullname = xaccAccountGetFullName (account, ':');
-  balance = g_hash_table_lookup (hash, fullname);
-  g_free (fullname);
-
+  balance = g_hash_table_lookup(hash, account);
   if (balance)
     return *balance;
   return gnc_numeric_zero ();
@@ -157,24 +157,19 @@
 set_final_balance (GHashTable *hash, Account *account, gnc_numeric in_balance)
 {
   gnc_numeric *balance;
-  char *fullname;
 
   if (!hash || !account)
     return;
 
-  fullname = xaccAccountGetFullName (account, ':');
-
-  balance = g_hash_table_lookup (hash, fullname);
+  balance = g_hash_table_lookup (hash, account);
   if (balance) {
     *balance = in_balance;
-    g_free (fullname);
     return;
   }
 
   balance = g_new (gnc_numeric, 1);
   *balance = in_balance;
-  g_hash_table_insert (hash, fullname, balance);
-  /* fullname string now owned by the hash */
+  g_hash_table_insert (hash, account, balance);
 }
 
 static gchar*
@@ -287,7 +282,7 @@
 	GtkCellRenderer *renderer;
 
 	locale_dir = gnc_get_ea_locale_dir (GNC_ACCOUNTS_DIR);
- 	list = gnc_load_example_account_list (temporary,
+ 	list = gnc_load_example_account_list (data->temporary,
 					      locale_dir);
 	g_free (locale_dir);
 
@@ -345,16 +340,11 @@
 				      hierarchy_data  *data)
 {
   GtkTextBuffer* buffer;
-  gpointer added_ptr;
-
-  added_ptr = g_object_get_data (G_OBJECT(hierarchy_window),
-                                 "account_list_added");
-
-  if (GPOINTER_TO_INT(added_ptr) == 0)
+  if (!data->account_list_added)
   {
     /* Build the categories tree if necessary */
     gnc_suspend_gui_refresh ();
-    temporary = qof_book_new();
+    data->temporary = qof_book_new();
     account_categories_tree_view_prepare (data);
     gnc_resume_gui_refresh ();
 
@@ -365,8 +355,7 @@
     buffer = gtk_text_view_get_buffer(data->category_description);
     gtk_text_buffer_set_text(buffer, "", -1);
 
-    g_object_set_data (G_OBJECT(hierarchy_window),
-                       "account_list_added", GINT_TO_POINTER(1));
+    data->account_list_added = TRUE;
   }
 }
 
@@ -450,13 +439,13 @@
  ************************************************************/
 
 static void
-delete_our_final_group (void)
+delete_our_final_group (hierarchy_data *data)
 {
-  if (our_final_group != NULL)
+  if (data->our_final_group != NULL)
   {
-    xaccAccountGroupBeginEdit (our_final_group);
-    xaccAccountGroupDestroy (our_final_group);
-    our_final_group = NULL;
+    xaccAccountGroupBeginEdit (data->our_final_group);
+    xaccAccountGroupDestroy (data->our_final_group);
+    data->our_final_group = NULL;
   }
 }
 
@@ -615,7 +604,17 @@
 	  allow_value = FALSE;
 	  string=_("zero");
 	} else {
-	  allow_value = !xaccAccountGetPlaceholder(account);
+          GncAccountMergeDisposition disp;
+          disp = determine_merge_disposition(gnc_book_get_group(gnc_get_current_book()), account);
+          if (disp == GNC_ACCOUNT_MERGE_DISPOSITION_CREATE_NEW)
+          {
+                  allow_value = !xaccAccountGetPlaceholder(account);
+          }
+          else
+          {
+                  allow_value = FALSE;
+                  string = _("existing account");
+          }
 	}
 	g_object_set (G_OBJECT (cell),
 		      "text", string,
@@ -652,6 +651,44 @@
 	gnc_engine_gen_event ((QofEntity*)account, GNC_EVENT_MODIFY);
 }
 
+static void
+use_existing_account_data_func(GtkTreeViewColumn *tree_column,
+                               GtkCellRenderer *cell,
+                               GtkTreeModel *tree_model,
+                               GtkTreeIter *iter,
+                               gpointer user_data)
+{
+  Account *new_acct;
+  AccountGroup *real_root;
+  GncAccountMergeDisposition disposition;
+  char *to_user = "(error; unknown condition)";
+
+  g_return_if_fail (GTK_TREE_MODEL (tree_model));
+  new_acct = gnc_tree_view_account_get_account_from_iter(tree_model, iter);
+  if (new_acct == NULL)
+  {
+    g_object_set (G_OBJECT(cell), "text", "(null account)", NULL);
+    return;
+  }
+
+  real_root = gnc_book_get_group(gnc_get_current_book());
+  disposition = determine_merge_disposition(real_root, new_acct);
+  switch (disposition)
+  {
+  case GNC_ACCOUNT_MERGE_DISPOSITION_ERROR:
+    to_user = "error: placeholders different";
+    break;
+  case GNC_ACCOUNT_MERGE_DISPOSITION_USE_EXISTING:
+    to_user = "yes";
+    break;
+  case GNC_ACCOUNT_MERGE_DISPOSITION_CREATE_NEW:
+    to_user = "no";
+    break;
+  }
+  
+  g_object_set(G_OBJECT(cell), "text", to_user, NULL);
+}
+
 void
 on_final_account_prepare (GnomeDruidPage  *gnomedruidpage,
                           gpointer         arg1,
@@ -676,18 +713,28 @@
     gtk_widget_destroy(GTK_WIDGET(data->final_account_tree));
     data->final_account_tree = NULL;
   }
-  delete_our_final_group ();
+  delete_our_final_group (data);
 
 
   /* Build a new account list */
   actlist = get_selected_account_list (data->categories_tree);
   com = gnc_currency_edit_get_currency (GNC_CURRENCY_EDIT(data->currency_selector));
-  our_final_group = hierarchy_merge_groups (actlist, com);
+  data->our_final_group = hierarchy_merge_groups (actlist, com);
 
 
   /* Now build a new account tree */
-  data->final_account_tree = GNC_TREE_VIEW_ACCOUNT(gnc_tree_view_account_new_with_group (our_final_group, FALSE));
+  data->final_account_tree
+    = GNC_TREE_VIEW_ACCOUNT(gnc_tree_view_account_new_with_group (data->our_final_group, FALSE));
   tree_view = GTK_TREE_VIEW(data->final_account_tree);
+  gnc_tree_view_account_set_name_edited(data->final_account_tree,
+                                        gnc_tree_view_account_name_edited_cb);
+  gnc_tree_view_account_set_code_edited(data->final_account_tree,
+                                        gnc_tree_view_account_code_edited_cb);
+  gnc_tree_view_account_set_description_edited(data->final_account_tree,
+                                               gnc_tree_view_account_description_edited_cb);
+  gnc_tree_view_account_set_notes_edited(data->final_account_tree,
+                                         gnc_tree_view_account_notes_edited_cb);
+
   gtk_tree_view_set_headers_visible (tree_view, TRUE);
   gnc_tree_view_configure_columns (GNC_TREE_VIEW(data->final_account_tree),
 				   "type", "placeholder", NULL);
@@ -712,6 +759,25 @@
 					   (gpointer)data, NULL);
   gnc_tree_view_append_column (GNC_TREE_VIEW(tree_view), column);
 
+  // only in the case where there *are* existing accounts...
+  if (xaccGroupGetNumSubAccounts(gnc_book_get_group(gnc_get_current_book())) > 0)
+  {
+    GList *renderers;
+    column = gnc_tree_view_add_text_column(GNC_TREE_VIEW(tree_view),
+                                           _("use existing"),
+                                           NULL,
+                                           NULL,
+                                           "yes",
+                                           GNC_TREE_VIEW_COLUMN_DATA_NONE,
+                                           GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
+                                           NULL);
+    renderers = gtk_tree_view_column_get_cell_renderers(column);
+    g_object_set(G_OBJECT(renderer), "xalign", 1.0, (char*)NULL);
+    gtk_tree_view_column_set_cell_data_func(column, GTK_CELL_RENDERER(renderers->data),
+                                            use_existing_account_data_func, (gpointer)data, NULL);
+    g_list_free(renderers);
+  }
+
   gtk_container_add(GTK_CONTAINER(data->final_account_tree_box),
 		    GTK_WIDGET(data->final_account_tree));
 
@@ -721,20 +787,47 @@
   gnc_resume_gui_refresh ();
 }
 
+static void _glist_free_helper(gpointer elt, gpointer user_data)
+{
+  g_free(elt);
+}
 
+gboolean
+on_final_account_next (GnomeDruidPage  *gnomedruidpage,
+                       gpointer         arg1,
+                       hierarchy_data  *data)
+{
+  GList *errors;
+  gboolean has_errors;
+
+  errors  = account_merge_error_detection(gnc_book_get_group(gnc_get_current_book()),
+                                          data->our_final_group);
+  has_errors = (g_list_length(errors) > 0);
+  if (has_errors)
+  {
+    gnc_info_dialog(data->dialog, "%d accounts in error, please resolve.", g_list_length(errors));
+  }
+
+  {
+    g_list_foreach(errors, _glist_free_helper, NULL);
+    g_list_free(errors);
+  }
+
+  return has_errors;
+}
+
 void
 on_cancel (GnomeDruid      *gnomedruid,
 	   hierarchy_data  *data)
 {
   gnc_suspend_gui_refresh ();
-  delete_hierarchy_window ();
-  delete_our_final_group ();
+  delete_hierarchy_dialog (data);
+  delete_our_final_group (data);
   gncp_new_user_finish ();
   g_free(data);
   gnc_resume_gui_refresh ();
 }
 
-
 static gpointer
 starting_balance_helper (Account *account, hierarchy_data *data)
 {
@@ -753,48 +846,40 @@
            gpointer         arg1,
            hierarchy_data  *data)
 {
+        GncHierarchyDruidFinishedCallback when_completed;
+	ENTER (" ");
+
+	if (data->our_final_group)
+        {
+	  xaccGroupForEachAccount (data->our_final_group,
+                                   (AccountCallback)starting_balance_helper,
+				   data, TRUE);
+        }
+
+        // delete before we suspend GUI events, and then muck with the model,
+        // because the model doesn't seem to handle this correctly.
+	delete_hierarchy_dialog (data);
+
 	gnc_suspend_gui_refresh ();
-	
-	if (our_final_group)
-	  xaccGroupForEachAccount (our_final_group, (AccountCallback)starting_balance_helper,
-				   data, TRUE);
-	ENTER (" ");
-	qof_book_merge_window = g_object_get_data (G_OBJECT (hierarchy_window), "Merge Druid");
-	if(qof_book_merge_window) {
-		DEBUG ("qof_book_merge_window found");
-		if (our_final_group) 
-			xaccGroupConcatGroup (gnc_get_current_group (), our_final_group);
-		gtk_widget_show(qof_book_merge_window);
-		qof_book_destroy(temporary);
-		delete_hierarchy_window ();
-		gnc_resume_gui_refresh ();
-		LEAVE (" ");
-		return;
-	}
-	delete_hierarchy_window ();
-	
-	gncp_new_user_finish ();
-	
-	gnc_set_first_startup (FALSE);
-	
-	if (our_final_group)
-	  xaccGroupConcatGroup (gnc_get_current_group (), our_final_group);
-	qof_book_destroy(temporary);
-	
+
+        account_group_merge(gnc_get_current_group(), data->our_final_group);
+
+        delete_our_final_group (data);
+        qof_book_destroy(data->temporary);
+
+        when_completed = data->when_completed;
 	g_free(data);
 	gnc_resume_gui_refresh ();
+        if (when_completed)
+        {
+                (*when_completed)();
+        }
 
-	{
-	  GncPluginPage *page;
-
-	  page = gnc_plugin_page_account_tree_new();
-	  gnc_main_window_open_page(NULL, page);
-	}
 	LEAVE (" ");
 }
 
 static GtkWidget *
-gnc_create_hierarchy_druid (void)
+gnc_create_hierarchy_druid (GncHierarchyDruidFinishedCallback when_completed)
 {
 	hierarchy_data *data;
 	GtkWidget *dialog;
@@ -840,38 +925,43 @@
 	data->final_account_tree_box = glade_xml_get_widget (xml, "final_account_tree_box");
 	data->final_account_tree = NULL;
 	
-	data->balance_hash = g_hash_table_new (g_str_hash, g_str_equal);
+	data->balance_hash = g_hash_table_new(NULL, NULL);
 	
 	g_signal_connect (G_OBJECT(dialog), "destroy",
 			  G_CALLBACK (gnc_hierarchy_destroy_cb), data);
 	
 	glade_xml_signal_autoconnect_full(xml, gnc_glade_autoconnect_full_func, data);
+
+        data->when_completed = when_completed;
 	
 	return dialog;
 }
 
 GtkWidget*
-gnc_ui_hierarchy_running (void)
+gnc_ui_hierarchy_druid(void)
 {
-	if (hierarchy_window) return hierarchy_window;
-	return NULL;
+  return gnc_create_hierarchy_druid(NULL);
 }
 
-void
-gnc_ui_hierarchy_druid (void)
+GtkWidget*
+gnc_ui_hierarchy_druid_with_callback(GncHierarchyDruidFinishedCallback when_finished)
 {
-	if (hierarchy_window) return;
+  return gnc_create_hierarchy_druid(when_finished);
+}
 
-	hierarchy_window = gnc_create_hierarchy_druid ();
-
-	return;
+static void
+create_account_page(void)
+{
+  GncPluginPage *page;
+  page = gnc_plugin_page_account_tree_new();
+  gnc_main_window_open_page(NULL, page);
 }
 
 static void
 gnc_ui_hierarchy_druid_hook (void)
 {
   if (gnc_gconf_get_bool(GCONF_SECTION, "show_on_new_file", NULL)) {
-    gnc_ui_hierarchy_druid();
+    gnc_ui_hierarchy_druid_with_callback(create_account_page);
   }
 }
 
@@ -881,3 +971,5 @@
   gnc_hook_add_dangler(HOOK_NEW_BOOK,
 		       (GFunc)gnc_ui_hierarchy_druid_hook, NULL);
 }
+
+

Modified: gnucash/trunk/src/gnome/druid-hierarchy.h
===================================================================
--- gnucash/trunk/src/gnome/druid-hierarchy.h	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome/druid-hierarchy.h	2006-01-15 23:04:19 UTC (rev 12357)
@@ -23,7 +23,17 @@
 #ifndef DRUID_HIERARCHY_H
 #define DRUID_HIERARCHY_H
 
-void gnc_ui_hierarchy_druid (void);
-GtkWidget* gnc_ui_hierarchy_running (void);
+/**
+ * A callback (provided by the caller) to be invoked when the druid
+ * completes successfully.  I.e., the new-user druid can finish the GnuCash
+ * New-User Experience, create an account plugin-page, &c.
+ **/
+
+typedef void (*GncHierarchyDruidFinishedCallback)(void);
+
+GtkWidget* gnc_ui_hierarchy_druid (void);
+GtkWidget* gnc_ui_hierarchy_druid_with_callback(GncHierarchyDruidFinishedCallback when_finished);
+
 void gnc_ui_hierarchy_druid_initialize (void);
+
 #endif

Modified: gnucash/trunk/src/gnome/druid-merge.c
===================================================================
--- gnucash/trunk/src/gnome/druid-merge.c	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome/druid-merge.c	2006-01-15 23:04:19 UTC (rev 12357)
@@ -88,16 +88,6 @@
 
 
 
-static gboolean
-on_qof_start_page_next(GnomeDruidPage  *gnomedruidpage,
-                       gpointer         arg1,
-                       gpointer         user_data)
-{
-	gtk_widget_show(druid_hierarchy_window);
-	gtk_widget_hide(qof_book_merge_window);
-	return FALSE;
-}
-
 static void
 on_MergeUpdate_clicked 	(GtkButton       *button,
               		    gpointer         user_data)
@@ -154,25 +144,6 @@
 	return FALSE;
 }
 
-static gboolean
-on_qof_book_merge_next (GnomeDruidPage  *gnomedruidpage,
-                       gpointer         arg1,
-                       gpointer         user_data)
-{
-    GtkWidget *top;
-    const char *message = _("You must resolve all collisions.");
-
-	ENTER (" count=%d", count);
-	if(count > 0) {
-		top = gtk_widget_get_toplevel (GTK_WIDGET (gnomedruidpage));
-	    gnc_error_dialog(top, message);
-		return TRUE;
-	}
-	buffer = "";
-	LEAVE (" ");
-	return FALSE;
-}
-
 static void
 on_merge_cancel (	GnomeDruid      *gnomedruid,
 			gpointer         user_data)
@@ -292,48 +263,6 @@
 	return dialog;
 }
 
-static GtkWidget *
-gnc_create_merge_druid ( void )
-{
-  GtkWidget *dialog;
-  GtkWidget *druid;
-  GladeXML *xml;
-
-	xml = gnc_glade_xml_new ("merge.glade", "Merge Druid");
-
-	glade_xml_signal_connect(xml, "on_start_page_next",
-		G_CALLBACK (on_qof_start_page_next));
-	
-	glade_xml_signal_connect(xml, "on_qof_book_merge_prepare",
-		G_CALLBACK (on_merge_prepare));
-
-	glade_xml_signal_connect(xml, "on_qof_book_merge_next",
-		G_CALLBACK (on_qof_book_merge_next));
-
-	glade_xml_signal_connect (xml, "on_finish", 
-		G_CALLBACK (on_merge_finish));
-
-	glade_xml_signal_connect (xml, "on_cancel", 
-		G_CALLBACK (on_merge_cancel));
-	
-	glade_xml_signal_connect (xml, "on_MergeUpdate_clicked",
-		G_CALLBACK (on_MergeUpdate_clicked));
-		
-	glade_xml_signal_connect (xml, "on_MergeDuplicate_clicked",
-		G_CALLBACK (on_MergeDuplicate_clicked));
-		
-	glade_xml_signal_connect (xml, "on_MergeNew_clicked",
-		G_CALLBACK (on_MergeNew_clicked));
-
-	dialog = glade_xml_get_widget (xml, "Merge Druid");
-	druid = glade_xml_get_widget (xml, "merge_druid");
-	gnc_druid_set_colors (GNOME_DRUID (druid));
-
-	gtk_signal_connect (GTK_OBJECT(dialog), "destroy",
-                      G_CALLBACK(qof_book_merge_destroy_cb), NULL);
-	return dialog;
-}
-
 void collision_rule_loop(qof_book_mergeData *mergeData, qof_book_mergeRule *rule, guint remainder)
 {
 	GSList *user_reports;
@@ -403,30 +332,3 @@
 	mergeBook = qof_session_get_book(merge_session);
 	gtk_widget_show(qsf_import_merge_window);
 }
-
-void
-gnc_ui_qof_book_merge_druid (void)
-{
-	if (qof_book_merge_window) return;
-	/*	QofSession changes to avoid using current book */
-	gnc_engine_suspend_events ();
-	previous_session = qof_session_get_current_session();
-	targetBook = qof_session_get_book(previous_session);
-	merge_session = qof_session_new();
-	qof_session_set_current_session(merge_session);
-	mergeBook = qof_session_get_book(merge_session);
-	gnc_engine_resume_events ();
-	g_return_if_fail(targetBook != NULL);
-	g_return_if_fail(mergeBook != NULL);
-	g_return_if_fail(merge_session != NULL);
-	qof_book_merge_window = gnc_create_merge_druid();
-	g_return_if_fail(qof_book_merge_window != NULL);
-	gnc_ui_hierarchy_druid();
-	druid_hierarchy_window = gnc_ui_hierarchy_running();
-	gtk_widget_hide (druid_hierarchy_window);
-	g_object_set_data (G_OBJECT (druid_hierarchy_window), "Merge Druid", qof_book_merge_window);
-	gtk_widget_show_all (qof_book_merge_window);
-	g_return_if_fail(targetBook != NULL);
-	g_return_if_fail(mergeBook != NULL);
-	g_return_if_fail(merge_session != NULL);
-}

Modified: gnucash/trunk/src/gnome/druid-merge.h
===================================================================
--- gnucash/trunk/src/gnome/druid-merge.h	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome/druid-merge.h	2006-01-15 23:04:19 UTC (rev 12357)
@@ -74,8 +74,6 @@
 	@author Copyright (c) 2004 Neil Williams <linux at codehelp.co.uk>
 */
 
-void gnc_ui_qof_book_merge_druid (void);
-
 void gnc_ui_qsf_import_merge_druid(QofSession *original, QofSession *import);
 
 GtkWidget* qof_book_merge_running (void);

Modified: gnucash/trunk/src/gnome/glade/account.glade
===================================================================
--- gnucash/trunk/src/gnome/glade/account.glade	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome/glade/account.glade	2006-01-15 23:04:19 UTC (rev 12357)
@@ -1147,7 +1147,7 @@
   <property name="visible">True</property>
   <property name="title" translatable="yes">New Account Hierarchy Setup</property>
   <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
   <property name="modal">False</property>
   <property name="default_width">640</property>
   <property name="default_height">500</property>
@@ -1156,7 +1156,7 @@
   <property name="decorated">True</property>
   <property name="skip_taskbar_hint">False</property>
   <property name="skip_pager_hint">False</property>
-  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
   <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
 
   <child>
@@ -1336,9 +1336,6 @@
 				      <property name="rules_hint">True</property>
 				      <property name="reorderable">True</property>
 				      <property name="enable_search">True</property>
-				      <property name="fixed_height_mode">False</property>
-				      <property name="hover_selection">False</property>
-				      <property name="hover_expand">False</property>
 				    </widget>
 				  </child>
 				</widget>
@@ -1598,8 +1595,9 @@
       <child>
 	<widget class="GnomeDruidPageStandard" id="final_account_page">
 	  <property name="visible">True</property>
-	  <property name="title" translatable="yes">Enter opening balances</property>
+	  <property name="title" translatable="yes">Setup new accounts</property>
 	  <signal name="prepare" handler="on_final_account_prepare"/>
+	  <signal name="next" handler="on_final_account_next" last_modification_time="Sun, 15 Jan 2006 16:54:20 GMT"/>
 
 	  <child internal-child="vbox">
 	    <widget class="GtkVBox" id="druid-vbox3">
@@ -1951,8 +1949,6 @@
 			      <property name="items">USD
 GBP
 EUR</property>
-			      <property name="add_tearoffs">False</property>
-			      <property name="focus_on_click">True</property>
 			    </widget>
 			  </child>
 			</widget>
@@ -2045,9 +2041,6 @@
 					  <property name="rules_hint">False</property>
 					  <property name="reorderable">False</property>
 					  <property name="enable_search">True</property>
-					  <property name="fixed_height_mode">False</property>
-					  <property name="hover_selection">False</property>
-					  <property name="hover_expand">False</property>
 					</widget>
 				      </child>
 				    </widget>
@@ -2199,9 +2192,6 @@
 				      <property name="rules_hint">False</property>
 				      <property name="reorderable">False</property>
 				      <property name="enable_search">True</property>
-				      <property name="fixed_height_mode">False</property>
-				      <property name="hover_selection">False</property>
-				      <property name="hover_expand">False</property>
 				    </widget>
 				  </child>
 				</widget>
@@ -2304,9 +2294,6 @@
 		      <property name="rules_hint">False</property>
 		      <property name="reorderable">False</property>
 		      <property name="enable_search">True</property>
-		      <property name="fixed_height_mode">False</property>
-		      <property name="hover_selection">False</property>
-		      <property name="hover_expand">False</property>
 		    </widget>
 		  </child>
 		</widget>
@@ -3025,9 +3012,6 @@
 		  <property name="rules_hint">True</property>
 		  <property name="reorderable">False</property>
 		  <property name="enable_search">True</property>
-		  <property name="fixed_height_mode">False</property>
-		  <property name="hover_selection">False</property>
-		  <property name="hover_expand">False</property>
 		</widget>
 		<packing>
 		  <property name="left_attach">0</property>

Modified: gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c	2006-01-15 23:04:19 UTC (rev 12357)
@@ -47,7 +47,7 @@
 #include "dialog-account.h"
 #include "dialog-transfer.h"
 #include "dialog-utils.h"
-#include "druid-merge.h"
+#include "druid-hierarchy.h"
 #include "gnc-account-sel.h"
 #include "gnc-component-manager.h"
 #include "gnc-engine.h"
@@ -118,7 +118,7 @@
 
 /* Command callbacks */
 static void gnc_plugin_page_account_tree_cmd_new_account (GtkAction *action, GncPluginPageAccountTree *plugin_page);
-static void gnc_plugin_page_account_tree_cmd_file_hierarchy_merge (GtkAction *action, GncPluginPageAccountTree *plugin_page);
+static void gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *plugin_page);
 static void gnc_plugin_page_account_tree_cmd_open_account (GtkAction *action, GncPluginPageAccountTree *page);
 static void gnc_plugin_page_account_tree_cmd_open_subaccounts (GtkAction *action, GncPluginPageAccountTree *page);
 static void gnc_plugin_page_account_tree_cmd_edit_account (GtkAction *action, GncPluginPageAccountTree *page);
@@ -146,7 +146,7 @@
 	  G_CALLBACK (gnc_plugin_page_account_tree_cmd_new_account) },
 	{ "FileAddAccountHierarchyDruidAction", GNC_STOCK_NEW_ACCOUNT, N_("New Account _Hierarchy..."), NULL,
 	  N_("Extend the current book by merging with new account type categories"),
-	  G_CALLBACK (gnc_plugin_page_account_tree_cmd_file_hierarchy_merge) },
+	  G_CALLBACK (gnc_plugin_page_account_tree_cmd_file_new_hierarchy) },
 	{ "FileOpenAccountAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _Account"), NULL,
 	  N_("Open the selected account"),
 	  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_account) },
@@ -422,6 +422,15 @@
 		     "show-column-menu", TRUE,
 		     NULL);
 
+        gnc_tree_view_account_set_name_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
+                                              gnc_tree_view_account_name_edited_cb);
+        gnc_tree_view_account_set_code_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
+                                              gnc_tree_view_account_code_edited_cb);
+        gnc_tree_view_account_set_description_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
+                                                     gnc_tree_view_account_description_edited_cb);
+        gnc_tree_view_account_set_notes_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
+                                               gnc_tree_view_account_notes_edited_cb);
+
 	priv->tree_view = tree_view;
 	selection = gtk_tree_view_get_selection(tree_view);
 	g_signal_connect (G_OBJECT (selection), "changed",
@@ -646,9 +655,9 @@
 }
 
 static void
-gnc_plugin_page_account_tree_cmd_file_hierarchy_merge (GtkAction *action, GncPluginPageAccountTree *page)
+gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *page)
 {
-	gnc_ui_qof_book_merge_druid();
+        gnc_ui_hierarchy_druid();
 }
 
 static void

Modified: gnucash/trunk/src/gnome-utils/gnc-tree-view-account.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-tree-view-account.c	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome-utils/gnc-tree-view-account.c	2006-01-15 23:04:19 UTC (rev 12357)
@@ -62,6 +62,11 @@
                                                      GtkTreeIter *iter,
                                                      gpointer data);
 
+static void gtva_setup_column_renderer_edited_cb(GncTreeViewAccount *account_view,
+                                                 GtkTreeViewColumn *column,
+                                                 GtkCellRenderer *renderer,
+                                                 GncTreeViewAccountColumnTextEdited col_edited_cb);
+
 typedef struct GncTreeViewAccountPrivate
 {
     AccountViewInfo avi;
@@ -69,6 +74,11 @@
     gnc_tree_view_account_filter_func filter_fn;
     gpointer                          filter_data;
     GtkDestroyNotify                  filter_destroy;
+
+  GtkTreeViewColumn *name_column;
+  GtkTreeViewColumn *code_column;
+  GtkTreeViewColumn *desc_column;
+  GtkTreeViewColumn *notes_column;
 } GncTreeViewAccountPrivate;
 
 #define GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(o)  \
@@ -345,12 +355,15 @@
   GtkTreeModel *model, *f_model, *s_model;
   GtkTreePath *virtual_root_path = NULL;
   const gchar *sample_type, *sample_commodity;
+  GncTreeViewAccountPrivate *priv;
 
   ENTER(" ");
   /* Create our view */
   view = g_object_new (GNC_TYPE_TREE_VIEW_ACCOUNT,
                        "name", "account_tree", NULL);
 
+  priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(GNC_TREE_VIEW_ACCOUNT (view));
+
   /* Create/get a pointer to the existing model for this set of books. */
   model = gnc_tree_model_account_new (group);
 
@@ -378,11 +391,12 @@
   sample_type = xaccAccountGetTypeStr(CREDIT);
   sample_commodity = gnc_commodity_get_fullname(gnc_default_currency());
 
-  gnc_tree_view_add_text_column(view, N_("Account Name"), "name",
-				GNC_STOCK_ACCOUNT, "Expenses:Entertainment",
-				GNC_TREE_MODEL_ACCOUNT_COL_NAME,
-				GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
-				NULL);
+  priv->name_column 
+    = gnc_tree_view_add_text_column(view, N_("Account Name"), "name",
+                                    GNC_STOCK_ACCOUNT, "Expenses:Entertainment",
+                                    GNC_TREE_MODEL_ACCOUNT_COL_NAME,
+                                    GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
+                                    NULL);
   gnc_tree_view_add_text_column(view, N_("Type"), "type", NULL, sample_type,
 				GNC_TREE_MODEL_ACCOUNT_COL_TYPE,
 				GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
@@ -392,16 +406,18 @@
 				GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY,
 				GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
 				NULL);
-  gnc_tree_view_add_text_column(view, N_("Account Code"), "account-code", NULL,
-				"1-123-1234",
-				GNC_TREE_MODEL_ACCOUNT_COL_CODE,
-				GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
-				NULL);
-  gnc_tree_view_add_text_column(view, N_("Description"), "description", NULL,
-				"Sample account description.",
-				GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION,
-				GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
-				NULL);
+  priv->code_column
+    = gnc_tree_view_add_text_column(view, N_("Account Code"), "account-code", NULL,
+                                    "1-123-1234",
+                                    GNC_TREE_MODEL_ACCOUNT_COL_CODE,
+                                    GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
+                                    NULL);
+  priv->desc_column
+    = gnc_tree_view_add_text_column(view, N_("Description"), "description", NULL,
+                                    "Sample account description.",
+                                    GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION,
+                                    GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
+                                    NULL);
   gnc_tree_view_add_numeric_column(view, N_("Last Num"), "lastnum", "12345",
 				   GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM,
 				   GNC_TREE_VIEW_COLUMN_COLOR_NONE,
@@ -479,11 +495,12 @@
 				   GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL,
 				   GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
 				   sort_by_total_value);
-  gnc_tree_view_add_text_column(view, N_("Notes"), "notes", NULL,
-				"Sample account notes.",
-				GNC_TREE_MODEL_ACCOUNT_COL_NOTES,
-				GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
-				NULL);
+  priv->notes_column
+    = gnc_tree_view_add_text_column(view, N_("Notes"), "notes", NULL,
+                                    "Sample account notes.",
+                                    GNC_TREE_MODEL_ACCOUNT_COL_NOTES,
+                                    GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
+                                    NULL);
   gnc_tree_view_add_text_column(view, N_("Tax Info"), "tax-info", NULL,
 				"Sample tax info.",
 				GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO,
@@ -1291,6 +1308,37 @@
     g_free(text);
 }
 
+/**
+ * If col_edited_cb is null, the editing callback (helper) will be
+ * effectively disconnected.
+ **/
+void
+gtva_setup_column_renderer_edited_cb(GncTreeViewAccount *account_view,
+                                     GtkTreeViewColumn *column,
+                                     GtkCellRenderer *renderer,
+                                     GncTreeViewAccountColumnTextEdited col_edited_cb)
+{
+  GtkTreeModel *s_model;
+
+  if (col_edited_cb == NULL)
+  {
+    g_object_set(G_OBJECT(renderer), "editable", FALSE, NULL);
+    g_object_set_data(G_OBJECT(renderer), "column_edited_callback", col_edited_cb);
+    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(account_view));
+    g_signal_handlers_disconnect_by_func(G_OBJECT(renderer), col_edited_cb, s_model);
+    g_object_set_data(G_OBJECT(renderer), "column_view", column);
+  }
+  else
+  {
+    g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL);
+    g_object_set_data(G_OBJECT(renderer), "column_edited_callback",
+                      col_edited_cb);
+    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(account_view));
+    g_signal_connect(G_OBJECT(renderer), "edited", 
+                     (GCallback) col_edited_helper, s_model);
+    g_object_set_data(G_OBJECT(renderer), "column_view", column);
+  }
+}
  
 GtkTreeViewColumn *
 gnc_tree_view_account_add_custom_column(GncTreeViewAccount *account_view,
@@ -1302,7 +1350,6 @@
 {
     GtkCellRenderer *renderer;
     GtkTreeViewColumn *column;
-    GtkTreeModel *s_model;
     
     g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (account_view), NULL);
     
@@ -1312,13 +1359,7 @@
     column = gtk_tree_view_column_new_with_attributes (column_title,
                                                        renderer, NULL);
     if (col_edited_cb) {
-        g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL);
-        g_object_set_data(G_OBJECT(renderer), "column_edited_callback",
-                          col_edited_cb);
-        s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(account_view));
-        g_signal_connect(G_OBJECT(renderer), "edited", 
-                         (GCallback) col_edited_helper, s_model);
-        g_object_set_data(G_OBJECT(renderer), "column_view", column);
+      gtva_setup_column_renderer_edited_cb(account_view, column, renderer, col_edited_cb);
     }
     gtk_tree_view_column_set_cell_data_func (column, renderer, 
                                              col_source_helper,
@@ -1793,3 +1834,95 @@
     /* Update tree view for any changes */
     gnc_tree_view_account_refilter(view);
 }
+
+// @@fixme -- factor this app-not-gui-specific-logic out.
+void
+gnc_tree_view_account_name_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_name)
+{
+  // check for accounts with the same name in our parent's group.
+  // should probably factor this consistency check out to the account
+  // itself... or maybe the account group.
+  {
+    AccountGroup *parent = xaccAccountGetParent(account);
+    Account *existing = xaccGetAccountFromName(parent, new_name);
+    if (existing != NULL && existing != account)
+    {
+      PERR("account with the same name [%s] already exists.", new_name);
+      return;
+    }
+  }
+  xaccAccountSetName(account, new_name);
+}
+
+void
+gnc_tree_view_account_code_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_code)
+{
+  xaccAccountSetCode(account, new_code);
+}
+
+void
+gnc_tree_view_account_description_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_desc)
+{
+  xaccAccountSetDescription(account, new_desc);
+}
+
+void
+gnc_tree_view_account_notes_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_notes)
+{
+  xaccAccountSetNotes(account, new_notes);
+}
+
+static void
+gtva_set_column_editor(GncTreeViewAccount *view,
+                       GtkTreeViewColumn *column,
+                       GncTreeViewAccountColumnTextEdited edited_cb)
+{
+  GList *renderers_orig, *renderers;
+  GtkCellRenderer *renderer;
+  
+  // look for the first text-renderer; on the 0th column of the account tree,
+  // there are two renderers: pixbuf and text.  So find the text one.
+  for (renderers_orig = renderers = gtk_tree_view_column_get_cell_renderers(column);
+       renderers && !GTK_IS_CELL_RENDERER_TEXT(renderers->data);
+       renderers = renderers->next);
+  renderer = GTK_CELL_RENDERER(renderers->data);
+  g_list_free(renderers_orig);
+  g_return_if_fail(renderer != NULL);
+  gtva_setup_column_renderer_edited_cb(GNC_TREE_VIEW_ACCOUNT(view), column, renderer, edited_cb);
+}
+
+void
+gnc_tree_view_account_set_name_edited(GncTreeViewAccount *view,
+                                      GncTreeViewAccountColumnTextEdited edited_cb)
+{
+  GncTreeViewAccountPrivate *priv;
+  priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view);
+  gtva_set_column_editor(view, priv->name_column, edited_cb);
+}
+
+void
+gnc_tree_view_account_set_code_edited(GncTreeViewAccount *view,
+                                      GncTreeViewAccountColumnTextEdited edited_cb)
+{
+  GncTreeViewAccountPrivate *priv;
+  priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view);
+  gtva_set_column_editor(view, priv->code_column, edited_cb);
+}
+
+void
+gnc_tree_view_account_set_description_edited(GncTreeViewAccount *view,
+                                             GncTreeViewAccountColumnTextEdited edited_cb)
+{
+  GncTreeViewAccountPrivate *priv;
+  priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view);
+  gtva_set_column_editor(view, priv->desc_column, edited_cb);
+}
+
+void
+gnc_tree_view_account_set_notes_edited(GncTreeViewAccount *view,
+                                       GncTreeViewAccountColumnTextEdited edited_cb)
+{
+  GncTreeViewAccountPrivate *priv;
+  priv = GNC_TREE_VIEW_ACCOUNT_GET_PRIVATE(view);
+  gtva_set_column_editor(view, priv->notes_column, edited_cb);
+}

Modified: gnucash/trunk/src/gnome-utils/gnc-tree-view-account.h
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-tree-view-account.h	2006-01-15 22:19:13 UTC (rev 12356)
+++ gnucash/trunk/src/gnome-utils/gnc-tree-view-account.h	2006-01-15 23:04:19 UTC (rev 12357)
@@ -180,8 +180,22 @@
     GncTreeViewAccountColumnSource source_cb, 
     GncTreeViewAccountColumnTextEdited edited_cb);
 
+void gnc_tree_view_account_set_name_edited(GncTreeViewAccount *view,
+                                           GncTreeViewAccountColumnTextEdited edited_cb);
+void gnc_tree_view_account_name_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_name);
 
+void gnc_tree_view_account_set_code_edited(GncTreeViewAccount *view,
+                                           GncTreeViewAccountColumnTextEdited edited_cb);
+void gnc_tree_view_account_code_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_code);
 
+void gnc_tree_view_account_set_description_edited(GncTreeViewAccount *view,
+                                                  GncTreeViewAccountColumnTextEdited edited_cb);
+void gnc_tree_view_account_description_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_desc);
+
+void gnc_tree_view_account_set_notes_edited(GncTreeViewAccount *view,
+                                            GncTreeViewAccountColumnTextEdited edited_cb);
+void gnc_tree_view_account_notes_edited_cb(Account *account, GtkTreeViewColumn *col, const gchar *new_notes);
+
 /** Add a new column to the set of columns in an account tree view.
  *  This column will be visible as soon as it is added and will
  *  display the contents of the specified KVP slot.
@@ -197,6 +211,7 @@
 void gnc_tree_view_account_add_kvp_column (GncTreeViewAccount *view,
 					   const gchar *column_title,
 					   const gchar *kvp_key);
+
 /** @} */
 
 



More information about the gnucash-changes mailing list