/*
* 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; either
* version 2 of the License, or (at your option) version 3.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
* Authors:
* Chris Lahey <clahey@ximian.com>
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "eab-editor.h"
#include "e-contact-editor.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <gdk/gdkkeysyms.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libebook/e-address-western.h>
#include <libedataserverui/e-client-utils.h>
#include <libedataserverui/e-categories-dialog.h>
#include <libedataserverui/e-category-completion.h>
#include <libedataserverui/e-source-combo-box.h>
#include "addressbook/printing/e-contact-print.h"
#include "addressbook/gui/widgets/eab-gui-util.h"
#include "e-util/e-util.h"
#include "libevolution-utils/e-alert-dialog.h"
#include "misc/e-dateedit.h"
#include "misc/e-image-chooser.h"
#include "misc/e-url-entry.h"
#include "e-util/e-icon-factory.h"
#include "e-util/e-util-private.h"
#include "shell/e-shell.h"
#include "eab-contact-merging.h"
#include "e-contact-editor-fullname.h"
#define EMAIL_SLOTS 4
#define PHONE_SLOTS 8
#define IM_SLOTS 4
#define ADDRESS_SLOTS 3
#define EVOLUTION_UI_SLOT_PARAM "X-EVOLUTION-UI-SLOT"
/* IM columns */
enum {
COLUMN_IM_ICON,
COLUMN_IM_SERVICE,
COLUMN_IM_SCREENNAME,
COLUMN_IM_LOCATION,
COLUMN_IM_LOCATION_TYPE,
COLUMN_IM_SERVICE_FIELD,
NUM_IM_COLUMNS
};
static void e_contact_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void e_contact_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void e_contact_editor_dispose (GObject *object);
static void e_contact_editor_raise (EABEditor *editor);
static void e_contact_editor_show (EABEditor *editor);
static void e_contact_editor_save_contact (EABEditor *editor,
gboolean should_close);
static void e_contact_editor_close (EABEditor *editor);
static gboolean e_contact_editor_is_valid (EABEditor *editor);
static gboolean e_contact_editor_is_changed (EABEditor *editor);
static GtkWindow *
e_contact_editor_get_window (EABEditor *editor);
static void save_contact (EContactEditor *ce,
gboolean should_close);
static void entry_activated (EContactEditor *editor);
static void set_entry_text (EContactEditor *editor,
GtkEntry *entry,
const gchar *string);
static void sensitize_ok (EContactEditor *ce);
static EABEditorClass *parent_class = NULL;
/* The arguments we take */
enum {
PROP_0,
PROP_SOURCE_CLIENT,
PROP_TARGET_CLIENT,
PROP_CONTACT,
PROP_IS_NEW_CONTACT,
PROP_EDITABLE,
PROP_CHANGED,
PROP_WRITABLE_FIELDS,
PROP_REQUIRED_FIELDS
};
enum {
DYNAMIC_LIST_EMAIL,
DYNAMIC_LIST_PHONE,
DYNAMIC_LIST_ADDRESS
};
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 }
};
/* Defaults from the table above */
static const gint phones_default[] = { 1, 6, 9, 2, 7, 12, 10, 10 };
static EContactField addresses[] = {
E_CONTACT_ADDRESS_WORK,
E_CONTACT_ADDRESS_HOME,
E_CONTACT_ADDRESS_OTHER
};
static EContactField address_labels[] = {
E_CONTACT_ADDRESS_LABEL_WORK,
E_CONTACT_ADDRESS_LABEL_HOME,
E_CONTACT_ADDRESS_LABEL_OTHER
};
static const gchar *address_name[] = {
"work",
"home",
"other"
};
static struct {
EContactField field;
const gchar *pretty_name;
}
im_service[] =
{
{ E_CONTACT_IM_AIM, N_ ("AIM") },
{ E_CONTACT_IM_JABBER, N_ ("Jabber") },
{ E_CONTACT_IM_YAHOO, N_ ("Yahoo") },
{ E_CONTACT_IM_GADUGADU, N_ ("Gadu-Gadu") },
{ E_CONTACT_IM_MSN, N_ ("MSN") },
{ E_CONTACT_IM_ICQ, N_ ("ICQ") },
{ E_CONTACT_IM_GROUPWISE, N_ ("GroupWise") },
{ E_CONTACT_IM_SKYPE, N_ ("Skype") },
{ E_CONTACT_IM_TWITTER, N_ ("Twitter") }
};
/* Defaults from the table above */
static const gint im_service_default[] = { 0, 2, 4, 5 };
static struct {
const gchar *name;
const gchar *pretty_name;
}
common_location[] =
{
{ "WORK", N_ ("Work") },
{ "HOME", N_ ("Home") },
{ "OTHER", N_ ("Other") }
};
/* Default from the table above */
static const gint email_default[] = { 0, 1, 2, 2 };
#define STRING_IS_EMPTY(x) (!(x) || !(*(x)))
#define STRING_MAKE_NON_NULL(x) ((x) ? (x) : "")
G_DEFINE_TYPE (EContactEditor, e_contact_editor, EAB_TYPE_EDITOR)
static void
e_contact_editor_contact_added (EABEditor *editor,
const GError *error,
EContact *contact)
{
if (!error)
return;
if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
eab_error_dialog (NULL, _("Error adding contact"), error);
}
static void
e_contact_editor_contact_modified (EABEditor *editor,
const GError *error,
EContact *contact)
{
if (!error)
return;
if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
eab_error_dialog (NULL, _("Error modifying contact"), error);
}
static void
e_contact_editor_contact_deleted (EABEditor *editor,
const GError *error,
EContact *contact)
{
if (!error)
return;
if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
eab_error_dialog (NULL, _("Error removing contact"), error);
}
static void
e_contact_editor_closed (EABEditor *editor)
{
g_object_unref (editor);
}
static void
e_contact_editor_class_init (EContactEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
EABEditorClass *editor_class = EAB_EDITOR_CLASS (class);
parent_class = g_type_class_ref (EAB_TYPE_EDITOR);
object_class->set_property = e_contact_editor_set_property;
object_class->get_property = e_contact_editor_get_property;
object_class->dispose = e_contact_editor_dispose;
editor_class->raise = e_contact_editor_raise;
editor_class->show = e_contact_editor_show;
editor_class->close = e_contact_editor_close;
editor_class->is_valid = e_contact_editor_is_valid;
editor_class->save_contact = e_contact_editor_save_contact;
editor_class->is_changed = e_contact_editor_is_changed;
editor_class->get_window = e_contact_editor_get_window;
editor_class->contact_added = e_contact_editor_contact_added;
editor_class->contact_modified = e_contact_editor_contact_modified;
editor_class->contact_deleted = e_contact_editor_contact_deleted;
editor_class->editor_closed = e_contact_editor_closed;
g_object_class_install_property (
object_class,
PROP_SOURCE_CLIENT,
g_param_spec_object (
"source_client",
"Source EBookClient",
NULL,
E_TYPE_BOOK_CLIENT,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_TARGET_CLIENT,
g_param_spec_object (
"target_client",
"Target EBookClient",
NULL,
E_TYPE_BOOK_CLIENT,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_CONTACT,
g_param_spec_object (
"contact",
"Contact",
NULL,
E_TYPE_CONTACT,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_IS_NEW_CONTACT,
g_param_spec_boolean (
"is_new_contact",
"Is New Contact",
NULL,
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_WRITABLE_FIELDS,
g_param_spec_pointer (
"writable_fields",
"Writable Fields",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_REQUIRED_FIELDS,
g_param_spec_pointer (
"required_fields",
"Required Fields",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_EDITABLE,
g_param_spec_boolean (
"editable",
"Editable",
NULL,
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_CHANGED,
g_param_spec_boolean (
"changed",
"Changed",
NULL,
FALSE,
G_PARAM_READWRITE));
}
static void
entry_activated (EContactEditor *editor)
{
save_contact (editor, TRUE);
}
/* FIXME: Linear time... */
static gboolean
is_field_supported (EContactEditor *editor,
EContactField field_id)
{
GSList *fields, *iter;
const gchar *field;
fields = editor->writable_fields;
if (!fields)
return FALSE;
field = e_contact_field_name (field_id);
if (!field)
return FALSE;
for (iter = fields; iter; iter = iter->next) {
const gchar *this_field = iter->data;
if (!this_field)
continue;
if (!strcmp (field, this_field))
return TRUE;
}
return FALSE;
}
/* This function tells you whether name_to_style will make sense. */
static gboolean
style_makes_sense (const EContactName *name,
const gchar *company,
gint style)
{
switch (style) {
case 0: /* Fall Through */
case 1:
return TRUE;
case 2:
if (name) {
if (name->additional && *name->additional)
return TRUE;
else
return FALSE;
}
case 3:
if (company && *company)
return TRUE;
else
return FALSE;
case 4: /* Fall Through */
case 5:
if (company && *company && name &&
((name->given && *name->given) ||
(name->family && *name->family)))
return TRUE;
else
return FALSE;
default:
return FALSE;
}
}
static gchar *
name_to_style (const EContactName *name,
const gchar *company,
gint style)
{
gchar *string;
gchar *strings[4], **stringptr;
gchar *midstring[4], **midstrptr;
gchar *substring;
switch (style) {
case 0:
stringptr = strings;
if (name) {
if (name->family && *name->family)
*(stringptr++) = name->family;
if (name->given && *name->given)
*(stringptr++) = name->given;
}
*stringptr = NULL;
string = g_strjoinv(", ", strings);
break;
case 1:
stringptr = strings;
if (name) {
if (name->given && *name->given)
*(stringptr++) = name->given;
if (name->family && *name->family)
*(stringptr++) = name->family;
}
*stringptr = NULL;
string = g_strjoinv(" ", strings);
break;
case 2:
midstrptr = midstring;
if (name) {
if (name->family && *name->family)
*(midstrptr++) = name->family;
if (name->given && *name->given)
*(midstrptr++) = name->given;
}
*midstrptr = NULL;
stringptr = strings;
*(stringptr++) = g_strjoinv(", ", midstring);
if (name) {
if (name->additional && *name->additional)
*(stringptr++) = name->additional;
}
*stringptr = NULL;
string = g_strjoinv(" ", strings);
break;
case 3:
string = g_strdup (company);
break;
case 4: /* Fall Through */
case 5:
stringptr = strings;
if (name) {
if (name->family && *name->family)
*(stringptr++) = name->family;
if (name->given && *name->given)
*(stringptr++) = name->given;
}
*stringptr = NULL;
substring = g_strjoinv(", ", strings);
if (!(company && *company))
company = "";
if (style == 4)
string = g_strdup_printf("%s (%s)", substring, company);
else
string = g_strdup_printf("%s (%s)", company, substring);
g_free (substring);
break;
default:
string = g_strdup("");
}
return string;
}
static gint
file_as_get_style (EContactEditor *editor)
{
GtkEntry *file_as = GTK_ENTRY (
gtk_bin_get_child (GTK_BIN (
e_builder_get_widget(editor->builder, "combo-file-as"))));
GtkEntry *company_w = GTK_ENTRY (
e_builder_get_widget (editor->builder, "entry-company"));
gchar *filestring;
gchar *trystring;
EContactName *name = editor->name;
const gchar *company;
gint i;
if (!(file_as && GTK_IS_ENTRY (file_as)))
return -1;
company = gtk_entry_get_text (GTK_ENTRY (company_w));
filestring = g_strdup (gtk_entry_get_text (file_as));
for (i = 0; i < 6; i++) {
trystring = name_to_style (name, company, i);
if (!strcmp (trystring, filestring)) {
g_free (trystring);
g_free (filestring);
return i;
}
g_free (trystring);
}
g_free (filestring);
return -1;
}
static void
file_as_set_style (EContactEditor *editor,
gint style)
{
gchar *string;
gint i;
GList *strings = NULL;
GtkComboBox *combo_file_as = GTK_COMBO_BOX (
e_builder_get_widget (editor->builder, "combo-file-as"));
GtkEntry *company_w = GTK_ENTRY (
e_builder_get_widget (editor->builder, "entry-company"));
const gchar *company;
if (!(combo_file_as && GTK_IS_COMBO_BOX (combo_file_as)))
return;
company = gtk_entry_get_text (GTK_ENTRY (company_w));
if (style == -1) {
GtkWidget *entry;
entry = gtk_bin_get_child (GTK_BIN (combo_file_as));
if (entry) {
string = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
strings = g_list_append (strings, string);
}
}
for (i = 0; i < 6; i++) {
if (style_makes_sense (editor->name, company, i)) {
gchar *u;
u = name_to_style (editor->name, company, i);
if (!STRING_IS_EMPTY (u))
strings = g_list_append (strings, u);
else
g_free (u);
}
}
if (combo_file_as) {
GList *l;
GtkListStore *list_store;
GtkTreeIter iter;
list_store = GTK_LIST_STORE (
gtk_combo_box_get_model (combo_file_as));
gtk_list_store_clear (list_store);
for (l = strings; l; l = l->next) {
gtk_list_store_append (list_store, &iter);
gtk_list_store_set (list_store, &iter, 0, l->data, -1);
}
}
g_list_foreach (strings, (GFunc) g_free, NULL);
g_list_free (strings);
if (style != -1) {
string = name_to_style (editor->name, company, style);
set_entry_text (
editor, GTK_ENTRY (gtk_bin_get_child (
GTK_BIN (combo_file_as))), string);
g_free (string);
}
}
static void
name_entry_changed (GtkWidget *widget,
EContactEditor *editor)
{
gint style = 0;
const gchar *string;
style = file_as_get_style (editor);
e_contact_name_free (editor->name);
string = gtk_entry_get_text (GTK_ENTRY (widget));
editor->name = e_contact_name_from_string (string);
file_as_set_style (editor, style);
editor->check_merge = TRUE;
sensitize_ok (editor);
if (string && !*string)
gtk_window_set_title (
GTK_WINDOW (editor->app), _("Contact Editor"));
}
static void
file_as_combo_changed (GtkWidget *widget,
EContactEditor *editor)
{
GtkWidget *entry;
gchar *string = NULL;
entry = gtk_bin_get_child (GTK_BIN (widget));
if (entry)
string = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
if (string && *string) {
gchar *title;
title = g_strdup_printf (_("Contact Editor - %s"), string);
gtk_window_set_title (GTK_WINDOW (editor->app), title);
g_free (title);
}
else {
gtk_window_set_title (
GTK_WINDOW (editor->app), _("Contact Editor"));
}
sensitize_ok (editor);
g_free (string);
}
static void
company_entry_changed (GtkWidget *widget,
EContactEditor *editor)
{
gint style = 0;
style = file_as_get_style (editor);
file_as_set_style (editor, style);
}
static void
update_file_as_combo (EContactEditor *editor)
{
file_as_set_style (editor, file_as_get_style (editor));
}
static void
fill_in_source_field (EContactEditor *editor)
{
GtkWidget *source_menu;
if (!editor->target_client)
return;
source_menu = e_builder_get_widget (
editor->builder, "source-combo-box-source");
e_source_combo_box_set_active (
E_SOURCE_COMBO_BOX (source_menu),
e_client_get_source (E_CLIENT (editor->target_client)));
}
static void
sensitize_ok (EContactEditor *ce)
{
GtkWidget *widget;
gboolean allow_save;
GtkWidget *entry_fullname =
e_builder_get_widget (ce->builder, "entry-fullname" );
GtkWidget *entry_file_as =
gtk_bin_get_child (GTK_BIN (
e_builder_get_widget (ce->builder, "combo-file-as")));
GtkWidget *company_name =
e_builder_get_widget (ce->builder, "entry-company");
const gchar *name_entry_string =
gtk_entry_get_text (GTK_ENTRY (entry_fullname));
const gchar *file_as_entry_string =
gtk_entry_get_text (GTK_ENTRY (entry_file_as));
const gchar *company_name_string =
gtk_entry_get_text (GTK_ENTRY (company_name));
allow_save = ce->target_editable && ce->changed;
if (!strcmp (name_entry_string, "") ||
!strcmp (file_as_entry_string, "")) {
if (strcmp (company_name_string , "")) {
allow_save = TRUE;
}
else
allow_save = FALSE;
}
widget = e_builder_get_widget (ce->builder, "button-ok");
gtk_widget_set_sensitive (widget, allow_save);
}
static void
object_changed (GObject *object,
EContactEditor *editor)
{
if (!editor->target_editable) {
g_warning ("non-editable contact editor has an editable field in it.");
return;
}
if (!editor->check_merge && GTK_IS_WIDGET (object)) {
const gchar *widget_name;
widget_name = gtk_widget_get_name (GTK_WIDGET (object));
if (widget_name &&
((g_str_equal (widget_name, "fullname")) ||
(g_str_equal (widget_name, "nickname")) ||
(g_str_equal (widget_name, "file-as")) ||
(g_str_has_prefix (widget_name, "email-"))))
editor->check_merge = TRUE;
}
if (!editor->changed) {
editor->changed = TRUE;
sensitize_ok (editor);
}
}
static void
image_chooser_changed (GtkWidget *widget,
EContactEditor *editor)
{
editor->image_set = TRUE;
editor->image_changed = TRUE;
}
static void
set_entry_text (EContactEditor *editor,
GtkEntry *entry,
const gchar *string)
{
const gchar *oldstring = gtk_entry_get_text (entry);
if (!string)
string = "";
if (strcmp (string, oldstring)) {
g_signal_handlers_block_matched (
entry, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
gtk_entry_set_text (entry, string);
g_signal_handlers_unblock_matched (
entry, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, 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)
{
GtkComboBox *location_combo_box;
GtkWidget *email_entry;
gchar *widget_name;
gint i;
GtkTreeIter iter;
GtkListStore *store;
widget_name = g_strdup_printf ("entry-email-%d", record);
email_entry = e_builder_get_widget (editor->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->builder, widget_name));
g_free (widget_name);
store = GTK_LIST_STORE (gtk_combo_box_get_model (location_combo_box));
gtk_list_store_clear (store);
for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
0, _(common_location[i].pretty_name),
-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->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf ("entry-email-%d", record);
email_entry = e_builder_get_widget (editor->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->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf ("entry-email-%d", record);
email_entry = e_builder_get_widget (editor->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));
}
static const gchar *
email_index_to_location (gint index)
{
return common_location[index].name;
}
static const gchar *
im_index_to_location (gint index)
{
return common_location[index].name;
}
static void
phone_index_to_type (gint index,
const gchar **type_1,
const gchar **type_2)
{
*type_1 = phones [index].type_1;
*type_2 = phones [index].type_2;
}
static gint
get_email_location (EVCardAttribute *attr)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
if (e_vcard_attribute_has_type (attr, common_location[i].name))
return i;
}
return -1;
}
static gint
get_im_location (EVCardAttribute *attr)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
if (e_vcard_attribute_has_type (attr, common_location[i].name))
return i;
}
return -1;
}
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 EVCardAttributeParam *
get_ui_slot_param (EVCardAttribute *attr)
{
EVCardAttributeParam *param = NULL;
GList *param_list;
GList *l;
param_list = e_vcard_attribute_get_params (attr);
for (l = param_list; l; l = g_list_next (l)) {
const gchar *str;
param = l->data;
str = e_vcard_attribute_param_get_name (param);
if (!g_ascii_strcasecmp (str, EVOLUTION_UI_SLOT_PARAM))
break;
param = NULL;
}
return param;
}
static gint
get_ui_slot (EVCardAttribute *attr)
{
EVCardAttributeParam *param;
gint slot = -1;
param = get_ui_slot_param (attr);
if (param) {
GList *value_list;
value_list = e_vcard_attribute_param_get_values (param);
slot = atoi (value_list->data);
}
return slot;
}
static void
set_ui_slot (EVCardAttribute *attr,
gint slot)
{
EVCardAttributeParam *param;
gchar *slot_str;
param = get_ui_slot_param (attr);
if (!param) {
param = e_vcard_attribute_param_new (EVOLUTION_UI_SLOT_PARAM);
e_vcard_attribute_add_param (attr, param);
}
e_vcard_attribute_param_remove_values (param);
slot_str = g_strdup_printf ("%d", slot);
e_vcard_attribute_param_add_value (param, slot_str);
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->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->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;
/* Clear */
for (record_n = 1; record_n <= EMAIL_SLOTS; record_n++) {
fill_in_email_record (
editor, record_n, NULL, email_default[record_n - 1]);
}
/* Fill in */
email_attr_list = e_contact_get_attributes (
editor->contact, E_CONTACT_EMAIL);
for (record_n = 1, l = email_attr_list;
l && record_n <= EMAIL_SLOTS; l = g_list_next (l)) {
EVCardAttribute *attr = l->data;
gchar *email_address;
gint slot;
email_address = e_vcard_attribute_get_value (attr);
slot = alloc_ui_slot (
editor, "entry-email",
get_ui_slot (attr), EMAIL_SLOTS);
if (slot < 1)
break;
fill_in_email_record (
editor, slot, email_address,
get_email_location (attr));
record_n++;
g_free (email_address);
}
g_list_free_full (email_attr_list, (GDestroyNotify) e_vcard_attribute_free);
}
static void
extract_email (EContactEditor *editor)
{
GList *attr_list = NULL;
GList *old_attr_list;
GList *l, *l_next;
gint i;
for (i = 1; i <= EMAIL_SLOTS; i++) {
gchar *address;
gint location;
extract_email_record (editor, i, &address, &location);
if (!STRING_IS_EMPTY (address)) {
EVCardAttribute *attr;
attr = e_vcard_attribute_new (
"", e_contact_vcard_attribute (E_CONTACT_EMAIL));
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);
attr_list = g_list_append (attr_list, attr);
}
g_free (address);
}
/* Splice in the old attributes, minus the EMAIL_SLOTS first */
old_attr_list = e_contact_get_attributes (editor->contact, E_CONTACT_EMAIL);
for (l = old_attr_list, i = 1; l && i <= EMAIL_SLOTS; l = l_next, i++) {
l_next = g_list_next (l);
e_vcard_attribute_free (l->data);
l = g_list_delete_link (l, l);
}
old_attr_list = l;
attr_list = g_list_concat (attr_list, old_attr_list);
e_contact_set_attributes (editor->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->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf ("entry-email-%d", record);
email_entry = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
gtk_widget_set_sensitive (location_combo_box, enabled);
gtk_editable_set_editable (GTK_EDITABLE (email_entry), enabled);
}
static void
sensitize_email (EContactEditor *editor)
{
gint i;
for (i = 1; i <= EMAIL_SLOTS; i++) {
gboolean enabled = TRUE;
if (!editor->target_editable)
enabled = FALSE;
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;
sensitize_email_record (editor, i, enabled);
}
}
static void
init_item_sensitiveable_combo_box (GtkComboBox *combo)
{
GtkCellRenderer *cell;
GtkListStore *store;
g_return_if_fail (combo != NULL);
g_return_if_fail (GTK_IS_COMBO_BOX (combo));
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
g_object_unref (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", 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,
gboolean expanded)
{
GtkWidget *arrow;
arrow = e_builder_get_widget (editor->builder, arrow_widget);
if (expanded)
gtk_arrow_set (
GTK_ARROW (arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
else
gtk_arrow_set (
GTK_ARROW (arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
}
static void
expand_widget_list (EContactEditor *editor,
const gchar **widget_names,
gboolean expanded)
{
gint i;
for (i = 0; widget_names[i]; i++)
gtk_widget_set_visible (
e_builder_get_widget (editor->builder, widget_names[i]),
expanded);
}
static void
expand_web (EContactEditor *editor,
gboolean expanded)
{
const gchar *names[] = {
"label-videourl", "label-fburl",
"entry-videourl", "entry-fburl",
NULL
};
set_arrow_image (editor, "arrow-web-expand", expanded);
expand_widget_list (editor, names, expanded);
}
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
};
set_arrow_image (editor, "arrow-phone-expand", expanded);
expand_widget_list (editor, names, expanded);
}
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
};
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->builder, "checkbutton-htmlmail");
table = GTK_TABLE (e_builder_get_widget (editor->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);
}
}
static void
init_email (EContactEditor *editor)
{
gint i;
for (i = 1; i <= EMAIL_SLOTS; i++)
init_email_record_location (editor, i);
expand_mail (editor, !editor->compress_ui);
}
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->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf ("entry-phone-%d", record);
phone_entry = e_builder_get_widget (editor->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->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf ("entry-phone-%d", record);
phone_entry = e_builder_get_widget (editor->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;
/* Clear */
for (record_n = 1; record_n <= PHONE_SLOTS; record_n++) {
fill_in_phone_record (editor, record_n, NULL, -1);
}
/* Fill in */
phone_attr_list = get_attributes_named (E_VCARD (editor->contact), "TEL");
for (record_n = 1, l = phone_attr_list;
l && record_n <= PHONE_SLOTS; l = g_list_next (l)) {
EVCardAttribute *attr = l->data;
gchar *phone;
gint slot;
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++;
g_free (phone);
}
}
static void
extract_phone (EContactEditor *editor)
{
GList *attr_list = NULL;
GList *old_attr_list;
GList *l, *l_next;
gint i;
for (i = 1; i <= PHONE_SLOTS; i++) {
gchar *phone;
gint phone_type;
extract_phone_record (editor, i, &phone, &phone_type);
if (!STRING_IS_EMPTY (phone)) {
EVCardAttribute *attr;
attr = e_vcard_attribute_new ("", "TEL");
if (phone_type >= 0) {
const gchar *type_1;
const gchar *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_2);
}
e_vcard_attribute_add_value (attr, phone);
set_ui_slot (attr, i);
attr_list = g_list_append (attr_list, attr);
}
g_free (phone);
}
/* Splice in the old attributes, minus the PHONE_SLOTS first */
old_attr_list = get_attributes_named (E_VCARD (editor->contact), "TEL");
for (l = old_attr_list, i = 1; l && i <= PHONE_SLOTS; l = l_next, i++) {
l_next = g_list_next (l);
e_vcard_attribute_free (l->data);
l = g_list_delete_link (l, l);
}
old_attr_list = l;
attr_list = g_list_concat (attr_list, old_attr_list);
set_attributes_named (E_VCARD (editor->contact), "TEL", attr_list);
free_attr_list (attr_list);
}
static void
init_phone_record_type (EContactEditor *editor,
gint record)
{
GtkWidget *phone_type_combo_box;
GtkWidget *phone_entry;
gchar *widget_name;
gint i;
GtkListStore *store;
widget_name = g_strdup_printf ("entry-phone-%d", record);
phone_entry = e_builder_get_widget (editor->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->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)));
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);
}
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);
}
static void
init_phone (EContactEditor *editor)
{
gint i;
expand_phone (editor, FALSE);
for (i = 1; i <= PHONE_SLOTS; i++)
init_phone_record_type (editor, i);
}
static void
sensitize_phone_types (EContactEditor *editor,
GtkWidget *combo_box)
{
GtkTreeModel *model;
GtkTreeIter iter;
gint i;
gboolean valid;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
valid = gtk_tree_model_get_iter_first (model, &iter);
for (i = 0; i < G_N_ELEMENTS (phones); i++) {
if (!valid) {
g_warning (G_STRLOC ": Unexpected end of phone items in combo box");
return;
}
gtk_list_store_set (
GTK_LIST_STORE (model), &iter,
1, 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->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf ("entry-phone-%d", record);
phone_entry = e_builder_get_widget (editor->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;
for (i = 1; i <= PHONE_SLOTS; i++) {
gboolean enabled = TRUE;
if (!editor->target_editable)
enabled = FALSE;
sensitize_phone_record (editor, i, enabled);
}
}
static void
init_im_record_location (EContactEditor *editor,
gint record)
{
#ifdef ENABLE_IM_LOCATION
GtkWidget *location_combo_box;
GtkListStore *store;
gint i;
gchar *widget_name;
widget_name = g_strdup_printf ("combobox-im-location-%d", record);
location_combo_box = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
init_item_sensitiveable_combo_box (GTK_COMBO_BOX (location_combo_box));
store = GTK_LIST_STORE (
gtk_combo_box_get_model (
GTK_COMBO_BOX (location_combo_box)));
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, TRUE,
-1);
}
g_signal_connect (
location_combo_box, "changed",
G_CALLBACK (object_changed), editor);
#endif
}
static void
init_im_record_service (EContactEditor *editor,
gint record)
{
GtkWidget *service_combo_box;
GtkListStore *store;
GtkWidget *name_entry;
gchar *widget_name;
gint i;
widget_name = g_strdup_printf ("entry-im-name-%d", record);
name_entry = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf ("combobox-im-service-%d", record);
service_combo_box = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
if (editor->compress_ui && record > 2) {
gtk_widget_hide (name_entry);
gtk_widget_hide (service_combo_box);
}
init_item_sensitiveable_combo_box (GTK_COMBO_BOX (service_combo_box));
store = GTK_LIST_STORE (
gtk_combo_box_get_model (
GTK_COMBO_BOX (service_combo_box)));
for (i = 0; i < G_N_ELEMENTS (im_service); i++) {
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
gtk_list_store_set (
store, &iter,
0, im_service[i].pretty_name,
1, TRUE,
-1);
}
g_signal_connect_swapped (
service_combo_box, "changed",
G_CALLBACK (gtk_widget_grab_focus), name_entry);
g_signal_connect (
service_combo_box, "changed",
G_CALLBACK (object_changed), editor);
g_signal_connect (
name_entry, "changed",
G_CALLBACK (object_changed), editor);
g_signal_connect_swapped (
name_entry, "activate",
G_CALLBACK (entry_activated), editor);
}
static void
init_im (EContactEditor *editor)
{
gint i;
for (i = 1; i <= IM_SLOTS; i++) {
init_im_record_service (editor, i);
init_im_record_location (editor, i);
}
}
static void
fill_in_im_record (EContactEditor *editor,
gint record,
gint service,
const gchar *name,
gint location)
{
GtkWidget *service_combo_box;
#ifdef ENABLE_IM_LOCATION
GtkWidget *location_combo_box;
#endif
GtkWidget *name_entry;
gchar *widget_name;
widget_name = g_strdup_printf ("combobox-im-service-%d", record);
service_combo_box = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
#ifdef ENABLE_IM_LOCATION
widget_name = g_strdup_printf ("combobox-im-location-%d", record);
location_combo_box = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
#endif
widget_name = g_strdup_printf ("entry-im-name-%d", record);
name_entry = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
#ifdef ENABLE_IM_LOCATION
set_combo_box_active (
editor, GTK_COMBO_BOX (location_combo_box),
location >= 0 ? location : 0);
#endif
set_combo_box_active (
editor, GTK_COMBO_BOX (service_combo_box),
service >= 0 ? service : im_service_default[record - 1]);
set_entry_text (editor, GTK_ENTRY (name_entry), name ? name : "");
}
static void
fill_in_im (EContactEditor *editor)
{
GList *im_attr_list;
GList *l;
gint record_n;
gint i;
/* Clear */
for (record_n = 1; record_n <= IM_SLOTS; record_n++) {
fill_in_im_record (editor, record_n, -1, NULL, -1);
}
/* Fill in */
for (record_n = 1, i = 0; i < G_N_ELEMENTS (im_service); i++) {
im_attr_list = e_contact_get_attributes (editor->contact, im_service[i].field);
for (l = im_attr_list; l && record_n <= IM_SLOTS; l = g_list_next (l)) {
EVCardAttribute *attr = l->data;
gchar *im_name;
gint slot;
im_name = e_vcard_attribute_get_value (attr);
slot = alloc_ui_slot (
editor, "entry-im-name",
get_ui_slot (attr), IM_SLOTS);
if (slot < 1)
break;
fill_in_im_record (
editor, slot, i, im_name,
get_im_location (attr));
record_n++;
g_free (im_name);
}
g_list_free_full (im_attr_list, (GDestroyNotify) e_vcard_attribute_free);
}
}
static void
extract_im_record (EContactEditor *editor,
gint record,
gint *service,
gchar **name,
gint *location)
{
GtkWidget *service_combo_box;
#ifdef ENABLE_IM_LOCATION
GtkWidget *location_combo_box;
#endif
GtkWidget *name_entry;
gchar *widget_name;
widget_name = g_strdup_printf ("combobox-im-service-%d", record);
service_combo_box = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
#ifdef ENABLE_IM_LOCATION
widget_name = g_strdup_printf ("combobox-im-location-%d", record);
location_combo_box = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
#endif
widget_name = g_strdup_printf ("entry-im-name-%d", record);
name_entry = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
*name = g_strdup (gtk_entry_get_text (GTK_ENTRY (name_entry)));
*service = gtk_combo_box_get_active (GTK_COMBO_BOX (service_combo_box));
#ifdef ENABLE_IM_LOCATION
*location = gtk_combo_box_get_active (GTK_COMBO_BOX (location_combo_box));
#else
*location = 1; /* set everything to HOME */
#endif
}
static void
extract_im (EContactEditor *editor)
{
GList **service_attr_list;
gint remaining_slots = IM_SLOTS;
gint i;
service_attr_list = g_new0 (GList *, G_N_ELEMENTS (im_service));
for (i = 1; i <= IM_SLOTS; i++) {
EVCardAttribute *attr;
gchar *name;
gint service;
gint location;
extract_im_record (editor, i, &service, &name, &location);
if (!STRING_IS_EMPTY (name)) {
attr = e_vcard_attribute_new (
"", e_contact_vcard_attribute (
im_service[service].field));
if (location >= 0)
e_vcard_attribute_add_param_with_value (
attr,
e_vcard_attribute_param_new (EVC_TYPE),
im_index_to_location (location));
e_vcard_attribute_add_value (attr, name);
set_ui_slot (attr, i);
service_attr_list[service] = g_list_append (
service_attr_list[service], attr);
}
g_free (name);
}
for (i = 0; i < G_N_ELEMENTS (im_service); i++) {
GList *old_service_attr_list;
gint filled_in_slots;
GList *l, *l_next;
gint j;
/* Splice in the old attributes, minus the filled_in_slots first */
old_service_attr_list = e_contact_get_attributes (
editor->contact, im_service[i].field);
filled_in_slots =
MIN (remaining_slots,
g_list_length (old_service_attr_list));
remaining_slots -= filled_in_slots;
for (l = old_service_attr_list, j = 0;
l && j < filled_in_slots; l = l_next, j++) {
l_next = g_list_next (l);
e_vcard_attribute_free (l->data);
l = g_list_delete_link (l, l);
}
old_service_attr_list = l;
service_attr_list[i] = g_list_concat (
service_attr_list[i], old_service_attr_list);
e_contact_set_attributes (
editor->contact,
im_service[i].field,
service_attr_list[i]);
free_attr_list (service_attr_list[i]);
}
g_free (service_attr_list);
}
static void
sensitize_im_types (EContactEditor *editor,
GtkWidget *combo_box)
{
GtkTreeModel *model;
GtkTreeIter iter;
gint i;
gboolean valid;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
valid = gtk_tree_model_get_iter_first (model, &iter);
for (i = 0; i < G_N_ELEMENTS (im_service); i++) {
if (!valid) {
g_warning (G_STRLOC ": Unexpected end of im items in combo box");
return;
}
gtk_list_store_set (
GTK_LIST_STORE (model), &iter,
1, is_field_supported (editor, im_service[i].field),
-1);
valid = gtk_tree_model_iter_next (model, &iter);
}
}
static void
sensitize_im_record (EContactEditor *editor,
gint record,
gboolean enabled)
{
GtkWidget *service_combo_box;
#ifdef ENABLE_IM_LOCATION
GtkWidget *location_combo_box;
#endif
GtkWidget *name_entry;
gchar *widget_name;
widget_name = g_strdup_printf ("combobox-im-service-%d", record);
service_combo_box = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
#ifdef ENABLE_IM_LOCATION
widget_name = g_strdup_printf ("combobox-im-location-%d", record);
location_combo_box = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
#endif
widget_name = g_strdup_printf ("entry-im-name-%d", record);
name_entry = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
gtk_widget_set_sensitive (service_combo_box, enabled);
#ifdef ENABLE_IM_LOCATION
gtk_widget_set_sensitive (location_combo_box, enabled);
#endif
gtk_editable_set_editable (GTK_EDITABLE (name_entry), enabled);
sensitize_im_types (editor, service_combo_box);
}
static void
sensitize_im (EContactEditor *editor)
{
gint i;
gboolean enabled;
gboolean no_ims_supported;
enabled = editor->target_editable;
no_ims_supported = TRUE;
for (i = 0; i < G_N_ELEMENTS (im_service); i++)
if (is_field_supported (editor, im_service[i].field)) {
no_ims_supported = FALSE;
break;
}
if (no_ims_supported)
enabled = FALSE;
for (i = 1; i <= IM_SLOTS; i++) {
sensitize_im_record (editor, i, enabled);
}
}
static void
init_personal (EContactEditor *editor)
{
gtk_expander_set_expanded (
GTK_EXPANDER (e_builder_get_widget (
editor->builder, "expander-personal-misc")),
!editor->compress_ui);
expand_web (editor, !editor->compress_ui);
}
static void
init_address_textview (EContactEditor *editor,
gint record)
{
gchar *textview_name;
GtkWidget *textview;
GtkTextBuffer *text_buffer;
textview_name = g_strdup_printf (
"textview-%s-address", address_name [record]);
textview = e_builder_get_widget (editor->builder, textview_name);
g_free (textview_name);
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
g_signal_connect (
text_buffer, "changed",
G_CALLBACK (object_changed), editor);
}
static void
init_address_field (EContactEditor *editor,
gint record,
const gchar *widget_field_name)
{
gchar *entry_name;
GtkWidget *entry;
entry_name = g_strdup_printf (
"entry-%s-%s", address_name [record], widget_field_name);
entry = e_builder_get_widget (editor->builder, entry_name);
g_free (entry_name);
g_signal_connect (
entry, "changed",
G_CALLBACK (object_changed), editor);
g_signal_connect_swapped (
entry, "activate",
G_CALLBACK (entry_activated), editor);
}
static void
init_address_record (EContactEditor *editor,
gint record)
{
init_address_textview (editor, record);
init_address_field (editor, record, "city");
init_address_field (editor, record, "state");
init_address_field (editor, record, "zip");
init_address_field (editor, record, "country");
init_address_field (editor, record, "pobox");
}
static void
init_address (EContactEditor *editor)
{
gint i;
for (i = 0; i < ADDRESS_SLOTS; i++)
init_address_record (editor, i);
gtk_expander_set_expanded (
GTK_EXPANDER (e_builder_get_widget (
editor->builder, "expander-address-other")),
!editor->compress_ui);
}
static void
fill_in_address_textview (EContactEditor *editor,
gint record,
EContactAddress *address)
{
gchar *textview_name;
GtkWidget *textview;
GtkTextBuffer *text_buffer;
GtkTextIter iter_end, iter_start;
textview_name = g_strdup_printf ("textview-%s-address", address_name [record]);
textview = e_builder_get_widget (editor->builder, textview_name);
g_free (textview_name);
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
gtk_text_buffer_set_text (text_buffer, address->street ? address->street : "", -1);
gtk_text_buffer_get_end_iter (text_buffer, &iter_end);
if (address->ext && *address->ext) {
gtk_text_buffer_insert (text_buffer, &iter_end, "\n", -1);
gtk_text_buffer_insert (text_buffer, &iter_end, address->ext, -1);
} else {
gtk_text_buffer_insert (text_buffer, &iter_end, "", -1);
}
gtk_text_buffer_get_iter_at_line (text_buffer, &iter_start, 0);
gtk_text_buffer_place_cursor (text_buffer, &iter_start);
}
static void
fill_in_address_label_textview (EContactEditor *editor,
gint record,
const gchar *label)
{
gchar *textview_name;
GtkWidget *textview;
GtkTextBuffer *text_buffer;
textview_name = g_strdup_printf (
"textview-%s-address", address_name [record]);
textview = e_builder_get_widget (editor->builder, textview_name);
g_free (textview_name);
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
gtk_text_buffer_set_text (text_buffer, label ? label : "", -1);
}
static void
fill_in_address_field (EContactEditor *editor,
gint record,
const gchar *widget_field_name,
const gchar *string)
{
gchar *entry_name;
GtkWidget *entry;
entry_name = g_strdup_printf (
"entry-%s-%s", address_name [record], widget_field_name);
entry = e_builder_get_widget (editor->builder, entry_name);
g_free (entry_name);
set_entry_text (editor, GTK_ENTRY (entry), string);
}
static void
fill_in_address_record (EContactEditor *editor,
gint record)
{
EContactAddress *address;
gchar *address_label;
address = e_contact_get (editor->contact, addresses[record]);
address_label = e_contact_get (editor->contact, address_labels[record]);
if (address &&
(!STRING_IS_EMPTY (address->street) ||
!STRING_IS_EMPTY (address->ext) ||
!STRING_IS_EMPTY (address->locality) ||
!STRING_IS_EMPTY (address->region) ||
!STRING_IS_EMPTY (address->code) ||
!STRING_IS_EMPTY (address->po) ||
!STRING_IS_EMPTY (address->country))) {
fill_in_address_textview (editor, record, address);
fill_in_address_field (editor, record, "city", address->locality);
fill_in_address_field (editor, record, "state", address->region);
fill_in_address_field (editor, record, "zip", address->code);
fill_in_address_field (editor, record, "country", address->country);
fill_in_address_field (editor, record, "pobox", address->po);
} else if (!STRING_IS_EMPTY (address_label)) {
fill_in_address_label_textview (editor, record, address_label);
}
g_free (address_label);
if (address)
g_boxed_free (e_contact_address_get_type (), address);
}
static void
fill_in_address (EContactEditor *editor)
{
gint i;
for (i = 0; i < ADDRESS_SLOTS; i++)
fill_in_address_record (editor, i);
}
static void
extract_address_textview (EContactEditor *editor,
gint record,
EContactAddress *address)
{
gchar *textview_name;
GtkWidget *textview;
GtkTextBuffer *text_buffer;
GtkTextIter iter_1, iter_2;
textview_name = g_strdup_printf ("textview-%s-address", address_name [record]);
textview = e_builder_get_widget (editor->builder, textview_name);
g_free (textview_name);
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
gtk_text_buffer_get_start_iter (text_buffer, &iter_1);
/* Skip blank lines */
while (gtk_text_iter_get_chars_in_line (&iter_1) < 1 &&
!gtk_text_iter_is_end (&iter_1))
gtk_text_iter_forward_line (&iter_1);
if (gtk_text_iter_is_end (&iter_1))
return;
iter_2 = iter_1;
gtk_text_iter_forward_to_line_end (&iter_2);
/* Extract street (first line of text) */
address->street = gtk_text_iter_get_text (&iter_1, &iter_2);
iter_1 = iter_2;
gtk_text_iter_forward_line (&iter_1);
if (gtk_text_iter_is_end (&iter_1))
return;
gtk_text_iter_forward_to_end (&iter_2);
/* Extract extended address (remaining lines of text) */
address->ext = gtk_text_iter_get_text (&iter_1, &iter_2);
}
static gchar *
extract_address_field (EContactEditor *editor,
gint record,
const gchar *widget_field_name)
{
gchar *entry_name;
GtkWidget *entry;
entry_name = g_strdup_printf (
"entry-%s-%s", address_name [record], widget_field_name);
entry = e_builder_get_widget (editor->builder, entry_name);
g_free (entry_name);
return g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
}
static gchar *
append_to_address_label (gchar *address_label,
const gchar *part,
gboolean newline)
{
gchar *new_address_label;
if (STRING_IS_EMPTY (part))
return address_label;
if (address_label)
new_address_label = g_strjoin (
newline ? "\n" : ", ",
address_label, part, NULL);
else
new_address_label = g_strdup (part);
g_free (address_label);
return new_address_label;
}
static void
set_address_label (EContact *contact,
EContactField field,
EContactAddress *address)
{
gchar *address_label = NULL;
gboolean format_address;
GSettings *settings;
if (!address) {
e_contact_set (contact, field, NULL);
return;
}
settings = g_settings_new ("org.gnome.evolution.addressbook");
format_address = g_settings_get_boolean (settings, "address-formatting");
g_object_unref (settings);
if (format_address) {
address_label = eab_format_address (contact,
(field == E_CONTACT_ADDRESS_LABEL_WORK) ? E_CONTACT_ADDRESS_WORK :
E_CONTACT_ADDRESS_HOME);
}
if (!format_address || !address_label) {
address_label = append_to_address_label (
address_label, address->street, TRUE);
address_label = append_to_address_label (
address_label, address->ext, TRUE);
address_label = append_to_address_label (
address_label, address->locality, TRUE);
address_label = append_to_address_label (
address_label, address->region, FALSE);
address_label = append_to_address_label (
address_label, address->code, TRUE);
address_label = append_to_address_label (
address_label, address->po, TRUE);
address_label = append_to_address_label (
address_label, address->country, TRUE);
}
e_contact_set (contact, field, address_label);
g_free (address_label);
}
static void
extract_address_record (EContactEditor *editor,
gint record)
{
EContactAddress *address;
address = g_new0 (EContactAddress, 1);
extract_address_textview (editor, record, address);
address->locality = extract_address_field (editor, record, "city");
address->region = extract_address_field (editor, record, "state");
address->code = extract_address_field (editor, record, "zip");
address->country = extract_address_field (editor, record, "country");
address->po = extract_address_field (editor, record, "pobox");
if (!STRING_IS_EMPTY (address->street) ||
!STRING_IS_EMPTY (address->ext) ||
!STRING_IS_EMPTY (address->locality) ||
!STRING_IS_EMPTY (address->region) ||
!STRING_IS_EMPTY (address->code) ||
!STRING_IS_EMPTY (address->po) ||
!STRING_IS_EMPTY (address->country)) {
e_contact_set (editor->contact, addresses[record], address);
set_address_label (editor->contact, address_labels[record], address);
}
else {
e_contact_set (editor->contact, addresses[record], NULL);
set_address_label (editor->contact, address_labels[record], NULL);
}
g_boxed_free (e_contact_address_get_type (), address);
}
static void
extract_address (EContactEditor *editor)
{
gint i;
for (i = 0; i < ADDRESS_SLOTS; i++)
extract_address_record (editor, i);
}
static void
sensitize_address_textview (EContactEditor *editor,
gint record,
gboolean enabled)
{
gchar *widget_name;
GtkWidget *textview;
GtkWidget *label;
widget_name = g_strdup_printf ("textview-%s-address", address_name [record]);
textview = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf ("label-%s-address", address_name [record]);
label = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), enabled);
gtk_widget_set_sensitive (label, enabled);
}
static void
sensitize_address_field (EContactEditor *editor,
gint record,
const gchar *widget_field_name,
gboolean enabled)
{
gchar *widget_name;
GtkWidget *entry;
GtkWidget *label;
widget_name = g_strdup_printf (
"entry-%s-%s", address_name [record], widget_field_name);
entry = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
widget_name = g_strdup_printf (
"label-%s-%s", address_name [record], widget_field_name);
label = e_builder_get_widget (editor->builder, widget_name);
g_free (widget_name);
gtk_editable_set_editable (GTK_EDITABLE (entry), enabled);
gtk_widget_set_sensitive (label, enabled);
}
static void
sensitize_address_record (EContactEditor *editor,
gint record,
gboolean enabled)
{
sensitize_address_textview (editor, record, enabled);
sensitize_address_field (editor, record, "city", enabled);
sensitize_address_field (editor, record, "state", enabled);
sensitize_address_field (editor, record, "zip", enabled);
sensitize_address_field (editor, record, "country", enabled);
sensitize_address_field (editor, record, "pobox", enabled);
}
static void
sensitize_address (EContactEditor *editor)
{
gint i;
for (i = 0; i < ADDRESS_SLOTS; i++) {
gboolean enabled = TRUE;
if (!editor->target_editable ||
!(is_field_supported (editor, addresses[i]) ||
is_field_supported (editor, address_labels[i])))
enabled = FALSE;
sensitize_address_record (editor, i, enabled);
}
}
typedef struct {
const gchar *widget_name;
gint field_id; /* EContactField or -1 */
gboolean process_data; /* If we should extract/fill in contents */
gboolean desensitize_for_read_only;
}
FieldMapping;
/* Table of widgets that interact with simple fields. This table is used to:
*
* - Fill in data.
* - Extract data.
* - Set sensitivity based on backend capabilities.
* - Set sensitivity based on book writeability. */
static FieldMapping simple_field_map[] = {
{ "entry-homepage", E_CONTACT_HOMEPAGE_URL, TRUE, TRUE },
{ "accellabel-homepage", E_CONTACT_HOMEPAGE_URL, FALSE, TRUE },
{ "entry-jobtitle", E_CONTACT_TITLE, TRUE, TRUE },
{ "label-jobtitle", E_CONTACT_TITLE, FALSE, TRUE },
{ "entry-company", E_CONTACT_ORG, TRUE, TRUE },
{ "label-company", E_CONTACT_ORG, FALSE, TRUE },
{ "entry-department", E_CONTACT_ORG_UNIT, TRUE, TRUE },
{ "label-department", E_CONTACT_ORG_UNIT, FALSE, TRUE },
{ "entry-profession", E_CONTACT_ROLE, TRUE, TRUE },
{ "label-profession", E_CONTACT_ROLE, FALSE, TRUE },
{ "entry-manager", E_CONTACT_MANAGER, TRUE, TRUE },
{ "label-manager", E_CONTACT_MANAGER, FALSE, TRUE },
{ "entry-assistant", E_CONTACT_ASSISTANT, TRUE, TRUE },
{ "label-assistant", E_CONTACT_ASSISTANT, FALSE, TRUE },
{ "entry-nickname", E_CONTACT_NICKNAME, TRUE, TRUE },
{ "label-nickname", E_CONTACT_NICKNAME, FALSE, TRUE },
{ "dateedit-birthday", E_CONTACT_BIRTH_DATE, TRUE, TRUE },
{ "label-birthday", E_CONTACT_BIRTH_DATE, FALSE, TRUE },
{ "dateedit-anniversary", E_CONTACT_ANNIVERSARY, TRUE, TRUE },
{ "label-anniversary", E_CONTACT_ANNIVERSARY, FALSE, TRUE },
{ "entry-spouse", E_CONTACT_SPOUSE, TRUE, TRUE },
{ "label-spouse", E_CONTACT_SPOUSE, FALSE, TRUE },
{ "entry-office", E_CONTACT_OFFICE, TRUE, TRUE },
{ "label-office", E_CONTACT_OFFICE, FALSE, TRUE },
{ "text-comments", E_CONTACT_NOTE, TRUE, TRUE },
{ "entry-fullname", E_CONTACT_FULL_NAME, TRUE, TRUE },
{ "button-fullname", E_CONTACT_FULL_NAME, FALSE, TRUE },
{ "entry-categories", E_CONTACT_CATEGORIES, TRUE, TRUE },
{ "button-categories", E_CONTACT_CATEGORIES, FALSE, TRUE },
{ "entry-weblog", E_CONTACT_BLOG_URL, TRUE, TRUE },
{ "label-weblog", E_CONTACT_BLOG_URL, FALSE, TRUE },
{ "entry-caluri", E_CONTACT_CALENDAR_URI, TRUE, TRUE },
{ "label-caluri", E_CONTACT_CALENDAR_URI, FALSE, TRUE },
{ "entry-fburl", E_CONTACT_FREEBUSY_URL, TRUE, TRUE },
{ "label-fburl", E_CONTACT_FREEBUSY_URL, FALSE, TRUE },
{ "entry-videourl", E_CONTACT_VIDEO_URL, TRUE, TRUE },
{ "label-videourl", E_CONTACT_VIDEO_URL, FALSE, TRUE },
{ "checkbutton-htmlmail", E_CONTACT_WANTS_HTML, TRUE, TRUE },
{ "image-chooser", E_CONTACT_PHOTO, TRUE, TRUE },
{ "button-image", E_CONTACT_PHOTO, FALSE, TRUE },
{ "combo-file-as", E_CONTACT_FILE_AS, TRUE, TRUE },
{ "accellabel-fileas", E_CONTACT_FILE_AS, FALSE, TRUE },
};
static void
init_simple_field (EContactEditor *editor,
GtkWidget *widget)
{
GObject *changed_object = NULL;
if (GTK_IS_ENTRY (widget)) {
changed_object = G_OBJECT (widget);
g_signal_connect_swapped (
widget, "activate",
G_CALLBACK (entry_activated), editor);
} else if (GTK_IS_COMBO_BOX (widget)) {
changed_object = G_OBJECT (widget);
g_signal_connect_swapped (
gtk_bin_get_child (GTK_BIN (widget)), "activate",
G_CALLBACK (entry_activated), editor);
} else if (GTK_IS_TEXT_VIEW (widget)) {
changed_object = G_OBJECT (
gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget)));
} else if (E_IS_URL_ENTRY (widget)) {
changed_object = G_OBJECT (
e_url_entry_get_entry (E_URL_ENTRY (widget)));
g_signal_connect_swapped (
changed_object, "activate",
G_CALLBACK (entry_activated), editor);
} else if (E_IS_DATE_EDIT (widget)) {
changed_object = G_OBJECT (widget);
} else if (E_IS_IMAGE_CHOOSER (widget)) {
changed_object = G_OBJECT (widget);
g_signal_connect (
widget, "changed",
G_CALLBACK (image_chooser_changed), editor);
} else if (GTK_IS_TOGGLE_BUTTON (widget)) {
g_signal_connect (
widget, "toggled",
G_CALLBACK (object_changed), editor);
}
if (changed_object)
g_signal_connect (
changed_object, "changed",
G_CALLBACK (object_changed), editor);
}
static void
fill_in_simple_field (EContactEditor *editor,
GtkWidget *widget,
gint field_id)
{
EContact *contact;
contact = editor->contact;
g_signal_handlers_block_matched (
widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
if (GTK_IS_ENTRY (widget)) {
gchar *text = e_contact_get (contact, field_id);
gtk_entry_set_text (GTK_ENTRY (widget), STRING_MAKE_NON_NULL (text));
g_free (text);
} else if (GTK_IS_COMBO_BOX (widget)) {
gchar *text = e_contact_get (contact, field_id);
gtk_entry_set_text (
GTK_ENTRY (gtk_bin_get_child (GTK_BIN (widget))),
STRING_MAKE_NON_NULL (text));
g_free (text);
} else if (GTK_IS_TEXT_VIEW (widget)) {
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
gchar *text = e_contact_get (contact, field_id);
gtk_text_buffer_set_text (buffer, STRING_MAKE_NON_NULL (text), -1);
g_free (text);
} else if (E_IS_URL_ENTRY (widget)) {
GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget));
gchar *text = e_contact_get (contact, field_id);
gtk_entry_set_text (GTK_ENTRY (entry), STRING_MAKE_NON_NULL (text));
g_free (text);
} else if (E_IS_DATE_EDIT (widget)) {
EContactDate *date = e_contact_get (contact, field_id);
if (date)
e_date_edit_set_date (
E_DATE_EDIT (widget),
date->year, date->month, date->day);
else
e_date_edit_set_time (E_DATE_EDIT (widget), -1);
e_contact_date_free (date);
} else if (E_IS_IMAGE_CHOOSER (widget)) {
EContactPhoto *photo = e_contact_get (contact, field_id);
if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
e_image_chooser_set_image_data (
E_IMAGE_CHOOSER (widget),
(gchar *) photo->data.inlined.data,
photo->data.inlined.length);
editor->image_set = TRUE;
}
else {
gchar *file_name;
file_name = e_icon_factory_get_icon_filename (
"avatar-default", GTK_ICON_SIZE_DIALOG);
e_image_chooser_set_from_file (
E_IMAGE_CHOOSER (widget), file_name);
editor->image_set = FALSE;
g_free (file_name);
}
editor->image_changed = FALSE;
e_contact_photo_free (photo);
} else if (GTK_IS_TOGGLE_BUTTON (widget)) {
gboolean val = e_contact_get (contact, field_id) != NULL;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), val);
} else {
g_warning (G_STRLOC ": Unhandled widget class in mappings!");
}
g_signal_handlers_unblock_matched (
widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
}
static void
extract_simple_field (EContactEditor *editor,
GtkWidget *widget,
gint field_id)
{
EContact *contact;
contact = editor->contact;
if (GTK_IS_ENTRY (widget)) {
const gchar *text = gtk_entry_get_text (GTK_ENTRY (widget));
e_contact_set (contact, field_id, (gchar *) text);
} else if (GTK_IS_COMBO_BOX_TEXT (widget)) {
gchar *text = NULL;
if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) {
GtkWidget *entry = gtk_bin_get_child (GTK_BIN (widget));
text = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
}
if (!text)
text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widget));
e_contact_set (contact, field_id, text);
g_free (text);
} else if (GTK_IS_COMBO_BOX (widget)) {
GtkTreeIter iter;
gchar *text = NULL;
if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) {
GtkWidget *entry = gtk_bin_get_child (GTK_BIN (widget));
text = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
}
if (!text && gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
GtkListStore *store;
store = GTK_LIST_STORE (
gtk_combo_box_get_model (
GTK_COMBO_BOX (widget)));
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
0, &text,
-1);
}
e_contact_set (contact, field_id, text);
g_free (text);
} else if (GTK_IS_TEXT_VIEW (widget)) {
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
GtkTextIter start, end;
gchar *text;
gtk_text_buffer_get_start_iter (buffer, &start);
gtk_text_buffer_get_end_iter (buffer, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
e_contact_set (contact, field_id, text);
g_free (text);
} else if (E_IS_URL_ENTRY (widget)) {
GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget));
const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
e_contact_set (contact, field_id, (gchar *) text);
} else if (E_IS_DATE_EDIT (widget)) {
EContactDate date;
if (e_date_edit_get_date (
E_DATE_EDIT (widget),
(gint *) &date.year,
(gint *) &date.month,
(gint *) &date.day))
e_contact_set (contact, field_id, &date);
else
e_contact_set (contact, field_id, NULL);
} else if (E_IS_IMAGE_CHOOSER (widget)) {
EContactPhoto photo;
photo.type = E_CONTACT_PHOTO_TYPE_INLINED;
photo.data.inlined.mime_type = NULL;
if (editor->image_changed) {
gchar *img_buff = NULL;
if (editor->image_set &&
e_image_chooser_get_image_data (
E_IMAGE_CHOOSER (widget),
&img_buff, &photo.data.inlined.length)) {
GdkPixbuf *pixbuf, *new;
GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
photo.data.inlined.data = (guchar *) img_buff;
img_buff = NULL;
gdk_pixbuf_loader_write (
loader,
photo.data.inlined.data,
photo.data.inlined.length, NULL);
gdk_pixbuf_loader_close (loader, NULL);
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
if (pixbuf) {
gint width, height, prompt_response;
g_object_ref (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
width = gdk_pixbuf_get_width (pixbuf);
if ((height > 96 || width > 96)) {
prompt_response =
e_alert_run_dialog_for_args
(GTK_WINDOW (editor->app),
"addressbook:prompt-resize",
NULL);
if (prompt_response == GTK_RESPONSE_YES) {
if ( width > height) {
height = height * 96 / width;
width = 96;
} else {
width = width *96 / height;
height = 96;
}
new = e_icon_factory_pixbuf_scale (pixbuf, width, height);
if (new) {
GdkPixbufFormat *format =
gdk_pixbuf_loader_get_format (loader);
gchar *format_name =
gdk_pixbuf_format_get_name (format);
g_free (photo.data.inlined.data);
gdk_pixbuf_save_to_buffer (
new, &img_buff,
&photo.data.inlined.length,
format_name, NULL, NULL);
photo.data.inlined.data = (guchar *) img_buff;
img_buff = NULL;
g_free (format_name);
g_object_unref (new);
}
} else if (prompt_response == GTK_RESPONSE_CANCEL) {
g_object_unref (pixbuf);
g_object_unref (loader);
return;
}
}
g_object_unref (pixbuf);
}
editor->image_changed = FALSE;
g_object_unref (loader);
e_contact_set (contact, field_id, &photo);
g_free (photo.data.inlined.data);
} else {
editor->image_changed = FALSE;
e_contact_set (contact, E_CONTACT_PHOTO, NULL);
}
}
} else if (GTK_IS_TOGGLE_BUTTON (widget)) {
gboolean val;
val = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
e_contact_set (contact, field_id, val ? (gpointer) 1 : NULL);
} else {
g_warning (G_STRLOC ": Unhandled widget class in mappings!");
}
}
static void
sensitize_simple_field (GtkWidget *widget,
gboolean enabled)
{
if (GTK_IS_ENTRY (widget))
gtk_editable_set_editable (GTK_EDITABLE (widget), enabled);
else if (GTK_IS_TEXT_VIEW (widget))
gtk_text_view_set_editable (GTK_TEXT_VIEW (widget), enabled);
else if (E_IS_URL_ENTRY (widget)) {
GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget));
gtk_editable_set_editable (GTK_EDITABLE (entry), enabled);
}
else if (E_IS_DATE_EDIT (widget))
e_date_edit_set_editable (E_DATE_EDIT (widget), enabled);
else
gtk_widget_set_sensitive (widget, enabled);
}
static void
init_simple (EContactEditor *editor)
{
GtkWidget *widget;
gint i;
for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) {
widget = e_builder_get_widget (
editor->builder, simple_field_map[i].widget_name);
if (!widget)
continue;
init_simple_field (editor, widget);
}
/* --- Special cases --- */
/* Update file_as */
widget = e_builder_get_widget (editor->builder, "entry-fullname");
g_signal_connect (
widget, "changed",
G_CALLBACK (name_entry_changed), editor);
widget = e_builder_get_widget (editor->builder, "combo-file-as");
gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (widget), 0);
g_signal_connect (
widget, "changed",
G_CALLBACK (file_as_combo_changed), editor);
widget = e_builder_get_widget (editor->builder, "entry-company");
g_signal_connect (
widget, "changed",
G_CALLBACK (company_entry_changed), editor);
}
static void
fill_in_simple (EContactEditor *editor)
{
EContactName *name;
gchar *filename;
gint i;
for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) {
GtkWidget *widget;
if (simple_field_map[i].field_id < 0 ||
!simple_field_map[i].process_data)
continue;
widget = e_builder_get_widget (
editor->builder, simple_field_map[i].widget_name);
if (!widget)
continue;
fill_in_simple_field (
editor, widget, simple_field_map[i].field_id);
}
/* --- Special cases --- */
/* Update broken-up name */
g_object_get (editor->contact, "name", &name, NULL);
if (editor->name)
e_contact_name_free (editor->name);
editor->name = name;
/* Update the contact editor title */
filename = (gchar *) e_contact_get (editor->contact, E_CONTACT_FILE_AS);
if (filename) {
gchar *title;
title = g_strdup_printf (_("Contact Editor - %s"), filename);
gtk_window_set_title (GTK_WINDOW (editor->app), title);
g_free (title);
g_free (filename);
} else
gtk_window_set_title (
GTK_WINDOW (editor->app), _("Contact Editor"));
/* Update file_as combo options */
update_file_as_combo (editor);
}
static void
extract_simple (EContactEditor *editor)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) {
GtkWidget *widget;
if (simple_field_map[i].field_id < 0 ||
!simple_field_map[i].process_data)
continue;
widget = e_builder_get_widget (
editor->builder, simple_field_map[i].widget_name);
if (!widget)
continue;
extract_simple_field (
editor, widget, simple_field_map[i].field_id);
}
/* Special cases */
e_contact_set (editor->contact, E_CONTACT_NAME, editor->name);
}
static void
sensitize_simple (EContactEditor *editor)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) {
GtkWidget *widget;
gboolean enabled = TRUE;
widget = e_builder_get_widget (
editor->builder, simple_field_map[i].widget_name);
if (!widget)
continue;
if (simple_field_map[i].field_id >= 0 &&
!is_field_supported (editor, simple_field_map[i].field_id))
enabled = FALSE;
if (simple_field_map[i].desensitize_for_read_only &&
!editor->target_editable)
enabled = FALSE;
sensitize_simple_field (widget, enabled);
}
}
static void
fill_in_all (EContactEditor *editor)
{
fill_in_source_field (editor);
fill_in_simple (editor);
fill_in_email (editor);
fill_in_phone (editor);
fill_in_im (editor);
fill_in_address (editor);
}
static void
extract_all (EContactEditor *editor)
{
extract_simple (editor);
extract_email (editor);
extract_phone (editor);
extract_im (editor);
extract_address (editor);
}
static void
sensitize_all (EContactEditor *editor)
{
sensitize_ok (editor);
sensitize_simple (editor);
sensitize_email (editor);
sensitize_phone (editor);
sensitize_im (editor);
sensitize_address (editor);
}
static void
init_all (EContactEditor *editor)
{
GtkRequisition tab_req;
GtkWidget *widget;
init_simple (editor);
init_email (editor);
init_phone (editor);
init_im (editor);
init_personal (editor);
init_address (editor);
/* with so many scrolled windows, we need to
* do some manual sizing */
widget = e_builder_get_widget (editor->builder, "vbox-size-leader");
gtk_widget_get_preferred_size (widget, &tab_req, NULL);
widget = e_builder_get_widget (
editor->builder, "scrolledwindow-size-leader"),
gtk_widget_set_size_request (
widget, tab_req.width, tab_req.height + 8);
}
static void
contact_editor_book_loaded_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
ESource *source = E_SOURCE (source_object);
EContactEditor *editor = user_data;
EClient *client = NULL;
GError *error = NULL;
e_client_utils_open_new_finish (source, result, &client, &error);
if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
g_warn_if_fail (client == NULL);
g_error_free (error);
goto exit;
} else if (error != NULL) {
GtkWidget *source_combo_box;
GtkWindow *parent;
g_warn_if_fail (client == NULL);
parent = eab_editor_get_window (EAB_EDITOR (editor));
eab_load_error_dialog (GTK_WIDGET (parent), NULL, source, error);
source_combo_box = e_builder_get_widget (
editor->builder, "source-combo-box-source");
e_source_combo_box_set_active (
E_SOURCE_COMBO_BOX (source_combo_box), source);
g_error_free (error);
goto exit;
}
g_return_if_fail (E_IS_CLIENT (client));
/* FIXME Write a private contact_editor_set_target_client(). */
g_object_set (editor, "target_client", client, NULL);
g_object_unref (client);
exit:
g_object_unref (editor);
}
static void
source_changed (ESourceComboBox *source_combo_box,
EContactEditor *editor)
{
ESource *target_source;
ESource *source_source;
ESource *source;
source = e_source_combo_box_ref_active (source_combo_box);
g_return_if_fail (source != NULL);
if (editor->cancellable != NULL) {
g_cancellable_cancel (editor->cancellable);
g_object_unref (editor->cancellable);
editor->cancellable = NULL;
}
target_source = e_client_get_source (E_CLIENT (editor->target_client));
source_source = e_client_get_source (E_CLIENT (editor->source_client));
if (e_source_equal (target_source, source))
goto exit;
if (e_source_equal (source_source, source)) {
g_object_set (
editor, "target_client",
editor->source_client, NULL);
goto exit;
}
editor->cancellable = g_cancellable_new ();
e_client_utils_open_new (
source, E_CLIENT_SOURCE_TYPE_CONTACTS,
FALSE, editor->cancellable,
contact_editor_book_loaded_cb, g_object_ref (editor));
exit:
g_object_unref (source);
}
static void
full_name_response (GtkDialog *dialog,
gint response,
EContactEditor *editor)
{
EContactName *name;
GtkWidget *fname_widget;
gint style = 0;
gboolean editable = FALSE;
g_object_get (dialog, "editable", &editable, NULL);
if (editable && response == GTK_RESPONSE_OK) {
g_object_get (dialog, "name", &name, NULL);
style = file_as_get_style (editor);
fname_widget = e_builder_get_widget (
editor->builder, "entry-fullname");
if (GTK_IS_ENTRY (fname_widget)) {
GtkEntry *entry;
gchar *full_name = e_contact_name_to_string (name);
const gchar *old_full_name;
entry = GTK_ENTRY (fname_widget);
old_full_name = gtk_entry_get_text (entry);
if (strcmp (full_name, old_full_name))
gtk_entry_set_text (entry, full_name);
g_free (full_name);
}
e_contact_name_free (editor->name);
editor->name = name;
file_as_set_style (editor, style);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
editor->fullname_dialog = NULL;
}
static gint
full_name_editor_delete_event_cb (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
if (GTK_IS_WIDGET (widget))
gtk_widget_destroy (widget);
return TRUE;
}
static void
full_name_clicked (GtkWidget *button,
EContactEditor *editor)
{
GtkDialog *dialog;
gboolean fullname_supported;
if (editor->fullname_dialog) {
gtk_window_present (GTK_WINDOW (editor->fullname_dialog));
return;
}
dialog = GTK_DIALOG (e_contact_editor_fullname_new (editor->name));
fullname_supported = is_field_supported (editor, E_CONTACT_FULL_NAME);
g_object_set (
dialog, "editable",
fullname_supported & editor->target_editable, NULL);
g_signal_connect (
dialog, "response",
G_CALLBACK (full_name_response), editor);
/* Close the fullname dialog if the editor is closed */
g_signal_connect_swapped (
editor, "editor_closed",
G_CALLBACK (full_name_editor_delete_event_cb), dialog);
gtk_widget_show (GTK_WIDGET (dialog));
editor->fullname_dialog = GTK_WIDGET (dialog);
}
static void
categories_response (GtkDialog *dialog,
gint response,
EContactEditor *editor)
{
gchar *categories;
GtkWidget *entry;
entry = e_builder_get_widget (editor->builder, "entry-categories");
if (response == GTK_RESPONSE_OK) {
categories = e_categories_dialog_get_categories (
E_CATEGORIES_DIALOG (dialog));
if (GTK_IS_ENTRY (entry))
gtk_entry_set_text (
GTK_ENTRY (entry), categories);
else
e_contact_set (
editor->contact,
E_CONTACT_CATEGORIES,
categories);
g_free (categories);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
editor->categories_dialog = NULL;
}
static gint
categories_editor_delete_event_cb (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
if (GTK_IS_WIDGET (widget))
gtk_widget_destroy (widget);
return TRUE;
}
static void
categories_clicked (GtkWidget *button,
EContactEditor *editor)
{
gchar *categories = NULL;
GtkDialog *dialog;
GtkWidget *entry = e_builder_get_widget(editor->builder, "entry-categories");
if (entry && GTK_IS_ENTRY (entry))
categories = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
else if (editor->contact)
categories = e_contact_get (editor->contact, E_CONTACT_CATEGORIES);
if (editor->categories_dialog != NULL) {
gtk_window_present (GTK_WINDOW (editor->categories_dialog));
g_free (categories);
return;
}else if (!(dialog = GTK_DIALOG (e_categories_dialog_new (categories)))) {
e_alert_run_dialog_for_args (
GTK_WINDOW (editor->app),
"addressbook:edit-categories", NULL);
g_free (categories);
return;
}
g_signal_connect (
dialog, "response",
G_CALLBACK (categories_response), editor);
/* Close the category dialog if the editor is closed*/
g_signal_connect_swapped (
editor, "editor_closed",
G_CALLBACK (categories_editor_delete_event_cb), dialog);
gtk_widget_show (GTK_WIDGET (dialog));
g_free (categories);
editor->categories_dialog = GTK_WIDGET (dialog);
}
static void
image_selected (EContactEditor *editor)
{
gchar *file_name;
GtkWidget *image_chooser;
file_name = gtk_file_chooser_get_filename (
GTK_FILE_CHOOSER (editor->file_selector));
if (!file_name)
return;
image_chooser = e_builder_get_widget (editor->builder, "image-chooser");
g_signal_handlers_block_by_func (
image_chooser, image_chooser_changed, editor);
e_image_chooser_set_from_file (
E_IMAGE_CHOOSER (image_chooser), file_name);
g_signal_handlers_unblock_by_func (
image_chooser, image_chooser_changed, editor);
editor->image_set = TRUE;
editor->image_changed = TRUE;
object_changed (G_OBJECT (image_chooser), editor);
}
static void
image_cleared (EContactEditor *editor)
{
GtkWidget *image_chooser;
gchar *file_name;
image_chooser = e_builder_get_widget (
editor->builder, "image-chooser");
file_name = e_icon_factory_get_icon_filename (
"avatar-default", GTK_ICON_SIZE_DIALOG);
g_signal_handlers_block_by_func (
image_chooser, image_chooser_changed, editor);
e_image_chooser_set_from_file (
E_IMAGE_CHOOSER (image_chooser), file_name);
g_signal_handlers_unblock_by_func (
image_chooser, image_chooser_changed, editor);
g_free (file_name);
editor->image_set = FALSE;
editor->image_changed = TRUE;
object_changed (G_OBJECT (image_chooser), editor);
}
static void
file_chooser_response (GtkWidget *widget,
gint response,
EContactEditor *editor)
{
if (response == GTK_RESPONSE_ACCEPT)
image_selected (editor);
else if (response == GTK_RESPONSE_NO)
image_cleared (editor);
gtk_widget_hide (editor->file_selector);
}
static gboolean
file_selector_deleted (GtkWidget *widget)
{
gtk_widget_hide (widget);
return TRUE;
}
static void
update_preview_cb (GtkFileChooser *file_chooser,
gpointer data)
{
GtkWidget *preview;
gchar *filename = NULL;
GdkPixbuf *pixbuf;
gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
preview = GTK_WIDGET (data);
filename = gtk_file_chooser_get_preview_filename (file_chooser);
if (filename == NULL)
return;
pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL);
if (!pixbuf) {
gchar *alternate_file;
alternate_file = e_icon_factory_get_icon_filename (
"avatar-default", GTK_ICON_SIZE_DIALOG);
if (alternate_file) {
pixbuf = gdk_pixbuf_new_from_file_at_size (
alternate_file, 128, 128, NULL);
g_free (alternate_file);
}
}
g_free (filename);
gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
if (pixbuf)
g_object_unref (pixbuf);
}
static void
image_clicked (GtkWidget *button,
EContactEditor *editor)
{
const gchar *title = _("Please select an image for this contact");
const gchar *no_image = _("_No image");
GtkImage *preview;
if (!editor->file_selector) {
editor->file_selector = gtk_file_chooser_dialog_new (
title, GTK_WINDOW (editor->app),
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
no_image, GTK_RESPONSE_NO,
NULL);
preview = GTK_IMAGE (gtk_image_new ());
gtk_file_chooser_set_preview_widget (
GTK_FILE_CHOOSER (editor->file_selector),
GTK_WIDGET (preview));
g_signal_connect (
editor->file_selector, "update-preview",
G_CALLBACK (update_preview_cb), preview);
gtk_dialog_set_default_response (
GTK_DIALOG (editor->file_selector),
GTK_RESPONSE_ACCEPT);
g_signal_connect (
editor->file_selector, "response",
G_CALLBACK (file_chooser_response), editor);
g_signal_connect_after (
editor->file_selector, "delete-event",
G_CALLBACK (file_selector_deleted),
editor->file_selector);
}
/* Display the dialog */
gtk_window_set_modal (GTK_WINDOW (editor->file_selector), TRUE);
gtk_window_present (GTK_WINDOW (editor->file_selector));
}
typedef struct {
EContactEditor *ce;
gboolean should_close;
gchar *new_id;
} EditorCloseStruct;
static void
contact_removed_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
EBookClient *book_client = E_BOOK_CLIENT (source_object);
EditorCloseStruct *ecs = user_data;
EContactEditor *ce = ecs->ce;
gboolean should_close = ecs->should_close;
GError *error = NULL;
e_book_client_remove_contact_finish (book_client, result, &error);
gtk_widget_set_sensitive (ce->app, TRUE);
ce->in_async_call = FALSE;
e_contact_set (ce->contact, E_CONTACT_UID, ecs->new_id);
eab_editor_contact_deleted (EAB_EDITOR (ce), error, ce->contact);
ce->is_new_contact = FALSE;
if (should_close) {
eab_editor_close (EAB_EDITOR (ce));
} else {
ce->changed = FALSE;
g_object_ref (ce->target_client);
g_object_unref (ce->source_client);
ce->source_client = ce->target_client;
sensitize_all (ce);
}
if (error)
g_error_free (error);
g_object_unref (ce);
g_free (ecs->new_id);
g_free (ecs);
}
static void
contact_added_cb (EBookClient *book_client,
const GError *error,
const gchar *id,
gpointer closure)
{
EditorCloseStruct *ecs = closure;
EContactEditor *ce = ecs->ce;
gboolean should_close = ecs->should_close;
if (ce->source_client != ce->target_client && !e_client_is_readonly (E_CLIENT (ce->source_client)) &&
!error && ce->is_new_contact == FALSE) {
ecs->new_id = g_strdup (id);
e_book_client_remove_contact (
ce->source_client, ce->contact, NULL, contact_removed_cb, ecs);
return;
}
gtk_widget_set_sensitive (ce->app, TRUE);
ce->in_async_call = FALSE;
e_contact_set (ce->contact, E_CONTACT_UID, id);
eab_editor_contact_added (EAB_EDITOR (ce), error, ce->contact);
if (!error) {
ce->is_new_contact = FALSE;
if (should_close) {
eab_editor_close (EAB_EDITOR (ce));
} else {
ce->changed = FALSE;
sensitize_all (ce);
}
}
g_object_unref (ce);
g_free (ecs);
}
static void
contact_modified_cb (EBookClient *book_client,
const GError *error,
gpointer closure)
{
EditorCloseStruct *ecs = closure;
EContactEditor *ce = ecs->ce;
gboolean should_close = ecs->should_close;
gtk_widget_set_sensitive (ce->app, TRUE);
ce->in_async_call = FALSE;
eab_editor_contact_modified (EAB_EDITOR (ce), error, ce->contact);
if (!error) {
if (should_close) {
eab_editor_close (EAB_EDITOR (ce));
}
else {
ce->changed = FALSE;
sensitize_all (ce);
}
}
g_object_unref (ce);
g_free (ecs);
}
static void
contact_modified_ready_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
EBookClient *book_client = E_BOOK_CLIENT (source_object);
GError *error = NULL;
e_book_client_modify_contact_finish (book_client, result, &error);
contact_modified_cb (book_client, error, user_data);
if (error)
g_error_free (error);
}
/* Emits the signal to request saving a contact */
static void
real_save_contact (EContactEditor *ce,
gboolean should_close)
{
EShell *shell;
EditorCloseStruct *ecs;
ESourceRegistry *registry;
shell = eab_editor_get_shell (EAB_EDITOR (ce));
registry = e_shell_get_registry (shell);
ecs = g_new0 (EditorCloseStruct, 1);
ecs->ce = ce;
g_object_ref (ecs->ce);
ecs->should_close = should_close;
gtk_widget_set_sensitive (ce->app, FALSE);
ce->in_async_call = TRUE;
if (ce->source_client != ce->target_client) {
/* Two-step move; add to target, then remove from source */
eab_merging_book_add_contact (
registry, ce->target_client,
ce->contact, contact_added_cb, ecs);
} else {
if (ce->is_new_contact)
eab_merging_book_add_contact (
registry, ce->target_client,
ce->contact, contact_added_cb, ecs);
else if (ce->check_merge)
eab_merging_book_modify_contact (
registry, ce->target_client,
ce->contact, contact_modified_cb, ecs);
else
e_book_client_modify_contact (
ce->target_client, ce->contact, NULL,
contact_modified_ready_cb, ecs);
}
}
static void
save_contact (EContactEditor *ce,
gboolean should_close)
{
gchar *uid;
const gchar *name_entry_string;
const gchar *file_as_entry_string;
const gchar *company_name_string;
GtkWidget *entry_fullname, *entry_file_as, *company_name;
if (!ce->target_client)
return;
if (ce->target_editable && e_client_is_readonly (E_CLIENT (ce->source_client))) {
if (e_alert_run_dialog_for_args (
GTK_WINDOW (ce->app),
"addressbook:prompt-move",
NULL) == GTK_RESPONSE_NO)
return;
}
entry_fullname = e_builder_get_widget (ce->builder, "entry-fullname" );
entry_file_as = gtk_bin_get_child (
GTK_BIN (e_builder_get_widget (ce->builder, "combo-file-as")));
company_name = e_builder_get_widget (ce->builder, "entry-company");
name_entry_string = gtk_entry_get_text (GTK_ENTRY (entry_fullname));
file_as_entry_string = gtk_entry_get_text (GTK_ENTRY (entry_file_as));
company_name_string = gtk_entry_get_text (GTK_ENTRY (company_name));
if (strcmp (company_name_string , "")) {
if (!strcmp (name_entry_string, ""))
gtk_entry_set_text (
GTK_ENTRY (entry_fullname),
company_name_string);
if (!strcmp (file_as_entry_string, ""))
gtk_entry_set_text (
GTK_ENTRY (entry_file_as),
company_name_string);
}
extract_all (ce);
if (!e_contact_editor_is_valid (EAB_EDITOR (ce))) {
uid = e_contact_get (ce->contact, E_CONTACT_UID);
g_object_unref (ce->contact);
ce->contact = e_contact_new ();
if (uid) {
e_contact_set (ce->contact, E_CONTACT_UID, uid);
g_free (uid);
}
return;
}
real_save_contact (ce, should_close);
}
static void
e_contact_editor_save_contact (EABEditor *editor,
gboolean should_close)
{
save_contact (E_CONTACT_EDITOR (editor), should_close);
}
/* Closes the dialog box and emits the appropriate signals */
static void
e_contact_editor_close (EABEditor *editor)
{
EContactEditor *ce = E_CONTACT_EDITOR (editor);
if (ce->app != NULL) {
gtk_widget_destroy (ce->app);
ce->app = NULL;
eab_editor_closed (editor);
}
}
static const EContactField non_string_fields[] = {
E_CONTACT_FULL_NAME,
E_CONTACT_ADDRESS,
E_CONTACT_ADDRESS_HOME,
E_CONTACT_ADDRESS_WORK,
E_CONTACT_ADDRESS_OTHER,
E_CONTACT_EMAIL,
E_CONTACT_IM_AIM,
E_CONTACT_IM_GROUPWISE,
E_CONTACT_IM_JABBER,
E_CONTACT_IM_YAHOO,
E_CONTACT_IM_GADUGADU,
E_CONTACT_IM_MSN,
E_CONTACT_IM_ICQ,
E_CONTACT_IM_SKYPE,
E_CONTACT_IM_TWITTER,
E_CONTACT_PHOTO,
E_CONTACT_LOGO,
E_CONTACT_X509_CERT,
E_CONTACT_CATEGORY_LIST,
E_CONTACT_BIRTH_DATE,
E_CONTACT_ANNIVERSARY
};
static gboolean
is_non_string_field (EContactField id)
{
gint count = sizeof (non_string_fields) / sizeof (EContactField);
gint i;
for (i = 0; i < count; i++)
if (id == non_string_fields[i])
return TRUE;
return FALSE;
}
/* insert checks here (date format, for instance, etc.) */
static gboolean
e_contact_editor_is_valid (EABEditor *editor)
{
EContactEditor *ce = E_CONTACT_EDITOR (editor);
GtkWidget *widget;
gboolean validation_error = FALSE;
GSList *iter;
GString *errmsg = g_string_new (_("The contact data is invalid:\n\n"));
time_t bday, now = time (NULL);
widget = e_builder_get_widget (ce->builder, "dateedit-birthday");
if (!(e_date_edit_date_is_valid (E_DATE_EDIT (widget)))) {
g_string_append_printf (
errmsg, _("'%s' has an invalid format"),
e_contact_pretty_name (E_CONTACT_BIRTH_DATE));
validation_error = TRUE;
}
/* If valid, see if the birthday is a future date */
bday = e_date_edit_get_time (E_DATE_EDIT (widget));
if (bday > now) {
g_string_append_printf (errmsg, _("'%s' cannot be a future date"),
e_contact_pretty_name (E_CONTACT_BIRTH_DATE));
validation_error = TRUE;
}
widget = e_builder_get_widget (ce->builder, "dateedit-anniversary");
if (!(e_date_edit_date_is_valid (E_DATE_EDIT (widget)))) {
g_string_append_printf (
errmsg, _("%s'%s' has an invalid format"),
validation_error ? ",\n" : "",
e_contact_pretty_name (E_CONTACT_ANNIVERSARY));
validation_error = TRUE;
}
for (iter = ce->required_fields; iter; iter = iter->next) {
const gchar *field_name = iter->data;
EContactField field_id = e_contact_field_id (field_name);
if (is_non_string_field (field_id)) {
if (e_contact_get_const (ce->contact, field_id) == NULL) {
g_string_append_printf (
errmsg, _("%s'%s' is empty"),
validation_error ? ",\n" : "",
e_contact_pretty_name (field_id));
validation_error = TRUE;
break;
}
} else {
const gchar *text;
text = e_contact_get_const (ce->contact, field_id);
if (STRING_IS_EMPTY (text)) {
g_string_append_printf (
errmsg, _("%s'%s' is empty"),
validation_error ? ",\n" : "",
e_contact_pretty_name (field_id));
validation_error = TRUE;
break;
}
}
}
if (validation_error) {
g_string_append (errmsg, ".");
e_alert_run_dialog_for_args (
GTK_WINDOW (ce->app),
"addressbook:generic-error",
_("Invalid contact."), errmsg->str, NULL);
g_string_free (errmsg, TRUE);
return FALSE;
}
else {
g_string_free (errmsg, TRUE);
return TRUE;
}
}
static gboolean
e_contact_editor_is_changed (EABEditor *editor)
{
return E_CONTACT_EDITOR (editor)->changed;
}
static GtkWindow *
e_contact_editor_get_window (EABEditor *editor)
{
return GTK_WINDOW (E_CONTACT_EDITOR (editor)->app);
}
static void
file_save_and_close_cb (GtkWidget *widget,
EContactEditor *ce)
{
save_contact (ce, TRUE);
}
static void
file_cancel_cb (GtkWidget *widget,
EContactEditor *ce)
{
eab_editor_close (EAB_EDITOR (ce));
}
/* Callback used when the dialog box is destroyed */
static gint
app_delete_event_cb (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
EContactEditor *ce;
ce = E_CONTACT_EDITOR (data);
/* if we're saving, don't allow the dialog to close */
if (ce->in_async_call)
return TRUE;
if (ce->changed) {
switch (eab_prompt_save_dialog (GTK_WINDOW (ce->app))) {
case GTK_RESPONSE_YES:
eab_editor_save_contact (EAB_EDITOR (ce), TRUE);
return TRUE;
case GTK_RESPONSE_NO:
break;
case GTK_RESPONSE_CANCEL:
default:
return TRUE;
}
}
eab_editor_close (EAB_EDITOR (ce));
return TRUE;
}
static void
show_help_cb (GtkWidget *widget,
gpointer data)
{
/* FIXME Pass a proper parent window. */
e_display_help (NULL, "contacts-usage-add-contact");
}
static GList *
add_to_tab_order (GList *list,
GtkBuilder *builder,
const gchar *name)
{
GtkWidget *widget = e_builder_get_widget (builder, name);
return g_list_prepend (list, widget);
}
static void
setup_tab_order (GtkBuilder *builder)
{
GtkWidget *container;
GList *list = NULL;
/*
container = e_builder_get_widget(builder, "table-contact-editor-general");
*
if (container) {
list = add_to_tab_order(list, builder, "entry-fullname");
list = add_to_tab_order(list, builder, "entry-jobtitle");
list = add_to_tab_order(list, builder, "entry-company");
list = add_to_tab_order(list, builder, "combo-file-as");
list = add_to_tab_order(list, builder, "entry-phone-1");
list = add_to_tab_order(list, builder, "entry-phone-2");
list = add_to_tab_order(list, builder, "entry-phone-3");
list = add_to_tab_order(list, builder, "entry-phone-4");
*
list = add_to_tab_order(list, builder, "entry-email1");
list = add_to_tab_order(list, builder, "alignment-htmlmail");
list = add_to_tab_order(list, builder, "entry-web");
list = add_to_tab_order(list, builder, "entry-homepage");
list = add_to_tab_order(list, builder, "button-fulladdr");
list = add_to_tab_order(list, builder, "text-address");
list = g_list_reverse (list);
e_container_change_tab_order (GTK_CONTAINER (container), list);
g_list_free (list);
}
*/
container = e_builder_get_widget (builder, "table-home-address");
gtk_container_get_focus_chain (GTK_CONTAINER (container), &list);
list = add_to_tab_order (list, builder, "scrolledwindow-home-address");
list = add_to_tab_order (list, builder, "entry-home-city");
list = add_to_tab_order (list, builder, "entry-home-zip");
list = add_to_tab_order (list, builder, "entry-home-state");
list = add_to_tab_order (list, builder, "entry-home-pobox");
list = add_to_tab_order (list, builder, "entry-home-country");
list = g_list_reverse (list);
gtk_container_set_focus_chain (GTK_CONTAINER (container), list);
g_list_free (list);
container = e_builder_get_widget (builder, "table-work-address");
gtk_container_get_focus_chain (GTK_CONTAINER (container), &list);
list = add_to_tab_order (list, builder, "scrolledwindow-work-address");
list = add_to_tab_order (list, builder, "entry-work-city");
list = add_to_tab_order (list, builder, "entry-work-zip");
list = add_to_tab_order (list, builder, "entry-work-state");
list = add_to_tab_order (list, builder, "entry-work-pobox");
list = add_to_tab_order (list, builder, "entry-work-country");
list = g_list_reverse (list);
gtk_container_set_focus_chain (GTK_CONTAINER (container), list);
g_list_free (list);
container = e_builder_get_widget (builder, "table-other-address");
gtk_container_get_focus_chain (GTK_CONTAINER (container), &list);
list = add_to_tab_order (list, builder, "scrolledwindow-other-address");
list = add_to_tab_order (list, builder, "entry-other-city");
list = add_to_tab_order (list, builder, "entry-other-zip");
list = add_to_tab_order (list, builder, "entry-other-state");
list = add_to_tab_order (list, builder, "entry-other-pobox");
list = add_to_tab_order (list, builder, "entry-other-country");
list = g_list_reverse (list);
gtk_container_set_focus_chain (GTK_CONTAINER (container), list);
g_list_free (list);
}
static void
expand_web_toggle (EContactEditor *ce)
{
GtkWidget *widget;
widget = e_builder_get_widget (ce->builder, "label-videourl");
expand_web (ce, !gtk_widget_get_visible (widget));
}
static void
expand_phone_toggle (EContactEditor *ce)
{
GtkWidget *phone_ext_table;
phone_ext_table = e_builder_get_widget (
ce->builder, "table-phone-extended");
expand_phone (ce, !gtk_widget_get_visible (phone_ext_table));
}
static void
expand_mail_toggle (EContactEditor *ce)
{
GtkWidget *mail;
mail = e_builder_get_widget (ce->builder, "entry-email-4");
expand_mail (ce, !gtk_widget_get_visible (mail));
}
static void
e_contact_editor_init (EContactEditor *e_contact_editor)
{
GtkBuilder *builder;
EShell *shell;
ESourceRegistry *registry;
GtkWidget *container;
GtkWidget *widget, *label;
GtkEntryCompletion *completion;
/* FIXME The shell should be obtained
* through a constructor property. */
shell = e_shell_get_default ();
registry = e_shell_get_registry (shell);
e_contact_editor->name = e_contact_name_new ();
e_contact_editor->contact = NULL;
e_contact_editor->changed = FALSE;
e_contact_editor->check_merge = FALSE;
e_contact_editor->image_set = FALSE;
e_contact_editor->image_changed = FALSE;
e_contact_editor->in_async_call = FALSE;
e_contact_editor->target_editable = TRUE;
e_contact_editor->fullname_dialog = NULL;
e_contact_editor->categories_dialog = NULL;
e_contact_editor->compress_ui = e_shell_get_express_mode (shell);
builder = gtk_builder_new ();
e_load_ui_builder_definition (builder, "contact-editor.ui");
e_contact_editor->builder = builder;
setup_tab_order (builder);
e_contact_editor->app =
e_builder_get_widget (builder, "contact editor");
widget = e_contact_editor->app;
gtk_widget_ensure_style (widget);
gtk_window_set_type_hint (
GTK_WINDOW (widget), GDK_WINDOW_TYPE_HINT_NORMAL);
container = gtk_dialog_get_action_area (GTK_DIALOG (widget));
gtk_container_set_border_width (GTK_CONTAINER (container), 12);
container = gtk_dialog_get_content_area (GTK_DIALOG (widget));
gtk_container_set_border_width (GTK_CONTAINER (container), 0);
init_all (e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-image");
g_signal_connect (
widget, "clicked",
G_CALLBACK (image_clicked), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-fullname");
g_signal_connect (
widget, "clicked",
G_CALLBACK (full_name_clicked), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-categories");
g_signal_connect (
widget, "clicked",
G_CALLBACK (categories_clicked), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "source-combo-box-source");
e_source_combo_box_set_registry (
E_SOURCE_COMBO_BOX (widget), registry);
g_signal_connect (
widget, "changed",
G_CALLBACK (source_changed), e_contact_editor);
label = e_builder_get_widget (
e_contact_editor->builder, "where-label");
gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-ok");
g_signal_connect (
widget, "clicked",
G_CALLBACK (file_save_and_close_cb), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-cancel");
g_signal_connect (
widget, "clicked",
G_CALLBACK (file_cancel_cb), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-help");
g_signal_connect (
widget, "clicked",
G_CALLBACK (show_help_cb), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-web-expand");
g_signal_connect_swapped (
widget, "clicked",
G_CALLBACK (expand_web_toggle), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-phone-expand");
g_signal_connect_swapped (
widget, "clicked",
G_CALLBACK (expand_phone_toggle), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "button-mail-expand");
g_signal_connect_swapped (
widget, "clicked",
G_CALLBACK (expand_mail_toggle), e_contact_editor);
widget = e_builder_get_widget (
e_contact_editor->builder, "entry-fullname");
if (widget)
gtk_widget_grab_focus (widget);
widget = e_builder_get_widget (
e_contact_editor->builder, "entry-categories");
completion = e_category_completion_new ();
gtk_entry_set_completion (GTK_ENTRY (widget), completion);
g_object_unref (completion);
/* Connect to the deletion of the dialog */
g_signal_connect (
e_contact_editor->app, "delete_event",
G_CALLBACK (app_delete_event_cb), e_contact_editor);
/* set the icon */
gtk_window_set_icon_name (
GTK_WINDOW (e_contact_editor->app), "contact-editor");
/* show window */
gtk_widget_show (e_contact_editor->app);
gtk_application_add_window (
GTK_APPLICATION (shell),
GTK_WINDOW (e_contact_editor->app));
}
static void
e_contact_editor_dispose (GObject *object)
{
EContactEditor *e_contact_editor = E_CONTACT_EDITOR (object);
if (e_contact_editor->file_selector != NULL) {
gtk_widget_destroy (e_contact_editor->file_selector);
e_contact_editor->file_selector = NULL;
}
if (e_contact_editor->writable_fields) {
e_client_util_free_string_slist (
e_contact_editor->writable_fields);
e_contact_editor->writable_fields = NULL;
}
if (e_contact_editor->required_fields) {
e_client_util_free_string_slist (
e_contact_editor->required_fields);
e_contact_editor->required_fields = NULL;
}
if (e_contact_editor->contact) {
g_object_unref (e_contact_editor->contact);
e_contact_editor->contact = NULL;
}
if (e_contact_editor->source_client) {
g_object_unref (e_contact_editor->source_client);
e_contact_editor->source_client = NULL;
}
if (e_contact_editor->target_client) {
g_signal_handler_disconnect (
e_contact_editor->target_client,
e_contact_editor->target_editable_id);
g_object_unref (e_contact_editor->target_client);
e_contact_editor->target_client = NULL;
}
if (e_contact_editor->name) {
e_contact_name_free (e_contact_editor->name);
e_contact_editor->name = NULL;
}
if (e_contact_editor->builder) {
g_object_unref (e_contact_editor->builder);
e_contact_editor->builder = NULL;
}
if (e_contact_editor->cancellable != NULL) {
g_object_unref (e_contact_editor->cancellable);
e_contact_editor->cancellable = NULL;
}
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
supported_fields_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
EBookClient *book_client = E_BOOK_CLIENT (source_object);
EContactEditor *ce = user_data;
gchar *prop_value = NULL;
GSList *fields;
gboolean success;
GError *error = NULL;
success = e_client_get_backend_property_finish (
E_CLIENT (book_client), result, &prop_value, &error);
if (!success)
prop_value = NULL;
if (error != NULL) {
g_warning (
"%s: Failed to get supported fields: %s",
G_STRFUNC, error->message);
g_error_free (error);
}
if (!g_slist_find (eab_editor_get_all_editors (), ce)) {
g_warning (
"supported_fields_cb called for book that's still "
"around, but contact editor that's been destroyed.");
g_free (prop_value);
return;
}
fields = e_client_util_parse_comma_strings (prop_value);
g_object_set (ce, "writable_fields", fields, NULL);
e_client_util_free_string_slist (fields);
g_free (prop_value);
eab_editor_show (EAB_EDITOR (ce));
sensitize_all (ce);
}
static void
required_fields_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
EBookClient *book_client = E_BOOK_CLIENT (source_object);
EContactEditor *ce = user_data;
gchar *prop_value = NULL;
GSList *fields;
gboolean success;
GError *error = NULL;
success = e_client_get_backend_property_finish (
E_CLIENT (book_client), result, &prop_value, &error);
if (!success)
prop_value = NULL;
if (error != NULL) {
g_warning (
"%s: Failed to get supported fields: %s",
G_STRFUNC, error->message);
g_error_free (error);
}
if (!g_slist_find (eab_editor_get_all_editors (), ce)) {
g_warning (
"supported_fields_cb called for book that's still "
"around, but contact editor that's been destroyed.");
g_free (prop_value);
return;
}
fields = e_client_util_parse_comma_strings (prop_value);
g_object_set (ce, "required_fields", fields, NULL);
e_client_util_free_string_slist (fields);
g_free (prop_value);
}
EABEditor *
e_contact_editor_new (EShell *shell,
EBookClient *book_client,
EContact *contact,
gboolean is_new_contact,
gboolean editable)
{
EABEditor *editor;
g_return_val_if_fail (E_IS_SHELL (shell), NULL);
g_return_val_if_fail (E_IS_BOOK_CLIENT (book_client), NULL);
g_return_val_if_fail (E_IS_CONTACT (contact), NULL);
editor = g_object_new (E_TYPE_CONTACT_EDITOR, "shell", shell, NULL);
g_object_set (
editor,
"source_client", book_client,
"contact", contact,
"is_new_contact", is_new_contact,
"editable", editable,
NULL);
return editor;
}
static void
notify_readonly_cb (EBookClient *book_client,
GParamSpec *pspec,
EContactEditor *ce)
{
EClient *client;
gint new_target_editable;
gboolean changed = FALSE;
client = E_CLIENT (ce->target_client);
new_target_editable = !e_client_is_readonly (client);
if (ce->target_editable != new_target_editable)
changed = TRUE;
ce->target_editable = new_target_editable;
if (changed)
sensitize_all (ce);
}
static void
e_contact_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
EContactEditor *editor;
editor = E_CONTACT_EDITOR (object);
switch (property_id) {
case PROP_SOURCE_CLIENT: {
gboolean writable;
gboolean changed = FALSE;
EBookClient *source_client;
source_client = E_BOOK_CLIENT (g_value_get_object (value));
if (source_client == editor->source_client)
break;
if (editor->source_client)
g_object_unref (editor->source_client);
editor->source_client = source_client;
g_object_ref (editor->source_client);
if (!editor->target_client) {
editor->target_client = editor->source_client;
g_object_ref (editor->target_client);
editor->target_editable_id = g_signal_connect (
editor->target_client, "notify::readonly",
G_CALLBACK (notify_readonly_cb), editor);
e_client_get_backend_property (
E_CLIENT (editor->target_client),
BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS,
NULL, supported_fields_cb, editor);
e_client_get_backend_property (
E_CLIENT (editor->target_client),
BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS,
NULL, required_fields_cb, editor);
}
writable = !e_client_is_readonly (E_CLIENT (editor->target_client));
if (writable != editor->target_editable) {
editor->target_editable = writable;
changed = TRUE;
}
if (changed)
sensitize_all (editor);
break;
}
case PROP_TARGET_CLIENT: {
gboolean writable;
gboolean changed = FALSE;
EBookClient *target_client;
target_client = E_BOOK_CLIENT (g_value_get_object (value));
if (target_client == editor->target_client)
break;
if (editor->target_client) {
g_signal_handler_disconnect (
editor->target_client,
editor->target_editable_id);
g_object_unref (editor->target_client);
}
editor->target_client = target_client;
g_object_ref (editor->target_client);
editor->target_editable_id = g_signal_connect (
editor->target_client, "notify::readonly",
G_CALLBACK (notify_readonly_cb), editor);
e_client_get_backend_property (
E_CLIENT (editor->target_client),
BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS,
NULL, supported_fields_cb, editor);
e_client_get_backend_property (
E_CLIENT (editor->target_client),
BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS,
NULL, required_fields_cb, editor);
if (!editor->is_new_contact)
editor->changed = TRUE;
writable = !e_client_is_readonly (E_CLIENT (editor->target_client));
if (writable != editor->target_editable) {
editor->target_editable = writable;
changed = TRUE;
}
if (changed)
sensitize_all (editor);
break;
}
case PROP_CONTACT:
if (editor->contact)
g_object_unref (editor->contact);
editor->contact = e_contact_duplicate (
E_CONTACT (g_value_get_object (value)));
fill_in_all (editor);
editor->changed = FALSE;
break;
case PROP_IS_NEW_CONTACT:
editor->is_new_contact = g_value_get_boolean (value);
break;
case PROP_EDITABLE: {
gboolean new_value = g_value_get_boolean (value);
gboolean changed = (editor->target_editable != new_value);
editor->target_editable = new_value;
if (changed)
sensitize_all (editor);
break;
}
case PROP_CHANGED: {
gboolean new_value = g_value_get_boolean (value);
gboolean changed = (editor->changed != new_value);
editor->changed = new_value;
if (changed)
sensitize_ok (editor);
break;
}
case PROP_WRITABLE_FIELDS:
if (editor->writable_fields)
e_client_util_free_string_slist (editor->writable_fields);
editor->writable_fields =
e_client_util_copy_string_slist (
NULL, g_value_get_pointer (value));
sensitize_all (editor);
break;
case PROP_REQUIRED_FIELDS:
if (editor->required_fields)
e_client_util_free_string_slist (editor->required_fields);
editor->required_fields =
e_client_util_copy_string_slist (
NULL, g_value_get_pointer (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
e_contact_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
EContactEditor *e_contact_editor;
e_contact_editor = E_CONTACT_EDITOR (object);
switch (property_id) {
case PROP_SOURCE_CLIENT:
g_value_set_object (value, e_contact_editor->source_client);
break;
case PROP_TARGET_CLIENT:
g_value_set_object (value, e_contact_editor->target_client);
break;
case PROP_CONTACT:
extract_all (e_contact_editor);
g_value_set_object (value, e_contact_editor->contact);
break;
case PROP_IS_NEW_CONTACT:
g_value_set_boolean (
value, e_contact_editor->is_new_contact);
break;
case PROP_EDITABLE:
g_value_set_boolean (
value, e_contact_editor->target_editable);
break;
case PROP_CHANGED:
g_value_set_boolean (
value, e_contact_editor->changed);
break;
case PROP_WRITABLE_FIELDS:
g_value_set_pointer (value, e_contact_editor->writable_fields);
break;
case PROP_REQUIRED_FIELDS:
g_value_set_pointer (value, e_contact_editor->required_fields);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/**
* e_contact_editor_raise:
* @config: The %EContactEditor object.
*
* Raises the dialog associated with this %EContactEditor object.
*/
static void
e_contact_editor_raise (EABEditor *editor)
{
EContactEditor *ce = E_CONTACT_EDITOR (editor);
GdkWindow *window;
window = gtk_widget_get_window (ce->app);
if (window != NULL)
gdk_window_raise (window);
}
/**
* e_contact_editor_show:
* @ce: The %EContactEditor object.
*
* Shows the dialog associated with this %EContactEditor object.
*/
static void
e_contact_editor_show (EABEditor *editor)
{
EContactEditor *ce = E_CONTACT_EDITOR (editor);
gtk_widget_show (ce->app);
}