evolution-3.6.4/calendar/alarm-notify/alarm-notify-dialog.c

No issues found

  1 /*
  2  * Evolution calendar - alarm notification dialog
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) version 3.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  *
 18  * Authors:
 19  *		Federico Mena-Quintero <federico@ximian.com>
 20  *
 21  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 22  *
 23  */
 24 
 25 #ifdef HAVE_CONFIG_H
 26 #include <config.h>
 27 #endif
 28 
 29 #include <stdio.h>
 30 #include <string.h>
 31 #include <glib/gi18n.h>
 32 
 33 #include "alarm-notify-dialog.h"
 34 #include "config-data.h"
 35 #include "util.h"
 36 
 37 #include "e-util/e-util.h"
 38 #include "e-util/e-util-private.h"
 39 #include "misc/e-buffer-tagger.h"
 40 
 41 enum {
 42 	ALARM_DISPLAY_COLUMN,
 43 	ALARM_SUMMARY_COLUMN,
 44 	ALARM_DESCRIPTION_COLUMN,
 45 	ALARM_LOCATION_COLUMN,
 46 
 47 	ALARM_START_COLUMN,
 48 	ALARM_END_COLUMN,
 49 
 50 	ALARM_FUNCINFO_COLUMN,
 51 
 52 	N_ALARM_COLUMNS
 53 };
 54 
 55 /* The useful contents of the alarm notify dialog */
 56 
 57 typedef struct {
 58 	AlarmNotifyFunc func;
 59 	gpointer func_data;
 60 } AlarmFuncInfo;
 61 
 62 typedef struct {
 63 	GtkBuilder *builder;
 64 
 65 	GtkWidget *dialog;
 66 	GtkWidget *snooze_time_min;
 67 	GtkWidget *snooze_time_hrs;
 68 	GtkWidget *snooze_time_days;
 69 	GtkWidget *snooze_btn;
 70 	GtkWidget *edit_btn;
 71 	GtkWidget *print_btn;
 72 	GtkWidget *dismiss_btn;
 73 	GtkWidget *minutes_label;
 74 	GtkWidget *hrs_label;
 75 	GtkWidget *days_label;
 76 	GtkWidget *description;
 77 	GtkWidget *location;
 78 	GtkWidget *treeview;
 79 
 80 	AlarmFuncInfo *cur_funcinfo;
 81 
 82 } AlarmNotify;
 83 
 84 static void	tree_selection_changed_cb	(GtkTreeSelection *selection,
 85 						 gpointer data);
 86 static void	fill_in_labels			(AlarmNotify *an,
 87 						 const gchar *summary,
 88 						 const gchar *description,
 89 						 const gchar *location,
 90 						 time_t occur_start,
 91 						 time_t occur_end);
 92 
 93 static void	edit_pressed_cb			(GtkButton *button,
 94 						 gpointer user_data);
 95 static void	snooze_pressed_cb		(GtkButton *button,
 96 						 gpointer user_data);
 97 
 98 static void
 99 an_update_minutes_label (GtkSpinButton *sb,
100                          gpointer data)
101 {
102 	AlarmNotify *an;
103 	gint snooze_timeout_min;
104 
105 	an = (AlarmNotify *) data;
106 
107 	snooze_timeout_min  = gtk_spin_button_get_value_as_int (sb);
108 	gtk_label_set_text (GTK_LABEL (an->minutes_label), ngettext ("minute", "minutes", snooze_timeout_min));
109 }
110 
111 static void
112 an_update_hrs_label (GtkSpinButton *sb,
113                      gpointer data)
114 {
115 	AlarmNotify *an;
116 	gint snooze_timeout_hrs;
117 
118 	an = (AlarmNotify *) data;
119 
120 	snooze_timeout_hrs  = gtk_spin_button_get_value_as_int (sb);
121 	gtk_label_set_text (GTK_LABEL (an->hrs_label), ngettext ("hour", "hours", snooze_timeout_hrs));
122 }
123 
124 static void
125 an_update_days_label (GtkSpinButton *sb,
126                       gpointer data)
127 {
128 	AlarmNotify *an;
129 	gint snooze_timeout_days;
130 
131 	an = (AlarmNotify *) data;
132 
133 	snooze_timeout_days  = gtk_spin_button_get_value_as_int (sb);
134 	gtk_label_set_text (GTK_LABEL (an->days_label), ngettext ("day", "days", snooze_timeout_days));
135 }
136 
137 static void
138 dialog_response_cb (GtkDialog *dialog,
139                     guint response_id,
140                     gpointer user_data)
141 {
142 	AlarmNotify *an = user_data;
143 	GtkTreeIter iter;
144 	GtkTreeModel *model = NULL;
145 	AlarmFuncInfo *funcinfo = NULL;
146 	GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (an->treeview));
147 
148 	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
149 		gtk_tree_model_get (model, &iter, ALARM_FUNCINFO_COLUMN, &funcinfo, -1);
150 	}
151 
152 	if (!funcinfo) {
153 		GtkTreeModel *treemodel = gtk_tree_view_get_model (GTK_TREE_VIEW (an->treeview));
154 		if (!gtk_tree_model_get_iter_first (treemodel, &iter))
155 			return;
156 
157 		gtk_tree_model_get (treemodel, &iter, ALARM_FUNCINFO_COLUMN, &funcinfo, -1);
158 	}
159 
160 	g_return_if_fail (funcinfo);
161 
162 	switch (response_id) {
163 	case GTK_RESPONSE_CLOSE:
164 	case GTK_RESPONSE_DELETE_EVENT:
165 		(* funcinfo->func) (ALARM_NOTIFY_CLOSE, -1, funcinfo->func_data);
166 		break;
167 	}
168 }
169 
170 static void
171 edit_pressed_cb (GtkButton *button,
172                  gpointer user_data)
173 {
174 	AlarmNotify *an = user_data;
175 	AlarmFuncInfo *funcinfo = NULL;
176 	GtkTreeIter iter;
177 	GtkTreeModel *model = NULL;
178 	GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (an->treeview));
179 
180 	if (gtk_tree_selection_get_selected (selection, &model, &iter))
181 		gtk_tree_model_get (model, &iter, ALARM_FUNCINFO_COLUMN, &funcinfo, -1);
182 
183 	g_return_if_fail (funcinfo);
184 
185 	(* funcinfo->func) (ALARM_NOTIFY_EDIT, -1, funcinfo->func_data);
186 }
187 
188 static void
189 print_pressed_cb (GtkButton *button,
190                  gpointer user_data)
191 {
192 	AlarmNotify *an = user_data;
193 	AlarmFuncInfo *funcinfo = NULL;
194 	GtkTreeIter iter;
195 	GtkTreeModel *model = NULL;
196 	GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (an->treeview));
197 
198 	if (gtk_tree_selection_get_selected (selection, &model, &iter))
199 		gtk_tree_model_get (model, &iter, ALARM_FUNCINFO_COLUMN, &funcinfo, -1);
200 
201 	g_return_if_fail (funcinfo);
202 
203 	(* funcinfo->func) (ALARM_NOTIFY_PRINT, -1, funcinfo->func_data);
204 }
205 
206 #define DEFAULT_SNOOZE_MINS 5
207 
208 static void
209 snooze_pressed_cb (GtkButton *button,
210                    gpointer user_data)
211 {
212 	gint snooze_timeout;
213 	AlarmNotify *an = user_data;
214 	GtkTreeIter iter;
215 	GtkTreeModel *model = NULL;
216 	AlarmFuncInfo *funcinfo = NULL;
217 	GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (an->treeview));
218 
219 	gtk_widget_grab_focus ((GtkWidget *) button);
220 
221 	if (gtk_tree_selection_get_selected (selection, &model, &iter))
222 		gtk_tree_model_get (model, &iter, ALARM_FUNCINFO_COLUMN, &funcinfo, -1);
223 
224 	g_return_if_fail (funcinfo);
225 
226 	snooze_timeout = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (an->snooze_time_min));
227 	snooze_timeout += 60 * (gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (an->snooze_time_hrs)));
228 	snooze_timeout += 60 * 24 * (gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (an->snooze_time_days)));
229 	if (!snooze_timeout)
230 		snooze_timeout = DEFAULT_SNOOZE_MINS;
231 	(* funcinfo->func) (ALARM_NOTIFY_SNOOZE, snooze_timeout, funcinfo->func_data);
232 }
233 
234 static void
235 dismiss_pressed_cb (GtkButton *button,
236                     gpointer user_data)
237 {
238 	AlarmNotify *an = user_data;
239 	GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (an->treeview));
240 
241 	g_return_if_fail (model != NULL);
242 
243 	if (gtk_tree_model_iter_n_children (model, NULL) <= 1) {
244 		gtk_dialog_response (GTK_DIALOG (an->dialog), GTK_RESPONSE_CLOSE);
245 	} else {
246 		GtkTreeIter iter;
247 		AlarmFuncInfo *funcinfo = NULL;
248 		GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (an->treeview));
249 
250 		if (gtk_tree_selection_get_selected (selection, &model, &iter))
251 			gtk_tree_model_get (model, &iter, ALARM_FUNCINFO_COLUMN, &funcinfo, -1);
252 
253 		g_return_if_fail (funcinfo);
254 
255 		(* funcinfo->func) (ALARM_NOTIFY_DISMISS, -1, funcinfo->func_data);
256 	}
257 }
258 
259 static void
260 dialog_destroyed_cb (GtkWidget *dialog,
261                      gpointer user_data)
262 {
263 	AlarmNotify *an = user_data;
264 
265 	g_object_unref (an->builder);
266 	g_free (an);
267 }
268 
269 /**
270  * notified_alarms_dialog_new:
271  *
272  * Return value: a new dialog in which you can add alarm notifications
273  **/
274 AlarmNotificationsDialog *
275 notified_alarms_dialog_new (void)
276 {
277 	GtkWidget *container;
278 	GtkWidget *image;
279 	GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
280 	AlarmNotificationsDialog *na = NULL;
281 	AlarmNotify *an = g_new0 (AlarmNotify, 1);
282 	GtkTreeViewColumn *column = NULL;
283 	GtkTreeSelection *selection = NULL;
284 	GtkTreeModel *model = GTK_TREE_MODEL (gtk_list_store_new (
285 			N_ALARM_COLUMNS,
286 
287 			G_TYPE_STRING, /* Display */
288 			G_TYPE_STRING, /* Summary */
289 			G_TYPE_STRING, /* Description */
290 			G_TYPE_STRING, /* Location */
291 
292 			G_TYPE_POINTER, /* Start */
293 			G_TYPE_POINTER, /* End */
294 
295 			G_TYPE_POINTER /* FuncInfo */));
296 
297 	an->builder = gtk_builder_new ();
298 	e_load_ui_builder_definition (an->builder, "alarm-notify.ui");
299 
300 	an->dialog = e_builder_get_widget (an->builder, "alarm-notify");
301 	an->snooze_time_min = e_builder_get_widget (an->builder, "snooze-time-min");
302 	an->minutes_label = e_builder_get_widget (an->builder, "minutes-label");
303 	an->snooze_time_hrs = e_builder_get_widget (an->builder, "snooze-time-hrs");
304 	an->hrs_label = e_builder_get_widget (an->builder, "hrs-label");
305 	an->snooze_time_days = e_builder_get_widget (an->builder, "snooze-time-days");
306 	an->days_label = e_builder_get_widget (an->builder, "days-label");
307 	an->description = e_builder_get_widget (an->builder, "description-label");
308 	an->location = e_builder_get_widget (an->builder, "location-label");
309 	an->treeview = e_builder_get_widget (an->builder, "appointments-treeview");
310 	an->snooze_btn = e_builder_get_widget (an->builder, "snooze-button");
311 	an->edit_btn = e_builder_get_widget (an->builder, "edit-button");
312 	an->print_btn = e_builder_get_widget (an->builder, "print-button");
313 	an->dismiss_btn = e_builder_get_widget (an->builder, "dismiss-button");
314 
315 	if (!(an->dialog && an->treeview
316 	      && an->snooze_time_min && an->snooze_time_hrs && an->snooze_time_days
317 	      && an->description && an->location && an->edit_btn && an->print_btn && an->snooze_btn && an->dismiss_btn)) {
318 		g_warning ("alarm_notify_dialog(): Could not find all widgets in alarm-notify.ui file!");
319 		g_object_unref (an->builder);
320 		g_free (an);
321 		return NULL;
322 	}
323 
324 	e_buffer_tagger_connect (GTK_TEXT_VIEW (an->description));
325 
326 	gtk_tree_view_set_model (GTK_TREE_VIEW (an->treeview), model);
327 
328 	gtk_window_set_keep_above (GTK_WINDOW (an->dialog), TRUE);
329 
330 	column = gtk_tree_view_column_new_with_attributes (
331 		_("Start time"),
332 		renderer, "text", ALARM_DISPLAY_COLUMN, NULL);
333 
334 	gtk_tree_view_column_set_attributes (
335 		column, renderer,
336 		"markup", ALARM_DISPLAY_COLUMN, NULL);
337 
338 	gtk_tree_view_append_column (GTK_TREE_VIEW (an->treeview), column);
339 
340 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (an->treeview));
341 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
342 	g_signal_connect (
343 		selection, "changed",
344 		G_CALLBACK (tree_selection_changed_cb), an);
345 	tree_selection_changed_cb (selection, an);
346 
347 	gtk_widget_realize (an->dialog);
348 
349 	container = gtk_dialog_get_action_area (GTK_DIALOG (an->dialog));
350 	gtk_container_set_border_width (GTK_CONTAINER (container), 12);
351 
352 	container = gtk_dialog_get_content_area (GTK_DIALOG (an->dialog));
353 	gtk_container_set_border_width (GTK_CONTAINER (container), 0);
354 
355 	image = e_builder_get_widget (an->builder, "alarm-image");
356 	gtk_image_set_from_icon_name (
357 		GTK_IMAGE (image), "stock_alarm", GTK_ICON_SIZE_DIALOG);
358 
359 	g_signal_connect (
360 		an->edit_btn, "clicked",
361 		G_CALLBACK (edit_pressed_cb), an);
362 	g_signal_connect (
363 		an->print_btn, "clicked",
364 		G_CALLBACK (print_pressed_cb), an);
365 	g_signal_connect (
366 		an->snooze_btn, "clicked",
367 		G_CALLBACK (snooze_pressed_cb), an);
368 	g_signal_connect (
369 		an->dismiss_btn, "clicked",
370 		G_CALLBACK (dismiss_pressed_cb), an);
371 	g_signal_connect (
372 		an->dialog, "response",
373 		G_CALLBACK (dialog_response_cb), an);
374 	g_signal_connect (
375 		an->dialog, "destroy",
376 		G_CALLBACK (dialog_destroyed_cb), an);
377 
378 	if (!gtk_widget_get_realized (an->dialog))
379 		gtk_widget_realize (an->dialog);
380 
381 	gtk_window_set_icon_name (GTK_WINDOW (an->dialog), "stock_alarm");
382 
383 	/* Set callback for updating the snooze "minutes" label */
384 	g_signal_connect (
385 		an->snooze_time_min, "value_changed",
386 		G_CALLBACK (an_update_minutes_label), an);
387 
388 	/* Set callback for updating the snooze "hours" label */
389 	g_signal_connect (
390 		an->snooze_time_hrs, "value_changed",
391 		G_CALLBACK (an_update_hrs_label), an);
392 
393 	/* Set callback for updating the snooze "days" label */
394 	g_signal_connect (
395 		an->snooze_time_days, "value_changed",
396 		G_CALLBACK (an_update_days_label), an);
397 
398 	na = g_new0 (AlarmNotificationsDialog, 1);
399 
400 	na->treeview = an->treeview;
401 	na->dialog = an->dialog;
402 
403 	return na;
404 }
405 
406 /**
407  * add_alarm_to_notified_alarms_dialog:
408  * @na: Pointer to the dialog-info
409  * @trigger: Trigger time for the alarm.
410  * @occur_start: Start of occurrence time for the event.
411  * @occur_end: End of occurrence time for the event.
412  * @vtype: Type of the component which corresponds to the alarm.
413  * @summary: Short summary of the appointment
414  * @description: Long description of the appointment
415  * @location: Location of the appointment
416  * @func: Function to be called when a dialog action is invoked.
417  * @func_data: Closure data for @func.
418  *
419  * The specified @func will be used to notify the client about result of
420  * the actions in the dialog.
421  *
422  * Return value: the iter in the treeview of the dialog
423  **/
424 
425 GtkTreeIter
426 add_alarm_to_notified_alarms_dialog (AlarmNotificationsDialog *na,
427                                      time_t trigger,
428                                      time_t occur_start,
429                                      time_t occur_end,
430                                      ECalComponentVType vtype,
431                                      const gchar *summary,
432                                      const gchar *description,
433                                      const gchar *location,
434                                      AlarmNotifyFunc func,
435                                      gpointer func_data)
436 {
437 	GtkTreeIter iter;
438 	GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (na->treeview));
439 	AlarmFuncInfo *funcinfo = NULL;
440 	gchar *to_display = NULL, *start, *end, *str_time;
441 	icaltimezone *current_zone;
442 
443 	/* Iter is not yet defined but still we return it in all the g_return_val_if_fail() calls? */
444 	g_return_val_if_fail (trigger != -1, iter);
445 
446 	/* Only VEVENTs or VTODOs can have alarms */
447 	g_return_val_if_fail (vtype == E_CAL_COMPONENT_EVENT || vtype == E_CAL_COMPONENT_TODO, iter);
448 	g_return_val_if_fail (summary != NULL, iter);
449 	g_return_val_if_fail (description != NULL, iter);
450 	g_return_val_if_fail (location != NULL, iter);
451 	g_return_val_if_fail (func != NULL, iter);
452 
453 	funcinfo = g_new0 (AlarmFuncInfo, 1);
454 	funcinfo->func = func;
455 	funcinfo->func_data = func_data;
456 
457 	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
458 
459 	current_zone = config_data_get_timezone ();
460 	start = timet_to_str_with_zone (occur_start, current_zone);
461 	end = timet_to_str_with_zone (occur_end, current_zone);
462 	str_time = calculate_time (occur_start, occur_end);
463 	to_display = g_markup_printf_escaped (
464 		"<big><b>%s</b></big>\n%s %s",
465 		summary, start, str_time);
466 	g_free (start);
467 	g_free (end);
468 	gtk_list_store_set (
469 		GTK_LIST_STORE (model), &iter,
470 		ALARM_DISPLAY_COLUMN, to_display, -1);
471 	g_free (to_display);
472 	g_free (str_time);
473 
474 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, ALARM_SUMMARY_COLUMN, summary, -1);
475 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, ALARM_DESCRIPTION_COLUMN, description, -1);
476 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, ALARM_LOCATION_COLUMN, location, -1);
477 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, ALARM_START_COLUMN, occur_start, -1);
478 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, ALARM_END_COLUMN, occur_end, -1);
479 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, ALARM_FUNCINFO_COLUMN, funcinfo, -1);
480 
481 	return iter;
482 }
483 
484 static void
485 tree_selection_changed_cb (GtkTreeSelection *selection,
486                            gpointer user_data)
487 {
488 	GtkTreeModel *model;
489 	GtkTreeIter iter;
490 	AlarmNotify *an = user_data;
491 
492 	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
493 		gchar *summary, *description, *location;
494 		time_t occur_start, occur_end;
495 
496 		gtk_widget_set_sensitive (an->snooze_btn, TRUE);
497 		gtk_widget_set_sensitive (an->edit_btn, TRUE);
498 		gtk_widget_set_sensitive (an->print_btn, TRUE);
499 		gtk_widget_set_sensitive (an->dismiss_btn, TRUE);
500 		gtk_tree_model_get (model, &iter, ALARM_SUMMARY_COLUMN, &summary, -1);
501 		gtk_tree_model_get (model, &iter, ALARM_DESCRIPTION_COLUMN, &description, -1);
502 		gtk_tree_model_get (model, &iter, ALARM_LOCATION_COLUMN, &location, -1);
503 		gtk_tree_model_get (model, &iter, ALARM_START_COLUMN, &occur_start, -1);
504 		gtk_tree_model_get (model, &iter, ALARM_END_COLUMN, &occur_end, -1);\
505 		gtk_tree_model_get (model, &iter, ALARM_FUNCINFO_COLUMN, &an->cur_funcinfo, -1);
506 
507 		fill_in_labels (an, summary, description, location, occur_start, occur_end);
508 
509 		g_free (summary);
510 		g_free (description);
511 		g_free (location);
512 	} else {
513 		gtk_widget_set_sensitive (an->snooze_btn, FALSE);
514 		gtk_widget_set_sensitive (an->edit_btn, FALSE);
515 		gtk_widget_set_sensitive (an->print_btn, FALSE);
516 		gtk_widget_set_sensitive (an->dismiss_btn, FALSE);
517 
518 		fill_in_labels (an, "", "", "", -1, -1);
519 	}
520 }
521 
522 static void
523 fill_in_labels (AlarmNotify *an,
524                 const gchar *summary,
525                 const gchar *description,
526                 const gchar *location,
527                 time_t occur_start,
528                 time_t occur_end)
529 {
530 	GtkTextTagTable *table = gtk_text_tag_table_new ();
531 	GtkTextBuffer *buffer =  gtk_text_buffer_new (table);
532 	gtk_text_buffer_set_text (buffer, description, -1);
533 	e_buffer_tagger_disconnect (GTK_TEXT_VIEW (an->description));
534 	gtk_text_view_set_buffer (GTK_TEXT_VIEW (an->description), buffer);
535 	gtk_label_set_text (GTK_LABEL (an->location), location);
536 	e_buffer_tagger_connect (GTK_TEXT_VIEW (an->description));
537 	e_buffer_tagger_update_tags (GTK_TEXT_VIEW (an->description));
538 	g_object_unref (table);
539 	g_object_unref (buffer);
540 }