gnucash stable: Bug 799706 - Rename Namespace

Robert Fewell bobit at code.gnucash.org
Thu Jan 8 05:38:33 EST 2026


Updated	 via  https://github.com/Gnucash/gnucash/commit/b5185e18 (commit)
	from  https://github.com/Gnucash/gnucash/commit/966d42b8 (commit)



commit b5185e1823870559e7ef114609d5a29827b352e1
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Wed Dec 31 15:01:33 2025 +0000

    Bug 799706 - Rename Namespace
    
    Add a rename namespace button to the Security editor that is enabled by
    the selection of a namespace row in the tree view.

diff --git a/gnucash/gnome-utils/gnc-tree-view-commodity.c b/gnucash/gnome-utils/gnc-tree-view-commodity.c
index b3c6f78010..9fd3bb4a93 100644
--- a/gnucash/gnome-utils/gnc-tree-view-commodity.c
+++ b/gnucash/gnome-utils/gnc-tree-view-commodity.c
@@ -626,7 +626,7 @@ gnc_tree_view_commodity_get_selected_commodity (GncTreeViewCommodity *view)
     if (!gtk_tree_selection_get_selected (selection, &s_model, &s_iter))
     {
         LEAVE("no commodity, get_selected failed");
-        return FALSE;
+        return NULL;
     }
 
     gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
@@ -644,6 +644,46 @@ gnc_tree_view_commodity_get_selected_commodity (GncTreeViewCommodity *view)
     return commodity;
 }
 
+/*
+ * Retrieve the selected namespace from a commodity tree view. The
+ * commodity tree must be in single selection mode.
+ */
+gnc_commodity_namespace *
+gnc_tree_view_commodity_get_selected_namespace (GncTreeViewCommodity *view)
+{
+    GtkTreeSelection *selection;
+    GtkTreeModel *model, *f_model, *s_model;
+    GtkTreeIter iter, f_iter, s_iter;
+    gnc_commodity_namespace *ns;
+
+    g_return_val_if_fail (GNC_IS_TREE_VIEW_COMMODITY(view), NULL);
+
+    ENTER("view %p", view);
+
+    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
+    if (!gtk_tree_selection_get_selected (selection, &s_model, &s_iter))
+    {
+        LEAVE("no namespace, get_selected failed");
+        return NULL;
+    }
+
+    gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
+                                                    &f_iter, &s_iter);
+
+    f_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT(s_model));
+    gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
+                                                      &iter, &f_iter);
+
+    model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER(f_model));
+
+    ns = gnc_tree_model_commodity_get_namespace (GNC_TREE_MODEL_COMMODITY(model),
+                                                 &iter);
+
+    LEAVE("namespace %p (%s)", ns,
+          ns ? gnc_commodity_namespace_get_name(ns) : "");
+    return ns;
+}
+
 /*
  * Select the commodity in the commodity tree view.
  */
diff --git a/gnucash/gnome-utils/gnc-tree-view-commodity.h b/gnucash/gnome-utils/gnc-tree-view-commodity.h
index 26643abbdd..8da07b2926 100644
--- a/gnucash/gnome-utils/gnc-tree-view-commodity.h
+++ b/gnucash/gnome-utils/gnc-tree-view-commodity.h
@@ -182,6 +182,19 @@ gnc_commodity * gnc_tree_view_commodity_get_cursor_commodity (GncTreeViewCommodi
 gnc_commodity * gnc_tree_view_commodity_get_selected_commodity  (GncTreeViewCommodity *view);
 
 
+/** This function returns the namespace associated with the selected
+ *  item in the commodity tree view.
+ *
+ *  @note It only makes sense to call this function when the commodity
+ *  tree is set to select a single item.
+ *
+ *  @param view A pointer to an commodity tree view.
+ *
+ *  @return The selected namespace, or NULL if no namespace was selected.
+ */
+gnc_commodity_namespace * gnc_tree_view_commodity_get_selected_namespace (GncTreeViewCommodity *view);
+
+
 /** Select the commodity in the associated commodity tree view.
  *
  *  @param view A pointer to an commodity tree view.
diff --git a/gnucash/gnome/dialog-commodities.cpp b/gnucash/gnome/dialog-commodities.cpp
index 99657b35f3..3f00b56078 100644
--- a/gnucash/gnome/dialog-commodities.cpp
+++ b/gnucash/gnome/dialog-commodities.cpp
@@ -28,6 +28,7 @@
 #include <glib/gi18n.h>
 
 #include "dialog-commodity.h"
+#include "gnc-commodity.hpp"
 #include "dialog-utils.h"
 #include "gnc-commodity.h"
 #include "gnc-component-manager.h"
@@ -62,6 +63,7 @@ typedef struct
     GtkWidget * edit_button;
     GtkWidget * remove_button;
     gboolean    show_currencies;
+    GtkWidget * rename_namespace_button;
 
     gboolean is_new;
 } CommoditiesDialog;
@@ -74,6 +76,9 @@ void gnc_commodities_dialog_add_clicked (GtkWidget *widget, gpointer data);
 void gnc_commodities_dialog_edit_clicked (GtkWidget *widget, gpointer data);
 void gnc_commodities_dialog_remove_clicked (GtkWidget *widget, gpointer data);
 void gnc_commodities_dialog_close_clicked (GtkWidget *widget, gpointer data);
+
+void gnc_commodities_dialog_rename_namespace_clicked (GtkWidget *widget, gpointer data);
+
 void gnc_commodities_show_currencies_toggled (GtkToggleButton *toggle, CommoditiesDialog *cd);
 }
 
@@ -270,6 +275,65 @@ gnc_commodities_dialog_close_clicked (GtkWidget *widget, gpointer data)
     gnc_close_gui_component_by_data (DIALOG_COMMODITIES_CM_CLASS, cd);
 }
 
+void
+gnc_commodities_dialog_rename_namespace_clicked (GtkWidget *widget, gpointer data)
+{
+    auto cd = static_cast<CommoditiesDialog*>(data);
+    auto ns = gnc_tree_view_commodity_get_selected_namespace (cd->commodity_tree);
+
+    if (!ns)
+        return;
+
+    const auto ns_name = gnc_commodity_namespace_get_name (ns);
+
+    GtkBuilder *builder = gtk_builder_new();
+    gnc_builder_add_from_file (builder, "dialog-commodities.glade", "rename_namespace_dialog");
+
+    GtkDialog *dialog = GTK_DIALOG(gtk_builder_get_object (builder, "rename_namespace_dialog"));
+    GtkWidget *entry = GTK_WIDGET(gtk_builder_get_object (builder, "rename_entry"));
+    GtkWidget *label = GTK_WIDGET(gtk_builder_get_object (builder, "rename_label"));
+
+    // Set the name for this dialog so it can be easily manipulated with css
+    gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-rename-namespace");
+    gnc_widget_style_context_add_class (GTK_WIDGET(dialog), "gnc-class-securities");
+
+    // Entry
+    gtk_entry_set_text (GTK_ENTRY(entry), ns_name);
+    gtk_editable_select_region (GTK_EDITABLE(entry), 0, -1);
+    gtk_entry_set_activates_default (GTK_ENTRY(entry), true);
+
+    // Set our parent
+    gtk_window_set_transient_for (GTK_WINDOW(dialog),
+                                  GTK_WINDOW(gtk_widget_get_toplevel(widget)));
+
+    gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, nullptr);
+    g_object_unref (G_OBJECT(builder));
+
+    gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+
+    bool rename_ok = false;
+    while (!rename_ok && gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
+    {
+        const auto commodity_table = gnc_get_current_commodities ();
+        const auto new_ns_name = gtk_entry_get_text (GTK_ENTRY(entry));
+
+        if (new_ns_name && *new_ns_name)
+        {
+            rename_ok = gnc_commodity_table_rename_namespace (commodity_table,
+                                                              ns_name,
+                                                              new_ns_name);
+            if (rename_ok)
+                qof_book_mark_session_dirty (gnc_get_current_book());
+            else
+                gtk_label_set_text (GTK_LABEL(label),
+                                    _("Rename failed, possibly new name exists"));
+        }
+        else
+            gtk_label_set_text (GTK_LABEL(label), _("No new name"));
+    }
+    gtk_widget_destroy (GTK_WIDGET(dialog));
+}
+
 static void
 gnc_commodities_dialog_selection_changed (GtkTreeSelection *selection,
         CommoditiesDialog *cd)
@@ -281,6 +345,18 @@ gnc_commodities_dialog_selection_changed (GtkTreeSelection *selection,
     remove_ok = commodity && !gnc_commodity_is_iso(commodity);
     gtk_widget_set_sensitive (cd->edit_button, commodity != NULL);
     gtk_widget_set_sensitive (cd->remove_button, remove_ok);
+
+    gtk_widget_set_sensitive (cd->rename_namespace_button, !commodity);
+
+    if (!commodity)
+    {
+        gnc_commodity_namespace *ns = gnc_tree_view_commodity_get_selected_namespace (cd->commodity_tree);
+        const char *ns_name = gnc_commodity_namespace_get_name (ns);
+
+        gtk_widget_set_sensitive (cd->rename_namespace_button,
+                                  !(g_strcmp0 (ns_name, GNC_COMMODITY_NS_LEGACY) == 0 ||
+                                    g_strcmp0 (ns_name, GNC_COMMODITY_NS_CURRENCY) == 0));
+    }
 }
 
 void
@@ -351,6 +427,9 @@ gnc_commodities_dialog_create (GtkWidget * parent, CommoditiesDialog *cd)
     cd->remove_button = GTK_WIDGET(gtk_builder_get_object (builder, "remove_button"));
     cd->edit_button = GTK_WIDGET(gtk_builder_get_object (builder, "edit_button"));
 
+    cd->rename_namespace_button = GTK_WIDGET(gtk_builder_get_object (builder, "rename_namespace_button"));
+    gtk_widget_set_sensitive (cd->rename_namespace_button, FALSE);
+
     /* commodity tree */
     scrolled_window = GTK_WIDGET(gtk_builder_get_object (builder, "commodity_list_window"));
     view = gnc_tree_view_commodity_new(cd->book,
diff --git a/gnucash/gtkbuilder/dialog-commodities.glade b/gnucash/gtkbuilder/dialog-commodities.glade
index cb7a10bc18..a7a0da752b 100644
--- a/gnucash/gtkbuilder/dialog-commodities.glade
+++ b/gnucash/gtkbuilder/dialog-commodities.glade
@@ -1,7 +1,113 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.38.2 -->
+<!-- Generated with glade 3.40.0 -->
 <interface>
   <requires lib="gtk+" version="3.22"/>
+  <object class="GtkDialog" id="rename_namespace_dialog">
+    <property name="can-focus">False</property>
+    <property name="type-hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox">
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">10</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox">
+            <property name="can-focus">False</property>
+            <property name="layout-style">end</property>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label" translatable="yes">_Cancel</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="can-default">True</property>
+                <property name="receives-default">True</property>
+                <property name="use-underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label" translatable="yes">_OK</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="can-default">True</property>
+                <property name="receives-default">True</property>
+                <property name="use-underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">5</property>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="label" translatable="yes">Rename Namespace</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="rename_entry">
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="rename_label">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <style>
+                  <class name="gnc-class-highlight"/>
+                </style>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">button2</action-widget>
+      <action-widget response="-5">button1</action-widget>
+    </action-widgets>
+  </object>
   <object class="GtkWindow" id="securities_window">
     <property name="can-focus">False</property>
     <property name="border-width">6</property>
@@ -116,6 +222,23 @@
             <property name="visible">True</property>
             <property name="can-focus">False</property>
             <property name="layout-style">end</property>
+            <child>
+              <object class="GtkButton" id="rename_namespace_button">
+                <property name="label" translatable="yes">Rename _Namespace</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">True</property>
+                <property name="tooltip-text" translatable="yes">Rename the current namespace.</property>
+                <property name="halign">start</property>
+                <property name="use-underline">True</property>
+                <signal name="clicked" handler="gnc_commodities_dialog_rename_namespace_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
             <child>
               <object class="GtkButton" id="add_button">
                 <property name="label" translatable="yes">_Add</property>
@@ -130,7 +253,7 @@
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">0</property>
+                <property name="position">2</property>
               </packing>
             </child>
             <child>
@@ -148,7 +271,7 @@
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">1</property>
+                <property name="position">3</property>
               </packing>
             </child>
             <child>
@@ -166,7 +289,7 @@
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">2</property>
+                <property name="position">4</property>
               </packing>
             </child>
             <child>
@@ -183,14 +306,13 @@
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">3</property>
+                <property name="position">5</property>
               </packing>
             </child>
           </object>
           <packing>
             <property name="expand">False</property>
             <property name="fill">True</property>
-            <property name="pack-type">end</property>
             <property name="position">1</property>
           </packing>
         </child>
diff --git a/libgnucash/engine/gnc-commodity.cpp b/libgnucash/engine/gnc-commodity.cpp
index 6ddb4d8b27..c803a94a9f 100644
--- a/libgnucash/engine/gnc-commodity.cpp
+++ b/libgnucash/engine/gnc-commodity.cpp
@@ -2134,6 +2134,37 @@ gnc_commodity_table_add_namespace(gnc_commodity_table * table,
     return ns;
 }
 
+bool
+gnc_commodity_table_rename_namespace(const gnc_commodity_table * table,
+                                     const char * namespace_name,
+                                     const char * new_namespace_name)
+{
+    if (!table || !namespace_name || !new_namespace_name ||
+        (g_strcmp0 (namespace_name, new_namespace_name) == 0) ||
+        (g_strcmp0 (new_namespace_name, GNC_COMMODITY_NS_ISO_GUI) == 0) ||
+        (g_strcmp0 (new_namespace_name, _(GNC_COMMODITY_NS_ISO_GUI)) == 0) ||
+        gnc_commodity_table_find_namespace (table, new_namespace_name))
+        return false;
+
+    auto ns = gnc_commodity_table_find_namespace (table, namespace_name);
+    if (!ns)
+        return false;
+
+    ns->name = CACHE_INSERT(static_cast<const char*>(new_namespace_name));
+
+    g_hash_table_insert (table->ns_table,
+                         (gpointer) ns->name,
+                         (gpointer) ns);
+
+    g_hash_table_remove (table->ns_table,
+                         (gpointer) namespace_name);
+
+    CACHE_REMOVE(namespace_name);
+
+    qof_instance_set_dirty (&ns->inst);
+    qof_event_gen (&ns->inst, QOF_EVENT_MODIFY, nullptr);
+    return true;
+}
 
 gnc_commodity_namespace *
 gnc_commodity_table_find_namespace(const gnc_commodity_table * table,
diff --git a/libgnucash/engine/gnc-commodity.hpp b/libgnucash/engine/gnc-commodity.hpp
index 223d9abe72..71b171da8a 100644
--- a/libgnucash/engine/gnc-commodity.hpp
+++ b/libgnucash/engine/gnc-commodity.hpp
@@ -36,6 +36,7 @@
 #include <vector>
 
 #include <gnc-commodity.h>
+#include <string>
 
 using CommVec = std::vector<gnc_commodity*>;
 
@@ -51,6 +52,20 @@ using CommVec = std::vector<gnc_commodity*>;
 void gnc_quote_source_set_fq_installed (const char* version_string,
                                         const std::vector<std::string>& sources_list);
 
+/** This function renames a namespace.
+ *
+ *  @param table A pointer to the commodity table
+ *
+ *  @param namespace_name The name of the namespace to rename.
+ *
+ *  @param new_namespace_name The new name for the namespace.
+ *
+ * @return Return true if rename successful.
+ */
+bool gnc_commodity_table_rename_namespace(const gnc_commodity_table * table,
+                                          const char * namespace_name,
+                                          const char * new_namespace_name);
+
 #endif /* GNC_COMMODITY_HPP */
 /** @} */
 /** @} */



Summary of changes:
 gnucash/gnome-utils/gnc-tree-view-commodity.c |  42 +++++++-
 gnucash/gnome-utils/gnc-tree-view-commodity.h |  13 +++
 gnucash/gnome/dialog-commodities.cpp          |  79 +++++++++++++++
 gnucash/gtkbuilder/dialog-commodities.glade   | 134 ++++++++++++++++++++++++--
 libgnucash/engine/gnc-commodity.cpp           |  31 ++++++
 libgnucash/engine/gnc-commodity.hpp           |  15 +++
 6 files changed, 307 insertions(+), 7 deletions(-)



More information about the gnucash-changes mailing list