Index: openacs-4/packages/contacts/lib/contacts.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/lib/contacts.adp,v
diff -u -r1.7 -r1.8
--- openacs-4/packages/contacts/lib/contacts.adp	1 Feb 2006 20:16:44 -0000	1.7
+++ openacs-4/packages/contacts/lib/contacts.adp	1 Apr 2006 07:07:16 -0000	1.8
@@ -13,3 +13,16 @@
 
 <br>
 <listtemplate name="contacts"></listtemplate>
+
+<if @add_columns@ not nil or @remove_columns@ not nil>
+<table cellpadding="0" cellspacing="0" border="0">
+  <tr>
+  <if @add_columns@ not nil>
+    <td><formtemplate id="add_column_form" style="../../../contacts/resources/forms/inline"></formtemplate></td>
+  </if>
+  <if @remove_columns@ not nil>
+    <td><formtemplate id="remove_column_form" style="../../../contacts/resources/forms/inline"></formtemplate></td>
+  </if>
+  </tr>
+</table>
+</if>
Index: openacs-4/packages/contacts/lib/contacts.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/lib/contacts.tcl,v
diff -u -r1.49 -r1.50
--- openacs-4/packages/contacts/lib/contacts.tcl	24 Mar 2006 13:18:04 -0000	1.49
+++ openacs-4/packages/contacts/lib/contacts.tcl	1 Apr 2006 07:07:16 -0000	1.50
@@ -7,7 +7,6 @@
 set _orderby "first_names,asc"
 set _format "normal"
 set _page_size "25"
-set _tasks_interval "7"
 set admin_p 0
 
 if { [string is false [exists_and_not_null package_id]] } {
@@ -34,6 +33,24 @@
     }
 }
 
+# see if the person is attemping to add
+# or remove a column
+set extended_columns [ns_queryget extended_columns]
+set add_column       [ns_queryget add_column]
+set remove_column    [ns_queryget remove_column]
+if { $extended_columns ne "" && $remove_column ne "" } {
+    set lindex_id [lsearch -exact $extended_columns $remove_column]
+    if { $lindex_id >= 0 } {
+	set extended_columns [lreplace $extended_columns $lindex_id $lindex_id]
+    }
+}
+if { $add_column ne "" } {
+    lappend extended_columns $add_column
+}
+
+set add_column ""
+set remove_column ""
+
 # This is for showing the employee_id and employeer relationship
 set type_list [db_list get_condition_type { }] 
 
@@ -70,9 +87,6 @@
 	{extend_values:text(hidden)
 	    {value "$extend_values"}
 	}
-	{attr_val_name:text(hidden)
-	    {value "$attr_val_name"}
-	}
     } -on_submit {
 	# We clear the list when no value is submited, otherwise
 	# we acumulate the extend values.
@@ -81,7 +95,7 @@
 	} else {
 	    lappend extend_values [list $extend_option] 
 	}
-	ad_returnredirect [export_vars -base "?" {search_id extend_values attr_val_name}]
+	ad_returnredirect [export_vars -base "?" {search_id extend_values extended_columns}]
     }
 }
 
@@ -102,29 +116,36 @@
 set last_modified_join ""
 set last_modified_clause ""
 
+
+set first_names_url   [export_vars -base $base_url -url {format search_id query page page_size extended_columns {orderby {first_names,asc}}}]
+set last_name_url     [export_vars -base $base_url -url {format search_id query page page_size extended_columns {orderby {last_name,asc}}}]
+set organization_url  [export_vars -base $base_url -url {format search_id query page page_size extended_columns {orderby {organization,asc}}}]
+set last_modified_url [export_vars -base $base_url -url {format search_id query page page_size extended_columns {orderby {last_modified,desc}}}]
 switch $orderby {
     "first_names,asc" {
-        set name_label "[_ contacts.Sort_by]: [_ contacts.First_Names] | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size attr_val_name {orderby {last_name,asc}}}]\">[_ contacts.Last_Name]</a> | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size attr_val_name {orderby {organization,asc}}}]\">[_ contacts.Organization]</a> | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size attr_val_name {orderby {last_modified,desc}}}]\">[_ contacts.Last_Modified]</a>"
+        set name_label "[_ contacts.Sort_by] [_ contacts.First_Names] | <a href=\"${last_name_url}\">[_ contacts.Last_Name]</a> | <a href=\"${organization_url}\">[_ contacts.Organization]</a> | <a href=\"${last_modified_url}\">[_ contacts.Last_Modified]</a>"
 	set left_join "left join persons on (p.party_id = persons.person_id)"
 	set sort_item "lower(first_names), lower(last_name)"
     }
     "last_name,asc" {
-        set name_label "[_ contacts.Sort_by] <a href=\"[export_vars -base $base_url -url {format search_id query page page_size attr_val_name {orderby {first_names,asc}}}]\">[_ contacts.First_Names]</a> | [_ contacts.Last_Name] | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size {orderby {organization,asc}}}]\">[_ contacts.Organization]</a> | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size {orderby {last_modified,desc}}}]\">[_ contacts.Last_Modified]</a>"
+        set name_label "[_ contacts.Sort_by] <a href=\"${first_names_url}\">[_ contacts.First_Names]</a> | [_ contacts.Last_Name] | <a href=\"${organization_url}\">[_ contacts.Organization]</a> | <a href=\"${last_modified_url}\">[_ contacts.Last_Modified]</a>"
 	set left_join "left join persons on (p.party_id = persons.person_id)"
 	set sort_item "lower(last_name), lower(first_names)"
     }
     "organization,asc" {
-        set name_label "[_ contacts.Sort_by] <a href=\"[export_vars -base $base_url -url {format search_id query page page_size attr_val_name {orderby {first_names,asc}}}]\">[_ contacts.First_Names]</a>  | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size {orderby {last_name,asc}}}]\">[_ contacts.Last_Name]</a> | [_ contacts.Organization] | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size {orderby {last_modified,desc}}}]\">[_ contacts.Last_Modified]</a>"
+        set name_label "[_ contacts.Sort_by] <a href=\"${first_names_url}\">[_ contacts.First_Names]</a> | <a href=\"${last_name_url}\">[_ contacts.Last_Name]</a> | [_ contacts.Organization] | <a href=\"${last_modified_url}\">[_ contacts.Last_Modified]</a>"
 	set left_join "left join organizations on (p.party_id = organizations.organization_id)"
 	set sort_item "lower(organizations.name)"
     }
     "last_modified,desc" {
-        set name_label "[_ contacts.Sort_by] <a href=\"[export_vars -base $base_url -url {format search_id query page page_size attr_val_name {orderby {first_names,asc}}}]\">[_ contacts.First_Names]</a>  | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size {orderby {last_name,asc}}}]\">[_ contacts.Last_Name]</a> | <a href=\"[export_vars -base $base_url -url {format search_id query page page_size {orderby {organization,asc}}}]\">[_ contacts.Organization]</a> | [_ contacts.Last_Modified]"
+        set name_label "[_ contacts.Sort_by] <a href=\"${first_names_url}\">[_ contacts.First_Names]</a> | <a href=\"${last_name_url}\">[_ contacts.Last_Name]</a> | <a href=\"${organization_url}\">[_ contacts.Organization]</a> | [_ contacts.Last_Modified]"
 	set left_join ""
 	set sort_item "cr.publish_date"
     }
 }
 
+
+
 append name_label " &nbsp;&nbsp; [_ contacts.Show]: "
 
 
@@ -136,15 +157,15 @@
     if { $page_size == $page_s } {
         lappend page_size_list $page_s
     } else {
-        lappend page_size_list "<a href=\"[export_vars -base $base_url -url {format search_id query page orderby attr_val_name {page_size $page_s}}]\">$page_s</a>"
+        lappend page_size_list "<a href=\"[export_vars -base $base_url -url {format search_id query page orderby extended_columns {page_size $page_s}}]\">$page_s</a>"
     }
 }
 append name_label [join $page_size_list " | "]
 
 if { [string is true [parameter::get -parameter "DisableCSV" -default "0"]] } {
     set format normal
 } else {
-    append name_label "&nbsp;&nbsp;&nbsp;[_ contacts.Get]: <a href=\"[export_vars -base $base_url -url {{format csv} search_id query page orderby attr_val_name page_size}]\">[_ contacts.CSV]</a>"
+    append name_label "&nbsp;&nbsp;&nbsp;[_ contacts.Get]: <a href=\"[export_vars -base $base_url -url {{format csv} search_id query page orderby page_size extended_columns}]\">[_ contacts.CSV]</a>"
 }
 
 template::multirow create bulk_acts pretty link detailed
@@ -234,65 +255,88 @@
 }
 
 
-# We are going to extend the list also by the attributes specified in the
-# parameters, if there is any. Only when attr_val_name is empty and exists a 
-# search_id, otherwise we would have duplicates since when attr_val_name is 
-# present then the default attributes specified on the parameter already come 
-# in this list.
+if { [exists_and_not_null search_id] } {
 
-if { ![exists_and_not_null attr_val_name] && [exists_and_not_null search_id] } {
-
-    set object_type [db_string get_object_type { }]
+    set object_type [db_string get_object_type {}]
     switch $object_type {
 	person { 
 	    set page_query_name "person_pagination"
 	    if {[string eq $orderby "organization,asc"]} {
 		set orderby "first_names,asc"
 	    }
-	    set default_attr_extend [parameter::get -parameter "DefaultPersonAttributeExtension"]
+#	    set default_attr_extend [parameter::get -parameter "DefaultPersonAttributeExtension"]
 	}
 	organization { 
 	    set page_query_name "organization_pagination"
 	    if {[string eq $orderby "first_names,asc"] || [string eq $orderby "last_name,asc"]} {
 		set orderby "organization,asc"
 	    }
-	    set default_attr_extend [parameter::get -parameter "DefaultOrganizationAttributeExtension"]
+#	    set default_attr_extend [parameter::get -parameter "DefaultOrganizationAttributeExtension"]
 	}
 	party { 
 	    set page_query_name "contacts_pagination"
-	    set default_attr_extend [parameter::get -parameter "DefaultPersonOrganAttributeExtension"]
+#	    set default_attr_extend [parameter::get -parameter "DefaultPersonOrganAttributeExtension"]
 	}
     }
-    
-    # We are going to take all the blank spaces and split the list by ";"
-    regsub -all " " $default_attr_extend "" default_attr_extend
-    set default_attr_extend [split $default_attr_extend ";"]
+}
 
-    foreach attr $default_attr_extend {
-	set attr_id [attribute::id -object_type "person" -attribute_name "$attr"]
-        if { [empty_string_p $attr_id] } {
-	    # Is not a person attribute is an organization attribute
-            set attr_id [attribute::id -object_type "organization" -attribute_name "$attr"]
-        }
-	lappend attr_val_name [list $attr_id $attr]
-    }
+set actions [list]
+if { $admin_p && [exists_and_not_null search_id] } {
+    set actions [list "[_ contacts.Set_default_extend]" "admin/ext-search-options?search_id=$search_id" "[_ contacts.Set_default_extend]" ]
 }
 
 
-# This is for the attributes
-set extend_attr [list]
-foreach attribute $attr_val_name {
-    set attr_id   [lindex $attribute 0]
-    lappend row_list $attr_id [list]
-    lappend elements $attr_id [list label [attribute::pretty_name -attribute_id $attr_id] display_template "@contacts.${attr_id};noquote@"]
-    lappend extend_attr $attr_id
+
+template::multirow create ext impl type type_pretty key key_pretty
+
+# permissions for what attributes/extensions are visible to this
+# user are to be handled by this callback proc. The callback
+# MUST only return keys that are visible to this user
+
+callback contacts::extensions \
+    -user_id [ad_conn user_id] \
+    -multirow ext \
+    -package_id [ad_conn package_id]
+
+
+set add_columns [list]
+set remove_columns [list]
+set db_extend_columns [list]
+if { $search_id ne "" } {
+    # now we get the extensions for this specific search
+    set db_extend_columns [contact::search::get_extensions -search_id $search_id]
 }
+set extended_columns [concat $db_extend_columns $extended_columns]
 
-set actions [list]
-if { $admin_p && [exists_and_not_null search_id] } {
-    set actions [list "[_ contacts.Set_default_extend]" "admin/ext-search-options?search_id=$search_id" "[_ contacts.Set_default_extend]" ]
+# we run through the multirow here to determine wether or not the columns are allowed
+template::multirow foreach ext {
+    set selected_p 0
+    set immutable_p 0
+    if { [lsearch $extended_columns "${type}__${key}"] >= 0 } {
+        # we want to use this column in our table
+        set selected_p 1
+        if { [lsearch $db_extend_columns "${type}__${key}"] >= 0 } {
+            set immutable_p 1
+        }
+        # we add the column to the template::list
+        lappend elements "${type}__${key}" [list label $key_pretty display_col "${type}__${key}" display_template "@contacts.${type}__${key};noquote@"]
+	lappend row_list "${type}__${key}" [list]
+    }
+    if { [string is true $selected_p] && [string is false $immutable_p] } {
+	lappend remove_columns [list $key_pretty "${type}__${key}" $type_pretty]
+    } elseif { [string is false $selected_p] } {
+	lappend add_columns [list $key_pretty "${type}__${key}" $type_pretty]
+    }
+
 }
 
+
+
+
+
+
+
+
 template::list::create \
     -html {width 100%} \
     -name "contacts" \
@@ -310,13 +354,12 @@
     -bulk_action_export_vars { search_id return_url } \
     -elements $elements \
     -filters {
-        attr_val_name {}
 	search_id {}
 	page_size {}
 	extend_values {}
 	attribute_values {}
-	tasks_interval {}
         query {}
+	extended_columns {}
     } -orderby {
         first_names {
             label "[_ contacts.First_Name]"
@@ -338,8 +381,7 @@
 	    orderby_asc "cr.publish_date"
 	    orderby_desc "cr.publish_date"
        }
-
-        default_value first_names,asc
+       default_value first_names,asc
     } -formats {
 	normal {
 	    label "[_ contacts.Table]"
@@ -358,7 +400,8 @@
 	}
     }
 
-set extend_list "$extend_attr contact_url message_url name orga_info"
+#set extend_list "$extend_attr contact_url message_url name orga_info"
+set extend_list "contact_url message_url name orga_info"
 
 if { ![string equal [lsearch -exact $type_list "employees"] "-1"] } {
     # We use this multirow since is going to retrive the attribute values
@@ -368,24 +411,6 @@
 	set contact_url [contact::url -party_id $party_id]
 	set message_url [export_vars -base "$contact_url/message" {{message_type "email"}}]
 	set name "[contact::name -party_id $party_id]"
-
-	foreach attribute $attr_val_name {
-	    set attr_id   [lindex $attribute 0]
-	    set attr_name [lindex $attribute 1]
-	    set contact_party_revision [contact::live_revision -party_id $party_id]
-	    set $attr_id  [ams::value \
-			       -object_id $contact_party_revision \
-			       -attribute_id $attr_id \
-			       -attribute_name "$attr_name"]
-	    
-	    if { ![exists_and_not_null $attr_id] } {
-		set contact_party_revision [contact::live_revision -party_id $employee_id]
-		set $attr_id  [ams::value \
-				   -object_id $contact_party_revision \
-				   -attribute_id $attr_id \
-				   -attribute_name "$attr_name"]
-	    }
-	}
 	
 	set display_employers_p [parameter::get \
 				     -parameter DisplayEmployersP \
@@ -418,15 +443,6 @@
 	set contact_url [contact::url -party_id $party_id]
 	set message_url [export_vars -base "$contact_url/message" {{message_type "email"}}]
 	set name "[contact::name -party_id $party_id]"
-	foreach attribute $attr_val_name {
-	    set attr_id   [lindex $attribute 0]
-	    set attr_name [lindex $attribute 1]
-	    set contact_party_revision [contact::live_revision -party_id $party_id]
-	    set $attr_id  [ams::value \
-			       -object_id $contact_party_revision \
-			       -attribute_id $attr_id \
-			       -attribute_name "$attr_name"]
-	}
 	
 	set display_employers_p [parameter::get \
 				     -parameter DisplayEmployersP \
@@ -462,5 +478,73 @@
 }
 
 
-list::write_output -name contacts
+set limit_clause ""
+if { $format != "csv" } {
+    if { $page_size ne "" } {
+	if { $page eq "" } { set page 1 }
+	set limit_clause "limit $page_size offset [expr [expr $page - 1 ] * $page_size]"
+    }
+}
+set select_query "select party_id from ( [db_map $page_query_name] $limit_clause) party_query"
 
+# extend the multirow
+contacts::multirow \
+    -extend $extended_columns \
+    -multirow contacts \
+    -select_query $select_query
+
+
+# create forms to add/remove columns from the multirow
+if { [llength $add_columns] > 0 } {
+    set add_columns [concat [list [list "[_ contacts.--add_column--]" "" ""]] $add_columns]
+}
+if { [llength $remove_columns] > 0 } {
+    set remove_columns [concat [list [list "[_ contacts.--remove_column--]" "" ""]] $remove_columns]
+}
+
+set extended_columns_preserved $extended_columns
+
+ad_form \
+    -name "add_column_form" \
+    -method "GET" \
+    -export {format search_id query page page_size orderby} \
+    -has_submit "1" \
+    -has_edit "1" \
+    -form {
+	{extended_columns:text(hidden),optional}
+	{add_column:text(select_with_optgroup)
+	    {label ""}
+	    {html {onChange "document.add_column_form.submit();"}}
+	    {options $add_columns}
+	}
+    } \
+    -on_request {} \
+    -on_submit {}
+
+ad_form \
+    -name "remove_column_form" \
+    -method "GET" \
+    -export {format search_id query page page_size orderby} \
+    -has_submit "1" \
+    -has_edit "1" \
+    -form {
+	{extended_columns:text(hidden),optional}
+	{remove_column:text(select_with_optgroup)
+	    {label ""}
+	    {html {onChange "document.remove_column_form.submit();"}}
+	    {options $remove_columns}
+	}
+    } \
+    -on_request {} \
+    -on_submit {}
+
+
+set extended_columns $extended_columns_preserved
+template::element::set_value add_column_form extended_columns $extended_columns
+template::element::set_value remove_column_form extended_columns $extended_columns
+
+
+
+
+
+list::write_output -name contacts
Index: openacs-4/packages/contacts/lib/contacts.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/lib/contacts.xql,v
diff -u -r1.22 -r1.23
--- openacs-4/packages/contacts/lib/contacts.xql	13 Mar 2006 07:21:59 -0000	1.22
+++ openacs-4/packages/contacts/lib/contacts.xql	1 Apr 2006 07:07:16 -0000	1.23
@@ -21,7 +21,7 @@
 <fullquery name="organization_pagination">
     <querytext>
 	select 
-	organizations.organization_id
+	organizations.organization_id as party_id
   	from organizations, cr_items ci, cr_revisions cr,
         group_distinct_member_map
  	where
@@ -36,7 +36,7 @@
 <fullquery name="person_pagination">
     <querytext>
 	select 
-	persons.person_id
+	persons.person_id as party_id
   	from persons, cr_items ci, cr_revisions cr,
         group_distinct_member_map
  	where
Index: openacs-4/packages/contacts/sql/postgresql/contacts-search-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/sql/postgresql/contacts-search-create.sql,v
diff -u -r1.11 -r1.12
--- openacs-4/packages/contacts/sql/postgresql/contacts-search-create.sql	15 Feb 2006 10:06:36 -0000	1.11
+++ openacs-4/packages/contacts/sql/postgresql/contacts-search-create.sql	1 Apr 2006 07:07:16 -0000	1.12
@@ -177,8 +177,5 @@
 			constraint contact_search_extend_map_extend_id_fk
 			references contact_extend_options (extend_id)
 			on delete cascade,
-	attribute_id	integer
-			constraint contact_search_extend_map_attribute_id_fk
-			references acs_attributes (attribute_id)
-			on delete cascade
+	extend_column   varchar(255)
 );
Index: openacs-4/packages/contacts/tcl/attribute-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/attribute-procs.tcl,v
diff -u -r1.11 -r1.12
--- openacs-4/packages/contacts/tcl/attribute-procs.tcl	26 Dec 2005 20:33:46 -0000	1.11
+++ openacs-4/packages/contacts/tcl/attribute-procs.tcl	1 Apr 2006 07:07:16 -0000	1.12
@@ -1,6 +1,6 @@
 ad_library {
 
-  Support procs for attributes in the contacts package
+    Support procs for attributes in the contacts package
 
     @author Matthew Geddert openacs@geddert.com
     @creation-date 2004-07-28
@@ -144,67 +144,12 @@
 	} else {
 	    set mailing_address_list [ams::widget \
 					  -widget postal_address \
-					  -request "value_list" \
+					  -request "value_list_text" \
 					  -value $value \
 					 ]
-            # This sets the address, muncipality,region, postal_code, country_code
-            template::util::list_of_lists_to_array $mailing_address_list row
-
-            # Now define the locale. This should not be set (usually), as you should always rely on the 
-            # locale of the session, (as the country name should be in the language of the user), 
-            # but who knows.
-            if {$locale eq ""} {
-                if { [ad_conn isconnected] } {
-                    # We are in an HTTP connection (request) so use that locale
-                    set locale [ad_conn locale]
-                } else {
-                    # There is no HTTP connection - resort to system locale
-                    set locale [lang::system::locale]
-                }
-            }
-
-            # Set the country right.
-	    set key "ams.country_$row(country_code)"
-
-	    if { [string is true [lang::message::message_exists_p $locale $key]] } {
-		set country [lang::message::lookup $locale $key]
-	    } else {
-		# cache the country codes
-		template::util::address::country_options_not_cached -locale $locale
-		
-		if { [string is true [lang::message::message_exists_p $locale $key]] } {
-		    set country [lang::message::lookup $locale $key]
-		} else {
-		    # we get the default en_US key which was created with the
-		    # template::util::address::country_options_not_cached proc
-		    set country [lang::message::lookup "en_US" $key]
-		}
-	    }
-            set row(country) $country
-
-            # Set the townline
-	    # Different formats depending on the country
-	    switch $row(country_code) {
-		"US" {
-		    set row(town_line) "$row(municipality), $row(region) $row(postal_code)"
-		}
-		"DE" {
-		    set row(town_line) "$row(postal_code) $row(municipality)"
-		}
-                "UK" {
-		    set row(town_line) "$row(municipality), $row(region) $row(postal_code)"
-                }
-                "CH" {
-		    set row(town_line) "$row(postal_code) $row(municipality)"
-                }                    
-		default {
-		    if { [parameter::get_from_package_key -package_key "ams" -parameter "DefaultAdressLayoutP" -default 1] } {
-			set row(town_line) "$row(municipality) $row(region) $row(postal_code)"
-		    } else {
-			set row(town_line) "$row(postal_code) $row(municipality) $row(region)"
-		    }
-		}
-	    }
+            # This sets the address, muncipality, region, postal_code, country_code, country
+	    array set row $mailing_address_list
+	    set row(town_line) [template::util::address::town_line -municipality $row(municipality) -region $row(region) -postal_code $row(postal_code) -country_code $row(country_code)]
 	    return 1
 	}
     }
Index: openacs-4/packages/contacts/tcl/contact-extend-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contact-extend-procs.tcl,v
diff -u -r1.4 -r1.5
--- openacs-4/packages/contacts/tcl/contact-extend-procs.tcl	15 Nov 2005 15:56:46 -0000	1.4
+++ openacs-4/packages/contacts/tcl/contact-extend-procs.tcl	1 Apr 2006 07:07:16 -0000	1.5
@@ -82,4 +82,105 @@
     Returns a list of the form { var_name pretty_name subquery description aggregated_p } of the extend_id
 } {
     return [db_list_of_lists get_options { }]
-}
\ No newline at end of file
+}
+
+
+
+
+
+
+
+
+
+
+
+namespace eval template::widget {}
+
+ad_proc -public template::widget::select_with_optgroup { element_reference tag_attributes } {
+
+    upvar $element_reference element
+
+    if { [info exists element(html)] } {
+        array set attributes $element(html)
+    }
+
+    array set attributes $tag_attributes
+    set options_list $element(options)
+    set widget_name $element(name)
+    set element_mode $element(mode)
+
+    # edit...
+    # Create an array for easier testing of selected values
+    template::util::list_to_lookup $element(values) values
+
+    if { ![string equal $element(mode) "edit"] } {
+	# this is the same as the menu display.
+        # we may want to customize it to use the optgroup
+        # as some sort of heading for certain options
+        set selected_list [list]
+
+        foreach option $options_list {
+	    
+            set label [lindex $option 0]
+            set value [lindex $option 1]
+	    
+            if { [info exists values($value)] } {
+                lappend selected_list $label
+                append output "<input type=\"hidden\" name=\"$widget_name\" value=\"[ad_quotehtml $value]\">"
+            }
+        }
+
+        append output [join $selected_list ", "]
+    } else {
+	
+
+	append output "<select name=\"$widget_name\" "
+	foreach name [array names attributes] {
+	    if { [string equal $attributes($name) {}] } {
+		append output " $name=\"$name\""
+	    } else {
+		append output " $name=\"$attributes($name)\""
+	    }
+	}
+	append output ">\n"
+
+
+	set optgroup {}
+	foreach option $options_list {
+	    
+	    set label [lindex $option 0]
+	    set value [lindex $option 1]
+	    set group [string trim [lindex $option 2]]
+
+
+	    if { $group eq "" } {
+		if { $optgroup ne "" } {
+		    append output "</optgroup>\n"
+		}
+		set optgroup {}
+	    } elseif { $group ne $optgroup } {
+		if { $optgroup ne "" } {
+		    append output "</optgroup>\n"
+		}
+		append output "<optgroup label=\"[ad_quotehtml $group]\">\n"
+		set optgroup $group
+	    }
+
+
+	    append output " <option value=\"[template::util::quote_html $value]\""
+	    if { [info exists values($value)] } {
+		append output " selected=\"selected\""
+	    }
+	    append output ">$label</option>\n"
+
+
+	}
+	if { $optgroup ne {} } {
+	    append output "</optgroup>\n"
+	}
+	append output "</select>"	
+    }
+
+    return $output
+}
+
Index: openacs-4/packages/contacts/tcl/contact-search-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contact-search-procs.tcl,v
diff -u -r1.23 -r1.24
--- openacs-4/packages/contacts/tcl/contact-search-procs.tcl	12 Mar 2006 17:54:18 -0000	1.23
+++ openacs-4/packages/contacts/tcl/contact-search-procs.tcl	1 Apr 2006 07:07:16 -0000	1.24
@@ -60,6 +60,17 @@
     db_1row select_search_info {} -column_array row
 }
 
+ad_proc -public contact::search::get_extensions { 
+    -search_id:required
+} {
+} {
+    return [db_list get_search_exensions {
+	    select extend_column
+	      from contact_search_extend_map
+	     where search_id = :search_id
+           }]
+}
+
 ad_proc -public contact::search::update {
     {-search_id ""}
     {-title ""}
Index: openacs-4/packages/contacts/tcl/contacts-callback-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contacts-callback-procs.tcl,v
diff -u -r1.30 -r1.31
--- openacs-4/packages/contacts/tcl/contacts-callback-procs.tcl	12 Mar 2006 14:43:03 -0000	1.30
+++ openacs-4/packages/contacts/tcl/contacts-callback-procs.tcl	1 Apr 2006 07:07:16 -0000	1.31
@@ -58,6 +58,21 @@
 } {
 }
 
+ad_proc -public -callback contacts::multirow::extend {
+    {-type}
+    {-key}
+    {-select_query}
+    {-format "html"}
+} {
+} -
+
+ad_proc -public -callback contacts::extensions {
+    {-multirow}
+    {-user_id}
+    {-package_id}
+} {
+} -
+
 ad_proc -public -callback contact::organization_new {
     {-package_id:required}
     {-contact_id:required}
@@ -556,3 +571,139 @@
     }
 
 }
+
+
+ad_proc -public -callback contacts::multirow::extend -impl attributes {
+    {-type}
+    {-key}
+    {-select_query}
+    {-format "html"}
+} {
+} {
+    if { $format ne "text" } {
+	set format "html"
+    }
+
+    set object_type $type
+
+    if { [lsearch [list party person organization] $object_type] >= 0 } {
+	set attribute_name $key
+	# now we check for a sub_attribute
+	regexp {^(.*)__(.*)$} $attribute_name match attribute_name sub_attribute_name
+
+	set attribute_id [attribute::id -object_type $object_type -attribute_name $attribute_name]
+	if { [db_0or1row get_attribute_info { select aa.*, aw.value_method from ams_attributes aa, ams_widgets aw where aa.widget = aw.widget and aa.attribute_id = :attribute_id }] } {
+	    set results [list]
+
+	    db_foreach get_ams_values "
+select ci.item_id as party_id, ${value_method}(aav.value_id) as value
+  from ams_attribute_values aav,
+       cr_items ci
+ where aav.attribute_id = $attribute_id
+   and aav.object_id = ci.live_revision
+   and ci.item_id in ( $select_query )
+            " {
+
+		if { [info exists sub_attribute_name] } {
+		    array set sub_attribute_values [ams::widget -widget $widget -request "value_list_${format}" -attribute_name $attribute_name -attribute_id $attribute_id -value $value]
+		    if { [info exists sub_attribute_values($sub_attribute_name)] } {
+			set value $sub_attribute_values($sub_attribute_name)
+			lappend results $party_id $value
+		    } else {
+			set results ""
+		    }
+		} else {
+		    lappend results $party_id [ams::widget -widget $widget -request "value_${format}" -attribute_name $attribute_name -attribute_id $attribute_id -value $value]
+		}
+
+	    }
+
+	    return $results
+	}
+    }
+    return [list]
+}
+
+
+ad_proc -public -callback contacts::extensions -impl attributes {
+    {-multirow}
+    {-user_id}
+    {-package_id}
+} {
+} {
+
+    set list_ids ""
+    set group_ids [list]
+    foreach group [contact::groups_list] {
+	lappend group_ids [lindex $group 0]
+    }
+    # since contact::groups_list doesn't get the default_groups
+    # we have to add them here
+    set group_ids [concat $group_ids [contacts::default_groups]]
+
+    foreach group_id $group_ids {
+	if { ![permission::permission_p -object_id $group_id -party_id $user_id -privilege read] } {
+	    continue
+	}
+	set list_id [ams::list::get_list_id \
+			 -package_key "contacts" \
+			 -object_type "person" \
+			 -list_name "${package_id}__${group_id}"]
+	if { $list_id ne "" } {
+	    lappend list_ids $list_id
+	}
+	set list_id [ams::list::get_list_id \
+			 -package_key "contacts" \
+			 -object_type "organization" \
+			 -list_name "${package_id}__${group_id}"]
+	if { $list_id ne "" } {
+	    lappend list_ids $list_id
+	}
+    }
+
+    if { [llength $list_ids] == 0 } {
+	return {}
+    }
+
+    set attr_list [db_list_of_lists get_all_attributes "
+select pretty_name, object_type, attribute_name, widget
+  from ams_attributes
+ where attribute_id in ( select attribute_id
+                           from ams_list_attribute_map
+                          where list_id in ([template::util::tcl_to_sql_list $list_ids])
+                       )
+   and not deprecated_p
+    "]
+
+    set attr_list [ams::util::localize_and_sort_list_of_lists -list $attr_list -position 0]
+    # now that its sorted by attribute_name, we sort it
+    # by object_type, lsort leaves the same order
+    # as the previous sort if the new sort is tied
+    # so this keeps the attributes ordered alphabetically
+    # by type
+    set attr_list [lsort -dictionary -index 1 $attr_list]
+    
+    # now we want to first get the sort by
+    foreach attr $attr_list {
+	util_unlist $attr pretty_name object_type attribute_name widget
+	switch $object_type {
+	    party { set type_pretty [_ contacts.Contact] }
+	    person { set type_pretty [_ contacts.Person] }
+	    organization { set type_pretty [_ contacts.Organization] }
+	}
+	append type_pretty " [_ contacts.Attributes]"
+	
+	set sub_attributes_list [ams::widget -widget $widget -request value_list_headings]
+	
+	if { [llength $sub_attributes_list] > 0 } {
+	    foreach {sub_attribute_name sub_pretty_name} $sub_attributes_list {
+		template::multirow append $multirow attribute $object_type $type_pretty "${attribute_name}__${sub_attribute_name}" "${pretty_name}: ${sub_pretty_name}"
+	    }
+	} else {
+	    template::multirow append $multirow attribute $object_type $type_pretty $attribute_name $pretty_name
+	}
+	
+    }
+
+}
+
Index: openacs-4/packages/contacts/tcl/contacts-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contacts-procs.tcl,v
diff -u -r1.74 -r1.75
--- openacs-4/packages/contacts/tcl/contacts-procs.tcl	15 Mar 2006 23:04:53 -0000	1.74
+++ openacs-4/packages/contacts/tcl/contacts-procs.tcl	1 Apr 2006 07:07:16 -0000	1.75
@@ -106,6 +106,40 @@
     }
 }
 
+ad_proc -public contacts::multirow {
+    {-extend ""}
+    {-multirow}
+    {-select_query}
+    {-party_id_column "party_id"}
+} {
+    This procedure extends a contacts multirow by the type.key pairs specified as 
+    a list as the extend param. The supplied select query will return a list of
+    party_ids to the callback proc... this proc is then to use the subselct
+    in their retrieval of the values requested. A list of lists, i.e.
+    {{party_id1 value1} {party_id2 value2}}
+    this procedure then takes that list of lists and matches values with parties
+    and extends the multirow provided with those values
+} {
+    foreach id $extend {
+	set ${id}__list ""
+	regexp {^(.*?)__(.*)$} $id match type key
+	set results [callback contacts::multirow::extend -type $type -key $key -select_query $select_query]
+	foreach result $results {
+	    if { $result ne "" } {
+		array set "${id}__array" $result
+	    }
+	}
+	template::multirow extend $multirow $id
+    }
+    template::multirow foreach $multirow {
+	foreach id $extend {
+	    if { [info exists ${id}__array(${party_id})] } {
+		set $id [set ${id}__array(${party_id})]
+	    }
+	}
+    }
+}
+
 ad_proc -private contact::util::generate_filename {
     {-title:required}
     {-extension:required}
Index: openacs-4/packages/contacts/www/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/index.adp,v
diff -u -r1.19 -r1.20
--- openacs-4/packages/contacts/www/index.adp	20 Feb 2006 22:01:03 -0000	1.19
+++ openacs-4/packages/contacts/www/index.adp	1 Apr 2006 07:07:16 -0000	1.20
@@ -14,6 +14,6 @@
 	base_url="@package_url@" 
 	extend_p="@extend_p@" 
 	extend_values="@extend_values@"
-	attr_val_name="@attr_val_name@"
+	search_id="@search_id@"
    >
-</else>
\ No newline at end of file
+</else>
Index: openacs-4/packages/contacts/www/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/index.tcl,v
diff -u -r1.20 -r1.21
--- openacs-4/packages/contacts/www/index.tcl	20 Feb 2006 22:01:03 -0000	1.20
+++ openacs-4/packages/contacts/www/index.tcl	1 Apr 2006 07:07:16 -0000	1.21
@@ -16,7 +16,7 @@
     {aggregate_attribute_id ""}
     {aggregate_extend_id:multiple ""}
     {extend_values:optional ""}
-    {attr_val_name:optional ""}
+    {extended_columns:optional ""}
 }
 
 if { [exists_and_not_null add_person] } {
@@ -27,6 +27,20 @@
     ad_script_abort
 }
 
+set extended_columns [ns_queryget extended_columns]
+set add_column       [ns_queryget add_column]
+set remove_column    [ns_queryget remove_column]
+if { $extended_columns ne "" && $remove_column ne "" } {
+    set lindex_id [lsearch -exact $extended_columns $remove_column]
+    if { $lindex_id >= 0 } {
+	set extended_columns [lreplace $extended_columns $lindex_id $lindex_id]
+    }
+}
+if { $add_column ne "" } {
+    lappend extended_columns $add_column
+}
+
+
 set aggregated_p 0
 if {[exists_and_not_null aggregate_attribute_id] } {
     set aggregated_p 1
@@ -83,7 +97,7 @@
     }
 }
 
-ad_form -name "search" -method "GET" -export {orderby page_size format} -form $form_elements \
+ad_form -name "search" -method "GET" -export {orderby page_size format extended_columns} -form $form_elements \
     -on_request {
     } -edit_request {
     } -on_refresh {
Index: openacs-4/packages/contacts/www/search.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/search.adp,v
diff -u -r1.11 -r1.12
--- openacs-4/packages/contacts/www/search.adp	20 Feb 2006 22:01:03 -0000	1.11
+++ openacs-4/packages/contacts/www/search.adp	1 Apr 2006 07:07:16 -0000	1.12
@@ -2,35 +2,21 @@
 
 <formtemplate id="advanced_search" style="../../../contacts/resources/forms/inline"></formtemplate>
 
+<if @search_exists_p@>
 <br />
 <br />
-<if @search_exists_p@>
-    <table>
-    <tr>
-        <td>
-        <formtemplate id="extend_attributes" style="../../../contacts/resources/forms/inline"></formtemplate>
-        </td>
-	<if @attribute_values@ not nil>
-        <td>
-	    <small>
-	    <b>@show_default_names;noquote@</b> @show_names;noquote@ 	
-  	    ( <a href="search?search_id=@search_id@">#contacts.Clear#</a> )
-	    <table><tr><td>
-            <form action="@package_url@">
-	        <input type="hidden" name="attr_val_name" value="@attr_val_name@">
-	        <input type="hidden" name="search_id" value="@search_id@">
-		<input type="submit" value="#contacts.Go#" style="font-size: 8px;">
-	    </form></td><td>
-            <form action="save-attribute">
-	        <input type="hidden" name="attr_val_name" value="@attr_val_name@">
-	        <input type="hidden" name="search_id" value="@search_id@">
-		<input type="submit" value="#contacts.Save#" style="font-size: 8px;">
-	    </form></td></tr></table>
-            </small>
-        </td>
-	</if>
-   </tr>
-   </table>
+<if @add_columns@ not nil or @remove_columns@ not nil>
+<table cellpadding="0" cellspacing="0" border="0">
+  <tr>
+  <if @add_columns@ not nil>
+    <td><formtemplate id="add_column_form" style="../../../contacts/resources/forms/inline"></formtemplate></td>
+  </if>
+  <if @remove_columns@ not nil>
+    <td><formtemplate id="remove_column_form" style="../../../contacts/resources/forms/inline"></formtemplate></td>
+  </if>
+  </tr>
+</table>
 </if>
+</if>
 
 
Index: openacs-4/packages/contacts/www/search.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/search.tcl,v
diff -u -r1.25 -r1.26
--- openacs-4/packages/contacts/www/search.tcl	20 Feb 2006 22:01:03 -0000	1.25
+++ openacs-4/packages/contacts/www/search.tcl	1 Apr 2006 07:07:16 -0000	1.26
@@ -22,20 +22,16 @@
     {attribute_values ""}
     {attribute_option ""}
     {attribute_names ""}
-    {attr_val_name ""}
+    {add_column ""}
+    {remove_column ""}
 } -validate {
     valid_object_type -requires {object_type} {
         if { [lsearch [list party person organization] $object_type] < 0 } {
             ad_complain "[_ contacts.You_have_specified_an_invalid_object_type]"
         }
     }
     valid_search_id -requires {search_id} {
-	db_0or1row condition_exists_p {
-                                        select owner_id
-                                          from contact_searches
-                                         where search_id = :search_id
-                                      }
-        if { [exists_and_not_null owner_id] } {
+        if { [db_0or1row condition_exists_p {}] } {
 	    set valid_owner_ids [list]
 	    lappend valid_owner_ids [ad_conn user_id]
 	    if { [permission::permission_p -object_id [ad_conn package_id] -privilege "admin"] } {
@@ -78,167 +74,99 @@
 # set query_pretty [list]
 if { [exists_and_not_null search_id] } {
     if { [contact::search::exists_p -search_id $search_id] } {
-        db_1row get_em { }
+        db_1row get_search_info { }
         set search_exists_p 1
     }
 }
 
 
 if { $search_exists_p } {
-    # Figure out if the search was over a person, organization or both
-    set search_for [db_string get_search_for { } -default ""]
+
+    template::multirow create ext impl type type_pretty key key_pretty
     
-    set search_for_clause ""
+    # permissions for what attributes/extensions are visible to this
+    # user are to be handled by this callback proc. The callback
+    # MUST only return keys that are visible to this user
     
-    # Get the var list of the search if type equals group
-    # so we can retrieve the default attributes of the group
-    # also.
-    set var_list [db_string get_var_list { } -default ""]
+    callback contacts::extensions \
+	-user_id [ad_conn user_id] \
+	-multirow ext \
+	-package_id [ad_conn package_id]
     
-    # We get the default attributes of persons, organizations or both and of the group
-    # if there is a condition for the gorup in the search (when var_list not null)
-    switch $search_for {
-	person {
-	    
-	    if { ![empty_string_p $var_list] } {
-		# Default attributes for the group and persons
-		set group_id [lindex [split $var_list " "] 1]
-		set search_for_clause "and (l.list_name like '%__-2' or l.list_name like '%__$group_id') "
-	    } else {
-		# Default attributes for person only
-		set search_for_clause "and l.list_name like '%__-2' "
-	    }
-	    append search_for_clause "and object_type = 'person'"
-	    
-	    # We are going to take the default attributes from the parameter
-	    set default_extend_attributes [parameter::get -parameter "DefaultPersonAttributeExtension"]
-	    
-	    }
-	organization {
-	    
-	    if { ![empty_string_p $var_list] } {
-		# Default attributes for the group and organizations
-		set group_id [lindex [split $var_list " "] 1]
-		set search_for_clause "and (l.list_name like '%__-2' or l.list_name like '%__$group_id') "
-	    } else {
-		# Default attributes for organization
-		set search_for_clause "and l.list_name like '%__-2' "
-		}
-	    append search_for_clause "and object_type = 'organization'"
-
-	    # We are going to take the default attributes from the parameter
-	    set default_extend_attributes [parameter::get -parameter "DefaultOrganizationAttributeExtension"]
-	}
-	party {
-	    if { ![empty_string_p $var_list] } {
-		# Default attributes for the group, persons and organizations
-		set group_id [lindex [split $var_list " "] 1]
-		set search_for_clause "and (l.list_name like '%__-2' or l.list_name like '%__$group_id') "
-	    }
-
-	    # We are going to take the default attributes from the parameter
-	    set default_extend_attributes [parameter::get -parameter "DefaultPersonOrganAttributeExtension"]
-	}
+    set add_columns [list]
+    set remove_columns [list]
+    set extended_columns [contact::search::get_extensions -search_id $search_id]
+    if { [lsearch $extended_columns $remove_column] >= 0 && $remove_column ne "" } {
+	# remove this extension
+	db_dml delete_column {}
+	set extended_columns [contact::search::get_extensions -search_id $search_id]
     }
-
-    set show_default_names ""
-    set show_names ""
-    # We add the default attributes, first we take out all spaces
-    # and then split by ";"
-    regsub -all " " $default_extend_attributes "" default_extend_attributes
-    set default_extend_attributes [split $default_extend_attributes ";"]
-
-    # Now we are going to add the mapped attributes in the contact_search_extend_map
-    set ema_list [db_list get_extend_mapped_attributes { }]
-
-    foreach extend_attribute_id $ema_list {
-	# We check that the attribute is nor already in the default list
-	# to avoid duplicates
-	ams::attribute::get -attribute_id $extend_attribute_id -array ea_info
-	set attribute_name $ea_info(attribute_name)
-	
-	if { [string equal [lsearch $default_extend_attributes $attribute_name] "-1"] } {
-	    lappend default_extend_attributes $attribute_name
-	}
+    if { [lsearch $extended_columns $add_column] <= 0 && $add_column ne ""  } {
+	db_dml insert_column {}
+	lappend extended_columns $add_column
     }
 
-    foreach attr $default_extend_attributes {
-	# Now we get the attribute_id
-	set attr_id [attribute::id -object_type "person" -attribute_name "$attr"]
-	if { [empty_string_p $attr_id] } {
-	    set attr_id [attribute::id -object_type "organization" -attribute_name "$attr"]
+    # we run through the multirow here to determine wether or not the columns are allowed
+    template::multirow foreach ext {
+	set selected_p 0
+	if { [lsearch $extended_columns "${type}__${key}"] >= 0 } {
+	    # we want to use this column in our table
+	    lappend remove_columns [list $key_pretty "${type}__${key}" $type_pretty]
+	} else {
+	    lappend add_columns [list $key_pretty "${type}__${key}" $type_pretty]
 	}
-
-	# We need to check if the attribute is not already present
-	# in the list, otherwise we could have duplicated.
-	if { ![empty_string_p $attr_id] } {
-	    lappend attribute_values $attr_id
-	    lappend default_names [attribute::pretty_name -attribute_id $attr_id]
-	}
-
-	if { [string equal [lsearch -exact $attr_val_name "[list $attr_id $attr]"] "-1"] } {
-	    lappend attr_val_name [list $attr_id $attr]
-	}
+	
     }
 
-    # To extend the result list using default attributes
-    if { [exists_and_not_null default_names] } {
-	set show_default_names "[join $default_names ", "], "
+    # create forms to add/remove columns from the multirow
+    if { [llength $add_columns] > 0 } {
+	set add_columns [concat [list [list "[_ contacts.--add_column--]" "" ""]] $add_columns]
     }
-
-    # To extend the reult list using the selected attributes
-    if { [exists_and_not_null attribute_names] } {
-	set show_names [join $attribute_names ", "]
+    if { [llength $remove_columns] > 0 } {
+	set remove_columns [concat [list [list "[_ contacts.--remove_column--]" "" ""]] $remove_columns]
     }
-
-    # Now we are going to create the select options
-    set attribute_values_query ""
-    if { [exists_and_not_null attribute_values] } {
-	set attribute_values_query "and lam.attribute_id not in ([template::util::tcl_to_sql_list $attribute_values])"
-    }
-    set attribute_options [db_list_of_lists get_ams_options " "]
-    set ams_options [list [list "- - - - - - - - - -" ""]]
-    foreach attribute $attribute_options {
-	set attribute_name [lang::util::localize [db_string get_ams_pretty_name { }]]
-	lappend ams_options [list $attribute_name $attribute]
-	}
     
-    ad_form -name extend_attributes -has_submit 1 -form {
-	{attribute_option:text(select),optional
-	    {label "[_ contacts.Extend_result_list_by]:"}
-	    {options { $ams_options }}
-	    {html { onChange "document.extend_attributes.submit();" }}
-	}
-	{search_id:text(hidden)
-	    {value "$search_id"}
-	}
-	{attribute_values:text(hidden)
-	    {value "$attribute_values"}
-	}
-	{attribute_names:text(hidden)
-	    {value "$attribute_names"}
-	}
-	{attr_val_name:text(hidden)
-	    {value "$attr_val_name"}
-	}
-    } -on_submit {
-	# We clear the list when no value is submited, otherwise
-        # we acumulate the extend values.
-        if { [empty_string_p $attribute_option] } {
-            set attribute_values [list]
-	    set attribute_names [list]
-	    set attr_val_name [list]
-        } else {
-	    set attribute $attribute_option
-	    ams::attribute::get -attribute_id $attribute -array attr_info
-	    set name $attr_info(attribute_name)
-	    lappend attribute_names [attribute::pretty_name -attribute_id $attribute]
+    set extended_columns_preserved $extended_columns
+    
+    ad_form \
+	-name "add_column_form" \
+	-method "GET" \
+	-export {format search_id query page page_size orderby} \
+	-has_submit "1" \
+	-has_edit "1" \
+	-form {
+	    {extended_columns:text(hidden),optional}
+	    {add_column:text(select_with_optgroup)
+		{label ""}
+		{html {onChange "document.add_column_form.submit();"}}
+		{options $add_columns}
+	    }
+	} \
+	-on_request {} \
+	-on_submit {}
+    
+    ad_form \
+	-name "remove_column_form" \
+	-method "GET" \
+	-export {format search_id query page page_size orderby} \
+	-has_submit "1" \
+	-has_edit "1" \
+	-form {
+	    {extended_columns:text(hidden),optional}
+	    {remove_column:text(select_with_optgroup)
+		{label ""}
+		{html {onChange "document.remove_column_form.submit();"}}
+		{options $remove_columns}
+	    }
+	} \
+	-on_request {} \
+	-on_submit {}
+    
 
-            lappend attribute_values $attribute
-	    lappend attr_val_name [list $attribute $name]
-        }
-        ad_returnredirect [export_vars -base "search" {search_id attribute_values attribute_names attr_val_name}]
-    }
+    set extended_columns $extended_columns_preserved
+    template::element::set_value add_column_form extended_columns $extended_columns
+    template::element::set_value remove_column_form extended_columns $extended_columns
+
 }
 
 
@@ -277,9 +205,7 @@
 
 if { $search_exists_p } {
     set conditions [list]
-    db_foreach selectqueries {
-        select condition_id, type as query_type, var_list as query_var_list from contact_search_conditions where search_id = :search_id
-    } {
+    db_foreach selectqueries {} {
 	set condition_name [contacts::search::condition_type -type $query_type -request pretty -var_list $query_var_list]
 	if { [empty_string_p $condition_name] } {
 	    set condition_name  "[_ contacts.Employees]"
Index: openacs-4/packages/contacts/www/search.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/search.xql,v
diff -u -r1.5 -r1.6
--- openacs-4/packages/contacts/www/search.xql	23 Nov 2005 17:29:47 -0000	1.5
+++ openacs-4/packages/contacts/www/search.xql	1 Apr 2006 07:07:16 -0000	1.6
@@ -1,6 +1,31 @@
 <?xml version="1.0"?>
 <queryset>
 
+<fullquery name="condition_exists_p">
+      <querytext>
+    select owner_id
+      from contact_searches
+     where search_id = :search_id
+      </querytext>
+</fullquery>
+
+<fullquery name="delete_column">
+      <querytext>
+    delete from contact_search_extend_map
+     where search_id = :search_id
+       and extend_column = :remove_column
+      </querytext>
+</fullquery>
+
+<fullquery name="insert_column">
+      <querytext>
+    insert into contact_search_extend_map
+           ( search_id, extend_column )
+           values
+           ( :search_id , :add_column )
+      </querytext>
+</fullquery>
+
 <fullquery name="contacts_pagination">
       <querytext>
     select gmm.member_id as party_id
@@ -147,7 +172,7 @@
     </querytext>
 </fullquery>
 
-<fullquery name="get_em">
+<fullquery name="get_search_info">
     <querytext>
 	select 
 		title, 
@@ -161,5 +186,13 @@
     </querytext>
 </fullquery>
 
+<fullquery name="selectqueries">
+    <querytext>
+        select condition_id, type as query_type, var_list as query_var_list
+          from contact_search_conditions
+         where search_id = :search_id
+    </querytext>
+</fullquery>
 
+
 </queryset>