1 /*
2 * RAL -- Rubrica Addressbook Library
3 * file: ref.c
4 *
5 * Copyright (C) Nicola Fragale <nicolafragale@libero.it>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 #include <gtk/gtk.h>
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24 #include <gconf/gconf-client.h>
25 #include <glib/gi18n-lib.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 #include "libral.h"
31
32 #include "data_view.h"
33 #include "app.h"
34 #include "types.h"
35 #include "themes.h"
36 #include "preferences.h"
37
38 static GdkCursor* hand_cursor;
39 static GdkCursor* regular_cursor;
40 static GdkCursor* wait_cursor;
41
42 static gboolean over_link;
43
44
45 enum {
46 PROP_0,
47 DATA_FONT,
48 };
49
50 struct _RubricaDataViewPrivate {
51 GtkWidget* text1; // header
52 GtkWidget* text2; // body
53
54 GtkTextBuffer* buf1; // header's buffer
55 GtkTextBuffer* buf2; // body's buffer
56
57 GtkIconTheme* theme;
58 GtkWidget* image;
59
60 gchar* font;
61
62 gboolean dispose_has_run;
63 };
64
65
66 /* signals enumeration
67 */
68 enum {
69 LAUNCH,
70 LAST_SIGNAL
71 };
72
73 static guint data_view_signals[LAST_SIGNAL] = {0};
74
75 #define RUBRICA_DATA_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
76 RUBRICA_DATA_VIEW_TYPE, \
77 RubricaDataViewPrivate))
78
79
80 static GObjectClass *parent_class = NULL;
81
82
83 static void rubrica_data_view_class_init (RubricaDataViewClass* klass);
84 static void rubrica_data_view_init (RubricaDataView* obj);
85
86 static void rubrica_data_view_finalize (RubricaDataView* self);
87 static void rubrica_data_view_dispose (RubricaDataView* self);
88
89
90 static void rubrica_data_view_set_property (GObject* obj, guint property_id,
91 GValue* value, GParamSpec* spec);
92 static void rubrica_data_view_get_property (GObject* obj, guint property_id,
93 GValue* value, GParamSpec* spec);
94
95
96 /* Private
97 */
98 static GtkTextTagTable* rubrica_data_view_create_tag_table(void);
99
100
101 static void insert_link (GtkTextBuffer *buffer,
102 GtkTextIter *iter, gchar *uri,
103 RubricaLinkType type);
104 static void follow_if_link (GtkWidget *view, GtkTextIter *iter,
105 gpointer data);
106 static void set_cursor (GtkWidget* view, gint x, gint y);
107
108
109 static void clean_buffer (GtkTextBuffer* buffer);
110 static void data_view_clear_header (RubricaDataView* view);
111 static void data_view_clear_body (RubricaDataView* view);
112
113 static void data_view_set_image (RubricaDataView* view,
114 GdkPixbuf* pixbuf);
115
116 static void data_view_write_card_header (GtkTextBuffer* buffer, gchar* label,
117 gchar* string);
118 static void data_view_write_pixbuf (GtkTextBuffer* buffer,
119 GdkPixbuf* pixbuf, gchar* label);
120 static void data_view_write_bold (GtkTextBuffer* buffer, gchar* label,
121 gchar* string, gboolean bool);
122 static void data_view_write_line (GtkTextBuffer* buffer, gchar* label,
123 gchar* string, gboolean tab);
124 static void data_view_write_link (GtkTextBuffer* buffer, gchar* label,
125 gchar* url, RubricaLinkType link);
126 static void data_view_write (GtkTextBuffer* buffer, gchar* str);
127
128 static void write_company_info (RubricaDataView* view, RCard* card);
129 static void write_personal_data (RubricaDataView* view, RPersonalCard* card);
130 static void write_groups (RubricaDataView* view, RCard* card);
131 static void write_addresses (RubricaDataView* view, RCard* card);
132 static void write_work (RubricaDataView* view, RPersonalCard* card);
133 static void write_net (RubricaDataView* view, RCard* card);
134 static void write_telephones (RubricaDataView* view, RCard* card);
135 static void write_notes (RubricaDataView* view, RPersonalCard* card);
136 static void write_company_notes (RubricaDataView* view, RCompanyCard* card);
137
138 static void data_view_show_personal_card (RubricaDataView* view, RCard* card);
139 static void data_view_show_company_card (RubricaDataView* view, RCard* card);
140
141
142 /* Callbacks
143 */
144 static gboolean key_press_event (GtkWidget *text_view,
145 GdkEventKey *event, gpointer data);
146 static gboolean event_after (GtkWidget *text_view, GdkEvent *ev,
147 gpointer data);
148 static gboolean motion_notify_event (GtkWidget* view,
149 GdkEventMotion *event, gpointer data);
150 static gboolean visibility_notify_event (GtkWidget* view,
151 GdkEventVisibility *event,
152 gpointer data);
153
154
155 void change_font (GtkTextTag *tag, gpointer data);
156
157
158 void
change_font(GtkTextTag * tag,gpointer data)159 change_font (GtkTextTag *tag, gpointer data)
160 {
161 PangoFontDescription* pfd;
162 const gchar* font = (gchar*) data;
163 gchar* name;
164
165 pfd = pango_font_description_from_string (font);
166
167 g_object_get(tag, "name", &name, NULL);
168 if (g_strrstr(name, "bold"))
169 g_object_set(tag, "font-desc", pfd, "weight", PANGO_WEIGHT_BOLD, NULL);
170 else
171 g_object_set(tag, "font-desc", pfd, NULL);
172
173 pango_font_description_free (pfd);
174 }
175
176 GType
rubrica_data_view_get_type()177 rubrica_data_view_get_type()
178 {
179 static GType data_view_type = 0;
180
181 if (!data_view_type)
182 {
183 static const GTypeInfo data_view_info =
184 {
185 sizeof(RubricaDataViewClass),
186 NULL,
187 NULL,
188 (GClassInitFunc) rubrica_data_view_class_init,
189 NULL,
190 NULL,
191 sizeof(RubricaDataView),
192 0,
193 (GInstanceInitFunc) rubrica_data_view_init
194 };
195
196 data_view_type = g_type_register_static (GTK_TYPE_VBOX,
197 "RubricaDataView",
198 &data_view_info, 0);
199 }
200
201 return data_view_type;
202 }
203
204
205 static void
rubrica_data_view_dispose(RubricaDataView * self)206 rubrica_data_view_dispose (RubricaDataView* self)
207 {
208 g_return_if_fail(IS_RUBRICA_DATA_VIEW(self));
209
210 if (self->priv->dispose_has_run)
211 return;
212
213 self->priv->dispose_has_run = TRUE;
214 }
215
216
217 static void
rubrica_data_view_finalize(RubricaDataView * self)218 rubrica_data_view_finalize (RubricaDataView* self)
219 {
220 g_return_if_fail(IS_RUBRICA_DATA_VIEW(self));
221 }
222
223
224 static void
rubrica_data_view_class_init(RubricaDataViewClass * klass)225 rubrica_data_view_class_init(RubricaDataViewClass* klass)
226 {
227 GObjectClass *object_class = G_OBJECT_CLASS (klass);
228 GParamSpec* pspec;
229
230 parent_class = g_type_class_peek_parent (klass);
231
232 object_class->finalize = (GObjectFinalizeFunc) rubrica_data_view_finalize;
233 object_class->dispose = (GObjectFinalizeFunc) rubrica_data_view_dispose;
234
235 object_class->set_property = (gpointer) rubrica_data_view_set_property;
236 object_class->get_property = (gpointer) rubrica_data_view_get_property;
237
238 g_type_class_add_private (klass, sizeof(RubricaDataViewPrivate));
239
240 /**
241 * RubricaDataView:data-font
242 *
243 *
244 */
245 pspec = g_param_spec_string("data-font",
246 "data font",
247 "the font used to display data",
248 NULL,
249 G_PARAM_READWRITE);
250 g_object_class_install_property(object_class, DATA_FONT, pspec);
251
252 data_view_signals[LAUNCH] =
253 g_signal_new("launch",
254 RUBRICA_DATA_VIEW_TYPE,
255 G_SIGNAL_RUN_LAST,
256 G_STRUCT_OFFSET(RubricaDataViewClass, launch),
257 NULL,
258 NULL,
259 g_cclosure_marshal_VOID__POINTER,
260 G_TYPE_NONE, /* return type */
261 1, /* params */
262 G_TYPE_POINTER); /* params type: error code */
263 }
264
265
266 static void
rubrica_data_view_init(RubricaDataView * self)267 rubrica_data_view_init(RubricaDataView* self)
268 {
269 GtkWidget* scrollwin;
270 GtkTextTagTable* tag_table;
271 GtkWidget* vbox;
272 GtkWidget* hbox;
273
274 hand_cursor = gdk_cursor_new (GDK_HAND2);
275 regular_cursor = gdk_cursor_new (GDK_XTERM);
276 wait_cursor = gdk_cursor_new (GDK_WATCH);
277 over_link = FALSE;
278
279 gtk_box_set_homogeneous(GTK_BOX(self), FALSE);
280 gtk_box_set_spacing(GTK_BOX(self), 6);
281 gtk_container_set_border_width(GTK_CONTAINER(self), 12);
282
283 tag_table = rubrica_data_view_create_tag_table();
284
285 self->priv = RUBRICA_DATA_VIEW_GET_PRIVATE(self);
286
287 self->priv->buf1 = gtk_text_buffer_new(tag_table);
288 self->priv->buf2 = gtk_text_buffer_new(tag_table);
289 self->priv->text1 = gtk_text_view_new_with_buffer(self->priv->buf1);
290 self->priv->text2 = gtk_text_view_new_with_buffer(self->priv->buf2);
291
292 self->priv->theme = gtk_icon_theme_get_default();
293 self->priv->image = gtk_image_new();
294 self->priv->font = NULL;
295
296 vbox = gtk_vbox_new(FALSE, 0);
297
298 scrollwin = gtk_scrolled_window_new (NULL, NULL);
299 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwin), vbox);
300 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
301 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
302 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
303 GTK_SHADOW_IN);
304 gtk_box_pack_start(GTK_BOX(self), scrollwin, TRUE, TRUE, 0);
305
306 hbox = gtk_hbox_new(FALSE, 0);
307
308 gtk_box_pack_start(GTK_BOX(hbox), self->priv->image, FALSE, FALSE, 0);
309 gtk_box_pack_start(GTK_BOX(hbox), self->priv->text1, TRUE, TRUE, 0);
310
311 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
312 gtk_box_pack_start(GTK_BOX(vbox), self->priv->text2, TRUE, TRUE, 0);
313
314 g_object_set(self->priv->text1,
315 "cursor-visible", FALSE,
316 "editable", FALSE,
317 "right-margin", 6,
318 "left-margin", 6,
319 "wrap-mode", GTK_WRAP_WORD, NULL);
320
321 g_object_set(self->priv->text2,
322 "cursor-visible", FALSE,
323 "editable", FALSE,
324 "right-margin", 6,
325 "left-margin", 6,
326 "wrap-mode", GTK_WRAP_WORD, NULL);
327
328 g_signal_connect (G_OBJECT (self->priv->text2), "key-press-event",
329 G_CALLBACK (key_press_event), self);
330
331 g_signal_connect (G_OBJECT (self->priv->text2), "event-after",
332 G_CALLBACK (event_after), self);
333
334 g_signal_connect (G_OBJECT (self->priv->text2), "motion-notify-event",
335 G_CALLBACK (motion_notify_event), self);
336
337 g_signal_connect (G_OBJECT (self->priv->text2), "visibility-notify-event",
338 G_CALLBACK (visibility_notify_event), self);
339
340 gtk_widget_show(GTK_WIDGET(self));
341 gtk_widget_show(self->priv->image);
342 gtk_widget_show(self->priv->text1);
343 gtk_widget_show(self->priv->text2);
344
345 gtk_widget_show(vbox);
346 gtk_widget_show(hbox);
347 gtk_widget_show(scrollwin);
348
349 self->priv->dispose_has_run = FALSE;
350 }
351
352
353 static void
rubrica_data_view_set_property(GObject * obj,guint property_id,GValue * value,GParamSpec * spec)354 rubrica_data_view_set_property (GObject* obj, guint property_id,
355 GValue* value, GParamSpec* spec)
356 {
357 RubricaDataView* self = (RubricaDataView*) obj;
358 RubricaDataViewPrivate* priv = RUBRICA_DATA_VIEW_GET_PRIVATE(self);
359 GtkTextTagTable* table;
360
361 switch (property_id)
362 {
363 case DATA_FONT:
364 if (priv->font)
365 g_free(priv->font);
366
367 priv->font = g_value_dup_string(value);
368 table = gtk_text_buffer_get_tag_table(priv->buf1);
369 gtk_text_tag_table_foreach(table, change_font, priv->font);
370 break;
371
372 default:
373 break;
374 }
375 }
376
377
378 static void
rubrica_data_view_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * spec)379 rubrica_data_view_get_property (GObject* obj, guint property_id,
380 GValue* value, GParamSpec* spec)
381 {
382 RubricaDataView* self = (RubricaDataView*) obj;
383 RubricaDataViewPrivate* priv = RUBRICA_DATA_VIEW_GET_PRIVATE(self);
384
385 switch (property_id)
386 {
387 case DATA_FONT:
388 g_value_set_string(value, priv->font);
389 break;
390
391 default:
392 break;
393 }
394 }
395
396
397
398 /* Private
399 */
400 static GtkTextTagTable*
rubrica_data_view_create_tag_table(void)401 rubrica_data_view_create_tag_table(void)
402 {
403 GtkTextTag* tag;
404 GtkTextTagTable* tag_table;
405 PangoFontDescription* pfd;
406 GConfClient* client;
407 const gchar* font = NULL;
408
409 client = gconf_client_get_default();
410 font = gconf_client_get_string(client, RUBRICA_GCONF_FONT, NULL);
411
412 tag_table = gtk_text_tag_table_new();
413
414 tag = gtk_text_tag_new("tabulato");
415 g_object_set(tag, "left-margin", 25, "right-margin", 25, NULL);
416 gtk_text_tag_table_add(tag_table, tag);
417
418 if (font)
419 pfd = pango_font_description_from_string (font);
420 else
421 pfd = pango_font_description_from_string ("Serif 10");
422
423 tag = gtk_text_tag_new("header");
424 g_object_set(tag, "font-desc", pfd, NULL);
425 gtk_text_tag_table_add(tag_table, tag);
426
427 tag = gtk_text_tag_new("header-bold");
428 g_object_set(tag, "font-desc", pfd, "weight", PANGO_WEIGHT_BOLD, NULL);
429 gtk_text_tag_table_add(tag_table, tag);
430
431 tag = gtk_text_tag_new("body");
432 g_object_set(tag, "font-desc", pfd, NULL);
433 gtk_text_tag_table_add(tag_table, tag);
434
435 tag = gtk_text_tag_new("body-bold");
436 g_object_set(tag, "font-desc", pfd, "weight", PANGO_WEIGHT_BOLD, NULL);
437 gtk_text_tag_table_add(tag_table, tag);
438 pango_font_description_free (pfd);
439
440 g_object_unref(client);
441
442 return tag_table;
443 }
444
445 /* Looks at all tags covering the position (x, y) in the text view,
446 * and if one of them is a link, change the cursor to the "hands" cursor
447 * typically used by web browsers.
448 */
449 static void
set_cursor(GtkWidget * text_view,gint x,gint y)450 set_cursor (GtkWidget* text_view, gint x, gint y)
451 {
452 GtkTextIter iter;
453 GSList *tags = NULL, *tagp = NULL;
454 gboolean hovering = FALSE;
455
456 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW(text_view), &iter, x, y);
457
458 tags = gtk_text_iter_get_tags (&iter);
459 for (tagp = tags; tagp != NULL; tagp = tagp->next)
460 {
461 GtkTextTag *tag = tagp->data;
462 RubricaLink* link = NULL;
463
464 link = g_object_get_data (G_OBJECT (tag), "link");
465 if (link)
466 {
467 hovering = TRUE;
468 break;
469 }
470 }
471
472 if (hovering != over_link)
473 {
474 GdkWindow* window;
475
476 over_link = hovering;
477
478 window = gtk_text_view_get_window(GTK_TEXT_VIEW(text_view),
479 GTK_TEXT_WINDOW_TEXT);
480
481 if (over_link)
482 gdk_window_set_cursor(window, hand_cursor);
483 else
484 gdk_window_set_cursor(window, regular_cursor);
485 }
486
487 if (tags)
488 g_slist_free (tags);
489 }
490
491
492 static void
insert_link(GtkTextBuffer * buffer,GtkTextIter * iter,gchar * uri,RubricaLinkType type)493 insert_link (GtkTextBuffer *buffer, GtkTextIter *iter, gchar *uri,
494 RubricaLinkType type)
495 {
496 GtkTextTag *tag;
497 RubricaLink* link;
498
499 tag = gtk_text_buffer_create_tag (buffer, NULL,
500 "foreground", "blue",
501 "underline", PANGO_UNDERLINE_SINGLE,
502 NULL);
503
504 link = g_new0(RubricaLink, 1);
505 link->uri = g_strdup(uri);
506 link->type = type;
507 g_object_set_data (G_OBJECT (tag), "link", link);
508
509 gtk_text_buffer_insert_with_tags (buffer, iter, uri, -1, tag, NULL);
510 gtk_text_buffer_insert_with_tags (buffer, iter, "\n", -1, tag, NULL);
511 }
512
513
514
515 /* Looks at all tags covering the position of iter in the text view,
516 * and if one of them is a link, follow it by showing the page identified
517 * by the data attached to it.
518 */
519 static void
follow_if_link(GtkWidget * text_view,GtkTextIter * iter,gpointer data)520 follow_if_link (GtkWidget *text_view, GtkTextIter *iter, gpointer data)
521 {
522 RubricaDataView *view = (RubricaDataView*) data;
523 GSList *tags = NULL;
524 GSList *tagp = NULL;
525
526 tags = gtk_text_iter_get_tags (iter);
527 for (tagp = tags; tagp != NULL; tagp = tagp->next)
528 {
529 RubricaLink* link;
530 GtkTextTag *tag = tagp->data;
531
532 link = g_object_get_data (G_OBJECT (tag), "link");
533
534 g_signal_emit_by_name(view, "launch", link, G_TYPE_POINTER);
535 }
536
537 if (tags)
538 g_slist_free (tags);
539 }
540
541
542 /* Links can be activated by pressing Enter.
543 */
544 static gboolean
key_press_event(GtkWidget * text_view,GdkEventKey * event,gpointer data)545 key_press_event (GtkWidget *text_view, GdkEventKey *event, gpointer data)
546 {
547 GtkTextIter iter;
548 GtkTextBuffer *buffer;
549
550 switch (event->keyval)
551 {
552 case GDK_Return:
553 case GDK_KP_Enter:
554 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
555 gtk_text_buffer_get_iter_at_mark (buffer, &iter,
556 gtk_text_buffer_get_insert (buffer));
557 follow_if_link (text_view, &iter, data);
558 break;
559
560 default:
561 break;
562 }
563
564 return FALSE;
565 }
566
567
568 /* Links can also be activated by clicking.
569 */
570 static gboolean
event_after(GtkWidget * text_view,GdkEvent * ev,gpointer data)571 event_after (GtkWidget *text_view, GdkEvent *ev, gpointer data)
572 {
573 GtkTextIter start, end, iter;
574 GtkTextBuffer *buffer;
575 GdkEventButton *event;
576 gint x, y;
577
578 if (ev->type != GDK_BUTTON_RELEASE)
579 return FALSE;
580
581 event = (GdkEventButton *)ev;
582
583 if (event->button != 1)
584 return FALSE;
585
586 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
587
588 /* we shouldn't follow a link if the user has selected something */
589 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
590 if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
591 return FALSE;
592
593 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
594 GTK_TEXT_WINDOW_WIDGET,
595 event->x, event->y, &x, &y);
596
597 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
598
599 follow_if_link (text_view, &iter, data);
600
601 return FALSE;
602 }
603
604
605
606 /* Update the cursor image if the pointer moved.
607 */
608 static gboolean
motion_notify_event(GtkWidget * text_view,GdkEventMotion * event,gpointer data)609 motion_notify_event (GtkWidget* text_view, GdkEventMotion *event,
610 gpointer data)
611 {
612 RubricaDataView* view = (RubricaDataView*) data;
613 RubricaDataViewPrivate* priv;
614 gint x, y;
615
616 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
617
618 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
619 GTK_TEXT_WINDOW_WIDGET,
620 event->x, event->y, &x, &y);
621
622 set_cursor (text_view, x, y);
623
624 gdk_window_get_pointer (text_view->window, NULL, NULL, NULL);
625
626 return FALSE;
627 }
628
629
630 /* Also update the cursor image if the window becomes visible
631 * (e.g. when a window covering it got iconified).
632 */
633 static gboolean
visibility_notify_event(GtkWidget * text_view,GdkEventVisibility * event,gpointer data)634 visibility_notify_event (GtkWidget* text_view, GdkEventVisibility *event,
635 gpointer data)
636 {
637 RubricaDataViewPrivate* priv = RUBRICA_DATA_VIEW_GET_PRIVATE(data);
638 gint wx, wy, bx, by;
639
640 gdk_window_get_pointer (priv->text2->window, &wx, &wy, NULL);
641
642 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (priv->text2),
643 GTK_TEXT_WINDOW_WIDGET,
644 wx, wy, &bx, &by);
645
646 set_cursor (text_view, bx, by);
647
648 return FALSE;
649 }
650
651
652 static void
clean_buffer(GtkTextBuffer * buffer)653 clean_buffer(GtkTextBuffer* buffer)
654 {
655 GtkTextIter start, end;
656
657 gtk_text_buffer_get_bounds(buffer, &start, &end);
658 gtk_text_buffer_delete(buffer, &start, &end);
659 gtk_text_buffer_get_iter_at_offset(buffer, &start, 0);
660 }
661
662
663 static void
data_view_clear_header(RubricaDataView * view)664 data_view_clear_header(RubricaDataView* view)
665 {
666 RubricaDataViewPrivate* priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
667
668 clean_buffer(priv->buf1);
669 }
670
671
672 static void
data_view_clear_body(RubricaDataView * view)673 data_view_clear_body(RubricaDataView* view)
674 {
675 RubricaDataViewPrivate* priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
676
677 clean_buffer(priv->buf2);
678 }
679
680
681 static void
data_view_set_image(RubricaDataView * view,GdkPixbuf * pixbuf)682 data_view_set_image(RubricaDataView* view, GdkPixbuf* pixbuf)
683 {
684 RubricaDataViewPrivate* priv;
685
686 g_return_if_fail(IS_RUBRICA_DATA_VIEW(view));
687 g_return_if_fail(pixbuf != NULL);
688
689 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
690
691 gtk_image_set_from_pixbuf(GTK_IMAGE(priv->image), pixbuf);
692 g_object_unref(pixbuf);
693 }
694
695
696 static void
data_view_write_card_header(GtkTextBuffer * buffer,gchar * label,gchar * string)697 data_view_write_card_header(GtkTextBuffer* buffer, gchar* label, gchar* string)
698 {
699 GtkTextIter iter;
700
701 g_return_if_fail(label != NULL);
702 g_return_if_fail(string != NULL);
703
704 gtk_text_buffer_get_end_iter (buffer, &iter);
705
706 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, label, -1,
707 "header-bold", NULL);
708 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, string, -1,
709 "header", NULL);
710 gtk_text_buffer_insert(buffer, &iter, "\n", -1);
711 }
712
713
714 static void
data_view_write_pixbuf(GtkTextBuffer * buffer,GdkPixbuf * pixbuf,gchar * label)715 data_view_write_pixbuf(GtkTextBuffer* buffer, GdkPixbuf* pixbuf, gchar* label)
716 {
717 GtkTextIter iter;
718
719 gtk_text_buffer_get_end_iter (buffer, &iter);
720
721 gtk_text_buffer_insert_pixbuf(buffer, &iter, pixbuf);
722 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, label, -1,
723 "body-bold", NULL);
724 gtk_text_buffer_insert(buffer, &iter, "\n", -1);
725 }
726
727
728 static void
data_view_write_bold(GtkTextBuffer * buffer,gchar * label,gchar * string,gboolean bool)729 data_view_write_bold(GtkTextBuffer* buffer, gchar* label, gchar* string,
730 gboolean bool)
731 {
732 GtkTextIter iter;
733
734 gtk_text_buffer_get_end_iter (buffer, &iter);
735
736 if (bool)
737 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, label, -1,
738 "body-bold", "tabulato", NULL);
739 else
740 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, label, -1,
741 "body-bold", NULL);
742
743 gtk_text_buffer_insert(buffer, &iter, string, -1);
744 gtk_text_buffer_insert(buffer, &iter, "\n", -1);
745 }
746
747
748 static void
data_view_write_line(GtkTextBuffer * buffer,gchar * label,gchar * string,gboolean tab)749 data_view_write_line(GtkTextBuffer* buffer, gchar* label,
750 gchar* string, gboolean tab)
751 {
752 if (string && (g_ascii_strcasecmp(string, "") != 0))
753 {
754 gchar* lbl;
755
756 lbl = g_strdup_printf("%s: ", label);
757
758 data_view_write_bold(buffer, lbl, string, tab);
759
760 g_free(lbl);
761 }
762 }
763
764
765 static void
data_view_write_link(GtkTextBuffer * buffer,gchar * label,gchar * url,RubricaLinkType link)766 data_view_write_link(GtkTextBuffer* buffer, gchar* label, gchar* url,
767 RubricaLinkType link)
768 {
769 GtkTextIter iter;
770 gchar* str;
771
772 str = g_strdup_printf("%s: ", label);
773
774 gtk_text_buffer_get_end_iter (buffer, &iter);
775
776 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, str, -1,
777 "body-bold", "tabulato", NULL);
778 insert_link(buffer, &iter, url, link);
779 }
780
781
782 static void
data_view_write(GtkTextBuffer * buffer,gchar * str)783 data_view_write(GtkTextBuffer* buffer, gchar* str)
784 {
785 GtkTextIter iter;
786
787 g_return_if_fail(str != NULL);
788
789 gtk_text_buffer_get_end_iter (buffer, &iter);
790 gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, str, -1,
791 "body", "tabulato", NULL);
792 }
793
794
795 static void
write_company_info(RubricaDataView * view,RCard * card)796 write_company_info(RubricaDataView* view, RCard* card)
797 {
798 RubricaDataViewPrivate* priv;
799 GtkTextBuffer* header;
800 GdkPixbuf* pixbuf = NULL;
801 gchar *name, *logo, *vat;
802 gchar *label, *string;
803
804 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
805 header = priv->buf1;
806
807 g_object_get(card, "card-name", &name, "company-logo", &logo,
808 "company-vat", &vat, NULL);
809
810 if (g_file_test(logo, G_FILE_TEST_EXISTS))
811 pixbuf = gdk_pixbuf_new_from_file_at_size(logo, 128, 128, NULL);
812 else
813 pixbuf = gtk_icon_theme_load_icon(priv->theme, "card_photo", 128, 0, NULL);
814
815 data_view_set_image(view, pixbuf);
816
817 label = g_strdup_printf("%s: ", _("Card"));
818 string = g_strdup_printf("%s\n\n", name);
819 data_view_write_card_header(header, label, string);
820 g_free(label);
821 g_free(string);
822
823 if (vat && (g_ascii_strcasecmp(vat, "") != 0))
824 {
825 /* Translators: VAT (Value Added Tax) */
826 string = g_strdup_printf("%s: ", _("Taxpayer number/VAT"));
827 data_view_write_bold(header, string, vat, FALSE);
828
829 g_free(string);
830 }
831 }
832
833
834 static void
write_personal_data(RubricaDataView * view,RPersonalCard * card)835 write_personal_data(RubricaDataView* view, RPersonalCard* card)
836 {
837 RubricaDataViewPrivate* priv;
838 RDate* date;
839 GtkTextBuffer* header;
840 GdkPixbuf* pixbuf = NULL;
841 RContact* contact;
842 gchar* card_name;
843 gchar *first = NULL, *last = NULL, *middle = NULL;
844 gchar *nick = NULL, *title = NULL, *prefix = NULL;
845 gchar *prof = NULL, *photo = NULL;
846 gchar *label, *string;
847
848 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
849 header = priv->buf1;
850 contact = r_personal_card_get_contact(R_PERSONAL_CARD(card));
851
852 g_object_get(contact,
853 "first-name", &first, "last-name", &last,
854 "middle-name", &middle, "nick-name", &nick,
855 "title", &title, "prefix", &prefix,
856 "profession", &prof, "photo", &photo, NULL);
857 g_object_get(R_CARD(card), "card-name", &card_name, NULL);
858
859 /* display photo */
860 if (g_file_test(photo, G_FILE_TEST_EXISTS))
861 pixbuf = gdk_pixbuf_new_from_file_at_size(photo, 128, 128, NULL);
862 else
863 pixbuf = gtk_icon_theme_load_icon(priv->theme, "card_photo", 128, 0, NULL);
864 data_view_set_image(view, pixbuf);
865
866 /* display card's name */
867 label = g_strdup_printf("%s: ", _("Card"));
868 string = g_strdup_printf("%s\n", card_name);
869 data_view_write_card_header(header, label, string);
870 g_free(label);
871 g_free(string);
872
873 /* display contact's data */
874 if (first || middle || last)
875 {
876 gchar *str;
877
878 label = g_strdup_printf("%s: ", _("Name"));
879 str = g_strdup_printf("%s %s %s",
880 last ? last : "",
881 first ? first : "",
882 middle ? middle : "");
883 data_view_write_bold(header, label, str, FALSE);
884
885 g_free(label);
886 g_free(str);
887 }
888
889 data_view_write_line(header, _("Nickname"), nick, FALSE);
890 data_view_write_line(header, _("Title"), title, FALSE);
891 data_view_write_line(header, _("Prefix"), prefix, FALSE );
892 data_view_write_line(header, _("Profession"), prof, FALSE);
893
894 date = r_contact_get_birthday(contact);
895 if (r_date_is_valid(date))
896 {
897 label = g_strdup_printf("%s: ", _("Birthday"));
898 data_view_write_bold(header, label, r_date_get_human_date(date), FALSE);
899
900 g_free(label);
901 }
902 }
903
904
905
906 static void
write_groups(RubricaDataView * view,RCard * card)907 write_groups(RubricaDataView* view, RCard* card)
908 {
909 RubricaDataViewPrivate* priv;
910 GtkTextBuffer* body;
911 gpointer group = NULL;
912
913 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
914 body = priv->buf2;
915
916 group = r_card_get_group(R_CARD(card));
917 if (group)
918 {
919 data_view_write(body, "\n");
920 data_view_write_bold(body, _("Card's groups"), "", FALSE);
921
922 for (; group; group = r_card_get_next_group(R_CARD(card)))
923 {
924 gchar *str, *name = NULL;
925
926 g_object_get(R_GROUP(group), "group-name", &name, NULL);
927
928 str = g_strdup_printf("%s\n", _(name));
929 data_view_write(body, str);
930
931 g_free(str);
932 }
933 }
934 }
935
936
937 static void
write_addresses(RubricaDataView * view,RCard * card)938 write_addresses(RubricaDataView* view, RCard* card)
939 {
940 RubricaDataViewPrivate* priv;
941 GtkTextBuffer* body;
942 RAddress* address;
943 GdkPixbuf* pixbuf = NULL;
944
945 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
946 body = priv->buf2;
947
948 address = r_card_get_address(R_CARD(card));
949 if (address)
950 {
951 pixbuf = gtk_icon_theme_load_icon (priv->theme, "mailbox", 20, 0, NULL);
952
953 data_view_write(body, "\n");
954 data_view_write_pixbuf(body, pixbuf, _("Addresses"));
955 g_object_unref(pixbuf);
956
957 for (; address; address = r_card_get_next_address(R_CARD(card)))
958 {
959 RAddressType type;
960 gchar *adtype, *street, *number, *zip;
961 gchar *city, *province, *state, *country;
962
963 g_object_get(address, "address-type", &type,
964 "street", &street, "street-number", &number,
965 "zip", &zip, "city", &city,
966 "province", &province, "state", &state,
967 "country", &country, NULL);
968
969 if ((street && (g_ascii_strcasecmp(street, "") != 0)) ||
970 (zip && (g_ascii_strcasecmp(zip, "") != 0)) ||
971 (city && (g_ascii_strcasecmp(city, "") != 0)) ||
972 (state && (g_ascii_strcasecmp(state, "") != 0)) ||
973 (country && (g_ascii_strcasecmp(country, "") != 0)))
974 {
975 GString* string;
976
977 string = g_string_new("");
978
979 adtype = r_address_lookup_enum2str(type);
980 data_view_write_bold(body, _(adtype), "", TRUE);
981
982 if (street && (g_ascii_strcasecmp(street, "") != 0))
983 {
984 g_string_printf(string, "%s", street);
985
986 if (number && (g_ascii_strcasecmp(number, "") != 0))
987 g_string_append_printf(string, ", %s", number);
988 }
989
990 if ((zip && (g_ascii_strcasecmp(zip, "") != 0)) ||
991 (city && (g_ascii_strcasecmp(city, "") != 0)) ||
992 (province && (g_ascii_strcasecmp(province, "") != 0)))
993 {
994 g_string_append_printf(string, "\n");
995
996 if (zip && (g_ascii_strcasecmp(zip, "") != 0))
997 g_string_append_printf(string, "%s ", zip);
998
999 if (city && (g_ascii_strcasecmp(city, "") != 0))
1000 g_string_append_printf(string, "%s", city);
1001
1002 if (province && (g_ascii_strcasecmp(province, "") != 0))
1003 g_string_append_printf(string, ", (%s) ", province);
1004 }
1005
1006 if ((state && (g_ascii_strcasecmp(state, "") != 0)) ||
1007 (country && (g_ascii_strcasecmp(country, "") != 0)))
1008 {
1009 g_string_append_printf(string, "\n");
1010
1011 if (state && (g_ascii_strcasecmp(state, "") != 0))
1012 g_string_append_printf(string, "%s ", state);
1013
1014 if (country && (g_ascii_strcasecmp(country, "") != 0))
1015 g_string_append_printf(string, "%s",country);
1016 }
1017
1018 data_view_write(body, string->str);
1019 data_view_write(body, "\n");
1020
1021 g_string_free(string, TRUE);
1022 }
1023 }
1024 }
1025 }
1026
1027
1028
1029 static void
write_work(RubricaDataView * view,RPersonalCard * card)1030 write_work(RubricaDataView* view, RPersonalCard* card)
1031 {
1032 RubricaDataViewPrivate* priv;
1033 GtkTextBuffer* body;
1034 RWork* work = NULL;
1035 GdkPixbuf* pixbuf = NULL;
1036 gchar *assignment = NULL, *organization = NULL;
1037 gchar *department = NULL, *subdep = NULL, *manager = NULL;
1038 gchar *collaborator = NULL, *mphone = NULL, *cphone = NULL;
1039
1040 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
1041 body = priv->buf2;
1042
1043 work = r_personal_card_get_work(R_PERSONAL_CARD(card));
1044 if (work && r_work_have_data(work))
1045 {
1046 g_object_get(work,
1047 "assignment", &assignment,
1048 "organization", &organization,
1049 "department", &department,
1050 "sub-department", &subdep,
1051 "manager-name", &manager,
1052 "collaborator", &collaborator,
1053 "manager-phone", &mphone,
1054 "collaborator-phone", &cphone, NULL);
1055
1056 pixbuf = gtk_icon_theme_load_icon (priv->theme, "role", 20, 0, NULL);
1057
1058 data_view_write(body, "\n");
1059 data_view_write_pixbuf(body, pixbuf, _("Work"));
1060 g_object_unref(pixbuf);
1061 data_view_write_line(body, _("Assignment"), assignment, TRUE);
1062 data_view_write_line(body, _("Organization"), organization, TRUE);
1063 data_view_write_line(body, _("Department"), department, TRUE);
1064 data_view_write_line(body, _("Subdepartment"), subdep, TRUE);
1065 data_view_write_line(body, _("Manager"), manager, TRUE);
1066 data_view_write_line(body, _("Manager's telephone"), collaborator, TRUE);
1067 data_view_write_line(body, _("Collaborator"), mphone, TRUE);
1068 data_view_write_line(body, _("Collaborator's telephone"), cphone, TRUE);
1069 }
1070 }
1071
1072
1073
1074 static void
write_net(RubricaDataView * view,RCard * card)1075 write_net (RubricaDataView* view, RCard* card)
1076 {
1077 RubricaDataViewPrivate* priv;
1078 GtkTextBuffer* body;
1079 GdkPixbuf* pixbuf = NULL;
1080 RNetAddress* net = NULL;
1081 RNetAddressType type;
1082 RubricaLinkType linktype = UNKNOWN_LINK;
1083 gchar* url;
1084
1085 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
1086 body = priv->buf2;
1087
1088 net = r_card_get_net_address(R_CARD(card));
1089 if (net)
1090 {
1091 pixbuf = gtk_icon_theme_load_icon (priv->theme, "net", 20, 0, NULL);
1092
1093 data_view_write(body, "\n");
1094 data_view_write_pixbuf(body, pixbuf, _("Net"));
1095 g_object_unref(pixbuf);
1096
1097 for (; net; net = r_card_get_next_net_address(R_CARD(card)))
1098 {
1099 gchar* ttype;
1100 g_object_get(R_NET_ADDRESS(net),
1101 "url", &url, "url-type", &type, NULL);
1102
1103 switch(type)
1104 {
1105 case R_NET_ADDRESS_WEB:
1106 linktype = WEB_LINK;
1107 break;
1108
1109 case R_NET_ADDRESS_EMAIL:
1110 linktype = EMAIL_LINK;
1111 break;
1112
1113 case R_NET_ADDRESS_EKIGA:
1114 linktype = TELEPHONE_LINK;
1115 break;
1116
1117 case R_NET_ADDRESS_IRC_AIM:
1118 linktype = IRC_LINK;
1119 break;
1120
1121 case R_NET_ADDRESS_IRC_ICQ:
1122 linktype = IRC_LINK;
1123 break;
1124
1125 case R_NET_ADDRESS_IRC_JABBER:
1126 linktype = IRC_LINK;
1127 break;
1128
1129 case R_NET_ADDRESS_IRC_YAHOO:
1130 linktype = IRC_LINK;
1131 break;
1132
1133 case R_NET_ADDRESS_IRC_MSN:
1134 linktype = IRC_LINK;
1135 break;
1136
1137
1138 default:
1139 break;
1140 }
1141
1142 ttype = r_net_address_decode_type(type);
1143 data_view_write_link(body, _(ttype), url, linktype);
1144 }
1145 }
1146 }
1147
1148
1149 static void
write_telephones(RubricaDataView * view,RCard * card)1150 write_telephones(RubricaDataView* view, RCard* card)
1151 {
1152 RubricaDataViewPrivate* priv;
1153 GtkTextBuffer* body;
1154 RTelephone* tel = NULL;
1155 GdkPixbuf* pixbuf = NULL;
1156
1157 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
1158 body = priv->buf2;
1159
1160 tel = r_card_get_telephone(R_CARD(card));
1161 if (tel)
1162 {
1163 pixbuf = gtk_icon_theme_load_icon (priv->theme, "phone", 20, 0, NULL);
1164
1165 data_view_write(body, "\n");
1166 data_view_write_pixbuf(body, pixbuf, _("Telephone"));
1167 g_object_unref(pixbuf);
1168
1169 for (; tel; tel = r_card_get_next_telephone(R_CARD(card)))
1170 {
1171 RTelephoneType ttype;
1172 gchar* num;
1173
1174 g_object_get(R_TELEPHONE(tel),
1175 "telephone-number", &num,
1176 "telephone-type", &ttype, NULL);
1177
1178 data_view_write_link(body, _(r_telephone_lookup_enum2str(ttype)),
1179 num, TELEPHONE_LINK);
1180 }
1181 }
1182 }
1183
1184
1185
1186 static void
write_notes(RubricaDataView * view,RPersonalCard * card)1187 write_notes(RubricaDataView* view, RPersonalCard* card)
1188 {
1189 RubricaDataViewPrivate* priv;
1190 GtkTextBuffer* body;
1191 RNotes* notes;
1192 GdkPixbuf* pixbuf = NULL;
1193 gchar *partner, *other_notes, *pubkey;
1194 gboolean has_partner;
1195
1196 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
1197 body = priv->buf2;
1198 notes = r_personal_card_get_notes(R_PERSONAL_CARD(card));
1199
1200 if (notes && r_notes_have_data(notes))
1201 {
1202 g_object_get(notes,
1203 "has-partner", &has_partner,
1204 "partner-name", &partner,
1205 "other-notes", &other_notes,
1206 "pubkey", &pubkey, NULL);
1207
1208 pixbuf = gtk_icon_theme_load_icon (priv->theme, "notes", 20, 0, NULL);
1209
1210 data_view_write(body, "\n");
1211 data_view_write_pixbuf(body, pixbuf, _("Notes"));
1212 g_object_unref(pixbuf);
1213
1214 if (has_partner)
1215 {
1216 data_view_write(body, _("Contact has a partner"));
1217 data_view_write(body, "\n");
1218
1219 data_view_write_line(body, _("partner's name"), partner, TRUE);
1220
1221 if (r_notes_know_birthday(notes))
1222 {
1223 data_view_write_line(body, _("partner's birthday"),
1224 r_notes_get_birth_date(notes), TRUE);
1225 }
1226
1227 if (r_notes_know_anniversary(notes))
1228 {
1229 data_view_write_line(body, _("anniversary"),
1230 r_notes_get_anniversary_date(notes), TRUE);
1231 }
1232 }
1233
1234 data_view_write_line(body, _("Public key"), pubkey, TRUE);
1235 data_view_write_line(body, _("Other notes"), other_notes, TRUE);
1236 }
1237 }
1238
1239
1240 static void
write_company_notes(RubricaDataView * view,RCompanyCard * card)1241 write_company_notes(RubricaDataView* view, RCompanyCard* card)
1242 {
1243 RubricaDataViewPrivate* priv;
1244 GtkTextBuffer* body;
1245 gchar* text = NULL;
1246
1247 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
1248 body = priv->buf2;
1249
1250 g_object_get(card, "company-notes", &text, NULL);
1251 if (text)
1252 {
1253 GdkPixbuf* pixbuf = NULL;
1254
1255 pixbuf = gtk_icon_theme_load_icon (priv->theme, "notes", 20, 0, NULL);
1256 data_view_write(body, "\n");
1257 data_view_write_pixbuf(body, pixbuf, _("Notes"));
1258 data_view_write(body, "\n");
1259 g_object_unref(pixbuf);
1260
1261 data_view_write(body, text);
1262 }
1263 }
1264
1265
1266
1267 static void
data_view_show_personal_card(RubricaDataView * view,RCard * card)1268 data_view_show_personal_card(RubricaDataView* view, RCard* card)
1269 {
1270 RubricaDataViewPrivate* priv;
1271
1272 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
1273
1274 /* Clean header and body buffers */
1275 data_view_clear_header(view);
1276 data_view_clear_body(view);
1277
1278 write_personal_data (view, R_PERSONAL_CARD(card));
1279 write_groups (view, card);
1280 write_addresses (view, card);
1281 write_work (view, R_PERSONAL_CARD(card));
1282 write_net (view, card);
1283 write_telephones (view, card);
1284 write_notes (view, R_PERSONAL_CARD(card));
1285 }
1286
1287
1288
1289 static void
data_view_show_company_card(RubricaDataView * view,RCard * card)1290 data_view_show_company_card(RubricaDataView* view, RCard* card)
1291 {
1292 RubricaDataViewPrivate* priv;
1293
1294 priv = RUBRICA_DATA_VIEW_GET_PRIVATE(view);
1295
1296 data_view_clear_header(view);
1297 data_view_clear_body(view);
1298
1299 write_company_info (view, card);
1300 write_groups (view, card);
1301 write_addresses (view, card);
1302 write_net (view, card);
1303 write_telephones (view, card);
1304 write_company_notes (view, R_COMPANY_CARD(card));
1305 }
1306
1307
1308
1309
1310
1311
1312 /* Public
1313 */
1314 /**
1315 * rubrica_data_view_new
1316 *
1317 * create a #RubricaDataView
1318 *
1319 * returns: a new #RubricaDataView*
1320 */
1321 GtkWidget*
rubrica_data_view_new()1322 rubrica_data_view_new()
1323 {
1324 GtkWidget* view;
1325
1326 view = GTK_WIDGET(g_object_new(RUBRICA_DATA_VIEW_TYPE, NULL));
1327
1328 return view;
1329 }
1330
1331
1332 void
rubrica_data_view_show_card(RubricaDataView * view,RCard * card)1333 rubrica_data_view_show_card (RubricaDataView* view, RCard* card)
1334 {
1335 g_return_if_fail(IS_RUBRICA_DATA_VIEW(view));
1336 g_return_if_fail(IS_R_CARD(card));
1337
1338 if (r_card_is_personal(card))
1339 data_view_show_personal_card(view, card);
1340 else
1341 data_view_show_company_card(view, card);
1342 }
1343