[glom/choices_celllayout] Choices combos: Reuse the list view implementation. Only works for Combo now.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom/choices_celllayout] Choices combos: Reuse the list view implementation. Only works for Combo now.
- Date: Sat, 2 Oct 2010 15:32:16 +0000 (UTC)
commit 5b00e24eda2d69acb2afc924bca9a994ac71933b
Author: Murray Cumming <murrayc murrayc com>
Date: Thu Sep 30 12:55:36 2010 +0200
Choices combos: Reuse the list view implementation. Only works for Combo now.
* glom/mode_data/db_adddel/treemodel_db.[h|cc]: Moved to:
* glom/mode_data/datawidget/treemodel_db.[h|cc]: so we can use it for the
choices combo widgets too.
* glom/mode_data/datawidget/combochoices.[h|cc]:
set_choices_related(): Make this pure virtual.
Remove set_choices_with_second().
* glom/mode_data/datawidget/cellcreation.[h|cc]: create_cell():
Use set_choices_related() instead of getting all rows as a list and
using set_choices_with_second().
* glom/datawidget/combochoiceswithtreemodel.[h|cc]:
Override set_choices_related() and cell_connect_cell_data_func().
Remove the use_model() pure virtual method.
* glom/mode_data/datawidget/cellrenderer_dblist.[h|cc]:
* glom/mode_data/datawidget/combo.[h|cc]:
* glom/mode_data/datawidget/comboentry.[h|cc]:
* glom/mode_data/datawidget/combo_as_radio_buttons.[h|cc]: Adapt,
setting up the view in overrides of set_choices_fixed() and
set_choices_related() instead of use_model(), and being value-based
where possible instead of converting values to and from text.
* glom/mode_data/db_adddel/db_adddel.[h|cc]: Move create_model_db() to
DbTreeModel::create_from_items() so we can use it for the combo choice
widgets too.
refresh_cell_choices_data_from_database_with_foreign_key():
Use set_choices_related() instead of getting all rows as a list and
using set_choices_with_second().
ChangeLog | 31 +++
Makefile_glom.am | 4 +-
glom/mode_data/box_data.cc | 2 +-
glom/mode_data/box_data_list.cc | 1 -
glom/mode_data/datawidget/cellcreation.cc | 6 +-
glom/mode_data/datawidget/cellcreation.h | 2 +-
glom/mode_data/datawidget/cellrenderer_dblist.cc | 60 ++++--
glom/mode_data/datawidget/cellrenderer_dblist.h | 11 +-
glom/mode_data/datawidget/combo.cc | 189 ++++++++++---------
glom/mode_data/datawidget/combo.h | 14 +-
.../mode_data/datawidget/combo_as_radio_buttons.cc | 9 +-
glom/mode_data/datawidget/combo_as_radio_buttons.h | 14 +-
glom/mode_data/datawidget/combochoices.cc | 8 +-
glom/mode_data/datawidget/combochoices.h | 9 +-
.../datawidget/combochoiceswithtreemodel.cc | 202 +++++++++++++++++++-
.../datawidget/combochoiceswithtreemodel.h | 35 +++-
glom/mode_data/datawidget/comboentry.cc | 68 ++++++-
glom/mode_data/datawidget/comboentry.h | 8 +-
glom/mode_data/datawidget/datawidget.cc | 2 +-
.../{db_adddel => datawidget}/treemodel_db.cc | 103 ++++++++++-
.../{db_adddel => datawidget}/treemodel_db.h | 23 ++-
glom/mode_data/db_adddel/db_adddel.cc | 129 +------------
glom/mode_data/db_adddel/db_adddel.h | 2 +-
po/POTFILES.in | 1 +
24 files changed, 640 insertions(+), 293 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index fb63762..b8cff05 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2010-10-02 Murray Cumming <murrayc murrayc com>
+
+ Choices combos: Reuse the list view implementation. Only works for Combo now.
+
+ * glom/mode_data/db_adddel/treemodel_db.[h|cc]: Moved to:
+ * glom/mode_data/datawidget/treemodel_db.[h|cc]: so we can use it for the
+ choices combo widgets too.
+ * glom/mode_data/datawidget/combochoices.[h|cc]:
+ set_choices_related(): Make this pure virtual.
+ Remove set_choices_with_second().
+ * glom/mode_data/datawidget/cellcreation.[h|cc]: create_cell():
+ Use set_choices_related() instead of getting all rows as a list and
+ using set_choices_with_second().
+ * glom/datawidget/combochoiceswithtreemodel.[h|cc]:
+ Override set_choices_related() and cell_connect_cell_data_func().
+ Remove the use_model() pure virtual method.
+ * glom/mode_data/datawidget/cellrenderer_dblist.[h|cc]:
+ * glom/mode_data/datawidget/combo.[h|cc]:
+ * glom/mode_data/datawidget/comboentry.[h|cc]:
+ * glom/mode_data/datawidget/combo_as_radio_buttons.[h|cc]: Adapt,
+ setting up the view in overrides of set_choices_fixed() and
+ set_choices_related() instead of use_model(), and being value-based
+ where possible instead of converting values to and from text.
+
+ * glom/mode_data/db_adddel/db_adddel.[h|cc]: Move create_model_db() to
+ DbTreeModel::create_from_items() so we can use it for the combo choice
+ widgets too.
+ refresh_cell_choices_data_from_database_with_foreign_key():
+ Use set_choices_related() instead of getting all rows as a list and
+ using set_choices_with_second().
+
2010-10-01 Murray Cumming <murrayc murrayc com>
Fix (unlikely) possible null dereferences shown by cppcheck.
diff --git a/Makefile_glom.am b/Makefile_glom.am
index 197d3cd..cc019a9 100644
--- a/Makefile_glom.am
+++ b/Makefile_glom.am
@@ -101,8 +101,6 @@ glom_source_files = \
glom/mode_data/db_adddel/db_adddel_withbuttons.h \
glom/mode_data/db_adddel/db_treeviewcolumn_glom.cc \
glom/mode_data/db_adddel/db_treeviewcolumn_glom.h \
- glom/mode_data/db_adddel/treemodel_db.cc \
- glom/mode_data/db_adddel/treemodel_db.h \
glom/mode_data/flowtablewithfields.cc \
glom/mode_data/flowtablewithfields.h \
glom/mode_data/notebook_data.cc \
@@ -141,6 +139,8 @@ glom_source_files = \
glom/mode_data/datawidget/combochoiceswithtreemodel.h \
glom/mode_data/datawidget/combo_as_radio_buttons.cc \
glom/mode_data/datawidget/combo_as_radio_buttons.h \
+ glom/mode_data/datawidget/treemodel_db.cc \
+ glom/mode_data/datawidget/treemodel_db.h \
glom/mode_find/box_data_details_find.cc \
glom/mode_find/box_data_details_find.h \
glom/mode_find/box_data_list_find.cc \
diff --git a/glom/mode_data/box_data.cc b/glom/mode_data/box_data.cc
index e6f2cde..edcb3cd 100644
--- a/glom/mode_data/box_data.cc
+++ b/glom/mode_data/box_data.cc
@@ -269,7 +269,7 @@ Document::type_list_layout_groups Box_Data::get_data_layout_groups(const Glib::u
{
//Get the layout information from the document:
layout_groups = document->get_data_layout_groups_plus_new_fields(layout_name, m_table_name, layout_platform);
-
+ document->fill_layout_field_details(m_table_name, layout_groups); //TODO: Do this automatically in Document?
const Privileges table_privs = Privs::get_current_privs(m_table_name);
//Fill in the field information for the fields mentioned in the layout:
diff --git a/glom/mode_data/box_data_list.cc b/glom/mode_data/box_data_list.cc
index 4b66b7b..d6a5e56 100644
--- a/glom/mode_data/box_data_list.cc
+++ b/glom/mode_data/box_data_list.cc
@@ -26,7 +26,6 @@
#include <libglom/privs.h>
#include <libglom/db_utils.h>
#include <libglom/utils.h> //For bold_message()).
-//#include <../utility_widgets/db_adddel/treemodel_db.h> //For DbTreeModel.
#include <sstream> //For stringstream
#include <glibmm/i18n.h>
diff --git a/glom/mode_data/datawidget/cellcreation.cc b/glom/mode_data/datawidget/cellcreation.cc
index d1f0bd4..510c96d 100644
--- a/glom/mode_data/datawidget/cellcreation.cc
+++ b/glom/mode_data/datawidget/cellcreation.cc
@@ -63,7 +63,7 @@ static void apply_formatting(Gtk::CellRenderer* renderer, const sharedptr<const
text_renderer->property_background() = bg;
}
-Gtk::CellRenderer* create_cell(const sharedptr<const LayoutItem>& layout_item, const Glib::ustring& table_name, Document* document, guint fixed_cell_height)
+Gtk::CellRenderer* create_cell(const sharedptr<const LayoutItem>& layout_item, const Glib::ustring& table_name, const Document* document, guint fixed_cell_height)
{
Gtk::CellRenderer* cell = 0;
@@ -213,9 +213,7 @@ Gtk::CellRenderer* create_cell(const sharedptr<const LayoutItem>& layout_item, c
//TODO: Update this when the relationship's field value changes:
if(choice_show_all) //Otherwise it must change whenever the relationships's ID value changes.
{
- const Utils::type_list_values_with_second list_values =
- Utils::get_choice_values_all(document, item_field);
- pCellRendererDbList->set_choices_with_second(list_values);
+ pCellRendererDbList->set_choices_related(document, item_field, Gnome::Gda::Value() /* TODO: Makes no sense */);
}
}
}
diff --git a/glom/mode_data/datawidget/cellcreation.h b/glom/mode_data/datawidget/cellcreation.h
index 0ef1a47..05b38af 100644
--- a/glom/mode_data/datawidget/cellcreation.h
+++ b/glom/mode_data/datawidget/cellcreation.h
@@ -30,7 +30,7 @@ namespace Glom
/** Create a Gtk::CellRenderer that's appropriate to display a layout item,
* for internal use by a DbAddDel or ComboChoices widget.
*/
-Gtk::CellRenderer* create_cell(const sharedptr<const LayoutItem>& layout_item, const Glib::ustring& table_name, Document* document, guint fixed_cell_height);
+Gtk::CellRenderer* create_cell(const sharedptr<const LayoutItem>& layout_item, const Glib::ustring& table_name, const Document* document, guint fixed_cell_height);
} //namespace Glom
diff --git a/glom/mode_data/datawidget/cellrenderer_dblist.cc b/glom/mode_data/datawidget/cellrenderer_dblist.cc
index 7e6a64a..fa64d5a 100644
--- a/glom/mode_data/datawidget/cellrenderer_dblist.cc
+++ b/glom/mode_data/datawidget/cellrenderer_dblist.cc
@@ -19,6 +19,7 @@
*/
#include "cellrenderer_dblist.h"
+#include <glom/mode_data/datawidget/cellcreation.h>
#include <gtkmm.h>
#include <libglom/data_structure/glomconversions.h>
@@ -27,7 +28,8 @@ namespace Glom
{
CellRendererDbList::CellRendererDbList()
-: m_repacked_first_cell(false)
+: m_repacked_first_cell(false),
+ m_document(0)
{
}
@@ -36,8 +38,10 @@ CellRendererDbList::~CellRendererDbList()
}
-void CellRendererDbList::use_model()
+void CellRendererDbList::set_choices_fixed(const FieldFormatting::type_list_values& list_values)
{
+ ComboChoicesWithTreeModel::set_choices_fixed(list_values);
+
Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
//Show model in the view:
@@ -48,6 +52,23 @@ void CellRendererDbList::use_model()
//The other cells are added in on_editing_started().
}
+void CellRendererDbList::set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value)
+{
+ ComboChoicesWithTreeModel::set_choices_related(document, layout_field, foreign_key_value);
+
+ Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
+
+ //Show model in the view:
+ property_model() = model;
+ property_text_column() = 0; //TODO: This must be a text column, in m_refModel.
+ property_editable() = true; //It would be useless if we couldn't edit it.
+
+ //The other cells are added in on_editing_started(),
+ //which uses the document.
+ m_document = document;
+}
+
+
void CellRendererDbList::set_restrict_values_to_list(bool val)
{
property_has_entry() = !val;
@@ -65,36 +86,46 @@ void CellRendererDbList::on_editing_started(Gtk::CellEditable* cell_editable, co
{
//Get the default column, created by set_text_column():
Gtk::CellRendererText* cell = dynamic_cast<Gtk::CellRendererText*>(combobox->get_first_cell());
-
+
//Unpack and repack it with expand=false instead of expand=true:
//We don't expand the first column, so we can align the other columns.
cell->reference();
combobox->clear();
combobox->pack_start(*cell, false);
cell->unreference();
-
+
//Make the renderer render the column:
combobox->add_attribute(*cell, "text", 0);
-
- cell->property_xalign() = 0.0f;
-
+
+ cell->property_xalign() = 0.0f;
+
m_repacked_first_cell = true; //Avoid doing this again.
}
-
- //Add extra cells:
+
+ //Add extra cells:
Glib::ListHandle<Gtk::CellRenderer*> cells = combobox->get_cells();
if(cells.size() < m_vec_model_columns.size())
{
for(guint col = cells.size(); col != m_vec_model_columns.size(); ++col)
{
- Gtk::CellRendererText* cell = Gtk::manage(new Gtk::CellRendererText);
+ Gtk::CellRenderer* cell = 0;
+ if(m_db_layout_items.empty())
+ cell = Gtk::manage(new Gtk::CellRendererText);
+ else if(col < m_db_layout_items.size())
+ {
+ sharedptr<const LayoutItem_Field> layout_item = m_db_layout_items[col];
+ cell = create_cell(layout_item, m_table_name, m_document, 0 /* fixed_cell_height */);
+ }
+
+ if(!cell)
+ continue;
//Use the renderer:
combobox->pack_start(*cell, true);
-
+
//Make the renderer render the column:
combobox->add_attribute(*cell, "text", col);
-
+
cell->property_xalign() = 0.0f;
}
}
@@ -154,11 +185,6 @@ Glib::ustring CellRendererDbList::get_text() const
return property_text();
}
-void CellRendererDbList::set_choices_with_second(const type_list_values_with_second& list_values)
-{
- DataWidgetChildren::ComboChoicesWithTreeModel::set_choices_with_second(list_values);
-}
-
} //namespace Glom
diff --git a/glom/mode_data/datawidget/cellrenderer_dblist.h b/glom/mode_data/datawidget/cellrenderer_dblist.h
index f48c0cb..71e60a2 100644
--- a/glom/mode_data/datawidget/cellrenderer_dblist.h
+++ b/glom/mode_data/datawidget/cellrenderer_dblist.h
@@ -41,13 +41,16 @@ public:
CellRendererDbList();
virtual ~CellRendererDbList();
- void set_choices_with_second(const type_list_values_with_second& list_values);
+ //This creates a simple ListStore, with a text cell renderer.
+ virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values);
+
+ //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);
void set_restrict_values_to_list(bool val = true);
private:
- virtual void use_model();
virtual void on_editing_started(Gtk::CellEditable* cell_editable, const Glib::ustring& path);
virtual void set_value(const Gnome::Gda::Value& value);
@@ -55,8 +58,10 @@ private:
void set_text(const Glib::ustring& text);
Glib::ustring get_text() const;
-
+
bool m_repacked_first_cell;
+
+ const Document* m_document;
};
} //namespace Glom
diff --git a/glom/mode_data/datawidget/combo.cc b/glom/mode_data/datawidget/combo.cc
index c19f110..1960d91 100644
--- a/glom/mode_data/datawidget/combo.cc
+++ b/glom/mode_data/datawidget/combo.cc
@@ -21,9 +21,12 @@
#include "combo.h"
#include <libglom/data_structure/glomconversions.h>
#include <gtkmm/messagedialog.h>
+#include <glom/mode_data/datawidget/cellcreation.h>
#include <glom/dialog_invalid_data.h>
#include <libglom/data_structure/glomconversions.h>
+#include <libglom/db_utils.h>
#include <glom/application.h>
+#include <glom/utils_ui.h>
#include <glibmm/i18n.h>
//#include <sstream> //For stringstream
@@ -69,13 +72,20 @@ ComboGlom::~ComboGlom()
{
}
-void ComboGlom::use_model()
+void ComboGlom::set_choices_fixed(const FieldFormatting::type_list_values& list_values)
{
+ ComboChoicesWithTreeModel::set_choices_fixed(list_values);
+
Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
+ if(!model)
+ {
+ std::cerr << G_STRFUNC << ": model is null." << std::endl;
+ return;
+ }
//Show the model in the view:
set_model(model);
-
+
clear();
const guint columns_count = model->get_n_columns();
@@ -98,35 +108,49 @@ void ComboGlom::use_model()
}
}
-void ComboGlom::check_for_change()
+void ComboGlom::set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value)
{
- Glib::ustring new_text = get_text();
- if(new_text != m_old_text)
+ ComboChoicesWithTreeModel::set_choices_related(document, layout_field, foreign_key_value);
+
+ Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
+ if(!model)
{
- //Validate the input:
- bool success = false;
+ std::cerr << G_STRFUNC << ": model is null." << std::endl;
+ return;
+ }
- sharedptr<const LayoutItem_Field> layout_item = sharedptr<const LayoutItem_Field>::cast_dynamic(get_layout_item());
- const Gnome::Gda::Value value = Conversions::parse_value(layout_item->get_glom_type(), new_text, layout_item->get_formatting_used().m_numeric_format, success);
+ //Show the model in the view:
+ set_model(model);
- if(success)
- {
- //Actually show the canonical text:
- set_value(value);
- m_signal_edited.emit(); //The text was edited, so tell the client code.
- }
- else
+ clear();
+
+ guint model_column_index = 0;
+ for(type_vec_const_layout_items::const_iterator iter = m_db_layout_items.begin(); iter != m_db_layout_items.end(); ++iter)
+ {
+ const sharedptr<const LayoutItem> layout_item = *iter;
+ if(!layout_item) //column_info.m_visible)
+ continue;
+
+ //Add the ViewColumn
+ Gtk::CellRenderer* cell = create_cell(layout_item, m_table_name, document, get_fixed_cell_height(*this));
+ if(cell)
{
- //Tell the user and offer to revert or try again:
- bool revert = glom_show_dialog_invalid_data(layout_item->get_glom_type());
- if(revert)
- {
- set_text(m_old_text);
- }
- else
- grab_focus(); //Force the user back into the same field, so that the field can be checked again and eventually corrected or reverted.
+ //Use the renderer:
+ //We don't expand the first column, so we can align the other columns.
+ //Otherwise the other columns appear center-aligned.
+ //This bug is relevant: https://bugzilla.gnome.org/show_bug.cgi?id=629133
+ pack_start(*cell, false);
+
+ cell_connect_cell_data_func(this, cell, model_column_index);
+
+ ++model_column_index;
}
- }
+ } //for
+}
+
+void ComboGlom::check_for_change()
+{
+ m_signal_edited.emit();
}
void ComboGlom::set_value(const Gnome::Gda::Value& value)
@@ -134,8 +158,44 @@ void ComboGlom::set_value(const Gnome::Gda::Value& value)
sharedptr<const LayoutItem_Field> layout_item = sharedptr<const LayoutItem_Field>::cast_dynamic(get_layout_item());
if(!layout_item)
return;
+
+ m_old_value = value;
+
+ Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
+ if(!model)
+ {
+ std::cerr << G_STRFUNC << ": model is null." << std::endl;
+ return;
+ }
+
+ bool found = false;
+ for(Gtk::TreeModel::iterator iter = model->children().begin(); iter != model->children().end(); ++iter)
+ {
+ const Gtk::TreeModel::Row row = *iter;
+ Gnome::Gda::Value this_value;
+ row.get_value(0, this_value);
+
+ if(this_value == value)
+ {
+ found = true;
+ #ifndef GLOM_ENABLE_MAEMO
+ set_active(iter);
+ #else
+ set_selected(iter);
+ #endif //GLOM_ENABLE_MAEMO
+ break;
+ }
+ }
- set_text(Conversions::get_text_for_gda_value(layout_item->get_glom_type(), value, layout_item->get_formatting_used().m_numeric_format));
+ if(!found)
+ {
+ //Not found, so mark it as blank:
+ #ifndef GLOM_ENABLE_MAEMO
+ unset_active();
+ #else
+ unselect();
+ #endif
+ }
//Show a different color if the value is numeric, if that's specified:
if(layout_item->get_glom_type() == Field::TYPE_NUMERIC)
@@ -160,70 +220,25 @@ void ComboGlom::set_value(const Gnome::Gda::Value& value)
}
}
-void ComboGlom::set_text(const Glib::ustring& text)
-{
- m_old_text = text;
-
- Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
- for(Gtk::TreeModel::iterator iter = model->children().begin(); iter != model->children().end(); ++iter)
- {
- const Gtk::TreeModel::Row row = *iter;
- Glib::ustring this_text;
- row.get_value(0, this_text);
-
- if(this_text == text)
- {
- #ifndef GLOM_ENABLE_MAEMO
- set_active(iter);
- #else
- set_selected(iter);
- #endif //GLOM_ENABLE_MAEMO
- return; //success
- }
- }
-
- //It's OK to pass "" to this method to unset any items:
- if(!text.empty())
- {
- g_warning("ComboGlom::set_text(): no item found for: %s", text.c_str());
- }
-
- //Not found, so mark it as blank:
- #ifndef GLOM_ENABLE_MAEMO
- unset_active();
- #else
- unselect();
- #endif
-}
-
Gnome::Gda::Value ComboGlom::get_value() const
{
- sharedptr<const LayoutItem_Field> layout_item = sharedptr<const LayoutItem_Field>::cast_dynamic(get_layout_item());
- bool success = false;
-
- const Glib::ustring text = get_text();
- return Conversions::parse_value(layout_item->get_glom_type(), text, layout_item->get_formatting_used().m_numeric_format, success);
-}
-
-Glib::ustring ComboGlom::get_text() const
-{
- //Get the active row:
- #ifndef GLOM_ENABLE_MAEMO
- Gtk::TreeModel::iterator iter = get_active();
- #else
- ComboGlom* unconst = const_cast<ComboGlom*>(this);
- Gtk::TreeModel::iterator iter = unconst->get_selected();
- #endif //GLOM_ENABLE_MAEMO
-
- if(iter)
- {
- const Gtk::TreeModel::Row row = *iter;
- Glib::ustring text;
- row.get_value(0, text);
- return text;
+ //Get the active row:
+ #ifndef GLOM_ENABLE_MAEMO
+ Gtk::TreeModel::iterator iter = get_active();
+ #else
+ ComboGlom* unconst = const_cast<ComboGlom*>(this);
+ Gtk::TreeModel::iterator iter = unconst->get_selected();
+ #endif //GLOM_ENABLE_MAEMO
+
+ if(iter)
+ {
+ const Gtk::TreeModel::Row row = *iter;
+ Gnome::Gda::Value value;
+ row.get_value(0, value);
+ return value;
}
-
- return Glib::ustring();
+
+ return Gnome::Gda::Value();
}
#ifndef GLOM_ENABLE_CLIENT_ONLY
diff --git a/glom/mode_data/datawidget/combo.h b/glom/mode_data/datawidget/combo.h
index 0ce94bf..81db53a 100644
--- a/glom/mode_data/datawidget/combo.h
+++ b/glom/mode_data/datawidget/combo.h
@@ -57,14 +57,13 @@ public:
virtual ~ComboGlom();
- virtual void set_read_only(bool read_only = true);
-
+ //This creates a simple ListStore, with a text cell renderer.
+ virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values);
- //Override this so we can store the text to compare later.
- //This is not virtual, so you must not use it via Gtk::Entry.
- void set_text(const Glib::ustring& text); //override
+ //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);
- Glib::ustring get_text() const;
+ virtual void set_read_only(bool read_only = true);
/** Set the text from a Gnome::Gda::Value.
*/
@@ -74,7 +73,6 @@ public:
private:
void init();
- virtual void use_model();
#ifndef GLOM_ENABLE_MAEMO
// Note that this is a normal signal handler when glibmm was complied
@@ -93,7 +91,7 @@ private:
virtual Application* get_application();
- Glib::ustring m_old_text;
+ Gnome::Gda::Value m_old_value; //TODO: Only useful for navigation, which currently has no implementation.
//Gnome::Gda::Value m_value; //The last-stored value. We have this because the displayed value might be unparseable.
#ifdef GLOM_ENABLE_MAEMO
diff --git a/glom/mode_data/datawidget/combo_as_radio_buttons.cc b/glom/mode_data/datawidget/combo_as_radio_buttons.cc
index de781dd..84be03c 100644
--- a/glom/mode_data/datawidget/combo_as_radio_buttons.cc
+++ b/glom/mode_data/datawidget/combo_as_radio_buttons.cc
@@ -100,7 +100,7 @@ void ComboAsRadioButtons::set_choices_with_second(const type_list_values_with_se
title += " - " + value_second; //TODO: Find a better way to join them?
}
-
+
++iterValues;
}
}
@@ -149,7 +149,12 @@ void ComboAsRadioButtons::set_choices_fixed(const FieldFormatting::type_list_val
}
}
-
+void ComboAsRadioButtons::set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value)
+{
+ const Utils::type_list_values_with_second list_values =
+ Utils::get_choice_values(document, layout_field, foreign_key_value);
+ set_choices_with_second(list_values);
+}
ComboAsRadioButtons::~ComboAsRadioButtons()
{
diff --git a/glom/mode_data/datawidget/combo_as_radio_buttons.h b/glom/mode_data/datawidget/combo_as_radio_buttons.h
index fd26438..23e8e17 100644
--- a/glom/mode_data/datawidget/combo_as_radio_buttons.h
+++ b/glom/mode_data/datawidget/combo_as_radio_buttons.h
@@ -37,7 +37,7 @@ namespace DataWidgetChildren
* Use this only when the user should only be allowed to enter values that are in the choices.
*/
class ComboAsRadioButtons
-:
+:
public Gtk::VBox,
public ComboChoices
{
@@ -47,11 +47,12 @@ public:
ComboAsRadioButtons();
virtual ~ComboAsRadioButtons();
-
+
virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values);
- virtual void set_read_only(bool read_only = true);
+ virtual void set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value);
+ virtual void set_read_only(bool read_only = true);
//Override this so we can store the text to compare later.
//This is not virtual, so you must not use it via Gtk::Entry.
@@ -68,7 +69,11 @@ public:
private:
void init();
- virtual void set_choices_with_second(const type_list_values_with_second& list_values);
+ 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;
+
+ //A utility function that's needed because we don't use a real db model:
+ void set_choices_with_second(const type_list_values_with_second& list_values);
void on_radiobutton_toggled();
@@ -94,4 +99,3 @@ private:
} //namespace Glom
#endif //GLOM_UTILITY_WIDGETS_COMBOENTRY_GLOM_H
-
diff --git a/glom/mode_data/datawidget/combochoices.cc b/glom/mode_data/datawidget/combochoices.cc
index b77420e..c4b8b1f 100644
--- a/glom/mode_data/datawidget/combochoices.cc
+++ b/glom/mode_data/datawidget/combochoices.cc
@@ -50,8 +50,9 @@ ComboChoices::~ComboChoices()
{
}
-bool ComboChoices::refresh_data_from_database_with_foreign_key(const Document* document, const Gnome::Gda::Value& foreign_key_value)
+bool ComboChoices::refresh_data_from_database_with_foreign_key(const Document* /* document */, const Gnome::Gda::Value& /* foreign_key_value */)
{
+ /** TODO:
sharedptr<LayoutItem_Field> layout_item =
sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
@@ -68,11 +69,13 @@ bool ComboChoices::refresh_data_from_database_with_foreign_key(const Document* d
set_choices_with_second(list_values);
set_value(old_value); //Try to preserve the value, even in iter-based ComboBoxes.
+ */
return true;
}
-void ComboChoices::set_choices_related(const Document* document)
+void ComboChoices::set_choices_related(const Document* /* document */, const sharedptr<const LayoutItem_Field>& /* layout_field */, const Gnome::Gda::Value& /* foreign_key_value */)
{
+ /* TODO:
type_list_values_with_second list_values;
sharedptr<LayoutItem_Field> layout_item =
@@ -94,6 +97,7 @@ void ComboChoices::set_choices_related(const Document* document)
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.
+ */
}
} //namespace DataWidgetChildren
diff --git a/glom/mode_data/datawidget/combochoices.h b/glom/mode_data/datawidget/combochoices.h
index 8fc68f9..948283b 100644
--- a/glom/mode_data/datawidget/combochoices.h
+++ b/glom/mode_data/datawidget/combochoices.h
@@ -51,14 +51,15 @@ public:
*/
virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values) = 0;
- //This is not pure virtual, so some widgets can (temporarily) use a default inefficient implementation.
/** 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,
* so the widget knows what choices to show, and how to format them.
*
+ * The LayoutItem_Fields should already have their full field details
+ *
* See also refresh_data_from_database_with_foreign_key().
*/
- virtual void set_choices_related(const Document* document);
+ virtual void set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value) = 0;
/** Update a choices widget's list of related choices if a relevant value in its parent table has changed.
*
@@ -69,10 +70,6 @@ public:
protected:
void init();
- 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 6007132..cc4dff9 100644
--- a/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
+++ b/glom/mode_data/datawidget/combochoiceswithtreemodel.cc
@@ -19,7 +19,9 @@
*/
#include "combochoiceswithtreemodel.h"
+#include <glom/mode_data/datawidget/treemodel_db.h>
#include <libglom/data_structure/glomconversions.h>
+#include <glom/utils_ui.h>
#include <glibmm/i18n.h>
//#include <sstream> //For stringstream
@@ -35,6 +37,7 @@ namespace DataWidgetChildren
{
ComboChoicesWithTreeModel::ComboChoicesWithTreeModel()
+: m_fixed_cell_height(0)
{
init();
}
@@ -49,7 +52,7 @@ void ComboChoicesWithTreeModel::init()
ComboChoices::init();
}
-void ComboChoicesWithTreeModel::create_model(guint columns_count)
+void ComboChoicesWithTreeModel::create_model_non_db(guint columns_count)
{
delete_model();
@@ -69,9 +72,6 @@ void ComboChoicesWithTreeModel::create_model(guint columns_count)
//Create the model:
m_refModel = Gtk::ListStore::create(record);
-
- //Call the derived class's (virtual) implementation of this:
- use_model();
}
void ComboChoicesWithTreeModel::delete_model()
@@ -88,6 +88,7 @@ void ComboChoicesWithTreeModel::delete_model()
m_refModel.reset();
}
+/*
void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_with_second& list_values)
{
//Recreate the entire model:
@@ -124,7 +125,7 @@ void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_w
std::cerr << G_STRFUNC << ": list_store is null." << std::endl;
return;
}
-
+
for(type_list_values_with_second::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
{
Gtk::TreeModel::iterator iterTree = list_store->append();
@@ -167,11 +168,12 @@ void ComboChoicesWithTreeModel::set_choices_with_second(const type_list_values_w
}
}
}
+*/
void ComboChoicesWithTreeModel::set_choices_fixed(const FieldFormatting::type_list_values& list_values)
{
- create_model(1);
+ create_model_non_db(1); //Use a regular ListStore without a dynamic column?
Glib::RefPtr<Gtk::ListStore> list_store = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(m_refModel);
if(!list_store)
@@ -179,7 +181,7 @@ void ComboChoicesWithTreeModel::set_choices_fixed(const FieldFormatting::type_li
std::cerr << G_STRFUNC << ": list_store is null." << std::endl;
return;
}
-
+
for(FieldFormatting::type_list_values::const_iterator iter = list_values.begin(); iter != list_values.end(); ++iter)
{
Gtk::TreeModel::iterator iterTree = list_store->append();
@@ -193,6 +195,52 @@ void ComboChoicesWithTreeModel::set_choices_fixed(const FieldFormatting::type_li
row.set_value(0, text);
}
}
+
+ //The derived class's (virtual) implementation calls this base method and
+ //then sets up the view, using the model.
+}
+
+void ComboChoicesWithTreeModel::set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value)
+{
+ const FieldFormatting& format = layout_field->get_formatting_used();
+ sharedptr<const Relationship> choice_relationship;
+ 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_extra, choice_show_all);
+
+ //Get the list of fields to show:
+ LayoutGroup::type_list_const_items extra_fields;
+ if(layout_choice_extra)
+ extra_fields = layout_choice_extra->get_items_recursive();
+
+ LayoutGroup::type_list_const_items layout_items;
+ layout_items.push_back(layout_choice_first);
+ layout_items.insert(layout_items.end(), extra_fields.begin(), extra_fields.end());
+
+ //Build the FoundSet:
+ const Glib::ustring to_table = choice_relationship->get_to_table();
+ FoundSet found_set;
+ found_set.m_table_name = to_table;
+
+ if(!foreign_key_value.is_null())
+ {
+ const sharedptr<const Field> to_field = document->get_field(to_table, choice_relationship->get_to_field());
+
+ found_set.m_where_clause = Utils::build_simple_where_expression(
+ to_table, to_field, foreign_key_value);
+ }
+
+
+ m_db_layout_items.clear();
+ m_refModel = DbTreeModel::create_from_items(found_set, layout_items, true /* allow_view */, false /* find mode */, m_db_layout_items);
+ if(!m_refModel)
+ {
+ std::cerr << G_STRFUNC << ": DbTreeModel::create_from_items() returned a null model." << std::endl;
+ }
+
+ //The derived class's (virtual) implementation calls this base method and
+ //then sets up the view, using the model.
}
Glib::RefPtr<Gtk::TreeModel> ComboChoicesWithTreeModel::get_choices_model()
@@ -200,5 +248,145 @@ Glib::RefPtr<Gtk::TreeModel> ComboChoicesWithTreeModel::get_choices_model()
return m_refModel;
}
+void ComboChoicesWithTreeModel::on_cell_data(const Gtk::TreeModel::iterator& iter, Gtk::CellRenderer* cell, guint model_column_index)
+{
+ //std::cout << G_STRFUNC << ": DEBUG: model_column_index=" << model_column_index << std::endl;
+ if(model_column_index >= m_db_layout_items.size())
+ {
+ std::cerr << G_STRFUNC << ": model_column_index is out of range." << std::endl;
+ return;
+ }
+
+ if(!cell)
+ {
+ std::cerr << G_STRFUNC << ": cell is null." << std::endl;
+ return;
+ }
+
+ if(iter)
+ {
+ const sharedptr<const LayoutItem>& layout_item = m_db_layout_items[model_column_index];
+
+ sharedptr<const LayoutItem_Field> field = sharedptr<const LayoutItem_Field>::cast_dynamic(layout_item);
+ if(field)
+ {
+ Gtk::TreeModel::Row treerow = *iter;
+ Gnome::Gda::Value value;
+ treerow->get_value(model_column_index, value);
+
+ const Field::glom_field_type type = field->get_glom_type();
+ switch(type)
+ {
+ case(Field::TYPE_BOOLEAN):
+ {
+ Gtk::CellRendererToggle* pDerived = dynamic_cast<Gtk::CellRendererToggle*>(cell);
+ if(pDerived)
+ pDerived->set_active( (value.get_value_type() == G_TYPE_BOOLEAN) && value.get_boolean() );
+
+ break;
+ }
+ case(Field::TYPE_IMAGE):
+ {
+ Gtk::CellRendererPixbuf* pDerived = dynamic_cast<Gtk::CellRendererPixbuf*>(cell);
+ if(pDerived)
+ {
+ const Glib::RefPtr<Gdk::Pixbuf> pixbuf = Utils::get_pixbuf_for_gda_value(value);
+
+ //Scale it down to a sensible size.
+ //TODO: if(pixbuf)
+ // pixbuf = Utils::image_scale_keeping_ratio(pixbuf, get_fixed_cell_height(), pixbuf->get_width());
+ g_object_set(pDerived->gobj(), "pixbuf", pixbuf ? pixbuf->gobj() : 0, (gpointer)0);
+ }
+ else
+ std::cerr << "Field::sql(): glom_type is TYPE_IMAGE but gda type is not VALUE_TYPE_BINARY" << std::endl;
+
+ break;
+ }
+ default:
+ {
+ //TODO: Maybe we should have custom cellcells for time, date, and numbers.
+ Gtk::CellRendererText* pDerived = dynamic_cast<Gtk::CellRendererText*>(cell);
+ if(pDerived)
+ {
+ //std::cout << "debug: " << G_STRFUNC << ": field name=" << field->get_name() << ", glom type=" << field->get_glom_type() << std::endl;
+ const Glib::ustring text = Conversions::get_text_for_gda_value(field->get_glom_type(), value, field->get_formatting_used().m_numeric_format);
+ pDerived->property_text() = text;
+ }
+ else
+ {
+ std::cerr << G_STRFUNC << ": cell has an unexpected type: " << typeid(cell).name() << std::endl;
+ }
+
+ //Show a different color if the value is numeric, if that's specified:
+ if(type == Field::TYPE_NUMERIC)
+ {
+ const Glib::ustring fg_color =
+ field->get_formatting_used().get_text_format_color_foreground_to_use(value);
+ if(!fg_color.empty())
+ g_object_set(pDerived->gobj(), "foreground", fg_color.c_str(), (gpointer)0);
+ else
+ g_object_set(pDerived->gobj(), "foreground", (const char*)0, (gpointer)0);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+void ComboChoicesWithTreeModel::cell_connect_cell_data_func(Gtk::CellLayout* celllayout, Gtk::CellRenderer* cell, guint model_column_index)
+{
+ celllayout->set_cell_data_func(*cell,
+ sigc::bind( sigc::mem_fun(*this, &ComboChoicesWithTreeModel::on_cell_data), cell, model_column_index));
+}
+
+int ComboChoicesWithTreeModel::get_fixed_cell_height(Gtk::Widget& widget)
+{
+ if(m_fixed_cell_height <= 0)
+ {
+ // Discover a suitable height, and cache it,
+ // by looking at the heights of all columns:
+ // Note that this is usually calculated during construct_specified_columns(),
+ // when all columns are known.
+
+ //Get a default:
+ const Glib::RefPtr<const Pango::Layout> refLayout = widget.create_pango_layout("example");
+ int width = 0;
+ int height = 0;
+ refLayout->get_pixel_size(width, height);
+ m_fixed_cell_height = height;
+
+ //Look at each column:
+ for(type_vec_const_layout_items::iterator iter = m_db_layout_items.begin(); iter != m_db_layout_items.end(); ++iter)
+ {
+ Glib::ustring font_name;
+
+ const sharedptr<const LayoutItem_WithFormatting> item_withformatting = sharedptr<const LayoutItem_WithFormatting>::cast_dynamic(*iter);
+ if(item_withformatting)
+ {
+ const FieldFormatting& formatting = item_withformatting->get_formatting_used();
+ font_name = formatting.get_text_format_font();
+ }
+
+ if(font_name.empty())
+ continue;
+
+ // Translators: This is just some example text used to discover an appropriate height for user-entered text in the UI. This text itself is never shown to the user.
+ Glib::RefPtr<Pango::Layout> refLayout = widget.create_pango_layout(_("Example"));
+ const Pango::FontDescription font(font_name);
+ refLayout->set_font_description(font);
+ int width = 0;
+ int height = 0;
+ refLayout->get_pixel_size(width, height);
+
+ if(height > m_fixed_cell_height)
+ m_fixed_cell_height = height;
+ }
+ }
+
+ return m_fixed_cell_height;
+}
+
} //namespace DataWidetChildren
} //namespace Glom
diff --git a/glom/mode_data/datawidget/combochoiceswithtreemodel.h b/glom/mode_data/datawidget/combochoiceswithtreemodel.h
index 750389a..bbfdcd4 100644
--- a/glom/mode_data/datawidget/combochoiceswithtreemodel.h
+++ b/glom/mode_data/datawidget/combochoiceswithtreemodel.h
@@ -37,30 +37,45 @@ 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);
+ //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);
+
+
//Not named get_model(), to avoid clashing with ComboBox::get_model().
Glib::RefPtr<Gtk::TreeModel> get_choices_model();
-
+
protected:
void init();
- void create_model(guint columns_count);
-
- /** Derived classes should implement this to present the model in their view,
- * for instance by adding Gtk::CellRenderers.
- */
- virtual void use_model() = 0;
-
- virtual void set_choices_with_second(const type_list_values_with_second& list_values);
+ void create_model_non_db(guint columns_count);
+ /** Get a suitable fixed height for cells, so we can display them more efficiently.
+ * This caches the result to avoid repeated recalculation.
+ */
+ int get_fixed_cell_height(Gtk::Widget& widget);
+
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;
+ typedef std::vector< sharedptr<const LayoutItem_Field> > type_vec_const_layout_items;
+ type_vec_const_layout_items m_db_layout_items; //If set_choices_related() was used.
+
+ //This avoids us making on_cell_data() public just so that derived classes can use it,
+ //though that shouldn't be necessary anyway.
+ void cell_connect_cell_data_func(Gtk::CellLayout* celllayout, Gtk::CellRenderer* cell, guint model_column_index);
+
private:
+ /// Render the model data to the cells in the view.
+ void on_cell_data(const Gtk::TreeModel::iterator& iter, Gtk::CellRenderer* cell, guint model_column_index);
+
Glib::RefPtr<Gtk::TreeModel> m_refModel;
-
+
void delete_model();
+
+ int m_fixed_cell_height;
};
} //namespace DataWidetChildren
diff --git a/glom/mode_data/datawidget/comboentry.cc b/glom/mode_data/datawidget/comboentry.cc
index fc68d07..590415b 100644
--- a/glom/mode_data/datawidget/comboentry.cc
+++ b/glom/mode_data/datawidget/comboentry.cc
@@ -22,6 +22,7 @@
#include <libglom/data_structure/glomconversions.h>
#include <gtkmm/messagedialog.h>
#include <glom/dialog_invalid_data.h>
+#include <glom/mode_data/datawidget/cellcreation.h>
#include <libglom/data_structure/glomconversions.h>
#include <glom/application.h>
#include <glibmm/i18n.h>
@@ -108,10 +109,19 @@ ComboEntry::~ComboEntry()
{
}
-void ComboEntry::use_model()
+
+void ComboEntry::set_choices_fixed(const FieldFormatting::type_list_values& list_values)
{
+ ComboChoicesWithTreeModel::set_choices_fixed(list_values);
+
//Show model in the view:
Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
+ if(!model)
+ {
+ std::cerr << G_STRFUNC << ": model is null." << std::endl;
+ return;
+ }
+
set_model(model);
set_text_column(0);
@@ -123,7 +133,7 @@ void ComboEntry::use_model()
{
//Get the default column, created by set_text_column():
cell = dynamic_cast<Gtk::CellRendererText*>(get_first_cell());
-
+
//Unpack and repack it with expand=false instead of expand=true:
//We don't expand the first column, so we can align the other columns.
cell->reference();
@@ -140,11 +150,61 @@ void ComboEntry::use_model()
//Make the renderer render the column:
add_attribute(*cell, "text", i);
-
+
cell->property_xalign() = 0.0f;
}
}
+void ComboEntry::set_choices_related(const Document* document, const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& foreign_key_value)
+{
+ ComboChoicesWithTreeModel::set_choices_related(document, layout_field, foreign_key_value);
+
+ Glib::RefPtr<Gtk::TreeModel> model = get_choices_model();
+ if(!model)
+ {
+ std::cerr << G_STRFUNC << ": model is null." << std::endl;
+ return;
+ }
+
+ //Show the model in the view:
+ set_model(model);
+ //clear() breaks GtkComboBoxEntry. TODO: Fix the C code? clear();
+ set_text_column(0); //TODO: Add a virtual model to TreeModelDb so we always have a text model?
+
+ const guint columns_count = model->get_n_columns();
+ for(guint i = 0; i < columns_count; ++i)
+ for(type_vec_const_layout_items::const_iterator iter = m_db_layout_items.begin(); iter != m_db_layout_items.end(); ++iter)
+ {
+ const sharedptr<const LayoutItem> layout_item = *iter;
+ Gtk::CellRenderer* cell = 0;
+
+ if(i == 0)
+ {
+ //Get the default column, created by set_text_column():
+ cell = get_first_cell();
+ if(!cell)
+ std::cerr << G_STRFUNC << ": get_first_cell() returned null." << std::endl;
+ else
+ {
+ //Unpack and repack it with expand=false instead of expand=true:
+ //We don't expand the first column, so we can align the other columns.
+ cell->reference();
+ clear();
+ pack_start(*cell, false);
+ cell->unreference();
+ }
+ }
+ else
+ {
+ //Create the cell:
+ cell = create_cell(layout_item, m_table_name, document, get_fixed_cell_height(*this));
+ pack_start(*cell, true);
+
+ cell_connect_cell_data_func(this, cell, i);
+ }
+ }
+}
+
void ComboEntry::set_layout_item(const sharedptr<LayoutItem>& layout_item, const Glib::ustring& table_name)
{
//Call base class:
@@ -183,7 +243,7 @@ void ComboEntry::check_for_change()
get_entry()->set_text(m_old_text);
}
- Glib::ustring new_text = get_entry()->get_text();
+ const Glib::ustring new_text = get_entry()->get_text();
if(new_text != m_old_text)
{
//Validate the input:
diff --git a/glom/mode_data/datawidget/comboentry.h b/glom/mode_data/datawidget/comboentry.h
index b151c12..b758601 100644
--- a/glom/mode_data/datawidget/comboentry.h
+++ b/glom/mode_data/datawidget/comboentry.h
@@ -57,6 +57,12 @@ public:
virtual ~ComboEntry();
+ //This creates a simple ListStore, with a text cell renderer.
+ virtual void set_choices_fixed(const FieldFormatting::type_list_values& list_values);
+
+ //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);
+
//Override this so we can store the text to compare later.
//This is not virtual, so you must not use it via Gtk::Entry.
void set_text(const Glib::ustring& text); //override
@@ -73,8 +79,6 @@ public:
private:
void init();
- virtual void use_model();
-
//Overrides of default signal handlers:
//TODO: Are these really default signal handlers?
diff --git a/glom/mode_data/datawidget/datawidget.cc b/glom/mode_data/datawidget/datawidget.cc
index 82e17d6..404f37f 100644
--- a/glom/mode_data/datawidget/datawidget.cc
+++ b/glom/mode_data/datawidget/datawidget.cc
@@ -130,7 +130,7 @@ DataWidget::DataWidget(const sharedptr<LayoutItem_Field>& field, const Glib::ust
combo = create_combo_widget_for_field(field);
combo->set_layout_item( get_layout_item(), table_name);
- combo->set_choices_related(document);
+ combo->set_choices_related(document, field, Gnome::Gda::Value() /* TODO: Doesn't make sense */);
}
else
{
diff --git a/glom/mode_data/db_adddel/treemodel_db.cc b/glom/mode_data/datawidget/treemodel_db.cc
similarity index 89%
rename from glom/mode_data/db_adddel/treemodel_db.cc
rename to glom/mode_data/datawidget/treemodel_db.cc
index e834657..ba47239 100644
--- a/glom/mode_data/db_adddel/treemodel_db.cc
+++ b/glom/mode_data/datawidget/treemodel_db.cc
@@ -203,12 +203,113 @@ DbTreeModel::~DbTreeModel()
clear();
}
-//static:
+
Glib::RefPtr<DbTreeModel> DbTreeModel::create(const Gtk::TreeModelColumnRecord& columns, const FoundSet& found_set, const type_vec_const_fields& column_fields, int column_index_key, bool get_records, bool find_mode)
{
return Glib::RefPtr<DbTreeModel>( new DbTreeModel(columns, found_set, column_fields, column_index_key, get_records, find_mode) );
}
+Glib::RefPtr<DbTreeModel> DbTreeModel::create_from_items(const FoundSet& found_set, const type_vec_layout_items& layout_items, bool get_records, bool find_mode, Base_DB::type_vecConstLayoutFields& fields_shown)
+{
+ //Create a const version of the input, because C++ can't convert it automatically:
+ type_vec_const_layout_items const_items;
+ const_items.insert(const_items.end(), layout_items.begin(), layout_items.end());
+
+ return create_from_items(found_set, const_items, get_records, find_mode, fields_shown);
+}
+
+Glib::RefPtr<DbTreeModel> DbTreeModel::create_from_items(const FoundSet& found_set, const type_vec_const_layout_items& layout_items, bool get_records, bool find_mode, Base_DB::type_vecConstLayoutFields& fields_shown)
+{
+ Glib::RefPtr<DbTreeModel> result;
+
+ typedef Gtk::TreeModelColumn<Gnome::Gda::Value> type_modelcolumn_value;
+ typedef std::vector< type_modelcolumn_value* > type_vecModelColumns;
+ type_vecModelColumns vecModelColumns(layout_items.size(), 0);
+
+ //Create the Gtk ColumnRecord:
+
+ Gtk::TreeModel::ColumnRecord record;
+
+ //Database columns:
+ DbTreeModel::type_vec_const_fields fields;
+ {
+ type_vecModelColumns::size_type i = 0;
+ for(type_vec_const_layout_items::const_iterator iter = layout_items.begin(); iter != layout_items.end(); ++iter)
+ {
+ sharedptr<const LayoutItem_Field> item_field = sharedptr<const LayoutItem_Field>::cast_dynamic(*iter);
+ if(item_field)
+ {
+ type_modelcolumn_value* pModelColumn = new type_modelcolumn_value;
+
+ //Store it so we can use it and delete it later:
+ vecModelColumns[i] = pModelColumn;
+
+ record.add( *pModelColumn );
+
+ fields.push_back(item_field);
+
+ i++;
+ }
+ }
+ }
+
+ fields_shown = fields;
+
+ {
+ //Find the primary key:
+ int column_index_key = 0;
+ bool key_found = false;
+ for( DbTreeModel::type_vec_const_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
+ {
+ const sharedptr<const LayoutItem_Field> layout_item = *iter;
+ if(!layout_item)
+ continue;
+
+ if( !(layout_item->get_has_relationship_name()) )
+ {
+ sharedptr<const Field> field_full = layout_item->get_full_field_details();
+ if(!field_full)
+ std::cerr << G_STRFUNC << ": The layout item (" << layout_item->get_name() << ") has no field details." << std::endl;
+ else if(field_full->get_primary_key() )
+ {
+ key_found = true;
+ break;
+ }
+ }
+
+ ++column_index_key;
+ }
+
+ if(key_found)
+ {
+ //Create the model from the ColumnRecord:
+ //Note that the model will use a dummy Gda DataModel if m_find_mode is true.
+ //std::cout << "debug: Creating new DbTreeModel() for table=" << m_found_set.m_table_name << std::endl;
+ result = DbTreeModel::create(record, found_set, fields, column_index_key, get_records, find_mode);
+ }
+ else
+ {
+ std::cerr << G_STRFUNC << ": no primary key field found in the list of items:" << std::endl;
+ for(DbTreeModel::type_vec_const_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
+ {
+ const sharedptr<const LayoutItem_Field> layout_item = *iter;
+ if(layout_item)
+ std::cerr << " field: " << layout_item->get_name() << std::endl;
+ }
+ }
+ }
+
+ //Delete the vector's items:
+ for(type_vecModelColumns::iterator iter = vecModelColumns.begin(); iter != vecModelColumns.end(); ++iter)
+ {
+ type_modelcolumn_value* pModelColumn = *iter;
+ if(pModelColumn)
+ delete pModelColumn;
+ }
+
+ return result;
+}
+
bool DbTreeModel::refresh_from_database(const FoundSet& found_set)
{
//std::cout << "DbTreeModel::refresh_from_database()" << std::endl;
diff --git a/glom/mode_data/db_adddel/treemodel_db.h b/glom/mode_data/datawidget/treemodel_db.h
similarity index 87%
rename from glom/mode_data/db_adddel/treemodel_db.h
rename to glom/mode_data/datawidget/treemodel_db.h
index f048ce9..3fbfcba 100644
--- a/glom/mode_data/db_adddel/treemodel_db.h
+++ b/glom/mode_data/datawidget/treemodel_db.h
@@ -73,13 +73,32 @@ public:
friend class DbTreeModelRow;
private:
- //Create a TreeModel with @a columns_count number of columns, each of type Glib::ustring.
+
DbTreeModel(const Gtk::TreeModelColumnRecord& columns, const FoundSet& found_set, const type_vec_const_fields& column_fields, int column_index_key, bool get_records = true, bool find_mode = false);
virtual ~DbTreeModel();
-public:
+ /** Create a new model, using the specified fields.
+ * The LayoutItem_Fields should already have their full field details.
+ */
static Glib::RefPtr<DbTreeModel> create(const Gtk::TreeModelColumnRecord& columns, const FoundSet& found_set, const type_vec_const_fields& column_fields, int column_index_key, bool get_records = true, bool find_mode = false);
+public:
+
+ typedef std::vector< sharedptr<LayoutItem> > type_vec_layout_items;
+ typedef std::vector< sharedptr<const LayoutItem> > type_vec_const_layout_items;
+
+
+ /** A convenience method, creating the model from a list of LayoutItems,
+ * instead of a list of LayoutItem_Fields.
+ */
+ static Glib::RefPtr<DbTreeModel> create_from_items(const FoundSet& found_set, const type_vec_layout_items& layout_items, bool get_records, bool find_mode, Base_DB::type_vecConstLayoutFields& fields_shown);
+
+ /** A convenience method, creating the model from a list of LayoutItems,
+ * instead of a list of LayoutItem_Fields.
+ * Any LayoutItem_Fields should already have their full field details.
+ */
+ static Glib::RefPtr<DbTreeModel> create_from_items(const FoundSet& found_set, const type_vec_const_layout_items& layout_items, bool get_records, bool find_mode, Base_DB::type_vecConstLayoutFields& fields_shown);
+
typedef DbTreeModelRow::DbValue DbValue;
void set_is_not_placeholder(const TreeModel::iterator& iter);
diff --git a/glom/mode_data/db_adddel/db_adddel.cc b/glom/mode_data/db_adddel/db_adddel.cc
index 18f2c77..dfe5e18 100644
--- a/glom/mode_data/db_adddel/db_adddel.cc
+++ b/glom/mode_data/db_adddel/db_adddel.cc
@@ -672,7 +672,7 @@ Gtk::CellRenderer* DbAddDel::construct_specified_columns_cellrenderer(const shar
#ifndef GLOM_ENABLE_MAEMO //There's no direct editing via the list view on Maemo.
//Connect to its signal:
pCellRendererToggle->signal_toggled().connect(
- sigc::bind( sigc::mem_fun(*this, &DbAddDel::on_treeview_cell_edited_bool), model_column_index, data_model_column_index ) );
+ sigc::bind( sigc::mem_fun(*this, &DbAddDel::on_treeview_cell_edited_bool), model_column_index, data_model_column_index ) );
#endif //GLOM_ENABLE_MAEMO
}
}
@@ -702,127 +702,6 @@ Gtk::CellRenderer* DbAddDel::construct_specified_columns_cellrenderer(const shar
return pCellRenderer;
}
-typedef std::vector< sharedptr<const LayoutItem> > type_vec_const_layout_items;
-typedef std::vector< sharedptr<LayoutItem> > type_vec_layout_items;
-
-static Glib::RefPtr<DbTreeModel> create_model_db(const FoundSet& found_set, const type_vec_const_layout_items& layout_items, bool get_records, bool find_mode, Base_DB::type_vecConstLayoutFields& fields_shown)
-{
- Glib::RefPtr<DbTreeModel> result;
-
- typedef Gtk::TreeModelColumn<Gnome::Gda::Value> type_modelcolumn_value;
- typedef std::vector< type_modelcolumn_value* > type_vecModelColumns;
- type_vecModelColumns vecModelColumns(layout_items.size(), 0);
-
- //Create the Gtk ColumnRecord:
-
- Gtk::TreeModel::ColumnRecord record;
-
- //Database columns:
- Base_DB::type_vecConstLayoutFields fields;
- {
- type_vecModelColumns::size_type i = 0;
- for(type_vec_const_layout_items::const_iterator iter = layout_items.begin(); iter != layout_items.end(); ++iter)
- {
- sharedptr<const LayoutItem_Field> item_field = sharedptr<const LayoutItem_Field>::cast_dynamic(*iter);
- if(item_field)
- {
- type_modelcolumn_value* pModelColumn = new type_modelcolumn_value;
-
- //Store it so we can use it and delete it later:
- vecModelColumns[i] = pModelColumn;
-
- record.add( *pModelColumn );
-
- fields.push_back(item_field);
-
- i++;
- }
- }
- }
-
- fields_shown = fields;
-
- {
- //Find the primary key:
- int column_index_key = 0;
- bool key_found = false;
- for(Base_DB::type_vecConstLayoutFields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
- {
- sharedptr<const LayoutItem_Field> layout_item = *iter;
- if( !(layout_item->get_has_relationship_name()) )
- {
- sharedptr<const Field> field_full = layout_item->get_full_field_details();
- if(field_full && field_full->get_primary_key() )
- {
- key_found = true;
- break;
- }
- }
-
- ++column_index_key;
- }
-
- if(key_found)
- {
- //Create the model from the ColumnRecord:
- //Note that the model will use a dummy Gda DataModel if m_find_mode is true.
- //std::cout << "debug: Creating new DbTreeModel() for table=" << m_found_set.m_table_name << std::endl;
- result = DbTreeModel::create(record, found_set, fields, column_index_key, get_records, find_mode);
- }
- else
- {
- g_warning("%s: no primary key field found.", __FUNCTION__);
- //for(DbTreeModel::type_vec_const_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
- //{
- // g_warning(" field: %s", (iter->get_name().c_str());
- //}
- }
- }
-
- //Delete the vector's items:
- for(type_vecModelColumns::iterator iter = vecModelColumns.begin(); iter != vecModelColumns.end(); ++iter)
- {
- type_modelcolumn_value* pModelColumn = *iter;
- if(pModelColumn)
- delete pModelColumn;
- }
-
- return result;
-}
-
-/*
-static Glib::RefPtr<DbTreeModel> create_model_db(const FoundSet& found_set, const type_vec_layout_items& layout_items, bool get_records, bool find_mode, Base_DB::type_vecLayoutFields& fields_shown)
-{
- //Create a const version of the input, because C++ can't convert it automatically:
- type_vec_const_layout_items const_items;
- const_items.insert(const_items.end(), layout_items.begin(), layout_items.end());
-
- Base_DB::type_vecConstLayoutFields fields_shown_const;
- Glib::RefPtr<DbTreeModel> result = create_model_db(found_set, const_items, get_records, find_mode, fields_shown_const);
-
- //Create a non-const version of the output parameter,
- //because we know it just contains copies of layout_items elements, which were non-const:
- fields_shown.clear();
- for(Base_DB::type_vecConstLayoutFields::const_iterator iter = fields_shown_const.begin(); iter != fields_shown_const.end(); ++iter)
- {
- sharedptr<const LayoutItem_Field> field = *iter;
- sharedptr<LayoutItem_Field> unconst = sharedptr<LayoutItem_Field>::cast_const(field);
- fields_shown.push_back(unconst);
- }
-
- return result;
-}
-*/
-
-static Glib::RefPtr<DbTreeModel> create_model_db(const FoundSet& found_set, const type_vec_layout_items& layout_items, bool get_records, bool find_mode, Base_DB::type_vecConstLayoutFields& fields_shown)
-{
- //Create a const version of the input, because C++ can't convert it automatically:
- type_vec_const_layout_items const_items;
- const_items.insert(const_items.end(), layout_items.begin(), layout_items.end());
-
- return create_model_db(found_set, const_items, get_records, find_mode, fields_shown);
-}
-
void DbAddDel::construct_specified_columns()
{
InnerIgnore innerIgnore(this);
@@ -851,7 +730,7 @@ void DbAddDel::construct_specified_columns()
return;
}
- m_refListStore = create_model_db(m_found_set, m_column_items, m_allow_view, m_find_mode, m_FieldsShown);
+ m_refListStore = DbTreeModel::create_from_items(m_found_set, m_column_items, m_allow_view, m_find_mode, m_FieldsShown);
//m_FieldsShown is needed by Base_DB_Table_Data::record_new().
#ifdef GLOM_ENABLE_MAEMO
@@ -1096,9 +975,7 @@ void DbAddDel::refresh_cell_choices_data_from_database_with_foreign_key(guint mo
return;
}
- const Utils::type_list_values_with_second list_values =
- Utils::get_choice_values(get_document(), layout_field, foreign_key_value);
- cell->set_choices_with_second(list_values);
+ cell->set_choices_related(get_document(), layout_field, foreign_key_value);
}
void DbAddDel::remove_all_columns()
diff --git a/glom/mode_data/db_adddel/db_adddel.h b/glom/mode_data/db_adddel/db_adddel.h
index 1152531..82e93ef 100644
--- a/glom/mode_data/db_adddel/db_adddel.h
+++ b/glom/mode_data/db_adddel/db_adddel.h
@@ -24,7 +24,7 @@
#include <gtkmm.h>
#include <libglom/data_structure/layout/layoutitem_field.h>
#include <libgdamm.h>
-#include <glom/mode_data/db_adddel/treemodel_db.h>
+#include <glom/mode_data/datawidget/treemodel_db.h>
#include <libglom/document/document.h>
#include <glom/base_db_table_data.h>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b6b0ae4..2769a16 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -118,6 +118,7 @@ glom/mode_design/translation/combobox_locale.cc
glom/mode_design/translation/dialog_change_language.cc
glom/mode_design/translation/window_translations.cc
glom/utility_widgets/adddel/adddel.cc
+glom/mode_data/datawidget/combochoiceswithtreemodel.cc
glom/mode_data/datawidget/comboentry.cc
glom/mode_data/datawidget/datawidget.cc
glom/mode_data/db_adddel/db_adddel.cc
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]