gnucash maint: Multiple changes pushed

Robert Fewell bobit at code.gnucash.org
Sat Jun 22 05:23:46 EDT 2019


Updated	 via  https://github.com/Gnucash/gnucash/commit/b50ed475 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8c387c1c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/90b2d8f1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5213a91b (commit)
	from  https://github.com/Gnucash/gnucash/commit/03d9bf90 (commit)



commit b50ed4755668575080697f939366f758df11f986
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Fri Jun 21 11:27:20 2019 +0100

    Make similar correction to gnc-imp-props-tx.cpp for incorrect find use.

diff --git a/gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp b/gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp
index 4df60017c..c1e358695 100644
--- a/gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp
+++ b/gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp
@@ -162,9 +162,8 @@ gnc_commodity* parse_commodity (const std::string& comm_str)
     auto table = gnc_commodity_table_get_table (gnc_get_current_book());
     gnc_commodity* comm = nullptr;
 
-    /* First try commodity as a unique name. */
-    if (comm_str.find("::"))
-        comm = gnc_commodity_table_lookup_unique (table, comm_str.c_str());
+    /* First try commodity as a unique name, returns null if not found */
+    comm = gnc_commodity_table_lookup_unique (table, comm_str.c_str());
 
     /* Then try mnemonic in the currency namespace */
     if (!comm)

commit 8c387c1c9745a5d5aa02d2fdbdf932dee40653c6
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Sun Jun 16 15:02:51 2019 +0100

    Bug797244 - Remove the invert prices for less than 1
    
    Previously where prices were less than 1, the commodities involved were
    swapped and the price inverted, this is no longer required so removed
    in the price importer and the transfer dialogue.

diff --git a/gnucash/gnome-utils/dialog-transfer.c b/gnucash/gnome-utils/dialog-transfer.c
index 5add381c5..6f10d66e6 100644
--- a/gnucash/gnome-utils/dialog-transfer.c
+++ b/gnucash/gnome-utils/dialog-transfer.c
@@ -1619,17 +1619,14 @@ new_price(XferDialog *xferData, time64 time)
     gnc_commodity *to = xferData->to_commodity;
     gnc_numeric value = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->price_edit));
 
-/* We want to store currency rates such that the rate > 1 and commodity
- * prices in terms of a currency regardless of value.
- */
     value = gnc_numeric_abs(value);
-    if (gnc_commodity_is_currency(from) && gnc_commodity_is_currency(to))
-    {
-        if (value.num < value.denom)
-            value = swap_commodities(&from, &to, value);
-    }
-    else if (gnc_commodity_is_currency(from))
-            value = swap_commodities(&from, &to, value);
+
+    /* store price against the non currency commodity */
+    if (gnc_commodity_is_currency (from)  && !gnc_commodity_is_currency (to))
+        value = swap_commodities (&from, &to, value);
+    /* store rate against default currency if present */
+    else if (from == gnc_default_currency() && to != gnc_default_currency())
+        value = swap_commodities (&from, &to, value);
 
     value = round_price (from, to, value);
     price = gnc_price_create (xferData->book);
diff --git a/gnucash/import-export/csv-imp/gnc-imp-props-price.cpp b/gnucash/import-export/csv-imp/gnc-imp-props-price.cpp
index 5514afed0..0d794b005 100644
--- a/gnucash/import-export/csv-imp/gnc-imp-props-price.cpp
+++ b/gnucash/import-export/csv-imp/gnc-imp-props-price.cpp
@@ -298,7 +298,6 @@ Result GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
 
     auto date = static_cast<time64>(GncDateTime(*m_date, DayPart::neutral));
 
-    bool rev = false;
     auto amount = *m_amount;
     Result ret_val = ADDED;
 
@@ -315,27 +314,11 @@ Result GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
         ret_val = REPLACED;
     }
 
-    if (gnc_commodity_is_currency (*m_from_commodity)) // Currency Import
-    {
-        // Check for currency in reverse direction.
-        if (old_price != nullptr)
-        {
-            // Check for price in reverse direction.
-            if (gnc_commodity_equiv (gnc_price_get_currency (old_price), *m_from_commodity))
-                rev = true;
-        }
-        DEBUG("Commodity from is a Currency");
-
-        // Check for price less than 1, reverse if so.
-        if (*m_amount < GncNumeric(1,1))
-            rev = true;
-
-    }
     char date_str [MAX_DATE_LENGTH + 1];
     memset (date_str, 0, sizeof(date_str));
     qof_print_date_buff (date_str, sizeof(date_str), date);
-    DEBUG("Date is %s, Rev is %d, Commodity from is '%s', Currency is '%s', "
-          "Amount is %s", date_str, rev,
+    DEBUG("Date is %s, Commodity from is '%s', Currency is '%s', "
+          "Amount is %s", date_str,
           gnc_commodity_get_fullname (*m_from_commodity),
           gnc_commodity_get_fullname (*m_to_currency),
           amount.to_string().c_str());
@@ -345,17 +328,10 @@ Result GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
         DEBUG("Create");
         GNCPrice *price = gnc_price_create (book);
         gnc_price_begin_edit (price);
-        if (rev)
-        {
-            amount = amount.inv(); //invert the amount
-            gnc_price_set_commodity (price, *m_to_currency);
-            gnc_price_set_currency (price, *m_from_commodity);
-        }
-        else
-        {
-            gnc_price_set_commodity (price, *m_from_commodity);
-            gnc_price_set_currency (price, *m_to_currency);
-        }
+
+        gnc_price_set_commodity (price, *m_from_commodity);
+        gnc_price_set_currency (price, *m_to_currency);
+
         auto amount_conv = amount.convert<RoundType::half_up>(CURRENCY_DENOM);
         gnc_price_set_value (price, static_cast<gnc_numeric>(amount_conv));
 

commit 90b2d8f1f5148150db51ab751169c54f32140339
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Sun Jun 16 15:01:13 2019 +0100

    Change the Commodity/Currency combo's on Price Import
    
    Change the way the sorting is done for the Commodity and Currency
    combo's for the Price Import. For the Commodity combo group all non
    currencies together at the start and add a separator row.

diff --git a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp
index cf6bd9c32..2e45fd397 100644
--- a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp
+++ b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp
@@ -335,11 +335,29 @@ static void csv_price_imp_preview_currency_fmt_sel_cb (GtkComboBox* format_selec
     info->preview_update_currency_format();
 }
 
+enum GncCommColumn {DISPLAYED_COMM, SORT_COMM, COMM_PTR, SEP};
+
 static void csv_price_imp_preview_currency_sel_cb (GtkComboBox* currency_selector, CsvImpPriceAssist* info)
 {
     info->preview_update_currency();
 }
 
+static gboolean separator_row_func (GtkTreeModel *smodel, GtkTreeIter *siter, gpointer data)
+{
+    gboolean      sep_row;
+    GtkTreeModel *store;
+    GtkTreeIter   iter;
+
+    store = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT(smodel));
+
+    gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT(smodel),
+                                                    &iter, siter);
+
+    gtk_tree_model_get (GTK_TREE_MODEL(store), &iter, SEP, &sep_row, -1);
+
+    return sep_row;
+}
+
 static void csv_price_imp_preview_commodity_sel_cb (GtkComboBox* commodity_selector, CsvImpPriceAssist* info)
 {
     info->preview_update_commodity();
@@ -375,7 +393,8 @@ gnc_commodity *get_commodity_from_combo (GtkComboBox *combo)
     gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT(sort_model),
                                                     &iter, &siter);
 
-    gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &string, 2, &comm, -1);
+    gtk_tree_model_get (GTK_TREE_MODEL(model), &iter,
+                        DISPLAYED_COMM, &string, COMM_PTR, &comm, -1);
 
     PINFO("Commodity string is %s", string);
 
@@ -397,7 +416,7 @@ set_commodity_for_combo (GtkComboBox *combo, gnc_commodity *comm)
 
     while (valid)
     {
-        gtk_tree_model_get (model, &iter, 2, &model_comm, -1);
+        gtk_tree_model_get (model, &iter, COMM_PTR, &model_comm, -1);
         if (model_comm == comm)
         {
             if (gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(sort_model), &siter, &iter))
@@ -426,13 +445,15 @@ GtkTreeModel *get_model (bool all_commodity)
     GList *namespace_list = gnc_commodity_table_get_namespaces (commodity_table);
     GtkTreeIter iter;
 
-    store = GTK_TREE_MODEL(gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER));
+    store = GTK_TREE_MODEL(gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING,
+                                                  G_TYPE_POINTER, G_TYPE_BOOLEAN));
     model = gtk_tree_model_sort_new_with_model (store);
-    // set sort to sort on second string, first string will be shown
-    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 1, GTK_SORT_ASCENDING);
+    // set sort order
+    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(model), SORT_COMM, GTK_SORT_ASCENDING);
 
     gtk_list_store_append (GTK_LIST_STORE(store), &iter);
-    gtk_list_store_set (GTK_LIST_STORE(store), &iter, 0, " ", 1, " ", 2, nullptr, -1);
+    gtk_list_store_set (GTK_LIST_STORE(store), &iter,
+                            DISPLAYED_COMM, " ", SORT_COMM, " ", COMM_PTR, nullptr, SEP, false, -1);
 
     namespace_list = g_list_first (namespace_list);
     while (namespace_list != nullptr)
@@ -447,6 +468,15 @@ GtkTreeModel *get_model (bool all_commodity)
             {
                 commodity_list = gnc_commodity_table_get_commodities (commodity_table, tmp_namespace);
                 commodity_list  = g_list_first (commodity_list);
+
+                // if this is the CURRENCY, add a row to be identified as a separator row
+                if ((g_utf8_collate (tmp_namespace, GNC_COMMODITY_NS_CURRENCY) == 0) && (all_commodity == true))
+                {
+                    gtk_list_store_append (GTK_LIST_STORE(store), &iter);
+                    gtk_list_store_set (GTK_LIST_STORE(store), &iter, DISPLAYED_COMM, " ",
+                                           SORT_COMM, "CURRENCY-", COMM_PTR, nullptr, SEP, true, -1);
+                }
+
                 while (commodity_list != nullptr)
                 {
                     const gchar *name_str;
@@ -456,11 +486,16 @@ GtkTreeModel *get_model (bool all_commodity)
 
                     name_str = gnc_commodity_get_printname (tmp_commodity);
 
-                    sort_str = g_strconcat (tmp_namespace, "::", gnc_commodity_get_mnemonic (tmp_commodity), nullptr);
-                    DEBUG("Name string is %s, Sort string is %s", name_str, sort_str);
+                    if (g_utf8_collate (tmp_namespace, GNC_COMMODITY_NS_CURRENCY) == 0)
+                        sort_str = g_strconcat ("CURRENCY-", name_str, nullptr);
+                    else
+                        sort_str = g_strconcat ("ALL-OTHER-", name_str, nullptr);
+
+                    DEBUG("Name string is '%s', Sort string is '%s'", name_str, sort_str);
 
                     gtk_list_store_append (GTK_LIST_STORE(store), &iter);
-                    gtk_list_store_set (GTK_LIST_STORE(store), &iter, 0, name_str, 1, sort_str, 2, tmp_commodity, -1);
+                    gtk_list_store_set (GTK_LIST_STORE(store), &iter, DISPLAYED_COMM, name_str,
+                                           SORT_COMM, sort_str, COMM_PTR, tmp_commodity, SEP, false, -1);
 
                     g_free (sort_str);
                     commodity_list = g_list_next (commodity_list);
@@ -594,8 +629,10 @@ CsvImpPriceAssist::CsvImpPriceAssist ()
         /* Add commodity selection widget */
         commodity_selector = GTK_WIDGET(gtk_builder_get_object (builder, "commodity_cbox"));
         gtk_combo_box_set_model (GTK_COMBO_BOX(commodity_selector), get_model (true));
-        g_signal_connect(G_OBJECT(commodity_selector), "changed",
-                         G_CALLBACK(csv_price_imp_preview_commodity_sel_cb), this);
+        gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX(commodity_selector),
+                                              separator_row_func, nullptr, nullptr);
+        g_signal_connect (G_OBJECT(commodity_selector), "changed",
+                          G_CALLBACK(csv_price_imp_preview_commodity_sel_cb), this);
 
         /* Add currency selection widget */
         currency_selector = GTK_WIDGET(gtk_builder_get_object (builder, "currency_cbox"));

commit 5213a91b0fdcceb9f324b3f885b8290bc973e835
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Sat Jun 15 10:57:04 2019 +0100

    Bug797278 - Create an option for type of commodity for Price import
    
    Currently when you use the 'Commodity From' column for Price imports it
    can match against the wrong commodity like COP (Conoco Philips) would
    match against the currency COP (Columbian Peso). To fix this add a new
    column type 'From Namespace' and rename 'Commodity From' to
    'From Symbol' so they match the Security Editor.

diff --git a/gnucash/gtkbuilder/assistant-csv-price-import.glade b/gnucash/gtkbuilder/assistant-csv-price-import.glade
index 97e5fe119..47cd7943e 100644
--- a/gnucash/gtkbuilder/assistant-csv-price-import.glade
+++ b/gnucash/gtkbuilder/assistant-csv-price-import.glade
@@ -52,11 +52,11 @@
         <property name="can_focus">False</property>
         <property name="label" translatable="yes">This assistant will help you import Prices from a CSV file.
 
-There is a minimum number of columns that have to be present for a successful import, these are Date, Amount, Commodity From and Currency To. If all entries are for the same Commodity / Currency then you can select them and then the columns will be Date and Amount.
+There is a minimum number of columns that have to be present for a successful import, these are Date, Amount, From Namespace, From Symbol and Currency To. If all entries are for the same Commodity / Currency then you can select them and then the columns will be Date and Amount.
 
 Various options exist for specifying the delimiter as well as a fixed width option. With the fixed width option, double click on the table of rows displayed to set a column width, then right mouse to change if required.
 
-Examples are "RR.L","21/11/2016",5.345,"GBP" and "USD","2016-11-21",1.56,"GBP"
+Examples are "FTSE","RR.L","21/11/2016",5.345,"GBP" and CURRENCY;USD;2016-11-21;1.56;GBP
 
 There is an option for specifying the start row, end row and an option to skip alternate rows beginning from the start row which can be used if you have some header text. Also there is an option to over write existing prices for that day if required.
 
diff --git a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp
index c539a4256..cf6bd9c32 100644
--- a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp
+++ b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp
@@ -1193,11 +1193,13 @@ void CsvImpPriceAssist::preview_update_col_type (GtkComboBox* cbox)
     if (old_col_type == GncPricePropType::TO_CURRENCY)
     {
         // look for a from_commodity column to reparse
-        preview_reparse_col_type (GncPricePropType::FROM_COMMODITY);
+        preview_reparse_col_type (GncPricePropType::FROM_SYMBOL);
+        preview_reparse_col_type (GncPricePropType::FROM_NAMESPACE);
     }
 
-    // if old_col_type is FROM_COMMODITY, force a reparse of currency
-    if (old_col_type == GncPricePropType::FROM_COMMODITY)
+    // if old_col_type is FROM_SYMBOL, or FROM_NAMESPACE force a reparse of currency
+    if ((old_col_type == GncPricePropType::FROM_SYMBOL) ||
+        (old_col_type == GncPricePropType::FROM_NAMESPACE))
     {
         // look for a to_currency column to reparse
         preview_reparse_col_type (GncPricePropType::TO_CURRENCY);
@@ -1624,10 +1626,20 @@ void CsvImpPriceAssist::preview_refresh_table ()
 
     auto column_types = price_imp->column_types_price();
 
-    // look for a commodity column, clear the commodity combo
-    auto col_type_comm = std::find (column_types.begin(),
-                column_types.end(), GncPricePropType::FROM_COMMODITY);
-    if (col_type_comm != column_types.end())
+    // look for a namespace column, clear the commodity combo
+    auto col_type_name = std::find (column_types.begin(),
+                column_types.end(), GncPricePropType::FROM_NAMESPACE);
+    if (col_type_name != column_types.end())
+    {
+        g_signal_handlers_block_by_func (commodity_selector, (gpointer) csv_price_imp_preview_commodity_sel_cb, this);
+        set_commodity_for_combo (GTK_COMBO_BOX(commodity_selector), nullptr);
+        g_signal_handlers_unblock_by_func (commodity_selector, (gpointer) csv_price_imp_preview_commodity_sel_cb, this);
+    }
+
+    // look for a symbol column, clear the commodity combo
+    auto col_type_sym = std::find (column_types.begin(),
+                column_types.end(), GncPricePropType::FROM_SYMBOL);
+    if (col_type_sym != column_types.end())
     {
         g_signal_handlers_block_by_func (commodity_selector, (gpointer) csv_price_imp_preview_commodity_sel_cb, this);
         set_commodity_for_combo (GTK_COMBO_BOX(commodity_selector), nullptr);
diff --git a/gnucash/import-export/csv-imp/gnc-imp-props-price.cpp b/gnucash/import-export/csv-imp/gnc-imp-props-price.cpp
index 4d737a0d0..5514afed0 100644
--- a/gnucash/import-export/csv-imp/gnc-imp-props-price.cpp
+++ b/gnucash/import-export/csv-imp/gnc-imp-props-price.cpp
@@ -46,7 +46,8 @@ std::map<GncPricePropType, const char*> gnc_price_col_type_strs = {
         { GncPricePropType::NONE, N_("None") },
         { GncPricePropType::DATE, N_("Date") },
         { GncPricePropType::AMOUNT, N_("Amount") },
-        { GncPricePropType::FROM_COMMODITY, N_("Commodity From") },
+        { GncPricePropType::FROM_SYMBOL, N_("From Symbol") },
+        { GncPricePropType::FROM_NAMESPACE, N_("From Namespace") },
         { GncPricePropType::TO_CURRENCY, N_("Currency To") },
 };
 
@@ -90,43 +91,28 @@ GncNumeric parse_amount_price (const std::string &str, int currency_format)
     return GncNumeric(val);
 }
 
-/** Convert comm_str into a gnc_commodity.
- * @param comm_str The string to be parsed
+/** Convert the combination of symbol_str and namespace_str into a gnc_commodity.
+ * @param symbol_str The symbol string to be parsed
+ * @param namespace_str The Namespace for this commodity
  * @return a gnc_commodity
  * @exception May throw std::invalid argument if string can't be parsed properly
  */
-gnc_commodity* parse_commodity_price_comm (const std::string& comm_str)
+gnc_commodity* parse_commodity_price_comm (const std::string& symbol_str, const std::string& namespace_str)
 {
-    if (comm_str.empty())
+    if (symbol_str.empty())
         return nullptr;
 
     auto table = gnc_commodity_table_get_table (gnc_get_current_book());
     gnc_commodity* comm = nullptr;
 
-    /* First try commodity as a unique name. */
-    if (comm_str.find("::"))
-        comm = gnc_commodity_table_lookup_unique (table, comm_str.c_str());
-
-    /* Then try mnemonic in the currency namespace */
-    if (!comm)
-        comm = gnc_commodity_table_lookup (table,
-                GNC_COMMODITY_NS_CURRENCY, comm_str.c_str());
+    /* First try commodity as a unique name, used in loading settings, returns null if not found */
+    comm = gnc_commodity_table_lookup_unique (table, symbol_str.c_str());
 
+    /* Now lookup with namespace and symbol */
     if (!comm)
     {
-        /* If that fails try mnemonic in all other namespaces */
-        auto namespaces = gnc_commodity_table_get_namespaces(table);
-        for (auto ns = namespaces; ns; ns = ns->next)
-        {
-            gchar* ns_str = (gchar*)ns->data;
-            if (g_utf8_collate(ns_str, GNC_COMMODITY_NS_CURRENCY) == 0)
-                continue;
-
-            comm = gnc_commodity_table_lookup (table,
-                    ns_str, comm_str.c_str());
-            if (comm)
-                break;
-        }
+        comm = gnc_commodity_table_lookup (table,
+                    namespace_str.c_str(), symbol_str.c_str());
     }
 
     if (!comm)
@@ -135,6 +121,26 @@ gnc_commodity* parse_commodity_price_comm (const std::string& comm_str)
         return comm;
 }
 
+/** Check for a valid namespace.
+ * @param namespace_str The string to be parsed
+ * @return a bool
+ * @exception May throw std::invalid argument if string can't be parsed properly
+ */
+bool parse_namespace (const std::string& namespace_str)
+{
+    if (namespace_str.empty())
+        return false;
+
+    auto table = gnc_commodity_table_get_table (gnc_get_current_book());
+
+    if (gnc_commodity_table_has_namespace (table, namespace_str.c_str()))
+        return true;
+    else
+        throw std::invalid_argument (_("Value can't be parsed into a valid namespace."));
+
+    return false;
+}
+
 void GncImportPrice::set (GncPricePropType prop_type, const std::string& value, bool enable_test_empty)
 {
     try
@@ -159,24 +165,56 @@ void GncImportPrice::set (GncPricePropType prop_type, const std::string& value,
                 m_amount = parse_amount_price (value, m_currency_format); // Throws if parsing fails
                 break;
 
-            case GncPricePropType::FROM_COMMODITY:
-                m_from_commodity = boost::none;
-                comm = parse_commodity_price_comm (value); // Throws if parsing fails
-                if (comm)
+            case GncPricePropType::FROM_SYMBOL:
+                m_from_symbol = boost::none;
+
+                if (value.empty())
+                    throw std::invalid_argument (_("'From Symbol' can not be empty."));
+                else
+                    m_from_symbol = value;
+
+                if (m_from_namespace)
+                {
+                    comm = parse_commodity_price_comm (value, *m_from_namespace); // Throws if parsing fails
+                    if (comm)
+                    {
+                        if (m_to_currency == comm)
+                                throw std::invalid_argument (_("'Commodity From' can not be the same as 'Currency To'."));
+                        m_from_commodity = comm;
+                    }
+                }
+                break;
+
+            case GncPricePropType::FROM_NAMESPACE:
+                m_from_namespace = boost::none;
+
+                if (value.empty())
+                    throw std::invalid_argument (_("'From Namespace' can not be empty."));
+
+                if (parse_namespace (value)) // Throws if parsing fails
                 {
-                    if (m_to_currency == comm)
-                        throw std::invalid_argument (_("'Commodity From' can not be the same as 'Currency To' column type."));
-                    m_from_commodity = comm;
+                    m_from_namespace = value;
+
+                    if (m_from_symbol)
+                    {
+                        comm = parse_commodity_price_comm (*m_from_symbol, *m_from_namespace); // Throws if parsing fails
+                        if (comm)
+                        {
+                            if (m_to_currency == comm)
+                                throw std::invalid_argument (_("'Commodity From' can not be the same as 'Currency To'."));
+                            m_from_commodity = comm;
+                        }
+                    }
                 }
                 break;
 
             case GncPricePropType::TO_CURRENCY:
                 m_to_currency = boost::none;
-                comm = parse_commodity_price_comm (value); // Throws if parsing fails
+                comm = parse_commodity_price_comm (value, GNC_COMMODITY_NS_CURRENCY); // Throws if parsing fails
                 if (comm)
                 {
                     if (m_from_commodity == comm)
-                        throw std::invalid_argument (_("'Currency To' can not be the same as 'Commodity From' column type."));
+                        throw std::invalid_argument (_("'Currency To' can not be the same as 'Commodity From'."));
                     if (gnc_commodity_is_currency (comm) != true)
                         throw std::invalid_argument (_("Value parsed into an invalid currency for a currency column type."));
                     m_to_currency = comm;
@@ -211,6 +249,13 @@ void GncImportPrice::reset (GncPricePropType prop_type)
 {
     try
     {
+        if ((prop_type == GncPricePropType::FROM_NAMESPACE) ||
+            (prop_type == GncPricePropType::FROM_SYMBOL))
+             set_from_commodity (nullptr);
+
+        if (prop_type == GncPricePropType::TO_CURRENCY)
+             set_to_currency (nullptr);
+
         // set enable_test_empty to false to allow empty values
         set (prop_type, std::string(), false);
     }
@@ -230,9 +275,9 @@ std::string GncImportPrice::verify_essentials (void)
     else if (m_amount == boost::none)
         return _("No amount column.");
     else if (m_to_currency == boost::none)
-        return _("No 'Currency to' column.");
+        return _("No 'Currency to'.");
     else if (m_from_commodity == boost::none)
-        return _("No 'Commodity from' column.");
+        return _("No 'Commodity from'.");
     else if (gnc_commodity_equal (*m_from_commodity, *m_to_currency))
         return _("'Commodity From' can not be the same as 'Currency To'.");
     else
@@ -260,7 +305,7 @@ Result GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
     GNCPrice *old_price = gnc_pricedb_lookup_day_t64 (pdb, *m_from_commodity,
                                                       *m_to_currency, date);
 
-    // Should old price be over writen
+    // Should old price be over written
     if ((old_price != nullptr) && (over == true))
     {
         DEBUG("Over write");
@@ -316,7 +361,6 @@ Result GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
 
         gnc_price_set_time64 (price, date);
         gnc_price_set_source (price, PRICE_SOURCE_USER_PRICE);
-//FIXME Not sure which one        gnc_price_set_source (price, PRICE_SOURCE_FQ);
         gnc_price_set_typestr (price, PRICE_TYPE_LAST);
         gnc_price_commit_edit (price);
 
diff --git a/gnucash/import-export/csv-imp/gnc-imp-props-price.hpp b/gnucash/import-export/csv-imp/gnc-imp-props-price.hpp
index 055cc4d12..38acdd077 100644
--- a/gnucash/import-export/csv-imp/gnc-imp-props-price.hpp
+++ b/gnucash/import-export/csv-imp/gnc-imp-props-price.hpp
@@ -50,7 +50,8 @@ enum class GncPricePropType {
     NONE,
     DATE,
     AMOUNT,
-    FROM_COMMODITY,
+    FROM_SYMBOL,
+    FROM_NAMESPACE,
     TO_CURRENCY,
     PRICE_PROPS = TO_CURRENCY
 };
@@ -77,7 +78,8 @@ private:
     const char *m_name;
 };
 
-gnc_commodity* parse_commodity_price_comm (const std::string& comm_str);
+gnc_commodity* parse_commodity_price_comm (const std::string& symbol_str, const std::string& namespace_str);
+bool parse_namespace (const std::string& namespace_str);
 GncNumeric parse_amount_price (const std::string &str, int currency_format);
 
 struct GncImportPrice
@@ -107,6 +109,8 @@ private:
     boost::optional<GncDate> m_date;
     boost::optional<GncNumeric> m_amount;
     boost::optional<gnc_commodity*> m_from_commodity;
+    boost::optional<std::string> m_from_namespace;
+    boost::optional<std::string> m_from_symbol;
     boost::optional<gnc_commodity*> m_to_currency;
     bool created = false;
 
diff --git a/gnucash/import-export/csv-imp/gnc-imp-settings-csv-price.cpp b/gnucash/import-export/csv-imp/gnc-imp-settings-csv-price.cpp
index a49c7f0ed..e34021c2c 100644
--- a/gnucash/import-export/csv-imp/gnc-imp-settings-csv-price.cpp
+++ b/gnucash/import-export/csv-imp/gnc-imp-settings-csv-price.cpp
@@ -76,7 +76,8 @@ static std::shared_ptr<CsvPriceImpSettings> create_int_gnc_exp_preset(void)
     preset->m_column_types_price = {
             GncPricePropType::DATE,
             GncPricePropType::AMOUNT,
-            GncPricePropType::FROM_COMMODITY,
+            GncPricePropType::FROM_SYMBOL,
+            GncPricePropType::FROM_NAMESPACE,
             GncPricePropType::TO_CURRENCY
     };
     return preset;
@@ -152,14 +153,14 @@ CsvPriceImpSettings::load (void)
 
     gchar *key_char = g_key_file_get_string (keyfile, group.c_str(), CSV_TO_CURR, &key_error);
     if (key_char && *key_char != '\0')
-        m_to_currency = parse_commodity_price_comm (key_char);
+        m_to_currency = parse_commodity_price_comm (key_char, "");
     m_load_error |= handle_load_error (&key_error, group);
     if (key_char)
         g_free (key_char);
 
     key_char = g_key_file_get_string (keyfile, group.c_str(), CSV_FROM_COMM, &key_error);
     if (key_char && *key_char != '\0')
-        m_from_commodity = parse_commodity_price_comm (key_char);
+        m_from_commodity = parse_commodity_price_comm (key_char, "");
     m_load_error |= handle_load_error (&key_error, group);
     if (key_char)
         g_free (key_char);
@@ -178,8 +179,8 @@ CsvPriceImpSettings::load (void)
             m_column_types_price.push_back(col_types_it->first);
         }
         else
-            PWARN("Found invalid column type '%s'. Inserting column type 'NONE' instead'.",
-                    col_types_str_price[i]);
+            PWARN("Found invalid column type '%s' in group '%s'. Inserting column type 'NONE' instead'.",
+                    col_types_str_price[i], group.c_str());
     }
     if (col_types_str_price)
         g_strfreev (col_types_str_price);
diff --git a/gnucash/import-export/csv-imp/gnc-import-price.cpp b/gnucash/import-export/csv-imp/gnc-import-price.cpp
index f4aa64575..f1a133d73 100644
--- a/gnucash/import-export/csv-imp/gnc-import-price.cpp
+++ b/gnucash/import-export/csv-imp/gnc-import-price.cpp
@@ -139,11 +139,18 @@ void GncPriceImport::from_commodity (gnc_commodity* from_commodity)
     m_settings.m_from_commodity = from_commodity;
     if (m_settings.m_from_commodity)
     {
-        auto col_type_comm = std::find (m_settings.m_column_types_price.begin(),
-                m_settings.m_column_types_price.end(), GncPricePropType::FROM_COMMODITY);
+        auto col_type_sym = std::find (m_settings.m_column_types_price.begin(),
+                m_settings.m_column_types_price.end(), GncPricePropType::FROM_SYMBOL);
 
-        if (col_type_comm != m_settings.m_column_types_price.end())
-            set_column_type_price (col_type_comm -m_settings.m_column_types_price.begin(),
+        if (col_type_sym != m_settings.m_column_types_price.end())
+            set_column_type_price (col_type_sym -m_settings.m_column_types_price.begin(),
+                            GncPricePropType::NONE);
+
+        auto col_type_name = std::find (m_settings.m_column_types_price.begin(),
+                m_settings.m_column_types_price.end(), GncPricePropType::FROM_NAMESPACE);
+
+        if (col_type_name != m_settings.m_column_types_price.end())
+            set_column_type_price (col_type_name -m_settings.m_column_types_price.begin(),
                             GncPricePropType::NONE);
 
         // force a refresh of the to_currency if the from_commodity is changed
@@ -171,7 +178,8 @@ void GncPriceImport::to_currency (gnc_commodity* to_currency)
                             GncPricePropType::NONE);
 
         // force a refresh of the from_commodity if the to_currency is changed
-        std::vector<GncPricePropType> commodities = { GncPricePropType::FROM_COMMODITY };
+        // either namespace or symbol will be sufice
+        std::vector<GncPricePropType> commodities = { GncPricePropType::FROM_SYMBOL };
         reset_formatted_column (commodities);
     }
 }
@@ -367,10 +375,11 @@ void GncPriceImport::tokenize (bool guessColTypes)
     m_parsed_lines.clear();
     for (auto tokenized_line : m_tokenizer->get_tokens())
     {
-        m_parsed_lines.push_back (std::make_tuple (tokenized_line, std::string(),
-                std::make_shared<GncImportPrice>(date_format(), currency_format()),
-                false));
         auto length = tokenized_line.size();
+        if (length > 0)
+            m_parsed_lines.push_back (std::make_tuple (tokenized_line, std::string(),
+                    std::make_shared<GncImportPrice>(date_format(), currency_format()),
+                    false));
         if (length > max_cols)
             max_cols = length;
     }
@@ -440,12 +449,20 @@ void GncPriceImport::verify_column_selections (ErrorListPrice& error_msg)
             error_msg.add_error( _("Please select a 'Currency to' column or set a Currency in the 'Currency To' field."));
     }
 
-    /* Verify a Commodity from column is selected.
+    /* Verify a From Symbol column is selected.
+     */
+    if (!check_for_column_type(GncPricePropType::FROM_SYMBOL))
+    {
+        if (!m_settings.m_from_commodity)
+            error_msg.add_error( _("Please select a 'From Symbol' column or set a Commodity in the 'Commodity From' field."));
+    }
+
+    /* Verify a From Namespace column is selected.
      */
-    if (!check_for_column_type(GncPricePropType::FROM_COMMODITY))
+    if (!check_for_column_type(GncPricePropType::FROM_NAMESPACE))
     {
         if (!m_settings.m_from_commodity)
-            error_msg.add_error( _("Please select a 'Commodity from' column or set a Commodity in the 'Commodity From' field."));
+            error_msg.add_error( _("Please select a 'From Namespace' column or set a Commodity in the 'Commodity From' field."));
     }
 
     /* Verify a 'Commodity from' does not equal 'Currency to'.
@@ -541,7 +558,7 @@ void GncPriceImport::create_price (std::vector<parse_line_t>::iterator& parsed_l
 
     error_message.clear();
 
-    // Add a TO_CURRENCY property with the selected 'currency to' if no 'currency to' column was set by the user
+    // Add a TO_CURRENCY property with the selected 'to_currency' if no 'Currency To' column was set by the user
     auto line_to_currency = price_props->get_to_currency();
     if (!line_to_currency)
     {
@@ -558,7 +575,7 @@ void GncPriceImport::create_price (std::vector<parse_line_t>::iterator& parsed_l
         }
     }
 
-    // Add a FROM_COMMODITY property with the selected 'commodity from' if no 'commodity from' column was set by the user
+    // Add a FROM_COMMODITY property with the selected 'from_commodity' if no 'From Namespace/Symbol' columns were set by the user
     auto line_from_commodity = price_props->get_from_commodity();
     if (!line_from_commodity)
     {
@@ -568,7 +585,7 @@ void GncPriceImport::create_price (std::vector<parse_line_t>::iterator& parsed_l
         {
             // Oops - the user didn't select a 'commodity from' column *and* we didn't get a selected value either!
             // Note if you get here this suggests a bug in the code!
-            error_message = _("No 'Commodity from' column selected and no selected Commodity specified either.\n"
+            error_message = _("No 'From Namespace/From Symbol' columns selected and no selected Commodity From specified either.\n"
                                        "This should never happen. Please report this as a bug.");
             PINFO("User warning: %s", error_message.c_str());
             throw std::invalid_argument(error_message);
@@ -667,7 +684,7 @@ void GncPriceImport::update_price_props (uint32_t row, uint32_t col, GncPricePro
                     enable_test_empty = false;
             }
             // set the to_currency based on combo so we can test for same.
-            if (prop_type == GncPricePropType::FROM_COMMODITY)
+            if (prop_type == GncPricePropType::FROM_SYMBOL)
             {
                 if (m_settings.m_to_currency)
                     price_props->set_to_currency (m_settings.m_to_currency);
@@ -706,11 +723,15 @@ GncPriceImport::set_column_type_price (uint32_t position, GncPricePropType type,
 
     m_settings.m_column_types_price.at (position) = type;
 
-    // If the user has set a 'commodity from' column, we can't have a commodity from selected
-    if (type == GncPricePropType::FROM_COMMODITY)
+    // If the user has set a 'from namespace' column, we can't have a 'commodity from' selected
+    if (type == GncPricePropType::FROM_NAMESPACE)
+        from_commodity (nullptr);
+
+    // If the user has set a 'from symbol' column, we can't have a 'commodity from' selected
+    if (type == GncPricePropType::FROM_SYMBOL)
         from_commodity (nullptr);
 
-    // If the user has set a 'currency to' column, we can't have a currency to selected
+    // If the user has set a 'currency to' column, we can't have a 'currency to' selected
     if (type == GncPricePropType::TO_CURRENCY)
         to_currency (nullptr);
 



Summary of changes:
 gnucash/gnome-utils/dialog-transfer.c              |  17 +--
 .../gtkbuilder/assistant-csv-price-import.glade    |   4 +-
 .../csv-imp/assistant-csv-price-import.cpp         |  85 ++++++++---
 .../import-export/csv-imp/gnc-imp-props-price.cpp  | 158 ++++++++++++---------
 .../import-export/csv-imp/gnc-imp-props-price.hpp  |   8 +-
 gnucash/import-export/csv-imp/gnc-imp-props-tx.cpp |   5 +-
 .../csv-imp/gnc-imp-settings-csv-price.cpp         |  11 +-
 gnucash/import-export/csv-imp/gnc-import-price.cpp |  57 +++++---
 8 files changed, 218 insertions(+), 127 deletions(-)



More information about the gnucash-changes mailing list