2 * Birthday application for Maemo.
3 * Copyright (C) 2010 Roman Moravcik
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.
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.
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
33 #include <glib/gi18n.h>
36 #include <hildon/hildon.h>
38 #include <libebook/e-book.h>
39 #include <libosso-abook/osso-abook.h>
53 sort_by_name_clicked (GtkButton *button,
58 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
59 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
60 COLUMN_FULLNAME, GTK_SORT_ASCENDING);
64 sort_by_date_clicked (GtkButton *button,
69 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
70 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
71 COLUMN_NEXT_BIRTHDAY, GTK_SORT_ASCENDING);
76 on_search_close_clicked (GtkButton *button,
79 GtkWidget *search = GTK_WIDGET (data);
82 gtk_widget_hide (search);
84 /* FIXME: refilter treeview */
89 on_key_press_event (GtkWidget *widget,
93 GtkWidget *search = GTK_WIDGET (data);
95 if ((event->keyval > GDK_space) && (event->keyval <= GDK_stricteq) && !GTK_WIDGET_VISIBLE (search)) {
97 gtk_widget_show (search);
99 /* FIXME: focus on entry */
106 calc_age (EContactDate *bdate)
116 tm_bday.tm_mday = bdate->day;
117 tm_bday.tm_mon = bdate->month - 1;
118 tm_bday.tm_year = bdate->year - 1900;
120 t_age = time (NULL) - mktime (&tm_bday);
121 tm_age = gmtime (&t_age);
122 age = tm_age->tm_year - 70;
131 calc_next_bday (EContactDate *bdate)
133 struct tm tm_current_bday, tm_next_bday;
134 struct tm *tm_current_date;
135 time_t t_current_date, t_current_bday, t_next_bday;
137 t_current_date = time (NULL);
138 tm_current_date = localtime (&t_current_date);
140 tm_current_bday.tm_sec = 0;
141 tm_current_bday.tm_min = 0;
142 tm_current_bday.tm_hour = 0;
143 tm_current_bday.tm_mday = bdate->day;
144 tm_current_bday.tm_mon = bdate->month - 1;
145 tm_current_bday.tm_year = tm_current_date->tm_year;
146 t_current_bday = mktime (&tm_current_bday);
148 if (t_current_date > t_current_bday) {
149 tm_next_bday.tm_sec = 0;
150 tm_next_bday.tm_min = 0;
151 tm_next_bday.tm_hour = 0;
152 tm_next_bday.tm_mday = bdate->day;
153 tm_next_bday.tm_mon = bdate->month - 1;
154 tm_next_bday.tm_year = tm_current_date->tm_year + 1;
155 t_next_bday = mktime (&tm_next_bday);
157 t_next_bday = t_current_bday;
160 return (t_next_bday - t_current_date) / 86400;
164 get_text_font_by_name (const gchar *name)
166 GtkSettings *settings;
169 settings = gtk_settings_get_default ();
170 style = gtk_rc_get_style_by_paths (settings, name, NULL, G_TYPE_NONE);
171 return pango_font_description_to_string (style->font_desc);
175 get_text_color_by_name (const gchar *name)
177 GtkSettings *settings;
181 settings = gtk_settings_get_default ();
182 style = gtk_rc_get_style_by_paths (settings, "GtkButton", "osso-logical-colors", G_OBJECT_TYPE(gtk_button_new()));
183 gtk_style_lookup_color (style, name, &color);
184 return gdk_color_to_string (&color);
187 static GtkListStore *
188 create_bday_liststore (GList *contacts)
193 gchar *text_font = NULL;
194 gchar *text_color = NULL;
196 text_font = get_text_font_by_name ("SmallSystemFont");
197 text_color = get_text_color_by_name ("SecondaryTextColor");
199 store = gtk_list_store_new(NUM_COLS,
200 GDK_TYPE_PIXBUF, /* COLUMN_AVATAR */
201 G_TYPE_STRING, /* COLUMN_DISPLAY */
202 G_TYPE_STRING, /* COLUMN_FULLNAME */
203 G_TYPE_INT); /* COLUMN_NEXT_BIRTHDAY */
205 for (contact = contacts; contact != NULL; contact = contact->next) {
206 EContactDate *bdate = NULL;
208 bdate = e_contact_get (E_CONTACT (contact->data), E_CONTACT_BIRTH_DATE);
210 EContactPhoto *photo = NULL;
211 GError *error = NULL;
212 GdkPixbuf *avatar = NULL;
213 gchar *fullname = NULL;
214 guint age = 0, next_birthday = 0;
215 gchar *display_column = NULL;
216 gchar *next_birthday_text = NULL;
218 photo = e_contact_get (E_CONTACT (contact->data), E_CONTACT_PHOTO);
220 if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
221 GdkPixbufLoader *loader;
223 loader = gdk_pixbuf_loader_new ();
224 if (gdk_pixbuf_loader_write (loader, (guchar *) photo->data.inlined.data, photo->data.inlined.length, NULL))
225 avatar = gdk_pixbuf_loader_get_pixbuf (loader);
228 gchar *avatar_filename = NULL;
230 avatar_filename = g_filename_from_uri (photo->data.uri, NULL, NULL);
231 if (avatar_filename) {
232 avatar = gdk_pixbuf_new_from_file (avatar_filename, &error);
233 g_free (avatar_filename);
238 gint height = gdk_pixbuf_get_height (avatar);
240 gint new_height = 48;
241 gint new_width = new_height * gdk_pixbuf_get_width (avatar) / height;
242 avatar = gdk_pixbuf_scale_simple (avatar, new_width, new_height, GDK_INTERP_BILINEAR);
245 e_contact_photo_free (photo);
248 avatar = gdk_pixbuf_new_from_file ("/usr/share/icons/hicolor/48x48/hildon/general_default_avatar.png", &error);
251 fullname = e_contact_get (E_CONTACT (contact->data), E_CONTACT_FULL_NAME);
253 fullname = e_contact_get (E_CONTACT (contact->data), E_CONTACT_GIVEN_NAME);
255 fullname = e_contact_get (E_CONTACT (contact->data), E_CONTACT_FAMILY_NAME);
257 fullname = e_contact_get (E_CONTACT (contact->data), E_CONTACT_NICKNAME);
259 fullname = e_contact_get (E_CONTACT (contact->data), E_CONTACT_ORG);
265 age = calc_age(bdate);
266 next_birthday = calc_next_bday(bdate);
267 next_birthday_text = g_strdup_printf(ngettext ("next birthday in %d day", "next birthday in %d days", next_birthday), next_birthday);
268 display_column = g_strdup_printf("%s <span font_desc=\"%s\" foreground=\"%s\"><sup>(%d)</sup>\n%02d.%02d.%04d, %s</span>",
269 fullname, text_font, text_color, age, bdate->day, bdate->month, bdate->year, next_birthday_text);
271 gtk_list_store_append (store, &iter);
272 gtk_list_store_set (store, &iter,
273 COLUMN_AVATAR, avatar,
274 COLUMN_DISPLAY, display_column,
275 COLUMN_FULLNAME, fullname,
276 COLUMN_NEXT_BIRTHDAY, next_birthday,
280 g_free (display_column);
281 display_column = NULL;
287 if (next_birthday_text)
288 g_free (next_birthday_text);
289 next_birthday_text = NULL;
291 e_contact_date_free (bdate);
308 GtkWidget *hbox, *entry, *button;
309 GtkEntryCompletion *completion;
312 hbox = gtk_hbox_new (FALSE, HILDON_MARGIN_DEFAULT);
315 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT);
316 hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry), HILDON_GTK_INPUT_MODE_FULL);
317 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
319 completion = gtk_entry_completion_new ();
320 gtk_entry_completion_set_inline_completion (completion, TRUE);
321 gtk_entry_completion_set_popup_completion (completion, FALSE);
322 gtk_entry_set_completion (GTK_ENTRY (entry), completion);
325 button = GTK_WIDGET (gtk_tool_button_new (gtk_image_new_from_icon_name
326 ("general_close", (GtkIconSize) HILDON_ICON_PIXEL_SIZE_FINGER), "Clear"));
327 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, TRUE, 0);
330 // g_signal_connect (entry, "changed", G_CALLBACK (onSearchEntryChanged), this);
331 g_signal_connect (button, "clicked", G_CALLBACK (on_search_close_clicked), hbox);
337 create_main_menu (GtkWidget *window)
342 menu = HILDON_APP_MENU (hildon_app_menu_new ());
343 hildon_window_set_app_menu (HILDON_WINDOW (window), menu);
345 filter = hildon_gtk_radio_button_new (HILDON_SIZE_FINGER_HEIGHT , NULL);
346 gtk_button_set_label (GTK_BUTTON (filter), _("Name"));
347 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (filter), FALSE);
348 g_signal_connect_after (filter, "clicked", G_CALLBACK (sort_by_name_clicked), NULL);
349 hildon_app_menu_add_filter (menu, GTK_BUTTON (filter));
351 filter = hildon_gtk_radio_button_new_from_widget (HILDON_SIZE_FINGER_HEIGHT , GTK_RADIO_BUTTON (filter));
352 gtk_button_set_label (GTK_BUTTON (filter), _("Date"));
353 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (filter), FALSE);
354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (filter), TRUE);
355 g_signal_connect_after (filter, "clicked", G_CALLBACK (sort_by_date_clicked), NULL);
356 hildon_app_menu_add_filter (menu, GTK_BUTTON (filter));
358 gtk_widget_show_all (GTK_WIDGET (menu));
362 create_main_window (GtkListStore *store)
364 HildonProgram *program = NULL;
365 GtkWidget *window, *main_vbox, *alignment, *label, *pannable, *search;
366 GtkTreeViewColumn *column;
367 GtkCellRenderer *renderer;
369 program = hildon_program_get_instance ();
370 g_set_application_name (_("Birthday"));
373 window = hildon_stackable_window_new ();
374 hildon_program_add_window (program, HILDON_WINDOW (window));
377 alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
378 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
379 HILDON_MARGIN_HALF, 0, HILDON_MARGIN_DEFAULT, HILDON_MARGIN_DEFAULT);
380 gtk_container_add (GTK_CONTAINER (window), alignment);
383 main_vbox = gtk_vbox_new (FALSE, 0);
384 gtk_container_add (GTK_CONTAINER (alignment), main_vbox);
386 /* no_search_result label */
387 label = gtk_label_new (_("No contacts with set birthdate"));
388 hildon_helper_set_logical_color (label, GTK_RC_FG,
389 GTK_STATE_NORMAL, "SecondaryTextColor");
390 hildon_helper_set_logical_font (label, "LargeSystemFont");
391 gtk_box_pack_start (GTK_BOX (main_vbox), label, TRUE, TRUE, 0);
393 /* alignment for pannable area */
394 alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
395 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
396 0, 0, HILDON_MARGIN_DEFAULT, 0);
397 gtk_box_pack_start (GTK_BOX (main_vbox), alignment, TRUE, TRUE, 0);
399 /* pannable for tree view */
400 pannable = hildon_pannable_area_new ();
401 g_object_set (G_OBJECT (pannable), "mov-mode", HILDON_MOVEMENT_MODE_VERT, NULL);
402 gtk_container_add (GTK_CONTAINER (alignment), pannable);
405 tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
406 gtk_container_add (GTK_CONTAINER (pannable), tree_view);
408 column = gtk_tree_view_column_new ();
409 gtk_tree_view_column_set_fixed_width (column, 709);
410 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
411 renderer = gtk_cell_renderer_text_new ();
412 gtk_tree_view_column_pack_start (column, renderer, TRUE);
413 gtk_tree_view_column_set_attributes (column, renderer,
414 "markup", COLUMN_DISPLAY,
416 g_object_set (G_OBJECT (renderer), "xpad", 10, NULL);
418 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
421 column = gtk_tree_view_column_new ();
422 gtk_tree_view_column_set_fixed_width (column, 48);
423 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
424 renderer = gtk_cell_renderer_pixbuf_new ();
425 gtk_tree_view_column_pack_end (column, renderer, FALSE);
426 gtk_tree_view_column_set_attributes (column, renderer,
427 "pixbuf", COLUMN_AVATAR,
429 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
432 search = create_search_bar();
433 gtk_box_pack_end (GTK_BOX (main_vbox), search, FALSE, FALSE, 0);
436 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
437 // g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (on_key_press_event), search);
439 gtk_widget_show_all (GTK_WIDGET (window));
440 gtk_widget_hide (GTK_WIDGET (label));
441 gtk_widget_hide (GTK_WIDGET (search));
445 int main (int argc, char **argv)
447 osso_context_t *osso_context;
450 GError *error = NULL;
455 hildon_gtk_init (&argc, &argv);
457 /* initialize localization */
458 setlocale(LC_ALL, "");
459 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
460 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
461 textdomain(GETTEXT_PACKAGE);
463 /* initialize osso */
464 osso_context = osso_initialize ("birthday", "0.1", TRUE, NULL);
465 if (osso_context == NULL) {
466 g_critical ("Error initializing osso");
471 if (!osso_abook_init (&argc, &argv, osso_context)) {
472 g_critical ("Error initializing libosso-abook");
476 ebook = e_book_new_system_addressbook (&error);
478 g_warning ("Error opening system address book: %s", error->message);
479 g_error_free (error);
483 if (!e_book_open (ebook, TRUE, &error)) {
484 g_warning ("Error opening system address book: %s", error->message);
485 g_error_free (error);
489 query = e_book_query_any_field_contains ("");
491 if (!e_book_get_contacts (ebook, query, &contacts, &error)) {
492 g_warning ("Error getting contacts: %s", error->message);
493 g_error_free (error);
497 store = create_bday_liststore (contacts);
498 window = create_main_window (store);
499 g_object_unref (G_OBJECT (store));
500 create_main_menu (window);
502 /* sort list by next birthdays */
503 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
504 COLUMN_NEXT_BIRTHDAY, GTK_SORT_ASCENDING);
509 osso_deinitialize (osso_context);