[GNC-dev] Fwd: gnucash master: Multiple changes pushed

Geert Janssens geert.gnucash at kobaltwit.be
Thu May 14 07:12:54 EDT 2020


Good point.

Geert

Op donderdag 14 mei 2020 13:01:45 CEST schreef Christopher Lam:
> Small warning/notice is warranted:
> This will automatically modify datafile to add feature as follows.
> 
>       <slot>
>         <slot:key>Register sort and filter settings stored in .gcm
> file</slot:key>
>         <slot:value type="string">Store the register sort and filter
> settings in .gcm metadata file (requires at least GnuCash 3.3)</slot:value>
>       </slot>
> 
> ---------- Forwarded message ---------
> From: Robert Fewell <bobit at code.gnucash.org>
> Date: Thu, 14 May 2020 at 09:36
> Subject: gnucash master: Multiple changes pushed
> To: <gnucash-changes at gnucash.org>
> 
> 
> Updated  via  https://github.com/Gnucash/gnucash/commit/6fb50d22 (commit)
>          via  https://github.com/Gnucash/gnucash/commit/bf9c4441 (commit)
>          via  https://github.com/Gnucash/gnucash/commit/b6de2981 (commit)
>          via  https://github.com/Gnucash/gnucash/commit/2494ad1a (commit)
>          via  https://github.com/Gnucash/gnucash/commit/74abd821 (commit)
>          via  https://github.com/Gnucash/gnucash/commit/4c8ebfe1 (commit)
>          via  https://github.com/Gnucash/gnucash/commit/2f5225ad (commit)
>          via  https://github.com/Gnucash/gnucash/commit/b622518f (commit)
>         from  https://github.com/Gnucash/gnucash/commit/a874483b (commit)
> 
> 
> 
> commit 6fb50d227a2a07acdfcf30194a949239bdb32ad3
> Author: Robert Fewell <14uBobIT at gmail.com>
> Date:   Sat May 2 14:45:14 2020 +0100
> 
>     Complete the move of saving register filter/sort to .gcm
> 
>     This commit changes the saving of register filter and sort information
>     from KVP entries to using the .gcm file. On register load these
>     settings are transferred to the .gcm file and the KVP entries removed.
>     A feature flag is also set when the first register is loaded by this
>     version.
> 
> diff --git a/gnucash/gnome/gnc-plugin-page-register.c
> b/gnucash/gnome/gnc-plugin-page-register.c
> index 36ff606ac..5229de385 100644
> --- a/gnucash/gnome/gnc-plugin-page-register.c
> +++ b/gnucash/gnome/gnc-plugin-page-register.c
> @@ -730,6 +730,10 @@ gnc_plugin_page_register_new_common (GNCLedgerDisplay*
> ledger)
>      gchar* label_color;
>      QofQuery* q;
> 
> +    // added for version 4.0 onwards
> +    if (!gnc_features_check_used (gnc_get_current_book(),
> GNC_FEATURE_REG_SORT_FILTER))
> +        gnc_features_set_used (gnc_get_current_book(),
> GNC_FEATURE_REG_SORT_FILTER);
> +
>      /* Is there an existing page? */
>      gsr = gnc_ledger_display_get_user_data (ledger);
>      if (gsr)
> @@ -1656,10 +1660,6 @@ static const gchar* style_names[] =
>  #define KEY_REGISTER_STYLE      "RegisterStyle"
>  #define KEY_DOUBLE_LINE         "DoubleLineMode"
> 
> -#define KEY_PAGE_SORT           "register_order"
> -#define KEY_PAGE_SORT_REV       "register_reversed"
> -#define KEY_PAGE_FILTER         "register_filter"
> -
>  #define LABEL_ACCOUNT       "Account"
>  #define LABEL_SUBACCOUNT    "SubAccount"
>  #define LABEL_GL            "GL"
> @@ -2061,6 +2061,18 @@ gnc_plugin_page_register_get_tab_color
> (GncPluginPage* plugin_page)
>      return g_strdup (color ? color : "Not Set");
>  }
> 
> +static void
> +gnc_plugin_page_register_check_for_empty_group (GKeyFile *state_file,
> const gchar *state_section)
> +{
> +    gsize num_keys;
> +    gchar **keys = g_key_file_get_keys (state_file, state_section,
> &num_keys, NULL);
> +
> +    if (num_keys == 0)
> +        gnc_state_drop_sections_for (state_section);
> +
> +    g_strfreev (keys);
> +}
> +
>  static const gchar*
>  gnc_plugin_page_register_get_filter_gcm (Account* leader)
>  {
> @@ -2094,7 +2106,6 @@ gnc_plugin_page_register_get_filter (GncPluginPage*
> plugin_page)
>  {
>      GncPluginPageRegisterPrivate* priv;
>      GNCLedgerDisplayType ledger_type;
> -    GNCLedgerDisplay* ld;
>      Account* leader;
>      const char* filter = NULL;
> 
> @@ -2102,19 +2113,12 @@ gnc_plugin_page_register_get_filter (GncPluginPage*
> plugin_page)
>                            _ ("unknown"));
> 
>      priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
> -    ld = priv->ledger;
> -    ledger_type = gnc_ledger_display_type (ld);
> -    leader = gnc_ledger_display_leader (ld);
> 
> -    // load from gcm file for LD_GL or when feature is set
> -    if (ledger_type == LD_GL ||
> -        gnc_features_check_used (gnc_get_current_book(),
> GNC_FEATURE_REG_SORT_FILTER))
> -        filter = gnc_plugin_page_register_get_filter_gcm (leader);
> -    else // load from kvp
> -    {
> -        if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
> -            filter = xaccAccountGetFilter (leader);
> -    }
> +    ledger_type = gnc_ledger_display_type (priv->ledger);
> +    leader = gnc_ledger_display_leader (priv->ledger);
> +
> +    // load from gcm file
> +    filter = gnc_plugin_page_register_get_filter_gcm (leader);
> 
>      return filter ? g_strdup (filter) : g_strdup_printf ("%s,%s,%s,%s",
>                                                           DEFAULT_FILTER,
> @@ -2137,6 +2141,8 @@ gnc_plugin_page_register_set_filter_gcm (Account*
> leader, const gchar* filter,
>      {
>          if (g_key_file_has_key (state_file, state_section,
> KEY_PAGE_FILTER, NULL))
>              g_key_file_remove_key (state_file, state_section,
> KEY_PAGE_FILTER, NULL);
> +
> +        gnc_plugin_page_register_check_for_empty_group (state_file,
> state_section);
>      }
>      else
>      {
> @@ -2156,32 +2162,20 @@ gnc_plugin_page_register_set_filter (GncPluginPage*
> plugin_page,
>  {
>      GncPluginPageRegisterPrivate* priv;
>      GNCLedgerDisplayType ledger_type;
> -    GNCLedgerDisplay* ld;
>      Account* leader;
>      gchar* default_filter;
> 
>      priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
> -    ld = priv->ledger;
> -    ledger_type = gnc_ledger_display_type (ld);
> -    leader = gnc_ledger_display_leader (ld);
> +
> +    ledger_type = gnc_ledger_display_type (priv->ledger);
> +    leader = gnc_ledger_display_leader (priv->ledger);
> 
>      default_filter = g_strdup_printf ("%s,%s,%s,%s", DEFAULT_FILTER,
>                                        "0", "0",
> get_filter_default_num_of_days (ledger_type));
> 
> -    // save to gcm file for LD_GL or when feature is set
> -    if (ledger_type == LD_GL ||
> -        gnc_features_check_used (gnc_get_current_book(),
> GNC_FEATURE_REG_SORT_FILTER))
> -        gnc_plugin_page_register_set_filter_gcm (leader, filter,
> default_filter);
> -    else // save to kvp
> -    {
> -        if (leader != NULL)
> -        {
> -            if (!filter || (g_strcmp0 (filter, default_filter) == 0))
> -                xaccAccountSetFilter (leader, NULL);
> -            else
> -                xaccAccountSetFilter (leader, filter);
> -        }
> -    }
> +    // save to gcm file
> +    gnc_plugin_page_register_set_filter_gcm (leader, filter,
> default_filter);
> +
>      g_free (default_filter);
>      return;
>  }
> @@ -2217,8 +2211,6 @@ static gchar*
>  gnc_plugin_page_register_get_sort_order (GncPluginPage* plugin_page)
>  {
>      GncPluginPageRegisterPrivate* priv;
> -    GNCLedgerDisplayType ledger_type;
> -    GNCLedgerDisplay* ld;
>      Account* leader;
>      const char* sort_order = NULL;
> 
> @@ -2226,19 +2218,12 @@ gnc_plugin_page_register_get_sort_order
> (GncPluginPage* plugin_page)
>                            _ ("unknown"));
> 
>      priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
> -    ld = priv->ledger;
> -    ledger_type = gnc_ledger_display_type (ld);
> -    leader = gnc_ledger_display_leader (ld);
> 
> -    // load from gcm file for LD_GL or when feature is set
> -    if (ledger_type == LD_GL ||
> -        gnc_features_check_used (gnc_get_current_book(),
> GNC_FEATURE_REG_SORT_FILTER))
> -        sort_order = gnc_plugin_page_register_get_sort_order_gcm (leader);
> -    else // load from kvp
> -    {
> -        if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
> -            sort_order = xaccAccountGetSortOrder (leader);
> -    }
> +    leader = gnc_ledger_display_leader (priv->ledger);
> +
> +    // load from gcm file
> +    sort_order = gnc_plugin_page_register_get_sort_order_gcm (leader);
> +
>      return g_strdup (sort_order ? sort_order : DEFAULT_SORT_ORDER);
>  }
> 
> @@ -2257,6 +2242,8 @@ gnc_plugin_page_register_set_sort_order_gcm (Account*
> leader,
>      {
>          if (g_key_file_has_key (state_file, state_section, KEY_PAGE_SORT,
> NULL))
>              g_key_file_remove_key (state_file, state_section,
> KEY_PAGE_SORT, NULL);
> +
> +        gnc_plugin_page_register_check_for_empty_group (state_file,
> state_section);
>      }
>      else
>          g_key_file_set_string (state_file, state_section, KEY_PAGE_SORT,
> sort_order);
> @@ -2268,30 +2255,14 @@ gnc_plugin_page_register_set_sort_order
> (GncPluginPage* plugin_page,
>                                           const gchar* sort_order)
>  {
>      GncPluginPageRegisterPrivate* priv;
> -    GNCLedgerDisplayType ledger_type;
> -    GNCLedgerDisplay* ld;
>      Account* leader;
> 
>      priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
> -    ld = priv->ledger;
> -    ledger_type = gnc_ledger_display_type (ld);
> -    leader = gnc_ledger_display_leader (ld);
> 
> -    // save to gcm file for LD_GL or when feature is set
> -    if (ledger_type == LD_GL ||
> -        gnc_features_check_used (gnc_get_current_book(),
> GNC_FEATURE_REG_SORT_FILTER))
> -        gnc_plugin_page_register_set_sort_order_gcm (leader, sort_order);
> -    else // save to kvp
> -    {
> -        if (leader != NULL)
> -        {
> -            if (!sort_order || (g_strcmp0 (sort_order, DEFAULT_SORT_ORDER)
> == 0))
> -                xaccAccountSetSortOrder (leader, NULL);
> -            else
> -                xaccAccountSetSortOrder (leader, sort_order);
> -        }
> -    }
> -    return;
> +    leader = gnc_ledger_display_leader (priv->ledger);
> +
> +    // save to gcm file
> +    gnc_plugin_page_register_set_sort_order_gcm (leader, sort_order);
>  }
> 
>  static gboolean
> @@ -2320,27 +2291,17 @@ static gboolean
>  gnc_plugin_page_register_get_sort_reversed (GncPluginPage* plugin_page)
>  {
>      GncPluginPageRegisterPrivate* priv;
> -    GNCLedgerDisplayType ledger_type;
> -    GNCLedgerDisplay* ld;
>      Account* leader;
>      gboolean sort_reversed = FALSE;
> 
>      g_return_val_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER (plugin_page),
> FALSE);
> 
>      priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
> -    ld = priv->ledger;
> -    ledger_type = gnc_ledger_display_type (ld);
> -    leader = gnc_ledger_display_leader (ld);
> 
> -    // load from gcm file for LD_GL or when feature is set
> -    if (ledger_type == LD_GL ||
> -        gnc_features_check_used (gnc_get_current_book(),
> GNC_FEATURE_REG_SORT_FILTER))
> -        sort_reversed = gnc_plugin_page_register_get_sort_reversed_gcm
> (leader);
> -    else // load from kvp
> -    {
> -        if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
> -            sort_reversed = xaccAccountGetSortReversed (leader);
> -    }
> +    leader = gnc_ledger_display_leader (priv->ledger);
> +
> +    // load from gcm file
> +    sort_reversed = gnc_plugin_page_register_get_sort_reversed_gcm
> (leader);
>      return sort_reversed;
>  }
> 
> @@ -2359,6 +2320,8 @@ gnc_plugin_page_register_set_sort_reversed_gcm
> (Account* leader,
>      {
>          if (g_key_file_has_key (state_file, state_section,
> KEY_PAGE_SORT_REV, NULL))
>              g_key_file_remove_key (state_file, state_section,
> KEY_PAGE_SORT_REV, NULL);
> +
> +        gnc_plugin_page_register_check_for_empty_group (state_file,
> state_section);
>      }
>      else
>          g_key_file_set_boolean (state_file, state_section,
> KEY_PAGE_SORT_REV,
> @@ -2372,25 +2335,13 @@ gnc_plugin_page_register_set_sort_reversed
> (GncPluginPage* plugin_page,
>                                              gboolean reverse_order)
>  {
>      GncPluginPageRegisterPrivate* priv;
> -    GNCLedgerDisplayType ledger_type;
> -    GNCLedgerDisplay* ld;
>      Account* leader;
> 
>      priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (plugin_page);
> -    ld = priv->ledger;
> -    ledger_type = gnc_ledger_display_type (ld);
> -    leader = gnc_ledger_display_leader (ld);
> +    leader = gnc_ledger_display_leader (priv->ledger);
> 
> -    // save to gcm file for LD_GL or when feature is set
> -    if (ledger_type == LD_GL ||
> -        gnc_features_check_used (gnc_get_current_book(),
> GNC_FEATURE_REG_SORT_FILTER))
> -        gnc_plugin_page_register_set_sort_reversed_gcm (leader,
> reverse_order);
> -    else // save to kvp
> -    {
> -        if (leader != NULL)
> -            xaccAccountSetSortReversed (leader, reverse_order);
> -    }
> -    return;
> +    // save to gcm file
> +    gnc_plugin_page_register_set_sort_reversed_gcm (leader, reverse_order);
> }
> 
>  static gchar*
> @@ -2556,7 +2507,7 @@ gnc_plugin_page_register_sort_response_cb (GtkDialog*
> dialog,
>      else
>      {
>          // clear the sort when unticking the save option
> -        if ((priv->sd.save_order == FALSE) &&
> (priv->sd.original_save_order == TRUE))
> +        if ((!priv->sd.save_order) && ((priv->sd.original_save_order) ||
> (priv->sd.original_reverse_order)))
>          {
>              gnc_plugin_page_register_set_sort_order (plugin_page,
> DEFAULT_SORT_ORDER);
>              gnc_plugin_page_register_set_sort_reversed (plugin_page,
> FALSE);
> diff --git a/gnucash/gnome/gnc-split-reg.c b/gnucash/gnome/gnc-split-reg.c
> index fd2a399f0..bc8b82571 100644
> --- a/gnucash/gnome/gnc-split-reg.c
> +++ b/gnucash/gnome/gnc-split-reg.c
> @@ -447,6 +447,82 @@ gnc_split_reg_get_register_state_group (GNCSplitReg
> *gsr)
>      }
>  }
> 
> +static void
> +gsr_drop_register_width_state (GNCSplitReg *gsr, GKeyFile* state_file,
> const gchar *state_section)
> +{
> +    GNCLedgerDisplayType ledger_type;
> +    GNCLedgerDisplay* ld;
> +
> +    gboolean sort_reversed = FALSE;
> +    gchar* sort_text = NULL;
> +    gchar* filter_text = NULL;
> +
> +    // Look for any old kvp entries and add them to .gcm file
> +    ledger_type = gnc_ledger_display_type (gsr->ledger);
> +
> +    // General ledger should already be using .gcm file
> +    if ((ledger_type == LD_SINGLE) || (ledger_type == LD_SUBACCOUNT))
> +    {
> +        Account *leader = gnc_ledger_display_leader (gsr->ledger);
> +        const char* kvp_filter = NULL;
> +        const char* kvp_sort_order = NULL;
> +        gboolean kvp_sort_reversed = FALSE;
> +
> +        kvp_filter = xaccAccountGetFilter (leader);
> +        if (kvp_filter)
> +        {
> +            gchar *temp_filter_text = g_strdup (kvp_filter);
> +            temp_filter_text = g_strdelimit (temp_filter_text, ",",
> +                                             ';'); // make it conform to
> .gcm file list
> +            g_key_file_set_string (state_file, state_section,
> KEY_PAGE_FILTER,
> +                                   temp_filter_text);
> +            g_free (temp_filter_text);
> +            xaccAccountSetFilter (leader, NULL);
> +        }
> +
> +        kvp_sort_order = xaccAccountGetSortOrder (leader);
> +        if (kvp_sort_order)
> +        {
> +            g_key_file_set_string (state_file, state_section,
> +                                   KEY_PAGE_SORT, kvp_sort_order);
> +            xaccAccountSetSortOrder (leader, NULL);
> +        }
> +
> +        kvp_sort_reversed = xaccAccountGetSortReversed (leader);
> +        if (kvp_sort_reversed)
> +        {
> +            g_key_file_set_boolean (state_file, state_section,
> +                                    KEY_PAGE_SORT_REV, kvp_sort_reversed);
> +            xaccAccountSetSortReversed (leader, FALSE);
> +        }
> +    }
> +
> +    sort_reversed = g_key_file_get_boolean (state_file, state_section,
> +                                            KEY_PAGE_SORT_REV, NULL);
> +
> +    sort_text = g_key_file_get_string (state_file, state_section,
> +                                       KEY_PAGE_SORT, NULL);
> +
> +    filter_text = g_key_file_get_string (state_file, state_section,
> +                                         KEY_PAGE_FILTER, NULL);
> +
> +    // drop the register state widths
> +    gnc_state_drop_sections_for (state_section);
> +
> +    if (filter_text)
> +        g_key_file_set_string (state_file, state_section, KEY_PAGE_FILTER,
> +                               filter_text);
> +    if (sort_text)
> +        g_key_file_set_string (state_file, state_section, KEY_PAGE_SORT,
> sort_text);
> +
> +    if (sort_reversed)
> +        g_key_file_set_boolean (state_file, state_section,
> KEY_PAGE_SORT_REV,
> +                                sort_reversed);
> +
> +    g_free (filter_text);
> +    g_free (sort_text);
> +}
> +
>  static
>  void
>  gsr_create_table( GNCSplitReg *gsr )
> @@ -457,9 +533,11 @@ gsr_create_table( GNCSplitReg *gsr )
>      Account * account = gnc_ledger_display_leader(gsr->ledger);
>      const GncGUID * guid = xaccAccountGetGUID(account);
>      gchar guidstr[GUID_ENCODING_LENGTH+1];
> +    GKeyFile* state_file = gnc_state_get_current();
>      gchar *register_state_section;
>      const gchar *default_state_section;
>      const gchar *group;
> +    gboolean has_date_width = FALSE;
> 
>      guid_to_string_buff (guid, guidstr);
> 
> @@ -470,9 +548,12 @@ gsr_create_table( GNCSplitReg *gsr )
>      sr = gnc_ledger_display_get_split_register (gsr->ledger);
>      default_state_section = gnc_split_reg_get_register_state_group (gsr);
> 
> +    // see if register group has the date_width key, old format pre 4.0
> +    has_date_width = g_key_file_has_key (state_file,
> register_state_section, "date_width", NULL);
> +
>      // if this is from a page recreate and no register state use those
> settings,
> -    // register state is dropped at the end of function.
> -    if (gsr->page_state_name && !g_key_file_has_group
> (gnc_state_get_current (), register_state_section))
> +    // register state width information is dropped at the end of function.
> +    if (gsr->page_state_name && !has_date_width)
>          group = gsr->page_state_name;
>      else
>      {
> @@ -505,12 +586,13 @@ gsr_create_table( GNCSplitReg *gsr )
>                        G_CALLBACK(gsr_emit_show_popup_menu), gsr);
> 
>      // if no default state and register has state, copy it.
> -    if (g_key_file_has_group (gnc_state_get_current (),
> register_state_section))
> +    if (has_date_width) // we have old register state section
>      {
>          if (!gnc_split_reg_register_has_user_state (gsr))
>               gnc_table_save_state (sr->table, default_state_section);
> -        // drop the register state
> -        gnc_state_drop_sections_for (register_state_section);
> +
> +        // drop the register width state information
> +        gsr_drop_register_width_state (gsr, state_file,
> register_state_section);
>      }
>      g_free (register_state_section);
>      LEAVE(" ");
> diff --git a/gnucash/gnome/gnc-split-reg.h b/gnucash/gnome/gnc-split-reg.h
> index 128e49ca6..dbd82f814 100644
> --- a/gnucash/gnome/gnc-split-reg.h
> +++ b/gnucash/gnome/gnc-split-reg.h
> @@ -37,6 +37,9 @@
>  #define IS_GNC_SPLIT_REG(obj)      G_TYPE_CHECK_INSTANCE_TYPE( obj,
> gnc_split_reg_get_type() )
> 
>  #define STATE_SECTION_REG_PREFIX "Register"
> +#define KEY_PAGE_SORT            "register_order"
> +#define KEY_PAGE_SORT_REV        "register_reversed"
> +#define KEY_PAGE_FILTER          "register_filter"
> 
>  typedef struct _GNCSplitReg GNCSplitReg;
>  typedef struct _GNCSplitRegClass GNCSplitRegClass;
> 
> commit bf9c44416e2024caf0d2dac1078f5e085442e0bb
> Author: Robert Fewell <14uBobIT at gmail.com>
> Date:   Sat May 2 14:41:35 2020 +0100
> 
>     Remove the setting of a comment for registers
> 
> diff --git a/gnucash/gnome/dialog-invoice.c b/gnucash/gnome/dialog-invoice.c
> index 8cfcda510..0e3bf45ee 100644
> --- a/gnucash/gnome/dialog-invoice.c
> +++ b/gnucash/gnome/dialog-invoice.c
> @@ -544,7 +544,7 @@ gnc_invoice_window_save_document_layout_to_user_state
> (InvoiceWindow *iw)
>      Table *table = gnc_entry_ledger_get_table (iw->ledger);
>      const gchar *group = gnc_invoice_window_get_state_group (iw);
> 
> -    gnc_table_save_state (table, group, NULL);
> +    gnc_table_save_state (table, group);
>  }
> 
>  /* Removes the user state layout information for Invoice/Bill/Voucher
> @@ -2368,7 +2368,7 @@ gnc_invoice_save_page (InvoiceWindow *iw,
>          g_key_file_set_string(key_file, group_name, KEY_OWNER_GUID,
> guidstr);
>      }
>      // save the open table layout
> -    gnc_table_save_state (table, group_name, NULL);
> +    gnc_table_save_state (table, group_name);
>  }
> 
>  GtkWidget *
> diff --git a/gnucash/gnome/gnc-plugin-page-register.c
> b/gnucash/gnome/gnc-plugin-page-register.c
> index c98ba9332..36ff606ac 100644
> --- a/gnucash/gnome/gnc-plugin-page-register.c
> +++ b/gnucash/gnome/gnc-plugin-page-register.c
> @@ -1739,7 +1739,7 @@ gnc_plugin_page_register_save_page (GncPluginPage*
> plugin_page,
>                              reg->use_double_line);
> 
>      // save the open table layout
> -    gnc_table_save_state (reg->table, group_name, NULL);
> +    gnc_table_save_state (reg->table, group_name);
> 
>      LEAVE(" ");
>  }
> diff --git a/gnucash/gnome/gnc-split-reg.c b/gnucash/gnome/gnc-split-reg.c
> index b8453bdd1..fd2a399f0 100644
> --- a/gnucash/gnome/gnc-split-reg.c
> +++ b/gnucash/gnome/gnc-split-reg.c
> @@ -508,7 +508,7 @@ gsr_create_table( GNCSplitReg *gsr )
>      if (g_key_file_has_group (gnc_state_get_current (),
> register_state_section))
>      {
>          if (!gnc_split_reg_register_has_user_state (gsr))
> -             gnc_table_save_state (sr->table, default_state_section, NULL);
> +             gnc_table_save_state (sr->table, default_state_section); //
> drop the register state
>          gnc_state_drop_sections_for (register_state_section);
>      }
> @@ -2008,7 +2008,7 @@ gnc_split_reg_save_register_layout_to_user_state
> (GNCSplitReg *gsr)
>      SplitRegister *split_reg = gnc_ledger_display_get_split_register
> (gsr->ledger);
>      const gchar *group = gnc_split_reg_get_register_state_group (gsr);
> 
> -    gnc_table_save_state (split_reg->table, group, NULL);
> +    gnc_table_save_state (split_reg->table, group);
>  }
> 
>  /* Removes the user state layout information for the register group
> diff --git a/gnucash/register/register-core/table-allgui.h
> b/gnucash/register/register-core/table-allgui.h
> index 53d1b7f1d..03a0e08af 100644
> --- a/gnucash/register/register-core/table-allgui.h
> +++ b/gnucash/register/register-core/table-allgui.h
> @@ -201,7 +201,7 @@ Table *     gnc_table_new (TableLayout *layout,
>                             TableControl *control);
>  void        gnc_virtual_location_init (VirtualLocation *vloc);
> 
> -void        gnc_table_save_state (Table *table, const gchar
> *state_section, gchar *account_fullname);
> +void        gnc_table_save_state (Table *table, const gchar
> *state_section);
>  void        gnc_table_destroy (Table *table);
> 
> 
> diff --git a/gnucash/register/register-gnome/table-gnome.c
> b/gnucash/register/register-gnome/table-gnome.c
> index 73d2f2303..825e77268 100644
> --- a/gnucash/register/register-gnome/table-gnome.c
> +++ b/gnucash/register/register-gnome/table-gnome.c
> @@ -68,7 +68,7 @@ static QofLogModule UNUSED_VAR log_module =
> GNC_MOD_REGISTER;
>  /** Implementation *****************************************************/
> 
>  void
> -gnc_table_save_state (Table *table, const gchar * state_section, gchar *
> account_fullname)
> +gnc_table_save_state (Table *table, const gchar * state_section)
>  {
>      GnucashSheet *sheet;
>      GNCHeaderWidths widths;
> @@ -108,12 +108,6 @@ gnc_table_save_state (Table *table, const gchar *
> state_section, gchar * account
>              g_key_file_remove_key (state_file, state_section, key, NULL);
>          g_free (key);
>      }
> -    if (account_fullname)
> -    {
> -        key = g_strdup_printf ("Register state for \"%s\"",
> account_fullname);
> -        g_key_file_set_comment (state_file, state_section, NULL, key,
> NULL);
> -        g_free (key);
> -    }
>      gnc_header_widths_destroy (widths);
>  }
> 
> 
> commit b6de2981b83d2f6fb480855b7f2522c87d2ea60a
> Author: Robert Fewell <14uBobIT at gmail.com>
> Date:   Sat May 2 14:38:37 2020 +0100
> 
>     Remove the state key file comment for Account filter
> 
> diff --git a/gnucash/gnome-utils/gnc-tree-view-account.c
> b/gnucash/gnome-utils/gnc-tree-view-account.c
> index 921038462..9d1a7445d 100644
> --- a/gnucash/gnome-utils/gnc-tree-view-account.c
> +++ b/gnucash/gnome-utils/gnc-tree-view-account.c
> @@ -2486,10 +2486,6 @@ gnc_tree_view_account_save_filter
> (GncTreeViewAccount *view,
>                             fd->show_zero_total);
>      g_key_file_set_boolean (key_file, group_name, SHOW_UNUSED_ACCOUNTS,
>                             fd->show_unused);
> -
> -    g_key_file_set_comment (key_file, group_name, ACCOUNT_TYPES,
> -                            "Account Filter Section below, four lines",
> NULL);
> -
>      LEAVE("");
>  }
> 
> 
> commit 2494ad1adf9bccccfae53b3b2924591da2a44113
> Author: Robert Fewell <14uBobIT at gmail.com>
> Date:   Sat May 2 14:37:40 2020 +0100
> 
>     Add option to save Layout for Register items
> 
>     Add two menu items under windows, one to save an existing register
>     layout based on the register type to there respective default layouts
>     so the user set column widths will be used when opening registers. The
>     second menu item will reset the column widths to defaults and remove
>     the associated default layout.
>     Open registers will also save there column widths to the page section
>     so these could can temporarily have different widths.
> 
> diff --git a/gnucash/gnome/gnc-plugin-page-register.c
> b/gnucash/gnome/gnc-plugin-page-register.c
> index 032566c95..c98ba9332 100644
> --- a/gnucash/gnome/gnc-plugin-page-register.c
> +++ b/gnucash/gnome/gnc-plugin-page-register.c
> @@ -253,6 +253,10 @@ static void
> gnc_plugin_page_register_cmd_account_report (GtkAction* action,
> 
> GncPluginPageRegister* plugin_page);
>  static void gnc_plugin_page_register_cmd_transaction_report (GtkAction*
> action,
>          GncPluginPageRegister* plugin_page);
> +static void gnc_plugin_page_register_cmd_save_layout (GtkAction *action,
> +
> GncPluginPageRegister *plugin_page);
> +static void gnc_plugin_page_register_cmd_reset_layout (GtkAction *action,
> +
>  GncPluginPageRegister *plugin_page);
>  static void gnc_plugin_page_register_cmd_associate_file_transaction (
>      GtkAction* action, GncPluginPageRegister* plugin_page);
>  static void gnc_plugin_page_register_cmd_associate_location_transaction (
> @@ -516,6 +520,18 @@ static GtkActionEntry gnc_plugin_page_register_actions
> [] =
>          N_ ("Open a register report for the selected Transaction"),
>          G_CALLBACK (gnc_plugin_page_register_cmd_transaction_report)
>      },
> +
> +    /* Windows menu */
> +    {
> +        "WindowsSaveLayoutAction", NULL, "_Use as Default Layout for this
> Register Group", NULL,
> +        N_("Use the current layout as default for all registers in the
> group 'Currency account registers'"),
> +        G_CALLBACK (gnc_plugin_page_register_cmd_save_layout)
> +    },
> +    {
> +        "WindowsResetLayoutAction", NULL, "_Reset Default Layout for this
> Register Group", NULL,
> +        N_("Reset default layout for all registers in the group 'Currency
> account registers' back to built-in defaults and update page accordingly"),
> +        G_CALLBACK (gnc_plugin_page_register_cmd_reset_layout)
> +    },
>  };
> 
>  static guint gnc_plugin_page_register_n_actions = G_N_ELEMENTS (
> @@ -640,6 +656,8 @@ typedef struct GncPluginPageRegisterPrivate
> 
>      GtkWidget* widget;
> 
> +    const gchar *page_state_name; /* Used for loading state information */
> +
>      gint event_handler_id;
>      gint component_manager_id;
>      GncGUID key;  /* The guid of the Account we're watching */
> @@ -904,6 +922,7 @@ gnc_plugin_page_register_init (GncPluginPageRegister*
> plugin_page)
>      priv->enable_refresh    = TRUE;
>      priv->search_query      = NULL;
>      priv->filter_query      = NULL;
> +    priv->page_state_name   = NULL;
>  }
> 
>  static void
> @@ -953,8 +972,10 @@ gnc_plugin_page_register_focus_widget (GncPluginPage*
> register_plugin_page)
>  {
>      if (GNC_IS_PLUGIN_PAGE_REGISTER (register_plugin_page))
>      {
> -        GNCSplitReg* gsr = gnc_plugin_page_register_get_gsr
> (GNC_PLUGIN_PAGE (
> -
>  register_plugin_page));
> +        GNCSplitReg *gsr = gnc_plugin_page_register_get_gsr
> (GNC_PLUGIN_PAGE(register_plugin_page));
> +
> +        gnc_plugin_page_register_ui_update (NULL,
> GNC_PLUGIN_PAGE_REGISTER(register_plugin_page));
> +
>          gnc_split_reg_focus_on_sheet (gsr);
>      }
>      return FALSE;
> @@ -1190,6 +1211,26 @@ gnc_plugin_page_register_ui_update (gpointer various,
> }
>          }
>      }
> +
> +    // update the register default layouts actions
> +    {
> +        gboolean has_default = FALSE;
> +        const gchar *group = gnc_split_reg_get_register_state_group
> (priv->gsr);
> +        GtkAction *layout_action = gnc_plugin_page_get_action
> (GNC_PLUGIN_PAGE(page), "WindowsSaveLayoutAction");
> +        gchar *tt = g_strdup_printf (gettext ("Use the current layout as
> default for all registers in the group '%s'"), _(group));
> +        gtk_action_set_tooltip (layout_action, tt);
> +        g_free (tt);
> +
> +        layout_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(page),
> "WindowsResetLayoutAction");
> +        tt = g_strdup_printf (gettext ("Reset default layout for all
> registers in the group '%s' back to built-in defaults and update page
> accordingly"), _(group));
> +        gtk_action_set_tooltip (layout_action, tt);
> +        g_free (tt);
> +
> +        // if there is no default layout do not enable reset action
> +        if (gnc_split_reg_register_has_user_state (priv->gsr))
> +            has_default = TRUE;
> +        gtk_action_set_sensitive (layout_action, has_default);
> +    }
>  }
> 
>  static void
> @@ -1330,11 +1371,12 @@ gnc_plugin_page_register_create_widget
> (GncPluginPage* plugin_page)
>      numRows = priv->lines_default;
>      numRows = MIN (numRows, DEFAULT_LINES_AMOUNT);
> 
> -    gnc_window = GNC_WINDOW (GNC_PLUGIN_PAGE (page)->window);
> +    gnc_window = GNC_WINDOW(GNC_PLUGIN_PAGE(page)->window);
>      gsr = gnc_split_reg_new (priv->ledger,
>                               gnc_window_get_gtk_window (gnc_window),
> -                             numRows, priv->read_only);
> -    priv->gsr = (GNCSplitReg*)gsr;
> +                             numRows, priv->read_only,
> priv->page_state_name);
> +    priv->gsr = (GNCSplitReg *)gsr;
> +
>      gtk_widget_show (gsr);
>      gtk_box_pack_start (GTK_BOX (priv->widget), gsr, TRUE, TRUE, 0);
> 
> @@ -1696,7 +1738,10 @@ gnc_plugin_page_register_save_page (GncPluginPage*
> plugin_page,
>      g_key_file_set_boolean (key_file, group_name, KEY_DOUBLE_LINE,
>                              reg->use_double_line);
> 
> -    LEAVE (" ");
> +    // save the open table layout
> +    gnc_table_save_state (reg->table, group_name, NULL);
> +
> +    LEAVE(" ");
>  }
> 
> 
> @@ -1833,6 +1878,7 @@ gnc_plugin_page_register_recreate_page (GtkWidget*
> window,
>       * sort/filter updates and double line/style changes */
>      priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (page);
>      priv->enable_refresh = FALSE;
> +    priv->page_state_name = group_name;
> 
>      /* Recreate page in given window */
>      gnc_plugin_page_set_use_new_window (page, FALSE);
> @@ -4977,6 +5023,46 @@ gnc_plugin_page_register_cmd_transaction_report
> (GtkAction* action,
>      LEAVE (" ");
>  }
> 
> +static void
> +gnc_plugin_page_register_cmd_save_layout (GtkAction *action,
> GncPluginPageRegister *plugin_page)
> +{
> +    GNCSplitReg *gsr;
> +    GtkAction *layout_action;
> +
> +    ENTER("(action %p, plugin_page %p)", action, plugin_page);
> +
> +    g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
> +
> +    gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE(plugin_page));
> +
> +    gnc_split_reg_save_register_layout_to_user_state (gsr);
> +
> +    layout_action = gnc_plugin_page_get_action
> (GNC_PLUGIN_PAGE(plugin_page),
> +
> "WindowsResetLayoutAction");
> +    gtk_action_set_sensitive (layout_action, TRUE);
> +    LEAVE(" ");
> +}
> +
> +static void
> +gnc_plugin_page_register_cmd_reset_layout (GtkAction *action,
> GncPluginPageRegister *plugin_page)
> +{
> +    GNCSplitReg *gsr;
> +    GtkAction *layout_action;
> +
> +    ENTER("(action %p, plugin_page %p)", action, plugin_page);
> +
> +    g_return_if_fail (GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
> +
> +    gsr = gnc_plugin_page_register_get_gsr (GNC_PLUGIN_PAGE(plugin_page));
> +
> +    gnc_split_reg_reset_register_layout_and_clear_user_state (gsr);
> +
> +    layout_action = gnc_plugin_page_get_action
> (GNC_PLUGIN_PAGE(plugin_page),
> +
> "WindowsResetLayoutAction");
> +    gtk_action_set_sensitive (layout_action, FALSE);
> +    LEAVE(" ");
> +}
> +
>  /************************************************************/
>  /*                    Auxiliary functions                   */
>  /************************************************************/
> diff --git a/gnucash/gnome/gnc-split-reg.c b/gnucash/gnome/gnc-split-reg.c
> index 7e2bbf4a8..b8453bdd1 100644
> --- a/gnucash/gnome/gnc-split-reg.c
> +++ b/gnucash/gnome/gnc-split-reg.c
> @@ -56,6 +56,7 @@
>  #include "gnucash-sheet.h"
>  #include "gnucash-register.h"
>  #include "table-allgui.h"
> +#include "gnc-state.h"
> 
>  #include "dialog-utils.h"
> 
> @@ -325,7 +326,8 @@ GtkWidget*
>  gnc_split_reg_new( GNCLedgerDisplay *ld,
>                     GtkWindow *parent,
>                     gint numberOfLines,
> -                   gboolean read_only )
> +                   gboolean read_only,
> +                   const gchar *group_name )
>  {
>      GNCSplitReg *gsrToRet;
> 
> @@ -340,6 +342,8 @@ gnc_split_reg_new( GNCLedgerDisplay *ld,
>      gsrToRet->ledger = ld;
>      gsrToRet->window = GTK_WIDGET(parent);
> 
> +    gsrToRet->page_state_name = group_name;
> +
>      gnc_split_reg_init2( gsrToRet );
> 
>      LEAVE("%p", gsrToRet);
> @@ -359,6 +363,7 @@ gnc_split_reg_init( GNCSplitReg *gsr )
>      gsr->height = -1;
>      gsr->numRows = 10;
>      gsr->read_only = FALSE;
> +    gsr->page_state_name = NULL;
>  }
> 
>  static void
> @@ -402,6 +407,46 @@ gsr_setup_table( GNCSplitReg *gsr )
>      LEAVE(" ");
>  }
> 
> +const gchar *
> +gnc_split_reg_get_register_state_group (GNCSplitReg *gsr)
> +{
> +    SplitRegister *split_reg = gnc_ledger_display_get_split_register
> (gsr->ledger);
> +
> +    switch (gnc_split_register_get_register_group (split_reg))
> +    {
> +        case REG_TYPE_GROUP_CURRENCY:
> +        {
> +            return N_("Currency account registers");
> +            break;
> +        }
> +        case REG_TYPE_GROUP_APAR:
> +        {
> +            return N_("Business account registers");
> +            break;
> +        }
> +        case REG_TYPE_GROUP_JOURNAL:
> +        {
> +            return N_("Journal registers");
> +            break;
> +        }
> +        case REG_TYPE_GROUP_STOCK:
> +        {
> +            return N_("Stock account registers");
> +            break;
> +        }
> +        case REG_TYPE_GROUP_PORTFOLIO:
> +        {
> +            return N_("Portfolio registers");
> +            break;
> +        }
> +        default:
> +        {
> +            return N_("Register group Unknown");
> +            break;
> +        }
> +    }
> +}
> +
>  static
>  void
>  gsr_create_table( GNCSplitReg *gsr )
> @@ -412,12 +457,31 @@ gsr_create_table( GNCSplitReg *gsr )
>      Account * account = gnc_ledger_display_leader(gsr->ledger);
>      const GncGUID * guid = xaccAccountGetGUID(account);
>      gchar guidstr[GUID_ENCODING_LENGTH+1];
> -    const gchar *state_section = NULL;
> -    guid_to_string_buff(guid, guidstr);
> -    state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr,
> NULL);
> +    gchar *register_state_section;
> +    const gchar *default_state_section;
> +    const gchar *group;
> +
> +    guid_to_string_buff (guid, guidstr);
> +
> +    register_state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ",
> guidstr, NULL);
> 
>      ENTER("gsr=%p", gsr);
> 
> +    sr = gnc_ledger_display_get_split_register (gsr->ledger);
> +    default_state_section = gnc_split_reg_get_register_state_group (gsr);
> +
> +    // if this is from a page recreate and no register state use those
> settings,
> +    // register state is dropped at the end of function.
> +    if (gsr->page_state_name && !g_key_file_has_group
> (gnc_state_get_current (), register_state_section))
> +        group = gsr->page_state_name;
> +    else
> +    {
> +        // if no default state, use register state if available
> +        if (gnc_split_reg_register_has_user_state (gsr))
> +            group = default_state_section;
> +        else
> +            group = register_state_section;
> +    }
>      gnc_ledger_display_set_user_data( gsr->ledger, (gpointer)gsr );
>      gnc_ledger_display_set_handlers( gsr->ledger,
>                                       gnc_split_reg_ld_destroy,
> @@ -425,7 +489,7 @@ gsr_create_table( GNCSplitReg *gsr )
> 
>      /* FIXME: We'd really rather pass this down... */
>      sr = gnc_ledger_display_get_split_register( gsr->ledger );
> -    register_widget = gnucash_register_new( sr->table, state_section );
> +    register_widget = gnucash_register_new( sr->table, group );
>      gsr->reg = GNUCASH_REGISTER( register_widget );
> 
>      gtk_box_pack_start (GTK_BOX (gsr), GTK_WIDGET(gsr->reg), TRUE, TRUE,
> 0);
> @@ -440,6 +504,15 @@ gsr_create_table( GNCSplitReg *gsr )
>      g_signal_connect (gsr->reg, "show_popup_menu",
>                        G_CALLBACK(gsr_emit_show_popup_menu), gsr);
> 
> +    // if no default state and register has state, copy it.
> +    if (g_key_file_has_group (gnc_state_get_current (),
> register_state_section))
> +    {
> +        if (!gnc_split_reg_register_has_user_state (gsr))
> +             gnc_table_save_state (sr->table, default_state_section, NULL);
> +        // drop the register state
> +        gnc_state_drop_sections_for (register_state_section);
> +    }
> +    g_free (register_state_section);
>      LEAVE(" ");
>  }
> 
> @@ -721,37 +794,10 @@ gnc_split_reg_ld_destroy( GNCLedgerDisplay *ledger )
>  {
>      GNCSplitReg *gsr = gnc_ledger_display_get_user_data( ledger );
> 
> -    Account * account = gnc_ledger_display_leader(ledger);
> -    const GncGUID * guid = xaccAccountGetGUID(account);
> -    gchar guidstr[GUID_ENCODING_LENGTH+1];
> -    gchar *state_section;
> -    gchar *acct_fullname;
> -    guid_to_string_buff(guid, guidstr);
> -
> -    state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr,
> NULL);
> -
> -    if (g_strcmp0(guidstr, "00000000000000000000000000000000") == 0)
> -        acct_fullname = g_strdup(_("General Journal"));
> -    else
> -        acct_fullname = gnc_account_get_full_name(account);
> -
> -    if (gsr)
> -    {
> -        SplitRegister *reg;
> -
> -        reg = gnc_ledger_display_get_split_register (ledger);
> -
> -        if (reg && reg->table)
> -            gnc_table_save_state (reg->table, state_section,
> acct_fullname);
> -
> -        /*
> -         * Don't destroy the window here any more.  The register no longer
> -         * owns it.
> -         */
> -    }
> -    g_free (state_section);
> -    g_free (acct_fullname);
> -
> +   /*
> +    * Don't destroy the window here any more.  The register no longer
> +    * owns it.
> +    */
>      gnc_ledger_display_set_user_data (ledger, NULL);
>      g_object_unref (gsr);
>  }
> @@ -1952,6 +1998,44 @@ gnc_split_reg_set_sheet_focus (GNCSplitReg *gsr,
> gboolean has_focus)
>      gnucash_sheet_set_has_focus (sheet, has_focus);
>  }
> 
> +/* Save user state layout information to the register group that
> + * this register belongs to so it can be used as the default
> + * user layout
> + */
> +void
> +gnc_split_reg_save_register_layout_to_user_state (GNCSplitReg *gsr)
> +{
> +    SplitRegister *split_reg = gnc_ledger_display_get_split_register
> (gsr->ledger);
> +    const gchar *group = gnc_split_reg_get_register_state_group (gsr);
> +
> +    gnc_table_save_state (split_reg->table, group, NULL);
> +}
> +
> +/* Removes the user state layout information for the register group
> + * that this register belongs to and also resets the current layout to
> + * the built-in defaults
> + */
> +void
> +gnc_split_reg_reset_register_layout_and_clear_user_state (GNCSplitReg *gsr)
> +{
> +    GnucashRegister *reg = gsr->reg;
> +    const gchar *group = gnc_split_reg_get_register_state_group (gsr);
> +
> +    gnucash_register_reset_sheet_layout (reg);
> +    gnc_state_drop_sections_for (group);
> +}
> +
> +/* Checks to see if there is user state layout information for the
> + * register group that this register belongs to.
> + */
> +gboolean
> +gnc_split_reg_register_has_user_state (GNCSplitReg *gsr)
> +{
> +    GKeyFile *state_file = gnc_state_get_current ();
> +    const gchar *group = gnc_split_reg_get_register_state_group (gsr);
> +    return g_key_file_has_group (state_file, group);
> +}
> +
>  void
>  gnc_split_reg_balancing_entry(GNCSplitReg *gsr, Account *account,
>                                time64 statement_date, gnc_numeric
> balancing_amount)
> diff --git a/gnucash/gnome/gnc-split-reg.h b/gnucash/gnome/gnc-split-reg.h
> index 8c0f78c24..128e49ca6 100644
> --- a/gnucash/gnome/gnc-split-reg.h
> +++ b/gnucash/gnome/gnc-split-reg.h
> @@ -85,6 +85,8 @@ struct _GNCSplitReg
>      /** The actual gnucash register widget. **/
>      GnucashRegister *reg;
> 
> +    const gchar *page_state_name; /* Used for loading open state
> information */
> +
>      gint numRows;
> 
>      guint    sort_type;
> @@ -179,11 +181,13 @@ GType gnc_split_reg_get_type(void);
>   * @param parent        The containing window.
>   * @param numberOfLines The initial number of lines for the register.
>   * @param read_only      If the contained register should be setup
> read-only.
> + * @param group_name     The group name of the page state section for this
> page
>   **/
>  GtkWidget* gnc_split_reg_new( GNCLedgerDisplay *ld,
>                                GtkWindow *parent,
>                                gint numberOfLines,
> -                              gboolean read_only );
> +                              gboolean read_only,
> +                              const gchar *group_name );
> 
>  /**
>   * Returns the GnucashRegister in effect for this GNCSplitReg.
> @@ -250,6 +254,14 @@ void gnc_split_reg_jump_to_split_amount(GNCSplitReg
> *gsr, Split *split);
>  void gnc_split_reg_focus_on_sheet (GNCSplitReg *gsr);
>  void gnc_split_reg_set_sheet_focus (GNCSplitReg *gsr, gboolean has_focus);
> 
> +/**
> + * Save/Reset/Has functions used for the user default register layouts.
> + **/
> +void gnc_split_reg_save_register_layout_to_user_state (GNCSplitReg *gsr);
> +void gnc_split_reg_reset_register_layout_and_clear_user_state (GNCSplitReg
> *gsr);
> +gboolean gnc_split_reg_register_has_user_state (GNCSplitReg *gsr);
> +const gchar *gnc_split_reg_get_register_state_group (GNCSplitReg *gsr);
> +
>  /*
>   * Create a transaction entry with given amount and date. One account is
>   * specified, the other is undefined i.e. it defaults to orphan account.
> diff --git a/gnucash/ui/gnc-plugin-page-register-ui.xml
> b/gnucash/ui/gnc-plugin-page-register-ui.xml
> index 517afcbca..dfbbcffbb 100644
> --- a/gnucash/ui/gnc-plugin-page-register-ui.xml
> +++ b/gnucash/ui/gnc-plugin-page-register-ui.xml
> @@ -66,6 +66,13 @@
>          <menuitem name="ReportsAcctTransReport"
> action="ReportsAcctTransReportAction"/>
>        </placeholder>
>      </menu>
> +
> +    <menu name="Windows" action="WindowsAction">
> +      <placeholder name="WindowsLayoutPlaceholder">
> +        <menuitem name="WindowsSaveLayout"
>  action="WindowsSaveLayoutAction"/>
> +        <menuitem name="WindowsResetLayout"
> action="WindowsResetLayoutAction"/>
> +       </placeholder>
> +    </menu>
>    </menubar>
> 
>    <toolbar name="DefaultToolbar">
> 
> commit 74abd821b39736465e5a3dd792d6224c5812a7bc
> Author: Robert Fewell <14uBobIT at gmail.com>
> Date:   Sat May 2 14:32:47 2020 +0100
> 
>     Add enum SplitRegisterTypeGroup to group registers
> 
>     Add SplitRegisterTypeGroup to group registers that have the same layout
>     and it will also be used to get the default user state information for
>     register cell widths.
> 
> diff --git a/gnucash/register/ledger-core/split-register-layout.c
> b/gnucash/register/ledger-core/split-register-layout.c
> index ffdb46523..ae5973e85 100644
> --- a/gnucash/register/ledger-core/split-register-layout.c
> +++ b/gnucash/register/ledger-core/split-register-layout.c
> @@ -83,17 +83,9 @@ gnc_split_register_set_cells (SplitRegister* reg,
> TableLayout* layout)
>      CellBlock* curs;
>      CellBlock* curs_last;
> 
> -    switch (reg->type)
> +    switch (gnc_split_register_get_register_group (reg))
>      {
> -    case BANK_REGISTER:
> -    case CASH_REGISTER:
> -    case ASSET_REGISTER:
> -    case CREDIT_REGISTER:
> -    case LIABILITY_REGISTER:
> -    case INCOME_REGISTER:
> -    case EXPENSE_REGISTER:
> -    case EQUITY_REGISTER:
> -    case TRADING_REGISTER:
> +    case REG_TYPE_GROUP_CURRENCY:
>      {
>          curs = gnc_table_layout_get_cursor (layout,
>                                              CURSOR_SINGLE_LEDGER);
> @@ -191,8 +183,7 @@ gnc_split_register_set_cells (SplitRegister* reg,
> TableLayout* layout)
>      }
>      /* --------------------------------------------------------- */
> 
> -    case PAYABLE_REGISTER:
> -    case RECEIVABLE_REGISTER:
> +    case REG_TYPE_GROUP_APAR:
>      {
>          curs = gnc_table_layout_get_cursor (layout,
>                                              CURSOR_SINGLE_LEDGER);
> @@ -269,9 +260,7 @@ gnc_split_register_set_cells (SplitRegister* reg,
> TableLayout* layout)
>      }
> 
>      /* --------------------------------------------------------- */
> -    case INCOME_LEDGER:
> -    case GENERAL_JOURNAL:
> -    case SEARCH_LEDGER:
> +    case REG_TYPE_GROUP_JOURNAL:
>      {
>          curs = gnc_table_layout_get_cursor (layout,
>                                              CURSOR_SINGLE_LEDGER);
> @@ -391,8 +380,7 @@ gnc_split_register_set_cells (SplitRegister* reg,
> TableLayout* layout)
>      }
> 
>      /* --------------------------------------------------------- */
> -    case STOCK_REGISTER:
> -    case CURRENCY_REGISTER:
> +    case REG_TYPE_GROUP_STOCK:
>      {
>          curs = gnc_table_layout_get_cursor (layout,
>                                              CURSOR_SINGLE_LEDGER);
> @@ -476,7 +464,7 @@ gnc_split_register_set_cells (SplitRegister* reg,
> TableLayout* layout)
>      }
> 
>      /* --------------------------------------------------------- */
> -    case PORTFOLIO_LEDGER:
> +    case REG_TYPE_GROUP_PORTFOLIO:
>      {
>          curs = gnc_table_layout_get_cursor (layout,
>                                              CURSOR_SINGLE_LEDGER);
> @@ -559,7 +547,7 @@ gnc_split_register_set_cells (SplitRegister* reg,
> TableLayout* layout)
> 
>      /* --------------------------------------------------------- */
>      default:
> -        PERR ("unknown register type %d \n", reg->type);
> +        PERR ("unknown register group type for %d \n", reg->type);
>          break;
>      }
>  }
> diff --git a/gnucash/register/ledger-core/split-register.c
> b/gnucash/register/ledger-core/split-register.c
> index 03adb2a1e..912d88106 100644
> --- a/gnucash/register/ledger-core/split-register.c
> +++ b/gnucash/register/ledger-core/split-register.c
> @@ -3183,3 +3183,52 @@ gnc_split_register_set_read_only (SplitRegister*
> reg, gboolean read_only)
>  {
>      gnc_table_model_set_read_only (reg->table->model, read_only);
>  }
> +
> +SplitRegisterTypeGroup
> +gnc_split_register_get_register_group (SplitRegister *reg)
> +{
> +    switch (reg->type)
> +    {
> +        case BANK_REGISTER:
> +        case CASH_REGISTER:
> +        case ASSET_REGISTER:
> +        case CREDIT_REGISTER:
> +        case LIABILITY_REGISTER:
> +        case INCOME_REGISTER:
> +        case EXPENSE_REGISTER:
> +        case EQUITY_REGISTER:
> +        case TRADING_REGISTER:
> +        {
> +            return REG_TYPE_GROUP_CURRENCY;
> +            break;
> +        }
> +        case PAYABLE_REGISTER:
> +        case RECEIVABLE_REGISTER:
> +        {
> +            return REG_TYPE_GROUP_APAR;
> +            break;
> +        }
> +        case INCOME_LEDGER:
> +        case GENERAL_JOURNAL:
> +        case SEARCH_LEDGER:
> +        {
> +            return REG_TYPE_GROUP_JOURNAL;
> +            break;
> +        }
> +        case STOCK_REGISTER:
> +        case CURRENCY_REGISTER:
> +        {
> +            return REG_TYPE_GROUP_STOCK;
> +            break;
> +        }
> +        case PORTFOLIO_LEDGER:
> +        {
> +            return REG_TYPE_GROUP_PORTFOLIO;
> +            break;
> +        }
> +        default:
> +            return REG_TYPE_GROUP_UNKNOWN;
> +            PERR ("unknown register type %d \n", reg->type);
> +        break;
> +    }
> +}
> diff --git a/gnucash/register/ledger-core/split-register.h
> b/gnucash/register/ledger-core/split-register.h
> index 9192d8529..279e60a55 100644
> --- a/gnucash/register/ledger-core/split-register.h
> +++ b/gnucash/register/ledger-core/split-register.h
> @@ -167,6 +167,19 @@ typedef enum
>      NUM_REGISTER_TYPES
>  } SplitRegisterType;
> 
> +/** @brief Register group types
> + *
> + * used for grouping registers that have the same layout */
> +typedef enum
> +{
> +    REG_TYPE_GROUP_UNKNOWN,
> +    REG_TYPE_GROUP_CURRENCY,
> +    REG_TYPE_GROUP_APAR,
> +    REG_TYPE_GROUP_STOCK,
> +    REG_TYPE_GROUP_JOURNAL,
> +    REG_TYPE_GROUP_PORTFOLIO,
> +} SplitRegisterTypeGroup;
> +
>  /** Register styles */
>  typedef enum
>  {
> @@ -327,6 +340,12 @@ void gnc_split_register_set_auto_complete
> (SplitRegister* reg,
>   */
>  void gnc_split_register_set_read_only (SplitRegister* reg, gboolean
> read_only);
> 
> +/** Group registers for common layouts.
> + *  @param reg a ::SplitRegister
> + *
> + *  @return the ::SplitRegisterTypeGroup that groups registers together
> + */
> +SplitRegisterTypeGroup gnc_split_register_get_register_group
> (SplitRegister *reg);
> 
>  /** Set the template account for use in a template register.
>   *
> diff --git a/gnucash/register/register-gnome/gnucash-register.c
> b/gnucash/register/register-gnome/gnucash-register.c
> index 91a0b94b8..6253a63b1 100644
> --- a/gnucash/register/register-gnome/gnucash-register.c
> +++ b/gnucash/register/register-gnome/gnucash-register.c
> @@ -186,10 +186,6 @@ void
>  gnucash_register_reset_sheet_layout (GnucashRegister *reg)
>  {
>      GNCHeaderWidths widths;
> -    Table *table;
> -    GList *node;
> -    gchar *key;
> -    guint value;
>      GnucashSheet *sheet;
>      gint current_width;
> 
> 
> commit 4c8ebfe1710e28aad9ae9bb9351c802cd1065f9b
> Author: Robert Fewell <14uBobIT at gmail.com>
> Date:   Sat May 2 14:32:04 2020 +0100
> 
>     Change state_section parameter for gnc_table_save_state
> 
>     Change state_section to a const gchar* and update where used as required
> 
> diff --git a/gnucash/gnome/dialog-invoice.c b/gnucash/gnome/dialog-invoice.c
> index a71ca3837..8cfcda510 100644
> --- a/gnucash/gnome/dialog-invoice.c
> +++ b/gnucash/gnome/dialog-invoice.c
> @@ -518,19 +518,19 @@ gnc_invoice_window_help_cb (GtkWidget *widget,
> gpointer data)
>      gnc_gnome_help(HF_HELP, HL_USAGE_INVOICE);
>  }
> 
> -static gchar *
> +static const gchar *
>  gnc_invoice_window_get_state_group (InvoiceWindow *iw)
>  {
>      switch (gncOwnerGetType (gncOwnerGetEndOwner (&iw->owner)))
>      {
>          case GNC_OWNER_VENDOR:
> -            return g_strdup ("Vendor documents");
> +            return "Vendor documents";
>              break;
>          case GNC_OWNER_EMPLOYEE:
> -            return g_strdup ("Employee documents");
> +            return "Employee documents";
>              break;
>          default:
> -            return g_strdup ("Customer documents");
> +            return "Customer documents";
>              break;
>      }
>  }
> @@ -542,10 +542,9 @@ void
>  gnc_invoice_window_save_document_layout_to_user_state (InvoiceWindow *iw)
>  {
>      Table *table = gnc_entry_ledger_get_table (iw->ledger);
> -    gchar *group = gnc_invoice_window_get_state_group (iw);
> +    const gchar *group = gnc_invoice_window_get_state_group (iw);
> 
>      gnc_table_save_state (table, group, NULL);
> -    g_free (group);
>  }
> 
>  /* Removes the user state layout information for Invoice/Bill/Voucher
> @@ -555,11 +554,10 @@ void
>  gnc_invoice_window_reset_document_layout_and_clear_user_state
> (InvoiceWindow *iw)
>  {
>      GnucashRegister *reg = iw->reg;
> -    gchar *group = gnc_invoice_window_get_state_group (iw);
> +    const gchar *group = gnc_invoice_window_get_state_group (iw);
> 
>      gnucash_register_reset_sheet_layout (reg);
>      gnc_state_drop_sections_for (group);
> -    g_free (group);
>  }
> 
>  /* Checks to see if there is user state layout information for
> @@ -570,10 +568,8 @@ gboolean
>  gnc_invoice_window_document_has_user_state (InvoiceWindow *iw)
>  {
>      GKeyFile *state_file = gnc_state_get_current ();
> -    gchar *group = gnc_invoice_window_get_state_group (iw);
> -    gboolean has_group = g_key_file_has_group (state_file, group);
> -    g_free (group);
> -    return has_group;
> +    const gchar *group = gnc_invoice_window_get_state_group (iw);
> +    return g_key_file_has_group (state_file, group);
>  }
> 
>  void
> @@ -2351,7 +2347,6 @@ gnc_invoice_save_page (InvoiceWindow *iw,
>                         const gchar *group_name)
>  {
>      Table *table = gnc_entry_ledger_get_table (iw->ledger);
> -    gchar *group = g_strdup (group_name);
>      gchar guidstr[GUID_ENCODING_LENGTH+1];
>      guid_to_string_buff(&iw->invoice_guid, guidstr);
>      g_key_file_set_string(key_file, group_name, KEY_INVOICE_TYPE,
> @@ -2373,8 +2368,7 @@ gnc_invoice_save_page (InvoiceWindow *iw,
>          g_key_file_set_string(key_file, group_name, KEY_OWNER_GUID,
> guidstr);
>      }
>      // save the open table layout
> -    gnc_table_save_state (table, group, NULL);
> -    g_free (group);
> +    gnc_table_save_state (table, group_name, NULL);
>  }
> 
>  GtkWidget *
> @@ -2568,21 +2562,20 @@ gnc_invoice_create_page (InvoiceWindow *iw,
> gpointer page)
>      /* Create the register */
>      {
>          GtkWidget *regWidget, *frame, *window;
> -        gchar *default_group = gnc_invoice_window_get_state_group (iw);
> -        gchar *group;
> +        const gchar *default_group = gnc_invoice_window_get_state_group
> (iw);
> +        const gchar *group;
> 
>          // if this is from a page recreate, use those settings
>          if (iw->page_state_name)
> -            group = g_strdup (iw->page_state_name);
> +            group = iw->page_state_name;
>          else
> -            group = g_strdup (default_group);
> +            group = default_group;
> 
>          /* Watch the order of operations, here... */
>          regWidget = gnucash_register_new (gnc_entry_ledger_get_table
>                                            (entry_ledger), group);
>          gtk_widget_show(regWidget);
> -        g_free (default_group);
> -        g_free (group);
> +
>          frame = GTK_WIDGET (gtk_builder_get_object (builder,
> "ledger_frame"));
>          gtk_container_add (GTK_CONTAINER (frame), regWidget);
> 
> diff --git a/gnucash/gnome/gnc-split-reg.c b/gnucash/gnome/gnc-split-reg.c
> index d8218d6a2..7e2bbf4a8 100644
> --- a/gnucash/gnome/gnc-split-reg.c
> +++ b/gnucash/gnome/gnc-split-reg.c
> @@ -412,7 +412,7 @@ gsr_create_table( GNCSplitReg *gsr )
>      Account * account = gnc_ledger_display_leader(gsr->ledger);
>      const GncGUID * guid = xaccAccountGetGUID(account);
>      gchar guidstr[GUID_ENCODING_LENGTH+1];
> -    gchar *state_section = NULL;
> +    const gchar *state_section = NULL;
>      guid_to_string_buff(guid, guidstr);
>      state_section = g_strconcat (STATE_SECTION_REG_PREFIX, " ", guidstr,
> NULL);
> 
> @@ -427,7 +427,7 @@ gsr_create_table( GNCSplitReg *gsr )
>      sr = gnc_ledger_display_get_split_register( gsr->ledger );
>      register_widget = gnucash_register_new( sr->table, state_section );
>      gsr->reg = GNUCASH_REGISTER( register_widget );
> -    g_free (state_section);
> +
>      gtk_box_pack_start (GTK_BOX (gsr), GTK_WIDGET(gsr->reg), TRUE, TRUE,
> 0);
>      gnucash_sheet_set_window (gnucash_register_get_sheet (gsr->reg),
> gsr->window);
>      gtk_widget_show ( GTK_WIDGET(gsr->reg) );
> diff --git a/gnucash/register/register-core/table-allgui.h
> b/gnucash/register/register-core/table-allgui.h
> index 5c0396b20..53d1b7f1d 100644
> --- a/gnucash/register/register-core/table-allgui.h
> +++ b/gnucash/register/register-core/table-allgui.h
> @@ -201,7 +201,7 @@ Table *     gnc_table_new (TableLayout *layout,
>                             TableControl *control);
>  void        gnc_virtual_location_init (VirtualLocation *vloc);
> 
> -void        gnc_table_save_state (Table *table, gchar *state_section,
> gchar *account_fullname);
> +void        gnc_table_save_state (Table *table, const gchar
> *state_section, gchar *account_fullname);
>  void        gnc_table_destroy (Table *table);
> 
> 
> diff --git a/gnucash/register/register-gnome/gnucash-register.c
> b/gnucash/register/register-gnome/gnucash-register.c
> index bdd05936c..91a0b94b8 100644
> --- a/gnucash/register/register-gnome/gnucash-register.c
> +++ b/gnucash/register/register-gnome/gnucash-register.c
> @@ -486,7 +486,7 @@ gnucash_register_attach_popup (GnucashRegister *reg,
>   *  to pass NULL as second parameter. */
> 
>  static void
> -gnucash_register_configure (GnucashSheet *sheet, gchar * state_section)
> +gnucash_register_configure (GnucashSheet *sheet, const gchar *
> state_section)
>  {
>      GNCHeaderWidths widths;
>      Table *table;
> @@ -644,7 +644,7 @@ gnucash_register_create_widget (Table *table)
> 
> 
>  GtkWidget *
> -gnucash_register_new (Table *table, gchar *state_section)
> +gnucash_register_new (Table *table, const gchar *state_section)
>  {
>      GnucashRegister *reg;
>      GtkWidget *widget;
> diff --git a/gnucash/register/register-gnome/gnucash-register.h
> b/gnucash/register/register-gnome/gnucash-register.h
> index c512f149f..968dbd8cf 100644
> --- a/gnucash/register/register-gnome/gnucash-register.h
> +++ b/gnucash/register/register-gnome/gnucash-register.h
> @@ -54,7 +54,7 @@ GType gnucash_register_get_type (void);
>  void gnucash_register_add_cell_types (void);
> 
>  /** this already has scrollbars attached */
> -GtkWidget *gnucash_register_new (Table *table, gchar *state_section);
> +GtkWidget *gnucash_register_new (Table *table, const gchar *state_section);
> 
>  void gnucash_register_goto_virt_cell (GnucashRegister *reg,
>                                        VirtualCellLocation vcell_loc);
> diff --git a/gnucash/register/register-gnome/table-gnome.c
> b/gnucash/register/register-gnome/table-gnome.c
> index ee0145e74..73d2f2303 100644
> --- a/gnucash/register/register-gnome/table-gnome.c
> +++ b/gnucash/register/register-gnome/table-gnome.c
> @@ -68,7 +68,7 @@ static QofLogModule UNUSED_VAR log_module =
> GNC_MOD_REGISTER;
>  /** Implementation *****************************************************/
> 
>  void
> -gnc_table_save_state (Table *table, gchar * state_section, gchar *
> account_fullname)
> +gnc_table_save_state (Table *table, const gchar * state_section, gchar *
> account_fullname)
>  {
>      GnucashSheet *sheet;
>      GNCHeaderWidths widths;
> 
> commit 2f5225ad337486b510d8b72ad5e8ffcccb35b41c
> Author: Robert Fewell <14uBobIT at gmail.com>
> Date:   Sat May 2 14:30:21 2020 +0100
> 
>     Add option to save Layout for Business items
> 
>     Add two menu items under windows, one to save an existing layout for
>     Invoices, Bills and Vouchers to there respective default layouts so the
>     user set column widths will be used. The second menu item will reset the
> column widths to defaults and remove the default layout.
>     Open Business items will also save there column widths to the page
>     section so these can temporarily have different widths.
> 
> diff --git a/gnucash/gnome/dialog-invoice.c b/gnucash/gnome/dialog-invoice.c
> index 37ce031ca..a71ca3837 100644
> --- a/gnucash/gnome/dialog-invoice.c
> +++ b/gnucash/gnome/dialog-invoice.c
> @@ -71,6 +71,7 @@
>  #include "gnc-plugin-business.h"
>  #include "gnc-plugin-page-invoice.h"
>  #include "gnc-main-window.h"
> +#include "gnc-state.h"
> 
>  #include "dialog-transfer.h"
> 
> @@ -141,6 +142,7 @@ struct _invoice_window
> 
>      GtkWidget  * dialog;         /* Used by 'New Invoice Window' */
>      GncPluginPage *page;        /* Used by 'Edit Invoice' Page */
> +    const gchar * page_state_name;    /* Used for loading open state
> information */
> 
>      /* Summary Bar Widgets */
>      GtkWidget  * total_label;
> @@ -516,6 +518,64 @@ gnc_invoice_window_help_cb (GtkWidget *widget,
> gpointer data)
>      gnc_gnome_help(HF_HELP, HL_USAGE_INVOICE);
>  }
> 
> +static gchar *
> +gnc_invoice_window_get_state_group (InvoiceWindow *iw)
> +{
> +    switch (gncOwnerGetType (gncOwnerGetEndOwner (&iw->owner)))
> +    {
> +        case GNC_OWNER_VENDOR:
> +            return g_strdup ("Vendor documents");
> +            break;
> +        case GNC_OWNER_EMPLOYEE:
> +            return g_strdup ("Employee documents");
> +            break;
> +        default:
> +            return g_strdup ("Customer documents");
> +            break;
> +    }
> +}
> +
> +/* Save user state layout information for Invoice/Bill/Voucher
> + * documents so it can be used for the default user set layout
> + */
> +void
> +gnc_invoice_window_save_document_layout_to_user_state (InvoiceWindow *iw)
> +{
> +    Table *table = gnc_entry_ledger_get_table (iw->ledger);
> +    gchar *group = gnc_invoice_window_get_state_group (iw);
> +
> +    gnc_table_save_state (table, group, NULL);
> +    g_free (group);
> +}
> +
> +/* Removes the user state layout information for Invoice/Bill/Voucher
> + * documents and also resets the current layout to the built-in defaults
> + */
> +void
> +gnc_invoice_window_reset_document_layout_and_clear_user_state
> (InvoiceWindow *iw)
> +{
> +    GnucashRegister *reg = iw->reg;
> +    gchar *group = gnc_invoice_window_get_state_group (iw);
> +
> +    gnucash_register_reset_sheet_layout (reg);
> +    gnc_state_drop_sections_for (group);
> +    g_free (group);
> +}
> +
> +/* Checks to see if there is user state layout information for
> + * Invoice/Bill/Voucher documents so it can be used for the
> + * default user layout
> + */
> +gboolean
> +gnc_invoice_window_document_has_user_state (InvoiceWindow *iw)
> +{
> +    GKeyFile *state_file = gnc_state_get_current ();
> +    gchar *group = gnc_invoice_window_get_state_group (iw);
> +    gboolean has_group = g_key_file_has_group (state_file, group);
> +    g_free (group);
> +    return has_group;
> +}
> +
>  void
>  gnc_invoice_window_destroy_cb (GtkWidget *widget, gpointer data)
>  {
> @@ -2122,7 +2182,7 @@ find_handler (gpointer find_data, gpointer user_data)
>  static InvoiceWindow *
>  gnc_invoice_new_page (QofBook *bookp, InvoiceDialogType type,
>                        GncInvoice *invoice, const GncOwner *owner,
> -                      GncMainWindow *window)
> +                      GncMainWindow *window, const gchar *group_name)
>  {
>      InvoiceWindow *iw;
>      GncOwner *billto;
> @@ -2158,6 +2218,7 @@ gnc_invoice_new_page (QofBook *bookp,
> InvoiceDialogType type,
>      iw->invoice_guid = *gncInvoiceGetGUID (invoice);
>      iw->is_credit_note = gncInvoiceGetIsCreditNote (invoice);
>      iw->width = -1;
> +    iw->page_state_name = group_name;
> 
>      /* Save this for later */
>      gncOwnerCopy (gncOwnerGetEndOwner (owner), &(iw->owner));
> @@ -2270,7 +2331,7 @@ gnc_invoice_recreate_page (GncMainWindow *window,
>      g_free(tmp_string);
>      g_free(owner_type);
> 
> -    iw = gnc_invoice_new_page (book, type, invoice, &owner, window);
> +    iw = gnc_invoice_new_page (book, type, invoice, &owner, window,
> group_name);
>      return iw->page;
> 
>  give_up:
> @@ -2289,6 +2350,8 @@ gnc_invoice_save_page (InvoiceWindow *iw,
>                         GKeyFile *key_file,
>                         const gchar *group_name)
>  {
> +    Table *table = gnc_entry_ledger_get_table (iw->ledger);
> +    gchar *group = g_strdup (group_name);
>      gchar guidstr[GUID_ENCODING_LENGTH+1];
>      guid_to_string_buff(&iw->invoice_guid, guidstr);
>      g_key_file_set_string(key_file, group_name, KEY_INVOICE_TYPE,
> @@ -2309,6 +2372,9 @@ gnc_invoice_save_page (InvoiceWindow *iw,
>          guid_to_string_buff(gncOwnerGetGUID(&iw->owner), guidstr);
>          g_key_file_set_string(key_file, group_name, KEY_OWNER_GUID,
> guidstr);
>      }
> +    // save the open table layout
> +    gnc_table_save_state (table, group, NULL);
> +    g_free (group);
>  }
> 
>  GtkWidget *
> @@ -2502,12 +2568,21 @@ gnc_invoice_create_page (InvoiceWindow *iw,
> gpointer page)
>      /* Create the register */
>      {
>          GtkWidget *regWidget, *frame, *window;
> +        gchar *default_group = gnc_invoice_window_get_state_group (iw);
> +        gchar *group;
> +
> +        // if this is from a page recreate, use those settings
> +        if (iw->page_state_name)
> +            group = g_strdup (iw->page_state_name);
> +        else
> +            group = g_strdup (default_group);
> 
>          /* Watch the order of operations, here... */
>          regWidget = gnucash_register_new (gnc_entry_ledger_get_table
> -                                          (entry_ledger), NULL);
> +                                          (entry_ledger), group);
>          gtk_widget_show(regWidget);
> -
> +        g_free (default_group);
> +        g_free (group);
>          frame = GTK_WIDGET (gtk_builder_get_object (builder,
> "ledger_frame"));
>          gtk_container_add (GTK_CONTAINER (frame), regWidget);
> 
> @@ -2779,7 +2854,7 @@ gnc_ui_invoice_edit (GtkWindow *parent, GncInvoice
> *invoice)
> 
>      iw = gnc_invoice_new_page (gncInvoiceGetBook(invoice), type,
>                                 invoice, gncInvoiceGetOwner (invoice),
> -                               GNC_MAIN_WINDOW(gnc_ui_get_main_window
> (GTK_WIDGET (parent))));
> +                               GNC_MAIN_WINDOW(gnc_ui_get_main_window
> (GTK_WIDGET (parent))), NULL);
> 
>      return iw;
>  }
> diff --git a/gnucash/gnome/dialog-invoice.h b/gnucash/gnome/dialog-invoice.h
> index a121b55c6..073268d40 100644
> --- a/gnucash/gnome/dialog-invoice.h
> +++ b/gnucash/gnome/dialog-invoice.h
> @@ -110,6 +110,10 @@ void gnc_invoice_window_duplicateCB (GtkWidget
> *widget, gpointer data);
>  void gnc_invoice_window_payment_cb (GtkWindow *parent, gpointer data);
>  void gnc_invoice_window_report_owner_cb (GtkWindow *parent, gpointer data);
> 
> +void gnc_invoice_window_save_document_layout_to_user_state (InvoiceWindow
> *iw);
> +void gnc_invoice_window_reset_document_layout_and_clear_user_state
> (InvoiceWindow *iw);
> +gboolean gnc_invoice_window_document_has_user_state (InvoiceWindow *iw);
> +
>  void gnc_invoice_window_entryUpCB (GtkWidget *widget, gpointer data);
>  void gnc_invoice_window_entryDownCB (GtkWidget *widget, gpointer data);
> 
> diff --git a/gnucash/gnome/gnc-plugin-page-invoice.c
> b/gnucash/gnome/gnc-plugin-page-invoice.c
> index ead2a8236..fb74f75a2 100644
> --- a/gnucash/gnome/gnc-plugin-page-invoice.c
> +++ b/gnucash/gnome/gnc-plugin-page-invoice.c
> @@ -83,6 +83,8 @@ static void gnc_plugin_page_invoice_cmd_delete (GtkAction
> *action, GncPluginPage
>  static void gnc_plugin_page_invoice_cmd_blank (GtkAction *action,
> GncPluginPageInvoice *plugin_page);
>  static void gnc_plugin_page_invoice_cmd_duplicateEntry (GtkAction *action,
> GncPluginPageInvoice *plugin_page);
>  static void gnc_plugin_page_invoice_cmd_pay_invoice (GtkAction *action,
> GncPluginPageInvoice *plugin_page);
> +static void gnc_plugin_page_invoice_cmd_save_layout (GtkAction *action,
> GncPluginPageInvoice *plugin_page);
> +static void gnc_plugin_page_invoice_cmd_reset_layout (GtkAction *action,
> GncPluginPageInvoice *plugin_page);
>  static void gnc_plugin_page_invoice_cmd_company_report (GtkAction *action,
> GncPluginPageInvoice *plugin_page);
> 
>  static void gnc_plugin_page_redraw_help_cb( GnucashRegister *gsr,
> GncPluginPageInvoice *invoice_page );
> @@ -211,6 +213,18 @@ static GtkActionEntry gnc_plugin_page_invoice_actions
> [] =
>          "Open a company report window for the owner of this invoice",
>          G_CALLBACK (gnc_plugin_page_invoice_cmd_company_report)
>      },
> +
> +    /* Windows menu */
> +    {
> +        "WindowsSaveLayoutAction", NULL, "_Use as Default Layout for
> Customer Documents", NULL,
> +        "Use the current layout as default for all customer invoices and
> credit notes",
> +        G_CALLBACK (gnc_plugin_page_invoice_cmd_save_layout)
> +    },
> +    {
> +        "WindowsResetLayoutAction", NULL, "_Reset Default Layout for
> Customer Documents", NULL,
> +        "Reset default layout for all customer invoices and credit notes
> back to built-in defaults and update the current page accordingly",
> +        G_CALLBACK (gnc_plugin_page_invoice_cmd_reset_layout)
> +    },
>  };
>  static guint gnc_plugin_page_invoice_n_actions = G_N_ELEMENTS
> (gnc_plugin_page_invoice_actions);
> 
> @@ -274,6 +288,13 @@ static action_toolbar_labels invoice_action_labels[] =
>      {NULL, NULL},
>  };
> 
> +static action_toolbar_labels invoice_action_layout_labels[] =
> +{
> +    {"WindowsSaveLayoutAction", N_("_Use as Default Layout for Customer
> Documents")},
> +    {"WindowsResetLayoutAction", N_("_Reset Default Layout for Customer
> Documents")},
> +    {NULL, NULL},
> +};
> +
>  static action_toolbar_labels bill_action_labels[] =
>  {
>      {"FilePrintAction", N_("_Print Bill")},
> @@ -286,6 +307,13 @@ static action_toolbar_labels bill_action_labels[] =
>      {NULL, NULL},
>  };
> 
> +static action_toolbar_labels bill_action_layout_labels[] =
> +{
> +    {"WindowsSaveLayoutAction", N_("_Use as Default Layout for Vendor
> Documents")},
> +    {"WindowsResetLayoutAction", N_("_Reset Default Layout for Vendor
> Documents")},
> +    {NULL, NULL},
> +};
> +
>  static action_toolbar_labels voucher_action_labels[] =
>  {
>      {"FilePrintAction", N_("_Print Voucher")},
> @@ -298,6 +326,13 @@ static action_toolbar_labels voucher_action_labels[] =
>      {NULL, NULL},
>  };
> 
> +static action_toolbar_labels voucher_action_layout_labels[] =
> +{
> +    {"WindowsSaveLayoutAction", N_("_Use as Default Layout for Employee
> Documents")},
> +    {"WindowsResetLayoutAction", N_("_Reset Default Layout for Employee
> Documents")},
> +    {NULL, NULL},
> +};
> +
>  static action_toolbar_labels creditnote_action_labels[] =
>  {
>      {"FilePrintAction", N_("_Print Credit Note")},
> @@ -324,6 +359,12 @@ static action_toolbar_labels invoice_action_tooltips[]
> = {
>      {NULL, NULL},
>  };
> 
> +static action_toolbar_labels invoice_action_layout_tooltips[] = {
> +    {"WindowsSaveLayoutAction", N_("Use the current layout as default for
> all customer invoices and credit notes")},
> +    {"WindowsResetLayoutAction", N_("Reset default layout for all customer
> invoices and credit notes back to built-in defaults and update the current
> page accordingly")},
> +    {NULL, NULL},
> +};
> +
>  static action_toolbar_labels bill_action_tooltips[] = {
>      {"FilePrintAction", N_("Make a printable bill")},
>      {"EditEditInvoiceAction", N_("Edit this bill")},
> @@ -337,6 +378,12 @@ static action_toolbar_labels bill_action_tooltips[] = {
> {NULL, NULL},
>  };
> 
> +static action_toolbar_labels bill_action_layout_tooltips[] = {
> +    {"WindowsSaveLayoutAction", N_("Use the current layout as default for
> all vendor bills and credit notes")},
> +    {"WindowsResetLayoutAction", N_("Reset default layout for all vendor
> bills and credit notes back to built-in defaults and update the current
> page accordingly")},
> +    {NULL, NULL},
> +};
> +
>  static action_toolbar_labels voucher_action_tooltips[] = {
>      {"FilePrintAction", N_("Make a printable voucher")},
>      {"EditEditInvoiceAction", N_("Edit this voucher")},
> @@ -350,6 +397,12 @@ static action_toolbar_labels voucher_action_tooltips[]
> = {
>      {NULL, NULL},
>  };
> 
> +static action_toolbar_labels voucher_action_layout_tooltips[] = {
> +    {"WindowsSaveLayoutAction", N_("Use the current layout as default for
> all employee vouchers and credit notes")},
> +    {"WindowsResetLayoutAction", N_("Reset default layout for all employee
> vouchers and credit notes back to built-in defaults and update the current
> page accordingly")},
> +    {NULL, NULL},
> +};
> +
>  static action_toolbar_labels creditnote_action_tooltips[] = {
>      {"FilePrintAction", N_("Make a printable credit note")},
>      {"EditEditInvoiceAction", N_("Edit this credit note")},
> @@ -497,6 +550,39 @@ gnc_plugin_page_invoice_finalize (GObject *object)
>      LEAVE(" ");
>  }
> 
> +static void
> +gnc_plugin_page_invoice_action_update (GtkActionGroup *action_group,
> +                                       action_toolbar_labels *action_list,
> +                                       void (*gtkfunc)(gpointer, gpointer))
> +{
> +    GtkAction *action;
> +    gint i;
> +
> +    for (i = 0; action_list[i].action_name; i++)
> +    {
> +        /* update the action */
> +        action = gtk_action_group_get_action (action_group,
> +                                              action_list[i].action_name);
> +        gtkfunc (action, _(action_list[i].label));
> +    }
> +}
> +
> +static void
> +gnc_plugin_page_update_reset_layout_action (GncPluginPage *page)
> +{
> +    GncPluginPageInvoicePrivate *priv;
> +    GtkAction *layout_action;
> +    gboolean has_default = FALSE;
> +
> +    g_return_if_fail (GNC_IS_PLUGIN_PAGE_INVOICE(page));
> +
> +    priv = GNC_PLUGIN_PAGE_INVOICE_GET_PRIVATE(page);
> +
> +    layout_action = gnc_plugin_page_get_action (page,
> "WindowsResetLayoutAction");
> +    if (gnc_invoice_window_document_has_user_state (priv->iw))
> +        has_default = TRUE;
> +    gtk_action_set_sensitive (layout_action, has_default);
> +}
> 
>  void
>  gnc_plugin_page_invoice_update_menus (GncPluginPage *page, gboolean
> is_posted, gboolean can_unpost)
> @@ -504,12 +590,16 @@ gnc_plugin_page_invoice_update_menus (GncPluginPage
> *page, gboolean is_posted, g
>      GtkActionGroup *action_group;
>      GncPluginPageInvoicePrivate *priv;
>      GncInvoiceType invoice_type;
> -    GtkAction *action;
>      gint i, j;
>      action_toolbar_labels *label_list;
>      action_toolbar_labels *tooltip_list;
> +    action_toolbar_labels *label_layout_list;
> +    action_toolbar_labels *tooltip_layout_list;
> 
>      gboolean is_readonly = qof_book_is_readonly(gnc_get_current_book());
> +
> +    g_return_if_fail (GNC_IS_PLUGIN_PAGE_INVOICE(page));
> +
>      priv = GNC_PLUGIN_PAGE_INVOICE_GET_PRIVATE(page);
>      invoice_type = gnc_invoice_get_type_from_window(priv->iw);
> 
> @@ -537,7 +627,27 @@ gnc_plugin_page_invoice_update_menus (GncPluginPage
> *page, gboolean is_posted, g
>              tooltip_list = invoice_action_tooltips;
>      }
> 
> -    g_return_if_fail(GNC_IS_PLUGIN_PAGE_INVOICE(page));
> +    // layout actions
> +    switch (invoice_type) {
> +        case GNC_INVOICE_CUST_INVOICE:
> +        case GNC_INVOICE_CUST_CREDIT_NOTE:
> +            label_layout_list = invoice_action_layout_labels;
> +            tooltip_layout_list = invoice_action_layout_tooltips;
> +            break;
> +        case GNC_INVOICE_VEND_INVOICE:
> +        case GNC_INVOICE_VEND_CREDIT_NOTE:
> +            label_layout_list = bill_action_layout_labels;
> +            tooltip_layout_list = bill_action_layout_tooltips;
> +            break;
> +        case GNC_INVOICE_EMPL_INVOICE:
> +        case GNC_INVOICE_EMPL_CREDIT_NOTE:
> +            label_layout_list = voucher_action_layout_labels;
> +            tooltip_layout_list = voucher_action_layout_tooltips;
> +            break;
> +        default: // catches GNC_INVOICE_UNDEFINED, use invoice by default
> +            label_layout_list = invoice_action_layout_labels;
> +            tooltip_layout_list = invoice_action_layout_tooltips;
> +    }
> 
>      if (is_readonly)
>      {
> @@ -556,21 +666,18 @@ gnc_plugin_page_invoice_update_menus (GncPluginPage
> *page, gboolean is_posted, g
>      gnc_plugin_update_actions (action_group,
> invoice_book_readwrite_actions,
>                                 "sensitive", !is_readonly);
> 
> -    for (i = 0; label_list[i].action_name; i++)
> -    {
> -        /* update the action labels */
> -        action = gtk_action_group_get_action(action_group,
> -                                             label_list[i].action_name);
> -        gtk_action_set_label(action, _(label_list[i].label));
> -    }
> +    /* update the action labels */
> +    gnc_plugin_page_invoice_action_update (action_group, label_list,
> (void*)gtk_action_set_label);
> +    /* update the action tooltips */
> +    gnc_plugin_page_invoice_action_update (action_group, tooltip_list,
> (void*)gtk_action_set_tooltip);
> 
> -    for (i = 0; tooltip_list[i].action_name; i++)
> -    {
> -        /* update the action tooltips */
> -        action = gtk_action_group_get_action(action_group,
> -                                             tooltip_list[i].action_name);
> -        gtk_action_set_tooltip(action, _(tooltip_list[i].label));
> -    }
> +    // if there is no default layout do not enable reset action
> +    gnc_plugin_page_update_reset_layout_action (page);
> +
> +    /* update the layout action labels */
> +    gnc_plugin_page_invoice_action_update (action_group,
> label_layout_list, (void*)gtk_action_set_label);
> +    /* update the layout action tooltips */
> +    gnc_plugin_page_invoice_action_update (action_group,
> tooltip_layout_list, (void*)gtk_action_set_tooltip);
>  }
> 
> 
> @@ -589,6 +696,9 @@ gnc_plugin_page_invoice_focus_widget (GncPluginPage
> *invoice_plugin_page)
>          GtkWidget *notes = gnc_invoice_get_notes(priv->iw);
>          GnucashSheet *sheet;
> 
> +        // if there is no default layout do not enable reset action
> +        gnc_plugin_page_update_reset_layout_action (invoice_plugin_page);
> +
>          if (!GNUCASH_IS_REGISTER(regWidget))
>              return FALSE;
> 
> @@ -1117,6 +1227,48 @@ gnc_plugin_page_invoice_cmd_pay_invoice (GtkAction
> *action,
>      LEAVE(" ");
>  }
> 
> +static void
> +gnc_plugin_page_invoice_cmd_save_layout (GtkAction *action,
> +        GncPluginPageInvoice *plugin_page)
> +{
> +    GncPluginPageInvoicePrivate *priv;
> +    GtkWindow *parent;
> +    GtkAction *layout_action;
> +
> +    g_return_if_fail (GNC_IS_PLUGIN_PAGE_INVOICE(plugin_page));
> +
> +    ENTER("(action %p, plugin_page %p)", action, plugin_page);
> +    priv = GNC_PLUGIN_PAGE_INVOICE_GET_PRIVATE(plugin_page);
> +    gnc_invoice_window_save_document_layout_to_user_state (priv->iw);
> +
> +    layout_action = gnc_plugin_page_get_action
> (GNC_PLUGIN_PAGE(plugin_page),
> +
> "WindowsResetLayoutAction");
> +    gtk_action_set_sensitive (layout_action, TRUE);
> +
> +    LEAVE(" ");
> +}
> +
> +static void
> +gnc_plugin_page_invoice_cmd_reset_layout (GtkAction *action,
> +        GncPluginPageInvoice *plugin_page)
> +{
> +    GncPluginPageInvoicePrivate *priv;
> +    GtkWindow *parent;
> +    GtkAction *layout_action;
> +
> +    g_return_if_fail (GNC_IS_PLUGIN_PAGE_INVOICE(plugin_page));
> +
> +    ENTER("(action %p, plugin_page %p)", action, plugin_page);
> +    priv = GNC_PLUGIN_PAGE_INVOICE_GET_PRIVATE(plugin_page);
> +    gnc_invoice_window_reset_document_layout_and_clear_user_state
> (priv->iw);
> +
> +    layout_action = gnc_plugin_page_get_action
> (GNC_PLUGIN_PAGE(plugin_page),
> +
> "WindowsResetLayoutAction");
> +    gtk_action_set_sensitive (layout_action, FALSE);
> +
> +    LEAVE(" ");
> +}
> +
>  static void
>  gnc_plugin_page_invoice_cmd_company_report (GtkAction *action,
>          GncPluginPageInvoice *plugin_page)
> diff --git a/gnucash/register/register-gnome/gnucash-register.c
> b/gnucash/register/register-gnome/gnucash-register.c
> index 3cafe0870..bdd05936c 100644
> --- a/gnucash/register/register-gnome/gnucash-register.c
> +++ b/gnucash/register/register-gnome/gnucash-register.c
> @@ -182,6 +182,37 @@ gnucash_register_refresh_from_prefs (GnucashRegister
> *reg)
>      gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
>  }
> 
> +void
> +gnucash_register_reset_sheet_layout (GnucashRegister *reg)
> +{
> +    GNCHeaderWidths widths;
> +    Table *table;
> +    GList *node;
> +    gchar *key;
> +    guint value;
> +    GnucashSheet *sheet;
> +    gint current_width;
> +
> +    g_return_if_fail (reg != NULL);
> +
> +    sheet = GNUCASH_SHEET(reg->sheet);
> +
> +    g_return_if_fail (sheet != NULL);
> +    g_return_if_fail (GNUCASH_IS_SHEET (sheet));
> +
> +    current_width = sheet->window_width - 1;
> +
> +    widths = gnc_header_widths_new ();
> +    gnucash_sheet_set_header_widths (sheet, widths);
> +
> +    gnucash_sheet_styles_set_dimensions (sheet, current_width);
> +
> +    gnucash_sheet_compile_styles (sheet);
> +    gnucash_sheet_table_load (sheet, TRUE);
> +    gnucash_sheet_cursor_set_from_table (sheet, TRUE);
> +    gnucash_sheet_redraw_all (sheet);
> +    gnc_header_widths_destroy (widths);
> +}
> 
>  void
>  gnucash_register_goto_virt_cell (GnucashRegister *reg,
> diff --git a/gnucash/register/register-gnome/gnucash-register.h
> b/gnucash/register/register-gnome/gnucash-register.h
> index 8fb4f7c1f..c512f149f 100644
> --- a/gnucash/register/register-gnome/gnucash-register.h
> +++ b/gnucash/register/register-gnome/gnucash-register.h
> @@ -83,5 +83,6 @@ void gnucash_register_set_moved_cb (GnucashRegister *reg,
>                                      GFunc cb, gpointer cb_data);
> 
>  GnucashSheet *gnucash_register_get_sheet (GnucashRegister *reg);
> +void gnucash_register_reset_sheet_layout (GnucashRegister *reg);
>  /** @} */
>  #endif
> diff --git a/gnucash/ui/gnc-plugin-page-invoice-ui.xml
> b/gnucash/ui/gnc-plugin-page-invoice-ui.xml
> index 8845d3205..8a823271e 100644
> --- a/gnucash/ui/gnc-plugin-page-invoice-ui.xml
> +++ b/gnucash/ui/gnc-plugin-page-invoice-ui.xml
> @@ -49,6 +49,14 @@
>          <menuitem name="ReportsCompanyReport"
>  action="ReportsCompanyReportAction"/>
>        </placeholder>
>      </menu>
> +
> +    <menu name="Windows" action="WindowsAction">
> +      <placeholder name="WindowsLayoutPlaceholder">
> +        <menuitem name="WindowsSaveLayout"
>  action="WindowsSaveLayoutAction"/>
> +        <menuitem name="WindowsResetLayout"
> action="WindowsResetLayoutAction"/>
> +       </placeholder>
> +    </menu>
> +
>    </menubar>
> 
>    <toolbar name="DefaultToolbar">
> diff --git a/gnucash/ui/gnc-windows-menu-ui.xml
> b/gnucash/ui/gnc-windows-menu-ui.xml
> index a0aa24f8a..59d1c507f 100644
> --- a/gnucash/ui/gnc-windows-menu-ui.xml
> +++ b/gnucash/ui/gnc-windows-menu-ui.xml
> @@ -5,6 +5,8 @@
>      <menu name="Windows" action="WindowsAction">
>        <menuitem name="WindowNew"      action="WindowNewAction"/>
>        <menuitem name="WindowMovePage" action="WindowMovePageAction"/>
> +      <separator name="ViewSep5"/>
> +      <placeholder name="WindowsLayoutPlaceholder"/>
>        <separator name="ViewSep4"/>
>        <menuitem name="Window0"        action="Window0Action"/>
>        <menuitem name="Window1"        action="Window1Action"/>
> @@ -20,4 +22,4 @@
>      </menu>
> 
>    </menubar>
> -</ui>
> \ No newline at end of file
> +</ui>
> 
> commit b622518fcef9870eff07c4a642b326c9ec9d4c73
> Author: Robert Fewell <14uBobIT at gmail.com>
> Date:   Mon Mar 2 14:49:14 2020 +0000
> 
>     Test for a valid register state comment before trying
>      to add it
> 
> diff --git a/gnucash/register/register-gnome/table-gnome.c
> b/gnucash/register/register-gnome/table-gnome.c
> index 53e53428b..ee0145e74 100644
> --- a/gnucash/register/register-gnome/table-gnome.c
> +++ b/gnucash/register/register-gnome/table-gnome.c
> @@ -108,10 +108,12 @@ gnc_table_save_state (Table *table, gchar *
> state_section, gchar * account_fulln
>              g_key_file_remove_key (state_file, state_section, key, NULL);
>          g_free (key);
>      }
> -    key = g_strdup_printf ("Register state for \"%s\"", account_fullname);
> -    g_key_file_set_comment (state_file, state_section, NULL, key, NULL);
> -    g_free (key);
> -
> +    if (account_fullname)
> +    {
> +        key = g_strdup_printf ("Register state for \"%s\"",
> account_fullname);
> +        g_key_file_set_comment (state_file, state_section, NULL, key,
> NULL);
> +        g_free (key);
> +    }
>      gnc_header_widths_destroy (widths);
>  }
> 
> 
> 
> 
> Summary of changes:
>  gnucash/gnome-utils/gnc-tree-view-account.c        |   4 -
>  gnucash/gnome/dialog-invoice.c                     |  76 ++++++-
>  gnucash/gnome/dialog-invoice.h                     |   4 +
>  gnucash/gnome/gnc-plugin-page-invoice.c            | 184 +++++++++++++--
>  gnucash/gnome/gnc-plugin-page-register.c           | 247
> ++++++++++++---------
>  gnucash/gnome/gnc-split-reg.c                      | 240
> +++++++++++++++++---
>  gnucash/gnome/gnc-split-reg.h                      |  17 +-
>  .../register/ledger-core/split-register-layout.c   |  26 +--
>  gnucash/register/ledger-core/split-register.c      |  49 ++++
>  gnucash/register/ledger-core/split-register.h      |  19 ++
>  gnucash/register/register-core/table-allgui.h      |   2 +-
>  gnucash/register/register-gnome/gnucash-register.c |  31 ++-
>  gnucash/register/register-gnome/gnucash-register.h |   3 +-
>  gnucash/register/register-gnome/table-gnome.c      |   6 +-
>  gnucash/ui/gnc-plugin-page-invoice-ui.xml          |   8 +
>  gnucash/ui/gnc-plugin-page-register-ui.xml         |   7 +
>  gnucash/ui/gnc-windows-menu-ui.xml                 |   4 +-
>  17 files changed, 731 insertions(+), 196 deletions(-)
> 
> _______________________________________________
> gnucash-changes mailing list
> gnucash-changes at gnucash.org
> https://lists.gnucash.org/mailman/listinfo/gnucash-changes
> _______________________________________________
> gnucash-devel mailing list
> gnucash-devel at gnucash.org
> https://lists.gnucash.org/mailman/listinfo/gnucash-devel






More information about the gnucash-devel mailing list