r23351 - gnucash/trunk/src - Re-implement state save/restore functionality in gnc_tree_view

Geert Janssens gjanssens at code.gnucash.org
Tue Oct 29 15:26:25 EDT 2013


Author: gjanssens
Date: 2013-10-29 15:26:23 -0400 (Tue, 29 Oct 2013)
New Revision: 23351
Trac: http://svn.gnucash.org/trac/changeset/23351

Modified:
   gnucash/trunk/src/business/business-gnome/gnc-plugin-page-owner-tree.c
   gnucash/trunk/src/gnome-utils/gnc-file.c
   gnucash/trunk/src/gnome-utils/gnc-tree-view.c
   gnucash/trunk/src/gnome/gnc-budget-view.c
   gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c
   gnucash/trunk/src/gnome/top-level.c
Log:
Re-implement state save/restore functionality in gnc_tree_view

The new implementation uses the gnucash metafile in .gnucash/books
to save gui state for any page that is based on gnc_tree_view.

Think Account Hierarchy, Budgets, Vendor/Customer/Employee overviews.
Each of these sets a unique name for a state section that the tree view
will use to store column width/visibility, sort column, sort order.

Modified: gnucash/trunk/src/business/business-gnome/gnc-plugin-page-owner-tree.c
===================================================================
--- gnucash/trunk/src/business/business-gnome/gnc-plugin-page-owner-tree.c	2013-10-29 19:26:02 UTC (rev 23350)
+++ gnucash/trunk/src/business/business-gnome/gnc-plugin-page-owner-tree.c	2013-10-29 19:26:23 UTC (rev 23351)
@@ -66,7 +66,6 @@
 static QofLogModule log_module = GNC_MOD_GUI;
 
 #define PLUGIN_PAGE_ACCT_TREE_CM_CLASS "plugin-page-owner-tree"
-#define STATE_SECTION_PREFIX "window/pages/"
 
 #define DELETE_DIALOG_FILTER  "filter"
 #define DELETE_DIALOG_OWNER "owner"
@@ -559,7 +558,7 @@
     GtkTreeView *tree_view;
     GtkWidget *scrolled_window;
     GtkTreeViewColumn *col;
-    gchar *state_section = NULL;
+    const gchar *state_section = NULL;
     gchar* label = "";
 
     ENTER("page %p", plugin_page);
@@ -607,26 +606,25 @@
         break;
     case GNC_OWNER_CUSTOMER :
         label = N_("Customers");
-        state_section = g_strconcat(STATE_SECTION_PREFIX, "customer_tree", NULL);
+        state_section = "Customers Overview";
         break;
     case GNC_OWNER_JOB :
         label = N_("Jobs");
-        state_section = g_strconcat(STATE_SECTION_PREFIX, "job_tree", NULL);
+        state_section = "Jobs Overview";
         break;
     case GNC_OWNER_VENDOR :
         label = N_("Vendors");
-        state_section = g_strconcat(STATE_SECTION_PREFIX, "vendor_tree", NULL);
+        state_section = "Vendors Overview";
         break;
     case GNC_OWNER_EMPLOYEE :
         label = N_("Employees");
-        state_section = g_strconcat(STATE_SECTION_PREFIX, "job_tree", NULL);
+        state_section = "Employees Overview";
         break;
     }
 
     g_object_set(G_OBJECT(tree_view), "state-section", state_section,
                                       "show-column-menu", TRUE,
                                       NULL);
-    g_free (state_section);
 
     g_object_set(G_OBJECT(plugin_page), "page-name", label, NULL);
 

Modified: gnucash/trunk/src/gnome/gnc-budget-view.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-budget-view.c	2013-10-29 19:26:02 UTC (rev 23350)
+++ gnucash/trunk/src/gnome/gnc-budget-view.c	2013-10-29 19:26:23 UTC (rev 23351)
@@ -68,7 +68,7 @@
 static QofLogModule log_module = GNC_MOD_BUDGET;
 
 #define PLUGIN_PAGE_BUDGET_CM_CLASS "budget-view"
-#define STATE_SECTION_PREFIX "window/pages/budget"
+#define STATE_SECTION_PREFIX "Budget"
 
 typedef struct GncBudgetViewPrivate GncBudgetViewPrivate;
 
@@ -313,7 +313,7 @@
     tree_view = gnc_tree_view_account_new(FALSE);
     gtk_container_add(GTK_CONTAINER(inner_scrolled_window), GTK_WIDGET(tree_view));
 
-    state_section = g_strjoin("/", STATE_SECTION_PREFIX, guid_to_string(&priv->key), NULL);
+    state_section = g_strjoin(" ", STATE_SECTION_PREFIX, guid_to_string(&priv->key), NULL);
     g_object_set(G_OBJECT(tree_view), "state-section", state_section, NULL);
     g_free (state_section);
 

Modified: gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c	2013-10-29 19:26:02 UTC (rev 23350)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c	2013-10-29 19:26:23 UTC (rev 23351)
@@ -71,7 +71,7 @@
 static QofLogModule log_module = GNC_MOD_GUI;
 
 #define PLUGIN_PAGE_ACCT_TREE_CM_CLASS "plugin-page-acct-tree"
-#define STATE_SECTION "window/pages/account_tree"
+#define STATE_SECTION "Account Hierarchy"
 
 #define DELETE_DIALOG_FILTER       "filter"
 #define DELETE_DIALOG_ACCOUNT      "account"

Modified: gnucash/trunk/src/gnome/top-level.c
===================================================================
--- gnucash/trunk/src/gnome/top-level.c	2013-10-29 19:26:02 UTC (rev 23350)
+++ gnucash/trunk/src/gnome/top-level.c	2013-10-29 19:26:23 UTC (rev 23351)
@@ -347,7 +347,7 @@
 #endif
 
     /* Write it all out to disk */
-    gnc_state_save (session);
+    //gnc_state_save (session);
     LEAVE("");
 }
 

Modified: gnucash/trunk/src/gnome-utils/gnc-file.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-file.c	2013-10-29 19:26:02 UTC (rev 23350)
+++ gnucash/trunk/src/gnome-utils/gnc-file.c	2013-10-29 19:26:23 UTC (rev 23351)
@@ -47,6 +47,7 @@
 #include "qof.h"
 #include "TransLog.h"
 #include "gnc-session.h"
+#include "gnc-state.h"
 #include "gnc-autosave.h"
 
 
@@ -530,6 +531,7 @@
         gnc_hook_run(HOOK_BOOK_CLOSED, session);
 
         gnc_close_gui_component_by_session (session);
+        gnc_state_save (session);
         gnc_clear_current_session();
         qof_event_resume ();
     }
@@ -707,6 +709,7 @@
         qof_session_call_close_hooks(current_session);
         gnc_hook_run(HOOK_BOOK_CLOSED, current_session);
         gnc_close_gui_component_by_session (current_session);
+        gnc_state_save (current_session);
         gnc_clear_current_session();
     }
 
@@ -1557,6 +1560,7 @@
     qof_session_call_close_hooks(session);
     gnc_hook_run(HOOK_BOOK_CLOSED, session);
     gnc_close_gui_component_by_session (session);
+    gnc_state_save (session);
     gnc_clear_current_session();
 
     qof_event_resume ();

Modified: gnucash/trunk/src/gnome-utils/gnc-tree-view.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-tree-view.c	2013-10-29 19:26:02 UTC (rev 23350)
+++ gnucash/trunk/src/gnome-utils/gnc-tree-view.c	2013-10-29 19:26:23 UTC (rev 23351)
@@ -43,6 +43,7 @@
 #include "gnc-gnome-utils.h"
 #include "gnc-gobject-utils.h"
 #include "gnc-cell-renderer-date.h"
+#include "gnc-state.h"
 
 /* The actual state key for a particular column visibility.  This is
  * attached to the menu items that are in the column selection menu.
@@ -57,8 +58,8 @@
 /* Partial state keys within this particular saved state section. These
    are appended to the various column names to create the actual
    keys. */
-#define STATE_KEY_VISIBLE      "visible"
-#define STATE_KEY_WIDTH        "width"
+#define STATE_KEY_SUFF_VISIBLE "visible"
+#define STATE_KEY_SUFF_WIDTH   "width"
 
 enum
 {
@@ -93,6 +94,10 @@
 static void gnc_tree_view_build_column_menu (GncTreeView *view);
 static void gnc_tree_view_select_column_cb (GtkTreeViewColumn *column,
         GncTreeView *view);
+static gchar *gnc_tree_view_get_sort_order (GncTreeView *view);
+static gchar *gnc_tree_view_get_sort_column (GncTreeView *view);
+static gchar **gnc_tree_view_get_column_order (GncTreeView *view,
+                                                     gsize *length);
 
 /** Private Data Structure ***********************************************/
 
@@ -333,6 +338,64 @@
 
     priv = GNC_TREE_VIEW_GET_PRIVATE(view);
 
+    if (priv->state_section)
+    {
+        /* Save state */
+        GList *column_list, *tmp;
+        GKeyFile *state_file = gnc_state_get_current();
+        gsize num_cols = 0;
+        gchar *sort_column = gnc_tree_view_get_sort_column (view);
+        gchar *sort_order = gnc_tree_view_get_sort_order (view);
+        gchar **col_order = gnc_tree_view_get_column_order (view, &num_cols);
+
+        if (sort_column)
+            g_key_file_set_string (state_file, priv->state_section, STATE_KEY_SORT_COLUMN, sort_column);
+        else if (g_key_file_has_key (state_file, priv->state_section, STATE_KEY_SORT_COLUMN, NULL))
+            g_key_file_remove_key (state_file, priv->state_section, STATE_KEY_SORT_COLUMN, NULL);
+
+        if (sort_order)
+            g_key_file_set_string (state_file, priv->state_section, STATE_KEY_SORT_ORDER, sort_order);
+        else if (g_key_file_has_key (state_file, priv->state_section, STATE_KEY_SORT_ORDER, NULL))
+            g_key_file_remove_key (state_file, priv->state_section, STATE_KEY_SORT_ORDER, NULL);
+
+        if (col_order && (num_cols > 0))
+            g_key_file_set_string_list (state_file, priv->state_section, STATE_KEY_COLUMN_ORDER,
+                                        (const gchar**) col_order, num_cols);
+        else if (g_key_file_has_key (state_file, priv->state_section, STATE_KEY_COLUMN_ORDER, NULL))
+            g_key_file_remove_key (state_file, priv->state_section, STATE_KEY_COLUMN_ORDER, NULL);
+
+
+        // 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))
+        {
+            GtkTreeViewColumn *column = tmp->data;
+            gchar *key=NULL;
+            const gchar *name = g_object_get_data (G_OBJECT (column), PREF_NAME);
+            if (!name)
+                continue;
+
+            if (!g_object_get_data (G_OBJECT (column), ALWAYS_VISIBLE))
+            {
+                key = g_strjoin ("_", name, STATE_KEY_SUFF_VISIBLE, NULL);
+                g_key_file_set_boolean (state_file, priv->state_section, key,
+                                        gtk_tree_view_column_get_visible (column));
+                g_free (key);
+            }
+
+            key = g_strjoin ("_", name, STATE_KEY_SUFF_WIDTH, NULL);
+            if (gtk_tree_view_column_get_fixed_width (column)
+                   != gtk_tree_view_column_get_width (column))
+            {
+                g_key_file_set_integer (state_file, priv->state_section, key,
+                                        gtk_tree_view_column_get_width (column));
+            }
+            else if (g_key_file_has_key (state_file, priv->state_section, key, NULL))
+                g_key_file_remove_key (state_file, priv->state_section, key, NULL);
+            g_free (key);
+        }
+        g_list_free(column_list);
+    }
     g_free(priv->state_section);
     priv->state_section = NULL;
 
@@ -427,6 +490,46 @@
 /** @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 saved state.  This
  *  function simply runs the list of all (visible and invisible)
  *  columns looking for a match.  Column names were attached to each
@@ -541,12 +644,10 @@
 /** 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 shown.  Next, this
- *  function checks to see if the column should be visible by default.
- *  If so this column will be shown as well.
+ *  function checks if visibility is stored in saved state. If so
+ *  use the value found there. If none of the above the default
+ *  visibility for the column is used.
  *
- *  FIXME This should be improved when saved state functionality is
- *        added again.
- *
  *  @param view A GncTreeView.
  *
  *  @param column The GtkTreeViewColumn in question.  Either this
@@ -555,7 +656,7 @@
  *  @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.
+ *  @return TRUE if the column should be visible.  FALSE otherwise.
  *
  *  @internal
  */
@@ -566,7 +667,7 @@
 {
     GncTreeViewPrivate *priv;
     gboolean visible;
-    gchar *key;
+    const gchar *col_name = pref_name;
 
     ENTER("column %p, name %s", column, pref_name ? pref_name : "(null)");
     priv = GNC_TREE_VIEW_GET_PRIVATE(view);
@@ -577,11 +678,11 @@
             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 ? pref_name : "(null)");
+        col_name = g_object_get_data(G_OBJECT(column), PREF_NAME);
+        DEBUG("col_name is %s", col_name ? col_name : "(null)");
     }
 
-    if (!pref_name)
+    if (!col_name)
     {
         LEAVE("1, no pref name");
         return TRUE;
@@ -590,10 +691,16 @@
     /* Using saved state ? */
     if (priv->state_section)
     {
-        visible = column ?
-                  (g_object_get_data(G_OBJECT(column), DEFAULT_VISIBLE) != NULL) : FALSE;
-        LEAVE("%d, saved state but using defaults", visible);
-        return visible;
+        GKeyFile *state_file = gnc_state_get_current ();
+        gchar *key = g_strdup_printf("%s_%s", col_name, STATE_KEY_SUFF_VISIBLE);
+
+        if (g_key_file_has_key (state_file, priv->state_section, key, NULL))
+        {
+            visible = g_key_file_get_boolean (state_file, priv->state_section, key, NULL);
+            g_free(key);
+            LEAVE("%d, state defined visibility", visible);
+            return visible;
+        }
     }
 
     /* Check the default columns list */
@@ -628,33 +735,269 @@
     priv = GNC_TREE_VIEW_GET_PRIVATE(view);
     visible = gnc_tree_view_column_visible(view, column, NULL);
     gtk_tree_view_column_set_visible(column, visible);
-    if (priv->state_section)
+    LEAVE("made %s", visible ? "visible" : "invisible");
+}
+
+/** Get the sort order for the sort column, converted into a string.
+ *
+ *  @param view The tree view.
+ *
+ *  @return a string representing the sort order. NULL if not sorted, else
+ *          either "ascending" or "descending".
+ *          Should be freed with g_free if no longer needed.
+ *
+ *  @internal
+ */
+static gchar *
+gnc_tree_view_get_sort_order (GncTreeView *view)
+{
+    GncTreeViewPrivate *priv;
+    GtkTreeModel *s_model;
+    GtkSortType order;
+    gint current;
+    gchar *order_str = NULL;
+
+    priv = GNC_TREE_VIEW_GET_PRIVATE(view);
+    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+    if (!s_model)
+        return NULL; /* no model, so sort order doesn't make sense */
+
+    if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model),
+            &current, &order))
+        return NULL; /* Model is not sorted, return */
+
+    gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model),
+                                         current, order);
+    order_str = g_strdup (order == GTK_SORT_ASCENDING ? "ascending" : "descending");
+    DEBUG("current sort_order is %s", order_str);
+    return order_str;
+}
+
+/** Get the current sort column.
+ *
+ *  @param view The tree view.
+ *
+ *  @return a string with the name of the sort column, or NULL if not sorted.
+ *          Should be freed with g_free if no longer needed.
+ *
+ *  @internal
+ */
+static gchar *
+gnc_tree_view_get_sort_column (GncTreeView *view)
+{
+    GtkTreeModel *s_model;
+    GtkTreeViewColumn *column;
+    GtkSortType order;
+    gint model_column, current;
+    const gchar *name;
+
+    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+    if (!s_model)
+        return NULL; /* no model -> no sort column */
+
+    if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model),
+            &current, &order))
+        return NULL; /* model not sorted */
+
+    column = view_column_find_by_model_id (view, current);
+    if (!column)
+        return NULL; /* column not visible, can't be used for sorting */
+
+    name = g_object_get_data(G_OBJECT(column), PREF_NAME);
+    DEBUG("current sort column is %s", name ? name : "(NULL)");
+    return g_strdup (name);
+}
+
+
+
+/** Get the current column order.
+ *
+ *  @param view The tree view.
+ *
+ *  @return an array of strings with the names of the columns in the order
+ *          they are currently ordered.
+ *          Should be freed with g_free if no longer needed.
+ *
+ *  @internal
+ */
+static gchar **
+gnc_tree_view_get_column_order (GncTreeView *view,
+                                gsize *length)
+{
+    const GList *tmp;
+    GList *columns;
+    gsize num_cols = 0;
+    gchar *col_names = NULL;
+    gchar **col_str_list;
+
+    /* First, convert from names to pointers */
+    ENTER(" ");
+
+    columns = gtk_tree_view_get_columns (GTK_TREE_VIEW(view));
+    for (tmp = columns; tmp; tmp = g_list_next(tmp))
     {
-        name = (gchar *)g_object_get_data(G_OBJECT(column), PREF_NAME);
-        if (!name)
+        GtkTreeViewColumn *column = tmp->data;
+        const gchar *name = g_object_get_data(G_OBJECT(column), PREF_NAME);
+        if (!col_names)
+            col_names = g_strdup (name);
+        else
         {
-            LEAVE("no pref name");
-            return;
+            gchar *col_names_prev = col_names;
+            col_names = g_strjoin (";", col_names_prev, name, NULL);
+            g_free (col_names_prev);
         }
-        LEAVE("made %s, set state key", visible ? "visible" : "invisible");
+        num_cols++;
+    }
+    DEBUG ("got %lu columns: %s", num_cols, col_names);
+    col_str_list = g_strsplit (col_names, ";", 0);
+
+    /* Clean up */
+    g_list_free(columns);
+    g_free (col_names);
+
+    LEAVE("column order get");
+    *length = num_cols;
+    return col_str_list;
+}
+
+/** Set the sort order for the sort column (if there is one)
+ *  of this tree view.
+ *
+ *  @param view 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)
+{
+    GncTreeViewPrivate *priv;
+    GtkTreeModel *s_model;
+    GtkSortType order = GTK_SORT_ASCENDING;
+    gint current;
+
+    priv = GNC_TREE_VIEW_GET_PRIVATE(view);
+    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+    if (!s_model)
         return;
+    if (g_strcmp0 (name, "descending") == 0)
+        order = GTK_SORT_DESCENDING;
+    if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model),
+            &current, NULL))
+        current = GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID;
+    gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model),
+                                         current, order);
+    DEBUG("sort_order set to %s", order == GTK_SORT_ASCENDING ? "ascending" : "descending");
+}
+
+/** Set the sort column for this tree view.
+ *
+ *  @param view 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;
+
+    s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+    if (!s_model)
+        return;
+
+    column = gnc_tree_view_find_column_by_name(view, name);
+    if (!column)
+    {
+        gtk_tree_sortable_set_sort_column_id(
+            GTK_TREE_SORTABLE(s_model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+            GTK_SORT_ASCENDING);
+        return;
     }
-    LEAVE("made %s", visible ? "visible" : "invisible");
+
+    model_column =
+        GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), MODEL_COLUMN));
+    if (model_column == GNC_TREE_VIEW_COLUMN_DATA_NONE)
+        return;
+
+    if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model),
+            &current, &order))
+        order = GTK_SORT_ASCENDING;
+
+    gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model),
+                                         model_column, order);
+    DEBUG("sort column set to %s", name);
 }
 
-/** This function is called to completely wipe the treeview's state
- *  information (column visibility, width, sorting order,..).  This function may
- *  be called at any time; either when the user wants to disconnect or
+/** Set the order of the columns (visible and invisible) for this
+ *  tree view.
+ *
+ *  @param view The tree view.
+ *
+ *  @param column_names An array of strings.  These strings are the
+ *  names of the columns in the order they should appear.
+ *
+ *  @param length The number of strings in the array.
+ *
+ *  @internal
+ */
+static void
+gnc_tree_view_set_column_order (GncTreeView *view,
+                                gchar **column_names,
+                                gsize length)
+{
+    GncTreeViewPrivate *priv;
+    GtkTreeViewColumn *column, *prev;
+    const GSList *tmp;
+    GSList *columns;
+    gsize idx;
+
+    /* First, convert from names to pointers */
+    ENTER(" ");
+    priv = GNC_TREE_VIEW_GET_PRIVATE(view);
+    columns = NULL;
+    for (idx = 0; idx < length; idx++)
+    {
+        const gchar *name = column_names[idx];
+        column = gnc_tree_view_find_column_by_name(view, name);
+        if (!column)
+            continue;
+        columns = g_slist_append(columns, column);
+    }
+
+    /* Then reorder the columns */
+    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;
+    }
+
+    /* Clean up */
+    g_slist_free(columns);
+    LEAVE("column order set");
+}
+
+/** Completely wipe the treeview's state information (column visibility, width,
+ *  sorting order,..).  This function may be called at any time;
+ *  either when the user wants to disconnect or
  *  when the view object is being destroyed.
  *
- *  FIXME this currently does nothing because state info is not saved yet
- *
  *  @param view The tree view.
  */
 
 void gnc_tree_view_remove_state_information(GncTreeView *view)
 {
     GncTreeViewPrivate *priv;
+    GKeyFile *state_file = gnc_state_get_current ();
 
     ENTER(" ");
     priv = GNC_TREE_VIEW_GET_PRIVATE(view);
@@ -664,18 +1007,17 @@
         return;
     }
 
+    g_key_file_remove_group (state_file, priv->state_section, NULL);
     g_free(priv->state_section);
     priv->state_section = NULL;
     LEAVE(" ");
 }
 
-/** This function is called to set up or remove an association between
- *  a saved state section and the display of a view.  It will first remove
- *  any existing association, and then install the new one.
+/** Set up or remove an association between a saved state section
+ *  and the display of a view.  It will first remove any existing association,
+ *  and then install the new one. If the new section has state
+ *  information, update the view with this information.
  *
- *  FIXME this currently does almost nothing because state information
- *        is currently not stored
- *
  *  Parameters are defined in gnc-tree-view.h
  */
 void
@@ -683,17 +1025,18 @@
                                  const gchar *section)
 {
     GncTreeViewPrivate *priv;
-    GtkTreeModel *model;
-    gulong id;
+    GKeyFile *state_file;
 
     g_return_if_fail(GNC_IS_TREE_VIEW(view));
 
     ENTER("view %p, section %s", view, section);
 
     priv = GNC_TREE_VIEW_GET_PRIVATE(view);
-    g_free(priv->state_section);
-    priv->state_section = NULL;
 
+    /* Drop any previous state section */
+    if (priv->state_section)
+        gnc_tree_view_remove_state_information (view);
+
     if (!section)
     {
         LEAVE("cleared state section");
@@ -703,16 +1046,83 @@
     /* Catch changes in state. Propagate to view. */
     priv->state_section = g_strdup(section);
 
+    state_file = gnc_state_get_current ();
+    if (g_key_file_has_group (state_file, priv->state_section))
+    {
+        gsize num_keys, idx;
+        gchar **keys = g_key_file_get_keys (state_file, priv->state_section, &num_keys, NULL);
+            for (idx = 0; idx < num_keys; idx++)
+            {
+                gchar *key = keys[idx];
+                if (g_strcmp0 (key, STATE_KEY_SORT_COLUMN) == 0)
+                {
+                    gnc_tree_view_set_sort_column (view,
+                            g_key_file_get_string (state_file, priv->state_section, key, NULL));
+                }
+                else if (g_strcmp0 (key, STATE_KEY_SORT_ORDER) == 0)
+                {
+                    gnc_tree_view_set_sort_order (view,
+                            g_key_file_get_string (state_file, priv->state_section, key, NULL));
+                }
+                else if (g_strcmp0 (key, STATE_KEY_COLUMN_ORDER) == 0)
+                {
+                    gsize length;
+                    gchar **columns = g_key_file_get_string_list (state_file, priv->state_section,
+                                                                  key, &length, NULL);
+                    gnc_tree_view_set_column_order (view, columns, length);
+                    g_strfreev (columns);
+                }
+                else
+                {
+                    /* Make a copy of the local part of the key so it can be split
+                     * into column name and key type */
+                    gboolean known = FALSE;
+                    gchar *column_name = g_strdup (key);
+                    gchar *type_name = g_strrstr (column_name, "_");
+                    *type_name++ = '\0';
 
+                    if (g_strcmp0 (type_name, STATE_KEY_SUFF_VISIBLE) == 0)
+                    {
+                        GtkTreeViewColumn *column = gnc_tree_view_find_column_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,
+                                        g_key_file_get_boolean (state_file, priv->state_section, key, NULL));
+                            }
+                        }
+                    }
+                    else if (g_strcmp0 (type_name, STATE_KEY_SUFF_WIDTH) == 0)
+                    {
+                        gint width = g_key_file_get_integer (state_file, priv->state_section, key, NULL);
+                        GtkTreeViewColumn *column = gnc_tree_view_find_column_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);
+                }
+            }
+    }
+
     /* Rebuild the column visibility menu */
-    gnc_tree_view_build_column_menu(view);
-    LEAVE("set state section");
+    gnc_tree_view_build_column_menu (view);
+    LEAVE ("set state section");
 }
 
-/** This function is called to get the current association between a
- *  state section and the display of a view.  It returns the same
- *  value passed to gnc_tree_view_set_state_section(); i.e. a string
- *  like "dialogs/edit_prices".
+/** Get the name of the state section this tree view is associated with.
+ *  It returns the same value passed to gnc_tree_view_set_state_section();
+ *  i.e. a string like "dialogs/edit_prices".
  *
  *  Parameters are defined in gnc-tree-view.h
  */
@@ -721,10 +1131,10 @@
 {
     GncTreeViewPrivate *priv;
 
-    g_return_val_if_fail(GNC_IS_TREE_VIEW(view), NULL);
+    g_return_val_if_fail (GNC_IS_TREE_VIEW (view), NULL);
 
-    priv = GNC_TREE_VIEW_GET_PRIVATE(view);
-    return(priv->state_section);
+    priv = GNC_TREE_VIEW_GET_PRIVATE (view);
+    return priv->state_section;
 }
 
 
@@ -802,7 +1212,7 @@
     g_object_set_data (G_OBJECT (widget), "column-binding", binding);
 
     /* Store data on the widget for callbacks */
-    key = g_strdup_printf("%s_%s", pref_name, STATE_KEY_VISIBLE);
+    key = g_strdup_printf("%s_%s", pref_name, STATE_KEY_SUFF_VISIBLE);
     g_object_set_data_full(G_OBJECT(widget), STATE_KEY, key, g_free);
     // LEAVE(" ");
 }



More information about the gnucash-changes mailing list