[glom] Combo widgets: Support multiple extra fields.



commit 7973657aa82d40fa1b0c9fae305264afe26878ba
Author: Murray Cumming <murrayc murrayc com>
Date:   Wed Sep 8 11:44:39 2010 +0200

    Combo widgets: Support multiple extra fields.
    
    * glom/libglom/utils.cc: get_choice_values(): Actually get extra values other
      than than the first one, by actually using the index instead of just 1.
    * glom/mode_data/datawidget/combochoiceswithtreemodel.[h|cc]:
      Added a virtual create_model(), to create model columns dynamically. So far
      they are just text columns.
      set_choices_with_second(): Recreate the model here each time.
    * glom/mode_data/datawidget/combo.[h|cc]:
    * glom/mode_data/datawidget/comboentry.[h|cc]: Override create_model() to
      also set up the view columns using the widgets' specific API.
    * glom/mode_data/datawidget/combochoices.h: set_choices_related():
      Stop this from being virtual because we no longer override it.

 ChangeLog                                          |   16 ++++
 glom/libglom/document/document.cc                  |    1 -
 glom/libglom/utils.cc                              |    3 +-
 glom/mode_data/datawidget/combo.cc                 |   57 +++++---------
 glom/mode_data/datawidget/combo.h                  |    5 +-
 glom/mode_data/datawidget/combochoices.h           |    2 +-
 .../datawidget/combochoiceswithtreemodel.cc        |   83 +++++++++++++++++---
 .../datawidget/combochoiceswithtreemodel.h         |   21 ++----
 glom/mode_data/datawidget/comboentry.cc            |   46 ++++-------
 glom/mode_data/datawidget/comboentry.h             |    5 +-
 glom/utility_widgets/db_adddel/db_adddel.h         |   11 ---
 11 files changed, 136 insertions(+), 114 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 6cb6bfb..14f07dc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
 2010-09-08  Murray Cumming  <murrayc murrayc com>
 
+	Combo widgets: Support multiple extra fields.
+
+	* glom/libglom/utils.cc: get_choice_values(): Actually get extra values other
+  than than the first one, by actually using the index instead of just 1.
+	* glom/mode_data/datawidget/combochoiceswithtreemodel.[h|cc]:
+  Added a virtual create_model(), to create model columns dynamically. So far
+  they are just text columns.
+  set_choices_with_second(): Recreate the model here each time.
+	* glom/mode_data/datawidget/combo.[h|cc]:
+	* glom/mode_data/datawidget/comboentry.[h|cc]: Override create_model() to
+  also set up the view columns using the widgets' specific API.
+	* glom/mode_data/datawidget/combochoices.h: set_choices_related():
+  Stop this from being virtual because we no longer override it.
+
+2010-09-08  Murray Cumming  <murrayc murrayc com>
+
 	Initial support for multiple show-also fields in related choices.
 
 	* glom/glom_developer.glade: Formatting box: related choices:
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index 6860a65..cc318dd 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -2020,7 +2020,6 @@ void Document::load_after_layout_item_formatting(const xmlpp::Element* element,
         xmlpp::Element* nodeExtraLayout = get_node_child_named(element, GLOM_ATTRIBUTE_FORMAT_CHOICES_RELATED_EXTRA_LAYOUT);
         if(nodeExtraLayout)
         {
-          std::cout << "debuga1" << std::endl;
           xmlpp::Element* nodeGroups = get_node_child_named(nodeExtraLayout, GLOM_NODE_DATA_LAYOUT_GROUPS);
           if(nodeGroups)
           {
diff --git a/glom/libglom/utils.cc b/glom/libglom/utils.cc
index 2691fa0..ff3770c 100644
--- a/glom/libglom/utils.cc
+++ b/glom/libglom/utils.cc
@@ -524,6 +524,7 @@ Utils::type_list_values_with_second Utils::get_choice_values(const Document* doc
       iter != extra_fields.end(); ++iter)
     {
       const sharedptr<const LayoutItem> item = *iter;
+      std::cout << "debug: item=" << item->get_name() << std::endl;
       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.
@@ -586,7 +587,7 @@ Utils::type_list_values_with_second Utils::get_choice_values(const Document* doc
         type_list_values list_values;
         for(guint i = 1; i < cols_count; ++i)
         {
-          list_values.push_back(datamodel->get_value_at(1, row));
+          list_values.push_back(datamodel->get_value_at(i, row));
         }
 
         itempair.second = list_values;
diff --git a/glom/mode_data/datawidget/combo.cc b/glom/mode_data/datawidget/combo.cc
index fe0d980..d693b18 100644
--- a/glom/mode_data/datawidget/combo.cc
+++ b/glom/mode_data/datawidget/combo.cc
@@ -38,8 +38,7 @@ namespace DataWidgetChildren
 {
 
 ComboGlom::ComboGlom()
-: ComboChoicesWithTreeModel(),
-  m_cell_second(0)
+: ComboChoicesWithTreeModel()
 {
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   setup_menu();
@@ -50,10 +49,7 @@ ComboGlom::ComboGlom()
 
 void ComboGlom::init()
 {
-  #ifndef GLOM_ENABLE_MAEMO
-  set_model(m_refModel);
-  pack_start(m_Columns.m_col_first);
-  #else
+  #ifdef GLOM_ENABLE_MAEMO
   //Maemo:
   set_selector(m_maemo_selector);
   m_maemo_selector.set_model(0, m_refModel);
@@ -73,40 +69,25 @@ ComboGlom::~ComboGlom()
 {
 }
 
-void ComboGlom::set_choices_related(const Document* document)
+void ComboGlom::create_model(guint columns_count)
 {
-  //TODO: Remove duplication with ComboEntry:
-  sharedptr<LayoutItem_Field> layout_item = 
-    sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
-  bool choice_show_all = false;
-  bool choice_has_second = false;
-  layout_item->get_formatting_used().get_has_related_choices(choice_show_all, choice_has_second);
-  
-  //Add the extra cell if necessary:
-  if(!m_cell_second && choice_has_second)
-  {
-    #ifndef GLOM_ENABLE_MAEMO
-    //We don't use this convenience method, because we want more control over the renderer.
-    //and CellLayout gives no way to get the renderer back afterwards.
-    //(well, maybe set_cell_data_func(), but that's a bit awkward.)
-    //pack_start(m_Columns.m_col_second);
+  //Create the model itself:
+  ComboChoicesWithTreeModel::create_model(columns_count);
 
-    m_cell_second = Gtk::manage(new Gtk::CellRendererText);
-    m_cell_second->set_property("xalign", 0.0);
+  //Show the model in the view:
+  set_model(m_refModel);
+
+  for(guint i = 0; i < columns_count; ++i)
+  {
+    Gtk::CellRendererText* cell = Gtk::manage(new Gtk::CellRendererText);
+    cell->set_property("xalign", 0.0);
 
     //Use the renderer:
-    pack_start(*m_cell_second);
+    pack_start(*cell);
 
     //Make the renderer render the column:
-    add_attribute(m_cell_second->_property_renderable(), m_Columns.m_col_second);
-    std::cout << "debug: Added second column." << std::endl;
-    #else
-    //Maemo:
-    column->pack_start(m_Columns.m_col_second);
-    #endif //GLOM_ENABLE_MAEMO
+    add_attribute(*cell, "text", i);
   }
-
-  ComboChoicesWithTreeModel::set_choices_related(document);
 }
 
 void ComboGlom::check_for_change()
@@ -177,7 +158,9 @@ void ComboGlom::set_text(const Glib::ustring& text)
 
   for(Gtk::TreeModel::iterator iter = m_refModel->children().begin(); iter != m_refModel->children().end(); ++iter)
   {
-    Glib::ustring this_text = (*iter)[m_Columns.m_col_first];
+    const Gtk::TreeModel::Row row = *iter;
+    Glib::ustring this_text;
+    row.get_value(0, this_text);
 
     if(this_text == text)
     {
@@ -225,8 +208,10 @@ Glib::ustring ComboGlom::get_text() const
 
   if(iter)
   {
-    Gtk::TreeModel::Row row = *iter;
-    return row[m_Columns.m_col_first];
+    const Gtk::TreeModel::Row row = *iter;
+    Glib::ustring text;
+    row.get_value(0, text);
+    return text;
   }
 
   return Glib::ustring();
diff --git a/glom/mode_data/datawidget/combo.h b/glom/mode_data/datawidget/combo.h
index 830cb5c..17afac0 100644
--- a/glom/mode_data/datawidget/combo.h
+++ b/glom/mode_data/datawidget/combo.h
@@ -72,10 +72,9 @@ public:
 
   virtual Gnome::Gda::Value get_value() const;
 
-  virtual void set_choices_related(const Document* document);
-
 private:
   void init();
+  virtual void create_model(guint columns_count);
 
   #ifndef GLOM_ENABLE_MAEMO
   // Note that this is a normal signal handler when glibmm was complied
@@ -100,8 +99,6 @@ private:
   #ifdef GLOM_ENABLE_MAEMO
   Hildon::TouchSelector m_maemo_selector;
   #endif
-
-  Gtk::CellRenderer* m_cell_second;
 };
 
 } //namespace DataWidetChildren
diff --git a/glom/mode_data/datawidget/combochoices.h b/glom/mode_data/datawidget/combochoices.h
index 6c885d0..5b0776b 100644
--- a/glom/mode_data/datawidget/combochoices.h
+++ b/glom/mode_data/datawidget/combochoices.h
@@ -51,7 +51,7 @@ public:
   /**
    * See also refresh_data_from_database_with_foreign_key().
    */
-  virtual void set_choices_related(const Document* document);
+  void set_choices_related(const Document* document);
 
   /** Update a choices widget's list of related choices if a relevant value in its parent table has changed.
    *
diff --git a/glom/mode_data/datawidget/combochoiceswithtreemodel.cc b/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
index 5726b7d..36de73c 100644
--- a/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
+++ b/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
@@ -39,20 +39,68 @@ ComboChoicesWithTreeModel::ComboChoicesWithTreeModel()
   init();
 }
 
+ComboChoicesWithTreeModel::~ComboChoicesWithTreeModel()
+{
+  delete_model();
+}
+
 void ComboChoicesWithTreeModel::init()
 {
   ComboChoices::init();
-  m_refModel = Gtk::ListStore::create(m_Columns);
 }
 
-ComboChoicesWithTreeModel::~ComboChoicesWithTreeModel()
+void ComboChoicesWithTreeModel::create_model(guint columns_count)
 {
+  delete_model();
+
+  Gtk::TreeModel::ColumnRecord record;
+
+  //Create the TreeModelColumns, adding them to the ColumnRecord:
+  m_vec_model_columns.resize(columns_count, 0);
+  for(guint i = 0; i < columns_count; ++i)
+  {
+    type_model_column* model_column = new type_model_column();
+
+    //Store it so we can use it and delete it later:
+    m_vec_model_columns[i] = model_column;
+
+    record.add(*model_column);
+  }
+
+  //Create the model:
+  m_refModel = Gtk::ListStore::create(record);
+}
+
+void ComboChoicesWithTreeModel::delete_model()
+{
+  //Delete the vector's items:
+  for(type_vec_model_columns::iterator iter = m_vec_model_columns.begin(); iter != m_vec_model_columns.end(); ++iter)
+  {
+    type_model_column* model_column = *iter;
+     if(model_column)
+       delete model_column;
+  }
+  m_vec_model_columns.clear();
+
+  m_refModel.reset();
 }
 
 void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_with_second& list_values)
 {
-  m_refModel->clear();
+  //Recreate the entire model:
+  guint columns_count = 1; //For the main field.
+  if(!list_values.empty())
+  {
+    type_list_values_with_second::const_iterator iter= list_values.begin();
+    if(iter != list_values.end())
+    {
+      const type_list_values& second = iter->second;
+      columns_count += second.size();
+    }
+  }
+  create_model(columns_count);
 
+  //Fill the model with data:
   //TODO: Remove duplication with ComboEntry:
   sharedptr<LayoutItem_Field> layout_item =
     sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
@@ -74,24 +122,36 @@ void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_w
 
     if(layout_choice_first)
     {
-      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);
+      const Glib::ustring text =
+        Conversions::get_text_for_gda_value(layout_choice_first->get_glom_type(), iter->first, layout_choice_first->get_formatting_used().m_numeric_format);
+      row.set_value(0, text);
 
-      //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())
       {
+        guint model_index = 1; //0 is for the main field.
+        type_list_values::const_iterator iterValues = extra_values.begin();
         for(LayoutGroup::type_list_const_items::const_iterator iterExtra = extra_fields.begin();
           iterExtra != extra_fields.end(); ++iterExtra)
         {
+          if(model_index >= columns_count)
+            break;
+
+          if(iterValues == extra_values.end())
+            break;
+
           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;
+            const Gnome::Gda::Value value = *iterValues;
+            const Glib::ustring text =
+              Conversions::get_text_for_gda_value(item_field->get_glom_type(), value, item_field->get_formatting_used().m_numeric_format);
+            row.set_value(model_index, text);
           }
+
+          ++model_index;
+          ++iterValues;
         }
       }
     }
@@ -101,7 +161,7 @@ void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_w
 
 void ComboChoicesWithTreeModel::set_choices(const FieldFormatting::type_list_values& list_values)
 {
-  m_refModel->clear();
+  create_model(1);
 
   for(FieldFormatting::type_list_values::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
   {
@@ -113,8 +173,7 @@ void ComboChoicesWithTreeModel::set_choices(const FieldFormatting::type_list_val
     {
       const Gnome::Gda::Value value = *iter;
       const Glib::ustring text = Conversions::get_text_for_gda_value(layout_item->get_glom_type(), value, layout_item->get_formatting_used().m_numeric_format);
-
-      row[m_Columns.m_col_first] = text;
+      row.set_value(0, text);
     }
   }
 }
diff --git a/glom/mode_data/datawidget/combochoiceswithtreemodel.h b/glom/mode_data/datawidget/combochoiceswithtreemodel.h
index 8cad4e8..6c0d16e 100644
--- a/glom/mode_data/datawidget/combochoiceswithtreemodel.h
+++ b/glom/mode_data/datawidget/combochoiceswithtreemodel.h
@@ -41,28 +41,21 @@ public:
 
 protected:
   void init();
+  virtual void create_model(guint columns_count);
 
   virtual void set_choices_with_second(const type_list_values_with_second& list_values);
 
-  //Tree model columns:
-  class ModelColumns : public Gtk::TreeModel::ColumnRecord
-  {
-  public:
-
-    ModelColumns()
-    { add(m_col_first); add(m_col_second); }
-
-    Gtk::TreeModelColumn<Glib::ustring> m_col_first; //The data to choose - this must be text.
-    Gtk::TreeModelColumn<Glib::ustring> m_col_second;
-  };
+  Glib::RefPtr<Gtk::ListStore> m_refModel;
 
-  ModelColumns m_Columns;
+private:
+  typedef Gtk::TreeModelColumn<Glib::ustring> type_model_column;
+  typedef std::vector< type_model_column* > type_vec_model_columns;
+  type_vec_model_columns m_vec_model_columns;
 
-  Glib::RefPtr<Gtk::ListStore> m_refModel;
+  void delete_model();
 };
 
 } //namespace DataWidetChildren
 } //namespace Glom
 
 #endif //GLOM_UTILITY_WIDGETS_COMBO_CHOICES_WITH_TREE_MODEL_H
-
diff --git a/glom/mode_data/datawidget/comboentry.cc b/glom/mode_data/datawidget/comboentry.cc
index 5188330..b7afa88 100644
--- a/glom/mode_data/datawidget/comboentry.cc
+++ b/glom/mode_data/datawidget/comboentry.cc
@@ -42,8 +42,7 @@ namespace DataWidgetChildren
 {
 
 ComboEntry::ComboEntry()
-: ComboChoicesWithTreeModel(),
-  m_cell_second(0)
+: ComboChoicesWithTreeModel()
 {
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   setup_menu();
@@ -72,10 +71,7 @@ const Gtk::Entry* ComboEntry::get_entry() const
 
 void ComboEntry::init()
 {
-#ifndef GLOM_ENABLE_MAEMO
-  set_model(m_refModel);
-  set_text_column(m_Columns.m_col_first);
-#else
+#ifdef GLOM_ENABLE_CLIENT_ONLY
   //Maemo:
   set_selector(m_maemo_selector);
 
@@ -112,36 +108,26 @@ ComboEntry::~ComboEntry()
 {
 }
 
-void ComboEntry::set_choices_related(const Document* document)
+void ComboEntry::create_model(guint columns_count)
 {
-  sharedptr<LayoutItem_Field> layout_item = 
-    sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
-  bool choice_show_all = false;
-  bool choice_has_second = false;
-  layout_item->get_formatting_used().get_has_related_choices(choice_show_all, choice_has_second);
-  
-  if(!m_cell_second && choice_has_second) //Use a more efficient way of discovering if there is a second column.
-  {
-    #ifndef GLOM_ENABLE_MAEMO
-    //We don't use this convenience method, because we want more control over the renderer.
-    //and CellLayout gives no way to get the renderer back afterwards.
-    //(well, maybe set_cell_data_func(), but that's a bit awkward.)
-    //pack_start(m_Columns.m_col_second);
+  //Create the model itself:
+  ComboChoicesWithTreeModel::create_model(columns_count);
 
-    m_cell_second = Gtk::manage(new Gtk::CellRendererText);
-    m_cell_second->set_property("xalign", 0.0);
+  //Show model in the view:
+  set_model(m_refModel);
+  set_text_column(0);
+
+  for(guint i = 1; i < columns_count; ++i)
+  {
+    Gtk::CellRendererText* cell = Gtk::manage(new Gtk::CellRendererText);
+    cell->set_property("xalign", 0.0);
 
     //Use the renderer:
-    pack_start(*m_cell_second);
+    pack_start(*cell);
 
     //Make the renderer render the column:
-    add_attribute(m_cell_second->_property_renderable(), m_Columns.m_col_second);
-    #else //GLOM_ENABLE_MAEMO
-    column->pack_start(m_Columns.m_col_second, false);
-    #endif //GLOM_ENABLE_MAEMO
+    add_attribute(*cell, "text", i);
   }
-
-  ComboChoicesWithTreeModel::set_choices_related(document);
 }
 
 void ComboEntry::set_layout_item(const sharedptr<LayoutItem>& layout_item, const Glib::ustring& table_name)
@@ -189,7 +175,7 @@ void ComboEntry::check_for_change()
     bool success = false;
 
     sharedptr<const LayoutItem_Field> layout_item = sharedptr<const LayoutItem_Field>::cast_dynamic(get_layout_item());
-    Gnome::Gda::Value value = Conversions::parse_value(layout_item->get_glom_type(), get_entry()->get_text(), layout_item->get_formatting_used().m_numeric_format, success);
+    const Gnome::Gda::Value value = Conversions::parse_value(layout_item->get_glom_type(), get_entry()->get_text(), layout_item->get_formatting_used().m_numeric_format, success);
 
     if(success)
     {
diff --git a/glom/mode_data/datawidget/comboentry.h b/glom/mode_data/datawidget/comboentry.h
index 87fa061..df8fe21 100644
--- a/glom/mode_data/datawidget/comboentry.h
+++ b/glom/mode_data/datawidget/comboentry.h
@@ -71,10 +71,9 @@ public:
 
   virtual void set_read_only(bool read_only = true);
 
-  virtual void set_choices_related(const Document* document);
-
 private:
   void init();
+  virtual void create_model(guint columns_count);
 
 
   //Overrides of default signal handlers:
@@ -110,8 +109,6 @@ private:
   #ifdef GLOM_ENABLE_MAEMO
   Hildon::TouchSelectorEntry m_maemo_selector;
   #endif
-
-  Gtk::CellRenderer* m_cell_second;
 };
 
 } //namespace DataWidetChildren
diff --git a/glom/utility_widgets/db_adddel/db_adddel.h b/glom/utility_widgets/db_adddel/db_adddel.h
index e09521d..7ea85dd 100644
--- a/glom/utility_widgets/db_adddel/db_adddel.h
+++ b/glom/utility_widgets/db_adddel/db_adddel.h
@@ -405,9 +405,6 @@ private:
   Gtk::TreeView m_TreeView;
   #endif
 
-
-  Gtk::TreeModel::ColumnRecord m_ColumnRecord;
-
   //typedef Gtk::ListStore type_model_store;
   typedef DbTreeModel type_model_store;
   Glib::RefPtr<type_model_store> m_refListStore;
@@ -493,14 +490,6 @@ private:
     bool m_bPreventUserSignals, m_bIgnoreTreeViewSignals;
   };
 
-/*
-  class DynamicColumnRecord : public Gtk::TreeModel::ColumnRecord
-  {
-    typedef std::vector<Gtk::TreeModelColumnBase> type_vecColumns;
-    type_vecColumns m_vecColumns;
-  };
-*/
-
   //When no columns have been chosen in the layout editor,
   //show this model to give the user a hint about what to do:
   class ModelColumnsEmptyHint : public Gtk::TreeModel::ColumnRecord



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