Add option to specify Commodity from and Currency to for whole file

Added two combo's to allow user to specify a Commodity from and Currency
 to for the whole file. Also reduced the property types to four and
 aligned all the commodity and currency variables.
This commit is contained in:
Robert Fewell 2017-12-01 11:25:06 +00:00
parent 3279973329
commit 8f3e175fb2
6 changed files with 525 additions and 97 deletions

View File

@ -90,6 +90,8 @@ public:
void preview_update_encoding (const char* encoding); void preview_update_encoding (const char* encoding);
void preview_update_date_format (); void preview_update_date_format ();
void preview_update_currency_format (); void preview_update_currency_format ();
void preview_update_currency ();
void preview_update_commodity ();
void preview_update_col_type (GtkComboBox* cbox); void preview_update_col_type (GtkComboBox* cbox);
void preview_update_fw_columns (GtkTreeView* treeview, GdkEventButton* event); void preview_update_fw_columns (GtkTreeView* treeview, GdkEventButton* event);
@ -134,6 +136,8 @@ private:
GtkWidget *csv_button; /**< The widget for the CSV button */ GtkWidget *csv_button; /**< The widget for the CSV button */
GtkWidget *fixed_button; /**< The widget for the Fixed Width button */ GtkWidget *fixed_button; /**< The widget for the Fixed Width button */
GtkWidget *over_write_cbutton; /**< The widget for Price Over Write */ GtkWidget *over_write_cbutton; /**< The widget for Price Over Write */
GtkWidget *commodity_selector; /**< The widget for commodity combo box */
GtkWidget *currency_selector; /**< The widget for currency combo box */
GOCharmapSel *encselector; /**< The widget for selecting the encoding */ GOCharmapSel *encselector; /**< The widget for selecting the encoding */
GtkWidget *separator_table; /**< Container for the separator checkboxes */ GtkWidget *separator_table; /**< Container for the separator checkboxes */
GtkCheckButton *sep_button[SEP_NUM_OF_TYPES]; /**< Checkbuttons for common separators */ GtkCheckButton *sep_button[SEP_NUM_OF_TYPES]; /**< Checkbuttons for common separators */
@ -321,6 +325,16 @@ static void csv_price_imp_preview_currency_fmt_sel_cb (GtkComboBox* format_selec
info->preview_update_currency_format(); info->preview_update_currency_format();
} }
static void csv_price_imp_preview_currency_sel_cb (GtkComboBox* currency_selector, CsvImpPriceAssist* info)
{
info->preview_update_currency();
}
static void csv_price_imp_preview_commodity_sel_cb (GtkComboBox* commodity_selector, CsvImpPriceAssist* info)
{
info->preview_update_commodity();
}
void csv_price_imp_preview_col_type_changed_cb (GtkComboBox* cbox, CsvImpPriceAssist* info) void csv_price_imp_preview_col_type_changed_cb (GtkComboBox* cbox, CsvImpPriceAssist* info)
{ {
info->preview_update_col_type (cbox); info->preview_update_col_type (cbox);
@ -334,6 +348,126 @@ csv_price_imp_preview_treeview_clicked_cb (GtkTreeView* treeview, GdkEventButton
return false; return false;
} }
static
gnc_commodity *get_commodity_from_combo (GtkComboBox *combo)
{
GtkTreeModel *model, *sort_model;
GtkTreeIter iter, siter;
gchar *string;
gnc_commodity *comm;
if (!gtk_combo_box_get_active_iter (combo, &siter))
return nullptr;
sort_model = gtk_combo_box_get_model (combo);
model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT(sort_model));
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);
PINFO("Commodity string is %s", string);
g_free (string);
return comm;
}
static void
set_commodity_for_combo (GtkComboBox *combo, gnc_commodity *comm)
{
GtkTreeModel *model, *sort_model;
GtkTreeIter iter, siter;
gnc_commodity *model_comm;
gboolean valid;
sort_model = gtk_combo_box_get_model (combo);
model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT(sort_model));
valid = gtk_tree_model_get_iter_first (model, &iter);
while (valid)
{
gtk_tree_model_get (model, &iter, 2, &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))
{
gtk_combo_box_set_active_iter (combo, &siter);
return;
}
}
/* Make iter point to the next row in the list store */
valid = gtk_tree_model_iter_next (model, &iter);
}
// Not found, set it to first iter
valid = gtk_tree_model_get_iter_first (model, &iter);
if (gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(sort_model), &siter, &iter))
gtk_combo_box_set_active_iter (combo, &siter);
}
static
GtkTreeModel *get_model (bool all_commodity)
{
GtkTreeModel *store, *model;
const gnc_commodity_table *commodity_table = gnc_get_current_commodities ();
gnc_commodity *tmp_commodity = nullptr;
char *tmp_namespace = nullptr;
GList *commodity_list = nullptr;
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));
model = gtk_tree_model_sort_new_with_model (store);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
0, GTK_SORT_ASCENDING);
gtk_list_store_append (GTK_LIST_STORE(store), &iter);
gtk_list_store_set (GTK_LIST_STORE(store), &iter, 0, " ", 1, nullptr, -1);
namespace_list = g_list_first (namespace_list);
while (namespace_list != nullptr)
{
tmp_namespace = (char*)namespace_list->data;
DEBUG("Looking at namespace %s", tmp_namespace);
/* Hide the template entry */
if (g_utf8_collate (tmp_namespace, "template" ) != 0)
{
if ((g_utf8_collate (tmp_namespace, GNC_COMMODITY_NS_CURRENCY ) == 0) || (all_commodity == true))
{
commodity_list = gnc_commodity_table_get_commodities (commodity_table, tmp_namespace);
commodity_list = g_list_first (commodity_list);
while (commodity_list != nullptr)
{
gchar *name_str;
gchar *save_str;
gchar *settings_str;
tmp_commodity = (gnc_commodity*)commodity_list->data;
DEBUG("Looking at commodity %s", gnc_commodity_get_fullname (tmp_commodity));
name_str = g_strconcat (tmp_namespace, " : (", gnc_commodity_get_mnemonic (tmp_commodity),
") ", gnc_commodity_get_fullname (tmp_commodity), nullptr);
settings_str = g_strconcat (tmp_namespace, "::", gnc_commodity_get_mnemonic (tmp_commodity), nullptr);
DEBUG("Name string is %s, Save string is %s", name_str, settings_str);
gtk_list_store_append (GTK_LIST_STORE(store), &iter);
gtk_list_store_set (GTK_LIST_STORE(store), &iter, 0, name_str, 1, settings_str, 2, tmp_commodity, -1);
g_free (name_str);
g_free (settings_str);
commodity_list = g_list_next (commodity_list);
}
}
}
namespace_list = g_list_next (namespace_list);
}
g_list_free (commodity_list);
g_list_free (namespace_list);
return model;
}
/******************************************************* /*******************************************************
* Assistant Constructor * Assistant Constructor
@ -343,6 +477,8 @@ CsvImpPriceAssist::CsvImpPriceAssist ()
auto builder = gtk_builder_new(); auto builder = gtk_builder_new();
gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "start_row_adj"); gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "start_row_adj");
gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "end_row_adj"); gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "end_row_adj");
gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "liststore1");
gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "liststore2");
gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "CSV Price Assistant"); gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "CSV Price Assistant");
csv_imp_asst = GTK_ASSISTANT(gtk_builder_get_object (builder, "CSV Price Assistant")); csv_imp_asst = GTK_ASSISTANT(gtk_builder_get_object (builder, "CSV Price Assistant"));
@ -453,6 +589,18 @@ CsvImpPriceAssist::CsvImpPriceAssist ()
gtk_container_add (encoding_container, GTK_WIDGET(encselector)); gtk_container_add (encoding_container, GTK_WIDGET(encselector));
gtk_widget_show_all (GTK_WIDGET(encoding_container)); gtk_widget_show_all (GTK_WIDGET(encoding_container));
/* 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);
/* Add currency selection widget */
currency_selector = GTK_WIDGET(gtk_builder_get_object (builder, "currency_cbox"));
gtk_combo_box_set_model (GTK_COMBO_BOX(currency_selector), get_model (false));
g_signal_connect(G_OBJECT(currency_selector), "changed",
G_CALLBACK(csv_price_imp_preview_currency_sel_cb), this);
/* The instructions label and image */ /* The instructions label and image */
instructions_label = GTK_LABEL(gtk_builder_get_object (builder, "instructions_label")); instructions_label = GTK_LABEL(gtk_builder_get_object (builder, "instructions_label"));
instructions_image = GTK_IMAGE(gtk_builder_get_object (builder, "instructions_image")); instructions_image = GTK_IMAGE(gtk_builder_get_object (builder, "instructions_image"));
@ -570,6 +718,9 @@ CsvImpPriceAssist::file_confirm_cb ()
preview_populate_settings_combo(); preview_populate_settings_combo();
gtk_combo_box_set_active (settings_combo, 0); gtk_combo_box_set_active (settings_combo, 0);
// set over_write to false as default
price_imp->over_write (false);
auto num = gtk_assistant_get_current_page (csv_imp_asst); auto num = gtk_assistant_get_current_page (csv_imp_asst);
gtk_assistant_set_current_page (csv_imp_asst, num + 1); gtk_assistant_set_current_page (csv_imp_asst, num + 1);
} }
@ -951,6 +1102,22 @@ CsvImpPriceAssist::preview_update_currency_format ()
preview_refresh_table (); preview_refresh_table ();
} }
void
CsvImpPriceAssist::preview_update_currency ()
{
gnc_commodity *comm = get_commodity_from_combo (GTK_COMBO_BOX(currency_selector));
price_imp->to_currency (comm);
preview_refresh_table ();
}
void
CsvImpPriceAssist::preview_update_commodity ()
{
gnc_commodity *comm = get_commodity_from_combo (GTK_COMBO_BOX(commodity_selector));
price_imp->from_commodity (comm);
preview_refresh_table ();
}
gboolean gboolean
csv_imp_preview_queue_rebuild_table (CsvImpPriceAssist *assist) csv_imp_preview_queue_rebuild_table (CsvImpPriceAssist *assist)
{ {
@ -1413,6 +1580,28 @@ void CsvImpPriceAssist::preview_refresh_table ()
for (uint32_t i = 0; i < ntcols; i++) for (uint32_t i = 0; i < ntcols; i++)
preview_style_column (i, combostore); preview_style_column (i, combostore);
auto column_types = price_imp->column_types_price();
// look for a commodity column, clear the commdoity combo
auto col_type_comm = std::find (column_types.begin(),
column_types.end(), GncPricePropType::FROM_COMMODITY);
if (col_type_comm != 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 currency column, clear the currency combo
auto col_type_curr = std::find (column_types.begin(),
column_types.end(), GncPricePropType::TO_CURRENCY);
if (col_type_curr != column_types.end())
{
g_signal_handlers_block_by_func (currency_selector, (gpointer) csv_price_imp_preview_currency_sel_cb, this);
set_commodity_for_combo (GTK_COMBO_BOX(currency_selector), nullptr);
g_signal_handlers_unblock_by_func (currency_selector, (gpointer) csv_price_imp_preview_currency_sel_cb, this);
}
/* Release our reference for the stores to allow proper memory management. */ /* Release our reference for the stores to allow proper memory management. */
g_object_unref (store); g_object_unref (store);
g_object_unref (combostore); g_object_unref (combostore);
@ -1460,6 +1649,13 @@ CsvImpPriceAssist::preview_refresh ()
price_imp->currency_format()); price_imp->currency_format());
go_charmap_sel_set_encoding (encselector, price_imp->encoding().c_str()); go_charmap_sel_set_encoding (encselector, price_imp->encoding().c_str());
// Set the commodity and currency combos
set_commodity_for_combo(GTK_COMBO_BOX(commodity_selector),
price_imp->from_commodity());
set_commodity_for_combo(GTK_COMBO_BOX(currency_selector),
price_imp->to_currency());
// Handle separator checkboxes and custom field, only relevant if the file format is csv // Handle separator checkboxes and custom field, only relevant if the file format is csv
if (price_imp->file_format() == GncImpFileFormat::CSV) if (price_imp->file_format() == GncImpFileFormat::CSV)
{ {
@ -1533,9 +1729,9 @@ CsvImpPriceAssist::assist_summary_page_prepare ()
auto text = std::string("<span size=\"medium\"><b>"); auto text = std::string("<span size=\"medium\"><b>");
text += _("The prices were imported from the file '") + m_file_name + "'."; text += _("The prices were imported from the file '") + m_file_name + "'.";
text += _("\n\nThe number of Prices added was ") + std::to_string(price_imp->m_prices_added); text += _("\n\nThe number of Prices added was ") + std::to_string(price_imp->m_prices_added);
text += _(" and ") + std::to_string(price_imp->m_prices_duplicated); text += _(", duplicated was ") + std::to_string(price_imp->m_prices_duplicated);
text += _(" were duplicated."); text += _(" and replaced was ") + std::to_string(price_imp->m_prices_replaced);
text += "</b></span>"; text += ".</b></span>";
gtk_label_set_markup (GTK_LABEL(summary_label), text.c_str()); gtk_label_set_markup (GTK_LABEL(summary_label), text.c_str());
} }

View File

@ -7,6 +7,26 @@
<property name="step_increment">1</property> <property name="step_increment">1</property>
<property name="page_increment">10</property> <property name="page_increment">10</property>
</object> </object>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name string -->
<column type="gchararray"/>
<!-- column-name save -->
<column type="gchararray"/>
<!-- column-name commodity -->
<column type="gpointer"/>
</columns>
</object>
<object class="GtkListStore" id="liststore2">
<columns>
<!-- column-name string -->
<column type="gchararray"/>
<!-- column-name save -->
<column type="gchararray"/>
<!-- column-name currency -->
<column type="gpointer"/>
</columns>
</object>
<object class="GtkAdjustment" id="start_row_adj"> <object class="GtkAdjustment" id="start_row_adj">
<property name="upper">1000</property> <property name="upper">1000</property>
<property name="step_increment">1</property> <property name="step_increment">1</property>
@ -515,7 +535,7 @@ Select location and file name for the Import, then click 'OK'...
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Normally prices are not over written, select this to change that.</property> <property name="tooltip_text" translatable="yes">Normally prices are not over written, select this to change that. This setting is not saved.</property>
<property name="draw_indicator">True</property> <property name="draw_indicator">True</property>
<signal name="toggled" handler="csv_price_imp_preview_overwrite_cb" swapped="no"/> <signal name="toggled" handler="csv_price_imp_preview_overwrite_cb" swapped="no"/>
</object> </object>
@ -804,6 +824,9 @@ For example
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
</child> </child>
<child>
<placeholder/>
</child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -811,6 +834,125 @@ For example
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
<object class="GtkHBox" id="commodity_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkComboBox" id="commodity_cbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="model">liststore1</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Commodity From&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
<object class="GtkHBox" id="currency_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkComboBox" id="currency_cbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="model">liststore1</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext3"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Currency To&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child> <child>
<object class="GtkScrolledWindow" id="scrolledwindow2"> <object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property> <property name="visible">True</property>
@ -860,7 +1002,7 @@ For example
<packing> <packing>
<property name="expand">True</property> <property name="expand">True</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">1</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -902,7 +1044,7 @@ For example
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="padding">5</property> <property name="padding">5</property>
<property name="position">2</property> <property name="position">3</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -930,7 +1072,7 @@ For example
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">3</property> <property name="position">4</property>
</packing> </packing>
</child> </child>
</object> </object>

View File

@ -125,7 +125,6 @@ void GncPriceImport::file_format(GncImpFileFormat format)
auto fwtok = dynamic_cast<GncFwTokenizer*>(m_tokenizer.get()); auto fwtok = dynamic_cast<GncFwTokenizer*>(m_tokenizer.get());
fwtok->columns (m_settings.m_column_widths); fwtok->columns (m_settings.m_column_widths);
} }
} }
GncImpFileFormat GncPriceImport::file_format() GncImpFileFormat GncPriceImport::file_format()
@ -140,6 +139,50 @@ void GncPriceImport::over_write (bool over)
bool GncPriceImport::over_write () { return m_over_write; } bool GncPriceImport::over_write () { return m_over_write; }
/** Sets a from commodity. This is the commodity all import data relates to.
* When a from commodity is set, there can't be any from columns selected
* in the import data.
* @param from_commodity Pointer to a commodity or NULL.
*/
void GncPriceImport::from_commodity (gnc_commodity* from_commodity)
{
m_settings.m_from_commodity = from_commodity;
if (m_settings.m_from_commodity)
{
auto col_type = std::find (m_settings.m_column_types_price.begin(),
m_settings.m_column_types_price.end(), GncPricePropType::FROM_COMMODITY);
if (col_type != m_settings.m_column_types_price.end())
set_column_type_price (col_type -m_settings.m_column_types_price.begin(),
GncPricePropType::NONE);
}
}
gnc_commodity *GncPriceImport::from_commodity () { return m_settings.m_from_commodity; }
/** Sets a to currency. This is the to currency all import data relates to.
* When a to currency is set, there can't be any to currency columns selected
* in the import data.
* @param to_currency Pointer to a commodity or NULL.
*/
void GncPriceImport::to_currency (gnc_commodity* to_currency)
{
m_settings.m_to_currency = to_currency;
if (m_settings.m_to_currency)
{
auto col_type = std::find (m_settings.m_column_types_price.begin(),
m_settings.m_column_types_price.end(), GncPricePropType::TO_CURRENCY);
if (col_type != m_settings.m_column_types_price.end())
set_column_type_price (col_type -m_settings.m_column_types_price.begin(),
GncPricePropType::NONE);
}
}
gnc_commodity *GncPriceImport::to_currency () { return m_settings.m_to_currency; }
void GncPriceImport::reset_formatted_column (std::vector<GncPricePropType>& col_types) void GncPriceImport::reset_formatted_column (std::vector<GncPricePropType>& col_types)
{ {
for (auto col_type: col_types) for (auto col_type: col_types)
@ -241,6 +284,8 @@ void GncPriceImport::settings (const CsvTransSettings& settings)
/* First apply file format as this may recreate the tokenizer */ /* First apply file format as this may recreate the tokenizer */
file_format (settings.m_file_format); file_format (settings.m_file_format);
/* Only then apply the other settings */ /* Only then apply the other settings */
from_commodity (m_settings.m_from_commodity);
to_currency (m_settings.m_to_currency);
m_settings = settings; m_settings = settings;
encoding (m_settings.m_encoding); encoding (m_settings.m_encoding);
@ -402,14 +447,19 @@ void GncPriceImport::verify_column_selections (ErrorListPrice& error_msg)
/* Verify a Currency to column is selected. /* Verify a Currency to column is selected.
*/ */
if (!check_for_column_type(GncPricePropType::CURRENCY_TO)) if (!check_for_column_type(GncPricePropType::TO_CURRENCY))
error_msg.add_error( _("Please select a Currency to column.")); {
if (!m_settings.m_to_currency)
error_msg.add_error( _("Please select a Currency to column or set a Currency in the Currency To field."));
}
/* Verify at least one from column (symbol_from or currency_from) column is selected. /* Verify a Commodity from column is selected.
*/ */
if (!check_for_column_type(GncPricePropType::SYMBOL_FROM) && if (!check_for_column_type(GncPricePropType::FROM_COMMODITY))
!check_for_column_type(GncPricePropType::CURRENCY_FROM)) {
error_msg.add_error( _("Please select a symbol or currency from column.")); 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."));
}
} }
@ -497,6 +547,40 @@ void GncPriceImport::create_price (std::vector<parse_line_t>::iterator& parsed_l
error_message.clear(); error_message.clear();
// Add a CURRENCY_TO property with the default currency to if no currency to column was set by the user
auto line_to_currency = price_props->get_to_currency();
if (!line_to_currency)
{
if (m_settings.m_to_currency)
price_props->set_to_currency(m_settings.m_to_currency);
else
{
// Oops - the user didn't select an Account column *and* we didn't get a default value either!
// Note if you get here this suggests a bug in the code!
error_message = _("No Currency to column selected and no default Currency 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);
}
}
// Add a COMMODITY_FROM property with the default commodity from if no commodity from column was set by the user
auto line_from_commodity = price_props->get_from_commodity();
if (!line_from_commodity)
{
if (m_settings.m_from_commodity)
price_props->set_from_commodity(m_settings.m_from_commodity);
else
{
// Oops - the user didn't select an Account column *and* we didn't get a default value either!
// Note if you get here this suggests a bug in the code!
error_message = _("No Commodity from column selected and no default Commodity 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);
}
}
/* If column parsing was successful, convert price properties into a price. */ /* If column parsing was successful, convert price properties into a price. */
try try
{ {
@ -507,11 +591,12 @@ void GncPriceImport::create_price (std::vector<parse_line_t>::iterator& parsed_l
/* If all went well, add this price to the list. */ /* If all went well, add this price to the list. */
auto price_created = price_props->create_price (book, pdb, m_over_write); auto price_created = price_props->create_price (book, pdb, m_over_write);
//FIXME Need to look at this if (price_created == ADDED)
if (price_created)
m_prices_added++; m_prices_added++;
else else if (price_created == DUPLICATED)
m_prices_duplicated++; m_prices_duplicated++;
else if (price_created == REPLACED)
m_prices_replaced++;
} }
catch (const std::invalid_argument& e) catch (const std::invalid_argument& e)
{ {
@ -537,6 +622,7 @@ void GncPriceImport::create_prices ()
m_prices_added = 0; m_prices_added = 0;
m_prices_duplicated = 0; m_prices_duplicated = 0;
m_prices_replaced = 0;
/* Iterate over all parsed lines */ /* Iterate over all parsed lines */
for (auto parsed_lines_it = m_parsed_lines.begin(); for (auto parsed_lines_it = m_parsed_lines.begin();
@ -550,8 +636,8 @@ void GncPriceImport::create_prices ()
/* Should not throw anymore, otherwise verify needs revision */ /* Should not throw anymore, otherwise verify needs revision */
create_price (parsed_lines_it); create_price (parsed_lines_it);
} }
PINFO("Number of lines is %d, added is %d, duplicates is %d", PINFO("Number of lines is %d, added %d, duplicated %d, replaced %d",
(int)m_parsed_lines.size(), m_prices_added, m_prices_duplicated); (int)m_parsed_lines.size(), m_prices_added, m_prices_duplicated, m_prices_replaced);
} }
bool bool
@ -611,6 +697,14 @@ GncPriceImport::set_column_type_price (uint32_t position, GncPricePropType type,
m_settings.m_column_types_price.at (position) = 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 default set
if (type == GncPricePropType::FROM_COMMODITY)
from_commodity (nullptr);
// If the user has set a Currency to column, we can't have a currency to default set
if (type == GncPricePropType::TO_CURRENCY)
to_currency (nullptr);
/* Update the preparsed data */ /* Update the preparsed data */
for (auto parsed_lines_it = m_parsed_lines.begin(); for (auto parsed_lines_it = m_parsed_lines.begin();
parsed_lines_it != m_parsed_lines.end(); parsed_lines_it != m_parsed_lines.end();

View File

@ -32,7 +32,7 @@
extern "C" { extern "C" {
#include "config.h" #include "config.h"
#include "gnc-commodity.h"
} }
#include <vector> #include <vector>
@ -85,6 +85,12 @@ public:
void over_write (bool over); void over_write (bool over);
bool over_write (); bool over_write ();
void from_commodity (gnc_commodity *from_commodity);
gnc_commodity *from_commodity ();
void to_currency (gnc_commodity *to_currency);
gnc_commodity *to_currency ();
void currency_format (int currency_format); void currency_format (int currency_format);
int currency_format (); int currency_format ();
@ -131,6 +137,7 @@ public:
price properties. */ price properties. */
int m_prices_added; int m_prices_added;
int m_prices_duplicated; int m_prices_duplicated;
int m_prices_replaced;
private: private:
/** A helper function used by create_prices. It will attempt /** A helper function used by create_prices. It will attempt

View File

@ -32,8 +32,6 @@ extern "C" {
#include "engine-helpers.h" #include "engine-helpers.h"
#include "gnc-ui-util.h" #include "gnc-ui-util.h"
#include "gnc-pricedb.h"
} }
#include <string> #include <string>
@ -48,9 +46,8 @@ std::map<GncPricePropType, const char*> gnc_price_col_type_strs = {
{ GncPricePropType::NONE, N_("None") }, { GncPricePropType::NONE, N_("None") },
{ GncPricePropType::DATE, N_("Date") }, { GncPricePropType::DATE, N_("Date") },
{ GncPricePropType::AMOUNT, N_("Amount") }, { GncPricePropType::AMOUNT, N_("Amount") },
{ GncPricePropType::CURRENCY_FROM, N_("Currency From") }, { GncPricePropType::FROM_COMMODITY, N_("Commodity From") },
{ GncPricePropType::CURRENCY_TO, N_("Currency To") }, { GncPricePropType::TO_CURRENCY, N_("Currency To") },
{ GncPricePropType::SYMBOL_FROM, N_("Symbol From") },
}; };
/* Regular expressions used to parse dates per date format */ /* Regular expressions used to parse dates per date format */
@ -243,6 +240,7 @@ gnc_commodity* parse_commodity_price_comm (const std::string& comm_str)
return comm; return comm;
} }
//FIXME can we change above to do below
gnc_commodity * parse_commodity_price_sym (const std::string& sym_str, bool is_currency) gnc_commodity * parse_commodity_price_sym (const std::string& sym_str, bool is_currency)
{ {
if (sym_str.empty()) if (sym_str.empty())
@ -285,8 +283,8 @@ gnc_commodity * parse_commodity_price_sym (const std::string& sym_str, bool is_c
throw std::invalid_argument (_("Value can't be parsed into a valid commodity.")); throw std::invalid_argument (_("Value can't be parsed into a valid commodity."));
else else
{ {
if (gnc_commodity_is_currency (retval) != is_currency) if ((is_currency == true) && (gnc_commodity_is_currency (retval) != true))
throw std::invalid_argument (_("Value parsed into an invalid commodity for column type.")); throw std::invalid_argument (_("Value parsed into an invalid currency for currency column type."));
else else
return retval; return retval;
} }
@ -312,25 +310,18 @@ void GncImportPrice::set (GncPricePropType prop_type, const std::string& value)
m_amount = parse_amount_price (value, m_currency_format); // Will throw if parsing fails m_amount = parse_amount_price (value, m_currency_format); // Will throw if parsing fails
break; break;
case GncPricePropType::CURRENCY_FROM: case GncPricePropType::FROM_COMMODITY:
m_currency_from = boost::none; m_from_commodity = boost::none;
comm = parse_commodity_price_sym (value, true); // Throws if parsing fails
if (comm)
m_currency_from = comm;
break;
case GncPricePropType::CURRENCY_TO:
m_currency_to = boost::none;
comm = parse_commodity_price_sym (value, true); // Throws if parsing fails
if (comm)
m_currency_to = comm;
break;
case GncPricePropType::SYMBOL_FROM:
m_symbol_from = boost::none;
comm = parse_commodity_price_sym (value, false); // Throws if parsing fails comm = parse_commodity_price_sym (value, false); // Throws if parsing fails
if (comm) if (comm)
m_symbol_from = comm; m_from_commodity = comm;
break;
case GncPricePropType::TO_CURRENCY:
m_to_currency = boost::none;
comm = parse_commodity_price_sym (value, true); // Throws if parsing fails
if (comm)
m_to_currency = comm;
break; break;
default: default:
@ -378,15 +369,15 @@ std::string GncImportPrice::verify_essentials (void)
return _("No date column."); return _("No date column.");
else if (m_amount == boost::none) else if (m_amount == boost::none)
return _("No amount column."); return _("No amount column.");
else if (m_currency_to == boost::none) else if (m_to_currency == boost::none)
return _("No Currency to column."); return _("No Currency to column.");
else if ((m_symbol_from == boost::none) && (m_currency_from == boost::none)) else if (m_from_commodity == boost::none)
return _("No from column."); return _("No Commodity from column.");
else else
return std::string(); return std::string();
} }
bool GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over) Result GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
{ {
/* Gently refuse to create the price if the basics are not set correctly /* Gently refuse to create the price if the basics are not set correctly
* This should have been tested before calling this function though! * This should have been tested before calling this function though!
@ -395,47 +386,40 @@ bool GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
if (!check.empty()) if (!check.empty())
{ {
PWARN ("Refusing to create price because essentials not set properly: %s", check.c_str()); PWARN ("Refusing to create price because essentials not set properly: %s", check.c_str());
return false; return FAILED;
} }
Timespec date; Timespec date;
timespecFromTime64 (&date, *m_date); timespecFromTime64 (&date, *m_date);
date.tv_nsec = 0; date.tv_nsec = 0;
#ifdef skip
//FIXME Numeric needs changing, copied from old version...
bool rev = false; bool rev = false;
gnc_commodity *comm_from = nullptr; auto amount = *m_amount;
if (m_currency_from != boost::none) // Currency Import GNCPrice *old_price = gnc_pricedb_lookup_day (pdb, *m_from_commodity, *m_to_currency, date);
if (gnc_commodity_is_currency (*m_from_commodity)) // Currency Import
{ {
// Check for currency in reverse direction. // Check for currency in reverse direction.
GNCPrice *rev_price = gnc_pricedb_lookup_day (pdb, *m_currency_to, *m_currency_from, date); if (old_price != nullptr)
if (rev_price != nullptr) {
rev = true; // Check for price in reverse direction.
gnc_price_unref (rev_price); 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. // Check for price less than 1, reverse if so.
if (gnc_numeric_compare (*m_amount, gnc_numeric_create (1, 1)) != 1) if (*m_amount < GncNumeric(1,1))
rev = true; rev = true;
comm_from = *m_currency_from;
DEBUG("Commodity from is a Currency");
} }
else
comm_from = *m_symbol_from;
DEBUG("Date is %s, Rev is %d, Commodity from is '%s', Currency is '%s', Amount is %s", gnc_print_date (date), DEBUG("Date is %s, Rev is %d, Commodity from is '%s', Currency is '%s', Amount is %s", gnc_print_date (date),
rev, gnc_commodity_get_fullname (comm_from), gnc_commodity_get_fullname (*m_currency_to), rev, gnc_commodity_get_fullname (*m_from_commodity), gnc_commodity_get_fullname (*m_to_currency),
gnc_num_dbg_to_string (*m_amount) ); amount.to_string().c_str());
GNCPrice *old_price = nullptr; Result ret_val = ADDED;
// Should the commodities be reversed
if (rev)
old_price = gnc_pricedb_lookup_day (pdb, *m_currency_to, comm_from, date);
else
old_price = gnc_pricedb_lookup_day (pdb, comm_from, *m_currency_to, date);
// Should old price be over writen // Should old price be over writen
if ((old_price != nullptr) && (over == true)) if ((old_price != nullptr) && (over == true))
@ -444,31 +428,29 @@ bool GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
gnc_pricedb_remove_price (pdb, old_price); gnc_pricedb_remove_price (pdb, old_price);
gnc_price_unref (old_price); gnc_price_unref (old_price);
old_price = nullptr; old_price = nullptr;
ret_val = REPLACED;
} }
#endif
bool ret_val = true;
#ifdef skip
// Create the new price // Create the new price
if (old_price == nullptr) if (old_price == nullptr)
{ {
DEBUG("Create"); DEBUG("Create");
GNCPrice *price = gnc_price_create (book); GNCPrice *price = gnc_price_create (book);
gnc_price_begin_edit (price); gnc_price_begin_edit (price);
if (rev) if (rev)
{ {
gnc_price_set_commodity (price, *m_currency_to); amount = amount.inv(); //invert the amount
gnc_price_set_currency (price, comm_from); gnc_price_set_commodity (price, *m_to_currency);
*m_amount = gnc_numeric_convert (gnc_numeric_invert (*m_amount), gnc_price_set_currency (price, *m_from_commodity);
CURRENCY_DENOM, GNC_HOW_RND_ROUND_HALF_UP);
gnc_price_set_value (price, *m_amount);
} }
else else
{ {
gnc_price_set_commodity (price, comm_from); gnc_price_set_commodity (price, *m_from_commodity);
gnc_price_set_currency (price, *m_currency_to); gnc_price_set_currency (price, *m_to_currency);
gnc_price_set_value (price, *m_amount);
} }
auto amount_conv = amount.convert<RoundType::half_up>(CURRENCY_DENOM);
gnc_price_set_value (price, static_cast<gnc_numeric>(amount_conv));
gnc_price_set_time (price, date); gnc_price_set_time (price, date);
gnc_price_set_source (price, PRICE_SOURCE_USER_PRICE); gnc_price_set_source (price, PRICE_SOURCE_USER_PRICE);
//FIXME Not sure which one gnc_price_set_source (price, PRICE_SOURCE_FQ); //FIXME Not sure which one gnc_price_set_source (price, PRICE_SOURCE_FQ);
@ -479,15 +461,15 @@ bool GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over)
gnc_price_unref (price); gnc_price_unref (price);
if (perr == false) if (perr == false)
throw std::invalid_argument (_("Failed to create price from selected columns.")); throw std::invalid_argument (_("Failed to create price from selected columns."));
//FIXME Not sure about this, should this be a PWARN //FIXME Not sure about this, should this be a PWARN
} }
else else
{
#endif gnc_price_unref (old_price);
ret_val = false; ret_val = DUPLICATED;
}
return ret_val; return ret_val;
} }

View File

@ -49,12 +49,13 @@ enum class GncPricePropType {
NONE, NONE,
DATE, DATE,
AMOUNT, AMOUNT,
CURRENCY_FROM, FROM_COMMODITY,
CURRENCY_TO, TO_CURRENCY,
SYMBOL_FROM, PRICE_PROPS = TO_CURRENCY
PRICE_PROPS = SYMBOL_FROM
}; };
enum Result { FAILED, ADDED, DUPLICATED, REPLACED };
/** Maps all column types to a string representation. /** Maps all column types to a string representation.
* The actual definition is in gnc-price-props.cpp. * The actual definition is in gnc-price-props.cpp.
* Attention: that definition should be adjusted for any * Attention: that definition should be adjusted for any
@ -91,7 +92,14 @@ public:
void set_currency_format (int currency_format) { m_currency_format = currency_format ;} void set_currency_format (int currency_format) { m_currency_format = currency_format ;}
void reset (GncPricePropType prop_type); void reset (GncPricePropType prop_type);
std::string verify_essentials (void); std::string verify_essentials (void);
bool create_price (QofBook* book, GNCPriceDB *pdb, bool over); Result create_price (QofBook* book, GNCPriceDB *pdb, bool over);
gnc_commodity* get_from_commodity () { if (m_from_commodity) return *m_from_commodity; else return nullptr; }
void set_from_commodity (gnc_commodity* comm) { if (comm) m_from_commodity = comm; else m_from_commodity = boost::none; }
gnc_commodity* get_to_currency () { if (m_to_currency) return *m_to_currency; else return nullptr; }
void set_to_currency (gnc_commodity* curr) { if (curr) m_to_currency = curr; else m_to_currency = boost::none; }
std::string errors(); std::string errors();
private: private:
@ -99,9 +107,8 @@ private:
int m_currency_format; int m_currency_format;
boost::optional<time64> m_date; boost::optional<time64> m_date;
boost::optional<GncNumeric> m_amount; boost::optional<GncNumeric> m_amount;
boost::optional<gnc_commodity*> m_currency_from; boost::optional<gnc_commodity*> m_from_commodity;
boost::optional<gnc_commodity*> m_currency_to; boost::optional<gnc_commodity*> m_to_currency;
boost::optional<gnc_commodity*> m_symbol_from;
bool created = false; bool created = false;
std::map<GncPricePropType, std::string> m_errors; std::map<GncPricePropType, std::string> m_errors;