No issues found
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
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #include "eab-contact-formatter.h"
22
23 #include "eab-gui-util.h"
24 #include "e-util/e-util.h"
25 #include "e-util/e-util-private.h"
26 #include "e-util/e-html-utils.h"
27 #include "e-util/e-icon-factory.h"
28 #include "e-util/e-plugin-ui.h"
29
30 #ifdef WITH_CONTACT_MAPS
31 #include "widgets/misc/e-contact-map.h"
32 #endif
33
34 #include <string.h>
35 #include <glib/gi18n.h>
36
37 G_DEFINE_TYPE (
38 EABContactFormatter,
39 eab_contact_formatter,
40 G_TYPE_OBJECT);
41
42 #define EAB_CONTACT_FORMATTER_GET_PRIVATE(obj) \
43 (G_TYPE_INSTANCE_GET_PRIVATE \
44 ((obj), EAB_TYPE_CONTACT_FORMATTER, EABContactFormatterPrivate))
45
46 #define TEXT_IS_RIGHT_TO_LEFT \
47 (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
48
49 enum {
50 PROP_0,
51 PROP_DISPLAY_MODE,
52 PROP_RENDER_MAPS,
53 PROP_STYLE,
54 PROP_STATE
55 };
56
57 struct _EABContactFormatterPrivate {
58
59 EContact *contact;
60
61 EABContactDisplayMode mode;
62 gboolean render_maps;
63
64 GtkStyle *style;
65 GtkStateType state;
66 };
67
68 static struct {
69 const gchar *name;
70 const gchar *pretty_name;
71 }
72 common_location[] =
73 {
74 { "WORK", N_ ("Work") },
75 { "HOME", N_ ("Home") },
76 { "OTHER", N_ ("Other") }
77 };
78
79 #define IMAGE_COL_WIDTH "20"
80 #define CONTACT_LIST_ICON "stock_contact-list"
81 #define AIM_ICON "im-aim"
82 #define GROUPWISE_ICON "im-nov"
83 #define ICQ_ICON "im-icq"
84 #define JABBER_ICON "im-jabber"
85 #define MSN_ICON "im-msn"
86 #define YAHOO_ICON "im-yahoo"
87 #define GADUGADU_ICON "im-gadugadu"
88 #define SKYPE_ICON "stock_people"
89 #define TWITTER_ICON "im-twitter"
90 #define VIDEOCONF_ICON "stock_video-conferencing"
91
92 #define MAX_COMPACT_IMAGE_DIMENSION 48
93
94 #define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n" \
95 "<head>\n<meta name=\"generator\" content=\"Evolution Addressbook Component\">\n" \
96 "<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">" \
97 "<style type=\"text/css\">\n" \
98 " div#header { width:100%; clear: both; }\n" \
99 " div#columns { width: 100%; clear: both; }\n" \
100 " div#footer { width: 100%; clear: both; }\n" \
101 " div.column { width: auto; float: left; margin-right: 15px; }\n" \
102 " img#contact-photo { float: left; }\n" \
103 " div#contact-name { float: left; margin-left: 20px; }\n" \
104 "</style>\n" \
105 "</head>\n"
106
107 static gboolean
108 icon_available (const gchar *icon)
109 {
110 GtkIconTheme *icon_theme;
111 GtkIconInfo *icon_info;
112
113 if (!icon)
114 return FALSE;
115
116 icon_theme = gtk_icon_theme_get_default ();
117 icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon, 16, 0);
118 if (icon_info != NULL)
119 gtk_icon_info_free (icon_info);
120
121 return icon_info != NULL;
122 }
123
124 static void
125 render_address_link (GString *buffer,
126 EContact *contact,
127 gint map_type)
128 {
129 EContactAddress *adr;
130 GString *link = g_string_new ("");
131
132 adr = e_contact_get (contact, map_type);
133 if (adr &&
134 (adr->street || adr->locality || adr->region || adr->country)) {
135 gchar *escaped;
136
137 if (adr->street && *adr->street)
138 g_string_append_printf (link, "%s, ", adr->street);
139
140 if (adr->locality && *adr->locality)
141 g_string_append_printf (link, "%s, ", adr->locality);
142
143 if (adr->region && *adr->region)
144 g_string_append_printf (link, "%s, ", adr->region);
145
146 if (adr->country && *adr->country)
147 g_string_append_printf (link, "%s", adr->country);
148
149 escaped = g_uri_escape_string (link->str, NULL, TRUE);
150 g_string_assign (link, escaped);
151 g_free (escaped);
152
153 g_string_prepend (link, "<a href=\"http://maps.google.com?q=");
154 g_string_append_printf (link, "\">%s</a>", _("Open map"));
155 }
156
157 if (adr)
158 e_contact_address_free (adr);
159
160 g_string_append (buffer, link->str);
161 g_string_free (link, TRUE);
162 }
163
164 static void
165 accum_address (GString *buffer,
166 EContact *contact,
167 const gchar *html_label,
168 EContactField adr_field,
169 EContactField label_field)
170 {
171 EContactAddress *adr;
172 const gchar *label;
173 GString *map_link = g_string_new ("<br>");
174
175 render_address_link (map_link, contact, adr_field);
176
177 label = e_contact_get_const (contact, label_field);
178 if (label) {
179 gchar *html = e_text_to_html (label, E_TEXT_TO_HTML_CONVERT_NL);
180
181 if (TEXT_IS_RIGHT_TO_LEFT) {
182 g_string_append_printf (
183 buffer,
184 "<tr>"
185 "<td align=\"right\" valign=\"top\" nowrap>%s</td>"
186 "<th>%s:<br>%s</th>"
187 "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td>"
188 "</tr>",
189 html, html_label, map_link->str);
190 } else {
191 g_string_append_printf (
192 buffer,
193 "<tr>"
194 "<td width=\"" IMAGE_COL_WIDTH "\"></td>"
195 "<th>%s:<br>%s</th>"
196 "<td valign=\"top\" nowrap>%s</td>"
197 "</tr>",
198 html_label, map_link->str, html);
199 }
200
201 g_free (html);
202 g_string_free (map_link, TRUE);
203 return;
204 }
205
206 adr = e_contact_get (contact, adr_field);
207 if (adr &&
208 (adr->po || adr->ext || adr->street || adr->locality ||
209 adr->region || adr->code || adr->country)) {
210
211 if (TEXT_IS_RIGHT_TO_LEFT) {
212 g_string_append_printf (
213 buffer, "<tr><td align=\"right\" valign=\"top\" nowrap>");
214 } else {
215 g_string_append_printf (
216 buffer,
217 "<tr>"
218 "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td>"
219 "<th>%s:<br>%s</th>"
220 "<td valign=\"top\" nowrap>",
221 html_label, map_link->str);
222 }
223
224 if (adr->po && *adr->po)
225 g_string_append_printf (buffer, "%s<br>", adr->po);
226
227 if (adr->ext && *adr->ext)
228 g_string_append_printf (buffer, "%s<br>", adr->ext);
229
230 if (adr->street && *adr->street)
231 g_string_append_printf (buffer, "%s<br>", adr->street);
232
233 if (adr->locality && *adr->locality)
234 g_string_append_printf (buffer, "%s<br>", adr->locality);
235
236 if (adr->region && *adr->region)
237 g_string_append_printf (buffer, "%s<br>", adr->region);
238
239 if (adr->code && *adr->code)
240 g_string_append_printf (buffer, "%s<br>", adr->code);
241
242 if (adr->country && *adr->country)
243 g_string_append_printf (buffer, "%s<br>", adr->country);
244
245 if (TEXT_IS_RIGHT_TO_LEFT) {
246 g_string_append_printf (
247 buffer,
248 "</td><th%s:<br>%s</th>"
249 "<td width=\"" IMAGE_COL_WIDTH "\"></td>"
250 "</tr>", html_label, map_link->str);
251 } else {
252 g_string_append_printf (buffer, "</td></tr>");
253 }
254
255 }
256
257 if (adr)
258 e_contact_address_free (adr);
259
260 g_string_free (map_link, TRUE);
261 }
262
263 static void
264 render_table_row (GString *buffer,
265 const gchar *label,
266 const gchar *str,
267 const gchar *icon,
268 guint html_flags)
269 {
270 const gchar *icon_html;
271 gchar *value;
272
273 if (html_flags)
274 value = e_text_to_html (str, html_flags);
275 else
276 value = (gchar *) str;
277
278 if (icon && icon_available (icon)) {
279 icon_html = g_strdup_printf ("<img src=\"gtk-stock://%s\" width=\"16\" height=\"16\" />", icon);
280 } else {
281 icon_html = "";
282 }
283
284 if (TEXT_IS_RIGHT_TO_LEFT) {
285 g_string_append_printf (
286 buffer, "<tr>"
287 "<td valign=\"top\" align=\"right\">%s</td>"
288 "<th align=\"right\" valign=\"top\" width=\"100\" nowrap>:%s</th>"
289 "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">%s</td>"
290 "</tr>",
291 value, label, icon_html);
292 } else {
293 g_string_append_printf (
294 buffer, "<tr>"
295 "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">%s</td>"
296 "<th valign=\"top\" width=\"100\" nowrap>%s:</th>"
297 "<td valign=\"top\">%s</td>"
298 "</tr>",
299 icon_html, label, value);
300 }
301
302 if (html_flags)
303 g_free (value);
304 }
305
306 static void
307 accum_attribute (GString *buffer,
308 EContact *contact,
309 const gchar *html_label,
310 EContactField field,
311 const gchar *icon,
312 guint html_flags)
313 {
314 const gchar *str;
315
316 str = e_contact_get_const (contact, field);
317
318 if (str != NULL && *str != '\0')
319 render_table_row (buffer, html_label, str, icon, html_flags);
320 }
321
322 static void
323 accum_time_attribute (GString *buffer,
324 EContact *contact,
325 const gchar *html_label,
326 EContactField field,
327 const gchar *icon,
328 guint html_flags)
329 {
330 EContactDate *date;
331 GDate *gdate = NULL;
332 gchar sdate[100];
333
334 date = e_contact_get (contact, field);
335 if (date) {
336 gdate = g_date_new_dmy (
337 date->day,
338 date->month,
339 date->year);
340 g_date_strftime (sdate, 100, "%x", gdate);
341 g_date_free (gdate);
342 render_table_row (buffer, html_label, sdate, icon, html_flags);
343 e_contact_date_free (date);
344 }
345 }
346
347 static void
348 accum_attribute_multival (GString *buffer,
349 EContact *contact,
350 const gchar *html_label,
351 EContactField field,
352 const gchar *icon,
353 guint html_flags)
354 {
355 GList *val_list, *l;
356 GString *val = g_string_new ("");
357
358 val_list = e_contact_get (contact, field);
359
360 for (l = val_list; l; l = l->next) {
361 if (l != val_list)
362 g_string_append (val, "<br>");
363
364 g_string_append (val, l->data);
365 }
366
367 if (val->str && *val->str)
368 render_table_row (buffer, html_label, val->str, icon, html_flags);
369
370 g_string_free (val, TRUE);
371 g_list_foreach (val_list, (GFunc) g_free, NULL);
372 g_list_free (val_list);
373 }
374
375 static const gchar *
376 get_email_location (EVCardAttribute *attr)
377 {
378 gint i;
379
380 for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
381 if (e_vcard_attribute_has_type (attr, common_location[i].name))
382 return _(common_location[i].pretty_name);
383 }
384
385 return _("Other");
386 }
387
388 static void
389 render_title_block (EABContactFormatter *formatter,
390 GString *buffer)
391 {
392 const gchar *str;
393 gchar *html;
394 EContactPhoto *photo;
395 EContact *contact;
396
397 contact = formatter->priv->contact;
398
399 g_string_append_printf (
400 buffer,
401 "<table border=\"0\"><tr>"
402 "<td %s valign=\"middle\">", TEXT_IS_RIGHT_TO_LEFT ?
403 "align=\"right\"" : "");
404
405 photo = e_contact_get (contact, E_CONTACT_PHOTO);
406 if (!photo)
407 photo = e_contact_get (contact, E_CONTACT_LOGO);
408
409 if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
410 gchar *photo_data;
411 photo_data = g_base64_encode (
412 photo->data.inlined.data,
413 photo->data.inlined.length);
414 g_string_append_printf (
415 buffer, "<img border=\"1\" src=\"data:%s;base64,%s\">",
416 photo->data.inlined.mime_type,
417 photo_data);
418 } else if (photo && photo->type == E_CONTACT_PHOTO_TYPE_URI && photo->data.uri && *photo->data.uri) {
419 gboolean is_local = g_str_has_prefix (photo->data.uri, "file://");
420 gchar *unescaped = g_uri_unescape_string (photo->data.uri, NULL);
421 g_string_append_printf (
422 buffer, "<img border=\"1\" src=\"%s%s\">",
423 is_local ? "evo-" : "", unescaped);
424 g_free (unescaped);
425 }
426
427 if (photo)
428 e_contact_photo_free (photo);
429
430 if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
431 g_string_append_printf (buffer, "<img src=\"gtk-stock://%s\">", CONTACT_LIST_ICON);
432 }
433
434 g_string_append_printf (
435 buffer,
436 "</td><td width=\"20\"></td><td %s valign=\"top\">\n",
437 TEXT_IS_RIGHT_TO_LEFT ? "align=\"right\"" : "");
438
439 str = e_contact_get_const (contact, E_CONTACT_FILE_AS);
440 if (!str)
441 str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
442
443 if (str) {
444 html = e_text_to_html (str, 0);
445 if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
446 g_string_append_printf (
447 buffer,
448 "<h2><a href=\"internal-mailto:0\">%s</a></h2>",
449 html);
450 } else {
451 g_string_append_printf (buffer, "<h2>%s</h2>", html);
452 }
453 g_free (html);
454 }
455
456 g_string_append (buffer, "</td></tr></table>");
457 }
458
459 static void
460 render_contact_list_row (EABContactFormatter *formatter,
461 EDestination *destination,
462 GString *buffer)
463 {
464 gchar *evolution_imagesdir;
465 gboolean list_collapsed = FALSE;
466 const gchar *textrep;
467 gchar *name = NULL, *email_addr = NULL;
468
469 evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
470
471 textrep = e_destination_get_textrep (destination, TRUE);
472 if (!eab_parse_qp_email (textrep, &name, &email_addr))
473 email_addr = g_strdup (textrep);
474
475 g_string_append (buffer, "<tr>");
476 if (e_destination_is_evolution_list (destination)) {
477 g_string_append_printf (
478 buffer,
479 "<td width=" IMAGE_COL_WIDTH " valign=\"top\" align=\"left\">"
480 "<img src=\"evo-file://%s/minus.png\" "
481 "id=\"%s\" "
482 "class=\"navigable _evo_collapse_button\">"
483 "</td><td width=\"100%%\" align=\"left\">%s",
484 evolution_imagesdir,
485 e_destination_get_contact_uid (destination),
486 name ? name : email_addr);
487
488 if (!list_collapsed) {
489 const GList *dest, *dests;
490 g_string_append_printf (
491 buffer,
492 "<br><table cellspacing=\"1\" id=\"list-%s\">",
493 e_destination_get_contact_uid (destination));
494
495 dests = e_destination_list_get_root_dests (destination);
496 for (dest = dests; dest; dest = dest->next) {
497 render_contact_list_row (
498 formatter, dest->data, buffer);
499 }
500
501 g_string_append (buffer, "</table>");
502 }
503
504 g_string_append (buffer, "</td>");
505
506 } else {
507 if (name && *name) {
508 g_string_append_printf (
509 buffer,
510 "<td colspan=\"2\">%s <"
511 "<a href=\"mailto:%s\">%s</a>>"
512 "</td>",
513 name, email_addr, email_addr);
514 } else {
515 g_string_append_printf (
516 buffer,
517 "<td colspan=\"2\">"
518 "<a href=\"mailto:%s\">%s</a>"
519 "</td>",
520 email_addr, email_addr);
521 }
522 }
523
524 g_string_append (buffer, "</tr>");
525
526 g_free (evolution_imagesdir);
527 g_free (name);
528 g_free (email_addr);
529 }
530
531 static void
532 render_contact_list (EABContactFormatter *formatter,
533 GString *buffer)
534 {
535 EContact *contact;
536 EDestination *destination;
537 const GList *dest, *dests;
538
539 contact = formatter->priv->contact;
540
541 destination = e_destination_new ();
542 e_destination_set_contact (destination, contact, 0);
543 dests = e_destination_list_get_root_dests (destination);
544
545 render_title_block (formatter, buffer);
546
547 g_string_append_printf (
548 buffer,
549 "<table border=\"0\"><tr><th colspan=\"2\">%s</th></tr>"
550 "<tr><td with=" IMAGE_COL_WIDTH "></td><td>", _("List Members:"));
551
552 g_string_append (buffer, "<table border=\"0\" cellspacing=\"1\">");
553
554 for (dest = dests; dest; dest = dest->next)
555 render_contact_list_row (formatter, dest->data, buffer);
556
557 g_string_append (buffer, "</table>");
558 g_string_append (buffer, "</td></tr></table>");
559
560 g_object_unref (destination);
561 }
562
563 static void
564 render_contact_column (EABContactFormatter *formatter,
565 GString *buffer)
566 {
567 EContact *contact;
568 GString *accum, *email;
569 GList *email_list, *l, *email_attr_list, *al;
570 gint email_num = 0;
571 const gchar *nl;
572
573 contact = formatter->priv->contact;
574 email = g_string_new ("");
575 nl = "";
576
577 email_list = e_contact_get (contact, E_CONTACT_EMAIL);
578 email_attr_list = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
579
580 for (l = email_list, al = email_attr_list; l && al; l = l->next, al = al->next) {
581 gchar *name = NULL, *mail = NULL;
582 gchar *attr_str = (gchar *) get_email_location ((EVCardAttribute *) al->data);
583
584 if (!eab_parse_qp_email (l->data, &name, &mail))
585 mail = e_text_to_html (l->data, 0);
586
587 g_string_append_printf (
588 email,
589 "%s%s%s<a href=\"internal-mailto:%d\">%s</a>%s "
590 "<span class=\"header\">(%s)</span>",
591 nl,
592 name ? name : "",
593 name ? " <" : "",
594 email_num,
595 mail,
596 name ? ">" : "",
597 attr_str ? attr_str : "");
598 email_num++;
599 nl = "<br>";
600
601 g_free (name);
602 g_free (mail);
603 }
604 g_list_foreach (email_list, (GFunc) g_free, NULL);
605 g_list_foreach (email_attr_list, (GFunc) e_vcard_attribute_free, NULL);
606 g_list_free (email_list);
607 g_list_free (email_attr_list);
608
609 accum = g_string_new ("");
610
611 if (email->len)
612 render_table_row (accum, _("Email"), email->str, NULL, 0);
613
614 accum_attribute (accum, contact, _("Nickname"), E_CONTACT_NICKNAME, NULL, 0);
615 accum_attribute_multival (accum, contact, _("AIM"), E_CONTACT_IM_AIM, AIM_ICON, 0);
616 accum_attribute_multival (accum, contact, _("GroupWise"), E_CONTACT_IM_GROUPWISE, GROUPWISE_ICON, 0);
617 accum_attribute_multival (accum, contact, _("ICQ"), E_CONTACT_IM_ICQ, ICQ_ICON, 0);
618 accum_attribute_multival (accum, contact, _("Jabber"), E_CONTACT_IM_JABBER, JABBER_ICON, 0);
619 accum_attribute_multival (accum, contact, _("MSN"), E_CONTACT_IM_MSN, MSN_ICON, 0);
620 accum_attribute_multival (accum, contact, _("Yahoo"), E_CONTACT_IM_YAHOO, YAHOO_ICON, 0);
621 accum_attribute_multival (accum, contact, _("Gadu-Gadu"), E_CONTACT_IM_GADUGADU, GADUGADU_ICON, 0);
622 accum_attribute_multival (accum, contact, _("Skype"), E_CONTACT_IM_SKYPE, SKYPE_ICON, 0);
623 accum_attribute_multival (accum, contact, _("Twitter"), E_CONTACT_IM_TWITTER, TWITTER_ICON, 0);
624
625 if (accum->len)
626 g_string_append_printf (
627 buffer,
628 "<div class=\"column\" id=\"contact-internet\">"
629 "<table border=\"0\" cellspacing=\"5\">%s</table>"
630 "</div>", accum->str);
631
632 g_string_free (accum, TRUE);
633 g_string_free (email, TRUE);
634 }
635
636 static void
637 accum_address_map (GString *buffer,
638 EContact *contact,
639 gint map_type)
640 {
641 #ifdef WITH_CONTACT_MAPS
642
643 g_string_append (buffer, "<tr><td colspan=\"3\">");
644
645 if (map_type == E_CONTACT_ADDRESS_WORK) {
646 g_string_append (
647 buffer,
648 "<object type=\"application/x-work-map-widget\" "
649 "width=\"250\" height=\"250\"></object>");
650 } else {
651 g_string_append (
652 buffer,
653 "<object type=\"application/x-home-map-widget\" "
654 "width=\"250\" height=\"250\"></object>");
655 }
656
657 g_string_append (buffer, "</td></tr>");
658
659 #endif
660 }
661
662 static void
663 render_work_column (EABContactFormatter *formatter,
664 GString *buffer)
665 {
666 EContact *contact = formatter->priv->contact;
667 GString *accum = g_string_new ("");
668
669 accum_attribute (accum, contact, _("Company"), E_CONTACT_ORG, NULL, 0);
670 accum_attribute (accum, contact, _("Department"), E_CONTACT_ORG_UNIT, NULL, 0);
671 accum_attribute (accum, contact, _("Profession"), E_CONTACT_ROLE, NULL, 0);
672 accum_attribute (accum, contact, _("Position"), E_CONTACT_TITLE, NULL, 0);
673 accum_attribute (accum, contact, _("Manager"), E_CONTACT_MANAGER, NULL, 0);
674 accum_attribute (accum, contact, _("Assistant"), E_CONTACT_ASSISTANT, NULL, 0);
675 accum_attribute (accum, contact, _("Video Chat"), E_CONTACT_VIDEO_URL, VIDEOCONF_ICON, E_TEXT_TO_HTML_CONVERT_URLS);
676 accum_attribute (accum, contact, _("Calendar"), E_CONTACT_CALENDAR_URI, NULL, E_TEXT_TO_HTML_CONVERT_URLS);
677 accum_attribute (accum, contact, _("Free/Busy"), E_CONTACT_FREEBUSY_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS);
678 accum_attribute (accum, contact, _("Phone"), E_CONTACT_PHONE_BUSINESS, NULL, 0);
679 accum_attribute (accum, contact, _("Fax"), E_CONTACT_PHONE_BUSINESS_FAX, NULL, 0);
680 accum_address (accum, contact, _("Address"), E_CONTACT_ADDRESS_WORK, E_CONTACT_ADDRESS_LABEL_WORK);
681 if (formatter->priv->render_maps)
682 accum_address_map (accum, contact, E_CONTACT_ADDRESS_WORK);
683
684 if (accum->len > 0) {
685 g_string_append_printf (
686 buffer,
687 "<div class=\"column\" id=\"contact-work\">"
688 "<h3>%s</h3>"
689 "<table border=\"0\" cellspacing=\"5\">%s</table>"
690 "</div>", _("Work"), accum->str);
691 }
692
693 g_string_free (accum, TRUE);
694 }
695
696 static void
697 render_personal_column (EABContactFormatter *formatter,
698 GString *buffer)
699 {
700 EContact *contact = formatter->priv->contact;
701 GString *accum = g_string_new ("");
702
703 accum_attribute (accum, contact, _("Home Page"), E_CONTACT_HOMEPAGE_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS);
704 accum_attribute (accum, contact, _("Web Log"), E_CONTACT_BLOG_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS);
705 accum_attribute (accum, contact, _("Phone"), E_CONTACT_PHONE_HOME, NULL, 0);
706 accum_attribute (accum, contact, _("Mobile Phone"), E_CONTACT_PHONE_MOBILE, NULL, 0);
707 accum_address (accum, contact, _("Address"), E_CONTACT_ADDRESS_HOME, E_CONTACT_ADDRESS_LABEL_HOME);
708 accum_time_attribute (accum, contact, _("Birthday"), E_CONTACT_BIRTH_DATE, NULL, 0);
709 accum_time_attribute (accum, contact, _("Anniversary"), E_CONTACT_ANNIVERSARY, NULL, 0);
710 accum_attribute (accum, contact, _("Spouse"), E_CONTACT_SPOUSE, NULL, 0);
711 if (formatter->priv->render_maps)
712 accum_address_map (accum, contact, E_CONTACT_ADDRESS_HOME);
713
714 if (accum->len > 0) {
715 g_string_append_printf (
716 buffer,
717 "<div class=\"column\" id=\"contact-personal\">"
718 "<h3>%s</h3>"
719 "<table border=\"0\" cellspacing=\"5\">%s</table>"
720 "</div>", _("Personal"), accum->str);
721 }
722
723 g_string_free (accum, TRUE);
724 }
725
726 static void
727 render_footer (EABContactFormatter *formatter,
728 GString *buffer)
729 {
730 EContact *contact;
731 const gchar *str;
732
733 contact = formatter->priv->contact;
734
735 str = e_contact_get_const (contact, E_CONTACT_NOTE);
736 if (!str || !*str)
737 return;
738
739 g_string_append (
740 buffer,
741 "<div id=\"footer\"><table border=\"0\" cellspacing=\"5\">");
742
743 render_table_row (
744 buffer, _("Note"),
745 e_contact_get_const (contact, E_CONTACT_NOTE),
746 NULL,
747 E_TEXT_TO_HTML_CONVERT_ADDRESSES |
748 E_TEXT_TO_HTML_CONVERT_URLS |
749 E_TEXT_TO_HTML_CONVERT_NL);
750
751 g_string_append (buffer, "</table></div>");
752 }
753
754 static void
755 render_contact (EABContactFormatter *formatter,
756 GString *buffer)
757 {
758 render_title_block (formatter, buffer);
759
760 g_string_append (buffer, "<div id=\"columns\">");
761 render_contact_column (formatter, buffer);
762 render_work_column (formatter, buffer);
763 render_personal_column (formatter, buffer);
764 g_string_append (buffer, "</div>");
765
766 render_footer (formatter, buffer);
767 }
768
769 static void
770 render_normal (EABContactFormatter *formatter,
771 GString *buffer)
772 {
773 g_string_append (buffer, HTML_HEADER);
774 g_string_append_printf (
775 buffer, "<body bgcolor=\"#%06x\" text=\"#%06x\">",
776 e_color_to_value (
777 &formatter->priv->style->base[formatter->priv->state]),
778 e_color_to_value (
779 &formatter->priv->style->text[formatter->priv->state]));
780
781 if (formatter->priv->contact) {
782
783 if (e_contact_get (formatter->priv->contact, E_CONTACT_IS_LIST))
784
785 render_contact_list (
786 formatter,
787 buffer);
788 else
789 render_contact (
790 formatter,
791 buffer);
792
793 }
794
795 g_string_append (buffer, "</body></html>\n");
796 }
797
798 static void
799 render_compact (EABContactFormatter *formatter,
800 GString *buffer)
801 {
802 EContact *contact = formatter->priv->contact;
803 const gchar *str;
804 gchar *html;
805 EContactPhoto *photo;
806
807 g_string_append (buffer, HTML_HEADER);
808 g_string_append (buffer, "<body>\n");
809
810 if (!contact) {
811 g_string_append (buffer, "</body></html>");
812 return;
813 }
814
815 g_string_append_printf (
816 buffer,
817 "<table><tr><td valign=\"top\">");
818
819 photo = e_contact_get (contact, E_CONTACT_PHOTO);
820
821 if (!photo)
822 photo = e_contact_get (contact, E_CONTACT_LOGO);
823
824 if (photo) {
825 gint calced_width = MAX_COMPACT_IMAGE_DIMENSION, calced_height = MAX_COMPACT_IMAGE_DIMENSION;
826 GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
827 GdkPixbuf *pixbuf;
828
829 /* figure out if we need to downscale the
830 * image here. we don't scale the pixbuf
831 * itself, just insert width/height tags in
832 * the html */
833 if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
834 gdk_pixbuf_loader_write (
835 loader, photo->data.inlined.data,
836 photo->data.inlined.length, NULL);
837 } else if (photo->type == E_CONTACT_PHOTO_TYPE_URI &&
838 photo->data.uri &&
839 g_ascii_strncasecmp (photo->data.uri, "file://", 7) == 0) {
840 gchar *filename, *contents = NULL;
841 gsize length;
842
843 filename = g_filename_from_uri (photo->data.uri, NULL, NULL);
844
845 if (filename) {
846 if (g_file_get_contents (filename, &contents, &length, NULL)) {
847 gdk_pixbuf_loader_write (loader, (const guchar *) contents, length, NULL);
848 g_free (contents);
849 }
850
851 g_free (filename);
852 }
853 }
854
855 gdk_pixbuf_loader_close (loader, NULL);
856 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
857
858 if (pixbuf)
859 g_object_ref (pixbuf);
860
861 g_object_unref (loader);
862
863 if (pixbuf) {
864 gint max_dimension;
865
866 calced_width = gdk_pixbuf_get_width (pixbuf);
867 calced_height = gdk_pixbuf_get_height (pixbuf);
868
869 max_dimension = calced_width;
870
871 if (max_dimension < calced_height)
872 max_dimension = calced_height;
873
874 if (max_dimension > MAX_COMPACT_IMAGE_DIMENSION) {
875 calced_width *= ((gfloat) MAX_COMPACT_IMAGE_DIMENSION / max_dimension);
876 calced_height *= ((gfloat) MAX_COMPACT_IMAGE_DIMENSION / max_dimension);
877 }
878
879 g_object_unref (pixbuf);
880 }
881
882 if (photo->type == E_CONTACT_PHOTO_TYPE_URI &&
883 photo->data.uri && *photo->data.uri) {
884 gboolean is_local = g_str_has_prefix (photo->data.uri, "file://");
885 gchar *unescaped = g_uri_unescape_string (photo->data.uri, NULL);
886 g_string_append_printf (
887 buffer,
888 "<img width=\"%d\" height=\"%d\" src=\"%s%s\">",
889 calced_width, calced_height,
890 is_local ? "evo-" : "", unescaped);
891 g_free (unescaped);
892 } else {
893 gchar *photo_data;
894
895 photo_data = g_base64_encode (
896 photo->data.inlined.data,
897 photo->data.inlined.length);
898 g_string_append_printf (
899 buffer,
900 "<img border=\"1\" src=\"data:%s;base64,%s\" "
901 "width=\"%d\" height=\"%d\">",
902 photo->data.inlined.mime_type,
903 photo_data,
904 calced_width, calced_height);
905 g_free (photo_data);
906 }
907
908 e_contact_photo_free (photo);
909 }
910
911 g_string_append (buffer, "</td><td width=\"5\"></td><td valign=\"top\">\n");
912
913 str = e_contact_get_const (contact, E_CONTACT_FILE_AS);
914
915 if (str) {
916 html = e_text_to_html (str, 0);
917 g_string_append_printf (buffer, "<b>%s</b>", html);
918 g_free (html);
919 } else {
920 str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
921
922 if (str) {
923 html = e_text_to_html (str, 0);
924 g_string_append_printf (buffer, "<b>%s</b>", html);
925 g_free (html);
926 }
927 }
928
929 g_string_append (buffer, "<hr>");
930
931 if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
932 GList *email_list;
933 GList *l;
934
935 g_string_append (
936 buffer,
937 "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
938 "<tr><td valign=\"top\">");
939 g_string_append_printf (
940 buffer,
941 "<b>%s:</b> <td>", _ ("List Members"));
942
943 email_list = e_contact_get (contact, E_CONTACT_EMAIL);
944
945 for (l = email_list; l; l = l->next) {
946 if (l->data) {
947 html = e_text_to_html (l->data, 0);
948 g_string_append_printf (buffer, "%s, ", html);
949 g_free (html);
950 }
951 }
952
953 g_string_append (buffer, "</td></tr></table>");
954
955 } else {
956
957 gboolean comma = FALSE;
958 str = e_contact_get_const (contact, E_CONTACT_TITLE);
959
960 if (str) {
961 html = e_text_to_html (str, 0);
962 g_string_append_printf (buffer, "<b>%s:</b> %s<br>", _ ("Job Title"), str);
963 g_free (html);
964 }
965
966 #define print_email() { \
967 html = eab_parse_qp_email_to_html (str); \
968 \
969 if (!html) \
970 html = e_text_to_html (str, 0); \
971 \
972 g_string_append_printf (buffer, "%s%s", comma ? ", " : "", html); \
973 g_free (html); \
974 comma = TRUE; \
975 }
976
977 g_string_append_printf (buffer, "<b>%s:</b> ", _ ("Email"));
978 str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);
979
980 if (str)
981 print_email ();
982
983 str = e_contact_get_const (contact, E_CONTACT_EMAIL_2);
984
985 if (str)
986 print_email ();
987
988 str = e_contact_get_const (contact, E_CONTACT_EMAIL_3);
989
990 if (str)
991 print_email ();
992
993 g_string_append (buffer, "<br>");
994
995 #undef print_email
996
997 str = e_contact_get_const (contact, E_CONTACT_HOMEPAGE_URL);
998
999 if (str) {
1000 html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS);
1001 g_string_append_printf (
1002 buffer, "<b>%s:</b> %s<br>",
1003 _ ("Home page"), html);
1004 g_free (html);
1005 }
1006
1007 str = e_contact_get_const (contact, E_CONTACT_BLOG_URL);
1008
1009 if (str) {
1010 html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS);
1011 g_string_append_printf (
1012 buffer, "<b>%s:</b> %s<br>",
1013 _ ("Blog"), html);
1014 }
1015 }
1016
1017 g_string_append (buffer, "</td></tr></table>\n");
1018
1019 g_string_append (buffer, "</body></html>\n");
1020 }
1021
1022 static CamelStream *
1023 format_contact (EABContactFormatter *formatter,
1024 GCancellable *cancellable)
1025 {
1026 GString *buffer;
1027 CamelStream *stream;
1028
1029 buffer = g_string_new ("");
1030
1031 if (formatter->priv->mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) {
1032 render_normal (formatter, buffer);
1033 } else {
1034 render_compact (formatter, buffer);
1035 }
1036
1037 stream = camel_stream_mem_new ();
1038 camel_stream_write_string (stream, buffer->str, cancellable, NULL);
1039
1040 g_string_free (buffer, TRUE);
1041
1042 return stream;
1043 }
1044
1045 static void
1046 do_start_async_formatter (GSimpleAsyncResult *result,
1047 GObject *object,
1048 GCancellable *cancellable)
1049 {
1050 EABContactFormatter *formatter;
1051 CamelStream *stream;
1052
1053 formatter = EAB_CONTACT_FORMATTER (object);
1054
1055 stream = format_contact (formatter, cancellable);
1056
1057 g_simple_async_result_set_op_res_gpointer (result, stream, NULL);
1058 }
1059
1060 static void
1061 eab_contact_formatter_set_property (GObject *object,
1062 guint property_id,
1063 const GValue *value,
1064 GParamSpec *pspec)
1065 {
1066 EABContactFormatter *formatter = EAB_CONTACT_FORMATTER (object);
1067
1068 switch (property_id) {
1069 case PROP_DISPLAY_MODE:
1070 eab_contact_formatter_set_display_mode (
1071 formatter, g_value_get_int (value));
1072 return;
1073 case PROP_RENDER_MAPS:
1074 eab_contact_formatter_set_render_maps (
1075 formatter, g_value_get_boolean (value));
1076 return;
1077 case PROP_STYLE:
1078 eab_contact_formatter_set_style (
1079 formatter, g_value_get_object (value));
1080 return;
1081 case PROP_STATE:
1082 eab_contact_formatter_set_state (
1083 formatter, g_value_get_uint (value));
1084 return;
1085 }
1086
1087 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1088 }
1089
1090 static void
1091 eab_contact_formatter_get_property (GObject *object,
1092 guint property_id,
1093 GValue *value,
1094 GParamSpec *pspec)
1095 {
1096 EABContactFormatter *formatter = EAB_CONTACT_FORMATTER (object);
1097
1098 switch (property_id) {
1099 case PROP_DISPLAY_MODE:
1100 g_value_set_int (
1101 value,
1102 eab_contact_formatter_get_display_mode (
1103 formatter));
1104 return;
1105 case PROP_RENDER_MAPS:
1106 g_value_set_boolean (
1107 value,
1108 eab_contact_formatter_get_render_maps (
1109 formatter));
1110 return;
1111 case PROP_STYLE:
1112 g_value_set_object (
1113 value,
1114 eab_contact_formatter_get_style (
1115 formatter));
1116 return;
1117 case PROP_STATE:
1118 g_value_set_uint (
1119 value,
1120 eab_contact_formatter_get_state (
1121 formatter));
1122 return;
1123 }
1124
1125 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1126 }
1127
1128 static void
1129 eab_contact_formatter_dispose (GObject *object)
1130 {
1131 EABContactFormatter *formatter;
1132
1133 formatter = EAB_CONTACT_FORMATTER (object);
1134
1135 if (formatter->priv->contact) {
1136 g_object_unref (formatter->priv->contact);
1137 formatter->priv->contact = NULL;
1138 }
1139
1140 if (formatter->priv->style) {
1141 g_object_unref (formatter->priv->style);
1142 formatter->priv->style = NULL;
1143 }
1144
1145 G_OBJECT_CLASS (eab_contact_formatter_parent_class)->dispose (object);
1146 }
1147
1148 static void
1149 eab_contact_formatter_class_init (EABContactFormatterClass *class)
1150 {
1151 GObjectClass *object_class;
1152
1153 g_type_class_add_private (class, sizeof (EABContactFormatterClass));
1154
1155 object_class = G_OBJECT_CLASS (class);
1156 object_class->dispose = eab_contact_formatter_dispose;
1157 object_class->set_property = eab_contact_formatter_set_property;
1158 object_class->get_property = eab_contact_formatter_get_property;
1159
1160 g_object_class_install_property (
1161 object_class,
1162 PROP_DISPLAY_MODE,
1163 g_param_spec_int (
1164 "display-mode",
1165 "",
1166 "",
1167 EAB_CONTACT_DISPLAY_RENDER_NORMAL,
1168 EAB_CONTACT_DISPLAY_RENDER_COMPACT,
1169 EAB_CONTACT_DISPLAY_RENDER_NORMAL,
1170 G_PARAM_READWRITE));
1171
1172 g_object_class_install_property (
1173 object_class,
1174 PROP_RENDER_MAPS,
1175 g_param_spec_boolean (
1176 "render-maps",
1177 "",
1178 "",
1179 FALSE,
1180 G_PARAM_READWRITE));
1181
1182 g_object_class_install_property (
1183 object_class,
1184 PROP_STYLE,
1185 g_param_spec_object (
1186 "style",
1187 NULL,
1188 NULL,
1189 GTK_TYPE_STYLE,
1190 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
1191
1192 g_object_class_install_property (
1193 object_class,
1194 PROP_STATE,
1195 g_param_spec_uint (
1196 "state",
1197 NULL,
1198 NULL,
1199 0,
1200 G_MAXUINT,
1201 0,
1202 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
1203 }
1204
1205 static void
1206 eab_contact_formatter_init (EABContactFormatter *formatter)
1207 {
1208 formatter->priv = EAB_CONTACT_FORMATTER_GET_PRIVATE (formatter);
1209
1210 formatter->priv->contact = NULL;
1211 formatter->priv->mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
1212 formatter->priv->render_maps = FALSE;
1213 }
1214
1215 EABContactFormatter *
1216 eab_contact_formatter_new (EABContactDisplayMode mode,
1217 gboolean render_maps)
1218 {
1219 return g_object_new (
1220 EAB_TYPE_CONTACT_FORMATTER,
1221 "display-mode", mode,
1222 "render-maps", render_maps,
1223 NULL);
1224 }
1225
1226 void
1227 eab_contact_formatter_set_display_mode (EABContactFormatter *formatter,
1228 EABContactDisplayMode mode)
1229 {
1230 g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
1231
1232 if (formatter->priv->mode == mode)
1233 return;
1234
1235 formatter->priv->mode = mode;
1236
1237 g_object_notify (G_OBJECT (formatter), "display-mode");
1238 }
1239
1240 EABContactDisplayMode
1241 eab_contact_formatter_get_display_mode (EABContactFormatter *formatter)
1242 {
1243 g_return_val_if_fail (EAB_IS_CONTACT_FORMATTER (formatter),
1244 EAB_CONTACT_DISPLAY_RENDER_NORMAL);
1245
1246 return formatter->priv->mode;
1247 }
1248
1249 void
1250 eab_contact_formatter_set_render_maps (EABContactFormatter *formatter,
1251 gboolean render_maps)
1252 {
1253 g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
1254
1255 if (formatter->priv->render_maps == render_maps)
1256 return;
1257
1258 formatter->priv->render_maps = render_maps;
1259
1260 g_object_notify (G_OBJECT (formatter), "render-maps");
1261 }
1262
1263 gboolean
1264 eab_contact_formatter_get_render_maps (EABContactFormatter *formatter)
1265 {
1266 g_return_val_if_fail (EAB_IS_CONTACT_FORMATTER (formatter), FALSE);
1267
1268 return formatter->priv->render_maps;
1269 }
1270
1271 void
1272 eab_contact_formatter_set_style (EABContactFormatter *formatter,
1273 GtkStyle *style)
1274 {
1275 g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
1276
1277 if (formatter->priv->style == style) {
1278 return;
1279 }
1280
1281 g_clear_object (&formatter->priv->style);
1282
1283 if (style != NULL) {
1284 formatter->priv->style = g_object_ref (style);
1285 }
1286
1287 g_object_notify (G_OBJECT (formatter), "style");
1288 }
1289
1290 GtkStyle *
1291 eab_contact_formatter_get_style (EABContactFormatter *formatter)
1292 {
1293 g_return_val_if_fail (EAB_IS_CONTACT_FORMATTER (formatter), NULL);
1294
1295 return formatter->priv->style;
1296 }
1297
1298 void
1299 eab_contact_formatter_set_state (EABContactFormatter *formatter,
1300 GtkStateType state)
1301 {
1302 g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
1303
1304 if (formatter->priv->state == state)
1305 return;
1306
1307 formatter->priv->state = state;
1308
1309 g_object_notify (G_OBJECT (formatter), "state");
1310 }
1311
1312 GtkStateType
1313 eab_contact_formatter_get_state (EABContactFormatter *formatter)
1314 {
1315 g_return_val_if_fail (EAB_IS_CONTACT_FORMATTER (formatter), 0);
1316
1317 return formatter->priv->state;
1318 }
1319
1320 void
1321 eab_contact_formatter_format_contact_sync (EABContactFormatter *formatter,
1322 EContact *contact,
1323 CamelStream *stream,
1324 GCancellable *cancellable)
1325 {
1326 CamelStream *out;
1327
1328 g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
1329 g_return_if_fail (E_IS_CONTACT (contact));
1330
1331 g_object_ref (contact);
1332
1333 if (formatter->priv->contact)
1334 g_object_unref (formatter->priv->contact);
1335
1336 formatter->priv->contact = contact;
1337
1338 out = format_contact (formatter, cancellable);
1339
1340 g_seekable_seek (G_SEEKABLE (out), 0, G_SEEK_SET, cancellable, NULL);
1341 camel_stream_write_to_stream (out, stream, cancellable, NULL);
1342
1343 g_object_unref (out);
1344 }
1345
1346 void
1347 eab_contact_formatter_format_contact_async (EABContactFormatter *formatter,
1348 EContact *contact,
1349 GCancellable *cancellable,
1350 GAsyncReadyCallback callback,
1351 gpointer user_data)
1352 {
1353 GSimpleAsyncResult *simple;
1354
1355 g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
1356 g_return_if_fail (E_IS_CONTACT (contact));
1357 g_return_if_fail (callback != NULL);
1358
1359 g_object_ref (contact);
1360 if (formatter->priv->contact)
1361 g_object_unref (formatter->priv->contact);
1362
1363 formatter->priv->contact = contact;
1364
1365 simple = g_simple_async_result_new (
1366 G_OBJECT (formatter), callback, user_data,
1367 eab_contact_formatter_format_contact_async);
1368
1369 g_simple_async_result_set_check_cancellable (simple, cancellable);
1370
1371 g_simple_async_result_run_in_thread (
1372 simple, do_start_async_formatter,
1373 G_PRIORITY_DEFAULT, cancellable);
1374
1375 g_object_unref (simple);
1376 }
1377
1378 static void
1379 collapse_contacts_list (WebKitDOMEventTarget *event_target,
1380 WebKitDOMEvent *event,
1381 gpointer user_data)
1382 {
1383 WebKitDOMDocument *document;
1384 WebKitDOMElement *list;
1385 gchar *id, *list_id;
1386 gchar *imagesdir, *src;
1387 gboolean hidden;
1388
1389 document = user_data;
1390 id = webkit_dom_html_element_get_id (WEBKIT_DOM_HTML_ELEMENT (event_target));
1391
1392 list_id = g_strconcat ("list-", id, NULL);
1393 list = webkit_dom_document_get_element_by_id (document, list_id);
1394 g_free (id);
1395 g_free (list_id);
1396
1397 if (!list)
1398 return;
1399
1400 imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
1401 hidden = webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (list));
1402
1403 if (hidden) {
1404 src = g_strdup_printf ("evo-file://%s/minus.png", imagesdir);
1405 } else {
1406 src = g_strdup_printf ("evo-file://%s/plus.png", imagesdir);
1407 }
1408
1409 webkit_dom_html_element_set_hidden (
1410 WEBKIT_DOM_HTML_ELEMENT (list), !hidden);
1411 webkit_dom_html_image_element_set_src (
1412 WEBKIT_DOM_HTML_IMAGE_ELEMENT (event_target), src);
1413
1414 g_free (src);
1415 g_free (imagesdir);
1416 }
1417
1418 void
1419 eab_contact_formatter_bind_dom (WebKitDOMDocument *document)
1420 {
1421 WebKitDOMNodeList *nodes;
1422 gulong i, length;
1423
1424 nodes = webkit_dom_document_get_elements_by_class_name (
1425 document, "_evo_collapse_button");
1426
1427 length = webkit_dom_node_list_get_length (nodes);
1428 for (i = 0; i < length; i++) {
1429
1430 WebKitDOMNode *node;
1431
1432 node = webkit_dom_node_list_item (nodes, i);
1433 webkit_dom_event_target_add_event_listener (
1434 WEBKIT_DOM_EVENT_TARGET (node), "click",
1435 G_CALLBACK (collapse_contacts_list), FALSE, document);
1436 }
1437 }