1 
2 /*
3  * Osmo - a handy personal organizer
4  *
5  * Copyright (C) 2007 Tomasz Maka <pasp@users.sourceforge.net>
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 "contacts_birthdays.h"
23 #include "i18n.h"
24 #include "calendar.h"
25 #include "contacts.h"
26 #include "calendar_notes.h"
27 #include "options_prefs.h"
28 #include "stock_icons.h"
29 #include "calendar_utils.h"
30 #include "utils.h"
31 #include "utils_gui.h"
32 #include "utils_date.h"
33 
34 #ifdef CONTACTS_ENABLED
35 
36 /*------------------------------------------------------------------------------*/
37 
38 void
birthdays_window_close_cb(GtkWidget * widget,GdkEvent * event,gpointer user_data)39 birthdays_window_close_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
40 {
41 	GUI *appGUI = (GUI *) user_data;
42 
43     gtk_window_get_size (GTK_WINDOW(appGUI->cnt->birthdays_window),
44                         &config.contacts_birthdays_win_w, &config.contacts_birthdays_win_h);
45 
46     gtk_widget_destroy (appGUI->cnt->birthdays_window);
47 }
48 
49 /*------------------------------------------------------------------------------*/
50 
51 void
button_birthdays_window_close_cb(GtkButton * button,gpointer user_data)52 button_birthdays_window_close_cb (GtkButton *button, gpointer user_data)
53 {
54 	birthdays_window_close_cb (GTK_WIDGET (button), NULL, user_data);
55 }
56 
57 /*------------------------------------------------------------------------------*/
58 
59 gint
birthdays_key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer user_data)60 birthdays_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
61 {
62 	switch (event->keyval) {
63 
64 		case GDK_KEY_Escape:
65 	        birthdays_window_close_cb (NULL, NULL, user_data);
66 			return TRUE;
67 
68 	}
69 
70 	return FALSE;
71 }
72 
73 /*------------------------------------------------------------------------------*/
74 
75 gint
birthdays_list_dbclick_cb(GtkWidget * widget,GdkEventButton * event,gpointer user_data)76 birthdays_list_dbclick_cb (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
77 {
78 GtkTreeIter iter;
79 GtkTreeModel *model, *contacts_model;
80 GtkTreePath *sort_path, *filter_path, *path;
81 gint id, id_c;
82 
83     GUI *appGUI = (GUI *) user_data;
84 	contacts_model = GTK_TREE_MODEL (appGUI->cnt->contacts_list_store);
85 
86     if (((event->type == GDK_2BUTTON_PRESS) && (event->button == 1)) == FALSE)
87 	    return FALSE;
88 
89 	if (gtk_tree_selection_get_selected (appGUI->cnt->birthdays_list_selection, &model, &iter)) {
90 
91 		if (strlen (gtk_entry_get_text (GTK_ENTRY (appGUI->cnt->contacts_find_entry)))) {
92 			gtk_entry_set_text (GTK_ENTRY (appGUI->cnt->contacts_find_entry), "");
93 			gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (appGUI->cnt->contacts_filter));
94 		}
95 
96 		gtk_tree_model_get (model, &iter, B_COLUMN_ID, &id, -1);
97 		gtk_widget_destroy (appGUI->cnt->birthdays_window);
98 
99 		contacts_selection_activate (FALSE, appGUI);
100 
101 		if (gtk_tree_model_get_iter_first (contacts_model, &iter) == TRUE) {
102 			sort_path = gtk_tree_model_get_path (contacts_model, &iter);
103 
104 			while (sort_path != NULL) {
105 				gtk_tree_view_set_cursor (GTK_TREE_VIEW (appGUI->cnt->contacts_list), sort_path, NULL, FALSE);
106 				filter_path = gtk_tree_model_sort_convert_path_to_child_path (GTK_TREE_MODEL_SORT (appGUI->cnt->contacts_sort), sort_path);
107 
108 				if (filter_path != NULL) {
109 					path = gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (appGUI->cnt->contacts_filter), filter_path);
110 
111 					if (path != NULL) {
112 						gtk_tree_model_get_iter (contacts_model, &iter, path);
113 						gtk_tree_model_get (contacts_model, &iter, COLUMN_ID, &id_c, -1);
114 
115 						if (id == id_c) {
116 							contacts_selection_activate (TRUE, appGUI);
117 							gtk_tree_view_set_cursor (GTK_TREE_VIEW (appGUI->cnt->contacts_list), sort_path, NULL, FALSE);
118 							gtk_tree_path_free (path);
119 							gtk_tree_path_free (filter_path);
120 							g_signal_emit_by_name (G_OBJECT (appGUI->cnt->contacts_list_selection), "changed");
121 							break;
122 						}
123 
124 						gtk_tree_path_free (path);
125 					}
126 
127 					gtk_tree_path_free (filter_path);
128 				}
129 
130 				gtk_tree_path_next (sort_path);
131 				if (gtk_tree_model_get_iter (contacts_model, &iter, sort_path) == FALSE) break;
132 			}
133 
134 			gtk_tree_path_free (sort_path);
135 		}
136 
137 	}
138 
139 	return TRUE;
140 }
141 
142 /*------------------------------------------------------------------------------*/
143 
144 void
contacts_create_birthdays_window(GUI * appGUI)145 contacts_create_birthdays_window (GUI *appGUI)
146 {
147 GtkWidget           *vbox1;
148 GtkWidget           *hseparator;
149 GtkWidget           *hbuttonbox;
150 GtkWidget           *close_button;
151 GtkTreeViewColumn   *column;
152 GtkCellRenderer     *renderer;
153 GtkWidget           *scrolledwindow;
154 gint n, id, age;
155 guint32 date;
156 gchar *text, buffer[BUFFER_SIZE], buff[BUFFER_SIZE];
157 GtkTreeIter iter, n_iter;
158 GDate *cdate_birthday, *cdate_current;
159 guint b_day, b_month, b_year;
160 guint c_day, c_month, c_year;
161 gboolean flag, leap, has_next;
162 
163 	cdate_birthday = g_date_new ();
164 	g_return_if_fail (cdate_birthday != NULL);
165 
166 	cdate_current = g_date_new ();
167 	g_return_if_fail (cdate_current != NULL);
168 
169 	n = 0;
170         has_next = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter);
171 	while (has_next) {
172 		gtk_tree_model_get (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter, COLUMN_BIRTH_DAY_DATE, &date, -1);
173 		if (date) n++;
174                 has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter);
175 	}
176 
177 	if (n == 0) {
178 		utl_gui_create_dialog (GTK_MESSAGE_INFO, _("No birthdays defined"), GTK_WINDOW (appGUI->main_window));
179 		return;
180 	}
181 
182 	appGUI->cnt->birthdays_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
183 	gtk_window_set_title (GTK_WINDOW (appGUI->cnt->birthdays_window), _("Birthdays list"));
184 	gtk_window_set_position (GTK_WINDOW (appGUI->cnt->birthdays_window), GTK_WIN_POS_CENTER_ON_PARENT);
185 	gtk_window_set_default_size (GTK_WINDOW (appGUI->cnt->birthdays_window),
186                                  config.contacts_birthdays_win_w, config.contacts_birthdays_win_h);
187 	gtk_window_set_modal (GTK_WINDOW (appGUI->cnt->birthdays_window), TRUE);
188 	g_signal_connect (G_OBJECT (appGUI->cnt->birthdays_window), "delete_event",
189 	                  G_CALLBACK (birthdays_window_close_cb), appGUI);
190 	if (config.fullscreen == FALSE) {
191 		gtk_window_set_transient_for (GTK_WINDOW (appGUI->cnt->birthdays_window), GTK_WINDOW (appGUI->main_window));
192 	}
193 	gtk_container_set_border_width (GTK_CONTAINER (appGUI->cnt->birthdays_window), 8);
194 	g_signal_connect (G_OBJECT (appGUI->cnt->birthdays_window), "key_press_event",
195 	                  G_CALLBACK (birthdays_key_press_cb), appGUI);
196 
197 	vbox1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
198 	gtk_widget_show (vbox1);
199 	gtk_container_add (GTK_CONTAINER (appGUI->cnt->birthdays_window), vbox1);
200 
201 	scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
202 	gtk_widget_show (scrolledwindow);
203 	gtk_box_pack_start (GTK_BOX (vbox1), scrolledwindow, TRUE, TRUE, 0);
204 
205 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
206 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
207 
208 	appGUI->cnt->birthdays_list_store = gtk_list_store_new (BIRTHDAYS_NUM_COLUMNS,
209 	                                                        G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING,
210 	                                                        G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
211 
212 	appGUI->cnt->birthdays_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (appGUI->cnt->birthdays_list_store));
213 	gtk_widget_show (appGUI->cnt->birthdays_list);
214 	gtk_widget_set_can_default (appGUI->cnt->birthdays_list, TRUE);
215 	gtk_container_add (GTK_CONTAINER (scrolledwindow), appGUI->cnt->birthdays_list);
216 
217 	appGUI->cnt->birthdays_list_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (appGUI->cnt->birthdays_list));
218 
219 	g_signal_connect (G_OBJECT (appGUI->cnt->birthdays_list), "button_press_event",
220 	                  G_CALLBACK (birthdays_list_dbclick_cb), appGUI);
221 
222 	/* create columns */
223 	renderer = gtk_cell_renderer_text_new ();
224 	g_object_set (G_OBJECT (renderer), "xpad", 8, NULL);
225 	column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer, "text", B_COLUMN_NAME, NULL);
226 	gtk_tree_view_column_set_visible (column, TRUE);
227 	gtk_tree_view_column_set_expand (column, TRUE);
228 	gtk_tree_view_append_column (GTK_TREE_VIEW (appGUI->cnt->birthdays_list), column);
229 	gtk_tree_view_column_set_sort_column_id (column, B_COLUMN_NAME);
230 
231 	renderer = gtk_cell_renderer_text_new ();
232 	column = gtk_tree_view_column_new_with_attributes (_("Days to birthday"), renderer, "text", B_COLUMN_DAYS_NUM, NULL);
233 	gtk_tree_view_column_set_visible (column, FALSE);
234 	gtk_tree_view_append_column (GTK_TREE_VIEW (appGUI->cnt->birthdays_list), column);
235 
236 	renderer = gtk_cell_renderer_text_new ();
237 	g_object_set (G_OBJECT (renderer), "xalign", 1.0, NULL);
238 	g_object_set (G_OBJECT (renderer), "xpad", 8, NULL);
239 	column = gtk_tree_view_column_new_with_attributes (_("Days to birthday"), renderer, "text", B_COLUMN_DAYS, NULL);
240 	gtk_tree_view_column_set_visible (column, TRUE);
241 	gtk_tree_view_append_column (GTK_TREE_VIEW (appGUI->cnt->birthdays_list), column);
242 	gtk_tree_view_column_set_sort_column_id (column, B_COLUMN_DAYS_NUM);
243 	g_signal_emit_by_name (column, "clicked");
244 
245 	column = gtk_tree_view_column_new_with_attributes (_("Age"), renderer, "text", B_COLUMN_AGE, NULL);
246 	gtk_tree_view_column_set_visible (column, config.cnt_visible_age_column);
247 	gtk_tree_view_append_column (GTK_TREE_VIEW (appGUI->cnt->birthdays_list), column);
248 	gtk_tree_view_column_set_sort_column_id (column, B_COLUMN_AGE);
249 
250 	column = gtk_tree_view_column_new_with_attributes (_("Birthday date"), renderer, "text", B_COLUMN_DATE, NULL);
251 	gtk_tree_view_column_set_visible (column, config.cnt_visible_birthday_date_column);
252 	gtk_tree_view_append_column (GTK_TREE_VIEW (appGUI->cnt->birthdays_list), column);
253 
254 	renderer = gtk_cell_renderer_text_new ();
255 	column = gtk_tree_view_column_new_with_attributes (_("Zodiac sign"), renderer, "text", B_COLUMN_ZODIAC, NULL);
256 	gtk_tree_view_column_set_visible (column, config.cnt_visible_zodiac_sign_column);
257 	gtk_tree_view_append_column (GTK_TREE_VIEW (appGUI->cnt->birthdays_list), column);
258 
259 	renderer = gtk_cell_renderer_text_new ();
260 	column = gtk_tree_view_column_new_with_attributes ("ID", renderer, "text", B_COLUMN_ID, NULL);
261 	gtk_tree_view_column_set_visible (column, FALSE);
262 	gtk_tree_view_append_column (GTK_TREE_VIEW (appGUI->cnt->birthdays_list), column);
263 
264 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (appGUI->cnt->birthdays_list), FALSE);
265 
266 	g_date_set_julian (cdate_current, utl_date_get_current_julian ());
267 	c_day = g_date_get_day (cdate_current);
268 	c_month = g_date_get_month (cdate_current);
269 	c_year = g_date_get_year (cdate_current);
270 
271         has_next = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter);
272 	while (has_next) {
273 		gtk_tree_model_get (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter, COLUMN_BIRTH_DAY_DATE, &date, -1);
274 
275 		if (g_date_valid_julian (date)) {
276 
277                     /* calculate age */
278                     g_date_set_julian (cdate_birthday, date);
279                     b_day = g_date_get_day (cdate_birthday);
280                     b_month = g_date_get_month (cdate_birthday);
281                     b_year = g_date_get_year (cdate_birthday);
282 
283                     age = (gint) c_year - b_year;
284                     if (b_month < c_month || (b_month == c_month && b_day < c_day)) age++;
285 
286                     if (age > 0) {
287 
288 			/* name */
289 			flag = FALSE;
290 			g_snprintf (buff, BUFFER_SIZE, "(%s)", _("None"));
291 
292 			gtk_tree_model_get (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter, COLUMN_LAST_NAME, &text, -1);
293 			if (text != NULL) {
294 				flag = TRUE;
295 				if (strcmp (text, buff) == 0) {
296 					text[0] = '\0';
297 					flag = FALSE;
298 				}
299 				g_strlcpy (buffer, text, BUFFER_SIZE);
300 				g_free (text);
301 			}
302 
303 			gtk_tree_model_get (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter, COLUMN_FIRST_NAME, &text, -1);
304 			if (text != NULL) {
305 				if (strcmp (text, buff) == 0) {
306 					text[0] = '\0';
307 				}
308 				if (flag == TRUE) {
309 					g_strlcat (buffer, " ", BUFFER_SIZE);
310 					g_strlcat (buffer, text, BUFFER_SIZE);
311 				} else {
312 					g_strlcpy (buffer, text, BUFFER_SIZE);
313 				}
314 				g_free (text);
315 			}
316 
317 			gtk_tree_model_get (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter, COLUMN_ID, &id, -1);
318 			gtk_list_store_append (appGUI->cnt->birthdays_list_store, &n_iter);
319 			gtk_list_store_set (appGUI->cnt->birthdays_list_store, &n_iter,
320 			                    B_COLUMN_ID, id, B_COLUMN_NAME, buffer, B_COLUMN_AGE, age, -1);
321 
322 			/* calculate days to birthday */
323 			b_year = c_year;
324 			if ((b_month < c_month) || (b_month == c_month && b_day < c_day)) b_year++;
325 
326 			leap = FALSE;
327 			if (g_date_valid_dmy (b_day, b_month, b_year) == FALSE) {
328 				g_date_set_day (cdate_birthday, b_day - 1);
329 				leap = TRUE;
330 			}
331 			g_date_set_year (cdate_birthday, b_year);
332 
333 			date = g_date_days_between (cdate_current, cdate_birthday);
334 			if (date == 0) {
335 				g_snprintf (buffer, BUFFER_SIZE, "%s", _("today"));
336 			} else {
337 				g_snprintf (buffer, BUFFER_SIZE, leap ? "%d + 1" : "%d", date);
338 			}
339 
340 			g_date_strftime (buff, BUFFER_SIZE, "%A, ", cdate_birthday);
341 			g_strlcat (buff, julian_to_str (g_date_get_julian (cdate_birthday), config.date_format, config.override_locale_settings), BUFFER_SIZE);
342 
343 			gtk_list_store_set (appGUI->cnt->birthdays_list_store, &n_iter,
344 			                    B_COLUMN_DAYS_NUM, date, B_COLUMN_DAYS, buffer,
345 			                    B_COLUMN_DATE, buff, B_COLUMN_ZODIAC, utl_get_zodiac_name (b_day, b_month), -1);
346                     }
347 		}
348                 has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (appGUI->cnt->contacts_list_store), &iter);
349 	}
350 	g_date_free (cdate_birthday);
351 	g_date_free (cdate_current);
352 
353 	hseparator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
354 	gtk_widget_show (hseparator);
355 	gtk_box_pack_start (GTK_BOX (vbox1), hseparator, FALSE, TRUE, 4);
356 
357 	hbuttonbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
358 	gtk_widget_show (hbuttonbox);
359 	gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox, FALSE, TRUE, 0);
360 	gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
361 	gtk_box_set_spacing (GTK_BOX (hbuttonbox), 4);
362 
363 	close_button = gtk_button_new_with_mnemonic (_("_Close"));
364 	gtk_widget_show (close_button);
365 	g_signal_connect (close_button, "clicked", G_CALLBACK (button_birthdays_window_close_cb), appGUI);
366 	gtk_container_add (GTK_CONTAINER (hbuttonbox), close_button);
367 
368 	gtk_widget_show (appGUI->cnt->birthdays_window);
369 	gtk_widget_grab_focus (close_button);
370 }
371 
372 /*------------------------------------------------------------------------------*/
373 
374 #endif  /* CONTACTS_ENABLED */
375 
376