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