[Gnucash-changes] r11905 - gnucash/trunk - Add code to save window state into a Glib Key-Value file. This code

David Hampton hampton at cvs.gnucash.org
Fri Nov 11 09:16:16 EST 2005


Author: hampton
Date: 2005-11-11 09:16:12 -0500 (Fri, 11 Nov 2005)
New Revision: 11905

Modified:
   gnucash/trunk/ChangeLog
   gnucash/trunk/src/app-utils/file-utils.c
   gnucash/trunk/src/app-utils/file-utils.h
   gnucash/trunk/src/app-utils/guile-util.c
   gnucash/trunk/src/app-utils/guile-util.h
   gnucash/trunk/src/business/business-gnome/gnc-plugin-business.c
   gnucash/trunk/src/business/business-gnome/gnc-plugin-page-invoice.h
   gnucash/trunk/src/gnome-utils/Makefile.am
   gnucash/trunk/src/gnome-utils/gnc-main-window.c
   gnucash/trunk/src/gnome-utils/gnc-plugin-page.c
   gnucash/trunk/src/gnome-utils/gnc-plugin-page.h
   gnucash/trunk/src/gnome-utils/ui/gnc-main-window-ui.xml
   gnucash/trunk/src/gnome/Makefile.am
   gnucash/trunk/src/gnome/gnc-plugin-account-tree.c
   gnucash/trunk/src/gnome/gnc-plugin-account-tree.h
   gnucash/trunk/src/gnome/gnc-plugin-budget.c
   gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c
   gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.h
   gnucash/trunk/src/gnome/gnc-plugin-page-budget.h
   gnucash/trunk/src/gnome/gnc-plugin-page-register.c
   gnucash/trunk/src/gnome/gnc-plugin-register.c
   gnucash/trunk/src/gnome/gw-gnc-spec.scm
   gnucash/trunk/src/report/report-gnome/Makefile.am
   gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.c
   gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.h
   gnucash/trunk/src/report/report-gnome/window-report.c
   gnucash/trunk/src/scm/main-window.scm
Log:
Add code to save window state into a Glib Key-Value file.  This code
is distributed between the gnc-main-window code and all of the plugin
pages.  It subsumes the existing state file code, and will call that
code upon file open if it cannot find a key-value state file.  This
code is also where the creation of the initial account tree page
occurs when no state file is found.


Modified: gnucash/trunk/ChangeLog
===================================================================
--- gnucash/trunk/ChangeLog	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/ChangeLog	2005-11-11 14:16:12 UTC (rev 11905)
@@ -1,5 +1,29 @@
 2005-11-11  David Hampton  <hampton at employees.org>
 
+	* src/app-utils/file-utils.[ch]:
+	* src/app-utils/guile-util.[ch]:
+	* src/business/business-gnome/gnc-plugin-business.c:
+	* src/business/business-gnome/gnc-plugin-page-invoice.h:
+	* src/gnome-utils/gnc-main-window.c:
+	* src/gnome-utils/gnc-plugin-page.[ch]:
+	* src/gnome-utils/ui/gnc-main-window-ui.xml:
+	* src/gnome/gnc-plugin-account-tree.[ch]:
+	* src/gnome/gnc-plugin-budget.c:
+	* src/gnome/gnc-plugin-page-account-tree.[ch]:
+	* src/gnome/gnc-plugin-page-budget.h:
+	* src/gnome/gnc-plugin-page-register.c:
+	* src/gnome/gnc-plugin-register.c:
+	* src/gnome/gw-gnc-spec.scm:
+	* src/report/report-gnome/gnc-plugin-page-report.[ch]:
+	* src/report/report-gnome/window-report.c:
+	* src/scm/main-window.scm: Add code to save window state into a
+	Glib Key-Value file.  This code is distributed between the
+	gnc-main-window code and all of the plugin pages.  It subsumes the
+	existing state file code, and will call that code upon file open
+	if it cannot find a key-value state file.  This code is also where
+	the creation of the initial account tree page occurs when no state
+	file is found.
+
 	* lib/glib26/gkeyfile.c:
 	* lib/glib26/gutils26.c: Fix a couple of gcc4 warnings.
 

Modified: gnucash/trunk/src/app-utils/file-utils.c
===================================================================
--- gnucash/trunk/src/app-utils/file-utils.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/app-utils/file-utils.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -34,6 +34,7 @@
 #include "file-utils.h"
 #include "messages.h"
 #include "gnc-engine.h"
+#include "gnc-gkeyfile-utils.h"
  
 /* This static indicates the debugging module that this .o belongs to.  */
 static QofLogModule log_module = GNC_MOD_GUILE;
@@ -166,4 +167,73 @@
 }
 
 
+/*  Find the state file that corresponds to this URL and guid.  The
+ *  URL is used to compute the base name of the file (which will be in
+ *  ~/.gnucash/books) and the guid is used to differentiate when the
+ *  user has multiple data files with the same name. */
+GKeyFile *
+gnc_find_state_file (const gchar *url,
+		     const gchar *guid,
+		     gchar **filename_p)
+{
+  gchar *basename, *original = NULL, *filename, *tmp, *file_guid;
+  GKeyFile *key_file = NULL;
+  GError *error = NULL;
+  gint i;
+
+  ENTER("url %s, guid %s", url, guid);
+  tmp = index(url, ':');
+  if (tmp)
+    url = tmp + 1;
+
+  basename = g_path_get_basename(url);
+  DEBUG("Basename %s", basename);
+  original = g_build_filename(g_get_home_dir(), ".gnucash",
+			      "books", basename, NULL);
+  g_free(basename);
+  DEBUG("Original %s", original);
+
+  i = 1;
+  while (1) {
+    if (i == 1)
+      filename = g_strdup(original);
+    else
+      filename = g_strdup_printf("%s_%d", original, i);
+    DEBUG("Trying %s", filename);
+    key_file = gnc_key_file_load_from_file(filename, FALSE);
+    DEBUG("Result %p", key_file);
+
+    if (!key_file) {
+      DEBUG("No key file by that name");
+      break;
+    }
+
+    file_guid = g_key_file_get_string(key_file,
+				      STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
+				      &error);
+    DEBUG("File GUID is %s", file_guid);
+    if (strcmp(guid, file_guid) == 0) {
+      DEBUG("Matched !!!");
+      g_free(file_guid);
+      break;
+    }
+
+    DEBUG("Clean up this pass");
+    g_free(file_guid);
+    g_key_file_free(key_file);
+    g_free(filename);
+    i++;
+  }
+
+  DEBUG("Clean up");
+  g_free(original);
+  if (filename_p)
+    *filename_p = filename;
+  else
+    g_free(filename);
+  LEAVE("key_file %p, filename %s", key_file,
+	filename_p ? *filename_p : "(none)");
+  return key_file;
+}
+
 /* ----------------------- END OF FILE ---------------------  */

Modified: gnucash/trunk/src/app-utils/file-utils.h
===================================================================
--- gnucash/trunk/src/app-utils/file-utils.h	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/app-utils/file-utils.h	2005-11-11 14:16:12 UTC (rev 11905)
@@ -30,6 +30,9 @@
 #define GNC_FILE_UTILS_H
 
 #include <stdio.h>		/* for FILE* */
+#ifndef HAVE_GLIB26
+#include "gkeyfile.h"
+#endif
 
 char * gncFindFile (const char * filename);
 
@@ -59,4 +62,24 @@
 gint64 gnc_getline (gchar **line, FILE *file);
 
 
+/* Definitions shared by file-utils.c and gnc-main-window.c */
+#define STATE_FILE_TOP		"Top"
+#define STATE_FILE_BOOK_GUID	"Book Guid"
+
+/** Find the state file that corresponds to this URL and guid.  The
+ *  URL is used to compute the base name of the file (which will be in
+ *  ~/.gnucash/books) and the guid is used to differentiate when the
+ *  user has multiple data files with the same name.
+ *
+ *  @param url The usrl of the data file being used.
+ *
+ *  @param guid The guid of the book associated with this data file.
+ *
+ *  @param next_filename Return the next available file name if the
+ *  data file cannot be found.
+ *
+ *  @return The name of the data file that was located.
+ */
+GKeyFile *gnc_find_state_file (const gchar *url, const gchar *guid, gchar **filename);
+
 #endif /* GNC_FILE_UTILS_H */

Modified: gnucash/trunk/src/app-utils/guile-util.c
===================================================================
--- gnucash/trunk/src/app-utils/guile-util.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/app-utils/guile-util.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -1152,3 +1152,27 @@
     return g_strdup(string);
   return NULL;
 }
+
+
+/*  Clean up a scheme options string for use in a key/value file.
+ *  This function removes all full line comments, removes all blank
+ *  lines, and removes all leading/trailing white space. */
+gchar *gnc_guile_strip_comments (const gchar *raw_text)
+{
+  gchar *text, **splits;
+  gint i, j;
+
+  splits = g_strsplit(raw_text, "\n", -1);
+  for (i = j = 0; splits[i]; i++) {
+    if ((splits[i][0] == ';') || (splits[i][0] == '\0')) {
+      g_free(splits[i]);
+      continue;
+    }
+    splits[j++] = g_strstrip(splits[i]);
+  }
+  splits[j] = NULL;
+
+  text = g_strjoinv(" ", splits);
+  g_strfreev(splits);
+  return text;
+}

Modified: gnucash/trunk/src/app-utils/guile-util.h
===================================================================
--- gnucash/trunk/src/app-utils/guile-util.h	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/app-utils/guile-util.h	2005-11-11 14:16:12 UTC (rev 11905)
@@ -95,4 +95,13 @@
 char * gnc_get_debit_string(GNCAccountType account_type);
 char * gnc_get_credit_string(GNCAccountType account_type);
 
+/** Clean up a scheme options string for use in a key/value file.
+ *  This function removes all full line comments, removes all blank
+ *  lines, and removes all leading/trailing white space.
+ *
+ *  @note: This function does not correctly handle comments that occur
+ *  at the end of a line. Fortunately there aren't any such
+ *  comments. */
+gchar *gnc_guile_strip_comments (const gchar *text);
+
 #endif

Modified: gnucash/trunk/src/business/business-gnome/gnc-plugin-business.c
===================================================================
--- gnucash/trunk/src/business/business-gnome/gnc-plugin-business.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/business/business-gnome/gnc-plugin-business.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -38,6 +38,7 @@
 #include "dialog-tax-table.h"
 #include "dialog-vendor.h"
 #include "gnc-plugin-business.h"
+#include "gnc-plugin-page-invoice.h"
 #include "gncOwner.h"
 #include "messages.h"
 #include "gnc-ui-util.h"
@@ -303,6 +304,10 @@
 {
 	GncPluginBusiness *plugin;
 
+	/* Reference the invoice page plugin to ensure it exists in
+	 * the gtk type system. */
+	GNC_TYPE_PLUGIN_PAGE_INVOICE;
+
 	plugin = g_object_new (GNC_TYPE_PLUGIN_BUSINESS,
 			      NULL);
 

Modified: gnucash/trunk/src/business/business-gnome/gnc-plugin-page-invoice.h
===================================================================
--- gnucash/trunk/src/business/business-gnome/gnc-plugin-page-invoice.h	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/business/business-gnome/gnc-plugin-page-invoice.h	2005-11-11 14:16:12 UTC (rev 11905)
@@ -49,7 +49,7 @@
 #define GNC_IS_PLUGIN_PAGE_INVOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_INVOICE))
 #define GNC_PLUGIN_PAGE_INVOICE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_INVOICE, GncPluginPageInvoiceClass))
 
-#define GNC_PLUGIN_PAGE_INVOICE_NAME "gnc-plugin-page-invoice"
+#define GNC_PLUGIN_PAGE_INVOICE_NAME "GncPluginPageInvoice"
 
 /* typedefs & structures */
 typedef struct {

Modified: gnucash/trunk/src/gnome/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome/Makefile.am	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/Makefile.am	2005-11-11 14:16:12 UTC (rev 11905)
@@ -12,6 +12,7 @@
   ${top_builddir}/src/report/report-gnome/libgncmod-report-gnome.la \
   ${top_builddir}/src/register/ledger-core/libgncmod-ledger-core.la \
   ${top_builddir}/src/gnome-search/libgncmod-gnome-search.la \
+  ${top_builddir}/lib/glib26/libgncglib.la \
   ${GUILE_LIBS} ${GNOME_LIBS} ${GLIB_LIBS} ${QOF_LIBS}
 
 libgw_gnc_la_SOURCES = gw-gnc.c
@@ -142,6 +143,7 @@
   -I${top_srcdir}/src/register/register-gnome \
   -I${top_srcdir}/src/report/report-system \
   -I${top_srcdir}/src/report/report-gnome \
+  -I${top_srcdir}/lib/glib26 \
   ${GUILE_INCS} \
   ${G_WRAP_COMPILE_ARGS} \
   ${GNOME_CFLAGS} \

Modified: gnucash/trunk/src/gnome/gnc-plugin-account-tree.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-account-tree.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gnc-plugin-account-tree.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -94,6 +94,10 @@
 {
 	GncPluginAccountTree *plugin;
 
+	/* Reference the account tree page plugin to ensure it exists
+	 * in the gtk type system. */
+	GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE;
+
 	plugin = g_object_new (GNC_TYPE_PLUGIN_ACCOUNT_TREE,
 			      NULL);
 
@@ -171,19 +175,10 @@
 gnc_plugin_account_tree_cmd_new_account_tree (GtkAction *action,
 					      GncMainWindowActionData *data)
 {
-	g_return_if_fail (data != NULL);
-	gnc_new_account_tree (data->window);
-}
-
-/************************************************************
- *                     Other Functions                      *
- ************************************************************/
-
-void
-gnc_new_account_tree (GncMainWindow *window)
-{
 	GncPluginPage *page;
 
+	g_return_if_fail (data != NULL);
+
 	page = gnc_plugin_page_account_tree_new ();
-	gnc_main_window_open_page (window, page);
+	gnc_main_window_open_page (data->window, page);
 }

Modified: gnucash/trunk/src/gnome/gnc-plugin-account-tree.h
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-account-tree.h	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gnc-plugin-account-tree.h	2005-11-11 14:16:12 UTC (rev 11905)
@@ -55,8 +55,6 @@
 
 GncPlugin *gnc_plugin_account_tree_new      (void);
 
-void       gnc_new_account_tree             (GncMainWindow *window);
-
 G_END_DECLS
 
 #endif /* __GNC_PLUGIN_ACCOUNT_TREE_H */

Modified: gnucash/trunk/src/gnome/gnc-plugin-budget.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-budget.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gnc-plugin-budget.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -106,6 +106,11 @@
 {
     GncPluginBudget *plugin;
     ENTER(" ");
+
+    /* Reference the budget page plugin to ensure it exists in the gtk
+     * type system. */
+    GNC_TYPE_PLUGIN_PAGE_BUDGET;
+
     plugin = g_object_new (GNC_TYPE_PLUGIN_BUDGET, NULL);
     LEAVE(" ");
     return GNC_PLUGIN (plugin);

Modified: gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -2,7 +2,7 @@
  * gnc-plugin-page-account-tree.c -- 
  *
  * Copyright (C) 2003 Jan Arne Petersen <jpetersen at uni-bonn.de>
- * Copyright (C) 2003 David Hampton <hampton at employees.org>
+ * Copyright (C) 2003,2005 David Hampton <hampton at employees.org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -22,10 +22,22 @@
  * Boston, MA  02111-1307,  USA       gnu at gnu.org
  */
 
+/** @addtogroup ContentPlugins
+    @{ */
+/** @addtogroup GncPluginPageAccountTree An Account Tree Plugin
+    @{ */
+/** @file gnc-plugin-page-account-tree.c
+    @brief  utility functions for the GnuCash UI
+    @author Copyright (C) 2003 Jan Arne Petersen <jpetersen at uni-bonn.de>
+            Copyright (C) 2003,2005 David Hampton <hampton at employees.org>
+*/
+
 #include "config.h"
 
 #include <gtk/gtk.h>
-
+#ifndef HAVE_GLIB26
+#include "gkeyfile.h"
+#endif
 #include "gnc-plugin-page-account-tree.h"
 #include "gnc-plugin-page-register.h"
 
@@ -69,8 +81,6 @@
 	GtkWidget *widget;
 	GtkTreeView *tree_view;
 
-	SCM         name_change_callback_id;
-
 	GNCOptionDB * odb;
 	SCM         options; 
 	int         options_id;
@@ -95,6 +105,8 @@
 
 static GtkWidget *gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page);
 static void gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page);
+static void gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
+static GncPluginPage *gnc_plugin_page_account_tree_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
 
 /* Callbacks */
 static gboolean gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
@@ -232,7 +244,7 @@
 		};
 		
 		gnc_plugin_page_account_tree_type = g_type_register_static (GNC_TYPE_PLUGIN_PAGE,
-								            "GncPluginPageAccountTree",
+								            GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME,
 								            &our_info, 0);
 	}
 
@@ -266,6 +278,8 @@
 	gnc_plugin_class->plugin_name     = GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME;
 	gnc_plugin_class->create_widget   = gnc_plugin_page_account_tree_create_widget;
 	gnc_plugin_class->destroy_widget  = gnc_plugin_page_account_tree_destroy_widget;
+	gnc_plugin_class->save_page       = gnc_plugin_page_account_tree_save_page;
+	gnc_plugin_class->recreate_page   = gnc_plugin_page_account_tree_recreate_page;
 
 	g_type_class_add_private(klass, sizeof(GncPluginPageAccountTreePrivate));
 
@@ -281,11 +295,6 @@
 }
 
 static void
-gnc_plugin_page_acct_tree_view_refresh (gpointer data)
-{
-}
-
-static void
 gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page)
 {
 	GtkActionGroup *action_group;
@@ -362,14 +371,6 @@
 
 	priv->odb     = gnc_option_db_new(priv->options);
 
-	priv->name_change_callback_id = 
-	  gnc_option_db_register_change_callback(priv->odb, 
-						 gnc_plugin_page_acct_tree_view_refresh,
-						 priv, 
-						 N_("Account Tree"),
-						 N_("Name of account view"));
-	scm_gc_protect_object(priv->name_change_callback_id);
-
 	LEAVE("page %p, priv %p, action group %p",
 	      plugin_page, priv, action_group);
 }
@@ -539,7 +540,241 @@
 	LEAVE("widget destroyed");
 }
 
+#define ACCT_COUNT "Number of Open Accounts"
+#define ACCT_OPEN  "Open Account %d"
+#define ACCT_SELECTED  "Selected Account"
 
+typedef struct foo {
+  GKeyFile *key_file;
+  const gchar *group_name;
+  int count;
+} bar_t;
+
+
+/** Save information about an expanded row.  This function is called
+ *  via a gtk_tree_view_map_expanded_rows, which calls it once per
+ *  expanded row.  Its job is to write the full account name of the
+ *  row out to the state file.
+ *
+ *  @param tree_view A pointer to the GtkTreeView embedded in an
+ *  account tree page.
+ *
+ *  @param path A pointer to a particular entry in the tree.
+ *
+ *  @param data A pointer to a data structure holding the information
+ *  related to the state file. */
+static void
+tree_save_expanded_row (GtkTreeView *tree_view,
+			GtkTreePath *path,
+			gpointer user_data)
+{
+	Account *account;
+	bar_t *bar = user_data;
+	gchar *key;
+	gchar *account_name;
+
+	account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(tree_view), path);
+	if (account == NULL)
+	  return;
+
+	account_name = xaccAccountGetFullName (account, gnc_get_account_separator ());
+	if (account_name == NULL)
+	  return;
+
+	key = g_strdup_printf(ACCT_OPEN, ++bar->count);
+	g_key_file_set_string(bar->key_file, bar->group_name, key, account_name);
+	g_free(key);
+	g_free(account_name);
+}
+
+
+/** Save information about the selected row.  Its job is to write the
+ *  full account name of the row out to the state file.
+ *
+ *  @param tree_view A pointer to the GtkTreeView embedded in an
+ *  account tree page.
+ *
+ *  @param path A pointer to a particular entry in the tree.
+ *
+ *  @param data A pointer to a data structure holding the information
+ *  related to the state file. */
+static void
+tree_save_selected_row (GncTreeViewAccount *view,
+			gpointer user_data)
+{
+	Account *account;
+	bar_t *bar = user_data;
+	gchar *account_name;
+
+	account = gnc_tree_view_account_get_selected_account(view);
+	if (account == NULL)
+	  return;
+
+	account_name = xaccAccountGetFullName (account, gnc_get_account_separator ());
+	if (account_name == NULL)
+	  return;
+
+	g_key_file_set_string(bar->key_file, bar->group_name, ACCT_SELECTED, account_name);
+	g_free(account_name);
+}
+
+
+/** Save enough information about this account tree page that it can
+ *  be recreated next time the user starts gnucash.
+ *
+ *  @param page The page to save.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be written.
+ *
+ *  @param group_name The group name to use when saving data. */
+static void
+gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page,
+					GKeyFile *key_file,
+					const gchar *group_name)
+{
+	GncPluginPageAccountTree *account_page;
+	GncPluginPageAccountTreePrivate *priv;
+	bar_t bar;
+	
+	g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page));
+	g_return_if_fail (key_file != NULL);
+	g_return_if_fail (group_name != NULL);
+
+	ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
+	      group_name);
+
+	account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page);
+	priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
+
+	bar.key_file = key_file;
+	bar.group_name = group_name;
+	bar.count = 0;
+	tree_save_selected_row(GNC_TREE_VIEW_ACCOUNT(priv->tree_view), &bar);
+	gtk_tree_view_map_expanded_rows(priv->tree_view,
+					tree_save_expanded_row, &bar);
+	g_key_file_set_integer(key_file, group_name, ACCT_COUNT, bar.count);
+	LEAVE(" ");
+}
+
+
+/** Expand a row in the tree that was expanded when the user last quit
+ *  gnucash.  Its job is to map from account name to tree row and
+ *  expand the row.
+ *
+ *  @param tree_view A pointer to the GtkTreeView embedded in an
+ *  account tree page.
+ *
+ *  @param account_name A pointer to the full account name. */
+static void
+tree_restore_expanded_row (GtkTreeView *tree_view,
+			   const gchar *account_name)
+{
+  Account *account;
+  QofBook *book;
+
+  book = qof_session_get_book(qof_session_get_current_session());
+  account = xaccGetAccountFromFullName(xaccGetAccountGroup(book),
+				       account_name,
+				       gnc_get_account_separator());
+  if (account)
+    gnc_tree_view_account_expand_to_account(GNC_TREE_VIEW_ACCOUNT(tree_view),
+					    account);
+}
+
+
+/** Select the row in the tree that was selected when the user last
+ *  quit gnucash.  Its job is to map from account name to tree row and
+ *  select the row.
+ *
+ *  @param tree_view A pointer to the GtkTreeView embedded in an
+ *  account tree page.
+ *
+ *  @param account_name A pointer to the full account name. */
+static void
+tree_restore_selected_row (GtkTreeView *tree_view,
+			   const gchar *account_name)
+{
+  Account *account;
+  QofBook *book;
+
+  book = qof_session_get_book(qof_session_get_current_session());
+  account = xaccGetAccountFromFullName(xaccGetAccountGroup(book),
+				       account_name,
+				       gnc_get_account_separator());
+  if (account)
+    gnc_tree_view_account_set_selected_account(GNC_TREE_VIEW_ACCOUNT(tree_view),
+					       account);
+}
+
+
+/** Create a new account tree page based on the information saved
+ *  during a previous instantiation of gnucash.
+ *
+ *  @param window The window where this page should be installed.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be read.
+ *
+ *  @param group_name The group name to use when restoring data. */
+static GncPluginPage *
+gnc_plugin_page_account_tree_recreate_page (GtkWidget *window,
+					    GKeyFile *key_file,
+					    const gchar *group_name)
+{
+	GncPluginPageAccountTree *account_page;
+	GncPluginPageAccountTreePrivate *priv;
+	GncPluginPage *page;
+	GError *error = NULL;
+	gchar *key, *value;
+	gint i, count;
+	
+	g_return_val_if_fail(key_file, NULL);
+	g_return_val_if_fail(group_name, NULL);
+	ENTER("key_file %p, group_name %s", key_file, group_name);
+
+	/* Create the new page. */
+	page = gnc_plugin_page_account_tree_new();
+	account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(page);
+	priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
+
+	/* Install it now so we can them manipulate the created widget */
+	gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
+
+	/* Expanded accounts */
+	count = g_key_file_get_integer(key_file, group_name, ACCT_COUNT, &error);
+	if (error) {
+	  g_warning("error reading group %s key %s: %s",
+		    group_name, ACCT_COUNT, error->message);
+	  g_error_free(error);
+	  LEAVE("bad value");
+	  return page;
+	}
+	for (i = 1; i <= count; i++) {
+	  key = g_strdup_printf(ACCT_OPEN, i);
+	  value = g_key_file_get_string(key_file, group_name, key, &error);
+	  if (error) {
+	    g_warning("error reading group %s key %s: %s",
+		      group_name, key, error->message);
+	    g_error_free(error);
+	    error = NULL;
+	  } else {
+	    tree_restore_expanded_row(priv->tree_view, value);
+	    g_free(value);
+	  }
+	}
+
+	/* Selected account (if any) */
+	value = g_key_file_get_string(key_file, group_name, ACCT_SELECTED, NULL);
+	if (value) {
+	  tree_restore_selected_row(priv->tree_view, value);
+	  g_free(value);
+	}
+	LEAVE(" ");
+	return page;
+}
+
+
 /* Callbacks */
 
 /** This button press handler calls the common button press handler
@@ -959,3 +1194,6 @@
 	xaccGroupScrubOrphans (group);
 	xaccGroupScrubImbalance (group);
 }
+
+/** @} */
+/** @} */

Modified: gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.h
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.h	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.h	2005-11-11 14:16:12 UTC (rev 11905)
@@ -50,7 +50,7 @@
 #define GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE))
 #define GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE, GncPluginPageAccountTreeClass))
 
-#define GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME "gnc-plugin-page-account-tree"
+#define GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME "GncPluginPageAccountTree"
 
 /* typedefs & structures */
 typedef struct {

Modified: gnucash/trunk/src/gnome/gnc-plugin-page-budget.h
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-page-budget.h	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-budget.h	2005-11-11 14:16:12 UTC (rev 11905)
@@ -45,7 +45,7 @@
 #define GNC_IS_PLUGIN_PAGE_BUDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_BUDGET))
 #define GNC_PLUGIN_PAGE_BUDGET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_BUDGET, GncPluginPageBudgetClass))
 
-#define GNC_PLUGIN_PAGE_BUDGET_NAME "gnc-plugin-page-budget"
+#define GNC_PLUGIN_PAGE_BUDGET_NAME "GncPluginPageBudget"
 
 /* typedefs & structures */
 typedef struct {

Modified: gnucash/trunk/src/gnome/gnc-plugin-page-register.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-page-register.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-register.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -2,7 +2,7 @@
  * gnc-plugin-page-register.c -- 
  *
  * Copyright (C) 2003 Jan Arne Petersen <jpetersen at uni-bonn.de>
- * Copyright (C) 2003 David Hampton <hampton at employees.org>
+ * Copyright (C) 2003,2005 David Hampton <hampton at employees.org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -22,9 +22,22 @@
  * Boston, MA  02111-1307,  USA       gnu at gnu.org
  */
 
+/** @addtogroup ContentPlugins
+    @{ */
+/** @addtogroup RegisterPlugin Register Page
+    @{ */
+/** @file gnc-plugin-page-register.c
+    @brief  Functions for creating a register page for the GnuCash UI
+    @author Copyright (C) 2003 Jan Arne Petersen <jpetersen at uni-bonn.de>
+    @author Copyright (C) 2003,2005 David Hampton <hampton at employees.org>
+*/
+
 #include "config.h"
 
 #include <gtk/gtk.h>
+#ifndef HAVE_GLIB26
+#include "gkeyfile.h"
+#endif
 #include <g-wrap-wct.h>
 
 #include "gnc-plugin-page-register.h"
@@ -75,6 +88,8 @@
 static GtkWidget *gnc_plugin_page_register_create_widget (GncPluginPage *plugin_page);
 static void gnc_plugin_page_register_destroy_widget (GncPluginPage *plugin_page);
 static void gnc_plugin_page_register_window_changed (GncPluginPage *plugin_page, GtkWidget *window);
+static void gnc_plugin_page_register_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
+static GncPluginPage *gnc_plugin_page_register_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
 
 static gchar *gnc_plugin_page_register_get_tab_name (GncPluginPage *plugin_page);
 
@@ -276,10 +291,11 @@
 };
 
 
-struct {
+struct status_action {
   const char *action_name;
   int value;
-} status_actions[] = {
+};
+static struct status_action status_actions[] = {
   { "filter_status_reconciled",   CLEARED_RECONCILED },
   { "filter_status_cleared",      CLEARED_CLEARED },
   { "filter_status_voided",       CLEARED_VOIDED },
@@ -445,6 +461,8 @@
 	gnc_plugin_class->create_widget   = gnc_plugin_page_register_create_widget;
 	gnc_plugin_class->destroy_widget  = gnc_plugin_page_register_destroy_widget;
 	gnc_plugin_class->window_changed  = gnc_plugin_page_register_window_changed;
+	gnc_plugin_class->save_page       = gnc_plugin_page_register_save_page;
+	gnc_plugin_class->recreate_page   = gnc_plugin_page_register_recreate_page;
 
 	g_type_class_add_private(klass, sizeof(GncPluginPageRegisterPrivate));
 }
@@ -533,9 +551,9 @@
 { 
 	GncPluginPageRegisterPrivate *priv ;
 	GtkActionGroup *action_group;
+	GtkAction *action;
 	Account *account;
 	SplitRegister *sr;
-	GtkAction *action;
 	int i;
 
 	priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
@@ -683,6 +701,214 @@
 	priv->gsr->window = 
 	  GTK_WIDGET(gnc_window_get_gtk_window(GNC_WINDOW(window)));
 }
+
+static const gchar *style_names[] = {
+  "Ledger",
+  "Auto Ledger",
+  "Journal",
+  NULL
+};
+
+#define KEY_REGISTER_TYPE	"Register Type"
+#define KEY_ACCOUNT_NAME	"Account Name"
+#define KEY_REGISTER_STYLE	"Register Style"
+#define KEY_DOUBLE_LINE		"Double Line Mode"
+
+#define LABEL_ACCOUNT		"Account"
+#define LABEL_SUBACCOUNT	"SubAccount"
+#define LABEL_GL		"GL"
+#define LABEL_SEARCH		"Search"
+
+
+/** Save enough information about this register page that it can be
+ *  recreated next time the user starts gnucash.
+ *
+ *  @param page The page to save.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be written.
+ *
+ *  @param group_name The group name to use when saving data. */
+static void
+gnc_plugin_page_register_save_page (GncPluginPage *plugin_page,
+				    GKeyFile *key_file,
+				    const gchar *group_name)
+{
+  GncPluginPageRegister *page;
+  GncPluginPageRegisterPrivate *priv;
+  GNCLedgerDisplayType ledger_type;
+  SplitRegister *reg;
+  Account *leader;
+
+  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
+  g_return_if_fail (key_file != NULL);
+  g_return_if_fail (group_name != NULL);
+
+  ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
+	group_name);
+
+  page = GNC_PLUGIN_PAGE_REGISTER(plugin_page);
+  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
+
+  reg = gnc_ledger_display_get_split_register(priv->ledger);
+  ledger_type = gnc_ledger_display_type(priv->ledger);
+  if (ledger_type > LD_GL) {
+    LEAVE("Unsupported ledger type");
+    return;
+  }
+  if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT)) {
+    const gchar *label;
+    label = (ledger_type == LD_SINGLE) ? LABEL_ACCOUNT : LABEL_SUBACCOUNT;
+    leader = gnc_ledger_display_leader(priv->ledger);
+    g_key_file_set_string(key_file, group_name, KEY_REGISTER_TYPE, label);
+    g_key_file_set_string(key_file, group_name, KEY_ACCOUNT_NAME,
+			  xaccAccountGetFullName(leader,
+						 gnc_get_account_separator()));
+  } else if (reg->type == GENERAL_LEDGER) {
+    g_key_file_set_string(key_file, group_name, KEY_REGISTER_TYPE,
+			  LABEL_GL);
+  } else if (reg->type == SEARCH_LEDGER) {
+    g_key_file_set_string(key_file, group_name, KEY_REGISTER_TYPE,
+			  LABEL_SEARCH);
+  } else {
+    LEAVE("Unsupported register type");
+    return;
+  }
+
+  g_key_file_set_string(key_file, group_name, KEY_REGISTER_STYLE,
+			style_names[reg->style]);
+  g_key_file_set_boolean(key_file, group_name, KEY_DOUBLE_LINE,
+			 reg->use_double_line);
+
+  LEAVE(" ");
+}
+
+
+/** Read and restore the edit menu settings on the specified register
+ *  page.  This function will restore the register style (ledger, auto
+ *  ledger, journal) and whether or not the register is in double line
+ *  mode.  It should eventually restore the "filter by" and "sort by
+ *  settings.
+ *
+ *  @param page The register being restored.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be read.
+ *
+ *  @param group_name The group name to use when restoring data. */
+static void
+gnc_plugin_page_register_restore_edit_menu (GncPluginPage *page,
+					    GKeyFile *key_file,
+					    const gchar *group_name)
+{
+  GncPluginPageRegisterPrivate *priv;
+  GtkActionGroup *action_group;
+  GtkAction *action;
+  GError *error = NULL;
+  gchar *style_name;
+  gint i;
+  gboolean use_double_line;
+
+  ENTER(" ");
+  priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE(page);
+  action_group = gnc_plugin_page_get_action_group(page);
+
+  /* Convert the style name to an index */
+  style_name = g_key_file_get_string(key_file, group_name,
+				     KEY_REGISTER_STYLE, &error);
+  for (i = 0 ; style_names[i]; i++) {
+    if (g_ascii_strcasecmp(style_name, style_names[i]) == 0) {
+      DEBUG("Found match for style name: %s", style_name);
+      break;
+    }
+  }
+  g_free(style_name);
+
+  /* Update the style menu action for this page */
+  if (i <= REG_STYLE_JOURNAL) {
+    DEBUG("Setting style: %d", i);
+    action_group =
+      gnc_plugin_page_get_action_group(page);
+    action= gtk_action_group_get_action(action_group, radio_entries_2[i].name);
+    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+  }
+
+  /* Update the  double line action on this page */
+  use_double_line =
+    g_key_file_get_boolean(key_file, group_name, KEY_DOUBLE_LINE, &error);
+  DEBUG("Setting double_line_mode: %d", use_double_line);
+  action = gtk_action_group_get_action(action_group,
+				       "ViewStyleDoubleLineAction");
+  gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_double_line);
+
+  LEAVE(" ");
+}
+
+
+/** Create a new register page based on the information saved during a
+ *  previous instantiation of gnucash.
+ *
+ *  @param window The window where this page should be installed.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be read.
+ *
+ *  @param group_name The group name to use when restoring data. */
+static GncPluginPage *
+gnc_plugin_page_register_recreate_page (GtkWidget *window,
+					GKeyFile *key_file,
+					const gchar *group_name)
+{
+  GncPluginPage *page;
+  GError *error = NULL;
+  gchar *reg_type, *acct_name;
+  Account *account;
+  QofBook *book;
+  gboolean include_subs;
+
+  g_return_val_if_fail(key_file, NULL);
+  g_return_val_if_fail(group_name, NULL);
+  ENTER("key_file %p, group_name %s", key_file, group_name);
+
+  /* Create the new page. */
+  reg_type = g_key_file_get_string(key_file, group_name,
+					 KEY_REGISTER_TYPE, &error);
+  DEBUG("Page type: %s", reg_type);
+  if ((g_ascii_strcasecmp(reg_type, LABEL_ACCOUNT) == 0) ||
+      (g_ascii_strcasecmp(reg_type, LABEL_SUBACCOUNT) == 0)) {
+    include_subs = (g_ascii_strcasecmp(reg_type, LABEL_SUBACCOUNT) == 0);
+    DEBUG("Include subs: %d", include_subs);
+    acct_name = g_key_file_get_string(key_file, group_name,
+				      KEY_ACCOUNT_NAME, &error);
+    book = qof_session_get_book(qof_session_get_current_session());
+    account = xaccGetAccountFromFullName(xaccGetAccountGroup(book),
+					 acct_name,
+					 gnc_get_account_separator());
+    g_free(acct_name);
+    if (account == NULL) {
+      LEAVE("Bad account name");
+      g_free(reg_type);
+      return NULL;
+    }
+    page = gnc_plugin_page_register_new (account, include_subs);
+  } else if (g_ascii_strcasecmp(reg_type, LABEL_GL) == 0) {
+    page = gnc_plugin_page_register_new_gl();
+  } else {
+    LEAVE("Bad ledger type");
+    g_free(reg_type);
+    return NULL;
+  }
+  g_free(reg_type);
+
+  /* Install it now so we can them manipulate the created widget */
+  gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
+
+  /* Now update the page to the last state it was in */
+  gnc_plugin_page_register_restore_edit_menu(page, key_file, group_name);
+  LEAVE(" ");
+  return page;
+}
+
 	
 static gchar *
 gnc_plugin_page_register_get_tab_name (GncPluginPage *plugin_page)
@@ -2370,3 +2596,6 @@
   gnucash_register_refresh_from_gconf(priv->gsr->reg);
   gtk_widget_queue_draw(priv->widget);
 }
+
+/** @} */
+/** @} */

Modified: gnucash/trunk/src/gnome/gnc-plugin-register.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-register.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gnc-plugin-register.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -128,6 +128,10 @@
 {
 	GncPluginRegister *plugin;
 
+	/* Reference the register page plugin to ensure it exists in
+	 * the gtk type system. */
+	GNC_TYPE_PLUGIN_PAGE_REGISTER;
+
 	plugin = g_object_new (GNC_TYPE_PLUGIN_REGISTER,
 			      NULL);
 

Modified: gnucash/trunk/src/gnome/gw-gnc-spec.scm
===================================================================
--- gnucash/trunk/src/gnome/gw-gnc-spec.scm	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome/gw-gnc-spec.scm	2005-11-11 14:16:12 UTC (rev 11905)
@@ -130,14 +130,6 @@
    '()
    "Destroy the UI.")
 
-  (gw:wrap-function
-   ws
-   'gnc:new-account-tree
-   '<gw:void>
-   "gnc_new_account_tree"
-   '((<gnc:MainWindow*> window))
-   "Create a new account tree window.")
-
   (gw:wrap-as-wct ws
                   '<gnc:ProgressDialog*>
                   "GNCProgressDialog *" "const GNCProgressDialog *")

Modified: gnucash/trunk/src/gnome-utils/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome-utils/Makefile.am	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome-utils/Makefile.am	2005-11-11 14:16:12 UTC (rev 11905)
@@ -17,6 +17,7 @@
   -I${top_srcdir}/src/network-utils \
   -I${top_srcdir}/src/app-utils \
   -I${top_srcdir}/src \
+  -I${top_srcdir}/lib/glib26 \
   ${LIBGUPPI_CFLAGS} \
   ${GLIB_CFLAGS} \
   ${GLADE_CFLAGS} \
@@ -40,10 +41,11 @@
   -I${top_srcdir}/src/backend/file \
   -I${top_srcdir}/src/network-utils \
   -I${top_srcdir}/src/app-utils \
+  -I${top_srcdir}/src \
   -I${top_srcdir}/lib/goffice \
   -I${top_srcdir}/lib/goffice/split \
+  -I${top_srcdir}/lib/glib26 \
   -I${top_srcdir}/lib \
-  -I${top_srcdir}/src \
   ${LIBGUPPI_CFLAGS} \
   ${GNOME_CFLAGS} \
   ${GTKHTML_CFLAGS} \
@@ -205,6 +207,7 @@
   ${top_builddir}/src/calculation/libgncmod-calculation.la \
   ${top_builddir}/src/network-utils/libgncmod-network-utils.la \
   ${top_builddir}/src/app-utils/libgncmod-app-utils.la \
+  ${top_builddir}/lib/glib26/libgncglib.la \
   ${LIBGUPPI_LIBS} \
   ${GNOME_LIBS} \
   ${GNOME_PRINT_LIBS} \
@@ -228,6 +231,7 @@
   ${top_builddir}/src/network-utils/libgncmod-network-utils.la \
   ${top_builddir}/src/app-utils/libgncmod-app-utils.la \
   ${top_builddir}/lib/goffice/libgoffice.la \
+  ${top_builddir}/lib/glib26/libgncglib.la \
   ${LIBGUPPI_LIBS} \
   ${GNOME_LIBS} \
   ${GNOME_PRINT_LIBS} \

Modified: gnucash/trunk/src/gnome-utils/gnc-main-window.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-main-window.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome-utils/gnc-main-window.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -35,8 +35,10 @@
 
 #include "config.h"
 
-#include <gdk/gdkpixbuf.h>
 #include <gtk/gtk.h>
+#ifndef HAVE_GLIB26
+#include "gkeyfile.h"
+#endif
 
 #include "gnc-plugin.h"
 #include "gnc-plugin-manager.h"
@@ -46,12 +48,15 @@
 #include "dialog-reset-warnings.h"
 #include "dialog-transfer.h"
 #include "dialog-utils.h"
+#include "file-utils.h"
 #include "gnc-component-manager.h"
 #include "gnc-engine.h"
 #include "gnc-file.h"
+#include "gnc-gkeyfile-utils.h"
 #include "gnc-gnome-utils.h"
 #include "gnc-gobject-utils.h"
 #include "gnc-gui-query.h"
+#include "gnc-hooks.h"
 #include "gnc-session.h"
 #include "gnc-ui.h"
 #include "gnc-version.h"
@@ -60,6 +65,7 @@
 #include "gnc-gconf-utils.h"
 // +JSLED
 #include "gnc-html.h"
+#include <g-wrap-wct.h>
 
 enum {
   PAGE_ADDED,
@@ -89,6 +95,8 @@
 static void gnc_main_window_setup_window (GncMainWindow *window);
 static void gnc_window_main_window_init (GncWindowIface *iface);
 
+static void main_window_update_page_name (GncMainWindow *window, GncPluginPage *page, const gchar *name_in);
+
 /* Callbacks */
 static void gnc_main_window_add_widget (GtkUIManager *merge, GtkWidget *widget, GncMainWindow *window);
 static void gnc_main_window_switch_page (GtkNotebook *notebook, GtkNotebookPage *notebook_page, gint pos, GncMainWindow *window);
@@ -105,6 +113,7 @@
 static void gnc_main_window_cmd_view_summary (GtkAction *action, GncMainWindow *window);
 static void gnc_main_window_cmd_view_statusbar (GtkAction *action, GncMainWindow *window);
 static void gnc_main_window_cmd_actions_reset_warnings (GtkAction *action, GncMainWindow *window);
+static void gnc_main_window_cmd_actions_rename_page (GtkAction *action, GncMainWindow *window);
 static void gnc_main_window_cmd_window_new (GtkAction *action, GncMainWindow *window);
 static void gnc_main_window_cmd_window_move_page (GtkAction *action, GncMainWindow *window);
 static void gnc_main_window_cmd_window_raise (GtkAction *action, GtkRadioAction *current, GncMainWindow *window);
@@ -117,6 +126,7 @@
 static void do_popup_menu(GncPluginPage *page, GdkEventButton *event);
 static gboolean gnc_main_window_popup_menu_cb (GtkWidget *widget, GncPluginPage *page);
 
+static GtkAction *gnc_main_window_find_action (GncMainWindow *window, const gchar *name);
 
 typedef struct GncMainWindowPrivate
 {
@@ -200,6 +210,9 @@
 	{ "ActionsForgetWarningsAction", NULL, N_("_Reset Warnings..."), NULL,
 	  N_("Reset the state of all warning message so they will be shown again."),
 	  G_CALLBACK (gnc_main_window_cmd_actions_reset_warnings) },
+	{ "ActionsRenamePageAction", NULL, N_("Rename Page"), NULL,
+	  N_("Rename this page."),
+	  G_CALLBACK (gnc_main_window_cmd_actions_rename_page) },
 
 	/* Windows menu */
 
@@ -298,21 +311,480 @@
 /************************************************************
  *                                                          *
  ************************************************************/
+#define WINDOW_COUNT		"Window Count"
+#define WINDOW_STRING		"Window %d"
+#define WINDOW_GEOMETRY		"Window Geometry"
+#define WINDOW_POSITION		"Window Position"
+#define WINDOW_FIRSTPAGE	"First Page"
+#define WINDOW_PAGECOUNT	"Page Count"
+#define PAGE_TYPE		"Page Type"
+#define PAGE_NAME		"Page Name"
+#define PAGE_STRING		"Page %d"
 
+typedef struct {
+  GKeyFile *key_file;
+  const gchar *group_name;
+  gint window_num;
+  gint page_num;
+  gint page_offset;
+} GncMainWindowSaveData;
+
+
+/** Restore a single page to a window.  This function calls a page
+ *  specific function to create the actual page.  It then handles all
+ *  the common tasks such as insuring the page is installed into a
+ *  window, updating the page name, and anything else that might be
+ *  common to all pages.
+ *
+ *  @param window The GncMainWindow where the new page will be
+ *  installed.
+ *
+ *  @param data A data structure containing state about the
+ *  window/page restoration process. */
 static void
-gnc_main_window_save_window (GncMainWindow *window, gpointer session)
+gnc_main_window_restore_page (GncMainWindow *window, GncMainWindowSaveData *data)
 {
-  DEBUG("window %p", window);
+  GncMainWindowPrivate *priv;
+  GncPluginPage *page;
+  gchar *page_group, *page_type = NULL, *name = NULL;
+  const gchar *class_type;
+  GError *error = NULL;
+
+  ENTER("window %p, data %p (key file %p, window %d, page start %d, page num %d)",
+	window, data, data->key_file, data->window_num, data->page_offset, data->page_num);
+
+  priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
+  page_group = g_strdup_printf(PAGE_STRING, data->page_offset + data->page_num);
+  page_type = g_key_file_get_string(data->key_file, page_group,
+				    PAGE_TYPE, &error);
+  if (error) {
+    g_warning("error reading group %s key %s: %s",
+	      page_group, PAGE_TYPE, error->message);
+    goto cleanup;
+  }
+
+  /* See if the page already exists. */
+  page = g_list_nth_data(priv->installed_pages, data->page_num);
+  if (page) {
+    class_type = GNC_PLUGIN_PAGE_GET_CLASS(page)->plugin_name;
+    if (strcmp(page_type, class_type) != 0) {
+      g_warning("error: page types don't match: state %s, existing page %s",
+		page_type, class_type);
+      goto cleanup;
+    }
+  } else {
+    /* create and install the page */
+    page = gnc_plugin_page_recreate_page(GTK_WIDGET(window), page_type,
+					 data->key_file, page_group);
+    if (page) {
+      /* Does the page still need to be installed into the window? */
+      if (page->window == NULL) {
+      	gnc_main_window_open_page(window, page);
+      }
+
+      /* Restore the page name */
+      name = g_key_file_get_string(data->key_file, page_group,
+				       PAGE_NAME, &error);
+      if (error) {
+	g_warning("error reading group %s key %s: %s",
+		  page_group, PAGE_NAME, error->message);
+	/* Fall through and still show the page. */
+      } else {
+	DEBUG("updating page name for %p to %s.", page, name);
+	main_window_update_page_name(window, page, name);
+	g_free(name);
+      }
+    }
+  }
+
+  LEAVE("ok");
+ cleanup:
+  if (error)
+    g_error_free(error);
+  if (page_type)
+    g_free(page_type);
+  g_free(page_group);
 }
 
+
+/** Restore all the pages in a given window.  This function restores
+ *  all the window specific attributes, then calls a helper function
+ *  to restore all the pages that are contained in the window.
+ *
+ *  @param window The GncMainWindow whose pages should be restored.
+ *
+ *  @param data A data structure containing state about the
+ *  window/page restoration process. */
 static void
-gnc_main_window_shutdown (gpointer session, gpointer user_data)
+gnc_main_window_restore_window (GncMainWindow *window, GncMainWindowSaveData *data)
 {
-  DEBUG("session %p (%s)", session, qof_session_get_url (session));
-  g_list_foreach (active_windows, (GFunc)gnc_main_window_save_window, session);
+  GncMainWindowPrivate *priv;
+  gint *pos, *geom;
+  gsize length;
+  gchar *window_group;
+  gint page_start, page_count, i;
+  GError *error = NULL;
+
+  /* Setup */
+  ENTER("window %p, data %p (key file %p, window %d)",
+	window, data, data->key_file, data->window_num);
+  priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
+  window_group = g_strdup_printf(WINDOW_STRING, data->window_num + 1);
+
+  /* Save the window coordinates, etc. */
+  pos = g_key_file_get_integer_list(data->key_file, window_group,
+				    WINDOW_POSITION, &length, &error);
+  if (error) {
+    g_warning("error reading group %s key %s: %s",
+	      window_group, WINDOW_POSITION, error->message);
+    g_error_free(error);
+    error = NULL;
+  } else if (length != 2) {
+    g_warning("invalid number of values for group %s key %s",
+	      window_group, WINDOW_POSITION);
+  } else {
+    gtk_window_move(GTK_WINDOW(window), pos[0], pos[1]);
+    DEBUG("window (%p) position %dx%d", window, pos[0], pos[1]);
+  }
+
+  geom = g_key_file_get_integer_list(data->key_file, window_group,
+				     WINDOW_GEOMETRY, &length, &error);
+  if (error) {
+    g_warning("error reading group %s key %s: %s",
+	      window_group, WINDOW_GEOMETRY, error->message);
+    g_error_free(error);
+    error = NULL;
+  } else if (length != 2) {
+    g_warning("invalid number of values for group %s key %s",
+	      window_group, WINDOW_GEOMETRY);
+  } else {
+    gtk_window_resize(GTK_WINDOW(window), geom[0], geom[1]);
+    DEBUG("window (%p) size %dx%d", window, geom[0], geom[1]);
+  }
+
+  /* Get this window's notebook info */
+  page_start = g_key_file_get_integer(data->key_file,
+				      window_group, WINDOW_FIRSTPAGE, &error);
+  if (error) {
+    g_warning("error reading group %s key %s: %s",
+	      window_group, WINDOW_FIRSTPAGE, error->message);
+    goto cleanup;
+  }
+  page_count = g_key_file_get_integer(data->key_file,
+				      window_group, WINDOW_PAGECOUNT, &error);
+  if (error) {
+    g_warning("error reading group %s key %s: %s",
+	      window_group, WINDOW_PAGECOUNT, error->message);
+    goto cleanup;
+  }
+
+  for (i = 0; i < page_count; i++) {
+    data->page_offset = page_start;
+    data->page_num = i;
+    gnc_main_window_restore_page(window, data);
+  }
+
+  LEAVE("window %p", window);
+ cleanup:
+  if (error)
+    g_error_free(error);
+  g_free(window_group);
 }
 
 
+/** Restore all windows.  This function finds the "new" state file
+ *  associated with a specific book guid.  It then iterates through
+ *  this state information, calling a helper function to recreate
+ *  each open window.
+ *
+ *  If the "new" state file cannot be found, this function will open
+ *  an account tree window and then attempt to invoke the old gnucash
+ *  1.x state routines.  This provides a fluid transition for users
+ *  from the old to the new state systems.
+ *
+ *  @note The name of the state file is based on the name of the data
+ *  file, not the path name of the data file.  If there are multiple
+ *  data files with the same name, the state files will be suffixed
+ *  with a number.  E.G. test_account, test_account_2, test_account_3,
+ *  etc.
+ *
+ *  @param session A pointer to the current session.
+ *
+ *  @param unused An unused pointer. */
+static void
+gnc_main_window_restore_all_state (gpointer session, gpointer unused)
+{
+  GncMainWindow *window;
+  GncMainWindowSaveData data;
+  QofBook *book;
+  const gchar *url, *guid_string;
+  gchar *file_guid, *filename = NULL;
+  const GUID *guid;
+  gint i, window_count;
+  GError *error = NULL;
+	
+  url = qof_session_get_url(session);
+  ENTER("session %p (%s)", session, url);
+  if (!url) {
+    LEAVE("no url, nothing to do");
+    return;
+  }
+
+  /* Get the book GUID */
+  book = qof_session_get_book(session);
+  guid = qof_entity_get_guid(QOF_ENTITY(book));
+  guid_string = guid_to_string(guid);
+
+  data.key_file = gnc_find_state_file(url, guid_string, &filename);
+  if (filename)
+    g_free(filename);
+  if (!data.key_file) {
+    GtkAction *action;
+
+    /* The default state should be to have an Account Tree page open
+     * in the window. */
+    DEBUG("no saved state file");
+    window = g_list_nth_data(active_windows, 0);
+    action = gnc_main_window_find_action(window, "FileNewAccountTreeAction");
+    gtk_action_activate(action);
+
+#if (GNUCASH_MAJOR_VERSION < 2) || ((GNUCASH_MAJOR_VERSION == 2) && (GNUCASH_MINOR_VERSION == 0))
+    /* See if there's an old style state file to be found */
+    scm_call_1(scm_c_eval_string("gnc:main-window-book-open-handler"),
+	       (session ?
+		gw_wcp_assimilate_ptr (session, scm_c_eval_string("<gnc:Session*>")) :
+		SCM_BOOL_F));
+#endif
+
+    LEAVE("old");
+    return;
+  }
+
+#ifdef DEBUG
+  /*  Debugging: dump a copy to stdout and the trace log */
+  {
+    gchar *file_data;
+    gint file_length;
+    file_data = g_key_file_to_data(data.key_file, &file_length, NULL);
+    DEBUG("=== File Data Read===\n%s\n=== File End ===\n", file_data);
+    g_free(file_data);
+  }
+#endif
+
+  /* validate top level info */
+  file_guid = g_key_file_get_string(data.key_file,
+				    STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
+				    &error);
+  if (error) {
+    g_warning("error reading group %s key %s: %s",
+	      STATE_FILE_TOP, STATE_FILE_BOOK_GUID, error->message);
+    LEAVE("can't read guid");
+    goto cleanup;
+  }
+  if (!file_guid || strcmp(guid_string, file_guid)) {
+    g_warning("guid mismatch: book guid %s, state file guid %s",
+	      guid_string, file_guid);
+    LEAVE("guid values do not match");
+    goto cleanup;
+  }
+
+  window_count =
+    g_key_file_get_integer(data.key_file, STATE_FILE_TOP, WINDOW_COUNT, &error);
+  if (error) {
+    g_warning("error reading group %s key %s: %s",
+	      STATE_FILE_TOP, WINDOW_COUNT, error->message);
+    LEAVE("can't read count");
+    goto cleanup;
+  }
+
+  /* Restore all state information on the open windows.  Window
+     numbers in state file are 1-based. GList indices are 0-based. */
+  for (i = 0; i < window_count; i++) {
+    data.window_num = i;
+    window = g_list_nth_data(active_windows, i);
+    if (window == NULL) {
+      DEBUG("Window %d doesn't exist. Creating new window.", i);
+      DEBUG("active_windows %p.", active_windows);
+      if (active_windows)
+	DEBUG("first window %p.", active_windows->data);
+      window = gnc_main_window_new();
+    }
+    gnc_main_window_restore_window(window, &data);
+  }
+
+  /* Clean up */
+  LEAVE("ok");
+ cleanup:
+  if (error)
+    g_error_free(error);
+  if (file_guid)
+    g_free(file_guid);
+  g_key_file_free(data.key_file);
+}
+
+
+/** Save the state of a single page to a disk.  This function handles
+ *  all the common tasks such as saving the page type and name, and
+ *  anything else that might be common to all pages.  It then calls a
+ *  page specific function to save the actual page.
+ *
+ *  @param page The GncPluginPage whose state should be saved.
+ *
+ *  @param data A data structure containing state about the
+ *  window/page saving process. */
+static void
+gnc_main_window_save_page (GncPluginPage *page, GncMainWindowSaveData *data)
+{
+  gchar *page_group;
+
+  ENTER("page %p, data %p (key file %p, window %d, page %d)",
+	page, data, data->key_file, data->window_num, data->page_num);
+  page_group = g_strdup_printf(PAGE_STRING, data->page_num++);
+  g_key_file_set_string(data->key_file, page_group, PAGE_TYPE,
+			GNC_PLUGIN_PAGE_GET_CLASS(page)->plugin_name);
+
+  g_key_file_set_string(data->key_file, page_group, PAGE_NAME,
+			gnc_plugin_page_get_page_name(page));
+
+  gnc_plugin_page_save_page(page, data->key_file, page_group);
+  g_free(page_group);
+  LEAVE(" ");
+}
+
+
+/** Saves all the pages in a single window to a disk.  This function
+ *  saves all the window specific attributes, then calls a helper
+ *  function to save all the pages that are contained in the window.
+ *
+ *  @param window The GncMainWindow whose pages should be saved.
+ *
+ *  @param data A data structure containing state about the
+ *  window/page saving process. */
+static void
+gnc_main_window_save_window (GncMainWindow *window, GncMainWindowSaveData *data)
+{
+  GncMainWindowPrivate *priv;
+  gint num_pages, coords[4];
+  gchar *window_group;
+
+  /* Setup */
+  ENTER("window %p, data %p (key file %p, window %d)",
+	window, data, data->key_file, data->window_num);
+  priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
+  window_group = g_strdup_printf(WINDOW_STRING, data->window_num++);
+
+  /* Save the window coordinates, etc. */
+  gtk_window_get_position(GTK_WINDOW(window), &coords[0], &coords[1]);
+  gtk_window_get_size(GTK_WINDOW(window), &coords[2], &coords[3]);
+  g_key_file_set_integer_list(data->key_file, window_group,
+			      WINDOW_POSITION, &coords[0], 2);
+  g_key_file_set_integer_list(data->key_file, window_group,
+			      WINDOW_GEOMETRY, &coords[2], 2);
+  DEBUG("window (%p) position %dx%d, size %dx%d", window,  coords[0], coords[1],
+	coords[2], coords[3]);
+
+  /* Save this window's notebook info */
+  num_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook));
+  g_key_file_set_integer(data->key_file, window_group,
+			 WINDOW_PAGECOUNT, num_pages);
+  g_key_file_set_integer(data->key_file, window_group,
+			 WINDOW_FIRSTPAGE, data->page_num);
+
+  /* Save individual pages in this window */
+  g_list_foreach(priv->installed_pages, (GFunc)gnc_main_window_save_page, data);
+
+  g_free(window_group);
+  LEAVE("window %p", window);
+}
+
+
+/** Save the state of all windows to disk.  This function finds the
+ *  name of the "new" state file associated with a specific book guid.
+ *  It saves some top level data, then iterates through the list of
+ *  open windows calling a helper function to save each window.
+ *
+ *  @note The name of the state file is based on the name of the data
+ *  file, not the path name of the data file.  If there are multiple
+ *  data files with the same name, the state files will be suffixed
+ *  with a number.  E.G. test_account, test_account_2, test_account_3,
+ *  etc.
+ *
+ *  @param page The GncPluginPage whose state should be saved.
+ *
+ *  @param data A data structure containing state about the
+ *  window/page saving process. */
+static void
+gnc_main_window_save_all_state (gpointer session, gpointer user_data)
+{
+	GncMainWindowSaveData data;
+	QofBook *book;
+	const char *url, *guid_string;
+	gchar *filename;
+	const GUID *guid;
+	GError *error = NULL;
+
+	url = qof_session_get_url(session);
+	ENTER("session %p (%s)", session, url);
+	if (!url) {
+	  LEAVE("no url, nothing to do");
+	  return;
+	}
+
+	/* Get the book GUID */
+	book = qof_session_get_book(session);
+	guid = qof_entity_get_guid(QOF_ENTITY(book));
+	guid_string = guid_to_string(guid);
+
+	/* Find the filename to use.  This returns the data from the
+	 * file so its possible that we could reuse the data and
+	 * maintain comments that were added to the data file, but
+	 * that's not something we currently do. For now the existing
+	 * data is dumped and completely regenerated.*/
+	data.key_file = gnc_find_state_file(url, guid_string, &filename);
+	if (data.key_file)
+	  g_key_file_free(data.key_file);
+
+	/* Set up the iterator data structures */
+	data.key_file = g_key_file_new();
+	data.window_num = 1;
+	data.page_num = 1;
+
+	/* Store top level info in the data structure */
+	g_key_file_set_string(data.key_file,
+			      STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
+			      guid_string);
+	g_key_file_set_integer(data.key_file,
+			       STATE_FILE_TOP, WINDOW_COUNT,
+			       g_list_length(active_windows));
+
+	/* Dump all state information on the open windows */
+	g_list_foreach(active_windows, (GFunc)gnc_main_window_save_window, &data);
+
+#ifdef DEBUG
+	/*  Debugging: dump a copy to the trace log */
+	{
+	  gchar *file_data;
+	  gint file_length;
+	  file_data = g_key_file_to_data(data.key_file, &file_length, NULL);
+	  DEBUG("=== File Data Written===\n%s\n=== File End ===\n", file_data);
+	  g_free(file_data);
+	}
+#endif
+
+	/* Write it all out to disk */
+	gnc_key_file_save_to_file(filename, data.key_file, &error);
+	if (error) {
+	  g_critical(_("Error: Failure saving state file.\n  %s"), error->message);
+	  g_error_free(error);
+	}
+	g_free(filename);
+
+	/* Clean up */
+	g_key_file_free(data.key_file);
+	LEAVE("");
+}
+
+
 /** See if the page already exists.  For each open window, look
  *  through the list of pages installed in that window and see if the
  *  specified page is there.
@@ -874,6 +1346,127 @@
 
 
 /************************************************************
+ *                 Tab Label Implementation                 *
+ ************************************************************/
+static gboolean
+main_window_find_tab_items (GncMainWindow *window,
+			    GncPluginPage *page,
+			    GtkWidget **label_p,
+			    GtkWidget **entry_p)
+{
+  GncMainWindowPrivate *priv;
+  GtkWidget *tab_hbox, *widget;
+  GList *children, *tmp;
+
+  ENTER("window %p, page %p, label_p %p, entry_p %p",
+	window, page, label_p, entry_p);
+  priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
+  *label_p = *entry_p = NULL;
+  tab_hbox = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook),
+					page->notebook_page);
+  children = gtk_container_get_children(GTK_CONTAINER(tab_hbox));
+  for (tmp = children; tmp; tmp = g_list_next(tmp)) {
+    widget = tmp->data;
+    if (GTK_IS_LABEL(widget)) {
+      *label_p = widget;
+    } else if (GTK_IS_ENTRY(widget)) {
+      *entry_p = widget;
+    }
+  }
+  g_list_free(children);
+
+  LEAVE("label %p, entry %p", *label_p, *entry_p);
+  return (*label_p && *entry_p);
+}
+
+static void
+main_window_update_page_name (GncMainWindow *window,
+			      GncPluginPage *page,
+			      const gchar *name_in)
+{
+  GncMainWindowPrivate *priv;
+  GtkWidget *label, *entry;
+  gchar *name;
+
+  ENTER(" ");
+
+  if ((name_in == NULL) || (*name_in == '\0')) {
+    LEAVE("no string");
+    return;
+  }
+  name = g_strstrip(g_strdup(name_in));
+  if (*name == '\0') {
+    g_free(name);
+    LEAVE("empty string");
+    return;
+  }
+
+  /* Update the plugin */
+  priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
+  gnc_plugin_page_set_page_name(page, name);
+
+  /* Update the notebook tab */
+  main_window_find_tab_items(window, page, &label, &entry);
+  gtk_label_set_text(GTK_LABEL(label), name);
+
+  /* Update the notebook menu */
+  label = gtk_notebook_get_menu_label (GTK_NOTEBOOK(priv->notebook),
+				       page->notebook_page);
+  gtk_label_set_text(GTK_LABEL(label), name);
+  
+  /* Force an update of the window title */
+  gnc_main_window_update_title(window);
+  g_free(name);
+  LEAVE("done");
+}
+
+static void
+gnc_main_window_tab_entry_activate (GtkWidget *entry,
+				    GncPluginPage *page)
+{
+  GtkWidget *label, *entry2;
+
+  g_return_if_fail(GTK_IS_ENTRY(entry));
+  g_return_if_fail(GNC_IS_PLUGIN_PAGE(page));
+
+  ENTER("");
+  if (!main_window_find_tab_items(GNC_MAIN_WINDOW(page->window),
+				  page, &label, &entry2)) {
+    LEAVE("can't find required widgets");
+    return;
+  }
+
+  main_window_update_page_name(GNC_MAIN_WINDOW(page->window), page,
+			       gtk_entry_get_text(GTK_ENTRY(entry)));
+
+  gtk_widget_hide(entry);
+  gtk_widget_show(label);
+  LEAVE("");
+}
+
+
+static gboolean
+gnc_main_window_tab_entry_editing_done (GtkWidget *entry,
+					GncPluginPage *page)
+{
+  ENTER("");
+  gnc_main_window_tab_entry_activate(entry, page);
+  LEAVE("");
+  return FALSE;
+}
+
+static gboolean
+gnc_main_window_tab_entry_focus_out_event (GtkWidget *entry,
+					   GdkEvent *event,
+					   GncPluginPage *page)
+{
+  ENTER("");
+  gnc_main_window_tab_entry_activate(entry, page);
+  LEAVE("");
+  return FALSE;
+}
+
+/************************************************************
  *                   Widget Implementation                  *
  ************************************************************/
 
@@ -982,7 +1575,10 @@
 			G_TYPE_NONE, 1,
 			G_TYPE_OBJECT);
 
-	qof_session_add_close_hook(gnc_main_window_shutdown, NULL);
+	gnc_hook_add_dangler(HOOK_BOOK_OPENED,
+			     gnc_main_window_restore_all_state, NULL);
+	gnc_hook_add_dangler(HOOK_BOOK_CLOSED,
+			     gnc_main_window_save_all_state, NULL);
 
 	gnc_gconf_general_register_cb (KEY_SHOW_CLOSE_BUTTON,
 				       gnc_main_window_update_tabs,
@@ -1249,7 +1845,7 @@
 {
 	GncMainWindowPrivate *priv;
 	GtkWidget *tab_hbox;
-	GtkWidget *label;
+	GtkWidget *label, *entry;
 	const gchar *icon;
 	GtkWidget *image;
 	gboolean immutable = FALSE;
@@ -1304,6 +1900,18 @@
 
 	gtk_box_pack_start (GTK_BOX (tab_hbox), label, TRUE, TRUE, 0);
   
+	entry = gtk_entry_new();
+	gtk_widget_hide (entry);
+	gtk_box_pack_start (GTK_BOX (tab_hbox), entry, TRUE, TRUE, 0);
+	g_signal_connect(G_OBJECT(entry), "activate",
+			 G_CALLBACK(gnc_main_window_tab_entry_activate), page);
+	g_signal_connect(G_OBJECT(entry), "focus-out-event",
+			 G_CALLBACK(gnc_main_window_tab_entry_focus_out_event),
+			 page);
+	g_signal_connect(G_OBJECT(entry), "editing-done",
+			 G_CALLBACK(gnc_main_window_tab_entry_editing_done),
+			 page);
+
 	/* Add close button - Not for immutable pages */
 	if (!immutable) {
 	  GtkWidget *close_image, *close_button;
@@ -1525,6 +2133,22 @@
 }
 
 
+static GtkAction *
+gnc_main_window_find_action (GncMainWindow *window, const gchar *name)
+{
+  GtkAction *action = NULL;
+  const GList *groups, *tmp;
+
+  groups = gtk_ui_manager_get_action_groups(window->ui_merge);
+  for (tmp = groups; tmp; tmp = g_list_next(tmp)) {
+    action = gtk_action_group_get_action(GTK_ACTION_GROUP(tmp->data), name);
+    if (action)
+      break;
+  }
+  return action;
+}
+
+
 /*  Retrieve a specific set of user interface actions from a window.
  *  This function can be used to get an group of action to be
  *  manipulated when the front page of a window has changed.
@@ -1556,9 +2180,11 @@
 	g_return_if_fail (GNC_IS_MAIN_WINDOW (window));
 	g_return_if_fail (GNC_IS_PLUGIN (plugin));
 
+	ENTER(" ");
 	gnc_plugin_add_to_window (GNC_PLUGIN (plugin),
 				  GNC_MAIN_WINDOW (window),
 				  window_type);
+	LEAVE(" ");
 }
 
 static void
@@ -1613,6 +2239,8 @@
 	gchar *filename;
 	SCM debugging;
 
+	ENTER(" ");
+
 	/* Catch window manager delete signal */
 	g_signal_connect (G_OBJECT (window), "delete-event",
 			  G_CALLBACK (gnc_main_window_delete_event), window);
@@ -1721,8 +2349,10 @@
 	g_signal_connect (G_OBJECT (manager), "plugin-removed",
 			  G_CALLBACK (gnc_main_window_plugin_removed), window);
 
+	LEAVE(" ");
 }
 
+/* Callbacks */
 static void
 gnc_main_window_add_widget (GtkUIManager *merge,
 			    GtkWidget *widget,
@@ -1915,6 +2545,43 @@
 }
 
 static void
+gnc_main_window_cmd_actions_rename_page (GtkAction *action, GncMainWindow *window)
+{
+  GncMainWindowPrivate *priv;
+  GncPluginPage *page;
+  GtkWidget *tab_hbox, *widget, *label = NULL, *entry = NULL;
+  GList *children, *tmp;
+
+  ENTER(" ");
+  priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
+  page = priv->current_page;
+  tab_hbox = gtk_notebook_get_tab_label(GTK_NOTEBOOK(priv->notebook),
+                                       page->notebook_page);
+  children = gtk_container_get_children(GTK_CONTAINER(tab_hbox));
+  for (tmp = children; tmp; tmp = g_list_next(tmp)) {
+    widget = tmp->data;
+    if (GTK_IS_LABEL(widget)) {
+      label = widget;
+    } else if (GTK_IS_ENTRY(widget)) {
+      entry = widget;
+    }
+  }
+  g_list_free(children);
+
+  if (!label || !entry) {
+    LEAVE("Missing label or entry.");
+    return;
+  }
+
+  gtk_entry_set_text(GTK_ENTRY(entry), gtk_label_get_text(GTK_LABEL(label)));
+  gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
+  gtk_widget_hide(label);
+  gtk_widget_show(entry);
+  gtk_widget_grab_focus(entry);
+  LEAVE("opened for editing");
+}
+
+static void
 gnc_main_window_cmd_view_toolbar (GtkAction *action, GncMainWindow *window)
 {
 	GncMainWindowPrivate *priv;

Modified: gnucash/trunk/src/gnome-utils/gnc-plugin-page.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-plugin-page.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome-utils/gnc-plugin-page.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -35,10 +35,15 @@
 #include "config.h"
 
 #include <gtk/gtk.h>
+#include "gnc-engine.h"
+#include "gnc-trace.h"
 #include "gnc-plugin.h"
 #include "gnc-plugin-page.h"
 #include "gnc-gobject-utils.h"
 
+/* This static indicates the debugging module that this .o belongs to.  */
+static QofLogModule log_module = GNC_MOD_GUI;
+
 static gpointer         parent_class = NULL;
 
 static void gnc_plugin_page_class_init (GncPluginPageClass *klass);
@@ -180,7 +185,85 @@
 	}
 }
 
+
+/** Call a plugin specific function to save enough information about
+ *  this page that it can be recreated next time the user starts
+ *  gnucash.
+ *
+ *  @param page The page to save.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be written.
+ *
+ *  @param group_name The group name to use when saving data. */
 void
+gnc_plugin_page_save_page (GncPluginPage *page,
+			   GKeyFile *key_file,
+			   const gchar *group_name)
+{
+	GncPluginPageClass *klass;
+
+	g_return_if_fail (GNC_IS_PLUGIN_PAGE (page));
+	g_return_if_fail (key_file != NULL);
+	g_return_if_fail (group_name != NULL);
+
+	ENTER(" ");
+	klass = GNC_PLUGIN_PAGE_GET_CLASS (page);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->save_page != NULL);
+
+	klass->save_page(page, key_file, group_name);
+	LEAVE(" ");
+}
+
+
+/** This function looks up a specific plugin type and then calls its
+ *  function to create a new page.
+ *
+ *  @param window The window where this page should be installed.
+ *
+ *  @param page_type The name of the page type to create.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be read.
+ *
+ *  @param group_name The group name to use when restoring data. */
+GncPluginPage *
+gnc_plugin_page_recreate_page(GtkWidget *window,
+			      const gchar *page_type,
+			      GKeyFile *key_file,
+			      const gchar *page_group)
+{
+  GncPluginPageClass *klass;
+  GncPluginPage *page = NULL;
+  GType type;
+
+  ENTER("type %s, keyfile %p, group %s", page_type, key_file, page_group);
+  type = g_type_from_name(page_type);
+  if (type == 0) {
+    LEAVE("Cannot find type named %s", page_type);
+    return NULL;
+  }
+
+  klass = g_type_class_ref(type);
+  if (klass == NULL) {
+    LEAVE("Cannot create class %s(%ld)", page_type, type);
+    return NULL;
+  }
+
+  if (!klass->recreate_page) {
+    LEAVE("Class %shas no recreate function.", page_type);
+    g_type_class_unref(klass);
+    return NULL;
+  }
+
+  page = (klass->recreate_page)(window, key_file, page_group);
+  g_type_class_unref(klass);
+  LEAVE(" ");
+  return page;
+}
+
+void
 gnc_plugin_page_merge_actions (GncPluginPage *page,
 			       GtkUIManager *ui_merge)
 {
@@ -601,6 +684,7 @@
 gnc_plugin_page_set_page_name (GncPluginPage *page, const gchar *name)
 {
   GncPluginPagePrivate *priv;
+  GncPluginPageClass *klass;
 
   g_return_if_fail (GNC_IS_PLUGIN_PAGE (page));
 
@@ -608,6 +692,12 @@
   if (priv->page_name)
     g_free(priv->page_name);
   priv->page_name = g_strdup(name);
+
+  /* Perform page specific actions */
+  klass = GNC_PLUGIN_PAGE_GET_CLASS (page);
+  if (klass->page_name_changed) {
+    klass->page_name_changed(page, name);
+  }
 }
 
 const gchar *

Modified: gnucash/trunk/src/gnome-utils/gnc-plugin-page.h
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-plugin-page.h	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome-utils/gnc-plugin-page.h	2005-11-11 14:16:12 UTC (rev 11905)
@@ -36,6 +36,7 @@
 #ifndef __GNC_PLUGIN_PAGE_H
 #define __GNC_PLUGIN_PAGE_H
 
+#include <glib.h>
 #include "guid.h"
 #include "qofbook.h"
 
@@ -50,6 +51,12 @@
 #define GNC_PLUGIN_PAGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_PLUGIN_PAGE, GncPluginPageClass))
 
 /* typedefs & structures */
+#ifndef HAVE_GLIB26
+#ifndef __G_KEY_FILE_H__
+typedef struct _GKeyFile GKeyFile;
+#endif
+#endif
+
 typedef struct GncPluginPage {
 	GObject gobject;		/**< The parent object data. */
 
@@ -84,7 +91,47 @@
 	/* Virtual Table */
 	GtkWidget *(* create_widget) (GncPluginPage *plugin_page);
 	void (* destroy_widget) (GncPluginPage *plugin_page);
+
+	/** Save enough information about this page so that it can be
+	 *  recreated next time the user starts gnucash.
+	 *  
+	 *  @param page The page to save.
+	 *
+	 *  @param key_file A pointer to the GKeyFile data structure where the
+	 *  page information should be written.
+	 *
+	 *  @param group_name The group name to use when writing data.
+	 *  The name is specific to this page instance. */
+	void (* save_page) (GncPluginPage *page, GKeyFile *file, const gchar *group);
+
+	/** Create a new page based on the information saved during a
+	 *  previous instantiation of gnucash.  This function may or
+	 *  may not install the new page in the window as it sees fit.
+	 *  Generally the function will install the page int the
+	 *  window in order to manipulate the menu items that are
+	 *  created at install time.
+	 *
+	 *  @param window The window where this new page will be
+	 *  installed.
+	 *
+	 *  @param key_file A pointer to the GKeyFile data structure where the
+	 *  page information should be retrieved.
+	 *
+	 *  @param group_name The group name to use when retrieving
+	 *  data.  The name is specific to this page instance.
+	 *
+	 *  @return A pointer to the new page. */
+        GncPluginPage * (* recreate_page) (GtkWidget *window, GKeyFile *file, const gchar *group);
+
 	void (* window_changed) (GncPluginPage *plugin_page, GtkWidget *window);
+
+	/** This function vector allows page specific actions to occur
+	 *  when the page name is changed.
+	 *  
+	 *  @param page The page to update.
+	 *  
+	 *  @param name The new name for this page. */
+	void (* page_name_changed) (GncPluginPage *plugin_page, const gchar *name);
 } GncPluginPageClass;
 
 /* function prototypes */
@@ -101,6 +148,14 @@
  */
 void gnc_plugin_page_show_summarybar (GncPluginPage *page, gboolean visible);
 
+void		      gnc_plugin_page_save_page (GncPluginPage *page,
+						 GKeyFile *key_file,
+						 const gchar *group_name);
+GncPluginPage *      gnc_plugin_page_recreate_page (GtkWidget *window,
+						    const gchar *page_type,
+						    GKeyFile *key_file,
+						    const gchar *group_name);
+
 void                  gnc_plugin_page_merge_actions   (GncPluginPage *plugin_page,
                                                        GtkUIManager *merge);
 void                  gnc_plugin_page_unmerge_actions (GncPluginPage *plugin_page,

Modified: gnucash/trunk/src/gnome-utils/ui/gnc-main-window-ui.xml
===================================================================
--- gnucash/trunk/src/gnome-utils/ui/gnc-main-window-ui.xml	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/gnome-utils/ui/gnc-main-window-ui.xml	2005-11-11 14:16:12 UTC (rev 11905)
@@ -82,6 +82,7 @@
       <menu name="ScrubMenu" action="ScrubMenuAction"/>
       <separator name="ActionSepE"/>
       <menuitem name="ActionsForgetWarnings" action="ActionsForgetWarningsAction"/>
+      <menuitem name="ActionsRenamePage" action="ActionsRenamePageAction"/>
     </menu>
   
     <placeholder name="AdditionalMenusPlaceholder"/>
@@ -139,6 +140,7 @@
   <popup name="MainPopup" action="FakeToplevel">
     <separator name="PopupSep1"/>
     <placeholder name="PopupPlaceholder1"/>
+    <menuitem name="ActionsRenamePage" action="ActionsRenamePageAction"/>
     <separator name="PopupSep2"/>
     <placeholder name="PopupPlaceholder2"/>
     <separator name="PopupSep3"/>

Modified: gnucash/trunk/src/report/report-gnome/Makefile.am
===================================================================
--- gnucash/trunk/src/report/report-gnome/Makefile.am	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/report/report-gnome/Makefile.am	2005-11-11 14:16:12 UTC (rev 11905)
@@ -14,6 +14,7 @@
   -I${top_srcdir}/src/gnome-utils \
   -I${top_srcdir}/src/gnome \
   -I${top_srcdir}/src/report/report-system \
+  -I${top_srcdir}/lib/glib26 \
   ${GLADE_CFLAGS} \
   ${GUILE_INCS} \
   ${GTKHTML_CFLAGS} \
@@ -42,6 +43,7 @@
   ${top_builddir}/src/gnc-module/libgncmodule.la \
   ${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
   ${top_builddir}/src/report/report-system/libgncmod-report-system.la \
+  ${top_builddir}/lib/glib26/libgncglib.la \
   ${GLADE_LIBS} \
   ${GUILE_LIBS} \
   ${GNOME_PRINT_LIBS} \

Modified: gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.c
===================================================================
--- gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -1,5 +1,6 @@
 /* gnc-plugin-page-report.c
  * Copyright (C) 2004 Joshua Sled <jsled at asynchronous.org>
+ * Copyright (C) 2005 David Hampton <hampton at employees.org>
  *
  * Originally from window-report.c:
  * Copyright (C) 1997 Robin D. Clark
@@ -26,10 +27,23 @@
  * Boston, MA  02111-1307,  USA       gnu at gnu.org
  */
 
+/** @addtogroup GUI
+    @{ */
+/** @addtogroup GuiReport Reports
+    @{ */
+/** @file gnc-plugin-page-report.c
+    @brief  Report page.
+    @author Copyright (C) 2004 Joshua Sled <jsled at asynchronous.org>
+    @author Copyright (C) 2005 David Hampton <hampton at employees.org>
+*/
+
 #include "config.h"
 
 #include <errno.h>
 #include <gtk/gtk.h>
+#ifndef HAVE_GLIB26
+#include "gkeyfile.h"
+#endif
 #include <g-wrap-wct.h>
 #include <libguile.h>
 #include <sys/stat.h>
@@ -47,6 +61,7 @@
 #include "gnc-ui-util.h"
 #include "gnc-ui.h"
 #include "gnc-window.h"
+#include "guile-util.h"
 #include "messages.h"
 #include "option-util.h"
 
@@ -111,6 +126,9 @@
 
 static GtkWidget* gnc_plugin_page_report_create_widget( GncPluginPage *plugin_page );
 static void gnc_plugin_page_report_destroy_widget( GncPluginPage *plugin_page );
+static void gnc_plugin_page_report_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
+static GncPluginPage *gnc_plugin_page_report_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
+static void gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name);
 
 static int gnc_plugin_page_report_check_urltype(URLType t);
 static void gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
@@ -233,6 +251,9 @@
 
 	gnc_plugin_page_class->create_widget   = gnc_plugin_page_report_create_widget;
 	gnc_plugin_page_class->destroy_widget  = gnc_plugin_page_report_destroy_widget;
+	gnc_plugin_page_class->save_page       = gnc_plugin_page_report_save_page;
+	gnc_plugin_page_class->recreate_page   = gnc_plugin_page_report_recreate_page;
+	gnc_plugin_page_class->page_name_changed = gnc_plugin_page_report_name_changed;
 
 	g_type_class_add_private(klass, sizeof(GncPluginPageReportPrivate));
 
@@ -474,7 +495,7 @@
         priv->option_change_cb_id = 
                 gnc_option_db_register_change_callback(priv->cur_odb,
                                                        gnc_plugin_page_report_option_change_cb,
-                                                       priv, NULL, NULL);
+                                                       report, NULL, NULL);
         
         if (gnc_html_history_forward_p(gnc_html_get_history(priv->html))) {
                 gnc_plugin_page_report_set_fwd_button(report, TRUE); 
@@ -491,17 +512,45 @@
         LEAVE( "done" );
 }
 
+
+/** This function is called when one of the options for a register
+ *  page has changed.  It is responsible for marking the report as
+ *  dirty, and causing the report to reload using the new options.
+ *
+ *  @note This function currently also calls the main window code to
+ *  update it if the name of the report has changed.  This code should
+ *  eventually go away, and the only way to change the name should be
+ *  via the main window.  gnucash.
+ *
+ *  @param data A pointer to the GncPluginPageReport data structure
+ *  that describes a report. */
 static void
 gnc_plugin_page_report_option_change_cb(gpointer data)
 {
-        GncPluginPageReportPrivate *priv = data;
+        GncPluginPageReport *report;
+        GncPluginPageReportPrivate *priv;
         SCM dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
+	const gchar *old_name;
+	gchar *new_name;
 
+	g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(data));
+	report = GNC_PLUGIN_PAGE_REPORT(data);
+	priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
+
         DEBUG( "option_change" );
         if (priv->cur_report == SCM_BOOL_F)
                 return;
         DEBUG( "set-dirty, queue-draw" );
 
+	/* Update the page (i.e. the notebook tab and window title) */
+	old_name = gnc_plugin_page_get_page_name(GNC_PLUGIN_PAGE(report));
+	new_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
+						      "Report name", NULL);
+	if (strcmp(old_name, new_name) != 0) {
+	  gnc_plugin_page_set_page_name(GNC_PLUGIN_PAGE(report), new_name);
+	}
+	g_free(new_name);
+
         /* it's probably already dirty, but make sure */
         scm_call_2(dirty_report, priv->cur_report, SCM_BOOL_T);
         
@@ -590,6 +639,144 @@
         scm_call_1(remover, scm_int2num(report_id));
 }
 
+
+/** The key name used it the state file for storing the report
+ *  options. */
+#define SCHEME_OPTIONS "Scheme Options"
+
+
+/** Save enough information about this report page that it can be
+ *  recreated next time the user starts gnucash.
+ *
+ *  @param page The page to save.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be written.
+ *
+ *  @param group_name The group name to use when saving data. */
+static void
+gnc_plugin_page_report_save_page (GncPluginPage *plugin_page,
+				  GKeyFile *key_file,
+				  const gchar *group_name)
+{
+	GncPluginPageReport *report;
+	GncPluginPageReportPrivate *priv;
+	SCM gen_save_text, scm_text;
+	gchar *text;
+	
+	g_return_if_fail (GNC_IS_PLUGIN_PAGE_REPORT(plugin_page));
+	g_return_if_fail (key_file != NULL);
+	g_return_if_fail (group_name != NULL);
+
+	ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
+	      group_name);
+
+	report = GNC_PLUGIN_PAGE_REPORT(plugin_page);
+        priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
+
+        gen_save_text = scm_c_eval_string("gnc:report-generate-restore-forms");
+        scm_text = scm_call_1(gen_save_text, priv->cur_report);
+
+	if (!SCM_STRINGP (scm_text)) {
+	  LEAVE("nothing to save");
+	  return;
+	}
+
+	text = gnc_guile_strip_comments(SCM_STRING_CHARS(scm_text));
+	g_key_file_set_string(key_file, group_name, SCHEME_OPTIONS, text);
+	g_free(text);
+	LEAVE(" ");
+}
+
+
+/** Create a new report page based on the information saved during a
+ *  previous instantiation of gnucash.
+ *
+ *  @param window The window where this page should be installed.
+ *
+ *  @param key_file A pointer to the GKeyFile data structure where the
+ *  page information should be read.
+ *
+ *  @param group_name The group name to use when restoring data. */
+static GncPluginPage *
+gnc_plugin_page_report_recreate_page (GtkWidget *window,
+				      GKeyFile *key_file,
+				      const gchar *group_name)
+{
+	GncPluginPage *page;
+	GError *error = NULL;
+	gchar *option_string;
+	gint report_id;
+	SCM scm_id;
+	
+	g_return_val_if_fail(key_file, NULL);
+	g_return_val_if_fail(group_name, NULL);
+	ENTER("key_file %p, group_name %s", key_file, group_name);
+
+	option_string = g_key_file_get_string(key_file, group_name,
+					      SCHEME_OPTIONS, &error);
+	if (error) {
+	  g_warning("error reading group %s key %s: %s",
+		    group_name, SCHEME_OPTIONS, error->message);
+	  LEAVE("bad value");
+	  return NULL;
+	}
+	scm_id = scm_c_eval_string(option_string);
+	if (!scm_integer_p(scm_id)) {
+	  g_free(option_string);
+	  LEAVE("report id not an integer");
+	  return NULL;
+	}
+
+	report_id = scm_num2int(scm_id, SCM_ARG1, __FUNCTION__);
+	page = gnc_plugin_page_report_new( report_id );
+
+	g_free(option_string);
+	LEAVE(" ");
+	return page;
+}
+
+
+/** Update a report page to reflect a name change made by external
+ *  code.  This is called from the main window code when a page's name
+ *  is changes.  The report code will update its copy of the name and
+ *  regenerate the report.
+ *
+ *  @internal
+ *  
+ *  @param page The page whose name has changed.
+ *
+ *  @param name The new name for the page. */
+static void
+gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name)
+{
+  GncPluginPageReportPrivate *priv;
+  static gint count = 1, max_count = 10;
+  const gchar *old_name;
+
+  g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(page));
+  g_return_if_fail(name != NULL);
+  g_return_if_fail(count++ <= max_count);
+
+  ENTER("page %p, name %s", page, name);
+  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(page);
+
+  /* Is this a redundant call? */
+  old_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
+						"Report name", NULL);
+  DEBUG("Comparing old name '%s' to new name '%s'", old_name, name);
+  if (old_name && (strcmp(old_name, name) == 0)) {
+    LEAVE("no change");
+    return;
+  }
+
+  gnc_option_db_set_string_option(priv->cur_odb, "General",
+				  "Report name", name);
+  gnc_plugin_page_report_option_change_cb(page);
+  LEAVE(" ");
+}
+
+
 /********************************************************************
  * gnc_report_window_destroy 
  * free and destroy a window 
@@ -696,8 +883,8 @@
         GncPluginPageReportPrivate *priv;
         GtkActionGroup *action_group;
         GncPluginPage *parent;
-        GString *tmpStr;
         gboolean use_new;
+	gchar *name;
 
         DEBUG( "property reportId=%d", reportId );
         priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
@@ -708,15 +895,14 @@
         /* Init parent declared variables */
         parent = GNC_PLUGIN_PAGE(plugin_page);
         use_new = gnc_gconf_get_bool(GCONF_GENERAL_REPORT, KEY_USE_NEW, NULL);
-        tmpStr = g_string_sized_new( 32 );
-        g_string_sprintf( tmpStr, "%s: %s", _("Report"),
-                          gnc_report_name( priv->initial_report ) );
+	name = gnc_report_name( priv->initial_report );
 	g_object_set(G_OBJECT(plugin_page),
-		     "page-name",      tmpStr->str,
+		     "page-name",      name,
 		     "page-uri",       "default:",
 		     "ui-description", "gnc-plugin-page-report-ui.xml",
 		     "use-new-window", use_new,
 		     NULL);
+	g_free(name);
 
         /* change me when the system supports multiple books */
         gnc_plugin_page_add_book(parent, gnc_get_current_book());
@@ -1125,3 +1311,6 @@
         reportPage = gnc_plugin_page_report_new( 42 /* url? */ );
         gnc_main_window_open_page( window, reportPage );
 }
+
+/** @} */
+/** @} */

Modified: gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.h
===================================================================
--- gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.h	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.h	2005-11-11 14:16:12 UTC (rev 11905)
@@ -47,7 +47,7 @@
 #define GNC_IS_PLUGIN_PAGE_REPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_REPORT))
 #define GNC_PLUGIN_PAGE_REPORT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReportClass))
 
-#define GNC_PLUGIN_PAGE_REPORT_NAME "gnc-plugin-page-report"
+#define GNC_PLUGIN_PAGE_REPORT_NAME "GncPluginPageReport"
 
 /* typedefs & structures */
 typedef struct {

Modified: gnucash/trunk/src/report/report-gnome/window-report.c
===================================================================
--- gnucash/trunk/src/report/report-gnome/window-report.c	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/report/report-gnome/window-report.c	2005-11-11 14:16:12 UTC (rev 11905)
@@ -293,6 +293,10 @@
 void
 gnc_report_init (void)
 {
+  /* Reference the report page plugin to ensure it exists in the gtk
+   * type system. */
+  GNC_TYPE_PLUGIN_PAGE_REPORT;
+
   gnc_html_register_stream_handler (URL_TYPE_HELP, gnc_html_file_stream_cb);
   gnc_html_register_stream_handler (URL_TYPE_FILE, gnc_html_file_stream_cb);
   gnc_html_register_stream_handler (URL_TYPE_REPORT, gnc_html_report_stream_cb);

Modified: gnucash/trunk/src/scm/main-window.scm
===================================================================
--- gnucash/trunk/src/scm/main-window.scm	2005-11-11 06:01:27 UTC (rev 11904)
+++ gnucash/trunk/src/scm/main-window.scm	2005-11-11 14:16:12 UTC (rev 11905)
@@ -40,12 +40,6 @@
             (gnc:register-option options opt))))
 
     (add-option
-     (gnc:make-string-option
-      (N_ "Account Tree") (N_ "Name of account view")
-      "a" (N_ "If you keep multiple account views open, it may be helpful \
-to give each one a descriptive name") (_ "Accounts")))
-
-    (add-option
      (gnc:make-simple-boolean-option
       (N_ "Account Tree") (N_ "Double click expands parent accounts")
       "a" (N_ "Double clicking on an account with children expands \
@@ -138,8 +132,6 @@
 	  ))))
 
 (define (gnc:main-window-book-close-handler session)
-  (gnc:main-window-save-state session)
-
   (let ((dead-reports '()))
     ;; get a list of the reports we'll be needing to nuke     
     (hash-fold 
@@ -169,7 +161,6 @@
 	 (dead-reports '()))
     (if conf-file-name 
         (try-load conf-file-name))
-    (gnc:new-account-tree #f)
 
     ;; the reports have only been created at this point; create their ui component.
     (hash-fold (lambda (key val prior-result)
@@ -190,11 +181,6 @@
 			   slots (_ "Book Options")
 			   changed_cb)))
 
-(gnc:hook-remove-dangler gnc:*book-opened-hook* 
-                         gnc:main-window-book-open-handler)
-(gnc:hook-add-dangler gnc:*book-opened-hook* 
-                      gnc:main-window-book-open-handler)
-
 (gnc:hook-remove-dangler gnc:*book-closed-hook* 
                          gnc:main-window-book-close-handler)
 (gnc:hook-add-dangler gnc:*book-closed-hook* 



More information about the gnucash-changes mailing list