[glom/modification: 25/33] record_new(): Take a table_name.
- From: Murray Cumming <murrayc src gnome org>
- To: svn-commits-list gnome org
- Subject: [glom/modification: 25/33] record_new(): Take a table_name.
- Date: Thu, 4 Jun 2009 17:01:25 -0400 (EDT)
commit 03cd46792ec4eb4bc305fc738a4883b67a4dcde4
Author: Murray Cumming <murrayc murrayc com>
Date: Fri May 8 00:01:09 2009 +0200
record_new(): Take a table_name.
* glom/base_db_table_data.[h|cc]: record_new(): Take a table_name,
so we can use this to add related records too, to make sure we get all
the necessary default values, lookups, calculatoins, and extra field
values, and generally reduce duplication.
add_related_record_for_field():
* glom/dialog_import_csv_progress.cc: on_idle_import():
* glom/mode_data/box_data_details.cc: on_button_new(),
on_flowtable_field_edited():
* glom/utility_widgets/db_adddel/db_adddel.cc: user_added(): Adapt.
---
ChangeLog | 11 ++
glom/base_db.cc | 5 +-
glom/base_db_table_data.cc | 133 +++++++++++++++++++++------
glom/base_db_table_data.h | 9 ++-
glom/dialog_import_csv_progress.cc | 6 +-
glom/mode_data/box_data_details.cc | 6 +-
glom/utility_widgets/db_adddel/db_adddel.cc | 2 +-
7 files changed, 135 insertions(+), 37 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 6345249..9e09f05 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -159,6 +159,17 @@
Added private update_go_to_details_button_sensitivity() method and
called it whenever the value is changed by the user or set via
set_value(). Fixes bug #565023.
+ record_new(): Take a table_name.
+
+ * glom/base_db_table_data.[h|cc]: record_new(): Take a table_name,
+ so we can use this to add related records too, to make sure we get all
+ the necessary default values, lookups, calculatoins, and extra field
+ values, and generally reduce duplication.
+ add_related_record_for_field():
+ * glom/dialog_import_csv_progress.cc: on_idle_import():
+ * glom/mode_data/box_data_details.cc: on_button_new(),
+ on_flowtable_field_edited():
+ * glom/utility_widgets/db_adddel/db_adddel.cc: user_added(): Adapt.
2009-05-07 Murray Cumming <murrayc murrayc com>
diff --git a/glom/base_db.cc b/glom/base_db.cc
index 932436b..c07b90e 100644
--- a/glom/base_db.cc
+++ b/glom/base_db.cc
@@ -92,7 +92,7 @@ private:
};
//Intializing static members:
-Base_DB::type_extra_field_values Base_DB::m_extra_field_values;
+Base_DB::type_extra_field_values Base_DB::m_extra_modification_field_values;
Base_DB::Base_DB()
@@ -1651,7 +1651,7 @@ bool Base_DB::insert_example_data(const Glib::ustring& table_name) const
strNames += field->get_name();
- Gnome::Gda::Value value = row_data[i];
+ const Gnome::Gda::Value value = row_data[i];
//std::cout << " DEBUG: example: field=" << field->get_name() << ", value=" << value.to_string() << std::endl;
//Add a SQL parameter for the value:
@@ -1682,6 +1682,7 @@ bool Base_DB::insert_example_data(const Glib::ustring& table_name) const
if((*iter)->get_auto_increment())
recalculate_next_auto_increment_value(table_name, (*iter)->get_name());
}
+
return insert_succeeded;
}
diff --git a/glom/base_db_table_data.cc b/glom/base_db_table_data.cc
index e1e870d..e75ff3a 100644
--- a/glom/base_db_table_data.cc
+++ b/glom/base_db_table_data.cc
@@ -68,20 +68,91 @@ Gtk::TreeModel::iterator Base_DB_Table_Data::get_row_selected()
return Gtk::TreeModel::iterator();
}
+/** A predicate for use with std::find_if() to find a std::pair whose
+ * first item is the same field.
+ */
+class predicate_pair_has_field
+{
+public:
+ predicate_pair_has_field(const sharedptr<const Field>& field)
+ {
+ m_field = field;
+ }
+
+ template <class T_Second>
+ bool operator() (const std::pair<sharedptr<Field>, T_Second>& element)
+ {
+ sharedptr<Field> field = element.first;
+
+ if(!field && !m_field)
+ return true;
-bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Value& primary_key_value)
+ if(!field || !m_field)
+ return false;
+
+ //TODO: Check more than just the name:
+ return (m_field->get_name() == field->get_name());
+ }
+
+private:
+ sharedptr<const Field> m_field;
+};
+
+
+bool Base_DB_Table_Data::record_new(const Glib::ustring& table_name, bool use_entered_data, const Gnome::Gda::Value& primary_key_value, const type_field_values& field_values)
{
- sharedptr<const Field> fieldPrimaryKey = get_field_primary_key();
+ //TODO: Remove these ugly optimizations:
+ sharedptr<const Field> fieldPrimaryKey;
+ if(table_name == m_table_name)
+ {
+ //An optimization:
+ fieldPrimaryKey = get_field_primary_key();
+ }
+ else
+ fieldPrimaryKey = get_field_primary_key_for_table(table_name);
+
const Glib::ustring primary_key_name = fieldPrimaryKey->get_name();
- type_vecLayoutFields fieldsToAdd = m_FieldsShown;
- if(m_TableFields.empty())
- m_TableFields = get_fields_for_table(m_table_name);
+ //Default to adding data for all fields that are on the layout,
+ //if they contain data:
+ type_vecLayoutFields fieldsToAdd;
+ if(table_name == m_table_name)
+ {
+ //An optimization:
+ //get_table_fields_to_show() needs knowledge of a layout,
+ //which is only in a derived class,
+ //but that class will have already set m_FieldsShown.
+ //if(!m_FieldsShown.empty())
+ // m_FieldsShown = get_table_fields_to_show(table_name);
+
+ fieldsToAdd = m_FieldsShown;
+ }
+
+ //use_entered_data is not expected to work if table_name != m_table_name:
+ //if(fieldsToAdd
+ // fieldsToAdd = get_table_fields_to_show(table_name);
+
+
+ //Get a list of all fields in the table,
+ //not just the ones on the layout:
+ type_vec_fields all_fields;
+ if(table_name == m_table_name)
+ {
+ //An optimization:
+ if(m_TableFields.empty())
+ m_TableFields = get_fields_for_table(table_name);
+
+ all_fields = m_TableFields;
+ }
+
+ if(all_fields.empty())
+ all_fields = get_fields_for_table(table_name);
- //Add values for all fields, not just the shown ones:
+
+ //Add values for all fields that default to something, not just the shown ones:
//For instance, we must always add the primary key, and fields with default/calculated/lookup values:
- for(type_vec_fields::const_iterator iter = m_TableFields.begin(); iter != m_TableFields.end(); ++iter)
+ for(type_vec_fields::const_iterator iter = all_fields.begin(); iter != all_fields.end(); ++iter)
{
//TODO: Search for the non-related field with the name, not just the field with the name:
type_vecLayoutFields::const_iterator iterFind = std::find_if(fieldsToAdd.begin(), fieldsToAdd.end(), predicate_FieldHasName<LayoutItem_Field>((*iter)->get_name()));
@@ -101,20 +172,34 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
for(type_vecLayoutFields::const_iterator iter = fieldsToAdd.begin(); iter != fieldsToAdd.end(); ++iter)
{
sharedptr<LayoutItem_Field> layout_item = *iter;
+ if(!layout_item)
+ continue;
+
+ const sharedptr<const Field>& field = layout_item->get_full_field_details();
+ if(!field)
+ continue;
//If the user did not enter something in this field:
- Gnome::Gda::Value value = get_entered_field_data(layout_item);
+ Gnome::Gda::Value value;
+
+ //If the caller supplied a field value the use it,
+ //otherwise try to get it from the UI:
+ type_field_values::const_iterator iterFind =
+ std::find_if(field_values.begin(), field_values.end(), predicate_pair_has_field(field));
+ if(iterFind != field_values.end())
+ value = iterFind->second;
+ else
+ value = get_entered_field_data(layout_item);
if(Conversions::value_is_empty(value)) //This deals with empty strings too.
{
- const sharedptr<const Field>& field = layout_item->get_full_field_details();
- if(field)
+ if(field) //TODO: Remove this check: we already check it above.
{
//If the default value should be calculated, then calculate it:
if(field->get_has_calculation())
{
const Glib::ustring calculation = field->get_calculation();
- const type_map_fields field_values = get_record_field_values_for_calculation(m_table_name, fieldPrimaryKey, primary_key_value);
+ const type_map_fields field_values = get_record_field_values_for_calculation(table_name, fieldPrimaryKey, primary_key_value);
//We need the connection when we run the script, so that the script may use it.
#ifdef GLIBMM_EXCEPTIONS_ENABLED
@@ -128,7 +213,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
// Don't evaluate function on error
#endif // GLIBMM_EXCEPTIONS_ENABLED
- const Gnome::Gda::Value value = glom_evaluate_python_function_implementation(field->get_glom_type(), calculation, field_values, document, m_table_name, sharedconnection->get_gda_connection());
+ const Gnome::Gda::Value value = glom_evaluate_python_function_implementation(field->get_glom_type(), calculation, field_values, document, table_name, sharedconnection->get_gda_connection());
set_entered_field_data(layout_item, value);
#ifndef GLIBMM_EXCEPTIONS_ENABLED
}
@@ -206,7 +291,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
//Check whether the value meets uniqueness constraints:
if(field->get_primary_key() || field->get_unique_key())
{
- if(!get_field_value_is_unique(m_table_name, layout_item, value))
+ if(!get_field_value_is_unique(table_name, layout_item, value))
{
//Ignore this field value. TODO: Warn the user about it.
}
@@ -235,7 +320,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
//Put it all together to create the record with these field values:
if(!strNames.empty() && !strValues.empty())
{
- const Glib::ustring strQuery = "INSERT INTO \"" + m_table_name + "\" (" + strNames + ") VALUES (" + strValues + ")";
+ const Glib::ustring strQuery = "INSERT INTO \"" + table_name + "\" (" + strNames + ") VALUES (" + strValues + ")";
const bool test = query_execute(strQuery, params);
if(!test)
std::cerr << "Box_Data::record_new(): INSERT failed." << std::endl;
@@ -252,7 +337,7 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
//TODO_Performance: We just set this with set_entered_field_data() above. Maybe we could just remember it.
const Gnome::Gda::Value field_value = get_entered_field_data(layout_item);
- LayoutFieldInRecord field_in_record(layout_item, m_table_name, fieldPrimaryKey, primary_key_value);
+ LayoutFieldInRecord field_in_record(layout_item, table_name, fieldPrimaryKey, primary_key_value);
//Get-and-set values for lookup fields, if this field triggers those relationships:
do_lookups(field_in_record, row, field_value);
@@ -368,9 +453,6 @@ bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const Layo
}
else
{
- //TODO: Calculate values, and do lookups?
- //TODO: Extra creation fields.
-
//Create the related record:
if(key_is_auto_increment)
{
@@ -379,20 +461,15 @@ bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const Layo
//Generate the new key value.
}
- //TODO: Use record_new() to avoid (incomplete) duplication?
- Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
- params->add_holder(primary_key_field->get_holder(primary_key_value));
- const Glib::ustring strQuery = "INSERT INTO \"" + relationship->get_to_table() + "\" (\"" + primary_key_field->get_name() + "\") VALUES (" + primary_key_field->get_gda_holder_string() + ")";
- const bool test = query_execute(strQuery, params);
- if(!test)
+ const bool added = record_new(relationship->get_to_table(), false /* use_entered_field_data */, primary_key_value);
+ if(!added)
{
- std::cerr << "Base_DB_Table_Data::add_related_record_for_field(): INSERT failed." << std::endl;
- return false;
+ std::cerr << "Base_DB_Table_Data::add_related_record_for_field(): record_new() failed." << std::endl;
}
if(key_is_auto_increment)
{
- //Set the key in the parent table
+ //Set the key in the parent table:
sharedptr<LayoutItem_Field> item_from_key = sharedptr<LayoutItem_Field>::create();
item_from_key->set_name(relationship->get_from_field());
@@ -423,6 +500,8 @@ bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const Layo
}
else
{
+ Glib::RefPtr<Gnome::Gda::Set> params = Gnome::Gda::Set::create();
+ params->add_holder(primary_key_field->get_holder(primary_key_value));
params->add_holder(parent_primary_key_field->get_holder(parent_primary_key_value));
const Glib::ustring strQuery = "UPDATE \"" + relationship->get_from_table() + "\" SET \"" + relationship->get_from_field() + "\" = " + primary_key_field->get_gda_holder_string() +
" WHERE \"" + relationship->get_from_table() + "\".\"" + parent_primary_key_field->get_name() + "\" = " + parent_primary_key_field->get_gda_holder_string();
diff --git a/glom/base_db_table_data.h b/glom/base_db_table_data.h
index ce6882a..1f47a5e 100644
--- a/glom/base_db_table_data.h
+++ b/glom/base_db_table_data.h
@@ -51,10 +51,17 @@ public:
protected:
+ typedef std::pair< sharedptr<Field>, Gnome::Gda::Value> type_field_and_value;
+ typedef std::list<type_field_and_value> type_field_values;
+
/** Create a new record with all the entered field values from the currently-active details/row.
+ * @param The table to which to add a new record.
+ * @param use_entered_data Whether the record should contain data already entered in the UI by the user, if table_name is m_table_name.
+ * @param primary_key_value The new primary key value for the new record. Otherwise the primary key value must be in the entered data or in the @a field_values parameter.
+ * @param field_values Values to use for fields, instead of entered data.
* @result true if the record was added to the database.
*/
- bool record_new(bool use_entered_data = true, const Gnome::Gda::Value& primary_key_value = Gnome::Gda::Value());
+ bool record_new(const Glib::ustring& table_name, bool use_entered_data = true, const Gnome::Gda::Value& primary_key_value = Gnome::Gda::Value(), const type_field_values& field_values = type_field_values());
Gnome::Gda::Value get_entered_field_data_field_only(const sharedptr<const Field>& field) const;
virtual Gnome::Gda::Value get_entered_field_data(const sharedptr<const LayoutItem_Field>& field) const;
diff --git a/glom/dialog_import_csv_progress.cc b/glom/dialog_import_csv_progress.cc
index ec73835..9e68870 100644
--- a/glom/dialog_import_csv_progress.cc
+++ b/glom/dialog_import_csv_progress.cc
@@ -57,7 +57,7 @@ void Dialog_Import_CSV_Progress::import(Dialog_Import_CSV& data_source)
{
case Dialog_Import_CSV::PARSING:
// Wait for the parsing to finish. We do not start importing before the file has been
- // parsed completely since we would not to rollback our changes in case of a
+ // parsed completely since we would not be able to roll back our changes in case of a
// parsing error.
m_progress_bar->set_text(Glib::ustring::compose(_("Parsing CSV file %1"), data_source.get_filename()));
m_ready_connection = data_source.signal_state_changed().connect(sigc::mem_fun(*this, &Dialog_Import_CSV_Progress::on_state_changed));
@@ -195,13 +195,13 @@ bool Dialog_Import_CSV_Progress::on_idle_import()
if(Glom::Conversions::value_is_empty(primary_key_value))
{
- Glib::ustring message(Glib::ustring::compose(_("Error importing row %1: Cannot import the row because the primary key is empty.\n"), m_current_row + 1));
+ const Glib::ustring message(Glib::ustring::compose(_("Error importing row %1: Cannot import the row because the primary key is empty.\n"), m_current_row + 1));
add_text(message);
}
else
{
std::cout << "Dialog_Import_CSV_Progress::on_idle_import(): Calling record_new() with primary_key_value=" << primary_key_value.to_string() << " ..." << std::endl;
- record_new(true /* use_entered_data */, primary_key_value);
+ record_new(m_table_name, true /* use_entered_data */, primary_key_value);
std::cout << "Dialog_Import_CSV_Progress::on_idle_import(): ... Finished calling record_new()" << std::endl;
}
diff --git a/glom/mode_data/box_data_details.cc b/glom/mode_data/box_data_details.cc
index b7917e4..98d9c83 100644
--- a/glom/mode_data/box_data_details.cc
+++ b/glom/mode_data/box_data_details.cc
@@ -419,7 +419,7 @@ void Box_Data_Details::on_button_new()
//Just make a new record, and show it:
Gnome::Gda::Value primary_key_value = get_next_auto_increment_value(m_table_name, m_field_primary_key->get_name()); //TODO: This should return a Gda::Value
- record_new(false /* use entered field data */, primary_key_value);
+ record_new(m_table_name, false /* use entered field data */, primary_key_value);
refresh_data_from_database_with_primary_key(primary_key_value);
}
else
@@ -849,7 +849,7 @@ void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutIte
//Make a new record, and show it:
Gnome::Gda::Value primary_key_value = get_next_auto_increment_value(m_table_name, m_field_primary_key->get_name());
- record_new(true /* use entered field data */, primary_key_value);
+ record_new(m_table_name, true /* use entered field data */, primary_key_value);
refresh_data_from_database_with_primary_key(primary_key_value);
}
}
@@ -870,7 +870,7 @@ void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutIte
//Create new record with this primary key,
//and all the other field values too.
//see comments after 'else':
- record_new(true /* use entered field data */);
+ record_new(m_table_name, true /* use entered field data */);
}
}
else
diff --git a/glom/utility_widgets/db_adddel/db_adddel.cc b/glom/utility_widgets/db_adddel/db_adddel.cc
index 5c10f39..8b35679 100644
--- a/glom/utility_widgets/db_adddel/db_adddel.cc
+++ b/glom/utility_widgets/db_adddel/db_adddel.cc
@@ -2382,7 +2382,7 @@ void DbAddDel::user_added(const Gtk::TreeModel::iterator& row)
if(m_find_mode)
return;
- const bool added = record_new(true /* use entered field data*/, primary_key_value);
+ const bool added = record_new(m_table_name, true /* use entered field data*/, primary_key_value);
if(added)
{
//Save the primary key value for later use:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]