Index: openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql	15 Feb 2005 13:55:34 -0000	1.1
+++ openacs-4/packages/dynamic-types/sql/postgresql/dtype-package-create.sql	24 Feb 2005 14:21:50 -0000	1.2
@@ -418,17 +418,9 @@
     from acs_object_types 
    where object_type = p_object_type;
 
-  select (case when p_object_type = ''content_revision'' then 1 
-          else 0 end) into v_content_revision_p
-    from dual;
-
-  if not v_content_revision_p then
-    select count(*) > 0 into v_content_revision_p
-      from acs_object_type_supertype_map
-     where object_type = p_object_type
-       and ancestor_type = ''content_revision'';
-  end if;
-
+  select content_type__is_content_type(p_object_type)
+         into v_content_revision_p;
+    
   --
   -- start building rule code
   --
@@ -576,7 +568,6 @@
   if not v_content_revision_p then
       execute ''create view '' || v_table_name ||
         ''i as select acs_objects.object_id, acs_objects.object_type,
-          acs_objects.package_id, acs_objects.title,
           acs_objects.context_id, acs_objects.security_inherit_p,
           acs_objects.creation_user, acs_objects.creation_date,
           acs_objects.creation_ip, acs_objects.last_modified,
@@ -590,7 +581,6 @@
       -- updates on this view
       execute ''create view '' || v_table_name ||
         ''i as select acs_objects.object_id, acs_objects.object_type,
-          acs_objects.package_id, acs_objects.title as object_title,
           acs_objects.context_id, acs_objects.security_inherit_p,
           acs_objects.creation_user, acs_objects.creation_date,
           acs_objects.creation_ip, acs_objects.last_modified,
Index: openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql,v
diff -u -r1.2 -r1.3
--- openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql	15 Feb 2005 13:55:34 -0000	1.2
+++ openacs-4/packages/dynamic-types/sql/postgresql/forms-create.sql	24 Feb 2005 14:21:50 -0000	1.3
@@ -442,7 +442,9 @@
        and object_type = p_object_type;
 
     if NOT FOUND then
-        raise EXCEPTION ''-20000: Attribute %: % does not exist in dtype_widget.register_form_widget'', p_object_type, p_attribute_name;
+        if p_object_type <> ''acs_object'' and p_attribute_name <> ''object_id'' then
+            raise EXCEPTION ''-20000: Attribute %: % does not exist in dtype_widget.register_form_widget'', p_object_type, p_attribute_name;
+        end if;
     end if;
 
     -- Look for the form
Index: openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.tcl	14 Feb 2005 14:33:28 -0000	1.1
+++ openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.tcl	24 Feb 2005 14:21:50 -0000	1.2
@@ -28,28 +28,25 @@
 } {
     upvar $array local
 
-    dtype::get_attributes -name $object_type attributes
-    db_1row select_table_name {}
+    set attributes_list [dtype::get_attributes -name $object_type -list t attributes]
 
     set columns [list]
 
-    set size [template::multirow size attributes]
-    for {set i 1} {$i <= $size} {incr i} {
-        template::multirow get attributes $i
-
-        switch $attributes(datatype) {
+    foreach attribute_info $attributes_list {
+        foreach {name pretty_name attribute_id datatype table_name column_name default_value min_n_values max_n_values static_p} $attribute_info break
+        switch $datatype {
               date -
               timestamp -
               time_of_day {
                   set format "'YYYY-MM-DD HH24:MI:SS'"
-                  lappend columns "to_char($attributes(column_name), $format) as $attributes(name)"
+                  lappend columns "to_char($column_name, $format) as $name"
               }
               default {
-                  lappend columns "$attributes(column_name) as $attributes(name)"
+                  lappend columns "$column_name as $name"
               }
         }
     }
-
+    db_1row select_table_name {}
     set columns [join $columns ", "]
     db_0or1row select_object {} -column_array local
 }
@@ -113,7 +110,9 @@
         set default_value [db_null]
     }
     
-    db_1row select_column_spec {}
+    if {![db_0or1row select_column_spec {}]} {
+        set column_spec ""
+    }
 
     db_exec_plsql create_attr {}
     
@@ -127,43 +126,50 @@
     {-name:required}
     {-start_with "acs_object"}
     {-storage_types "type_specific"}
+    {-list "f"}
     multirow
 } {
     Gets all the attributes of a object_type.  Optionally
     it can return only those attributes after a given name.
 } {
-    template::multirow create $multirow \
-        name \
-        pretty_name \
-        attribute_id \
-        datatype \
-        table_name \
-        column_name \
-        default_value \
-        min_n_values \
-        max_n_values \
-        storage \
-        static_p
 
     set attributes [dtype::get_attributes_list \
         -name $name \
         -start_with $start_with \
         -storage_types $storage_types]
 
-    foreach attribute $attributes {
-        template::multirow append $multirow \
-            [lindex $attribute 0] \
-            [lindex $attribute 1] \
-            [lindex $attribute 2] \
-            [lindex $attribute 3] \
-            [lindex $attribute 4] \
-            [lindex $attribute 5] \
-            [lindex $attribute 6] \
-            [lindex $attribute 7] \
-            [lindex $attribute 8] \
-            [lindex $attribute 9] \
-            [lindex $attribute 10]
-    }
+    if {!$list} {
+    
+        template::multirow create $multirow \
+            name \
+            pretty_name \
+            attribute_id \
+            datatype \
+            table_name \
+            column_name \
+            default_value \
+            min_n_values \
+            max_n_values \
+            storage \
+            static_p
+        
+        foreach attribute $attributes {
+            template::multirow append $multirow \
+                [lindex $attribute 0] \
+                [lindex $attribute 1] \
+                [lindex $attribute 2] \
+                [lindex $attribute 3] \
+                [lindex $attribute 4] \
+                [lindex $attribute 5] \
+                [lindex $attribute 6] \
+                [lindex $attribute 7] \
+                [lindex $attribute 8] \
+                [lindex $attribute 9] \
+                [lindex $attribute 10]
+        }
+    } else {
+        return $attributes
+    } 
 }
 
 ad_proc -private dtype::get_attributes_list {
@@ -239,6 +245,7 @@
     util::event::fire -event dtype.attribute event
 }
 
+
 ad_proc -public dtype::def_from_table {
     {-supertype "acs_object"}
     {-table_name:required}
@@ -280,23 +287,183 @@
     "
 
     # get columns from table
-    set cols [dtype::table::get_table_array -table $table_name]
+    array set cols [dtype::table::get_table_array -table $table_name]
+    set fks [dtype::table::get_fk -table $table_name]
+    foreach l $fks {
+        foreach {col fk_col fk_table object_p} $l break
+        # if columns has a foreign key and its not referrign to an
+        # acs_object, its probably a lookup table
+        if {!$object_p} {
+            set cols($col) "enumeration"
+        }
+    }
     set type_map [dtype::table::get_db_type_map]
-    foreach {col type} $cols {
+ns_log notice "
+DB --------------------------------------------------------------------------------
+DB DAVE debugging procedure dtype::def_from_table
+DB --------------------------------------------------------------------------------
+DB fks = '${fks}'
+DB [array names cols]
+DB --------------------------------------------------------------------------------"
+    foreach col [array names cols] {
+        set type $cols($col)
         # append create attribute code
         if {$col != $id_column} {
-        append code "
-            dtype::create_attribute \
-                -name \"${col}\" \
-                -object_type \"${name}\" \
-                -data_type \"[string map $type_map $type]\" \
-                -pretty_name \"[dtype::table::pretty_name $col]\" \
-                -pretty_plural \"[dtype::table::pretty_plural $col]\" \
-                -sort_order \"\" \
-                -default_value \"\"
+            # if foreign key and foreign key is not an object
+            append code "
+dtype::create_attribute \
+    -name \"${col}\" \
+    -object_type \"${name}\" \
+    -data_type \"[string map $type_map $type]\" \
+    -pretty_name \"[dtype::table::pretty_name $col]\" \
+    -pretty_plural \"[dtype::table::pretty_plural $col]\" \
+    -sort_order \"\" \
+    -default_value \"\"
 "
+            }
         }
-    }
+    
     return $code
 }
 
+ad_proc -public dtype::create_form {
+    -object_type
+    {-dform "standard"}
+    {-dforms {content_revision standard acs_object empty_acs_object}}
+    {-exclude ""}
+    {-spec ""}
+    {-evaluate "t"}
+} {
+     Create a dynamic types form for object type based on type
+     definition using intelligent defaults.
+    
+    @author Dave Bauer (dave@thedesignexperience.org)
+    @creation-date 2005-02-14
+    
+    @param object_type Object type form is for
+
+    @param dform Name of form. We can't use 'default' because that is
+    reserved for the unspecificed form.
+
+    @param exclude Attributes to exclude from automatically generated form.
+
+    @param spec Declarative specification for form defintion. Optional
+    instead of calling dtype::form::generate_widget repeatedly
+
+    @param evaluate T or F, whether to evalute the code or just
+    return it 
+
+    @return If evaluate is false, return code generated.
+    
+    @error 
+} {
+    set code ""
+    # get widget defaults
+
+    # get all types
+    set types [dtype::form::types_list \
+        -object_id "" \
+        -object_type $object_type]
+    set object_type [lindex $types 0]
+    
+    array set type_dforms $dforms
+
+    # FIXME use spec if available!
+    
+    # get default widgets
+    foreach type $types {
+                    if {[info exists type_dforms($type)]} {
+                set type_dform $type_dforms($type)
+            } else {
+                set type_dform "implicit"
+            }
+        
+        dtype::form::metadata::widgets -object_type $type \
+                                   -dform $type_dform \
+                                   -multirow widgets
+        set fks [dtype::table::get_fk -table [dtype::get_table_name -object_type $type]]
+        foreach l $fks {
+            set fk_array([lindex $l 0]) [lrange $l 1 end]
+        }
+        template::multirow foreach widgets {
+            append code "
+            dtype::form::metadata::create_widget \
+                -object_type $object_type \
+                -dform $dform \
+                -attribute_name $attribute_name \
+                -widget $widget \
+                -required_p 0 \
+                -create_form_p 1
+"
+            # check attribute datatype
+            # for foreign keys, if should be enumeration
+            # if so, we want to create a select widget
+            # that queries the fk table
+            if {$datatype == "enumeration" && [info exists fk_array($attribute_name)]} {
+                set object_p [lindex $fk_array($attribute_name) 2]
+                if {!$object_p} {
+                    # create widget param for select list
+                    # if type of the foreign key table is a subtype of
+                    # content revision, use the i view
+                    # also check if its a dtype
+                    
+                    append code "
+                    dtype::form::metadata::create_widget_param \
+                        -object_type $object_type \
+                        -dform $dform \
+                        -attribute_name $attribute_name \
+                        -param_name options \
+                        -type multilist \
+                        -source query \
+                        -value \"select title, [lindex $fk_array($attribute_name) 0] from [lindex $fk_array($attribute_name) 1]\"
+                        "
+                 }
+
+            }
+
+            
+        }
+    }
+    if {$evaluate} {
+        eval $code
+    } else {
+        return $code
+    }
+}
+
+ad_proc -public dtype::get_table_name {
+    -object_type
+} {
+    
+    Get name of type specicifc storage table
+    
+    @author Dave Bauer (dave@thedesignexperience.org)
+    @creation-date 2005-02-14
+    
+    @param object_type Object type
+
+    @return Table Name
+    
+    @error 
+} {
+    return [db_string get_table_name "" -default ""]
+}
+
+ad_proc -public dtype::get_id_column {
+    -object_type
+} {
+    
+    Get name of type specicifc storage table
+    
+    @author Dave Bauer (dave@thedesignexperience.org)
+    @creation-date 2005-02-14
+    
+    @param object_type Object type
+
+    @return Table Name
+    
+    @error 
+} {
+    return [db_string get_id_column "" -default ""]
+}
+
Index: openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.xql,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.xql	14 Feb 2005 14:33:28 -0000	1.1
+++ openacs-4/packages/dynamic-types/tcl/dynamic-type-procs.xql	24 Feb 2005 14:21:50 -0000	1.2
@@ -52,5 +52,19 @@
  
          
    
- 
+
+  
+    
+      select table_name from acs_object_types where
+      object_type=:object_type
+    
+  
+
+  
+    
+      select id_column from acs_object_types where
+      object_type=:object_type
+    
+  
+  
 
Index: openacs-4/packages/dynamic-types/tcl/form-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/tcl/form-procs.tcl,v
diff -u -r1.3 -r1.4
--- openacs-4/packages/dynamic-types/tcl/form-procs.tcl	18 Feb 2005 17:54:18 -0000	1.3
+++ openacs-4/packages/dynamic-types/tcl/form-procs.tcl	24 Feb 2005 14:21:50 -0000	1.4
@@ -1,3 +1,4 @@
+
 ad_library {
     A library of functions to generate forms for acs_objects from stored 
     metadata.
@@ -89,7 +90,7 @@
             set override(object_id) [db_nextval acs_object_id_seq]
         }
     }
-
+    
     template::element create $form ${prefix}dform_action \
         -widget hidden \
         -datatype text \
@@ -134,9 +135,6 @@
     Process a dynamic type form submission created by a function such as
     dtype::form::add_elements.  
 
-    @param object_id the object represented in the form.  If set the form is
-           assumed to be an edit form, otherwise it is assumed to be an object
-           create form
     @param object_type the object type whose metadata will define the form
     @param dform specifies the stored object form used
     @param dforms specifies the stored object form to use for particular object 
@@ -263,15 +261,11 @@
     set columns [list]
     set values [list]
 
-    # DAVEB since add_elements excludes acs_object attributes, we need
-    # to set some of them to reasonable defaults
-    # object_type
-    # what do we do about context_id? Its application specific
     # LEED context_id and similar fields should be passed in using the
     # -defaults { context_id 1234 } argument
     
     foreach type $types {
-
+        set missing_columns ""
         # Add attributes to $columns and associated bind variables to $values 
         # for each type
         if {[info exists type_dforms($type)]} {
@@ -280,6 +274,13 @@
             set type_dform $dform
         }
 
+        # Add attributes to $columns and associated bind variables to $values 
+        # for each type
+        if {[info exists type_dforms($type)]} {
+            set type_dform $type_dforms($type)
+        } else {
+            set type_dform $dform
+        }
         # get the attribute metadata for the object type
         dtype::get_attributes -name $type \
                   -start_with $type \
@@ -298,15 +299,27 @@
 ns_log debug "PROCESSING: $attributes(name)"
             if {[info exists widgets($attributes(attribute_id))]} {
 ns_log debug "PROCESSING: found $attributes(name) in form"
-
                 # first check for the attribute in the submitted form
-                set crv_$attributes(name) [template::element::get_values \
+                array set this_widget_info $widgets($attributes(attribute_id))
+                switch $this_widget_info(widget) {
+                    file {}
+                    checkbox -
+                    multiselect {
+                        set crv_$attributes(name) [template::element::get_values \
+                                                       $form \
+                                                       ${prefix}$attributes(name)]
+                    }
+                    default {
+                        set crv_$attributes(name) [template::element::get_value \
                                                $form \
                                                ${prefix}$attributes(name)]
-
+                    }
+                }
             } elseif {[info exists default($attributes(name))]} {
 ns_log debug "PROCESSING: using supplied default for $attributes(name)"
 
+            if {![string equal [set crv_$attributes(name)] ""]} {
+
                 # second check if the caller supplied a default value
                 set crv_$attributes(name) $default($attributes(name))
 
@@ -327,7 +340,6 @@
                 lappend missing_columns $attributes(column_name)
 
             }
-
             if {![string equal [set crv_$attributes(name)] ""]} {
                 lappend columns $attributes(column_name)
 
@@ -356,17 +368,17 @@
             if {$new_p} { 
                 db_dml insert_statement "
                     insert into ${type_info(table_name)}i 
-                    (item_id, [join $columns ", "])
+                    ([join [concat "item_id" "revision_id" $columns] ", "])
                     values 
-                    (:item_id, [join $values ", "])"
+                    ([join [concat ":item_id" ":object_id" $values] ", "])"
             } else { 
                 set latest_revision [content::item::get_latest_revision -item_id $item_id]
 
                 db_dml insert_statement "
                     insert into ${type_info(table_name)}i 
-                    (item_id, [join [concat $columns $missing_columns] ", "])
-                    select item_id, 
-                    [join [concat $values $missing_columns] ", "]
+                    ([join [concat "item_id" "revision_id" $columns $missing_columns] ", "])
+                    select  
+                    [join [concat ":item_id" ":object_id" $values $missing_columns] ", "]
                     from ${type_info(table_name)}i
                     where revision_id = $latest_revision"
             }
@@ -480,10 +492,10 @@
         if {![template::util::is_true $widgets(is_required)]} {
           append element_create_cmd " -optional"
         }
-
+        
         if {![string equal $widgets(widget) file]} {
             # Append the initial value
-            if {[info exists override($widgets(attribute_name))]} {
+            if {[info exists override(${widgets(attribute_name)})]} {
                 append element_create_cmd " [dtype::form::value_switch \
                     -widget $widgets(widget) \
                     -value $override($widgets(attribute_name))]"
@@ -584,7 +596,8 @@
                 append element_create_cmd " [dtype::form::value_switch \
                     -widget $widgets(widget) \
                     -value $override($widgets(attribute_name))]"
-            } elseif {!$new_p} {
+            } elseif {$new_p} {
+                # don't try to put content in the form element on new form
                 append element_create_cmd " [dtype::form::value_switch \
                     -widget $widgets(widget) \
                     -value $widgets(default_value)]"
@@ -612,13 +625,13 @@
         file {}
         checkbox -
         multiselect {
-            return "-values $value"
+            return "-values \"$value\""
         }
         date {
             return "-value {[template::util::date::from_ansi $value]}"
         }
         default {
-            return "-value $value"
+            return "-value \"$value\""
         }
     }
 }
@@ -693,7 +706,6 @@
     if {[string equal $object_type ""]} {
         set object_type [db_string get_object_type {}]
     }
-
     switch $param(param_source) {
         eval {
             set value [eval $param(value)]
@@ -709,6 +721,11 @@
                     }
                     multilist {
                         set value [db_list_of_lists param_query $param(value)]
+                        # if the option list is empty, return
+                        # somethign the select widget can use
+                        if {$value eq ""} {
+                            set value [list [list]]
+                        }
                     }             
                 }
             }] {
@@ -725,7 +742,6 @@
         }
     }
     # end switch
-
     return $value
 }
 
@@ -781,14 +797,6 @@
     set metadata [dtype::form::metadata::widgets_list \
         -object_type $object_type \
         -dform $dform]
-ns_log notice "
-
-DB --------------------------------------------------------------------------------
-DB DAVE debugging procedure dtype::form::metadata::widgets
-DB --------------------------------------------------------------------------------
-DB object_type = '${object_type}'
-DB metadata = '${metadata}'
-DB --------------------------------------------------------------------------------"
     foreach widget $metadata {
         if {$multirow_p} {
             eval "template::multirow append \$multirow $widget"
Index: openacs-4/packages/dynamic-types/tcl/table-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dynamic-types/tcl/table-procs-postgresql.xql,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/dynamic-types/tcl/table-procs-postgresql.xql	14 Feb 2005 14:33:28 -0000	1.1
+++ openacs-4/packages/dynamic-types/tcl/table-procs-postgresql.xql	24 Feb 2005 14:21:50 -0000	1.2
@@ -15,12 +15,15 @@
   
   
   
-    int4 integer varchar string boolean boolean numeric number real
-      number float number integer integer serial integer money money
-      date date timestamp timestamp timestamptz timestamp "timestamp
-      with time zone" timestamp "timestamp without time zone"
-      timestamp time time_of_day "time without time zone" time_of_day
-      "time with time zone" time_of_day "" enumeration "" url "" email text text "" keyword
+    int4 integer varchar text boolean boolean numeric
+    number real number float number integer integer serial integer
+    money money date date timestamptz date
+    "timestamp with time zone" date
+    "timestamp without time zone" date
+    timestamp date
+    "time without time zone" time_of_day
+    "time with time zone" time_of_day  time time_of_day "" enumeration
+    "" url "" email "" keyword
   
 
   
@@ -74,4 +77,30 @@
    and   t.table_name=st.relname
     
   
+
+  
+    
+      select pa1.attname,
+        pa2.attname,
+        pc2.relname,
+        case when ot.object_type is null then 0 else 1 end
+        as object_p
+      from pg_attribute pa1,
+        pg_attribute pa2,
+        pg_constraint,
+        pg_class pc1,
+        pg_class pc2
+        left join
+        acs_object_types ot
+        on pc2.relname=ot.table_name
+      where conrelid=pc1.oid
+        and pc1.relname=:table
+        and contype='f'
+        and confrelid=pc2.oid
+        and pa2.attnum = any(pg_constraint.confkey)
+        and pa2.attrelid=pc2.oid
+        and pc1.oid=pa1.attrelid
+        and pa1.attnum=any(pg_constraint.conkey);
+      
+