evolution-3.6.4/addressbook/gui/contact-editor/e-contact-editor.c

Location Tool Test ID Function Issue
e-contact-editor.c:1139:3 clang-analyzer Value stored to 'l' is never read
e-contact-editor.c:1139:3 clang-analyzer Value stored to 'l' is never read
e-contact-editor.c:1491:3 clang-analyzer Value stored to 'l' is never read
e-contact-editor.c:1491:3 clang-analyzer Value stored to 'l' is never read
e-contact-editor.c:1908:4 clang-analyzer Value stored to 'l' is never read
e-contact-editor.c:1908:4 clang-analyzer Value stored to 'l' is never read
   1 /*
   2  * This program is free software; you can redistribute it and/or
   3  * modify it under the terms of the GNU Lesser General Public
   4  * License as published by the Free Software Foundation; either
   5  * version 2 of the License, or (at your option) version 3.
   6  *
   7  * This program is distributed in the hope that it will be useful,
   8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10  * Lesser General Public License for more details.
  11  *
  12  * You should have received a copy of the GNU Lesser General Public
  13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  14  *
  15  *
  16  * Authors:
  17  *		Chris Lahey <clahey@ximian.com>
  18  *
  19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  20  *
  21  */
  22 
  23 #ifdef HAVE_CONFIG_H
  24 #include <config.h>
  25 #endif
  26 
  27 #include "eab-editor.h"
  28 #include "e-contact-editor.h"
  29 
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <time.h>
  33 #include <gtk/gtk.h>
  34 #include <glib/gi18n.h>
  35 #include <gdk/gdkkeysyms.h>
  36 #include <gdk-pixbuf/gdk-pixbuf.h>
  37 
  38 #include <libedataserverui/libedataserverui.h>
  39 
  40 #include "addressbook/printing/e-contact-print.h"
  41 #include "addressbook/gui/widgets/eab-gui-util.h"
  42 #include "e-util/e-util.h"
  43 #include "libevolution-utils/e-alert-dialog.h"
  44 #include "misc/e-dateedit.h"
  45 #include "misc/e-image-chooser.h"
  46 #include "misc/e-url-entry.h"
  47 #include "e-util/e-icon-factory.h"
  48 #include "e-util/e-util-private.h"
  49 #include "shell/e-shell.h"
  50 
  51 #include "eab-contact-merging.h"
  52 
  53 #include "e-contact-editor-fullname.h"
  54 
  55 #define EMAIL_SLOTS   4
  56 #define PHONE_SLOTS   8
  57 #define IM_SLOTS      4
  58 #define ADDRESS_SLOTS 3
  59 
  60 #define EVOLUTION_UI_SLOT_PARAM "X-EVOLUTION-UI-SLOT"
  61 
  62 /* IM columns */
  63 enum {
  64 	COLUMN_IM_ICON,
  65 	COLUMN_IM_SERVICE,
  66 	COLUMN_IM_SCREENNAME,
  67 	COLUMN_IM_LOCATION,
  68 	COLUMN_IM_LOCATION_TYPE,
  69 	COLUMN_IM_SERVICE_FIELD,
  70 	NUM_IM_COLUMNS
  71 };
  72 
  73 static void	e_contact_editor_set_property	(GObject *object,
  74 						 guint property_id,
  75 						 const GValue *value,
  76 						 GParamSpec *pspec);
  77 static void	e_contact_editor_get_property	(GObject *object,
  78 						 guint property_id,
  79 						 GValue *value,
  80 						 GParamSpec *pspec);
  81 static void	e_contact_editor_dispose	(GObject *object);
  82 static void	e_contact_editor_raise		(EABEditor *editor);
  83 static void	e_contact_editor_show		(EABEditor *editor);
  84 static void	e_contact_editor_save_contact	(EABEditor *editor,
  85 						 gboolean should_close);
  86 static void	e_contact_editor_close		(EABEditor *editor);
  87 static gboolean	e_contact_editor_is_valid	(EABEditor *editor);
  88 static gboolean	e_contact_editor_is_changed	(EABEditor *editor);
  89 static GtkWindow *
  90 		e_contact_editor_get_window	(EABEditor *editor);
  91 static void	save_contact			(EContactEditor *ce,
  92 						 gboolean should_close);
  93 static void	entry_activated			(EContactEditor *editor);
  94 
  95 static void	set_entry_text			(EContactEditor *editor,
  96 						 GtkEntry *entry,
  97 						 const gchar *string);
  98 static void	sensitize_ok			(EContactEditor *ce);
  99 
 100 static EABEditorClass *parent_class = NULL;
 101 
 102 enum {
 103 	PROP_0,
 104 	PROP_SOURCE_CLIENT,
 105 	PROP_TARGET_CLIENT,
 106 	PROP_CONTACT,
 107 	PROP_IS_NEW_CONTACT,
 108 	PROP_EDITABLE,
 109 	PROP_CHANGED,
 110 	PROP_WRITABLE_FIELDS,
 111 	PROP_REQUIRED_FIELDS
 112 };
 113 
 114 enum {
 115 	DYNAMIC_LIST_EMAIL,
 116 	DYNAMIC_LIST_PHONE,
 117 	DYNAMIC_LIST_ADDRESS
 118 };
 119 
 120 static struct {
 121 	EContactField field_id;
 122 	const gchar *type_1;
 123 	const gchar *type_2;
 124 }
 125 phones[] = {
 126 	{ E_CONTACT_PHONE_ASSISTANT,    EVC_X_ASSISTANT,       NULL    },
 127 	{ E_CONTACT_PHONE_BUSINESS,     "WORK",                "VOICE" },
 128 	{ E_CONTACT_PHONE_BUSINESS_FAX, "WORK",                "FAX"   },
 129 	{ E_CONTACT_PHONE_CALLBACK,     EVC_X_CALLBACK,        NULL    },
 130 	{ E_CONTACT_PHONE_CAR,          "CAR",                 NULL    },
 131 	{ E_CONTACT_PHONE_COMPANY,      "X-EVOLUTION-COMPANY", NULL    },
 132 	{ E_CONTACT_PHONE_HOME,         "HOME",                "VOICE" },
 133 	{ E_CONTACT_PHONE_HOME_FAX,     "HOME",                "FAX"   },
 134 	{ E_CONTACT_PHONE_ISDN,         "ISDN",                NULL    },
 135 	{ E_CONTACT_PHONE_MOBILE,       "CELL",                NULL    },
 136 	{ E_CONTACT_PHONE_OTHER,        "VOICE",               NULL    },
 137 	{ E_CONTACT_PHONE_OTHER_FAX,    "FAX",                 NULL    },
 138 	{ E_CONTACT_PHONE_PAGER,        "PAGER",               NULL    },
 139 	{ E_CONTACT_PHONE_PRIMARY,      "PREF",                NULL    },
 140 	{ E_CONTACT_PHONE_RADIO,        EVC_X_RADIO,           NULL    },
 141 	{ E_CONTACT_PHONE_TELEX,        EVC_X_TELEX,           NULL    },
 142 	{ E_CONTACT_PHONE_TTYTDD,       EVC_X_TTYTDD,          NULL    }
 143 };
 144 
 145 /* Defaults from the table above */
 146 static const gint phones_default[] = { 1, 6, 9, 2, 7, 12, 10, 10 };
 147 
 148 static EContactField addresses[] = {
 149 	E_CONTACT_ADDRESS_WORK,
 150 	E_CONTACT_ADDRESS_HOME,
 151 	E_CONTACT_ADDRESS_OTHER
 152 };
 153 
 154 static EContactField address_labels[] = {
 155 	E_CONTACT_ADDRESS_LABEL_WORK,
 156 	E_CONTACT_ADDRESS_LABEL_HOME,
 157 	E_CONTACT_ADDRESS_LABEL_OTHER
 158 };
 159 
 160 static const gchar *address_name[] = {
 161 	"work",
 162 	"home",
 163 	"other"
 164 };
 165 
 166 static struct {
 167 	EContactField field;
 168 	const gchar *pretty_name;
 169 }
 170 im_service[] =
 171 {
 172 	{ E_CONTACT_IM_AIM,       N_ ("AIM")       },
 173 	{ E_CONTACT_IM_JABBER,    N_ ("Jabber")    },
 174 	{ E_CONTACT_IM_YAHOO,     N_ ("Yahoo")     },
 175 	{ E_CONTACT_IM_GADUGADU,  N_ ("Gadu-Gadu") },
 176 	{ E_CONTACT_IM_MSN,       N_ ("MSN")       },
 177 	{ E_CONTACT_IM_ICQ,       N_ ("ICQ")       },
 178 	{ E_CONTACT_IM_GROUPWISE, N_ ("GroupWise") },
 179 	{ E_CONTACT_IM_SKYPE,     N_ ("Skype")     },
 180 	{ E_CONTACT_IM_TWITTER,   N_ ("Twitter")   }
 181 };
 182 
 183 /* Defaults from the table above */
 184 static const gint im_service_default[] = { 0, 2, 4, 5 };
 185 
 186 static struct {
 187 	const gchar *name;
 188 	const gchar *pretty_name;
 189 }
 190 common_location[] =
 191 {
 192 	{ "WORK",  N_ ("Work")  },
 193 	{ "HOME",  N_ ("Home")  },
 194 	{ "OTHER", N_ ("Other") }
 195 };
 196 
 197 /* Default from the table above */
 198 static const gint email_default[] = { 0, 1, 2, 2 };
 199 
 200 #define STRING_IS_EMPTY(x)      (!(x) || !(*(x)))
 201 #define STRING_MAKE_NON_NULL(x) ((x) ? (x) : "")
 202 
 203 G_DEFINE_TYPE (EContactEditor, e_contact_editor, EAB_TYPE_EDITOR)
 204 
 205 static void
 206 e_contact_editor_contact_added (EABEditor *editor,
 207                                 const GError *error,
 208                                 EContact *contact)
 209 {
 210 	if (!error)
 211 		return;
 212 
 213 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
 214 	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 215 		return;
 216 
 217 	eab_error_dialog (NULL, _("Error adding contact"), error);
 218 }
 219 
 220 static void
 221 e_contact_editor_contact_modified (EABEditor *editor,
 222                                    const GError *error,
 223                                    EContact *contact)
 224 {
 225 	if (!error)
 226 		return;
 227 
 228 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
 229 	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 230 		return;
 231 
 232 	eab_error_dialog (NULL, _("Error modifying contact"), error);
 233 }
 234 
 235 static void
 236 e_contact_editor_contact_deleted (EABEditor *editor,
 237                                   const GError *error,
 238                                   EContact *contact)
 239 {
 240 	if (!error)
 241 		return;
 242 
 243 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
 244 	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 245 		return;
 246 
 247 	eab_error_dialog (NULL, _("Error removing contact"), error);
 248 }
 249 
 250 static void
 251 e_contact_editor_closed (EABEditor *editor)
 252 {
 253 	g_object_unref (editor);
 254 }
 255 
 256 static void
 257 e_contact_editor_class_init (EContactEditorClass *class)
 258 {
 259 	GObjectClass *object_class = G_OBJECT_CLASS (class);
 260 	EABEditorClass *editor_class = EAB_EDITOR_CLASS (class);
 261 
 262 	parent_class = g_type_class_ref (EAB_TYPE_EDITOR);
 263 
 264 	object_class->set_property = e_contact_editor_set_property;
 265 	object_class->get_property = e_contact_editor_get_property;
 266 	object_class->dispose = e_contact_editor_dispose;
 267 
 268 	editor_class->raise = e_contact_editor_raise;
 269 	editor_class->show = e_contact_editor_show;
 270 	editor_class->close = e_contact_editor_close;
 271 	editor_class->is_valid = e_contact_editor_is_valid;
 272 	editor_class->save_contact = e_contact_editor_save_contact;
 273 	editor_class->is_changed = e_contact_editor_is_changed;
 274 	editor_class->get_window = e_contact_editor_get_window;
 275 	editor_class->contact_added = e_contact_editor_contact_added;
 276 	editor_class->contact_modified = e_contact_editor_contact_modified;
 277 	editor_class->contact_deleted = e_contact_editor_contact_deleted;
 278 	editor_class->editor_closed = e_contact_editor_closed;
 279 
 280 	g_object_class_install_property (
 281 		object_class,
 282 		PROP_SOURCE_CLIENT,
 283 		g_param_spec_object (
 284 			"source_client",
 285 			"Source EBookClient",
 286 			NULL,
 287 			E_TYPE_BOOK_CLIENT,
 288 			G_PARAM_READWRITE));
 289 
 290 	g_object_class_install_property (
 291 		object_class,
 292 		PROP_TARGET_CLIENT,
 293 		g_param_spec_object (
 294 			"target_client",
 295 			"Target EBookClient",
 296 			NULL,
 297 			E_TYPE_BOOK_CLIENT,
 298 			G_PARAM_READWRITE));
 299 
 300 	g_object_class_install_property (
 301 		object_class,
 302 		PROP_CONTACT,
 303 		g_param_spec_object (
 304 			"contact",
 305 			"Contact",
 306 			NULL,
 307 			E_TYPE_CONTACT,
 308 			G_PARAM_READWRITE));
 309 
 310 	g_object_class_install_property (
 311 		object_class,
 312 		PROP_IS_NEW_CONTACT,
 313 		g_param_spec_boolean (
 314 			"is_new_contact",
 315 			"Is New Contact",
 316 			NULL,
 317 			FALSE,
 318 			G_PARAM_READWRITE));
 319 
 320 	g_object_class_install_property (
 321 		object_class,
 322 		PROP_WRITABLE_FIELDS,
 323 		g_param_spec_pointer (
 324 			"writable_fields",
 325 			"Writable Fields",
 326 			NULL,
 327 			G_PARAM_READWRITE));
 328 
 329 	g_object_class_install_property (
 330 		object_class,
 331 		PROP_REQUIRED_FIELDS,
 332 		g_param_spec_pointer (
 333 			"required_fields",
 334 			"Required Fields",
 335 			NULL,
 336 			G_PARAM_READWRITE));
 337 
 338 	g_object_class_install_property (
 339 		object_class,
 340 		PROP_EDITABLE,
 341 		g_param_spec_boolean (
 342 			"editable",
 343 			"Editable",
 344 			NULL,
 345 			FALSE,
 346 			G_PARAM_READWRITE));
 347 
 348 	g_object_class_install_property (
 349 		object_class,
 350 		PROP_CHANGED,
 351 		g_param_spec_boolean (
 352 			"changed",
 353 			"Changed",
 354 			NULL,
 355 			FALSE,
 356 			G_PARAM_READWRITE));
 357 }
 358 
 359 static void
 360 entry_activated (EContactEditor *editor)
 361 {
 362 	save_contact (editor, TRUE);
 363 }
 364 
 365 /* FIXME: Linear time... */
 366 static gboolean
 367 is_field_supported (EContactEditor *editor,
 368                     EContactField field_id)
 369 {
 370 	GSList      *fields, *iter;
 371 	const gchar *field;
 372 
 373 	fields = editor->writable_fields;
 374 	if (!fields)
 375 		return FALSE;
 376 
 377 	field = e_contact_field_name (field_id);
 378 	if (!field)
 379 		return FALSE;
 380 
 381 	for (iter = fields; iter; iter = iter->next) {
 382 		const gchar *this_field = iter->data;
 383 
 384 		if (!this_field)
 385 			continue;
 386 
 387 		if (!strcmp (field, this_field))
 388 			return TRUE;
 389 	}
 390 
 391 	return FALSE;
 392 }
 393 
 394 /* This function tells you whether name_to_style will make sense.  */
 395 static gboolean
 396 style_makes_sense (const EContactName *name,
 397                    const gchar *company,
 398                    gint style)
 399 {
 400 	switch (style) {
 401 	case 0: /* Fall Through */
 402 	case 1:
 403 		return TRUE;
 404 	case 2:
 405 		if (name) {
 406 			if (name->additional && *name->additional)
 407 				return TRUE;
 408 			else
 409 				return FALSE;
 410 		}
 411 	case 3:
 412 		if (company && *company)
 413 			return TRUE;
 414 		else
 415 			return FALSE;
 416 	case 4: /* Fall Through */
 417 	case 5:
 418 		if (company && *company && name &&
 419 			((name->given && *name->given) ||
 420 			 (name->family && *name->family)))
 421 			return TRUE;
 422 		else
 423 			return FALSE;
 424 	default:
 425 		return FALSE;
 426 	}
 427 }
 428 
 429 static gchar *
 430 name_to_style (const EContactName *name,
 431                const gchar *company,
 432                gint style)
 433 {
 434 	gchar *string;
 435 	gchar *strings[4], **stringptr;
 436 	gchar *midstring[4], **midstrptr;
 437 	gchar *substring;
 438 	switch (style) {
 439 	case 0:
 440 		stringptr = strings;
 441 		if (name) {
 442 			if (name->family && *name->family)
 443 				*(stringptr++) = name->family;
 444 			if (name->given && *name->given)
 445 				*(stringptr++) = name->given;
 446 		}
 447 		*stringptr = NULL;
 448 		string = g_strjoinv (", ", strings);
 449 		break;
 450 	case 1:
 451 		stringptr = strings;
 452 		if (name) {
 453 			if (name->given && *name->given)
 454 				*(stringptr++) = name->given;
 455 			if (name->family && *name->family)
 456 				*(stringptr++) = name->family;
 457 		}
 458 		*stringptr = NULL;
 459 		string = g_strjoinv (" ", strings);
 460 		break;
 461 	case 2:
 462 		midstrptr = midstring;
 463 		if (name) {
 464 			if (name->family && *name->family)
 465 				*(midstrptr++) = name->family;
 466 			if (name->given && *name->given)
 467 				*(midstrptr++) = name->given;
 468 		}
 469 		*midstrptr = NULL;
 470 		stringptr = strings;
 471 		*(stringptr++) = g_strjoinv(", ", midstring);
 472 		if (name) {
 473 			if (name->additional && *name->additional)
 474 				*(stringptr++) = name->additional;
 475 		}
 476 		*stringptr = NULL;
 477 		string = g_strjoinv (" ", strings);
 478 		break;
 479 	case 3:
 480 		string = g_strdup (company);
 481 		break;
 482 	case 4: /* Fall Through */
 483 	case 5:
 484 		stringptr = strings;
 485 		if (name) {
 486 			if (name->family && *name->family)
 487 				*(stringptr++) = name->family;
 488 			if (name->given && *name->given)
 489 				*(stringptr++) = name->given;
 490 		}
 491 		*stringptr = NULL;
 492 		substring = g_strjoinv (", ", strings);
 493 		if (!(company && *company))
 494 			company = "";
 495 		if (style == 4)
 496 			string = g_strdup_printf ("%s (%s)", substring, company);
 497 		else
 498 			string = g_strdup_printf ("%s (%s)", company, substring);
 499 		g_free (substring);
 500 		break;
 501 	default:
 502 		string = g_strdup ("");
 503 	}
 504 	return string;
 505 }
 506 
 507 static gint
 508 file_as_get_style (EContactEditor *editor)
 509 {
 510 	GtkEntry *file_as = GTK_ENTRY (
 511 		gtk_bin_get_child (GTK_BIN (
 512 		e_builder_get_widget (editor->builder, "combo-file-as"))));
 513 	GtkEntry *company_w = GTK_ENTRY (
 514 		e_builder_get_widget (editor->builder, "entry-company"));
 515 	gchar *filestring;
 516 	gchar *trystring;
 517 	EContactName *name = editor->name;
 518 	const gchar *company;
 519 	gint i;
 520 
 521 	if (!(file_as && GTK_IS_ENTRY (file_as)))
 522 		return -1;
 523 
 524 	company = gtk_entry_get_text (GTK_ENTRY (company_w));
 525 	filestring = g_strdup (gtk_entry_get_text (file_as));
 526 
 527 	for (i = 0; i < 6; i++) {
 528 		trystring = name_to_style (name, company, i);
 529 		if (!strcmp (trystring, filestring)) {
 530 			g_free (trystring);
 531 			g_free (filestring);
 532 			return i;
 533 		}
 534 		g_free (trystring);
 535 	}
 536 	g_free (filestring);
 537 	return -1;
 538 }
 539 
 540 static void
 541 file_as_set_style (EContactEditor *editor,
 542                    gint style)
 543 {
 544 	gchar *string;
 545 	gint i;
 546 	GList *strings = NULL;
 547 	GtkComboBox *combo_file_as = GTK_COMBO_BOX (
 548 		e_builder_get_widget (editor->builder, "combo-file-as"));
 549 	GtkEntry *company_w = GTK_ENTRY (
 550 		e_builder_get_widget (editor->builder, "entry-company"));
 551 	const gchar *company;
 552 
 553 	if (!(combo_file_as && GTK_IS_COMBO_BOX (combo_file_as)))
 554 		return;
 555 
 556 	company = gtk_entry_get_text (GTK_ENTRY (company_w));
 557 
 558 	if (style == -1) {
 559 		GtkWidget *entry;
 560 
 561 		entry = gtk_bin_get_child (GTK_BIN (combo_file_as));
 562 		if (entry) {
 563 			string = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
 564 			strings = g_list_append (strings, string);
 565 		}
 566 	}
 567 
 568 	for (i = 0; i < 6; i++) {
 569 		if (style_makes_sense (editor->name, company, i)) {
 570 			gchar *u;
 571 			u = name_to_style (editor->name, company, i);
 572 			if (!STRING_IS_EMPTY (u))
 573 				strings = g_list_append (strings, u);
 574 			else
 575 				g_free (u);
 576 		}
 577 	}
 578 
 579 	if (combo_file_as) {
 580 		GList *l;
 581 		GtkListStore *list_store;
 582 		GtkTreeIter iter;
 583 
 584 		list_store = GTK_LIST_STORE (
 585 			gtk_combo_box_get_model (combo_file_as));
 586 
 587 		gtk_list_store_clear (list_store);
 588 
 589 		for (l = strings; l; l = l->next) {
 590 			gtk_list_store_append (list_store, &iter);
 591 			gtk_list_store_set (list_store, &iter, 0, l->data, -1);
 592 		}
 593 	}
 594 
 595 	g_list_foreach (strings, (GFunc) g_free, NULL);
 596 	g_list_free (strings);
 597 
 598 	if (style != -1) {
 599 		string = name_to_style (editor->name, company, style);
 600 		set_entry_text (
 601 			editor, GTK_ENTRY (gtk_bin_get_child (
 602 			GTK_BIN (combo_file_as))), string);
 603 		g_free (string);
 604 	}
 605 }
 606 
 607 static void
 608 name_entry_changed (GtkWidget *widget,
 609                     EContactEditor *editor)
 610 {
 611 	gint style = 0;
 612 	const gchar *string;
 613 
 614 	style = file_as_get_style (editor);
 615 	e_contact_name_free (editor->name);
 616 	string = gtk_entry_get_text (GTK_ENTRY (widget));
 617 	editor->name = e_contact_name_from_string (string);
 618 	file_as_set_style (editor, style);
 619 
 620 	editor->check_merge = TRUE;
 621 
 622 	sensitize_ok (editor);
 623 	if (string && !*string)
 624 		gtk_window_set_title (
 625 			GTK_WINDOW (editor->app), _("Contact Editor"));
 626 }
 627 
 628 static void
 629 file_as_combo_changed (GtkWidget *widget,
 630                        EContactEditor *editor)
 631 {
 632 	GtkWidget *entry;
 633 	gchar *string = NULL;
 634 
 635 	entry = gtk_bin_get_child (GTK_BIN (widget));
 636 	if (entry)
 637 		string = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
 638 
 639 	if (string && *string) {
 640 		gchar *title;
 641 		title = g_strdup_printf (_("Contact Editor - %s"), string);
 642 		gtk_window_set_title (GTK_WINDOW (editor->app), title);
 643 		g_free (title);
 644 	}
 645 	else {
 646 		gtk_window_set_title (
 647 			GTK_WINDOW (editor->app), _("Contact Editor"));
 648 	}
 649 	sensitize_ok (editor);
 650 
 651 	g_free (string);
 652 }
 653 
 654 static void
 655 company_entry_changed (GtkWidget *widget,
 656                        EContactEditor *editor)
 657 {
 658 	gint style = 0;
 659 
 660 	style = file_as_get_style (editor);
 661 	file_as_set_style (editor, style);
 662 }
 663 
 664 static void
 665 update_file_as_combo (EContactEditor *editor)
 666 {
 667 	file_as_set_style (editor, file_as_get_style (editor));
 668 }
 669 
 670 static void
 671 fill_in_source_field (EContactEditor *editor)
 672 {
 673 	GtkWidget *source_menu;
 674 
 675 	if (!editor->target_client)
 676 		return;
 677 
 678 	source_menu = e_builder_get_widget (
 679 		editor->builder, "source-combo-box-source");
 680 
 681 	e_source_combo_box_set_active (
 682 		E_SOURCE_COMBO_BOX (source_menu),
 683 		e_client_get_source (E_CLIENT (editor->target_client)));
 684 }
 685 
 686 static void
 687 sensitize_ok (EContactEditor *ce)
 688 {
 689 	GtkWidget *widget;
 690 	gboolean   allow_save;
 691 	GtkWidget *entry_fullname =
 692 		e_builder_get_widget (ce->builder, "entry-fullname");
 693 	GtkWidget *entry_file_as =
 694 		gtk_bin_get_child (GTK_BIN (
 695 		e_builder_get_widget (ce->builder, "combo-file-as")));
 696 	GtkWidget *company_name =
 697 		e_builder_get_widget (ce->builder, "entry-company");
 698 	const gchar *name_entry_string =
 699 		gtk_entry_get_text (GTK_ENTRY (entry_fullname));
 700 	const gchar *file_as_entry_string =
 701 		gtk_entry_get_text (GTK_ENTRY (entry_file_as));
 702 	const gchar *company_name_string =
 703 		gtk_entry_get_text (GTK_ENTRY (company_name));
 704 
 705 	allow_save = ce->target_editable && ce->changed;
 706 
 707 	if (!strcmp (name_entry_string, "") ||
 708 	    !strcmp (file_as_entry_string, "")) {
 709 		if (strcmp (company_name_string , "")) {
 710 			allow_save = TRUE;
 711 		}
 712 		else
 713 			allow_save = FALSE;
 714 	}
 715 	widget = e_builder_get_widget (ce->builder, "button-ok");
 716 	gtk_widget_set_sensitive (widget, allow_save);
 717 }
 718 
 719 static void
 720 object_changed (GObject *object,
 721                 EContactEditor *editor)
 722 {
 723 	if (!editor->target_editable) {
 724 		g_warning ("non-editable contact editor has an editable field in it.");
 725 		return;
 726 	}
 727 
 728 	if (!editor->check_merge && GTK_IS_WIDGET (object)) {
 729 		const gchar *widget_name;
 730 
 731 		widget_name = gtk_widget_get_name (GTK_WIDGET (object));
 732 
 733 		if (widget_name &&
 734 		    ((g_str_equal (widget_name, "fullname")) ||
 735 		     (g_str_equal (widget_name, "nickname")) ||
 736 		     (g_str_equal (widget_name, "file-as")) ||
 737 		     (g_str_has_prefix (widget_name, "email-"))))
 738 			editor->check_merge = TRUE;
 739 	}
 740 
 741 	if (!editor->changed) {
 742 		editor->changed = TRUE;
 743 		sensitize_ok (editor);
 744 	}
 745 }
 746 
 747 static void
 748 image_chooser_changed (GtkWidget *widget,
 749                        EContactEditor *editor)
 750 {
 751 	editor->image_set = TRUE;
 752 	editor->image_changed = TRUE;
 753 }
 754 
 755 static void
 756 set_entry_text (EContactEditor *editor,
 757                 GtkEntry *entry,
 758                 const gchar *string)
 759 {
 760 	const gchar *oldstring = gtk_entry_get_text (entry);
 761 
 762 	if (!string)
 763 		string = "";
 764 
 765 	if (strcmp (string, oldstring)) {
 766 		g_signal_handlers_block_matched (
 767 			entry, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
 768 		gtk_entry_set_text (entry, string);
 769 		g_signal_handlers_unblock_matched (
 770 			entry, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
 771 	}
 772 }
 773 
 774 static void
 775 set_combo_box_active (EContactEditor *editor,
 776                       GtkComboBox *combo_box,
 777                       gint active)
 778 {
 779 	g_signal_handlers_block_matched (
 780 		combo_box, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
 781 	gtk_combo_box_set_active (combo_box, active);
 782 	g_signal_handlers_unblock_matched (
 783 		combo_box, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
 784 }
 785 
 786 static void
 787 init_email_record_location (EContactEditor *editor,
 788                             gint record)
 789 {
 790 	GtkComboBox *location_combo_box;
 791 	GtkWidget *email_entry;
 792 	gchar     *widget_name;
 793 	gint       i;
 794 	GtkTreeIter iter;
 795 	GtkListStore *store;
 796 
 797 	widget_name = g_strdup_printf ("entry-email-%d", record);
 798 	email_entry = e_builder_get_widget (editor->builder, widget_name);
 799 	g_free (widget_name);
 800 
 801 	widget_name = g_strdup_printf ("combobox-email-%d", record);
 802 	location_combo_box = GTK_COMBO_BOX (
 803 		e_builder_get_widget (editor->builder, widget_name));
 804 	g_free (widget_name);
 805 
 806 	store = GTK_LIST_STORE (gtk_combo_box_get_model (location_combo_box));
 807 	gtk_list_store_clear (store);
 808 
 809 	for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
 810 		gtk_list_store_append (store, &iter);
 811 		gtk_list_store_set (
 812 			store, &iter,
 813 			0, _(common_location[i].pretty_name),
 814 			-1);
 815 	}
 816 
 817 	g_signal_connect_swapped (
 818 		location_combo_box, "changed",
 819 		G_CALLBACK (gtk_widget_grab_focus), email_entry);
 820 	g_signal_connect (
 821 		location_combo_box, "changed",
 822 		G_CALLBACK (object_changed), editor);
 823 	g_signal_connect (
 824 		email_entry, "changed",
 825 		G_CALLBACK (object_changed), editor);
 826 	g_signal_connect_swapped (
 827 		email_entry, "activate",
 828 		G_CALLBACK (entry_activated), editor);
 829 }
 830 
 831 static void
 832 fill_in_email_record (EContactEditor *editor,
 833                       gint record,
 834                       const gchar *address,
 835                       gint location)
 836 {
 837 	GtkWidget *location_combo_box;
 838 	GtkWidget *email_entry;
 839 	gchar     *widget_name;
 840 
 841 	widget_name = g_strdup_printf ("combobox-email-%d", record);
 842 	location_combo_box = e_builder_get_widget (editor->builder, widget_name);
 843 	g_free (widget_name);
 844 
 845 	widget_name = g_strdup_printf ("entry-email-%d", record);
 846 	email_entry = e_builder_get_widget (editor->builder, widget_name);
 847 	g_free (widget_name);
 848 
 849 	set_combo_box_active (
 850 		editor, GTK_COMBO_BOX (location_combo_box),
 851 		location >= 0 ? location : email_default[2]);
 852 	set_entry_text (editor, GTK_ENTRY (email_entry), address ? address : "");
 853 }
 854 
 855 static void
 856 extract_email_record (EContactEditor *editor,
 857                       gint record,
 858                       gchar **address,
 859                       gint *location)
 860 {
 861 	GtkWidget *location_combo_box;
 862 	GtkWidget *email_entry;
 863 	gchar *widget_name;
 864 	const gchar *text;
 865 
 866 	widget_name = g_strdup_printf ("combobox-email-%d", record);
 867 	location_combo_box = e_builder_get_widget (editor->builder, widget_name);
 868 	g_free (widget_name);
 869 
 870 	widget_name = g_strdup_printf ("entry-email-%d", record);
 871 	email_entry = e_builder_get_widget (editor->builder, widget_name);
 872 	g_free (widget_name);
 873 
 874 	text = gtk_entry_get_text (GTK_ENTRY (email_entry));
 875 	*address  = g_strstrip (g_strdup (text));
 876 	*location = gtk_combo_box_get_active (GTK_COMBO_BOX (location_combo_box));
 877 }
 878 
 879 static const gchar *
 880 email_index_to_location (gint index)
 881 {
 882 	return common_location[index].name;
 883 }
 884 
 885 static const gchar *
 886 im_index_to_location (gint index)
 887 {
 888 	return common_location[index].name;
 889 }
 890 
 891 static void
 892 phone_index_to_type (gint index,
 893                      const gchar **type_1,
 894                      const gchar **type_2)
 895 {
 896 	*type_1 = phones [index].type_1;
 897 	*type_2 = phones [index].type_2;
 898 }
 899 
 900 static gint
 901 get_email_location (EVCardAttribute *attr)
 902 {
 903 	gint i;
 904 
 905 	for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
 906 		if (e_vcard_attribute_has_type (attr, common_location[i].name))
 907 			return i;
 908 	}
 909 
 910 	return -1;
 911 }
 912 
 913 static gint
 914 get_im_location (EVCardAttribute *attr)
 915 {
 916 	gint i;
 917 
 918 	for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
 919 		if (e_vcard_attribute_has_type (attr, common_location[i].name))
 920 			return i;
 921 	}
 922 
 923 	return -1;
 924 }
 925 
 926 static gint
 927 get_phone_type (EVCardAttribute *attr)
 928 {
 929 	gint i;
 930 
 931 	for (i = 0; i < G_N_ELEMENTS (phones); i++) {
 932 		if (e_vcard_attribute_has_type (attr, phones[i].type_1) &&
 933 			(phones[i].type_2 == NULL ||
 934 			 e_vcard_attribute_has_type (attr, phones[i].type_2)))
 935 			return i;
 936 	}
 937 
 938 	return -1;
 939 }
 940 
 941 static EVCardAttributeParam *
 942 get_ui_slot_param (EVCardAttribute *attr)
 943 {
 944 	EVCardAttributeParam *param = NULL;
 945 	GList                *param_list;
 946 	GList                *l;
 947 
 948 	param_list = e_vcard_attribute_get_params (attr);
 949 
 950 	for (l = param_list; l; l = g_list_next (l)) {
 951 		const gchar *str;
 952 
 953 		param = l->data;
 954 
 955 		str = e_vcard_attribute_param_get_name (param);
 956 		if (!g_ascii_strcasecmp (str, EVOLUTION_UI_SLOT_PARAM))
 957 			break;
 958 
 959 		param = NULL;
 960 	}
 961 
 962 	return param;
 963 }
 964 
 965 static gint
 966 get_ui_slot (EVCardAttribute *attr)
 967 {
 968 	EVCardAttributeParam *param;
 969 	gint                  slot = -1;
 970 
 971 	param = get_ui_slot_param (attr);
 972 
 973 	if (param) {
 974 		GList *value_list;
 975 
 976 		value_list = e_vcard_attribute_param_get_values (param);
 977 		slot = atoi (value_list->data);
 978 	}
 979 
 980 	return slot;
 981 }
 982 
 983 static void
 984 set_ui_slot (EVCardAttribute *attr,
 985              gint slot)
 986 {
 987 	EVCardAttributeParam *param;
 988 	gchar                *slot_str;
 989 
 990 	param = get_ui_slot_param (attr);
 991 	if (!param) {
 992 		param = e_vcard_attribute_param_new (EVOLUTION_UI_SLOT_PARAM);
 993 		e_vcard_attribute_add_param (attr, param);
 994 	}
 995 
 996 	e_vcard_attribute_param_remove_values (param);
 997 
 998 	slot_str = g_strdup_printf ("%d", slot);
 999 	e_vcard_attribute_param_add_value (param, slot_str);
1000 	g_free (slot_str);
1001 }
1002 
1003 static gint
1004 alloc_ui_slot (EContactEditor *editor,
1005                const gchar *widget_base,
1006                gint preferred_slot,
1007                gint num_slots)
1008 {
1009 	gchar       *widget_name;
1010 	GtkWidget   *widget;
1011 	const gchar *entry_contents;
1012 	gint         i;
1013 
1014 	/* See if we can get the preferred slot */
1015 
1016 	if (preferred_slot >= 1) {
1017 		widget_name = g_strdup_printf ("%s-%d", widget_base, preferred_slot);
1018 		widget = e_builder_get_widget (editor->builder, widget_name);
1019 		entry_contents = gtk_entry_get_text (GTK_ENTRY (widget));
1020 		g_free (widget_name);
1021 
1022 		if (STRING_IS_EMPTY (entry_contents))
1023 			return preferred_slot;
1024 	}
1025 
1026 	/* Find first empty slot */
1027 
1028 	for (i = 1; i <= num_slots; i++) {
1029 		widget_name = g_strdup_printf ("%s-%d", widget_base, i);
1030 		widget = e_builder_get_widget (editor->builder, widget_name);
1031 		entry_contents = gtk_entry_get_text (GTK_ENTRY (widget));
1032 		g_free (widget_name);
1033 
1034 		if (STRING_IS_EMPTY (entry_contents))
1035 			return i;
1036 	}
1037 
1038 	return -1;
1039 }
1040 
1041 static void
1042 free_attr_list (GList *attr_list)
1043 {
1044 	GList *l;
1045 
1046 	for (l = attr_list; l; l = g_list_next (l)) {
1047 		EVCardAttribute *attr = l->data;
1048 		e_vcard_attribute_free (attr);
1049 	}
1050 
1051 	g_list_free (attr_list);
1052 }
1053 
1054 static void
1055 fill_in_email (EContactEditor *editor)
1056 {
1057 	GList *email_attr_list;
1058 	GList *l;
1059 	gint   record_n;
1060 
1061 	/* Clear */
1062 
1063 	for (record_n = 1; record_n <= EMAIL_SLOTS; record_n++) {
1064 		fill_in_email_record (
1065 			editor, record_n, NULL, email_default[record_n - 1]);
1066 	}
1067 
1068 	/* Fill in */
1069 
1070 	email_attr_list = e_contact_get_attributes (
1071 		editor->contact, E_CONTACT_EMAIL);
1072 
1073 	for (record_n = 1, l = email_attr_list;
1074 		l && record_n <= EMAIL_SLOTS; l = g_list_next (l)) {
1075 		EVCardAttribute *attr = l->data;
1076 		gchar           *email_address;
1077 		gint             slot;
1078 
1079 		email_address = e_vcard_attribute_get_value (attr);
1080 		slot = alloc_ui_slot (
1081 			editor, "entry-email",
1082 			get_ui_slot (attr), EMAIL_SLOTS);
1083 		if (slot < 1)
1084 			break;
1085 
1086 		fill_in_email_record (
1087 			editor, slot, email_address,
1088 			get_email_location (attr));
1089 
1090 		record_n++;
1091 
1092 		g_free (email_address);
1093 	}
1094 
1095 	g_list_free_full (email_attr_list, (GDestroyNotify) e_vcard_attribute_free);
1096 }
1097 
1098 static void
1099 extract_email (EContactEditor *editor)
1100 {
1101 	GList *attr_list = NULL;
1102 	GList *old_attr_list;
1103 	GList *l, *l_next;
1104 	gint   i;
1105 
1106 	for (i = 1; i <= EMAIL_SLOTS; i++) {
1107 		gchar *address;
1108 		gint   location;
1109 
1110 		extract_email_record (editor, i, &address, &location);
1111 
1112 		if (!STRING_IS_EMPTY (address)) {
1113 			EVCardAttribute *attr;
1114 			attr = e_vcard_attribute_new (
1115 				"", e_contact_vcard_attribute (E_CONTACT_EMAIL));
1116 
1117 			if (location >= 0)
1118 				e_vcard_attribute_add_param_with_value (
1119 					attr,
1120 					e_vcard_attribute_param_new (EVC_TYPE),
1121 					email_index_to_location (location));
1122 
1123 			e_vcard_attribute_add_value (attr, address);
1124 			set_ui_slot (attr, i);
1125 
1126 			attr_list = g_list_append (attr_list, attr);
1127 		}
1128 
1129 		g_free (address);
1130 	}
1131 
1132 	/* Splice in the old attributes, minus the EMAIL_SLOTS first */
1133 
1134 	old_attr_list = e_contact_get_attributes (editor->contact, E_CONTACT_EMAIL);
1135 	for (l = old_attr_list, i = 1; l && i <= EMAIL_SLOTS; l = l_next, i++) {
1136 		l_next = g_list_next (l);
1137 
1138 		e_vcard_attribute_free (l->data);
1139 		l = g_list_delete_link (l, l);
Value stored to 'l' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Value stored to 'l' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1140 } 1141 1142 old_attr_list = l; 1143 attr_list = g_list_concat (attr_list, old_attr_list); 1144 1145 e_contact_set_attributes (editor->contact, E_CONTACT_EMAIL, attr_list); 1146 1147 free_attr_list (attr_list); 1148 } 1149 1150 static void 1151 sensitize_email_record (EContactEditor *editor, 1152 gint record, 1153 gboolean enabled) 1154 { 1155 GtkWidget *location_combo_box; 1156 GtkWidget *email_entry; 1157 gchar *widget_name; 1158 1159 widget_name = g_strdup_printf ("combobox-email-%d", record); 1160 location_combo_box = e_builder_get_widget (editor->builder, widget_name); 1161 g_free (widget_name); 1162 1163 widget_name = g_strdup_printf ("entry-email-%d", record); 1164 email_entry = e_builder_get_widget (editor->builder, widget_name); 1165 g_free (widget_name); 1166 1167 gtk_widget_set_sensitive (location_combo_box, enabled); 1168 gtk_editable_set_editable (GTK_EDITABLE (email_entry), enabled); 1169 } 1170 1171 static void 1172 sensitize_email (EContactEditor *editor) 1173 { 1174 gint i; 1175 1176 for (i = 1; i <= EMAIL_SLOTS; i++) { 1177 gboolean enabled = TRUE; 1178 1179 if (!editor->target_editable) 1180 enabled = FALSE; 1181 1182 if (E_CONTACT_FIRST_EMAIL_ID + i - 1 <= E_CONTACT_LAST_EMAIL_ID && 1183 !is_field_supported (editor, E_CONTACT_FIRST_EMAIL_ID + i - 1)) 1184 enabled = FALSE; 1185 1186 sensitize_email_record (editor, i, enabled); 1187 } 1188 } 1189 1190 static void 1191 init_item_sensitiveable_combo_box (GtkComboBox *combo) 1192 { 1193 GtkCellRenderer *cell; 1194 GtkListStore *store; 1195 1196 g_return_if_fail (combo != NULL); 1197 g_return_if_fail (GTK_IS_COMBO_BOX (combo)); 1198 1199 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN); 1200 gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store)); 1201 g_object_unref (store); 1202 1203 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo)); 1204 1205 cell = gtk_cell_renderer_text_new (); 1206 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE); 1207 gtk_cell_layout_set_attributes ( 1208 GTK_CELL_LAYOUT (combo), cell, 1209 "text", 0, "sensitive", 1, NULL); 1210 } 1211 1212 /* EContact can get attributes by field ID only, 1213 * and there is none for TEL, so we need this */ 1214 static GList * 1215 get_attributes_named (EVCard *vcard, 1216 const gchar *attr_name) 1217 { 1218 GList *attr_list_in; 1219 GList *attr_list_out = NULL; 1220 GList *l; 1221 1222 attr_list_in = e_vcard_get_attributes (vcard); 1223 1224 for (l = attr_list_in; l; l = g_list_next (l)) { 1225 EVCardAttribute *attr = l->data; 1226 const gchar *name; 1227 1228 name = e_vcard_attribute_get_name (attr); 1229 1230 if (!g_ascii_strcasecmp (attr_name, name)) { 1231 attr_list_out = g_list_append ( 1232 attr_list_out, 1233 e_vcard_attribute_copy (attr)); 1234 } 1235 } 1236 1237 return attr_list_out; 1238 } 1239 1240 /* EContact can set attributes by field ID only, 1241 * and there is none for TEL, so we need this */ 1242 static void 1243 set_attributes_named (EVCard *vcard, 1244 const gchar *attr_name, 1245 GList *attr_list) 1246 { 1247 GList *l; 1248 1249 e_vcard_remove_attributes (vcard, NULL, attr_name); 1250 1251 for (l = attr_list; l; l = g_list_next (l)) { 1252 EVCardAttribute *attr = l->data; 1253 1254 e_vcard_add_attribute (vcard, e_vcard_attribute_copy (attr)); 1255 } 1256 } 1257 1258 static void 1259 set_arrow_image (EContactEditor *editor, 1260 const gchar *arrow_widget, 1261 gboolean expanded) 1262 { 1263 GtkWidget *arrow; 1264 1265 arrow = e_builder_get_widget (editor->builder, arrow_widget); 1266 if (expanded) 1267 gtk_arrow_set ( 1268 GTK_ARROW (arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE); 1269 else 1270 gtk_arrow_set ( 1271 GTK_ARROW (arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE); 1272 } 1273 1274 static void 1275 expand_widget_list (EContactEditor *editor, 1276 const gchar **widget_names, 1277 gboolean expanded) 1278 { 1279 gint i; 1280 for (i = 0; widget_names[i]; i++) 1281 gtk_widget_set_visible ( 1282 e_builder_get_widget (editor->builder, widget_names[i]), 1283 expanded); 1284 } 1285 1286 static void 1287 expand_web (EContactEditor *editor, 1288 gboolean expanded) 1289 { 1290 const gchar *names[] = { 1291 "label-videourl", "label-fburl", 1292 "entry-videourl", "entry-fburl", 1293 NULL 1294 }; 1295 set_arrow_image (editor, "arrow-web-expand", expanded); 1296 expand_widget_list (editor, names, expanded); 1297 } 1298 1299 static void 1300 expand_phone (EContactEditor *editor, 1301 gboolean expanded) 1302 { 1303 const gchar *names[] = { 1304 "entry-phone-3", "combobox-phone-3", 1305 "entry-phone-4", "combobox-phone-4", 1306 "table-phone-extended", NULL 1307 }; 1308 set_arrow_image (editor, "arrow-phone-expand", expanded); 1309 expand_widget_list (editor, names, expanded); 1310 } 1311 1312 static void 1313 expand_mail (EContactEditor *editor, 1314 gboolean expanded) 1315 { 1316 GtkTable *table; 1317 GtkWidget *check; 1318 const gchar *names[] = { 1319 "entry-email-2", "combobox-email-2", 1320 "entry-email-3", "combobox-email-3", 1321 "entry-email-4", "combobox-email-4", 1322 NULL 1323 }; 1324 set_arrow_image (editor, "arrow-mail-expand", expanded); 1325 expand_widget_list (editor, names, expanded); 1326 1327 /* move 'use html mail' into position */ 1328 check = e_builder_get_widget (editor->builder, "checkbutton-htmlmail"); 1329 table = GTK_TABLE (e_builder_get_widget (editor->builder, "email-table")); 1330 if (check != NULL && table != NULL) { 1331 GtkWidget *parent; 1332 1333 g_object_ref (check); 1334 parent = gtk_widget_get_parent (check); 1335 gtk_container_remove (GTK_CONTAINER (parent), check); 1336 if (expanded) 1337 gtk_table_attach_defaults (table, check, 0, 4, 2, 3); 1338 else 1339 gtk_table_attach_defaults (table, check, 2, 4, 0, 1); 1340 g_object_unref (check); 1341 } 1342 } 1343 1344 static void 1345 init_email (EContactEditor *editor) 1346 { 1347 gint i; 1348 1349 for (i = 1; i <= EMAIL_SLOTS; i++) 1350 init_email_record_location (editor, i); 1351 1352 expand_mail (editor, !editor->compress_ui); 1353 } 1354 1355 static void 1356 fill_in_phone_record (EContactEditor *editor, 1357 gint record, 1358 const gchar *phone, 1359 gint phone_type) 1360 { 1361 GtkWidget *phone_type_combo_box; 1362 GtkWidget *phone_entry; 1363 gchar *widget_name; 1364 1365 widget_name = g_strdup_printf ("combobox-phone-%d", record); 1366 phone_type_combo_box = e_builder_get_widget (editor->builder, widget_name); 1367 g_free (widget_name); 1368 1369 widget_name = g_strdup_printf ("entry-phone-%d", record); 1370 phone_entry = e_builder_get_widget (editor->builder, widget_name); 1371 g_free (widget_name); 1372 1373 set_combo_box_active ( 1374 editor, GTK_COMBO_BOX (phone_type_combo_box), 1375 phone_type >= 0 ? phone_type : phones_default[record - 1]); 1376 set_entry_text (editor, GTK_ENTRY (phone_entry), phone ? phone : ""); 1377 1378 if (phone && *phone && record >= 3) 1379 expand_phone (editor, TRUE); 1380 } 1381 1382 static void 1383 extract_phone_record (EContactEditor *editor, 1384 gint record, 1385 gchar **phone, 1386 gint *phone_type) 1387 { 1388 GtkWidget *phone_type_combo_box; 1389 GtkWidget *phone_entry; 1390 gchar *widget_name; 1391 1392 widget_name = g_strdup_printf ("combobox-phone-%d", record); 1393 phone_type_combo_box = e_builder_get_widget (editor->builder, widget_name); 1394 g_free (widget_name); 1395 1396 widget_name = g_strdup_printf ("entry-phone-%d", record); 1397 phone_entry = e_builder_get_widget (editor->builder, widget_name); 1398 g_free (widget_name); 1399 1400 *phone = g_strdup (gtk_entry_get_text (GTK_ENTRY (phone_entry))); 1401 *phone_type = gtk_combo_box_get_active (GTK_COMBO_BOX (phone_type_combo_box)); 1402 } 1403 1404 static void 1405 fill_in_phone (EContactEditor *editor) 1406 { 1407 GList *phone_attr_list; 1408 GList *l; 1409 gint record_n; 1410 1411 /* Clear */ 1412 1413 for (record_n = 1; record_n <= PHONE_SLOTS; record_n++) { 1414 fill_in_phone_record (editor, record_n, NULL, -1); 1415 } 1416 1417 /* Fill in */ 1418 1419 phone_attr_list = get_attributes_named (E_VCARD (editor->contact), "TEL"); 1420 1421 for (record_n = 1, l = phone_attr_list; 1422 l && record_n <= PHONE_SLOTS; l = g_list_next (l)) { 1423 EVCardAttribute *attr = l->data; 1424 gchar *phone; 1425 gint slot; 1426 1427 phone = e_vcard_attribute_get_value (attr); 1428 slot = alloc_ui_slot (editor, "entry-phone", get_ui_slot (attr), PHONE_SLOTS); 1429 if (slot < 1) 1430 break; 1431 1432 fill_in_phone_record ( 1433 editor, slot, phone, get_phone_type (attr)); 1434 1435 record_n++; 1436 1437 g_free (phone); 1438 } 1439 } 1440 1441 static void 1442 extract_phone (EContactEditor *editor) 1443 { 1444 GList *attr_list = NULL; 1445 GList *old_attr_list; 1446 GList *l, *l_next; 1447 gint i; 1448 1449 for (i = 1; i <= PHONE_SLOTS; i++) { 1450 gchar *phone; 1451 gint phone_type; 1452 1453 extract_phone_record (editor, i, &phone, &phone_type); 1454 1455 if (!STRING_IS_EMPTY (phone)) { 1456 EVCardAttribute *attr; 1457 1458 attr = e_vcard_attribute_new ("", "TEL"); 1459 1460 if (phone_type >= 0) { 1461 const gchar *type_1; 1462 const gchar *type_2; 1463 1464 phone_index_to_type (phone_type, &type_1, &type_2); 1465 1466 e_vcard_attribute_add_param_with_value ( 1467 attr, e_vcard_attribute_param_new (EVC_TYPE), type_1); 1468 1469 if (type_2) 1470 e_vcard_attribute_add_param_with_value ( 1471 attr, e_vcard_attribute_param_new (EVC_TYPE), type_2); 1472 1473 } 1474 1475 e_vcard_attribute_add_value (attr, phone); 1476 set_ui_slot (attr, i); 1477 1478 attr_list = g_list_append (attr_list, attr); 1479 } 1480 1481 g_free (phone); 1482 } 1483 1484 /* Splice in the old attributes, minus the PHONE_SLOTS first */ 1485 1486 old_attr_list = get_attributes_named (E_VCARD (editor->contact), "TEL"); 1487 for (l = old_attr_list, i = 1; l && i <= PHONE_SLOTS; l = l_next, i++) { 1488 l_next = g_list_next (l); 1489 1490 e_vcard_attribute_free (l->data); 1491 l = g_list_delete_link (l, l);
Value stored to 'l' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Value stored to 'l' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1492 } 1493 1494 old_attr_list = l; 1495 attr_list = g_list_concat (attr_list, old_attr_list); 1496 1497 set_attributes_named (E_VCARD (editor->contact), "TEL", attr_list); 1498 1499 free_attr_list (attr_list); 1500 } 1501 1502 static void 1503 init_phone_record_type (EContactEditor *editor, 1504 gint record) 1505 { 1506 GtkWidget *phone_type_combo_box; 1507 GtkWidget *phone_entry; 1508 gchar *widget_name; 1509 gint i; 1510 GtkListStore *store; 1511 1512 widget_name = g_strdup_printf ("entry-phone-%d", record); 1513 phone_entry = e_builder_get_widget (editor->builder, widget_name); 1514 g_free (widget_name); 1515 1516 widget_name = g_strdup_printf ("combobox-phone-%d", record); 1517 phone_type_combo_box = e_builder_get_widget (editor->builder, widget_name); 1518 g_free (widget_name); 1519 1520 init_item_sensitiveable_combo_box (GTK_COMBO_BOX (phone_type_combo_box)); 1521 1522 store = GTK_LIST_STORE ( 1523 gtk_combo_box_get_model ( 1524 GTK_COMBO_BOX (phone_type_combo_box))); 1525 1526 for (i = 0; i < G_N_ELEMENTS (phones); i++) { 1527 GtkTreeIter iter; 1528 1529 gtk_list_store_append (store, &iter); 1530 gtk_list_store_set ( 1531 store, &iter, 1532 0, e_contact_pretty_name (phones[i].field_id), 1533 1, TRUE, 1534 -1); 1535 } 1536 1537 g_signal_connect_swapped ( 1538 phone_type_combo_box, "changed", 1539 G_CALLBACK (gtk_widget_grab_focus), phone_entry); 1540 g_signal_connect ( 1541 phone_type_combo_box, "changed", 1542 G_CALLBACK (object_changed), editor); 1543 g_signal_connect ( 1544 phone_entry, "changed", 1545 G_CALLBACK (object_changed), editor); 1546 g_signal_connect_swapped ( 1547 phone_entry, "activate", 1548 G_CALLBACK (entry_activated), editor); 1549 } 1550 1551 static void 1552 init_phone (EContactEditor *editor) 1553 { 1554 gint i; 1555 1556 expand_phone (editor, FALSE); 1557 1558 for (i = 1; i <= PHONE_SLOTS; i++) 1559 init_phone_record_type (editor, i); 1560 } 1561 1562 static void 1563 sensitize_phone_types (EContactEditor *editor, 1564 GtkWidget *combo_box) 1565 { 1566 GtkTreeModel *model; 1567 GtkTreeIter iter; 1568 gint i; 1569 gboolean valid; 1570 1571 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); 1572 valid = gtk_tree_model_get_iter_first (model, &iter); 1573 1574 for (i = 0; i < G_N_ELEMENTS (phones); i++) { 1575 if (!valid) { 1576 g_warning (G_STRLOC ": Unexpected end of phone items in combo box"); 1577 return; 1578 } 1579 1580 gtk_list_store_set ( 1581 GTK_LIST_STORE (model), &iter, 1582 1, is_field_supported (editor, phones[i].field_id), 1583 -1); 1584 1585 valid = gtk_tree_model_iter_next (model, &iter); 1586 } 1587 } 1588 1589 static void 1590 sensitize_phone_record (EContactEditor *editor, 1591 gint record, 1592 gboolean enabled) 1593 { 1594 GtkWidget *phone_type_combo_box; 1595 GtkWidget *phone_entry; 1596 gchar *widget_name; 1597 1598 widget_name = g_strdup_printf ("combobox-phone-%d", record); 1599 phone_type_combo_box = e_builder_get_widget (editor->builder, widget_name); 1600 g_free (widget_name); 1601 1602 widget_name = g_strdup_printf ("entry-phone-%d", record); 1603 phone_entry = e_builder_get_widget (editor->builder, widget_name); 1604 g_free (widget_name); 1605 1606 gtk_widget_set_sensitive (phone_type_combo_box, enabled); 1607 gtk_editable_set_editable (GTK_EDITABLE (phone_entry), enabled); 1608 1609 sensitize_phone_types (editor, phone_type_combo_box); 1610 } 1611 1612 static void 1613 sensitize_phone (EContactEditor *editor) 1614 { 1615 gint i; 1616 1617 for (i = 1; i <= PHONE_SLOTS; i++) { 1618 gboolean enabled = TRUE; 1619 1620 if (!editor->target_editable) 1621 enabled = FALSE; 1622 1623 sensitize_phone_record (editor, i, enabled); 1624 } 1625 } 1626 1627 static void 1628 init_im_record_location (EContactEditor *editor, 1629 gint record) 1630 { 1631 1632 #ifdef ENABLE_IM_LOCATION 1633 GtkWidget *location_combo_box; 1634 GtkListStore *store; 1635 gint i; 1636 gchar *widget_name; 1637 1638 widget_name = g_strdup_printf ("combobox-im-location-%d", record); 1639 location_combo_box = e_builder_get_widget (editor->builder, widget_name); 1640 g_free (widget_name); 1641 1642 init_item_sensitiveable_combo_box (GTK_COMBO_BOX (location_combo_box)); 1643 1644 store = GTK_LIST_STORE ( 1645 gtk_combo_box_get_model ( 1646 GTK_COMBO_BOX (location_combo_box))); 1647 1648 for (i = 0; i < G_N_ELEMENTS (common_location); i++) { 1649 GtkTreeIter iter; 1650 1651 gtk_list_store_append (store, &iter); 1652 gtk_list_store_set ( 1653 store, &iter, 1654 0, _(common_location[i].pretty_name), 1655 1, TRUE, 1656 -1); 1657 } 1658 1659 g_signal_connect ( 1660 location_combo_box, "changed", 1661 G_CALLBACK (object_changed), editor); 1662 #endif 1663 } 1664 1665 static void 1666 init_im_record_service (EContactEditor *editor, 1667 gint record) 1668 { 1669 GtkWidget *service_combo_box; 1670 GtkListStore *store; 1671 GtkWidget *name_entry; 1672 gchar *widget_name; 1673 gint i; 1674 1675 widget_name = g_strdup_printf ("entry-im-name-%d", record); 1676 name_entry = e_builder_get_widget (editor->builder, widget_name); 1677 g_free (widget_name); 1678 1679 widget_name = g_strdup_printf ("combobox-im-service-%d", record); 1680 service_combo_box = e_builder_get_widget (editor->builder, widget_name); 1681 g_free (widget_name); 1682 1683 if (editor->compress_ui && record > 2) { 1684 gtk_widget_hide (name_entry); 1685 gtk_widget_hide (service_combo_box); 1686 } 1687 1688 init_item_sensitiveable_combo_box (GTK_COMBO_BOX (service_combo_box)); 1689 1690 store = GTK_LIST_STORE ( 1691 gtk_combo_box_get_model ( 1692 GTK_COMBO_BOX (service_combo_box))); 1693 1694 for (i = 0; i < G_N_ELEMENTS (im_service); i++) { 1695 GtkTreeIter iter; 1696 1697 gtk_list_store_append (store, &iter); 1698 gtk_list_store_set ( 1699 store, &iter, 1700 0, im_service[i].pretty_name, 1701 1, TRUE, 1702 -1); 1703 } 1704 1705 g_signal_connect_swapped ( 1706 service_combo_box, "changed", 1707 G_CALLBACK (gtk_widget_grab_focus), name_entry); 1708 g_signal_connect ( 1709 service_combo_box, "changed", 1710 G_CALLBACK (object_changed), editor); 1711 g_signal_connect ( 1712 name_entry, "changed", 1713 G_CALLBACK (object_changed), editor); 1714 g_signal_connect_swapped ( 1715 name_entry, "activate", 1716 G_CALLBACK (entry_activated), editor); 1717 } 1718 1719 static void 1720 init_im (EContactEditor *editor) 1721 { 1722 gint i; 1723 1724 for (i = 1; i <= IM_SLOTS; i++) { 1725 init_im_record_service (editor, i); 1726 init_im_record_location (editor, i); 1727 } 1728 } 1729 1730 static void 1731 fill_in_im_record (EContactEditor *editor, 1732 gint record, 1733 gint service, 1734 const gchar *name, 1735 gint location) 1736 { 1737 GtkWidget *service_combo_box; 1738 #ifdef ENABLE_IM_LOCATION 1739 GtkWidget *location_combo_box; 1740 #endif 1741 GtkWidget *name_entry; 1742 gchar *widget_name; 1743 1744 widget_name = g_strdup_printf ("combobox-im-service-%d", record); 1745 service_combo_box = e_builder_get_widget (editor->builder, widget_name); 1746 g_free (widget_name); 1747 1748 #ifdef ENABLE_IM_LOCATION 1749 widget_name = g_strdup_printf ("combobox-im-location-%d", record); 1750 location_combo_box = e_builder_get_widget (editor->builder, widget_name); 1751 g_free (widget_name); 1752 #endif 1753 1754 widget_name = g_strdup_printf ("entry-im-name-%d", record); 1755 name_entry = e_builder_get_widget (editor->builder, widget_name); 1756 g_free (widget_name); 1757 1758 #ifdef ENABLE_IM_LOCATION 1759 set_combo_box_active ( 1760 editor, GTK_COMBO_BOX (location_combo_box), 1761 location >= 0 ? location : 0); 1762 #endif 1763 set_combo_box_active ( 1764 editor, GTK_COMBO_BOX (service_combo_box), 1765 service >= 0 ? service : im_service_default[record - 1]); 1766 set_entry_text (editor, GTK_ENTRY (name_entry), name ? name : ""); 1767 } 1768 1769 static void 1770 fill_in_im (EContactEditor *editor) 1771 { 1772 GList *im_attr_list; 1773 GList *l; 1774 gint record_n; 1775 gint i; 1776 1777 /* Clear */ 1778 1779 for (record_n = 1; record_n <= IM_SLOTS; record_n++) { 1780 fill_in_im_record (editor, record_n, -1, NULL, -1); 1781 } 1782 1783 /* Fill in */ 1784 1785 for (record_n = 1, i = 0; i < G_N_ELEMENTS (im_service); i++) { 1786 im_attr_list = e_contact_get_attributes (editor->contact, im_service[i].field); 1787 1788 for (l = im_attr_list; l && record_n <= IM_SLOTS; l = g_list_next (l)) { 1789 EVCardAttribute *attr = l->data; 1790 gchar *im_name; 1791 gint slot; 1792 1793 im_name = e_vcard_attribute_get_value (attr); 1794 slot = alloc_ui_slot ( 1795 editor, "entry-im-name", 1796 get_ui_slot (attr), IM_SLOTS); 1797 if (slot < 1) 1798 break; 1799 1800 fill_in_im_record ( 1801 editor, slot, i, im_name, 1802 get_im_location (attr)); 1803 1804 record_n++; 1805 1806 g_free (im_name); 1807 } 1808 1809 g_list_free_full (im_attr_list, (GDestroyNotify) e_vcard_attribute_free); 1810 } 1811 } 1812 1813 static void 1814 extract_im_record (EContactEditor *editor, 1815 gint record, 1816 gint *service, 1817 gchar **name, 1818 gint *location) 1819 { 1820 GtkWidget *service_combo_box; 1821 #ifdef ENABLE_IM_LOCATION 1822 GtkWidget *location_combo_box; 1823 #endif 1824 GtkWidget *name_entry; 1825 gchar *widget_name; 1826 1827 widget_name = g_strdup_printf ("combobox-im-service-%d", record); 1828 service_combo_box = e_builder_get_widget (editor->builder, widget_name); 1829 g_free (widget_name); 1830 1831 #ifdef ENABLE_IM_LOCATION 1832 widget_name = g_strdup_printf ("combobox-im-location-%d", record); 1833 location_combo_box = e_builder_get_widget (editor->builder, widget_name); 1834 g_free (widget_name); 1835 #endif 1836 1837 widget_name = g_strdup_printf ("entry-im-name-%d", record); 1838 name_entry = e_builder_get_widget (editor->builder, widget_name); 1839 g_free (widget_name); 1840 1841 *name = g_strdup (gtk_entry_get_text (GTK_ENTRY (name_entry))); 1842 *service = gtk_combo_box_get_active (GTK_COMBO_BOX (service_combo_box)); 1843 #ifdef ENABLE_IM_LOCATION 1844 *location = gtk_combo_box_get_active (GTK_COMBO_BOX (location_combo_box)); 1845 #else 1846 *location = 1; /* set everything to HOME */ 1847 #endif 1848 } 1849 1850 static void 1851 extract_im (EContactEditor *editor) 1852 { 1853 GList **service_attr_list; 1854 gint remaining_slots = IM_SLOTS; 1855 gint i; 1856 1857 service_attr_list = g_new0 (GList *, G_N_ELEMENTS (im_service)); 1858 1859 for (i = 1; i <= IM_SLOTS; i++) { 1860 EVCardAttribute *attr; 1861 gchar *name; 1862 gint service; 1863 gint location; 1864 1865 extract_im_record (editor, i, &service, &name, &location); 1866 1867 if (!STRING_IS_EMPTY (name)) { 1868 attr = e_vcard_attribute_new ( 1869 "", e_contact_vcard_attribute ( 1870 im_service[service].field)); 1871 1872 if (location >= 0) 1873 e_vcard_attribute_add_param_with_value ( 1874 attr, 1875 e_vcard_attribute_param_new (EVC_TYPE), 1876 im_index_to_location (location)); 1877 1878 e_vcard_attribute_add_value (attr, name); 1879 set_ui_slot (attr, i); 1880 1881 service_attr_list[service] = g_list_append ( 1882 service_attr_list[service], attr); 1883 } 1884 1885 g_free (name); 1886 } 1887 1888 for (i = 0; i < G_N_ELEMENTS (im_service); i++) { 1889 GList *old_service_attr_list; 1890 gint filled_in_slots; 1891 GList *l, *l_next; 1892 gint j; 1893 1894 /* Splice in the old attributes, minus the filled_in_slots first */ 1895 1896 old_service_attr_list = e_contact_get_attributes ( 1897 editor->contact, im_service[i].field); 1898 filled_in_slots = MIN ( 1899 remaining_slots, 1900 g_list_length (old_service_attr_list)); 1901 remaining_slots -= filled_in_slots; 1902 1903 for (l = old_service_attr_list, j = 0; 1904 l && j < filled_in_slots; l = l_next, j++) { 1905 l_next = g_list_next (l); 1906 1907 e_vcard_attribute_free (l->data); 1908 l = g_list_delete_link (l, l);
Value stored to 'l' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Value stored to 'l' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1909 } 1910 1911 old_service_attr_list = l; 1912 service_attr_list[i] = g_list_concat ( 1913 service_attr_list[i], old_service_attr_list); 1914 1915 e_contact_set_attributes ( 1916 editor->contact, 1917 im_service[i].field, 1918 service_attr_list[i]); 1919 1920 free_attr_list (service_attr_list[i]); 1921 } 1922 1923 g_free (service_attr_list); 1924 } 1925 1926 static void 1927 sensitize_im_types (EContactEditor *editor, 1928 GtkWidget *combo_box) 1929 { 1930 GtkTreeModel *model; 1931 GtkTreeIter iter; 1932 gint i; 1933 gboolean valid; 1934 1935 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)); 1936 valid = gtk_tree_model_get_iter_first (model, &iter); 1937 1938 for (i = 0; i < G_N_ELEMENTS (im_service); i++) { 1939 if (!valid) { 1940 g_warning (G_STRLOC ": Unexpected end of im items in combo box"); 1941 return; 1942 } 1943 1944 gtk_list_store_set ( 1945 GTK_LIST_STORE (model), &iter, 1946 1, is_field_supported (editor, im_service[i].field), 1947 -1); 1948 1949 valid = gtk_tree_model_iter_next (model, &iter); 1950 } 1951 } 1952 1953 static void 1954 sensitize_im_record (EContactEditor *editor, 1955 gint record, 1956 gboolean enabled) 1957 { 1958 GtkWidget *service_combo_box; 1959 #ifdef ENABLE_IM_LOCATION 1960 GtkWidget *location_combo_box; 1961 #endif 1962 GtkWidget *name_entry; 1963 gchar *widget_name; 1964 1965 widget_name = g_strdup_printf ("combobox-im-service-%d", record); 1966 service_combo_box = e_builder_get_widget (editor->builder, widget_name); 1967 g_free (widget_name); 1968 1969 #ifdef ENABLE_IM_LOCATION 1970 widget_name = g_strdup_printf ("combobox-im-location-%d", record); 1971 location_combo_box = e_builder_get_widget (editor->builder, widget_name); 1972 g_free (widget_name); 1973 #endif 1974 1975 widget_name = g_strdup_printf ("entry-im-name-%d", record); 1976 name_entry = e_builder_get_widget (editor->builder, widget_name); 1977 g_free (widget_name); 1978 1979 gtk_widget_set_sensitive (service_combo_box, enabled); 1980 #ifdef ENABLE_IM_LOCATION 1981 gtk_widget_set_sensitive (location_combo_box, enabled); 1982 #endif 1983 gtk_editable_set_editable (GTK_EDITABLE (name_entry), enabled); 1984 sensitize_im_types (editor, service_combo_box); 1985 } 1986 1987 static void 1988 sensitize_im (EContactEditor *editor) 1989 { 1990 gint i; 1991 gboolean enabled; 1992 gboolean no_ims_supported; 1993 1994 enabled = editor->target_editable; 1995 no_ims_supported = TRUE; 1996 1997 for (i = 0; i < G_N_ELEMENTS (im_service); i++) 1998 if (is_field_supported (editor, im_service[i].field)) { 1999 no_ims_supported = FALSE; 2000 break; 2001 } 2002 2003 if (no_ims_supported) 2004 enabled = FALSE; 2005 2006 for (i = 1; i <= IM_SLOTS; i++) { 2007 sensitize_im_record (editor, i, enabled); 2008 } 2009 } 2010 2011 static void 2012 init_personal (EContactEditor *editor) 2013 { 2014 gtk_expander_set_expanded ( 2015 GTK_EXPANDER (e_builder_get_widget ( 2016 editor->builder, "expander-personal-misc")), 2017 !editor->compress_ui); 2018 2019 expand_web (editor, !editor->compress_ui); 2020 } 2021 2022 static void 2023 init_address_textview (EContactEditor *editor, 2024 gint record) 2025 { 2026 gchar *textview_name; 2027 GtkWidget *textview; 2028 GtkTextBuffer *text_buffer; 2029 2030 textview_name = g_strdup_printf ( 2031 "textview-%s-address", address_name[record]); 2032 textview = e_builder_get_widget (editor->builder, textview_name); 2033 g_free (textview_name); 2034 2035 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); 2036 2037 g_signal_connect ( 2038 text_buffer, "changed", 2039 G_CALLBACK (object_changed), editor); 2040 } 2041 2042 static void 2043 init_address_field (EContactEditor *editor, 2044 gint record, 2045 const gchar *widget_field_name) 2046 { 2047 gchar *entry_name; 2048 GtkWidget *entry; 2049 2050 entry_name = g_strdup_printf ( 2051 "entry-%s-%s", address_name[record], widget_field_name); 2052 entry = e_builder_get_widget (editor->builder, entry_name); 2053 g_free (entry_name); 2054 2055 g_signal_connect ( 2056 entry, "changed", 2057 G_CALLBACK (object_changed), editor); 2058 g_signal_connect_swapped ( 2059 entry, "activate", 2060 G_CALLBACK (entry_activated), editor); 2061 } 2062 2063 static void 2064 init_address_record (EContactEditor *editor, 2065 gint record) 2066 { 2067 init_address_textview (editor, record); 2068 init_address_field (editor, record, "city"); 2069 init_address_field (editor, record, "state"); 2070 init_address_field (editor, record, "zip"); 2071 init_address_field (editor, record, "country"); 2072 init_address_field (editor, record, "pobox"); 2073 } 2074 2075 static void 2076 init_address (EContactEditor *editor) 2077 { 2078 gint i; 2079 2080 for (i = 0; i < ADDRESS_SLOTS; i++) 2081 init_address_record (editor, i); 2082 2083 gtk_expander_set_expanded ( 2084 GTK_EXPANDER (e_builder_get_widget ( 2085 editor->builder, "expander-address-other")), 2086 !editor->compress_ui); 2087 } 2088 2089 static void 2090 fill_in_address_textview (EContactEditor *editor, 2091 gint record, 2092 EContactAddress *address) 2093 { 2094 gchar *textview_name; 2095 GtkWidget *textview; 2096 GtkTextBuffer *text_buffer; 2097 GtkTextIter iter_end, iter_start; 2098 2099 textview_name = g_strdup_printf ("textview-%s-address", address_name[record]); 2100 textview = e_builder_get_widget (editor->builder, textview_name); 2101 g_free (textview_name); 2102 2103 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); 2104 gtk_text_buffer_set_text (text_buffer, address->street ? address->street : "", -1); 2105 2106 gtk_text_buffer_get_end_iter (text_buffer, &iter_end); 2107 if (address->ext && *address->ext) { 2108 gtk_text_buffer_insert (text_buffer, &iter_end, "\n", -1); 2109 gtk_text_buffer_insert (text_buffer, &iter_end, address->ext, -1); 2110 } else { 2111 gtk_text_buffer_insert (text_buffer, &iter_end, "", -1); 2112 } 2113 gtk_text_buffer_get_iter_at_line (text_buffer, &iter_start, 0); 2114 gtk_text_buffer_place_cursor (text_buffer, &iter_start); 2115 } 2116 2117 static void 2118 fill_in_address_label_textview (EContactEditor *editor, 2119 gint record, 2120 const gchar *label) 2121 { 2122 gchar *textview_name; 2123 GtkWidget *textview; 2124 GtkTextBuffer *text_buffer; 2125 2126 textview_name = g_strdup_printf ( 2127 "textview-%s-address", address_name[record]); 2128 textview = e_builder_get_widget (editor->builder, textview_name); 2129 g_free (textview_name); 2130 2131 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); 2132 gtk_text_buffer_set_text (text_buffer, label ? label : "", -1); 2133 } 2134 2135 static void 2136 fill_in_address_field (EContactEditor *editor, 2137 gint record, 2138 const gchar *widget_field_name, 2139 const gchar *string) 2140 { 2141 gchar *entry_name; 2142 GtkWidget *entry; 2143 2144 entry_name = g_strdup_printf ( 2145 "entry-%s-%s", address_name[record], widget_field_name); 2146 entry = e_builder_get_widget (editor->builder, entry_name); 2147 g_free (entry_name); 2148 2149 set_entry_text (editor, GTK_ENTRY (entry), string); 2150 } 2151 2152 static void 2153 fill_in_address_record (EContactEditor *editor, 2154 gint record) 2155 { 2156 EContactAddress *address; 2157 gchar *address_label; 2158 2159 address = e_contact_get (editor->contact, addresses[record]); 2160 address_label = e_contact_get (editor->contact, address_labels[record]); 2161 2162 if (address && 2163 (!STRING_IS_EMPTY (address->street) || 2164 !STRING_IS_EMPTY (address->ext) || 2165 !STRING_IS_EMPTY (address->locality) || 2166 !STRING_IS_EMPTY (address->region) || 2167 !STRING_IS_EMPTY (address->code) || 2168 !STRING_IS_EMPTY (address->po) || 2169 !STRING_IS_EMPTY (address->country))) { 2170 fill_in_address_textview (editor, record, address); 2171 fill_in_address_field (editor, record, "city", address->locality); 2172 fill_in_address_field (editor, record, "state", address->region); 2173 fill_in_address_field (editor, record, "zip", address->code); 2174 fill_in_address_field (editor, record, "country", address->country); 2175 fill_in_address_field (editor, record, "pobox", address->po); 2176 } else if (!STRING_IS_EMPTY (address_label)) { 2177 fill_in_address_label_textview (editor, record, address_label); 2178 } 2179 2180 g_free (address_label); 2181 if (address) 2182 g_boxed_free (e_contact_address_get_type (), address); 2183 } 2184 2185 static void 2186 fill_in_address (EContactEditor *editor) 2187 { 2188 gint i; 2189 2190 for (i = 0; i < ADDRESS_SLOTS; i++) 2191 fill_in_address_record (editor, i); 2192 } 2193 2194 static void 2195 extract_address_textview (EContactEditor *editor, 2196 gint record, 2197 EContactAddress *address) 2198 { 2199 gchar *textview_name; 2200 GtkWidget *textview; 2201 GtkTextBuffer *text_buffer; 2202 GtkTextIter iter_1, iter_2; 2203 2204 textview_name = g_strdup_printf ("textview-%s-address", address_name[record]); 2205 textview = e_builder_get_widget (editor->builder, textview_name); 2206 g_free (textview_name); 2207 2208 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); 2209 gtk_text_buffer_get_start_iter (text_buffer, &iter_1); 2210 2211 /* Skip blank lines */ 2212 while (gtk_text_iter_get_chars_in_line (&iter_1) < 1 && 2213 !gtk_text_iter_is_end (&iter_1)) 2214 gtk_text_iter_forward_line (&iter_1); 2215 2216 if (gtk_text_iter_is_end (&iter_1)) 2217 return; 2218 2219 iter_2 = iter_1; 2220 gtk_text_iter_forward_to_line_end (&iter_2); 2221 2222 /* Extract street (first line of text) */ 2223 address->street = gtk_text_iter_get_text (&iter_1, &iter_2); 2224 2225 iter_1 = iter_2; 2226 gtk_text_iter_forward_line (&iter_1); 2227 2228 if (gtk_text_iter_is_end (&iter_1)) 2229 return; 2230 2231 gtk_text_iter_forward_to_end (&iter_2); 2232 2233 /* Extract extended address (remaining lines of text) */ 2234 address->ext = gtk_text_iter_get_text (&iter_1, &iter_2); 2235 } 2236 2237 static gchar * 2238 extract_address_field (EContactEditor *editor, 2239 gint record, 2240 const gchar *widget_field_name) 2241 { 2242 gchar *entry_name; 2243 GtkWidget *entry; 2244 2245 entry_name = g_strdup_printf ( 2246 "entry-%s-%s", address_name[record], widget_field_name); 2247 entry = e_builder_get_widget (editor->builder, entry_name); 2248 g_free (entry_name); 2249 2250 return g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); 2251 } 2252 2253 static gchar * 2254 append_to_address_label (gchar *address_label, 2255 const gchar *part, 2256 gboolean newline) 2257 { 2258 gchar *new_address_label; 2259 2260 if (STRING_IS_EMPTY (part)) 2261 return address_label; 2262 2263 if (address_label) 2264 new_address_label = g_strjoin ( 2265 newline ? "\n" : ", ", 2266 address_label, part, NULL); 2267 else 2268 new_address_label = g_strdup (part); 2269 2270 g_free (address_label); 2271 return new_address_label; 2272 } 2273 2274 static void 2275 set_address_label (EContact *contact, 2276 EContactField field, 2277 EContactAddress *address) 2278 { 2279 gchar *address_label = NULL; 2280 gboolean format_address; 2281 GSettings *settings; 2282 2283 if (!address) { 2284 e_contact_set (contact, field, NULL); 2285 return; 2286 } 2287 2288 settings = g_settings_new ("org.gnome.evolution.addressbook"); 2289 format_address = g_settings_get_boolean (settings, "address-formatting"); 2290 g_object_unref (settings); 2291 2292 if (format_address) { 2293 address_label = eab_format_address ( 2294 contact, 2295 (field == E_CONTACT_ADDRESS_LABEL_WORK) ? 2296 E_CONTACT_ADDRESS_WORK : 2297 E_CONTACT_ADDRESS_HOME); 2298 } 2299 2300 if (!format_address || !address_label) { 2301 address_label = append_to_address_label ( 2302 address_label, address->street, TRUE); 2303 address_label = append_to_address_label ( 2304 address_label, address->ext, TRUE); 2305 address_label = append_to_address_label ( 2306 address_label, address->locality, TRUE); 2307 address_label = append_to_address_label ( 2308 address_label, address->region, FALSE); 2309 address_label = append_to_address_label ( 2310 address_label, address->code, TRUE); 2311 address_label = append_to_address_label ( 2312 address_label, address->po, TRUE); 2313 address_label = append_to_address_label ( 2314 address_label, address->country, TRUE); 2315 } 2316 2317 e_contact_set (contact, field, address_label); 2318 g_free (address_label); 2319 } 2320 2321 static void 2322 extract_address_record (EContactEditor *editor, 2323 gint record) 2324 { 2325 EContactAddress *address; 2326 2327 address = g_new0 (EContactAddress, 1); 2328 2329 extract_address_textview (editor, record, address); 2330 address->locality = extract_address_field (editor, record, "city"); 2331 address->region = extract_address_field (editor, record, "state"); 2332 address->code = extract_address_field (editor, record, "zip"); 2333 address->country = extract_address_field (editor, record, "country"); 2334 address->po = extract_address_field (editor, record, "pobox"); 2335 2336 if (!STRING_IS_EMPTY (address->street) || 2337 !STRING_IS_EMPTY (address->ext) || 2338 !STRING_IS_EMPTY (address->locality) || 2339 !STRING_IS_EMPTY (address->region) || 2340 !STRING_IS_EMPTY (address->code) || 2341 !STRING_IS_EMPTY (address->po) || 2342 !STRING_IS_EMPTY (address->country)) { 2343 e_contact_set (editor->contact, addresses[record], address); 2344 set_address_label (editor->contact, address_labels[record], address); 2345 } 2346 else { 2347 e_contact_set (editor->contact, addresses[record], NULL); 2348 set_address_label (editor->contact, address_labels[record], NULL); 2349 } 2350 2351 g_boxed_free (e_contact_address_get_type (), address); 2352 } 2353 2354 static void 2355 extract_address (EContactEditor *editor) 2356 { 2357 gint i; 2358 2359 for (i = 0; i < ADDRESS_SLOTS; i++) 2360 extract_address_record (editor, i); 2361 } 2362 2363 static void 2364 sensitize_address_textview (EContactEditor *editor, 2365 gint record, 2366 gboolean enabled) 2367 { 2368 gchar *widget_name; 2369 GtkWidget *textview; 2370 GtkWidget *label; 2371 2372 widget_name = g_strdup_printf ("textview-%s-address", address_name[record]); 2373 textview = e_builder_get_widget (editor->builder, widget_name); 2374 g_free (widget_name); 2375 2376 widget_name = g_strdup_printf ("label-%s-address", address_name[record]); 2377 label = e_builder_get_widget (editor->builder, widget_name); 2378 g_free (widget_name); 2379 2380 gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), enabled); 2381 gtk_widget_set_sensitive (label, enabled); 2382 } 2383 2384 static void 2385 sensitize_address_field (EContactEditor *editor, 2386 gint record, 2387 const gchar *widget_field_name, 2388 gboolean enabled) 2389 { 2390 gchar *widget_name; 2391 GtkWidget *entry; 2392 GtkWidget *label; 2393 2394 widget_name = g_strdup_printf ( 2395 "entry-%s-%s", address_name[record], widget_field_name); 2396 entry = e_builder_get_widget (editor->builder, widget_name); 2397 g_free (widget_name); 2398 2399 widget_name = g_strdup_printf ( 2400 "label-%s-%s", address_name[record], widget_field_name); 2401 label = e_builder_get_widget (editor->builder, widget_name); 2402 g_free (widget_name); 2403 2404 gtk_editable_set_editable (GTK_EDITABLE (entry), enabled); 2405 gtk_widget_set_sensitive (label, enabled); 2406 } 2407 2408 static void 2409 sensitize_address_record (EContactEditor *editor, 2410 gint record, 2411 gboolean enabled) 2412 { 2413 sensitize_address_textview (editor, record, enabled); 2414 sensitize_address_field (editor, record, "city", enabled); 2415 sensitize_address_field (editor, record, "state", enabled); 2416 sensitize_address_field (editor, record, "zip", enabled); 2417 sensitize_address_field (editor, record, "country", enabled); 2418 sensitize_address_field (editor, record, "pobox", enabled); 2419 } 2420 2421 static void 2422 sensitize_address (EContactEditor *editor) 2423 { 2424 gint i; 2425 2426 for (i = 0; i < ADDRESS_SLOTS; i++) { 2427 gboolean enabled = TRUE; 2428 2429 if (!editor->target_editable || 2430 !(is_field_supported (editor, addresses[i]) || 2431 is_field_supported (editor, address_labels[i]))) 2432 enabled = FALSE; 2433 2434 sensitize_address_record (editor, i, enabled); 2435 } 2436 } 2437 2438 typedef struct { 2439 const gchar *widget_name; 2440 gint field_id; /* EContactField or -1 */ 2441 gboolean process_data; /* If we should extract/fill in contents */ 2442 gboolean desensitize_for_read_only; 2443 } 2444 FieldMapping; 2445 2446 /* Table of widgets that interact with simple fields. This table is used to: 2447 * 2448 * - Fill in data. 2449 * - Extract data. 2450 * - Set sensitivity based on backend capabilities. 2451 * - Set sensitivity based on book writeability. */ 2452 2453 static FieldMapping simple_field_map[] = { 2454 { "entry-homepage", E_CONTACT_HOMEPAGE_URL, TRUE, TRUE }, 2455 { "accellabel-homepage", E_CONTACT_HOMEPAGE_URL, FALSE, TRUE }, 2456 2457 { "entry-jobtitle", E_CONTACT_TITLE, TRUE, TRUE }, 2458 { "label-jobtitle", E_CONTACT_TITLE, FALSE, TRUE }, 2459 2460 { "entry-company", E_CONTACT_ORG, TRUE, TRUE }, 2461 { "label-company", E_CONTACT_ORG, FALSE, TRUE }, 2462 2463 { "entry-department", E_CONTACT_ORG_UNIT, TRUE, TRUE }, 2464 { "label-department", E_CONTACT_ORG_UNIT, FALSE, TRUE }, 2465 2466 { "entry-profession", E_CONTACT_ROLE, TRUE, TRUE }, 2467 { "label-profession", E_CONTACT_ROLE, FALSE, TRUE }, 2468 2469 { "entry-manager", E_CONTACT_MANAGER, TRUE, TRUE }, 2470 { "label-manager", E_CONTACT_MANAGER, FALSE, TRUE }, 2471 2472 { "entry-assistant", E_CONTACT_ASSISTANT, TRUE, TRUE }, 2473 { "label-assistant", E_CONTACT_ASSISTANT, FALSE, TRUE }, 2474 2475 { "entry-nickname", E_CONTACT_NICKNAME, TRUE, TRUE }, 2476 { "label-nickname", E_CONTACT_NICKNAME, FALSE, TRUE }, 2477 2478 { "dateedit-birthday", E_CONTACT_BIRTH_DATE, TRUE, TRUE }, 2479 { "label-birthday", E_CONTACT_BIRTH_DATE, FALSE, TRUE }, 2480 2481 { "dateedit-anniversary", E_CONTACT_ANNIVERSARY, TRUE, TRUE }, 2482 { "label-anniversary", E_CONTACT_ANNIVERSARY, FALSE, TRUE }, 2483 2484 { "entry-spouse", E_CONTACT_SPOUSE, TRUE, TRUE }, 2485 { "label-spouse", E_CONTACT_SPOUSE, FALSE, TRUE }, 2486 2487 { "entry-office", E_CONTACT_OFFICE, TRUE, TRUE }, 2488 { "label-office", E_CONTACT_OFFICE, FALSE, TRUE }, 2489 2490 { "text-comments", E_CONTACT_NOTE, TRUE, TRUE }, 2491 2492 { "entry-fullname", E_CONTACT_FULL_NAME, TRUE, TRUE }, 2493 { "button-fullname", E_CONTACT_FULL_NAME, FALSE, TRUE }, 2494 2495 { "entry-categories", E_CONTACT_CATEGORIES, TRUE, TRUE }, 2496 { "button-categories", E_CONTACT_CATEGORIES, FALSE, TRUE }, 2497 2498 { "entry-weblog", E_CONTACT_BLOG_URL, TRUE, TRUE }, 2499 { "label-weblog", E_CONTACT_BLOG_URL, FALSE, TRUE }, 2500 2501 { "entry-caluri", E_CONTACT_CALENDAR_URI, TRUE, TRUE }, 2502 { "label-caluri", E_CONTACT_CALENDAR_URI, FALSE, TRUE }, 2503 2504 { "entry-fburl", E_CONTACT_FREEBUSY_URL, TRUE, TRUE }, 2505 { "label-fburl", E_CONTACT_FREEBUSY_URL, FALSE, TRUE }, 2506 2507 { "entry-videourl", E_CONTACT_VIDEO_URL, TRUE, TRUE }, 2508 { "label-videourl", E_CONTACT_VIDEO_URL, FALSE, TRUE }, 2509 2510 { "checkbutton-htmlmail", E_CONTACT_WANTS_HTML, TRUE, TRUE }, 2511 2512 { "image-chooser", E_CONTACT_PHOTO, TRUE, TRUE }, 2513 { "button-image", E_CONTACT_PHOTO, FALSE, TRUE }, 2514 2515 { "combo-file-as", E_CONTACT_FILE_AS, TRUE, TRUE }, 2516 { "accellabel-fileas", E_CONTACT_FILE_AS, FALSE, TRUE }, 2517 }; 2518 2519 static void 2520 init_simple_field (EContactEditor *editor, 2521 GtkWidget *widget) 2522 { 2523 GObject *changed_object = NULL; 2524 2525 if (GTK_IS_ENTRY (widget)) { 2526 changed_object = G_OBJECT (widget); 2527 g_signal_connect_swapped ( 2528 widget, "activate", 2529 G_CALLBACK (entry_activated), editor); 2530 2531 } else if (GTK_IS_COMBO_BOX (widget)) { 2532 changed_object = G_OBJECT (widget); 2533 g_signal_connect_swapped ( 2534 gtk_bin_get_child (GTK_BIN (widget)), "activate", 2535 G_CALLBACK (entry_activated), editor); 2536 2537 } else if (GTK_IS_TEXT_VIEW (widget)) { 2538 changed_object = G_OBJECT ( 2539 gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget))); 2540 2541 } else if (E_IS_URL_ENTRY (widget)) { 2542 changed_object = G_OBJECT ( 2543 e_url_entry_get_entry (E_URL_ENTRY (widget))); 2544 g_signal_connect_swapped ( 2545 changed_object, "activate", 2546 G_CALLBACK (entry_activated), editor); 2547 2548 } else if (E_IS_DATE_EDIT (widget)) { 2549 changed_object = G_OBJECT (widget); 2550 2551 } else if (E_IS_IMAGE_CHOOSER (widget)) { 2552 changed_object = G_OBJECT (widget); 2553 g_signal_connect ( 2554 widget, "changed", 2555 G_CALLBACK (image_chooser_changed), editor); 2556 2557 } else if (GTK_IS_TOGGLE_BUTTON (widget)) { 2558 g_signal_connect ( 2559 widget, "toggled", 2560 G_CALLBACK (object_changed), editor); 2561 } 2562 2563 if (changed_object) 2564 g_signal_connect ( 2565 changed_object, "changed", 2566 G_CALLBACK (object_changed), editor); 2567 } 2568 2569 static void 2570 fill_in_simple_field (EContactEditor *editor, 2571 GtkWidget *widget, 2572 gint field_id) 2573 { 2574 EContact *contact; 2575 2576 contact = editor->contact; 2577 2578 g_signal_handlers_block_matched ( 2579 widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor); 2580 2581 if (GTK_IS_ENTRY (widget)) { 2582 gchar *text = e_contact_get (contact, field_id); 2583 gtk_entry_set_text (GTK_ENTRY (widget), STRING_MAKE_NON_NULL (text)); 2584 g_free (text); 2585 2586 } else if (GTK_IS_COMBO_BOX (widget)) { 2587 gchar *text = e_contact_get (contact, field_id); 2588 gtk_entry_set_text ( 2589 GTK_ENTRY (gtk_bin_get_child (GTK_BIN (widget))), 2590 STRING_MAKE_NON_NULL (text)); 2591 g_free (text); 2592 2593 } else if (GTK_IS_TEXT_VIEW (widget)) { 2594 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget)); 2595 gchar *text = e_contact_get (contact, field_id); 2596 gtk_text_buffer_set_text (buffer, STRING_MAKE_NON_NULL (text), -1); 2597 g_free (text); 2598 2599 } else if (E_IS_URL_ENTRY (widget)) { 2600 GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget)); 2601 gchar *text = e_contact_get (contact, field_id); 2602 gtk_entry_set_text (GTK_ENTRY (entry), STRING_MAKE_NON_NULL (text)); 2603 g_free (text); 2604 2605 } else if (E_IS_DATE_EDIT (widget)) { 2606 EContactDate *date = e_contact_get (contact, field_id); 2607 if (date) 2608 e_date_edit_set_date ( 2609 E_DATE_EDIT (widget), 2610 date->year, date->month, date->day); 2611 else 2612 e_date_edit_set_time (E_DATE_EDIT (widget), -1); 2613 2614 e_contact_date_free (date); 2615 2616 } else if (E_IS_IMAGE_CHOOSER (widget)) { 2617 EContactPhoto *photo = e_contact_get (contact, field_id); 2618 editor->image_set = FALSE; 2619 if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) { 2620 e_image_chooser_set_image_data ( 2621 E_IMAGE_CHOOSER (widget), 2622 (gchar *) photo->data.inlined.data, 2623 photo->data.inlined.length); 2624 editor->image_set = TRUE; 2625 } else if (photo && photo->type == E_CONTACT_PHOTO_TYPE_URI) { 2626 gchar *file_name = g_filename_from_uri (photo->data.uri, NULL, NULL); 2627 if (file_name) { 2628 e_image_chooser_set_from_file ( 2629 E_IMAGE_CHOOSER (widget), 2630 file_name); 2631 editor->image_set = TRUE; 2632 g_free (file_name); 2633 } 2634 } 2635 2636 if (!editor->image_set) { 2637 gchar *file_name; 2638 2639 file_name = e_icon_factory_get_icon_filename ( 2640 "avatar-default", GTK_ICON_SIZE_DIALOG); 2641 e_image_chooser_set_from_file ( 2642 E_IMAGE_CHOOSER (widget), file_name); 2643 editor->image_set = FALSE; 2644 g_free (file_name); 2645 } 2646 2647 editor->image_changed = FALSE; 2648 e_contact_photo_free (photo); 2649 2650 } else if (GTK_IS_TOGGLE_BUTTON (widget)) { 2651 gboolean val = e_contact_get (contact, field_id) != NULL; 2652 2653 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), val); 2654 2655 } else { 2656 g_warning (G_STRLOC ": Unhandled widget class in mappings!"); 2657 } 2658 2659 g_signal_handlers_unblock_matched ( 2660 widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor); 2661 } 2662 2663 static void 2664 extract_simple_field (EContactEditor *editor, 2665 GtkWidget *widget, 2666 gint field_id) 2667 { 2668 EContact *contact; 2669 2670 contact = editor->contact; 2671 2672 if (GTK_IS_ENTRY (widget)) { 2673 const gchar *text = gtk_entry_get_text (GTK_ENTRY (widget)); 2674 e_contact_set (contact, field_id, (gchar *) text); 2675 2676 } else if (GTK_IS_COMBO_BOX_TEXT (widget)) { 2677 gchar *text = NULL; 2678 2679 if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) { 2680 GtkWidget *entry = gtk_bin_get_child (GTK_BIN (widget)); 2681 2682 text = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); 2683 } 2684 2685 if (!text) 2686 text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widget)); 2687 2688 e_contact_set (contact, field_id, text); 2689 2690 g_free (text); 2691 } else if (GTK_IS_COMBO_BOX (widget)) { 2692 GtkTreeIter iter; 2693 gchar *text = NULL; 2694 2695 if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) { 2696 GtkWidget *entry = gtk_bin_get_child (GTK_BIN (widget)); 2697 2698 text = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); 2699 } 2700 2701 if (!text && gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) { 2702 GtkListStore *store; 2703 2704 store = GTK_LIST_STORE ( 2705 gtk_combo_box_get_model ( 2706 GTK_COMBO_BOX (widget))); 2707 2708 gtk_tree_model_get ( 2709 GTK_TREE_MODEL (store), &iter, 2710 0, &text, 2711 -1); 2712 } 2713 2714 e_contact_set (contact, field_id, text); 2715 2716 g_free (text); 2717 2718 } else if (GTK_IS_TEXT_VIEW (widget)) { 2719 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget)); 2720 GtkTextIter start, end; 2721 gchar *text; 2722 2723 gtk_text_buffer_get_start_iter (buffer, &start); 2724 gtk_text_buffer_get_end_iter (buffer, &end); 2725 text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); 2726 e_contact_set (contact, field_id, text); 2727 g_free (text); 2728 2729 } else if (E_IS_URL_ENTRY (widget)) { 2730 GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget)); 2731 const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry)); 2732 e_contact_set (contact, field_id, (gchar *) text); 2733 2734 } else if (E_IS_DATE_EDIT (widget)) { 2735 EContactDate date; 2736 if (e_date_edit_get_date ( 2737 E_DATE_EDIT (widget), 2738 (gint *) &date.year, 2739 (gint *) &date.month, 2740 (gint *) &date.day)) 2741 e_contact_set (contact, field_id, &date); 2742 else 2743 e_contact_set (contact, field_id, NULL); 2744 2745 } else if (E_IS_IMAGE_CHOOSER (widget)) { 2746 EContactPhoto photo; 2747 photo.type = E_CONTACT_PHOTO_TYPE_INLINED; 2748 photo.data.inlined.mime_type = NULL; 2749 if (editor->image_changed) { 2750 gchar *img_buff = NULL; 2751 if (editor->image_set && 2752 e_image_chooser_get_image_data ( 2753 E_IMAGE_CHOOSER (widget), 2754 &img_buff, &photo.data.inlined.length)) { 2755 GdkPixbuf *pixbuf, *new; 2756 GdkPixbufLoader *loader = gdk_pixbuf_loader_new (); 2757 2758 photo.data.inlined.data = (guchar *) img_buff; 2759 img_buff = NULL; 2760 gdk_pixbuf_loader_write ( 2761 loader, 2762 photo.data.inlined.data, 2763 photo.data.inlined.length, NULL); 2764 gdk_pixbuf_loader_close (loader, NULL); 2765 2766 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); 2767 if (pixbuf) { 2768 gint width, height, prompt_response; 2769 2770 g_object_ref (pixbuf); 2771 2772 height = gdk_pixbuf_get_height (pixbuf); 2773 width = gdk_pixbuf_get_width (pixbuf); 2774 if ((height > 96 || width > 96)) { 2775 2776 prompt_response = 2777 e_alert_run_dialog_for_args 2778 (GTK_WINDOW (editor->app), 2779 "addressbook:prompt-resize", 2780 NULL); 2781 2782 if (prompt_response == GTK_RESPONSE_YES) { 2783 if (width > height) { 2784 height = height * 96 / width; 2785 width = 96; 2786 } else { 2787 width = width *96 / height; 2788 height = 96; 2789 } 2790 2791 new = e_icon_factory_pixbuf_scale (pixbuf, width, height); 2792 if (new) { 2793 GdkPixbufFormat *format = 2794 gdk_pixbuf_loader_get_format (loader); 2795 gchar *format_name = 2796 gdk_pixbuf_format_get_name (format); 2797 g_free (photo.data.inlined.data); 2798 gdk_pixbuf_save_to_buffer ( 2799 new, &img_buff, 2800 &photo.data.inlined.length, 2801 format_name, NULL, NULL); 2802 photo.data.inlined.data = (guchar *) img_buff; 2803 img_buff = NULL; 2804 g_free (format_name); 2805 g_object_unref (new); 2806 } 2807 } else if (prompt_response == GTK_RESPONSE_CANCEL) { 2808 g_object_unref (pixbuf); 2809 g_object_unref (loader); 2810 return; 2811 } 2812 } 2813 g_object_unref (pixbuf); 2814 } 2815 editor->image_changed = FALSE; 2816 g_object_unref (loader); 2817 2818 e_contact_set (contact, field_id, &photo); 2819 2820 g_free (photo.data.inlined.data); 2821 2822 } else { 2823 editor->image_changed = FALSE; 2824 e_contact_set (contact, E_CONTACT_PHOTO, NULL); 2825 } 2826 } 2827 2828 } else if (GTK_IS_TOGGLE_BUTTON (widget)) { 2829 gboolean val; 2830 2831 val = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); 2832 e_contact_set (contact, field_id, val ? (gpointer) 1 : NULL); 2833 2834 } else { 2835 g_warning (G_STRLOC ": Unhandled widget class in mappings!"); 2836 } 2837 } 2838 2839 static void 2840 sensitize_simple_field (GtkWidget *widget, 2841 gboolean enabled) 2842 { 2843 if (GTK_IS_ENTRY (widget)) 2844 gtk_editable_set_editable (GTK_EDITABLE (widget), enabled); 2845 else if (GTK_IS_TEXT_VIEW (widget)) 2846 gtk_text_view_set_editable (GTK_TEXT_VIEW (widget), enabled); 2847 else if (E_IS_URL_ENTRY (widget)) { 2848 GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget)); 2849 gtk_editable_set_editable (GTK_EDITABLE (entry), enabled); 2850 } 2851 else if (E_IS_DATE_EDIT (widget)) 2852 e_date_edit_set_editable (E_DATE_EDIT (widget), enabled); 2853 else 2854 gtk_widget_set_sensitive (widget, enabled); 2855 } 2856 2857 static void 2858 init_simple (EContactEditor *editor) 2859 { 2860 GtkWidget *widget; 2861 gint i; 2862 2863 for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) { 2864 widget = e_builder_get_widget ( 2865 editor->builder, simple_field_map[i].widget_name); 2866 if (!widget) 2867 continue; 2868 2869 init_simple_field (editor, widget); 2870 } 2871 2872 /* --- Special cases --- */ 2873 2874 /* Update file_as */ 2875 2876 widget = e_builder_get_widget (editor->builder, "entry-fullname"); 2877 g_signal_connect ( 2878 widget, "changed", 2879 G_CALLBACK (name_entry_changed), editor); 2880 2881 widget = e_builder_get_widget (editor->builder, "combo-file-as"); 2882 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (widget), 0); 2883 g_signal_connect ( 2884 widget, "changed", 2885 G_CALLBACK (file_as_combo_changed), editor); 2886 2887 widget = e_builder_get_widget (editor->builder, "entry-company"); 2888 g_signal_connect ( 2889 widget, "changed", 2890 G_CALLBACK (company_entry_changed), editor); 2891 } 2892 2893 static void 2894 fill_in_simple (EContactEditor *editor) 2895 { 2896 EContactName *name; 2897 gchar *filename; 2898 gint i; 2899 2900 for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) { 2901 GtkWidget *widget; 2902 2903 if (simple_field_map[i].field_id < 0 || 2904 !simple_field_map[i].process_data) 2905 continue; 2906 2907 widget = e_builder_get_widget ( 2908 editor->builder, simple_field_map[i].widget_name); 2909 if (!widget) 2910 continue; 2911 2912 fill_in_simple_field ( 2913 editor, widget, simple_field_map[i].field_id); 2914 } 2915 2916 /* --- Special cases --- */ 2917 2918 /* Update broken-up name */ 2919 2920 g_object_get (editor->contact, "name", &name, NULL); 2921 2922 if (editor->name) 2923 e_contact_name_free (editor->name); 2924 2925 editor->name = name; 2926 2927 /* Update the contact editor title */ 2928 2929 filename = (gchar *) e_contact_get (editor->contact, E_CONTACT_FILE_AS); 2930 2931 if (filename) { 2932 gchar *title; 2933 title = g_strdup_printf (_("Contact Editor - %s"), filename); 2934 gtk_window_set_title (GTK_WINDOW (editor->app), title); 2935 g_free (title); 2936 g_free (filename); 2937 } else 2938 gtk_window_set_title ( 2939 GTK_WINDOW (editor->app), _("Contact Editor")); 2940 2941 /* Update file_as combo options */ 2942 2943 update_file_as_combo (editor); 2944 } 2945 2946 static void 2947 extract_simple (EContactEditor *editor) 2948 { 2949 gint i; 2950 2951 for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) { 2952 GtkWidget *widget; 2953 2954 if (simple_field_map[i].field_id < 0 || 2955 !simple_field_map[i].process_data) 2956 continue; 2957 2958 widget = e_builder_get_widget ( 2959 editor->builder, simple_field_map[i].widget_name); 2960 if (!widget) 2961 continue; 2962 2963 extract_simple_field ( 2964 editor, widget, simple_field_map[i].field_id); 2965 } 2966 2967 /* Special cases */ 2968 2969 e_contact_set (editor->contact, E_CONTACT_NAME, editor->name); 2970 } 2971 2972 static void 2973 sensitize_simple (EContactEditor *editor) 2974 { 2975 gint i; 2976 2977 for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) { 2978 GtkWidget *widget; 2979 gboolean enabled = TRUE; 2980 2981 widget = e_builder_get_widget ( 2982 editor->builder, simple_field_map[i].widget_name); 2983 if (!widget) 2984 continue; 2985 2986 if (simple_field_map[i].field_id >= 0 && 2987 !is_field_supported (editor, simple_field_map[i].field_id)) 2988 enabled = FALSE; 2989 2990 if (simple_field_map[i].desensitize_for_read_only && 2991 !editor->target_editable) 2992 enabled = FALSE; 2993 2994 sensitize_simple_field (widget, enabled); 2995 } 2996 } 2997 2998 static void 2999 fill_in_all (EContactEditor *editor) 3000 { 3001 fill_in_source_field (editor); 3002 fill_in_simple (editor); 3003 fill_in_email (editor); 3004 fill_in_phone (editor); 3005 fill_in_im (editor); 3006 fill_in_address (editor); 3007 } 3008 3009 static void 3010 extract_all (EContactEditor *editor) 3011 { 3012 extract_simple (editor); 3013 extract_email (editor); 3014 extract_phone (editor); 3015 extract_im (editor); 3016 extract_address (editor); 3017 } 3018 3019 static void 3020 sensitize_all (EContactEditor *editor) 3021 { 3022 sensitize_ok (editor); 3023 sensitize_simple (editor); 3024 sensitize_email (editor); 3025 sensitize_phone (editor); 3026 sensitize_im (editor); 3027 sensitize_address (editor); 3028 } 3029 3030 static void 3031 init_all (EContactEditor *editor) 3032 { 3033 const gchar *contents[] = { "viewport1", "viewport2", "viewport3", "text-comments" }; 3034 gint ii; 3035 GtkRequisition tab_req, requisition; 3036 GtkWidget *widget; 3037 3038 init_simple (editor); 3039 init_email (editor); 3040 init_phone (editor); 3041 init_im (editor); 3042 init_personal (editor); 3043 init_address (editor); 3044 3045 /* with so many scrolled windows, we need to 3046 * do some manual sizing */ 3047 requisition.width = -1; 3048 requisition.height = -1; 3049 3050 for (ii = 0; ii < G_N_ELEMENTS (contents); ii++) { 3051 widget = e_builder_get_widget (editor->builder, contents[ii]); 3052 3053 gtk_widget_get_preferred_size (widget, NULL, &tab_req); 3054 3055 if (tab_req.width > requisition.width) 3056 requisition.width = tab_req.width; 3057 if (tab_req.height > requisition.height) 3058 requisition.height = tab_req.height; 3059 } 3060 3061 if (requisition.width > 0 && requisition.height > 0) { 3062 GtkWindow *window; 3063 GdkScreen *screen; 3064 GdkRectangle monitor_area; 3065 gint x = 0, y = 0, monitor, width, height; 3066 3067 window = GTK_WINDOW (e_builder_get_widget (editor->builder, "contact editor")); 3068 3069 gtk_widget_get_preferred_size (GTK_WIDGET (window), &tab_req, NULL); 3070 width = tab_req.width - 320 + 24; 3071 height = tab_req.height - 240 + 24; 3072 3073 screen = gtk_window_get_screen (window); 3074 gtk_window_get_position (window, &x, &y); 3075 3076 monitor = gdk_screen_get_monitor_at_point (screen, x, y); 3077 if (monitor < 0 || monitor >= gdk_screen_get_n_monitors (screen)) 3078 monitor = 0; 3079 3080 gdk_screen_get_monitor_workarea (screen, monitor, &monitor_area); 3081 3082 if (requisition.width > monitor_area.width - width) 3083 requisition.width = monitor_area.width - width; 3084 3085 if (requisition.height > monitor_area.height - height) 3086 requisition.height = monitor_area.height - height; 3087 3088 if (requisition.width > 0 && requisition.height > 0) 3089 gtk_window_set_default_size (window, width + requisition.width, height + requisition.height); 3090 } 3091 } 3092 3093 static void 3094 contact_editor_book_loaded_cb (GObject *source_object, 3095 GAsyncResult *result, 3096 gpointer user_data) 3097 { 3098 ESource *source = E_SOURCE (source_object); 3099 EContactEditor *editor = user_data; 3100 EClient *client = NULL; 3101 GError *error = NULL; 3102 3103 e_client_utils_open_new_finish (source, result, &client, &error); 3104 3105 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) || 3106 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { 3107 g_warn_if_fail (client == NULL); 3108 g_error_free (error); 3109 goto exit; 3110 3111 } else if (error != NULL) { 3112 GtkWidget *source_combo_box; 3113 GtkWindow *parent; 3114 3115 g_warn_if_fail (client == NULL); 3116 3117 parent = eab_editor_get_window (EAB_EDITOR (editor)); 3118 eab_load_error_dialog (GTK_WIDGET (parent), NULL, source, error); 3119 3120 source_combo_box = e_builder_get_widget ( 3121 editor->builder, "source-combo-box-source"); 3122 e_source_combo_box_set_active ( 3123 E_SOURCE_COMBO_BOX (source_combo_box), source); 3124 3125 g_error_free (error); 3126 goto exit; 3127 } 3128 3129 g_return_if_fail (E_IS_CLIENT (client)); 3130 3131 /* FIXME Write a private contact_editor_set_target_client(). */ 3132 g_object_set (editor, "target_client", client, NULL); 3133 3134 g_object_unref (client); 3135 3136 exit: 3137 g_object_unref (editor); 3138 } 3139 3140 static void 3141 source_changed (ESourceComboBox *source_combo_box, 3142 EContactEditor *editor) 3143 { 3144 ESource *target_source; 3145 ESource *source_source; 3146 ESource *source; 3147 3148 source = e_source_combo_box_ref_active (source_combo_box); 3149 g_return_if_fail (source != NULL); 3150 3151 if (editor->cancellable != NULL) { 3152 g_cancellable_cancel (editor->cancellable); 3153 g_object_unref (editor->cancellable); 3154 editor->cancellable = NULL; 3155 } 3156 3157 target_source = e_client_get_source (E_CLIENT (editor->target_client)); 3158 source_source = e_client_get_source (E_CLIENT (editor->source_client)); 3159 3160 if (e_source_equal (target_source, source)) 3161 goto exit; 3162 3163 if (e_source_equal (source_source, source)) { 3164 g_object_set ( 3165 editor, "target_client", 3166 editor->source_client, NULL); 3167 goto exit; 3168 } 3169 3170 editor->cancellable = g_cancellable_new (); 3171 3172 e_client_utils_open_new ( 3173 source, E_CLIENT_SOURCE_TYPE_CONTACTS, 3174 FALSE, editor->cancellable, 3175 contact_editor_book_loaded_cb, g_object_ref (editor)); 3176 3177 exit: 3178 g_object_unref (source); 3179 } 3180 3181 static void 3182 full_name_response (GtkDialog *dialog, 3183 gint response, 3184 EContactEditor *editor) 3185 { 3186 EContactName *name; 3187 GtkWidget *fname_widget; 3188 gint style = 0; 3189 gboolean editable = FALSE; 3190 3191 g_object_get (dialog, "editable", &editable, NULL); 3192 3193 if (editable && response == GTK_RESPONSE_OK) { 3194 g_object_get (dialog, "name", &name, NULL); 3195 3196 style = file_as_get_style (editor); 3197 3198 fname_widget = e_builder_get_widget ( 3199 editor->builder, "entry-fullname"); 3200 3201 if (GTK_IS_ENTRY (fname_widget)) { 3202 GtkEntry *entry; 3203 gchar *full_name = e_contact_name_to_string (name); 3204 const gchar *old_full_name; 3205 3206 entry = GTK_ENTRY (fname_widget); 3207 old_full_name = gtk_entry_get_text (entry); 3208 3209 if (strcmp (full_name, old_full_name)) 3210 gtk_entry_set_text (entry, full_name); 3211 g_free (full_name); 3212 } 3213 3214 e_contact_name_free (editor->name); 3215 editor->name = name; 3216 3217 file_as_set_style (editor, style); 3218 } 3219 3220 gtk_widget_destroy (GTK_WIDGET (dialog)); 3221 editor->fullname_dialog = NULL; 3222 } 3223 3224 static gint 3225 full_name_editor_delete_event_cb (GtkWidget *widget, 3226 GdkEvent *event, 3227 gpointer data) 3228 { 3229 if (GTK_IS_WIDGET (widget)) 3230 gtk_widget_destroy (widget); 3231 3232 return TRUE; 3233 } 3234 3235 static void 3236 full_name_clicked (GtkWidget *button, 3237 EContactEditor *editor) 3238 { 3239 GtkDialog *dialog; 3240 gboolean fullname_supported; 3241 3242 if (editor->fullname_dialog) { 3243 gtk_window_present (GTK_WINDOW (editor->fullname_dialog)); 3244 return; 3245 } 3246 3247 dialog = GTK_DIALOG (e_contact_editor_fullname_new (editor->name)); 3248 fullname_supported = is_field_supported (editor, E_CONTACT_FULL_NAME); 3249 3250 g_object_set ( 3251 dialog, "editable", 3252 fullname_supported & editor->target_editable, NULL); 3253 3254 g_signal_connect ( 3255 dialog, "response", 3256 G_CALLBACK (full_name_response), editor); 3257 3258 /* Close the fullname dialog if the editor is closed */ 3259 g_signal_connect_swapped ( 3260 editor, "editor_closed", 3261 G_CALLBACK (full_name_editor_delete_event_cb), dialog); 3262 3263 gtk_widget_show (GTK_WIDGET (dialog)); 3264 editor->fullname_dialog = GTK_WIDGET (dialog); 3265 } 3266 3267 static void 3268 categories_response (GtkDialog *dialog, 3269 gint response, 3270 EContactEditor *editor) 3271 { 3272 gchar *categories; 3273 GtkWidget *entry; 3274 3275 entry = e_builder_get_widget (editor->builder, "entry-categories"); 3276 3277 if (response == GTK_RESPONSE_OK) { 3278 categories = e_categories_dialog_get_categories ( 3279 E_CATEGORIES_DIALOG (dialog)); 3280 if (GTK_IS_ENTRY (entry)) 3281 gtk_entry_set_text ( 3282 GTK_ENTRY (entry), categories); 3283 else 3284 e_contact_set ( 3285 editor->contact, 3286 E_CONTACT_CATEGORIES, 3287 categories); 3288 g_free (categories); 3289 } 3290 3291 gtk_widget_destroy (GTK_WIDGET (dialog)); 3292 editor->categories_dialog = NULL; 3293 } 3294 3295 static gint 3296 categories_editor_delete_event_cb (GtkWidget *widget, 3297 GdkEvent *event, 3298 gpointer data) 3299 { 3300 if (GTK_IS_WIDGET (widget)) 3301 gtk_widget_destroy (widget); 3302 3303 return TRUE; 3304 } 3305 3306 static void 3307 categories_clicked (GtkWidget *button, 3308 EContactEditor *editor) 3309 { 3310 gchar *categories = NULL; 3311 GtkDialog *dialog; 3312 GtkWidget *entry = e_builder_get_widget (editor->builder, "entry-categories"); 3313 3314 if (entry && GTK_IS_ENTRY (entry)) 3315 categories = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); 3316 else if (editor->contact) 3317 categories = e_contact_get (editor->contact, E_CONTACT_CATEGORIES); 3318 3319 if (editor->categories_dialog != NULL) { 3320 gtk_window_present (GTK_WINDOW (editor->categories_dialog)); 3321 g_free (categories); 3322 return; 3323 }else if (!(dialog = GTK_DIALOG (e_categories_dialog_new (categories)))) { 3324 e_alert_run_dialog_for_args ( 3325 GTK_WINDOW (editor->app), 3326 "addressbook:edit-categories", NULL); 3327 g_free (categories); 3328 return; 3329 } 3330 3331 g_signal_connect ( 3332 dialog, "response", 3333 G_CALLBACK (categories_response), editor); 3334 3335 /* Close the category dialog if the editor is closed*/ 3336 g_signal_connect_swapped ( 3337 editor, "editor_closed", 3338 G_CALLBACK (categories_editor_delete_event_cb), dialog); 3339 3340 gtk_widget_show (GTK_WIDGET (dialog)); 3341 g_free (categories); 3342 3343 editor->categories_dialog = GTK_WIDGET (dialog); 3344 } 3345 3346 static void 3347 image_selected (EContactEditor *editor) 3348 { 3349 gchar *file_name; 3350 GtkWidget *image_chooser; 3351 3352 file_name = gtk_file_chooser_get_filename ( 3353 GTK_FILE_CHOOSER (editor->file_selector)); 3354 3355 if (!file_name) 3356 return; 3357 3358 image_chooser = e_builder_get_widget (editor->builder, "image-chooser"); 3359 3360 g_signal_handlers_block_by_func ( 3361 image_chooser, image_chooser_changed, editor); 3362 e_image_chooser_set_from_file ( 3363 E_IMAGE_CHOOSER (image_chooser), file_name); 3364 g_signal_handlers_unblock_by_func ( 3365 image_chooser, image_chooser_changed, editor); 3366 3367 editor->image_set = TRUE; 3368 editor->image_changed = TRUE; 3369 object_changed (G_OBJECT (image_chooser), editor); 3370 } 3371 3372 static void 3373 image_cleared (EContactEditor *editor) 3374 { 3375 GtkWidget *image_chooser; 3376 gchar *file_name; 3377 3378 image_chooser = e_builder_get_widget ( 3379 editor->builder, "image-chooser"); 3380 3381 file_name = e_icon_factory_get_icon_filename ( 3382 "avatar-default", GTK_ICON_SIZE_DIALOG); 3383 3384 g_signal_handlers_block_by_func ( 3385 image_chooser, image_chooser_changed, editor); 3386 e_image_chooser_set_from_file ( 3387 E_IMAGE_CHOOSER (image_chooser), file_name); 3388 g_signal_handlers_unblock_by_func ( 3389 image_chooser, image_chooser_changed, editor); 3390 3391 g_free (file_name); 3392 3393 editor->image_set = FALSE; 3394 editor->image_changed = TRUE; 3395 object_changed (G_OBJECT (image_chooser), editor); 3396 } 3397 3398 static void 3399 file_chooser_response (GtkWidget *widget, 3400 gint response, 3401 EContactEditor *editor) 3402 { 3403 if (response == GTK_RESPONSE_ACCEPT) 3404 image_selected (editor); 3405 else if (response == GTK_RESPONSE_NO) 3406 image_cleared (editor); 3407 3408 gtk_widget_hide (editor->file_selector); 3409 } 3410 3411 static gboolean 3412 file_selector_deleted (GtkWidget *widget) 3413 { 3414 gtk_widget_hide (widget); 3415 return TRUE; 3416 } 3417 3418 static void 3419 update_preview_cb (GtkFileChooser *file_chooser, 3420 gpointer data) 3421 { 3422 GtkWidget *preview; 3423 gchar *filename = NULL; 3424 GdkPixbuf *pixbuf; 3425 3426 gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE); 3427 preview = GTK_WIDGET (data); 3428 filename = gtk_file_chooser_get_preview_filename (file_chooser); 3429 if (filename == NULL) 3430 return; 3431 3432 pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL); 3433 if (!pixbuf) { 3434 gchar *alternate_file; 3435 alternate_file = e_icon_factory_get_icon_filename ( 3436 "avatar-default", GTK_ICON_SIZE_DIALOG); 3437 if (alternate_file) { 3438 pixbuf = gdk_pixbuf_new_from_file_at_size ( 3439 alternate_file, 128, 128, NULL); 3440 g_free (alternate_file); 3441 } 3442 } 3443 g_free (filename); 3444 3445 gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf); 3446 if (pixbuf) 3447 g_object_unref (pixbuf); 3448 } 3449 3450 static void 3451 image_clicked (GtkWidget *button, 3452 EContactEditor *editor) 3453 { 3454 const gchar *title = _("Please select an image for this contact"); 3455 const gchar *no_image = _("_No image"); 3456 GtkImage *preview; 3457 3458 if (!editor->file_selector) { 3459 editor->file_selector = gtk_file_chooser_dialog_new ( 3460 title, GTK_WINDOW (editor->app), 3461 GTK_FILE_CHOOSER_ACTION_OPEN, 3462 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 3463 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, 3464 no_image, GTK_RESPONSE_NO, 3465 NULL); 3466 preview = GTK_IMAGE (gtk_image_new ()); 3467 gtk_file_chooser_set_preview_widget ( 3468 GTK_FILE_CHOOSER (editor->file_selector), 3469 GTK_WIDGET (preview)); 3470 g_signal_connect ( 3471 editor->file_selector, "update-preview", 3472 G_CALLBACK (update_preview_cb), preview); 3473 gtk_dialog_set_default_response ( 3474 GTK_DIALOG (editor->file_selector), 3475 GTK_RESPONSE_ACCEPT); 3476 3477 g_signal_connect ( 3478 editor->file_selector, "response", 3479 G_CALLBACK (file_chooser_response), editor); 3480 3481 g_signal_connect_after ( 3482 editor->file_selector, "delete-event", 3483 G_CALLBACK (file_selector_deleted), 3484 editor->file_selector); 3485 } 3486 3487 /* Display the dialog */ 3488 3489 gtk_window_set_modal (GTK_WINDOW (editor->file_selector), TRUE); 3490 gtk_window_present (GTK_WINDOW (editor->file_selector)); 3491 } 3492 3493 typedef struct { 3494 EContactEditor *ce; 3495 gboolean should_close; 3496 gchar *new_id; 3497 } EditorCloseStruct; 3498 3499 static void 3500 contact_removed_cb (GObject *source_object, 3501 GAsyncResult *result, 3502 gpointer user_data) 3503 { 3504 EBookClient *book_client = E_BOOK_CLIENT (source_object); 3505 EditorCloseStruct *ecs = user_data; 3506 EContactEditor *ce = ecs->ce; 3507 gboolean should_close = ecs->should_close; 3508 GError *error = NULL; 3509 3510 e_book_client_remove_contact_finish (book_client, result, &error); 3511 3512 gtk_widget_set_sensitive (ce->app, TRUE); 3513 ce->in_async_call = FALSE; 3514 3515 e_contact_set (ce->contact, E_CONTACT_UID, ecs->new_id); 3516 3517 eab_editor_contact_deleted (EAB_EDITOR (ce), error, ce->contact); 3518 3519 ce->is_new_contact = FALSE; 3520 3521 if (should_close) { 3522 eab_editor_close (EAB_EDITOR (ce)); 3523 } else { 3524 ce->changed = FALSE; 3525 3526 g_object_ref (ce->target_client); 3527 g_object_unref (ce->source_client); 3528 ce->source_client = ce->target_client; 3529 3530 sensitize_all (ce); 3531 } 3532 3533 if (error) 3534 g_error_free (error); 3535 3536 g_object_unref (ce); 3537 g_free (ecs->new_id); 3538 g_free (ecs); 3539 } 3540 3541 static void 3542 contact_added_cb (EBookClient *book_client, 3543 const GError *error, 3544 const gchar *id, 3545 gpointer closure) 3546 { 3547 EditorCloseStruct *ecs = closure; 3548 EContactEditor *ce = ecs->ce; 3549 gboolean should_close = ecs->should_close; 3550 3551 if (ce->source_client != ce->target_client && !e_client_is_readonly (E_CLIENT (ce->source_client)) && 3552 !error && ce->is_new_contact == FALSE) { 3553 ecs->new_id = g_strdup (id); 3554 e_book_client_remove_contact ( 3555 ce->source_client, ce->contact, NULL, contact_removed_cb, ecs); 3556 return; 3557 } 3558 3559 gtk_widget_set_sensitive (ce->app, TRUE); 3560 ce->in_async_call = FALSE; 3561 3562 e_contact_set (ce->contact, E_CONTACT_UID, id); 3563 3564 eab_editor_contact_added (EAB_EDITOR (ce), error, ce->contact); 3565 3566 if (!error) { 3567 ce->is_new_contact = FALSE; 3568 3569 if (should_close) { 3570 eab_editor_close (EAB_EDITOR (ce)); 3571 } else { 3572 ce->changed = FALSE; 3573 sensitize_all (ce); 3574 } 3575 } 3576 3577 g_object_unref (ce); 3578 g_free (ecs); 3579 } 3580 3581 static void 3582 contact_modified_cb (EBookClient *book_client, 3583 const GError *error, 3584 gpointer closure) 3585 { 3586 EditorCloseStruct *ecs = closure; 3587 EContactEditor *ce = ecs->ce; 3588 gboolean should_close = ecs->should_close; 3589 3590 gtk_widget_set_sensitive (ce->app, TRUE); 3591 ce->in_async_call = FALSE; 3592 3593 eab_editor_contact_modified (EAB_EDITOR (ce), error, ce->contact); 3594 3595 if (!error) { 3596 if (should_close) { 3597 eab_editor_close (EAB_EDITOR (ce)); 3598 } 3599 else { 3600 ce->changed = FALSE; 3601 sensitize_all (ce); 3602 } 3603 } 3604 3605 g_object_unref (ce); 3606 g_free (ecs); 3607 } 3608 3609 static void 3610 contact_modified_ready_cb (GObject *source_object, 3611 GAsyncResult *result, 3612 gpointer user_data) 3613 { 3614 EBookClient *book_client = E_BOOK_CLIENT (source_object); 3615 GError *error = NULL; 3616 3617 e_book_client_modify_contact_finish (book_client, result, &error); 3618 3619 contact_modified_cb (book_client, error, user_data); 3620 3621 if (error) 3622 g_error_free (error); 3623 } 3624 3625 /* Emits the signal to request saving a contact */ 3626 static void 3627 real_save_contact (EContactEditor *ce, 3628 gboolean should_close) 3629 { 3630 EShell *shell; 3631 EditorCloseStruct *ecs; 3632 ESourceRegistry *registry; 3633 3634 shell = eab_editor_get_shell (EAB_EDITOR (ce)); 3635 registry = e_shell_get_registry (shell); 3636 3637 ecs = g_new0 (EditorCloseStruct, 1); 3638 ecs->ce = ce; 3639 g_object_ref (ecs->ce); 3640 3641 ecs->should_close = should_close; 3642 3643 gtk_widget_set_sensitive (ce->app, FALSE); 3644 ce->in_async_call = TRUE; 3645 3646 if (ce->source_client != ce->target_client) { 3647 /* Two-step move; add to target, then remove from source */ 3648 eab_merging_book_add_contact ( 3649 registry, ce->target_client, 3650 ce->contact, contact_added_cb, ecs); 3651 } else { 3652 if (ce->is_new_contact) 3653 eab_merging_book_add_contact ( 3654 registry, ce->target_client, 3655 ce->contact, contact_added_cb, ecs); 3656 else if (ce->check_merge) 3657 eab_merging_book_modify_contact ( 3658 registry, ce->target_client, 3659 ce->contact, contact_modified_cb, ecs); 3660 else 3661 e_book_client_modify_contact ( 3662 ce->target_client, ce->contact, NULL, 3663 contact_modified_ready_cb, ecs); 3664 } 3665 } 3666 3667 static void 3668 save_contact (EContactEditor *ce, 3669 gboolean should_close) 3670 { 3671 gchar *uid; 3672 const gchar *name_entry_string; 3673 const gchar *file_as_entry_string; 3674 const gchar *company_name_string; 3675 GtkWidget *entry_fullname, *entry_file_as, *company_name; 3676 3677 if (!ce->target_client) 3678 return; 3679 3680 if (ce->target_editable && e_client_is_readonly (E_CLIENT (ce->source_client))) { 3681 if (e_alert_run_dialog_for_args ( 3682 GTK_WINDOW (ce->app), 3683 "addressbook:prompt-move", 3684 NULL) == GTK_RESPONSE_NO) 3685 return; 3686 } 3687 3688 entry_fullname = e_builder_get_widget (ce->builder, "entry-fullname"); 3689 entry_file_as = gtk_bin_get_child ( 3690 GTK_BIN (e_builder_get_widget (ce->builder, "combo-file-as"))); 3691 company_name = e_builder_get_widget (ce->builder, "entry-company"); 3692 name_entry_string = gtk_entry_get_text (GTK_ENTRY (entry_fullname)); 3693 file_as_entry_string = gtk_entry_get_text (GTK_ENTRY (entry_file_as)); 3694 company_name_string = gtk_entry_get_text (GTK_ENTRY (company_name)); 3695 3696 if (strcmp (company_name_string , "")) { 3697 if (!strcmp (name_entry_string, "")) 3698 gtk_entry_set_text ( 3699 GTK_ENTRY (entry_fullname), 3700 company_name_string); 3701 if (!strcmp (file_as_entry_string, "")) 3702 gtk_entry_set_text ( 3703 GTK_ENTRY (entry_file_as), 3704 company_name_string); 3705 } 3706 3707 extract_all (ce); 3708 3709 if (!e_contact_editor_is_valid (EAB_EDITOR (ce))) { 3710 uid = e_contact_get (ce->contact, E_CONTACT_UID); 3711 g_object_unref (ce->contact); 3712 ce->contact = e_contact_new (); 3713 if (uid) { 3714 e_contact_set (ce->contact, E_CONTACT_UID, uid); 3715 g_free (uid); 3716 } 3717 return; 3718 } 3719 3720 real_save_contact (ce, should_close); 3721 } 3722 3723 static void 3724 e_contact_editor_save_contact (EABEditor *editor, 3725 gboolean should_close) 3726 { 3727 save_contact (E_CONTACT_EDITOR (editor), should_close); 3728 } 3729 3730 /* Closes the dialog box and emits the appropriate signals */ 3731 static void 3732 e_contact_editor_close (EABEditor *editor) 3733 { 3734 EContactEditor *ce = E_CONTACT_EDITOR (editor); 3735 3736 if (ce->app != NULL) { 3737 gtk_widget_destroy (ce->app); 3738 ce->app = NULL; 3739 eab_editor_closed (editor); 3740 } 3741 } 3742 3743 static const EContactField non_string_fields[] = { 3744 E_CONTACT_FULL_NAME, 3745 E_CONTACT_ADDRESS, 3746 E_CONTACT_ADDRESS_HOME, 3747 E_CONTACT_ADDRESS_WORK, 3748 E_CONTACT_ADDRESS_OTHER, 3749 E_CONTACT_EMAIL, 3750 E_CONTACT_IM_AIM, 3751 E_CONTACT_IM_GROUPWISE, 3752 E_CONTACT_IM_JABBER, 3753 E_CONTACT_IM_YAHOO, 3754 E_CONTACT_IM_GADUGADU, 3755 E_CONTACT_IM_MSN, 3756 E_CONTACT_IM_ICQ, 3757 E_CONTACT_IM_SKYPE, 3758 E_CONTACT_IM_TWITTER, 3759 E_CONTACT_PHOTO, 3760 E_CONTACT_LOGO, 3761 E_CONTACT_X509_CERT, 3762 E_CONTACT_CATEGORY_LIST, 3763 E_CONTACT_BIRTH_DATE, 3764 E_CONTACT_ANNIVERSARY 3765 3766 }; 3767 3768 static gboolean 3769 is_non_string_field (EContactField id) 3770 { 3771 gint count = sizeof (non_string_fields) / sizeof (EContactField); 3772 gint i; 3773 for (i = 0; i < count; i++) 3774 if (id == non_string_fields[i]) 3775 return TRUE; 3776 return FALSE; 3777 3778 } 3779 3780 /* insert checks here (date format, for instance, etc.) */ 3781 static gboolean 3782 e_contact_editor_is_valid (EABEditor *editor) 3783 { 3784 EContactEditor *ce = E_CONTACT_EDITOR (editor); 3785 GtkWidget *widget; 3786 gboolean validation_error = FALSE; 3787 GSList *iter; 3788 GString *errmsg = g_string_new (_("The contact data is invalid:\n\n")); 3789 time_t bday, now = time (NULL); 3790 3791 widget = e_builder_get_widget (ce->builder, "dateedit-birthday"); 3792 if (!(e_date_edit_date_is_valid (E_DATE_EDIT (widget)))) { 3793 g_string_append_printf ( 3794 errmsg, _("'%s' has an invalid format"), 3795 e_contact_pretty_name (E_CONTACT_BIRTH_DATE)); 3796 validation_error = TRUE; 3797 } 3798 /* If valid, see if the birthday is a future date */ 3799 bday = e_date_edit_get_time (E_DATE_EDIT (widget)); 3800 if (bday > now) { 3801 g_string_append_printf ( 3802 errmsg, _("'%s' cannot be a future date"), 3803 e_contact_pretty_name (E_CONTACT_BIRTH_DATE)); 3804 validation_error = TRUE; 3805 } 3806 3807 widget = e_builder_get_widget (ce->builder, "dateedit-anniversary"); 3808 if (!(e_date_edit_date_is_valid (E_DATE_EDIT (widget)))) { 3809 g_string_append_printf ( 3810 errmsg, _("%s'%s' has an invalid format"), 3811 validation_error ? ",\n" : "", 3812 e_contact_pretty_name (E_CONTACT_ANNIVERSARY)); 3813 validation_error = TRUE; 3814 } 3815 3816 for (iter = ce->required_fields; iter; iter = iter->next) { 3817 const gchar *field_name = iter->data; 3818 EContactField field_id = e_contact_field_id (field_name); 3819 3820 if (is_non_string_field (field_id)) { 3821 if (e_contact_get_const (ce->contact, field_id) == NULL) { 3822 g_string_append_printf ( 3823 errmsg, _("%s'%s' is empty"), 3824 validation_error ? ",\n" : "", 3825 e_contact_pretty_name (field_id)); 3826 validation_error = TRUE; 3827 break; 3828 } 3829 3830 } else { 3831 const gchar *text; 3832 3833 text = e_contact_get_const (ce->contact, field_id); 3834 3835 if (STRING_IS_EMPTY (text)) { 3836 g_string_append_printf ( 3837 errmsg, _("%s'%s' is empty"), 3838 validation_error ? ",\n" : "", 3839 e_contact_pretty_name (field_id)); 3840 validation_error = TRUE; 3841 break; 3842 } 3843 3844 } 3845 } 3846 3847 if (validation_error) { 3848 g_string_append (errmsg, "."); 3849 e_alert_run_dialog_for_args ( 3850 GTK_WINDOW (ce->app), 3851 "addressbook:generic-error", 3852 _("Invalid contact."), errmsg->str, NULL); 3853 g_string_free (errmsg, TRUE); 3854 return FALSE; 3855 } 3856 else { 3857 g_string_free (errmsg, TRUE); 3858 return TRUE; 3859 } 3860 } 3861 3862 static gboolean 3863 e_contact_editor_is_changed (EABEditor *editor) 3864 { 3865 return E_CONTACT_EDITOR (editor)->changed; 3866 } 3867 3868 static GtkWindow * 3869 e_contact_editor_get_window (EABEditor *editor) 3870 { 3871 return GTK_WINDOW (E_CONTACT_EDITOR (editor)->app); 3872 } 3873 3874 static void 3875 file_save_and_close_cb (GtkWidget *widget, 3876 EContactEditor *ce) 3877 { 3878 save_contact (ce, TRUE); 3879 } 3880 3881 static void 3882 file_cancel_cb (GtkWidget *widget, 3883 EContactEditor *ce) 3884 { 3885 eab_editor_close (EAB_EDITOR (ce)); 3886 } 3887 3888 /* Callback used when the dialog box is destroyed */ 3889 static gint 3890 app_delete_event_cb (GtkWidget *widget, 3891 GdkEvent *event, 3892 gpointer data) 3893 { 3894 EContactEditor *ce; 3895 3896 ce = E_CONTACT_EDITOR (data); 3897 3898 /* if we're saving, don't allow the dialog to close */ 3899 if (ce->in_async_call) 3900 return TRUE; 3901 3902 if (ce->changed) { 3903 switch (eab_prompt_save_dialog (GTK_WINDOW (ce->app))) { 3904 case GTK_RESPONSE_YES: 3905 eab_editor_save_contact (EAB_EDITOR (ce), TRUE); 3906 return TRUE; 3907 3908 case GTK_RESPONSE_NO: 3909 break; 3910 3911 case GTK_RESPONSE_CANCEL: 3912 default: 3913 return TRUE; 3914 3915 } 3916 } 3917 3918 eab_editor_close (EAB_EDITOR (ce)); 3919 return TRUE; 3920 } 3921 3922 static void 3923 show_help_cb (GtkWidget *widget, 3924 gpointer data) 3925 { 3926 /* FIXME Pass a proper parent window. */ 3927 e_display_help (NULL, "contacts-usage-add-contact"); 3928 } 3929 3930 static GList * 3931 add_to_tab_order (GList *list, 3932 GtkBuilder *builder, 3933 const gchar *name) 3934 { 3935 GtkWidget *widget = e_builder_get_widget (builder, name); 3936 return g_list_prepend (list, widget); 3937 } 3938 3939 static void 3940 setup_tab_order (GtkBuilder *builder) 3941 { 3942 GtkWidget *container; 3943 GList *list = NULL; 3944 /* 3945 container = e_builder_get_widget (builder, "table-contact-editor-general"); 3946 * 3947 if (container) { 3948 list = add_to_tab_order (list, builder, "entry-fullname"); 3949 list = add_to_tab_order (list, builder, "entry-jobtitle"); 3950 list = add_to_tab_order (list, builder, "entry-company"); 3951 list = add_to_tab_order (list, builder, "combo-file-as"); 3952 list = add_to_tab_order (list, builder, "entry-phone-1"); 3953 list = add_to_tab_order (list, builder, "entry-phone-2"); 3954 list = add_to_tab_order (list, builder, "entry-phone-3"); 3955 list = add_to_tab_order (list, builder, "entry-phone-4"); 3956 * 3957 list = add_to_tab_order (list, builder, "entry-email1"); 3958 list = add_to_tab_order (list, builder, "alignment-htmlmail"); 3959 list = add_to_tab_order (list, builder, "entry-web"); 3960 list = add_to_tab_order (list, builder, "entry-homepage"); 3961 list = add_to_tab_order (list, builder, "button-fulladdr"); 3962 list = add_to_tab_order (list, builder, "text-address"); 3963 list = g_list_reverse (list); 3964 e_container_change_tab_order (GTK_CONTAINER (container), list); 3965 g_list_free (list); 3966 } 3967 */ 3968 3969 container = e_builder_get_widget (builder, "table-home-address"); 3970 gtk_container_get_focus_chain (GTK_CONTAINER (container), &list); 3971 3972 list = add_to_tab_order (list, builder, "scrolledwindow-home-address"); 3973 list = add_to_tab_order (list, builder, "entry-home-city"); 3974 list = add_to_tab_order (list, builder, "entry-home-zip"); 3975 list = add_to_tab_order (list, builder, "entry-home-state"); 3976 list = add_to_tab_order (list, builder, "entry-home-pobox"); 3977 list = add_to_tab_order (list, builder, "entry-home-country"); 3978 list = g_list_reverse (list); 3979 3980 gtk_container_set_focus_chain (GTK_CONTAINER (container), list); 3981 g_list_free (list); 3982 3983 container = e_builder_get_widget (builder, "table-work-address"); 3984 gtk_container_get_focus_chain (GTK_CONTAINER (container), &list); 3985 3986 list = add_to_tab_order (list, builder, "scrolledwindow-work-address"); 3987 list = add_to_tab_order (list, builder, "entry-work-city"); 3988 list = add_to_tab_order (list, builder, "entry-work-zip"); 3989 list = add_to_tab_order (list, builder, "entry-work-state"); 3990 list = add_to_tab_order (list, builder, "entry-work-pobox"); 3991 list = add_to_tab_order (list, builder, "entry-work-country"); 3992 list = g_list_reverse (list); 3993 3994 gtk_container_set_focus_chain (GTK_CONTAINER (container), list); 3995 g_list_free (list); 3996 3997 container = e_builder_get_widget (builder, "table-other-address"); 3998 gtk_container_get_focus_chain (GTK_CONTAINER (container), &list); 3999 4000 list = add_to_tab_order (list, builder, "scrolledwindow-other-address"); 4001 list = add_to_tab_order (list, builder, "entry-other-city"); 4002 list = add_to_tab_order (list, builder, "entry-other-zip"); 4003 list = add_to_tab_order (list, builder, "entry-other-state"); 4004 list = add_to_tab_order (list, builder, "entry-other-pobox"); 4005 list = add_to_tab_order (list, builder, "entry-other-country"); 4006 list = g_list_reverse (list); 4007 4008 gtk_container_set_focus_chain (GTK_CONTAINER (container), list); 4009 g_list_free (list); 4010 } 4011 4012 static void 4013 expand_web_toggle (EContactEditor *ce) 4014 { 4015 GtkWidget *widget; 4016 4017 widget = e_builder_get_widget (ce->builder, "label-videourl"); 4018 expand_web (ce, !gtk_widget_get_visible (widget)); 4019 } 4020 4021 static void 4022 expand_phone_toggle (EContactEditor *ce) 4023 { 4024 GtkWidget *phone_ext_table; 4025 4026 phone_ext_table = e_builder_get_widget ( 4027 ce->builder, "table-phone-extended"); 4028 expand_phone (ce, !gtk_widget_get_visible (phone_ext_table)); 4029 } 4030 4031 static void 4032 expand_mail_toggle (EContactEditor *ce) 4033 { 4034 GtkWidget *mail; 4035 4036 mail = e_builder_get_widget (ce->builder, "entry-email-4"); 4037 expand_mail (ce, !gtk_widget_get_visible (mail)); 4038 } 4039 4040 static void 4041 e_contact_editor_init (EContactEditor *e_contact_editor) 4042 { 4043 GtkBuilder *builder; 4044 EShell *shell; 4045 ESourceRegistry *registry; 4046 GtkWidget *container; 4047 GtkWidget *widget, *label; 4048 GtkEntryCompletion *completion; 4049 4050 /* FIXME The shell should be obtained 4051 * through a constructor property. */ 4052 shell = e_shell_get_default (); 4053 registry = e_shell_get_registry (shell); 4054 4055 e_contact_editor->name = e_contact_name_new (); 4056 4057 e_contact_editor->contact = NULL; 4058 e_contact_editor->changed = FALSE; 4059 e_contact_editor->check_merge = FALSE; 4060 e_contact_editor->image_set = FALSE; 4061 e_contact_editor->image_changed = FALSE; 4062 e_contact_editor->in_async_call = FALSE; 4063 e_contact_editor->target_editable = TRUE; 4064 e_contact_editor->fullname_dialog = NULL; 4065 e_contact_editor->categories_dialog = NULL; 4066 e_contact_editor->compress_ui = e_shell_get_express_mode (shell); 4067 4068 builder = gtk_builder_new (); 4069 e_load_ui_builder_definition (builder, "contact-editor.ui"); 4070 4071 e_contact_editor->builder = builder; 4072 4073 setup_tab_order (builder); 4074 4075 e_contact_editor->app = 4076 e_builder_get_widget (builder, "contact editor"); 4077 widget = e_contact_editor->app; 4078 4079 gtk_widget_ensure_style (widget); 4080 gtk_window_set_type_hint ( 4081 GTK_WINDOW (widget), GDK_WINDOW_TYPE_HINT_NORMAL); 4082 container = gtk_dialog_get_action_area (GTK_DIALOG (widget)); 4083 gtk_container_set_border_width (GTK_CONTAINER (container), 12); 4084 container = gtk_dialog_get_content_area (GTK_DIALOG (widget)); 4085 gtk_container_set_border_width (GTK_CONTAINER (container), 0); 4086 4087 init_all (e_contact_editor); 4088 4089 widget = e_builder_get_widget ( 4090 e_contact_editor->builder, "button-image"); 4091 g_signal_connect ( 4092 widget, "clicked", 4093 G_CALLBACK (image_clicked), e_contact_editor); 4094 widget = e_builder_get_widget ( 4095 e_contact_editor->builder, "button-fullname"); 4096 g_signal_connect ( 4097 widget, "clicked", 4098 G_CALLBACK (full_name_clicked), e_contact_editor); 4099 widget = e_builder_get_widget ( 4100 e_contact_editor->builder, "button-categories"); 4101 g_signal_connect ( 4102 widget, "clicked", 4103 G_CALLBACK (categories_clicked), e_contact_editor); 4104 widget = e_builder_get_widget ( 4105 e_contact_editor->builder, "source-combo-box-source"); 4106 e_source_combo_box_set_registry ( 4107 E_SOURCE_COMBO_BOX (widget), registry); 4108 g_signal_connect ( 4109 widget, "changed", 4110 G_CALLBACK (source_changed), e_contact_editor); 4111 label = e_builder_get_widget ( 4112 e_contact_editor->builder, "where-label"); 4113 gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); 4114 widget = e_builder_get_widget ( 4115 e_contact_editor->builder, "button-ok"); 4116 g_signal_connect ( 4117 widget, "clicked", 4118 G_CALLBACK (file_save_and_close_cb), e_contact_editor); 4119 widget = e_builder_get_widget ( 4120 e_contact_editor->builder, "button-cancel"); 4121 g_signal_connect ( 4122 widget, "clicked", 4123 G_CALLBACK (file_cancel_cb), e_contact_editor); 4124 widget = e_builder_get_widget ( 4125 e_contact_editor->builder, "button-help"); 4126 g_signal_connect ( 4127 widget, "clicked", 4128 G_CALLBACK (show_help_cb), e_contact_editor); 4129 widget = e_builder_get_widget ( 4130 e_contact_editor->builder, "button-web-expand"); 4131 g_signal_connect_swapped ( 4132 widget, "clicked", 4133 G_CALLBACK (expand_web_toggle), e_contact_editor); 4134 widget = e_builder_get_widget ( 4135 e_contact_editor->builder, "button-phone-expand"); 4136 g_signal_connect_swapped ( 4137 widget, "clicked", 4138 G_CALLBACK (expand_phone_toggle), e_contact_editor); 4139 widget = e_builder_get_widget ( 4140 e_contact_editor->builder, "button-mail-expand"); 4141 g_signal_connect_swapped ( 4142 widget, "clicked", 4143 G_CALLBACK (expand_mail_toggle), e_contact_editor); 4144 4145 widget = e_builder_get_widget ( 4146 e_contact_editor->builder, "entry-fullname"); 4147 if (widget) 4148 gtk_widget_grab_focus (widget); 4149 4150 widget = e_builder_get_widget ( 4151 e_contact_editor->builder, "entry-categories"); 4152 completion = e_category_completion_new (); 4153 gtk_entry_set_completion (GTK_ENTRY (widget), completion); 4154 g_object_unref (completion); 4155 4156 /* Connect to the deletion of the dialog */ 4157 4158 g_signal_connect ( 4159 e_contact_editor->app, "delete_event", 4160 G_CALLBACK (app_delete_event_cb), e_contact_editor); 4161 4162 /* set the icon */ 4163 gtk_window_set_icon_name ( 4164 GTK_WINDOW (e_contact_editor->app), "contact-editor"); 4165 4166 /* show window */ 4167 gtk_widget_show (e_contact_editor->app); 4168 4169 gtk_application_add_window ( 4170 GTK_APPLICATION (shell), 4171 GTK_WINDOW (e_contact_editor->app)); 4172 } 4173 4174 static void 4175 e_contact_editor_dispose (GObject *object) 4176 { 4177 EContactEditor *e_contact_editor = E_CONTACT_EDITOR (object); 4178 4179 if (e_contact_editor->file_selector != NULL) { 4180 gtk_widget_destroy (e_contact_editor->file_selector); 4181 e_contact_editor->file_selector = NULL; 4182 } 4183 4184 if (e_contact_editor->writable_fields) { 4185 e_client_util_free_string_slist ( 4186 e_contact_editor->writable_fields); 4187 e_contact_editor->writable_fields = NULL; 4188 } 4189 4190 if (e_contact_editor->required_fields) { 4191 e_client_util_free_string_slist ( 4192 e_contact_editor->required_fields); 4193 e_contact_editor->required_fields = NULL; 4194 } 4195 4196 if (e_contact_editor->contact) { 4197 g_object_unref (e_contact_editor->contact); 4198 e_contact_editor->contact = NULL; 4199 } 4200 4201 if (e_contact_editor->source_client) { 4202 g_object_unref (e_contact_editor->source_client); 4203 e_contact_editor->source_client = NULL; 4204 } 4205 4206 if (e_contact_editor->target_client) { 4207 g_signal_handler_disconnect ( 4208 e_contact_editor->target_client, 4209 e_contact_editor->target_editable_id); 4210 g_object_unref (e_contact_editor->target_client); 4211 e_contact_editor->target_client = NULL; 4212 } 4213 4214 if (e_contact_editor->name) { 4215 e_contact_name_free (e_contact_editor->name); 4216 e_contact_editor->name = NULL; 4217 } 4218 4219 if (e_contact_editor->builder) { 4220 g_object_unref (e_contact_editor->builder); 4221 e_contact_editor->builder = NULL; 4222 } 4223 4224 if (e_contact_editor->cancellable != NULL) { 4225 g_object_unref (e_contact_editor->cancellable); 4226 e_contact_editor->cancellable = NULL; 4227 } 4228 4229 /* Chain up to parent's dispose() method. */ 4230 G_OBJECT_CLASS (parent_class)->dispose (object); 4231 } 4232 4233 static void 4234 supported_fields_cb (GObject *source_object, 4235 GAsyncResult *result, 4236 gpointer user_data) 4237 { 4238 EBookClient *book_client = E_BOOK_CLIENT (source_object); 4239 EContactEditor *ce = user_data; 4240 gchar *prop_value = NULL; 4241 GSList *fields; 4242 gboolean success; 4243 GError *error = NULL; 4244 4245 success = e_client_get_backend_property_finish ( 4246 E_CLIENT (book_client), result, &prop_value, &error); 4247 4248 if (!success) 4249 prop_value = NULL; 4250 4251 if (error != NULL) { 4252 g_warning ( 4253 "%s: Failed to get supported fields: %s", 4254 G_STRFUNC, error->message); 4255 g_error_free (error); 4256 } 4257 4258 if (!g_slist_find (eab_editor_get_all_editors (), ce)) { 4259 g_warning ( 4260 "supported_fields_cb called for book that's still " 4261 "around, but contact editor that's been destroyed."); 4262 g_free (prop_value); 4263 return; 4264 } 4265 4266 fields = e_client_util_parse_comma_strings (prop_value); 4267 4268 g_object_set (ce, "writable_fields", fields, NULL); 4269 4270 e_client_util_free_string_slist (fields); 4271 g_free (prop_value); 4272 4273 eab_editor_show (EAB_EDITOR (ce)); 4274 4275 sensitize_all (ce); 4276 } 4277 4278 static void 4279 required_fields_cb (GObject *source_object, 4280 GAsyncResult *result, 4281 gpointer user_data) 4282 { 4283 EBookClient *book_client = E_BOOK_CLIENT (source_object); 4284 EContactEditor *ce = user_data; 4285 gchar *prop_value = NULL; 4286 GSList *fields; 4287 gboolean success; 4288 GError *error = NULL; 4289 4290 success = e_client_get_backend_property_finish ( 4291 E_CLIENT (book_client), result, &prop_value, &error); 4292 4293 if (!success) 4294 prop_value = NULL; 4295 4296 if (error != NULL) { 4297 g_warning ( 4298 "%s: Failed to get supported fields: %s", 4299 G_STRFUNC, error->message); 4300 g_error_free (error); 4301 } 4302 4303 if (!g_slist_find (eab_editor_get_all_editors (), ce)) { 4304 g_warning ( 4305 "supported_fields_cb called for book that's still " 4306 "around, but contact editor that's been destroyed."); 4307 g_free (prop_value); 4308 return; 4309 } 4310 4311 fields = e_client_util_parse_comma_strings (prop_value); 4312 4313 g_object_set (ce, "required_fields", fields, NULL); 4314 4315 e_client_util_free_string_slist (fields); 4316 g_free (prop_value); 4317 } 4318 4319 EABEditor * 4320 e_contact_editor_new (EShell *shell, 4321 EBookClient *book_client, 4322 EContact *contact, 4323 gboolean is_new_contact, 4324 gboolean editable) 4325 { 4326 EABEditor *editor; 4327 4328 g_return_val_if_fail (E_IS_SHELL (shell), NULL); 4329 g_return_val_if_fail (E_IS_BOOK_CLIENT (book_client), NULL); 4330 g_return_val_if_fail (E_IS_CONTACT (contact), NULL); 4331 4332 editor = g_object_new (E_TYPE_CONTACT_EDITOR, "shell", shell, NULL); 4333 4334 g_object_set ( 4335 editor, 4336 "source_client", book_client, 4337 "contact", contact, 4338 "is_new_contact", is_new_contact, 4339 "editable", editable, 4340 NULL); 4341 4342 return editor; 4343 } 4344 4345 static void 4346 notify_readonly_cb (EBookClient *book_client, 4347 GParamSpec *pspec, 4348 EContactEditor *ce) 4349 { 4350 EClient *client; 4351 gint new_target_editable; 4352 gboolean changed = FALSE; 4353 4354 client = E_CLIENT (ce->target_client); 4355 new_target_editable = !e_client_is_readonly (client); 4356 4357 if (ce->target_editable != new_target_editable) 4358 changed = TRUE; 4359 4360 ce->target_editable = new_target_editable; 4361 4362 if (changed) 4363 sensitize_all (ce); 4364 } 4365 4366 static void 4367 e_contact_editor_set_property (GObject *object, 4368 guint property_id, 4369 const GValue *value, 4370 GParamSpec *pspec) 4371 { 4372 EContactEditor *editor; 4373 4374 editor = E_CONTACT_EDITOR (object); 4375 4376 switch (property_id) { 4377 case PROP_SOURCE_CLIENT: { 4378 gboolean writable; 4379 gboolean changed = FALSE; 4380 EBookClient *source_client; 4381 4382 source_client = E_BOOK_CLIENT (g_value_get_object (value)); 4383 4384 if (source_client == editor->source_client) 4385 break; 4386 4387 if (editor->source_client) 4388 g_object_unref (editor->source_client); 4389 4390 editor->source_client = source_client; 4391 g_object_ref (editor->source_client); 4392 4393 if (!editor->target_client) { 4394 editor->target_client = editor->source_client; 4395 g_object_ref (editor->target_client); 4396 4397 editor->target_editable_id = g_signal_connect ( 4398 editor->target_client, "notify::readonly", 4399 G_CALLBACK (notify_readonly_cb), editor); 4400 4401 e_client_get_backend_property ( 4402 E_CLIENT (editor->target_client), 4403 BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS, 4404 NULL, supported_fields_cb, editor); 4405 4406 e_client_get_backend_property ( 4407 E_CLIENT (editor->target_client), 4408 BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS, 4409 NULL, required_fields_cb, editor); 4410 } 4411 4412 writable = !e_client_is_readonly (E_CLIENT (editor->target_client)); 4413 if (writable != editor->target_editable) { 4414 editor->target_editable = writable; 4415 changed = TRUE; 4416 } 4417 4418 if (changed) 4419 sensitize_all (editor); 4420 4421 break; 4422 } 4423 4424 case PROP_TARGET_CLIENT: { 4425 gboolean writable; 4426 gboolean changed = FALSE; 4427 EBookClient *target_client; 4428 4429 target_client = E_BOOK_CLIENT (g_value_get_object (value)); 4430 4431 if (target_client == editor->target_client) 4432 break; 4433 4434 if (editor->target_client) { 4435 g_signal_handler_disconnect ( 4436 editor->target_client, 4437 editor->target_editable_id); 4438 g_object_unref (editor->target_client); 4439 } 4440 4441 editor->target_client = target_client; 4442 g_object_ref (editor->target_client); 4443 4444 editor->target_editable_id = g_signal_connect ( 4445 editor->target_client, "notify::readonly", 4446 G_CALLBACK (notify_readonly_cb), editor); 4447 4448 e_client_get_backend_property ( 4449 E_CLIENT (editor->target_client), 4450 BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS, 4451 NULL, supported_fields_cb, editor); 4452 4453 e_client_get_backend_property ( 4454 E_CLIENT (editor->target_client), 4455 BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS, 4456 NULL, required_fields_cb, editor); 4457 4458 if (!editor->is_new_contact) 4459 editor->changed = TRUE; 4460 4461 writable = !e_client_is_readonly (E_CLIENT (editor->target_client)); 4462 4463 if (writable != editor->target_editable) { 4464 editor->target_editable = writable; 4465 changed = TRUE; 4466 } 4467 4468 if (changed) 4469 sensitize_all (editor); 4470 4471 break; 4472 } 4473 4474 case PROP_CONTACT: 4475 if (editor->contact) 4476 g_object_unref (editor->contact); 4477 editor->contact = e_contact_duplicate ( 4478 E_CONTACT (g_value_get_object (value))); 4479 fill_in_all (editor); 4480 editor->changed = FALSE; 4481 break; 4482 4483 case PROP_IS_NEW_CONTACT: 4484 editor->is_new_contact = g_value_get_boolean (value); 4485 break; 4486 4487 case PROP_EDITABLE: { 4488 gboolean new_value = g_value_get_boolean (value); 4489 gboolean changed = (editor->target_editable != new_value); 4490 4491 editor->target_editable = new_value; 4492 4493 if (changed) 4494 sensitize_all (editor); 4495 break; 4496 } 4497 4498 case PROP_CHANGED: { 4499 gboolean new_value = g_value_get_boolean (value); 4500 gboolean changed = (editor->changed != new_value); 4501 4502 editor->changed = new_value; 4503 4504 if (changed) 4505 sensitize_ok (editor); 4506 break; 4507 } 4508 case PROP_WRITABLE_FIELDS: 4509 if (editor->writable_fields) 4510 e_client_util_free_string_slist (editor->writable_fields); 4511 4512 editor->writable_fields = 4513 e_client_util_copy_string_slist ( 4514 NULL, g_value_get_pointer (value)); 4515 4516 sensitize_all (editor); 4517 break; 4518 case PROP_REQUIRED_FIELDS: 4519 if (editor->required_fields) 4520 e_client_util_free_string_slist (editor->required_fields); 4521 editor->required_fields = 4522 e_client_util_copy_string_slist ( 4523 NULL, g_value_get_pointer (value)); 4524 break; 4525 default: 4526 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 4527 break; 4528 } 4529 } 4530 4531 static void 4532 e_contact_editor_get_property (GObject *object, 4533 guint property_id, 4534 GValue *value, 4535 GParamSpec *pspec) 4536 { 4537 EContactEditor *e_contact_editor; 4538 4539 e_contact_editor = E_CONTACT_EDITOR (object); 4540 4541 switch (property_id) { 4542 case PROP_SOURCE_CLIENT: 4543 g_value_set_object (value, e_contact_editor->source_client); 4544 break; 4545 4546 case PROP_TARGET_CLIENT: 4547 g_value_set_object (value, e_contact_editor->target_client); 4548 break; 4549 4550 case PROP_CONTACT: 4551 extract_all (e_contact_editor); 4552 g_value_set_object (value, e_contact_editor->contact); 4553 break; 4554 4555 case PROP_IS_NEW_CONTACT: 4556 g_value_set_boolean ( 4557 value, e_contact_editor->is_new_contact); 4558 break; 4559 4560 case PROP_EDITABLE: 4561 g_value_set_boolean ( 4562 value, e_contact_editor->target_editable); 4563 break; 4564 4565 case PROP_CHANGED: 4566 g_value_set_boolean ( 4567 value, e_contact_editor->changed); 4568 break; 4569 4570 case PROP_WRITABLE_FIELDS: 4571 g_value_set_pointer (value, e_contact_editor->writable_fields); 4572 break; 4573 case PROP_REQUIRED_FIELDS: 4574 g_value_set_pointer (value, e_contact_editor->required_fields); 4575 break; 4576 default: 4577 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 4578 break; 4579 } 4580 } 4581 4582 /** 4583 * e_contact_editor_raise: 4584 * @config: The %EContactEditor object. 4585 * 4586 * Raises the dialog associated with this %EContactEditor object. 4587 */ 4588 static void 4589 e_contact_editor_raise (EABEditor *editor) 4590 { 4591 EContactEditor *ce = E_CONTACT_EDITOR (editor); 4592 GdkWindow *window; 4593 4594 window = gtk_widget_get_window (ce->app); 4595 4596 if (window != NULL) 4597 gdk_window_raise (window); 4598 } 4599 4600 /** 4601 * e_contact_editor_show: 4602 * @ce: The %EContactEditor object. 4603 * 4604 * Shows the dialog associated with this %EContactEditor object. 4605 */ 4606 static void 4607 e_contact_editor_show (EABEditor *editor) 4608 { 4609 EContactEditor *ce = E_CONTACT_EDITOR (editor); 4610 gtk_widget_show (ce->app); 4611 }