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