evolution-3.6.4/addressbook/gui/widgets/e-minicard.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-minicard.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-minicard.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
   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 <string.h>
  28 #include <gdk/gdkkeysyms.h>
  29 #include <glib/gi18n.h>
  30 #include <libgnomecanvas/libgnomecanvas.h>
  31 #include <text/e-text.h>
  32 #include <e-util/e-util.h>
  33 #include <misc/e-canvas-utils.h>
  34 #include <misc/e-canvas.h>
  35 #include "eab-gui-util.h"
  36 #include "e-minicard.h"
  37 #include "e-minicard-label.h"
  38 #include "e-minicard-view.h"
  39 #include <e-util/e-html-utils.h>
  40 #include <e-util/e-icon-factory.h>
  41 #include "ea-addressbook.h"
  42 
  43 static void e_minicard_set_property  (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
  44 static void e_minicard_get_property  (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
  45 static void e_minicard_dispose (GObject *object);
  46 static void e_minicard_finalize (GObject *object);
  47 static gboolean e_minicard_event (GnomeCanvasItem *item, GdkEvent *event);
  48 static void e_minicard_realize (GnomeCanvasItem *item);
  49 static void e_minicard_reflow (GnomeCanvasItem *item, gint flags);
  50 static void e_minicard_style_set (EMinicard *minicard, GtkStyle *previous_style);
  51 
  52 static void e_minicard_resize_children (EMinicard *e_minicard);
  53 static void remodel (EMinicard *e_minicard);
  54 
  55 static gint e_minicard_drag_begin (EMinicard *minicard, GdkEvent *event);
  56 
  57 #define d(x)
  58 
  59 #define LIST_ICON_NAME "stock_contact-list"
  60 
  61 static void
  62 e_minicard_field_destroy (EMinicardField *field)
  63 {
  64 	g_object_run_dispose (G_OBJECT (field->label));
  65 	g_free (field);
  66 }
  67 
  68 enum {
  69 	PROP_0,
  70 	PROP_WIDTH,
  71 	PROP_HEIGHT,
  72 	PROP_HAS_FOCUS,
  73 	PROP_SELECTED,
  74 	PROP_HAS_CURSOR,
  75 	PROP_EDITABLE,
  76 	PROP_CONTACT
  77 };
  78 
  79 enum {
  80 	SELECTED,
  81 	DRAG_BEGIN,
  82 	OPEN_CONTACT,
  83 	STYLE_SET,
  84 	LAST_SIGNAL
  85 };
  86 
  87 static struct {
  88 	const gchar *name;
  89 	const gchar *pretty_name;
  90 }
  91 common_location[] =
  92 {
  93 	{ "WORK",  N_ ("Work Email")  },
  94 	{ "HOME",  N_ ("Home Email")  },
  95 	{ "OTHER", N_ ("Other Email") }
  96 };
  97 
  98 static guint signals[LAST_SIGNAL] = {0, };
  99 
 100 G_DEFINE_TYPE (EMinicard, e_minicard, GNOME_TYPE_CANVAS_GROUP)
 101 
 102 static void
 103 e_minicard_class_init (EMinicardClass *class)
 104 {
 105 	GObjectClass *object_class;
 106 	GnomeCanvasItemClass *item_class;
 107 
 108 	object_class = G_OBJECT_CLASS (class);
 109 	object_class->set_property = e_minicard_set_property;
 110 	object_class->get_property = e_minicard_get_property;
 111 	object_class->dispose = e_minicard_dispose;
 112 	object_class->finalize = e_minicard_finalize;
 113 
 114 	item_class = GNOME_CANVAS_ITEM_CLASS (class);
 115 	item_class->realize = e_minicard_realize;
 116 	item_class->event = e_minicard_event;
 117 
 118 	class->style_set = e_minicard_style_set;
 119 	class->selected = NULL;
 120 
 121 	g_object_class_install_property (
 122 		object_class,
 123 		PROP_WIDTH,
 124 		g_param_spec_double (
 125 			"width",
 126 			"Width",
 127 			NULL,
 128 			0.0, G_MAXDOUBLE, 10.0,
 129 			G_PARAM_READWRITE));
 130 
 131 	g_object_class_install_property (
 132 		object_class,
 133 		PROP_HEIGHT,
 134 		g_param_spec_double (
 135 			"height",
 136 			"Height",
 137 			NULL,
 138 			0.0, G_MAXDOUBLE, 10.0,
 139 			G_PARAM_READABLE));
 140 
 141 	g_object_class_install_property (
 142 		object_class,
 143 		PROP_HAS_FOCUS,
 144 		/* XXX should be _enum */
 145 		g_param_spec_int (
 146 			"has_focus",
 147 			"Has Focus",
 148 			NULL,
 149 			E_MINICARD_FOCUS_TYPE_START,
 150 			E_MINICARD_FOCUS_TYPE_END,
 151 			E_MINICARD_FOCUS_TYPE_START,
 152 			G_PARAM_READWRITE));
 153 
 154 	g_object_class_install_property (
 155 		object_class,
 156 		PROP_SELECTED,
 157 		g_param_spec_boolean (
 158 			"selected",
 159 			"Selected",
 160 			NULL,
 161 			FALSE,
 162 			G_PARAM_READWRITE));
 163 
 164 	g_object_class_install_property (
 165 		object_class,
 166 		PROP_HAS_CURSOR,
 167 		g_param_spec_boolean (
 168 			"has_cursor",
 169 			"Has Cursor",
 170 			NULL,
 171 			FALSE,
 172 			G_PARAM_READWRITE));
 173 
 174 	g_object_class_install_property (
 175 		object_class,
 176 		PROP_EDITABLE,
 177 		g_param_spec_boolean (
 178 			"editable",
 179 			"Editable",
 180 			NULL,
 181 			FALSE,
 182 			G_PARAM_READWRITE));
 183 
 184 	g_object_class_install_property (
 185 		object_class,
 186 		PROP_CONTACT,
 187 		g_param_spec_object (
 188 			"contact",
 189 			"Contact",
 190 			NULL,
 191 			E_TYPE_CONTACT,
 192 			G_PARAM_READWRITE));
 193 
 194 	signals[SELECTED] = g_signal_new (
 195 		"selected",
 196 		G_OBJECT_CLASS_TYPE (object_class),
 197 		G_SIGNAL_RUN_LAST,
 198 		G_STRUCT_OFFSET (EMinicardClass, selected),
 199 		NULL, NULL,
 200 		e_marshal_INT__POINTER,
 201 		G_TYPE_INT, 1,
 202 		G_TYPE_POINTER);
 203 
 204 	signals[DRAG_BEGIN] = g_signal_new (
 205 		"drag_begin",
 206 		G_OBJECT_CLASS_TYPE (object_class),
 207 		G_SIGNAL_RUN_LAST,
 208 		G_STRUCT_OFFSET (EMinicardClass, drag_begin),
 209 		NULL, NULL,
 210 		e_marshal_INT__POINTER,
 211 		G_TYPE_INT, 1,
 212 		G_TYPE_POINTER);
 213 
 214 	signals[OPEN_CONTACT] = g_signal_new (
 215 		"open-contact",
 216 		G_OBJECT_CLASS_TYPE (object_class),
 217 		G_SIGNAL_RUN_LAST,
 218 		G_STRUCT_OFFSET (EMinicardClass, open_contact),
 219 		NULL, NULL,
 220 		g_cclosure_marshal_VOID__OBJECT,
 221 		G_TYPE_NONE, 1,
 222 		E_TYPE_CONTACT);
 223 
 224 	signals[STYLE_SET] = g_signal_new (
 225 		"style_set",
 226 		G_TYPE_FROM_CLASS (object_class),
 227 		G_SIGNAL_RUN_FIRST,
 228 		G_STRUCT_OFFSET (EMinicardClass, style_set),
 229 		NULL, NULL,
 230 		g_cclosure_marshal_VOID__OBJECT,
 231 		G_TYPE_NONE, 1,
 232 		GTK_TYPE_STYLE);
 233 
 234 	/* init the accessibility support for e_minicard */
 235 	e_minicard_a11y_init ();
 236 }
 237 
 238 static void
 239 e_minicard_init (EMinicard *minicard)
 240 {
 241 	minicard->rect             = NULL;
 242 	minicard->fields           = NULL;
 243 	minicard->width            = 10;
 244 	minicard->height           = 10;
 245 	minicard->has_focus        = FALSE;
 246 	minicard->selected         = FALSE;
 247 	minicard->editable         = FALSE;
 248 	minicard->has_cursor       = FALSE;
 249 
 250 	minicard->contact          = NULL;
 251 
 252 	minicard->list_icon_pixbuf = e_icon_factory_get_icon (LIST_ICON_NAME, GTK_ICON_SIZE_MENU);
 253 	minicard->list_icon_size   = gdk_pixbuf_get_height (minicard->list_icon_pixbuf);
 254 
 255 	minicard->changed          = FALSE;
 256 
 257 	e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (minicard), e_minicard_reflow);
 258 }
 259 
 260 static void
 261 set_selected (EMinicard *minicard,
 262               gboolean selected)
 263 {
 264 	GnomeCanvas *canvas;
 265 	GtkStyle *style;
 266 
 267 	canvas = GNOME_CANVAS_ITEM (minicard)->canvas;
 268 	style = gtk_widget_get_style (GTK_WIDGET (canvas));
 269 
 270 	if (selected) {
 271 		gnome_canvas_item_set (
 272 			minicard->rect,
 273 			"outline_color_gdk", &style->bg[GTK_STATE_ACTIVE],
 274 			NULL);
 275 		gnome_canvas_item_set (
 276 			minicard->header_rect,
 277 			"fill_color_gdk", &style->bg[GTK_STATE_SELECTED],
 278 			NULL);
 279 		gnome_canvas_item_set (
 280 			minicard->header_text,
 281 			"fill_color_gdk", &style->text[GTK_STATE_SELECTED],
 282 			NULL);
 283 	} else {
 284 		gnome_canvas_item_set (
 285 			minicard->rect,
 286 			"outline_color", NULL,
 287 			NULL);
 288 		gnome_canvas_item_set (
 289 			minicard->header_rect,
 290 			"fill_color_gdk", &style->bg[GTK_STATE_NORMAL],
 291 			NULL);
 292 		gnome_canvas_item_set (
 293 			minicard->header_text,
 294 			"fill_color_gdk", &style->text[GTK_STATE_NORMAL],
 295 			NULL);
 296 	}
 297 	minicard->selected = selected;
 298 }
 299 
 300 static void
 301 set_has_cursor (EMinicard *minicard,
 302                 gboolean has_cursor)
 303 {
 304 	if (!minicard->has_focus && has_cursor)
 305 		e_canvas_item_grab_focus (GNOME_CANVAS_ITEM (minicard), FALSE);
 306 	minicard->has_cursor = has_cursor;
 307 }
 308 
 309 static void
 310 e_minicard_set_property (GObject *object,
 311                          guint property_id,
 312                          const GValue *value,
 313                          GParamSpec *pspec)
 314 {
 315 	GnomeCanvasItem *item;
 316 	EMinicard *e_minicard;
 317 	EContact *contact;
 318 	GList *l;
 319 
 320 	item = GNOME_CANVAS_ITEM (object);
 321 	e_minicard = E_MINICARD (object);
 322 
 323 	switch (property_id) {
 324 	case PROP_WIDTH:
 325 		if (e_minicard->width != g_value_get_double (value)) {
 326 			e_minicard->width = g_value_get_double (value);
 327 			e_minicard_resize_children (e_minicard);
 328 			if (item->flags & GNOME_CANVAS_ITEM_REALIZED)
 329 				e_canvas_item_request_reflow (item);
 330 		}
 331 	  break;
 332 	case PROP_HAS_FOCUS:
 333 		if (e_minicard->fields) {
 334 			if (g_value_get_int (value) == E_FOCUS_START ||
 335 			     g_value_get_int (value) == E_FOCUS_CURRENT) {
 336 				gnome_canvas_item_set (
 337 					E_MINICARD_FIELD (e_minicard->fields->data)->label,
 338 					"has_focus", g_value_get_int (value),
 339 					NULL);
 340 			} else if (g_value_get_int (value) == E_FOCUS_END) {
 341 				gnome_canvas_item_set (
 342 					E_MINICARD_FIELD (g_list_last (e_minicard->fields)->data)->label,
 343 					"has_focus", g_value_get_int (value),
 344 					NULL);
 345 			}
 346 		}
 347 		else {
 348 			if (!e_minicard->has_focus)
 349 				e_canvas_item_grab_focus (item, FALSE);
 350 		}
 351 		break;
 352 	case PROP_SELECTED:
 353 		if (e_minicard->selected != g_value_get_boolean (value))
 354 			set_selected (e_minicard, g_value_get_boolean (value));
 355 		break;
 356 	case PROP_EDITABLE:
 357 		e_minicard->editable = g_value_get_boolean (value);
 358 		for (l = e_minicard->fields; l; l = l->next) {
 359 			g_object_set (
 360 				E_MINICARD_FIELD (l->data)->label,
 361 				"editable", FALSE /* e_minicard->editable */,
 362 				NULL);
 363 		}
 364 		break;
 365 	case PROP_HAS_CURSOR:
 366 		d (g_print ("%s: PROP_HAS_CURSOR\n", G_STRFUNC));
 367 		if (e_minicard->has_cursor != g_value_get_boolean (value))
 368 			set_has_cursor (e_minicard, g_value_get_boolean (value));
 369 		break;
 370 	case PROP_CONTACT:
 371 		contact = E_CONTACT (g_value_get_object (value));
 372 		if (contact)
 373 			g_object_ref (contact);
 374 
 375 		if (e_minicard->contact)
 376 			g_object_unref (e_minicard->contact);
 377 
 378 		e_minicard->contact = contact;
 379 
 380 		remodel (e_minicard);
 381 		e_canvas_item_request_reflow (item);
 382 		e_minicard->changed = FALSE;
 383 		break;
 384 	default:
 385 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 386 		break;
 387 	}
 388 }
 389 
 390 static void
 391 e_minicard_get_property (GObject *object,
 392                          guint property_id,
 393                          GValue *value,
 394                          GParamSpec *pspec)
 395 {
 396 	EMinicard *e_minicard;
 397 
 398 	e_minicard = E_MINICARD (object);
 399 
 400 	switch (property_id) {
 401 	case PROP_WIDTH:
 402 		g_value_set_double (value, e_minicard->width);
 403 		break;
 404 	case PROP_HEIGHT:
 405 		g_value_set_double (value, e_minicard->height);
 406 		break;
 407 	case PROP_HAS_FOCUS:
 408 		g_value_set_int (value, e_minicard->has_focus ? E_FOCUS_CURRENT : E_FOCUS_NONE);
 409 		break;
 410 	case PROP_SELECTED:
 411 		g_value_set_boolean (value, e_minicard->selected);
 412 		break;
 413 	case PROP_HAS_CURSOR:
 414 		g_value_set_boolean (value, e_minicard->has_cursor);
 415 		break;
 416 	case PROP_EDITABLE:
 417 		g_value_set_boolean (value, e_minicard->editable);
 418 		break;
 419 	case PROP_CONTACT:
 420 		g_value_set_object (value, e_minicard->contact);
 421 		break;
 422 	default:
 423 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 424 		break;
 425 	}
 426 }
 427 
 428 static void
 429 e_minicard_dispose (GObject *object)
 430 {
 431 	EMinicard *e_minicard;
 432 
 433 	g_return_if_fail (object != NULL);
 434 	g_return_if_fail (E_IS_MINICARD (object));
 435 
 436 	e_minicard = E_MINICARD (object);
 437 
 438 	if (e_minicard->fields) {
 439 		g_list_foreach (e_minicard->fields, (GFunc) e_minicard_field_destroy, NULL);
 440 		g_list_free (e_minicard->fields);
 441 		e_minicard->fields = NULL;
 442 	}
 443 
 444 	if (e_minicard->list_icon_pixbuf) {
 445 		g_object_unref (e_minicard->list_icon_pixbuf);
 446 		e_minicard->list_icon_pixbuf = NULL;
 447 	}
 448 
 449 	/* Chain up to parent's dispose() method. */
 450 	G_OBJECT_CLASS (e_minicard_parent_class)->dispose (object);
 451 }
 452 
 453 static void
 454 e_minicard_finalize (GObject *object)
 455 {
 456 	EMinicard *e_minicard;
 457 
 458 	g_return_if_fail (object != NULL);
 459 	g_return_if_fail (E_IS_MINICARD (object));
 460 
 461 	e_minicard = E_MINICARD (object);
 462 
 463 	if (e_minicard->contact) {
 464 		g_object_unref (e_minicard->contact);
 465 		e_minicard->contact = NULL;
 466 	}
 467 
 468 	if (e_minicard->list_icon_pixbuf) {
 469 		g_object_unref (e_minicard->list_icon_pixbuf);
 470 		e_minicard->list_icon_pixbuf = NULL;
 471 	}
 472 
 473 	/* Chain up to parent's finalize() method. */
 474 	G_OBJECT_CLASS (e_minicard_parent_class)->finalize (object);
 475 }
 476 
 477 static void
 478 e_minicard_style_set (EMinicard *minicard,
 479                       GtkStyle *previous_style)
 480 {
 481 	GnomeCanvasItem *item = GNOME_CANVAS_ITEM (minicard);
 482 
 483 	if ((item->flags & GNOME_CANVAS_ITEM_REALIZED))
 484 		set_selected (minicard, minicard->selected);
 485 }
 486 
 487 static void
 488 e_minicard_realize (GnomeCanvasItem *item)
 489 {
 490 	EMinicard *e_minicard;
 491 	GnomeCanvasGroup *group;
 492 	GnomeCanvas *canvas;
 493 	GtkStyle *style;
 494 
 495 	e_minicard = E_MINICARD (item);
 496 	group = GNOME_CANVAS_GROUP (item);
 497 
 498 	canvas = GNOME_CANVAS_ITEM (item)->canvas;
 499 	style = gtk_widget_get_style (GTK_WIDGET (canvas));
 500 
 501 	GNOME_CANVAS_ITEM_CLASS (e_minicard_parent_class)->realize (item);
 502 
 503 	e_minicard->rect = gnome_canvas_item_new (
 504 		group,
 505 		gnome_canvas_rect_get_type (),
 506 		"x1", (gdouble) 0,
 507 		"y1", (gdouble) 0,
 508 		"x2", (gdouble) MAX (e_minicard->width - 1, 0),
 509 		"y2", (gdouble) MAX (e_minicard->height - 1, 0),
 510 		"outline_color", NULL,
 511 		NULL);
 512 
 513 	e_minicard->header_rect = gnome_canvas_item_new (
 514 		group,
 515 		gnome_canvas_rect_get_type (),
 516 		"x1", (gdouble) 2,
 517 		"y1", (gdouble) 2,
 518 		"x2", (gdouble) MAX (e_minicard->width - 3, 0),
 519 		"y2", (gdouble) MAX (e_minicard->height - 3, 0),
 520 		"fill_color_gdk", &style->bg[GTK_STATE_NORMAL],
 521 		NULL);
 522 
 523 	e_minicard->header_text = gnome_canvas_item_new (
 524 		group,
 525 		e_text_get_type (),
 526 		"width", (gdouble) MAX (e_minicard->width - 12, 0),
 527 		"clip", TRUE,
 528 		"use_ellipsis", TRUE,
 529 		"fill_color_gdk", &style->fg[GTK_STATE_NORMAL],
 530 		"text", "",
 531 		NULL);
 532 
 533 	e_canvas_item_move_absolute (e_minicard->header_text, 6, 6);
 534 
 535 	e_minicard->list_icon = gnome_canvas_item_new (
 536 		group,
 537 		gnome_canvas_pixbuf_get_type (),
 538 		"pixbuf", e_minicard->list_icon_pixbuf,
 539 		NULL);
 540 
 541 	set_selected (e_minicard, e_minicard->selected);
 542 
 543 	remodel (e_minicard);
 544 	e_canvas_item_request_reflow (item);
 545 }
 546 
 547 void
 548 e_minicard_activate_editor (EMinicard *minicard)
 549 {
 550 	g_return_if_fail (E_IS_MINICARD (minicard));
 551 
 552 	g_signal_emit (minicard, signals[OPEN_CONTACT], 0, minicard->contact);
 553 }
 554 
 555 static gboolean
 556 e_minicard_event (GnomeCanvasItem *item,
 557                   GdkEvent *event)
 558 {
 559 	EMinicard *e_minicard;
 560 
 561 	e_minicard = E_MINICARD (item);
 562 
 563 	switch (event->type) {
 564 	case GDK_FOCUS_CHANGE:
 565 		{
 566 			GdkEventFocus *focus_event = (GdkEventFocus *) event;
 567 			d (g_print ("%s: GDK_FOCUS_CHANGE: %s\n", G_STRFUNC, focus_event->in?"in":"out"));
 568 			if (focus_event->in) {
 569 				/* Chris: When EMinicard gets the cursor, if it doesn't have the focus, it should take it.  */
 570 				e_minicard->has_focus = TRUE;
 571 				if (!e_minicard->selected) {
 572 					e_minicard_selected (e_minicard, event);
 573 				}
 574 			}
 575 			else {
 576 				e_minicard->has_focus = FALSE;
 577 			}
 578 		}
 579 		break;
 580 	case GDK_BUTTON_PRESS: {
 581 		if (1 <= event->button.button && event->button.button <= 2) {
 582 			gint ret_val = e_minicard_selected (e_minicard, event);
 583 			GdkEventMask mask = ((1 << (4 + event->button.button)) |
 584 					     GDK_POINTER_MOTION_MASK |
 585 					     GDK_BUTTON_PRESS_MASK |
 586 					     GDK_BUTTON_RELEASE_MASK);
 587 
 588 			e_canvas_item_grab_focus (item, TRUE);
 589 
 590 			if (gnome_canvas_item_grab (GNOME_CANVAS_ITEM (e_minicard),
 591 						    mask, NULL, event->button.time)) {
 592 				return FALSE;
 593 			}
 594 			gtk_grab_add (GTK_WIDGET (GNOME_CANVAS_ITEM (e_minicard)->canvas));
 595 			e_minicard->button_x = event->button.x;
 596 			e_minicard->button_y = event->button.y;
 597 			e_minicard->drag_button = event->button.button;
 598 			e_minicard->drag_button_down = TRUE;
 599 			return ret_val;
 600 		} else if (event->button.button == 3) {
 601 			gint ret_val = e_minicard_selected (e_minicard, event);
 602 			if (ret_val != 0)
 603 				return ret_val;
 604 		}
 605 		break;
 606 	}
 607 	case GDK_BUTTON_RELEASE:
 608 		e_minicard_selected (e_minicard, event);
 609 		if (e_minicard->drag_button == event->button.button) {
 610 			e_minicard->drag_button = 0;
 611 			e_minicard->drag_button_down = FALSE;
 612 			e_minicard->button_x = -1;
 613 			e_minicard->button_y = -1;
 614 
 615 			if (gtk_widget_has_grab (GTK_WIDGET (GNOME_CANVAS_ITEM (e_minicard)->canvas))) {
 616 				gtk_grab_remove (GTK_WIDGET (GNOME_CANVAS_ITEM (e_minicard)->canvas));
 617 				gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (e_minicard), event->button.time);
 618 			}
 619 		}
 620 		break;
 621 	case GDK_MOTION_NOTIFY:
 622 		if (e_minicard->drag_button_down && event->motion.state & GDK_BUTTON1_MASK) {
 623 			if (MAX (abs (e_minicard->button_x - event->motion.x),
 624 				 abs (e_minicard->button_y - event->motion.y)) > 3) {
 625 				gint ret_val;
 626 
 627 				ret_val = e_minicard_drag_begin (e_minicard, event);
 628 
 629 				e_minicard->drag_button_down = FALSE;
 630 
 631 				return ret_val;
 632 			}
 633 		}
 634 		break;
 635 	case GDK_2BUTTON_PRESS:
 636 		if (event->button.button == 1 && E_IS_MINICARD_VIEW (item->parent)) {
 637 			e_minicard_activate_editor (e_minicard);
 638 			return TRUE;
 639 		}
 640 		break;
 641 	case GDK_KEY_PRESS:
 642 		if (event->key.keyval == GDK_KEY_Tab ||
 643 			event->key.keyval == GDK_KEY_KP_Tab ||
 644 			event->key.keyval == GDK_KEY_ISO_Left_Tab) {
 645 
 646 			EMinicardView *view = E_MINICARD_VIEW (item->parent);
 647 			EReflow *reflow = E_REFLOW (view);
 648 
 649 			if (reflow == NULL) {
 650 				return FALSE;
 651 			}
 652 
 653 			if (event->key.state & GDK_SHIFT_MASK) {
 654 				if (event->key.state & GDK_CONTROL_MASK) {
 655 					return FALSE;
 656 				}
 657 				else {
 658 					gint row_count = e_selection_model_row_count (reflow->selection);
 659 					gint model_index = e_selection_model_cursor_row (reflow->selection);
 660 					gint view_index = e_sorter_model_to_sorted (reflow->selection->sorter, model_index);
 661 
 662 					if (view_index == 0)
 663 						view_index = row_count - 1;
 664 					else
 665 						view_index--;
 666 
 667 					model_index = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), view_index);
 668 					if (reflow->items[model_index] == NULL) {
 669 						reflow->items[model_index] = e_reflow_model_incarnate (reflow->model, model_index, GNOME_CANVAS_GROUP (reflow));
 670 						g_object_set (
 671 							reflow->items[model_index],
 672 							"width", (gdouble) reflow->column_width,
 673 							NULL);
 674 
 675 					}
 676 					e_canvas_item_grab_focus (reflow->items[model_index], FALSE);
 677 					return TRUE;
 678 				}
 679 			}
 680 			else {
 681 				if (event->key.state & GDK_CONTROL_MASK) {
 682 					return FALSE;
 683 				}
 684 				else {
 685 					gint row_count = e_selection_model_row_count (reflow->selection);
 686 					gint model_index = e_selection_model_cursor_row (reflow->selection);
 687 					gint view_index = e_sorter_model_to_sorted (reflow->selection->sorter, model_index);
 688 
 689 					if (view_index == row_count - 1)
 690 						view_index = 0;
 691 					else
 692 						view_index++;
 693 
 694 					model_index = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), view_index);
 695 					if (reflow->items[model_index] == NULL) {
 696 						reflow->items[model_index] = e_reflow_model_incarnate (reflow->model, model_index, GNOME_CANVAS_GROUP (reflow));
 697 						g_object_set (
 698 							reflow->items[model_index],
 699 							"width", (gdouble) reflow->column_width,
 700 							NULL);
 701 
 702 					}
 703 					e_canvas_item_grab_focus (reflow->items[model_index], FALSE);
 704 					return TRUE;
 705 				}
 706 			}
 707 		}
 708 		else if (event->key.keyval == GDK_KEY_Return ||
 709 				event->key.keyval == GDK_KEY_KP_Enter) {
 710 			e_minicard_activate_editor (e_minicard);
 711 			return TRUE;
 712 		}
 713 		break;
 714 	default:
 715 		break;
 716 	}
 717 
 718 	return FALSE;
 719 }
 720 
 721 static void
 722 e_minicard_resize_children (EMinicard *e_minicard)
 723 {
 724 	GList *list;
 725 	gboolean is_list = GPOINTER_TO_INT (e_contact_get (e_minicard->contact, E_CONTACT_IS_LIST));
 726 
 727 	if (e_minicard->header_text) {
 728 		gnome_canvas_item_set (
 729 			e_minicard->header_text,
 730 			"width", ((gdouble) e_minicard->width - 12
 731 			- (is_list ? e_minicard->list_icon_size : 0.0)),
 732 			NULL);
 733 	}
 734 	if (e_minicard->list_icon) {
 735 		e_canvas_item_move_absolute (
 736 			e_minicard->list_icon,
 737 			e_minicard->width - e_minicard->list_icon_size - 3,
 738 			3);
 739 	}
 740 	for (list = e_minicard->fields; list; list = g_list_next (list)) {
 741 		gnome_canvas_item_set (
 742 			E_MINICARD_FIELD (list->data)->label,
 743 			"width", (gdouble) e_minicard->width - 4.0,
 744 			NULL);
 745 	}
 746 }
 747 
 748 static void
 749 add_field (EMinicard *e_minicard,
 750            EContactField field,
 751            gdouble left_width)
 752 {
 753 	GnomeCanvasItem *new_item;
 754 	GnomeCanvasGroup *group;
 755 	EMinicardField *minicard_field;
 756 	gchar *name;
 757 	gchar *string;
 758 	gboolean is_rtl = (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL);
 759 
 760 	group = GNOME_CANVAS_GROUP (e_minicard);
 761 
 762 	name = g_strdup_printf ("%s:", e_contact_pretty_name (field));
 763 	string = e_contact_get (e_minicard->contact, field);
 764 
 765 	new_item = e_minicard_label_new (group);
 766 
 767 	if (e_minicard->contact && e_contact_get (e_minicard->contact, E_CONTACT_IS_LIST))
 768 		gnome_canvas_item_set (
 769 			new_item,
 770 			"fieldname", is_rtl ? "" : string,
 771 			"field", is_rtl ? string : "",
 772 			"max_field_name_length", left_width,
 773 			"editable", FALSE /* e_minicard->editable */,
 774 			"width", e_minicard->width - 4.0,
 775 			NULL);
 776 	else
 777 		gnome_canvas_item_set (
 778 			new_item,
 779 			"fieldname", is_rtl ? string : name,
 780 			"field", is_rtl ? name : string,
 781 			"max_field_name_length", left_width,
 782 			"editable", FALSE /* e_minicard->editable */,
 783 			"width", e_minicard->width - 4.0,
 784 			NULL);
 785 
 786 #ifdef notyet
 787 	g_object_set (
 788 		E_MINICARD_LABEL (new_item)->field,
 789 		"allow_newlines", e_card_simple_get_allow_newlines (e_minicard->contact, field),
 790 		NULL);
 791 #endif
 792 	g_object_set_data (
 793 		G_OBJECT (E_MINICARD_LABEL (new_item)->field),
 794 		"EMinicard:field",
 795 		GINT_TO_POINTER (field));
 796 
 797 	minicard_field = g_new (EMinicardField, 1);
 798 	minicard_field->field = field;
 799 	minicard_field->label = new_item;
 800 
 801 	e_minicard->fields = g_list_append (e_minicard->fields, minicard_field);
 802 	e_canvas_item_move_absolute (new_item, 2, e_minicard->height);
 803 	g_free (name);
 804 	g_free (string);
 805 }
 806 
 807 static const gchar *
 808 get_email_location (EVCardAttribute *attr)
 809 {
 810 	gint i;
 811 
 812 	for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
 813 		if (e_vcard_attribute_has_type (attr, common_location[i].name))
 814 			return _(common_location[i].pretty_name);
 815 	}
 816 
 817 	return _("Other Email");
 818 }
 819 
 820 static void
 821 add_email_field (EMinicard *e_minicard,
 822                  GList *email_list,
 823                  gdouble left_width,
 824                  gint limit,
 825                  gboolean is_list)
 826 {
 827 	GnomeCanvasItem *new_item;
 828 	GnomeCanvasGroup *group;
 829 	EMinicardField *minicard_field;
 830 	gchar *name;
 831 	GList *l, *le;
 832 	gint count =0;
 833 	gboolean is_rtl = (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL);
 834 	GList *emails = e_contact_get (e_minicard->contact, E_CONTACT_EMAIL);
 835 	group = GNOME_CANVAS_GROUP (e_minicard);
 836 
 837 	for (l = email_list, le = emails; l != NULL && count < limit && le != NULL; l = l->next, le = le->next) {
 838 		const gchar *tmp;
 839 		gchar *email = NULL;
 840 		gchar *string = NULL;
 841 		gchar *parsed_name = NULL;
 842 		gboolean parser_check;
 843 
 844 		/* do not use name for fields in the contact list */
 845 		if (is_list) {
 846 			name = (gchar *)"";
 847 		} else {
 848 			tmp = get_email_location ((EVCardAttribute *) l->data);
 849 			name = g_strdup_printf ("%s:", tmp);
 850 		}
 851 
 852 		parser_check = eab_parse_qp_email ((const gchar *) le->data, &parsed_name, &email);
 853 		if (parser_check) {
 854 			/* if true, we had a quoted printable mail address */
 855 			string = g_strdup_printf ("%s <%s>", parsed_name, email);
 856 		} else {
 857 			/* we got a NON-quoted printable string */
 858 			string = g_strdup (le->data);
 859 		}
 860 
 861 		new_item = e_minicard_label_new (group);
 862 
 863 		gnome_canvas_item_set (
 864 			new_item,
 865 			"fieldname", is_rtl ? string : name,
 866 			"field", is_rtl ? name : string,
 867 			"max_field_name_length", left_width,
 868 			"editable", FALSE /* e_minicard->editable */,
 869 			"width", e_minicard->width - 4.0,
 870 			NULL);
 871 
 872 #ifdef notyet
 873 		g_object_set (
 874 			E_MINICARD_LABEL (new_item)->field,
 875 			"allow_newlines", e_card_simple_get_allow_newlines (e_minicard->contact, field),
 876 			NULL);
 877 #endif
 878 		g_object_set_data (
 879 			G_OBJECT (E_MINICARD_LABEL (new_item)->field),
 880 			"EMinicard:field",
 881 			GINT_TO_POINTER (E_CONTACT_EMAIL));
 882 
 883 		minicard_field = g_new (EMinicardField, 1);
 884 		minicard_field->field = E_CONTACT_EMAIL;
 885 		minicard_field->label = new_item;
 886 
 887 		e_minicard->fields = g_list_append (e_minicard->fields, minicard_field);
 888 		e_canvas_item_move_absolute (new_item, 2, e_minicard->height);
 889 		count++;
 890 		if (!is_list)
 891 			g_free (name);
 892 		g_free (string);
 893 		g_free (parsed_name);
 894 		g_free (email);
 895 	}
 896 	g_list_foreach (emails, (GFunc) g_free, NULL);
 897 	g_list_free (emails);
 898 }
 899 
 900 static gint
 901 get_left_width (EMinicard *e_minicard,
 902                 gboolean is_list)
 903 {
 904 	gchar *name;
 905 	EContactField field;
 906 	gint width = -1;
 907 	PangoLayout *layout;
 908 
 909 	if (is_list)
 910 		return 0;
 911 
 912 	layout = gtk_widget_create_pango_layout (GTK_WIDGET (GNOME_CANVAS_ITEM (e_minicard)->canvas), "");
 913 	for (field = E_CONTACT_FULL_NAME; field != E_CONTACT_LAST_SIMPLE_STRING; field++) {
 914 		gint this_width;
 915 
 916 		if (field == E_CONTACT_FAMILY_NAME || field == E_CONTACT_GIVEN_NAME)
 917 			continue;
 918 
 919 		name = g_strdup_printf ("%s:", e_contact_pretty_name (field));
 920 		pango_layout_set_text (layout, name, -1);
 921 		pango_layout_get_pixel_size (layout, &this_width, NULL);
 922 		if (width < this_width)
 923 			width = this_width;
 924 		g_free (name);
 925 	}
 926 	g_object_unref (layout);
 927 	return width;
 928 }
 929 
 930 static void
 931 remodel (EMinicard *e_minicard)
 932 {
 933 	GnomeCanvasItem *item = GNOME_CANVAS_ITEM (e_minicard);
 934 	gint count = 0;
 935 
 936 	if (!(item->flags & GNOME_CANVAS_ITEM_REALIZED))
 937 		return;
 938 
 939 	if (e_minicard->contact) {
 940 		EContactField field;
 941 		GList *list;
 942 		gchar *file_as;
 943 		gint left_width = -1;
 944 		gboolean is_list = FALSE;
 945 		gboolean email_rendered = FALSE;
 946 		gboolean has_voice = FALSE, has_fax = FALSE;
 947 
 948 		if (e_minicard->header_text) {
 949 			file_as = e_contact_get (e_minicard->contact, E_CONTACT_FILE_AS);
 950 			gnome_canvas_item_set (
 951 				e_minicard->header_text,
 952 				"text", file_as ? file_as : "",
 953 				NULL);
 954 			g_free (file_as);
 955 		}
 956 
 957 		if (e_minicard->contact && e_contact_get (e_minicard->contact, E_CONTACT_IS_LIST))
 958 			is_list = TRUE;
 959 
 960 		if (is_list)
 961 			gnome_canvas_item_show (e_minicard->list_icon);
 962 		else
 963 			gnome_canvas_item_hide (e_minicard->list_icon);
 964 
 965 		list = e_minicard->fields;
 966 		e_minicard->fields = NULL;
 967 
 968 		for (field = E_CONTACT_FULL_NAME; field != (E_CONTACT_LAST_SIMPLE_STRING -1) && count < 5; field++) {
 969 			EMinicardField *minicard_field = NULL;
 970 			gboolean is_email = FALSE;
 971 
 972 			if (field == E_CONTACT_FAMILY_NAME || field == E_CONTACT_GIVEN_NAME ||
 973 			    (has_voice && field == E_CONTACT_PHONE_OTHER) ||
 974 			    (has_fax && field == E_CONTACT_PHONE_OTHER_FAX))
 975 				continue;
 976 
 977 			if (field == E_CONTACT_FULL_NAME && is_list)
 978 				continue;
 979 
 980 			if (field == E_CONTACT_EMAIL_1 || field == E_CONTACT_EMAIL_2 || field == E_CONTACT_EMAIL_3 || field == E_CONTACT_EMAIL_4) {
 981 				if (email_rendered)
 982 					continue;
 983 				email_rendered = TRUE;
 984 				is_email = TRUE;
 985 			}
 986 
 987 			if (list)
 988 				minicard_field = list->data;
 989 			if (minicard_field && minicard_field->field == field) {
 990 				GList *this_list = list;
 991 				gchar *string;
 992 
 993 				string = e_contact_get (e_minicard->contact, field);
 994 				if (string && *string) {
 995 					e_minicard->fields = g_list_append (e_minicard->fields, minicard_field);
 996 					g_object_set (
 997 						minicard_field->label,
 998 						"field", string,
 999 						NULL);
1000 					count++;
1001 				} else {
1002 					e_minicard_field_destroy (minicard_field);
1003 				}
1004 				list = g_list_delete_link (list, this_list);
1005 				g_free (string);
1006 			} else {
1007 				gchar *string;
1008 				if (left_width == -1) {
1009 					left_width = get_left_width (e_minicard, is_list);
1010 				}
1011 
1012 				if (is_email) {
1013 					GList *email;
1014 					gint limit;
1015 
1016 					limit = 5 - count;
1017 					email = e_contact_get_attributes (e_minicard->contact, E_CONTACT_EMAIL);
1018 					add_email_field (e_minicard, email, left_width, limit, is_list);
1019 					if (count + limit >5)
1020 						count = 5;
1021 					else
1022 						count = count + g_list_length (email);
1023 					g_list_free_full (email, (GDestroyNotify) e_vcard_attribute_free);
1024 				} else {
1025 					string = e_contact_get (e_minicard->contact, field);
1026 					if (string && *string) {
1027 						add_field (e_minicard, field, left_width);
1028 						count++;
1029 
1030 						has_voice = has_voice ||
1031 							    field == E_CONTACT_PHONE_BUSINESS ||
1032 							    field == E_CONTACT_PHONE_BUSINESS_2 ||
1033 							    field == E_CONTACT_PHONE_HOME ||
1034 							    field == E_CONTACT_PHONE_HOME_2;
1035 						has_fax = has_fax ||
1036 							  field == E_CONTACT_PHONE_BUSINESS_FAX ||
1037 							  field == E_CONTACT_PHONE_HOME_FAX;
1038 					}
1039 					g_free (string);
1040 				}
1041 			}
1042 		}
1043 
1044 		g_list_foreach (list, (GFunc) e_minicard_field_destroy, NULL);
1045 		g_list_free (list);
1046 	}
1047 }
1048 
1049 static void
1050 e_minicard_reflow (GnomeCanvasItem *item,
1051                    gint flags)
1052 {
1053 	EMinicard *e_minicard = E_MINICARD (item);
1054 
1055 	if (item->flags & GNOME_CANVAS_ITEM_REALIZED) {
1056 		GList *list;
1057 		gdouble text_height;
1058 		gint old_height;
1059 
1060 		old_height = e_minicard->height;
1061 
1062 		g_object_get (
1063 			e_minicard->header_text,
1064 			"text_height", &text_height,
1065 			NULL);
1066 
1067 		e_minicard->height = text_height + 10.0;
1068 
1069 		gnome_canvas_item_set (
1070 			e_minicard->header_rect,
1071 			"y2", text_height + 9.0,
1072 			NULL);
1073 
1074 		for (list = e_minicard->fields; list; list = g_list_next (list)) {
1075 			EMinicardField *field = E_MINICARD_FIELD (list->data);
1076 			/* Why not use the item that is passed in? */
1077 			GnomeCanvasItem *item = field->label;
1078 			g_object_get (
1079 				item,
1080 				"height", &text_height,
1081 				NULL);
1082 			e_canvas_item_move_absolute (item, 2, e_minicard->height);
1083 			e_minicard->height += text_height;
1084 		}
1085 		e_minicard->height += 2;
1086 
1087 		gnome_canvas_item_set (
1088 			e_minicard->rect,
1089 			"x2", (gdouble) e_minicard->width - 1.0,
1090 			"y2", (gdouble) e_minicard->height - 1.0,
1091 			NULL);
1092 		gnome_canvas_item_set (
1093 			e_minicard->header_rect,
1094 			"x2", (gdouble) e_minicard->width - 3.0,
1095 			NULL);
1096 
1097 		if (old_height != e_minicard->height)
1098 			e_canvas_item_request_parent_reflow (item);
1099 	}
1100 }
1101 
1102 const gchar *
1103 e_minicard_get_card_id (EMinicard *minicard)
1104 {
1105 	g_return_val_if_fail (minicard != NULL, NULL);
1106 	g_return_val_if_fail (E_IS_MINICARD (minicard), NULL);
1107 
1108 	if (minicard->contact) {
1109 		return e_contact_get_const (minicard->contact, E_CONTACT_UID);
1110 	} else {
1111 		return "";
1112 	}
1113 }
1114 
1115 gint
1116 e_minicard_compare (EMinicard *minicard1,
1117                     EMinicard *minicard2)
1118 {
1119 	gint cmp = 0;
1120 
1121 	g_return_val_if_fail (minicard1 != NULL, 0);
1122 	g_return_val_if_fail (E_IS_MINICARD (minicard1), 0);
1123 	g_return_val_if_fail (minicard2 != NULL, 0);
1124 	g_return_val_if_fail (E_IS_MINICARD (minicard2), 0);
1125 
1126 	if (minicard1->contact && minicard2->contact) {
1127 		gchar *file_as1, *file_as2;
1128 		g_object_get (
1129 			minicard1->contact,
1130 			"file_as", &file_as1,
1131 			NULL);
1132 		g_object_get (
1133 			minicard2->contact,
1134 			"file_as", &file_as2,
1135 			NULL);
1136 
1137 		if (file_as1 && file_as2)
1138 			cmp = g_utf8_collate (file_as1, file_as2);
1139 		else if (file_as1)
1140 			cmp = -1;
1141 		else if (file_as2)
1142 			cmp = 1;
1143 		else
1144 			cmp = strcmp (e_minicard_get_card_id (minicard1), e_minicard_get_card_id (minicard2));
1145 
1146 		g_free (file_as1);
1147 		g_free (file_as2);
1148 	}
1149 
1150 	return cmp;
1151 }
1152 
1153 gint
1154 e_minicard_selected (EMinicard *minicard,
1155                      GdkEvent *event)
1156 {
1157 	gint ret_val = 0;
1158 	GnomeCanvasItem *item = GNOME_CANVAS_ITEM (minicard);
1159 	if (item->parent) {
1160 		guint signal_id = g_signal_lookup ("selection_event", G_OBJECT_TYPE (item->parent));
1161 		/* We should probably check the signature here, but I
1162 		 * don't think it's worth the time required to code
1163 		 * it.
1164 		 */
1165 		if (signal_id != 0) {
1166 			g_signal_emit (
1167 				item->parent,
1168 				signal_id, 0,
1169 				item, event, &ret_val);
1170 		}
1171 	}
1172 	return ret_val;
1173 }
1174 
1175 static gint
1176 e_minicard_drag_begin (EMinicard *minicard,
1177                        GdkEvent *event)
1178 {
1179 	gint ret_val = 0;
1180 	GnomeCanvasItem *parent;
1181 	g_signal_emit (
1182 		minicard,
1183 		signals[DRAG_BEGIN], 0,
1184 		event, &ret_val);
1185 
1186 	parent = GNOME_CANVAS_ITEM (minicard)->parent;
1187 	if (parent && E_IS_REFLOW (parent)) {
1188 		E_REFLOW (parent)->maybe_in_drag = FALSE;
1189 	}
1190 	return ret_val;
1191 }