e4881f1695b84e705d6b8ecee60e6cec347a971f
[birthday] / src / birthday.c
1 /*
2  *  Birthday application for Maemo.
3  *  Copyright (C) 2010 Roman Moravcik
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <time.h>
29
30 #include <libosso.h>
31
32 #include <glib.h>
33 #include <glib/gi18n.h>
34
35 #include <gtk/gtk.h>
36 #include <hildon/hildon.h>
37
38 #include <libebook/e-book.h>
39 #include <libosso-abook/osso-abook.h>
40
41 enum
42 {
43         COLUMN_AVATAR = 0,
44         COLUMN_DISPLAY,
45         COLUMN_FULLNAME,
46         COLUMN_NEXT_BIRTHDAY,
47         NUM_COLS
48 };
49
50 static unsigned int
51 calc_age (EContactDate *bdate)
52 {
53     struct tm tm_bday;
54     struct tm *tm_age;
55     time_t t_age;
56     int age = 0;
57
58     tm_bday.tm_sec = 0;
59     tm_bday.tm_min = 0;
60     tm_bday.tm_hour = 0;
61     tm_bday.tm_mday = bdate->day;
62     tm_bday.tm_mon = bdate->month - 1;
63     tm_bday.tm_year = bdate->year - 1900;
64
65     t_age = time (NULL) - mktime (&tm_bday);
66     tm_age = gmtime (&t_age);
67     age = tm_age->tm_year - 70;
68
69     if (age < 0)
70         age = 0;
71
72     return age;
73 }
74
75 static unsigned int
76 calc_next_bday (EContactDate *bdate)
77 {
78     struct tm tm_current_bday, tm_next_bday;
79     struct tm *tm_current_date;
80     time_t t_current_date, t_current_bday, t_next_bday, t_next_bday_in;
81
82     t_current_date = time (NULL);
83     tm_current_date = localtime (&t_current_date);
84
85     tm_current_bday.tm_sec = 0;
86     tm_current_bday.tm_min = 0;
87     tm_current_bday.tm_hour = 0;
88     tm_current_bday.tm_mday = bdate->day;
89     tm_current_bday.tm_mon = bdate->month - 1;
90     tm_current_bday.tm_year = tm_current_date->tm_year;
91     t_current_bday = mktime (&tm_current_bday);
92
93     if (t_current_date > t_current_bday) {
94         tm_next_bday.tm_sec = 0;
95         tm_next_bday.tm_min = 0;
96         tm_next_bday.tm_hour = 0;
97         tm_next_bday.tm_mday = bdate->day;
98         tm_next_bday.tm_mon = bdate->month - 1;
99         tm_next_bday.tm_year = tm_current_date->tm_year + 1;
100         t_next_bday = mktime (&tm_next_bday);
101     } else {
102         t_next_bday = t_current_bday;
103     }
104     t_next_bday_in = t_next_bday - t_current_date;
105     return (t_next_bday_in / 86400) + 1;
106 }
107
108 static gchar *
109 get_text_font_by_name (const gchar *name)
110 {
111         GtkSettings *settings;
112         GtkStyle *style;
113
114         settings = gtk_settings_get_default ();
115         style = gtk_rc_get_style_by_paths (settings, name, NULL, G_TYPE_NONE);
116         return pango_font_description_to_string (style->font_desc);
117 }
118
119 static gchar *
120 get_text_color_by_name (const gchar *name)
121 {
122         GtkSettings *settings;
123         GtkStyle *style;
124         GdkColor color;
125
126         settings = gtk_settings_get_default ();
127         style = gtk_rc_get_style_by_paths (settings, "GtkButton", "osso-logical-colors", G_OBJECT_TYPE(gtk_button_new()));
128         gtk_style_lookup_color (style, name, &color);
129         return gdk_color_to_string (&color);
130 }
131
132 static GtkListStore *
133 create_bday_liststore(GList *contacts)
134 {
135         GtkListStore *store;
136         GtkTreeIter iter;
137         GList *contact;
138         gchar *text_font = NULL;
139         gchar *text_color = NULL;
140
141         text_font = get_text_font_by_name ("SmallSystemFont");
142         text_color = get_text_color_by_name ("SecondaryTextColor");
143
144         store = gtk_list_store_new(NUM_COLS,
145                                    GDK_TYPE_PIXBUF,     /* COLUMN_AVATAR */
146                                    G_TYPE_STRING,       /* COLUMN_DISPLAY */
147                                    G_TYPE_STRING,       /* COLUMN_FULLNAME */
148                                    G_TYPE_INT);         /* COLUMN_NEXT_BIRTHDAY */
149
150         for (contact = contacts; contact != NULL; contact = contact->next) {
151                 EContactDate *bdate;
152
153                 bdate = e_contact_get (E_CONTACT (contact->data), E_CONTACT_BIRTH_DATE);
154                 if (bdate) {
155                         EContactPhoto *photo;
156                         GError *error = NULL;
157                         GdkPixbuf *avatar;
158                         gchar *avatar_filename = NULL;
159                         gchar *fullname = NULL;
160                         guint age = 0, next_birthday = 0;
161                         gchar *display_column = NULL;
162                         gchar *next_birthday_text = NULL;
163
164                         photo = e_contact_get (E_CONTACT (contact->data), E_CONTACT_PHOTO);
165
166                         if (photo) {
167                                 avatar_filename = g_filename_from_uri (photo->data.uri, NULL, NULL);
168                                 if (avatar_filename) {
169                                         avatar = gdk_pixbuf_new_from_file_at_size (avatar_filename, 48, 48, &error);
170                                         g_free (avatar_filename);
171                                         avatar_filename = NULL;
172                                 }
173                                 
174                         } else {
175                                 avatar = gdk_pixbuf_new_from_file ("/usr/share/icons/hicolor/48x48/hildon/general_default_avatar.png", &error);
176                         }
177
178                         fullname = e_contact_get (E_CONTACT (contact->data), E_CONTACT_FULL_NAME);
179                         age = calc_age(bdate);
180                         next_birthday = calc_next_bday(bdate);
181                         next_birthday_text = g_strdup_printf(ngettext ("next birthday in %d day", "next birthday in %d days", next_birthday), next_birthday);
182                         display_column = g_strdup_printf("%s <span font_desc=\"%s\" foreground=\"%s\"><sup>(%d)</sup>\n%02d.%02d.%04d, %s</span>",
183                                                          fullname, text_font, text_color, age, bdate->day, bdate->month, bdate->year, next_birthday_text);
184
185                         gtk_list_store_append (store, &iter);
186                         gtk_list_store_set (store, &iter,
187                                             COLUMN_AVATAR, avatar,
188                                             COLUMN_DISPLAY, display_column,
189                                             COLUMN_FULLNAME, fullname,
190                                             COLUMN_NEXT_BIRTHDAY, next_birthday,
191                                             -1);
192
193                         if (next_birthday_text)
194                                 g_free (next_birthday_text);
195                         next_birthday_text = NULL;
196                 }
197         }
198
199         if (text_font)
200                 g_free (text_font);
201
202         if (text_color)
203                 g_free (text_color);
204
205         return store;
206 }
207
208 static GtkWidget *
209 create_main_window(GtkListStore *store)
210 {
211         HildonProgram *program = NULL;
212         GtkWidget *window, *main_vbox, *alignment, *label, *pannable, *tree_view;
213         GtkTreeViewColumn *column;
214         GtkCellRenderer *renderer;
215
216         program = hildon_program_get_instance ();
217         g_set_application_name (_("Birthday"));
218
219         /* main window */
220         window = hildon_stackable_window_new ();
221         hildon_program_add_window (program, HILDON_WINDOW (window));
222
223         /* aligment */
224         alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
225         gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
226                                    HILDON_MARGIN_HALF, 0, HILDON_MARGIN_DEFAULT, HILDON_MARGIN_DEFAULT);
227         gtk_container_add (GTK_CONTAINER (window), alignment);
228
229         /* main vbox */
230         main_vbox = gtk_vbox_new (FALSE, 0);
231         gtk_container_add (GTK_CONTAINER (alignment), main_vbox);
232
233         /* no_search_result label */
234         label = gtk_label_new (_("No contacts with set birthdate"));
235         hildon_helper_set_logical_color (label, GTK_RC_FG,
236                                          GTK_STATE_NORMAL, "SecondaryTextColor");
237         hildon_helper_set_logical_font (label, "LargeSystemFont");
238         gtk_box_pack_start (GTK_BOX (main_vbox), label, TRUE, TRUE, 0);
239
240         /* alignment for pannable area */
241         alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
242         gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
243                                    0, 0, HILDON_MARGIN_DEFAULT, HILDON_MARGIN_DEFAULT);
244         gtk_box_pack_start (GTK_BOX (main_vbox), alignment, TRUE, TRUE, 0);
245
246         /* pannable for tree view */
247         pannable = hildon_pannable_area_new ();
248         gtk_container_add (GTK_CONTAINER (alignment), pannable);
249
250         /* tree view */
251         tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
252         gtk_container_add(GTK_CONTAINER(pannable), tree_view);
253         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
254                                               COLUMN_NEXT_BIRTHDAY, GTK_SORT_ASCENDING);
255
256         /* display column */
257         column = gtk_tree_view_column_new ();
258         gtk_tree_view_column_set_fixed_width (column, 704);
259         gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
260         renderer = gtk_cell_renderer_text_new ();
261         gtk_tree_view_column_pack_start (column, renderer, TRUE);
262         gtk_tree_view_column_set_attributes (column, renderer,
263                                              "markup", COLUMN_DISPLAY,
264                                              NULL);
265         g_object_set (G_OBJECT (renderer), "xpad", 10, NULL);
266
267         gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
268
269         /* avatar column */
270         column = gtk_tree_view_column_new ();
271         gtk_tree_view_column_set_fixed_width (column, 64);
272         gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
273         renderer = gtk_cell_renderer_pixbuf_new ();
274         gtk_tree_view_column_pack_end (column, renderer, FALSE);
275         gtk_tree_view_column_set_attributes (column, renderer,
276                                              "pixbuf", COLUMN_AVATAR,
277                                              NULL);
278         gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
279
280
281
282         /* window signals */
283         g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
284
285         gtk_widget_show_all (GTK_WIDGET(window));
286         gtk_widget_hide (GTK_WIDGET(label));
287         return window;
288 }
289
290 int main (int argc, char **argv)
291 {
292         osso_context_t *osso_context;
293         EBook *ebook;
294         EBookQuery *query;
295         GError *error = NULL;
296         GtkWidget *window;
297         GtkListStore *store;
298         GList *contacts;
299
300         hildon_gtk_init (&argc, &argv);
301
302         /* initialize localization */
303         setlocale(LC_ALL, "");
304         bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
305         bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
306         textdomain(GETTEXT_PACKAGE);
307
308         /* initialize osso */
309         osso_context = osso_initialize ("birthday", "0.1", TRUE, NULL);
310         if (osso_context == NULL) {
311                 g_critical ("Error initializing osso");
312                 return 1;
313         }
314
315         /* init abook */
316         if (!osso_abook_init (&argc, &argv, osso_context)) {
317                 g_critical ("Error initializing libosso-abook");
318                 goto exit;
319         }
320
321         ebook = e_book_new_system_addressbook (&error);
322         if (!ebook) {
323                 g_warning ("Error opening system address book: %s", error->message);
324                 g_error_free (error);
325                 goto exit;
326         }
327
328         if (!e_book_open (ebook, TRUE, &error)) {
329                 g_warning ("Error opening system address book: %s", error->message);
330                 g_error_free (error);
331                 goto exit;
332         }
333
334         query = e_book_query_any_field_contains ("");
335
336         if (!e_book_get_contacts (ebook, query, &contacts, &error)) {
337                 g_warning ("Error getting contacts: %s", error->message);
338                 g_error_free (error);
339                 goto exit;
340         }
341
342         store = create_bday_liststore(contacts);
343         window = create_main_window(store);
344
345         gtk_main();
346
347 exit:
348         osso_deinitialize (osso_context);
349         return 0;
350 }