[glom] Foreign key ID fields: Add a New Button next to the existing Find button.



commit 6c215ec6a1a0aa95bf220ad657c2397060771471
Author: Murray Cumming <murrayc murrayc com>
Date:   Wed Dec 21 21:56:53 2011 +0100

    Foreign key ID fields: Add a New Button next to the existing Find button.
    
    	* glom/mode_data/datawidget/dialog_new_record.[h|cc]: A new dialog to
    	quickly add a new related record.
    	* ui/operator/dialog_new_record.glade: The UI layout for that dialog.
    
    	* glom/mode_data/datawidget/datawidget: Constructor: Whenever we would
    	add a Find or Open button, also add a New button, so the user does not
    	need to manually go to the other table, add a record, and then come
    	back to the right record. Add offer_related_record_id_new() to implement
    	this.
    	Added signal_choices_changed() which is emitted when this would result
    	in the list of related choices changing.
    	* glom/mode_data/box_data_details.cc: Constructor: Handle the
    	field_choices_changed() signal, calling:
    	* glom/mode_data/flowtablewithfields.cc: a new update_choices() method,
    	to update all affected combo boxes.
    
    	* tests/test_glade_derived_instantiation.cc: Test the new dialog.
    
    	This will not quite work properly yet when the related choices should
    	be restricted by an ID value.

 ChangeLog                                      |   25 +++++
 Makefile.am                                    |    1 +
 Makefile_glom.am                               |    4 +-
 glom/mode_data/box_data_details.cc             |   10 ++-
 glom/mode_data/box_data_details.h              |    4 +-
 glom/mode_data/datawidget/datawidget.cc        |   75 +++++++++++++-
 glom/mode_data/datawidget/datawidget.h         |   16 +++
 glom/mode_data/datawidget/dialog_new_record.cc |   90 ++++++++++++++++
 glom/mode_data/datawidget/dialog_new_record.h  |   67 ++++++++++++
 glom/mode_data/flowtablewithfields.cc          |   47 ++++++++-
 glom/mode_data/flowtablewithfields.h           |   15 +++
 po/POTFILES.in                                 |    1 +
 tests/test_glade_derived_instantiation.cc      |   34 +++---
 ui/operator/dialog_new_record.glade            |  133 ++++++++++++++++++++++++
 14 files changed, 501 insertions(+), 21 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 23d63bf..f9b8d80 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2011-12-29  Murray Cumming  <murrayc murrayc com>
+
+	Foreign key ID fields: Add a New Button next to the existing Find button.
+
+	* glom/mode_data/datawidget/dialog_new_record.[h|cc]: A new dialog to 
+	quickly add a new related record.
+	* ui/operator/dialog_new_record.glade: The UI layout for that dialog.
+
+	* glom/mode_data/datawidget/datawidget: Constructor: Whenever we would 
+	add a Find or Open button, also add a New button, so the user does not 
+	need to manually go to the other table, add a record, and then come 
+	back to the right record. Add offer_related_record_id_new() to implement
+	this.
+	Added signal_choices_changed() which is emitted when this would result
+	in the list of related choices changing.
+	* glom/mode_data/box_data_details.cc: Constructor: Handle the 
+	field_choices_changed() signal, calling:
+	* glom/mode_data/flowtablewithfields.cc: a new update_choices() method,
+	to update all affected combo boxes.
+
+	* tests/test_glade_derived_instantiation.cc: Test the new dialog.
+
+	This will not quite work properly yet when the related choices should 
+	be restricted by an ID value.
+
 2011-12-27  David King  <davidk openismus com>
 
 	Add simple clipboard handlers to App_WithDoc_Gtk
diff --git a/Makefile.am b/Makefile.am
index 1b2d27a..7d707cc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -118,6 +118,7 @@ dist_glade_operator_DATA = \
 	ui/operator/dialog_image_save_progress.glade \
 	ui/operator/dialog_import_csv.glade \
 	ui/operator/dialog_import_csv_progress.glade \
+	ui/operator/dialog_new_record.glade \
 	ui/operator/window_main.glade
 		
 glade_developerdir = $(pkgdatadir)/glade/developer
diff --git a/Makefile_glom.am b/Makefile_glom.am
index b756d3f..ce853b6 100644
--- a/Makefile_glom.am
+++ b/Makefile_glom.am
@@ -173,7 +173,9 @@ glom_source_files = \
 	glom/mode_data/datawidget/dialog_choose_date.cc			\
 	glom/mode_data/datawidget/dialog_choose_date.h			\
 	glom/mode_data/datawidget/dialog_choose_id.cc			\
-	glom/mode_data/datawidget/dialog_choose_id.h				\
+	glom/mode_data/datawidget/dialog_choose_id.h			\
+	glom/mode_data/datawidget/dialog_new_record.cc			\
+	glom/mode_data/datawidget/dialog_new_record.h			\
 	glom/mode_data/datawidget/combo.cc				\
 	glom/mode_data/datawidget/combo.h				\
 	glom/mode_data/datawidget/combochoices.cc			\
diff --git a/glom/mode_data/box_data_details.cc b/glom/mode_data/box_data_details.cc
index 3ebfd75..40f7346 100644
--- a/glom/mode_data/box_data_details.cc
+++ b/glom/mode_data/box_data_details.cc
@@ -93,6 +93,7 @@ Box_Data_Details::Box_Data_Details(bool bWithNavButtons /* = true */)
   pack_start(m_hbox_content);
 
   m_FlowTable.signal_field_edited().connect( sigc::mem_fun(*this,  &Box_Data_Details::on_flowtable_field_edited) );
+  m_FlowTable.signal_field_choices_changed().connect( sigc::mem_fun(*this,  &Box_Data_Details::on_flowtable_field_choices_changed) );
   m_FlowTable.signal_field_open_details_requested().connect( sigc::mem_fun(*this,  &Box_Data_Details::on_flowtable_field_open_details_requested) );
   show_all();
 
@@ -864,7 +865,6 @@ void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutIte
     else
     {
       //It is not auto-generated:
-
       if(m_field_primary_key && strFieldName == m_field_primary_key->get_name()) //if it is the primary key that is being edited.
       {
         if(!check_entered_value_for_uniqueness(m_table_name, layout_field, field_value, window))
@@ -893,6 +893,14 @@ void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutIte
   } //if(get_primary_key_value_selected().size())
 }
 
+void Box_Data_Details::on_flowtable_field_choices_changed(const sharedptr<const LayoutItem_Field>& layout_field)
+{
+  if(m_ignore_signals)
+    return;
+
+  m_FlowTable.update_choices(layout_field);
+}
+
 void Box_Data_Details::on_userlevel_changed(AppState::userlevels user_level)
 {
 #ifndef GLOM_ENABLE_CLIENT_ONLY
diff --git a/glom/mode_data/box_data_details.h b/glom/mode_data/box_data_details.h
index d114504..903a434 100644
--- a/glom/mode_data/box_data_details.h
+++ b/glom/mode_data/box_data_details.h
@@ -119,7 +119,9 @@ protected:
   //Signal handler: The last arg is bind-ed.
   //virtual void on_related_user_requested_details(Gnome::Gda::Value key_value, Glib::ustring table_name);
 
-  virtual void on_flowtable_field_edited(const sharedptr<const LayoutItem_Field>& id, const Gnome::Gda::Value& value);
+  //TODO: Does this need to be virtual?
+  virtual void on_flowtable_field_edited(const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& value);
+  void on_flowtable_field_choices_changed(const sharedptr<const LayoutItem_Field>& layout_field);
   void on_flowtable_field_open_details_requested(const sharedptr<const LayoutItem_Field>& id, const Gnome::Gda::Value& value);
   void on_flowtable_related_record_changed(const Glib::ustring& relationship_name);
   void on_flowtable_requested_related_details(const Glib::ustring& table_name, Gnome::Gda::Value primary_key_value);
diff --git a/glom/mode_data/datawidget/datawidget.cc b/glom/mode_data/datawidget/datawidget.cc
index 39fbd7b..37d6cdf 100644
--- a/glom/mode_data/datawidget/datawidget.cc
+++ b/glom/mode_data/datawidget/datawidget.cc
@@ -32,6 +32,7 @@
 #include <glom/mode_design/layout/dialog_choose_field.h>
 #include <glom/mode_data/datawidget/dialog_choose_id.h>
 #include <glom/mode_data/datawidget/dialog_choose_date.h>
+#include <glom/mode_data/datawidget/dialog_new_record.h>
 #include <glom/mode_design/layout/layout_item_dialogs/dialog_field_layout.h>
 #include <glom/utils_ui.h>
 #include <glom/glade_utils.h>
@@ -129,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, field, Gnome::Gda::Value() /* TODO: Doesn't make sense */);
+        combo->set_choices_related(document, field, Gnome::Gda::Value() /* no ID means show all related records */);
       }
       else
       {
@@ -231,6 +232,11 @@ DataWidget::DataWidget(const sharedptr<LayoutItem_Field>& field, const Glib::ust
         button_select->set_tooltip_text(_("Enter search criteria to identify records in the other table, to choose an ID for this field."));
         hbox_parent->pack_start(*button_select, Gtk::PACK_SHRINK);
         button_select->signal_clicked().connect(sigc::mem_fun(*this, &DataWidget::on_button_select_id));
+
+        Gtk::Button* button_new = Gtk::manage(new Gtk::Button(Gtk::Stock::NEW));
+        button_new->set_tooltip_text(_("Enter details for a new record in the other table, then use its ID for this field."));
+        hbox_parent->pack_start(*button_new, Gtk::PACK_SHRINK);
+        button_new->signal_clicked().connect(sigc::mem_fun(*this, &DataWidget::on_button_new_id));
       }
     }
 
@@ -261,6 +267,10 @@ DataWidget::type_signal_edited DataWidget::signal_edited()
   return m_signal_edited;
 }
 
+DataWidget::type_signal_choices_changed DataWidget::signal_choices_changed()
+{
+  return m_signal_choices_changed;
+}
 
 void DataWidget::set_value(const Gnome::Gda::Value& value)
 {
@@ -587,6 +597,20 @@ const Gtk::Widget* DataWidget::get_data_child_widget() const
    }
  }
 
+void DataWidget::on_button_new_id()
+{
+  Gnome::Gda::Value chosen_id;
+  const bool chosen = offer_related_record_id_new(chosen_id);
+  if(!chosen)
+    return;
+
+  //Update the choices, if any, to show the new related record:
+  m_signal_choices_changed.emit();
+
+  set_value(chosen_id);
+  m_signal_edited.emit(chosen_id);
+}
+
 void DataWidget::on_button_choose_date()
 {
   DataWidgetChildren::Dialog_ChooseDate* dialog = 0;
@@ -668,4 +692,53 @@ bool DataWidget::offer_related_record_id_find(Gnome::Gda::Value& chosen_id)
   return result;
 }
 
+
+bool DataWidget::offer_related_record_id_new(Gnome::Gda::Value& chosen_id)
+{
+  bool result = false;
+
+  //Initialize output variable:
+  chosen_id = Gnome::Gda::Value();
+
+  DataWidgetChildren::Dialog_NewRecord* dialog = 0;
+  Glom::Utils::get_glade_widget_derived_with_warning(dialog);
+
+  if(dialog)
+  {
+    //dialog->set_document(get_document(), table_name, field);
+    Gtk::Window* parent = get_application();
+    if(parent)
+      dialog->set_transient_for(*parent);
+    add_view(dialog);
+
+    //Discover the related table, in the relationship that uses this ID field:
+    Glib::ustring related_table_name;
+    sharedptr<const LayoutItem_Field> layoutField = sharedptr<LayoutItem_Field>::cast_dynamic(get_layout_item());
+    if(layoutField)
+    {
+      sharedptr<const Relationship> relationship = get_document()->get_field_used_in_relationship_to_one(m_table_name, layoutField);
+      if(relationship)
+        related_table_name = relationship->get_to_table();
+    }
+    else
+      g_warning("get_layout_item() was not a LayoutItem_Field");
+
+    dialog->init_db_details(related_table_name, Base_DB::get_active_layout_platform(get_document()));
+
+
+    const int response = dialog->run();
+    dialog->hide();
+    if(response == Gtk::RESPONSE_OK)
+    {
+      //Get the chosen ID:
+      result = dialog->get_id_chosen(chosen_id);
+    }
+
+    remove_view(dialog);
+    delete dialog;
+  }
+
+  return result;
+}
+
 } //namespace Glom
diff --git a/glom/mode_data/datawidget/datawidget.h b/glom/mode_data/datawidget/datawidget.h
index 16e9000..7cd6f68 100644
--- a/glom/mode_data/datawidget/datawidget.h
+++ b/glom/mode_data/datawidget/datawidget.h
@@ -79,6 +79,16 @@ public:
   typedef sigc::signal<void, const Gnome::Gda::Value&> type_signal_open_details_requested;
   type_signal_open_details_requested signal_open_details_requested();
 
+  /** For instance,
+   * void on_choices_changed();
+   */
+  typedef sigc::signal<void> type_signal_choices_changed;
+
+  /** This is emitted when the related records, used by a choices combobox,
+   * have been changed. For instance, when the user adds a new choice via the "New" button.
+   */
+  type_signal_choices_changed signal_choices_changed();
+
 private:
   //virtual void setup_menu();
 
@@ -92,6 +102,7 @@ private:
 #endif // !GLOM_ENABLE_CLIENT_ONLY
   void on_button_open_details();
   void on_button_select_id();
+  void on_button_new_id();
   void on_button_choose_date();
 
   // Don't call it on_style_changed, otherwise we would override a virtual
@@ -115,12 +126,17 @@ private:
    */
   bool offer_related_record_id_find(Gnome::Gda::Value& chosen_id);
 
+  /** Show a dialog with Details so that the user can add a new record and then use that ID value to indicate that related record.
+   */
+  bool offer_related_record_id_new(Gnome::Gda::Value& chosen_id);
+
 private:
   void update_go_to_details_button_sensitivity();
 
 protected:
   type_signal_edited m_signal_edited;
   type_signal_open_details_requested m_signal_open_details_requested;
+  type_signal_choices_changed m_signal_choices_changed;
 
   Gtk::Label m_label;
   Gtk::Widget* m_child;
diff --git a/glom/mode_data/datawidget/dialog_new_record.cc b/glom/mode_data/datawidget/dialog_new_record.cc
new file mode 100644
index 0000000..f6f987b
--- /dev/null
+++ b/glom/mode_data/datawidget/dialog_new_record.cc
@@ -0,0 +1,90 @@
+/* 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 "dialog_new_record.h"
+#include <glom/utils_ui.h> //For bold_message()).
+//#include <libgnome/gnome-i18n.h>
+#include <glibmm/i18n.h>
+
+namespace Glom
+{
+
+namespace DataWidgetChildren
+{
+
+const char* Dialog_NewRecord::glade_id("dialog_new_record");
+const bool Dialog_NewRecord::glade_developer(false);
+
+Dialog_NewRecord::Dialog_NewRecord()
+: m_label_table_name(0),
+  m_alignment_parent(0)
+{
+}
+
+Dialog_NewRecord::Dialog_NewRecord(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
+: Gtk::Dialog(cobject),
+  m_label_table_name(0),
+  m_alignment_parent(0)
+{
+  builder->get_widget("label_table_name", m_label_table_name);
+  builder->get_widget("alignment_parent", m_alignment_parent);
+
+  setup();
+}
+
+Dialog_NewRecord::~Dialog_NewRecord()
+{
+  remove_view(&m_box_details);
+}
+
+void Dialog_NewRecord::setup()
+{
+  m_alignment_parent->add(m_box_details);
+
+  //Fill composite view:
+  add_view(&m_box_details);
+}
+
+bool Dialog_NewRecord::get_id_chosen(Gnome::Gda::Value& chosen_id) const
+{
+  chosen_id = m_box_details.get_primary_key_value_selected();
+  return true;
+}
+
+bool Dialog_NewRecord::init_db_details(const Glib::ustring& table_name, const Glib::ustring& layout_platform)
+{
+  m_table_name = table_name;
+  m_layout_platform = layout_platform;
+
+  m_label_table_name->set_text( get_document()->get_table_title(m_table_name) );
+
+  FoundSet found_set;
+  found_set.m_table_name = m_table_name;
+  const Gnome::Gda::Value primary_key_for_details;
+  const bool result = m_box_details.init_db_details(found_set, layout_platform, primary_key_for_details);
+  m_box_details.do_new_record();
+
+  m_table_name = table_name;
+
+  return result;
+}
+
+} //namespace DataWidetChildren
+} //namespace Glom
diff --git a/glom/mode_data/datawidget/dialog_new_record.h b/glom/mode_data/datawidget/dialog_new_record.h
new file mode 100644
index 0000000..f64a521
--- /dev/null
+++ b/glom/mode_data/datawidget/dialog_new_record.h
@@ -0,0 +1,67 @@
+/* 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_MODE_DATA_DIALOG_NEW_RECORD_H
+#define GLOM_MODE_DATA_DIALOG_NEW_RECORD_H
+
+#include <gtkmm/dialog.h>
+#include <libglom/document/document.h>
+#include <glom/base_db.h>
+#include <glom/mode_data/box_data_details.h>
+
+namespace Glom
+{
+
+namespace DataWidgetChildren
+{
+
+class Dialog_NewRecord
+  : public Gtk::Dialog,
+    public View_Composite_Glom
+{
+public:
+  static const char* glade_id;
+  static const bool glade_developer;
+
+  Dialog_NewRecord();
+  Dialog_NewRecord(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder);
+  virtual ~Dialog_NewRecord();
+
+  virtual bool init_db_details(const Glib::ustring& table_name, const Glib::ustring& layout_platform);
+
+  bool get_id_chosen(Gnome::Gda::Value& chosen_id) const;
+
+private:
+
+  void setup();
+
+  Gtk::Label* m_label_table_name;
+  Gtk::Alignment* m_alignment_parent;
+
+  Glib::ustring m_table_name;
+  Glib::ustring m_layout_platform;
+
+  Box_Data_Details m_box_details;
+};
+
+} //namespace DataWidetChildren
+} //namespace Glom
+
+#endif //GLOM_MODE_DATA_DIALOG_NEW_RECORD_H
diff --git a/glom/mode_data/flowtablewithfields.cc b/glom/mode_data/flowtablewithfields.cc
index 81143dd..1bf28c9 100644
--- a/glom/mode_data/flowtablewithfields.cc
+++ b/glom/mode_data/flowtablewithfields.cc
@@ -233,8 +233,10 @@ void FlowTableWithFields::add_layout_group(const sharedptr<LayoutGroup>& group,
     flow_table->set_layout_item(group, m_table_name);
     add_layoutwidgetbase(flow_table);
 
-    //Connect signal:
+    //Connect signals:
+    //TODO: Find a less repetitive way to do this chaining-up of signal emissions:
     flow_table->signal_field_edited().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_flowtable_entry_edited) );
+    flow_table->signal_field_choices_changed().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_flowtable_entry_choices_changed) );
     flow_table->signal_field_open_details_requested().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_flowtable_entry_open_details_requested) );
     flow_table->signal_related_record_changed().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_flowtable_related_record_changed) );
     flow_table->signal_requested_related_details().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_flowtable_requested_related_details) );
@@ -544,6 +546,7 @@ void FlowTableWithFields::add_field(const sharedptr<LayoutItem_Field>& layoutite
   add(*eventbox, *(info.m_second), true);
 
   info.m_second->signal_edited().connect( sigc::bind(sigc::mem_fun(*this, &FlowTableWithFields::on_entry_edited), layoutitem_field)  ); //TODO:  Is it a good idea to bind the LayoutItem? sigc::bind() probably stores a copy at this point.
+  info.m_second->signal_choices_changed().connect( sigc::bind(sigc::mem_fun(*this, &FlowTableWithFields::on_entry_choices_changed), layoutitem_field)  );
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   info.m_second->signal_layout_item_added().connect( sigc::bind(
@@ -791,6 +794,33 @@ void FlowTableWithFields::set_field_editable(const sharedptr<const LayoutItem_Fi
   }
 }
 
+void FlowTableWithFields::update_choices(const sharedptr<const LayoutItem_Field>& field)
+{
+  type_list_widgets list_widgets = get_field(field, true);
+  for(type_list_widgets::iterator iter = list_widgets.begin(); iter != list_widgets.end(); ++iter)
+  {
+    DataWidget* datawidget = dynamic_cast<DataWidget*>(*iter);
+    if(!datawidget)
+      continue;
+
+    DataWidgetChildren::ComboChoices* combo = 
+      dynamic_cast<DataWidgetChildren::ComboChoices*>(datawidget->get_data_child_widget());
+    if(!combo)
+      continue;
+
+    const sharedptr<const LayoutItem> layout_item = combo->get_layout_item();
+    const sharedptr<const LayoutItem_Field> layout_item_field = 
+      sharedptr<const LayoutItem_Field>::cast_dynamic(layout_item);
+    if(!layout_item_field || !layout_item_field->get_formatting_used().get_has_related_choices())
+      continue;
+
+    //TODO: Handle not-all related choices, too.
+    combo->set_choices_related(get_document(), field, Gnome::Gda::Value() /* no ID means show all related records */);
+  }
+
+  //TODO: See also "Refresh choices widgets which should show the related records for relationships that use this field"
+}
+
 
 FlowTableWithFields::type_portals FlowTableWithFields::get_portals(const sharedptr<const LayoutItem_Field>& from_key)
 {
@@ -1019,6 +1049,11 @@ FlowTableWithFields::type_signal_field_edited FlowTableWithFields::signal_field_
   return m_signal_field_edited;
 }
 
+FlowTableWithFields::type_signal_field_choices_changed FlowTableWithFields::signal_field_choices_changed()
+{
+  return m_signal_field_choices_changed;
+}
+
 FlowTableWithFields::type_signal_field_open_details_requested FlowTableWithFields::signal_field_open_details_requested()
 {
   return m_signal_field_open_details_requested;
@@ -1049,6 +1084,11 @@ void FlowTableWithFields::on_entry_edited(const Gnome::Gda::Value& value, const
   m_signal_field_edited.emit(field, value);
 }
 
+void FlowTableWithFields::on_entry_choices_changed(const sharedptr<const LayoutItem_Field> field)
+{
+  m_signal_field_choices_changed.emit(field);
+}
+
 void FlowTableWithFields::on_entry_open_details_requested(const Gnome::Gda::Value& value, const sharedptr<const LayoutItem_Field> field)
 {
   m_signal_field_open_details_requested.emit(field, value);
@@ -1059,6 +1099,11 @@ void FlowTableWithFields::on_flowtable_entry_edited(const sharedptr<const Layout
   m_signal_field_edited.emit(field, value);
 }
 
+void FlowTableWithFields::on_flowtable_entry_choices_changed(const sharedptr<const LayoutItem_Field>& field)
+{
+  m_signal_field_choices_changed.emit(field);
+}
+
 void FlowTableWithFields::on_flowtable_entry_open_details_requested(const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value)
 {
   m_signal_field_open_details_requested.emit(field, value);
diff --git a/glom/mode_data/flowtablewithfields.h b/glom/mode_data/flowtablewithfields.h
index c4c06e5..5fba929 100644
--- a/glom/mode_data/flowtablewithfields.h
+++ b/glom/mode_data/flowtablewithfields.h
@@ -107,6 +107,11 @@ public:
    */
   void set_other_field_value(const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& value);
 
+  /** Refresh the list of related records in choice combo boxes, 
+   * in any instance of the specified field.
+   */
+  void update_choices(const sharedptr<const LayoutItem_Field>& field);
+
   typedef std::list<Gtk::Widget*> type_list_widgets;
   typedef std::list<const Gtk::Widget*> type_list_const_widgets;
 
@@ -147,6 +152,13 @@ public:
   type_signal_field_edited signal_field_edited();
 
   /** For instance,
+   * void on_flowtable_field_choices_changed(const sharedptr<const LayoutItem_Field>& field);
+   */
+  typedef sigc::signal<void, const sharedptr<const LayoutItem_Field>&> type_signal_field_choices_changed;
+  type_signal_field_choices_changed signal_field_choices_changed();
+
+
+  /** For instance,
    * void on_flowtable_field_open_details_requested(const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value);
    */
   typedef sigc::signal<void, const sharedptr<const LayoutItem_Field>&, const Gnome::Gda::Value&> type_signal_field_open_details_requested;
@@ -198,8 +210,10 @@ private:
   //int get_suitable_width(Field::glom_field_type field_type);
 
   void on_entry_edited(const Gnome::Gda::Value& value, const sharedptr<const LayoutItem_Field> field);
+  void on_entry_choices_changed(const sharedptr<const LayoutItem_Field> field);
   void on_entry_open_details_requested(const Gnome::Gda::Value& value, const sharedptr<const LayoutItem_Field> field);
   void on_flowtable_entry_edited(const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value);
+  void on_flowtable_entry_choices_changed(const sharedptr<const LayoutItem_Field>& field);
   void on_flowtable_entry_open_details_requested(const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value);
   void on_flowtable_related_record_changed(const Glib::ustring& relationship_name);
   void on_flowtable_requested_related_details(const Glib::ustring& table_name, Gnome::Gda::Value primary_key_value);
@@ -271,6 +285,7 @@ private:
   type_vec_sizegroups m_vec_size_groups;
 
   type_signal_field_edited m_signal_field_edited;
+  type_signal_field_choices_changed m_signal_field_choices_changed;
   type_signal_field_open_details_requested m_signal_field_open_details_requested;
 
   //type_signal_related_record_added m_signal_related_record_added;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f056d39..4af0307 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -144,6 +144,7 @@ ui/operator/dialog_connection.glade
 ui/operator/dialog_data_invalid_format.glade
 ui/operator/dialog_existing_or_new.glade
 ui/operator/dialog_find_id.glade
+ui/operator/dialog_new_record.glade
 ui/operator/dialog_image_load_progress.glade
 ui/operator/dialog_image_save_progress.glade
 ui/operator/dialog_import_csv.glade
diff --git a/tests/test_glade_derived_instantiation.cc b/tests/test_glade_derived_instantiation.cc
index a7cc090..98160ac 100644
--- a/tests/test_glade_derived_instantiation.cc
+++ b/tests/test_glade_derived_instantiation.cc
@@ -1,19 +1,3 @@
-#include <glom/glade_utils.h>
-#include <glom/application.h>
-#include <glom/dialog_existing_or_new.h>
-#include <glom/mode_design/print_layouts/box_print_layouts.h>
-#include <glom/mode_design/relationships_overview/dialog_relationships_overview.h>
-#include <glom/mode_design/dialog_relationships.h>
-#include <glom/mode_design/report_layout/dialog_layout_report.h>
-#include <glom/box_reports.h>
-#include <glom/navigation/box_tables.h>
-#include <glom/import_csv/dialog_import_csv.h>
-#include <glom/import_csv/dialog_import_csv_progress.h>
-#include <glom/mode_data/datawidget/dialog_choose_date.h>
-#include <glom/mode_data/datawidget/dialog_choose_id.h>
-#include <glom/utility_widgets/dialog_flowtable.h>
-#include <glom/utility_widgets/dialog_image_load_progress.h>
-#include <glom/utility_widgets/dialog_image_save_progress.h>
 /* Glom
  *
  * Copyright (C) 2010-2011 Murray Cumming
@@ -34,6 +18,23 @@
  * Boston, MA 02111-1307, USA.
  */
  
+#include <glom/glade_utils.h>
+#include <glom/application.h>
+#include <glom/dialog_existing_or_new.h>
+#include <glom/mode_design/print_layouts/box_print_layouts.h>
+#include <glom/mode_design/relationships_overview/dialog_relationships_overview.h>
+#include <glom/mode_design/dialog_relationships.h>
+#include <glom/mode_design/report_layout/dialog_layout_report.h>
+#include <glom/box_reports.h>
+#include <glom/navigation/box_tables.h>
+#include <glom/import_csv/dialog_import_csv.h>
+#include <glom/import_csv/dialog_import_csv_progress.h>
+#include <glom/mode_data/datawidget/dialog_choose_date.h>
+#include <glom/mode_data/datawidget/dialog_choose_id.h>
+#include <glom/mode_data/datawidget/dialog_new_record.h>
+#include <glom/utility_widgets/dialog_flowtable.h>
+#include <glom/utility_widgets/dialog_image_load_progress.h>
+#include <glom/utility_widgets/dialog_image_save_progress.h>
 #include <glom/mode_design/layout/dialog_choose_field.h>
 #include <glom/mode_design/dialog_add_related_table.h>
 #include <glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.h>
@@ -127,6 +128,7 @@ int main(int argc, char *argv[])
   instantiate_widget<Dialog_Import_CSV_Progress>();
   instantiate_widget<DataWidgetChildren::Dialog_ChooseID>();
   instantiate_widget<DataWidgetChildren::Dialog_ChooseDate>();
+  instantiate_widget<DataWidgetChildren::Dialog_NewRecord>();
   instantiate_widget<Dialog_InvalidData>();
   instantiate_widget<DialogImageLoadProgress>();
   instantiate_widget<DialogImageSaveProgress>();
diff --git a/ui/operator/dialog_new_record.glade b/ui/operator/dialog_new_record.glade
new file mode 100644
index 0000000..e906d8e
--- /dev/null
+++ b/ui/operator/dialog_new_record.glade
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <object class="GtkDialog" id="dialog_new_record">
+    <property name="can_focus">False</property>
+    <property name="border_width">6</property>
+    <property name="title" translatable="yes">Find Related Record</property>
+    <property name="default_width">300</property>
+    <property name="default_height">500</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="vbox81">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="hbuttonbox39">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button_close">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox82">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">6</property>
+            <property name="spacing">12</property>
+            <child>
+              <object class="GtkAlignment" id="alignment_parent_top">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkVBox" id="vbox83">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox81">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkLabel" id="label203">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes">&lt;b&gt;Table:&lt;/b&gt;</property>
+                            <property name="use_markup">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="label_table_name">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes">table_name</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkAlignment" id="alignment_parent">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-5">button_close</action-widget>
+    </action-widgets>
+  </object>
+</interface>



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