[evolution] Bug #653892 - Allow to enter more than four email addresses



commit c2de4087369147ed6797f6b7866629ff9da19dfc
Author: Christian Schaarschmidt <schaarsc gmx de>
Date:   Tue May 6 14:31:50 2014 +0200

    Bug #653892 - Allow to enter more than four email addresses

 addressbook/gui/contact-editor/contact-editor.ui   |  181 ++-------
 .../gui/contact-editor/e-contact-editor-dyntable.c |   30 +-
 addressbook/gui/contact-editor/e-contact-editor.c  |  414 ++++++++------------
 addressbook/gui/widgets/eab-contact-merging.c      |   78 +++--
 addressbook/printing/e-contact-print.c             |  287 +++++++++++---
 .../evolution-addressbook-export-list-cards.c      |   11 +
 e-util/e-name-selector-entry.c                     |   98 +++--
 e-util/e-tree-model-generator.c                    |   12 +-
 e-util/e-tree-model-generator.h                    |    2 +-
 9 files changed, 574 insertions(+), 539 deletions(-)
---
diff --git a/addressbook/gui/contact-editor/contact-editor.ui 
b/addressbook/gui/contact-editor/contact-editor.ui
index 0c6edc8..d4ae442 100644
--- a/addressbook/gui/contact-editor/contact-editor.ui
+++ b/addressbook/gui/contact-editor/contact-editor.ui
@@ -311,157 +311,40 @@
                                 <property name="visible">True</property>
                                 <property name="label_xalign">0</property>
                                 <property name="shadow_type">none</property>
-                                <child>
-                                  <object class="GtkTable" id="email-table">
-                                    <property name="visible">True</property>
-                                    <property name="border_width">12</property>
-                                    <property name="n_rows">3</property>
-                                    <property name="n_columns">4</property>
-                                    <property name="column_spacing">6</property>
-                                    <property name="row_spacing">6</property>
-                                    <child>
-                                      <object class="GtkEntry" id="entry-email-3">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="name">email-3</property>
-                                      </object>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkEntry" id="entry-email-1">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="name">email-1</property>
-                                      </object>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkEntry" id="entry-email-2">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="name">email-2</property>
-                                      </object>
-                                      <packing>
-                                        <property name="left_attach">3</property>
-                                        <property name="right_attach">4</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkEntry" id="entry-email-4">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="name">email-4</property>
-                                      </object>
-                                      <packing>
-                                        <property name="left_attach">3</property>
-                                        <property name="right_attach">4</property>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkCheckButton" id="checkbutton-htmlmail">
-                                        <property name="label" translatable="yes">_Wants to receive HTML 
mail</property>
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="receives_default">False</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="draw_indicator">True</property>
-                                      </object>
-                                      <packing>
-                                        <property name="right_attach">4</property>
-                                        <property name="top_attach">2</property>
-                                        <property name="bottom_attach">3</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkComboBox" id="combobox-email-1">
-                                        <property name="visible">True</property>
-                                        <property name="model">model2</property>
-                                        <child>
-                                          <object class="GtkCellRendererText" id="renderer2"/>
-                                          <attributes>
-                                            <attribute name="text">0</attribute>
-                                          </attributes>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options">GTK_FILL</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkComboBox" id="combobox-email-3">
-                                        <property name="visible">True</property>
-                                        <property name="model">model3</property>
-                                        <child>
-                                          <object class="GtkCellRendererText" id="renderer3"/>
-                                          <attributes>
-                                            <attribute name="text">0</attribute>
-                                          </attributes>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options">GTK_FILL</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkComboBox" id="combobox-email-2">
-                                        <property name="visible">True</property>
-                                        <property name="model">model4</property>
-                                        <child>
-                                          <object class="GtkCellRendererText" id="renderer4"/>
-                                          <attributes>
-                                            <attribute name="text">0</attribute>
-                                          </attributes>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="left_attach">2</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options">GTK_FILL</property>
-                                      </packing>
-                                    </child>
+
                                     <child>
-                                      <object class="GtkComboBox" id="combobox-email-4">
+                                      <object class="GtkVBox" id="vboxmail">
                                         <property name="visible">True</property>
-                                        <property name="model">model5</property>
-                                        <child>
-                                          <object class="GtkCellRendererText" id="renderer5"/>
-                                          <attributes>
-                                            <attribute name="text">0</attribute>
-                                          </attributes>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="left_attach">2</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options">GTK_FILL</property>
-                                      </packing>
-                                    </child>
-                                  </object>
-                                </child>
+                                        <property name="border_width">12</property>
+                                        <property name="orientation">vertical</property>
+                                        <property name="spacing">6</property>
+                                                  
+                                           <child>
+                                             <object class="EContactEditorDynTable" 
type-func="e_contact_editor_dyntable_get_type" id="mail-dyntable">
+                                               <property name="visible">True</property>
+                                             </object>
+                                               <packing>
+                                                   <property name="position">0</property>
+                                               </packing>
+                                           </child>
+
+                                           <child>
+                                             <object class="GtkCheckButton" id="checkbutton-htmlmail">
+                                               <property name="label" translatable="yes">_Wants to receive 
HTML mail</property>
+                                               <property name="visible">True</property>
+                                               <property name="can_focus">True</property>
+                                               <property name="receives_default">False</property>
+                                               <property name="use_underline">True</property>
+                                               <property name="draw_indicator">True</property>
+                                             </object>
+                                             <packing>
+                                               <property name="position">1</property>
+                                             </packing>
+                                           </child>
+
+                                         </object>
+                                       </child>
+
                                 <child type="label">
                                   <object class="GtkHBox" id="hbox561">
                                     <property name="visible">True</property>
diff --git a/addressbook/gui/contact-editor/e-contact-editor-dyntable.c 
b/addressbook/gui/contact-editor/e-contact-editor-dyntable.c
index eb70272..68f298c 100644
--- a/addressbook/gui/contact-editor/e-contact-editor-dyntable.c
+++ b/addressbook/gui/contact-editor/e-contact-editor-dyntable.c
@@ -257,6 +257,9 @@ add_empty_entry (EContactEditorDynTable *dyntable)
        GtkWidget *box, *entry;
        EContactEditorDynTableClass *class;
 
+       if (dyntable->priv->curr_entries >= dyntable->priv->max_entries)
+               return;
+
        grid = GTK_GRID (dyntable);
        position_to_grid (dyntable, dyntable->priv->curr_entries, &col, &row);
 
@@ -331,7 +334,9 @@ remove_empty_entries (EContactEditorDynTable *dyntable, gboolean fillup)
 
        }
 
-       if (fillup && dyntable->priv->curr_entries < dyntable->priv->show_min_entries)
+       if (fillup
+               && (dyntable->priv->curr_entries < dyntable->priv->show_min_entries
+                           || (dyntable->priv->justified && col < dyntable->priv->columns-1)))
                add_empty_entry (dyntable);
 
 }
@@ -409,21 +414,28 @@ void
 e_contact_editor_dyntable_set_max_entries (EContactEditorDynTable *dyntable,
                                            guint max)
 {
-       GtkTreeIter iter;
        GtkTreeModel *store;
-       gboolean holds_data;
+       gint n_children;
 
        g_return_if_fail (max > 0);
 
        store = GTK_TREE_MODEL (dyntable->priv->data_store);
-       holds_data = gtk_tree_model_get_iter_first (store, &iter);
-       g_return_if_fail (!holds_data);
+
+       n_children = gtk_tree_model_iter_n_children (store, NULL);
+       if (n_children > max) {
+               g_warning ("Dyntable holds %i items, setting max to %i, instead of %i",
+                               n_children, n_children, max);
+               max = n_children;
+       }
 
        dyntable->priv->max_entries = max;
        if (dyntable->priv->show_max_entries>max)
                dyntable->priv->show_max_entries = max;
        if (dyntable->priv->show_min_entries>max)
                        dyntable->priv->show_min_entries = max;
+
+       remove_empty_entries (dyntable, TRUE);
+       show_button (dyntable);
 }
 
 /* show at least number_of_entries, with or without data */
@@ -492,10 +504,12 @@ e_contact_editor_dyntable_fill_in_data (EContactEditorDynTable *dyntable)
                w = gtk_grid_get_child_at (grid, col + 1, row);
                class->widget_fill (dyntable, w, str_data);
 
-               if (pos >= dyntable->priv->max_entries)
-                       break;
-
                valid = gtk_tree_model_iter_next (store, &iter);
+
+               if (valid && pos >= dyntable->priv->max_entries) {
+                       g_warning ("dyntable is configured with max_entries = %i, ignoring the rest.", 
dyntable->priv->max_entries);
+                       break;
+               }
        }
 
        /* fix visibility of added items */
diff --git a/addressbook/gui/contact-editor/e-contact-editor.c 
b/addressbook/gui/contact-editor/e-contact-editor.c
index ab75571..081c9fb 100644
--- a/addressbook/gui/contact-editor/e-contact-editor.c
+++ b/addressbook/gui/contact-editor/e-contact-editor.c
@@ -48,7 +48,7 @@
 
 #define SLOTS_PER_LINE 2
 #define SLOTS_IN_COLLAPSED_STATE SLOTS_PER_LINE
-#define EMAIL_SLOTS   4
+#define EMAIL_SLOTS   50
 #define PHONE_SLOTS   50
 #define SIP_SLOTS     4
 #define IM_SLOTS      50
@@ -179,7 +179,8 @@ im_service[] =
        { E_CONTACT_IM_ICQ,       N_ ("ICQ")       },
        { E_CONTACT_IM_GROUPWISE, N_ ("GroupWise") },
        { E_CONTACT_IM_SKYPE,     N_ ("Skype")     },
-       { E_CONTACT_IM_TWITTER,   N_ ("Twitter")   }
+       { E_CONTACT_IM_TWITTER,   N_ ("Twitter")   },
+       { E_CONTACT_IM_GOOGLE_TALK, N_ ("Google Talk")}
 };
 
 static EContactField
@@ -193,7 +194,8 @@ im_service_fetch_set[] =
        E_CONTACT_IM_ICQ,
        E_CONTACT_IM_GROUPWISE,
        E_CONTACT_IM_SKYPE,
-       E_CONTACT_IM_TWITTER
+       E_CONTACT_IM_TWITTER,
+       E_CONTACT_IM_GOOGLE_TALK
 };
 
 /* Defaults from the table above */
@@ -899,108 +901,28 @@ set_entry_text (EContactEditor *editor,
 }
 
 static void
-set_combo_box_active (EContactEditor *editor,
-                      GtkComboBox *combo_box,
-                      gint active)
-{
-       g_signal_handlers_block_matched (
-               combo_box, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
-       gtk_combo_box_set_active (combo_box, active);
-       g_signal_handlers_unblock_matched (
-               combo_box, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
-}
-
-static void
-init_email_record_location (EContactEditor *editor,
-                            gint record)
+init_email_record_location (EContactEditor *editor)
 {
-       GtkComboBox *location_combo_box;
-       GtkWidget *email_entry;
-       gchar     *widget_name;
-       gint       i;
-       GtkTreeIter iter;
+       GtkWidget *w;
        GtkListStore *store;
+       gint i;
+       EContactEditorDynTable *dyntable;
 
-       widget_name = g_strdup_printf ("entry-email-%d", record);
-       email_entry = e_builder_get_widget (editor->priv->builder, widget_name);
-       g_free (widget_name);
-
-       widget_name = g_strdup_printf ("combobox-email-%d", record);
-       location_combo_box = GTK_COMBO_BOX (
-               e_builder_get_widget (editor->priv->builder, widget_name));
-       g_free (widget_name);
-
-       store = GTK_LIST_STORE (gtk_combo_box_get_model (location_combo_box));
-       gtk_list_store_clear (store);
+       w = e_builder_get_widget (editor->priv->builder, "mail-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
+       store = e_contact_editor_dyntable_get_combo_store (dyntable);
 
        for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
+               GtkTreeIter iter;
+
                gtk_list_store_append (store, &iter);
-               gtk_list_store_set (
-                       store, &iter,
-                       0, _(common_location[i].pretty_name),
-                       -1);
+               gtk_list_store_set (store, &iter,
+                                   DYNTABLE_COMBO_COLUMN_TEXT, _(common_location[i].pretty_name),
+                                   DYNTABLE_COMBO_COLUMN_SENSITIVE, TRUE,
+                                   -1);
        }
 
-       g_signal_connect_swapped (
-               location_combo_box, "changed",
-               G_CALLBACK (gtk_widget_grab_focus), email_entry);
-       g_signal_connect (
-               location_combo_box, "changed",
-               G_CALLBACK (object_changed), editor);
-       g_signal_connect (
-               email_entry, "changed",
-               G_CALLBACK (object_changed), editor);
-       g_signal_connect_swapped (
-               email_entry, "activate",
-               G_CALLBACK (entry_activated), editor);
-}
-
-static void
-fill_in_email_record (EContactEditor *editor,
-                      gint record,
-                      const gchar *address,
-                      gint location)
-{
-       GtkWidget *location_combo_box;
-       GtkWidget *email_entry;
-       gchar     *widget_name;
-
-       widget_name = g_strdup_printf ("combobox-email-%d", record);
-       location_combo_box = e_builder_get_widget (editor->priv->builder, widget_name);
-       g_free (widget_name);
-
-       widget_name = g_strdup_printf ("entry-email-%d", record);
-       email_entry = e_builder_get_widget (editor->priv->builder, widget_name);
-       g_free (widget_name);
-
-       set_combo_box_active (
-               editor, GTK_COMBO_BOX (location_combo_box),
-               location >= 0 ? location : email_default[2]);
-       set_entry_text (editor, GTK_ENTRY (email_entry), address ? address : "");
-}
-
-static void
-extract_email_record (EContactEditor *editor,
-                      gint record,
-                      gchar **address,
-                      gint *location)
-{
-       GtkWidget *location_combo_box;
-       GtkWidget *email_entry;
-       gchar *widget_name;
-       const gchar *text;
-
-       widget_name = g_strdup_printf ("combobox-email-%d", record);
-       location_combo_box = e_builder_get_widget (editor->priv->builder, widget_name);
-       g_free (widget_name);
-
-       widget_name = g_strdup_printf ("entry-email-%d", record);
-       email_entry = e_builder_get_widget (editor->priv->builder, widget_name);
-       g_free (widget_name);
-
-       text = gtk_entry_get_text (GTK_ENTRY (email_entry));
-       *address  = g_strstrip (g_strdup (text));
-       *location = gtk_combo_box_get_active (GTK_COMBO_BOX (location_combo_box));
+       e_contact_editor_dyntable_set_combo_defaults (dyntable, email_default, G_N_ELEMENTS (email_default));
 }
 
 static const gchar *
@@ -1127,99 +1049,55 @@ set_ui_slot (EVCardAttribute *attr,
        g_free (slot_str);
 }
 
-static gint
-alloc_ui_slot (EContactEditor *editor,
-               const gchar *widget_base,
-               gint preferred_slot,
-               gint num_slots)
-{
-       gchar       *widget_name;
-       GtkWidget   *widget;
-       const gchar *entry_contents;
-       gint         i;
-
-       /* See if we can get the preferred slot */
-
-       if (preferred_slot >= 1) {
-               widget_name = g_strdup_printf ("%s-%d", widget_base, preferred_slot);
-               widget = e_builder_get_widget (editor->priv->builder, widget_name);
-               entry_contents = gtk_entry_get_text (GTK_ENTRY (widget));
-               g_free (widget_name);
-
-               if (STRING_IS_EMPTY (entry_contents))
-                       return preferred_slot;
-       }
-
-       /* Find first empty slot */
-
-       for (i = 1; i <= num_slots; i++) {
-               widget_name = g_strdup_printf ("%s-%d", widget_base, i);
-               widget = e_builder_get_widget (editor->priv->builder, widget_name);
-               entry_contents = gtk_entry_get_text (GTK_ENTRY (widget));
-               g_free (widget_name);
-
-               if (STRING_IS_EMPTY (entry_contents))
-                       return i;
-       }
-
-       return -1;
-}
-
-static void
-free_attr_list (GList *attr_list)
-{
-       GList *l;
-
-       for (l = attr_list; l; l = g_list_next (l)) {
-               EVCardAttribute *attr = l->data;
-               e_vcard_attribute_free (attr);
-       }
-
-       g_list_free (attr_list);
-}
-
 static void
 fill_in_email (EContactEditor *editor)
 {
        GList *email_attr_list;
        GList *l;
-       gint   record_n;
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+       GtkListStore *data_store;
+       GtkTreeIter iter;
+
+       w = e_builder_get_widget (editor->priv->builder, "mail-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
 
        /* Clear */
 
-       for (record_n = 1; record_n <= EMAIL_SLOTS; record_n++) {
-               fill_in_email_record (
-                       editor, record_n, NULL, email_default[record_n - 1]);
-       }
+       e_contact_editor_dyntable_clear_data (dyntable);
 
        /* Fill in */
 
+       data_store = e_contact_editor_dyntable_extract_data (dyntable);
+
        email_attr_list = e_contact_get_attributes (
                editor->priv->contact, E_CONTACT_EMAIL);
 
-       for (record_n = 1, l = email_attr_list;
-               l && record_n <= EMAIL_SLOTS; l = g_list_next (l)) {
+       for (l = email_attr_list; l; l = g_list_next (l)) {
                EVCardAttribute *attr = l->data;
                gchar           *email_address;
+               gint             email_location;
                gint             slot;
 
                email_address = e_vcard_attribute_get_value (attr);
-               slot = alloc_ui_slot (
-                       editor, "entry-email",
-                       get_ui_slot (attr), EMAIL_SLOTS);
+               email_location = get_email_location (attr);
+               slot = get_ui_slot (attr);
                if (slot < 1)
-                       break;
-
-               fill_in_email_record (
-                       editor, slot, email_address,
-                       get_email_location (attr));
+                       slot = EMAIL_SLOTS + 1; //add at the end
 
-               record_n++;
+               gtk_list_store_append (data_store, &iter);
+               gtk_list_store_set (data_store, &iter,
+                                   DYNTABLE_STORE_COLUMN_SORTORDER, slot,
+                                   DYNTABLE_STORE_COLUMN_SELECTED_ITEM, email_location,
+                                   DYNTABLE_STORE_COLUMN_ENTRY_STRING, email_address,
+                                   -1);
 
                g_free (email_address);
        }
 
        g_list_free_full (email_attr_list, (GDestroyNotify) e_vcard_attribute_free);
+
+       e_contact_editor_dyntable_fill_in_data (dyntable);
 }
 
 static void
@@ -1229,32 +1107,45 @@ extract_email (EContactEditor *editor)
        GList *old_attr_list;
        GList *ll;
        gint   i;
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+       GtkListStore *data_store;
+       GtkTreeModel *tree_model;
+       GtkTreeIter iter;
+       gboolean valid;
+
+       w = e_builder_get_widget (editor->priv->builder, "mail-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
+       data_store = e_contact_editor_dyntable_extract_data (dyntable);
+       tree_model = GTK_TREE_MODEL (data_store);
 
-       for (i = 1; i <= EMAIL_SLOTS; i++) {
+       valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+       while (valid) {
                gchar *address;
                gint   location;
+               EVCardAttribute *attr;
 
-               extract_email_record (editor, i, &address, &location);
+               attr = e_vcard_attribute_new (
+                       "", e_contact_vcard_attribute (E_CONTACT_EMAIL));
 
-               if (!STRING_IS_EMPTY (address)) {
-                       EVCardAttribute *attr;
-                       attr = e_vcard_attribute_new (
-                               "", e_contact_vcard_attribute (E_CONTACT_EMAIL));
+               gtk_tree_model_get (tree_model,&iter,
+                                  DYNTABLE_STORE_COLUMN_SELECTED_ITEM, &location,
+                                  DYNTABLE_STORE_COLUMN_ENTRY_STRING, &address,
+                                  -1);
 
-                       if (location >= 0)
-                               e_vcard_attribute_add_param_with_value (
-                                       attr,
-                                       e_vcard_attribute_param_new (EVC_TYPE),
-                                       email_index_to_location (location));
+               if (location >= 0)
+                       e_vcard_attribute_add_param_with_value (
+                               attr,
+                               e_vcard_attribute_param_new (EVC_TYPE),
+                               email_index_to_location (location));
 
-                       e_vcard_attribute_add_value (attr, address);
-                       set_ui_slot (attr, i);
+               e_vcard_attribute_add_value (attr, address);
 
-                       attr_list = g_list_append (attr_list, attr);
-               }
+               attr_list = g_list_prepend (attr_list, attr);
 
-               g_free (address);
+               valid = gtk_tree_model_iter_next (tree_model, &iter);
        }
+       attr_list = g_list_reverse (attr_list);
 
        /* Splice in the old attributes, minus the EMAIL_SLOTS first */
 
@@ -1269,47 +1160,41 @@ extract_email (EContactEditor *editor)
 
        e_contact_set_attributes (editor->priv->contact, E_CONTACT_EMAIL, attr_list);
 
-       free_attr_list (attr_list);
-}
-
-static void
-sensitize_email_record (EContactEditor *editor,
-                        gint record,
-                        gboolean enabled)
-{
-       GtkWidget *location_combo_box;
-       GtkWidget *email_entry;
-       gchar     *widget_name;
-
-       widget_name = g_strdup_printf ("combobox-email-%d", record);
-       location_combo_box = e_builder_get_widget (editor->priv->builder, widget_name);
-       g_free (widget_name);
-
-       widget_name = g_strdup_printf ("entry-email-%d", record);
-       email_entry = e_builder_get_widget (editor->priv->builder, widget_name);
-       g_free (widget_name);
-
-       gtk_widget_set_sensitive (location_combo_box, enabled);
-       gtk_editable_set_editable (GTK_EDITABLE (email_entry), enabled);
+       g_list_free_full (attr_list, (GDestroyNotify) e_vcard_attribute_free);
 }
 
 static void
 sensitize_email (EContactEditor *editor)
 {
-       gint i;
-
-       for (i = 1; i <= EMAIL_SLOTS; i++) {
-               gboolean enabled = TRUE;
-
-               if (!editor->priv->target_editable)
-                       enabled = FALSE;
+       gboolean enabled = FALSE;
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+       guint max_entries = SLOTS_IN_COLLAPSED_STATE;
 
-               if (E_CONTACT_FIRST_EMAIL_ID + i - 1 <= E_CONTACT_LAST_EMAIL_ID &&
-                   !is_field_supported (editor, E_CONTACT_FIRST_EMAIL_ID + i - 1))
-                       enabled = FALSE;
+       w = e_builder_get_widget (editor->priv->builder, "mail-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
 
-               sensitize_email_record (editor, i, enabled);
+       if (editor->priv->target_editable) {
+               if (is_field_supported (editor, E_CONTACT_EMAIL)) {
+                       enabled = TRUE;
+                       max_entries = EMAIL_SLOTS;
+               } else if (is_field_supported (editor, E_CONTACT_EMAIL_4)) {
+                       enabled = TRUE;
+                       max_entries = 4;
+               } else if (is_field_supported (editor, E_CONTACT_EMAIL_3)) {
+                       enabled = TRUE;
+                       max_entries = 3;
+               } else if (is_field_supported (editor, E_CONTACT_EMAIL_2)) {
+                       enabled = TRUE;
+                       max_entries = 2;
+               } else if (is_field_supported (editor, E_CONTACT_EMAIL_1)) {
+                       enabled = TRUE;
+                       max_entries = 1;
+               }
        }
+
+       gtk_widget_set_sensitive (w, enabled);
+       e_contact_editor_dyntable_set_max_entries (dyntable, max_entries);
 }
 
 static void
@@ -1427,43 +1312,52 @@ static void
 expand_mail (EContactEditor *editor,
              gboolean expanded)
 {
-       GtkTable  *table;
-       GtkWidget *check;
-       const gchar *names[] = {
-               "entry-email-2", "combobox-email-2",
-               "entry-email-3", "combobox-email-3",
-               "entry-email-4", "combobox-email-4",
-               NULL
-       };
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+
        set_arrow_image (editor, "arrow-mail-expand", expanded);
-       expand_widget_list (editor, names, expanded);
 
-       /* move 'use html mail' into position */
-       check = e_builder_get_widget (editor->priv->builder, "checkbutton-htmlmail");
-       table = GTK_TABLE (e_builder_get_widget (editor->priv->builder, "email-table"));
-       if (check != NULL && table != NULL) {
-               GtkWidget *parent;
-
-               g_object_ref (check);
-               parent = gtk_widget_get_parent (check);
-               gtk_container_remove (GTK_CONTAINER (parent), check);
-               if (expanded)
-                       gtk_table_attach_defaults (table, check, 0, 4, 2, 3);
-               else
-                       gtk_table_attach_defaults (table, check, 2, 4, 0, 1);
-               g_object_unref (check);
-       }
+       w = e_builder_get_widget (editor->priv->builder, "mail-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
+
+       if (expanded)
+               e_contact_editor_dyntable_set_show_max (dyntable, EMAIL_SLOTS);
+       else
+               e_contact_editor_dyntable_set_show_max (dyntable, SLOTS_IN_COLLAPSED_STATE);
+}
+
+static void
+row_added_mail (EContactEditorDynTable *dyntable, EContactEditor *editor)
+{
+       expand_mail (editor, TRUE);
 }
 
 static void
 init_email (EContactEditor *editor)
 {
-       gint i;
+       GtkWidget *w;
+       EContactEditorDynTable *dyntable;
+
+       w = e_builder_get_widget (editor->priv->builder, "mail-dyntable");
+       dyntable = E_CONTACT_EDITOR_DYNTABLE (w);
 
-       for (i = 1; i <= EMAIL_SLOTS; i++)
-               init_email_record_location (editor, i);
+       e_contact_editor_dyntable_set_max_entries (dyntable, EMAIL_SLOTS);
+       e_contact_editor_dyntable_set_num_columns (dyntable, SLOTS_PER_LINE, TRUE);
+       e_contact_editor_dyntable_set_show_min (dyntable, SLOTS_IN_COLLAPSED_STATE);
 
-       expand_mail (editor, !editor->priv->compress_ui);
+       g_signal_connect (
+               w, "changed",
+               G_CALLBACK (object_changed), editor);
+       g_signal_connect_swapped (
+               w, "activate",
+               G_CALLBACK (entry_activated), editor);
+       g_signal_connect (
+               w, "row-added",
+               G_CALLBACK (row_added_mail), editor);
+
+       init_email_record_location (editor);
+
+       expand_mail (editor, TRUE);
 }
 
 static void
@@ -1496,6 +1390,9 @@ fill_in_phone (EContactEditor *editor)
                gint phone_type;
 
                slot = get_ui_slot (attr);
+               if (slot < 0)
+                       slot = PHONE_SLOTS + 1; /* append at the end */
+
                phone_type = get_phone_type (attr);
                phone = e_vcard_attribute_get_value (attr);
 
@@ -1510,9 +1407,8 @@ fill_in_phone (EContactEditor *editor)
        }
 
        e_contact_editor_dyntable_fill_in_data (dyntable);
-       g_list_free_full (tel_attr_list, (GDestroyNotify) e_vcard_attribute_free);
 
-       expand_phone (editor, TRUE);
+       g_list_free_full (tel_attr_list, (GDestroyNotify) e_vcard_attribute_free);
 }
 
 static void
@@ -1626,7 +1522,7 @@ init_phone (EContactEditor *editor)
 
        e_contact_editor_dyntable_set_max_entries (dyntable, PHONE_SLOTS);
        e_contact_editor_dyntable_set_num_columns (dyntable, SLOTS_PER_LINE, TRUE);
-       e_contact_editor_dyntable_set_show_min (dyntable, SLOTS_PER_LINE);
+       e_contact_editor_dyntable_set_show_min (dyntable, SLOTS_IN_COLLAPSED_STATE);
 
        g_signal_connect (
                w, "changed",
@@ -1639,6 +1535,8 @@ init_phone (EContactEditor *editor)
                G_CALLBACK (row_added_phone), editor);
 
        init_phone_record_type (editor);
+
+       expand_phone (editor, TRUE);
 }
 
 static void
@@ -1676,12 +1574,17 @@ static void
 sensitize_phone (EContactEditor *editor)
 {
        GtkWidget *w;
-       gboolean enabled = TRUE;
+       gboolean enabled = FALSE;
+       int i;
 
        w = e_builder_get_widget (editor->priv->builder, "phone-dyntable");
 
-       if (!editor->priv->target_editable)
-               enabled = FALSE;
+       if (editor->priv->target_editable) {
+               enabled = is_field_supported (editor, E_CONTACT_TEL);
+               for (i = 0; i < G_N_ELEMENTS (phones) && !enabled; i++) {
+                       enabled = is_field_supported (editor, phones[i].field_id);
+               }
+       }
 
        gtk_widget_set_sensitive (w, enabled);
 
@@ -1734,8 +1637,6 @@ fill_in_sip (EContactEditor *editor)
 
        e_contact_editor_dyntable_fill_in_data (dyntable);
        g_list_free_full (sip_attr_list, (GDestroyNotify) e_vcard_attribute_free);
-
-       expand_sip (editor, TRUE);
 }
 
 static void
@@ -1845,7 +1746,7 @@ init_sip (EContactEditor *editor)
 
        e_contact_editor_dyntable_set_max_entries (dyntable, SIP_SLOTS);
        e_contact_editor_dyntable_set_num_columns (dyntable, SLOTS_PER_LINE, TRUE);
-       e_contact_editor_dyntable_set_show_min (dyntable, SLOTS_PER_LINE);
+       e_contact_editor_dyntable_set_show_min (dyntable, SLOTS_IN_COLLAPSED_STATE);
 
        g_signal_connect (
                w, "changed",
@@ -1858,6 +1759,8 @@ init_sip (EContactEditor *editor)
                G_CALLBACK (row_added_sip), editor);
 
        init_sip_record_type (editor);
+
+       expand_sip (editor, TRUE);
 }
 
 static void
@@ -1950,7 +1853,7 @@ init_im (EContactEditor *editor)
 
        e_contact_editor_dyntable_set_max_entries (dyntable, IM_SLOTS);
        e_contact_editor_dyntable_set_num_columns (dyntable, SLOTS_PER_LINE, TRUE);
-       e_contact_editor_dyntable_set_show_min (dyntable, SLOTS_PER_LINE);
+       e_contact_editor_dyntable_set_show_min (dyntable, SLOTS_IN_COLLAPSED_STATE);
 
        g_signal_connect (
                w, "changed",
@@ -1963,6 +1866,8 @@ init_im (EContactEditor *editor)
                G_CALLBACK (row_added_im), editor);
 
        init_im_record_type (editor);
+
+       expand_im (editor, TRUE);
 }
 
 static gint
@@ -2034,8 +1939,6 @@ fill_in_im (EContactEditor *editor)
        g_list_free_full (im_attr_list, (GDestroyNotify) e_vcard_attribute_free);
 
        e_contact_editor_dyntable_fill_in_data (dyntable);
-
-       expand_im (editor, TRUE);
 }
 
 static void
@@ -4263,10 +4166,7 @@ expand_im_toggle (EContactEditor *ce)
 static void
 expand_mail_toggle (EContactEditor *ce)
 {
-       GtkWidget *mail;
-
-       mail = e_builder_get_widget (ce->priv->builder, "entry-email-4");
-       expand_mail (ce, !gtk_widget_get_visible (mail));
+       expand_mail (ce, !is_arrow_image_arrow_down (ce, "arrow-mail-expand"));
 }
 
 static void
diff --git a/addressbook/gui/widgets/eab-contact-merging.c b/addressbook/gui/widgets/eab-contact-merging.c
index c788d40..3843178 100644
--- a/addressbook/gui/widgets/eab-contact-merging.c
+++ b/addressbook/gui/widgets/eab-contact-merging.c
@@ -543,40 +543,64 @@ check_if_same (EContact *contact,
                EContact *match)
 {
        EContactField field;
-       GList *email_attr_list;
-       gint num_of_email;
-       gchar *str = NULL, *string = NULL, *string1 = NULL;
+       gchar *string = NULL, *string1 = NULL;
        gboolean res = TRUE;
 
-       email_attr_list = e_contact_get_attributes (match, E_CONTACT_EMAIL);
-       num_of_email = g_list_length (email_attr_list);
 
        for (field = E_CONTACT_FULL_NAME; res && field != (E_CONTACT_LAST_SIMPLE_STRING -1); field++) {
 
-               if ((field == E_CONTACT_EMAIL_1 || field == E_CONTACT_EMAIL_2
-                    || field == E_CONTACT_EMAIL_3 || field == E_CONTACT_EMAIL_4) && (num_of_email < 4)) {
-                       str = (gchar *) e_contact_get_const (contact, field);
-                       switch (num_of_email)
-                       {
-                       case 0:
+               if (field == E_CONTACT_EMAIL_1) {
+                       GList *email_attr_list1, *email_attr_list2, *iter1, *iter2;
+                       gint num_of_email1, num_of_email2;
+
+                       email_attr_list1 = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
+                       num_of_email1 = g_list_length (email_attr_list1);
+
+                       email_attr_list2 = e_contact_get_attributes (match, E_CONTACT_EMAIL);
+                       num_of_email2 = g_list_length (email_attr_list2);
+
+                       if (num_of_email1 != num_of_email2) {
                                res = FALSE;
                                break;
-                       case 1:
-                               if ((str && *str) && (g_ascii_strcasecmp (e_contact_get_const (match, 
E_CONTACT_EMAIL_1),str)))
-                                       res = FALSE;
-                               break;
-                       case 2:
-                               if ((str && *str) && (g_ascii_strcasecmp (str,e_contact_get_const (match, 
E_CONTACT_EMAIL_1))) &&
-                                               (g_ascii_strcasecmp (e_contact_get_const (match, 
E_CONTACT_EMAIL_2),str)))
-                                       res = FALSE;
-                               break;
-                       case 3:
-                               if ((str && *str) && (g_ascii_strcasecmp (e_contact_get_const (match, 
E_CONTACT_EMAIL_1),str)) &&
-                                               (g_ascii_strcasecmp (e_contact_get_const (match, 
E_CONTACT_EMAIL_2),str)) &&
-                                               (g_ascii_strcasecmp (e_contact_get_const (match, 
E_CONTACT_EMAIL_3),str)))
-                                       res = FALSE;
-                               break;
+                       } else { /* Do pairwise-comparisons on all of the e-mail addresses. */
+                               iter1 = email_attr_list1;
+                               while (iter1) {
+                                       gboolean         match = FALSE;
+                                       EVCardAttribute *attr;
+                                       gchar           *email_address1;
+
+                                       attr = iter1->data;
+                                       email_address1 = e_vcard_attribute_get_value (attr);
+
+                                       iter2 = email_attr_list2;
+                                       while ( iter2 && match == FALSE) {
+                                               gchar *email_address2;
+
+                                               attr = iter2->data;
+                                               email_address2 = e_vcard_attribute_get_value (attr);
+
+                                               if (g_ascii_strcasecmp (email_address1, email_address2) == 0) 
{
+                                                       match = TRUE;
+                                               }
+
+                                               g_free (email_address2);
+                                               iter2 = g_list_next (iter2);
+                                       }
+
+                                       g_free (email_address1);
+                                       iter1 = g_list_next (iter1);
+
+                                       if (match == FALSE) {
+                                               res = FALSE;
+                                               break;
+                                       }
+                               }
                        }
+
+                       g_list_free_full (email_attr_list1, (GDestroyNotify) e_vcard_attribute_free);
+                       g_list_free_full (email_attr_list2, (GDestroyNotify) e_vcard_attribute_free);
+               } else if (field > E_CONTACT_FIRST_EMAIL_ID && field <= E_CONTACT_LAST_EMAIL_ID) {
+                       /* nothing to do, all emails are checked above */
                }
                else {
                        string = (gchar *) e_contact_get_const (contact, field);
@@ -592,8 +616,6 @@ check_if_same (EContact *contact,
                }
        }
 
-       g_list_free_full (email_attr_list, (GDestroyNotify) e_vcard_attribute_free);
-
        return res;
 }
 
diff --git a/addressbook/printing/e-contact-print.c b/addressbook/printing/e-contact-print.c
index 3b1b1cd..bcd27f8 100644
--- a/addressbook/printing/e-contact-print.c
+++ b/addressbook/printing/e-contact-print.c
@@ -63,6 +63,61 @@ struct _EContactPrintContext
        GSList *contact_list;
 };
 
+/* TODO refactor phone_type
+ * to avoid build dependency loop, code related to phone types was copied from e-contact-editor.c
+ * once e-contact offers some kind of "translation service" code should be removed from here.
+ */
+static struct {
+       EContactField field_id;
+       const gchar *type_1;
+       const gchar *type_2;
+} phones[] = {
+       { E_CONTACT_PHONE_ASSISTANT,    EVC_X_ASSISTANT,       NULL    },
+       { E_CONTACT_PHONE_BUSINESS,     "WORK",                "VOICE" },
+       { E_CONTACT_PHONE_BUSINESS_FAX, "WORK",                "FAX"   },
+       { E_CONTACT_PHONE_CALLBACK,     EVC_X_CALLBACK,        NULL    },
+       { E_CONTACT_PHONE_CAR,          "CAR",                 NULL    },
+       { E_CONTACT_PHONE_COMPANY,      "X-EVOLUTION-COMPANY", NULL    },
+       { E_CONTACT_PHONE_HOME,         "HOME",                "VOICE" },
+       { E_CONTACT_PHONE_HOME_FAX,     "HOME",                "FAX"   },
+       { E_CONTACT_PHONE_ISDN,         "ISDN",                NULL    },
+       { E_CONTACT_PHONE_MOBILE,       "CELL",                NULL    },
+       { E_CONTACT_PHONE_OTHER,        "VOICE",               NULL    },
+       { E_CONTACT_PHONE_OTHER_FAX,    "FAX",                 NULL    },
+       { E_CONTACT_PHONE_PAGER,        "PAGER",               NULL    },
+       { E_CONTACT_PHONE_PRIMARY,      "PREF",                NULL    },
+       { E_CONTACT_PHONE_RADIO,        EVC_X_RADIO,           NULL    },
+       { E_CONTACT_PHONE_TELEX,        EVC_X_TELEX,           NULL    },
+       { E_CONTACT_PHONE_TTYTDD,       EVC_X_TTYTDD,          NULL    }
+};
+
+static gint
+get_phone_type (EVCardAttribute *attr)
+{
+       gint i;
+
+       for (i = 0; i < G_N_ELEMENTS (phones); i++) {
+               if (e_vcard_attribute_has_type (attr, phones[i].type_1) &&
+                   (phones[i].type_2 == NULL || e_vcard_attribute_has_type (attr, phones[i].type_2)))
+                       return i;
+       }
+
+       return -1;
+}
+
+static gint
+get_phone_type_field_id (EVCardAttribute *attr)
+{
+       gint type_index;
+
+       type_index = get_phone_type (attr);
+
+       if (type_index >= 0)
+               return phones [type_index].field_id;
+       else
+               return -1;
+}
+
 static gdouble
 get_font_height (PangoFontDescription *desc)
 {
@@ -227,6 +282,30 @@ e_contact_start_new_column (EContactPrintContext *ctxt)
        }
 }
 
+/*
+ * returns (transfer-full) a formated email or a copy of value if parsing failed.
+ */
+static gchar*
+format_email (const gchar* value)
+{
+       gchar *email = NULL, *name = NULL;
+
+       if (eab_parse_qp_email (value, &name, &email)) {
+               gchar* res;
+               if (name && *name)
+                       res = g_strdup_printf ("%s <%s>", name, email);
+               else
+                       res = g_strdup_printf ("%s", email);
+
+               g_free (name);
+               g_free (email);
+
+               return res;
+       }
+
+       return g_strdup (value);
+}
+
 static gchar *
 get_contact_string_value (EContact *contact,
                           gint field)
@@ -243,21 +322,8 @@ get_contact_string_value (EContact *contact,
            field == E_CONTACT_EMAIL_2 ||
            field == E_CONTACT_EMAIL_3 ||
            field == E_CONTACT_EMAIL_4) {
-               gchar *email = NULL, *name = NULL;
-
-               if (eab_parse_qp_email (value, &name, &email)) {
-                       gchar *res;
-
-                       if (name && *name)
-                               res = g_strdup_printf ("%s <%s>", name, email);
-                       else
-                               res = g_strdup_printf ("%s", email);
-
-                       g_free (name);
-                       g_free (email);
-
-                       return res;
-               }
+               gchar* res = format_email (value);
+               return res;
        }
        return g_strdup (value);
 }
@@ -296,8 +362,34 @@ e_contact_get_contact_height (EContact *contact,
                        "%s:  %s",
                        e_contact_pretty_name (field), value);
 
-               cntct_height += e_contact_text_height (
-                       ctxt->context, ctxt->style->body_font, text);
+               if (field == E_CONTACT_FIRST_EMAIL_ID) {
+                       GList *emails = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
+                       guint n = g_list_length (emails);
+                       cntct_height += n * e_contact_text_height (
+                                               ctxt->context,
+                                               ctxt->style->body_font,
+                                               text);
+                       g_list_free_full (emails, (GDestroyNotify) e_vcard_attribute_free);
+               } else if (field > E_CONTACT_FIRST_EMAIL_ID &&
+                          field <= E_CONTACT_LAST_EMAIL_ID) {
+                       /* ignore */
+               } else if (field == E_CONTACT_FIRST_PHONE_ID) {
+                       GList *phones = e_contact_get_attributes (contact, E_CONTACT_TEL);
+                       guint n = g_list_length (phones);
+                       cntct_height += n * e_contact_text_height (
+                                               ctxt->context,
+                                               ctxt->style->body_font,
+                                               text);
+                       g_list_free_full (phones, (GDestroyNotify) e_vcard_attribute_free);
+               } else if (field > E_CONTACT_FIRST_PHONE_ID &&
+                          field <= E_CONTACT_LAST_PHONE_ID) {
+                       /* ignore */
+               } else {
+                       cntct_height += e_contact_text_height (
+                                       ctxt->context,
+                                       ctxt->style->body_font,
+                                       text);
+               }
 
                cntct_height += .2 * get_font_height (ctxt->style->body_font);
 
@@ -309,19 +401,116 @@ e_contact_get_contact_height (EContact *contact,
 
        return cntct_height;
 }
+static void
+print_line (EContactPrintContext *ctxt,
+            const gchar *pretty_name,
+            const gchar *value)
+{
+       GtkPageSetup *setup;
+       gdouble page_height;
+       gint wrapped_lines = 0;
+       gchar *text;
+
+       setup = gtk_print_context_get_page_setup (ctxt->context);
+       page_height = gtk_page_setup_get_page_height (setup, GTK_UNIT_POINTS);
+
+       text = g_strdup_printf (
+               "%s:  %s",
+               pretty_name, value);
+
+
+       if (ctxt->y > page_height)
+               e_contact_start_new_column (ctxt);
+
+       if (ctxt->pages == ctxt->page_nr)
+               e_contact_output (
+                       ctxt->context, ctxt->style->body_font,
+                       ctxt->x, ctxt->y, ctxt->column_width + 4, text);
+
+       if (get_font_width (ctxt->context,
+               ctxt->style->body_font, text) > ctxt->column_width)
+               wrapped_lines =
+                       (get_font_width (ctxt->context,
+                       ctxt->style->body_font, text) /
+                       (ctxt->column_width + 4)) + 1;
+       ctxt->y =
+               ctxt->y + ((wrapped_lines + 1) *
+               e_contact_text_height (
+                       ctxt->context,
+                       ctxt->style->body_font,
+                       text));
+
+       ctxt->y += .2 * get_font_height (ctxt->style->body_font);
+
+       g_free (text);
+}
+
+static void
+print_emails (EContact *contact,
+              EContactPrintContext *ctxt)
+{
+       gint i;
+       GList *emails, *l;
+
+       emails = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
+
+       for (i = 1, l = emails; l; l = g_list_next (l), i++) {
+               EVCardAttribute *attr = l->data;
+               gchar *email_address;
+               gchar *formatted_email;
+               gchar *pretty_name;
+
+               email_address = e_vcard_attribute_get_value (attr);
+               formatted_email = format_email (email_address);
+               pretty_name = g_strdup_printf ("%s %2d", N_ ("Email"), i);
+
+               print_line (ctxt, pretty_name, formatted_email);
+
+               g_free (pretty_name);
+               g_free (email_address);
+               g_free (formatted_email);
+       }
+
+       g_list_free_full (emails, (GDestroyNotify) e_vcard_attribute_free);
+}
+
+static void
+print_phones (EContact *contact,
+              EContactPrintContext * ctxt)
+{
+       GList *phones, *l;
+
+       phones = e_contact_get_attributes (contact, E_CONTACT_TEL);
+
+       for (l = phones; l; l = g_list_next (l)) {
+               EVCardAttribute *attr = l->data;
+               gchar *phone;
+               gint field_id;
+               const gchar *pretty_name;
+
+               phone = e_vcard_attribute_get_value (attr);
+               field_id = get_phone_type_field_id (attr);
+               if (field_id >= 0) {
+                       pretty_name = e_contact_pretty_name (field_id);
+               } else {
+                       pretty_name = N_ ("unknown phone type");
+               }
+               print_line (ctxt, pretty_name, phone);
+
+               g_free (phone);
+       }
+
+       g_list_free_full (phones, (GDestroyNotify) e_vcard_attribute_free);
+}
 
 static void
 e_contact_print_contact (EContact *contact,
                          EContactPrintContext *ctxt)
 {
-       GtkPageSetup *setup;
        gchar *file_as;
        cairo_t *cr;
-       gdouble page_height;
        gint field;
 
-       setup = gtk_print_context_get_page_setup (ctxt->context);
-       page_height = gtk_page_setup_get_page_height (setup, GTK_UNIT_POINTS);
 
        cr = gtk_print_context_get_cairo_context (ctxt->context);
        cairo_save (cr);
@@ -353,45 +542,29 @@ e_contact_print_contact (EContact *contact,
 
        for (field = E_CONTACT_FILE_AS; field != E_CONTACT_LAST_SIMPLE_STRING; field++)
        {
-               gchar *value;
-               gchar *text;
-               gint wrapped_lines = 0;
+               if (field == E_CONTACT_FIRST_EMAIL_ID)
+                       print_emails (contact, ctxt);
+               else if (field > E_CONTACT_FIRST_EMAIL_ID &&
+                        field <= E_CONTACT_LAST_EMAIL_ID)
+                       ; /* ignore, all emails are printed in print_emails() */
+               else if (field == E_CONTACT_FIRST_PHONE_ID)
+                       print_phones (contact, ctxt);
+               else if (field > E_CONTACT_FIRST_PHONE_ID &&
+                        field <= E_CONTACT_LAST_PHONE_ID)
+                       ; /* ignore, all phones are printed in print_phones() */
+               else {
+                       gchar *value;
+
+                       value = get_contact_string_value (contact, field);
+                       if (value == NULL || *value == '\0') {
+                               g_free (value);
+                               continue;
+                       }
 
-               if (ctxt->y > page_height)
-                       e_contact_start_new_column (ctxt);
+                       print_line (ctxt, e_contact_pretty_name (field), value);
 
-               value = get_contact_string_value (contact, field);
-               if (value == NULL || *value == '\0') {
                        g_free (value);
-                       continue;
                }
-
-               text = g_strdup_printf (
-                       "%s:  %s",
-                       e_contact_pretty_name (field), value);
-
-               if (ctxt->pages == ctxt->page_nr)
-                       e_contact_output (
-                               ctxt->context, ctxt->style->body_font,
-                               ctxt->x, ctxt->y, ctxt->column_width + 4, text);
-
-               if (get_font_width (ctxt->context,
-                       ctxt->style->body_font, text) > ctxt->column_width)
-                       wrapped_lines =
-                               (get_font_width (ctxt->context,
-                               ctxt->style->body_font, text) /
-                               (ctxt->column_width + 4)) + 1;
-               ctxt->y =
-                       ctxt->y + ((wrapped_lines + 1) *
-                       e_contact_text_height (
-                               ctxt->context,
-                               ctxt->style->body_font,
-                               text));
-
-               ctxt->y += .2 * get_font_height (ctxt->style->body_font);
-
-               g_free (value);
-               g_free (text);
        }
 
        ctxt->y += get_font_height (ctxt->style->headings_font) * .4 + 8;
diff --git a/addressbook/tools/evolution-addressbook-export-list-cards.c 
b/addressbook/tools/evolution-addressbook-export-list-cards.c
index 3faf245..c6261f6 100644
--- a/addressbook/tools/evolution-addressbook-export-list-cards.c
+++ b/addressbook/tools/evolution-addressbook-export-list-cards.c
@@ -461,6 +461,17 @@ e_contact_get_csv (EContact *contact,
                    GSList *csv_all_fields)
 {
        gchar *aline;
+       GList *emails;
+       guint n_emails;
+       gchar *full_name;
+
+       emails = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
+       n_emails = g_list_length (emails);
+       full_name = e_contact_get (contact, E_CONTACT_FULL_NAME);
+       if (n_emails > 4)
+               g_warning ("%s: only 4 out of %i emails have been exported", full_name, n_emails);
+       g_free (full_name);
+       g_list_free_full (emails, (GDestroyNotify) e_vcard_attribute_free);
 
        aline = e_contact_to_csv (contact, csv_all_fields);
        return aline;
diff --git a/e-util/e-name-selector-entry.c b/e-util/e-name-selector-entry.c
index 0f872e7..a50c886 100644
--- a/e-util/e-name-selector-entry.c
+++ b/e-util/e-name-selector-entry.c
@@ -832,11 +832,13 @@ utf8_casefold_collate_len (const gchar *str1,
 
 static gchar *
 build_textrep_for_contact (EContact *contact,
-                           EContactField cue_field)
+                           EContactField cue_field,
+                           gint email_num)
 {
        gchar *name = NULL;
        gchar *email = NULL;
        gchar *textrep;
+       GList *l;
 
        switch (cue_field) {
                case E_CONTACT_FULL_NAME:
@@ -846,12 +848,11 @@ build_textrep_for_contact (EContact *contact,
                        email = e_contact_get (contact, E_CONTACT_EMAIL_1);
                        break;
 
-               case E_CONTACT_EMAIL_1:
-               case E_CONTACT_EMAIL_2:
-               case E_CONTACT_EMAIL_3:
-               case E_CONTACT_EMAIL_4:
+               case E_CONTACT_EMAIL:
                        name = NULL;
-                       email = e_contact_get (contact, cue_field);
+                       l = e_contact_get (contact, cue_field);
+                       email = strdup (g_list_nth_data (l, email_num));
+                       g_list_free_full (l, g_free);
                        break;
 
                default:
@@ -877,11 +878,11 @@ contact_match_cue (ENameSelectorEntry *name_selector_entry,
                    EContact *contact,
                    const gchar *cue_str,
                    EContactField *matched_field,
-                   gint *matched_field_rank)
+                   gint *matched_field_rank,
+                   gint *matched_email_num)
 {
        EContactField  fields[] = { E_CONTACT_FULL_NAME, E_CONTACT_NICKNAME, E_CONTACT_FILE_AS,
-                                    E_CONTACT_EMAIL_1, E_CONTACT_EMAIL_2, E_CONTACT_EMAIL_3,
-                                    E_CONTACT_EMAIL_4 };
+                                   E_CONTACT_EMAIL };
        gchar         *email;
        gboolean       result = FALSE;
        gint           cue_len;
@@ -903,36 +904,47 @@ contact_match_cue (ENameSelectorEntry *name_selector_entry,
        }
        g_free (email);
 
-       for (i = 0; i < G_N_ELEMENTS (fields); i++) {
+       for (i = 0; i < G_N_ELEMENTS (fields) && result == FALSE; i++) {
+               gint   email_num;
                gchar *value;
                gchar *value_sane;
+               GList *emails = NULL, *ll = NULL;
 
                /* Don't match e-mail addresses in contact lists */
                if (e_contact_get (contact, E_CONTACT_IS_LIST) &&
-                   fields[i] >= E_CONTACT_FIRST_EMAIL_ID &&
-                   fields[i] <= E_CONTACT_LAST_EMAIL_ID)
+                   fields[i] == E_CONTACT_EMAIL)
                        continue;
 
-               value = e_contact_get (contact, fields[i]);
-               if (!value)
-                       continue;
+               if (fields[i] == E_CONTACT_EMAIL) {
+                       emails = e_contact_get (contact, fields[i]);
+               } else {
+                       value = e_contact_get (contact, fields[i]);
+                       if (!value)
+                               continue;
+                       emails = g_list_append (emails, value);
+               }
 
-               value_sane = sanitize_string (value);
-               g_free (value);
+               for (ll = emails, email_num = 0; ll; ll = ll->next, email_num++) {
+                       value = ll->data;
+                       value_sane = sanitize_string (value);
 
-               ENS_DEBUG (g_print ("Comparing '%s' to '%s'\n", value, cue_str));
+                       ENS_DEBUG (g_print ("Comparing '%s' to '%s'\n", value, cue_str));
 
-               if (!utf8_casefold_collate_len (value_sane, cue_str, cue_len)) {
-                       if (matched_field)
-                               *matched_field = fields [i];
-                       if (matched_field_rank)
-                               *matched_field_rank = i;
+                       if (!utf8_casefold_collate_len (value_sane, cue_str, cue_len)) {
+                               if (matched_field)
+                                       *matched_field = fields[i];
+                               if (matched_field_rank)
+                                       *matched_field_rank = i;
+                               if (matched_email_num)
+                                       *matched_email_num = email_num;
 
-                       result = TRUE;
+                               result = TRUE;
+                               g_free (value_sane);
+                               break;
+                       }
                        g_free (value_sane);
-                       break;
                }
-               g_free (value_sane);
+               g_list_free_full (emails, g_free);
        }
 
        return result;
@@ -944,12 +956,14 @@ find_existing_completion (ENameSelectorEntry *name_selector_entry,
                           EContact **contact,
                           gchar **text,
                           EContactField *matched_field,
+                          gint *matched_email_num,
                           EBookClient **book_client)
 {
        GtkTreeIter    iter;
        EContact      *best_contact = NULL;
        gint           best_field_rank = G_MAXINT;
        EContactField  best_field = 0;
+       gint           best_email_num = -1;
        EBookClient   *best_book_client = NULL;
 
        g_assert (cue_str);
@@ -965,6 +979,7 @@ find_existing_completion (ENameSelectorEntry *name_selector_entry,
        do {
                EContact      *current_contact;
                gint           current_field_rank;
+               gint           current_email_num;
                EContactField  current_field;
                gboolean       matches;
 
@@ -972,13 +987,15 @@ find_existing_completion (ENameSelectorEntry *name_selector_entry,
                if (!current_contact)
                        continue;
 
-               matches = contact_match_cue (name_selector_entry, current_contact, cue_str, &current_field, 
&current_field_rank);
+               matches = contact_match_cue (name_selector_entry, current_contact, cue_str, &current_field, 
&current_field_rank, &current_email_num);
                if (matches && current_field_rank < best_field_rank) {
                        best_contact = current_contact;
                        best_field_rank = current_field_rank;
                        best_field = current_field;
                        best_book_client = e_contact_store_get_client 
(name_selector_entry->priv->contact_store, &iter);
+                       best_email_num = current_email_num;
                }
+
        } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (name_selector_entry->priv->contact_store), &iter));
 
        if (!best_contact)
@@ -987,12 +1004,13 @@ find_existing_completion (ENameSelectorEntry *name_selector_entry,
        if (contact)
                *contact = best_contact;
        if (text)
-               *text = build_textrep_for_contact (best_contact, best_field);
+               *text = build_textrep_for_contact (best_contact, best_field, best_email_num);
        if (matched_field)
                *matched_field = best_field;
        if (book_client)
                *book_client = best_book_client;
-
+       if (matched_email_num)
+               *matched_email_num = best_email_num;
        return TRUE;
 }
 
@@ -1060,6 +1078,7 @@ type_ahead_complete (ENameSelectorEntry *name_selector_entry)
        EBookClient   *book_client = NULL;
        EContactField  matched_field;
        EDestination  *destination;
+       gint           matched_email_num;
        gint           cursor_pos;
        gint           range_start = 0;
        gint           range_end = 0;
@@ -1088,7 +1107,7 @@ type_ahead_complete (ENameSelectorEntry *name_selector_entry)
 
        cue_str = get_entry_substring (name_selector_entry, range_start, range_end);
        if (!find_existing_completion (name_selector_entry, cue_str, &contact,
-                                      &textrep, &matched_field, &book_client)) {
+                                      &textrep, &matched_field, &matched_email_num, &book_client)) {
                g_free (cue_str);
                return;
        }
@@ -1133,9 +1152,8 @@ type_ahead_complete (ENameSelectorEntry *name_selector_entry)
        if (contact && destination) {
                gint email_n = 0;
 
-               if (matched_field >= E_CONTACT_FIRST_EMAIL_ID && matched_field <= E_CONTACT_LAST_EMAIL_ID)
-                       email_n = matched_field - E_CONTACT_FIRST_EMAIL_ID;
-
+               if (matched_field == E_CONTACT_EMAIL)
+                       email_n = matched_email_num;
                e_destination_set_contact (destination, contact, email_n);
                if (book_client)
                        e_destination_set_client (destination, book_client);
@@ -2042,6 +2060,7 @@ contact_layout_pixbuffer (GtkCellLayout *cell_layout,
        GtkTreeIter    contact_store_iter;
        gint           email_n;
        EContactPhoto *photo;
+       gboolean       iter_is_valid;
        GdkPixbuf *pixbuf = NULL;
 
        if (!name_selector_entry->priv->contact_store)
@@ -2050,11 +2069,15 @@ contact_layout_pixbuffer (GtkCellLayout *cell_layout,
        gtk_tree_model_filter_convert_iter_to_child_iter (
                GTK_TREE_MODEL_FILTER (model),
                &generator_iter, iter);
-       e_tree_model_generator_convert_iter_to_child_iter (
+       iter_is_valid = e_tree_model_generator_convert_iter_to_child_iter (
                name_selector_entry->priv->email_generator,
                &contact_store_iter, &email_n,
                &generator_iter);
 
+       if (!iter_is_valid) {
+               return;
+       }
+
        contact = e_contact_store_get_contact (name_selector_entry->priv->contact_store, &contact_store_iter);
        if (!contact) {
                g_object_set (cell, "pixbuf", pixbuf, NULL);
@@ -2121,6 +2144,7 @@ contact_layout_formatter (GtkCellLayout *cell_layout,
        gchar         *file_as_str;
        gchar         *email_str;
        gint           email_n;
+       gboolean       iter_is_valid;
 
        if (!name_selector_entry->priv->contact_store)
                return;
@@ -2128,11 +2152,15 @@ contact_layout_formatter (GtkCellLayout *cell_layout,
        gtk_tree_model_filter_convert_iter_to_child_iter (
                GTK_TREE_MODEL_FILTER (model),
                &generator_iter, iter);
-       e_tree_model_generator_convert_iter_to_child_iter (
+       iter_is_valid = e_tree_model_generator_convert_iter_to_child_iter (
                name_selector_entry->priv->email_generator,
                &contact_store_iter, &email_n,
                &generator_iter);
 
+       if (!iter_is_valid) {
+               return;
+       }
+
        contact = e_contact_store_get_contact (name_selector_entry->priv->contact_store, &contact_store_iter);
        email_list = e_contact_get (contact, E_CONTACT_EMAIL);
        email_str = g_list_nth_data (email_list, email_n);
diff --git a/e-util/e-tree-model-generator.c b/e-util/e-tree-model-generator.c
index f035d12..981ca51 100644
--- a/e-util/e-tree-model-generator.c
+++ b/e-util/e-tree-model-generator.c
@@ -969,7 +969,7 @@ e_tree_model_generator_convert_path_to_child_path (ETreeModelGenerator *tree_mod
  * The permutation index is the index of the generated row based on this
  * child row, with the first generated row based on this child row being 0.
  **/
-void
+gboolean
 e_tree_model_generator_convert_iter_to_child_iter (ETreeModelGenerator *tree_model_generator,
                                                    GtkTreeIter *child_iter,
                                                    gint *permutation_n,
@@ -979,9 +979,10 @@ e_tree_model_generator_convert_iter_to_child_iter (ETreeModelGenerator *tree_mod
        GArray      *group;
        gint         index;
        gint         internal_offset = 0;
+       gboolean     iter_is_valid = FALSE;
 
-       g_return_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator));
-       g_return_if_fail (ITER_IS_VALID (tree_model_generator, generator_iter));
+       g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator), iter_is_valid);
+       g_return_val_if_fail (ITER_IS_VALID (tree_model_generator, generator_iter), iter_is_valid);
 
        path = gtk_tree_path_new ();
        ITER_GET (generator_iter, &group, &index);
@@ -1000,11 +1001,14 @@ e_tree_model_generator_convert_iter_to_child_iter (ETreeModelGenerator *tree_mod
        }
 
        if (child_iter)
-               gtk_tree_model_get_iter (tree_model_generator->priv->child_model, child_iter, path);
+               iter_is_valid = gtk_tree_model_get_iter (tree_model_generator->priv->child_model, child_iter, 
path);
+
        if (permutation_n)
                *permutation_n = internal_offset;
 
        gtk_tree_path_free (path);
+
+       return iter_is_valid;
 }
 
 /* ---------------- *
diff --git a/e-util/e-tree-model-generator.h b/e-util/e-tree-model-generator.h
index 59cf0ad..739df1f 100644
--- a/e-util/e-tree-model-generator.h
+++ b/e-util/e-tree-model-generator.h
@@ -92,7 +92,7 @@ void          e_tree_model_generator_convert_child_iter_to_iter
 GtkTreePath *  e_tree_model_generator_convert_path_to_child_path
                                                (ETreeModelGenerator *tree_model_generator,
                                                 GtkTreePath *generator_path);
-void           e_tree_model_generator_convert_iter_to_child_iter
+gboolean       e_tree_model_generator_convert_iter_to_child_iter
                                                (ETreeModelGenerator *tree_model_generator,
                                                 GtkTreeIter *child_iter,
                                                 gint *permutation_n,


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