[glom/feature_choices_related_layout] In progress



commit dbf7d551709b291c5e76520ad9d2a99f867ef26f
Author: Murray Cumming <murrayc murrayc com>
Date:   Wed Aug 11 17:41:22 2010 +0200

    In progress

 .../data_structure/layout/fieldformatting.cc       |   16 ++--
 .../data_structure/layout/fieldformatting.h        |   13 ++-
 glom/libglom/data_structure/layout/layoutgroup.cc  |   32 +++++-
 glom/libglom/data_structure/layout/layoutgroup.h   |   15 ++--
 glom/libglom/document/document.cc                  |   70 ++++++++++---
 glom/libglom/utils.cc                              |   34 +++++--
 glom/libglom/utils.h                               |    4 +-
 .../mode_data/datawidget/combo_as_radio_buttons.cc |   53 +++++++---
 glom/mode_data/datawidget/combochoices.cc          |  104 ++------------------
 glom/mode_data/datawidget/combochoices.h           |    3 +-
 .../datawidget/combochoiceswithtreemodel.cc        |   31 +++++-
 11 files changed, 205 insertions(+), 170 deletions(-)
---
diff --git a/glom/libglom/data_structure/layout/fieldformatting.cc b/glom/libglom/data_structure/layout/fieldformatting.cc
index 2d0cd7f..8a9d91e 100644
--- a/glom/libglom/data_structure/layout/fieldformatting.cc
+++ b/glom/libglom/data_structure/layout/fieldformatting.cc
@@ -56,7 +56,7 @@ FieldFormatting::FieldFormatting(const FieldFormatting& src)
   m_text_color_background(src.m_text_color_background),
   m_horizontal_alignment(src.m_horizontal_alignment),
   m_choices_related_field(src.m_choices_related_field),
-  m_choices_related_field_second(src.m_choices_related_field_second),
+  m_choices_extra_layout_group(src.m_choices_extra_layout_group),
   m_choices_related_show_all(src.m_choices_related_show_all)
 {
 }
@@ -75,7 +75,7 @@ bool FieldFormatting::operator==(const FieldFormatting& src) const
     (m_choices_custom == src.m_choices_custom) &&
     (m_choices_related == src.m_choices_related) &&
     (m_choices_related_field == src.m_choices_related_field) &&
-    (m_choices_related_field_second == src.m_choices_related_field_second) &&
+    (m_choices_extra_layout_group == src.m_choices_extra_layout_group) &&
     (m_text_format_multiline == src.m_text_format_multiline) &&
     (m_text_multiline_height_lines == src.m_text_multiline_height_lines) &&
     (m_text_font == src.m_text_font) &&
@@ -98,7 +98,7 @@ FieldFormatting& FieldFormatting::operator=(const FieldFormatting& src)
   m_choices_custom = src.m_choices_custom;
   m_choices_related = src.m_choices_related;
   m_choices_related_field = src.m_choices_related_field;
-  m_choices_related_field_second = src.m_choices_related_field_second;
+  m_choices_extra_layout_group = src.m_choices_extra_layout_group;
   m_choices_related_show_all = src.m_choices_related_show_all;
 
   m_text_format_multiline = src.m_text_format_multiline;
@@ -234,7 +234,7 @@ bool FieldFormatting::get_has_related_choices() const
 bool FieldFormatting::get_has_related_choices(bool& show_all, bool& with_second) const
 {
   show_all = m_choices_related_show_all;
-  with_second = m_choices_related_field_second;
+  with_second = m_choices_extra_layout_group;
   return m_choices_related;
 }
 
@@ -243,21 +243,21 @@ void FieldFormatting::set_has_related_choices(bool val)
   m_choices_related = val;
 }
 
-void FieldFormatting::set_choices_related(const sharedptr<const Relationship>& relationship, const sharedptr<const LayoutItem_Field>& field, const sharedptr<const LayoutItem_Field>& field_second, bool show_all)
+void FieldFormatting::set_choices_related(const sharedptr<const Relationship>& relationship, const sharedptr<const LayoutItem_Field>& field, const sharedptr<LayoutGroup>& extra_layout, bool show_all)
 {
   set_relationship(relationship);
 
   m_choices_related_field = field;
-  m_choices_related_field_second = field_second;
+  m_choices_extra_layout_group = extra_layout;
   m_choices_related_show_all = show_all;
 }
 
-void FieldFormatting::get_choices_related(sharedptr<const Relationship>& relationship, sharedptr<const LayoutItem_Field>& field, sharedptr<const LayoutItem_Field>& field_second, bool& show_all) const
+void FieldFormatting::get_choices_related(sharedptr<const Relationship>& relationship, sharedptr<const LayoutItem_Field>& field, sharedptr<const LayoutGroup>& extra_layout, bool& show_all) const
 {
   relationship = get_relationship();
 
   field = m_choices_related_field;
-  field_second = m_choices_related_field_second;
+  extra_layout = m_choices_extra_layout_group;
   show_all = m_choices_related_show_all;
 }
 
diff --git a/glom/libglom/data_structure/layout/fieldformatting.h b/glom/libglom/data_structure/layout/fieldformatting.h
index 0ee8406..44e4dd9 100644
--- a/glom/libglom/data_structure/layout/fieldformatting.h
+++ b/glom/libglom/data_structure/layout/fieldformatting.h
@@ -31,6 +31,7 @@ namespace Glom
 {
 
 class LayoutItem_Field;
+class LayoutGroup;
 
 //TODO: This should probably be renamed to Formatting, because it is used for static text items too.
 class FieldFormatting : public UsesRelationship //The UsesRelationship base has the relationship for the choices.
@@ -68,15 +69,15 @@ public:
    */
   void set_choices_restricted(bool val = true, bool as_radio_buttons = false);
 
-  void get_choices_related(sharedptr<const Relationship>& relationship_name, sharedptr<const LayoutItem_Field>& field, sharedptr<const LayoutItem_Field>& field_second, bool& show_all) const;
-  void set_choices_related(const sharedptr<const Relationship>& relationship_name, const sharedptr<const LayoutItem_Field>& field, const sharedptr<const LayoutItem_Field>& field_second, bool show_all);
-  
+  void get_choices_related(sharedptr<const Relationship>& relationship_name, sharedptr<const LayoutItem_Field>& field, sharedptr<const LayoutGroup>& extra_layout, bool& show_all) const;
+  void set_choices_related(const sharedptr<const Relationship>& relationship_name, const sharedptr<const LayoutItem_Field>& field, const sharedptr<LayoutGroup>& extra_layout, bool show_all);
+
   //Just for convenience:
   sharedptr<const Relationship> get_choices_related_relationship(bool& show_all) const;
-  
 
 
- 
+
+
   /** Get whether the text should be displayed with multiple lines in the
    * details view. Text is displayed with a single line in the list view.
    * @returns whether the text should be displayed with multiple lines
@@ -168,7 +169,7 @@ private:
   HorizontalAlignment m_horizontal_alignment;
 
   sharedptr<const LayoutItem_Field> m_choices_related_field;
-  sharedptr<const LayoutItem_Field> m_choices_related_field_second;
+  sharedptr<LayoutGroup> m_choices_extra_layout_group;
   bool m_choices_related_show_all;
 };
 
diff --git a/glom/libglom/data_structure/layout/layoutgroup.cc b/glom/libglom/data_structure/layout/layoutgroup.cc
index 0fd490c..2220877 100644
--- a/glom/libglom/data_structure/layout/layoutgroup.cc
+++ b/glom/libglom/data_structure/layout/layoutgroup.cc
@@ -149,7 +149,7 @@ void LayoutGroup::add_item(const sharedptr<LayoutItem>& item, const sharedptr<co
   //std::vector::insert() adds before rather than after:
   // jhs: We want to add after rather than before - at least for dnd
   //++iter;
- 
+
   m_list_items.insert(iter, item);
 }
 
@@ -157,7 +157,7 @@ void LayoutGroup::remove_item (const sharedptr<LayoutItem>& item)
 {
   sharedptr<LayoutItem> unconst = sharedptr<LayoutItem>::cast_const(item);
   type_list_items::iterator iter = std::find(m_list_items.begin(), m_list_items.end(), unconst);
-  m_list_items.erase(iter);  
+  m_list_items.erase(iter);
 }
 
 LayoutGroup::type_list_items LayoutGroup::get_items()
@@ -179,6 +179,26 @@ LayoutGroup::type_list_const_items LayoutGroup::get_items() const
   return result;
 }
 
+LayoutGroup::type_list_const_items LayoutGroup::get_items_recursive() const
+{
+  type_list_const_items result;
+
+  for(type_list_items::const_iterator iter = m_list_items.begin(); iter != m_list_items.end(); ++iter)
+  {
+    const sharedptr<const LayoutItem> item = *iter;
+    sharedptr<const LayoutGroup> group = sharedptr<const LayoutGroup>::cast_dynamic(item);
+    if(group)
+    {
+      const type_list_const_items sub_result = group->get_items_recursive();
+      result.insert(result.end(), sub_result.begin(), sub_result.end());
+    }
+    else
+      result.push_back(item);
+  }
+
+  return result;
+}
+
 void LayoutGroup::remove_relationship(const sharedptr<const Relationship>& relationship)
 {
   LayoutGroup::type_list_items::iterator iterItem = m_list_items.begin();
@@ -193,7 +213,7 @@ void LayoutGroup::remove_relationship(const sharedptr<const Relationship>& relat
         if(*(uses_rel->get_relationship()) == *relationship) //TODO_Performance: Slow if there are lots of translations.
         {
           m_list_items.erase(iterItem);
-          iterItem = m_list_items.begin(); //Start again, because we changed the container.AddDel 
+          iterItem = m_list_items.begin(); //Start again, because we changed the container.AddDel
           continue;
         }
       }
@@ -222,7 +242,7 @@ void LayoutGroup::remove_field(const Glib::ustring& field_name)
         if(field_item->get_name() == field_name)
         {
           m_list_items.erase(iterItem);
-          iterItem = m_list_items.begin(); //Start again, because we changed the container.AddDel 
+          iterItem = m_list_items.begin(); //Start again, because we changed the container.AddDel
           continue;
         }
       }
@@ -257,7 +277,7 @@ void LayoutGroup::remove_field(const Glib::ustring& table_name, const Glib::ustr
         if(field_item->get_name() == field_name)
         {
           m_list_items.erase(iterItem);
-          iterItem = m_list_items.begin(); //Start again, because we changed the container.AddDel 
+          iterItem = m_list_items.begin(); //Start again, because we changed the container.AddDel
           continue;
         }
       }
@@ -422,7 +442,7 @@ void LayoutGroup::set_columns_count(guint columns_count)
 {
   m_columns_count = columns_count;
 }
-  
+
 double LayoutGroup::get_border_width() const
 {
   return m_border_width;
diff --git a/glom/libglom/data_structure/layout/layoutgroup.h b/glom/libglom/data_structure/layout/layoutgroup.h
index d44fe6f..f95395c 100644
--- a/glom/libglom/data_structure/layout/layoutgroup.h
+++ b/glom/libglom/data_structure/layout/layoutgroup.h
@@ -58,14 +58,14 @@ public:
 
   /** Add the item after the specified existing item.
    * @param item The item to add.
-   * @param position The item after which the item should be added. 
+   * @param position The item after which the item should be added.
    */
   void add_item(const sharedptr<LayoutItem>& item, const sharedptr<const LayoutItem>& position);
-  
+
   /** Remove a layout item from the group
    * @param item The item to remove.
    */
-  void remove_item (const sharedptr<LayoutItem>& item);  
+  void remove_item (const sharedptr<LayoutItem>& item);
 
   /** Remove any instance of the field (from the current table) from the layout.
    */
@@ -94,13 +94,17 @@ public:
 
   guint get_columns_count() const;
   void set_columns_count(guint columns_count);
-  
+
   typedef std::vector< sharedptr<LayoutItem> > type_list_items;
   type_list_items get_items();
 
   typedef std::vector< sharedptr<const LayoutItem> > type_list_const_items;
   type_list_const_items get_items() const;
 
+  /** Get the items recursively, depth-first, not returning any groups.
+   */
+  type_list_const_items get_items_recursive() const;
+
   virtual Glib::ustring get_part_type_name() const;
   virtual Glib::ustring get_report_part_id() const;
 
@@ -118,6 +122,3 @@ private:
 } //namespace Glom
 
 #endif //GLOM_DATASTRUCTURE_LAYOUTGROUP_H
-
-
-
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index f830de7..3d71af6 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -197,7 +197,8 @@ namespace Glom
 #define GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED "choices_related"
 #define GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_RELATIONSHIP "choices_related_relationship"
 #define GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_FIELD "choices_related_field"
-#define GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_SECOND "choices_related_second"
+#define GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_EXTRA_LAYOUT "choices_related_extra_layout"
+#define GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_SECOND "choices_related_second" //deprecated
 #define GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_SHOW_ALL "choices_related_show_all"
 
 #define GLOM_NODE_TRANSLATIONS_SET "trans_set"
@@ -1986,20 +1987,49 @@ void Document::load_after_layout_item_formatting(const xmlpp::Element* element,
     const Glib::ustring relationship_name = get_node_attribute_value(element, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_RELATIONSHIP);
     if(!relationship_name.empty())
     {
+      sharedptr<const Relationship> relationship = get_relationship(table_name, relationship_name);
+
       bool show_all = get_node_attribute_value_as_bool(element, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_SHOW_ALL);
       if(get_document_format_version() < 6)
       {
         show_all = true; //This was the behaviour before this checkbox existed.
       }
-      
+
       const Glib::ustring field_first = get_node_attribute_value(element, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_FIELD);
-      const Glib::ustring field_second = get_node_attribute_value(element, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_SECOND);
-      /* TODO:
-      sharedptr<Relationship> relationship = get_relationship(table_name, relationship_name);
+      sharedptr<LayoutItem_Field> layout_field_first = sharedptr<LayoutItem_Field>::create();
+      layout_field_first->set_name(field_first);
+
+      sharedptr<LayoutGroup> extra_layouts;
+
+      //Previous versions just saved a single extra field name, instead of a whole set of layoutgroups:
+      if(m_document_format_version < 6)
+      {
+        //The deprecated way:
+        const Glib::ustring field_second = get_node_attribute_value(element, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_SECOND);
+        if(!field_second.empty())
+        {
+          extra_layouts = sharedptr<LayoutGroup>::create();
+          sharedptr<LayoutItem_Field> item = sharedptr<LayoutItem_Field>::create();
+          item->set_name(field_second);
+          extra_layouts->add_item(item);
+        }
+      }
+      else
+      {
+        //Get the extra layout for related choices:
+        xmlpp::Element* nodeExtraLayout = get_node_child_named(element, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_EXTRA_LAYOUT);
+        if(nodeExtraLayout)
+        {
+          xmlpp::Element* nodeGroups = get_node_child_named(nodeExtraLayout, GLOM_NODE_DATA_LAYOUT_GROUPS);
+          if(nodeGroups)
+            load_after_layout_group(nodeGroups, relationship->get_to_table(), extra_layouts);
+        }
+      }
+
       format.set_choices_related(relationship,
-        field_first, field_second,
+        layout_field_first, extra_layouts,
         show_all);
-      */
+
       //Full details are updated in filled-in ().
     }
   }
@@ -2997,20 +3027,26 @@ void Document::save_before_layout_item_formatting(xmlpp::Element* nodeItem, cons
     set_node_attribute_value_as_bool(nodeItem, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED, format.get_has_related_choices() );
 
     sharedptr<const Relationship> choice_relationship;
-    sharedptr<const LayoutItem_Field> choice_layout_first, choice_layout_second;
+    sharedptr<const LayoutItem_Field> choice_layout_first;
+    sharedptr<const LayoutGroup> choice_extra_layouts;
     bool choice_show_all = false;
-    format.get_choices_related(choice_relationship, choice_layout_first, choice_layout_second, choice_show_all);
+    format.get_choices_related(choice_relationship, choice_layout_first, choice_extra_layouts, choice_show_all);
 
-    Glib::ustring choice_field, choice_second;
+    Glib::ustring choice_field;
     if(choice_layout_first)
       choice_field = choice_layout_first->get_name();
-    if(choice_layout_second)
-      choice_second = choice_layout_first->get_name();
-    
+
     set_node_attribute_value(nodeItem, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_RELATIONSHIP, glom_get_sharedptr_name(choice_relationship));
     set_node_attribute_value(nodeItem, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_FIELD, choice_field);
-    set_node_attribute_value(nodeItem, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_SECOND, choice_second);
     set_node_attribute_value_as_bool(nodeItem, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_SHOW_ALL, choice_show_all);
+
+    //Save the extra fields to show for related choices:
+    if(choice_extra_layouts)
+    {
+      xmlpp::Element* nodeExtraLayout = nodeItem->add_child(GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_EXTRA_LAYOUT);
+      xmlpp::Element* nodeGroups = nodeExtraLayout->add_child(GLOM_NODE_DATA_LAYOUT_GROUPS);
+      save_before_layout_group(nodeGroups, choice_extra_layouts);
+    }
   }
 }
 
@@ -3923,7 +3959,7 @@ sharedptr<const Relationship> Document::get_field_used_in_relationship_to_one(co
   if(!layout_field)
   {
     std::cerr << G_STRFUNC << ": layout_field was null" << std::endl;
-    return result; 
+    return result;
   }
 
   const Glib::ustring table_used = layout_field->get_table_used(table_name);
@@ -3931,7 +3967,7 @@ sharedptr<const Relationship> Document::get_field_used_in_relationship_to_one(co
   if(iterFind == m_tables.end())
   {
     std::cerr << G_STRFUNC << ": table not found:" << table_used << std::endl;
-    return result; 
+    return result;
   }
 
   //Look at each relationship:
@@ -4201,7 +4237,7 @@ guint Document::get_latest_known_document_format_version()
   // Version 3: (Glom 1.10). Support for the old one-big-string example_rows format was removed, and we now use (unquoted) non-postgres libgda escaping.
   // Version 4: (Glom 1.12). Portal navigation options were simplified, with a "none" option. network_sharing was added, defaulting to off.
   // Version 5: (Glom 1.14). Extra layout item formatting options were added, plus a startup script.
-  // Version 6: (Glom 1.16). Extra show_all option for choices that show related records.
+  // Version 6: (Glom 1.16). Extra show_all option for choices that show related records. Extra related choice fields are now a layout group instead of just a second field name.
 
   return 6;
 }
diff --git a/glom/libglom/utils.cc b/glom/libglom/utils.cc
index 5aa0b8b..839d788 100644
--- a/glom/libglom/utils.cc
+++ b/glom/libglom/utils.cc
@@ -503,9 +503,10 @@ Utils::type_list_values_with_second Utils::get_choice_values(const Document* doc
 
   const FieldFormatting& format = field->get_formatting_used();
   sharedptr<const Relationship> choice_relationship;
-  sharedptr<const LayoutItem_Field> layout_choice_first, layout_choice_second;
+  sharedptr<const LayoutItem_Field> layout_choice_first;
+  sharedptr<const LayoutGroup> layout_choice_extra;
   bool choice_show_all = false;
-  format.get_choices_related(choice_relationship, layout_choice_first, layout_choice_second, choice_show_all);
+  format.get_choices_related(choice_relationship, layout_choice_first, layout_choice_extra, choice_show_all);
 
   if(!choice_relationship)
   {
@@ -515,8 +516,19 @@ Utils::type_list_values_with_second Utils::get_choice_values(const Document* doc
 
   Utils::type_vecConstLayoutFields fields;
   fields.push_back(layout_choice_first);
-  if(layout_choice_second)
-    fields.push_back(layout_choice_second);
+
+  if(layout_choice_extra)
+  {
+    const LayoutGroup::type_list_const_items extra_fields = layout_choice_extra->get_items_recursive();
+    for(LayoutGroup::type_list_const_items::const_iterator iter = extra_fields.begin();
+      iter != extra_fields.end(); ++iter)
+    {
+      const sharedptr<const LayoutItem> item = *iter;
+      const sharedptr<const LayoutItem_Field> item_field = sharedptr<const LayoutItem_Field>::cast_dynamic(item);
+      if(item_field)
+         fields.push_back(item_field); //TODO: Don't ignore other usable items such as static text.
+    }
+  }
 
   const Glib::ustring to_table = choice_relationship->get_to_table();
   const sharedptr<const Field> to_field = document->get_field(to_table, choice_relationship->get_to_field());
@@ -566,11 +578,19 @@ Utils::type_list_values_with_second Utils::get_choice_values(const Document* doc
     for(guint row = 0; row < count; ++row)
     {
 
-      std::pair<Gnome::Gda::Value, Gnome::Gda::Value> itempair;
+      std::pair<Gnome::Gda::Value, type_list_values> itempair;
       itempair.first = datamodel->get_value_at(0, row);
 
-      if(layout_choice_second && (cols_count > 1))
-        itempair.second = datamodel->get_value_at(1, row);
+      if(layout_choice_extra && (cols_count > 1))
+      {
+        type_list_values list_values;
+        for(guint i = 1; i < cols_count; ++i)
+        {
+          list_values.push_back(datamodel->get_value_at(1, row));
+        }
+
+        itempair.second = list_values;
+      }
 
       result.push_back(itempair);
     }
diff --git a/glom/libglom/utils.h b/glom/libglom/utils.h
index 07ef714..8fd204e 100644
--- a/glom/libglom/utils.h
+++ b/glom/libglom/utils.h
@@ -111,8 +111,8 @@ Glib::RefPtr<Gnome::Gda::SqlBuilder> build_sql_select_with_key(
 
 Gnome::Gda::SqlExpr get_find_where_clause_quick(const Document* document, const Glib::ustring& table_name, const Gnome::Gda::Value& quick_search);
 
-
-typedef std::list< std::pair<Gnome::Gda::Value, Gnome::Gda::Value> > type_list_values_with_second;
+typedef std::list<Gnome::Gda::Value> type_list_values;
+typedef std::list< std::pair<Gnome::Gda::Value, type_list_values> > type_list_values_with_second; //TODO: Rename this now that we have more than just 1 extra field.
 type_list_values_with_second get_choice_values_all(const Document* document, const sharedptr<const LayoutItem_Field>& field);
 
 type_list_values_with_second get_choice_values(const Document* document, const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& foreign_key_value);
diff --git a/glom/mode_data/datawidget/combo_as_radio_buttons.cc b/glom/mode_data/datawidget/combo_as_radio_buttons.cc
index 2551795..4b3021b 100644
--- a/glom/mode_data/datawidget/combo_as_radio_buttons.cc
+++ b/glom/mode_data/datawidget/combo_as_radio_buttons.cc
@@ -54,7 +54,7 @@ void ComboAsRadioButtons::init()
 void ComboAsRadioButtons::set_choices_with_second(const type_list_values_with_second& list_values)
 {
   //Clear existing buttons:
-  for(type_map_buttons::iterator iter = m_map_buttons.begin(); 
+  for(type_map_buttons::iterator iter = m_map_buttons.begin();
     iter != m_map_buttons.end(); ++iter)
   {
      Gtk::RadioButton* button = iter->second;
@@ -62,14 +62,19 @@ void ComboAsRadioButtons::set_choices_with_second(const type_list_values_with_se
   }
   m_map_buttons.clear();
 
-  sharedptr<LayoutItem_Field> layout_item = 
+  sharedptr<LayoutItem_Field> layout_item =
     sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
   const FieldFormatting& format = layout_item->get_formatting_used();
   sharedptr<const Relationship> choice_relationship;
-  sharedptr<const LayoutItem_Field> layout_choice_first, layout_choice_second;
+  sharedptr<const LayoutItem_Field> layout_choice_first;
+  sharedptr<const LayoutGroup> layout_choice_extra;
   bool choice_show_all = false;
-  format.get_choices_related(choice_relationship, layout_choice_first, layout_choice_second, choice_show_all);
-  
+  format.get_choices_related(choice_relationship, layout_choice_first, layout_choice_extra, choice_show_all);
+
+  LayoutGroup::type_list_const_items extra_fields;
+  if(layout_choice_extra)
+    extra_fields = layout_choice_extra->get_items_recursive();
+
   //Add new buttons:
   Gtk::RadioButton::Group group;
   for(type_list_values_with_second::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
@@ -78,12 +83,28 @@ void ComboAsRadioButtons::set_choices_with_second(const type_list_values_with_se
     {
       const Glib::ustring value_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 title = value_first;
-      if(layout_choice_second)
+
+      //TODO: Support multiple extra fields:
+      //For now, use only the first extra field:
+      const type_list_values extra_values = iter->second;
+      if(layout_choice_extra && !extra_values.empty())
       {
-        const Glib::ustring value_second = Conversions::get_text_for_gda_value(layout_choice_second->get_glom_type(), iter->second, layout_choice_second->get_formatting_used().m_numeric_format);
-        title += " - " + value_second; //TODO: Find a better way to join them?
+        for(LayoutGroup::type_list_const_items::const_iterator iterExtra = extra_fields.begin();
+          iterExtra != extra_fields.end(); ++iterExtra)
+        {
+          const sharedptr<const LayoutItem> item = *iterExtra;
+          const sharedptr<const LayoutItem_Field> item_field = sharedptr<const LayoutItem_Field>::cast_dynamic(item);
+          if(item_field)
+          {
+            const Gnome::Gda::Value value = *(extra_values.begin()); //TODO: Use a vector instead?
+            const Glib::ustring value_second = Conversions::get_text_for_gda_value(item_field->get_glom_type(), value, item_field->get_formatting_used().m_numeric_format);
+
+            title += " - " + value_second; //TODO: Find a better way to join them?
+            break;
+          }
+        }
       }
-      
+
       Gtk::RadioButton* button = new Gtk::RadioButton(group, title);
       m_map_buttons[value_first] = button;
       pack_start(*button);
@@ -95,13 +116,13 @@ void ComboAsRadioButtons::set_choices_with_second(const type_list_values_with_se
       button->signal_button_press_event().connect(
         sigc::mem_fun(*this, &ComboAsRadioButtons::on_radiobutton_button_press_event), false);
     }
-  } 
+  }
 }
 
 void ComboAsRadioButtons::set_choices(const FieldFormatting::type_list_values& list_values)
 {
   //Clear existing buttons:
-  for(type_map_buttons::iterator iter = m_map_buttons.begin(); 
+  for(type_map_buttons::iterator iter = m_map_buttons.begin();
     iter != m_map_buttons.end(); ++iter)
   {
      Gtk::RadioButton* button = iter->second;
@@ -117,7 +138,7 @@ void ComboAsRadioButtons::set_choices(const FieldFormatting::type_list_values& l
     if(layout_item)
     {
       const Glib::ustring value_first = Conversions::get_text_for_gda_value(layout_item->get_glom_type(), *iter, layout_item->get_formatting_used().m_numeric_format);
-      
+
       Gtk::RadioButton* button = new Gtk::RadioButton(group, value_first);
       m_map_buttons[value_first] = button;
       pack_start(*button);
@@ -125,20 +146,20 @@ void ComboAsRadioButtons::set_choices(const FieldFormatting::type_list_values& l
       button->signal_toggled().connect(
         sigc::mem_fun(*this, &ComboAsRadioButtons::on_radiobutton_toggled));
     }
-  } 
+  }
 }
 
 
 
 ComboAsRadioButtons::~ComboAsRadioButtons()
 {
-  for(type_map_buttons::iterator iter = m_map_buttons.begin(); 
+  for(type_map_buttons::iterator iter = m_map_buttons.begin();
     iter != m_map_buttons.end(); ++iter)
   {
      Gtk::RadioButton* button = iter->second;
      delete button;
   }
-  m_map_buttons.clear();	
+  m_map_buttons.clear();
 }
 
 void ComboAsRadioButtons::check_for_change()
@@ -226,7 +247,7 @@ Glib::ustring ComboAsRadioButtons::get_text() const
       return iter->first;
     }
   }
-      
+
   return Glib::ustring();
 }
 
diff --git a/glom/mode_data/datawidget/combochoices.cc b/glom/mode_data/datawidget/combochoices.cc
index 1a5f1bd..b77420e 100644
--- a/glom/mode_data/datawidget/combochoices.cc
+++ b/glom/mode_data/datawidget/combochoices.cc
@@ -52,9 +52,9 @@ ComboChoices::~ComboChoices()
 
 bool ComboChoices::refresh_data_from_database_with_foreign_key(const Document* document, const Gnome::Gda::Value& foreign_key_value)
 {
-  sharedptr<LayoutItem_Field> layout_item = 
+  sharedptr<LayoutItem_Field> layout_item =
     sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
-    
+
   if(!layout_item || Conversions::value_is_empty(foreign_key_value))
   {
     //Clear the choices list:
@@ -62,95 +62,11 @@ bool ComboChoices::refresh_data_from_database_with_foreign_key(const Document* d
     set_choices_with_second(list_values);
     return true;
   }
-  
-  sharedptr<const Relationship> choice_relationship;
-  sharedptr<const LayoutItem_Field> choice_field, choice_field_second;
-  bool choice_show_all = false;
-  layout_item->get_formatting_used().get_choices_related(choice_relationship, choice_field, choice_field_second, choice_show_all); 
-
-  if(!choice_field)
-  {
-    std::cerr << G_STRFUNC << ": !choice_field." << std::endl;
-    return false;
-  }
-
-  
-  if(choice_show_all)
-  {
-    //The list should be set in set_choices_related() instead.
-    std::cerr << G_STRFUNC << ": Called with choice_show_all=true." << std::endl;
-    return false;
-  }
-
-  Utils::type_vecConstLayoutFields fields;
-  fields.push_back(choice_field);
-  if(choice_field_second)
-    fields.push_back(choice_field_second);
-
-  //std::cout << G_STRFUNC << "debug: choice_field=" << choice_field->get_name() << ", choice_field_second" << choice_field_second->get_name() << std::endl;
-
-  const Glib::ustring to_table = choice_relationship->get_to_table();
-  const sharedptr<const Field> to_field = document->get_field(to_table, choice_relationship->get_to_field());
-
-  //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 false;
-  }
-
-  //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 false;
-  }
 
-  const std::string sql_query =
-    Utils::sqlbuilder_get_full_query(builder);
-  //std::cout << "get_choice_values: Executing SQL: " << sql_query << std::endl;
-  Glib::RefPtr<Gnome::Gda::DataModel> datamodel = 
-    connection->get_gda_connection()->statement_execute_select(sql_query);
-
-  if(datamodel)
-  {
-    type_list_values_with_second list_values;
-
-    const guint count = datamodel->get_n_rows();
-    const guint cols_count = datamodel->get_n_columns();
-    //std::cout << "  result: count=" << count << std::endl;
-    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(choice_field_second && (cols_count > 1))
-        itempair.second = datamodel->get_value_at(1, row);
-
-      list_values.push_back(itempair);
-    }
-
-    const Gnome::Gda::Value old_value = get_value();
-    set_choices_with_second(list_values);
-    set_value(old_value); //Try to preserve the value, even in iter-based ComboBoxes.
-  }
-  else
-  {
-      std::cerr << G_STRFUNC << ": Error while executing SQL" << std::endl <<
-                   "  " <<  sql_query << std::endl;
-      return false;
-  }
+  const Utils::type_list_values_with_second list_values = Utils::get_choice_values(document, layout_item, foreign_key_value);
+  const Gnome::Gda::Value old_value = get_value();
+  set_choices_with_second(list_values);
+  set_value(old_value); //Try to preserve the value, even in iter-based ComboBoxes.
 
   return true;
 }
@@ -158,14 +74,14 @@ bool ComboChoices::refresh_data_from_database_with_foreign_key(const Document* d
 void ComboChoices::set_choices_related(const Document* document)
 {
   type_list_values_with_second list_values;
-  
-  sharedptr<LayoutItem_Field> layout_item = 
+
+  sharedptr<LayoutItem_Field> layout_item =
     sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
   if(layout_item)
   {
     bool choice_show_all = false;
-    const sharedptr<const Relationship> choice_relationship = 
-      layout_item->get_formatting_used().get_choices_related_relationship(choice_show_all); 
+    const sharedptr<const Relationship> choice_relationship =
+      layout_item->get_formatting_used().get_choices_related_relationship(choice_show_all);
 
     //Set the values now because if it will be the same regardless of the foreign key value.
     //Otherwise show them when refresh_data_from_database_with_foreign_key() is called.
diff --git a/glom/mode_data/datawidget/combochoices.h b/glom/mode_data/datawidget/combochoices.h
index 8f85323..6c885d0 100644
--- a/glom/mode_data/datawidget/combochoices.h
+++ b/glom/mode_data/datawidget/combochoices.h
@@ -62,7 +62,8 @@ public:
 protected:
   void init();
 
-  typedef std::list< std::pair<Gnome::Gda::Value, Gnome::Gda::Value> > type_list_values_with_second;
+  typedef std::list<Gnome::Gda::Value> type_list_values;
+  typedef std::list< std::pair<Gnome::Gda::Value, type_list_values> > type_list_values_with_second;
   virtual void set_choices_with_second(const type_list_values_with_second& list_values) = 0;
 
   //Gnome::Gda::Value m_value; //The last-stored value. We have this because the displayed value might be unparseable.
diff --git a/glom/mode_data/datawidget/combochoiceswithtreemodel.cc b/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
index 0b64031..5726b7d 100644
--- a/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
+++ b/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
@@ -54,14 +54,19 @@ void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_w
   m_refModel->clear();
 
   //TODO: Remove duplication with ComboEntry:
-  sharedptr<LayoutItem_Field> layout_item = 
+  sharedptr<LayoutItem_Field> layout_item =
     sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
   const FieldFormatting& format = layout_item->get_formatting_used();
   sharedptr<const Relationship> choice_relationship;
-  sharedptr<const LayoutItem_Field> layout_choice_first, layout_choice_second;
+  sharedptr<const LayoutItem_Field> layout_choice_first;
+  sharedptr<const LayoutGroup> layout_choice_extra;
   bool choice_show_all = false;
-  format.get_choices_related(choice_relationship, layout_choice_first, layout_choice_second, choice_show_all);
-  
+  format.get_choices_related(choice_relationship, layout_choice_first, layout_choice_extra, choice_show_all);
+
+  LayoutGroup::type_list_const_items extra_fields;
+  if(layout_choice_extra)
+    extra_fields = layout_choice_extra->get_items_recursive();
+
   for(type_list_values_with_second::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
   {
     Gtk::TreeModel::iterator iterTree = m_refModel->append();
@@ -71,9 +76,23 @@ void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_w
     {
       row[m_Columns.m_col_first] = Conversions::get_text_for_gda_value(layout_choice_first->get_glom_type(), iter->first, layout_choice_first->get_formatting_used().m_numeric_format);
 
-      if(layout_choice_second)
+      //TODO: Support multiple extra fields:
+      //For now, use only the first extra field:
+      const type_list_values extra_values = iter->second;
+      if(layout_choice_extra && !extra_values.empty())
       {
-        row[m_Columns.m_col_second] = Conversions::get_text_for_gda_value(layout_choice_second->get_glom_type(), iter->second, layout_choice_second->get_formatting_used().m_numeric_format);
+        for(LayoutGroup::type_list_const_items::const_iterator iterExtra = extra_fields.begin();
+          iterExtra != extra_fields.end(); ++iterExtra)
+        {
+          const sharedptr<const LayoutItem> item = *iterExtra;
+          const sharedptr<const LayoutItem_Field> item_field = sharedptr<const LayoutItem_Field>::cast_dynamic(item);
+          if(item_field)
+          {
+            const Gnome::Gda::Value value = *(extra_values.begin()); //TODO: Use a vector instead?
+            row[m_Columns.m_col_second] = Conversions::get_text_for_gda_value(item_field->get_glom_type(), value, item_field->get_formatting_used().m_numeric_format);
+            break;
+          }
+        }
       }
     }
   }



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