diff options
author | Christian Schaarschmidt <schaarsc@gmx.de> | 2014-03-24 23:29:31 +0800 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2014-03-24 23:29:31 +0800 |
commit | 2263c3c6049be334e48c650e06332e18ca5af7d2 (patch) | |
tree | 984167a9b6c1845bc60819c5ad498ed2e9b74cf5 | |
parent | ec1862c1497ac44f89c1fe3d92d922b525da96d9 (diff) | |
download | gsoc2013-evolution-2263c3c6049be334e48c650e06332e18ca5af7d2.tar gsoc2013-evolution-2263c3c6049be334e48c650e06332e18ca5af7d2.tar.gz gsoc2013-evolution-2263c3c6049be334e48c650e06332e18ca5af7d2.tar.bz2 gsoc2013-evolution-2263c3c6049be334e48c650e06332e18ca5af7d2.tar.lz gsoc2013-evolution-2263c3c6049be334e48c650e06332e18ca5af7d2.tar.xz gsoc2013-evolution-2263c3c6049be334e48c650e06332e18ca5af7d2.tar.zst gsoc2013-evolution-2263c3c6049be334e48c650e06332e18ca5af7d2.zip |
Bug #724059 - Allow arbitrary number of phone entries in the contact editor
-rw-r--r-- | addressbook/gui/contact-editor/Makefile.am | 4 | ||||
-rw-r--r-- | addressbook/gui/contact-editor/contact-editor.ui | 220 | ||||
-rw-r--r-- | addressbook/gui/contact-editor/e-contact-editor-dyntable.c | 738 | ||||
-rw-r--r-- | addressbook/gui/contact-editor/e-contact-editor-dyntable.h | 126 | ||||
-rw-r--r-- | addressbook/gui/contact-editor/e-contact-editor.c | 372 |
5 files changed, 1026 insertions, 434 deletions
diff --git a/addressbook/gui/contact-editor/Makefile.am b/addressbook/gui/contact-editor/Makefile.am index 4e5d0b7111..c8499b7da4 100644 --- a/addressbook/gui/contact-editor/Makefile.am +++ b/addressbook/gui/contact-editor/Makefile.am @@ -21,7 +21,9 @@ libecontacteditor_la_SOURCES = \ e-contact-editor.c \ e-contact-editor.h \ e-contact-quick-add.c \ - e-contact-quick-add.h + e-contact-quick-add.h \ + e-contact-editor-dyntable.h \ + e-contact-editor-dyntable.c libecontacteditor_la_LDFLAGS = -avoid-version $(NO_UNDEFINED) diff --git a/addressbook/gui/contact-editor/contact-editor.ui b/addressbook/gui/contact-editor/contact-editor.ui index 7e48bc5443..9b7e94ea1e 100644 --- a/addressbook/gui/contact-editor/contact-editor.ui +++ b/addressbook/gui/contact-editor/contact-editor.ui @@ -528,215 +528,17 @@ <property name="border_width">12</property> <property name="orientation">vertical</property> <property name="spacing">6</property> - <child> - <object class="GtkTable" id="table84"> - <property name="visible">True</property> - <property name="n_rows">2</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-phone-1"> - <property name="visible">True</property> - <property name="can_focus">True</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-phone-3"> - <property name="visible">True</property> - <property name="can_focus">True</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-phone-4"> - <property name="visible">True</property> - <property name="can_focus">True</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="GtkEntry" id="entry-phone-2"> - <property name="visible">True</property> - <property name="can_focus">True</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="GtkComboBox" id="combobox-phone-1"> - <property name="visible">True</property> - </object> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkComboBox" id="combobox-phone-3"> - <property name="visible">True</property> - </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-phone-2"> - <property name="visible">True</property> - </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-phone-4"> - <property name="visible">True</property> - </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> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkTable" id="table-phone-extended"> - <property name="n_rows">2</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-phone-5"> - <property name="visible">True</property> - <property name="can_focus">True</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-phone-7"> - <property name="visible">True</property> - <property name="can_focus">True</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-phone-6"> - <property name="visible">True</property> - <property name="can_focus">True</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-phone-8"> - <property name="visible">True</property> - <property name="can_focus">True</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="GtkComboBox" id="combobox-phone-5"> - <property name="visible">True</property> - </object> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkComboBox" id="combobox-phone-7"> - <property name="visible">True</property> - </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-phone-6"> - <property name="visible">True</property> - </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-phone-8"> - <property name="visible">True</property> - </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> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> + + <child> + <object class="EContactEditorDynTable" type-func="e_contact_editor_dyntable_get_type" id="phone-dyntable"> + <property name="visible">True</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + + </object> </child> <child type="label"> diff --git a/addressbook/gui/contact-editor/e-contact-editor-dyntable.c b/addressbook/gui/contact-editor/e-contact-editor-dyntable.c new file mode 100644 index 0000000000..4706d5b1f9 --- /dev/null +++ b/addressbook/gui/contact-editor/e-contact-editor-dyntable.c @@ -0,0 +1,738 @@ +/* + * e-contact-editor-dyntable.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "e-contact-editor-dyntable.h" + +G_DEFINE_TYPE(EContactEditorDynTable, e_contact_editor_dyntable, GTK_TYPE_GRID) + +/* one position is occupied by two widgets: combo+entry */ +#define ENTRY_SIZE 2 +#define MAX_CAPACITY 100 + +enum { + CHANGED_SIGNAL, + ACTIVATE_SIGNAL, + ROW_ADDED_SIGNAL, + LAST_SIGNAL +}; + +static guint dyntable_signals[LAST_SIGNAL]; + +struct _EContactEditorDynTablePrivate { + + /* absolute max, dyntable will ignore the rest */ + guint max_entries; + + /* current number of entries with text or requested by user*/ + guint curr_entries; + + /* minimum to show, with or without text */ + guint show_min_entries; + + /* no matter how much data, show only */ + guint show_max_entries; + + /* number of entries (combo/text) per row */ + guint columns; + + /* if true, fill line with empty slots*/ + gboolean justified; + + GtkWidget *add_button; + GtkListStore *combo_store; + GtkListStore *data_store; + + /* array of default values for combo box */ + const gint *combo_defaults; + + /* number of elements in the array */ + size_t combo_defaults_n; +}; + +GtkWidget* +e_contact_editor_dyntable_new (void) +{ + GtkWidget* widget; + widget = GTK_WIDGET (g_object_new (e_contact_editor_dyntable_get_type (), NULL)); + return widget; +} + +static void +set_combo_box_active (EContactEditorDynTable *dyntable, + GtkComboBox *combo_box, + gint active) +{ + g_signal_handlers_block_matched (combo_box, + G_SIGNAL_MATCH_DATA, 0, 0, NULL, + NULL, dyntable); + gtk_combo_box_set_active (combo_box, active); + g_signal_handlers_unblock_matched (combo_box, + G_SIGNAL_MATCH_DATA, 0, 0, NULL, + NULL, dyntable); +} + +/* translate position into column/row */ +static void +position_to_grid (EContactEditorDynTable *dyntable, + guint pos, + guint *col, + guint *row) +{ + *row = pos / dyntable->priv->columns; + *col = pos % dyntable->priv->columns * ENTRY_SIZE; +} + +static void +move_widget (GtkGrid *grid, GtkWidget *w, guint col, guint row) +{ + GValue rowValue = G_VALUE_INIT, colValue = G_VALUE_INIT; + + g_value_init (&rowValue, G_TYPE_UINT); + g_value_init (&colValue, G_TYPE_UINT); + + g_value_set_uint (&rowValue, row); + g_value_set_uint (&colValue, col); + + gtk_container_child_set_property (GTK_CONTAINER (grid), w, + "left-attach", &colValue); + gtk_container_child_set_property (GTK_CONTAINER (grid), w, + "top-attach", &rowValue); +} + +static gboolean +is_button_required (EContactEditorDynTable *dyntable) +{ + if (dyntable->priv->curr_entries >= dyntable->priv->max_entries) + return FALSE; + if (dyntable->priv->curr_entries <= dyntable->priv->show_max_entries) + return TRUE; + else + return FALSE; +} + +static void +sensitize_button (EContactEditorDynTable *dyntable) +{ + guint row, col, current_entries; + GtkWidget *w; + GtkGrid *grid; + EContactEditorDynTableClass *class; + gboolean enabled; + + grid = GTK_GRID (dyntable); + class = E_CONTACT_EDITOR_DYNTABLE_GET_CLASS (dyntable); + + current_entries = dyntable->priv->curr_entries; + enabled = TRUE; + if (current_entries > 0) { + /* last entry */ + current_entries--; + position_to_grid (dyntable, current_entries, &col, &row); + w = gtk_grid_get_child_at (grid, col + 1, row); + + enabled = !class->widget_is_empty (dyntable, w); + } + + gtk_widget_set_sensitive (dyntable->priv->add_button, enabled); +} + +static void +show_button (EContactEditorDynTable *dyntable) +{ + guint col,row, pos; + gboolean visible = FALSE; + GtkGrid *grid; + + grid = GTK_GRID (dyntable); + + /* move button to end of current line */ + pos = dyntable->priv->curr_entries; + if (pos > 0) + pos--; + position_to_grid(dyntable, pos, &col, &row); + move_widget (grid, dyntable->priv->add_button, + dyntable->priv->columns*ENTRY_SIZE+1, row); + + /* set visibility */ + if (is_button_required (dyntable)) + visible = TRUE; + + gtk_widget_set_visible (dyntable->priv->add_button, visible); + + sensitize_button (dyntable); +} + +static void +increment_counter (EContactEditorDynTable *dyntable) +{ + dyntable->priv->curr_entries++; + show_button (dyntable); +} + +static void +decrement_counter (EContactEditorDynTable *dyntable) +{ + dyntable->priv->curr_entries--; + show_button (dyntable); +} + +static gint +get_next_combo_index (EContactEditorDynTable *dyntable) +{ + size_t array_size = dyntable->priv->combo_defaults_n; + gint idx = 0; + + if (dyntable->priv->combo_defaults != NULL) { + idx = dyntable->priv->combo_defaults[dyntable->priv->curr_entries % array_size]; + } + + return idx; +} + +static GtkWidget* +combo_box_create (EContactEditorDynTable *dyntable) +{ + GtkWidget *w; + GtkComboBox *combo; + GtkListStore *store; + GtkCellRenderer *cell; + + w = gtk_combo_box_new (); + combo = GTK_COMBO_BOX (w); + store = dyntable->priv->combo_store; + + gtk_combo_box_set_model (combo, GTK_TREE_MODEL(store)); + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo)); + + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell, + "text", DYNTABLE_COMBO_COLUMN_TEXT, + "sensitive", DYNTABLE_COMBO_COLUMN_SENSITIVE, + NULL); + + gtk_combo_box_set_active (combo, get_next_combo_index (dyntable)); + + return w; +} + +static void +emit_changed (EContactEditorDynTable *dyntable) +{ + g_signal_emit (dyntable, dyntable_signals[CHANGED_SIGNAL], 0); +} + +static void +emit_activated (EContactEditorDynTable *dyntable) +{ + g_signal_emit (dyntable, dyntable_signals[ACTIVATE_SIGNAL], 0); +} + +static void +emit_row_added (EContactEditorDynTable *dyntable) +{ + g_signal_emit (dyntable, dyntable_signals[ROW_ADDED_SIGNAL], 0); +} + +static void +add_empty_entry (EContactEditorDynTable *dyntable) +{ + GtkGrid *grid; + guint row, col; + GtkWidget *box, *entry; + EContactEditorDynTableClass *class; + + grid = GTK_GRID (dyntable); + position_to_grid (dyntable, dyntable->priv->curr_entries, &col, &row); + + /* create new entry at last position */ + class = E_CONTACT_EDITOR_DYNTABLE_GET_CLASS (dyntable); + box = combo_box_create (dyntable); + gtk_grid_attach (grid, box, col, row, 1, 1); + gtk_widget_show (box); + + entry = class->widget_create (dyntable); + g_object_set (entry, "margin-left", 2, NULL); + g_object_set (entry, "margin-right", 5, NULL); + gtk_widget_set_hexpand (entry, GTK_EXPAND); + gtk_grid_attach (grid, entry, col + 1, row, 1, 1); + gtk_widget_show (entry); + + g_signal_connect_swapped(box, "changed", + G_CALLBACK (gtk_widget_grab_focus), entry); + g_signal_connect_swapped(box, "changed", + G_CALLBACK (emit_changed), dyntable); + g_signal_connect_swapped(entry, "changed", + G_CALLBACK (emit_changed), dyntable); + g_signal_connect_swapped(entry, "changed", + G_CALLBACK (sensitize_button), dyntable); + g_signal_connect_swapped(entry, "activate", + G_CALLBACK (emit_activated), dyntable); + + increment_counter (dyntable); + + if ( (dyntable->priv->justified && col < dyntable->priv->columns-1) || + (dyntable->priv->curr_entries < dyntable->priv->show_min_entries) ) + add_empty_entry (dyntable); + + gtk_widget_grab_focus (entry); +} + +static void +remove_empty_entries (EContactEditorDynTable *dyntable, gboolean fillup) +{ + guint row, col, pos; + GtkGrid* grid; + GtkWidget* w; + EContactEditorDynTableClass *class; + + grid = GTK_GRID (dyntable); + class = E_CONTACT_EDITOR_DYNTABLE_GET_CLASS (dyntable); + + for (pos = 0; pos < dyntable->priv->curr_entries; pos++) { + position_to_grid (dyntable, pos, &col, &row); + w = gtk_grid_get_child_at (grid, col + 1, row); + + if (w != NULL && class->widget_is_empty (dyntable, w)) { + guint pos2, next_col, next_row; + + gtk_widget_destroy (w); + w = gtk_grid_get_child_at (grid, col, row); + gtk_widget_destroy (w); + + /* now fill gap */ + for (pos2 = pos + 1; pos2 < dyntable->priv->curr_entries; pos2++) { + position_to_grid (dyntable, pos2, &next_col, &next_row); + w = gtk_grid_get_child_at (grid, next_col, next_row); + move_widget (grid, w, col, row); + w = gtk_grid_get_child_at (grid, next_col + 1, next_row); + move_widget (grid, w, col + 1, row); + col = next_col; + row = next_row; + } + decrement_counter (dyntable); + pos--; /* check the new widget on our current position */ + } + + } + + if (fillup && dyntable->priv->curr_entries < dyntable->priv->show_min_entries) + add_empty_entry (dyntable); + +} + +/* clears data, not the combo box list store */ +void +e_contact_editor_dyntable_clear_data (EContactEditorDynTable *dyntable) +{ + guint i, col, row; + GtkGrid *grid; + GtkWidget *w; + EContactEditorDynTableClass *class; + + grid = GTK_GRID(dyntable); + class = E_CONTACT_EDITOR_DYNTABLE_GET_CLASS(dyntable); + + for (i = 0; i < dyntable->priv->curr_entries; i++) { + position_to_grid (dyntable, i, &col, &row); + w = gtk_grid_get_child_at (grid, col + 1, row); + class->widget_clear (dyntable, w); + } + remove_empty_entries (dyntable, TRUE); + + gtk_list_store_clear (dyntable->priv->data_store); +} + +static void +adjust_visibility_of_widgets (EContactEditorDynTable *dyntable) +{ + guint pos, col, row; + GtkGrid *grid; + GtkWidget *w; + + grid = GTK_GRID (dyntable); + for (pos = 0; pos < dyntable->priv->curr_entries; pos++) { + gboolean visible = FALSE; + + if (pos < dyntable->priv->show_max_entries) + visible = TRUE; + + position_to_grid (dyntable, pos, &col, &row); + w = gtk_grid_get_child_at (grid, col, row); + gtk_widget_set_visible (w, visible); + w = gtk_grid_get_child_at (grid, col + 1, row); + gtk_widget_set_visible (w, visible); + } + + show_button (dyntable); +} + +/* number of columns can only be set before any data is added to this dyntable */ +void e_contact_editor_dyntable_set_num_columns (EContactEditorDynTable *dyntable, + guint number_of_columns, + gboolean justified) +{ + GtkTreeIter iter; + GtkTreeModel *store; + gboolean holds_data; + + g_return_if_fail (number_of_columns > 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); + + remove_empty_entries(dyntable, FALSE); + + dyntable->priv->columns = number_of_columns; + dyntable->priv->justified = justified; + + remove_empty_entries(dyntable, TRUE); +} + +void +e_contact_editor_dyntable_set_max_entries (EContactEditorDynTable *dyntable, + guint max) +{ + GtkTreeIter iter; + GtkTreeModel *store; + gboolean holds_data; + + 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); + + 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; +} + +/* show at least number_of_entries, with or without data */ +void +e_contact_editor_dyntable_set_show_min (EContactEditorDynTable *dyntable, + guint number_of_entries) +{ + if (number_of_entries > dyntable->priv->show_max_entries) + dyntable->priv->show_min_entries = dyntable->priv->show_max_entries; + else + dyntable->priv->show_min_entries = number_of_entries; + + if (dyntable->priv->curr_entries < dyntable->priv->show_min_entries) + add_empty_entry (dyntable); + + adjust_visibility_of_widgets (dyntable); +} + +/* show no more than number_of_entries, hide the rest */ +void +e_contact_editor_dyntable_set_show_max (EContactEditorDynTable *dyntable, + guint number_of_entries) +{ + if (number_of_entries > dyntable->priv->max_entries) { + dyntable->priv->show_max_entries = dyntable->priv->max_entries; + } else if (number_of_entries < dyntable->priv->show_min_entries) { + dyntable->priv->show_max_entries = dyntable->priv->show_min_entries; + } else { + dyntable->priv->show_max_entries = number_of_entries; + } + + adjust_visibility_of_widgets (dyntable); +} + +/* use data_store to fill data into widgets */ +void +e_contact_editor_dyntable_fill_in_data (EContactEditorDynTable *dyntable) +{ + guint pos = 0, col, row; + EContactEditorDynTableClass *class; + GtkGrid *grid; + GtkTreeIter iter; + GtkTreeModel *store; + GtkWidget *w; + gboolean valid; + gchar *str_data; + gint int_data; + + class = E_CONTACT_EDITOR_DYNTABLE_GET_CLASS (dyntable); + grid = GTK_GRID (dyntable); + store = GTK_TREE_MODEL (dyntable->priv->data_store); + + valid = gtk_tree_model_get_iter_first (store, &iter); + while (valid) { + gtk_tree_model_get (store, &iter, + DYNTABLE_STORE_COLUMN_ENTRY_STRING, &str_data, + DYNTABLE_STORE_COLUMN_SELECTED_ITEM, &int_data, + -1); + + if (pos >= dyntable->priv->curr_entries) + add_empty_entry (dyntable); + + position_to_grid (dyntable, pos++, &col, &row); + w = gtk_grid_get_child_at (grid, col, row); + set_combo_box_active (dyntable, GTK_COMBO_BOX(w), int_data); + w = gtk_grid_get_child_at (grid, col + 1, row); + class->widget_fill (dyntable, w, str_data); + + g_return_if_fail(pos < dyntable->priv->max_entries); + valid = gtk_tree_model_iter_next (store, &iter); + } + + /* fix visibility of added items */ + adjust_visibility_of_widgets (dyntable); +} + +/* the model returned has 3 columns + * + * UINT: sort order + * UINT: active combo item + * STRING: data extracted with widget_extract() + */ +GtkListStore* +e_contact_editor_dyntable_extract_data (EContactEditorDynTable *dyntable) +{ + EContactEditorDynTableClass *class; + GtkGrid *grid; + GtkListStore *data_store; + GtkWidget *w; + guint pos, col, row; + + grid = GTK_GRID(dyntable); + class = E_CONTACT_EDITOR_DYNTABLE_GET_CLASS(dyntable); + data_store = dyntable->priv->data_store; + + gtk_list_store_clear (data_store); + + for (pos = 0; pos < dyntable->priv->curr_entries; pos++) { + + position_to_grid (dyntable, pos, &col, &row); + w = gtk_grid_get_child_at (grid, col + 1, row); + + if (!class->widget_is_empty (dyntable, w)) { + GtkTreeIter iter; + gchar *dup; + gint combo_item; + const gchar *data; + + data = class->widget_extract (dyntable, w); + w = gtk_grid_get_child_at (grid, col, row); + combo_item = gtk_combo_box_get_active (GTK_COMBO_BOX(w)); + + dup = g_strdup (data); + g_strstrip(dup); + + gtk_list_store_append (data_store, &iter); + gtk_list_store_set (data_store, &iter, + DYNTABLE_STORE_COLUMN_SORTORDER, pos, + DYNTABLE_STORE_COLUMN_SELECTED_ITEM, combo_item, + DYNTABLE_STORE_COLUMN_ENTRY_STRING, dup, + -1); + + g_free (dup); + } + } + + return dyntable->priv->data_store; +} + +/* the model returned has two columns + * + * STRING: bound to attribute "text" + * BOOLEAN: bound to attribute "sensitive" + */ +GtkListStore* +e_contact_editor_dyntable_get_combo_store (EContactEditorDynTable *dyntable) +{ + return dyntable->priv->combo_store; +} + +void +e_contact_editor_dyntable_set_combo_defaults (EContactEditorDynTable *dyntable, + const gint *defaults, + size_t defaults_n) +{ + dyntable->priv->combo_defaults = defaults; + dyntable->priv->combo_defaults_n = defaults_n; +} + +static void +dispose_impl (GObject *object) +{ + GtkListStore *store; + EContactEditorDynTable *dyntable; + + dyntable = E_CONTACT_EDITOR_DYNTABLE(object); + + store = dyntable->priv->data_store; + if (store) { + gtk_list_store_clear (store); + g_object_unref (store); + dyntable->priv->data_store = NULL; + } + + store = dyntable->priv->combo_store; + if (store) { + g_object_unref (store); + dyntable->priv->combo_store = NULL; + } + + G_OBJECT_CLASS(e_contact_editor_dyntable_parent_class)->dispose (object); +} + +static GtkWidget* +default_impl_widget_create (EContactEditorDynTable *dyntable) +{ + return gtk_entry_new (); +} + +static void +default_impl_widget_clear (EContactEditorDynTable *dyntable, + GtkWidget *w) +{ + GtkEntry *e; + e = GTK_ENTRY(w); + gtk_entry_set_text (e, ""); +} + +static const gchar* +default_impl_widget_extract (EContactEditorDynTable *dyntable, + GtkWidget *w) +{ + GtkEntry *e; + + e = GTK_ENTRY(w); + return gtk_entry_get_text (e); +} + +static void +default_impl_widget_fill (EContactEditorDynTable *dyntable, + GtkWidget *w, + const gchar *value) +{ + GtkEntry *e; + + e = GTK_ENTRY(w); + gtk_entry_set_text (e, value); +} + +static gboolean +default_impl_widget_is_empty (EContactEditorDynTable *dyntable, + GtkWidget *w) +{ + GtkEntry *e; + const gchar *data; + gchar * dup; + size_t len = -1; + + e = GTK_ENTRY(w); + if (0 == gtk_entry_get_text_length (e)) + return TRUE; + + data = gtk_entry_get_text (e); + + dup = g_strdup (data); + g_strchug (dup); + len = strlen (dup); + g_free (dup); + + return len <= 0; +} + +static void +e_contact_editor_dyntable_init (EContactEditorDynTable *dyntable) +{ + GtkGrid *grid; + + dyntable->priv = G_TYPE_INSTANCE_GET_PRIVATE(dyntable, + E_TYPE_CONTACT_EDITOR_DYNTABLE, + EContactEditorDynTablePrivate); + + /* fill in defaults */ + dyntable->priv->max_entries = MAX_CAPACITY; + dyntable->priv->curr_entries = 0; + dyntable->priv->show_min_entries = 0; + dyntable->priv->show_max_entries = dyntable->priv->max_entries; + dyntable->priv->columns = 2; + dyntable->priv->justified = FALSE; + dyntable->priv->combo_defaults = NULL; + + dyntable->priv->combo_store = gtk_list_store_new (DYNTABLE_COBMO_COLUMN_NUM_COLUMNS, + G_TYPE_STRING, G_TYPE_BOOLEAN); + dyntable->priv->data_store = gtk_list_store_new (DYNTABLE_STORE_COLUMN_NUM_COLUMNS, + G_TYPE_UINT, G_TYPE_INT, G_TYPE_STRING); + gtk_tree_sortable_set_sort_column_id ( + GTK_TREE_SORTABLE (dyntable->priv->data_store), + DYNTABLE_STORE_COLUMN_SORTORDER, + GTK_SORT_ASCENDING); + + dyntable->priv->add_button = gtk_button_new_with_label ("+"); + g_signal_connect_swapped (dyntable->priv->add_button, "clicked", + G_CALLBACK (add_empty_entry), dyntable); + g_signal_connect_swapped(dyntable->priv->add_button, "clicked", + G_CALLBACK (emit_row_added), dyntable); + + grid = GTK_GRID (dyntable); + + gtk_grid_attach (grid, dyntable->priv->add_button, 0, 0, 1, 1); + gtk_widget_set_valign (dyntable->priv->add_button, GTK_ALIGN_CENTER); + gtk_widget_set_halign (dyntable->priv->add_button, GTK_ALIGN_START); + gtk_widget_show (dyntable->priv->add_button); + + if (dyntable->priv->curr_entries < dyntable->priv->show_min_entries) + add_empty_entry (dyntable); +} + +static void +e_contact_editor_dyntable_class_init (EContactEditorDynTableClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof(EContactEditorDynTablePrivate)); + + dyntable_signals[CHANGED_SIGNAL] = g_signal_new ("changed", + G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(EContactEditorDynTableClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + dyntable_signals[ACTIVATE_SIGNAL] = g_signal_new ("activate", + G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(EContactEditorDynTableClass, activate), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + dyntable_signals[ROW_ADDED_SIGNAL] = g_signal_new ("row-added", + G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(EContactEditorDynTableClass, row_added), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class = G_OBJECT_CLASS (class); + object_class->dispose = dispose_impl; + + /* virtual functions */ + class->widget_create = default_impl_widget_create; + class->widget_is_empty = default_impl_widget_is_empty; + class->widget_clear = default_impl_widget_clear; + class->widget_extract = default_impl_widget_extract; + class->widget_fill = default_impl_widget_fill; +} diff --git a/addressbook/gui/contact-editor/e-contact-editor-dyntable.h b/addressbook/gui/contact-editor/e-contact-editor-dyntable.h new file mode 100644 index 0000000000..c5c9238d56 --- /dev/null +++ b/addressbook/gui/contact-editor/e-contact-editor-dyntable.h @@ -0,0 +1,126 @@ +/* + * e-contact-editor-dyntable.h + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef E_CONTACT_EDITOR_DYNTABLE_H_ +#define E_CONTACT_EDITOR_DYNTABLE_H_ + +#include <gtk/gtk.h> +#include <string.h> + +#define E_TYPE_CONTACT_EDITOR_DYNTABLE \ + (e_contact_editor_dyntable_get_type ()) +#define E_CONTACT_EDITOR_DYNTABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_CONTACT_EDITOR_DYNTABLE, EContactEditorDynTable)) +#define E_CONTACT_EDITOR_DYNTABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((klass), E_TYPE_CONTACT_EDITOR_DYNTABLE, EContactEditorDynTableClass)) +#define E_IS_CONTACT_EDITOR_DYNTABLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_CONTACT_EDITOR_DYNTABLE)) +#define E_IS_CONTACT_EDITOR_DYNTABLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((obj), E_TYPE_CONTACT_EDITOR_DYNTABLE)) +#define E_CONTACT_EDITOR_DYNTABLE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + (obj,E_TYPE_CONTACT_EDITOR_DYNTABLE, EContactEditorDynTableClass)) + +G_BEGIN_DECLS + +typedef enum { + DYNTABLE_STORE_COLUMN_SORTORDER, + DYNTABLE_STORE_COLUMN_SELECTED_ITEM, + DYNTABLE_STORE_COLUMN_ENTRY_STRING, + DYNTABLE_STORE_COLUMN_NUM_COLUMNS +} EContactEditorDynTableStoreColumns; + +typedef enum { + DYNTABLE_COMBO_COLUMN_TEXT, + DYNTABLE_COMBO_COLUMN_SENSITIVE, + DYNTABLE_COBMO_COLUMN_NUM_COLUMNS +} EContactEditorDynTableComboColumns; + +typedef struct _EContactEditorDynTable EContactEditorDynTable; +typedef struct _EContactEditorDynTableClass EContactEditorDynTableClass; +typedef struct _EContactEditorDynTablePrivate EContactEditorDynTablePrivate; + +struct _EContactEditorDynTableClass { + GtkGridClass parent_class; + + /* Signals */ + void (*changed) (EContactEditorDynTable* dyntable); + void (*activate) (EContactEditorDynTable* dyntable); + void (*row_added) (EContactEditorDynTable* dyntable); + + /* virtual */ + + /* defaults to GtkEntiy */ + GtkWidget* (*widget_create) (EContactEditorDynTable *dyntable); + + /* defaults to string_is_empty(txt) */ + gboolean (*widget_is_empty) (EContactEditorDynTable *dyntable, + GtkWidget *w); + + /* defaults to entry_set_text("") */ + void (*widget_clear) (EContactEditorDynTable *dyntable, + GtkWidget *w); + + /* default impl gtk_entry_set_text + * other widgets may need to "parse" value before usage. + */ + void (*widget_fill) (EContactEditorDynTable *dyntable, + GtkWidget *w, + const gchar *value); + + /* default impl returns gtk_entry_get_text + * other widget may require some kind of "encoding" + */ + const gchar* (*widget_extract) (EContactEditorDynTable *dyntable, + GtkWidget *w); + +}; + +struct _EContactEditorDynTable { + GtkGrid parent; + + EContactEditorDynTablePrivate* priv; +}; + +GtkWidget* e_contact_editor_dyntable_new (void); +GType e_contact_editor_dyntable_get_type (void) G_GNUC_CONST; +void e_contact_editor_dyntable_set_show_min (EContactEditorDynTable *dyntable, + guint number_of_entries); +void e_contact_editor_dyntable_set_show_max (EContactEditorDynTable *dyntable, + guint number_of_entries); +void e_contact_editor_dyntable_set_num_columns (EContactEditorDynTable *dyntable, + guint number_of_columns, + gboolean justified); +void e_contact_editor_dyntable_set_max_entries (EContactEditorDynTable *dyntable, + guint max); + +GtkListStore* e_contact_editor_dyntable_get_combo_store (EContactEditorDynTable* dyntable); +void e_contact_editor_dyntable_set_combo_defaults (EContactEditorDynTable* dyntable, + const gint *defaults, + size_t defaults_n); +void e_contact_editor_dyntable_clear_data (EContactEditorDynTable *dyntable); +void e_contact_editor_dyntable_fill_in_data (EContactEditorDynTable *dyntable); +GtkListStore* e_contact_editor_dyntable_extract_data (EContactEditorDynTable *dyntable); + +G_END_DECLS + +#endif /* E_CONTACT_EDITOR_DYNTABLE_H_ */ diff --git a/addressbook/gui/contact-editor/e-contact-editor.c b/addressbook/gui/contact-editor/e-contact-editor.c index aa02ab0eb6..a27f8cdb57 100644 --- a/addressbook/gui/contact-editor/e-contact-editor.c +++ b/addressbook/gui/contact-editor/e-contact-editor.c @@ -44,9 +44,12 @@ #include "eab-contact-merging.h" #include "e-contact-editor-fullname.h" +#include "e-contact-editor-dyntable.h" +#define SLOTS_PER_LINE 2 +#define SLOTS_IN_COLLAPSED_STATE SLOTS_PER_LINE #define EMAIL_SLOTS 4 -#define PHONE_SLOTS 8 +#define PHONE_SLOTS 50 #define IM_SLOTS 4 #define ADDRESS_SLOTS 3 @@ -1316,52 +1319,6 @@ init_item_sensitiveable_combo_box (GtkComboBox *combo) "text", 0, "sensitive", 1, NULL); } -/* EContact can get attributes by field ID only, - * and there is none for TEL, so we need this */ -static GList * -get_attributes_named (EVCard *vcard, - const gchar *attr_name) -{ - GList *attr_list_in; - GList *attr_list_out = NULL; - GList *l; - - attr_list_in = e_vcard_get_attributes (vcard); - - for (l = attr_list_in; l; l = g_list_next (l)) { - EVCardAttribute *attr = l->data; - const gchar *name; - - name = e_vcard_attribute_get_name (attr); - - if (!g_ascii_strcasecmp (attr_name, name)) { - attr_list_out = g_list_append ( - attr_list_out, - e_vcard_attribute_copy (attr)); - } - } - - return attr_list_out; -} - -/* EContact can set attributes by field ID only, - * and there is none for TEL, so we need this */ -static void -set_attributes_named (EVCard *vcard, - const gchar *attr_name, - GList *attr_list) -{ - GList *l; - - e_vcard_remove_attributes (vcard, NULL, attr_name); - - for (l = attr_list; l; l = g_list_next (l)) { - EVCardAttribute *attr = l->data; - - e_vcard_add_attribute (vcard, e_vcard_attribute_copy (attr)); - } -} - static void set_arrow_image (EContactEditor *editor, const gchar *arrow_widget, @@ -1378,6 +1335,22 @@ set_arrow_image (EContactEditor *editor, GTK_ARROW (arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE); } +static gboolean +is_arrow_image_arrow_down (EContactEditor *editor, + const gchar *arrow_widget) +{ + GtkWidget *arrow; + gint value; + + arrow = e_builder_get_widget (editor->priv->builder, arrow_widget); + g_object_get (arrow, "arrow-type", &value, NULL); + + if (value == GTK_ARROW_DOWN) + return TRUE; + + return FALSE; +} + static void expand_widget_list (EContactEditor *editor, const gchar **widget_names, @@ -1407,13 +1380,18 @@ static void expand_phone (EContactEditor *editor, gboolean expanded) { - const gchar *names[] = { - "entry-phone-3", "combobox-phone-3", - "entry-phone-4", "combobox-phone-4", - "table-phone-extended", NULL - }; + GtkWidget *w; + EContactEditorDynTable *dyntable; + set_arrow_image (editor, "arrow-phone-expand", expanded); - expand_widget_list (editor, names, expanded); + + w = e_builder_get_widget (editor->priv->builder, "phone-dyntable"); + dyntable = E_CONTACT_EDITOR_DYNTABLE (w); + + if (expanded) + e_contact_editor_dyntable_set_show_max (dyntable, PHONE_SLOTS); + else + e_contact_editor_dyntable_set_show_max (dyntable, SLOTS_IN_COLLAPSED_STATE); } static void @@ -1460,89 +1438,51 @@ init_email (EContactEditor *editor) } static void -fill_in_phone_record (EContactEditor *editor, - gint record, - const gchar *phone, - gint phone_type) -{ - GtkWidget *phone_type_combo_box; - GtkWidget *phone_entry; - gchar *widget_name; - - widget_name = g_strdup_printf ("combobox-phone-%d", record); - phone_type_combo_box = e_builder_get_widget (editor->priv->builder, widget_name); - g_free (widget_name); - - widget_name = g_strdup_printf ("entry-phone-%d", record); - phone_entry = e_builder_get_widget (editor->priv->builder, widget_name); - g_free (widget_name); - - set_combo_box_active ( - editor, GTK_COMBO_BOX (phone_type_combo_box), - phone_type >= 0 ? phone_type : phones_default[record - 1]); - set_entry_text (editor, GTK_ENTRY (phone_entry), phone ? phone : ""); - - if (phone && *phone && record >= 3) - expand_phone (editor, TRUE); -} - -static void -extract_phone_record (EContactEditor *editor, - gint record, - gchar **phone, - gint *phone_type) -{ - GtkWidget *phone_type_combo_box; - GtkWidget *phone_entry; - gchar *widget_name; - - widget_name = g_strdup_printf ("combobox-phone-%d", record); - phone_type_combo_box = e_builder_get_widget (editor->priv->builder, widget_name); - g_free (widget_name); - - widget_name = g_strdup_printf ("entry-phone-%d", record); - phone_entry = e_builder_get_widget (editor->priv->builder, widget_name); - g_free (widget_name); - - *phone = g_strdup (gtk_entry_get_text (GTK_ENTRY (phone_entry))); - *phone_type = gtk_combo_box_get_active (GTK_COMBO_BOX (phone_type_combo_box)); -} - -static void fill_in_phone (EContactEditor *editor) { GList *phone_attr_list; GList *l; - gint record_n; + GtkWidget *w; + EContactEditorDynTable *dyntable; + GtkListStore *data_store; + GtkTreeIter iter; + + w = e_builder_get_widget (editor->priv->builder, "phone-dyntable"); + dyntable = E_CONTACT_EDITOR_DYNTABLE (w); /* Clear */ - for (record_n = 1; record_n <= PHONE_SLOTS; record_n++) { - fill_in_phone_record (editor, record_n, NULL, -1); - } + e_contact_editor_dyntable_clear_data (dyntable); /* Fill in */ - phone_attr_list = get_attributes_named (E_VCARD (editor->priv->contact), "TEL"); + phone_attr_list = e_contact_get_attributes (editor->priv->contact, E_CONTACT_TEL); + data_store = e_contact_editor_dyntable_extract_data (dyntable); - for (record_n = 1, l = phone_attr_list; - l && record_n <= PHONE_SLOTS; l = g_list_next (l)) { + for (l = phone_attr_list;l ; l = g_list_next (l)) { EVCardAttribute *attr = l->data; gchar *phone; gint slot; + gint phone_type; + slot = get_ui_slot (attr); + phone_type = get_phone_type (attr); phone = e_vcard_attribute_get_value (attr); - slot = alloc_ui_slot (editor, "entry-phone", get_ui_slot (attr), PHONE_SLOTS); - if (slot < 1) - break; - fill_in_phone_record ( - editor, slot, phone, get_phone_type (attr)); - - 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, phone_type, + DYNTABLE_STORE_COLUMN_ENTRY_STRING, phone, + -1); g_free (phone); } + + e_contact_editor_dyntable_fill_in_data (dyntable); + g_list_free_full (phone_attr_list, (GDestroyNotify) e_vcard_attribute_free); + + expand_phone (editor, TRUE); } static void @@ -1552,45 +1492,54 @@ extract_phone (EContactEditor *editor) GList *old_attr_list; GList *ll; gint i; + GtkWidget *w; + EContactEditorDynTable *dyntable; + GtkListStore *data_store; + GtkTreeModel *tree_model; + GtkTreeIter iter; + gboolean valid; - for (i = 1; i <= PHONE_SLOTS; i++) { - gchar *phone; - gint phone_type; + w = e_builder_get_widget (editor->priv->builder, "phone-dyntable"); + dyntable = E_CONTACT_EDITOR_DYNTABLE (w); + data_store = e_contact_editor_dyntable_extract_data (dyntable); + tree_model = GTK_TREE_MODEL (data_store); - extract_phone_record (editor, i, &phone, &phone_type); + valid = gtk_tree_model_get_iter_first (tree_model, &iter); + while (valid){ + gint phone_type; + gchar *phone; + EVCardAttribute *attr; - if (!STRING_IS_EMPTY (phone)) { - EVCardAttribute *attr; + attr = e_vcard_attribute_new ("", "TEL"); + gtk_tree_model_get (tree_model,&iter, + DYNTABLE_STORE_COLUMN_SELECTED_ITEM, &phone_type, + DYNTABLE_STORE_COLUMN_ENTRY_STRING, &phone, + -1); - attr = e_vcard_attribute_new ("", "TEL"); + if (phone_type >= 0) { + const gchar *type_1; + const gchar *type_2; - if (phone_type >= 0) { - const gchar *type_1; - const gchar *type_2; + phone_index_to_type (phone_type, &type_1, &type_2); - phone_index_to_type (phone_type, &type_1, &type_2); + e_vcard_attribute_add_param_with_value ( + attr, e_vcard_attribute_param_new (EVC_TYPE), type_1); + if (type_2) e_vcard_attribute_add_param_with_value ( - attr, e_vcard_attribute_param_new (EVC_TYPE), type_1); + attr, e_vcard_attribute_param_new (EVC_TYPE), type_2); + } - if (type_2) - e_vcard_attribute_add_param_with_value ( - attr, e_vcard_attribute_param_new (EVC_TYPE), type_2); + e_vcard_attribute_add_value (attr, phone); - } - - e_vcard_attribute_add_value (attr, phone); - set_ui_slot (attr, i); + attr_list = g_list_append (attr_list, attr); - attr_list = g_list_append (attr_list, attr); - } - - g_free (phone); + valid = gtk_tree_model_iter_next (tree_model, &iter); } /* Splice in the old attributes, minus the PHONE_SLOTS first */ - old_attr_list = get_attributes_named (E_VCARD (editor->priv->contact), "TEL"); + old_attr_list = e_contact_get_attributes (editor->priv->contact, E_CONTACT_TEL); for (ll = old_attr_list, i = 1; ll && i <= PHONE_SLOTS; i++) { e_vcard_attribute_free (ll->data); ll = g_list_delete_link (ll, ll); @@ -1599,81 +1548,82 @@ extract_phone (EContactEditor *editor) old_attr_list = ll; attr_list = g_list_concat (attr_list, old_attr_list); - set_attributes_named (E_VCARD (editor->priv->contact), "TEL", attr_list); + e_contact_set_attributes (editor->priv->contact, E_CONTACT_TEL, attr_list); - free_attr_list (attr_list); + g_list_free_full (attr_list, (GDestroyNotify) e_vcard_attribute_free); } static void -init_phone_record_type (EContactEditor *editor, - gint record) +init_phone_record_type (EContactEditor *editor) { - GtkWidget *phone_type_combo_box; - GtkWidget *phone_entry; - gchar *widget_name; - gint i; + GtkWidget *w; GtkListStore *store; + gint i; + EContactEditorDynTable *dyntable; - widget_name = g_strdup_printf ("entry-phone-%d", record); - phone_entry = e_builder_get_widget (editor->priv->builder, widget_name); - g_free (widget_name); - - widget_name = g_strdup_printf ("combobox-phone-%d", record); - phone_type_combo_box = e_builder_get_widget (editor->priv->builder, widget_name); - g_free (widget_name); - - init_item_sensitiveable_combo_box (GTK_COMBO_BOX (phone_type_combo_box)); - - store = GTK_LIST_STORE ( - gtk_combo_box_get_model ( - GTK_COMBO_BOX (phone_type_combo_box))); + w = e_builder_get_widget (editor->priv->builder, "phone-dyntable"); + dyntable = E_CONTACT_EDITOR_DYNTABLE (w); + store = e_contact_editor_dyntable_get_combo_store (dyntable); for (i = 0; i < G_N_ELEMENTS (phones); i++) { GtkTreeIter iter; gtk_list_store_append (store, &iter); - gtk_list_store_set ( - store, &iter, - 0, e_contact_pretty_name (phones[i].field_id), - 1, TRUE, - -1); + gtk_list_store_set (store, &iter, + DYNTABLE_COMBO_COLUMN_TEXT, e_contact_pretty_name (phones[i].field_id), + DYNTABLE_COMBO_COLUMN_SENSITIVE, TRUE, + -1); } - g_signal_connect_swapped ( - phone_type_combo_box, "changed", - G_CALLBACK (gtk_widget_grab_focus), phone_entry); - g_signal_connect ( - phone_type_combo_box, "changed", - G_CALLBACK (object_changed), editor); - g_signal_connect ( - phone_entry, "changed", - G_CALLBACK (object_changed), editor); - g_signal_connect_swapped ( - phone_entry, "activate", - G_CALLBACK (entry_activated), editor); + e_contact_editor_dyntable_set_combo_defaults (dyntable, phones_default, G_N_ELEMENTS (phones_default)); +} + +static void +row_added_phone (EContactEditorDynTable *dyntable, EContactEditor *editor) +{ + expand_phone (editor, TRUE); } static void init_phone (EContactEditor *editor) { - gint i; + GtkWidget *w; + EContactEditorDynTable *dyntable; + + w = e_builder_get_widget (editor->priv->builder, "phone-dyntable"); + dyntable = E_CONTACT_EDITOR_DYNTABLE (w); - expand_phone (editor, FALSE); + 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); - for (i = 1; i <= PHONE_SLOTS; i++) - init_phone_record_type (editor, i); + 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_phone), editor); + + init_phone_record_type (editor); } static void -sensitize_phone_types (EContactEditor *editor, - GtkWidget *combo_box) +sensitize_phone_types (EContactEditor *editor) { + GtkWidget *w; + GtkListStore *listStore; GtkTreeModel *model; GtkTreeIter iter; gint i; gboolean valid; - model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); + w = e_builder_get_widget (editor->priv->builder, "phone-dyntable"); + listStore = e_contact_editor_dyntable_get_combo_store (E_CONTACT_EDITOR_DYNTABLE (w)); + model = GTK_TREE_MODEL (listStore); + valid = gtk_tree_model_get_iter_first (model, &iter); for (i = 0; i < G_N_ELEMENTS (phones); i++) { @@ -1682,51 +1632,29 @@ sensitize_phone_types (EContactEditor *editor, return; } - gtk_list_store_set ( - GTK_LIST_STORE (model), &iter, - 1, is_field_supported (editor, phones[i].field_id), - -1); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + DYNTABLE_COMBO_COLUMN_SENSITIVE, + is_field_supported (editor, phones[i].field_id), + -1); valid = gtk_tree_model_iter_next (model, &iter); } } static void -sensitize_phone_record (EContactEditor *editor, - gint record, - gboolean enabled) -{ - GtkWidget *phone_type_combo_box; - GtkWidget *phone_entry; - gchar *widget_name; - - widget_name = g_strdup_printf ("combobox-phone-%d", record); - phone_type_combo_box = e_builder_get_widget (editor->priv->builder, widget_name); - g_free (widget_name); - - widget_name = g_strdup_printf ("entry-phone-%d", record); - phone_entry = e_builder_get_widget (editor->priv->builder, widget_name); - g_free (widget_name); - - gtk_widget_set_sensitive (phone_type_combo_box, enabled); - gtk_editable_set_editable (GTK_EDITABLE (phone_entry), enabled); - - sensitize_phone_types (editor, phone_type_combo_box); -} - -static void sensitize_phone (EContactEditor *editor) { - gint i; + GtkWidget *w; + gboolean enabled = TRUE; - for (i = 1; i <= PHONE_SLOTS; i++) { - gboolean enabled = TRUE; + w = e_builder_get_widget (editor->priv->builder, "phone-dyntable"); - if (!editor->priv->target_editable) - enabled = FALSE; + if (!editor->priv->target_editable) + enabled = FALSE; - sensitize_phone_record (editor, i, enabled); - } + gtk_widget_set_sensitive (w, enabled); + + sensitize_phone_types (editor); } static void @@ -4159,11 +4087,7 @@ expand_web_toggle (EContactEditor *ce) static void expand_phone_toggle (EContactEditor *ce) { - GtkWidget *phone_ext_table; - - phone_ext_table = e_builder_get_widget ( - ce->priv->builder, "table-phone-extended"); - expand_phone (ce, !gtk_widget_get_visible (phone_ext_table)); + expand_phone (ce, !is_arrow_image_arrow_down (ce, "arrow-phone-expand")); } static void |