[Gnucash-changes] Convert common functions into a new base gnc-tree-view object.

David Hampton hampton at cvs.gnucash.org
Sat May 21 00:54:07 EDT 2005


Log Message:
-----------
Convert common functions into a new base gnc-tree-view object.
Integrate the object with gconf for tracking sizes and visibilities of
columns within a view.  Add a new popup menu for selecting column
visibilities.  Make it easier to add new columns after a view has been
created.

Tags:
----
gnucash-gnome2-dev

Modified Files:
--------------
    gnucash:
        ChangeLog
        GNOME2_STATUS
    gnucash/src/gnome-utils:
        Makefile.am

Added Files:
-----------
    gnucash/src/gnome-utils:
        gnc-tree-view.c
        gnc-tree-view.h

Removed Files:
-------------
    gnucash/src/gnome-utils:
        gnc-tree-view-common.c
        gnc-tree-view-common.h

Revision Data
-------------
Index: ChangeLog
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/ChangeLog,v
retrieving revision 1.1487.2.206
retrieving revision 1.1487.2.207
diff -LChangeLog -LChangeLog -u -r1.1487.2.206 -r1.1487.2.207
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,50 @@
+2005-05-21  David Hampton  <hampton at employees.org>
+
+	* src/gnome-utils/Makefile.am:
+	* src/gnome-utils/gnc-tree-view-common.[ch]:
+	* src/gnome-utils/gnc-tree-view.[ch]: Convert common functions
+	into a new base gnc-tree-view object.  Integrate the object with
+	gconf for tracking sizes and visibilities of columns within a
+	view.  Add a new popup menu for selecting column visibilities.
+	Make it easier to add new columns after a view has been created.
+	
+	* src/gnome-utils/gnc-tree-view-*: Base these views on the new
+	common gnc-tree-view class.
+
+	* src/gnome-utils/gnc-tree-model-*: Remove the dedicated column
+	for right aligning numbers.  This is done by a simpler method now.
+
+	* src/gnome/dialog-budget-category.c:
+	* src/gnome/dialog-commodities.c:
+	* src/gnome/dialog-price-edit-db.c:
+	* src/gnome/druid-hierarchy.c:
+	* src/gnome/gnc-plugin-page-account-tree.c:
+	* src/import-export/import-account-matcher.c: Changes because
+	called functions have moved in to the base gnc tree view.
+
+	* src/app-utils/gnc-ui-util.[ch]:
+	* src/gnome-utils/dialog-account.c:
+	* src/scm/main-window.scm: Prune three or four layers of
+	complicated code that is only ever used to extract a single value
+	from an account.
+
+2005-05-20  David Hampton  <hampton at employees.org>
+
+	* src/gnome-utils/gnc-tree-model-account.c: Store the book as part
+	of the model private data.  In the event handler for the model,
+	ensure that events are for accounts that are in the model.
+
+2005-05-19  David Hampton  <hampton at employees.org>
+
+	* src/core-utils/gnc-gconf-utils.[ch]: Add some more utility
+	functions.
+
+	* src/gnome/schemas/apps_gnucash_dialog_commodities.schemas:
+	* src/gnome-utils/gnc-tree-view-commodity.c: Renamed "exchange
+	code" to "cusip code".  The former seems like it is referring to
+	NASDAQ, NYSE, etc, not a code that is unique to a specific
+	security.  The latter is by definition security specific.
+	
 2005-05-15  David Hampton  <hampton at employees.org>
 
 	* src/gnome-utils/gnc-tree-view-account.[ch]:
Index: GNOME2_STATUS
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/Attic/GNOME2_STATUS,v
retrieving revision 1.1.2.51
retrieving revision 1.1.2.52
diff -LGNOME2_STATUS -LGNOME2_STATUS -u -r1.1.2.51 -r1.1.2.52
--- GNOME2_STATUS
+++ GNOME2_STATUS
@@ -216,9 +216,6 @@
 
     - dialog doesn't expand/fill on resize
 
-    - changing displayed columns has strange effects (some columns being
-      added, some not, some seeming off-by-one errors, &c.)
-
   - Stylesheets
 
     - Dialog opens with inappropriate scrollbars.
--- src/gnome-utils/gnc-tree-view-common.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/* 
- * gnc-tree-view-common.c -- common utilities for manipulating a
- *                     GtkTreeView within gnucash
- *
- * 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
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, contact:
- *
- * Free Software Foundation           Voice:  +1-617-542-5942
- * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652
- * Boston, MA  02111-1307,  USA       gnu at gnu.org
- */
-
-#include "config.h"
-
-#include <gtk/gtk.h>
-#include <libgnome/libgnome.h>
-#include <string.h>
-
-#include "gnc-tree-view-common.h"
-#include "gnc-engine-util.h"
-#include "gnc-gconf-utils.h"
-#include "gnc-gnome-utils.h"
-
-#define COLUMN_NUM "column"
-#define TREE_NAME  "tree-name"
-
-/** Static Globals *******************************************************/
-
-/* This static indicates the debugging module that this .o belongs to.  */
-static short module = MOD_GUI;
-
-
-/************************************************************/
-/*                   Auxiliary Functions                    */
-/************************************************************/
-
-static gint
-view_column_find_by_name(gnc_view_column *defaults,
-			 const gchar *name)
-{
-  gint i;
-
-  g_return_val_if_fail (name != NULL, -1);
-
-  for (i = 0; defaults[i].pref_name != NULL; i++) {
-    if (strcmp(defaults[i].pref_name, name) == 0)
-      return i;
-  }
-  return -1;
-}
-
-
-/************************************************************/
-/*                    Tree View Creation                    */
-/************************************************************/
-
-void
-gnc_tree_view_common_create_columns (GtkTreeView *view,
-				     const gchar *tree_name,
-				     const gchar *stock_icon,
-				     gnc_view_column *defaults)
-{
-  GtkTreeModel *s_model;
-  GtkCellRenderer *renderer;
-  GtkTreeViewColumn *column;
-  gboolean is_sortable;
-  gint i;
-
-  ENTER("view %p, name %s, icon %s, defaults %p",
-	view, tree_name, stock_icon, defaults);
-  g_object_set_data(G_OBJECT(view), TREE_NAME, g_strdup(tree_name));
-
-  /*
-   * Get the model
-   */
-  s_model = gtk_tree_view_get_model(view);
-  is_sortable = GTK_IS_TREE_MODEL_SORT(s_model);
-
-  /*
-   * Create the first column.  This column is special in that it will
-   * have the disclosure triangle to expand the tree, and it may have
-   * an icon in it.
-   */
-  column = gtk_tree_view_column_new ();
-  g_object_set_data(G_OBJECT(column), COLUMN_NUM, GINT_TO_POINTER(0));
-  gtk_tree_view_column_set_title (column, gettext(defaults[0].field_name));
-  if (stock_icon) {
-    renderer = gtk_cell_renderer_pixbuf_new ();
-    g_object_set (renderer, "stock-id", stock_icon, NULL);
-    gtk_tree_view_column_pack_start (column, renderer, FALSE);
-  }
-  renderer = gtk_cell_renderer_text_new ();
-  gtk_tree_view_column_pack_start (column, renderer, FALSE);
-  gtk_tree_view_column_add_attribute (column,
-				      renderer,
-				      "text", defaults[0].column);
-  if (defaults[0].visibility_column != GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS)
-    gtk_tree_view_column_add_attribute (column, renderer,
-					"visible", defaults[0].visibility_column);
-  if (defaults[0].color_column != GNC_TREE_VIEW_COLUMN_COLOR_NONE)
-    gtk_tree_view_column_add_attribute (column, renderer,
-					"foreground", defaults[0].color_column);
-  if (defaults[0].align_column != GNC_TREE_VIEW_COLUMN_ALIGN_NONE)
-    gtk_tree_view_column_add_attribute (column, renderer,
-					"xalign", defaults[0].align_column);
-  gtk_tree_view_append_column (view, column);
-
-  /*
-   * Set the attributes of this first column
-   */
-  g_object_set(G_OBJECT(column),
-	       "visible",     TRUE,
-	       "alignment",   defaults[0].label_align,
-	       "min-width",   50,  /* DRH - Should be based on title width */
-	       "resizable",   TRUE,
-	       "reorderable", TRUE,
-	       "sizing",      defaults[0].sizing,
-	       NULL);
-  gtk_tree_view_set_expander_column (view, column);
-  if (is_sortable) {
-    gtk_tree_view_column_set_sort_column_id (column, 0);
-    if (defaults[0].sort_fn)
-      gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(s_model), 0,
-				       defaults[0].sort_fn,
-				       NULL /* user_data */,
-				       NULL /* destroy fn */);
-  }
-  DEBUG("Created %s column", defaults[0].pref_name);
-
-
-  /*
-   * Now create any additional columns.  These columns may contain
-   * regular text or toggle buttons.
-   */
-  for (i = 1; defaults[i].pref_name != NULL; i++) {
-    if (defaults[i].is_toggle) {
-      renderer = gtk_cell_renderer_toggle_new ();
-      column = gtk_tree_view_column_new_with_attributes (gettext(defaults[i].field_name),
-							 renderer,
-							 "active", defaults[i].column,
-							 NULL);
-      if (defaults[i].toggle_edited)
-	g_signal_connect (G_OBJECT (renderer), "toggled",
-			  G_CALLBACK (defaults[i].toggle_edited),
-			  view);
-    } else {
-      renderer = gtk_cell_renderer_text_new ();
-      column = gtk_tree_view_column_new_with_attributes (gettext(defaults[i].field_name),
-							 renderer,
-							 "text", defaults[i].column,
-							 NULL);
-      if (defaults[i].color_column != GNC_TREE_VIEW_COLUMN_COLOR_NONE)
-	gtk_tree_view_column_add_attribute (column, renderer,
-					    "foreground", defaults[i].color_column);
-      if (defaults[i].align_column != GNC_TREE_VIEW_COLUMN_ALIGN_NONE)
-	gtk_tree_view_column_add_attribute (column, renderer,
-					    "xalign", defaults[i].align_column);
-    }
-    if (defaults[i].visibility_column != GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS)
-      gtk_tree_view_column_add_attribute (column, renderer,
-					  "visible", defaults[i].visibility_column);
-
-    g_object_set_data(G_OBJECT(column), COLUMN_NUM, GINT_TO_POINTER(i));
-    gtk_tree_view_append_column (view, column);
-
-    /*
-     * Set the attributes of this column
-     */
-    g_object_set(G_OBJECT(column),
-		 "visible",     TRUE,
-		 "alignment",   defaults[i].label_align,
-		 "min-width",   50,  /* DRH - Should be based on title width */
-		 "resizable",   TRUE,
-		 "reorderable", TRUE,
-		 "sizing",      defaults[i].sizing,
-		 NULL);
-
-    if (is_sortable) {
-      gtk_tree_view_column_set_sort_column_id (column, i);
-      if (defaults[i].sort_fn)
-	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(s_model), i,
-					 defaults[i].sort_fn,
-					 NULL /* user_data */,
-					 NULL /* destroy fn */);
-    }
-
-    DEBUG("Created %s column", defaults[i].pref_name);
-  }
-  LEAVE(" ");
-}
-
-
-
-/************************************************************/
-/*         Commodity Tree View Get/Save Settings            */
-/************************************************************/
-
-static void
-gnc_tree_view_common_save_sort_info (GtkTreeView *view,
-				     const gchar *section,
-				     gnc_view_column *defaults)
-{
-  GtkTreeViewColumn *column;
-  GtkTreeModel *s_model;
-  gboolean      has_sort_column;
-  gint          sort_column_id;
-  GtkSortType   order;
-  GEnumClass   *enum_class;
-  GEnumValue   *enum_value;
-  const gchar  *col_name, *enum_name;
-
-  s_model = gtk_tree_view_get_model (view);
-  has_sort_column = gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE(s_model),
-							  &sort_column_id,
-							  &order);
-
-  if (has_sort_column) {
-    column = gtk_tree_view_get_column (view, sort_column_id);
-    col_name = defaults[sort_column_id].pref_name;
-  } else {
-    col_name = "none"; 
-    order = GTK_SORT_ASCENDING;
-  }
-
-  enum_class = g_type_class_ref (GTK_TYPE_SORT_TYPE);
-  enum_value = g_enum_get_value (enum_class, order);
-  enum_name  = enum_value->value_nick;
-
-  gnc_gconf_set_string(section, "sort_column", col_name, NULL);
-  gnc_gconf_set_string(section, "sort_order", enum_name, NULL);
-}
-
-void
-gnc_tree_view_common_save_settings (GtkTreeView *view,
-				    const gchar *section,
-				    gnc_view_column *defaults)
-{
-  GtkTreeViewColumn *column;
-  GSList *column_names = NULL;
-  gchar *key;
-  const gchar *tree_name;
-  const gchar *name;
-  gint i, num;
-
-  g_return_if_fail (GTK_IS_TREE_VIEW(view));
-  g_return_if_fail (section != NULL);
-  g_return_if_fail (defaults != NULL);
-
-  tree_name = g_object_get_data(G_OBJECT(view), TREE_NAME);
-  ENTER("view %p, name %s, section %s, defaults %p",
-	view, tree_name, section, defaults);
-
-  for (i = 0; defaults[i].pref_name != NULL; i++) {
-    column = gtk_tree_view_get_column (view, i);
-    num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), COLUMN_NUM));
-
-    /* Save up the column names */
-    name = defaults[num].pref_name;
-    column_names = g_slist_append(column_names, (gpointer)name);
-
-    /* Remember whether the column is visible */
-    key = g_strdup_printf("%s_visible", name);
-    gnc_gconf_set_bool(section, key,
-		       gtk_tree_view_column_get_visible(column), NULL);
-    g_free(key);
-
-    /* Remember whether the column width */
-    key = g_strdup_printf("%s_width", name);
-    gnc_gconf_set_int(section, key,
-		      gtk_tree_view_column_get_width(column), NULL);
-    g_free(key);
-  }
-
-  gnc_tree_view_common_save_sort_info (view, section, defaults);
-
-  gnc_gconf_set_list(section, "column_order", GCONF_VALUE_STRING,
-		     column_names, NULL);
-  gnc_gconf_suggest_sync();
-  LEAVE(" ");
-}
-
-static void
-gnc_tree_view_common_restore_sort_info (GtkTreeView *view,
-					const gchar *section,
-					gnc_view_column *defaults)
-{
-  GtkTreeModel *s_model;
-  gchar        *value;
-  gint          sort_column_id = -1;
-  GtkSortType   order = GTK_SORT_ASCENDING;
-  GEnumClass   *enum_class;
-  GEnumValue   *enum_value;
-
-  value = gnc_gconf_get_string(section, "sort_column", NULL);
-  if (value) {
-    sort_column_id = view_column_find_by_name(defaults, value);
-    g_free(value);
-  }
-
-  value = gnc_gconf_get_string(section, "sort_order", NULL);
-  if (value) {
-    enum_class = g_type_class_ref (GTK_TYPE_SORT_TYPE);
-    enum_value = g_enum_get_value_by_nick (enum_class, value);
-    if (enum_value)
-      order = enum_value->value;
-    g_free(value);
-  }
-
-  s_model = gtk_tree_view_get_model (view);
-  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(s_model),
-					sort_column_id,
-					order);
-}
-
-void
-gnc_tree_view_common_restore_settings (GtkTreeView *view,
-				       const gchar *section,
-				       gnc_view_column *defaults)
-{
-  GtkTreeViewColumn *column, *prev;
-  const gchar *col_name;
-  const gchar *tree_name;
-  gchar *key;
-  GSList *column_names, *tmp, *next;
-  gboolean visible;
-  gint i, width;
-
-  g_return_if_fail (GTK_IS_TREE_VIEW(view));
-  g_return_if_fail (section != NULL);
-  g_return_if_fail (defaults != NULL);
-
-  tree_name = g_object_get_data(G_OBJECT(view), TREE_NAME);
-  ENTER("view %p, name %s, section %s, defaults %p",
-	view, tree_name, section, defaults);
-
-  /* Get the column order information first.  This can be used as a
-   * key to see if 1) there is any information present in the users
-   * gconf files, and 2) the gconf schema have been installed.  If the
-   * result is a null list, neither of the two is present and this
-   * routine should bail now. We'll actually swap the columns around
-   * after setting up all the other information. */
-  column_names = gnc_gconf_get_list(section, "column_order",
-				    GCONF_VALUE_STRING, NULL);
-  if (column_names == NULL)
-    return;
-
-  /* Restore the sort information, if any */
-  gnc_tree_view_common_restore_sort_info (view, section, defaults);
-
-  /* Restore any per-column information */
-  for (i = 0; defaults[i].pref_name != NULL; i++) {
-    column = gtk_tree_view_get_column (view, i);
-    col_name = defaults[i].pref_name;
-    DEBUG("Processing column %s", col_name);
-
-    /* visible */
-    key = g_strdup_printf("%s_visible", col_name);
-    visible = gnc_gconf_get_bool(section, key, NULL);
-    DEBUG("  Setting %s column visibility to %d", col_name, visible);
-    gtk_tree_view_column_set_visible (column, visible);
-    g_free(key);
-
-    /* column width */
-    key = g_strdup_printf("%s_width", col_name);
-    width = gnc_gconf_get_int(section, key, NULL);
-    if (width != 0) {
-      DEBUG("  Would set %s column width to %d", col_name, width);
-      // gtk_tree_view_column_set_width (column, width);
-    }
-    g_free(key);
-  }
-
-  /* Now swap the columns around the way the user had them. */
-  DEBUG("Processing column order");
-
-  /* First, convert from names to pointers */
-  for (tmp = column_names; tmp; tmp = next) {
-    next = g_slist_next(tmp);
-    i = view_column_find_by_name(defaults, tmp->data);
-    DEBUG("Processing %s column for order", (gchar *)tmp->data);
-    g_free(tmp->data);
-    if (i != -1) {
-      column = gtk_tree_view_get_column (view, i);
-      tmp->data = column;
-    } else {
-      column_names = g_slist_delete_link(column_names, tmp);
-    }
-  }
-    
-  /* Then reorder the columns */
-  prev = NULL;
-  for (tmp = column_names; tmp; tmp = g_slist_next(tmp)) {
-    column = tmp->data;
-    gtk_tree_view_move_column_after (view, column, prev);
-    prev = column;
-  }
-
-  g_slist_free(column_names);
-  LEAVE(" ");
-}
--- /dev/null
+++ src/gnome-utils/gnc-tree-view.c
@@ -0,0 +1,1923 @@
+/* 
+ * gnc-tree-view.c -- new GtkTreeView with extra features used by 
+ *                    all the tree views in gnucash
+ *
+ * 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
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652
+ * Boston, MA  02111-1307,  USA       gnu at gnu.org
+ */
+
+/** @addtogroup GUI
+    @{ */
+/** @addtogroup GncTreeView
+ * @{ */
+/** @file gnc-tree-view.c
+    @brief Base GncTreeView implementation for gnucash trees.
+    @author David Hampton <hampton at employees.org>
+*/
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <libgnome/libgnome.h>
+#include <string.h>
+
+#include "gnc-tree-view.h"
+#include "gnc-engine-util.h"
+#include "gnc-gconf-utils.h"
+#include "gnc-gnome-utils.h"
+
+/* The column id refers to a specific column in the tree model.  It is
+ * also attached to the side of the tree column to allow lookup of a
+ * GtkTreeViewColumn when passed a column id from the underlying
+ * model. By convention, negative column numbers are used when the
+ * visible column has no association with the underlying model.*/
+#define MODEL_COLUMN "model_column"
+
+/* A column with this attribute cannot be hidden from view. */
+#define ALWAYS_VISIBLE  "always-visible"
+
+/* For checkbox columns, this contains the real title for the column. */
+#define REAL_TITLE  "real_title"
+
+/* The name of this column as it should appear in gconf.  This is
+ * attached to the column when it is created, and used to map back and
+ * forth to gconf keys.  The actual gconf keys are built from these
+ * strings. */
+#define PREF_NAME  "pref-name"
+
+/* The actual gconf key for a particular column visibility.  This is
+ * attached to the menu items that are in the column selection menu.
+ * Makes it very easy to update gconf when a menu item is toggled. */
+#define GCONF_KEY  "gconf-key"
+
+/* Gconf keys within this particular section of gconf. */
+#define GCONF_KEY_SORT_COLUMN  "sort_column"
+#define GCONF_KEY_SORT_ORDER   "sort_order"
+#define GCONF_KEY_COLUMN_ORDER "column_order"
+
+/* Partial gconf keys within this particular section of gconf. These
+   are appended to the various column names to create the actual
+   keys. */
+#define GCONF_KEY_VISIBLE      "visible"
+#define GCONF_KEY_WIDTH        "width"
+
+enum {
+  PROP_0,
+  PROP_GCONF_SECTION,
+  PROP_SHOW_COLUMN_MENU,
+};
+
+/** Static Globals *******************************************************/
+
+/* This static indicates the debugging module that this .o belongs to.  */
+static short module = MOD_GUI;
+static GList *active_views = NULL;
+
+/** Declarations *********************************************************/
+static void gnc_tree_view_class_init (GncTreeViewClass *klass);
+static void gnc_tree_view_init (GncTreeView *view);
+static void gnc_tree_view_finalize (GObject *object);
+static void gnc_tree_view_destroy (GtkObject *object);
+static void gnc_tree_view_set_property (GObject         *object,
+					guint            prop_id,
+					const GValue    *value,
+					GParamSpec      *pspec);
+static void gnc_tree_view_get_property (GObject         *object,
+					guint            prop_id,
+					GValue          *value,
+					GParamSpec      *pspec);
+static void gnc_tree_view_remove_gconf(GncTreeView *view);
+static gboolean gnc_tree_view_drop_ok_cb (GtkTreeView *view,
+					  GtkTreeViewColumn *column,
+					  GtkTreeViewColumn *prev_column,
+					  GtkTreeViewColumn *next_column,
+					  gpointer data);
+static void gtk_tree_view_sort_column_changed_cb (GtkTreeSortable *treesortable,
+						  GncTreeView *view);
+static void gnc_tree_view_build_column_menu (GncTreeView *view);
+static void gnc_tree_view_select_column_cb (GtkTreeViewColumn *column,
+					    GncTreeView *view);
+
+/** Private Data Structure ***********************************************/
+
+struct GncTreeViewPrivate
+{
+  GtkTooltips       *title_tips;
+  GSList            *default_visible;
+
+  /* Column selection menu related values */
+  GtkTreeViewColumn *column_menu_column;
+  GtkWidget         *column_menu;
+  gboolean           show_column_menu;
+
+  /* Gconf related values */
+  gchar             *gconf_section;
+  gboolean           seen_gconf_visibility;
+  gulong             columns_changed_cb_id;
+  gulong             sort_column_changed_cb_id;
+  gulong             size_allocate_cb_id;
+};
+
+
+/************************************************************/
+/*               g_object required functions                */
+/************************************************************/
+
+/** @name Gnc Tree View Object Implementation
+ @{ */
+
+static GObjectClass *parent_class = NULL;
+
+/** Create a new glib type for the base gnucash tree view.
+ *
+ *  @internal
+ *
+ *  @return The new type value.
+ */
+GType
+gnc_tree_view_get_type (void)
+{
+	static GType gnc_tree_view_type = 0;
+
+	if (gnc_tree_view_type == 0) {
+		static const GTypeInfo our_info = {
+			sizeof (GncTreeViewClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gnc_tree_view_class_init,
+			NULL,
+			NULL,
+			sizeof (GncTreeView),
+			0,
+			(GInstanceInitFunc) gnc_tree_view_init
+		};
+		
+		gnc_tree_view_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
+							     "GncTreeView",
+							     &our_info, 0);
+	}
+
+	return gnc_tree_view_type;
+}
+
+#if DEBUG_REFERENCE_COUNTING
+static void
+dump_view (GncTreeView *view, gpointer dummy)
+{
+    g_warning("GncTreeView %p still exists.", view);
+}
+
+static gint
+gnc_tree_view_report_references (void)
+{
+  g_list_foreach(active_views, (GFunc)dump_view, NULL);
+  return 0;
+}
+#endif
+
+/** Initialize the class for the new base gnucash tree view.  This
+ *  will set up any function pointers that override functions in the
+ *  parent class, and also installs the proprieties that are unique to
+ *  this class.
+ *
+ *  @param klass The new class structure created by the object system.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_class_init (GncTreeViewClass *klass)
+{
+	GObjectClass *gobject_class;
+	GtkObjectClass *gtkobject_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	gobject_class = G_OBJECT_CLASS (klass);
+	gtkobject_class = GTK_OBJECT_CLASS (klass);
+
+	gobject_class->set_property = gnc_tree_view_set_property;
+	gobject_class->get_property = gnc_tree_view_get_property;
+
+        g_object_class_install_property (gobject_class,
+					 PROP_GCONF_SECTION,
+					 g_param_spec_string ("gconf-section",
+							      "Gconf Section",
+							      "The Gconf section to use for storing settings",
+							      NULL,
+							      G_PARAM_READWRITE));
+        g_object_class_install_property (gobject_class,
+					 PROP_SHOW_COLUMN_MENU,
+					 g_param_spec_boolean ("show-column-menu",
+							       "Show Column Menu",
+							       "Show the column menu so user can change what columns are visible.",
+							       FALSE,
+							       G_PARAM_READWRITE));
+  
+	/* GObject signals */
+	gobject_class->finalize = gnc_tree_view_finalize;
+
+	/* GtkObject signals */
+	gtkobject_class->destroy = gnc_tree_view_destroy;
+
+#if DEBUG_REFERENCE_COUNTING
+	gtk_quit_add (0,
+		      (GtkFunction)gnc_tree_view_report_references,
+		      NULL);
+#endif
+}
+
+/** Initialize a new instance of a base gnucash tree view.  This
+ *  function allocates and initializes the object private storage
+ *  space.  It also adds the new object to a list (for memory tracking
+ *  purposes), and sets up a callback for the column drag function.
+ *
+ *  @param view The new object instance created by the object system.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_init (GncTreeView *view)
+{
+  GtkTreeViewColumn *column;
+  GtkWidget *icon;
+  GtkRequisition requisition;
+
+
+  view->priv = g_new0 (GncTreeViewPrivate, 1);
+
+  view->priv->default_visible = NULL;
+  view->priv->column_menu = NULL;
+  view->priv->show_column_menu = FALSE;
+  view->priv->gconf_section = NULL;
+  view->priv->seen_gconf_visibility = FALSE;
+  view->priv->columns_changed_cb_id = 0;
+  view->priv->sort_column_changed_cb_id = 0;
+  view->priv->size_allocate_cb_id = 0;
+
+  active_views = g_list_append (active_views, view);
+
+  /* Ask gtk to help the user keep track of rows. */
+  g_object_set(view, "rules-hint", TRUE, NULL);
+
+  /* Handle column drag and drop */
+  gtk_tree_view_set_column_drag_function(GTK_TREE_VIEW(view),
+					 gnc_tree_view_drop_ok_cb, NULL, NULL);
+
+  /* Create the next to last column which is always present, visible,
+   * and empty. Override the defaults and make this a one pixel wide
+   * column, but have it take up any extra space in the window. */
+  column = gnc_tree_view_add_text_column (view, NULL, NULL, NULL, NULL,
+					  -1, -1, NULL);
+  gtk_object_set(GTK_OBJECT(column),
+		 "fixed-width", 1,
+		 "expand", TRUE, NULL);
+
+  /* Create the last column which contains the column selection
+   * widget.  gnc_tree_view_add_text_column will do most of the
+   * work. */
+  icon = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN,
+				  GTK_ICON_SIZE_SMALL_TOOLBAR);
+  gtk_widget_show(icon);
+  gtk_widget_size_request(icon, &requisition);
+  column = gnc_tree_view_add_text_column (view, NULL, NULL, NULL, NULL,
+					  -1, -1, NULL);
+  gtk_object_set(GTK_OBJECT(column),
+		 "clickable", TRUE,
+		 "widget", icon,
+		 "fixed-width", requisition.width + 10,
+		 NULL);
+  g_signal_connect(G_OBJECT(column), "clicked",
+		   G_CALLBACK (gnc_tree_view_select_column_cb),
+		   view);
+  view->priv->column_menu_column = column;
+}
+
+/** Finalize the GncTreeView object.  This function is called from the
+ *  G_Object level to complete the destruction of the object.  It
+ *  should release any memory not previously released by the destroy
+ *  function (i.e. the private data structure), then chain up to the
+ *  parent's destroy function.
+ *
+ *  @param object The object being destroyed.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_finalize (GObject *object)
+{
+  GncTreeView *view;
+
+  ENTER("view %p", object);
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GNC_IS_TREE_VIEW (object));
+
+  view = GNC_TREE_VIEW (object);
+  active_views = g_list_remove (active_views, view);
+
+  g_free (view->priv);
+
+  if (G_OBJECT_CLASS (parent_class)->finalize)
+    (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+  LEAVE(" ");
+}
+
+/** Destroy the GncTreeView object.  This function is called (possibly
+ *  multiple times) from the Gtk_Object level to destroy the object.
+ *  It should release any memory owned by the object that isn't
+ *  fundamental to the implementation.  In this function any active
+ *  callbacks are disconnected, all memory other than the private data
+ *  structure are freed.
+ *
+ *  @param object The object being destroyed.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_destroy (GtkObject *object)
+{
+  GncTreeView *view;
+  GSList *slist;
+
+  ENTER("view %p", object);
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GNC_IS_TREE_VIEW (object));
+
+  view = GNC_TREE_VIEW (object);
+
+  gnc_tree_view_remove_gconf(view);
+
+  if (view->priv->default_visible) {
+    slist = view->priv->default_visible;
+    view->priv->default_visible = NULL;
+    g_slist_foreach(slist, (GFunc)g_free, NULL);
+    g_slist_free(slist);
+  }
+
+  if (view->priv->column_menu) {
+    DEBUG("removing column selection menu");
+    gtk_widget_unref(view->priv->column_menu);
+    view->priv->column_menu = NULL;
+  }
+
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+  LEAVE(" ");
+}
+
+/** @} */
+
+/************************************************************/
+/*                g_object other functions                  */
+/************************************************************/
+
+/** @name Gnc Tree View Object Implementation
+ @{ */
+
+/** Retrieve a property specific to this GncTreeView object.  This is
+ *  nothing more than a dispatch function for routines that can be
+ *  called directly.  It has the nice feature of allowing a single
+ *  function call to retrieve multiple properties.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_get_property (GObject     *object,
+			    guint        prop_id,
+			    GValue      *value,
+			    GParamSpec  *pspec)
+{
+  GncTreeView *view = GNC_TREE_VIEW (object);
+  
+  switch (prop_id)
+    {
+    case PROP_GCONF_SECTION:
+      g_value_set_string (value, view->priv->gconf_section);
+      break;
+    case PROP_SHOW_COLUMN_MENU:
+      g_value_set_boolean (value, view->priv->show_column_menu);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+/** Set a property specific to this GncTreeView object.  This is
+ *  nothing more than a dispatch function for routines that can be
+ *  called directly.  It has the nice feature of allowing a new view
+ *  to be created with a varargs list specifying the properties,
+ *  instead of having to explicitly call each property function.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_set_property (GObject      *object,
+			    guint         prop_id,
+			    const GValue *value,
+			    GParamSpec   *pspec)
+{
+  GncTreeView *view = GNC_TREE_VIEW (object);
+  
+  switch (prop_id)
+    {
+    case PROP_GCONF_SECTION:
+      gnc_tree_view_set_gconf_section (view, g_value_get_string (value));
+      break;
+    case PROP_SHOW_COLUMN_MENU:
+      gnc_tree_view_set_show_column_menu (view, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+/** @} */
+
+/************************************************************/
+/*                   Auxiliary Functions                    */
+/************************************************************/
+
+/** @name Gnc Tree View Auxiliary Functions
+ @{ */
+
+/** Find a tree column given a column id number from the underlying
+ *  data model.  This function should only be called by code that has
+ *  visibility into the data model.  The column id numbers shouldn't
+ *  be used for any other purpose.
+ *
+ *  This function simply runs the list of all (visible and invisible)
+ *  columns looking for a match.  Column id numbers were attached to
+ *  each column at the time the column was created.
+ *
+ *  @param view The visible tree widget.
+ *
+ *  @param wanted The column id number to find.
+ *
+ *  @internal
+ */
+static GtkTreeViewColumn *
+view_column_find_by_model_id (GncTreeView *view,
+			      const gint wanted)
+{
+  GtkTreeViewColumn *column, *found = NULL;
+  GList *column_list, *tmp;
+  gint id;
+
+  // ENTER("view %p, name %s", view, name);
+  column_list = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
+  for (tmp = column_list; tmp; tmp = g_list_next(tmp)) {
+    column = tmp->data;
+    id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), MODEL_COLUMN));
+    if (id != wanted)
+      continue;
+    found = column;
+    break;
+  }
+  g_list_free(column_list);
+
+  // LEAVE("column %p", found);
+  return found;
+}
+
+/** Find a tree column given the "pref name" used with gconf.  This
+ *  function simply runs the list of all (visible and invisible)
+ *  columns looking for a match.  Column names were attached to each
+ *  column at the time the column was created.
+ *
+ *  @param view The visible tree widget.
+ *
+ *  @param id The "pref name" to find.
+ *
+ *  @internal
+ */
+static GtkTreeViewColumn *
+view_column_find_by_name (GncTreeView *view,
+			  const gchar *wanted)
+{
+  GtkTreeViewColumn *column, *found = NULL;
+  GList *column_list, *tmp;
+  const gchar *name;
+
+  // ENTER("view %p, wanted %s", view, wanted);
+  column_list = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
+  for (tmp = column_list; tmp; tmp = g_list_next(tmp)) {
+    column = tmp->data;
+    name = g_object_get_data(G_OBJECT(column), PREF_NAME);
+    if (!name || (strcmp(name, wanted) != 0))
+      continue;
+    found = column;
+    break;
+  }
+  g_list_free(column_list);
+
+  // LEAVE("column %p", found);
+  return found;
+}
+
+/** @} */
+
+/************************************************************/
+/*                     Tree Callbacks                       */
+/************************************************************/
+
+/** @name Gnc Tree View Callback Functions
+ @{ */
+
+/** This function is called to determine whether it is acceptable to
+ *  drop a dragged tree column at a given location.  This function
+ *  will be called multiple times by the GtkTreeView code while the
+ *  user is dragging a column.  Each call is a check to see if the
+ *  proposed location is an acceptable place to drop the column.  In
+ *  the case of a GncTreeView, the only drop locations that are
+ *  prohibited are on the right side of the visible tree.
+ *
+ *  @param view The visible tree widget.
+ *
+ *  @param column The column being dragged.
+ *
+ *  @param prev_column The column before (left) of the proposed drop
+ *  location.
+ *
+ *  @param next_column The column after (right) of the proposed drop
+ *  location.
+ *
+ *  @param data Unused.
+ *
+ *  @return TRUE if this drop location is acceptable. FALSE if not
+ *  acceptable.
+ *
+ *  @internal
+ */
+static gboolean
+gnc_tree_view_drop_ok_cb (GtkTreeView *view,
+			  GtkTreeViewColumn *column,
+			  GtkTreeViewColumn *prev_column,
+			  GtkTreeViewColumn *next_column,
+			  gpointer data)
+{
+  const gchar *pref_name;
+
+  /* Should we allow a drop at the left side of the tree view before
+   * the widget to open a new display level?  I can think of cases
+   * where the user might want to do this with a checkbox column. */
+  if (prev_column == NULL)
+    return TRUE;
+
+  /* Do not allow a drop at the right side of the tree view after the
+   * column selection widget.  */
+  if (next_column == NULL)
+    return FALSE;
+
+  /* Columns without pref names are considered fixed at the right hand
+   * side of the view.  At the time of this writing, the only two are
+   * the column where the "column selection widget" is stored, and the
+   * "padding" column to the left of that where extra view space ends
+   * up. */
+  pref_name = g_object_get_data(G_OBJECT(prev_column), PREF_NAME);
+  if (!pref_name)
+    return FALSE;
+
+  /* Everything else is allowed. */
+  return TRUE;
+}
+
+/** This function is called when the sort order has changed on the
+ *  underlying GtkTreeModel.  It propagates these changes to gconf to
+ *  keep it in sync with the user's view of the tree.
+ *
+ *  @param sortable The underlying sortable model.
+ *
+ *  @param view A pointer to the GncTreeView that displays the model
+ *  data.
+ *
+ *  @internal
+ */
+static void
+gtk_tree_view_sort_column_changed_cb (GtkTreeSortable *treesortable,
+				      GncTreeView *view)
+{
+  GtkTreeViewColumn *column;
+  const gchar  	    *gconf_section;
+  gchar        	    *column_pref_name;
+  GtkSortType  	     order;
+  gint         	     id;
+
+  g_return_if_fail(GTK_IS_TREE_SORTABLE(treesortable));
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  ENTER(" ");
+  if (!view->priv->gconf_section) {
+    LEAVE("no gconf section");
+    return;
+  }
+
+  /* Set defaults, then extract data from the model */
+  if (!gtk_tree_sortable_get_sort_column_id(treesortable, &id, &order)) {
+    order = GTK_SORT_ASCENDING;
+    id = 0;
+  }
+  column = view_column_find_by_model_id (view, id);
+  column_pref_name = g_object_get_data(G_OBJECT(column), PREF_NAME);
+
+  /* Store the values in gconf */
+  gconf_section = view->priv->gconf_section;
+  gnc_gconf_set_string(gconf_section, "sort_column", column_pref_name, NULL);
+  gnc_gconf_set_string(gconf_section, "sort_order",
+		       gnc_enum_to_nick(GTK_TYPE_SORT_TYPE, order), NULL);
+  LEAVE(" ");
+}
+
+/** This function is called when the column order has changed in the
+ *  gtk tree view.  It propagates these changes to gconf to keep it in
+ *  sync with the user's view of the tree.  This function runs the
+ *  list of all tree column data structures, building a second list of
+ *  column names.  This second list is passed to gconf for storing.
+ *  Only columns that have names can be saved in this fashion.
+ *
+ *  @param view The tree view.
+ *
+ *  @param data Unused.
+ *
+ *  @internal
+ */
+static void
+gtk_tree_view_columns_changed_cb (GncTreeView *view,
+				  gpointer data)
+{
+  GList *column_list, *tmp;
+  GSList *column_names = NULL;
+  gchar *name;
+
+  //ENTER("view %p, data %p", view, data);
+  column_list = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
+  for (tmp = column_list; tmp; tmp = g_list_next(tmp)) {
+    name = g_object_get_data(tmp->data, PREF_NAME);
+    if (!name)
+      continue;
+    column_names = g_slist_append(column_names, name);
+    //DEBUG("%s", name);
+  }
+  g_list_free(column_list);
+
+  gnc_gconf_set_list(view->priv->gconf_section, GCONF_KEY_COLUMN_ORDER,
+		     GCONF_VALUE_STRING, column_names, NULL);
+  g_slist_free(column_names);
+  //LEAVE(" ");
+}
+
+/** This is the helper function for gtk_tree_view_size_allocate_cb().
+ *  It compares the actual column width to the width as stored in
+ *  gconf.  If the two are different, it the updates gconf with the
+ *  actual width.  This will trigger a notification from gconf that
+ *  the size has changes, and that code must be smart enough to
+ *  prevent an infinite loop.  Not storing unchanged values prevents
+ *  spurious callbacks from gconf and just saves processing time.
+ *
+ *  @param column The column whose size should be updated in gconf..
+ *
+ *  @param view The tree view.
+ *
+ *  @internal
+ */
+static void
+gtk_tree_view_size_allocate_helper (GtkTreeViewColumn *column,
+				    GncTreeView *view)
+{
+  const gchar *column_pref_name;
+  gint new_width, current_width;
+  gchar *key;
+
+  g_return_if_fail(GTK_IS_TREE_VIEW_COLUMN(column));
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  /* Any updates to be made? */
+  column_pref_name = g_object_get_data(G_OBJECT(column), PREF_NAME);
+  if (!column_pref_name)
+    return;
+  new_width = gtk_tree_view_column_get_width (column);
+  if (!new_width)
+    return;
+
+  /* Do it */
+  key = g_strdup_printf("%s_%s", column_pref_name, GCONF_KEY_WIDTH);
+  current_width = gnc_gconf_get_int(view->priv->gconf_section, key, NULL);
+  if (new_width != current_width) {
+    gnc_gconf_set_int(view->priv->gconf_section, key, new_width, NULL);
+    DEBUG("set %s width to %d", column_pref_name, new_width);
+  }
+  g_free(key);
+}
+
+/** This function is called when the tree size has been reallocated.
+ *  When called, one of two events has occurred.  1) The column sizes
+ *  within the tree have changed.  2) The window containing the tree
+ *  has been resized.  This code is concerned with case one.  Case two
+ *  is a don't care, unless the window resizing has caused a column
+ *  resizing.
+ *
+ *  This function simply runs the list of all tree columns, calling the
+ *  gtk_tree_view_size_allocate_helper() function on each column.
+ *  There is no callback that can be used for notification of an
+ *  individual column change.  Its this or nothing.
+ *
+ *  @param widget The tree view.
+ *
+ *  @param allocation Unused.
+ *
+ *  @param data Unused.
+ *
+ *  @internal
+ */
+static void
+gtk_tree_view_size_allocate_cb (GtkWidget *widget,
+				GtkAllocation *allocation,
+				gpointer data)
+{
+  GncTreeView *view;
+  GList *column_list;
+
+  g_return_if_fail(GNC_IS_TREE_VIEW(widget));
+
+  view = GNC_TREE_VIEW(widget);
+  column_list = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
+  g_list_foreach(column_list, (GFunc)gtk_tree_view_size_allocate_helper, view);
+  g_list_free(column_list);
+}
+
+/** @} */
+
+/************************************************************/
+/*                  Gconf Setup / Callbacks                 */
+/************************************************************/
+
+/** @name Gnc Tree View Gconf Callback / Related Functions
+ @{ */
+
+/** Determine the visibility of a column.  This function first looks
+ *  for columns specially marked to be always visible, or columns
+ *  without a preference name.  These are always show.  Next this
+ *  function checks to see if gconf is responsible for this view *and*
+ *  that gconf visibility keys have been seen.  (This handles the
+ *  'first run' case where gconf should manage a view but no keys yet
+ *  exist in gconf.)  If so, the gconf visibility key is returned.
+ *  Otherwise the "'default visible column' list is checked and a
+ *  value of TRUE returned if the pref name is found.
+ *
+ *  @param view A GncTreeView.
+ *
+ *  @param column The GtkTreeViewColumn in question.  Either this
+ *  value or the pref_name parameter must be non-NULL.
+ *
+ *  @param pref_name The name of the column in question.  Either this
+ *  value or the column parameter must be non-NULL.
+ *
+ *  @returns TRUE if the column should be visible.  FALSE otherwise.
+ *
+ *  @internal
+ */
+static gboolean
+gnc_tree_view_column_visible (GncTreeView *view,
+			      GtkTreeViewColumn *column,
+			      const gchar *pref_name)
+{
+  gboolean visible;
+  gchar *key;
+
+  ENTER("column %p, name %s", column, pref_name);
+  if (column) {
+    if (g_object_get_data(G_OBJECT(column), ALWAYS_VISIBLE)) {
+      LEAVE("1, first column");
+      return TRUE;
+    }
+    pref_name = (gchar *)g_object_get_data(G_OBJECT(column), PREF_NAME);
+    DEBUG("pref_name is %s", pref_name);
+  }
+
+  if (!pref_name) {
+    LEAVE("1, no pref name");
+    return TRUE;
+  }
+  
+  /* Using gconf? */
+  if (view->priv->gconf_section) {
+    if (view->priv->seen_gconf_visibility) {
+      key = g_strdup_printf("%s_%s", pref_name, GCONF_KEY_VISIBLE);
+      visible = gnc_gconf_get_bool(view->priv->gconf_section, key, NULL);
+      g_free(key);
+      LEAVE("%d, gconf visibility", visible);
+      return visible;
+    }
+
+    visible =  (g_slist_find_custom(view->priv->default_visible, pref_name,
+				    (GCompareFunc)strcmp) != NULL);
+    LEAVE("%d, gconf but using defaults", visible);
+    return visible;
+  }
+
+  /* Check the default columns list */
+  visible = (g_slist_find_custom(view->priv->default_visible, pref_name,
+				 (GCompareFunc)strcmp) != NULL);
+  LEAVE("defaults says %d", visible);
+  return visible;
+}
+
+/** This function updates the visibility of a single column.  It
+ *  checks if the column should be visible, and if so tells the view
+ *  to show the column and (f needed) updates the gconf database.
+ *
+ *  @param column The column whose visibility should be updated.
+ *
+ *  @param view The GncTreeView containing the column.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_update_visibility (GtkTreeViewColumn *column,
+				 GncTreeView *view)
+{
+  gchar *name, *key;
+  gboolean visible;
+
+  g_return_if_fail(GTK_IS_TREE_VIEW_COLUMN(column));
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  ENTER(" ");
+  visible = gnc_tree_view_column_visible(view, column, NULL);
+  gtk_tree_view_column_set_visible(column, visible);
+  if (view->priv->gconf_section) {
+    name = (gchar *)g_object_get_data(G_OBJECT(column), PREF_NAME);
+    if (!name) {
+      LEAVE("no pref name");
+      return;
+    }
+    key = g_strdup_printf("%s_%s", name, GCONF_KEY_VISIBLE);
+    gnc_gconf_set_bool(view->priv->gconf_section, key, visible, NULL);
+    g_free(key);
+    LEAVE("made visible, set gconf key");
+    return;
+  }
+  LEAVE("made visible");
+}
+
+/** This function is called via the gconf notification callback when
+ *  the sort order has changed in gconf.  It must update the model
+ *  sort order to match what is specified in gconf.  The sort column
+ *  used will be whatever is the current sort column.  This function
+ *  is careful to prevent an infinite loop by blocking the
+ *  "sort-column-changed" callback that is attached to the model.
+ *
+ *  @param widget The tree view.
+ *
+ *  @param name The sort order enum (in string form). Either
+ *  "ascending" or "descending".
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_set_sort_order (GncTreeView *view,
+			      const gchar *name)
+{
+  GtkTreeModel *s_model;
+  GtkSortType order;
+  gint current;
+
+  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+  if (!s_model)
+    return;
+  order = gnc_enum_from_nick(GTK_TYPE_SORT_TYPE, name, GTK_SORT_ASCENDING);
+  if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model),
+					    &current, &order))
+    current = 0;
+  g_signal_handler_block(s_model, view->priv->sort_column_changed_cb_id);
+  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model),
+				       current, order);
+  g_signal_handler_unblock(s_model, view->priv->sort_column_changed_cb_id);
+  DEBUG("sort_order set to %s", gnc_enum_to_nick(GTK_TYPE_SORT_TYPE, order));
+}
+
+/** This function is called via the gconf notification callback when
+ *  the sort column has changed in gconf.  It must update the model
+ *  sort column to match what is specified in gconf.  The sort order
+ *  used for this column will be whatever sort order is in use on the
+ *  current sort column.  This function is careful to prevent an
+ *  infinite loop by blocking the "sort-column-changed" callback that
+ *  is attached to the model.
+ *
+ *  @param widget The tree view.
+ *
+ *  @param name The name of the column that should be made the sort column.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_set_sort_column (GncTreeView *view,
+			       const gchar *name)
+{
+  GtkTreeModel *s_model;
+  GtkTreeViewColumn *column;
+  GtkSortType order;
+  gint model_column, current;
+
+  column = view_column_find_by_name(view, name);
+  if (!column)
+    return;
+
+  model_column =
+    GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), MODEL_COLUMN));
+  if (model_column == GNC_TREE_VIEW_COLUMN_DATA_NONE)
+    return;
+
+  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+  if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model),
+					    &current, &order))
+    order = GTK_SORT_ASCENDING;
+  g_signal_handler_block(s_model, view->priv->sort_column_changed_cb_id);
+  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model),
+				       model_column, order);
+  g_signal_handler_unblock(s_model, view->priv->sort_column_changed_cb_id);
+  DEBUG("sort column set to %s", name);
+}
+
+/** This function is called via the gconf notification callback when
+ *  the column order has changed in gconf.  It must update the order
+ *  of the columns in the model to match what is specified in gconf.
+ *  This function is careful to prevent an infinite loop by blocking
+ *  the "columns-changed" callback that is attached to the view.
+ *
+ *  @param widget The tree view.
+ *
+ *  @param name A list of pointers to strings.  These strings are the
+ *  names of the columns in the order they should appear.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_set_column_order (GncTreeView *view,
+				const GSList *column_names)
+{
+  GtkTreeViewColumn *column, *prev;
+  const gchar *name;
+  const GSList *tmp;
+  GSList *columns;
+
+  /* First, convert from names to pointers */
+  ENTER(" ");
+  columns = NULL;
+  for (tmp = column_names; tmp; tmp = g_slist_next(tmp)) {
+    name = gconf_value_get_string(tmp->data);
+    column = view_column_find_by_name(view, name);
+    if (!column)
+      continue;
+    columns = g_slist_append(columns, column);
+  }
+    
+  /* Then reorder the columns */
+  g_signal_handler_block(view, view->priv->columns_changed_cb_id);
+  for (prev = NULL, tmp = columns; tmp; tmp = g_slist_next(tmp)) {
+    column = tmp->data;
+    gtk_tree_view_move_column_after(GTK_TREE_VIEW(view), column, prev);
+    prev = column;
+  }
+  g_signal_handler_unblock(view, view->priv->columns_changed_cb_id);
+
+  /* Clean up */
+  g_slist_free(columns);
+  LEAVE("column order set");
+}
+
+/** This function is called via the gconf notification callback when
+ *  any change has occurred.  It must update the appropriate aspect of
+ *  the model/view to match what is specified in gconf.  Some of the
+ *  updates are handled in this function, while others are handled by
+ *  other helper functions.
+ *
+ *  @param client A pointer to the gconf client object from which
+ *  detected a change in gconf.  Unused by this function.
+ *
+ *  @cnxn_id The identifier for the notification that this callback
+ *  represents.  Unused since this code only has a single notification
+ *  request.
+ *
+ *  @entry A pointer to the key/value pair in gconf that changed.
+ *
+ *  @param data The tree view.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_gconf_changed (GConfClient *client,
+			     guint cnxn_id,
+			     GConfEntry *entry,
+			     gpointer data)
+{
+  GncTreeView *view;
+  GtkTreeViewColumn *column;
+  GConfValue *value;
+  const gchar *key, *local;
+  gchar *column_name, *type_name;
+  gboolean known;
+  gint width;
+
+  g_return_if_fail(GNC_IS_TREE_VIEW(data));
+
+  ENTER(" ");
+  view = GNC_TREE_VIEW(data);
+  key = gconf_entry_get_key(entry);
+  value = gconf_entry_get_value(entry);
+  if (!value) {
+    /* Values can be unset */
+    LEAVE("Unset valued for %s", key);
+    return;
+  }
+
+  DEBUG("Key %s, value %p", key, value);
+  local = rindex(key, '/')+1;
+  if (strcmp(local, GCONF_KEY_SORT_COLUMN) == 0) {
+    gnc_tree_view_set_sort_column(view, gconf_value_get_string(value));
+  } else if (strcmp(local, GCONF_KEY_SORT_ORDER) == 0) {
+    gnc_tree_view_set_sort_order(view, gconf_value_get_string(value));
+  } else if (strcmp(local, GCONF_KEY_COLUMN_ORDER) == 0) {
+    gnc_tree_view_set_column_order(view, gconf_value_get_list(value));
+  } else {
+    /* Make a copy of the local part of the key so it can be split
+     * into column name and key type */
+    known = FALSE;
+    column_name = strdup(local);
+    type_name = rindex(column_name, '_');
+    *type_name++ = '\0';
+
+    if (strcmp(type_name, GCONF_KEY_VISIBLE) == 0) {
+      view->priv->seen_gconf_visibility = TRUE;
+      column = view_column_find_by_name(view, column_name);
+      if (column) {
+	known = TRUE;
+	if (!g_object_get_data(G_OBJECT(column), ALWAYS_VISIBLE)) {
+	  gtk_tree_view_column_set_visible(column, gconf_value_get_bool(value));
+	}
+      }
+    } else if (strcmp(type_name, GCONF_KEY_WIDTH) == 0) {
+      width = gconf_value_get_int(value);
+      column = view_column_find_by_name(view, column_name);
+      if (column) {
+	known = TRUE;
+	if (width && (width != gtk_tree_view_column_get_width(column))) {
+	  gtk_tree_view_column_set_fixed_width(column, width);
+	}
+      }
+    }
+    if (!known) {
+      DEBUG("Ignored key %s", key);
+    }
+    g_free(column_name);
+  }
+  LEAVE(" ");
+}
+
+/** This function is called force synchronization between the gconf
+ *  database and a tree view.  It will be called for major events like
+ *  assigning a gconf section to a tree view.  All values in gconf
+ *  will be propagated into the view.  This function simply requests a
+ *  list of all key in the section from gconf, then feeds them one at
+ *  a time to gnc_tree_view_gconf_changed().
+ *
+ *  @param view The tree view.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_gconf_force_update (GncTreeView *view)
+{
+  GSList *all_entries, *etmp;
+  GList *columns;
+
+  ENTER("view %p", view);
+  all_entries = gnc_gconf_client_all_entries(G_OBJECT(view),
+					     view->priv->gconf_section);
+
+  /* Set a flag indicating that the gconf data section may be empty.
+   * It will be checked later on and appropriate action taken if its
+   * still set. */
+  view->priv->seen_gconf_visibility = FALSE;
+
+  /* Pull all the entries from gconf */
+  for (etmp = all_entries; etmp; etmp = g_slist_next(etmp)) {
+    gnc_tree_view_gconf_changed(NULL, 0, etmp->data, view);
+    gconf_entry_free(etmp->data);
+  }
+  g_slist_free(all_entries);
+
+  /* No visibilities seen yet.  Write out any columns we may have */
+  if (!view->priv->seen_gconf_visibility) {
+    columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
+    g_list_foreach(columns, (GFunc)gnc_tree_view_update_visibility, view);
+    g_list_free(columns);
+  }
+  
+  LEAVE(" ");
+}
+
+/** This internal function is called to disconnect a tree view from a
+ *  gconf section.  It first disconnects any signals that are in
+ *  effect on the model/view, then removes the gconf notification
+ *  callback, then clears the gconf section string.  This function may
+ *  be called at any time; either when the user wants to disconnect or
+ *  when the view object is being destroyed.
+ *
+ *  @param view The tree view.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_remove_gconf(GncTreeView *view)
+{
+  GtkTreeModel *model;
+
+  ENTER(" ");
+  if (!view->priv->gconf_section) {
+    LEAVE("no gconf section");
+    return;
+  }
+
+  if (view->priv->sort_column_changed_cb_id) {
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
+    if (model) {
+      DEBUG("removing sort_column_changed callback (# %ld)",
+	    view->priv->sort_column_changed_cb_id);
+      g_signal_handler_disconnect(GTK_TREE_SORTABLE(model),
+				  view->priv->sort_column_changed_cb_id);
+      view->priv->sort_column_changed_cb_id = 0;
+    }
+  }
+
+  if (view->priv->columns_changed_cb_id) {
+    DEBUG("removing columns_changed callback (# %ld)",
+	  view->priv->columns_changed_cb_id);
+    g_signal_handler_disconnect(view, view->priv->columns_changed_cb_id);
+    view->priv->columns_changed_cb_id = 0;
+  }
+
+  if (view->priv->size_allocate_cb_id) {
+    DEBUG("removing size_allocate callback (# %ld)",
+	  view->priv->size_allocate_cb_id);
+    g_signal_handler_disconnect(view, view->priv->size_allocate_cb_id);
+    view->priv->size_allocate_cb_id = 0;
+  }
+
+  DEBUG("removing gconf notification");
+  gnc_gconf_remove_notification(G_OBJECT(view), view->priv->gconf_section);
+  g_free(view->priv->gconf_section);
+  view->priv->gconf_section = NULL;
+  LEAVE(" ");
+}
+
+/** This function is called to set up or remove an association between
+ *  a gconf section and the display of a view.  It will first remove
+ *  any existing association, and then install the new one.  This
+ *  involves storing the gconf section value, requesting notification
+ *  from gconf of any changes to keys in that section, then attaching
+ *  several signals to catch user changes to the view.
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+void
+gnc_tree_view_set_gconf_section (GncTreeView *view,
+				 const gchar *section)
+{
+  GtkTreeModel *model;
+  gulong id;
+
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  ENTER("view %p, section %s", view, section);
+  gnc_tree_view_remove_gconf(view);
+
+  if (!section) {
+    LEAVE("cleared gconf section");
+    return;
+  }
+
+  /* Catch changes in gconf. Propagate to view. */
+  view->priv->gconf_section = g_strdup(section);
+  gnc_gconf_add_notification(G_OBJECT(view), section,
+			     gnc_tree_view_gconf_changed);
+
+  /* Catch changes to the sort column. Propagate to gconf. The key can
+   * be set before the model, so the code must handle that case. */
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
+  if (model)
+    view->priv->sort_column_changed_cb_id =
+      g_signal_connect(GTK_TREE_SORTABLE(model), "sort-column-changed",
+		       (GCallback)gtk_tree_view_sort_column_changed_cb, view);
+
+  /* Catch changes to the column order. Propagate to gconf */
+  id = g_signal_connect(view, "columns-changed",
+			(GCallback)gtk_tree_view_columns_changed_cb, NULL);
+  view->priv->columns_changed_cb_id = id;
+
+  /* Catch changes to the column width. Propagate to gconf */
+  id = g_signal_connect(view, "size-allocate",
+			(GCallback)gtk_tree_view_size_allocate_cb, NULL);
+  view->priv->size_allocate_cb_id = id;
+
+  /* Force an update of the view with all items from gconf. */
+  gnc_tree_view_gconf_force_update(view);
+
+  /* Rebuild the column visibility menu */
+  gnc_tree_view_build_column_menu(view);
+  LEAVE("set gconf section");
+}
+
+/** This function is called to get the current association between a
+ *  gconf section and the display of a view.  It returns the same
+ *  value passed to gnc_tree_view_set_gconf_section(); i.e. a string
+ *  like "dialogs/edit_prices".
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+const gchar *
+gnc_tree_view_get_gconf_section (GncTreeView *view)
+{
+  g_return_val_if_fail(GNC_IS_TREE_VIEW(view), NULL);
+
+  return(view->priv->gconf_section);
+}
+
+
+/** @} */
+
+/************************************************************/
+/*                   Column Selection Menu                  */
+/************************************************************/
+
+/** @name Gnc Tree View Column Selection Menu Related Functions
+ @{ */
+
+/** This function is called when an entry in the column selection menu
+ *  is toggled.  It must update gconf with the current value of the
+ *  checkbox.  This will trigger a callback to other functions which
+ *  will then change the actual state of the view.
+ *
+ *  @param checkmenuitem A checkbox visible in the menu.
+ *
+ *  @param view The tree view.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
+				 GncTreeView *view)
+{
+  gboolean value;
+  gchar *key;
+
+  g_return_if_fail(GTK_IS_CHECK_MENU_ITEM(checkmenuitem));
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  ENTER("checkmenuitem %p, view %p", checkmenuitem, view);
+  if (!view->priv->gconf_section) {
+    LEAVE("no gconf section");
+    return;
+  }
+
+  key = g_object_get_data(G_OBJECT(checkmenuitem), GCONF_KEY);
+  value = gtk_check_menu_item_get_active(checkmenuitem);
+  gnc_gconf_set_bool(view->priv->gconf_section, key, value, NULL);
+  LEAVE("set gconf section %s, key %s, visible %d",
+	view->priv->gconf_section, key, value);
+}
+
+/** This function is called to create a single checkmenuitem in the
+ *  column selection menu.  It is called once for each column in the
+ *  view.  It creates a menu item for the corresponding column, and
+ *  attaches to it a copy of the gconf key for this column's
+ *  visibility.  This makes the toggle callback function trivial.
+ *
+ *  This function will create the column selection menu if one doesn't
+ *  already exist.
+ *
+ *  @param column Create a menu item for this column.
+ *
+ *  @param view The tree view.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_create_menu_item (GtkTreeViewColumn *column,
+				GncTreeView *view)
+{
+  GncTreeViewPrivate *priv;
+  GtkWidget *widget;
+  const gchar *column_name, *pref_name;
+  gulong id;
+  gchar *key;
+
+  // ENTER("view %p, column %p", view, column);
+  priv = view->priv;
+  if (!priv->gconf_section) {
+    // LEAVE("no gconf section");
+    return;
+  }
+
+  pref_name = g_object_get_data(G_OBJECT(column), PREF_NAME);
+  if (!pref_name) {
+    // LEAVE("column has no pref_name");
+    return;
+  }
+
+  /* Create the menu if we don't have one already */
+  if (!priv->column_menu) {
+    priv->column_menu = gtk_menu_new();
+    g_object_ref(priv->column_menu);
+    gtk_object_sink(GTK_OBJECT(priv->column_menu));
+  }
+
+  /* Create the check menu item */
+  column_name = g_object_get_data(G_OBJECT(column), REAL_TITLE);
+  if (!column_name)
+    column_name = gtk_tree_view_column_get_title(column);
+  widget = gtk_check_menu_item_new_with_label(column_name);
+  gtk_menu_shell_append(GTK_MENU_SHELL(priv->column_menu), widget);
+
+  /* Should never be able to hide the first column */
+  if (g_object_get_data(G_OBJECT(column), ALWAYS_VISIBLE)) {
+    g_object_set_data(G_OBJECT(widget), ALWAYS_VISIBLE, GINT_TO_POINTER(1));
+    gtk_widget_set_sensitive(widget, FALSE);
+  }
+
+  /* Set up the callback  */
+  id = g_signal_connect(widget, "toggled",
+			(GCallback)gnc_tree_view_menu_item_toggled, view);
+
+  /* Store data on the widget for callbacks */
+  key = g_strdup_printf("%s_%s", pref_name, GCONF_KEY_VISIBLE);
+  g_object_set_data_full(G_OBJECT(widget), GCONF_KEY, key, g_free);
+  // LEAVE(" ");
+}
+
+/** This function is called to build the column selection menu.  It
+ *  first destroys any old column selection menu, then checks to see
+ *  if a new menu should be built.  If so, it calls the
+ *  gnc_tree_view_create_menu_item() for each column in the view.
+ *  This function is invoked then either the "gconf-section" or the
+ *  "show-column-menu" property is changed on the view.
+ *
+ *  @param view Build a selection menu for this tree view.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_build_column_menu (GncTreeView *view)
+{
+  GncTreeViewPrivate *priv;
+  GList *column_list;
+
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  ENTER("view %p", view);
+  priv = GNC_TREE_VIEW(view)->priv;
+
+  /* Destroy any old menu */
+  if (priv->column_menu) {
+    gtk_widget_unref(priv->column_menu);
+    priv->column_menu = NULL;
+  }
+
+  if (priv->show_column_menu && priv->gconf_section) {
+    /* Show the menu popup button */
+    if (view->priv->column_menu_column)
+      g_object_set(G_OBJECT(view->priv->column_menu_column),
+		   "visible", TRUE, NULL);
+
+    /* Now build a new menu */
+    column_list = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
+    g_list_foreach(column_list, (GFunc)gnc_tree_view_create_menu_item, view);
+    g_list_free(column_list);
+  } else {
+    /* Hide the menu popup button */
+    if (view->priv->column_menu_column)
+      g_object_set(G_OBJECT(view->priv->column_menu_column),
+		   "visible", FALSE, NULL);
+  }
+  LEAVE("menu: show %d, section %s", priv->show_column_menu,
+	priv->gconf_section);
+}
+
+/** This function is called to synchronize the checkbox on a menu item
+ *  with the current gconf visibility value for the corresponding
+ *  column (which will be the visibility of the column if the rest of
+ *  the code in this file is working correctly).  It simply takes the
+ *  gconf key attached to the menu item, reads it, and sets the menu
+ *  item to the retrieved value.  It does take care to block signals
+ *  from the menu item to prevent updating gconf (since the value was
+ *  just read from gconf).
+ *
+ *  @param checkmenuitem The menu item to update.
+ *
+ *  @param view The tree view.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_update_column_menu_item (GtkCheckMenuItem *checkmenuitem,
+				       GncTreeView *view)
+{
+  gchar *key;
+  gboolean visible;
+
+  g_return_if_fail(GTK_IS_CHECK_MENU_ITEM(checkmenuitem));
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  key = g_object_get_data(G_OBJECT(checkmenuitem), GCONF_KEY);
+  if (g_object_get_data(G_OBJECT(checkmenuitem), ALWAYS_VISIBLE)) {
+    visible = TRUE;
+  } else {
+    visible = gnc_gconf_get_bool(view->priv->gconf_section, key, NULL);
+  }
+
+  g_signal_handlers_block_by_func(checkmenuitem,
+				  gnc_tree_view_menu_item_toggled, view);
+  gtk_check_menu_item_set_active(checkmenuitem, visible);
+  g_signal_handlers_unblock_by_func(checkmenuitem,
+				    gnc_tree_view_menu_item_toggled, view);
+}
+
+/** This function when the user clicks on the button to show the
+ *  column selection menu.  It first synchronize the checkboxes on all
+ *  menu item with the gconf visibility values.  It then pops up the
+ *  menu for the user to choose from.
+ *
+ *  @param column The tree column containing the column selection
+ *  button.
+ *
+ *  @param view The tree view.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_select_column_cb (GtkTreeViewColumn *column,
+				GncTreeView *view)
+{
+  GtkWidget *widget, *menu;
+
+  g_return_if_fail(GTK_IS_TREE_VIEW_COLUMN(column));
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  menu = view->priv->column_menu;
+  if (!menu)
+    return;
+
+  /* Synchronize the menu before display */
+  gtk_container_foreach(GTK_CONTAINER(menu),
+			(GtkCallback)gnc_tree_view_update_column_menu_item,
+			view);
+
+  /* Ensure all components are visible */
+  gtk_widget_show_all(menu);
+
+  /* Pop the menu up at the button */
+  widget = gtk_tree_view_column_get_widget(column);
+  gtk_menu_popup(GTK_MENU(view->priv->column_menu), NULL, GTK_WIDGET(menu),
+		 NULL, NULL, 0, gtk_get_current_event_time());
+}
+
+/** This function is called to set the "show-column-menu" property on
+ *  this view.  This function has no visible effect if the
+ *  "gconf-section" property has not been set.
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+void
+gnc_tree_view_set_show_column_menu (GncTreeView *view,
+				    gboolean visible)
+{
+  GncTreeViewPrivate *priv;
+
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  ENTER("view %p, show menu %d", view, visible);
+  priv = GNC_TREE_VIEW(view)->priv;
+  priv->show_column_menu = visible;
+  gnc_tree_view_build_column_menu(view);
+  LEAVE(" ");
+}
+
+/** This function is called to get the current value of the
+ *  "show-column-menu" property.  It returns the same value passed to
+ *  gnc_tree_view_set_show_menu_column().
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+gboolean
+gnc_tree_view_get_show_column_menu (GncTreeView *view)
+{
+  g_return_val_if_fail(GNC_IS_TREE_VIEW(view), FALSE);
+
+  return(view->priv->show_column_menu);
+}
+
+/** @} */
+
+/************************************************************/
+/*                    Tree View Creation                    */
+/************************************************************/
+
+/** Attach a data model to a visible GncTreeView widget.  Users of
+ *  this view object must use this function instead of directly
+ *  calling the gtk_tree_view_set_model function.  This function takes
+ *  the additional step of attaching a callback function to the model
+ *  to catch any changes to the sorting of the model.  These changes
+ *  are propagated into gconf by the callback function.
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+void
+gnc_tree_view_set_model(GncTreeView *view, GtkTreeModel *model)
+{
+  GtkTreeModel *old_model;
+
+  /* Remove existing callback */
+  if (view->priv->sort_column_changed_cb_id) {
+    old_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
+    g_signal_handler_disconnect (old_model,
+				 view->priv->sort_column_changed_cb_id);
+    view->priv->sort_column_changed_cb_id = 0;
+  }
+
+  gtk_tree_view_set_model (GTK_TREE_VIEW(view), model);
+
+  /* Maybe add a new callback */
+  if (model && view->priv->gconf_section) {
+    view->priv->sort_column_changed_cb_id =
+      g_signal_connect(GTK_TREE_SORTABLE(model), "sort-column-changed",
+		       (GCallback)gtk_tree_view_sort_column_changed_cb, view);
+  }
+}
+
+/** Configure (by name) the default set of visible columns in an gnc
+ *  tree view.  This is the list of columns that will be shown if the
+ *  view isn't using gconf to manage column visibility.  If gconf is
+ *  used, this list will be used the very first time the view is
+ *  presented to the user, then gconf will be used after that.  The
+ *  available list of columns can be found in the file
+ *  gnc-tree-view-xxx.c.
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+void
+gnc_tree_view_configure_columns (GncTreeView *view,
+				 gchar *first_column_name,
+				 ...)
+{
+  GSList *slist;
+  GList *columns;
+  gchar *name;
+  va_list args;
+
+  g_return_if_fail(GNC_IS_TREE_VIEW(view));
+
+  ENTER(" ");
+  /* Delete any old list of column names */
+  if (view->priv->default_visible) {
+    slist = view->priv->default_visible;
+    view->priv->default_visible = NULL;
+    g_slist_foreach(slist, (GFunc)g_free, NULL);
+    g_slist_free(slist);
+  }
+
+  /* Build a new list */
+  va_start (args, first_column_name);
+  name = first_column_name;
+  while (name != NULL) {
+    view->priv->default_visible =
+      g_slist_append(view->priv->default_visible, g_strdup(name));
+    name = va_arg(args, gchar*);
+  }
+  va_end (args);
+
+  /* Update the view and gconf */
+  columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
+  g_list_foreach(columns, (GFunc)gnc_tree_view_update_visibility, view);
+  g_list_free(columns);
+
+  if (view->priv->gconf_section)
+    view->priv->seen_gconf_visibility = TRUE;
+  LEAVE(" ");
+}
+
+
+/** This internal function sets a variety of common properties on a
+ *  newly created GtkTreeViewColumn and its renderer.
+ *
+ *  @param view A pointer to a generic GncTreeView.
+ *
+ *  @param column The newly created tree view column.
+ *
+ *  @param pref_name The internal name of this column.  This name is
+ *  used in several functions to look up the column, and it is also
+ *  used to create the keys used to record the column width and
+ *  visibility in gconf.
+ *
+ *  @param data_column The index of the GtkTreeModel data column used
+ *  to determine the data that will be displayed in this column for
+ *  each row in the view.  Use GNC_TREE_VIEW_COLUMN_DATA_NONE if you
+ *  plan on using an non-model data source for this column.
+ *
+ *  @param default_width The width this column should be if not
+ *  specified by gconf.  If the this value is zero, the column will
+ *  be marked as automatically sized.
+ *
+ *  @param resizable Whether to mark the column as user resizable.
+ *  This marking is only relevant for fixed width columns.
+ *
+ *  @param column_sort_function The function that GtkTreeModelSort
+ *  will call to compare two rows to determine their displayed order.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_column_properties (GncTreeView *view,
+				 GtkTreeViewColumn *column,
+				 const gchar *pref_name,
+				 gint data_column,
+				 gint default_width,
+				 gboolean resizable,
+				 GtkTreeIterCompareFunc column_sort_fn)
+{
+  GtkTreeModel *s_model;
+  gboolean visible;
+  int width = 0;
+  gchar *key;
+
+  /* Set data used by other functions */
+  if (pref_name)
+    g_object_set_data(G_OBJECT(column), PREF_NAME, (gpointer)pref_name);
+  if (data_column == 0)
+    g_object_set_data(G_OBJECT(column), ALWAYS_VISIBLE, GINT_TO_POINTER(1));
+  if (data_column != GNC_TREE_VIEW_COLUMN_DATA_NONE)
+    g_object_set_data(G_OBJECT(column), MODEL_COLUMN,
+		      GINT_TO_POINTER(data_column));
+
+  /* Get visibility */
+  visible = gnc_tree_view_column_visible(view, NULL, pref_name);
+
+  /* Get width */
+  if (view->priv->gconf_section) {
+    key = g_strdup_printf("%s_%s", pref_name, GCONF_KEY_WIDTH);
+    width = gnc_gconf_get_int(view->priv->gconf_section, key, NULL);
+    g_free(key);
+  }
+
+  /* If gconf comes back with a width of zero (or there is no gconf
+   * width) the use the default width for the column.  Allow for
+   * padding L and R of the displayed data. */
+  if (width == 0)
+    width = default_width + 10;
+  if (width == 0)
+    width = 10;
+
+  /* Set column attributes */
+  g_object_set(G_OBJECT(column),
+	       "visible",     visible,
+	       "sizing",      GTK_TREE_VIEW_COLUMN_FIXED,
+	       "fixed-width", width,
+	       "resizable",   resizable && pref_name != NULL,
+	       "reorderable", pref_name != NULL,
+	       NULL);
+
+  s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+  if (GTK_IS_TREE_MODEL_SORT(s_model)) {
+    gtk_tree_view_column_set_sort_column_id (column, data_column);
+    if (column_sort_fn) {
+      gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(s_model),
+				       data_column, column_sort_fn,
+				       NULL /* user_data */,
+				       NULL /* destroy fn */);
+    }
+  }
+
+  /* Add to the column selection menu */
+  if (pref_name) {
+    gnc_tree_view_create_menu_item(column, view);
+  }
+}
+
+/** This function adds a new toggle column to a GncTreeView base view.
+ *  It takes all the parameters necessary to hook a GtkTreeModel
+ *  column to a GtkTreeViewColumn.  It handles creating a tooltip to
+ *  show the full title name, and setting the sort and edit callback
+ *  functions.  If the tree has a gconf section associated with it,
+ *  this function also wires up the column so that its visibility and
+ *  width are remembered.
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+GtkTreeViewColumn *
+gnc_tree_view_add_toggle_column (GncTreeView *view,
+				 const gchar *column_title,
+				 const gchar *column_short_title,
+				 const gchar *pref_name,
+				 gint model_data_column,
+				 gint model_visibility_column,
+				 GtkTreeIterCompareFunc column_sort_fn,
+				 renderer_toggled toggle_edited_cb)
+{
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  PangoLayout* layout;
+  int title_width;
+
+  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
+
+  renderer = gtk_cell_renderer_toggle_new ();
+  column =
+    gtk_tree_view_column_new_with_attributes (gettext(column_short_title),
+					      renderer,
+					      "active", model_data_column,
+					      NULL);
+
+  /* Add the full title to the object for menu creation */
+  g_object_set_data_full(G_OBJECT(column), REAL_TITLE,
+			 g_strdup(column_title), g_free);
+  if (toggle_edited_cb)
+    g_signal_connect(G_OBJECT(renderer), "toggled",
+		     G_CALLBACK(toggle_edited_cb), view);
+
+  if (model_visibility_column != GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS)
+    gtk_tree_view_column_add_attribute (column, renderer,
+					"visible", model_visibility_column);
+
+  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view),
+					   column_short_title);
+  pango_layout_get_pixel_size(layout, &title_width, NULL);
+  g_object_unref(layout);
+
+  gnc_tree_view_column_properties (view, column, pref_name, model_data_column,
+				   title_width, FALSE, column_sort_fn);
+
+  gnc_tree_view_append_column (view, column);
+
+  /* Also add the full title to the object as a tooltip */
+  if (!view->priv->title_tips)
+    view->priv->title_tips = gtk_tooltips_new();
+  gtk_tooltips_set_tip(view->priv->title_tips,
+		       column->button,
+		       column_title, NULL);
+
+  return column;
+}
+
+/** This function adds a new text column to a GncTreeView base view.
+ *  It takes all the parameters necessary to hook a GtkTreeModel
+ *  column to a GtkTreeViewColumn.  If the tree has a gconf section
+ *  associated with it, this function also wires up the column so that
+ *  its visibility and width are remembered.
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+GtkTreeViewColumn *
+gnc_tree_view_add_text_column (GncTreeView *view,
+			       const gchar *column_title,
+			       const gchar *pref_name,
+			       const gchar *stock_icon_name,
+			       const gchar *sizing_text,
+			       gint model_data_column,
+			       gint model_visibility_column,
+			       GtkTreeIterCompareFunc column_sort_fn)
+{
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  PangoLayout* layout;
+  int default_width, title_width;
+
+  g_return_val_if_fail (GNC_IS_TREE_VIEW(view), NULL);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, gettext(column_title));
+
+  /* Set up an icon renderer if requested */
+  if (stock_icon_name) {
+    renderer = gtk_cell_renderer_pixbuf_new ();
+    g_object_set (renderer, "stock-id", stock_icon_name, NULL);
+    gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  }
+
+  /* Set up a text renderer and attributes */
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+  /* Set renderer attributes controlled by the model */
+  if (model_data_column != GNC_TREE_VIEW_COLUMN_DATA_NONE)
+    gtk_tree_view_column_add_attribute (column, renderer,
+					"text", model_data_column);
+  if (model_visibility_column != GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS)
+    gtk_tree_view_column_add_attribute (column, renderer,
+					"visible", model_visibility_column);
+
+  /* Default size is the larger of the column title and the sizing text */
+  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), column_title);
+  pango_layout_get_pixel_size(layout, &title_width, NULL);
+  g_object_unref(layout);
+  layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), sizing_text);
+  pango_layout_get_pixel_size(layout, &default_width, NULL);
+  g_object_unref(layout);
+  default_width = MAX(default_width, title_width);
+  if (default_width)
+    default_width += 10; /* padding on either side */
+  gnc_tree_view_column_properties (view, column, pref_name, model_data_column,
+				   default_width, TRUE, column_sort_fn);
+
+  gnc_tree_view_append_column (view, column);
+  return column;
+}
+
+/** This function adds a new numeric column to a GncTreeView base
+ *  view.  It takes all the parameters necessary to hook a
+ *  GtkTreeModel column to a GtkTreeViewColumn.  If the tree has a
+ *  gconf section associated with it, this function also wires up the
+ *  column so that its visibility and width are remembered.  A numeric
+ *  column is nothing more then a text column with a few extra
+ *  attributes.
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+GtkTreeViewColumn *
+gnc_tree_view_add_numeric_column (GncTreeView *view,
+				  const gchar *column_title,
+				  const gchar *pref_name,
+				  const gchar *sizing_text,
+				  gint model_data_column,
+				  gint model_color_column,
+				  gint model_visibility_column,
+				  GtkTreeIterCompareFunc column_sort_fn)
+{
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  GList *renderers;
+
+  column = gnc_tree_view_add_text_column (view, column_title, pref_name,
+					  NULL, sizing_text, model_data_column,
+					  model_visibility_column,
+					  column_sort_fn);
+
+  /* Get the list of one renderer */
+  renderers = gtk_tree_view_column_get_cell_renderers(column);
+  renderer = renderers->data;
+  g_list_free(renderers);
+
+  /* Right align the column title and data */
+  g_object_set(G_OBJECT(column), "alignment",   1.0, NULL);
+  g_object_set(G_OBJECT(renderer), "xalign",   1.0, NULL);
+
+  /* Change the text color */
+  if (model_color_column != GNC_TREE_VIEW_COLUMN_COLOR_NONE)
+    gtk_tree_view_column_add_attribute (column, renderer,
+					"foreground", model_color_column);
+
+  return column;
+}
+
+/** Add a column to a view based upon a GncTreeView.  This function
+ *  knows about the two special columns on the right side of this type
+ *  of view, and adds the new column before these two columns.  You
+ *  could say that it appends to the data columns and ignores the
+ *  infrastructure columns.
+ *
+ *  Parameters are defined in gnc-tree-view.h
+ */
+gint
+gnc_tree_view_append_column (GncTreeView *view,
+			     GtkTreeViewColumn *column)
+{
+  GList *columns;
+  int n;
+
+  /* There's no easy way to get this number. */
+  columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
+  n = g_list_length(columns);
+  g_list_free(columns);
+
+  /* Ignore the initial two columns (the spacer and the selection menu) */
+  if (n >= 2)
+    n -= 2;
+  return gtk_tree_view_insert_column (GTK_TREE_VIEW(view), column, n);
+}
+
+/** @} */
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/Makefile.am,v
retrieving revision 1.48.2.28
retrieving revision 1.48.2.29
diff -Lsrc/gnome-utils/Makefile.am -Lsrc/gnome-utils/Makefile.am -u -r1.48.2.28 -r1.48.2.29
--- src/gnome-utils/Makefile.am
+++ src/gnome-utils/Makefile.am
@@ -74,9 +74,9 @@
   gnc-tree-model-example-account.c \
   gnc-tree-model-price.c \
   gnc-tree-model-selection.c \
+  gnc-tree-view.c \
   gnc-tree-view-account.c \
   gnc-tree-view-commodity.c \
-  gnc-tree-view-common.c \
   gnc-tree-view-price.c \
   gncmod-gnome-utils.c \
   misc-gnome-utils.c \
@@ -124,9 +124,9 @@
   gnc-tree-model-example-account.h \
   gnc-tree-model-price.h \
   gnc-tree-model-selection.h \
+  gnc-tree-view.h \
   gnc-tree-view-account.h \
   gnc-tree-view-commodity.h \
-  gnc-tree-view-common.h \
   gnc-tree-view-price.h \
   misc-gnome-utils.h \
   print-session.h
--- /dev/null
+++ src/gnome-utils/gnc-tree-view.h
@@ -0,0 +1,350 @@
+/********************************************************************\
+ * gnc-tree-view.h -- new GtkTreeView with extra features used by   *
+ *                    all the tree views in gnucash                 *
+ * Copyright (C) 2003 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   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
+ * Boston, MA  02111-1307,  USA       gnu at gnu.org                   *
+ *                                                                  *
+\********************************************************************/
+
+/** @addtogroup GUI
+    @{ */
+/** @file gnc-tree-view.h
+    @brief common utilities for manipulating a GtkTreeView within gnucash  
+    @author David Hampton <hampton at employees.org>
+*/
+
+#ifndef __GNC_TREE_VIEW_H
+#define __GNC_TREE_VIEW_H
+
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtktreeview.h>
+
+G_BEGIN_DECLS
+
+/* type macros */
+#define GNC_TYPE_TREE_VIEW            (gnc_tree_view_get_type ())
+#define GNC_TREE_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNC_TYPE_TREE_VIEW, GncTreeView))
+#define GNC_TREE_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GNC_TYPE_TREE_VIEW, GncTreeViewClass))
+#define GNC_IS_TREE_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNC_TYPE_TREE_VIEW))
+#define GNC_IS_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_TREE_VIEW))
+#define GNC_TREE_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_TREE_VIEW, GncTreeViewClass))
+
+/* typedefs & structures */
+typedef struct GncTreeViewPrivate GncTreeViewPrivate;
+
+typedef struct {
+	GtkTreeView parent;
+
+	GncTreeViewPrivate *priv;
+} GncTreeView;
+
+typedef struct {
+	GtkTreeViewClass parent;
+} GncTreeViewClass;
+
+/* Standard g_object type */
+GType gnc_tree_view_get_type (void);
+
+
+
+
+
+#define GNC_TREE_VIEW_COLUMN_DATA_NONE -1
+#define GNC_TREE_VIEW_COLUMN_COLOR_NONE -1
+#define GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS -1
+
+
+typedef void (* renderer_toggled) (GtkCellRendererToggle *cell_renderer_toggle,
+				   const gchar           *path,
+				   gpointer               user_data);
+
+
+/** @name Tree View Creation */
+/** @{ */
+
+/** This function adds a new toggle column to a GncTreeView base view.
+ *  It takes all the parameters necessary to hook a GtkTreeModel
+ *  column to a GtkTreeViewColumn.  It handles creating a tooltip to
+ *  show the full title name, and setting the sort and edit callback
+ *  functions.  If the tree has a gconf section associated with it,
+ *  this function also wires up the column so that its visibility and
+ *  width are remembered.
+ *
+ *  @param view A pointer to a generic GncTreeView.
+ *
+ *  @param column_title The full title for this column.  This will be
+ *  added as a tooltip what will be displayed when the mouse is
+ *  hovered over the column title button.
+ *
+ *  @param column_short_title This is what will actually be displayed
+ *  as the title of the column.  This should be a single character, as
+ *  anything more will unnecessarily expand the width of the column.
+ *
+ *  @param pref_name The internal name of this column.  This name is
+ *  used in several functions to look up the column, and it is also
+ *  used to create the keys used to record the column width and
+ *  visibility in gconf.
+ *
+ *  @param model_data_column The index of the GtkTreeModel data column
+ *  used to determine whether the displayed checkbox for each row will
+ *  be show as checked or empty.  Use GNC_TREE_VIEW_COLUMN_DATA_NONE
+ *  if you plan on using an non-model data source for this column.
+ *
+ *  @param model_visibility_column The index of the GtkTreeModel data
+ *  column used to determine whether or not a checkbox for each row
+ *  will be displayed at all.  Use GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS
+ *  if the checkbox should be displayed in all rows.
+ *
+ *  @param column_sort_function The function that GtkTreeModelSort
+ *  will call to compare two rows to determine their displayed order.
+ *
+ *  @param toggle_edited_cb The function to call when the user toggles
+ *  the state of a checkbox.
+ *
+ *  @return The newly created GtkTreeViewColumn.
+ */
+GtkTreeViewColumn *
+gnc_tree_view_add_toggle_column (GncTreeView *view,
+				 const gchar *column_title,
+				 const gchar *column_short_title,
+				 const gchar *pref_name,
+				 gint model_data_column,
+				 gint model_visibility_column,
+				 GtkTreeIterCompareFunc column_sort_fn,
+				 renderer_toggled toggle_edited_cb);
+
+/** This function adds a new text column to a GncTreeView base view.
+ *  It takes all the parameters necessary to hook a GtkTreeModel
+ *  column to a GtkTreeViewColumn.  If the tree has a gconf section
+ *  associated with it, this function also wires up the column so that
+ *  its visibility and width are remembered.
+ *
+ *  @param view A pointer to a generic GncTreeView.
+ *
+ *  @param column_title The title for this column.  This will be
+ *  added as a tooltip what will be displayed when the mouse is
+ *  hovered over the column title button.
+ *
+ *  @param pref_name The internal name of this column.  This name is
+ *  used in several functions to look up the column, and it is also
+ *  used to create the keys used to record the column width and
+ *  visibility in gconf.
+ *
+ *  @param stock_icon_name The name of the stock icon to display to
+ *  the left of the text in this column.  Used for adding icons like
+ *  the "account" icon to a view.  This must be a registered stock
+ *  icon, not a filename.
+ *
+ *  @param sizing_text A string used to compute the default width of
+ *  the column.  This text is never displayed.
+ *
+ *  @param model_data_column The index of the GtkTreeModel data column
+ *  used to determine the data that will be displayed in this column
+ *  for each row in the view.  Use GNC_TREE_VIEW_COLUMN_DATA_NONE if
+ *  you plan on using an non-model data source for this column.
+ *
+ *  @param model_visibility_column The index of the GtkTreeModel data
+ *  column used to determine whether or not a checkbox for each row
+ *  will be displayed at all.  Use GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS
+ *  if the checkbox should be displayed in all rows.
+ *
+ *  @param column_sort_function The function that GtkTreeModelSort
+ *  will call to compare two rows to determine their displayed
+ *  order.
+ *
+ *  @return The newly created GtkTreeViewColumn.
+ */
+GtkTreeViewColumn *
+gnc_tree_view_add_text_column (GncTreeView *view,
+			       const gchar *column_title,
+			       const gchar *pref_name,
+			       const gchar *stock_icon_name,
+			       const gchar *sizing_text,
+			       gint model_data_column,
+			       gint model_visibility_column,
+			       GtkTreeIterCompareFunc column_sort_fn);
+
+/** This function adds a new numeric column to a GncTreeView base
+ *  view.  It takes all the parameters necessary to hook a
+ *  GtkTreeModel column to a GtkTreeViewColumn.  If the tree has a
+ *  gconf section associated with it, this function also wires up the
+ *  column so that its visibility and width are remembered.  A numeric
+ *  column is nothing more then a text column with a few extra
+ *  attributes.
+ *
+ *  @param view A pointer to a generic GncTreeView.
+ *
+ *  @param column_title The title for this column.  This will be
+ *  added as a tooltip what will be displayed when the mouse is
+ *  hovered over the column title button.
+ *
+ *  @param pref_name The internal name of this column.  This name is
+ *  used in several functions to look up the column, and it is also
+ *  used to create the keys used to record the column width and
+ *  visibility in gconf.
+ *
+ *  @param sizing_text A string used to compute the default width of
+ *  the column.  This text is never displayed.
+ *
+ *  @param model_data_column The index of the GtkTreeModel data column
+ *  used to determine the data that will be displayed in this column
+ *  for each row in the view.  Use GNC_TREE_VIEW_COLUMN_DATA_NONE if
+ *  you plan on using an non-model data source for this column.
+ *
+ *  @param model_color_column The index of the GtkTreeModel data
+ *  column used to determine the foreground color of any text in this
+ *  column.  It should be used to display negative numbers in red.
+ *  Use GNC_TREE_VIEW_COLUMN_COLOR_NONE if the text in this column
+ *  should always be displayed in black.
+ *
+ *  @param model_visibility_column The index of the GtkTreeModel data
+ *  column used to determine whether or not a checkbox for each row
+ *  will be displayed at all.  Use GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS
+ *  if the checkbox should be displayed in all rows.
+ *
+ *  @param column_sort_function The function that GtkTreeModelSort
+ *  will call to compare two rows to determine their displayed
+ *  order.
+ *
+ *  @return The newly created GtkTreeViewColumn.
+ */
+GtkTreeViewColumn *
+gnc_tree_view_add_numeric_column (GncTreeView *view,
+				  const gchar *column_title,
+				  const gchar *pref_name,
+				  const gchar *sizing_text,
+				  gint model_data_column,
+				  gint model_color_column,
+				  gint model_visibility_column,
+				  GtkTreeIterCompareFunc column_sort_fn);
+
+/** Add a column to a view based upon a GncTreeView.  This function
+ *  knows about the two special columns on the right side of this type
+ *  of view, and adds the new column before these two columns.  You
+ *  could say that it appends to the data columns and ignores the
+ *  infrastructure columns.
+ *
+ *  @param view A pointer to a generic GncTreeView.
+ *
+ *  @param column The column to append.
+ *
+ *  @return The index of the newly added column.
+ */
+gint gnc_tree_view_append_column (GncTreeView *view,
+				  GtkTreeViewColumn *column);
+
+/** @} */
+
+
+/** @name Tree View Properties */
+/** @{ */
+
+/** Attach a data model to a visible GncTreeView widget.  Users of
+ *  this view object must use this function instead of directly
+ *  calling the gtk_tree_view_set_model function.  This function takes
+ *  the additional step of attaching a callback function to the model
+ *  to catch any changes to the sorting of the model.  These changes
+ *  are propagated into gconf by the callback function.
+ *
+ *  @param view The visible tree widget.
+ *
+ *  @param model The data model to attach.
+ */
+void gnc_tree_view_set_model(GncTreeView *view, GtkTreeModel *model);
+
+/** Configure (by name) the default set of visible columns in an gnc
+ *  tree view.  This is the list of columns that will be shown if the
+ *  view isn't using gconf to manage column visibility.  If gconf is
+ *  used, this list will be used the very first time the view is
+ *  presented to the user, then gconf will be used after that.  The
+ *  available list of columns can be found in the file
+ *  gnc-tree-view-xxx.c.
+ *
+ *  @param view A pointer to an gnc tree view.
+ *
+ *  @param column_names A list of column names to make visible.
+ */
+void gnc_tree_view_configure_columns (GncTreeView *view,
+				      gchar *first_column_name,
+				      ...);
+
+/** This function is called to set up or remove an association between
+ *  a gconf section and the display of a view.  It will first remove
+ *  any existing association, and then install the new one.  This
+ *  involves storing the gconf section value, requesting notification
+ *  from gconf of any changes to keys in that section, then attaching
+ *  several signals to catch user changes to the view.
+ *
+ *  @note This function currently marks the first column as autosized
+ *  and all other columns as fixed size (with the size tracked by
+ *  gconf).  This may change in the future.  It must change if we want
+ *  to take advantage of the "fixed row height" performance
+ *  enhancements added to GtkTreeView in gtk-2.4
+ *
+ *  @param view The tree view.
+ *
+ *  @param section Link the view to this gconf section.  This is
+ *  everything after "/apps/gnucash".  I.E. "dialogs/edit_prices".
+ *  Use NULL to disconnect a gconf association.
+ */
+void gnc_tree_view_set_gconf_section (GncTreeView *view,
+				      const gchar *section);
+
+/** This function is called to get the current association between a
+ *  gconf section and the display of a view.  It returns the same
+ *  value passed to gnc_tree_view_set_gconf_section(); i.e. a string
+ *  like "dialogs/edit_prices".
+ *
+ *  @param view The tree view.
+ *
+ *  @return The current gconf section.  This is everything after
+ *  "/apps/gnucash".  I.E "dialogs/edit_prices".
+ */
+const gchar *gnc_tree_view_get_gconf_section (GncTreeView *view);
+
+/** This function is called to set the "show-column-menu" property on
+ *  this view.  This function has no visible effect if the
+ *  "gconf-section" property has not been set.
+ *
+ *  @param view The tree view.
+ *
+ *  @param visible Create the column selection menu if TRUE.
+ */
+void
+gnc_tree_view_set_show_column_menu (GncTreeView *view,
+				    gboolean visible);
+
+/** This function is called to get the current value of the
+ *  "show-column-menu" property.  It returns the same value passed to
+ *  gnc_tree_view_set_show_menu_column().
+ *
+ *  @param view The tree view.
+ *
+ *  @return Whether or not the column selection menu should be shown.
+ */
+gboolean
+gnc_tree_view_get_show_column_menu (GncTreeView *view);
+
+/** @} */
+
+/** @} */
+
+G_END_DECLS
+
+#endif /* __GNC_TREE_VIEW_H */
--- src/gnome-utils/gnc-tree-view-common.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/********************************************************************\
- * gnc-tree-view-common.h -- common utilities for manipulating a    *
- *                     GtkTreeView within gnucash                   *
- * Copyright (C) 2003 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   *
- * published by the Free Software Foundation; either version 2 of   *
- * the License, or (at your option) any later version.              *
- *                                                                  *
- * This program is distributed in the hope that it will be useful,  *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
- * GNU General Public License for more details.                     *
- *                                                                  *
- * You should have received a copy of the GNU General Public License*
- * along with this program; if not, contact:                        *
- *                                                                  *
- * Free Software Foundation           Voice:  +1-617-542-5942       *
- * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
- * Boston, MA  02111-1307,  USA       gnu at gnu.org                   *
- *                                                                  *
-\********************************************************************/
-
-/** @addtogroup GUI
-    @{ */
-/** @addtogroup GuiTreeModel
- * @{ */
-/** @file gnc-tree-view-common.h
-    @brief common utilities for manipulating a GtkTreeView within gnucash  
-    @author David Hampton <hampton at employees.org>
-*/
-
-#ifndef __GNC_TREE_VIEW_COMMON_H
-#define __GNC_TREE_VIEW_COMMON_H
-
-#include <gtk/gtktreemodel.h>
-#include <gtk/gtktreeview.h>
-
-#define GNC_TREE_VIEW_COLUMN_COLOR_NONE -1
-#define GNC_TREE_VIEW_COLUMN_ALIGN_NONE -1
-#define GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS -1
-
-typedef void (* renderer_toggled) (GtkCellRendererToggle *cell_renderer_toggle,
-				   const gchar           *path,
-				   gpointer               user_data);
-
-typedef struct {
-  gint column;
-  gint visibility_column;
-  gint color_column;
-  gfloat label_align;
-  gint align_column;
-  GtkTreeIterCompareFunc sort_fn;
-  GtkTreeViewColumnSizing sizing;
-  gboolean is_toggle;
-  renderer_toggled toggle_edited;
-  const char *pref_name;
-  const char *field_name;
-} gnc_view_column;
-
-/** @name Tree View Creation State 
- @{ */
-
-/** This function creates all the columns in a GtkTreeView.  It is
- *  passed a data structure that specifies all the details for each
- *  column
- *
- *  @param view A pointer to a generic GtkTreeView.
- *
- *  @param name The name of this view.  This string is used for
- *  debugging messages only.
- *
- *  @param stock_icon The name of the stock icon to use in the first
- *  column of the tree.  If null, no icon will be included.
- *
- *  @param defaults A pointer to the data structure describing the
- *  tree view. */
-void gnc_tree_view_common_create_columns (GtkTreeView *view,
-					  const gchar *tree_name,
-					  const gchar *stock_icon,
-					  gnc_view_column *defaults);
-/** @} */
-
-
-/** @name Tree View Save/Restore State 
- @{ */
-
-/** This function saves all settings common to a GtkTreeView as used
- *  in gnucash.  This function currently saves the order in which the
- *  column appear in the view, and the visibility and width of each
- *  column.  If the view is sortable, it also remembers the selected
- *  sort column and sort order.  A future enhancement will be to make
- *  it remember which rows in the tree are expanded.
- *
- *  @param view A pointer to a generic GtkTreeView.
- *
- *  @param section The name of a gconf section where the tree
- *  information should be saved.
- *
- *  @param defaults A pointer to the data structure describing the
- *  tree view. */
-void gnc_tree_view_common_save_settings (GtkTreeView *view,
-					 const gchar *section,
-					 gnc_view_column *defaults);
-
-/** This function restores all the settings common to a GtkTreeView as
- *  used in gnucash.  This function currently restores the order in
- *  which the column appear in the view, and the visibility (but not
- *  the width) of each column.  If the view is sortable, it also
- *  restores the selected sort column and sort order.  A future
- *  enhancement will be to make it restore which rows in the tree are
- *  expanded.
- *
- *  @param view A pointer to a generic GtkTreeView.
- *
- *  @param section The name of a gconf section where the tree
- *  information should be restored from.
- *
- *  @param defaults A pointer to the data structure describing the
- *  tree view. */
-void gnc_tree_view_common_restore_settings (GtkTreeView *view,
-					    const gchar *section,
-					    gnc_view_column *defaults);
-/** @} */
-
-
-/** @} */
-/** @} */
-
-G_END_DECLS
-
-#endif /* __GNC_TREE_VIEW_COMMON_H */


More information about the gnucash-changes mailing list