glom r1580 - in trunk: . glom glom/libglom/data_structure/layout glom/libglom/document glom/mode_data glom/utility_widgets/calendar glom/utility_widgets/db_adddel



Author: murrayc
Date: Mon Apr 21 15:45:40 2008
New Revision: 1580
URL: http://svn.gnome.org/viewvc/glom?rev=1580&view=rev

Log:
2008-04-21  Murray Cumming  <murrayc murrayc com>

* glom/Makefile.am:
* glom/combobox_fields.h 
* glom/combobox_fields.cc: Added set_fields() that takes a field type to 
reduce the list.
* glom/glom_developer.glade: window_data_layout(): Added a Add Related 
Calendar button and added a Date section, which is hidden for the 
existing layout dialogs.
* glom/libglom/data_structure/layout/Makefile.am:
Added layoutitem_calendarportal.[h|cc]
* glom/libglom/document/document_glom.cc
  load_after_layout_group(), Glom.save_before_layout_group(): Handle 
LayoutItem_CalendarPortal items.

* glom/mode_data/Makefile.am:
* glom/mode_data/box_data_portal.cc
* glom/mode_data/box_data_portal.h: Added this new base class for 
related records widgets, using LayoutItem_Portal as the base class for 
their layout data.
* glom/mode_data/box_data_list_related.cc
* glom/mode_data/box_data_list_related.h: Derive from Box_Data_Portal, 
to which some of the code has moved.
* glom/mode_data/box_data_calendar_related.cc
* glom/mode_data/box_data_calendar_related.h: Added this new portal, 
which shows the related records in a calendar.

* glom/mode_data/dialog_layout_calendar_related.cc
* glom/mode_data/dialog_layout_calendar_related.h:
* glom/mode_data/dialog_layout_details.h
* glom/mode_data/dialog_layout_details.cc:
Allow adding of a related calendar portal.

* glom/mode_data/dialog_layout_list.cc (Glom.Dialog_Layout_List):
* glom/mode_data/flowtablewithfields.cc
* glom/mode_data/flowtablewithfields.h: Handle Box_Data_Portal instead 
of just Box_Data_List_Related, and handle Box_Data_Calendar_Related 
specifically where necessary.
* glom/utility_widgets/calendar/Makefile.am: Fixed a typo.
* glom/utility_widgets/calendar/glomgtkcalendar.c
  (glom_gtk_calendar_init, glom_gtk_calendar_new): Use the correct GType.

Added:
   trunk/glom/mode_data/box_data_portal.cc
      - copied, changed from r1579, /trunk/glom/mode_data/box_data_list_related.cc
   trunk/glom/mode_data/box_data_portal.h
      - copied, changed from r1579, /trunk/glom/mode_data/box_data_list_related.h
Modified:
   trunk/ChangeLog
   trunk/glom/Makefile.am
   trunk/glom/combobox_fields.cc
   trunk/glom/combobox_fields.h
   trunk/glom/glom_developer.glade
   trunk/glom/libglom/data_structure/layout/Makefile.am
   trunk/glom/libglom/document/document_glom.cc
   trunk/glom/mode_data/Makefile.am
   trunk/glom/mode_data/box_data_calendar_related.cc
   trunk/glom/mode_data/box_data_calendar_related.h
   trunk/glom/mode_data/box_data_list_related.cc
   trunk/glom/mode_data/box_data_list_related.h
   trunk/glom/mode_data/dialog_layout_calendar_related.cc
   trunk/glom/mode_data/dialog_layout_calendar_related.h
   trunk/glom/mode_data/dialog_layout_details.cc
   trunk/glom/mode_data/dialog_layout_details.h
   trunk/glom/mode_data/dialog_layout_list.cc
   trunk/glom/mode_data/flowtablewithfields.cc
   trunk/glom/mode_data/flowtablewithfields.h
   trunk/glom/utility_widgets/calendar/Makefile.am
   trunk/glom/utility_widgets/calendar/glomgtkcalendar.c
   trunk/glom/utility_widgets/db_adddel/db_adddel.h

Modified: trunk/glom/Makefile.am
==============================================================================
--- trunk/glom/Makefile.am	(original)
+++ trunk/glom/Makefile.am	Mon Apr 21 15:45:40 2008
@@ -39,7 +39,7 @@
                combobox_fields.h combobox_fields.cc \
                combobox_relationship.h combobox_relationship.cc \
                dialog_connection.h dialog_connection.cc \
-	       dialog_existing_or_new.h dialog_existing_or_new.cc \
+               dialog_existing_or_new.h dialog_existing_or_new.cc \
                dialog_invalid_data.h dialog_invalid_data.cc \
                filechooser_export.h filechooser_export.cc \
                box_reports.h box_reports.cc \
@@ -75,6 +75,7 @@
               utility_widgets/adddel/libutility_widgets_adddel.a \
               utility_widgets/adddel/eggcolumnchooser/libutility_widgets_adddel_eggcolumnchooserdialog.a \
               utility_widgets/db_adddel/libutility_widgets_db_adddel.a \
+              utility_widgets/calendar/libutility_widgets_calendar.a \
               utility_widgets/canvas/libutility_widgets_canvas.a \
               utility_widgets/cellrendererlist/libutility_widgets_cellrendererlist.a \
               utility_widgets/eggtoolpalette/libeggtoolpalette.la \

Modified: trunk/glom/combobox_fields.cc
==============================================================================
--- trunk/glom/combobox_fields.cc	(original)
+++ trunk/glom/combobox_fields.cc	Mon Apr 21 15:45:40 2008
@@ -113,6 +113,9 @@
 
   const Document_Glom::type_vecFields fields = document->get_table_fields(parent_table_name);
 
+  if(!m_model)
+    return;
+  
   m_model->clear();
 
   //Fill the model:
@@ -127,8 +130,40 @@
   }
 }
 
+void ComboBox_Fields::set_fields(Document_Glom* document, const Glib::ustring parent_table_name, Field::glom_field_type field_type)
+{
+  if(!document)
+    return;
+
+  const Document_Glom::type_vecFields fields = document->get_table_fields(parent_table_name);
+
+  if(!m_model)
+    return;
+  
+  m_model->clear();
+
+  //Fill the model:
+  for(type_vecFields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
+  {
+    sharedptr<Field> rel = *iter;
+    if(rel && (rel->get_glom_type() == field_type))
+    {
+      std::cout << "DEBUG: ComboBox_Fields::set_fields() 1" << std::endl;
+      Gtk::TreeModel::iterator tree_iter = m_model->append();
+      std::cout << "DEBUG: ComboBox_Fields::set_fields() 2" << std::endl;
+      Gtk::TreeModel::Row row = *tree_iter;
+
+      row[m_model_columns.m_field] = rel;
+      row[m_model_columns.m_separator] = false;
+    }
+  }
+}
+
 void ComboBox_Fields::set_fields(const type_vecFields& fields, bool with_none_item)
 {
+  if(!m_model)
+    return;
+  
   m_model->clear();
 
   if(with_none_item)

Modified: trunk/glom/combobox_fields.h
==============================================================================
--- trunk/glom/combobox_fields.h	(original)
+++ trunk/glom/combobox_fields.h	Mon Apr 21 15:45:40 2008
@@ -39,9 +39,26 @@
   virtual ~ComboBox_Fields();
 
   typedef std::vector< sharedptr<Field> > type_vecFields;
+    
+  /** Fill the combo box with fields.
+   * @param fields The fields to show in the combo box.
+   * @param with_none_type Whether to show an extra None item.
+   */
   void set_fields(const type_vecFields& fields, bool with_none_item = false);
 
+  /** Fill the combo box with fields.
+   * @param document The Document, used to get the list of fields.
+   * @param parent_table_name The table whose fields should be shown.
+   * @param field_type Show only fields of this type.
+   */
   void set_fields(Document_Glom* document, const Glib::ustring parent_table_name);
+    
+  /** Fill the combo box with fields, but only fields of a certain type.
+   * @param document The Document, used to get the list of fields.
+   * @param parent_table_name The table whose fields should be shown.
+   * @param field_type Show only fields of this type.
+   */
+  void set_fields(Document_Glom* document, const Glib::ustring parent_table_name, Field::glom_field_type field_type);
 
   void set_selected_field(const sharedptr<const Field>& field);
   void set_selected_field(const Glib::ustring& field_name);

Modified: trunk/glom/glom_developer.glade
==============================================================================
--- trunk/glom/glom_developer.glade	(original)
+++ trunk/glom/glom_developer.glade	Mon Apr 21 15:45:40 2008
@@ -8429,6 +8429,56 @@
                             <property name="position">5</property>
                           </packing>
                         </child>
+ <child>
+                          <widget class="GtkButton" id="button_add_related_calendar">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="can_default">True</property>
+                            <property name="tooltip" translatable="yes">Add a related records calendar portal. This is a calendar showing records from a related table. Remember to edit this layout item to specify the relationship to use, and the fields to show from the related table.</property>
+                            <property name="response_id">0</property>
+                            <child>
+                              <widget class="GtkAlignment" id="alignment22">
+                                <property name="visible">True</property>
+                                <property name="xscale">0</property>
+                                <property name="yscale">0</property>
+                                <child>
+                                  <widget class="GtkHBox" id="hbox29">
+                                    <property name="visible">True</property>
+                                    <property name="spacing">2</property>
+                                    <child>
+                                      <widget class="GtkImage" id="image19">
+                                        <property name="visible">True</property>
+                                        <property name="stock">gtk-add</property>
+                                      </widget>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <widget class="GtkLabel" id="label74">
+                                        <property name="visible">True</property>
+                                        <property name="label" translatable="yes">Add Related Calendar</property>
+                                        <property name="use_underline">True</property>
+                                      </widget>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </widget>
+                                </child>
+                              </widget>
+                            </child>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="pack_type">GTK_PACK_END</property>
+                            <property name="position">4</property>
+                          </packing>
+                        </child>
                         <child>
                           <widget class="GtkButton" id="button_add_related">
                             <property name="visible">True</property>
@@ -8887,6 +8937,60 @@
             <property name="position">2</property>
           </packing>
         </child>
+ <child>
+          <widget class="GtkFrame" id="frame_calendar">
+            <property name="visible">True</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">GTK_SHADOW_NONE</property>
+            <child>
+              <widget class="GtkAlignment" id="alignment25">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkHBox" id="hbox44">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <widget class="GtkLabel" id="label26">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Date Field</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="combobox_date_field">
+                        <property name="visible">True</property>
+                        <property name="tooltip" translatable="yes">This field will be used to decide which records to show in the calendar.</property>
+                        <!-- <property name="row_span_column">1</property> -->
+                        <!-- <property name="active">1</property> -->
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="frame_navigation1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">&lt;b&gt;Dates&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="type">label_item</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
         <child>
           <widget class="GtkHButtonBox" id="hbuttonbox7">
             <property name="visible">True</property>

Modified: trunk/glom/libglom/data_structure/layout/Makefile.am
==============================================================================
--- trunk/glom/libglom/data_structure/layout/Makefile.am	(original)
+++ trunk/glom/libglom/data_structure/layout/Makefile.am	Mon Apr 21 15:45:40 2008
@@ -7,6 +7,7 @@
                               layoutgroup.h layoutgroup.cc \
                               layoutitem_field.h layoutitem_field.cc \
                               layoutitem_portal.h layoutitem_portal.cc \
+                              layoutitem_calendarportal.h layoutitem_calendarportal.cc \
                               layoutitem_notebook.h layoutitem_notebook.cc \
                               layoutitem_button.h layoutitem_button.cc \
                               layoutitem_text.h layoutitem_text.cc \

Modified: trunk/glom/libglom/document/document_glom.cc
==============================================================================
--- trunk/glom/libglom/document/document_glom.cc	(original)
+++ trunk/glom/libglom/document/document_glom.cc	Mon Apr 21 15:45:40 2008
@@ -29,6 +29,7 @@
 #include <glom/libglom/data_structure/layout/layoutitem_button.h>
 #include <glom/libglom/data_structure/layout/layoutitem_text.h>
 #include <glom/libglom/data_structure/layout/layoutitem_image.h>
+#include <glom/libglom/data_structure/layout/layoutitem_calendarportal.h>
 #include <glom/libglom/data_structure/layout/layoutitem_line.h>
 #include <glom/libglom/standard_table_prefs_fields.h>
 #include <giomm.h>
@@ -67,6 +68,8 @@
 #define GLOM_NODE_DATA_LAYOUT_PORTAL "data_layout_portal"
 #define GLOM_NODE_DATA_LAYOUT_PORTAL_NAVIGATIONRELATIONSHIP "portal_navigation_relationship"
 #define GLOM_ATTRIBUTE_PORTAL_NAVIGATIONRELATIONSHIP_MAIN "navigation_main"
+#define GLOM_NODE_DATA_LAYOUT_CALENDAR_PORTAL "data_layout_calendar_portal"
+#define GLOM_ATTRIBUTE_PORTAL_CALENDAR_DATE_FIELD "date_field"
 #define GLOM_NODE_DATA_LAYOUT_ITEM "data_layout_item" //A field.
 #define GLOM_NODE_LAYOUT_ITEM_CUSTOM_TITLE "title_custom"
 #define GLOM_ATTRIBUTE_LAYOUT_ITEM_CUSTOM_TITLE_USE "use_custom"
@@ -2044,9 +2047,18 @@
         load_after_layout_group(element, table_name, notebook, with_print_layout_positions);
         item_added = notebook; 
       }
-      else if(element->get_name() == GLOM_NODE_DATA_LAYOUT_PORTAL)
+      else if( (element->get_name() == GLOM_NODE_DATA_LAYOUT_PORTAL) || (element->get_name() == GLOM_NODE_DATA_LAYOUT_CALENDAR_PORTAL) )
       {
-        sharedptr<LayoutItem_Portal> portal = sharedptr<LayoutItem_Portal>::create();
+        sharedptr<LayoutItem_Portal> portal;
+        sharedptr<LayoutItem_CalendarPortal> calendar_portal;
+
+        if(element->get_name() == GLOM_NODE_DATA_LAYOUT_PORTAL)
+          portal = sharedptr<LayoutItem_Portal>::create();
+        else if(element->get_name() == GLOM_NODE_DATA_LAYOUT_CALENDAR_PORTAL)
+        {
+          calendar_portal = sharedptr<LayoutItem_CalendarPortal>::create();
+          portal = calendar_portal;
+        }
 
         load_after_layout_item_usesrelationship(element, table_name, portal); 
        
@@ -2071,6 +2083,15 @@
         portal->set_navigation_relationship_specific(relationship_navigation_specific_main, relationship_navigation_specific);
 
         load_after_layout_group(element, portal->get_table_used(table_name), portal, with_print_layout_positions);
+        
+        //Get the calendar portal's date field:
+        if(calendar_portal)
+        {
+          const Glib::ustring date_field_name = get_node_attribute_value(element, GLOM_ATTRIBUTE_PORTAL_CALENDAR_DATE_FIELD);
+          sharedptr<Field> date_field = get_field(calendar_portal->get_table_used(table_name), date_field_name);
+          calendar_portal->set_date_field(date_field);
+        }
+        
         item_added = portal; 
       }
       else if(element->get_name() == GLOM_NODE_DATA_LAYOUT_ITEM_GROUPBY)
@@ -2837,7 +2858,17 @@
             sharedptr<const LayoutItem_Portal> portal = sharedptr<const LayoutItem_Portal>::cast_dynamic(group);
             if(portal) //If it is a related records portal
             {
-              child = node->add_child(GLOM_NODE_DATA_LAYOUT_PORTAL);
+              sharedptr<const LayoutItem_CalendarPortal> calendar_portal = sharedptr<const LayoutItem_CalendarPortal>::cast_dynamic(portal);
+              if(calendar_portal)
+              {
+                child = node->add_child(GLOM_NODE_DATA_LAYOUT_CALENDAR_PORTAL);
+                sharedptr<const Field> date_field = calendar_portal->get_date_field();
+                if(date_field)
+                  set_node_attribute_value(child, GLOM_ATTRIBUTE_PORTAL_CALENDAR_DATE_FIELD, date_field->get_name());
+              }
+              else
+                child = node->add_child(GLOM_NODE_DATA_LAYOUT_PORTAL);
+
               save_before_layout_item_usesrelationship(child, portal);
 
               //Portal navigation details:

Modified: trunk/glom/mode_data/Makefile.am
==============================================================================
--- trunk/glom/mode_data/Makefile.am	(original)
+++ trunk/glom/mode_data/Makefile.am	Mon Apr 21 15:45:40 2008
@@ -11,6 +11,8 @@
                          box_data_details.cc box_data_details.h \
                          box_data_list_related.cc box_data_list_related.h \
                          box_data_list.cc box_data_list.h \
+                         box_data_calendar_related.cc box_data_calendar_related.h \
+                         box_data_portal.cc box_data_portal.h \
                          notebook_data.cc notebook_data.h \
                          dialog_layout.cc dialog_layout.h \
                          dialog_choose_field.cc dialog_choose_field.h \
@@ -21,6 +23,7 @@
 if !GLOM_ENABLE_CLIENT_ONLY
 libmode_data_a_SOURCES += dialog_layout_list.cc dialog_layout_list.h \
                           dialog_layout_details.cc dialog_layout_details.h \
+                          dialog_layout_calendar_related.cc dialog_layout_calendar_related.h \
                           dialog_layout_list_related.cc dialog_layout_list_related.h \
                           treestore_layout.cc treestore_layout.h
 endif

Modified: trunk/glom/mode_data/box_data_calendar_related.cc
==============================================================================
--- trunk/glom/mode_data/box_data_calendar_related.cc	(original)
+++ trunk/glom/mode_data/box_data_calendar_related.cc	Mon Apr 21 15:45:40 2008
@@ -18,8 +18,9 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include "box_data_list_related.h"
-#include "dialog_layout_list_related.h"
+#include "box_data_calendar_related.h"
+#include "dialog_layout_calendar_related.h"
+#include <glom/application.h>
 #include <glom/libglom/data_structure/glomconversions.h>
 #include <glom/frame_glom.h> //For show_ok_dialog()
 #include <bakery/App/App_Gtk.h> //For util_bold_message().
@@ -28,37 +29,32 @@
 namespace Glom
 {
 
-Box_Data_List_Related::Box_Data_List_Related()
+Box_Data_Calendar_Related::Box_Data_Calendar_Related()
+: m_pMenuPopup(0)
 {
   set_size_request(400, -1); //An arbitrary default.
 
-  //m_Frame.set_label_widget(m_Label_Related);
-  m_Frame.set_shadow_type(Gtk::SHADOW_NONE);
-
-  m_Frame.add(m_Alignment);
-  m_Frame.show();
-
-  m_Frame.set_label_widget(m_Label);
-  m_Label.show();
-
-  m_Alignment.set_padding(Utils::DEFAULT_SPACING_SMALL /* top */, 0, Utils::DEFAULT_SPACING_LARGE /* left */, 0);
-  m_Alignment.show();
-
-  remove(m_AddDel);
-  m_Alignment.add(m_AddDel);
-  m_AddDel.show();
-  add(m_Frame);
+  remove(m_AddDel); //TODO: Don't even have this at all.
+  m_Alignment.add(m_calendar);
+  m_calendar.show();
+  
+  //Tell the calendar how to get the record details to show:
+  m_calendar.set_detail_func( sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_calendar_details) );
+  
+  setup_menu();
+  //m_calendar.add_events(Gdk::BUTTON_PRESS_MASK); //Allow us to catch button_press_event and button_release_event
+  m_calendar.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_calendar_button_press_event) );
 
-  m_layout_name = "list_related"; //TODO: We need a unique name when 2 portals use the same table.
+  m_layout_name = "list_related_calendar"; //TODO: We need a unique name when 2 portals use the same table.
 }
 
-void Box_Data_List_Related::enable_buttons()
+void Box_Data_Calendar_Related::enable_buttons()
 {
-  const bool view_details_possible = get_has_suitable_record_to_view_details();
-  m_AddDel.set_allow_view_details(view_details_possible); //Don't allow the user to go to a record in a hidden table.
+  //const bool view_details_possible = get_has_suitable_record_to_view_details();
+  //m_calendar.set_allow_view_details(view_details_possible); //Don't allow the user to go to a record in a hidden table.
 }
 
-bool Box_Data_List_Related::init_db_details(const sharedptr<const LayoutItem_Portal>& portal, bool show_title)
+bool Box_Data_Calendar_Related::init_db_details(const sharedptr<const LayoutItem_CalendarPortal>& portal, bool show_title)
 {
   m_portal = glom_sharedptr_clone(portal);
 
@@ -91,10 +87,20 @@
   return Box_Data_List::init_db_details(found_set); //Calls create_layout() and fill_from_database().
 }
 
-bool Box_Data_List_Related::refresh_data_from_database_with_foreign_key(const Gnome::Gda::Value& foreign_key_value)
+bool Box_Data_Calendar_Related::refresh_data_from_database_with_foreign_key(const Gnome::Gda::Value& foreign_key_value)
 {
+  std::cout << "DEBUG: Box_Data_Calendar_Related::refresh_data_from_database_with_foreign_key()" << std::endl;
+  
+  
   m_key_value = foreign_key_value;
 
+  if(!m_key_field)
+    std::cout << "DEBUG: Box_Data_Calendar_Related::refresh_data_from_database_with_foreign_key(): m_key_field is NULL" << std::endl;
+  
+  if(Conversions::value_is_empty(m_key_value))
+    std::cout << "DEBUG: Box_Data_Calendar_Related::refresh_data_from_database_with_foreign_key(): m_key_value is empty." << std::endl;
+  
+  
   if(m_key_field)
   {
     if(!Conversions::value_is_empty(m_key_value))
@@ -108,8 +114,7 @@
       Glib::ustring where_clause_to_table_name = relationship->get_to_table();
       sharedptr<Field> where_clause_to_key_field = m_key_field;
 
-      FoundSet found_set = m_found_set;
-      found_set.m_table_name = m_portal->get_table_used(Glib::ustring() /* parent table - not relevant */);
+      m_found_set.m_table_name = m_portal->get_table_used(Glib::ustring() /* parent table - not relevant */);
       
       sharedptr<const Relationship> relationship_related = m_portal->get_related_relationship();
       if(relationship_related)
@@ -118,44 +123,42 @@
          sharedptr<UsesRelationship> uses_rel_temp = sharedptr<UsesRelationship>::create();
          uses_rel_temp->set_relationship(relationship);
          //found_set.m_extra_join = uses_rel_temp->get_sql_join_alias_definition();
-         found_set.m_extra_join = "LEFT OUTER JOIN \"" + relationship->get_to_table() + "\" AS \"" + uses_rel_temp->get_sql_join_alias_name() + "\" ON (\"" + uses_rel_temp->get_sql_join_alias_name() + "\".\"" + relationship_related->get_from_field() + "\" = \"" + relationship_related->get_to_table() + "\".\"" + relationship_related->get_to_field() + "\")";
+         m_found_set.m_extra_join = "LEFT OUTER JOIN \"" + relationship->get_to_table() + "\" AS \"" + uses_rel_temp->get_sql_join_alias_name() + "\" ON (\"" + uses_rel_temp->get_sql_join_alias_name() + "\".\"" + relationship_related->get_from_field() + "\" = \"" + relationship_related->get_to_table() + "\".\"" + relationship_related->get_to_field() + "\")";
 
          //Add an extra GROUP BY to ensure that we get no repeated records from the doubly-related table:
-         found_set.m_extra_group_by = "GROUP BY \"" + found_set.m_table_name + "\".\"" + m_key_field->get_name() + "\"";
+         m_found_set.m_extra_group_by = "GROUP BY \"" + m_found_set.m_table_name + "\".\"" + m_key_field->get_name() + "\"";
 
          //Adjust the WHERE clause appropriately for the extra JOIN:
          where_clause_to_table_name = uses_rel_temp->get_sql_join_alias_name();
 
-         Glib::ustring to_field_name = uses_rel_temp->get_to_field_used();
+         const Glib::ustring to_field_name = uses_rel_temp->get_to_field_used();
          where_clause_to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), to_field_name);
          //std::cout << "extra_join=" << found_set.m_extra_join << std::endl;
  
          //std::cout << "extra_join where_clause_to_key_field=" << where_clause_to_key_field->get_name() << std::endl;
       }
 
-      found_set.m_where_clause = "\"" + where_clause_to_table_name + "\".\"" + relationship->get_to_field() + "\" = " + where_clause_to_key_field->sql(m_key_value);
-
-
-      //g_warning("refresh_data_from_database(): where_clause=%s", where_clause.c_str());
-      return Box_Data_List::refresh_data_from_database_with_where_clause(found_set);
+      m_found_set.m_where_clause = "\"" + where_clause_to_table_name + "\".\"" + relationship->get_to_field() + "\" = " + where_clause_to_key_field->sql(m_key_value);
+      return true;
     }
     else
     {
       //If there is no from key value then no records can be shown:
-      refresh_data_from_database_blank();
+      //TODO
       return true;
     }
   }
   else
   {
     //If there is no to field then this relationship specifies all records in the table.
-    FoundSet found_set = m_found_set;
-    found_set.m_where_clause = Glib::ustring();
-    return Box_Data_List::refresh_data_from_database_with_where_clause(found_set);
+    m_found_set.m_where_clause = Glib::ustring();
+    return true;
   }
+  
+  //The actual data is retrieved in the detail_func handler.
 }
 
-bool Box_Data_List_Related::fill_from_database()
+bool Box_Data_Calendar_Related::fill_from_database()
 {
   bool result = false;
   bool allow_add = true;
@@ -192,12 +195,12 @@
   if(allow_add && m_portal->get_relationship())
     allow_add = m_portal->get_relationship()->get_auto_create();
 
-  m_AddDel.set_allow_add(allow_add);
+  //TODO: m_calendar.set_allow_add(allow_add);
 
   return result;
 }
 
-void Box_Data_List_Related::on_record_added(const Gnome::Gda::Value& primary_key_value, const Gtk::TreeModel::iterator& row)
+void Box_Data_Calendar_Related::on_record_added(const Gnome::Gda::Value& primary_key_value, const Gtk::TreeModel::iterator& row)
 {
   //primary_key_value is a new autogenerated or human-entered key for the row.
   //It has already been added to the database.
@@ -212,7 +215,7 @@
     //m_key_field is the field in this table that must match another field in the parent table.
     sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
     layout_item->set_full_field_details(m_key_field);
-    key_value = m_AddDel.get_value(row, layout_item);
+    //TODO: key_value = m_calendar.get_value(row, layout_item);
   }
 
   Box_Data_List::on_record_added(key_value, row); //adds blank row.
@@ -227,11 +230,11 @@
   }
   else if(Conversions::value_is_empty(m_key_value))
   {
-    g_warning("Box_Data_List_Related::on_record_added(): m_key_value is NULL.");
+    g_warning("Box_Data_Calendar_Related::on_record_added(): m_key_value is NULL.");
   }
   else
   {
-    sharedptr<Field> field_primary_key = m_AddDel.get_key_field();
+    sharedptr<Field> field_primary_key; //TODO: = m_calendar.get_key_field();
 
     //Create the link by setting the foreign key
     if(m_key_field)
@@ -246,7 +249,7 @@
         sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
         layout_item->set_full_field_details(field_primary_key);
 
-        m_AddDel.set_value(row, layout_item, m_key_value);
+        //TODO: m_calendar.set_value(row, layout_item, m_key_value);
       }
     }
 
@@ -254,77 +257,13 @@
   }
 }
 
-sharedptr<LayoutItem_Portal> Box_Data_List_Related::get_portal() const
-{
-  return m_portal;
-}
-
-sharedptr<const Field> Box_Data_List_Related::get_key_field() const
-{
-  return m_key_field;
-}
-
-void Box_Data_List_Related::on_record_deleted(const Gnome::Gda::Value& /* primary_key_value */)
+void Box_Data_Calendar_Related::on_record_deleted(const Gnome::Gda::Value& /* primary_key_value */)
 {
   //Allow the parent record (Details view) to recalculate aggregations:
   signal_record_changed().emit(m_portal->get_relationship_name());
 }
 
-
-void Box_Data_List_Related::on_adddel_user_changed(const Gtk::TreeModel::iterator& row, guint col)
-{
-  if(!(m_portal->get_relationship_used_allows_edit()))
-  {
-    std::cerr << "Box_Data_List_Related::on_adddel_user_added() called on non-editable portal. This should not happen." << std::endl;
-   return;
-  }
-
-  //Call base class:
-  Box_Data_List::on_adddel_user_changed(row, col);
-
-  //Let parent respond:
-  if(row)
-    signal_record_changed().emit(m_portal->get_relationship_name());
-}
-
-void Box_Data_List_Related::on_adddel_user_added(const Gtk::TreeModel::iterator& row, guint col_with_first_value)
-{
-  if(!m_portal->get_relationship_used_allows_edit())
-  {
-    std::cerr << "Box_Data_List_Related::on_adddel_user_added() called on non-editable portal. This should not happen." << std::endl;
-   return;
-  }
-
-  //Like Box_Data_List::on_adddel_user_added(),
-  //but it doesn't allow adding if the new record cannot be a related record.
-  //This would happen if there is already one related record and the relationship uses the primary key in the related record.
-
-  bool bAllowAdd = true;
-
-  if(m_key_field && (m_key_field->get_unique_key() || m_key_field->get_primary_key()))
-  {
-    if(m_AddDel.get_count() > 0) //If there is already 1 record
-      bAllowAdd = false;
-  }
-
-  if(bAllowAdd)
-  {
-    Box_Data_List::on_adddel_user_added(row, col_with_first_value);
-  }
-  else
-  {
-    //Tell user that they can't do that:
-    Gtk::MessageDialog dialog(Bakery::App_Gtk::util_bold_message(_("Extra related records not possible.")), true, Gtk::MESSAGE_WARNING);
-    dialog.set_secondary_text(_("You attempted to add a new related record, but there can only be one related record, because the relationship uses a unique key.")),
-    dialog.set_transient_for(*get_app_window());
-    dialog.run();
-
-    //Replace with correct values:
-    fill_from_database();
-  }
-}
-
-Box_Data_List_Related::type_vecLayoutFields Box_Data_List_Related::get_fields_to_show() const
+Box_Data_Calendar_Related::type_vecLayoutFields Box_Data_Calendar_Related::get_fields_to_show() const
 {
   const Document_Glom* document = get_document();
   if(document)
@@ -355,45 +294,34 @@
   return type_vecLayoutFields();
 }
 
-Box_Data_List_Related::type_signal_record_changed Box_Data_List_Related::signal_record_changed()
-{
-  return m_signal_record_changed;
-}
-
 #ifndef GLOM_ENABLE_CLIENT_ONLY
-void Box_Data_List_Related::on_dialog_layout_hide()
+void Box_Data_Calendar_Related::on_dialog_layout_hide()
 {
-  Dialog_Layout_List_Related* dialog_related = dynamic_cast<Dialog_Layout_List_Related*>(m_pDialogLayout);
+  Dialog_Layout_Calendar_Related* dialog_related = dynamic_cast<Dialog_Layout_Calendar_Related*>(m_pDialogLayout);
   g_assert(dialog_related != NULL);
   m_portal = dialog_related->get_portal_layout();
 
 
   //Update the UI:
-  init_db_details(m_portal); 
+  sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
+  init_db_details(derived_portal); 
 
   Box_Data::on_dialog_layout_hide();
 
-  sharedptr<LayoutItem_Portal> pLayoutItem = sharedptr<LayoutItem_Portal>::cast_dynamic(get_layout_item());
+  sharedptr<LayoutItem_CalendarPortal> pLayoutItem = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(get_layout_item());
   if(pLayoutItem)
   {
-    *pLayoutItem = *m_portal;
+    sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
+    if(derived_portal)
+      *pLayoutItem = *derived_portal;
+    
     signal_layout_changed().emit(); //TODO: Check whether it has really changed.
   }
 }
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
-void Box_Data_List_Related::on_adddel_user_requested_add()
-{
-  //Prevent an add on a portal with no fields:
-  //TODO: Warn the user instead of just doing nothing.
-  if(!m_portal->m_list_items.empty())
-    Box_Data_List::on_adddel_user_requested_add();
-}
-
-
 
-
-bool Box_Data_List_Related::get_has_suitable_record_to_view_details() const
+bool Box_Data_Calendar_Related::get_has_suitable_record_to_view_details() const
 {
   Glib::ustring navigation_table_name;
   sharedptr<const UsesRelationship> navigation_relationship;
@@ -402,7 +330,7 @@
   return !(navigation_table_name.empty());
 }
 
-void Box_Data_List_Related::get_suitable_table_to_view_details(Glib::ustring& table_name, sharedptr<const UsesRelationship>& relationship) const
+void Box_Data_Calendar_Related::get_suitable_table_to_view_details(Glib::ustring& table_name, sharedptr<const UsesRelationship>& relationship) const
 {
  
   //Initialize output parameters:
@@ -442,13 +370,13 @@
 
   if(navigation_table_name.empty())
   {
-    std::cerr << "Box_Data_List_Related::get_suitable_table_to_view_details(): navigation_table_name is empty." << std::endl;
+    std::cerr << "Box_Data_Calendar_Related::get_suitable_table_to_view_details(): navigation_table_name is empty." << std::endl;
     return;
   }
 
   if(document->get_table_is_hidden(navigation_table_name))
   {
-    std::cerr << "Box_Data_List_Related::get_suitable_table_to_view_details(): navigation_table_name indicates a hidden table: " << navigation_table_name << std::endl;
+    std::cerr << "Box_Data_Calendar_Related::get_suitable_table_to_view_details(): navigation_table_name indicates a hidden table: " << navigation_table_name << std::endl;
     return;
   }
 
@@ -456,7 +384,7 @@
   relationship = navigation_relationship;
 }
 
-void Box_Data_List_Related::get_suitable_record_to_view_details(const Gnome::Gda::Value& primary_key_value, Glib::ustring& table_name, Gnome::Gda::Value& table_primary_key_value) const
+void Box_Data_Calendar_Related::get_suitable_record_to_view_details(const Gnome::Gda::Value& primary_key_value, Glib::ustring& table_name, Gnome::Gda::Value& table_primary_key_value) const
 {
   //Initialize output parameters:
   table_name = Glib::ustring();
@@ -487,7 +415,7 @@
   type_vecLayoutFields fieldsToGet;
   fieldsToGet.push_back(layout_item);
 
-  const Glib::ustring query = Utils::build_sql_select_with_key(m_portal->get_table_used(Glib::ustring() /* not relevant */), fieldsToGet, m_AddDel.get_key_field(), primary_key_value);
+  const Glib::ustring query; //TODO: = Utils::build_sql_select_with_key(m_portal->get_table_used(Glib::ustring() /* not relevant */), fieldsToGet, m_calendar.get_key_field(), primary_key_value);
   Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute(query);
 
 
@@ -498,20 +426,20 @@
     table_name = navigation_table_name;
     table_primary_key_value = data_model->get_value_at(0, 0);
 
-    //std::cout << "Box_Data_List_Related::get_suitable_record_to_view_details(): table_primary_key_value=" << table_primary_key_value.to_string() << std::endl;
+    //std::cout << "Box_Data_Calendar_Related::get_suitable_record_to_view_details(): table_primary_key_value=" << table_primary_key_value.to_string() << std::endl;
 
     //The value is empty when there there is no record to match the key in the related table:
     //For instance, if an invoice lines record mentions a product id, but the product does not exist in the products table.
     if(Conversions::value_is_empty(table_primary_key_value))
     {
       value_found = false;
-      std::cout << "debug: Box_Data_List_Related::get_suitable_record_to_view_details(): SQL query returned empty primary key." << std::endl;
+      std::cout << "debug: Box_Data_Calendar_Related::get_suitable_record_to_view_details(): SQL query returned empty primary key." << std::endl;
     }
   }
   else
   {
     value_found = false;
-    std::cout << "debug: Box_Data_List_Related::get_suitable_record_to_view_details(): SQL query returned no suitable primary key." << std::endl;
+    std::cout << "debug: Box_Data_Calendar_Related::get_suitable_record_to_view_details(): SQL query returned no suitable primary key." << std::endl;
   }
 
   if(!value_found)
@@ -526,7 +454,7 @@
   }
 }
 
-Document_Glom::type_list_layout_groups Box_Data_List_Related::create_layout_get_layout()
+Document_Glom::type_list_layout_groups Box_Data_Calendar_Related::create_layout_get_layout()
 {
   Document_Glom::type_list_layout_groups result;
 
@@ -536,27 +464,237 @@
   return result;
 }
 
-Dialog_Layout* Box_Data_List_Related::create_layout_dialog() const
+Dialog_Layout* Box_Data_Calendar_Related::create_layout_dialog() const
 {
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   Glib::RefPtr<Gnome::Glade::Xml> refXml = Gnome::Glade::Xml::create(GLOM_GLADEDIR "glom_developer.glade", "window_data_layout");
   if(refXml)
   {
-    Dialog_Layout_List_Related* dialog = 0;
+    Dialog_Layout_Calendar_Related* dialog = 0;
     refXml->get_widget_derived("window_data_layout", dialog);
     return dialog;
+  }
+#endif // !GLOM_ENABLE_CLIENT_ONLY
+
+  return NULL;
+}
+
+void Box_Data_Calendar_Related::prepare_layout_dialog(Dialog_Layout* dialog)
+{
+  Dialog_Layout_Calendar_Related* related_dialog = dynamic_cast<Dialog_Layout_Calendar_Related*>(dialog);
+  g_assert(related_dialog != NULL);
+  
+  sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
+  related_dialog->set_document(m_layout_name, get_document(), derived_portal);
+}
+
+Glib::ustring Box_Data_Calendar_Related::on_calendar_details(guint year, guint month, guint day)
+{
+  sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
+    
+  
+  if(!derived_portal || !derived_portal->get_date_field())
+  {
+    std::cout << "DEBUG: Box_Data_Calendar_Related::on_calendar_details(): date_field is NULL" << std::endl;
+    return Glib::ustring();
+  }
+  
+  Glib::Date date(day, Glib::Date::Month(month+1), year);
+  Gnome::Gda::Value date_value(date);
+
+  sharedptr<Relationship> relationship = m_portal->get_relationship();
+  Glib::ustring where_clause_to_table_name = relationship->get_to_table();
+  
+  const Glib::ustring date_field_name = derived_portal->get_date_field()->get_name();
+    
+  sharedptr<const Relationship> relationship_related = m_portal->get_related_relationship();
+  if(relationship_related)
+  {
+    //Adjust the WHERE clause appropriately for the extra JOIN:
+    sharedptr<UsesRelationship> uses_rel_temp = sharedptr<UsesRelationship>::create();
+    uses_rel_temp->set_relationship(relationship);
+    where_clause_to_table_name = uses_rel_temp->get_sql_join_alias_name();
+  }
+
+  //Add an AND to the existing where clause, to get only records with this date, if any:
+  const Glib::ustring extra_where_clause = "\"" + where_clause_to_table_name + "\".\"" + derived_portal->get_date_field()->get_name() + "\" = " + derived_portal->get_date_field()->sql(date_value);
+  Glib::ustring where_clause;
+  if(m_found_set.m_where_clause.empty())
+    where_clause = extra_where_clause;
+  else
+    where_clause = "( " + m_found_set.m_where_clause + " ) AND ( " + extra_where_clause + " )";
+  
+  const Glib::ustring sql_query = Utils::build_sql_select_with_where_clause(m_found_set.m_table_name, m_FieldsShown, where_clause, m_found_set.m_extra_join, m_found_set.m_sort_clause, m_found_set.m_extra_group_by);
+  //std::cout << "DEBUG: sql_query=" << sql_query << std::endl;
+  Glib::RefPtr<Gnome::Gda::DataModel> datamodel = query_execute(sql_query, get_app_window());
+  if(!(datamodel && datamodel->get_n_rows()))
+    return Glib::ustring();
+ 
+  //Execute the query to get the data:
+  Glib::ustring result;
+  const int row_index = 0;
+  int column_index = 0;
+  for(type_vecLayoutFields::const_iterator iter = m_FieldsShown.begin(); iter != m_FieldsShown.end(); ++iter)
+  {
+    sharedptr<LayoutItem> layout_item = *iter;
+    
+    Glib::ustring text;
+    
+    //Text for a text item:
+    sharedptr<LayoutItem_Text> layout_item_text = sharedptr<LayoutItem_Text>::cast_dynamic(layout_item);
+    if(layout_item_text)
+      text = layout_item_text->get_text();
+    else
+    {  
+      //Text for a field:
+      sharedptr<LayoutItem_Field> layout_item_field = sharedptr<LayoutItem_Field>::cast_dynamic(layout_item);
+      if(layout_item_field)
+      {
+        const Gnome::Gda::Value value = datamodel->get_value_at(row_index, column_index);
+        text = Conversions::get_text_for_gda_value(layout_item_field->get_glom_type(), value, layout_item_field->get_formatting_used().m_numeric_format);
+        std::cout << "  DEBUG: text=" << text << std::endl;
+        ++column_index;
+      }
+    }
+    
+    if(!text.empty())
+    {
+      if(!result.empty())
+          result += ", "; //TODO: Internationalization?
+      
+      result += text;
     }
   }
   
-  return NULL;
+  return result;
+}
+
+void Box_Data_Calendar_Related::setup_menu()
+{
+  m_refActionGroup = Gtk::ActionGroup::create();
+
+  m_refActionGroup->add(Gtk::Action::create("ContextMenu", "Context Menu") );
+
+  m_refContextEdit =  Gtk::Action::create("ContextEdit", Gtk::Stock::EDIT);
+
+  m_refActionGroup->add(m_refContextEdit,
+    sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_MenuPopup_activate_Edit) );
+
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+  // Don't add ContextLayout in client only mode because it would never
+  // be sensitive anyway
+  m_refContextLayout =  Gtk::Action::create("ContextLayout", _("Layout"));
+  m_refActionGroup->add(m_refContextLayout,
+    sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_MenuPopup_activate_layout) );
+
+  //TODO: This does not work until this widget is in a container in the window:
+  App_Glom* pApp = get_application();
+  if(pApp)
+  {
+    pApp->add_developer_action(m_refContextLayout); //So that it can be disabled when not in developer mode.
+    pApp->update_userlevel_ui(); //Update our action's sensitivity. 
+  }
+#endif // !GLOM_ENABLE_CLIENT_ONLY
+
+  m_refUIManager = Gtk::UIManager::create();
+
+  m_refUIManager->insert_action_group(m_refActionGroup);
+
+  //TODO: add_accel_group(m_refUIManager->get_accel_group());
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+  try
+  {
+#endif
+    Glib::ustring ui_info = 
+        "<ui>"
+        "  <popup name='ContextMenu'>"
+        "    <menuitem action='ContextEdit'/>"
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+        "    <menuitem action='ContextLayout'/>"
+#endif
+        "  </popup>"
+        "</ui>";
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+    m_refUIManager->add_ui_from_string(ui_info);
+  }
+  catch(const Glib::Error& ex)
+  {
+    std::cerr << "building menus failed: " <<  ex.what();
+  }
+#else
+  std::auto_ptr<Glib::Error> error;
+  m_refUIManager->add_ui_from_string(ui_info, error);
+  if(error.get() != NULL)
+  {
+    std::cerr << "building menus failed: " << error->what();
+  }
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+
+  //Get the menu:
+  m_pMenuPopup = dynamic_cast<Gtk::Menu*>( m_refUIManager->get_widget("/ContextMenu") ); 
+  if(!m_pMenuPopup)
+    g_warning("menu not found");
+
+ 
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+  if(pApp)
+    m_refContextLayout->set_sensitive(pApp->get_userlevel() == AppState::USERLEVEL_DEVELOPER);
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 }
 
-void prepare_layout_dialog(Dialog_Layout* dialog)
+void Box_Data_Calendar_Related::on_calendar_button_press_event(GdkEventButton *event)
 {
-  Dialog_Layout_List_Related* related_dialog = dynamic_cast<Dialog_Layout_List_Related*>(dialog);
-  g_assert(related_dialog != NULL);
-  related_dialog->set_document(m_layout_name, get_document(), m_portal);
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+  //Enable/Disable items.
+  //We did this earlier, but get_application is more likely to work now:
+  App_Glom* pApp = get_application();
+  if(pApp)
+  {
+    pApp->add_developer_action(m_refContextLayout); //So that it can be disabled when not in developer mode.
+    pApp->update_userlevel_ui(); //Update our action's sensitivity. 
+  }
+#endif
+
+  GdkModifierType mods;
+  gdk_window_get_pointer( Gtk::Widget::gobj()->window, 0, 0, &mods );
+  if(mods & GDK_BUTTON3_MASK)
+  {
+    //Give user choices of actions on this item:
+    m_pMenuPopup->popup(event->button, event->time);
+    return; //handled.
+  }
+  else
+  {
+    if(event->type == GDK_2BUTTON_PRESS)
+    {
+      //Double-click means edit.
+      //Don't do this usually, because users sometimes double-click by accident when they just want to edit a cell.
+
+      //TODO: If the cell is not editable, handle the double-click as an edit/selection.
+      //on_MenuPopup_activate_Edit();
+      return; //Not handled.
+    }
+  }
+
+  return; //Not handled. TODO: Call base class?
+}
+
+void
+Box_Data_Calendar_Related::on_MenuPopup_activate_Edit()
+{
+  const Gnome::Gda::Value primary_key_value; //TODO: = m_AddDel.get_value_key(row); //The primary key is in the key.
+
+  signal_user_requested_details().emit(primary_key_value);
+}
+
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+void Box_Data_Calendar_Related::on_MenuPopup_activate_layout()
+{
+  show_layout_dialog();
 }
+#endif // !GLOM_ENABLE_CLIENT_ONLY
+
 
 } //namespace Glom

Modified: trunk/glom/mode_data/box_data_calendar_related.h
==============================================================================
--- trunk/glom/mode_data/box_data_calendar_related.h	(original)
+++ trunk/glom/mode_data/box_data_calendar_related.h	Mon Apr 21 15:45:40 2008
@@ -18,30 +18,30 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#ifndef BOX_DATA_LIST_RELATED_H
-#define BOX_DATA_LIST_RELATED_H
+#ifndef BOX_DATA_CALENDAR_RELATED_H
+#define BOX_DATA_CALENDAR_RELATED_H
 
 #include "config.h" // GLOM_ENABLE_CLIENT_ONLY
 
-#include "box_data_list.h"
+#include "box_data_portal.h"
+#include <glom/libglom/data_structure/layout/layoutitem_calendarportal.h>
 #include "../utility_widgets/layoutwidgetbase.h"
+#include "../utility_widgets/calendar/glomcalendar.h"
 
 namespace Glom
 {
 
-class Dialog_Layout_List_Related;
+class Dialog_Layout_Calendar_Related;
 
-class Box_Data_List_Related : 
-  public Box_Data_List,
-  public LayoutWidgetBase
+class Box_Data_Calendar_Related : public Box_Data_Portal
 {
 public: 
-  Box_Data_List_Related();
+  Box_Data_Calendar_Related();
 
   /**
    * @param portal: The full portal details
    */
-  virtual bool init_db_details(const sharedptr<const LayoutItem_Portal>& portal, bool show_title = true);
+    virtual bool init_db_details(const sharedptr<const LayoutItem_CalendarPortal>& portal, bool show_title = true);
 
   /**
    * @param foreign_key_value: The value that should be found in this table.
@@ -49,26 +49,14 @@
    */
   virtual bool refresh_data_from_database_with_foreign_key(const Gnome::Gda::Value& foreign_key_value);
 
-  sharedptr<LayoutItem_Portal> get_portal() const;
-  virtual sharedptr<const Field> get_key_field() const;
-
-  sigc::signal<void, Gnome::Gda::Value> signal_record_added;
-
   bool get_has_suitable_record_to_view_details() const;
   void get_suitable_table_to_view_details(Glib::ustring& table_name, sharedptr<const UsesRelationship>& relationship) const;
   void get_suitable_record_to_view_details(const Gnome::Gda::Value& primary_key_value, Glib::ustring& table_name, Gnome::Gda::Value& table_primary_key_value) const;
 
-  ///@param relationship_name
-  typedef sigc::signal<void, const Glib::ustring&> type_signal_record_changed;
-  type_signal_record_changed signal_record_changed();
-
 protected:
   virtual bool fill_from_database(); //Override.
   virtual type_vecLayoutFields get_fields_to_show() const; //override
 
-  virtual void on_adddel_user_requested_add();
-  virtual void on_adddel_user_changed(const Gtk::TreeModel::iterator& row, guint col);
-  virtual void on_adddel_user_added(const Gtk::TreeModel::iterator& row, guint col_with_first_value); //Override.
   virtual void on_record_added(const Gnome::Gda::Value& primary_key_value, const Gtk::TreeModel::iterator& row); //Override. Not a signal handler.
   virtual void on_record_deleted(const Gnome::Gda::Value& primary_key_value); //override.
 
@@ -83,16 +71,33 @@
   virtual void prepare_layout_dialog(Dialog_Layout* dialog); // override.
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
+  Glib::ustring on_calendar_details(guint year, guint month, guint day);
+    
+  void setup_menu();
+  void on_calendar_button_press_event(GdkEventButton *event);
+ 
+  void on_MenuPopup_activate_Edit();
+  void on_MenuPopup_activate_Add();
+  void on_MenuPopup_activate_Delete();
+    
+  #ifndef GLOM_ENABLE_CLIENT_ONLY
+  void on_MenuPopup_activate_layout();
+  #endif
+    
 protected:
   virtual Document_Glom::type_list_layout_groups create_layout_get_layout(); //override.
 
-  Gtk::Frame m_Frame;
-  Gtk::Alignment m_Alignment;
-  Gtk::Label m_Label;
-
-  sharedptr<LayoutItem_Portal> m_portal;
-  sharedptr<Field> m_key_field;
-  Gnome::Gda::Value m_key_value;
+  GlomGtk::Calendar m_calendar;
+    
+  //TODO: Avoid repeating these in so many widgets:
+  Gtk::Menu* m_pMenuPopup;
+  Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup;
+  Glib::RefPtr<Gtk::UIManager> m_refUIManager;
+  Glib::RefPtr<Gtk::Action> m_refContextEdit, m_refContextAdd, m_refContextDelete;
+
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+  Glib::RefPtr<Gtk::Action> m_refContextLayout;
+#endif
 
   type_signal_record_changed m_signal_record_changed;
 };

Modified: trunk/glom/mode_data/box_data_list_related.cc
==============================================================================
--- trunk/glom/mode_data/box_data_list_related.cc	(original)
+++ trunk/glom/mode_data/box_data_list_related.cc	Mon Apr 21 15:45:40 2008
@@ -33,22 +33,9 @@
 {
   set_size_request(400, -1); //An arbitrary default.
 
-  //m_Frame.set_label_widget(m_Label_Related);
-  m_Frame.set_shadow_type(Gtk::SHADOW_NONE);
-
-  m_Frame.add(m_Alignment);
-  m_Frame.show();
-
-  m_Frame.set_label_widget(m_Label);
-  m_Label.show();
-
-  m_Alignment.set_padding(Utils::DEFAULT_SPACING_SMALL /* top */, 0, Utils::DEFAULT_SPACING_LARGE /* left */, 0);
-  m_Alignment.show();
 
   remove(m_AddDel);
   m_Alignment.add(m_AddDel);
-  m_AddDel.show();
-  add(m_Frame);
 
   m_layout_name = "list_related"; //TODO: We need a unique name when 2 portals use the same table.
 }
@@ -255,16 +242,6 @@
   }
 }
 
-sharedptr<LayoutItem_Portal> Box_Data_List_Related::get_portal() const
-{
-  return m_portal;
-}
-
-sharedptr<const Field> Box_Data_List_Related::get_key_field() const
-{
-  return m_key_field;
-}
-
 void Box_Data_List_Related::on_record_deleted(const Gnome::Gda::Value& /* primary_key_value */)
 {
   //Allow the parent record (Details view) to recalculate aggregations:
@@ -356,11 +333,6 @@
   return type_vecLayoutFields();
 }
 
-Box_Data_List_Related::type_signal_record_changed Box_Data_List_Related::signal_record_changed()
-{
-  return m_signal_record_changed;
-}
-
 #ifndef GLOM_ENABLE_CLIENT_ONLY
 void Box_Data_List_Related::on_dialog_layout_hide()
 {

Modified: trunk/glom/mode_data/box_data_list_related.h
==============================================================================
--- trunk/glom/mode_data/box_data_list_related.h	(original)
+++ trunk/glom/mode_data/box_data_list_related.h	Mon Apr 21 15:45:40 2008
@@ -23,17 +23,14 @@
 
 #include "config.h" // GLOM_ENABLE_CLIENT_ONLY
 
-#include "box_data_list.h"
-#include "../utility_widgets/layoutwidgetbase.h"
+#include "box_data_portal.h"
 
 namespace Glom
 {
 
 class Dialog_Layout_List_Related;
 
-class Box_Data_List_Related : 
-  public Box_Data_List,
-  public LayoutWidgetBase
+class Box_Data_List_Related : public Box_Data_Portal
 {
 public: 
   Box_Data_List_Related();
@@ -49,18 +46,10 @@
    */
   virtual bool refresh_data_from_database_with_foreign_key(const Gnome::Gda::Value& foreign_key_value);
 
-  sharedptr<LayoutItem_Portal> get_portal() const;
-  virtual sharedptr<const Field> get_key_field() const;
-
-  sigc::signal<void, Gnome::Gda::Value> signal_record_added;
-
   bool get_has_suitable_record_to_view_details() const;
   void get_suitable_table_to_view_details(Glib::ustring& table_name, sharedptr<const UsesRelationship>& relationship) const;
   void get_suitable_record_to_view_details(const Gnome::Gda::Value& primary_key_value, Glib::ustring& table_name, Gnome::Gda::Value& table_primary_key_value) const;
 
-  ///@param relationship_name
-  typedef sigc::signal<void, const Glib::ustring&> type_signal_record_changed;
-  type_signal_record_changed signal_record_changed();
 
 protected:
   virtual bool fill_from_database(); //Override.
@@ -85,16 +74,6 @@
 
 protected:
   virtual Document_Glom::type_list_layout_groups create_layout_get_layout(); //override.
-
-  Gtk::Frame m_Frame;
-  Gtk::Alignment m_Alignment;
-  Gtk::Label m_Label;
-
-  sharedptr<LayoutItem_Portal> m_portal;
-  sharedptr<Field> m_key_field;
-  Gnome::Gda::Value m_key_value;
-
-  type_signal_record_changed m_signal_record_changed;
 };
 
 } //namespace Glom

Copied: trunk/glom/mode_data/box_data_portal.cc (from r1579, /trunk/glom/mode_data/box_data_list_related.cc)
==============================================================================
--- /trunk/glom/mode_data/box_data_list_related.cc	(original)
+++ trunk/glom/mode_data/box_data_portal.cc	Mon Apr 21 15:45:40 2008
@@ -18,8 +18,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include "box_data_list_related.h"
-#include "dialog_layout_list_related.h"
+#include "box_data_portal.h"
 #include <glom/libglom/data_structure/glomconversions.h>
 #include <glom/libglom/glade_utils.h>
 #include <glom/frame_glom.h> //For show_ok_dialog()
@@ -29,7 +28,7 @@
 namespace Glom
 {
 
-Box_Data_List_Related::Box_Data_List_Related()
+Box_Data_Portal::Box_Data_Portal()
 {
   set_size_request(400, -1); //An arbitrary default.
 
@@ -42,24 +41,17 @@
   m_Frame.set_label_widget(m_Label);
   m_Label.show();
 
+  //The AddDel or Calendar is added to this:
   m_Alignment.set_padding(Utils::DEFAULT_SPACING_SMALL /* top */, 0, Utils::DEFAULT_SPACING_LARGE /* left */, 0);
   m_Alignment.show();
 
-  remove(m_AddDel);
-  m_Alignment.add(m_AddDel);
-  m_AddDel.show();
   add(m_Frame);
 
-  m_layout_name = "list_related"; //TODO: We need a unique name when 2 portals use the same table.
+  m_layout_name = "list_portal"; //Replaced by derived classes.
 }
 
-void Box_Data_List_Related::enable_buttons()
-{
-  const bool view_details_possible = get_has_suitable_record_to_view_details();
-  m_AddDel.set_allow_view_details(view_details_possible); //Don't allow the user to go to a record in a hidden table.
-}
 
-bool Box_Data_List_Related::init_db_details(const sharedptr<const LayoutItem_Portal>& portal, bool show_title)
+bool Box_Data_Portal::init_db_details(const sharedptr<const LayoutItem_Portal>& portal, bool show_title)
 {
   m_portal = glom_sharedptr_clone(portal);
 
@@ -92,7 +84,7 @@
   return Box_Data_List::init_db_details(found_set); //Calls create_layout() and fill_from_database().
 }
 
-bool Box_Data_List_Related::refresh_data_from_database_with_foreign_key(const Gnome::Gda::Value& foreign_key_value)
+bool Box_Data_Portal::refresh_data_from_database_with_foreign_key(const Gnome::Gda::Value& foreign_key_value)
 {
   m_key_value = foreign_key_value;
 
@@ -156,176 +148,23 @@
   }
 }
 
-bool Box_Data_List_Related::fill_from_database()
-{
-  bool result = false;
-  bool allow_add = true;
-
-  if(m_key_field && m_found_set.m_where_clause.empty()) //There's a key field, but no value.
-  {
-    //No Foreign Key value, so just show the field names:
-
-    result = Box_DB_Table::fill_from_database();
-
-    //create_layout();
-
-    fill_end();
-  }
-  else
-  {
-    result = Box_Data_List::fill_from_database();
-
-
-    //Is there already one record here?
-    if(m_has_one_or_more_records) //This was set by Box_Data_List::fill_from_database().
-    {
-      //Is the to_field unique? If so, there can not be more than one.
-      if(m_key_field && m_key_field->get_unique_key()) //automatically true if it is a primary key
-        allow_add = false;
-    }
-
-    //TODO: Disable add if the from_field already has a value and the to_field is auto-incrementing because
-    //- we cannot override the auto-increment in the to_field.
-    //- we cannot change the value in the from_field to the new auto_increment value in the to_field.
-  }
-
-  //Prevent addition of new records if that is what the relationship specifies:
-  if(allow_add && m_portal->get_relationship())
-    allow_add = m_portal->get_relationship()->get_auto_create();
-
-  m_AddDel.set_allow_add(allow_add);
-
-  return result;
-}
-
-void Box_Data_List_Related::on_record_added(const Gnome::Gda::Value& primary_key_value, const Gtk::TreeModel::iterator& row)
-{
-  //primary_key_value is a new autogenerated or human-entered key for the row.
-  //It has already been added to the database.
-
-  if(!row)
-    return;
-
-  Gnome::Gda::Value key_value;
-
-  if(m_key_field)
-  {
-    //m_key_field is the field in this table that must match another field in the parent table.
-    sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
-    layout_item->set_full_field_details(m_key_field);
-    key_value = m_AddDel.get_value(row, layout_item);
-  }
-
-  Box_Data_List::on_record_added(key_value, row); //adds blank row.
-
-  //Make sure that the new related record is related,
-  //by setting the foreign key:
-  //If it's not auto-generated.
-  if(!Conversions::value_is_empty(key_value)) //If there is already a value.
-  {
-    //It was auto-generated. Tell the parent about it, so it can make a link.
-    signal_record_added.emit(key_value);
-  }
-  else if(Conversions::value_is_empty(m_key_value))
-  {
-    g_warning("Box_Data_List_Related::on_record_added(): m_key_value is NULL.");
-  }
-  else
-  {
-    sharedptr<Field> field_primary_key = m_AddDel.get_key_field();
-
-    //Create the link by setting the foreign key
-    if(m_key_field)
-    {
-      Glib::ustring strQuery = "UPDATE \"" + m_portal->get_table_used(Glib::ustring() /* not relevant */) + "\"";
-      strQuery += " SET \"" +  /* get_table_name() + "." +*/ m_key_field->get_name() + "\" = " + m_key_field->sql(m_key_value);
-      strQuery += " WHERE \"" + get_table_name() + "\".\"" + field_primary_key->get_name() + "\" = " + field_primary_key->sql(primary_key_value);
-      const bool test = query_execute(strQuery, get_app_window());
-      if(test)
-      {
-        //Show it on the view, if it's visible:
-        sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
-        layout_item->set_full_field_details(field_primary_key);
-
-        m_AddDel.set_value(row, layout_item, m_key_value);
-      }
-    }
-
-    //on_adddel_user_changed(row, iKey); //Update the database.
-  }
-}
-
-sharedptr<LayoutItem_Portal> Box_Data_List_Related::get_portal() const
+sharedptr<LayoutItem_Portal> Box_Data_Portal::get_portal() const
 {
   return m_portal;
 }
 
-sharedptr<const Field> Box_Data_List_Related::get_key_field() const
+sharedptr<const Field> Box_Data_Portal::get_key_field() const
 {
   return m_key_field;
 }
 
-void Box_Data_List_Related::on_record_deleted(const Gnome::Gda::Value& /* primary_key_value */)
-{
-  //Allow the parent record (Details view) to recalculate aggregations:
-  signal_record_changed().emit(m_portal->get_relationship_name());
-}
-
-
-void Box_Data_List_Related::on_adddel_user_changed(const Gtk::TreeModel::iterator& row, guint col)
-{
-  if(!(m_portal->get_relationship_used_allows_edit()))
-  {
-    std::cerr << "Box_Data_List_Related::on_adddel_user_added() called on non-editable portal. This should not happen." << std::endl;
-   return;
-  }
-
-  //Call base class:
-  Box_Data_List::on_adddel_user_changed(row, col);
-
-  //Let parent respond:
-  if(row)
-    signal_record_changed().emit(m_portal->get_relationship_name());
-}
-
-void Box_Data_List_Related::on_adddel_user_added(const Gtk::TreeModel::iterator& row, guint col_with_first_value)
-{
-  if(!m_portal->get_relationship_used_allows_edit())
-  {
-    std::cerr << "Box_Data_List_Related::on_adddel_user_added() called on non-editable portal. This should not happen." << std::endl;
-   return;
-  }
-
-  //Like Box_Data_List::on_adddel_user_added(),
-  //but it doesn't allow adding if the new record cannot be a related record.
-  //This would happen if there is already one related record and the relationship uses the primary key in the related record.
-
-  bool bAllowAdd = true;
-
-  if(m_key_field && (m_key_field->get_unique_key() || m_key_field->get_primary_key()))
-  {
-    if(m_AddDel.get_count() > 0) //If there is already 1 record
-      bAllowAdd = false;
-  }
-
-  if(bAllowAdd)
-  {
-    Box_Data_List::on_adddel_user_added(row, col_with_first_value);
-  }
-  else
-  {
-    //Tell user that they can't do that:
-    Gtk::MessageDialog dialog(Bakery::App_Gtk::util_bold_message(_("Extra related records not possible.")), true, Gtk::MESSAGE_WARNING);
-    dialog.set_secondary_text(_("You attempted to add a new related record, but there can only be one related record, because the relationship uses a unique key.")),
-    dialog.set_transient_for(*get_app_window());
-    dialog.run();
+//void Box_Data_Portal::on_record_deleted(const Gnome::Gda::Value& /* primary_key_value */)
+//{
+//  //Allow the parent record (Details view) to recalculate aggregations:
+//  signal_record_changed().emit(m_portal->get_relationship_name());
+//}
 
-    //Replace with correct values:
-    fill_from_database();
-  }
-}
-
-Box_Data_List_Related::type_vecLayoutFields Box_Data_List_Related::get_fields_to_show() const
+Box_Data_Portal::type_vecLayoutFields Box_Data_Portal::get_fields_to_show() const
 {
   const Document_Glom* document = get_document();
   if(document)
@@ -356,45 +195,21 @@
   return type_vecLayoutFields();
 }
 
-Box_Data_List_Related::type_signal_record_changed Box_Data_List_Related::signal_record_changed()
+Box_Data_Portal::type_signal_record_changed Box_Data_Portal::signal_record_changed()
 {
   return m_signal_record_changed;
 }
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
-void Box_Data_List_Related::on_dialog_layout_hide()
+void Box_Data_Portal::on_dialog_layout_hide()
 {
-  Dialog_Layout_List_Related* dialog_related = dynamic_cast<Dialog_Layout_List_Related*>(m_pDialogLayout);
-  g_assert(dialog_related != NULL);
-  m_portal = dialog_related->get_portal_layout();
-
-
-  //Update the UI:
-  init_db_details(m_portal); 
-
-  Box_Data::on_dialog_layout_hide();
-
-  sharedptr<LayoutItem_Portal> pLayoutItem = sharedptr<LayoutItem_Portal>::cast_dynamic(get_layout_item());
-  if(pLayoutItem)
-  {
-    *pLayoutItem = *m_portal;
-    signal_layout_changed().emit(); //TODO: Check whether it has really changed.
-  }
+  //Overridden in derived classes.
 }
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
-void Box_Data_List_Related::on_adddel_user_requested_add()
-{
-  //Prevent an add on a portal with no fields:
-  //TODO: Warn the user instead of just doing nothing.
-  if(!m_portal->m_list_items.empty())
-    Box_Data_List::on_adddel_user_requested_add();
-}
 
 
-
-
-bool Box_Data_List_Related::get_has_suitable_record_to_view_details() const
+bool Box_Data_Portal::get_has_suitable_record_to_view_details() const
 {
   Glib::ustring navigation_table_name;
   sharedptr<const UsesRelationship> navigation_relationship;
@@ -403,7 +218,7 @@
   return !(navigation_table_name.empty());
 }
 
-void Box_Data_List_Related::get_suitable_table_to_view_details(Glib::ustring& table_name, sharedptr<const UsesRelationship>& relationship) const
+void Box_Data_Portal::get_suitable_table_to_view_details(Glib::ustring& table_name, sharedptr<const UsesRelationship>& relationship) const
 {
  
   //Initialize output parameters:
@@ -443,13 +258,13 @@
 
   if(navigation_table_name.empty())
   {
-    std::cerr << "Box_Data_List_Related::get_suitable_table_to_view_details(): navigation_table_name is empty." << std::endl;
+    std::cerr << "Box_Data_Portal::get_suitable_table_to_view_details(): navigation_table_name is empty." << std::endl;
     return;
   }
 
   if(document->get_table_is_hidden(navigation_table_name))
   {
-    std::cerr << "Box_Data_List_Related::get_suitable_table_to_view_details(): navigation_table_name indicates a hidden table: " << navigation_table_name << std::endl;
+    std::cerr << "Box_Data_Portal::get_suitable_table_to_view_details(): navigation_table_name indicates a hidden table: " << navigation_table_name << std::endl;
     return;
   }
 
@@ -457,7 +272,7 @@
   relationship = navigation_relationship;
 }
 
-void Box_Data_List_Related::get_suitable_record_to_view_details(const Gnome::Gda::Value& primary_key_value, Glib::ustring& table_name, Gnome::Gda::Value& table_primary_key_value) const
+void Box_Data_Portal::get_suitable_record_to_view_details(const Gnome::Gda::Value& primary_key_value, Glib::ustring& table_name, Gnome::Gda::Value& table_primary_key_value) const
 {
   //Initialize output parameters:
   table_name = Glib::ustring();
@@ -488,7 +303,7 @@
   type_vecLayoutFields fieldsToGet;
   fieldsToGet.push_back(layout_item);
 
-  const Glib::ustring query = Utils::build_sql_select_with_key(m_portal->get_table_used(Glib::ustring() /* not relevant */), fieldsToGet, m_AddDel.get_key_field(), primary_key_value);
+  const Glib::ustring query = Utils::build_sql_select_with_key(m_portal->get_table_used(Glib::ustring() /* not relevant */), fieldsToGet, get_key_field(), primary_key_value);
   Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute(query);
 
 
@@ -499,20 +314,20 @@
     table_name = navigation_table_name;
     table_primary_key_value = data_model->get_value_at(0, 0);
 
-    //std::cout << "Box_Data_List_Related::get_suitable_record_to_view_details(): table_primary_key_value=" << table_primary_key_value.to_string() << std::endl;
+    //std::cout << "Box_Data_Portal::get_suitable_record_to_view_details(): table_primary_key_value=" << table_primary_key_value.to_string() << std::endl;
 
     //The value is empty when there there is no record to match the key in the related table:
     //For instance, if an invoice lines record mentions a product id, but the product does not exist in the products table.
     if(Conversions::value_is_empty(table_primary_key_value))
     {
       value_found = false;
-      std::cout << "debug: Box_Data_List_Related::get_suitable_record_to_view_details(): SQL query returned empty primary key." << std::endl;
+      std::cout << "debug: Box_Data_Portal::get_suitable_record_to_view_details(): SQL query returned empty primary key." << std::endl;
     }
   }
   else
   {
     value_found = false;
-    std::cout << "debug: Box_Data_List_Related::get_suitable_record_to_view_details(): SQL query returned no suitable primary key." << std::endl;
+    std::cout << "debug: Box_Data_Portal::get_suitable_record_to_view_details(): SQL query returned no suitable primary key." << std::endl;
   }
 
   if(!value_found)
@@ -527,7 +342,7 @@
   }
 }
 
-Document_Glom::type_list_layout_groups Box_Data_List_Related::create_layout_get_layout()
+Document_Glom::type_list_layout_groups Box_Data_Portal::create_layout_get_layout()
 {
   Document_Glom::type_list_layout_groups result;
 
@@ -538,24 +353,15 @@
 }
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
-Dialog_Layout* Box_Data_List_Related::create_layout_dialog() const
+Dialog_Layout* Box_Data_Portal::create_layout_dialog() const
 {
-  Glib::RefPtr<Gnome::Glade::Xml> refXml = Gnome::Glade::Xml::create(Utils::get_glade_file_path("glom_developer.glade"), "window_data_layout");
-  if(refXml)
-  {
-    Dialog_Layout_List_Related* dialog = 0;
-    refXml->get_widget_derived("window_data_layout", dialog);
-    return dialog;
-  }
-  
-  return NULL;
+  //Overridden inderived classes.
+  return 0;
 }
 
-void Box_Data_List_Related::prepare_layout_dialog(Dialog_Layout* dialog)
+void Box_Data_Portal::prepare_layout_dialog(Dialog_Layout* dialog)
 {
-  Dialog_Layout_List_Related* related_dialog = dynamic_cast<Dialog_Layout_List_Related*>(dialog);
-  g_assert(related_dialog != NULL);
-  related_dialog->set_document(m_layout_name, get_document(), m_portal);
+  //Overridden inderived classes.
 }
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 

Copied: trunk/glom/mode_data/box_data_portal.h (from r1579, /trunk/glom/mode_data/box_data_list_related.h)
==============================================================================
--- /trunk/glom/mode_data/box_data_list_related.h	(original)
+++ trunk/glom/mode_data/box_data_portal.h	Mon Apr 21 15:45:40 2008
@@ -1,6 +1,6 @@
 /* Glom
  *
- * Copyright (C) 2001-2004 Murray Cumming
+ * Copyright (C) 2001-2008 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
@@ -18,8 +18,8 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#ifndef BOX_DATA_LIST_RELATED_H
-#define BOX_DATA_LIST_RELATED_H
+#ifndef BOX_DATA_PORTAL_H
+#define BOX_DATA_PORTAL_H
 
 #include "config.h" // GLOM_ENABLE_CLIENT_ONLY
 
@@ -29,14 +29,14 @@
 namespace Glom
 {
 
-class Dialog_Layout_List_Related;
-
-class Box_Data_List_Related : 
+/** This is a base class for data widgets that should show multiple related records. 
+ */
+class Box_Data_Portal : 
   public Box_Data_List,
   public LayoutWidgetBase
 {
 public: 
-  Box_Data_List_Related();
+  Box_Data_Portal();
 
   /**
    * @param portal: The full portal details
@@ -49,7 +49,7 @@
    */
   virtual bool refresh_data_from_database_with_foreign_key(const Gnome::Gda::Value& foreign_key_value);
 
-  sharedptr<LayoutItem_Portal> get_portal() const;
+  virtual sharedptr<LayoutItem_Portal> get_portal() const;
   virtual sharedptr<const Field> get_key_field() const;
 
   sigc::signal<void, Gnome::Gda::Value> signal_record_added;
@@ -63,21 +63,16 @@
   type_signal_record_changed signal_record_changed();
 
 protected:
-  virtual bool fill_from_database(); //Override.
+  //virtual bool fill_from_database(); //Override.
   virtual type_vecLayoutFields get_fields_to_show() const; //override
 
-  virtual void on_adddel_user_requested_add();
-  virtual void on_adddel_user_changed(const Gtk::TreeModel::iterator& row, guint col);
-  virtual void on_adddel_user_added(const Gtk::TreeModel::iterator& row, guint col_with_first_value); //Override.
-  virtual void on_record_added(const Gnome::Gda::Value& primary_key_value, const Gtk::TreeModel::iterator& row); //Override. Not a signal handler.
-  virtual void on_record_deleted(const Gnome::Gda::Value& primary_key_value); //override.
+  //virtual void on_record_added(const Gnome::Gda::Value& primary_key_value, const Gtk::TreeModel::iterator& row); //Override. Not a signal handler.
+  //virtual void on_record_deleted(const Gnome::Gda::Value& primary_key_value); //override.
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   virtual void on_dialog_layout_hide(); //override.
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
-  virtual void enable_buttons(); //override
-
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   virtual Dialog_Layout* create_layout_dialog() const; // override.
   virtual void prepare_layout_dialog(Dialog_Layout* dialog); // override.
@@ -99,4 +94,4 @@
 
 } //namespace Glom
 
-#endif
+#endif //BOX_DATA_PORTAL_H

Modified: trunk/glom/mode_data/dialog_layout_calendar_related.cc
==============================================================================
--- trunk/glom/mode_data/dialog_layout_calendar_related.cc	(original)
+++ trunk/glom/mode_data/dialog_layout_calendar_related.cc	Mon Apr 21 15:45:40 2008
@@ -0,0 +1,421 @@
+/* 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_layout_calendar_related.h"
+#include "dialog_choose_field.h"
+#include "../layout_item_dialogs/dialog_field_layout.h"
+#include <bakery/App/App_Gtk.h> //For util_bold_message().
+
+//#include <libgnome/gnome-i18n.h>
+#include <gtkmm/togglebutton.h>
+#include <glibmm/i18n.h>
+
+namespace Glom
+{
+
+Dialog_Layout_Calendar_Related::Dialog_Layout_Calendar_Related(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade)
+: Dialog_Layout_List(cobject, refGlade),
+  m_combo_relationship(0),
+  m_checkbutton_show_child_relationships(0),
+  m_radio_navigation_automatic(0),
+  m_radio_navigation_specify(0),
+  m_label_navigation_automatic(0),
+  m_combo_navigation_specify(0),
+  m_combobox_date_field(0)
+{
+  // Show the appropriate alternate widgets:
+  m_box_table_widgets->hide();
+  m_box_related_table_widgets->show();
+  m_box_related_navigation->show();
+
+  refGlade->get_widget_derived("combo_relationship_name", m_combo_relationship);
+  m_combo_relationship->signal_changed().connect(sigc::mem_fun(*this, &Dialog_Layout_Calendar_Related::on_combo_relationship_changed));
+
+  refGlade->get_widget("checkbutton_show_child_relationships", m_checkbutton_show_child_relationships);
+  m_checkbutton_show_child_relationships->signal_toggled().connect(sigc::mem_fun(*this, &Dialog_Layout_Calendar_Related::on_checkbutton_show_child_relationships));
+
+  
+
+  refGlade->get_widget("radiobutton_navigation_automatic", m_radio_navigation_automatic);
+  refGlade->get_widget("label_navigation_automatic", m_label_navigation_automatic);
+  make_sensitivity_depend_on_toggle_button(*m_radio_navigation_automatic, *m_label_navigation_automatic);
+
+  refGlade->get_widget("radiobutton_navigation_specify", m_radio_navigation_specify);
+  refGlade->get_widget_derived("combobox_navigation_specify", m_combo_navigation_specify);
+  make_sensitivity_depend_on_toggle_button(*m_radio_navigation_specify, *m_combo_navigation_specify);
+  m_combo_navigation_specify->signal_changed().connect(sigc::mem_fun(*this, &Dialog_Layout_Calendar_Related::on_combo_navigation_specific_changed));
+
+  refGlade->get_widget_derived("combobox_date_field", m_combobox_date_field);
+  m_combobox_date_field->signal_changed().connect(sigc::mem_fun(*this, &Dialog_Layout_Calendar_Related::on_combo_date_field_changed));
+
+  
+  m_modified = false;
+
+  //show_all_children();
+
+  //The base class hid this, but we do want it here:
+  //(We share one glade definition for several dialogs.)
+  Gtk::Frame* box_calendar = 0;
+  refGlade->get_widget("frame_calendar", box_calendar); 
+  box_calendar->show();
+  
+  //This entry must be in the Glade file, because it's used by the base class,
+  //but we don't want it here, because it is confusing when dealing with relationships:
+  if(m_entry_table_title)
+    m_entry_table_title->hide(); // We don't use this (it's from the base class).
+
+  if(m_label_table_title)
+    m_label_table_title->hide(); // We don't use this (it's from the base class).
+}
+
+Dialog_Layout_Calendar_Related::~Dialog_Layout_Calendar_Related()
+{
+}
+
+void Dialog_Layout_Calendar_Related::set_document(const Glib::ustring& layout, Document_Glom* document, const sharedptr<const LayoutItem_CalendarPortal>& portal)
+{
+  type_vecLayoutFields empty_fields; //Just to satisfy the base class.
+  Dialog_Layout::set_document(layout, document, portal->get_relationship()->get_from_table(), empty_fields);
+  //m_table_name is now actually the parent_table_name.
+
+  m_portal = glom_sharedptr_clone(portal);
+
+  update_ui();
+}
+
+void Dialog_Layout_Calendar_Related::update_ui(bool including_relationship_list)
+{
+  if(!m_portal || !(m_portal->get_relationship()))
+   return;
+
+  m_modified = false;
+
+  const Glib::ustring related_table_name = m_portal->get_table_used(Glib::ustring() /* parent table - not relevant*/);
+
+  //Update the tree models from the document
+  Document_Glom* document = get_document();
+  if(document)
+  {
+    //Fill the relationships combo:
+    if(including_relationship_list)
+    {
+      bool show_child_relationships = m_checkbutton_show_child_relationships->get_active();
+        
+      //For the showing of child relationships if necessary:
+      if(!show_child_relationships && m_portal->get_related_relationship())
+      {
+        show_child_relationships = true;
+      }
+
+      m_combo_relationship->set_relationships(document, m_portal->get_relationship()->get_from_table(), show_child_relationships, false /* don't show parent table */); //We don't show the optional parent table because portal use _only_ relationships, of course.
+
+      if(show_child_relationships != m_checkbutton_show_child_relationships->get_active())
+      {
+         m_checkbutton_show_child_relationships->set_active(show_child_relationships);
+      }
+    }
+
+    //Set the table name and title:
+    sharedptr<LayoutItem_CalendarPortal> portal_temp = m_portal;
+    m_combo_relationship->set_selected_relationship(m_portal->get_relationship(), m_portal->get_related_relationship()); 
+
+    Document_Glom::type_list_layout_groups mapGroups;
+    mapGroups.push_back(m_portal);
+    document->fill_layout_field_details(related_table_name, mapGroups); //Update with full field information.
+
+    //Show the field layout
+    //typedef std::list< Glib::ustring > type_listStrings;
+
+    m_model_items->clear();
+
+    for(Document_Glom::type_list_layout_groups::const_iterator iter = mapGroups.begin(); iter != mapGroups.end(); ++iter)
+    {
+      sharedptr<const LayoutGroup> group = *iter;
+      sharedptr<const LayoutGroup> portal = sharedptr<const LayoutItem_CalendarPortal>::cast_dynamic(group);
+      if(portal)
+      {
+        for(LayoutGroup::type_list_items::const_iterator iterInner = group->m_list_items.begin(); iterInner != group->m_list_items.end(); ++iterInner)
+        {
+          sharedptr<const LayoutItem> item = *iterInner;
+          sharedptr<const LayoutGroup> groupInner = sharedptr<const LayoutGroup>::cast_dynamic(item);
+
+          if(groupInner)
+            add_group(Gtk::TreeModel::iterator() /* null == top-level */, groupInner);
+          else
+          {
+            //Add the item to the treeview:
+            Gtk::TreeModel::iterator iter = m_model_items->append();
+            Gtk::TreeModel::Row row = *iter;
+            row[m_model_items->m_columns.m_col_layout_item] = glom_sharedptr_clone(item);
+          }
+        }
+      }
+    }
+  }
+
+  //Show the navigation information:
+  //const Document_Glom::type_vecRelationships vecRelationships = document->get_relationships(m_portal->get_relationship()->get_from_table());
+  m_combo_navigation_specify->set_relationships(document, related_table_name, true /* show related relationships */, false /* don't show parent table */); //TODO: Don't show the hidden tables, and don't show relationships that are not used by any fields.
+  //m_combo_navigation_specify->set_display_parent_table(""); //This would be superfluous, and a bit confusing.
+
+  bool navigation_is_automatic = false;
+  bool navigation_specific_main = false;
+  sharedptr<UsesRelationship> navrel = m_portal->get_navigation_relationship_specific(navigation_specific_main);
+  if(navigation_specific_main)
+    m_combo_navigation_specify->set_selected_parent_table(related_table_name);
+  else if(navrel)
+  {
+    //std::cout << "debug navrel=" << navrel->get_relationship()->get_name() << std::endl;
+    m_combo_navigation_specify->set_selected_relationship(navrel->get_relationship(), navrel->get_related_relationship());
+  }
+  else
+  {
+    navigation_is_automatic = true;
+
+    sharedptr<const Relationship> none;
+    m_combo_navigation_specify->set_selected_relationship(none);
+  }
+
+  //Set the appropriate radio button:
+  //std::cout << "debug: navigation_is_automatic=" << navigation_is_automatic << std::endl;
+  m_radio_navigation_automatic->set_active(navigation_is_automatic); 
+  m_radio_navigation_specify->set_active(!navigation_is_automatic); 
+
+
+  //Describe the automatic navigation:
+  sharedptr<const UsesRelationship> relationship_navigation_automatic;
+  bool navigation_automatic_main = false;
+  relationship_navigation_automatic = get_portal_navigation_relationship_automatic(m_portal, navigation_automatic_main);
+  Glib::ustring automatic_navigation_description;
+  
+  if(navigation_automatic_main)
+    automatic_navigation_description = m_portal->get_relationship_name_used();
+  else if(relationship_navigation_automatic)
+  {
+    automatic_navigation_description = m_portal->get_relationship_name_used();
+
+    if(relationship_navigation_automatic->get_has_relationship_name())
+      automatic_navigation_description += ("::" + relationship_navigation_automatic->get_relationship_name());
+
+    if(relationship_navigation_automatic->get_has_related_relationship_name())
+      automatic_navigation_description += ("::" + relationship_navigation_automatic->get_related_relationship_name());
+  }
+
+  if(automatic_navigation_description.empty())
+  {
+    automatic_navigation_description = _("None: No visible tables are specified by the fields.");
+  }
+
+  m_label_navigation_automatic->set_text(automatic_navigation_description);
+
+  sharedptr<Field> debugfield = m_portal->get_date_field();
+  if(!debugfield)
+    std::cout << "DEBUG: set_document(): date field is NULL" << std::endl;
+  else
+    std::cout << "DEBUG: set_document(): date field:" << debugfield->get_name() << std::endl;
+  
+  m_combobox_date_field->set_fields(document, related_table_name, Field::TYPE_DATE);
+  m_combobox_date_field->set_selected_field(m_portal->get_date_field());
+    
+  m_modified = false;
+}
+
+void Dialog_Layout_Calendar_Related::save_to_document()
+{
+  Dialog_Layout::save_to_document();
+
+  if(m_modified)
+  {
+    //Get the data from the TreeView and store it in the document:
+
+    //Get the groups and their fields:
+    Document_Glom::type_list_layout_groups mapGroups;
+
+    //Add the fields to the portal:
+    //The code that created this dialog must read m_portal back out again.
+    m_portal->remove_all_items();
+
+    guint field_sequence = 1; //0 means no sequence
+    for(Gtk::TreeModel::iterator iterFields = m_model_items->children().begin(); iterFields != m_model_items->children().end(); ++iterFields)
+    {
+      Gtk::TreeModel::Row row = *iterFields;
+
+      sharedptr<LayoutItem> item = row[m_model_items->m_columns.m_col_layout_item];
+      const Glib::ustring field_name = item->get_name();
+      if(!field_name.empty())
+      {
+        m_portal->add_item(item); //Add it to the group:
+
+        ++field_sequence;
+      }
+    }
+
+    if(m_radio_navigation_specify->get_active())
+    {
+      sharedptr<Relationship> rel, rel_related;
+      rel = m_combo_navigation_specify->get_selected_relationship(rel_related);
+
+      bool specify_main = (!rel && !rel_related);
+      sharedptr<UsesRelationship> uses_rel = sharedptr<UsesRelationship>::create();
+      uses_rel->set_relationship(rel);
+      uses_rel->set_related_relationship(rel_related);
+
+      m_portal->set_navigation_relationship_specific(specify_main, uses_rel);
+      //std::cout << "debug99 main=specify_main" << ", relationship=" << (rel ? rel->get_name() : "none") << std::endl;
+    }
+    else
+    {
+      //std::cout << "debug: set_navigation_relationship_specific(false, none)" << std::endl;
+      sharedptr<UsesRelationship> none;
+      m_portal->set_navigation_relationship_specific(false, none);
+    }
+    
+    m_portal->set_date_field( m_combobox_date_field->get_selected_field() );
+    
+    sharedptr<Field> debugfield = m_portal->get_date_field();
+    if(!debugfield)
+      std::cout << "DEBUG: save_to_document(): date field is NULL" << std::endl;
+    else
+      std::cout << "DEBUG: save_to_document(): date field:" << debugfield->get_name() << std::endl;
+  }
+}
+
+void Dialog_Layout_Calendar_Related::on_checkbutton_show_child_relationships()
+{
+  update_ui();
+}
+
+void Dialog_Layout_Calendar_Related::on_combo_relationship_changed()
+{
+  if(!m_portal)
+    return;
+
+  sharedptr<Relationship> relationship_related;
+  sharedptr<Relationship> relationship = m_combo_relationship->get_selected_relationship(relationship_related);
+  if(relationship)
+  {
+    //Clear the list of fields if the relationship has changed, because the fields could not possible be correct for the new table:
+    bool relationship_changed = false;
+    const Glib::ustring old_relationship_name = glom_get_sharedptr_name(m_portal->get_relationship());
+    const Glib::ustring old_relationship_related_name = glom_get_sharedptr_name(m_portal->get_related_relationship());
+    if( (old_relationship_name != glom_get_sharedptr_name(relationship)) ||
+        (old_relationship_related_name != glom_get_sharedptr_name(relationship_related)) )
+      relationship_changed = true;
+
+    m_portal->set_relationship(relationship);
+    m_portal->set_related_relationship(relationship_related);
+
+    if(relationship_changed)
+      m_portal->remove_all_items();
+
+    //Refresh everything for the new relationship:
+    update_ui(false /* not including the list of relationships */);
+
+    m_modified = true;
+  }
+}
+
+sharedptr<Relationship> Dialog_Layout_Calendar_Related::get_relationship() const
+{
+  std::cout << "debug: I wonder if this function is used." << std::endl;
+  return m_combo_relationship->get_selected_relationship();
+}
+
+void Dialog_Layout_Calendar_Related::on_combo_navigation_specific_changed()
+{
+  m_modified = true;
+}
+
+void Dialog_Layout_Calendar_Related::on_combo_date_field_changed()
+{
+  m_modified = true;
+}
+
+//Overridden so we can show related fields instead of fields from the parent table:
+void Dialog_Layout_Calendar_Related::on_button_field_add()
+{
+  //Get the chosen field:
+  //std::cout << "debug: related relationship=" << glom_get_sharedptr_name(m_portal->get_related_relationship()) << std::endl;
+  //std::cout << "debug table used =" << m_portal->get_table_used(m_table_name) << std::endl;
+
+  sharedptr<LayoutItem_Field> field = offer_field_list(m_portal->get_table_used(m_table_name), this);
+  if(field)
+  {
+    //Add the field details to the layout treeview:
+    Gtk::TreeModel::iterator iter =  m_model_items->append();
+    if(iter)
+    {
+      Gtk::TreeModel::Row row = *iter;
+      row[m_model_items->m_columns.m_col_layout_item] = field;
+
+      //Scroll to, and select, the new row:
+      Glib::RefPtr<Gtk::TreeView::Selection> refTreeSelection = m_treeview_fields->get_selection();
+      if(refTreeSelection)
+        refTreeSelection->select(iter);
+
+      m_treeview_fields->scroll_to_row( Gtk::TreeModel::Path(iter) );
+    }
+  }
+}
+
+void Dialog_Layout_Calendar_Related::on_button_edit()
+{
+  Glib::RefPtr<Gtk::TreeView::Selection> refTreeSelection = m_treeview_fields->get_selection();
+  if(refTreeSelection)
+  {
+    //TODO: Handle multiple-selection:
+    Gtk::TreeModel::iterator iter = refTreeSelection->get_selected();
+    if(iter)
+    {
+      Gtk::TreeModel::Row row = *iter;
+      sharedptr<LayoutItem> layout_item = row[m_model_items->m_columns.m_col_layout_item];
+      sharedptr<LayoutItem_Field> field = sharedptr<LayoutItem_Field>::cast_dynamic(layout_item);
+
+      //Get the chosen field:
+      sharedptr<LayoutItem_Field> field_chosen = offer_field_list(field, m_portal->get_table_used(m_table_name), this);
+      if(field_chosen)
+      {
+        //Set the field details in the layout treeview:
+
+        row[m_model_items->m_columns.m_col_layout_item] = field_chosen;
+
+        //Scroll to, and select, the new row:
+        /*
+        Glib::RefPtr<Gtk::TreeView::Selection> refTreeSelection = m_treeview_fields->get_selection();
+        if(refTreeSelection)
+          refTreeSelection->select(iter);
+
+        m_treeview_fields->scroll_to_row( Gtk::TreeModel::Path(iter) );
+
+        treeview_fill_sequences(m_model_items, m_model_items->m_columns.m_col_sequence); //The document should have checked this already, but it does not hurt to check again.
+        */
+      }
+    }
+  }
+}
+
+sharedptr<LayoutItem_CalendarPortal> Dialog_Layout_Calendar_Related::get_portal_layout()
+{
+  return m_portal;
+}
+
+
+} //namespace Glom
+

Modified: trunk/glom/mode_data/dialog_layout_calendar_related.h
==============================================================================
--- trunk/glom/mode_data/dialog_layout_calendar_related.h	(original)
+++ trunk/glom/mode_data/dialog_layout_calendar_related.h	Mon Apr 21 15:45:40 2008
@@ -0,0 +1,80 @@
+/* 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_LAYOUT_LIST_RELATED_H
+#define GLOM_MODE_DATA_DIALOG_LAYOUT_LIST_RELATED_H
+
+#include "dialog_layout_list.h"
+#include <glom/libglom/data_structure/layout/layoutitem_calendarportal.h>
+#include <glom/utility_widgets/combo_textglade.h>
+#include <glom/combobox_relationship.h>
+#include <glom/combobox_fields.h>
+
+namespace Glom
+{
+
+class Dialog_Layout_Calendar_Related : public Dialog_Layout_List
+{
+public:
+  Dialog_Layout_Calendar_Related(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade);
+  virtual ~Dialog_Layout_Calendar_Related();
+
+  /**
+   * @param layout "list" or "details"
+   * @param document The document, so that the dialog can load the previous layout, and save changes.
+   * @param table_name The table name.
+   * @param table_fields: The actual fields in the table, in case the document does not yet know about them all.
+   */
+  virtual void set_document(const Glib::ustring& layout, Document_Glom* document, const sharedptr<const LayoutItem_CalendarPortal>& portal);
+  virtual void update_ui(bool including_relationships_list = true);
+
+  sharedptr<Relationship> get_relationship() const;
+  sharedptr<LayoutItem_CalendarPortal>  get_portal_layout();
+
+protected:
+
+  virtual void save_to_document();
+
+  //signal handlers:
+  virtual void on_button_field_add(); //override
+  virtual void on_button_edit(); //override
+ 
+  void on_combo_relationship_changed();
+  
+  void on_combo_navigation_specific_changed();
+  void on_combo_date_field_changed();
+  void on_checkbutton_show_child_relationships();
+
+
+  ComboBox_Relationship* m_combo_relationship;
+  Gtk::CheckButton* m_checkbutton_show_child_relationships;
+  sharedptr<LayoutItem_CalendarPortal> m_portal;
+
+  Gtk::RadioButton* m_radio_navigation_automatic;
+  Gtk::RadioButton* m_radio_navigation_specify;
+  Gtk::Label* m_label_navigation_automatic;
+  ComboBox_Relationship* m_combo_navigation_specify;
+    
+  ComboBox_Fields* m_combobox_date_field;
+};
+
+} //namespace Glom
+
+#endif //GLOM_MODE_DATA_DIALOG_LAYOUT_LIST_RELATED_H

Modified: trunk/glom/mode_data/dialog_layout_details.cc
==============================================================================
--- trunk/glom/mode_data/dialog_layout_details.cc	(original)
+++ trunk/glom/mode_data/dialog_layout_details.cc	Mon Apr 21 15:45:40 2008
@@ -45,6 +45,7 @@
   m_button_field_add_group(0),
   m_button_add_notebook(0),
   m_button_add_related(0),
+  m_button_add_related_calendar(0),
   m_button_add_button(0),
   m_button_add_text(0),
   m_button_add_image(0),
@@ -62,6 +63,10 @@
   refGlade->get_widget("frame_related_table_navigation", m_box_related_navigation); 
   m_box_related_navigation->hide();
 
+  Gtk::Frame* box_calendar = 0;
+  refGlade->get_widget("frame_calendar", box_calendar); 
+  box_calendar->hide();
+
   refGlade->get_widget("label_table_name", m_label_table_name);
 
   refGlade->get_widget("treeview_fields", m_treeview_fields);
@@ -147,6 +152,9 @@
   refGlade->get_widget("button_add_related", m_button_add_related);
   m_button_add_related->signal_clicked().connect( sigc::mem_fun(*this, &Dialog_Layout_Details::on_button_add_related) );
 
+  refGlade->get_widget("button_add_related_calendar", m_button_add_related_calendar);
+  m_button_add_related_calendar->signal_clicked().connect( sigc::mem_fun(*this, &Dialog_Layout_Details::on_button_add_related_calendar) );
+
   refGlade->get_widget("button_add_button", m_button_add_button);
   m_button_add_button->signal_clicked().connect( sigc::mem_fun(*this, &Dialog_Layout_Details::on_button_add_button) );
 
@@ -782,6 +790,36 @@
   enable_buttons();
 }
 
+void Dialog_Layout_Details::on_button_add_related_calendar()
+{
+  Gtk::TreeModel::iterator parent = get_selected_group_parent();
+
+  sharedptr<Relationship> relationship = offer_relationship_list();
+  if(relationship)
+  {
+    Gtk::TreeModel::iterator iter = append_appropriate_row();
+    if(iter)
+    {
+      Gtk::TreeModel::Row row = *iter;
+
+      sharedptr<LayoutItem_Portal> portal = sharedptr<LayoutItem_CalendarPortal>::create();
+      portal->set_relationship(relationship);
+      row[m_model_items->m_columns.m_col_layout_item] = portal;
+
+      //Scroll to, and select, the new row:
+      Glib::RefPtr<Gtk::TreeSelection> refTreeSelection = m_treeview_fields->get_selection();
+      if(refTreeSelection)
+        refTreeSelection->select(iter);
+
+      m_treeview_fields->scroll_to_row( Gtk::TreeModel::Path(iter) );
+
+      m_modified = true;
+    }
+  }
+
+  enable_buttons();
+}
+
 Gtk::TreeModel::iterator Dialog_Layout_Details::get_selected_group_parent() const
 {
   //Get the selected group, or a suitable parent group, or the first group:
@@ -1076,7 +1114,11 @@
       sharedptr<LayoutItem_Portal> layout_portal = sharedptr<LayoutItem_Portal>::cast_dynamic(layout_item);
       if(layout_portal)
       {
-        markup = _("Related: ") + layout_portal->get_relationship_name();
+        sharedptr<LayoutItem_CalendarPortal> layout_calendar = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(layout_portal);
+        if(layout_calendar)
+          markup = _("Related Calendar: ") + layout_portal->get_relationship_name();
+        else
+          markup = _("Related List: ") + layout_portal->get_relationship_name();
       }
       else
       {

Modified: trunk/glom/mode_data/dialog_layout_details.h
==============================================================================
--- trunk/glom/mode_data/dialog_layout_details.h	(original)
+++ trunk/glom/mode_data/dialog_layout_details.h	Mon Apr 21 15:45:40 2008
@@ -65,6 +65,7 @@
   void on_button_field_add_group();
   void on_button_add_notebook();
   void on_button_add_related();
+  void on_button_add_related_calendar();
   void on_button_add_button();
   void on_button_add_text();
   void on_button_add_image();
@@ -96,6 +97,7 @@
   Gtk::Button* m_button_field_add_group;
   Gtk::Button* m_button_add_notebook;
   Gtk::Button* m_button_add_related;
+  Gtk::Button* m_button_add_related_calendar;
   Gtk::Button* m_button_add_button;
   Gtk::Button* m_button_add_text;
   Gtk::Button* m_button_add_image;

Modified: trunk/glom/mode_data/dialog_layout_list.cc
==============================================================================
--- trunk/glom/mode_data/dialog_layout_list.cc	(original)
+++ trunk/glom/mode_data/dialog_layout_list.cc	Mon Apr 21 15:45:40 2008
@@ -36,6 +36,13 @@
   //These do not make sense in a list:
   m_button_add_notebook->hide();
   m_button_add_related->hide();
+  m_button_add_related_calendar->hide();
+
+  //We don't want this part of the dialog:
+  //(We share one glade definition for several dialogs.)
+  Gtk::Frame* box_calendar = 0;
+  refGlade->get_widget("frame_calendar", box_calendar); 
+  box_calendar->hide();
 }
 
 Dialog_Layout_List::~Dialog_Layout_List()

Modified: trunk/glom/mode_data/flowtablewithfields.cc
==============================================================================
--- trunk/glom/mode_data/flowtablewithfields.cc	(original)
+++ trunk/glom/mode_data/flowtablewithfields.cc	Mon Apr 21 15:45:40 2008
@@ -120,7 +120,11 @@
     sharedptr<LayoutItem_Portal> portal = sharedptr<LayoutItem_Portal>::cast_dynamic(item);
     if(portal)
     {
-      add_layout_related_at_position(portal, add_before);
+      sharedptr<LayoutItem_CalendarPortal> calendar_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(portal);
+      if(calendar_portal)
+        add_layout_related_calendar_at_position(calendar_portal, add_before);
+      else
+        add_layout_related_at_position(portal, add_before);
     }
     else
     {
@@ -272,6 +276,39 @@
   return 0;
 }
 
+Box_Data_Calendar_Related* FlowTableWithFields::create_related_calendar(const sharedptr<LayoutItem_CalendarPortal>& portal, bool show_title)
+{
+  if(!portal)
+    return 0;
+
+  Document_Glom* pDocument = static_cast<Document_Glom*>(get_document());
+  if(pDocument)
+  {
+    sharedptr<Relationship> relationship = pDocument->get_relationship(m_table_name, portal->get_relationship_name());
+    if(relationship)
+    {
+      Box_Data_Calendar_Related* portal_box = Gtk::manage(new Box_Data_Calendar_Related);
+      add_view(portal_box); //Give it access to the document, needed to get the layout and fields information.
+
+      portal_box->init_db_details(portal, show_title); //Create the layout
+
+      portal_box->set_layout_item(portal, relationship->get_to_table());
+      portal_box->show();
+
+      m_portals.push_back(portal_box);
+
+      //Connect signals:
+      portal_box->signal_record_changed().connect( sigc::mem_fun(*this, &FlowTableWithFields::on_portal_record_changed) );
+
+      portal_box->signal_user_requested_details().connect( sigc::bind( sigc::mem_fun(*this, &FlowTableWithFields::on_portal_user_requested_details), portal_box));
+
+      return portal_box;
+    }
+  }
+
+  return 0;
+}
+
 void FlowTableWithFields::add_layout_related_at_position(const sharedptr<LayoutItem_Portal>& portal, const type_list_layoutwidgets::iterator& add_before)
 {
   Box_Data_List_Related* portal_box = create_related(portal);
@@ -282,6 +319,16 @@
   }
 }
 
+void FlowTableWithFields::add_layout_related_calendar_at_position(const sharedptr<LayoutItem_CalendarPortal>& portal, const type_list_layoutwidgets::iterator& add_before)
+{
+  Box_Data_Calendar_Related* portal_box = create_related_calendar(portal);
+  if(portal_box)
+  {
+    add(*portal_box, true /* expand */);
+    add_layoutwidgetbase(portal_box, add_before);
+  }
+}
+
 void FlowTableWithFields::add_layout_notebook_at_position(const sharedptr<LayoutItem_Notebook>& notebook, const type_list_layoutwidgets::iterator& add_before)
 {
   if(!notebook)
@@ -745,13 +792,20 @@
    for(type_portals::const_iterator iter = m_portals.begin(); iter != m_portals.end(); ++iter)
   {
     //*iter is a FlowTableItem.
-    Box_Data_List_Related* pPortalUI = *iter;
+    Box_Data_Portal* pPortalUI = *iter;
     if(pPortalUI)
     {
       sharedptr<LayoutItem_Portal> portal = pPortalUI->get_portal();
-      sharedptr<Relationship> relationship = portal->get_relationship(); //In this case, we only care about the first relationship (not any child relationships), because that's what would trigger a change.
-      if(relationship && (relationship->get_from_field() == from_key_name))
-        result.push_back(pPortalUI);
+      if(portal)
+      {
+        sharedptr<Relationship> relationship = portal->get_relationship(); //In this case, we only care about the first relationship (not any child relationships), because that's what would trigger a change.
+        if(relationship && (relationship->get_from_field() == from_key_name))
+          result.push_back(pPortalUI);
+      }
+      else
+      {
+        std::cerr << "FlowTableWithFields::get_portals(): get_portal() returned NULL." << std::endl;
+      }
     }
   }
 
@@ -868,7 +922,7 @@
 
   for(type_portals::iterator iter = m_portals.begin(); iter != m_portals.end(); ++iter)
   {
-    Box_Data_List_Related* pPortal = *iter;
+    Box_Data_Portal* pPortal = *iter;
     remove_view(pPortal);
     remove(*pPortal);
     delete pPortal;
@@ -1115,7 +1169,7 @@
   signal_related_record_changed().emit(relationship_name);
 }
 
-void FlowTableWithFields::on_portal_user_requested_details(Gnome::Gda::Value primary_key_value, Box_Data_List_Related* portal_box)
+void FlowTableWithFields::on_portal_user_requested_details(Gnome::Gda::Value primary_key_value, Box_Data_Portal* portal_box)
 {
   sharedptr<const LayoutItem_Portal> portal = portal_box->get_portal();
   if(!portal)
@@ -1141,6 +1195,7 @@
   }
 }
 
+
 void FlowTableWithFields::on_flowtable_requested_related_details(const Glib::ustring& table_name, Gnome::Gda::Value primary_key_value)
 {
   //Forward it to the parent:

Modified: trunk/glom/mode_data/flowtablewithfields.h
==============================================================================
--- trunk/glom/mode_data/flowtablewithfields.h	(original)
+++ trunk/glom/mode_data/flowtablewithfields.h	Mon Apr 21 15:45:40 2008
@@ -32,6 +32,7 @@
 #include <glom/libglom/data_structure/layout/layoutitem_field.h>
 #include <glom/libglom/data_structure/layout/layoutitem_notebook.h>
 #include <glom/libglom/data_structure/layout/layoutitem_portal.h>
+#include <glom/libglom/data_structure/layout/layoutitem_calendarportal.h>
 #include <glom/libglom/data_structure/layout/layoutitem_button.h>
 #include <glom/libglom/data_structure/layout/layoutitem_text.h>
 #include <glom/libglom/data_structure/layout/layoutitem_placeholder.h>
@@ -40,6 +41,7 @@
 #include <glom/utility_widgets/layoutwidgetbase.h>
 #include <glom/utility_widgets/layoutwidgetutils.h>
 #include "box_data_list_related.h"
+#include "box_data_calendar_related.h"
 #include "treestore_layout.h" //Forthe enum.
 #include <map>
 #include <list>
@@ -163,8 +165,7 @@
   void on_datawidget_layout_item_added(LayoutWidgetBase::enumType item_type, DataWidget* pDataWidget);
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
-  void on_portal_user_requested_details(Gnome::Gda::Value primary_key_value, Box_Data_List_Related* portal_box);
-
+  void on_portal_user_requested_details(Gnome::Gda::Value primary_key_value, Box_Data_Portal* portal_box);
   class Info
   {
   public:
@@ -185,7 +186,7 @@
   typedef std::list< FlowTableWithFields* > type_sub_flow_tables;
   type_sub_flow_tables m_sub_flow_tables;
 
-  typedef std::list< Box_Data_List_Related* > type_portals;
+  typedef std::list< Box_Data_Portal* > type_portals;
   type_portals m_portals;
 
   //Remember the sequence of LayoutWidgetBase widgets, so we can iterate over them later:
@@ -204,10 +205,11 @@
   void add_layout_group_at_position(const sharedptr<LayoutGroup>& group, const type_list_layoutwidgets::iterator& add_before);
   void add_layout_notebook_at_position(const sharedptr<LayoutItem_Notebook>& notebook, const type_list_layoutwidgets::iterator& add_before);
   void add_layout_related_at_position(const sharedptr<LayoutItem_Portal>& portal, const type_list_layoutwidgets::iterator& add_before);
+  void add_layout_related_calendar_at_position(const sharedptr<LayoutItem_CalendarPortal>& portal, const type_list_layoutwidgets::iterator& add_before);
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
-	virtual void on_dnd_add_placeholder(LayoutWidgetBase* above);
-	virtual void on_dnd_remove_placeholder();
+  virtual void on_dnd_add_placeholder(LayoutWidgetBase* above);
+  virtual void on_dnd_remove_placeholder();
     
   // Methods for the different layout object
   virtual void on_dnd_add_layout_item_field (LayoutWidgetBase* above);
@@ -227,6 +229,7 @@
   sharedptr<LayoutItem_Portal> get_layout_item_from_relation();
   
   Box_Data_List_Related* create_related(const sharedptr<LayoutItem_Portal>& portal, bool show_title = true);
+  Box_Data_Calendar_Related* create_related_calendar(const sharedptr<LayoutItem_CalendarPortal>& portal, bool show_title = true);
 
   Gtk::Alignment* m_placeholder;
   

Modified: trunk/glom/utility_widgets/calendar/Makefile.am
==============================================================================
--- trunk/glom/utility_widgets/calendar/Makefile.am	(original)
+++ trunk/glom/utility_widgets/calendar/Makefile.am	Mon Apr 21 15:45:40 2008
@@ -2,6 +2,6 @@
 
 AM_CPPFLAGS = -I top_srcdir@/ $(GLOM_CFLAGS)
 
-noinst_LIBRARIES = libutility_widgets_cellrendererlist.a
-libutility_widgets_cellrendererlist_a_SOURCES = glomgtkcalendar.c glomgtkcalendar.h \
-                                                glomcalendar.cc glomcalendar.h
+noinst_LIBRARIES = libutility_widgets_calendar.a
+libutility_widgets_calendar_a_SOURCES = glomgtkcalendar.c glomgtkcalendar.h \
+                                        glomcalendar.cc glomcalendar.h

Modified: trunk/glom/utility_widgets/calendar/glomgtkcalendar.c
==============================================================================
--- trunk/glom/utility_widgets/calendar/glomgtkcalendar.c	(original)
+++ trunk/glom/utility_widgets/calendar/glomgtkcalendar.c	Mon Apr 21 15:45:40 2008
@@ -717,7 +717,7 @@
 #endif
 
   priv = calendar->priv = G_TYPE_INSTANCE_GET_PRIVATE (calendar,
-						       GTK_TYPE_CALENDAR,
+						       GLOM_GTK_TYPE_CALENDAR,
 						       GlomGtkCalendarPrivate);
 
   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
@@ -3570,7 +3570,7 @@
 GtkWidget*
 glom_gtk_calendar_new (void)
 {
-  return g_object_new (GTK_TYPE_CALENDAR, NULL);
+  return g_object_new (GLOM_GTK_TYPE_CALENDAR, NULL);
 }
 
 /**

Modified: trunk/glom/utility_widgets/db_adddel/db_adddel.h
==============================================================================
--- trunk/glom/utility_widgets/db_adddel/db_adddel.h	(original)
+++ trunk/glom/utility_widgets/db_adddel/db_adddel.h	Mon Apr 21 15:45:40 2008
@@ -260,6 +260,7 @@
   //Signal handlers:
   void treeviewcolumn_on_cell_data(Gtk::CellRenderer* renderer, const Gtk::TreeModel::iterator& iter, int model_column_index, int data_model_column_index);
 
+  //TODO: Remove virtuals after checking that there are no method overrides:
   virtual void on_treeview_cell_edited(const Glib::ustring& path_string, const Glib::ustring& new_text, int model_column_index, int data_model_column_index);
   virtual void on_treeview_cell_edited_bool(const Glib::ustring& path_string, int model_column_index, int data_model_column_index);
 
@@ -268,12 +269,12 @@
 
   virtual bool on_button_press_event_Popup(GdkEventButton* event);
 
-  virtual void on_MenuPopup_activate_Edit();
-  virtual void on_MenuPopup_activate_Add();
-  virtual void on_MenuPopup_activate_Delete();
+  void on_MenuPopup_activate_Edit();
+  void on_MenuPopup_activate_Add();
+  void on_MenuPopup_activate_Delete();
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
-  virtual void on_MenuPopup_activate_layout();
+  void on_MenuPopup_activate_layout();
 #endif
 
   virtual void on_treeview_button_press_event(GdkEventButton* event);
@@ -339,6 +340,7 @@
 
   Glib::ustring m_open_button_title; //Allow us to change "Open" to "Select".
 
+  //TODO: Avoid repeating these in so many widgets:
   Gtk::Menu* m_pMenuPopup;
   Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup;
   Glib::RefPtr<Gtk::UIManager> m_refUIManager;



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