[glom/feature_choices_show_all] List: Choices with !show_all: Update the list when the from_field changes.



commit 8d38f199264fd836a41251a34cc86ec85d2608de
Author: Murray Cumming <murrayc murrayc com>
Date:   Fri Aug 6 00:55:22 2010 +0200

    List: Choices with !show_all: Update the list when the from_field changes.
    
    	* glom/libglom/utils.[h|cc]: Added a get_choice_values() overload that
    	takes the foreign_key.
    	* glom/utility_widgets/db_adddel/db_adddel.[h|cc]: Added get_choice_index()
    	to get the affected choice lists when a field value changes.
    	Added refresh_cell_choices_data_from_database_with_foreign_key() to update
    	these lists.
    	set_value(): Use these methods to update choice lists when appropriate,
    	as already happens in the Details view.

 ChangeLog                                   |   15 +++-
 glom/libglom/utils.cc                       |  127 +++++++++++++++++++++-
 glom/libglom/utils.h                        |    2 +
 glom/mode_data/datawidget/combochoices.cc   |    6 +-
 glom/mode_data/flowtablewithfields.cc       |    2 +-
 glom/utility_widgets/db_adddel/db_adddel.cc |  158 ++++++++++++++++++++++-----
 glom/utility_widgets/db_adddel/db_adddel.h  |    8 +-
 7 files changed, 282 insertions(+), 36 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index e0237bc..5063778 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2010-08-06  Murray Cumming  <murrayc murrayc com>
+
+	List: Choices with !show_all: Update the list when the from_field changes.
+
+	* glom/libglom/utils.[h|cc]: Added a get_choice_values() overload that 
+	takes the foreign_key.
+	* glom/utility_widgets/db_adddel/db_adddel.[h|cc]: Added get_choice_index() 
+	to get the affected choice lists when a field value changes.
+	Added refresh_cell_choices_data_from_database_with_foreign_key() to update 
+	these lists.
+	set_value(): Use these methods to update choice lists when appropriate, 
+	as already happens in the Details view.
+
 2010-08-05  Murray Cumming  <murrayc murrayc com>
 
 	List view: When a value is edited, update other instances of the same field.
@@ -19,7 +32,7 @@
 
 2010-08-04  Murray Cumming  <murrayc murrayc com>
 
-	Choices with !show_all: Update the list when the from_field changes.
+	Details: Choices with !show_all: Update the list when the from_field changes.
 
 	* glom/libglom/data_structure/layout/fieldformatting.[h|cc]: Renamed
 	set/get_choices() to set/get_choices_related().
diff --git a/glom/libglom/utils.cc b/glom/libglom/utils.cc
index e6df8a8..f8f6829 100644
--- a/glom/libglom/utils.cc
+++ b/glom/libglom/utils.cc
@@ -485,7 +485,7 @@ Utils::type_list_values_with_second Utils::get_choice_values(const sharedptr<con
   field->get_formatting_used().get_choices_related(choice_relationship, choice_field, choice_second, choice_show_all);
   if(!choice_relationship || choice_field.empty())
   {
-    //std::cout <<" debug: field has no choices: " << field->get_name() << std::endl;
+    std::cout <<" debug: field has no choices: " << field->get_name() << std::endl;
     return list_values;
   }
   
@@ -520,8 +520,11 @@ Utils::type_list_values_with_second Utils::get_choice_values(const sharedptr<con
   sharedptr<SharedConnection> connection = ConnectionPool::get_instance()->connect();
 
   if(!connection)
+  {
+    std::cerr << G_STRFUNC << ": No connection." << std::endl;
     return list_values;
-
+  }
+  
   const std::string sql_query =
     sqlbuilder_get_full_query(builder);
   //std::cout << "get_choice_values: Executing SQL: " << sql_query << std::endl;
@@ -552,6 +555,126 @@ Utils::type_list_values_with_second Utils::get_choice_values(const sharedptr<con
   return list_values;
 }
 
+Utils::type_list_values_with_second Utils::get_choice_values(Document* document, const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& foreign_key_value, sharedptr<LayoutItem_Field>& layout_choice_first, sharedptr<LayoutItem_Field>& layout_choice_second)
+{
+  //Initialize output parameters:
+  layout_choice_first = sharedptr<LayoutItem_Field>();
+  layout_choice_second = sharedptr<LayoutItem_Field>();
+    
+  //TODO: Reduce duplication between this and get_choice_values(field).
+  
+  type_list_values_with_second result;
+  
+  if(Conversions::value_is_empty(foreign_key_value))
+  {
+    std::cout << G_STRFUNC << "debug: foreign_key_value is empty." << std::endl;
+    return result;
+  }
+  
+  const FieldFormatting& format = field->get_formatting_used();
+  sharedptr<const Relationship> choice_relationship;
+  Glib::ustring choice_field, choice_second;
+  bool choice_show_all = false;
+  format.get_choices_related(choice_relationship, choice_field, choice_second, choice_show_all);
+  
+  if(!choice_relationship)
+  {
+    std::cerr << G_STRFUNC << ": !choice_relationship." << std::endl;
+    return result;
+  }
+
+  const Glib::ustring to_table = choice_relationship->get_to_table();
+  sharedptr<const Field> field_details = document->get_field(to_table, choice_field);
+  if(!field_details)
+  {
+    std::cerr << G_STRFUNC << ": !field_details." << std::endl;
+    return result;
+  }
+  
+  layout_choice_first = sharedptr<LayoutItem_Field>::create();
+  layout_choice_first->set_full_field_details(field_details);
+  
+  
+  if(!choice_second.empty())
+  {
+    sharedptr<const Field> field_details = document->get_field(to_table, choice_second);
+    if(!field_details)
+    {
+      std::cerr << G_STRFUNC << ": !field_details (second)." << std::endl;
+      return result;
+    }
+    
+    layout_choice_second->set_full_field_details(field_details);
+  }
+ 
+  
+  
+  Utils::type_vecLayoutFields fields;
+  fields.push_back(layout_choice_first);
+  if(layout_choice_second)
+    fields.push_back(layout_choice_second);
+    
+  sharedptr<Field> to_field = document->get_field(to_table, choice_relationship->get_to_field());
+    
+  if(!to_field)
+  {
+    std::cerr << G_STRFUNC << ": to_field is null." << std::endl;
+  }
+    
+  //TODO: Support related relationships (in the UI too):
+  Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Utils::build_sql_select_with_key(
+    to_table,
+    fields,
+    to_field,
+    foreign_key_value);
+    
+  if(!builder)
+  {
+    std::cerr << G_STRFUNC << ": builder is null." << std::endl;
+    return result;
+  }
+
+  //TODO: builder->select_order_by(choice_field_id);
+
+  //Connect to database and get the related values:
+  sharedptr<SharedConnection> connection = ConnectionPool::get_instance()->connect();
+
+  if(!connection)
+  {
+    std::cerr << G_STRFUNC << ": connection is null." << std::endl;
+    return result;
+  }
+
+  const std::string sql_query =
+    Utils::sqlbuilder_get_full_query(builder);
+  //std::cout << "debug: sql_query=" << sql_query << std::endl;
+  Glib::RefPtr<Gnome::Gda::DataModel> datamodel = connection->get_gda_connection()->statement_execute_select(sql_query);
+
+  if(datamodel)
+  {
+    const guint count = datamodel->get_n_rows();
+    const guint cols_count = datamodel->get_n_columns();
+    for(guint row = 0; row < count; ++row)
+    {
+
+      std::pair<Gnome::Gda::Value, Gnome::Gda::Value> itempair;
+      itempair.first = datamodel->get_value_at(0, row);
+
+      if(layout_choice_second && (cols_count > 1))
+        itempair.second = datamodel->get_value_at(1, row);
+
+      result.push_back(itempair);
+    }
+  }
+  else
+  {
+      std::cerr << G_STRFUNC << ": Error while executing SQL" << std::endl <<
+                   "  " <<  sql_query << std::endl;
+      return result;
+  }
+
+  return result;
+}
 
 Glib::ustring Utils::create_name_from_title(const Glib::ustring& title)
 {
diff --git a/glom/libglom/utils.h b/glom/libglom/utils.h
index 72429c5..493cbcf 100644
--- a/glom/libglom/utils.h
+++ b/glom/libglom/utils.h
@@ -110,6 +110,8 @@ Gnome::Gda::SqlExpr get_find_where_clause_quick(Document* document, const Glib::
 typedef std::list< std::pair<Gnome::Gda::Value, Gnome::Gda::Value> > type_list_values_with_second;
 type_list_values_with_second get_choice_values(const sharedptr<const LayoutItem_Field>& field);
 
+type_list_values_with_second get_choice_values(Document* document, const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& foreign_key_value, sharedptr<LayoutItem_Field>& layout_choice_first, sharedptr<LayoutItem_Field>& layout_choice_second);
+
 /// Get the full query string suitable for use with std::cout.
 std::string sqlbuilder_get_full_query(
   const Glib::RefPtr<Gnome::Gda::Connection>& connection,
diff --git a/glom/mode_data/datawidget/combochoices.cc b/glom/mode_data/datawidget/combochoices.cc
index f010410..8b1f5ee 100644
--- a/glom/mode_data/datawidget/combochoices.cc
+++ b/glom/mode_data/datawidget/combochoices.cc
@@ -61,8 +61,10 @@ bool ComboChoices::refresh_data_from_database_with_foreign_key(const Gnome::Gda:
 
   if(Conversions::value_is_empty(foreign_key_value))
   {
-    std::cerr << G_STRFUNC << ": foreign_key_value is empty." << std::endl;
-    return false;
+    //Clear the choices list:
+    type_list_values_with_second list_values;
+    set_choices_with_second(list_values);
+    return true;
   }
    
   if(m_related_show_all)
diff --git a/glom/mode_data/flowtablewithfields.cc b/glom/mode_data/flowtablewithfields.cc
index e26f0f3..e1612f3 100644
--- a/glom/mode_data/flowtablewithfields.cc
+++ b/glom/mode_data/flowtablewithfields.cc
@@ -947,7 +947,7 @@ FlowTableWithFields::type_choice_widgets FlowTableWithFields::get_choice_widgets
     FlowTableWithFields* subtable = *iter;
     if(subtable)
     {
-      type_choice_widgets sub_list = subtable->get_choice_widgets(from_key);
+      const type_choice_widgets sub_list = subtable->get_choice_widgets(from_key);
       if(!sub_list.empty())
       {
         //Add to the main result:
diff --git a/glom/utility_widgets/db_adddel/db_adddel.cc b/glom/utility_widgets/db_adddel/db_adddel.cc
index e1cb37e..d2fe609 100644
--- a/glom/utility_widgets/db_adddel/db_adddel.cc
+++ b/glom/utility_widgets/db_adddel/db_adddel.cc
@@ -833,7 +833,7 @@ Gtk::CellRenderer* DbAddDel::construct_specified_columns_cellrenderer(const shar
       {
         sharedptr<const Relationship> choice_relationship;
         Glib::ustring choice_field, choice_second;
-        bool choice_show_all; //TODO: Use this.
+        bool choice_show_all;
         item_field->get_formatting_used().get_choices_related(choice_relationship, choice_field, choice_second, choice_show_all);
 
         if(choice_relationship && !choice_field.empty())
@@ -857,16 +857,19 @@ Gtk::CellRenderer* DbAddDel::construct_specified_columns_cellrenderer(const shar
           }
 
           //TODO: Update this when the relationship's field value changes:
-          Utils::type_list_values_with_second list_values = Utils::get_choice_values(item_field);
-          for(Utils::type_list_values_with_second::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
+          if(choice_show_all) //Otherwise it must change whenever the relationships's ID value changes.
           {
-            const Glib::ustring first = Conversions::get_text_for_gda_value(item_field->get_glom_type(), iter->first, item_field->get_formatting_used().m_numeric_format);
+            Utils::type_list_values_with_second list_values = Utils::get_choice_values(item_field);
+            for(Utils::type_list_values_with_second::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
+            {
+              const Glib::ustring first = Conversions::get_text_for_gda_value(item_field->get_glom_type(), iter->first, item_field->get_formatting_used().m_numeric_format);
 
-            Glib::ustring second;
-            if(use_second)
-              second = Conversions::get_text_for_gda_value(layout_field_second->get_glom_type(), iter->second, layout_field_second->get_formatting_used().m_numeric_format);
+              Glib::ustring second;
+              if(use_second)
+                second = Conversions::get_text_for_gda_value(layout_field_second->get_glom_type(), iter->second, layout_field_second->get_formatting_used().m_numeric_format);
 
-              pCellRendererCombo->append_list_item(first, second);
+                pCellRendererCombo->append_list_item(first, second);
+            }
           }
         }
       }
@@ -1216,31 +1219,35 @@ void DbAddDel::set_value(const Gtk::TreeModel::iterator& iter, const sharedptr<c
   InnerIgnore innerIgnore(this);
 
   if(!m_refListStore)
-    g_warning("DbAddDel::set_value: No model.");
-  else
   {
-    Gtk::TreeModel::Row treerow = *iter;
-    if(treerow)
-    {
-      const type_list_indexes list_indexes = get_data_model_column_index(layout_item, set_specified_field_layout);
-      for(type_list_indexes::const_iterator iter = list_indexes.begin(); iter != list_indexes.end(); ++iter)
-      {
-        const guint treemodel_col = *iter + get_count_hidden_system_columns();
-        treerow.set_value(treemodel_col, value);
+    std::cerr << G_STRFUNC << ": No model." << std::endl;
+    return;
+  }
 
-        //Mark this row as not a placeholder because it has real data now.
-        if(!(Conversions::value_is_empty(value)))
-        {
-          //treerow.set_value(m_col_key, Glib::ustring("placeholder debug value setted"));
-          //treerow.set_value(m_col_placeholder, false);
-        }
-      }
+  //Show the value in any columns:
+  Gtk::TreeModel::Row treerow = *iter;
+  if(treerow)
+  {
+    const type_list_indexes list_indexes = get_data_model_column_index(layout_item, set_specified_field_layout);
+    for(type_list_indexes::const_iterator iter = list_indexes.begin(); iter != list_indexes.end(); ++iter)
+    {
+      const guint treemodel_col = *iter + get_count_hidden_system_columns();
+      treerow.set_value(treemodel_col, value);
     }
-
-    //Add extra blank if necessary:
-    //add_blank();
   }
-
+    
+  /// Get indexes of any columns with choices with !show_all relationships that have @a from_key as the from_key.
+  type_list_indexes list_choice_cells = get_choice_index(layout_item /* from_key field name */);
+  std::cout << "debug: list_choice_cells.size() == " << list_choice_cells.size() << std::endl;
+  for(type_list_indexes::iterator iter = list_choice_cells.begin(); iter != list_choice_cells.end(); ++iter)
+  {
+    const guint model_index = *iter;
+    refresh_cell_choices_data_from_database_with_foreign_key(model_index, value /* foreign key value */);
+  }
+ 
+  //Add extra blank if necessary:
+  //add_blank();
+ 
   //g_warning("DbAddDel::set_value end");
 }
 
@@ -1249,6 +1256,64 @@ void DbAddDel::set_value_selected(const sharedptr<const LayoutItem_Field>& layou
   set_value(get_item_selected(), layout_item, value);
 }
 
+void DbAddDel::refresh_cell_choices_data_from_database_with_foreign_key(guint model_index, const Gnome::Gda::Value& foreign_key_value)
+{
+  if(m_ColumnTypes.size() <= model_index)
+  {
+    std::cerr << G_STRFUNC << ": model_index is out of range: model_index=" << model_index << ", size=" << m_ColumnTypes.size() << std::endl;
+    return;
+  }
+      
+  sharedptr<const LayoutItem> item = m_ColumnTypes[model_index].m_item;
+  sharedptr<const LayoutItem_Field> layout_field = sharedptr<const LayoutItem_Field>::cast_dynamic(item);
+  if(!layout_field)
+  {
+    std::cerr << G_STRFUNC << ": The layout item was not a LayoutItem_Field." << std::endl;
+    return;
+  }
+  
+  guint view_column_index = 0;
+  const bool test = get_view_column_index(model_index, view_column_index);
+  if(!test)
+  {
+    std::cerr << G_STRFUNC << ": view column not found for model_column=" << model_index << std::endl;
+    return;
+  }
+  
+  CellRendererList* cell = 
+    dynamic_cast<CellRendererList*>( m_TreeView.get_column_cell_renderer(view_column_index) );
+  if(!cell)
+  {
+    std::cerr << G_STRFUNC << ": cell renderer not found for model_column=" << model_index << std::endl;
+    return;
+  }
+ 
+  //Set the choices:
+  cell->remove_all_list_items();
+  
+  sharedptr<LayoutItem_Field> layout_choice_first;
+  sharedptr<LayoutItem_Field> layout_choice_second; 
+  Utils::type_list_values_with_second list_values = 
+    Utils::get_choice_values(get_document(), layout_field, foreign_key_value,
+      layout_choice_first, layout_choice_second);
+
+  for(Utils::type_list_values_with_second::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
+  {
+    const Glib::ustring first = 
+      Conversions::get_text_for_gda_value(
+        layout_choice_first->get_glom_type(), iter->first, layout_choice_first->get_formatting_used().m_numeric_format);
+
+    Glib::ustring second;
+    if(layout_choice_second)
+    {
+      second = Conversions::get_text_for_gda_value(
+        layout_choice_second->get_glom_type(), iter->second, layout_choice_second->get_formatting_used().m_numeric_format);
+    }
+
+    cell->append_list_item(first, second);
+  }
+}
+
 void DbAddDel::remove_all_columns()
 {
   m_ColumnTypes.clear();
@@ -1370,6 +1435,41 @@ DbAddDel::type_list_indexes DbAddDel::get_column_index(const sharedptr<const Lay
   return list_indexes;
 }
 
+DbAddDel::type_list_indexes DbAddDel::get_choice_index(const sharedptr<const LayoutItem_Field>& from_key)
+{
+  type_list_indexes result;
+  
+  if(!from_key)
+    return result;
+    
+  const Glib::ustring from_key_name = from_key->get_name();
+
+  guint index = 0;
+  for(type_ColumnTypes::const_iterator iter = m_ColumnTypes.begin(); iter != m_ColumnTypes.end(); ++iter)
+  {
+    sharedptr<const LayoutItem_Field> field = sharedptr<const LayoutItem_Field>::cast_dynamic(iter->m_item);
+    if(!field)
+       continue;
+
+    const FieldFormatting& format = field->get_formatting_used();
+
+    sharedptr<const Relationship> choice_relationship;
+    Glib::ustring choice_field, choice_second;
+    bool choice_show_all = false;
+    format.get_choices_related(choice_relationship, choice_field, choice_second, choice_show_all);
+    if(choice_relationship && !choice_show_all) //"Show All" choices don't use the ID field values.
+    {
+      if(choice_relationship->get_from_field() == from_key_name)
+        result.push_back(index);
+    }
+    
+    index++;
+  }
+
+  return result;
+}
+
+
 sharedptr<const LayoutItem_Field> DbAddDel::get_column_field(guint column_index) const
 {
   if(column_index < m_ColumnTypes.size())
diff --git a/glom/utility_widgets/db_adddel/db_adddel.h b/glom/utility_widgets/db_adddel/db_adddel.h
index ef99b1b..388a2fc 100644
--- a/glom/utility_widgets/db_adddel/db_adddel.h
+++ b/glom/utility_widgets/db_adddel/db_adddel.h
@@ -61,6 +61,7 @@ public:
 };
 
 class DbTreeViewColumnGlom;
+class CellRendererList;
 
 /** For adding/deleting/selecting record rows.
  */
@@ -286,7 +287,10 @@ private:
 
   typedef std::list<guint> type_list_indexes;
   ///Return the column indexes of any columns that display this field.
-  virtual type_list_indexes get_column_index(const sharedptr<const LayoutItem>& layout_item) const;
+  type_list_indexes get_column_index(const sharedptr<const LayoutItem>& layout_item) const;
+  
+  /// Get indexes of any columns with choices with !show_all relationships that have @a from_key as the from_key.
+  type_list_indexes get_choice_index(const sharedptr<const LayoutItem_Field>& from_key);
 
   /** Return the query column index of any columns that display this field:
    * @param including_specified_field_layout If false, then don't return the actual layout item itself.
@@ -385,6 +389,8 @@ private:
 
   //TODO: Remove this and use AppGlom::get_application() instead?
   Application* get_application();
+  
+  void refresh_cell_choices_data_from_database_with_foreign_key(guint model_index, const Gnome::Gda::Value& foreign_key_value);
 
   static void apply_formatting(Gtk::CellRenderer* renderer, const sharedptr<const LayoutItem_WithFormatting>& layout_item);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]