[glom] Custom Choices: Allow these to be translated when used for text fields.



commit 96619f58ccf77966016028c96811d530cd57f1f4
Author: Murray Cumming <murrayc murrayc com>
Date:   Wed Jan 4 23:36:26 2012 +0100

    Custom Choices: Allow these to be translated when used for text fields.
    
    * glom/libglom/filelist.am:
    * glom/libglom/data_structure/layout/choicevalue.[h|cc]: Add the
    ChoiceValue translatable item. The translations are only meaningful
    when this is used for a text field.
    * glom/libglom/data_structure/translatable_item.[h|cc]:
    Make get_title_original() virtual, so ChoiceValue can override it,
    to return a text representation of its Gnome::Gda::Value.
    Always use get_title_original() instead of the member variable,
    so that the method override is used when appropriate.
    * glom/libglom/data_structure/layout/fieldformatting.h:
    set/get_choices_custom(): Return a list of ChoiceValues instead of
    Gnome::Gda::Values.
    * glom/mode_data/datawidget/cellcreation.cc:
    * glom/mode_design/layout/layout_item_dialogs/box_formatting.cc: Adapt.
    
    * glom/libglom/document/document.[h|cc]:
    load_after_layout_item_formatting(), save_before_layout_item_formatting():
    Adapt and load/save the ChoiceValue translations too.
    fill_translatable_layout_items(): Return the ChoiceValue items too.
    Add a static fill_translatable_custom_choices() helper function.
    
    * glom/mode_data/datawidget/combochoices.h: set_choices_fixed():
    Add an optional restricted parameter, because the translations are
    only useful if the choices are restricted.
    * glom/mode_data/datawidget/cellrenderer_dblist.[h|cc]:
    * glom/mode_data/datawidget/combo_as_radio_buttons.[h|cc]:
    * glom/mode_data/datawidget/datawidget.cc:Adapted.
    * glom/mode_data/datawidget/combochoiceswithtreemodel.[h|cc]:
    set_choices_fixed(): Use get_title() if the choice could be translated.
    * glom/mode_data/datawidget/combo.[h|cc]: set_choices_fixed():
    Use the (translated) text value if the choice could be translated.
    
    * glom/mode_design/translation/window_translations.cc:
    load_from_document(): For text fields, handle the ChoiceValues too.
    
    * tests/test_document_load.cc: Adapt.
    * tests/test_document_load_translations.cc: Test ChoiceValue
    translations too.
    * examples/example_film_manager.glom: Add some translations for the
    Scene::Day/Night field's choices. Also make the choices for this
    field restricted, so the translations can be used.
    * glom/glom_document.dtd: custom_choice: Mention the new trans_set
    child tags.
    
    This fixes bug #666343

 ChangeLog                                          |   50 +++++++++++
 examples/example_film_manager.glom                 |   18 +++-
 glom/glom_document.dtd                             |    4 +-
 glom/libglom/data_structure/choicevalue.cc         |   94 ++++++++++++++++++++
 glom/libglom/data_structure/choicevalue.h          |   74 +++++++++++++++
 .../data_structure/layout/fieldformatting.h        |    4 +-
 glom/libglom/data_structure/translatable_item.cc   |   16 +++-
 glom/libglom/data_structure/translatable_item.h    |    5 +-
 glom/libglom/document/document.cc                  |   58 +++++++++++-
 glom/libglom/document/document.h                   |    7 ++-
 glom/libglom/filelist.am                           |    2 +
 glom/mode_data/datawidget/cellcreation.cc          |    6 +-
 glom/mode_data/datawidget/cellrenderer_dblist.cc   |    4 +-
 glom/mode_data/datawidget/cellrenderer_dblist.h    |    2 +-
 glom/mode_data/datawidget/combo.cc                 |   23 ++++-
 glom/mode_data/datawidget/combo.h                  |    2 +-
 .../mode_data/datawidget/combo_as_radio_buttons.cc |    9 ++-
 glom/mode_data/datawidget/combo_as_radio_buttons.h |    2 +-
 glom/mode_data/datawidget/combochoices.h           |    2 +-
 .../datawidget/combochoiceswithtreemodel.cc        |   33 ++++++--
 .../datawidget/combochoiceswithtreemodel.h         |    2 +-
 glom/mode_data/datawidget/datawidget.cc            |    6 +-
 .../layout/layout_item_dialogs/box_formatting.cc   |   15 +++-
 .../mode_design/translation/window_translations.cc |   27 ++++++-
 tests/test_document_load.cc                        |   21 ++++-
 tests/test_document_load_translations.cc           |   65 +++++++++++++-
 26 files changed, 497 insertions(+), 54 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 455d635..193dd5a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,55 @@
 2012-01-04  Murray Cumming  <murrayc murrayc com>
 
+	Custom Choices: Allow these to be translated when used for text fields. 
+
+	* glom/libglom/filelist.am:
+	* glom/libglom/data_structure/layout/choicevalue.[h|cc]: Add the
+	ChoiceValue translatable item. The translations are only meaningful
+	when this is used for a text field.
+	* glom/libglom/data_structure/translatable_item.[h|cc]:
+	Make get_title_original() virtual, so ChoiceValue can override it,
+	to return a text representation of its Gnome::Gda::Value.
+	Always use get_title_original() instead of the member variable,
+	so that the method override is used when appropriate.
+	* glom/libglom/data_structure/layout/fieldformatting.h:
+	set/get_choices_custom(): Return a list of ChoiceValues instead of 
+	Gnome::Gda::Values.
+	* glom/mode_data/datawidget/cellcreation.cc:
+	* glom/mode_design/layout/layout_item_dialogs/box_formatting.cc: Adapt.
+
+	* glom/libglom/document/document.[h|cc]: 
+	load_after_layout_item_formatting(), save_before_layout_item_formatting():
+	Adapt and load/save the ChoiceValue translations too.
+	fill_translatable_layout_items(): Return the ChoiceValue items too.
+	Add a static fill_translatable_custom_choices() helper function. 
+
+	* glom/mode_data/datawidget/combochoices.h: set_choices_fixed():
+	Add an optional restricted parameter, because the translations are 
+	only useful if the choices are restricted.
+	* glom/mode_data/datawidget/cellrenderer_dblist.[h|cc]:
+	* glom/mode_data/datawidget/combo_as_radio_buttons.[h|cc]:
+	* glom/mode_data/datawidget/datawidget.cc:Adapted.
+	* glom/mode_data/datawidget/combochoiceswithtreemodel.[h|cc]:
+	set_choices_fixed(): Use get_title() if the choice could be translated.
+	* glom/mode_data/datawidget/combo.[h|cc]: set_choices_fixed():
+	Use the (translated) text value if the choice could be translated.
+
+	* glom/mode_design/translation/window_translations.cc:
+	load_from_document(): For text fields, handle the ChoiceValues too.
+
+	* tests/test_document_load.cc: Adapt.
+	* tests/test_document_load_translations.cc: Test ChoiceValue 
+	translations too.
+	* examples/example_film_manager.glom: Add some translations for the 
+	Scene::Day/Night field's choices. Also make the choices for this 
+	field restricted, so the translations can be used.
+	* glom/glom_document.dtd: custom_choice: Mention the new trans_set
+	child tags.
+
+	This fixes bug #666343
+
+2012-01-04  Murray Cumming  <murrayc murrayc com>
+
 	Detailsï Make restricted choices work.
 
 	* glom/mode_data/datawidget/combochoiceswithtreemode.[h|cc]:
diff --git a/examples/example_film_manager.glom b/examples/example_film_manager.glom
index 438013b..0f989ed 100644
--- a/examples/example_film_manager.glom
+++ b/examples/example_film_manager.glom
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <glom_document xmlns="http://glom.org/glom_document"; database_title="Openismus Film Manager" is_example="true" translation_original_locale="en_US" format_version="7">
-  <connection server="localhost" user="" database="glom_film_production_manager" self_hosted="true" port="5433" try_other_ports="false" hosting_mode="postgres_self"/>
+  <connection server="localhost" user="" database="glom_film_production_manager" self_hosted="true" port="5435" try_other_ports="false" hosting_mode="postgres_self"/>
   <table name="accommodation" title="Accommodation">
     <example_rows/>
     <trans_set>
@@ -3832,17 +3832,25 @@ Orientation=portrait
         </trans_set>
       </field>
       <field name="day_or_night" type="Text" title="Day/Night">
-        <formatting choices_custom="true">
+        <formatting choices_restricted="true" choices_custom="true">
           <custom_choice_list>
-            <custom_choice value="Day"/>
-            <custom_choice value="Night"/>
+            <custom_choice value="Day">
+              <trans_set>
+                <trans loc="de_DE" val="Tag"/>
+              </trans_set>
+            </custom_choice>
+            <custom_choice value="Night">
+              <trans_set>
+                <trans loc="de_DE" val="Nacht"/>
+              </trans_set>
+            </custom_choice>
             <custom_choice value="Morning"/>
             <custom_choice value="Evening"/>
             <custom_choice value="Dawn"/>
           </custom_choice_list>
         </formatting>
         <trans_set>
-          <trans loc="de_DE" val="Day/Night"/>
+          <trans loc="de_DE" val="Tag/Nacht"/>
         </trans_set>
       </field>
       <field name="interior_or_exterior" type="Text" title="Interior/Exterior">
diff --git a/glom/glom_document.dtd b/glom/glom_document.dtd
index bfd1f14..4cbe6ca 100644
--- a/glom/glom_document.dtd
+++ b/glom/glom_document.dtd
@@ -189,7 +189,9 @@ TODO: Should we specify the presence of child text nodes in the ELEMENT somehow?
     <!ELEMENT custom_choice_list (custom_choice*)>
     <!ATTLIST custom_choice_list>
 
-    <!ELEMENT custom_choice EMPTY>
+<!-- A custom choice for a field's default formatting or for a layout item.
+     The title is just a text-version of the value and can be ignored. TODO: Do not write it? -->
+    <!ELEMENT custom_choice (trans_set?)>
     <!ATTLIST custom_choice
         value CDATA #REQUIRED>
 
diff --git a/glom/libglom/data_structure/choicevalue.cc b/glom/libglom/data_structure/choicevalue.cc
new file mode 100644
index 0000000..00ee7b4
--- /dev/null
+++ b/glom/libglom/data_structure/choicevalue.cc
@@ -0,0 +1,94 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2004 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libglom/data_structure/choicevalue.h>
+#include <glibmm/i18n.h>
+
+#include <iostream>
+
+namespace Glom
+{
+
+ChoiceValue::ChoiceValue()
+{
+  m_translatable_item_type = TRANSLATABLE_TYPE_CHOICEVALUE;
+}
+
+ChoiceValue::ChoiceValue(const ChoiceValue& src)
+: TranslatableItem(src)
+{
+  //TODO_Performance: Implement this properly, without the extra copy.
+  operator=(src);
+}
+
+ChoiceValue::~ChoiceValue()
+{
+}
+
+ChoiceValue& ChoiceValue::operator=(const ChoiceValue& src)
+{
+  TranslatableItem::operator=(src);
+
+  m_value = src.m_value;
+
+  return *this;
+}
+
+bool ChoiceValue::operator==(const ChoiceValue& src) const
+{
+  return TranslatableItem::operator==(src)
+         && (m_value == src.m_value);
+}
+
+bool ChoiceValue::operator!=(const ChoiceValue& src) const
+{
+  return !(operator==(src));
+}
+
+ChoiceValue* ChoiceValue::clone() const
+{
+  return new ChoiceValue(*this);
+}
+
+void ChoiceValue::set_value(const Gnome::Gda::Value& value)
+{
+  m_value = value;
+}
+
+Gnome::Gda::Value ChoiceValue::get_value() const
+{
+  return m_value;
+}
+
+Glib::ustring ChoiceValue::get_title_original() const
+{
+  return m_value.to_string();
+}
+
+bool ChoiceValue::is_translatable() const
+{
+  if(m_value.get_value_type() == G_TYPE_STRING)
+    return true;
+
+  return false;
+}
+
+
+} //namespace Glom
diff --git a/glom/libglom/data_structure/choicevalue.h b/glom/libglom/data_structure/choicevalue.h
new file mode 100644
index 0000000..b93ea03
--- /dev/null
+++ b/glom/libglom/data_structure/choicevalue.h
@@ -0,0 +1,74 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2004 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GLOM_DATASTRUCTURE_CHOICEVALUE_H
+#define GLOM_DATASTRUCTURE_CHOICEVALUE_H
+
+#include <libglom/data_structure/translatable_item.h>
+#include <libgdamm/value.h>
+
+namespace Glom
+{
+
+
+/** A value of a custom choice, for a field or a layout item.
+ * This is translatable, but that only make sense for text fields.
+ *
+ * Text-specific methods such as get/set_title() should be ignored.
+ */
+class ChoiceValue : public TranslatableItem
+{
+public:
+
+  ChoiceValue();
+  ChoiceValue(const ChoiceValue& src);
+  ~ChoiceValue();
+
+  ChoiceValue& operator=(const ChoiceValue& src);
+
+  bool operator==(const ChoiceValue& src) const;
+  bool operator!=(const ChoiceValue& src) const;
+
+  ChoiceValue* clone() const;
+
+  void set_value(const Gnome::Gda::Value& value);
+  Gnome::Gda::Value get_value() const;
+
+  /** This override makes sure that we can generically use
+   * ChoiceValue like any other TranslatableItem,
+   * assuming that the value is a title,
+   * if it is a text value.
+   */
+  virtual Glib::ustring get_title_original() const;
+
+  /** Whether the value is of a type that can be translated.
+   * This means that it must be a text type.
+   */
+  bool is_translatable() const;
+  
+
+private:
+  Gnome::Gda::Value m_value;
+};
+
+} //namespace Glom
+
+#endif //GLOM_DATASTRUCTURE_CHOICEVALUE_H
+
diff --git a/glom/libglom/data_structure/layout/fieldformatting.h b/glom/libglom/data_structure/layout/fieldformatting.h
index 383193c..a447711 100644
--- a/glom/libglom/data_structure/layout/fieldformatting.h
+++ b/glom/libglom/data_structure/layout/fieldformatting.h
@@ -24,7 +24,7 @@
 #include <libglom/data_structure/layout/usesrelationship.h>
 #include <libglom/data_structure/numeric_format.h>
 #include <libglom/data_structure/relationship.h>
-#include <libglom/sharedptr.h>
+#include <libglom/data_structure/choicevalue.h>
 #include <libgdamm/value.h>
 #include <list>
 
@@ -55,7 +55,7 @@ public:
   bool get_has_custom_choices() const;
   void set_has_custom_choices(bool val = true);
 
-  typedef std::list<Gnome::Gda::Value> type_list_values;
+  typedef std::list< sharedptr<ChoiceValue> > type_list_values;
   virtual type_list_values get_choices_custom() const;
   virtual void set_choices_custom(const type_list_values& choices);
 
diff --git a/glom/libglom/data_structure/translatable_item.cc b/glom/libglom/data_structure/translatable_item.cc
index 7b8e21c..1ae12bd 100644
--- a/glom/libglom/data_structure/translatable_item.cc
+++ b/glom/libglom/data_structure/translatable_item.cc
@@ -116,8 +116,9 @@ Glib::ustring TranslatableItem::get_title_translation(const Glib::ustring& local
   }
 
   //Fall back to the original title:
-  if(!m_title.empty())
-    return m_title;
+  const Glib::ustring title_original = get_title_original();
+  if(!title_original.empty())
+    return title_original;
 
   //Fall back to first translation, if any.
   //This would be quite unusual.
@@ -152,7 +153,7 @@ Glib::ustring TranslatableItem::get_title() const
       return translated_title;
   }
 
-  return m_title;
+  return get_title_original();
 }
 
 
@@ -185,6 +186,7 @@ void TranslatableItem::set_title_original(const Glib::ustring& title)
   m_title = title;
 }
 
+//TODO: Make this virtual and handle it in ChoiceValue?
 void TranslatableItem::clear_title_in_all_locales()
 {
   m_title.clear();
@@ -281,8 +283,10 @@ Glib::ustring TranslatableItem::get_translatable_type_name_nontranslated(enumTra
     return "Button";
   else if(item_type == TRANSLATABLE_TYPE_TEXTOBJECT)
     return "Text";
- else if(item_type == TRANSLATABLE_TYPE_IMAGEOBJECT)
+  else if(item_type == TRANSLATABLE_TYPE_IMAGEOBJECT)
     return "Image";
+  else if(item_type == TRANSLATABLE_TYPE_CHOICEVALUE)
+    return "Field Choice";
   else
     return "Unknown";
 }
@@ -311,8 +315,10 @@ Glib::ustring TranslatableItem::get_translatable_type_name(enumTranslatableItemT
     return _("Button");
   else if(item_type == TRANSLATABLE_TYPE_TEXTOBJECT)
     return _("Text");
- else if(item_type == TRANSLATABLE_TYPE_IMAGEOBJECT)
+  else if(item_type == TRANSLATABLE_TYPE_IMAGEOBJECT)
     return _("Image");
+  else if(item_type == TRANSLATABLE_TYPE_CHOICEVALUE)
+    return _("Field Choice");
   else
     return _("Unknown");
 }
diff --git a/glom/libglom/data_structure/translatable_item.h b/glom/libglom/data_structure/translatable_item.h
index 8c09811..deb3e2e 100644
--- a/glom/libglom/data_structure/translatable_item.h
+++ b/glom/libglom/data_structure/translatable_item.h
@@ -59,7 +59,7 @@ public:
 
   /** Get the title's original (non-translated, usually English) text.
    */
-  Glib::ustring get_title_original() const;
+  virtual Glib::ustring get_title_original() const;
 
 
   /** Set the title's translation for the current locale.
@@ -98,7 +98,8 @@ public:
      TRANSLATABLE_TYPE_TABLE,
      TRANSLATABLE_TYPE_BUTTON,
      TRANSLATABLE_TYPE_TEXTOBJECT,
-     TRANSLATABLE_TYPE_IMAGEOBJECT
+     TRANSLATABLE_TYPE_IMAGEOBJECT,
+     TRANSLATABLE_TYPE_CHOICEVALUE
    };
 
   enumTranslatableItemType get_translatable_item_type();
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index 14c7656..4028529 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -2075,7 +2075,8 @@ void Document::load_after_layout_item_formatting(const xmlpp::Element* element,
                 field_type = field_temp->get_glom_type();
             }
 
-            const Gnome::Gda::Value value = get_node_attribute_value_as_value(element, GLOM_ATTRIBUTE_VALUE, field_type);
+            sharedptr<ChoiceValue> value = sharedptr<ChoiceValue>::create();
+            load_after_choicevalue(element, value, field_type);
             list_values.push_back(value);
           }
         }
@@ -2544,7 +2545,11 @@ void Document::load_after_translations(const xmlpp::Element* element, Translatab
   if(!element)
     return;
 
-  item.set_title_original( get_node_attribute_value(element, GLOM_ATTRIBUTE_TITLE) );
+  const ChoiceValue* choicevalue = dynamic_cast<ChoiceValue*>(&item);
+  if(!choicevalue) //This item does not use the title, but uses the title translations to translate its value, if it is of type text.
+  {
+    item.set_title_original( get_node_attribute_value(element, GLOM_ATTRIBUTE_TITLE) );
+  };
 
   const xmlpp::Element* nodeTranslations = get_node_child_named(element, GLOM_NODE_TRANSLATIONS_SET);
   if(nodeTranslations)
@@ -2599,6 +2604,15 @@ void Document::load_after_print_layout_position(const xmlpp::Element* nodeItem,
   }
 }
 
+void Document::load_after_choicevalue(const xmlpp::Element* element, const sharedptr<ChoiceValue>& item, Field::glom_field_type field_type)
+{
+  const Gnome::Gda::Value value = get_node_attribute_value_as_value(element, GLOM_ATTRIBUTE_VALUE, field_type);
+  item->set_value(value);
+
+  sharedptr<ChoiceValue> nonconst_item = item; //TODO: Avoid this.
+  load_after_translations(element, *nonconst_item);
+}
+
 bool Document::load_after(int& failure_code)
 {
   //Initialize the output variable:
@@ -3230,8 +3244,9 @@ void Document::save_before_layout_item_formatting(xmlpp::Element* nodeItem, cons
       const FieldFormatting::type_list_values list_values = format.get_choices_custom();
       for(FieldFormatting::type_list_values::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
       {
+        const sharedptr<const ChoiceValue> value = *iter; 
         xmlpp::Element* childChoice = child->add_child(GLOM_NODE_FORMAT_CUSTOM_CHOICE);
-        set_node_attribute_value_as_value(childChoice, GLOM_ATTRIBUTE_VALUE, *iter, field_type);
+        save_before_choicevalue(childChoice, value, field_type);
       }
     }
 
@@ -3608,8 +3623,11 @@ void Document::save_before_translations(xmlpp::Element* element, const Translata
   if(!element)
     return;
 
-  set_node_attribute_value(element, GLOM_ATTRIBUTE_TITLE, item.get_title_original());
-
+  const ChoiceValue* choicevalue = dynamic_cast<const ChoiceValue*>(&item);
+  if(!choicevalue) //This item does not use the title, but uses the title translations to translate its value, if it is of type text.
+  {
+    set_node_attribute_value(element, GLOM_ATTRIBUTE_TITLE, item.get_title_original());
+  }
 
   if(!item.get_has_translations())
     return;
@@ -3655,6 +3673,15 @@ void Document::save_before_print_layout_position(xmlpp::Element* nodeItem, const
     nodeItem->remove_child(child);
 }
 
+void Document::save_before_choicevalue(xmlpp::Element* nodeItem, const sharedptr<const ChoiceValue>& item, Field::glom_field_type field_type)
+{
+  if(!item)
+    return;
+
+  set_node_attribute_value_as_value(nodeItem, GLOM_ATTRIBUTE_VALUE, item->get_value(), field_type);
+  save_before_translations(nodeItem, *item);
+}
+
 bool Document::save_before()
 {
   //TODO: Use some callback UI to show a busy cursor?
@@ -4415,6 +4442,22 @@ Document::type_list_translatables Document::get_translatable_report_items(const
   return the_list;
 }
 
+void Document::fill_translatable_custom_choices(FieldFormatting& formatting, type_list_translatables& the_list)
+{
+  if(!formatting.get_has_custom_choices())
+    return;
+
+  FieldFormatting::type_list_values values = formatting.get_choices_custom();
+  for(FieldFormatting::type_list_values::iterator iter = values.begin(); iter != values.end(); ++iter)
+  {
+    sharedptr<ChoiceValue> value = *iter;
+
+    //TODO: Make the translator comment mention the field name as well 
+    //as just the fact that it's a custom choice.
+    the_list.push_back(value);
+  }
+}
+
 void Document::fill_translatable_layout_items(const sharedptr<LayoutGroup>& group, type_list_translatables& the_list)
 {
   the_list.push_back(group);
@@ -4460,6 +4503,11 @@ void Document::fill_translatable_layout_items(const sharedptr<LayoutGroup>& grou
           {
             the_list.push_back(custom_title);
           }
+
+          //Custom Choices, if any:
+          //Only text fields can have translated choice values:
+          if(layout_field->get_glom_type() == Field::TYPE_TEXT)
+            fill_translatable_custom_choices(layout_field->m_formatting, the_list);
         }
       }
     }
diff --git a/glom/libglom/document/document.h b/glom/libglom/document/document.h
index 35d76d8..1107bbf 100644
--- a/glom/libglom/document/document.h
+++ b/glom/libglom/document/document.h
@@ -261,6 +261,9 @@ public:
   type_list_translatables get_translatable_layout_items(const Glib::ustring& table_name);
   type_list_translatables get_translatable_report_items(const Glib::ustring& table_name, const Glib::ustring& report_title);
 
+  static void fill_translatable_custom_choices(FieldFormatting& formatting, type_list_translatables& the_list);
+
+
   void fill_layout_field_details(const Glib::ustring& parent_table_name, const sharedptr<LayoutGroup>& layout_group) const;
   void fill_layout_field_details(const Glib::ustring& parent_table_name, type_list_layout_groups& groups) const;
 
@@ -498,6 +501,7 @@ private:
 
   void save_before_translations(xmlpp::Element* nodeItem, const TranslatableItem& item);
   void save_before_print_layout_position(xmlpp::Element* nodeItem, const sharedptr<const LayoutItem>& item);
+  void save_before_choicevalue(xmlpp::Element* nodeItem, const sharedptr<const ChoiceValue>& item, Field::glom_field_type field_type);
 
   void save_changes();
 
@@ -511,10 +515,11 @@ private:
 
   void load_after_translations(const xmlpp::Element* element, TranslatableItem& item);
   void load_after_print_layout_position(const xmlpp::Element* nodeItem, const sharedptr<LayoutItem>& item);
+  void load_after_choicevalue(const xmlpp::Element* element, const sharedptr<ChoiceValue>& item, Field::glom_field_type field_type);
 
   void on_app_state_userlevel_changed(AppState::userlevels userlevel);
 
-  void fill_translatable_layout_items(const sharedptr<LayoutGroup>& group, type_list_translatables& the_list);
+  static void fill_translatable_layout_items(const sharedptr<LayoutGroup>& group, type_list_translatables& the_list);
 
   void fill_sort_field_details(const Glib::ustring& parent_table_name, FieldFormatting::type_list_sort_fields& sort_fields) const;
 
diff --git a/glom/libglom/filelist.am b/glom/libglom/filelist.am
index 781eac8..6fff9a1 100644
--- a/glom/libglom/filelist.am
+++ b/glom/libglom/filelist.am
@@ -28,6 +28,7 @@ libglom_toplevel_headers =				\
 	glom/libglom/report_builder.h
 
 libglom_data_structure_headers =				\
+	glom/libglom/data_structure/choicevalue.h			\
 	glom/libglom/data_structure/field.h			\
 	glom/libglom/data_structure/fieldtypes.h		\
 	glom/libglom/data_structure/foundset.h			\
@@ -117,6 +118,7 @@ libglom_sources =							\
 	glom/libglom/xsl_utils.h					\
 	glom/libglom/connectionpool_backends/backend.cc			\
 	glom/libglom/connectionpool_backends/backend.h			\
+  glom/libglom/data_structure/choicevalue.cc \	
 	glom/libglom/data_structure/field.cc				\
 	glom/libglom/data_structure/fieldtypes.cc			\
 	glom/libglom/data_structure/foundset.cc				\
diff --git a/glom/mode_data/datawidget/cellcreation.cc b/glom/mode_data/datawidget/cellcreation.cc
index f3f6f05..59db73d 100644
--- a/glom/mode_data/datawidget/cellcreation.cc
+++ b/glom/mode_data/datawidget/cellcreation.cc
@@ -201,7 +201,11 @@ Gtk::CellRenderer* create_cell(const sharedptr<const LayoutItem>& layout_item, c
       const FieldFormatting::type_list_values list_values = item_field->get_formatting_used().get_choices_custom();
       for(FieldFormatting::type_list_values::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
       {
-        pCellRendererList->append_list_item( Conversions::get_text_for_gda_value(item_field->get_glom_type(), *iter, item_field->get_formatting_used().m_numeric_format) );
+        const sharedptr< const ChoiceValue> value = *iter;
+        if(!value)
+          continue;
+
+        pCellRendererList->append_list_item( Conversions::get_text_for_gda_value(item_field->get_glom_type(), value->get_value(), item_field->get_formatting_used().m_numeric_format) );
       }
     }
   }
diff --git a/glom/mode_data/datawidget/cellrenderer_dblist.cc b/glom/mode_data/datawidget/cellrenderer_dblist.cc
index b60a932..eb85e58 100644
--- a/glom/mode_data/datawidget/cellrenderer_dblist.cc
+++ b/glom/mode_data/datawidget/cellrenderer_dblist.cc
@@ -40,9 +40,9 @@ CellRendererDbList::~CellRendererDbList()
 }
 
 
-void CellRendererDbList::set_choices_fixed(const FieldFormatting::type_list_values& list_values)
+void CellRendererDbList::set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool restricted)
 {
-  ComboChoicesWithTreeModel::set_choices_fixed(list_values);
+  ComboChoicesWithTreeModel::set_choices_fixed(list_values, restricted);
 
   Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
 
diff --git a/glom/mode_data/datawidget/cellrenderer_dblist.h b/glom/mode_data/datawidget/cellrenderer_dblist.h
index 715e18e..213bb40 100644
--- a/glom/mode_data/datawidget/cellrenderer_dblist.h
+++ b/glom/mode_data/datawidget/cellrenderer_dblist.h
@@ -41,7 +41,7 @@ public:
   virtual ~CellRendererDbList();
 
   //This creates a simple ListStore, with a text cell renderer.
-  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values);
+  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool restricted = false);
 
   //This creates a db-based tree model, with appropriate cell renderers:
   virtual void set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value);
diff --git a/glom/mode_data/datawidget/combo.cc b/glom/mode_data/datawidget/combo.cc
index 77c6a1b..57d816c 100644
--- a/glom/mode_data/datawidget/combo.cc
+++ b/glom/mode_data/datawidget/combo.cc
@@ -85,9 +85,9 @@ void ComboGlom::on_fixed_cell_data(const Gtk::TreeModel::iterator& iter, Gtk::Ce
   set_cell_for_field_value(cell, field, value);
 }
 
-void ComboGlom::set_choices_fixed(const FieldFormatting::type_list_values& list_values)
+void ComboGlom::set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool restricted)
 {
-  ComboChoicesWithTreeModel::set_choices_fixed(list_values);
+  ComboChoicesWithTreeModel::set_choices_fixed(list_values, restricted);
 
   Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
   if(!model)
@@ -118,8 +118,13 @@ void ComboGlom::set_choices_fixed(const FieldFormatting::type_list_values& list_
   
   guint columns_count = model->get_n_columns();
   if(columns_count)
-    columns_count -= 1; //The last one is the just the extra text-equivalent of the first one, for GtkComboBox wth has-entry=true.
+    columns_count -= 1; //The last one is the just the extra text-equivalent of the first one, for GtkComboBox with has-entry=true, or for translations.
 
+  const sharedptr<const LayoutItem>& layout_item = get_layout_item();
+  const sharedptr<const LayoutItem_Field> field = sharedptr<const LayoutItem_Field>::cast_dynamic(layout_item);
+
+  //For fixed (custom) choices, this will always be 1 column anyway,
+  //so the for() loop here is excessive.
   for(guint i = 0; i < columns_count; ++i)
   {
     //set_entry_text_column() adds its own CellRenderer,
@@ -136,8 +141,16 @@ void ComboGlom::set_choices_fixed(const FieldFormatting::type_list_values& list_
     cell_area->pack_start(*cell, true /* expand */, true /* align */, true /* fixed */);
 
     //Make the renderer render the column:
-    set_cell_data_func(*cell,
-      sigc::bind( sigc::mem_fun(*this, &ComboGlom::on_fixed_cell_data), cell, i));
+    if(restricted && field && (field->get_glom_type() == Field::TYPE_TEXT))
+    {
+      //Use the translation instead:
+      add_attribute(*cell, "text", columns_count); //The extra text column.
+    }
+    else
+    {
+      set_cell_data_func(*cell,
+        sigc::bind( sigc::mem_fun(*this, &ComboGlom::on_fixed_cell_data), cell, i));
+    }
   }
 }
 
diff --git a/glom/mode_data/datawidget/combo.h b/glom/mode_data/datawidget/combo.h
index 021bb31..0f609f4 100644
--- a/glom/mode_data/datawidget/combo.h
+++ b/glom/mode_data/datawidget/combo.h
@@ -50,7 +50,7 @@ public:
   virtual ~ComboGlom();
 
   //This creates a simple ListStore, with a text cell renderer.
-  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values);
+  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool restricted = false);
 
   //This creates a db-based tree model, with appropriate cell renderers:
   virtual void set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_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 2ee500d..44c213e 100644
--- a/glom/mode_data/datawidget/combo_as_radio_buttons.cc
+++ b/glom/mode_data/datawidget/combo_as_radio_buttons.cc
@@ -121,7 +121,7 @@ void ComboAsRadioButtons::set_choices_with_second(const type_list_values_with_se
   }
 }
 
-void ComboAsRadioButtons::set_choices_fixed(const FieldFormatting::type_list_values& list_values)
+void ComboAsRadioButtons::set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool /* restricted */)
 {
   //Clear existing buttons:
   for(type_map_buttons::iterator iter = m_map_buttons.begin();
@@ -139,7 +139,12 @@ void ComboAsRadioButtons::set_choices_fixed(const FieldFormatting::type_list_val
     sharedptr<const LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
     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);
+      const sharedptr<ChoiceValue> choicevalue = *iter;
+      Gnome::Gda::Value value;
+      if(choicevalue)
+        value = choicevalue->get_value();
+
+      const Glib::ustring value_first = Conversions::get_text_for_gda_value(layout_item->get_glom_type(), value, layout_item->get_formatting_used().m_numeric_format);
 
       Gtk::RadioButton* button = new Gtk::RadioButton(group, value_first);
       m_map_buttons[value_first] = button;
diff --git a/glom/mode_data/datawidget/combo_as_radio_buttons.h b/glom/mode_data/datawidget/combo_as_radio_buttons.h
index 2ef9ad5..5aa277c 100644
--- a/glom/mode_data/datawidget/combo_as_radio_buttons.h
+++ b/glom/mode_data/datawidget/combo_as_radio_buttons.h
@@ -50,7 +50,7 @@ public:
 
   virtual ~ComboAsRadioButtons();
 
-  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values);
+  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool restricted = false);
 
   virtual void set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value);
 
diff --git a/glom/mode_data/datawidget/combochoices.h b/glom/mode_data/datawidget/combochoices.h
index 118bf17..f856784 100644
--- a/glom/mode_data/datawidget/combochoices.h
+++ b/glom/mode_data/datawidget/combochoices.h
@@ -48,7 +48,7 @@ public:
   /** Set a list of choice values, for instance for a list of custom choices.
    * You should first call set_layout_item() to provide formatting details.
    */
-  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values) = 0;
+  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool restricted = false) = 0;
 
   /** Show the list of related chocie values based on the LayoutItem's formatting choices.
    * You should first call set_layout_item() to provide that formatting detail,
diff --git a/glom/mode_data/datawidget/combochoiceswithtreemodel.cc b/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
index 684fea6..c4a3ade 100644
--- a/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
+++ b/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
@@ -203,7 +203,7 @@ void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_w
 */
 
 
-void ComboChoicesWithTreeModel::set_choices_fixed(const FieldFormatting::type_list_values& list_values)
+void ComboChoicesWithTreeModel::set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool restricted)
 {
   create_model_non_db(1); //Use a regular ListStore without a dynamic column?
 
@@ -220,14 +220,33 @@ void ComboChoicesWithTreeModel::set_choices_fixed(const FieldFormatting::type_li
     Gtk::TreeModel::Row row = *iterTree;
 
     sharedptr<const LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
-    if(layout_item)
+    if(!layout_item)
+      continue;
+    
+    const sharedptr<ChoiceValue> choicevalue = *iter;
+    if(!choicevalue)
+      continue;
+
+    //Note that this is never a translated version of the value.
+    //This is the original value that will be stored in, or read form, the database.
+    const Gnome::Gda::Value value = choicevalue->get_value();
+    row.set_value(0, value);
+
+    //The text to show in the combo box for the item:
+    Glib::ustring text;
+    if(restricted && choicevalue->is_translatable())
+    {
+      //Show the translated text of the value:
+      //This will never be stored in the database:
+      text = choicevalue->get_title();
+    }
+    else
     {
-      const Gnome::Gda::Value value = *iter;
-      row.set_value(0, value);
-      
-      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.set_value(1, text);
+      text = Conversions::get_text_for_gda_value(layout_item->get_glom_type(), 
+        value, layout_item->get_formatting_used().m_numeric_format);
     }
+
+    row.set_value(1, text);
   }
 
   //The derived class's (virtual) implementation calls this base method and
diff --git a/glom/mode_data/datawidget/combochoiceswithtreemodel.h b/glom/mode_data/datawidget/combochoiceswithtreemodel.h
index e33c1c6..75a7f83 100644
--- a/glom/mode_data/datawidget/combochoiceswithtreemodel.h
+++ b/glom/mode_data/datawidget/combochoiceswithtreemodel.h
@@ -40,7 +40,7 @@ public:
   virtual ~ComboChoicesWithTreeModel();
 
   //This creates a simple ListStore, with a text cell renderer.
-  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values);
+  virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values, bool restricted = false);
 
   //This creates a db-based tree model, with appropriate cell renderers:
   virtual void set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value);
diff --git a/glom/mode_data/datawidget/datawidget.cc b/glom/mode_data/datawidget/datawidget.cc
index 7b05c04..7c74e01 100644
--- a/glom/mode_data/datawidget/datawidget.cc
+++ b/glom/mode_data/datawidget/datawidget.cc
@@ -47,7 +47,7 @@ namespace Glom
 static DataWidgetChildren::ComboChoices* create_combo_widget_for_field(const sharedptr<LayoutItem_Field>& field)
 {
   DataWidgetChildren::ComboChoices* result = 0;
-  bool as_radio_buttons = false; //TODO: Use this.
+  bool as_radio_buttons = false;
   const bool restricted = field->get_formatting_used().get_choices_restricted(as_radio_buttons);
   if(restricted)
   {
@@ -123,7 +123,9 @@ DataWidget::DataWidget(const sharedptr<LayoutItem_Field>& field, const Glib::ust
         //set_choices_fixed() needs this, for the numeric layout:
         combo->set_layout_item( get_layout_item(), table_name);
 
-        combo->set_choices_fixed( field->get_formatting_used().get_choices_custom() );
+	const FieldFormatting& formatting = field->get_formatting_used();
+	bool as_radio_buttons = false; //Ignored;
+        combo->set_choices_fixed( formatting.get_choices_custom(), formatting.get_choices_restricted(as_radio_buttons));
       }
       else if(field->get_formatting_used().get_has_related_choices())
       {
diff --git a/glom/mode_design/layout/layout_item_dialogs/box_formatting.cc b/glom/mode_design/layout/layout_item_dialogs/box_formatting.cc
index fb2805c..9a235a0 100644
--- a/glom/mode_design/layout/layout_item_dialogs/box_formatting.cc
+++ b/glom/mode_design/layout/layout_item_dialogs/box_formatting.cc
@@ -329,8 +329,13 @@ void Box_Formatting::set_formatting_for_non_field(const FieldFormatting& format,
     FieldFormatting::type_list_values list_choice_values = format.get_choices_custom();
     for(FieldFormatting::type_list_values::const_iterator iter = list_choice_values.begin(); iter != list_choice_values.end(); ++iter)
     {
+      const sharedptr<ChoiceValue> choicevalue = *iter;
+      Gnome::Gda::Value value;
+      if(choicevalue)
+        value = choicevalue->get_value();
+
       //Display the value in the choices list as it would be displayed in the format:
-      const Glib::ustring value_text = Conversions::get_text_for_gda_value(m_field->get_glom_type(), *iter, format.m_numeric_format);
+      const Glib::ustring value_text = Conversions::get_text_for_gda_value(m_field->get_glom_type(), value, format.m_numeric_format);
       Gtk::TreeModel::iterator iter = m_adddel_choices_custom->add_item(value_text);
       m_adddel_choices_custom->set_value(iter, m_col_index_custom_choices, value_text);
     }
@@ -414,10 +419,14 @@ bool Box_Formatting::get_formatting(FieldFormatting& format) const
         if(!text.empty())
         {
           bool success = false;
-          Gnome::Gda::Value value = Conversions::parse_value(m_field->get_glom_type(), text, m_format.m_numeric_format, success);
+          const Gnome::Gda::Value value = Conversions::parse_value(m_field->get_glom_type(), text, m_format.m_numeric_format, success);
 
           if(success)
-            list_choice_values.push_back(value);
+          {
+            sharedptr<ChoiceValue> choicevalue = sharedptr<ChoiceValue>::create();
+            choicevalue->set_value(value);
+            list_choice_values.push_back(choicevalue);
+          }
         }
       }
     }
diff --git a/glom/mode_design/translation/window_translations.cc b/glom/mode_design/translation/window_translations.cc
index fd6ec4a..f3975c5 100644
--- a/glom/mode_design/translation/window_translations.cc
+++ b/glom/mode_design/translation/window_translations.cc
@@ -238,14 +238,39 @@ void Window_Translations::load_from_document()
     Document::type_vec_fields fields = document->get_table_fields(table_name);
     for(Document::type_vec_fields::iterator iter = fields.begin(); iter != fields.end(); ++iter)
     {
+      sharedptr<Field> field = *iter;
+      if(!field)
+        continue;
+
       Gtk::TreeModel::iterator iterTree = m_model->append();
       Gtk::TreeModel::Row row = *iterTree;
 
-      sharedptr<Field> field = *iter;
       row[m_columns.m_col_item] = field;
       row[m_columns.m_col_translation] = field->get_title_translation(m_translation_locale, false);
       row[m_columns.m_col_parent_table] = table_name;
 
+      //Custom Choices, if any:
+      if(field->get_glom_type() == Field::TYPE_TEXT) //Choices for other field types could not be translated.
+      {
+        Document::type_list_translatables list_choice_items;
+        Document::fill_translatable_custom_choices(field->m_default_formatting, list_choice_items);
+        for(Document::type_list_translatables::iterator iter = list_choice_items.begin(); iter != list_choice_items.end(); ++iter)
+        {
+          sharedptr<TranslatableItem> item = *iter;
+          if(!item)
+            continue;
+
+          if(item->get_title_original().empty())
+            continue;
+
+          Gtk::TreeModel::iterator iterTree = m_model->append();
+          Gtk::TreeModel::Row row = *iterTree;
+
+          row[m_columns.m_col_item] = item;
+          row[m_columns.m_col_translation] = item->get_title_translation(m_translation_locale, false);
+          row[m_columns.m_col_parent_table] = table_name;
+        }
+      }
     }
 
     //The table's relationships:
diff --git a/tests/test_document_load.cc b/tests/test_document_load.cc
index 118d279..840a8d8 100644
--- a/tests/test_document_load.cc
+++ b/tests/test_document_load.cc
@@ -46,6 +46,23 @@ bool contains_named(const T_Container& container, const Glib::ustring& name)
   return iter != container.end();
 }
 
+template<typename T_Container>
+bool contains_value(const T_Container& container, const Glib::ustring& name)
+{
+  typedef typename T_Container::value_type type_item;
+  typedef typename T_Container::const_iterator type_iterator;
+
+  for(type_iterator iter = container.begin(); iter != container.end(); ++iter)
+  {
+    const type_item item = *iter;
+    if(item->get_value() == Gnome::Gda::Value(name))
+      return true;
+  }
+
+  return false;
+}
+
+
 static bool groups_contain_named(const Glom::Document::type_list_groups& container, const Glib::ustring& name)
 {
   const Glom::Document::type_list_groups::const_iterator iter =
@@ -229,8 +246,8 @@ int main()
   g_assert(!formatting.get_has_related_choices());
   Glom::FieldFormatting::type_list_values choices = formatting.get_choices_custom();
   g_assert(!choices.empty());
-  g_assert(contains(choices, Gnome::Gda::Value("Mr")));
-  g_assert(contains(choices, Gnome::Gda::Value("Mrs")));
+  g_assert(contains_value(choices, "Mr"));
+  g_assert(contains_value(choices, "Mrs"));
   
   //Check that the default formatting is used on the layout:
   field_on_layout = 
diff --git a/tests/test_document_load_translations.cc b/tests/test_document_load_translations.cc
index 0e84ad2..5ebfd75 100644
--- a/tests/test_document_load_translations.cc
+++ b/tests/test_document_load_translations.cc
@@ -38,14 +38,53 @@ bool contains(const T_Container& container, const T_Value& name)
   return iter != container.end();
 }
 
+
+
+/** A predicate for use with std::find_if() to find a Field or LayoutItem which refers 
+ * to the same field, looking at just the name.
+ */
+template<class T_Element>
+class predicate_ItemHasTitle
+{
+public:
+  predicate_ItemHasTitle(const Glib::ustring& title)
+  {
+    m_title = title;
+  }
+
+  virtual ~predicate_ItemHasTitle()
+  {
+  }
+
+  bool operator() (const Glom::sharedptr<T_Element>& element)
+  {
+    return (element->get_title() == m_title);
+  }
+
+  bool operator() (const Glom::sharedptr<const T_Element>& element)
+  {
+    return (element->get_title() == m_title);
+  }
+
+private:
+  Glib::ustring m_title;
+};
+
+
 template<typename T_Container>
-bool contains_named(const T_Container& container, const Glib::ustring& name)
+typename T_Container::value_type get_titled(const T_Container& container, const Glib::ustring& title)
 {
+  typedef typename T_Container::value_type type_sharedptr;
+  type_sharedptr result;
+
   typedef typename T_Container::value_type::object_type type_item;
   typename T_Container::const_iterator iter =
     std::find_if(container.begin(), container.end(),
-      Glom::predicate_FieldHasName<type_item>(name));
-  return iter != container.end();
+      predicate_ItemHasTitle<type_item>(title));
+  if(iter != container.end())
+    result = *iter;
+
+  return result;
 }
 
 static Glom::sharedptr<const Glom::LayoutItem_Field> get_field_on_layout(const Glom::Document& document, const Glib::ustring& layout_table_name, const Glib::ustring& table_name, const Glib::ustring& field_name)
@@ -172,10 +211,30 @@ int main()
   g_assert( document.get_table_title("scenes") == "Szenen" );
   Glom::TranslatableItem::set_current_locale(locale_original);
 
+  //Check a field:
   Glom::sharedptr<const Glom::Field> field = document.get_field("contacts", "contact_id");
   g_assert(field);
   check_title(field, "Contact ID", "Kontakt ID");
 
+  //Check a field and its custom choices:
+  field = document.get_field("scenes", "day_or_night");
+  g_assert(field);
+  check_title(field, "Day/Night", "Tag/Nacht");
+
+  Glom::FieldFormatting formatting = field->m_default_formatting;
+  g_assert(formatting.get_has_custom_choices());
+  Glom::FieldFormatting::type_list_values values = formatting.get_choices_custom();
+  //g_assert(contains(values, "Day"));
+  Glom::sharedptr<Glom::ChoiceValue> value = get_titled(values, "Day");
+  g_assert(value);
+  check_title(value, "Day", "Tag");
+  g_assert(value->get_value() == Gnome::Gda::Value("Day"));
+
+  Glom::TranslatableItem::set_current_locale(locale_de);
+  g_assert( value->get_title_original() == "Day" );
+  Glom::TranslatableItem::set_current_locale(locale_original);
+  g_assert( value->get_title_original() == "Day" );
+
   //Check a relationship:
   const Glom::sharedptr<const Glom::Relationship> relationship = document.get_relationship("characters", "contacts_actor");
   g_assert(relationship);



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